From 53fe8204cfb1e163aa7a7294dd4577b9e99f0405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BE=99=E8=85=BE=E7=8C=AB=E8=B7=83?= <1043137532@qq.com> Date: Fri, 15 May 2026 22:06:22 +0800 Subject: [PATCH] 2.12.8.0 --- .editorconfig | 10 +- PCLCS/Constants.cs | 75 + PCLCS/PCLCS.csproj | 31 +- PCLCS/Resource/Resource.cs | 33 + Plain Craft Launcher 2.sln | 2 +- Plain Craft Launcher 2/App.config | 11 +- Plain Craft Launcher 2/Application.xaml | 11 +- Plain Craft Launcher 2/Application.xaml.vb | 138 +- .../Controls/MyButton.xaml.vb | 4 +- Plain Craft Launcher 2/Controls/MyCard.vb | 13 +- .../Controls/MyCheckBox.xaml.vb | 4 +- Plain Craft Launcher 2/Controls/MyComboBox.vb | 6 +- .../Controls/MyComboBoxItem.vb | 2 +- .../Controls/MyExtraButton.xaml.vb | 6 +- .../Controls/MyExtraTextButton.xaml.vb | 4 +- .../Controls/MyHint.xaml.vb | 4 +- .../Controls/MyIconButton.xaml.vb | 4 +- .../Controls/MyIconTextButton.xaml.vb | 4 +- Plain Craft Launcher 2/Controls/MyImage.vb | 18 +- .../Controls/MyListItem.xaml.vb | 10 +- .../Controls/MyLoading.xaml.vb | 6 +- Plain Craft Launcher 2/Controls/MyMenuItem.vb | 2 +- .../Controls/MyMsg/MyMsgInput.xaml.vb | 6 +- .../Controls/MyMsg/MyMsgSelect.xaml.vb | 6 +- .../Controls/MyMsg/MyMsgText.xaml.vb | 6 +- .../Controls/MyPageRight.vb | 98 +- .../Controls/MyRadioBox.xaml.vb | 55 +- .../Controls/MyRadioButton.xaml.vb | 7 +- .../Controls/MyScrollBar.vb | 2 +- .../Controls/MySlider.xaml.vb | 4 +- .../Controls/MySliderDot.xaml.vb | 2 +- Plain Craft Launcher 2/Controls/MyTextBox.vb | 4 +- .../Controls/MyTextButton.vb | 2 +- Plain Craft Launcher 2/FormMain.xaml.vb | 311 +- .../Modules/Base/ModAnimation.vb | 21 +- .../Modules/Base/ModBase.vb | 1357 +- .../Modules/Base/ModLoader.vb | 55 +- Plain Craft Launcher 2/Modules/Base/ModNet.vb | 292 +- .../Modules/Base/ModValidate.vb | 31 +- .../Modules/Base/MyBitmap.vb | 6 +- .../Modules/Base/PclLogger.vb | 54 + Plain Craft Launcher 2/Modules/Constants.vb | 78 - .../Modules/Minecraft/ModCrash.vb | 287 +- .../Modules/Minecraft/ModDownload.vb | 116 +- .../Modules/Minecraft/ModJava.vb | 159 +- .../Modules/Minecraft/ModLaunch.vb | 534 +- .../Modules/Minecraft/ModMinecraft.vb | 534 +- .../Modules/Minecraft/ModModpack.vb | 279 +- .../Modules/Minecraft/ModWatcher.vb | 37 +- Plain Craft Launcher 2/Modules/ModEvent.vb | 32 +- Plain Craft Launcher 2/Modules/ModMain.vb | 167 +- Plain Craft Launcher 2/Modules/ModMusic.vb | 59 +- Plain Craft Launcher 2/Modules/ModSecret.vb | 10 +- .../{ResourceFile.vb => LocalResourceFile.vb} | 51 +- ...eFileLoader.vb => LocalResourceLoaders.vb} | 207 +- .../Modules/Resource/ResourceProject.vb | 73 +- .../Modules/Resource/ResourceSearcher.vb | 73 +- .../Modules/Resource/ResourceVersion.vb | 74 +- .../Modules/Resource/WikiEntry.vb | 29 +- .../My Project/AssemblyInfo.vb | 4 +- .../My Project/Resources.Designer.vb | 31 +- .../My Project/Resources.resx | 5 +- .../Pages/PageDownload/ModDownloadLib.vb | 367 +- .../PageDownload/PageDownloadInstall.xaml.vb | 34 +- .../PageDownload/PageDownloadLeft.xaml.vb | 2 +- .../Resource/MyResourceItem.xaml.vb | 8 +- .../Resource/PageDownloadCompDetail.xaml.vb | 146 +- .../PageDownload/Resource/PageResource.xaml | 5 +- .../Resource/PageResource.xaml.vb | 14 +- .../Pages/PageInstance/MyLocalModItem.xaml | 2 +- .../Pages/PageInstance/MyLocalModItem.xaml.vb | 12 +- .../PageInstance/PageInstanceExport.xaml.vb | 147 +- .../PageInstance/PageInstanceLeft.xaml.vb | 2 +- .../PageInstance/PageInstanceMod.xaml.vb | 182 +- .../PageInstanceModDisabled.xaml.vb | 2 +- .../PageInstance/PageInstanceOverall.xaml.vb | 93 +- .../Pages/PageInstance/PageInstanceSetup.xaml | 4 +- .../PageInstance/PageInstanceSetup.xaml.vb | 36 +- .../Pages/PageLaunch/MyMsgLogin.xaml.vb | 12 +- .../Pages/PageLaunch/MySkin.xaml.vb | 43 +- .../Pages/PageLaunch/PageLaunchLeft.xaml.vb | 184 +- .../Pages/PageLaunch/PageLaunchRight.xaml.vb | 109 +- .../Pages/PageLaunch/PageLoginAuth.xaml.vb | 24 +- .../PageLaunch/PageLoginAuthSkin.xaml.vb | 16 +- .../Pages/PageLaunch/PageLoginLegacy.xaml.vb | 16 +- .../Pages/PageLaunch/PageLoginMs.xaml.vb | 10 +- .../Pages/PageLaunch/PageLoginMsSkin.xaml.vb | 37 +- .../Pages/PageLaunch/PageLoginNide.xaml.vb | 20 +- .../PageLaunch/PageLoginNideSkin.xaml.vb | 12 +- .../Pages/PageLink/PageLinkMain.xaml.vb | 98 +- .../Pages/PageOther/PageOtherAbout.xaml | 498 +- .../Pages/PageOther/PageOtherHelp.xaml.vb | 17 +- .../PageOther/PageOtherHelpDetail.xaml.vb | 6 +- .../Pages/PageOther/PageOtherLeft.xaml.vb | 23 +- .../Pages/PageSelectLeft.xaml.vb | 56 +- .../Pages/PageSelectRight.xaml.vb | 19 +- .../Pages/PageSetup/PageSetupLaunch.xaml | 32 +- .../Pages/PageSetup/PageSetupLaunch.xaml.vb | 57 +- .../Pages/PageSetup/PageSetupLeft.xaml.vb | 26 +- .../Pages/PageSetup/PageSetupLink.xaml.vb | 4 +- .../Pages/PageSetup/PageSetupSystem.xaml.vb | 10 +- .../Pages/PageSetup/PageSetupUI.xaml | 5 +- .../Pages/PageSetup/PageSetupUI.xaml.vb | 164 +- .../Pages/PageSetup/Settings.vb | 31 +- .../Pages/PageSpeedLeft.xaml.vb | 28 +- .../Plain Craft Launcher 2.vbproj | 20 +- .../Resources/Ookii.Dialogs.Wpf.dll | Bin 107696 -> 105472 bytes .../Resources/System.ValueTuple.dll | Bin 75048 -> 0 bytes Plain Craft Launcher 2/Resources/moddata.txt | 27010 ++++++++++++++++ Plain Craft Launcher 2/Resources/moddata.zip | Bin 394453 -> 0 bytes 110 files changed, 30470 insertions(+), 4729 deletions(-) create mode 100644 PCLCS/Constants.cs create mode 100644 PCLCS/Resource/Resource.cs create mode 100644 Plain Craft Launcher 2/Modules/Base/PclLogger.vb delete mode 100644 Plain Craft Launcher 2/Modules/Constants.vb rename Plain Craft Launcher 2/Modules/Resource/{ResourceFile.vb => LocalResourceFile.vb} (88%) rename Plain Craft Launcher 2/Modules/Resource/{ResourceFileLoader.vb => LocalResourceLoaders.vb} (62%) delete mode 100644 Plain Craft Launcher 2/Resources/System.ValueTuple.dll create mode 100644 Plain Craft Launcher 2/Resources/moddata.txt delete mode 100644 Plain Craft Launcher 2/Resources/moddata.zip diff --git a/.editorconfig b/.editorconfig index c987a5b..2e8a8b4 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,12 @@ -[*.{cs,vb}] +# 如果要从更高级别的目录继承 .editorconfig 设置,请删除以下行 +root = true + +[*.cs] + +# IDE0320: 使匿名函数成为静态函数 +csharp_prefer_static_anonymous_function = false + +[*.{cs,vb}] # IDE0028: 简化集合初始化 dotnet_style_collection_initializer = true:silent diff --git a/PCLCS/Constants.cs b/PCLCS/Constants.cs new file mode 100644 index 0000000..597d637 --- /dev/null +++ b/PCLCS/Constants.cs @@ -0,0 +1,75 @@ +namespace PCLCS; + +/// +/// 社区资源的类型。 +/// +[Flags] +public enum ResourceTypes { + /// Mod。 + Mod = 1, + /// 整合包。 + ModPack = 2, + /// 资源包。 + ResourcePack = 4, + /// 光影包。 + Shader = 8, + /// 数据包。 + DataPack = 16, + /// 服务端插件。 + Plugin = 32, + /// 同时包含数据包以及 Mod。 + ModOrDataPack = Mod | DataPack, + /// 允许任意种类,或种类未知。 + Any = Mod | ModPack | ResourcePack | Shader | DataPack | Plugin, +} + +/// +/// 社区资源的来源平台。 +/// +[Flags] +public enum ResourcePlatforms { + CurseForge = 1, + Modrinth = 2, + Any = CurseForge | Modrinth, +} + +/// +/// Mod 加载器的类型。 +/// +[Flags] +public enum ModLoaders { + None = 0, + Forge = 1, + LiteLoader = 2, + Fabric = 4, + Quilt = 8, + NeoForge = 16, + All = Forge | LiteLoader | Fabric | Quilt | NeoForge, +} + +/// +/// 在爱发电中的赞助等级。 +/// +public enum DonationRank { + None = 0, + Rank6 = 6, + Rank12 = 12, + Rank23 = 23, + Rank54 = 54, + Rank98 = 98, +} + +public static class Versions { + /// + /// 土豆码版本号。 + /// + public const char POTATO_VERSION = '1'; + /// + /// 版本管理中 Mod 信息缓存的版本号。 + /// + public const int LOCAL_MOD_CACHE_VERSION = 17; + /// + /// Minecraft 本地实例信息缓存的版本号。 + /// + public const int MCINSTANCE_CACHE_VERSION = 37; +} diff --git a/PCLCS/PCLCS.csproj b/PCLCS/PCLCS.csproj index 4361b6a..7a7285f 100644 --- a/PCLCS/PCLCS.csproj +++ b/PCLCS/PCLCS.csproj @@ -1,7 +1,7 @@  - net462 + net48 Library True bin\ @@ -11,34 +11,22 @@ true 13.0 enable - 8.0 + enable - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - - - - - - - + - - - - - @@ -47,6 +35,11 @@ + + + + + $(DefineConstants);SNAPSHOT diff --git a/PCLCS/Resource/Resource.cs b/PCLCS/Resource/Resource.cs new file mode 100644 index 0000000..7b65aeb --- /dev/null +++ b/PCLCS/Resource/Resource.cs @@ -0,0 +1,33 @@ +namespace PCLCS; +public static class Resource { + + /// + /// 将 CurseForge 的 ModLoaderType 映射为 枚举。 + /// + public static ModLoaders FromCurseForgeModLoaderType(int modLoaderType) => modLoaderType switch { + // https://docs.curseforge.com/rest-api/#tocS_ModLoaderType + 1 => ModLoaders.Forge, + 3 => ModLoaders.LiteLoader, + 4 => ModLoaders.Fabric, + 5 => ModLoaders.Quilt, + 6 => ModLoaders.NeoForge, + _ => ModLoaders.None, + }; + + /// + /// 将 映射为 CurseForge 的单一 ModLoaderType。 + /// + public static int ToCurseForgeModLoaderType(ModLoaders loaders) { + if (loaders == ModLoaders.None) return 0; + if (!loaders.Flags().IsSingle()) throw new ArgumentException($"传入的枚举值 {loaders} 并非单个 Mod Loader", nameof(loaders)); + return loaders switch { + ModLoaders.Forge => 1, + ModLoaders.LiteLoader => 3, + ModLoaders.Fabric => 4, + ModLoaders.Quilt => 5, + ModLoaders.NeoForge => 6, + _ => 0, + }; + } + +} diff --git a/Plain Craft Launcher 2.sln b/Plain Craft Launcher 2.sln index 62d69ae..a86d0e1 100644 --- a/Plain Craft Launcher 2.sln +++ b/Plain Craft Launcher 2.sln @@ -9,7 +9,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PCLCS", "PCLCS\PCLCS.csproj EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeloongCore", "MeloongCore\Shared\MeloongCore.csproj", "{D22BBF3C-2177-0208-4E29-8466AA41AC6F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeloongCoreWpf", "MeloongCore\Wpf\MeloongCoreWpf.csproj", "{2DFFE2A0-1101-816B-D240-F644B2D74A68}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MeloongCore.Wpf", "MeloongCore\Wpf\MeloongCore.Wpf.csproj", "{2DFFE2A0-1101-816B-D240-F644B2D74A68}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/Plain Craft Launcher 2/App.config b/Plain Craft Launcher 2/App.config index 0e1a473..fd2f486 100644 --- a/Plain Craft Launcher 2/App.config +++ b/Plain Craft Launcher 2/App.config @@ -5,13 +5,10 @@ - - + + - - - @@ -25,10 +22,6 @@ - - - - diff --git a/Plain Craft Launcher 2/Application.xaml b/Plain Craft Launcher 2/Application.xaml index 5dcdce8..fde857c 100644 --- a/Plain Craft Launcher 2/Application.xaml +++ b/Plain Craft Launcher 2/Application.xaml @@ -3,6 +3,8 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:behaviors="clr-namespace:PCL.Controls.Behaviors" xmlns:local="clr-namespace:PCL" + xmlns:core="clr-namespace:MeloongCore;assembly=MeloongCore" + xmlns:corewpf="clr-namespace:MeloongCore.Wpf;assembly=MeloongCore.Wpf" xmlns:sys="clr-namespace:System;assembly=mscorlib" StartupUri="FormMain.xaml" ShutdownMode="OnExplicitShutdown"> @@ -10,10 +12,10 @@ - - - - + + + + @@ -366,6 +368,7 @@ + diff --git a/Plain Craft Launcher 2/Application.xaml.vb b/Plain Craft Launcher 2/Application.xaml.vb index 1405bae..0824938 100644 --- a/Plain Craft Launcher 2/Application.xaml.vb +++ b/Plain Craft Launcher 2/Application.xaml.vb @@ -1,47 +1,37 @@ Imports System.Reflection Imports System.Windows.Threading +Imports Microsoft.Win32 Public Class Application '开始 Private Sub Application_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup Try + '提升主线程优先级 + Thread.CurrentThread.Priority = ThreadPriority.Highest '执行开发版测试 If BuildType = BuildTypes.Debug Then Try ModDevelop.Start() Catch ex As Exception - Log(ex, "开发者模式测试出错", NotifyLevel.MsgBox) + Logger.Error(ex, "开发者模式测试出错", LogBehavior.Alert) End Try End If - '提升主线程优先级 - Thread.CurrentThread.Priority = ThreadPriority.Highest - '确保 .NET Framework 版本 + '检查 .NET Framework 版本 Try - Dim VersionTest As New FormattedText("", Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, Fonts.SystemTypefaces.First, 96, New MyColor, DPI) - Catch ex As UriFormatException '修复 #3555 - Environment.SetEnvironmentVariable("windir", Environment.GetEnvironmentVariable("SystemRoot"), EnvironmentVariableTarget.User) - Dim VersionTest As New FormattedText("", Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, Fonts.SystemTypefaces.First, 96, New MyColor, DPI) - End Try - '检测当前文件夹权限 - Try - DirectoryUtils.Create(PathExeFolder & "PCL\") + Using ndpKey As RegistryKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey("SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\") + If ndpKey?.GetValue("Release") IsNot Nothing AndAlso CInt(ndpKey.GetValue("Release")) < 528040 Then OldEnvironmentAssert() + End Using Catch ex As Exception - MsgBox($"PCL 无法创建 PCL 文件夹({PathExeFolder & "PCL"}),请尝试:" & vbCrLf & - "1. 将 PCL 移动到其他文件夹" & If(PathExeFolder.StartsWithF("C:", True), ",例如 C 盘和桌面以外的其他位置。", "。") & vbCrLf & - "2. 删除当前目录中的 PCL 文件夹,然后再试。" & vbCrLf & - "3. 右键 PCL 选择属性,打开 兼容性 中的 以管理员身份运行此程序。", - MsgBoxStyle.Critical, "运行环境错误") - Environment.[Exit](ProcessReturnValues.Cancel) + Logger.Warn(ex, "检查 .NET Framework 版本失败") + End Try + '修复 WPF 字体加载(#3467) + Try + Dim _unused As New FormattedText("", Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, Fonts.SystemTypefaces.First, 96, New MyColor, DPI) + Catch ex As UriFormatException + Environment.SetEnvironmentVariable("windir", Environment.GetEnvironmentVariable("SystemRoot"), EnvironmentVariableTarget.User) + Dim _unused As New FormattedText("", Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, Fonts.SystemTypefaces.First, 96, New MyColor, DPI) End Try - If Not CheckPermission(PathExeFolder & "PCL") Then - MsgBox("PCL 没有对当前文件夹的写入权限,请尝试:" & vbCrLf & - "1. 将 PCL 移动到其他文件夹" & If(PathExeFolder.StartsWithF("C:", True), ",例如 C 盘和桌面以外的其他位置。", "。") & vbCrLf & - "2. 删除当前目录中的 PCL 文件夹,然后再试。" & vbCrLf & - "3. 右键 PCL 选择属性,打开 兼容性 中的 以管理员身份运行此程序。", - MsgBoxStyle.Critical, "运行环境错误") - Environment.[Exit](ProcessReturnValues.Cancel) - End If '检查参数调用 If e.Args.Length > 0 Then If e.Args(0) = "--update" Then @@ -73,18 +63,30 @@ Public Class Application End If End If '初始化文件结构 - DirectoryUtils.Create(PathExeFolder & "PCL\Pictures\") - DirectoryUtils.Create(PathExeFolder & "PCL\Musics\") + Try + DirectoryUtils.Create(PathExeFolder & "PCL\Pictures\") + DirectoryUtils.Create(PathExeFolder & "PCL\Musics\") + CheckPermissionWithException(PathExeFolder & "PCL\") + Catch ex As Exception + MsgBox($"PCL 没有对当前文件夹的权限({PathExeFolder}PCL\),请尝试:" & vbCrLf & + "1. 将 PCL 移动到其他文件夹" & If(PathExeFolder.StartsWithF("C:", True), ",例如 C 盘和桌面以外的其他位置。", "。") & vbCrLf & + "2. 删除当前目录中的 PCL 文件夹,然后再试。" & vbCrLf & + "3. 右键 PCL 选择属性,打开 兼容性 中的 以管理员身份运行此程序。", + MsgBoxStyle.Critical, "运行环境错误") + Environment.[Exit](ProcessReturnValues.Cancel) + End Try +RetryCacheCheck: Try DirectoryUtils.Create(PathTemp) - If Not CheckPermission(PathTemp) Then Throw New Exception("PCL 没有对 " & PathTemp & " 的访问权限") + CheckPermissionWithException(PathTemp) Catch ex As Exception If PathTemp = Path.GetTempPath() & "PCL\" Then - MyMsgBox("PCL 无法访问缓存文件夹,可能导致程序出错或无法正常使用!" & vbCrLf & vbCrLf & "错误原因:" & ex.GetDetail(), "缓存文件夹不可用") + MyMsgBox("PCL 无法访问缓存文件夹,可能导致程序出错或无法正常使用!" & vbCrLf & vbCrLf & "错误原因:" & ex.GetDisplay(True), "缓存文件夹不可用") Else - MyMsgBox("手动设置的缓存文件夹不可用,PCL 将使用默认缓存文件夹。" & vbCrLf & vbCrLf & "错误原因:" & ex.GetDetail(), "缓存文件夹不可用") + MyMsgBox("手动设置的缓存文件夹不可用,PCL 将使用默认缓存文件夹。" & vbCrLf & vbCrLf & "错误原因:" & ex.GetDisplay(True), "缓存文件夹不可用") Settings.Set("SystemSystemCache", "") PathTemp = Path.GetTempPath() & "PCL\" + GoTo RetryCacheCheck End If End Try DirectoryUtils.Create(PathTemp & "Cache\") @@ -123,22 +125,21 @@ WaitRetry: ServicePointManager.EnableDnsRoundRobin = True ServicePointManager.ReusePort = True '设置初始窗口 - If Settings.Get("UiLauncherLogo") Then + If Settings.Get(Of Boolean)("UiLauncherLogo") Then FrmStart = New SplashScreen("Images\icon.ico") FrmStart.Show(False, True) End If '日志初始化 - LogStart() - '添加日志 - Log($"[Start] 程序版本:{VersionDisplay} ({VersionCode}{If(CommitHash = "", "", $",#{CommitHash}")})") + MeloongCore.Main.Init(New PclLogger With {.logFolder = PathUtils.CurrentFolder & "PCL", .MinLevel = If(ModeDebug, LogLevel.Trace, LogLevel.Info)}) + Logger.Info($"程序版本:{VersionDisplay} ({VersionCode}{If(CommitHash = "", "", $",#{CommitHash}")})") If BuildType = BuildTypes.Snapshot Then - Log($"[Start] 识别码:{Identify}{If(ThemeCheckOne(9), ",已解锁反馈主题", ",未解锁反馈主题")}") + Logger.Info($"识别码:{Identify}{If(ThemeCheckOne(9), ",已解锁反馈主题", ",未解锁反馈主题")}") Else - Log($"[Start] 识别码:{Identify}") + Logger.Info($"识别码:{Identify}") End If - Log($"[Start] 程序路径:{PathExe}") - Log($"[Start] 系统编码:{Encoding.Default.HeaderName} ({Encoding.Default.CodePage}, GBK={IsGBKEncoding})") - Log($"[Start] 管理员权限:{IsAdmin()}") + Logger.Info($"程序路径:{PathExe}") + Logger.Info($"系统编码:{Encoding.Default.HeaderName} ({Encoding.Default.CodePage}, GBK={IsGBKEncoding})") + Logger.Info($"管理员权限:{SystemUtils.HasAdminRole()}") '检测异常环境 If PathExeFolder.Contains(Path.GetTempPath()) OrElse PathExeFolder.Contains("AppData\Local\Temp\") Then MyMsgBox("请将 PCL 从压缩包中解压后再使用!" & vbCrLf & "如果不会解压,可以在网上寻找教程。", "需要解压!", "我知道了", IsWarn:=True, ForceWait:=True) @@ -148,7 +149,7 @@ WaitRetry: MyMsgBox("PCL 和新版 Minecraft 均不再支持 32 位系统,部分功能将无法使用。" & vbCrLf & "非常建议重装为 64 位系统后再进行游戏!", "环境警告", "我知道了", IsWarn:=True) End If '计时 - Log("[Start] 第一阶段加载用时:" & GetTimeMs() - ApplicationStartTick & " ms") + Logger.Info($"第一阶段加载用时:{GetTimeMs() - ApplicationStartTick} ms") ApplicationStartTick = GetTimeMs() AniControlEnabled += 1 Catch ex As Exception @@ -157,7 +158,7 @@ WaitRetry: FilePath = PathExe Catch End Try - MsgBox(ex.GetDetail(True) & vbCrLf & "PCL 所在路径:" & If(String.IsNullOrEmpty(FilePath), "获取失败", FilePath), MsgBoxStyle.Critical, "PCL 初始化错误") + MsgBox(ex.GetDisplay(True) & vbCrLf & "PCL 所在路径:" & If(String.IsNullOrEmpty(FilePath), "获取失败", FilePath), MsgBoxStyle.Critical, "PCL 初始化错误") FormMain.EndProgramForce(ProcessReturnValues.Exception) End Try End Sub @@ -181,43 +182,48 @@ WaitRetry: End If '正常处理 e.Handled = True - If IsProgramEnded Then Return + If IsProgramEnding Then Return FeedbackInfo() - Dim Detail As String = e.Exception.GetDetail(True) + Dim Detail As String = e.Exception.GetDisplay(True) If Detail.Contains("System.Windows.Threading.Dispatcher.Invoke") OrElse Detail.Contains("MS.Internal.AppModel.ITaskbarList.HrInit") OrElse Detail.Contains("未能加载文件或程序集") OrElse Detail.Contains(".NET Framework") Then ' “自动错误判断” 的结果分析 - OpenWebsite("https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/thank-you/net462-offline-installer") - Log(e.Exception, "你的 .NET Framework 版本过低或损坏,请下载并重新安装 .NET Framework 4.6.2!" & vbCrLf & "若无法安装,可在卸载高版本的 .NET Framework 后再试。", NotifyLevel.Critical, "运行环境错误") + OldEnvironmentAssert(e.Exception) Else - Log(e.Exception, "程序出现未知错误", NotifyLevel.Critical, "锟斤拷烫烫烫") + Logger.Error(e.Exception, "程序出现未知错误", LogBehavior.AlertThenCrash) + End If + End Sub + Private Shared Sub OldEnvironmentAssert(Optional ex As Exception = Nothing) + OpenWebsite("https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/thank-you/net48-offline-installer") + If ex Is Nothing Then + Logger.Error($"你的 .NET Framework 版本过低或损坏,请下载并重新安装 .NET Framework 4.8!{vbCrLf}若安装失败,可以先卸载高版本的 .NET Framework 然后再试。", LogBehavior.AlertThenCrash) + Else + Logger.Error(ex, $"你的 .NET Framework 版本过低或损坏,请下载并重新安装 .NET Framework 4.8!{vbCrLf}若安装失败,可以先卸载高版本的 .NET Framework 然后再试。", LogBehavior.AlertThenCrash) End If End Sub '动态 DLL 加载 Private Sub New() '这里必须尽早调用,且不能使用任何库,否则加载 MeloongCore 就会导致崩溃 - Static Prefixes As String() = {"NAudio", "Newtonsoft.Json", "Ookii.Dialogs.Wpf", "Imazen.WebP", "CacheCow.Common", "CacheCow.Client.FileStore", "CacheCow.Client", "System.Net.Http.Formatting", "System.ValueTuple", "PCLCS", "MeloongCore.Wpf", "MeloongCore"} - Static Locks As New Dictionary(Of String, Object)(StringComparer.Ordinal) - Static LoadedAssembly As New Dictionary(Of String, Assembly)(StringComparer.Ordinal) '缓存 + Static Prefixes As String() = {"NAudio", "Newtonsoft.Json", "Ookii.Dialogs.Wpf", "Imazen.WebP", "CacheCow.Common", "CacheCow.Client.FileStore", "CacheCow.Client", "System.Net.Http.Formatting", "PCLCS", "MeloongCore.Wpf", "MeloongCore"} + Static LoadedAssemblies As New ConcurrentDictionary(Of String, Lazy(Of Assembly))(StringComparer.Ordinal) '缓存 AddHandler AppDomain.CurrentDomain.AssemblyResolve, Function(sender As Object, Args As ResolveEventArgs) As Assembly Dim Prefix As String = Prefixes.FirstOrDefault(Function(p) Args.Name.StartsWith(p, StringComparison.Ordinal)) If Prefix Is Nothing Then Return Nothing - If Not Locks.ContainsKey(Prefix) Then Locks(Prefix) = New Object() - SyncLock Locks(Prefix) - If Not LoadedAssembly.ContainsKey(Prefix) Then - LoadedAssembly(Prefix) = Assembly.Load(My.Resources.ResourceManager.GetObject(Prefix)) - If Prefix = "Imazen.WebP" Then ExtractLibwebp() 'WebP 特判 - End If - Return LoadedAssembly(Prefix) - End SyncLock + Dim LazyAssembly = LoadedAssemblies.GetOrAdd(Prefix, Function(p) New Lazy(Of Assembly)( + Function() + Dim LoadedAssembly = Assembly.Load(DirectCast(My.Resources.ResourceManager.GetObject(p), Byte())) + If p = "Imazen.WebP" Then ExtractLibwebp() 'WebP 特判 + Return LoadedAssembly + End Function, LazyThreadSafetyMode.ExecutionAndPublication)) + Return LazyAssembly.Value End Function End Sub Private Shared Sub ExtractLibwebp() '这个方法会调用 ModBase,进而调用 MeloongCore,所以不能放在 New 里 SetDllDirectory(PathPure.TrimEnd("\"c)) Try - FileUtils.Write(PathPure & "libwebp.dll", GetResources("libwebp64")) + ExtractResources(PathPure & "libwebp.dll", "libwebp64") Catch ex As Exception - Log(ex, "写入 libwebp.dll 失败") '防止同时加载多个图片时,同时写入文件导致文件占用,进而导致崩溃 + Logger.Warn(ex, "写入 libwebp.dll 失败") '防止同时加载多个图片时,同时写入文件导致文件占用,进而导致崩溃 End Try End Sub Private Declare Function SetDllDirectory Lib "kernel32" Alias "SetDllDirectoryA" (lpPathName As String) As Boolean @@ -226,10 +232,10 @@ WaitRetry: '控件模板事件 Private Sub MyIconButton_Click(sender As Object, e As EventArgs) - Select Case Settings.Get("LoginType") + Select Case Settings.Get(Of McLoginType)("LoginType") Case McLoginType.Ms '微软 - Dim MsJson As JObject = GetJson(Settings.Get("LoginMsJson")) + Dim MsJson As JObject = GetJson(Settings.Get(Of String)("LoginMsJson")) MsJson.Remove(sender.Tag) Settings.Set("LoginMsJson", MsJson.ToString(Newtonsoft.Json.Formatting.None)) If FrmLoginMs.ComboAccounts.SelectedItem Is sender.Parent Then FrmLoginMs.ComboAccounts.SelectedIndex = 0 @@ -237,19 +243,19 @@ WaitRetry: Case McLoginType.Legacy '离线 Dim Names As New List(Of String) - Names.AddRange(Settings.Get("LoginLegacyName").ToString.Split("¨")) + Names.AddRange(Settings.Get(Of String)("LoginLegacyName").ToString.Split("¨")) Names.Remove(sender.Tag) Settings.Set("LoginLegacyName", Names.Join("¨"c)) FrmLoginLegacy.ComboName.ItemsSource = Names FrmLoginLegacy.ComboName.Text = If(Names.Any, Names(0), "") Case Else '第三方 - Dim Token As String = GetStringFromEnum(Settings.Get("LoginType")) + Dim Token As String = Settings.Get(Of McLoginType)("LoginType").ToString() Dim Dict As New Dictionary(Of String, String) Dim Names As New List(Of String) Dim Passs As New List(Of String) - If Not Settings.Get("Login" & Token & "Email") = "" Then Names.AddRange(Settings.Get("Login" & Token & "Email").ToString.Split("¨")) - If Not Settings.Get("Login" & Token & "Pass") = "" Then Passs.AddRange(Settings.Get("Login" & Token & "Pass").ToString.Split("¨")) + If Not Settings.Get(Of String)("Login" & Token & "Email") = "" Then Names.AddRange(Settings.Get(Of String)("Login" & Token & "Email").Split("¨")) + If Not Settings.Get(Of String)("Login" & Token & "Pass") = "" Then Passs.AddRange(Settings.Get(Of String)("Login" & Token & "Pass").Split("¨")) For i = 0 To Names.Count - 1 Dict.Add(Names(i), Passs(i)) Next diff --git a/Plain Craft Launcher 2/Controls/MyButton.xaml.vb b/Plain Craft Launcher 2/Controls/MyButton.xaml.vb index 992673e..4d710d5 100644 --- a/Plain Craft Launcher 2/Controls/MyButton.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyButton.xaml.vb @@ -136,7 +136,7 @@ Public Class MyButton End If Catch ex As Exception - Log(ex, "刷新按钮颜色出错") + Logger.Warn(ex, "刷新按钮颜色出错") End Try End Sub @@ -144,7 +144,7 @@ Public Class MyButton Private IsMouseDown As Boolean = False Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp If Not IsMouseDown Then Return - Log("[Control] 按下按钮:" & Text) + Logger.Info($"按下按钮:{Text}") RaiseEvent Click(sender, e) RaiseCustomEvent() '自定义事件 End Sub diff --git a/Plain Craft Launcher 2/Controls/MyCard.vb b/Plain Craft Launcher 2/Controls/MyCard.vb index 8224be2..5c5b73e 100644 --- a/Plain Craft Launcher 2/Controls/MyCard.vb +++ b/Plain Craft Launcher 2/Controls/MyCard.vb @@ -164,7 +164,7 @@ Case 13 Stack.Children.Add(NeoForgeDownloadListItem(Data, AddressOf NeoForgeSave_Click, True)) Case Else - Log("未知的虚拟化种类:" & Type, NotifyLevel.MsgBoxAndFeedback) + Logger.Error($"未知的虚拟化种类:{Type}") End Select Next Stack.Children.Add(New FrameworkElement With {.Height = 18}) '下边距,同时适应折叠 @@ -296,9 +296,10 @@ If Not IsSwapped AndAlso TypeOf SwapControl Is StackPanel Then StackInstall(SwapControl, SwapType, Title) '若尚未加载,会在 Loaded 事件中触发无动画的折叠,不需要在这里进行 If Not IsLoaded Then Return - '更新高度 + '更新样式 SwapControl.Visibility = Visibility.Visible TriggerForceResize() + UpdateCursorStyle() '改变箭头 AniStart(AaRotateTransform(MainSwap, If(_IsSwapped, If(SwapLogoRight, 270, 0), 180) - CType(MainSwap.RenderTransform, RotateTransform).Angle, 250,, New AniEaseOutFluent(AniEasePower.ExtraStrong)), "MyCard Swap " & Uuid, True) End Set @@ -351,12 +352,18 @@ End If IsSwapped = Not IsSwapped - Log("[Control] " & If(IsSwapped, "折叠卡片", "展开卡片") & If(Title Is Nothing, "", ":" & Title)) + Logger.Info($"{If(IsSwapped, "折叠卡片", "展开卡片")}{If(Title Is Nothing, "", ":" & Title)}") RaiseEvent Swap(Me, e) End Sub Private Sub MyCard_MouseLeave_Swap(sender As Object, e As MouseEventArgs) Handles Me.MouseLeave IsSwapMouseDown = False End Sub + Private Sub UpdateCursorStyle() Handles Me.MouseMove + If _MainSwap Is Nothing Then Cursor = Nothing : Return + Dim Pos As Double = Mouse.GetPosition(Me).Y + Cursor = If(MainSwap.Visibility = Visibility.Visible AndAlso (IsSwapped OrElse (Pos <= SwapedHeight - 6 AndAlso Not (Pos = 0 AndAlso Not IsMouseDirectlyOver))), + Cursors.Hand, Nothing) + End Sub #End Region diff --git a/Plain Craft Launcher 2/Controls/MyCheckBox.xaml.vb b/Plain Craft Launcher 2/Controls/MyCheckBox.xaml.vb index bfcf1ea..12b6fad 100644 --- a/Plain Craft Launcher 2/Controls/MyCheckBox.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyCheckBox.xaml.vb @@ -59,7 +59,7 @@ Public Class MyCheckBox SyncUI() RaiseCustomEvent() Catch ex As Exception - Log(ex, "设置 Checked 失败") + Logger.Warn(ex, "设置 Checked 失败") End Try End Sub Private Sub SyncUI() @@ -133,7 +133,7 @@ Public Class MyCheckBox Private AllowMouseDown As Boolean = True Private Sub Checkbox_MouseUp() Handles Me.MouseLeftButtonUp If Not MouseDowned Then Return - Log("[Control] 按下复选框(" & (Not Checked).ToString & "):" & Text) + Logger.Info($"按下复选框({(Not Checked)}):{Text}") MouseDowned = False SetChecked(Not Checked, True) AniStart(AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushHalfWhite", 100), "MyCheckBox Background " & Uuid) diff --git a/Plain Craft Launcher 2/Controls/MyComboBox.vb b/Plain Craft Launcher 2/Controls/MyComboBox.vb index 06f93bb..8419fe2 100644 --- a/Plain Craft Launcher 2/Controls/MyComboBox.vb +++ b/Plain Craft Launcher 2/Controls/MyComboBox.vb @@ -22,7 +22,7 @@ End If If HintText.Length > 0 Then TextBox.HintText = HintText Catch ex As Exception - Log(ex, "初始化可编辑文本框失败(" & If(Name, "") & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"初始化可编辑文本框失败({If(Name, "")})") End Try End Sub Private _Text As String = SelectedItem @@ -107,7 +107,7 @@ Try CType(Template.FindName("PanPopup", Me), Grid).Opacity = FrmMain.Opacity Catch ex As Exception - Log(ex, "设置下拉框透明度失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "设置下拉框透明度失败") End Try End Sub Private Sub MyComboBox_DropDownClosed(sender As Object, e As EventArgs) Handles Me.DropDownClosed @@ -147,7 +147,7 @@ ElseIf Items.Count > NewValue Then SelectedIndex = NewValue Else - Log($"[Setting] 尝试显示设置 {SettingService.GetKey(Me)},但没有找到设置值 {NewValue} 的对应项", NotifyLevel.DebugModeOnly) + Logger.Warn($"尝试显示设置 {SettingService.GetKey(Me)},但没有找到设置值 {NewValue} 的对应项") SelectedIndex = -1 SelectedItem = Nothing End If diff --git a/Plain Craft Launcher 2/Controls/MyComboBoxItem.vb b/Plain Craft Launcher 2/Controls/MyComboBoxItem.vb index 5e431d5..eb6ce15 100644 --- a/Plain Craft Launcher 2/Controls/MyComboBoxItem.vb +++ b/Plain Craft Launcher 2/Controls/MyComboBoxItem.vb @@ -61,7 +61,7 @@ End Operator Private Sub MyComboBoxItem_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp - Log("[Control] 选择下拉列表项:" & Tostring()) + Logger.Info($"选择下拉列表项:{Tostring()}") End Sub End Class diff --git a/Plain Craft Launcher 2/Controls/MyExtraButton.xaml.vb b/Plain Craft Launcher 2/Controls/MyExtraButton.xaml.vb index 6f90827..899d029 100644 --- a/Plain Craft Launcher 2/Controls/MyExtraButton.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyExtraButton.xaml.vb @@ -84,7 +84,7 @@ '触发点击事件 Private Sub Button_LeftMouseUp(sender As Object, e As MouseButtonEventArgs) Handles PanClick.MouseLeftButtonUp If IsLeftMouseHeld Then - Log("[Control] 按下附加按钮" & If(ToolTip = "", "", ":" & ToolTip.ToString)) + Logger.Info($"按下附加按钮{If(ToolTip = "", "", ":" & ToolTip)}") RaiseEvent Click(sender, e) e.Handled = True Button_LeftMouseUp() @@ -92,7 +92,7 @@ End Sub Private Sub Button_RightMouseUp(sender As Object, e As MouseButtonEventArgs) Handles PanClick.MouseRightButtonUp If IsRightMouseHeld Then - Log("[Control] 右键按下附加按钮" & If(ToolTip = "", "", ":" & ToolTip.ToString)) + Logger.Info($"右键按下附加按钮{If(ToolTip = "", "", ":" & ToolTip)}") RaiseEvent RightClick(sender, e) e.Handled = True Button_RightMouseUp() @@ -193,7 +193,7 @@ End If Catch ex As Exception - Log(ex, "刷新图标按钮颜色出错") + Logger.Warn(ex, "刷新图标按钮颜色出错") End Try End Sub diff --git a/Plain Craft Launcher 2/Controls/MyExtraTextButton.xaml.vb b/Plain Craft Launcher 2/Controls/MyExtraTextButton.xaml.vb index 266ba47..d100f04 100644 --- a/Plain Craft Launcher 2/Controls/MyExtraTextButton.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyExtraTextButton.xaml.vb @@ -82,7 +82,7 @@ Public Class MyExtraTextButton '触发点击事件 Private Sub Button_LeftMouseUp(sender As Object, e As MouseButtonEventArgs) Handles PanClick.MouseLeftButtonUp If Not IsLeftMouseHeld Then Return - Log("[Control] 按下附加图标按钮:" & Text) + Logger.Info($"按下附加图标按钮:{Text}") RaiseEvent Click(sender, e) e.Handled = True RaiseCustomEvent() @@ -156,7 +156,7 @@ Public Class MyExtraTextButton End If Catch ex As Exception - Log(ex, "刷新附加图标按钮颜色出错") + Logger.Warn(ex, "刷新附加图标按钮颜色出错") End Try End Sub diff --git a/Plain Craft Launcher 2/Controls/MyHint.xaml.vb b/Plain Craft Launcher 2/Controls/MyHint.xaml.vb index 9724691..918b9fa 100644 --- a/Plain Craft Launcher 2/Controls/MyHint.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyHint.xaml.vb @@ -99,7 +99,7 @@ Public Class MyHint End Property Public Property RelativeSetup As String = "" Private Sub MyHint_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded - If CanClose AndAlso Settings.Get(RelativeSetup) Then Visibility = Visibility.Collapsed + If CanClose AndAlso Settings.Get(Of Boolean)(RelativeSetup) Then Visibility = Visibility.Collapsed End Sub Private Sub BtnClose_Click(sender As Object, e As EventArgs) Handles BtnClose.Click Settings.SetSafe(RelativeSetup, True) @@ -112,7 +112,7 @@ Public Class MyHint Private Sub MyHint_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp If Not IsMouseDown Then Return IsMouseDown = False - Log("[Control] 按下提示条" & If(String.IsNullOrEmpty(Name), "", ":" & Name)) + Logger.Info($"按下提示条{If(String.IsNullOrEmpty(Name), "", ":" & Name)}") RaiseEvent Click(sender, e) If e.Handled Then Return e.Handled = True diff --git a/Plain Craft Launcher 2/Controls/MyIconButton.xaml.vb b/Plain Craft Launcher 2/Controls/MyIconButton.xaml.vb index 462f1d2..86693d8 100644 --- a/Plain Craft Launcher 2/Controls/MyIconButton.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyIconButton.xaml.vb @@ -54,7 +54,7 @@ Public Class MyIconButton Private IsMouseDown As Boolean = False Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp If Not IsMouseDown Then Return - Log("[Control] 按下图标按钮" & If(String.IsNullOrEmpty(Name), "", ":" & Name)) + Logger.Info($"按下图标按钮{If(String.IsNullOrEmpty(Name), "", ":" & Name)}") RaiseEvent Click(sender, e) e.Handled = True Button_MouseUp() @@ -160,7 +160,7 @@ Public Class MyIconButton End If Catch ex As Exception - Log(ex, "刷新图标按钮动画状态出错") + Logger.Warn(ex, "刷新图标按钮动画状态出错") End Try End Sub diff --git a/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.vb b/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.vb index dd5ed21..76b48e5 100644 --- a/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyIconTextButton.xaml.vb @@ -70,7 +70,7 @@ Public Class MyIconTextButton Private IsMouseDown As Boolean = False Private Sub MyIconTextButton_MouseUp() Handles Me.MouseLeftButtonUp If Not IsMouseDown Then Return - Log("[Control] 按下带图标按钮:" & Text) + Logger.Info($"按下带图标按钮:{Text}") IsMouseDown = False RaiseEvent Click(Me, New RouteEventArgs(True)) RaiseCustomEvent() '自定义事件 @@ -166,7 +166,7 @@ Public Class MyIconTextButton End If Catch ex As Exception - Log(ex, "刷新带图标按钮颜色出错") + Logger.Warn(ex, "刷新带图标按钮颜色出错") End Try End Sub diff --git a/Plain Craft Launcher 2/Controls/MyImage.vb b/Plain Craft Launcher 2/Controls/MyImage.vb index ff98bfd..06a18fe 100644 --- a/Plain Craft Launcher 2/Controls/MyImage.vb +++ b/Plain Craft Launcher 2/Controls/MyImage.vb @@ -88,9 +88,9 @@ Dim Bitmap As ImageSource = If(value Is Nothing, Nothing, New MyBitmap(value)) '在这里先触发可能的文件读取,尽量避免在 UI 线程中读取文件 RunInUi(Sub() MyBase.Source = Bitmap) Catch ex As Exception - Log(ex, $"加载图片失败({value})") + Logger.Warn(ex, $"加载图片失败({value})") Try - If value.StartsWithF(PathTemp) AndAlso File.Exists(value) Then File.Delete(value) + If value.StartsWithF(PathTemp) Then FileUtils.Delete(value) Catch End Try End Try @@ -113,7 +113,7 @@ '从缓存加载网络图片 Dim EnableCache As Boolean = Me.EnableCache Dim TempPath As String = $"{PathTemp}MyImage\{GetHash(Source)}.png{If(EnableCache, "", GetUuid())}" '不启用缓存时在末尾加上随机字符串,避免冲突 - Dim TempFile As New FileInfo(TempPath) + Dim TempFile = FileUtils.GetInfo(TempPath) If EnableCache AndAlso TempFile.Exists Then ActualSource = TempPath '显示缓存的图片 If (Date.Now - TempFile.LastWriteTime) < FileCacheExpiredTime Then Return '无需刷新缓存 @@ -130,24 +130,24 @@ {Source, FallbackSource}, {Source}), TempPath, SimulateBrowserHeaders:=True) ActualSource = TempPath - If Not EnableCache Then File.Delete(TempPath) + If Not EnableCache Then FileUtils.Delete(TempPath) Catch ex As Exception Try - If TempPath IsNot Nothing Then File.Delete(TempPath) + If TempPath IsNot Nothing Then FileUtils.Delete(TempPath) Catch End Try '加载本地备用图片 If IsLocalFallback Then Try ActualSource = FallbackSource - Log(ex, $"下载图片失败,使用本地备用图片({Source})") + Logger.Warn(ex, $"下载图片失败,使用本地备用图片({Source})") Return Catch exx As Exception - Log(ex, $"下载图片失败({Source})", NotifyLevel.AllUsers) - Log(exx, $"加载备用图片失败({FallbackSource})", NotifyLevel.AllUsers) + Logger.Error(ex, $"下载图片失败({Source})", LogBehavior.Toast) + Logger.Error(exx, $"加载备用图片失败({FallbackSource})", LogBehavior.Toast) End Try Else - Log(ex, $"下载图片失败({Source},备用:{FallbackSource})", NotifyLevel.AllUsers) + Logger.Error(ex, $"下载图片失败({Source},备用:{FallbackSource})", LogBehavior.Toast) End If End Try End Sub, "MyImage PicLoader " & GetUuid() & "#", ThreadPriority.BelowNormal) diff --git a/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb b/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb index 1aa26ef..5e43479 100644 --- a/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyListItem.xaml.vb @@ -479,7 +479,7 @@ Public Class MyListItem End If Catch ex As Exception - Log(ex, "设置 Checked 失败") + Logger.Warn(ex, "设置 Checked 失败") End Try End Sub @@ -515,12 +515,12 @@ Public Class MyListItem '实际的单击处理 Select Case Type Case CheckType.Clickable - Log("[Control] 按下单击列表项:" & Title) + Logger.Info($"按下单击列表项:{Title}") Case CheckType.RadioBox - Log("[Control] 按下单选列表项:" & Title) + Logger.Info($"按下单选列表项:{Title}") If Not Checked Then SetChecked(True, True, True) Case CheckType.CheckBox - Log("[Control] 按下复选列表项(" & (Not Checked).ToString & "):" & Title) + Logger.Info($"按下复选列表项({Not Checked}):{Title}") SetChecked(Not Checked, True, True) End Select End Sub @@ -643,7 +643,7 @@ Public Class MyListItem Dim Entry As New HelpEntry(CustomEvent.GetAbsoluteUrls(CustomEventService.GetEventData(Me), CustomEventService.GetEventType(Me))(0)) Entry.SetToListItem(Me) Catch ex As Exception - Log(ex, "设置帮助 MyListItem 失败", NotifyLevel.MsgBox) + Logger.Error(ex, "设置帮助 MyListItem 失败", LogBehavior.Alert) CustomEventService.SetEventType(Me, CustomEvent.EventType.None) CustomEventService.SetEventData(Me, "") End Try diff --git a/Plain Craft Launcher 2/Controls/MyLoading.xaml.vb b/Plain Craft Launcher 2/Controls/MyLoading.xaml.vb index c887824..5ad4427 100644 --- a/Plain Craft Launcher 2/Controls/MyLoading.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyLoading.xaml.vb @@ -76,10 +76,8 @@ Public Class MyLoading If Ex Is Nothing Then LabText.Text = "未知错误" Else - Do While Ex.InnerException IsNot Nothing - Ex = Ex.InnerException - Loop - LabText.Text = If(Ex.IsNetworkRelated(), "网络环境不佳,请稍后再试,或使用 VPN 改善网络环境", Ex.Message) + Ex = Ex.RootException() + LabText.Text = If(Ex.IsBadNetwork(), "网络环境不佳,请稍后再试,或使用 VPN 改善网络环境", Ex.Message) End If Else LabText.Text = TextError diff --git a/Plain Craft Launcher 2/Controls/MyMenuItem.vb b/Plain Craft Launcher 2/Controls/MyMenuItem.vb index 629456a..acdd587 100644 --- a/Plain Craft Launcher 2/Controls/MyMenuItem.vb +++ b/Plain Craft Launcher 2/Controls/MyMenuItem.vb @@ -7,7 +7,7 @@ If IconControl IsNot Nothing Then IconControl.Data = (New GeometryConverter).ConvertFromString(Icon) End If '对父级设置透明度 - CType(Parent, ContextMenu).Opacity = Settings.Get("UiLauncherTransparent") / 1000 + 0.4 + CType(Parent, ContextMenu).Opacity = Settings.Get(Of Integer)("UiLauncherTransparent") / 1000 + 0.4 End Sub '基础 diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.vb b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.vb index f93c550..001297c 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgInput.xaml.vb @@ -26,7 +26,7 @@ ShapeLine.StrokeThickness = GetWPFSize(1) Catch ex As Exception - Log(ex, "输入弹窗初始化失败", NotifyLevel.AllUsers) + Logger.Error(ex, "输入弹窗初始化失败", LogBehavior.Toast) End Try End Sub @@ -46,10 +46,10 @@ AaDouble(Sub(i) TransformRotate.Angle += i, -TransformRotate.Angle, 300, 60, New AniEaseOutFluent(AniEasePower.Weak)) }, "MyMsgBox " & Uuid) '记录日志 - Log("[Control] 输入弹窗:" & LabTitle.Text) + Logger.Info($"输入弹窗:{LabTitle.Text}") Catch ex As Exception - Log(ex, "输入弹窗加载失败", NotifyLevel.AllUsers) + Logger.Error(ex, "输入弹窗加载失败", LogBehavior.Toast) End Try End Sub Private Sub Close() diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.vb b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.vb index 4706991..b8d8279 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.vb @@ -35,7 +35,7 @@ Next Catch ex As Exception - Log(ex, "选择弹窗初始化失败", NotifyLevel.AllUsers) + Logger.Error(ex, "选择弹窗初始化失败", LogBehavior.Toast) End Try End Sub @@ -53,10 +53,10 @@ AaDouble(Sub(i) TransformRotate.Angle += i, -TransformRotate.Angle, 300, 60, New AniEaseOutFluent(AniEasePower.Weak)) }, "MyMsgBox " & Uuid) '记录日志 - Log("[Control] 选择弹窗:" & LabTitle.Text) + Logger.Info($"选择弹窗:{LabTitle.Text}") Catch ex As Exception - Log(ex, "选择弹窗加载失败", NotifyLevel.AllUsers) + Logger.Error(ex, "选择弹窗加载失败", LogBehavior.Toast) End Try End Sub Private Sub Close() diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.vb b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.vb index cebe7e3..4982af4 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgText.xaml.vb @@ -25,7 +25,7 @@ ShapeLine.StrokeThickness = GetWPFSize(1) Catch ex As Exception - Log(ex, "普通弹窗初始化失败", NotifyLevel.AllUsers) + Logger.Error(ex, "普通弹窗初始化失败", LogBehavior.Toast) End Try End Sub @@ -44,10 +44,10 @@ AaDouble(Sub(i) TransformRotate.Angle += i, -TransformRotate.Angle, 300, 60, New AniEaseOutFluent(AniEasePower.Weak)) }, "MyMsgBox " & Uuid) '记录日志 - Log("[Control] 普通弹窗:" & LabTitle.Text & vbCrLf & LabCaption.Text) + Logger.Info($"普通弹窗:{LabTitle.Text}{vbCrLf}{LabCaption.Text}") Catch ex As Exception - Log(ex, "普通弹窗加载失败", NotifyLevel.AllUsers) + Logger.Error(ex, "普通弹窗加载失败", LogBehavior.Toast) End Try End Sub Private Sub Close() diff --git a/Plain Craft Launcher 2/Controls/MyPageRight.vb b/Plain Craft Launcher 2/Controls/MyPageRight.vb index ba337ce..c7656d7 100644 --- a/Plain Craft Launcher 2/Controls/MyPageRight.vb +++ b/Plain Craft Launcher 2/Controls/MyPageRight.vb @@ -35,7 +35,7 @@ Set(value As PageStates) If _PageState = value Then Return _PageState = value - If ModeDebug Then Log("[UI] 页面状态切换为 " & GetStringFromEnum(value)) + Logger.Trace($"页面状态切换为 {value}") End Set End Property @@ -59,9 +59,9 @@ ''' 无论是否在加载总是要显示的容器。可以为 Nothing。 ''' 在工作线程执行的加载器。 ''' 当加载器执行完成,在 UI 线程触发的 UI 初始化事件。 - Public Sub PageLoaderInit(LoaderUi As MyLoading, PanLoader As FrameworkElement, PanContent As FrameworkElement, PanAlways As FrameworkElement, - RealLoader As LoaderBase, - Optional FinishedInvoke As Action(Of LoaderBase) = Nothing, Optional InputInvoke As Func(Of Object) = Nothing, + Public Sub PageLoaderInit(Of TIn, TOut)(LoaderUi As MyLoading, PanLoader As FrameworkElement, PanContent As FrameworkElement, PanAlways As FrameworkElement, + RealLoader As LoaderTask(Of TIn, TOut), + Optional FinishedInvoke As Action(Of LoaderTask(Of TIn, TOut)) = Nothing, Optional InputInvoke As Func(Of TIn) = Nothing, Optional AutoRun As Boolean = True) '初始化参数 Me.PanLoader = PanLoader @@ -89,13 +89,59 @@ If PanAlways IsNot Nothing Then PanAlways.Visibility = Visibility.Collapsed '初次运行加载器 If PageLoaderAutoRun Then - If PageLoader.GetType.Name.StartsWithF("LoaderTask") Then - PageLoader.Start(CType(PageLoader, Object).StartGetInput(Nothing, PageLoaderInputInvoke)) - Else - Dim Input = Nothing - If PageLoaderInputInvoke IsNot Nothing Then Input = PageLoaderInputInvoke() - PageLoader.Start(Input) - End If + '上下两个重载只有这里不一样 + PageLoader.Start(RealLoader.StartGetInput(Nothing, PageLoaderInputInvoke)) + End If + If PageLoader.State = LoadState.Finished AndAlso FinishedInvoke IsNot Nothing Then + RunInUiWait(Sub() FinishedInvoke(RealLoader)) '加载器已提前完成,直接触发事件 + End If + '设置加载环 + PageLoaderUi.State = RealLoader + AddHandler PageLoaderUi.Click, Sub() If RealLoader.State = LoadState.Failed Then PageLoaderRestart() '点击重试事件 + End Sub + ''' + ''' 表明页面存在需要在后台执行的加载器。 + ''' + ''' MyLoading 控件。 + ''' MyLoading 控件对应的卡片。 + ''' 加载结束后出现的内容容器。 + ''' 无论是否在加载总是要显示的容器。可以为 Nothing。 + ''' 在工作线程执行的加载器。 + ''' 当加载器执行完成,在 UI 线程触发的 UI 初始化事件。 + Public Sub PageLoaderInit(Of TIn)(LoaderUi As MyLoading, PanLoader As FrameworkElement, PanContent As FrameworkElement, PanAlways As FrameworkElement, + RealLoader As LoaderCombo(Of TIn), + Optional FinishedInvoke As Action(Of LoaderCombo(Of TIn)) = Nothing, Optional InputInvoke As Func(Of TIn) = Nothing, + Optional AutoRun As Boolean = True) + '初始化参数 + Me.PanLoader = PanLoader + Me.PanContent = PanContent + Me.PanAlways = PanAlways + Me.PageLoader = RealLoader + Me.PageLoaderUi = LoaderUi + Me.PageLoaderInputInvoke = InputInvoke + Me.PageLoaderAutoRun = AutoRun + '添加结束 Invoke + If FinishedInvoke IsNot Nothing Then + AddHandler RealLoader.PreviewFinish, + Sub() + Do While PageState = MyPageRight.PageStates.PageExit OrElse PageState = MyPageRight.PageStates.ContentExit + Thread.Sleep(10) '不在退出动画时执行 UI 线程操作,避免退出动画被重置 + Loop + RunInUiWait(Sub() FinishedInvoke(RealLoader)) + Thread.Sleep(20) '由于大量初始化控件会导致掉帧,延迟触发 State 改变事件 + End Sub + End If + AddHandler RealLoader.OnStateChangedUi, Sub(Loader As LoaderBase, NewState As LoadState, OldState As LoadState) RunInUi(Sub() PageLoaderState(Loader, NewState, OldState)) + '隐藏 UI + PanLoader.Visibility = Visibility.Collapsed + PanContent.Visibility = Visibility.Collapsed + If PanAlways IsNot Nothing Then PanAlways.Visibility = Visibility.Collapsed + '初次运行加载器 + If PageLoaderAutoRun Then + '上下两个重载只有这里不一样 + Dim Input = Nothing + If PageLoaderInputInvoke IsNot Nothing Then Input = PageLoaderInputInvoke() + PageLoader.Start(Input) End If If PageLoader.State = LoadState.Finished AndAlso FinishedInvoke IsNot Nothing Then RunInUiWait(Sub() FinishedInvoke(RealLoader)) '加载器已提前完成,直接触发事件 @@ -125,7 +171,7 @@ ''' 需要根据加载器状态,从 Empty 切换到 ContentEnter、LoaderWait、LoaderEnter。 ''' Public Sub PageOnEnter() - If ModeDebug Then Log("[UI] 已触发 PageOnEnter") + Logger.Trace("已触发 PageOnEnter") RaiseEvent PageEnter() Select Case PageState Case PageStates.Empty @@ -155,7 +201,7 @@ Case PageStates.ContentEnter '重复调用 PageOnEnter,直接忽略 Case Else - Throw New Exception("在状态为 " & GetStringFromEnum(PageState) & " 时触发了 PageOnEnter 事件。") + Throw New Exception("在状态为 " & PageState.ToString() & " 时触发了 PageOnEnter 事件。") End Select End Sub Public Event PageEnter() @@ -164,7 +210,7 @@ ''' 需要立即切换至 PageExit 或 Empty。 ''' Public Sub PageOnExit() - If ModeDebug Then Log("[UI] 已触发 PageOnExit") + Logger.Trace("已触发 PageOnExit") RaiseEvent PageExit() Select Case PageState Case PageStates.ContentEnter, PageStates.ContentStay @@ -189,7 +235,7 @@ ''' Public Sub PageOnForceExit() If PageState = PageStates.Empty Then Return - If ModeDebug Then Log("[UI] 已触发 PageOnForceExit") + Logger.Trace("已触发 PageOnForceExit") PageState = PageStates.Empty AniStop("PageRight PageChange " & PageUuid) '由于动画会被强制中止,所以需要手动进行隐藏 @@ -206,7 +252,7 @@ ''' 需要在 PageEnter 事件确认要显示的子页面有哪些。 ''' Public Sub PageOnContentExit() - If ModeDebug Then Log("[UI] 已触发 PageOnContentExit") + Logger.Trace("已触发 PageOnContentExit") If PageLoader IsNot Nothing AndAlso PageLoader.State = LoadState.Loading Then 'Loading 的加载器可能触发进一步变化,难以预测会触发子页面的动画还是加载器完成的动画 Throw New Exception("在调用 PageOnContentExit 时,加载器不能为 Loading 状态") @@ -235,7 +281,7 @@ ''' 需要根据目前状态,从 ContentEnter 切换到 ContentStay,或从 LoaderEnter 切换到 LoaderStayForce。 ''' Private Sub PageOnEnterAnimationFinished() - If ModeDebug Then Log("[UI] 已触发 PageOnEnterAnimationFinished") + Logger.Trace("已触发 PageOnEnterAnimationFinished") Select Case PageState Case PageStates.ContentEnter PageState = PageStates.ContentStay @@ -243,7 +289,7 @@ PageState = PageStates.LoaderStayForce AniStart(AaCode(AddressOf PageOnLoaderStayFinished, 400), "PageRight PageChange " & PageUuid) Case Else - Throw New Exception("在状态为 " & GetStringFromEnum(PageState) & " 时触发了 PageOnEnterAnimationFinished 事件。") + Throw New Exception("在状态为 " & PageState.ToString() & " 时触发了 PageOnEnterAnimationFinished 事件。") End Select End Sub ''' @@ -251,7 +297,7 @@ ''' 需要根据目前状态,从 AllExit 切换到 Empty,或从 LoaderExit 切换到 ContentEnter,或从 ContentExit 重新触发 PageOnEnter。 ''' Private Sub PageOnExitAnimationFinished() - If ModeDebug Then Log("[UI] 已触发 PageOnExitAnimationFinished") + Logger.Trace("已触发 PageOnExitAnimationFinished") Select Case PageState Case PageStates.PageExit PageState = PageStates.Empty @@ -261,7 +307,7 @@ PageState = PageStates.ContentEnter TriggerEnterAnimation(PanContent) Case Else - Throw New Exception("在状态为 " & GetStringFromEnum(PageState) & " 时触发了 PageOnExitAnimationFinished 事件。") + Throw New Exception("在状态为 " & PageState.ToString() & " 时触发了 PageOnExitAnimationFinished 事件。") End Select End Sub ''' @@ -269,7 +315,7 @@ ''' 需要从 LoaderWait 切换到 LoaderEnter。 ''' Private Sub PageOnLoaderWaitFinished() - If ModeDebug Then Log("[UI] 已触发 PageOnLoaderWaitFinished") + Logger.Trace("已触发 PageOnLoaderWaitFinished") Select Case PageState Case PageStates.LoaderWait PageState = PageStates.LoaderEnter @@ -279,7 +325,7 @@ TriggerEnterAnimation(PanLoader) End If Case Else - Throw New Exception("在状态为 " & GetStringFromEnum(PageState) & " 时触发了 PageOnLoaderWaitFinished 事件。") + Throw New Exception("在状态为 " & PageState.ToString() & " 时触发了 PageOnLoaderWaitFinished 事件。") End Select End Sub ''' @@ -287,7 +333,7 @@ ''' 需要从 LoaderStayForce 切换到 LoaderStay 或 LoaderExit。 ''' Private Sub PageOnLoaderStayFinished() - If ModeDebug Then Log("[UI] 已触发 PageOnLoaderStayFinished") + Logger.Trace("已触发 PageOnLoaderStayFinished") Select Case PageState Case PageStates.LoaderStayForce If PageLoader.State = LoadState.Finished Then @@ -297,7 +343,7 @@ PageState = PageStates.LoaderStay End If Case Else - Throw New Exception("在状态为 " & GetStringFromEnum(PageState) & " 时触发了 PageOnLoaderWaitFinished 事件。") + Throw New Exception("在状态为 " & PageState.ToString() & " 时触发了 PageOnLoaderWaitFinished 事件。") End Select End Sub @@ -308,7 +354,7 @@ Select Case NewState Case LoadState.Failed, LoadState.Loading If OldState = LoadState.Failed OrElse OldState = LoadState.Loading Then Return - If ModeDebug Then Log("[UI] 已触发 PageLoaderState (Start/Refresh)") + Logger.Trace("已触发 PageLoaderState (Start/Refresh)") '(重新)开始运行 '需要从部分状态切换到 ReloadExit Select Case PageState @@ -320,7 +366,7 @@ End Select Case LoadState.Finished, LoadState.Interrupted, LoadState.Waiting If Not (OldState = LoadState.Failed OrElse OldState = LoadState.Loading) Then Return - If ModeDebug Then Log("[UI] 已触发 PageLoaderState (Stop/Interrupt)") + Logger.Trace("已触发 PageLoaderState (Stop/Interrupt)") '运行结束 '需要从 LoaderWait 切换到 ContentEnter,或从 LoaderStay 切换到 LoaderExit Select Case PageState diff --git a/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb b/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb index 4afc8ad..a5f1510 100644 --- a/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyRadioBox.xaml.vb @@ -49,12 +49,12 @@ Public Class MyRadioBox '自定义属性基础 Dim IsChanged As Boolean = False If IsLoaded AndAlso Not value = Checked Then RaiseEvent PreviewChange(Me, New RouteEventArgs(user)) - If Not value = Checked Then + If value <> Checked Then SetValue(CheckedProperty, value) IsChanged = True End If - '保证只有一个单选框选中 + '保证最多只有一个单选框选中 If Parent Is Nothing Then Return Dim RadioboxList As New List(Of MyRadioBox) Dim CheckedCount As Integer = 0 @@ -64,31 +64,26 @@ Public Class MyRadioBox If Control.Checked Then CheckedCount += 1 End If Next - Select Case CheckedCount '判断选中情况 - Case 0 - '没有任何单选框被选中,选择第一个 - RadioboxList(0).Checked = True - Case Is > 1 - '选中项目多于 1 个 - If Checked Then - '如果本控件选中,则取消其他所有控件的选中 - For Each Control As MyRadioBox In RadioboxList - If Control.Checked AndAlso Not Control.Equals(Me) Then Control.Checked = False - Next - Else - '如果本控件未选中,则只保留第一个选中的控件 - Dim FirstChecked = False - For Each Control As MyRadioBox In RadioboxList - If Control.Checked Then - If FirstChecked Then - Control.Checked = False '修改 Checked 会自动触发 Change 事件,所以不用额外触发 - Else - FirstChecked = True - End If + If CheckedCount > 1 Then + If Checked Then + '如果本控件选中,则取消其他所有控件的选中 + For Each Control As MyRadioBox In RadioboxList + If Control.Checked AndAlso Not Control.Equals(Me) Then Control.Checked = False + Next + Else + '如果本控件未选中,则只保留第一个选中的控件 + Dim FirstChecked = False + For Each Control As MyRadioBox In RadioboxList + If Control.Checked Then + If FirstChecked Then + Control.Checked = False '修改 Checked 会自动触发 Change 事件,所以不用额外触发 + Else + FirstChecked = True End If - Next - End If - End Select + End If + Next + End If + End If If IsChanged Then '触发事件 @@ -100,10 +95,11 @@ Public Class MyRadioBox End If Catch ex As Exception - Log(ex, "单选框勾选改变错误", NotifyLevel.AllUsers) + Logger.Error(ex, "单选框勾选改变错误", LogBehavior.Toast) End Try End Sub Private Sub SyncUI() + Cursor = If(Checked, Nothing, Cursors.Hand) If AniControlEnabled = 0 AndAlso IsLoaded Then '防止默认属性变更触发动画 If Checked Then '由无变有 @@ -175,7 +171,7 @@ Public Class MyRadioBox Private AllowMouseDown As Boolean = True Private Sub Radiobox_MouseUp() Handles Me.MouseLeftButtonUp If Not MouseDowned Then Return - Log("[Control] 按下单选框:" & Text) + Logger.Info($"按下单选框:{Text}") SetChecked(True, True) MouseDowned = False AniStart(AaColor(ShapeBorder, Ellipse.FillProperty, "ColorBrushHalfWhite", 100), "MyRadioBox Background " & Uuid) @@ -202,6 +198,9 @@ Public Class MyRadioBox Private Const AnimationTimeOfMouseIn As Integer = 100 '鼠标指向动画长度 Private Const AnimationTimeOfMouseOut As Integer = 200 '鼠标指向动画长度 Private Const AnimationTimeOfCheck As Integer = 150 '勾选状态变更动画长度 + Private Sub MyRadioBox_Loaded() Handles Me.Loaded + Cursor = If(Checked, Nothing, Cursors.Hand) + End Sub Private Sub Radiobox_IsEnabledChanged() Handles Me.IsEnabledChanged If Me.IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画 '有动画 diff --git a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.vb b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.vb index 44a44fd..23d77f8 100644 --- a/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MyRadioButton.xaml.vb @@ -104,7 +104,7 @@ Public Class MyRadioButton RaiseCustomEvent() Catch ex As Exception - Log(ex, "单选按钮勾选改变错误", NotifyLevel.AllUsers) + Logger.Error(ex, "单选按钮勾选改变错误", LogBehavior.Toast) End Try End Sub @@ -145,7 +145,7 @@ Public Class MyRadioButton Private Sub Radiobox_MouseUp() Handles Me.MouseLeftButtonUp If Checked Then Return If Not IsMouseDown Then Return - Log("[Control] 按下单选按钮:" & Text) + Logger.Info($"按下单选按钮:{Text}") IsMouseDown = False Dim e As New RouteEventArgs(True) RaiseEvent PreviewClick(Me, e) @@ -167,6 +167,7 @@ Public Class MyRadioButton Private Const AnimationTimeOfMouseOut As Integer = 150 '鼠标移出动画长度 Private Const AnimationTimeOfCheck As Integer = 120 '勾选状态变更动画长度 Private Sub RefreshColor(Optional obj = Nothing, Optional e = Nothing) Handles Me.MouseEnter, Me.MouseLeave, Me.Loaded + Cursor = If(Checked, Nothing, Cursors.Hand) Try If IsLoaded AndAlso AniControlEnabled = 0 AndAlso Not False.Equals(e) Then '防止默认属性变更触发动画,若强制不执行动画,则 e 为 False @@ -255,7 +256,7 @@ Public Class MyRadioButton End If Catch ex As Exception - Log(ex, "刷新单选按钮颜色出错") + Logger.Warn(ex, "刷新单选按钮颜色出错") End Try End Sub diff --git a/Plain Craft Launcher 2/Controls/MyScrollBar.vb b/Plain Craft Launcher 2/Controls/MyScrollBar.vb index 21f4de3..02dc221 100644 --- a/Plain Craft Launcher 2/Controls/MyScrollBar.vb +++ b/Plain Craft Launcher 2/Controls/MyScrollBar.vb @@ -44,7 +44,7 @@ End If Catch ex As Exception - Log(ex, "滚动条颜色改变出错") + Logger.Warn(ex, "滚动条颜色改变出错") End Try End Sub diff --git a/Plain Craft Launcher 2/Controls/MySlider.xaml.vb b/Plain Craft Launcher 2/Controls/MySlider.xaml.vb index 26b87c4..b7aa098 100644 --- a/Plain Craft Launcher 2/Controls/MySlider.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MySlider.xaml.vb @@ -63,7 +63,7 @@ Public Class MySlider If AniControlEnabled = 0 Then RaiseEvent Change(Me, False) Catch ex As Exception - Log(ex, "滑动条进度改变出错", NotifyLevel.AllUsers) + Logger.Error(ex, "滑动条进度改变出错", LogBehavior.Toast) End Try End Set End Property @@ -156,7 +156,7 @@ Public Class MySlider End If Catch ex As Exception - Log(ex, "滑动条颜色改变出错") + Logger.Warn(ex, "滑动条颜色改变出错") End Try End Sub diff --git a/Plain Craft Launcher 2/Controls/MySliderDot.xaml.vb b/Plain Craft Launcher 2/Controls/MySliderDot.xaml.vb index e5edbc7..94b053c 100644 --- a/Plain Craft Launcher 2/Controls/MySliderDot.xaml.vb +++ b/Plain Craft Launcher 2/Controls/MySliderDot.xaml.vb @@ -59,7 +59,7 @@ If AniControlEnabled = 0 Then RaiseEvent Change(Me, False) Catch ex As Exception - Log(ex, "滑动条进度改变出错", LogLevel.Hint) + Logger.Warning(ex, "滑动条进度改变出错", LogLevel.Hint) End Try End Set End Property diff --git a/Plain Craft Launcher 2/Controls/MyTextBox.vb b/Plain Craft Launcher 2/Controls/MyTextBox.vb index 8688ae7..93e044f 100644 --- a/Plain Craft Launcher 2/Controls/MyTextBox.vb +++ b/Plain Craft Launcher 2/Controls/MyTextBox.vb @@ -228,7 +228,7 @@ '改变文本 RaiseEvent ValidatedTextChanged(sender, e) Catch ex As Exception - Log(ex, "进行输入验证时出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "进行输入验证时出错") End Try End Sub @@ -282,7 +282,7 @@ End If Catch ex As Exception - Log(ex, "文本框颜色改变出错") + Logger.Warn(ex, "文本框颜色改变出错") End Try End Sub Private Sub RefreshTextColor() Handles Me.IsEnabledChanged diff --git a/Plain Craft Launcher 2/Controls/MyTextButton.vb b/Plain Craft Launcher 2/Controls/MyTextButton.vb index 4bde410..9339f8f 100644 --- a/Plain Craft Launcher 2/Controls/MyTextButton.vb +++ b/Plain Craft Launcher 2/Controls/MyTextButton.vb @@ -45,7 +45,7 @@ Private Sub MyTextButton_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonUp If Not IsMouseDown Then Return IsMouseDown = False - Log("[Control] 按下文本按钮:" & Text) + Logger.Info($"按下文本按钮:{Text}") RaiseEvent Click(Me, Nothing) RaiseCustomEvent() e.Handled = True diff --git a/Plain Craft Launcher 2/FormMain.xaml.vb b/Plain Craft Launcher 2/FormMain.xaml.vb index 8f12edc..5ab4ed7 100644 --- a/Plain Craft Launcher 2/FormMain.xaml.vb +++ b/Plain Craft Launcher 2/FormMain.xaml.vb @@ -11,6 +11,11 @@ Public Class FormMain Dim FeatureList As New List(Of KeyValuePair(Of Integer, String)) '统计更新日志条目 If BuildType = BuildTypes.Release Then + If LastVersion < 400 Then 'Release 2.12.8.0 + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:升级框架到 .NET Framework 4.8")) + FeatureCount += 28 + BugCount += 19 + End If If LastVersion < 398 Then 'Release 2.12.7.3 FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:下载游戏、整合包的稳定性")) FeatureCount += 1 @@ -63,58 +68,17 @@ Public Class FormMain FeatureCount += 32 BugCount += 21 End If - If LastVersion < 372 Then 'Release 2.10.9 - FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:如果版本设置了自定义描述,会在标题后面以淡灰色显示其版本号")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "新增:支持为一个控件设置多个自定义事件")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "新增:修改变量、弹出提示自定义事件")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "新增:添加大量替换标记,允许在更多设置和 XAML 中使用更多替换标记")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法安装 MMC 整合包")) - FeatureCount += 33 - BugCount += 11 - End If - If LastVersion < 369 Then 'Release 2.10.8 - FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "新增:允许在版本设置中设置禁止更新 Mod,以防整合包玩家误操作")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:网络与下载稳定性优化")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化:若整合包需要 PCL 不兼容的加载器,允许选择跳过它的安装")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "删除:由于已不再需要,删除手动安装包下载功能")) - FeatureCount += 21 - BugCount += 32 - End If - If LastVersion < 367 Then 'Release 2.10.6 - FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:启用 MCIM 社区资源镜像源,以缓解社区资源难以下载的问题")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:正版登录出错时无法给出正确的错误信息")) - FeatureCount += 9 - BugCount += 9 - End If - If LastVersion < 365 Then 'Release 2.10.5 - FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:下载资源时,会单独记忆每种资源上次下载到的文件夹,以防混淆")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:网络底层框架与下载稳定性")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法启动一部分 LabyMod 和 GTNH 客户端")) - FeatureCount += 22 - BugCount += 26 - End If - If LastVersion < 361 Then 'Release 2.10.3 - FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法安装部分使用老版本 PCL 导出的整合包")) - End If - If LastVersion < 359 Then 'Release 2.10.2 - If LastVersion >= 357 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:下载资源包、光影包时能自动跳转到对应的文件夹")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:调整界面样式与动画,让整体视觉更干净,操作体验更顺滑")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法从 CurseForge 下载 Mod 等资源,或是安装整合包")) - FeatureCount += 28 - BugCount += 28 - End If - If LastVersion < 357 Then 'Release 2.10.0 - FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "新增:下载资源包、光影包、数据包")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "新增:允许设置文件下载源")) - FeatureCount += 9 - BugCount += 26 - End If Else '5: FEAT+ '4: IMP+ FEAT* '3:BUG+ IMP* FEAT- '2:BUG* IMP- '1:BUG- + If LastVersion < 399 Then 'Snapshot 2.12.8.0 + FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:升级框架到 .NET Framework 4.8")) + FeatureCount += 28 + BugCount += 19 + End If If LastVersion < 397 Then 'Snapshot 2.12.7.3 If LastVersion >= 393 AndAlso LastVersion < 397 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法使用自定义隐藏主题")) End If @@ -212,68 +176,6 @@ Public Class FormMain FeatureCount += 7 BugCount += 10 End If - If LastVersion < 371 Then 'Snapshot 2.10.9 - FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:如果版本设置了自定义描述,会在标题后面以淡灰色显示其版本号")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "新增:支持为一个控件设置多个自定义事件")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "新增:修改变量、弹出提示自定义事件")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "新增:添加大量替换标记,允许在更多设置和 XAML 中使用更多替换标记")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法安装 MMC 整合包")) - FeatureCount += 33 - BugCount += 11 - End If - If LastVersion < 370 Then 'Snapshot 2.10.8 - If LastVersion >= 368 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:网络与下载稳定性优化")) - FeatureCount += 3 - BugCount += 4 - End If - If LastVersion < 368 Then 'Snapshot 2.10.7 - FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "新增:允许在版本设置中设置禁止更新 Mod,以防整合包玩家误操作")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:网络与下载稳定性优化")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "优化:若整合包需要 PCL 不兼容的加载器,允许选择跳过它的安装")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "删除:由于已不再需要,删除手动安装包下载功能")) - FeatureCount += 19 - BugCount += 28 - End If - If LastVersion < 366 Then 'Snapshot 2.10.6 - FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:启用 MCIM 社区资源镜像源,以缓解社区资源难以下载的问题")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:正版登录出错时无法给出正确的错误信息")) - FeatureCount += 9 - BugCount += 9 - End If - If LastVersion < 364 Then 'Snapshot 2.10.5 - If LastVersion >= 363 Then - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法添加新的正版账号")) - BugCount += 1 - End If - End If - If LastVersion < 363 Then 'Snapshot 2.10.4 - FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:下载资源时,会单独记忆每种资源上次下载到的文件夹,以防混淆")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "优化:网络底层框架与下载稳定性")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法启动一部分 LabyMod 和 GTNH 客户端")) - FeatureCount += 22 - BugCount += 26 - End If - If LastVersion < 362 Then 'Snapshot 2.10.3 - FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法安装部分使用老版本 PCL 导出的整合包")) - End If - If LastVersion < 360 Then 'Snapshot 2.10.2 - FeatureList.Add(New KeyValuePair(Of Integer, String)(2, "修复:无法从 CurseForge 下载 Mod 等资源,或是安装整合包")) - If LastVersion >= 358 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(1, "修复:无法加载正版皮肤的头像")) - FeatureCount += 3 - BugCount += 5 - End If - If LastVersion < 358 Then 'Snapshot 2.10.1 - If LastVersion >= 356 Then FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:下载资源包、光影包时能自动跳转到对应的文件夹")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "优化:调整界面样式与动画,让整体视觉更干净,操作体验更顺滑")) - FeatureCount += 25 - BugCount += 23 - End If - If LastVersion < 356 Then 'Snapshot 2.10.0 - FeatureList.Add(New KeyValuePair(Of Integer, String)(5, "新增:下载资源包、光影包、数据包")) - FeatureList.Add(New KeyValuePair(Of Integer, String)(3, "新增:允许设置文件下载源")) - FeatureCount += 9 - BugCount += 26 - End If End If '整理更新日志文本 Dim ContentList As New List(Of String) @@ -308,7 +210,7 @@ Public Class FormMain FrmLaunchLeft = New PageLaunchLeft FrmLaunchRight = New PageLaunchRight '版本号改变 - Dim LastVersion As Integer = Settings.Get("SystemLastVersionReg") + Dim LastVersion As Integer = Settings.Get(Of Integer)("SystemLastVersionReg") If LastVersion < VersionCode Then '触发升级 UpgradeSub(LastVersion) @@ -319,19 +221,19 @@ Public Class FormMain '版本隔离设置迁移 If Not Settings.HasSaved("LaunchArgumentIndieV2") Then If Settings.HasSaved("LaunchArgumentIndie") Then - Log("[Start] 从老 PCL 迁移版本隔离") - Settings.Set("LaunchArgumentIndieV2", Settings.Get("LaunchArgumentIndie")) + Logger.Info("从老 PCL 迁移版本隔离") + Settings.Set("LaunchArgumentIndieV2", Settings.Get(Of Integer)("LaunchArgumentIndie")) ElseIf HasIniKey("Setup", "LaunchVersionSelect") Then - Log("[Start] 从老 PCL 升级,但此前未调整版本隔离,使用老的版本隔离默认值") + Logger.Info("从老 PCL 升级,但此前未调整版本隔离,使用老的版本隔离默认值") Settings.Set("LaunchArgumentIndieV2", Settings.GetDefault("LaunchArgumentIndie")) Else - Log("[Start] 全新的 PCL,使用新的版本隔离默认值") + Logger.Info("全新的 PCL,使用新的版本隔离默认值") Settings.Set("LaunchArgumentIndieV2", Settings.GetDefault("LaunchArgumentIndieV2")) End If End If '刷新主题 ThemeCheckAll(False) - ThemeRefresh(Settings.Get("UiLauncherTheme")) + ThemeRefresh(Settings.Get(Of Integer)("UiLauncherTheme")) '注册拖拽事件(不能直接加 Handles,否则没用;#6340) [AddHandler](DragDrop.DragEnterEvent, New DragEventHandler(AddressOf HandleDrag), handledEventsToo:=True) [AddHandler](DragDrop.DragOverEvent, New DragEventHandler(AddressOf HandleDrag), handledEventsToo:=True) @@ -339,7 +241,7 @@ Public Class FormMain InitializeComponent() Opacity = 0 '开启管理员权限下的文件拖拽 - If IsAdmin() Then + If SystemUtils.HasAdminRole() Then Static Helper As New DragHelper AddHandler SourceInitialized, Sub() @@ -364,7 +266,7 @@ Public Class FormMain '尽早执行的加载池 McFolderListLoader.Start(0) '为了让下载已存在文件检测可以正常运行,必须跑一次;为了让启动按钮尽快可用,需要尽早执行;为了与 PageLaunchLeft 联动,需要为 0 而不是 GetUuid - Log("[Start] 第二阶段加载用时:" & GetTimeMs() - ApplicationStartTick & " ms") + Logger.Info($"第二阶段加载用时:{GetTimeMs() - ApplicationStartTick} ms") End Sub Private Sub FormMain_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded ApplicationStartTick = GetTimeMs() @@ -397,10 +299,10 @@ Public Class FormMain '加载窗口 ThemeRefreshMain() Try - Height = Settings.Get("WindowHeight") - Width = Settings.Get("WindowWidth") + Height = Settings.Get(Of Integer)("WindowHeight") + Width = Settings.Get(Of Integer)("WindowWidth") Catch ex As Exception '修复 #2019 - Log(ex, "读取窗口默认大小失败", NotifyLevel.AllUsers) + Logger.Error(ex, "读取窗口默认大小失败", LogBehavior.Toast) Height = MinHeight + 100 Width = MinWidth + 100 End Try @@ -417,14 +319,14 @@ Public Class FormMain HwndSource.AddHook(New Interop.HwndSourceHook(AddressOf WndProc)) AniStart({ AaCode(Sub() AniControlEnabled -= 1, 50), - AaOpacity(Me, Settings.Get("UiLauncherTransparent") / 1000 + 0.4, 250, 100), + AaOpacity(Me, Settings.Get(Of Integer)("UiLauncherTransparent") / 1000 + 0.4, 250, 100), AaDouble(Sub(i) TransformPos.Y += i, -TransformPos.Y, 600, 100, New AniEaseOutBack(AniEasePower.Weak)), AaDouble(Sub(i) TransformRotate.Angle += i, -TransformRotate.Angle, 500, 100, New AniEaseOutBack(AniEasePower.Weak)), AaCode( Sub() PanBack.RenderTransform = Nothing IsWindowLoadFinished = True - Log($"[System] DPI:{DPI},系统版本:{Environment.OSVersion.VersionString},PCL 位置:{PathExe}") + Logger.Info($"DPI:{DPI},系统版本:{Environment.OSVersion.VersionString},PCL 位置:{PathExe}") End Sub, , True) }, "Form Show") 'Timer 启动 @@ -435,9 +337,9 @@ Public Class FormMain Sub() 'EULA 提示 Const EulaVersion As Integer = 2 - If Settings.Get("SystemEulaVersion") < EulaVersion Then + If Settings.Get(Of Integer)("SystemEulaVersion") < EulaVersion Then Select Case MyMsgBox( - If(Settings.Get("SystemEulaVersion") = 0, + If(Settings.Get(Of Integer)("SystemEulaVersion") = 0, "在使用 PCL 前,请先阅读用户协议与免责声明。", $"PCL 的用户协议与免责声明已更新。{vbCrLf}请阅读更新后的用户协议与免责声明。"), "协议授权", "同意", "拒绝", "查看用户协议与免责声明", @@ -457,13 +359,13 @@ Public Class FormMain ServerLoader.Start() RunInNewThread(AddressOf TryClearTaskTemp, "TryClearTaskTemp", ThreadPriority.BelowNormal) Catch ex As Exception - Log(ex, "初始化加载池运行失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "初始化加载池运行失败") End Try '清理自动更新文件 Try - File.Delete(PathExeFolder & "PCL\Plain Craft Launcher 2.exe") + FileUtils.Delete(PathExeFolder & "PCL\Plain Craft Launcher 2.exe") Catch ex As Exception - Log(ex, "清理自动更新文件失败") + Logger.Warn(ex, "清理自动更新文件失败") End Try '上报 Telemetry("启动") @@ -473,19 +375,19 @@ Public Class FormMain End If End Sub, "初始化", ThreadPriority.Lowest) - Log("[Start] 第三阶段加载用时:" & GetTimeMs() - ApplicationStartTick & " ms") + Logger.Info($"第三阶段加载用时:{GetTimeMs() - ApplicationStartTick} ms") End Sub '根据打开次数触发的事件 Private Sub RunCountSub() - Settings.Set("SystemCount", Settings.Get("SystemCount") + 1) + Settings.Set("SystemCount", Settings.Get(Of Integer)("SystemCount") + 1) If BuildType = BuildTypes.Snapshot Then - Select Case Settings.Get("SystemCount") + Select Case Settings.Get(Of Integer)("SystemCount") Case 1 MyMsgBox("欢迎使用 PCL 快照版!" & vbCrLf & "快照版包含尚未在正式版发布的测试性功能,仅用于赞助者本人尝鲜。所以请不要发给其他人或者用于制作整合包哦!" & vbCrLf & "如果你并非通过赞助或赞助者本人邀请进群获得的本程序,那么可能是有人在违规传播,记得提醒他一下啦。", "快照版使用说明") End Select - If Settings.Get("SystemCount") >= 99 Then + If Settings.Get(Of Integer)("SystemCount") >= 99 Then If ThemeUnlock(6, False) Then MyMsgBox("你已经使用了 99 次 PCL 啦,感谢你长期以来的支持!" & vbCrLf & "隐藏主题 铁杆粉 已解锁!", "提示") @@ -495,75 +397,75 @@ Public Class FormMain End Sub '升级与降级事件 Private Sub UpgradeSub(LastVersionCode As Integer) - Log("[Start] 版本号从 " & LastVersionCode & " 升高到 " & VersionCode) + Logger.Info($"版本号从 {LastVersionCode} 升高到 {VersionCode}") Settings.Set("SystemLastVersionReg", VersionCode) '检查有记录的最高版本号 Dim LowerVersionCode As Integer - Dim SettingKey = If(BuildType = BuildTypes.Snapshot, "SystemHighestAlphaVersionReg", "SystemHighestBetaVersionReg") - LowerVersionCode = Settings.Get("SystemHighestAlphaVersionReg") + Const SettingKey = If(BuildType = BuildTypes.Snapshot, "SystemHighestAlphaVersionReg", "SystemHighestBetaVersionReg") + LowerVersionCode = Settings.Get(Of Integer)("SystemHighestAlphaVersionReg") If LowerVersionCode < VersionCode Then - Settings.Set("SystemHighestAlphaVersionReg", VersionCode) - Log($"[Start] 最高版本号从 {LowerVersionCode} 升高到 {VersionCode}") + Settings.Set(SettingKey, VersionCode) + Logger.Info($"最高版本号从 {LowerVersionCode} 升高到 {VersionCode}") End If '被移除的窗口设置选项 - If Settings.Get("LaunchArgumentWindowType") = 5 Then Settings.Set("LaunchArgumentWindowType", 1) + If Settings.Get(Of Integer)("LaunchArgumentWindowType") = 5 Then Settings.Set("LaunchArgumentWindowType", 1) '修改主题设置项名称 If LowerVersionCode <= 207 Then Dim UnlockedTheme As New List(Of String) From {"2"} - UnlockedTheme.AddRange(New List(Of String)(Settings.Get("UiLauncherThemeHide").ToString.Split("|"))) - UnlockedTheme.AddRange(New List(Of String)(Settings.Get("UiLauncherThemeHide2").ToString.Split("|"))) + UnlockedTheme.AddRange(New List(Of String)(Settings.Get(Of String)("UiLauncherThemeHide").ToString.Split("|"))) + UnlockedTheme.AddRange(New List(Of String)(Settings.Get(Of String)("UiLauncherThemeHide2").ToString.Split("|"))) Settings.Set("UiLauncherThemeHide2", UnlockedTheme.Distinct.ToList.Join("|"c)) End If '重置欧皇彩 - If LastVersionCode <= 115 AndAlso Settings.Get("UiLauncherThemeHide2").ToString.Split("|").Contains("13") Then - Dim UnlockedTheme As New List(Of String)(Settings.Get("UiLauncherThemeHide2").ToString.Split("|")) + If LastVersionCode <= 115 AndAlso Settings.Get(Of String)("UiLauncherThemeHide2").ToString.Split("|").Contains("13") Then + Dim UnlockedTheme As New List(Of String)(Settings.Get(Of String)("UiLauncherThemeHide2").ToString.Split("|")) UnlockedTheme.Remove("13") Settings.Set("UiLauncherThemeHide2", UnlockedTheme.Join("|"c)) MyMsgBox("由于新版 PCL 修改了欧皇彩的解锁方式,你需要重新解锁欧皇彩。" & vbCrLf & "多谢各位的理解啦!", "重新解锁提醒") End If '重置滑稽彩 - If LastVersionCode <= 152 AndAlso Settings.Get("UiLauncherThemeHide2").ToString.Split("|").Contains("12") Then - Dim UnlockedTheme As New List(Of String)(Settings.Get("UiLauncherThemeHide2").ToString.Split("|")) + If LastVersionCode <= 152 AndAlso Settings.Get(Of String)("UiLauncherThemeHide2").ToString.Split("|").Contains("12") Then + Dim UnlockedTheme As New List(Of String)(Settings.Get(Of String)("UiLauncherThemeHide2").ToString.Split("|")) UnlockedTheme.Remove("12") Settings.Set("UiLauncherThemeHide2", UnlockedTheme.Join("|"c)) MyMsgBox("由于新版 PCL 修改了滑稽彩的解锁方式,你需要重新解锁滑稽彩。" & vbCrLf & "多谢各位的理解啦!", "重新解锁提醒") End If '移动自定义皮肤 - If LastVersionCode <= 161 AndAlso File.Exists(PathExeFolder & "PCL\CustomSkin.png") AndAlso Not File.Exists(PathAppdata & "CustomSkin.png") Then - CopyFile(PathExeFolder & "PCL\CustomSkin.png", PathAppdata & "CustomSkin.png") - Log("[Start] 已移动离线自定义皮肤 (162)") + If LastVersionCode <= 161 AndAlso FileUtils.Exists(PathExeFolder & "PCL\CustomSkin.png") AndAlso Not FileUtils.Exists(PathAppdata & "CustomSkin.png") Then + FileUtils.Copy(PathExeFolder & "PCL\CustomSkin.png", PathAppdata & "CustomSkin.png") + Logger.Info("已移动离线自定义皮肤 (162)") End If - If LastVersionCode <= 263 AndAlso File.Exists(PathTemp & "CustomSkin.png") AndAlso Not File.Exists(PathAppdata & "CustomSkin.png") Then - CopyFile(PathTemp & "CustomSkin.png", PathAppdata & "CustomSkin.png") - Log("[Start] 已移动离线自定义皮肤 (264)") + If LastVersionCode <= 263 AndAlso FileUtils.Exists(PathTemp & "CustomSkin.png") AndAlso Not FileUtils.Exists(PathAppdata & "CustomSkin.png") Then + FileUtils.Copy(PathTemp & "CustomSkin.png", PathAppdata & "CustomSkin.png") + Logger.Info("已移动离线自定义皮肤 (264)") End If '解除帮助页面的隐藏 If LastVersionCode <= 205 Then Settings.Set("UiHiddenOtherHelp", False) - Log("[Start] 已解除帮助页面的隐藏") + Logger.Info("已解除帮助页面的隐藏") End If '单向迁移微软登录结果(#4836) - If Not Settings.Get("CacheMsV2Migrated") Then + If Not Settings.Get(Of Boolean)("CacheMsV2Migrated") Then Settings.Set("CacheMsV2Migrated", True) - Settings.Set("CacheMsV2OAuthRefresh", Settings.Get("CacheMsOAuthRefresh")) - Settings.Set("CacheMsV2Access", Settings.Get("CacheMsAccess")) - Settings.Set("CacheMsV2ProfileJson", Settings.Get("CacheMsProfileJson")) - Settings.Set("CacheMsV2Uuid", Settings.Get("CacheMsUuid")) - Settings.Set("CacheMsV2Name", Settings.Get("CacheMsName")) - Log("[Start] 已从老版本迁移微软登录结果") + Settings.Set("CacheMsV2OAuthRefresh", Settings.Get(Of String)("CacheMsOAuthRefresh")) + Settings.Set("CacheMsV2Access", Settings.Get(Of String)("CacheMsAccess")) + Settings.Set("CacheMsV2ProfileJson", Settings.Get(Of String)("CacheMsProfileJson")) + Settings.Set("CacheMsV2Uuid", Settings.Get(Of String)("CacheMsUuid")) + Settings.Set("CacheMsV2Name", Settings.Get(Of String)("CacheMsName")) + Logger.Info("已从老版本迁移微软登录结果") End If 'Mod 命名设置迁移 If Settings.HasSaved("ToolDownloadTranslate") AndAlso Not Settings.HasSaved("ToolDownloadTranslateV2") Then - Settings.Set("ToolDownloadTranslateV2", Settings.Get("ToolDownloadTranslate") + 1) - Log("[Start] 已从老版本迁移 Mod 命名设置") + Settings.Set("ToolDownloadTranslateV2", Settings.Get(Of Integer)("ToolDownloadTranslate") + 1) + Logger.Info("已从老版本迁移 Mod 命名设置") End If '重置 JVM 参数设置 If LastVersionCode <= 381 AndAlso Settings.HasSaved("LaunchAdvanceJvm") AndAlso - Settings.Get("LaunchAdvanceJvm").ToString.Replace("-XX:+UseG1GC ", "").Replace("-XX:-UseAdaptiveSizePolicy ", "").Trim = Settings.GetDefault("LaunchAdvanceJvm") Then + Settings.Get(Of String)("LaunchAdvanceJvm").ToString.Replace("-XX:+UseG1GC ", "").Replace("-XX:-UseAdaptiveSizePolicy ", "").Trim = Settings.GetDefault("LaunchAdvanceJvm") Then Settings.Reset("LaunchAdvanceJvm") - Log("[Start] 已重置 JVM 参数设置") + Logger.Info("已重置 JVM 参数设置") End If '输出更新日志 If LastVersionCode <= 0 Then Return @@ -571,7 +473,7 @@ Public Class FormMain ShowUpdateLog(LowerVersionCode) End Sub Private Sub DowngradeSub(LastVersionCode As Integer) - Log("[Start] 版本号从 " & LastVersionCode & " 降低到 " & VersionCode) + Logger.Info($"版本号从 {LastVersionCode} 降低到 {VersionCode}") Settings.Set("SystemLastVersionReg", VersionCode) End Sub @@ -594,7 +496,7 @@ Public Class FormMain If SendWarning AndAlso MyMsgBox("还有下载任务尚未完成,是否确定退出?", "提示", "确定", "取消") = 2 Then Return RunInNewThread( Sub() - Log("[System] 正在强行停止任务") + Logger.Info("正在强行停止任务") For Each Task As LoaderBase In LoaderTaskbar.ToList() Task.Interrupt() Next @@ -631,26 +533,26 @@ Public Class FormMain Else EndProgramForce() End If - Log("[System] 收到关闭指令") + Logger.Info("收到关闭指令") End Sub) End Sub Private Shared IsLogShown As Boolean = False Public Shared Sub EndProgramForce(Optional ReturnCode As ProcessReturnValues = ProcessReturnValues.Success) On Error Resume Next - IsProgramEnded = True + IsProgramEnding = True AniControlEnabled += 1 If IsUpdateWaitingRestart Then UpdateRestart(False) If ReturnCode = ProcessReturnValues.Exception Then If Not IsLogShown Then FeedbackInfo() - Log("请在 https://github.com/Meloong-Git/PCL/issues 提交错误报告,以便于作者解决此问题!") + Logger.Info("请在 https://github.com/Meloong-Git/PCL/issues 提交错误报告,以便于作者解决此问题!") IsLogShown = True StartProcess(PathExeFolder & "PCL\Log1.txt") End If Thread.Sleep(500) '防止 PCL 在记事本打开前就被掐掉 End If - Log("[System] 程序已退出,返回值:" & GetStringFromEnum(ReturnCode)) - LogFlush() + Logger.Info($"程序已退出,返回值:{ReturnCode}") + Logger.Instance.Flush() If ReturnCode <> ProcessReturnValues.Success Then Environment.Exit(ReturnCode) Process.GetCurrentProcess.Kill() End Sub @@ -693,11 +595,11 @@ Public Class FormMain FrmMain.UpdateBackgroundAndTitleBar() End Sub Public Sub UpdateBackgroundAndTitleBar() - Log("[FormMain] 从设置更新背景图片与标题栏样式") + Logger.Info("从设置更新背景图片与标题栏样式") '背景图片透明度 - ImgBack.Opacity = Settings.Get("UiBackgroundOpacity") / 1000 + ImgBack.Opacity = Settings.Get(Of Integer)("UiBackgroundOpacity") / 1000 '背景图片模糊 - Dim BlurRadius As Double = Settings.Get("UiBackgroundBlur") + 1 + Dim BlurRadius As Double = Settings.Get(Of Integer)("UiBackgroundBlur") + 1 If BlurRadius = 1 Then ImgBack.Effect = Nothing Else @@ -705,7 +607,7 @@ Public Class FormMain End If ImgBack.Margin = New Thickness(-BlurRadius / 1.8) '背景图片适应方式 - Dim BackgroundType As Integer = Settings.Get("UiBackgroundSuit") + Dim BackgroundType As Integer = Settings.Get(Of Integer)("UiBackgroundSuit") If ImgBack.Background IsNot Nothing Then Dim Brush As ImageBrush = CType(ImgBack.Background, ImageBrush) If BackgroundType = 0 Then @@ -761,7 +663,7 @@ Public Class FormMain End Select End If '标题栏显示类型 - Select Case Settings.Get("UiLogoType") + Select Case Settings.Get(Of Integer)("UiLogoType") Case 0 '无 ShapeTitleLogo.Visibility = Visibility.Collapsed LabTitleLogo.Visibility = Visibility.Collapsed @@ -802,14 +704,14 @@ Public Class FormMain ImageTitleLogo.Source = PathExeFolder & "PCL\Logo.png" Catch ex As Exception ImageTitleLogo.Source = Nothing - Log(ex, "显示标题栏图片失败", NotifyLevel.MsgBox) + Logger.Error(ex, "显示标题栏图片失败", LogBehavior.Alert) End Try End Select FrmSetupUI?.CardLogo.TriggerForceResize() '标题栏文本 - LabTitleLogo.Text = Settings.Get("UiLogoText") + LabTitleLogo.Text = Settings.Get(Of String)("UiLogoText") '标题栏文本是否居左 - PanTitleMain.ColumnDefinitions(0).Width = New GridLength(If(Settings.Get("UiLogoLeft") AndAlso Settings.Get("UiLogoType") = 0, 0, 1), GridUnitType.Star) + PanTitleMain.ColumnDefinitions(0).Width = New GridLength(If(Settings.Get(Of Boolean)("UiLogoLeft") AndAlso Settings.Get(Of Integer)("UiLogoType") = 0, 0, 1), GridUnitType.Star) End Sub #End Region @@ -900,14 +802,14 @@ Public Class FormMain LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.RunOnUpdated, MaxDepth:=1, ExtraPath:="versions\") End If Catch ex As Exception - Log(ex, "切回窗口时出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "切回窗口时出错") End Try '读取剪贴板,自动加入联机房间 Return 'TODO: 联机复活赛 If PageLinkMain.LinkState <> PageLinkMain.LinkStates.Waiting Then Return '已启动联机 If PageCurrent = PageType.Link Then Return '已在联机界面 Dim Code = ClipboardGetText() : If Code Is Nothing Then Return '剪贴板无文本 - If Settings.Get("LinkLastAutoJoinInviteCode") = Code Then Return + If Settings.Get(Of String)("LinkLastAutoJoinInviteCode") = Code Then Return If PageLinkMain.ValidateCodeFormat(Code) IsNot Nothing Then Return '不是邀请码 Settings.Set("LinkLastAutoJoinInviteCode", Code) RunInThread( @@ -949,9 +851,9 @@ Public Class FormMain End If PrevData = e.Data PrevEffects = e.Effects - Log("[System] 设置拖放类型:" & GetStringFromEnum(e.Effects)) + Logger.Info($"设置拖放类型:{e.Effects}") Catch ex As Exception - Log(ex, "处理拖放时出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "处理拖放时出错") End Try End Sub Private Sub FrmMain_Drop(sender As Object, e As DragEventArgs) Handles Me.Drop @@ -961,13 +863,13 @@ Public Class FormMain '获取文本 Try Dim Str As String = e.Data.GetData(DataFormats.Text) - Log("[System] 接受文本拖拽:" & Str) + Logger.Info($"接受文本拖拽:{Str}") If Str.StartsWithF("authlib-injector:yggdrasil-server:") Then 'Authlib 拖拽 e.Handled = True e.Effects = DragDropEffects.Copy Dim AuthlibServer As String = EscapeUtils.FormUrlUnescape(Str.Substring("authlib-injector:yggdrasil-server:".Length)) - Log("[System] Authlib 拖拽:" & AuthlibServer) + Logger.Info($"Authlib 拖拽:{AuthlibServer}") If Not String.IsNullOrEmpty(New ValidateHttp().Validate(AuthlibServer)) Then Hint($"输入的 Authlib 验证服务器不符合网址格式({AuthlibServer})!", HintType.Red) Return @@ -1014,7 +916,7 @@ Public Class FormMain FileDrag(New List(Of String) From {FilePath}) End If Catch ex As Exception - Log(ex, "无法接取文本拖拽事件", NotifyLevel.DevelopOnly) + Logger.Warn(ex, "无法接取文本拖拽事件") Return End Try ElseIf e.Data.GetDataPresent(DataFormats.FileDrop) Then @@ -1029,26 +931,27 @@ Public Class FormMain FileDrag(CType(FilePathRaw, IEnumerable(Of String))) End If Catch ex As Exception - Log(ex, "接取拖拽事件失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "接取拖拽事件失败") End Try End Sub Private Sub FileDrag(FilePathList As IEnumerable(Of String)) RunInNewThread( Sub() Dim FilePath As String = FilePathList.First - Log("[System] 接受文件拖拽:" & FilePath & If(FilePathList.Any, $" 等 {FilePathList.Count} 个文件", ""), NotifyLevel.DevelopOnly) + Logger.Warn($"接受文件拖拽:{FilePath}{If(FilePathList.Any, $" 等 {FilePathList.Count} 个文件", "")}") '基础检查 - If Directory.Exists(FilePathList.First) AndAlso Not File.Exists(FilePathList.First) Then + If DirectoryUtils.Exists(FilePathList.First) AndAlso Not FileUtils.Exists(FilePathList.First) Then Hint("请拖入一个文件,而非文件夹!", HintType.Red) Return - ElseIf Not File.Exists(FilePathList.First) Then + ElseIf Not FileUtils.Exists(FilePathList.First) Then Hint("拖入的文件不存在:" & FilePathList.First, HintType.Red) Return End If '多文件拖拽 + Dim PathList As List(Of String) = FilePathList.ToList() If FilePathList.Count > 1 Then '必须要求全部为 jar 文件 - For Each File In FilePathList + For Each File In PathList If Not {"jar", "litemod", "disabled", "old"}.Contains(File.AfterLast(".").Lower) Then Hint("一次请只拖入一个文件!", HintType.Red) Return @@ -1058,13 +961,13 @@ Public Class FormMain '主页 Dim Extension As String = FilePath.AfterLast(".").Lower If Extension = "xaml" Then - Log("[System] 文件后缀为 XAML,作为主页加载") - If File.Exists(PathExeFolder & "PCL\Custom.xaml") Then + Logger.Info("文件后缀为 XAML,作为主页加载") + If FileUtils.Exists(PathExeFolder & "PCL\Custom.xaml") Then If MyMsgBox("已存在一个主页文件,是否要将它覆盖?", "覆盖确认", "覆盖", "取消") = 2 Then Return End If End If - CopyFile(FilePath, PathExeFolder & "PCL\Custom.xaml") + FileUtils.Copy(FilePath, PathExeFolder & "PCL\Custom.xaml") RunInUi( Sub() Settings.Set("UiCustomType", 1) @@ -1074,10 +977,10 @@ Public Class FormMain Return End If '安装 Mod - If PageInstanceMod.InstallMods(FilePathList) Then Return + If PageInstanceMod.InstallMods(PathList) Then Return '安装整合包 If {"zip", "rar", "mrpack"}.Any(Function(t) t = Extension) Then '部分压缩包是 zip 格式但后缀为 rar,总之试一试 - Log("[System] 文件为压缩包,尝试作为整合包安装") + Logger.Info("文件为压缩包,尝试作为整合包安装") Try ModpackInstall(FilePath) Return @@ -1094,7 +997,7 @@ Public Class FormMain End If '错误报告分析 Try - Log("[System] 尝试进行错误报告分析") + Logger.Info("尝试进行错误报告分析") Dim Analyzer As New CrashAnalyzer Analyzer.Import(FilePath) If Not Analyzer.Prepare() Then Exit Try @@ -1102,7 +1005,7 @@ Public Class FormMain Analyzer.Output(True, New List(Of String)) Return Catch ex As Exception - Log(ex, "自主错误报告分析失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "自主错误报告分析失败") End Try '未知操作 Hint("PCL 无法确定应当执行的文件拖拽操作……") @@ -1115,16 +1018,16 @@ Public Class FormMain If msg = 30 Then Dim NowDate = Date.Now If NowDate.Date = ApplicationOpenTime.Date Then - Log("[System] 系统时间微调为:" & NowDate.ToLongDateString & " " & NowDate.ToLongTimeString) + Logger.Info($"系统时间微调为:{NowDate.ToLongDateString} {NowDate.ToLongTimeString}") IsSystemTimeChanged = False Else - Log("[System] 系统时间修改为:" & NowDate.ToLongDateString & " " & NowDate.ToLongTimeString) + Logger.Info($"系统时间修改为:{NowDate.ToLongDateString} {NowDate.ToLongTimeString}") IsSystemTimeChanged = True End If ElseIf msg = 400 * 16 + 2 Then - Log("[System] 收到置顶信息:" & hwnd.ToInt64) + Logger.Info($"收到置顶信息:{hwnd.ToInt64}") If Not IsWindowLoadFinished Then - Log("[System] 窗口尚未加载完成,忽略置顶请求") + Logger.Info("窗口尚未加载完成,忽略置顶请求") Return IntPtr.Zero End If ShowWindowToTop() @@ -1147,7 +1050,7 @@ Public Class FormMain Left -= 10000 ShowInTaskbar = False Visibility = Visibility.Hidden - Log("[System] 窗口已隐藏,位置:(" & Left & "," & Top & ")") + Logger.Info($"窗口已隐藏,位置:({Left},{Top})") Else '取消隐藏 If Left < -2000 Then Left += 10000 @@ -1170,7 +1073,7 @@ Public Class FormMain Topmost = False SetForegroundWindow(Handle) Focus() - Log($"[System] 窗口已置顶,位置:({Left}, {Top}), {Width} x {Height}") + Logger.Info($"窗口已置顶,位置:({Left}, {Top}), {Width} x {Height}") End Sub) End Sub @@ -1501,9 +1404,9 @@ Public Class FormMain BtnExtraApril.ShowRefresh() #End Region - Log("[Control] 切换主要页面:" & GetStringFromEnum(Stack) & ", " & SubType) + Logger.Info($"切换主要页面:{Stack}, {SubType}") Catch ex As Exception - Log(ex, "切换主要页面失败(ID " & PageCurrent.Page & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"切换主要页面失败(ID {PageCurrent.Page})") Finally AniControlEnabled -= 1 End Try @@ -1686,7 +1589,7 @@ Public Class FormMain Next Hint("已关闭运行中的 Minecraft!", HintType.Green) Catch ex As Exception - Log(ex, "强制关闭所有 Minecraft 失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "强制关闭所有 Minecraft 失败") End Try End Sub Public Function BtnExtraShutdown_ShowCheck() As Boolean @@ -1701,7 +1604,7 @@ Public Class FormMain If RealScroll IsNot Nothing Then RealScroll.PerformVerticalOffsetDelta(-RealScroll.VerticalOffset) Else - Log("[UI] 无法返回顶部,未找到合适的 RealScroll", NotifyLevel.AllUsers) + Logger.Error("无法返回顶部,未找到合适的 RealScroll", LogBehavior.Toast) End If End Sub Private Function BtnExtraBack_ShowCheck() As Boolean diff --git a/Plain Craft Launcher 2/Modules/Base/ModAnimation.vb b/Plain Craft Launcher 2/Modules/Base/ModAnimation.vb index 25092a6..4223717 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModAnimation.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModAnimation.vb @@ -12,7 +12,7 @@ Public Module ModAnimation ''' Public ReadOnly Property AniSpeed As Double Get - Dim Setting As Integer = Settings.Get("SystemDebugAnim") + Dim Setting As Integer = Settings.Get(Of Integer)("SystemDebugAnim") Return If(Setting >= 30, 200, (Setting * 0.1 + 0.1).Clamp(0.1, 3)) End Get End Property @@ -114,7 +114,7 @@ Public Module ModAnimation Public ValueLast As Object Public Overrides Function ToString() As String - Return GetStringFromEnum(TypeMain) & " | " & TimeFinished & "/" & TimeTotal & "(" & Math.Round(TimePercent * 100) & "%)" & If(Obj Is Nothing, "", " | " & Obj.ToString & "(" & Obj.GetType.Name & ")") + Return TypeMain.ToString() & " | " & TimeFinished & "/" & TimeTotal & "(" & Math.Round(TimePercent * 100) & "%)" & If(Obj Is Nothing, "", " | " & Obj.ToString & "(" & Obj.GetType.Name & ")") End Function End Structure @@ -521,13 +521,14 @@ Public Module ModAnimation ''' ''' Public Function AaStack(Stack As StackPanel, Optional Time As Integer = 100, Optional Delay As Integer = 25) As List(Of AniData) - AaStack = New List(Of AniData) + Dim Result = New List(Of AniData) Dim AniDelay As Integer = 0 For Each Item In Stack.Children Item.Opacity = 0 - AaStack.Add(AaOpacity(Item, 1, Time, AniDelay)) + Result.Add(AaOpacity(Item, 1, Time, AniDelay)) AniDelay += Delay Next + Return Result End Function #End Region @@ -810,7 +811,7 @@ Public Module ModAnimation RunInNewThread( Sub() Try - Log("[Animation] 动画线程开始") + Logger.Info("动画线程开始") Do While True '两帧之间的间隔时间 Dim DeltaTime As Long = (GetTimeMs() - AniLastTick).Clamp(0, 100000) @@ -831,7 +832,7 @@ Public Module ModAnimation AniCount = 0 AniTimer(DeltaTime * AniSpeed) If RandomInteger(0, 64 * If(ModeDebug, 5, 30)) = 0 AndAlso ((AniFPS < 62 AndAlso AniFPS > 0) OrElse AniCount > 4 OrElse NetManager.FileRemain <> 0) Then - Log("[Report] FPS " & AniFPS & ", 动画 " & AniCount & ", 下载中 " & NetManager.FileRemain & "(" & FormatFileSize(NetManager.Speed) & "/s)") + Logger.Info($"FPS {AniFPS}, 动画 {AniCount}, 下载中 {NetManager.FileRemain}({FormatFileSize(NetManager.Speed)}/s)") End If End Sub) Sleeper: @@ -839,7 +840,7 @@ Sleeper: Thread.Sleep(1) Loop Catch ex As Exception - Log(ex, "动画帧执行失败", NotifyLevel.Critical) + Logger.Error(ex, "动画帧执行失败", LogBehavior.AlertThenCrash) End Try End Sub, "Animation", ThreadPriority.AboveNormal) End Sub @@ -850,7 +851,7 @@ Sleeper: Public Sub AniTimer(DeltaTick As Integer) Try - If DeltaTick / AniSpeed > 100 Then Log("[Animation] 两个动画帧间隔 " & DeltaTick & " ms", NotifyLevel.DevelopOnly) + If DeltaTick / AniSpeed > 100 Then Logger.Info($"两个动画帧间隔 {DeltaTick} ms") Dim i As Integer = -1 '循环每个动画组 Do While i + 1 < AniGroups.Count @@ -915,7 +916,7 @@ NextAni: Loop Catch ex As Exception - Log(ex, "动画刻执行失败", NotifyLevel.AllUsers) + Logger.Error(ex, "动画刻执行失败", LogBehavior.Toast) End Try End Sub @@ -1052,7 +1053,7 @@ NextAni: End Select Ani.TimePercent = Ani.TimeFinished / Ani.TimeTotal '修改执行百分比 Catch ex As Exception - Log(ex, "执行动画失败:" & Ani.ToString, NotifyLevel.AllUsers) + Logger.Error(ex, $"执行动画失败:{Ani}", LogBehavior.Toast) End Try Return Ani End Function diff --git a/Plain Craft Launcher 2/Modules/Base/ModBase.vb b/Plain Craft Launcher 2/Modules/Base/ModBase.vb index 286349a..4ab2286 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModBase.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModBase.vb @@ -1,9 +1,6 @@ Imports System.Globalization -Imports System.Net.Sockets Imports System.Runtime.CompilerServices Imports System.Security.Cryptography -Imports System.Security.Principal -Imports System.Text.RegularExpressions Imports System.Threading.Tasks Imports System.Xaml Imports Newtonsoft.Json @@ -13,12 +10,12 @@ Public Module ModBase #Region "声明" '下列版本信息由更新器自动修改 - Public Const VersionBaseName As String = "2.12.7.3" '显示用版本名 + Public Const VersionBaseName As String = "2.12.8.0" '显示用版本名 Public Const CommitHash As String = "" 'Commit Hash,由 GitHub Workflow 自动替换 #If RELEASE Then - Public Const VersionCode As Integer = 398 '正式版 + Public Const VersionCode As Integer = 400 '正式版 #Else - Public Const VersionCode As Integer = 397 '快照版 + Public Const VersionCode As Integer = 399 '快照版 #End If '版本信息 @@ -58,7 +55,7 @@ Public Module ModBase ''' ''' 程序的缓存文件夹路径,以 \ 结尾。 ''' - Public PathTemp As String = If(Settings.Get("SystemSystemCache") = "", Path.GetTempPath() & "PCL\", Settings.Get("SystemSystemCache")).ToString.Replace("/", "\").TrimEnd("\") & "\" + Public PathTemp As String = If(Settings.Get(Of String)("SystemSystemCache") = "", Path.GetTempPath() & "PCL\", Settings.Get(Of String)("SystemSystemCache")).ToString.Replace("/", "\").TrimEnd("\") & "\" ''' ''' AppData 中的 PCL 文件夹路径,以 \ 结尾。 ''' @@ -80,9 +77,9 @@ Public Module ModBase ''' Public Identify As String = GetIdentify() ''' - ''' 程序是否已结束。 + ''' 程序是否正在结束。 ''' - Public IsProgramEnded As Boolean = False + Public IsProgramEnding As Boolean = False ''' ''' 是否为 32 位系统。 ''' @@ -96,6 +93,12 @@ Public Module ModBase ''' Public OsDrive As String = Environment.GetLogicalDrives().Where(Function(p) Directory.Exists(p)).First.Upper.First & ":\" '#3799 + Public ReadOnly Property ModeDebug As Boolean + Get + Return Settings.Get(Of Boolean)("SystemDebugMode") + End Get + End Property + #End Region #Region "矢量图标" @@ -213,22 +216,22 @@ Public Module ModBase Return New MyColor(col) End Operator Public Shared Widening Operator CType(conv As MyColor) As Color - Return Color.FromArgb(DoubleToByte(conv.A), DoubleToByte(conv.R), DoubleToByte(conv.G), DoubleToByte(conv.B)) + Return Color.FromArgb(ClampToByte(conv.A), ClampToByte(conv.R), ClampToByte(conv.G), ClampToByte(conv.B)) End Operator Public Shared Widening Operator CType(conv As MyColor) As System.Drawing.Color - Return System.Drawing.Color.FromArgb(DoubleToByte(conv.A), DoubleToByte(conv.R), DoubleToByte(conv.G), DoubleToByte(conv.B)) + Return System.Drawing.Color.FromArgb(ClampToByte(conv.A), ClampToByte(conv.R), ClampToByte(conv.G), ClampToByte(conv.B)) End Operator Public Shared Widening Operator CType(bru As SolidColorBrush) As MyColor Return New MyColor(bru.Color) End Operator Public Shared Widening Operator CType(conv As MyColor) As SolidColorBrush - Return New SolidColorBrush(Color.FromArgb(DoubleToByte(conv.A), DoubleToByte(conv.R), DoubleToByte(conv.G), DoubleToByte(conv.B))) + Return New SolidColorBrush(Color.FromArgb(ClampToByte(conv.A), ClampToByte(conv.R), ClampToByte(conv.G), ClampToByte(conv.B))) End Operator Public Shared Widening Operator CType(bru As Brush) As MyColor Return New MyColor(bru) End Operator Public Shared Widening Operator CType(conv As MyColor) As Brush - Return New SolidColorBrush(Color.FromArgb(DoubleToByte(conv.A), DoubleToByte(conv.R), DoubleToByte(conv.G), DoubleToByte(conv.B))) + Return New SolidColorBrush(Color.FromArgb(ClampToByte(conv.A), ClampToByte(conv.R), ClampToByte(conv.G), ClampToByte(conv.B))) End Operator '颜色运算 @@ -266,7 +269,7 @@ Public Module ModBase ''' ''' 将一个数字限制为 0~255 的 Byte 值。 ''' - Public Shared Function DoubleToByte(d As Double) As Byte + Public Shared Function ClampToByte(d As Double) As Byte If d < 0 Then d = 0 If d > 255 Then d = 255 Return Math.Round(d) @@ -351,46 +354,45 @@ Public Module ModBase Return v1 End Function Public Function FromHSL(sH As Double, sS As Double, sL As Double) As MyColor - If sS = 0 Then - R = sL * 2.55 - G = R - B = R - Else - Dim H = sH / 360 - Dim S = sS / 100 - Dim L = sL / 100 - S = If(L < 0.5, S * L + L, S * (1.0 - L) + L) - L = 2 * L - S - R = 255 * Hue(L, S, H + 1 / 3) - G = 255 * Hue(L, S, H) - B = 255 * Hue(L, S, H - 1 / 3) - End If A = 255 + If sS = 0 Then + R = sL * 2.55 : G = R : B = R + Return Me + End If + + Dim H = sH / 360 + Dim S = sS / 100 + Dim L = sL / 100 + S = If(L < 0.5, S * L + L, S * (1.0 - L) + L) + L = 2 * L - S + R = 255 * Hue(L, S, H + 1 / 3) + G = 255 * Hue(L, S, H) + B = 255 * Hue(L, S, H - 1 / 3) Return Me End Function Public Function FromHSL2(sH As Double, sS As Double, sL As Double) As MyColor + A = 255 If sS = 0 Then R = sL * 2.55 : G = R : B = R - Else - '初始化 - sH = (sH + 3600000) Mod 360 - Dim cent As Double() = { - +0.1, -0.06, -0.3, '0, 30, 60 - -0.19, -0.15, -0.24, '90, 120, 150 - -0.32, -0.09, +0.18, '180, 210, 240 - +0.05, -0.12, -0.02, '270, 300, 330 - +0.1, -0.06} '最后两位与前两位一致,加是变亮,减是变暗 - '计算色调对应的亮度片区 - Dim center As Double = sH / 30.0 - Dim intCenter As Integer = Math.Floor(center) '亮度片区编号 - center = 50 - ( - (1 - center + intCenter) * cent(intCenter) + (center - intCenter) * cent(intCenter + 1) - ) * sS - 'center = 50 + (cent(intCenter) + (center - intCenter) * (cent(intCenter + 1) - cent(intCenter))) * sS - sL = If(sL < center, sL / center, 1 + (sL - center) / (100 - center)) * 50 - FromHSL(sH, sS, sL) + Return Me End If - A = 255 + + '初始化 + sH = (sH + 3600000) Mod 360 + Dim cent As Double() = { + +0.1, -0.06, -0.3, '0, 30, 60 + -0.19, -0.15, -0.24, '90, 120, 150 + -0.32, -0.09, +0.18, '180, 210, 240 + +0.05, -0.12, -0.02, '270, 300, 330 + +0.1, -0.06} '最后两位与前两位一致,加是变亮,减是变暗 + '计算色调对应的亮度片区 + Dim center As Double = sH / 30.0 + Dim intCenter As Integer = Math.Floor(center) '亮度片区编号 + center = 50 - ( + (1 - center + intCenter) * cent(intCenter) + (center - intCenter) * cent(intCenter + 1) + ) * sS + sL = If(sL < center, sL / center, 1 + (sL - center) / (100 - center)) * 50 + FromHSL(sH, sS, sL) Return Me End Function @@ -467,33 +469,6 @@ Public Module ModBase TaskDone = 5 End Enum - ''' - ''' 可以使用 Equals 和等号的 List。 - ''' - Public Class EqualableList(Of T) - Inherits List(Of T) - Public Overrides Function Equals(obj As Object) As Boolean - If TryCast(obj, List(Of T)) Is Nothing Then - '类型不同 - Return False - Else - '类型相同 - Dim objList As List(Of T) = obj - If objList.Count <> Count Then Return False - For i = 0 To objList.Count - 1 - If Not objList(i).Equals(Me(i)) Then Return False - Next - Return True - End If - End Function - Public Shared Operator =(left As EqualableList(Of T), right As EqualableList(Of T)) As Boolean - Return EqualityComparer(Of EqualableList(Of T)).Default.Equals(left, right) - End Operator - Public Shared Operator <>(left As EqualableList(Of T), right As EqualableList(Of T)) As Boolean - Return Not left = right - End Operator - End Class - #End Region #Region "文件" @@ -509,7 +484,7 @@ Public Module ModBase Try Return If(My.Computer.Registry.CurrentUser.OpenSubKey("Software\" & RegFolder, False)?.GetValue(Key), DefaultValue) Catch ex As Exception - Log(ex, "读取注册表出错:" & Key, NotifyLevel.AllUsers) + Logger.Error(ex, $"读取注册表出错:{Key}", LogBehavior.Toast) Return DefaultValue End Try End Function @@ -522,7 +497,7 @@ Public Module ModBase If SubKey Is Nothing Then SubKey = My.Computer.Registry.CurrentUser.CreateSubKey("Software\" & RegFolder) '如果不存在就创建 SubKey.SetValue(Key, Value) Catch ex As Exception - Log(ex, "写入注册表出错:" & Key, If(ThrowException, NotifyLevel.AllUsers, NotifyLevel.DevelopOnly)) + Logger.Warn(ex, $"写入注册表出错:{Key}", If(ThrowException, LogBehavior.Toast, LogBehavior.ToastIfDebug)) If ThrowException Then Throw End Try End Sub @@ -541,7 +516,7 @@ Public Module ModBase If SubKey?.GetValue(Key) Is Nothing Then Return SubKey.DeleteValue(Key) Catch ex As Exception - Log(ex, "删除注册表出错:" & Key, If(ThrowException, NotifyLevel.AllUsers, NotifyLevel.DevelopOnly)) + Logger.Warn(ex, $"删除注册表出错:{Key}", If(ThrowException, LogBehavior.Toast, LogBehavior.ToastIfDebug)) If ThrowException Then Throw End Try End Sub @@ -572,16 +547,16 @@ Public Module ModBase Dim Cache As ConcurrentDictionary(Of String, String) = Nothing If IniCache.TryGetValue(FileName, Cache) Then Return Cache '读取文件 - If Not File.Exists(FileName) Then Return Nothing + If Not FileUtils.Exists(FileName) Then Return Nothing Dim Ini As New ConcurrentDictionary(Of String, String) - For Each Line In ReadFile(FileName).Split(vbCrLf.ToArray(), StringSplitOptions.RemoveEmptyEntries) + For Each Line In FileUtils.ReadAsLines(FileName, True) Dim Index As Integer = Line.IndexOfF(":") If Index > 0 Then Ini(Line.Substring(0, Index)) = Line.Substring(Index + 1) '可能会有重复键,见 #3616 Next IniCache(FileName) = Ini Return Ini Catch ex As Exception - Log(ex, $"生成 ini 文件缓存失败({FileName})", NotifyLevel.AllUsers) + Logger.Error(ex, $"生成 ini 文件缓存失败({FileName})", LogBehavior.Toast) Return Nothing End Try End Function @@ -646,248 +621,10 @@ Public Module ModBase FileName = If(FileName.Contains(":\"), FileName, PathExeFolder & FileName) FileUtils.Write(FileName, FileContent.ToString) Catch ex As Exception - Log(ex, $"写入文件失败({FileName} → {Key}:{Value})", NotifyLevel.AllUsers) + Logger.Error(ex, $"写入文件失败({FileName} → {Key}:{Value})", LogBehavior.Toast) End Try End Sub - '路径处理 - ''' - ''' 从文件路径或者 URL 获取不包含文件名的路径,或获取文件夹的父文件夹路径。 - ''' 取决于原路径格式,路径以 / 或 \ 结尾。 - ''' 不包含路径将会抛出异常。 - ''' - Public Function GetPathFromFullPath(FullName As String) As String - If String.IsNullOrEmpty(FullName) OrElse Not (FullName.Contains("\") OrElse FullName.Contains("/")) Then Throw New ArgumentException("参数不包含路径:" & FullName) - If FullName.EndsWithF("\") OrElse FullName.EndsWithF("/") Then - '是文件夹路径 - Dim IsRight As Boolean = FullName.EndsWithF("\") - FullName = Left(FullName, Len(FullName) - 1) - GetPathFromFullPath = Left(FullName, FullName.LastIndexOfAny({"\", "/"})) & If(IsRight, "\", "/") - Else - '是文件路径 - GetPathFromFullPath = Left(FullName, FullName.LastIndexOfAny({"\", "/"}) + 1) - If GetPathFromFullPath = "" Then Throw New Exception("不包含路径:" & FullName) - End If - End Function - ''' - ''' 从文件路径或者 Url 获取不包含路径的文件名。不包含文件名将会抛出异常。 - ''' - Public Function GetFileNameFromPath(FilePath As String) As String - FilePath = FilePath.Replace("/", "\") - If FilePath.EndsWithF("\") Then Throw New Exception("不包含文件名:" & FilePath) - If FilePath.Contains("?") Then FilePath = FilePath.Substring(0, FilePath.IndexOfF("?")) '去掉网络参数后的 ? - If FilePath.Contains("\") Then FilePath = FilePath.Substring(FilePath.LastIndexOfF("\") + 1) - Dim length As Integer = FilePath.Length - If length = 0 Then Throw New Exception("不包含文件名:" & FilePath) - Return FilePath - End Function - ''' - ''' 从文件夹路径获取文件夹名。 - ''' - Public Function GetFolderNameFromPath(FolderPath As String) As String - If FolderPath.EndsWithF(":\") OrElse FolderPath.EndsWithF(":\\") Then Return FolderPath.Substring(0, 1) - If FolderPath.EndsWithF("\") OrElse FolderPath.EndsWithF("/") Then FolderPath = Left(FolderPath, FolderPath.Length - 1) - Return GetFileNameFromPath(FolderPath) - End Function - - '读取、复制文件 - ''' - ''' 复制文件。会自动创建文件夹、会覆盖已有的文件。 - ''' - Public Sub CopyFile(FromPath As String, ToPath As String) - Try - '还原文件路径 - FromPath = If(FromPath.Contains(":\"), FromPath, PathExeFolder & FromPath) - ToPath = If(ToPath.Contains(":\"), ToPath, PathExeFolder & ToPath) - '如果复制同一个文件则跳过 - If FromPath = ToPath Then Return - '确保目录存在 - DirectoryUtils.Create(ToPath, isFilePath:=True) - '复制文件 - File.Copy(FromPath, ToPath, True) - Catch ex As Exception - Throw New Exception("复制文件出错:" & FromPath & " → " & ToPath, ex) - End Try - End Sub - ''' - ''' 读取文件,如果失败则返回空数组。 - ''' - Public Function ReadFileBytes(FilePath As String, Optional Encoding As Encoding = Nothing) As Byte() - Try - '还原文件路径 - If Not FilePath.Contains(":\") Then FilePath = PathExeFolder & FilePath - If File.Exists(FilePath) Then - Dim FileBytes As Byte() - Using ReadStream As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) '支持读取使用中的文件 - ReDim FileBytes(ReadStream.Length - 1) - ReadStream.Read(FileBytes, 0, ReadStream.Length) - End Using - Return FileBytes - Else - Log("[System] 欲读取的文件不存在,已返回空内容:" & FilePath) - Return {} - End If - Catch ex As Exception - Log(ex, "读取文件出错:" & FilePath) - Return {} - End Try - End Function - ''' - ''' 读取文件,如果失败则返回空字符串。 - ''' - ''' 文件完整或相对路径。 - Public Function ReadFile(FilePath As String, Optional Encoding As Encoding = Nothing) As String - Dim FileBytes = ReadFileBytes(FilePath) - ReadFile = If(Encoding Is Nothing, DecodeBytes(FileBytes), Encoding.GetString(FileBytes)) - End Function - ''' - ''' 读取流中的所有文本。 - ''' - Public Function ReadFile(Stream As Stream, Optional Encoding As Encoding = Nothing) As String - Try - Dim srcBuf As Byte() = New Byte(16384) {} - Dim DataCount As Integer = Stream.Read(srcBuf, 0, 16384) - Dim Result As New List(Of Byte) - While DataCount > 0 - If DataCount > 0 Then Result.AddRange(srcBuf.ToList.GetRange(0, DataCount)) - DataCount = Stream.Read(srcBuf, 0, 16384) - End While - Dim Bts = Result.ToArray - Return If(Encoding, GetEncoding(Bts)).GetString(Bts) - Catch ex As Exception - Log(ex, "读取流出错") - Return "" - End Try - End Function - - '文件编码 - ''' - ''' 根据字节数组分析其编码。 - ''' - Public Function GetEncoding(Bytes As Byte()) As Encoding - Dim Length As Integer = Bytes.Count - If Length < 3 Then Return New UTF8Encoding(False) '不带 BOM 的 UTF8 - '根据 BOM 判断编码 - If Bytes(0) >= &HEF Then - '有 BOM 类型 - If Bytes(0) = &HEF AndAlso Bytes(1) = &HBB Then - Return New UTF8Encoding(True) '带 BOM 的 UTF8 - ElseIf Bytes(0) = &HFE AndAlso Bytes(1) = &HFF Then - Return Encoding.BigEndianUnicode - ElseIf Bytes(0) = &HFF AndAlso Bytes(1) = &HFE Then - Return Encoding.Unicode - Else - Return Encoding.GetEncoding("GB18030") - End If - End If - '无 BOM 文件:GB18030(ANSI)或 UTF8 - Dim UTF8 = Encoding.UTF8.GetString(Bytes) - Dim ErrorChar As Char = Encoding.UTF8.GetString({239, 191, 189}).ToCharArray()(0) - If UTF8.Contains(ErrorChar) Then - Return Encoding.GetEncoding("GB18030") - Else - Return New UTF8Encoding(False) '不带 BOM 的 UTF8 - End If - End Function - ''' - ''' 解码 Bytes。 - ''' - Public Function DecodeBytes(Bytes As Byte()) As String - Dim Length As Integer = Bytes.Length - If Length < 3 Then Return Encoding.UTF8.GetString(Bytes) - '根据 BOM 判断编码 - If Bytes(0) >= &HEF Then - '有 BOM 类型 - If Bytes(0) = &HEF AndAlso Bytes(1) = &HBB Then - Return Encoding.UTF8.GetString(Bytes, 3, Length - 3) - ElseIf Bytes(0) = &HFE AndAlso Bytes(1) = &HFF Then - Return Encoding.BigEndianUnicode.GetString(Bytes, 3, Length - 3) - ElseIf Bytes(0) = &HFF AndAlso Bytes(1) = &HFE Then - Return Encoding.Unicode.GetString(Bytes, 3, Length - 3) - Else - Return Encoding.GetEncoding("GB18030").GetString(Bytes, 3, Length - 3) - End If - End If - '无 BOM 文件:GB18030(ANSI)或 UTF8 - Dim UTF8 = Encoding.UTF8.GetString(Bytes) - Dim ErrorChar As Char = Encoding.UTF8.GetString({239, 191, 189}).ToCharArray()(0) - If UTF8.Contains(ErrorChar) Then - Return Encoding.GetEncoding("GB18030").GetString(Bytes) - Else - Return UTF8 - End If - End Function - - '对话框 - ''' - ''' 弹出保存对话框并且要求保存位置,返回用户输入的完整路径。 - ''' - ''' 要求的格式。如:“常用图片文件(*.png;*.jpg)|*.png;*.jpg”。 - ''' 弹窗的标题。 - ''' 默认的文件名。 - Public Function SelectSaveFile(Title As String, FileName As String, Optional FileFilter As String = Nothing, Optional InitialDirectory As String = Nothing) As String - Using fileDialog As New Forms.SaveFileDialog - fileDialog.AddExtension = True - fileDialog.AutoUpgradeEnabled = True - fileDialog.Title = Title - fileDialog.FileName = FileName - If FileFilter IsNot Nothing Then fileDialog.Filter = FileFilter - If Not String.IsNullOrEmpty(InitialDirectory) AndAlso Directory.Exists(InitialDirectory) Then fileDialog.InitialDirectory = InitialDirectory - fileDialog.ShowDialog() - SelectSaveFile = If(fileDialog.FileName.Contains(":\"), fileDialog.FileName, "") - Log("[UI] 选择文件返回:" & SelectSaveFile) - End Using - End Function - ''' - ''' 弹出选取文件对话框,要求选择一个文件。 - ''' - ''' 要求的格式。如:“常用图片文件(*.png;*.jpg)|*.png;*.jpg”。 - ''' 弹窗的标题。 - Public Function SelectFile(FileFilter As String, Title As String, Optional InitialDirectory As String = Nothing) As String - Using fileDialog As New Forms.OpenFileDialog - fileDialog.AddExtension = True - fileDialog.AutoUpgradeEnabled = True - fileDialog.CheckFileExists = True - fileDialog.Filter = FileFilter - fileDialog.Multiselect = False - fileDialog.Title = Title - fileDialog.ValidateNames = True - If Not String.IsNullOrEmpty(InitialDirectory) AndAlso Directory.Exists(InitialDirectory) Then fileDialog.InitialDirectory = InitialDirectory - fileDialog.ShowDialog() - Log("[UI] 选择单个文件返回:" & fileDialog.FileName) - Return fileDialog.FileName - End Using - End Function - ''' - ''' 弹出选取文件对话框,要求选择多个文件。 - ''' - ''' 要求的格式。如:“常用图片文件(*.png;*.jpg)|*.png;*.jpg”。 - ''' 弹窗的标题。 - Public Function SelectFiles(FileFilter As String, Title As String) As String() - Using fileDialog As New Forms.OpenFileDialog - fileDialog.AddExtension = True - fileDialog.AutoUpgradeEnabled = True - fileDialog.CheckFileExists = True - fileDialog.Filter = FileFilter - fileDialog.Multiselect = True - fileDialog.Title = Title - fileDialog.ValidateNames = True - fileDialog.ShowDialog() - Log("[UI] 选择多个文件返回:" & fileDialog.FileNames.Join(",")) - Return fileDialog.FileNames - End Using - End Function - ''' - ''' 弹出选取文件夹对话框,要求选取文件夹。 - ''' 返回以 \ 结尾的完整路径,如果没有选择则返回空字符串。 - ''' - Public Function SelectFolder(Optional Title As String = "选择文件夹") As String - Dim folderDialog As New Ookii.Dialogs.Wpf.VistaFolderBrowserDialog With {.ShowNewFolderButton = True, .RootFolder = Environment.SpecialFolder.Desktop, .Description = Title, .UseDescriptionForTitle = True} - folderDialog.ShowDialog() - SelectFolder = If(String.IsNullOrEmpty(folderDialog.SelectedPath), "", folderDialog.SelectedPath & If(folderDialog.SelectedPath.EndsWithF("\"), "", "\")) - Log("[UI] 选择文件夹返回:" & SelectFolder) - End Function - '文件校验 ''' ''' 检查是否拥有某一文件夹的 I/O 权限。如果文件夹不存在,会返回 False。 @@ -895,16 +632,15 @@ Public Module ModBase Public Function CheckPermission(Folder As String) As Boolean Try If String.IsNullOrEmpty(Folder) Then Return False - If Not Folder.EndsWithF("\") Then Folder += "\" + Folder = PathUtils.AddSlashSuffix(Folder) If Folder.EndsWithF(":\System Volume Information\") OrElse Folder.EndsWithF(":\$RECYCLE.BIN\") Then Return False - If Not Directory.Exists(Folder) Then Return False - Dim FileName As String = "CheckPermission" & GetUuid() - If File.Exists(Folder & FileName) Then File.Delete(Folder & FileName) - File.Create(Folder & FileName).Dispose() - File.Delete(Folder & FileName) + If Not DirectoryUtils.Exists(Folder) Then Return False + Dim TestFilePath As String = $"{Folder}CheckPermission{GetUuid()}.txt" + FileUtils.Write(TestFilePath, "临时文件,用于检测该文件夹的权限是否正常。") + FileUtils.Delete(TestFilePath) Return True Catch ex As Exception - Log(ex, "没有对文件夹 " & Folder & " 的权限,请尝试以管理员权限运行 PCL") + Logger.Warn(ex, $"没有对文件夹 {Folder} 的权限,请尝试以管理员权限运行 PCL") Return False End Try End Function @@ -913,108 +649,13 @@ Public Module ModBase ''' Public Sub CheckPermissionWithException(Folder As String) If String.IsNullOrWhiteSpace(Folder) Then Throw New ArgumentNullException("文件夹名不能为空!") - If Not Folder.EndsWithF("\") Then Folder += "\" - If Not Directory.Exists(Folder) Then Throw New DirectoryNotFoundException("文件夹不存在!") - If File.Exists(Folder & "CheckPermission") Then File.Delete(Folder & "CheckPermission") - File.Create(Folder & "CheckPermission").Dispose() - File.Delete(Folder & "CheckPermission") + Folder = PathUtils.AddSlashSuffix(Folder) + If Folder.EndsWithF(":\System Volume Information\") OrElse Folder.EndsWithF(":\$RECYCLE.BIN\") Then Throw New UnauthorizedAccessException("没有对系统文件夹的权限!") + If Not DirectoryUtils.Exists(Folder) Then Throw New DirectoryNotFoundException("文件夹不存在!") + Dim TestFilePath As String = $"{Folder}CheckPermission{GetUuid()}.txt" + FileUtils.Write(TestFilePath, "临时文件,用于检测该文件夹的权限是否正常。") + FileUtils.Delete(TestFilePath) End Sub - ''' - ''' 获取文件 MD5,若失败则返回空字符串。 - ''' - Public Function GetFileMD5(FilePath As String) As String - Dim Retried As Boolean = False -Re: - Try - Using File As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) - Using h = MD5Cng.Create() - Return BitConverter.ToString(h.ComputeHash(File)).Replace("-", "").Lower() - End Using - End Using - Catch ex As Exception - If Retried OrElse TypeOf ex Is FileNotFoundException Then - Log(ex, "获取文件 MD5 失败:" & FilePath) - Return "" - Else - Retried = True - Log(ex, "获取文件 MD5 可重试失败:" & FilePath, NotifyLevel.Silent) - Thread.Sleep(RandomInteger(200, 500)) - GoTo Re - End If - End Try - End Function - ''' - ''' 获取文件 SHA512,若失败则返回空字符串。 - ''' - Public Function GetFileSHA512(FilePath As String) As String - Dim Retried As Boolean = False -Re: - Try - Using File As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) - Using h = SHA512Cng.Create() - Return BitConverter.ToString(h.ComputeHash(File)).Replace("-", "").Lower() - End Using - End Using - Catch ex As Exception - If Retried OrElse TypeOf ex Is FileNotFoundException Then - Log(ex, "获取文件 SHA512 失败:" & FilePath) - Return "" - Else - Retried = True - Log(ex, "获取文件 SHA512 可重试失败:" & FilePath, NotifyLevel.Silent) - Thread.Sleep(RandomInteger(200, 500)) - GoTo Re - End If - End Try - End Function - ''' - ''' 获取文件 SHA256,若失败则返回空字符串。 - ''' - Public Function GetFileSHA256(FilePath As String) As String - Dim Retry As Boolean = False -Re: - Try - Using File As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) - Using h = SHA256Cng.Create() - Return BitConverter.ToString(h.ComputeHash(File)).Replace("-", "").Lower() - End Using - End Using - Catch ex As Exception - If Retry OrElse TypeOf ex Is FileNotFoundException Then - Log(ex, "获取文件 SHA256 失败:" & FilePath) - Return "" - Else - Retry = True - Log(ex, "获取文件 SHA256 可重试失败:" & FilePath, NotifyLevel.Silent) - Thread.Sleep(RandomInteger(200, 500)) - GoTo Re - End If - End Try - End Function - ''' - ''' 获取文件 SHA1,若失败则返回空字符串。 - ''' - Public Function GetFileSHA1(FilePath As String) As String - Dim Retry As Boolean = False -Re: - Try - Using File As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) - Using h = SHA1Cng.Create() - Return BitConverter.ToString(h.ComputeHash(File)).Replace("-", "").Lower() - End Using - End Using - Catch ex As Exception - If Retry OrElse TypeOf ex Is FileNotFoundException Then - Log(ex, "获取文件 SHA1 失败:" & FilePath) - Return "" - Else - Retry = True - Log(ex, "获取文件 SHA1 可重试失败:" & FilePath, NotifyLevel.Silent) - Thread.Sleep(RandomInteger(200, 500)) - GoTo Re - End If - End Try - End Function ''' ''' 文件的校验规则。 @@ -1056,28 +697,31 @@ Re: ''' Public Function Check(LocalPath As String) As String Try - Dim Info As New FileInfo(LocalPath) + Dim Info = FileUtils.GetInfo(LocalPath) If Not Info.Exists Then Return "文件不存在:" & LocalPath Dim FileSize As Long = Info.Length If ActualSize >= 0 AndAlso ActualSize <> FileSize Then Return $"文件大小应为 {ActualSize} B,实际为 {FileSize} B" & - If(FileSize < 2000, ",内容为:" & ReadFile(LocalPath), "") + If(FileSize < 2000, ",内容为:" & FileUtils.ReadAsString(LocalPath), "") End If If MinSize >= 0 AndAlso MinSize > FileSize Then Return $"文件大小应大于 {MinSize} B,实际为 {FileSize} B" & - If(FileSize < 2000, ",内容为:" & ReadFile(LocalPath), "") + If(FileSize < 2000, ",内容为:" & FileUtils.ReadAsString(LocalPath), "") End If If Not String.IsNullOrEmpty(Hash) Then If Hash.Length < 35 Then 'MD5 - If Hash.Lower <> GetFileMD5(LocalPath) Then Return "文件 MD5 应为 " & Hash & ",实际为 " & GetFileMD5(LocalPath) + Dim md5 As String = HashUtils.ComputeFromFile(LocalPath, HashUtils.HashMethod.Md5) + If Hash.Lower <> md5 Then Return "文件 MD5 应为 " & Hash & ",实际为 " & md5 ElseIf Hash.Length = 64 Then 'SHA256 - If Hash.Lower <> GetFileSHA256(LocalPath) Then Return "文件 SHA256 应为 " & Hash & ",实际为 " & GetFileSHA256(LocalPath) + Dim sha256 As String = HashUtils.ComputeFromFile(LocalPath, HashUtils.HashMethod.Sha256) + If Hash.Lower <> sha256 Then Return "文件 SHA256 应为 " & Hash & ",实际为 " & sha256 Else 'SHA1 (40) - If Hash.Lower <> GetFileSHA1(LocalPath) Then Return "文件 SHA1 应为 " & Hash & ",实际为 " & GetFileSHA1(LocalPath) + Dim sha1 As String = HashUtils.ComputeFromFile(LocalPath, HashUtils.HashMethod.Sha1) + If Hash.Lower <> sha1 Then Return "文件 SHA1 应为 " & Hash & ",实际为 " & sha1 End If End If If IsJson Then - Dim Content As String = ReadFile(LocalPath) + Dim Content As String = FileUtils.ReadAsString(LocalPath) If Content = "" Then Throw New Exception("读取到的文件为空") Try GetJson(Content) @@ -1087,269 +731,18 @@ Re: End If Return Nothing Catch ex As Exception - Log(ex, "检查文件出错") - Return ex.GetBrief() + Logger.Warn(ex, "检查文件出错") + Return ex.GetDisplay(False) End Try End Function End Class - '压缩文件 - ''' - ''' 尝试根据后缀名判断文件种类并解压文件,支持 gz 与 zip,会尝试将 jar 以 zip 方式解压。 - ''' 会尝试创建目标文件夹;会覆盖已有文件,不会删除多余文件。 - ''' 会先使用 UTF-8 解压,失败后换用 GB18030 解压。 - ''' - Public Sub ExtractCompressedFile(CompressFilePath As String, DestDirectory As String, Optional ProgressIncrementHandler As Action(Of Double) = Nothing) - DestDirectory = DirectoryUtils.ToDirectoryFormat(DestDirectory) - DirectoryUtils.Create(DestDirectory) - '解压 gz(gz 不需要考虑编码) - If CompressFilePath.EndsWithF(".gz", True) Then - Using stream As New GZipStream(New FileStream(CompressFilePath, FileMode.Open, FileAccess.Read, FileShare.Read), CompressionMode.Decompress) - Using decompressedFile As New FileStream( - DestDirectory & GetFileNameFromPath(CompressFilePath).Lower.Replace(".tar", "").Replace(".gz", ""), FileMode.Create, FileAccess.Write) - stream.CopyTo(decompressedFile) - End Using - End Using - Return - End If - '解压 zip - Dim TryExtractZip = - Sub(Encoding As Encoding) - Using Archive = ZipFile.Open(CompressFilePath, ZipArchiveMode.Read, Encoding) - Dim EntryCount = Archive.Entries.Count - For Each Entry In Archive.Entries - If ProgressIncrementHandler IsNot Nothing AndAlso EntryCount > 0 Then ProgressIncrementHandler(1 / EntryCount) - Dim Destination As String = Path.Combine(DestDirectory, Entry.FullName) - If Not Path.GetFullPath(Destination).StartsWithF(Path.GetFullPath(DestDirectory), True) Then Continue For 'ZipSlip 漏洞修复 - If DirectoryUtils.IsDirectoryFormat(Destination) Then Continue For '不创建空文件夹 - Destination = FileUtils.ShortenPath(Destination) - DirectoryUtils.Create(Destination, isFilePath:=True) - Entry.ExtractToFile(Destination, True) '#7329 - Next - End Using - End Sub - Try - TryExtractZip(New UTF8Encoding(False, True)) - Catch ex As Exception - Log(ex, $"首次解压尝试失败,将更换编码并重试({CompressFilePath} → {DestDirectory})") - Try - TryExtractZip(Encoding.GetEncoding("GB18030")) - Catch - Throw - End Try - End Try - End Sub - ''' - ''' 将多个文件打包为一个压缩文件。 - ''' 这些文件会被直接放在压缩包根目录下。 - ''' - Public Sub CreateCompressedFile(OutputFullPath As String, SourceFiles As IEnumerable(Of String)) - DirectoryUtils.Create(OutputFullPath, isFilePath:=True) - Using ZipStream As New FileStream(OutputFullPath, FileMode.Create) - Using Archive As New ZipArchive(ZipStream, ZipArchiveMode.Create) - For Each FilePath In SourceFiles - If Not File.Exists(FilePath) Then Return - Using SourceStream As New FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read), - EntryStream As Stream = Archive.CreateEntry(Path.GetFileName(FilePath), CompressionLevel.Optimal).Open() - SourceStream.CopyTo(EntryStream) - End Using - Next - End Using - End Using - End Sub - - ''' - ''' 删除文件夹,返回删除的文件个数。通过参数选择是否抛出异常。 - ''' - Public Function DeleteDirectory(Folder As String, Optional IgnoreIssue As Boolean = False) As Integer - If Not Directory.Exists(Folder) Then Return 0 - If Not Folder.EndsWithF("\") Then Folder &= "\" - If Folder.EndsWithF(":\") OrElse - Folder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) & "\" OrElse - Folder = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) & "\" OrElse - Folder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) & "\" Then '#7030 - Throw New UnauthorizedAccessException("这是重要的系统文件夹,无法删除:" & Folder) - End If - '实际删除 - Dim DeletedCount As Integer = 0 - Dim Files As String() - Try - Files = Directory.GetFiles(Folder) - Catch ex As DirectoryNotFoundException '#4549,也可能已被其他线程删除 - If Directory.Exists(Folder) Then - Log(ex, $"疑似为孤立符号链接,尝试直接删除({Folder})", NotifyLevel.DevelopOnly) - Directory.Delete(Folder) - End If - Return DeletedCount - End Try - For Each FilePath As String In Files - Dim RetriedFile As Boolean = False -RetryFile: - Try - File.Delete(FilePath) - DeletedCount += 1 - Catch ex As DirectoryNotFoundException - Return DeletedCount - Catch ex As Exception - If Not RetriedFile Then - RetriedFile = True - Log(ex, $"删除文件失败,将在 0.3s 后重试({FilePath})") - Thread.Sleep(300) - GoTo RetryFile - ElseIf IgnoreIssue Then - Log(ex, "删除单个文件可忽略地失败") - Else - Throw - End If - End Try - Next - For Each str As String In Directory.GetDirectories(Folder) - DeleteDirectory(str, IgnoreIssue) - Next - Dim RetriedDir As Boolean = False -RetryDir: - Try - Directory.Delete(Folder, True) - Catch ex As DirectoryNotFoundException - Catch ex As Exception - If Not RetriedDir AndAlso Not RunInUi() Then - RetriedDir = True - Log(ex, $"删除文件夹失败,将在 0.3s 后重试({Folder})") - Thread.Sleep(300) - GoTo RetryDir - ElseIf IgnoreIssue Then - Log(ex, "删除单个文件夹可忽略地失败") - Else - Throw - End If - End Try - Return DeletedCount - End Function - ''' - ''' 复制文件夹,失败会抛出异常。 - ''' - Public Sub CopyDirectory(FromPath As String, ToPath As String, Optional ProgressIncrementHandler As Action(Of Double) = Nothing) - FromPath = FromPath.Replace("/", "\") - If Not FromPath.EndsWithF("\") Then FromPath &= "\" - ToPath = ToPath.Replace("/", "\") - If Not ToPath.EndsWithF("\") Then ToPath &= "\" - Dim AllFiles = EnumerateFiles(FromPath).ToList - Dim FileCount As Long = AllFiles.Count - For Each File In AllFiles - CopyFile(File.FullName, File.FullName.Replace(FromPath, ToPath)) - If ProgressIncrementHandler IsNot Nothing AndAlso FileCount > 0 Then ProgressIncrementHandler(1 / FileCount) - Next - End Sub - ''' - ''' 遍历文件夹中的所有文件。 - ''' - Public Function EnumerateFiles(Directory As String) As IEnumerable(Of FileInfo) - Dim Info As New DirectoryInfo(Directory) - If Not Info.Exists Then Return New List(Of FileInfo) - Return Info.EnumerateFiles("*", SearchOption.AllDirectories) - End Function - #End Region #Region "文本" Public vbLQ As Char = Convert.ToChar(8220) Public vbRQ As Char = Convert.ToChar(8221) - ''' - ''' 提取 Exception 与 Inner Exception 的详细描述与堆栈信息。返回内容总是多于一行。 - ''' - ''' 是否必须显示所有堆栈。通常用于判定堆栈信息。 - Public Function GetDetail(Ex As Exception, Optional ShowAllStacks As Boolean = False) As String - If Ex Is Nothing Then Return "无可用错误信息!" - - '获取最底层的异常 - Dim OuterEx As Exception = Ex - Dim InnerEx As Exception = Ex - Do Until InnerEx.InnerException Is Nothing - InnerEx = InnerEx.InnerException - Loop - - '获取各级错误的描述与堆栈信息 - Dim DescList As New List(Of String) - Dim IsInner As Boolean = False - Do Until Ex Is Nothing - DescList.Add(If(IsInner, "→ ", "") & Ex.Message.ReplaceLineEndings(vbCrLf, mergeMultiple:=True)) - If Ex.StackTrace IsNot Nothing Then - For Each Stack As String In Ex.StackTrace.Split(vbCrLf.ToCharArray, StringSplitOptions.RemoveEmptyEntries) - If ShowAllStacks OrElse Stack.ContainsIgnoreCase("pcl") Then - DescList.Add(Stack.ReplaceLineEndings("")) - End If - Next - End If - If Ex.GetType.FullName <> "System.Exception" Then DescList.Add(" 错误类型:" & Ex.GetType.FullName) - Ex = Ex.InnerException - IsInner = True - Loop - - '构造输出信息 - Dim UsualReason As String = AnalyzeUsualReason(InnerEx, OuterEx, DescList) - If UsualReason Is Nothing Then - Return DescList.Join(vbCrLf) - Else - Return UsualReason & vbCrLf & vbCrLf & "————————————" & vbCrLf & "详细错误信息:" & vbCrLf & DescList.Join(vbCrLf) - End If - End Function - ''' - ''' 提取 Exception 与 Inner Exception 的描述,汇总到一行。 - ''' - Public Function GetBrief(Ex As Exception) As String - If Ex Is Nothing Then Return "无可用错误信息!" - - '获取最底层的异常 - Dim OuterEx As Exception = Ex - Dim InnerEx As Exception = Ex - Do Until InnerEx.InnerException Is Nothing - InnerEx = InnerEx.InnerException - Loop - - '获取各级错误的描述 - Dim DescList As New List(Of String) - Do Until Ex Is Nothing - DescList.Add(Ex.Message.ReplaceLineEndings(" ", mergeMultiple:=True)) - Ex = Ex.InnerException - Loop - DescList = DescList.Distinct.ToList - Dim Desc As String = DescList.Join(vbCrLf & "→ ") - - '构造输出信息 - Dim UsualReason As String = AnalyzeUsualReason(InnerEx, OuterEx, DescList) - If UsualReason IsNot Nothing Then - Return UsualReason & "详细错误:" & DescList.First - Else - DescList.Reverse() '让最深层错误在最左边 - Return DescList.Join(" ← ") - End If - End Function - Private Function AnalyzeUsualReason(InnerEx As Exception, OuterEx As Exception, DescList As List(Of String)) As String - If TypeOf InnerEx Is TypeLoadException OrElse TypeOf InnerEx Is BadImageFormatException OrElse TypeOf InnerEx Is MissingMethodException OrElse TypeOf InnerEx Is NotImplementedException OrElse TypeOf InnerEx Is TypeInitializationException Then - Return "PCL 的运行环境存在问题。请尝试重新安装 .NET Framework 4.6.2 然后再试。若无法安装,请先卸载较新版本的 .NET Framework,然后再尝试安装。" - ElseIf TypeOf InnerEx Is UnauthorizedAccessException Then - Return "PCL 的权限不足。请尝试右键 PCL 选择以管理员身份运行。" - ElseIf TypeOf InnerEx Is OutOfMemoryException Then - Return "你的电脑运行内存不足,导致 PCL 无法继续运行。请在关闭一部分不需要的程序后再试。" - ElseIf TypeOf InnerEx Is Runtime.InteropServices.COMException Then - Return "由于操作系统或显卡存在问题,导致出现错误。请尝试重启 PCL。" - ElseIf TypeOf InnerEx Is SocketException AndAlso DescList.Any(Function(l) l.Contains("WSAStartup")) Then - Return "请尝试卸载中国移动云盘,然后再试。" - ElseIf OuterEx.IsNetworkRelated() Then - Return "你的网络环境不佳,请稍后再试,或使用 VPN 改善网络环境。" - Else - Return Nothing - End If - End Function - - ''' - ''' 返回一个枚举对应的字符串。 - ''' - ''' 一个已经实例化的枚举类型。 - Public Function GetStringFromEnum(EnumData As [Enum]) As String - Return [Enum].GetName(EnumData.GetType, EnumData) - End Function ''' ''' 将对象转换为枚举类型,支持数字或原文两种格式,若为空字符串或 Nothing 则返回 0。 ''' 若转换失败会抛出异常。 @@ -1437,59 +830,6 @@ RetryDir: End Try End Function - '正则 - ''' - ''' 搜索字符串中的所有正则匹配项。 - ''' - Public Function RegexSearch(str As String, pattern As String, Optional options As RegexOptions = RegexOptions.None) As List(Of String) - Try - RegexSearch = New List(Of String) - Dim RegexSearchRes = New Regex(pattern, options).Matches(str) - If RegexSearchRes Is Nothing Then Return RegexSearch - For Each item As Match In RegexSearchRes - RegexSearch.Add(item.Value) - Next - Catch ex As Exception - Log(ex, "正则匹配全部项出错") - Return New List(Of String) - End Try - End Function - ''' - ''' 获取字符串中的第一个正则匹配项,若无匹配则返回 Nothing。 - ''' - Public Function RegexSeek(str As String, pattern As String, Optional options As RegexOptions = RegexOptions.None) As String - Try - Dim Result = Regex.Match(str, pattern, options).Value - Return If(Result = "", Nothing, Result) - Catch ex As Exception - Log(ex, "正则匹配第一项出错") - Return Nothing - End Try - End Function - ''' - ''' 检查字符串是否匹配某正则模式。 - ''' - Public Function RegexCheck(str As String, pattern As String, Optional options As RegexOptions = RegexOptions.None) As Boolean - Try - Return Regex.IsMatch(str, pattern, options) - Catch ex As Exception - Log(ex, "正则检查出错") - Return False - End Try - End Function - ''' - ''' 进行正则替换。失败时会抛出异常。 - ''' - Public Function RegexReplace(AllContents As String, SearchRegex As String, ReplaceTo As String, Optional options As RegexOptions = RegexOptions.None) As String - Return Regex.Replace(AllContents, SearchRegex, ReplaceTo, options) - End Function - ''' - ''' 对每个正则匹配分别进行替换。失败时会抛出异常。 - ''' - Public Function RegexReplace(AllContents As String, SearchRegex As String, ReplaceTo As MatchEvaluator, Optional options As RegexOptions = RegexOptions.None) As String - Return Regex.Replace(AllContents, SearchRegex, ReplaceTo, options) - End Function - #End Region #Region "搜索" @@ -1602,7 +942,7 @@ RetryDir: Dim ResultList As New List(Of SearchEntry(Of T)) If Not Entries.Any() Then Return ResultList '进行搜索,获取相似信息 - Dim QueryParts = Query.Split({" "c}, StringSplitOptions.RemoveEmptyEntries) + Dim QueryParts = Query.Split(" ", True) Dim Candidates As New List(Of SearchEntry(Of T)) For Each Entry In Entries Entry.Similarity = SearchSimilarityWeighted(Entry.SearchSource, Query) @@ -1685,14 +1025,6 @@ RetryDir: Inherits Exception End Class - ''' - ''' 当前程序是否拥有管理员权限。 - ''' - Public Function IsAdmin() As Boolean - Dim id As WindowsIdentity = WindowsIdentity.GetCurrent() - Dim principal As New WindowsPrincipal(id) - Return principal.IsInRole(WindowsBuiltInRole.Administrator) - End Function ''' ''' 以管理员权限运行当前程序,并等待程序运行结束。 ''' 返回程序的返回代码,如果运行失败将抛出异常。 @@ -1703,13 +1035,6 @@ RetryDir: Return NewProcess.ExitCode End Function - ''' - ''' 判断当前系统语言是否为中文。 - ''' - Public Function IsSystemLanguageChinese() As Boolean - Return CultureInfo.CurrentCulture.Name.StartsWithF("zh-") OrElse CultureInfo.CurrentUICulture.Name.StartsWithF("zh-") - End Function - ''' ''' 判断对象是否为某个泛型类型的实例。 ''' @@ -1736,12 +1061,7 @@ RetryDir: End SyncLock End Function - ''' - ''' 获取格式类似于“11:08:52.037”的当前时间的字符串。 - ''' - Public Function GetTimeNow() As String - Return Date.Now.ToString("HH':'mm':'ss'.'fff") - End Function + '时间相关 ''' ''' 获取一个单调递增时间值(毫秒)。 ''' @@ -1755,76 +1075,90 @@ RetryDir: Dim EndFix = If(Span.TotalMilliseconds > 0, "后", "前") If Span.TotalMilliseconds < 0 Then Span = -Span Dim TotalMonthes = Math.Floor(Span.Days / 30) + Dim Result As String If IsShortForm Then If TotalMonthes >= 12 Then '1+ 年,“3 年” - GetTimeSpanString = Math.Floor(TotalMonthes / 12) & " 年" + Result = Math.Floor(TotalMonthes / 12) & " 年" ElseIf TotalMonthes >= 2 Then '2~11 月,“5 个月” - GetTimeSpanString = TotalMonthes & " 个月" + Result = TotalMonthes & " 个月" ElseIf Span.TotalDays >= 2 Then '2 天 ~ 2 月,“23 天” - GetTimeSpanString = Span.Days & " 天" + Result = Span.Days & " 天" ElseIf Span.TotalHours >= 1 Then '1 小时 ~ 2 天,“15 小时” - GetTimeSpanString = Span.Hours & " 小时" + Result = Span.Hours & " 小时" ElseIf Span.TotalMinutes >= 1 Then '1 分钟 ~ 1 小时,“49 分钟” - GetTimeSpanString = Span.Minutes & " 分钟" + Result = Span.Minutes & " 分钟" ElseIf Span.TotalSeconds >= 1 Then '1 秒 ~ 1 分钟,“23 秒” - GetTimeSpanString = Span.Seconds & " 秒" + Result = Span.Seconds & " 秒" Else '不到 1 秒 - GetTimeSpanString = "1 秒" + Result = "1 秒" End If Else If TotalMonthes >= 61 Then '5+ 年,“5 年” - GetTimeSpanString = Math.Floor(TotalMonthes / 12) & " 年" + Result = Math.Floor(TotalMonthes / 12) & " 年" ElseIf TotalMonthes >= 12 Then '12~60 月,“1 年 2 个月” - GetTimeSpanString = Math.Floor(TotalMonthes / 12) & " 年" & If((TotalMonthes Mod 12) > 0, " " & (TotalMonthes Mod 12) & " 个月", "") + Result = Math.Floor(TotalMonthes / 12) & " 年" & If((TotalMonthes Mod 12) > 0, " " & (TotalMonthes Mod 12) & " 个月", "") ElseIf TotalMonthes >= 4 Then '4~11 月,“5 个月” - GetTimeSpanString = TotalMonthes & " 个月" + Result = TotalMonthes & " 个月" ElseIf TotalMonthes >= 1 Then '1~4 月,“2 个月 13 天” - GetTimeSpanString = TotalMonthes & " 月" & If((Span.Days Mod 30) > 0, " " & (Span.Days Mod 30) & " 天", "") + Result = TotalMonthes & " 月" & If((Span.Days Mod 30) > 0, " " & (Span.Days Mod 30) & " 天", "") ElseIf Span.TotalDays >= 4 Then '4~30 天,“23 天” - GetTimeSpanString = Span.Days & " 天" + Result = Span.Days & " 天" ElseIf Span.TotalDays >= 1 Then '1~3 天,“2 天 20 小时” - GetTimeSpanString = Span.Days & " 天" & If(Span.Hours > 0, " " & Span.Hours & " 小时", "") + Result = Span.Days & " 天" & If(Span.Hours > 0, " " & Span.Hours & " 小时", "") ElseIf Span.TotalHours >= 10 Then '10 小时 ~ 1 天,“15 小时” - GetTimeSpanString = Span.Hours & " 小时" + Result = Span.Hours & " 小时" ElseIf Span.TotalHours >= 1 Then '1~10 小时,“1 小时 20 分钟” - GetTimeSpanString = Span.Hours & " 小时" & If(Span.Minutes > 0, " " & Span.Minutes & " 分钟", "") + Result = Span.Hours & " 小时" & If(Span.Minutes > 0, " " & Span.Minutes & " 分钟", "") ElseIf Span.TotalMinutes >= 10 Then '10 分钟 ~ 1 小时,“49 分钟” - GetTimeSpanString = Span.Minutes & " 分钟" + Result = Span.Minutes & " 分钟" ElseIf Span.TotalMinutes >= 1 Then '1~10 分钟,“9 分 23 秒” - GetTimeSpanString = Span.Minutes & " 分" & If(Span.Seconds > 0, " " & Span.Seconds & " 秒", "") + Result = Span.Minutes & " 分" & If(Span.Seconds > 0, " " & Span.Seconds & " 秒", "") ElseIf Span.TotalSeconds >= 1 Then '1 秒 ~ 1 分钟,“23 秒” - GetTimeSpanString = Span.Seconds & " 秒" + Result = Span.Seconds & " 秒" Else '不到 1 秒 - GetTimeSpanString = "1 秒" + Result = "1 秒" End If End If - GetTimeSpanString += EndFix + Result += EndFix + Return Result End Function ''' ''' 获取十进制 Unix 时间戳。 ''' - Public Function GetUnixTimestamp() As Long + Public Function GetUnixTimestampUtc() As Long Return (Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000 End Function + ''' + ''' 时间戳转化为日期。 + ''' + Public Function GetDate(timeStamp As Integer) As Date + Return DateTimeOffset.FromUnixTimeSeconds(timeStamp).LocalDateTime + End Function + ''' + ''' 将 UTC 时间转化为当前时区的时间。 + ''' + Public Function GetLocalTime(UtcDate As Date) As Date + Return DateTime.SpecifyKind(UtcDate, DateTimeKind.Utc).ToLocalTime + End Function ''' ''' 用于储存 RaiseByMouse 的 EventArgs。 @@ -1850,9 +1184,9 @@ RetryDir: ''' 会自动进行长路径处理。 ''' Public Function StartProcess(StartInfo As ProcessStartInfo) As Process - StartInfo.FileName = FileUtils.ShortenPath(StartInfo.FileName) - If Not String.IsNullOrEmpty(StartInfo.WorkingDirectory) Then StartInfo.WorkingDirectory = FileUtils.ShortenPath(StartInfo.WorkingDirectory) - Log("[System] 启动进程:" & StartInfo.FileName & " " & StartInfo.Arguments) + StartInfo.FileName = PathUtils.ToShortPath(StartInfo.FileName) + If Not String.IsNullOrEmpty(StartInfo.WorkingDirectory) Then StartInfo.WorkingDirectory = PathUtils.ToShortPath(StartInfo.WorkingDirectory) + Logger.Info($"启动进程:{StartInfo.FileName} {StartInfo.Arguments}") Return Process.Start(StartInfo) End Function ''' @@ -1865,12 +1199,12 @@ RetryDir: Optional WorkingDirectory As String = Nothing, Optional Encoding As Encoding = Nothing, Optional PrintLog As Boolean = True) As String Dim Info = New ProcessStartInfo With { .Arguments = Arguments, - .FileName = FileUtils.ShortenPath(FileName), + .FileName = PathUtils.ToShortPath(FileName), .UseShellExecute = False, .CreateNoWindow = True, .RedirectStandardError = True, .RedirectStandardOutput = True, - .WorkingDirectory = FileUtils.ShortenPath(If(WorkingDirectory, PathExeFolder.TrimEnd("\"c))), + .WorkingDirectory = PathUtils.ToShortPath(If(WorkingDirectory, PathExeFolder.TrimEnd("\"c))), .StandardErrorEncoding = Encoding, .StandardOutputEncoding = Encoding } @@ -1881,7 +1215,7 @@ RetryDir: Info.EnvironmentVariables.Add("appdata", WorkingDirectory) End If End If - If PrintLog Then Log("[System] 执行命令并等待返回结果:" & FileName & " " & Arguments) + If PrintLog Then Logger.Info($"执行命令并等待返回结果:{FileName} {Arguments}") Using Program As New Process With {.StartInfo = Info} Program.Start() Dim Result As String = Program.StandardOutput.ReadToEnd & Program.StandardError.ReadToEnd @@ -1900,9 +1234,9 @@ RetryDir: Try Action() Catch ex As ThreadInterruptedException - Log(Name & ":线程已中止") + Logger.Info($"{Name}:线程已中止") Catch ex As Exception - Log(ex, Name & ":线程执行失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"{Name}:线程执行失败") End Try End Sub) With {.Name = If(Name, "Runtime New Invoke " & GetUuid() & "#"), .Priority = Priority} th.Start() @@ -1989,21 +1323,6 @@ RetryDir: Return DefaultValue End Function - ''' - ''' 时间戳转化为日期。 - ''' - Public Function GetDate(timeStamp As Integer) As Date - Dim dtStart As Date = TimeZone.CurrentTimeZone.ToLocalTime(New Date(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)) - Dim lTime As Long = (CLng(timeStamp) * 10000000) - Return dtStart.Add(New TimeSpan(lTime)) - End Function - ''' - ''' 将 UTC 时间转化为当前时区的时间。 - ''' - Public Function GetLocalTime(UtcDate As Date) As Date - Return DateTime.SpecifyKind(UtcDate, DateTimeKind.Utc).ToLocalTime - End Function - ''' ''' 打开网页。 ''' @@ -2012,10 +1331,10 @@ RetryDir: If Not Url.StartsWithF("http", True) AndAlso Not Url.StartsWithF("minecraft://", True) AndAlso Not Url.StartsWithF("minecraft-preview://", True) Then Throw New Exception(Url & " 不是一个有效的网址,它必须以 http 开头!") End If - Log("[System] 正在打开网页:" & Url) + Logger.Info($"正在打开网页:{Url}") StartProcess(Url) Catch ex As Exception - Log(ex, "无法打开网页(" & Url & ")") + Logger.Warn(ex, $"无法打开网页({Url})") ClipboardSet(Url, False) MyMsgBox("可能由于浏览器未正确配置,PCL 无法为你打开网页。" & vbCrLf & "网址已经复制到剪贴板,若有需要可以手动粘贴访问。" & vbCrLf & $"网址:{Url}", "无法打开网页") @@ -2028,14 +1347,14 @@ RetryDir: Public Sub OpenExplorer(Location As String) Try Location = Location.Replace("/", "\").Trim(" "c, """"c) - Log("[System] 正在打开资源管理器:" & Location) + Logger.Info($"正在打开资源管理器:{Location}") If Location.EndsWithF("\") Then StartProcess(Location) Else StartProcess("explorer", $"/select,""{Location}""") End If Catch ex As Exception - Log(ex, "打开资源管理器失败,请尝试关闭安全软件(如 360 安全卫士)", NotifyLevel.MsgBox) + Logger.Error(ex, "打开资源管理器失败,请尝试关闭安全软件(如 360 安全卫士)", LogBehavior.Alert) End Try End Sub @@ -2045,24 +1364,19 @@ RetryDir: Public Sub ClipboardSet(Text As String, Optional ShowSuccessHint As Boolean = True) RunInThread( Sub() - Dim RetryCount As Integer = 0 -Retry: Try - RunInUi( + ResilientUtils.Retry( Sub() - My.Computer.Clipboard.Clear() - If Not String.IsNullOrEmpty(Text) Then My.Computer.Clipboard.SetText(Text) + RunInUi( + Sub() + My.Computer.Clipboard.Clear() + If Not String.IsNullOrEmpty(Text) Then My.Computer.Clipboard.SetText(Text) + End Sub) End Sub) + If ShowSuccessHint Then Hint("已成功复制!", HintType.Green) Catch ex As Exception - RetryCount += 1 - If RetryCount <= 5 Then - Thread.Sleep(20) - GoTo Retry - Else - Log(ex, "可能由于剪贴板被其他程序占用,文本复制失败", NotifyLevel.AllUsers) - End If + Logger.Error(ex, "可能由于剪贴板被其他程序占用,文本复制失败", LogBehavior.Toast) End Try - If ShowSuccessHint Then Hint("已成功复制!", HintType.Green) End Sub) End Sub ''' @@ -2075,19 +1389,26 @@ Retry: Try If My.Computer.Clipboard.ContainsText() Then Result = My.Computer.Clipboard.GetText() Catch ex As Exception - Log(ex, "获取剪贴板文本失败") + Logger.Warn(ex, "获取剪贴板文本失败") End Try End Sub) Return Result End Function ''' - ''' 以 Byte() 形式获取程序中的资源。 + ''' 将程序中的资源释放到文件。 ''' - Public Function GetResources(ResourceName As String) As Byte() - Log("[System] 获取资源:" & ResourceName) - Return My.Resources.ResourceManager.GetObject(ResourceName) - End Function + Public Sub ExtractResources(FilePath As String, ResourceName As String) + Logger.Info($"将资源写入到文件:{ResourceName} → {FilePath}") + Dim Resource = My.Resources.ResourceManager.GetObject(ResourceName) + If TypeOf Resource Is Byte() Then + FileUtils.Write(FilePath, DirectCast(Resource, Byte())) + ElseIf TypeOf Resource Is String Then + FileUtils.Write(FilePath, DirectCast(Resource, String)) + Else + Throw New Exception($"资源 {ResourceName} 的类型不支持:{Resource.GetType.Name}") + End If + End Sub #End Region @@ -2199,300 +1520,6 @@ Retry: #End Region -#Region "Debug" - - Public ReadOnly Property ModeDebug As Boolean - Get - Return Settings.Get("SystemDebugMode") - End Get - End Property - - 'Log - Public Enum NotifyLevel - ''' - ''' 不提示,只记录日志。 - ''' - Silent = 0 - ''' - ''' 只在开发中版本弹出提示条。 - ''' - DevelopOnly = 1 - ''' - ''' 只在开发中版本或调试模式下弹出提示条。 - ''' - DebugModeOnly = 2 - ''' - ''' 对所有用户弹出提示条。 - ''' - AllUsers = 3 - ''' - ''' 弹出窗口,不要求提交反馈。 - ''' - MsgBox = 4 - ''' - ''' 弹出窗口,并要求提交反馈。 - ''' - MsgBoxAndFeedback = 5 - ''' - ''' 弹出 Windows 原生弹窗,并要求提交反馈。 - ''' 可在无法保证 UI 能正常运行时使用此级别。 - ''' - Critical = 6 - End Enum - Private LogList As New StringBuilder - Private LogWritter As StreamWriter - Public Sub LogStart() - RunInNewThread( - Sub() - Dim IsInitSuccess As Boolean = True - Try - For i = 4 To 1 Step -1 - If File.Exists(PathExeFolder & "PCL\Log" & i & ".txt") Then - If File.Exists(PathExeFolder & "PCL\Log" & (i + 1) & ".txt") Then File.Delete(PathExeFolder & "PCL\Log" & (i + 1) & ".txt") - CopyFile(PathExeFolder & "PCL\Log" & i & ".txt", PathExeFolder & "PCL\Log" & (i + 1) & ".txt") - End If - Next - File.Create(PathExeFolder & "PCL\Log1.txt").Dispose() - Catch ex As IOException - IsInitSuccess = False - Hint("可能同时开启了多个 PCL,程序可能会出现未知问题!", HintType.Red) - Log(ex, "日志初始化失败(疑似文件占用问题)") - Catch ex As Exception - IsInitSuccess = False - Log(ex, "日志初始化失败", NotifyLevel.AllUsers) - End Try - Try - LogWritter = New StreamWriter(PathExeFolder & "PCL\Log1.txt", True) With {.AutoFlush = True} - Catch ex As Exception - LogWritter = Nothing - Log(ex, "日志写入失败", NotifyLevel.AllUsers) - End Try - While True - If IsInitSuccess Then - LogFlush() - Else - LogList = New StringBuilder '清空 LogList 避免内存爆炸 - End If - Thread.Sleep(50) - End While - End Sub, "Log Writer", ThreadPriority.Lowest) - End Sub - Private ReadOnly LogFlushLock As New Object '防止外部调用 LogFlush 时同时输出多次日志 - Public Sub LogFlush() - On Error Resume Next - If LogWritter Is Nothing Then Return - Dim Log As String = Nothing - SyncLock LogFlushLock - If LogList.Length > 0 Then - Dim LogListCache As StringBuilder - LogListCache = LogList - LogList = New StringBuilder - Log = LogListCache.ToString - End If - End SyncLock - If Log IsNot Nothing Then - LogWritter.Write(Log) - End If - End Sub - - Private ReadOnly LogListLock As New Object '防止日志乱码,只在调试模式下启用 - Private IsCriticalErrorTriggered As Boolean = False - ''' - ''' 输出 Log。 - ''' - ''' 如果要求弹窗,指定弹窗的标题。 - Public Sub Log(Text As String, Optional Level As NotifyLevel = NotifyLevel.Silent, Optional Title As String = "出现错误") - On Error Resume Next - '放在最后会导致无法显示极端错误下的弹窗(如无法写入日志文件) - '处理错误会导致再次调用 Log() 导致无限循环 - - '输出日志 - Dim AppendText As String = $"[{GetTimeNow()}] <{If(Thread.CurrentThread.Name = "", "主线程", Thread.CurrentThread.Name)}> {Text}{vbCrLf}" '减轻同步锁占用 - AppendText = FilterUserName(FilterAccessToken(AppendText, "*"), "*") - If ModeDebug Then - SyncLock LogListLock - LogList.Append(AppendText) - End SyncLock - Else - LogList.Append(AppendText) - End If - If BuildType = BuildTypes.Debug Then Console.Write(AppendText) - If IsProgramEnded OrElse Level = NotifyLevel.Silent Then Return - - '去除前缀 - Text = Text.RegexReplace("\[[^\]]+?\] ", "") - - '输出提示 - Select Case Level - Case NotifyLevel.DevelopOnly - If BuildType = BuildTypes.Debug Then Hint("[开发者模式] " & Text, HintType.Blue, False) - Case NotifyLevel.DebugModeOnly - If BuildType = BuildTypes.Debug OrElse ModeDebug Then Hint("[调试模式] " & Text, HintType.Blue, False) - Case NotifyLevel.AllUsers - Hint(Text, HintType.Red, False) - Case NotifyLevel.MsgBox - MyMsgBox(Text, Title, IsWarn:=True) - Case NotifyLevel.MsgBoxAndFeedback - If CanFeedback(False) Then - If MyMsgBox(Text & vbCrLf & vbCrLf & "是否反馈此问题?如果不反馈,这个问题可能永远无法得到解决!", Title, "反馈", "取消", IsWarn:=True) = 1 Then Feedback(False, True) - Else - MyMsgBox(Text & vbCrLf & vbCrLf & "将 PCL 更新至最新版或许可以解决这个问题……", Title, IsWarn:=True) - End If - Case NotifyLevel.Critical - If IsCriticalErrorTriggered Then - FormMain.EndProgramForce(ProcessReturnValues.Exception) - Return - End If - IsCriticalErrorTriggered = True - If CanFeedback(False) Then - If MsgBox(Text & vbCrLf & vbCrLf & "是否反馈此问题?如果不反馈,这个问题可能永远无法得到解决!", MsgBoxStyle.Critical + MsgBoxStyle.YesNo, Title) = MsgBoxResult.Yes Then Feedback(False, True) - Else - MsgBox(Text & vbCrLf & vbCrLf & "将 PCL 更新至最新版或许可以解决这个问题……", MsgBoxStyle.Critical, Title) - End If - End Select - - '上报 - If Level >= NotifyLevel.AllUsers Then - Telemetry("PCL 错误", - "Level", GetStringFromEnum(Level), - "Title", FilterUserName(FilterAccessToken(Title, "*"), "*"), - "Exception", FilterUserName(FilterAccessToken(Text, "*"), "*")) - End If - End Sub - ''' - ''' 输出错误信息。 - ''' - ''' 错误描述。会在处理时在末尾加入冒号。 - Public Sub Log(Ex As Exception, Desc As String, Optional Level As NotifyLevel = NotifyLevel.DebugModeOnly, Optional Title As String = "出现错误") - On Error Resume Next - If TypeOf Ex Is ThreadInterruptedException Then Return - - '获取错误信息 - Dim ExFull As String = $"{Desc}:{Ex.GetDetail()}" - - '输出日志 - Dim AppendText As String = $"[{GetTimeNow()}] <{If(Thread.CurrentThread.Name = "", "主线程", Thread.CurrentThread.Name)}> {Desc}:{Ex.GetDetail(True)}{vbCrLf}" '减轻同步锁占用 - AppendText = FilterUserName(FilterAccessToken(AppendText, "*"), "*") - If ModeDebug Then - SyncLock LogListLock - LogList.Append(AppendText) - End SyncLock - Else - LogList.Append(AppendText) - End If - If BuildType = BuildTypes.Debug Then Console.Write(AppendText) - If IsProgramEnded Then Return - - '输出提示 - Select Case Level - Case NotifyLevel.Silent - Case NotifyLevel.DevelopOnly - If BuildType = BuildTypes.Debug Then - Dim ExLine As String = Desc & ":" & Ex.GetBrief() - Hint("[开发者模式] " & ExLine, HintType.Blue, False) - End If - Case NotifyLevel.DebugModeOnly - If BuildType = BuildTypes.Debug OrElse ModeDebug Then - Dim ExLine As String = Desc & ":" & Ex.GetBrief() - Hint("[调试模式] " & ExLine, HintType.Blue, False) - End If - Case NotifyLevel.AllUsers - Dim ExLine As String = Desc & ":" & Ex.GetBrief() - Hint(ExLine, HintType.Red, False) - Case NotifyLevel.MsgBox - MyMsgBox(ExFull, Title, IsWarn:=True) - Case NotifyLevel.MsgBoxAndFeedback - If CanFeedback(False) Then - If MyMsgBox(ExFull & vbCrLf & vbCrLf & "是否反馈此问题?如果不反馈,这个问题可能永远无法得到解决!", Title, "反馈", "取消", IsWarn:=True) = 1 Then Feedback(False, True) - Else - MyMsgBox(ExFull & vbCrLf & vbCrLf & "将 PCL 更新至最新版或许可以解决这个问题……", Title, IsWarn:=True) - End If - Case NotifyLevel.Critical - If IsCriticalErrorTriggered Then - FormMain.EndProgramForce(ProcessReturnValues.Exception) - Return - End If - IsCriticalErrorTriggered = True - If CanFeedback(False) Then - If MsgBox(ExFull & vbCrLf & vbCrLf & "是否反馈此问题?如果不反馈,这个问题可能永远无法得到解决!", MsgBoxStyle.Critical + MsgBoxStyle.YesNo, Title) = MsgBoxResult.Yes Then Feedback(False, True) - Else - MsgBox(ExFull & vbCrLf & vbCrLf & "将 PCL 更新至最新版或许可以解决这个问题……", MsgBoxStyle.Critical, Title) - End If - End Select - - '上报 - If Level >= NotifyLevel.AllUsers Then - Telemetry("PCL 异常", - "Level", GetStringFromEnum(Level), - "Title", FilterUserName(FilterAccessToken(Title, "*"), "*"), - "Exception", FilterUserName(FilterAccessToken(ExFull, "*"), "*")) - End If - End Sub - - '反馈 - Public Sub Feedback(Optional ShowMsgbox As Boolean = True, Optional ForceOpenLog As Boolean = False) - On Error Resume Next - FeedbackInfo() - If ForceOpenLog OrElse (ShowMsgbox AndAlso MyMsgBox("若你在汇报一个 Bug,请点击 打开文件夹 按钮,并上传 Log(1~5).txt 中包含错误信息的文件。" & vbCrLf & "游戏崩溃一般与启动器无关,请不要因为游戏崩溃而提交反馈。", "反馈提交提醒", "打开文件夹", "不需要") = 1) Then - OpenExplorer(PathExeFolder & "PCL\Log1.txt") - End If - OpenWebsite("https://github.com/Meloong-Git/PCL/issues/") - End Sub - Public Function CanFeedback(ShowHint As Boolean) As Boolean - If False.Equals(PageSetupSystem.IsLauncherNewest) Then - If ShowHint Then - If MyMsgBox($"你的 PCL 不是最新版,因此无法提交反馈。{vbCrLf}请在更新后,确认该问题在最新版中依然存在,然后再提交反馈。", "无法提交反馈", "更新", "取消") = 1 Then - UpdateCheckByButton() - End If - End If - Return False - Else - Return True - End If - End Function - ''' - ''' 在日志中输出系统诊断信息。 - ''' - Public Sub FeedbackInfo() - On Error Resume Next - Log("[System] 诊断信息:" & vbCrLf & - "操作系统:" & My.Computer.Info.OSFullName & "(32 位:" & Is32BitSystem & ")" & vbCrLf & - "剩余内存:" & Int(My.Computer.Info.AvailablePhysicalMemory / 1024 / 1024) & " M / " & Int(My.Computer.Info.TotalPhysicalMemory / 1024 / 1024) & " M" & vbCrLf & - "DPI:" & DPI & "(" & Math.Round(DPI / 96, 2) * 100 & "%)" & vbCrLf & - "MC 文件夹:" & If(McFolderSelected, "Nothing") & vbCrLf & - "文件位置:" & PathExeFolder) - End Sub - - '遥测 - Public Sub Telemetry([Event] As String, ParamArray Datas As String()) - If BuildType = BuildTypes.Debug Then Return '开发版不上传遥测 - If Not Settings.Get("SystemSystemTelemetry") Then Return '用户关闭了遥测 - If Not ClsBaseUrl.StartsWithF("http") Then Return '开源版没有设置遥测地址 - RunInNewThread( - Sub() - Try - Log($"[System] 匿名数据上报:{[Event]}") - Dim Url As String = $"{ClsBaseUrl}&Event={EscapeUtils.UrlEscape([Event])}" - For i = 0 To Datas.Length - 1 Step 2 - Url &= "&" & EscapeUtils.UrlEscape(Datas(i)) & "=" & EscapeUtils.UrlEscape(Datas(i + 1).ReplaceLineEndings(vbCrLf)) - Next - NetRequestByClient(Url, MakeLog:=False) - Catch ex As Exception - Log(ex, "匿名数据上报失败") - End Try - End Sub, "Telemetry", ThreadPriority.Lowest) - End Sub - - '获取当前的堆栈信息 - Public Function GetStackTrace() As String - Return (New StackTrace).GetFrames().Skip(1). - Select(Function(f) f.GetMethod). - Select(Function(f) $"{f.Name}({f.GetParameters.Select(Function(p) p.ToString).Join(", ")}) - {f.Module}"). - Join(vbCrLf).Replace(vbCrLf & vbCrLf, vbCrLf) - End Function - -#End Region - #Region "随机" Private ReadOnly Random As New Random @@ -2526,87 +1553,3 @@ Retry: #End Region End Module - -#Region "WPF" - -''' -''' 对数据绑定进行加法运算,使用参数决定加数。 -''' -Public Class AdditionConverter - Implements IValueConverter - Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert - If value Is Nothing Then Return 0 - Dim before As Double - If Not Double.TryParse(value.ToString(), before) Then Return 0 - Dim scale As Double = 1 - If parameter IsNot Nothing Then Double.TryParse(parameter.ToString(), scale) - Return before + scale - End Function - Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack - If value Is Nothing Then Return Binding.DoNothing - Dim before As Double - If Not Double.TryParse(value.ToString(), before) Then Return Binding.DoNothing - Dim scale As Double = 1 - If parameter IsNot Nothing Then Double.TryParse(parameter.ToString(), scale) - If scale = 0 Then Return Binding.DoNothing - Return before - scale - End Function -End Class - -''' -''' 对数据绑定进行乘法运算,使用参数决定乘数。 -''' -Public Class MultiplicationConverter - Implements IValueConverter - Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert - If value Is Nothing Then Return 0 - Dim before As Double - If Not Double.TryParse(value.ToString(), before) Then Return 0 - Dim scale As Double = 1 - If parameter IsNot Nothing Then Double.TryParse(parameter.ToString(), scale) - Return before * scale - End Function - Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack - If value Is Nothing Then Return Binding.DoNothing - Dim before As Double - If Not Double.TryParse(value.ToString(), before) Then Return Binding.DoNothing - Dim scale As Double = 1 - If parameter IsNot Nothing Then Double.TryParse(parameter.ToString(), scale) - If scale = 0 Then Return Binding.DoNothing - Return before / scale - End Function -End Class - -''' -''' 将取反的 Boolean 绑定到 Visibility。 -''' -Public Class InverseBooleanToVisibilityConverter - Implements IValueConverter - Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert - If value Is Nothing Then Return Visibility.Visible - Dim boolValue As Boolean - Return If(Boolean.TryParse(value.ToString(), boolValue), If(boolValue, Visibility.Collapsed, Visibility.Visible), Visibility.Visible) - End Function - Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack - If value Is Nothing Then Return False - Return If(TypeOf value Is Visibility, value <> Visibility.Visible, False) - End Function -End Class - -''' -''' 将 Boolean 取反。 -''' -Public Class InverseBooleanConverter - Implements IValueConverter - Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert - If value Is Nothing Then Return False - Dim boolValue As Boolean - Return If(Boolean.TryParse(value.ToString(), boolValue), Not boolValue, False) - End Function - Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack - If value Is Nothing Then Return False - Return If(Boolean.TryParse(value.ToString(), value), Not value, False) - End Function -End Class - -#End Region diff --git a/Plain Craft Launcher 2/Modules/Base/ModLoader.vb b/Plain Craft Launcher 2/Modules/Base/ModLoader.vb index 546664b..2adc2e2 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModLoader.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModLoader.vb @@ -38,7 +38,7 @@ RealParent = RealParent.Parent End While Catch ex As Exception - Log(ex, "获取父加载器失败(" & Name & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"获取父加载器失败({Name})") Return Nothing End Try End Get @@ -88,9 +88,9 @@ Set(value As LoadState) If _State = value Then Return Dim OldState = _State - If value = LoadState.Finished AndAlso Settings.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(100, 2000)) + If value = LoadState.Finished AndAlso Settings.Get(Of Boolean)("SystemDebugDelay") Then Thread.Sleep(RandomInteger(100, 2000)) _State = value - If Not LogBlackList.Contains(Name) Then Log($"[Loader] 加载器 {Name} 状态改变:{GetStringFromEnum(value)}") + If Not LogBlackList.Contains(Name) Then Logger.Info($"加载器 {Name} 状态改变:{value}") '实现 ILoadingTrigger 接口与 OnStateChanged 回调 RunInUi( Sub() @@ -229,13 +229,13 @@ ''' ''' 用于异步执行并监控单一函数的加载器。 ''' - Public Class LoaderTask(Of InputType, OutputType) + Public Class LoaderTask(Of TIn, TOut) Inherits LoaderBase '线程设定 Protected Friend ThreadPriority As ThreadPriority '执行事件 - Protected Friend LoadDelegate As Action(Of LoaderTask(Of InputType, OutputType)) + Protected Friend LoadDelegate As Action(Of LoaderTask(Of TIn, TOut)) Protected Friend InputDelegate As Func(Of Object) '状态指示 ''' @@ -265,25 +265,25 @@ ''' Public LastRunningThread As Thread = Nothing '输入输出 - Public Input As InputType = Nothing - Public Output As OutputType = Nothing + Public Input As TIn = Nothing + Public Output As TOut = Nothing '获取输入 - Public Function StartGetInput(Optional Input As InputType = Nothing, Optional InputDelegate As Func(Of Object) = Nothing) As InputType 'InputDelegate 参数存在匿名调用 + Public Function StartGetInput(Optional Input As TIn = Nothing, Optional InputDelegate As Func(Of TIn) = Nothing) As TIn 'InputDelegate 参数存在匿名调用 If InputDelegate Is Nothing Then InputDelegate = Me.InputDelegate - Dim NewInput As InputType = Nothing '若 InputType 不能为 Nothing,则会导致 Input Is Nothing 永远失败,因此需要额外判断 + Dim NewInput As TIn = Nothing '若 InputType 不能为 Nothing,则会导致 Input Is Nothing 永远失败,因此需要额外判断 If (Input Is Nothing OrElse (NewInput IsNot Nothing AndAlso Input.Equals(NewInput))) AndAlso InputDelegate IsNot Nothing Then RunInUiWait(Sub() Input = InputDelegate()) End If Return Input End Function '代码执行 - Public Function ShouldStart(ByRef Input As Object, Optional IsForceRestart As Boolean = False, Optional IgnoreReloadTimeout As Boolean = False) As Boolean + Public Function ShouldStart(ByRef Input As TIn, Optional IsForceRestart As Boolean = False, Optional IgnoreReloadTimeout As Boolean = False) As Boolean '获取输入 Try Input = StartGetInput(Input) Catch ex As Exception - Log(ex, "加载输入获取失败(" & Name & ")", NotifyLevel.AllUsers) + Logger.Error(ex, $"加载输入获取失败({Name})", LogBehavior.Toast) [Error] = ex SyncLock LockState State = LoadState.Failed @@ -319,21 +319,21 @@ Sub() Try IsForceRestarting = IsForceRestart - If ModeDebug AndAlso Not LogBlackList.Contains(Name) Then Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已{If(IsForceRestarting, "强制", "")}启动") + If Not LogBlackList.Contains(Name) Then Logger.Trace(Function() $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已{If(IsForceRestarting, "强制", "")}启动") LoadDelegate(Me) If IsInterrupted Then - Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已中断但线程正常运行至结束,输出被弃用(最新线程:{If(LastRunningThread Is Nothing, -1, LastRunningThread.ManagedThreadId)})", NotifyLevel.DevelopOnly) + Logger.Warn($"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已中断但线程正常运行至结束,输出被弃用(最新线程:{If(LastRunningThread Is Nothing, -1, LastRunningThread.ManagedThreadId)})") Return End If - If ModeDebug AndAlso Not LogBlackList.Contains(Name) Then Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已完成") + If Not LogBlackList.Contains(Name) Then Logger.Trace(Function() $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已完成") RaisePreviewFinish() State = LoadState.Finished LastFinishedTime = GetTimeMs() '未中断,本次输出有效 Catch ex As CancelledException - If ModeDebug Then Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已触发取消中断,已完成 {Math.Round(Progress * 100)}%") + Logger.Trace(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已触发取消中断,已完成 {Math.Round(Progress * 100)}%") If Not IsInterrupted Then State = LoadState.Interrupted Catch ex As ThreadInterruptedException - If ModeDebug Then Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已触发线程中断,已完成 {Math.Round(Progress * 100)}%") + Logger.Trace(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已触发线程中断,已完成 {Math.Round(Progress * 100)}%") '如果线程是因为判断到 IsInterrupted 而提前中止,则代表已有新线程被重启,此时不应当改为 Interrupted '如果线程是在没有 IsInterrupted 时手动引发了 ThreadInterruptedException,则代表没有重启线程,这通常代表用户手动取消,应当改为 Interrupted If Not IsInterrupted Then State = LoadState.Interrupted @@ -354,7 +354,7 @@ If IsInterrupted OrElse State >= LoadState.Finished Then Return State = LoadState.Failed End SyncLock - Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 出错,已完成 {Math.Round(Progress * 100)}%", NotifyLevel.DevelopOnly) + Logger.Warn(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 出错,已完成 {Math.Round(Progress * 100)}%") TriggerThreadInterrupt() End Sub Public Overrides Sub Interrupt() @@ -368,7 +368,7 @@ If LastRunningThread Is Nothing Then Return If LastRunningThread.IsAlive Then LastRunningThread.Interrupt() - If ModeDebug Then Log($"[Loader] 加载线程 {Name} ({LastRunningThread.ManagedThreadId}) 已中断") + Logger.Trace(Function() $"加载线程 {Name} ({LastRunningThread.ManagedThreadId}) 已中断") End If LastRunningThread = Nothing End Sub @@ -376,7 +376,7 @@ Public Sub New() '仅仅是为了避免一些智障报错(继承类必须重写 New 的情况) End Sub - Public Sub New(Name As String, LoadDelegate As Action(Of LoaderTask(Of InputType, OutputType)), Optional InputDelegate As Func(Of InputType) = Nothing, Optional Priority As ThreadPriority = ThreadPriority.Normal) + Public Sub New(Name As String, LoadDelegate As Action(Of LoaderTask(Of TIn, TOut)), Optional InputDelegate As Func(Of TIn) = Nothing, Optional Priority As ThreadPriority = ThreadPriority.Normal) Me.Name = Name Me.LoadDelegate = LoadDelegate Me.InputDelegate = InputDelegate @@ -515,7 +515,7 @@ '检查是否需要重启 If Loader.GetType.Name.StartsWithF("LoaderTask") Then '类型名后面带有泛型,必须用 StartsWith If CType(Loader, Object).ShouldStart(If(Input IsNot Nothing AndAlso Loader.GetType.GenericTypeArguments.First Is Input.GetType, Input, Nothing), IgnoreReloadTimeout:=True) Then - Log("[Loader] 由于输入条件变更,重启已完成的加载器 " & Loader.Name) + Logger.Info($"由于输入条件变更,重启已完成的加载器 {Loader.Name}") GoTo Restart End If '更新下一个加载器的输入 @@ -527,7 +527,7 @@ '检查是否需要重启 If Loader.GetType.Name.StartsWithF("LoaderTask") Then If CType(Loader, Object).ShouldStart(If(Input IsNot Nothing AndAlso Loader.GetType.GenericTypeArguments.First Is Input.GetType, Input, Nothing), IgnoreReloadTimeout:=True) Then - Log("[Loader] 由于输入条件变更,重启进行中的加载器 " & Loader.Name, NotifyLevel.DevelopOnly) + Logger.Warn($"由于输入条件变更,重启进行中的加载器 {Loader.Name}") GoTo Restart End If End If @@ -598,7 +598,7 @@ Restart: Public Sub LoaderTaskbarAdd(Of T)(Loader As LoaderCombo(Of T)) If FrmSpeedLeft IsNot Nothing Then FrmSpeedLeft.TaskRemove(Loader) LoaderTaskbar.Add(Loader) - Log($"[Taskbar] {Loader.Name} 已加入任务列表") + Logger.Info($"{Loader.Name} 已加入任务列表") End Sub Public Sub LoaderTaskbarProgressRefresh() Try @@ -610,7 +610,7 @@ Restart: (Task.State = LoadState.Waiting OrElse Task.State = LoadState.Interrupted) Then FrmSpeedLeft?.TaskRefresh(Task) LoaderTaskbar.Remove(Task) - Log($"[Taskbar] {Task.Name} 已移出任务列表") + Logger.Info($"{Task.Name} 已移出任务列表") End If Next '更新平滑后的进度 @@ -635,7 +635,7 @@ Restart: FrmMain.BtnExtraDownload.ShowRefresh() End If Catch ex As Exception - Log(ex, "刷新任务栏进度显示失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "刷新任务栏进度显示失败") End Try End Sub Public Function LoaderTaskbarProgressGet() As Double @@ -643,7 +643,7 @@ Restart: If Not LoaderTaskbar.Any Then Return 1 Return LoaderTaskbar.Select(Function(l) l.Progress).Average().Clamp(0, 1) Catch ex As Exception - Log(ex, "获取任务栏进度出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "获取任务栏进度出错") Return 0.5 End Try End Function @@ -671,11 +671,10 @@ Restart: ''' ''' 用于检查文件夹修改的额外路径。该路径不会传入加载器。 Public Function LoaderFolderRun(Loader As LoaderBase, FolderPath As String, Type As LoaderFolderRunType, Optional MaxDepth As Integer = 0, Optional ExtraPath As String = "", Optional WaitForExit As Boolean = False) As Boolean - Dim FolderInfo As DirectoryInfo Dim Value As New LoaderFolderDictionaryEntry With {.FolderPath = FolderPath & ExtraPath, .LastCheckTime = Nothing} Try '获取数据 - FolderInfo = New DirectoryInfo(FolderPath & ExtraPath) + Dim FolderInfo = DirectoryUtils.GetInfo(FolderPath & ExtraPath) Value.LastCheckTime = If(FolderInfo.Exists, GetActualLastWriteTimeUtc(FolderInfo, MaxDepth), DirectCast(Nothing, Date?)) '如果已经检查过,则跳过 If Type = LoaderFolderRunType.RunOnUpdated AndAlso LoaderFolderDictionary.ContainsKey(Loader) Then @@ -687,7 +686,7 @@ Restart: End If End If Catch ex As Exception - Log(ex, "文件夹加载器启动检测出错") + Logger.Warn(ex, "文件夹加载器启动检测出错") End Try '写入检查数据 LoaderFolderDictionary(Loader) = Value diff --git a/Plain Craft Launcher 2/Modules/Base/ModNet.vb b/Plain Craft Launcher 2/Modules/Base/ModNet.vb index b0e7c24..fad8b5d 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModNet.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModNet.vb @@ -1,5 +1,4 @@ Imports System.Net.Sockets -Imports System.Runtime.CompilerServices Imports System.Threading.Tasks Public Module ModNet @@ -14,12 +13,12 @@ Public Module ModNet Optional Timeout As Integer = 25000, Optional Headers As String(,) = Nothing, Optional RequireJson As Boolean = False, Optional Encoding As Encoding = Nothing, Optional SimulateBrowserHeaders As Boolean = False, Optional MakeLog As Boolean = True) As String If Method Is Nothing Then Method = HttpMethod.Get - If MakeLog Then Log("[Net] 发起网络请求(" & Method.Method & "," & Url & "),最大超时 " & Timeout) + If MakeLog Then Logger.Info($"发起网络请求({Method.Method},{Url}),最大超时 {Timeout}") Try Dim HeaderDictionary = If(Headers, {}).ToDictionary If ContentType IsNot Nothing Then HeaderDictionary("Content-Type") = ContentType If Accept IsNot Nothing Then HeaderDictionary("Accept") = Accept - Dim Result = If(Encoding, Encoding.UTF8).GetString(SendRequest(Url, Method, Content, HeaderDictionary, Timeout:=Timeout, Encoding:=Encoding, SimulateBrowserHeaders:=SimulateBrowserHeaders)) + Dim Result = SendRequest(Url, Method, Content, HeaderDictionary, Timeout:=Timeout, Encoding:=Encoding, SimulateBrowserHeaders:=SimulateBrowserHeaders).GetString(Encoding) '检查结果是否为完整 JSON(在 #6683 中可能返回空,在被 GFW 截断时可能不完整) '在此处检查并报错,可以让 NetRequestByClientRetry 等方法进行重试 If RequireJson Then @@ -36,7 +35,7 @@ Public Module ModNet Catch ex As ThreadInterruptedException Throw Catch ex As Exception - If MakeLog Then Log(ex, "网络请求失败", NotifyLevel.DevelopOnly) + If MakeLog Then Logger.Warn(ex, "网络请求失败") Throw End Try End Function @@ -72,9 +71,10 @@ Retry: Catch ex As ThreadInterruptedException Throw Catch ex As Exception - If TypeOf ex Is ResponsedWebException Then - If CType(ex, ResponsedWebException).StatusCode = HttpStatusCode.Forbidden Then Throw - If CType(ex, ResponsedWebException).StatusCode = 429 Then Thread.Sleep(10000) 'Too Many Requests + If TypeOf ex Is HttpRequestCodeException Then + If CType(ex, HttpRequestCodeException).StatusCode = HttpStatusCode.Forbidden Then Throw + If CType(ex, HttpRequestCodeException).StatusCode = HttpStatusCode.NotFound Then Throw + If CType(ex, HttpRequestCodeException).StatusCode = 429 Then Thread.Sleep(10000) 'Too Many Requests End If '重试 Select Case RetryCount @@ -157,8 +157,9 @@ RequestFinished: Dim NewTask As New LoaderDownload("源码获取 " & GetUuid() & "#", New List(Of NetFile) From {New NetFile(Urls, Temp, New FileChecker With {.IsJson = IsJson}, SimulateBrowserHeaders)}) Try NewTask.WaitForExitTime(Timeout, TimeoutMessage:="连接服务器超时(第一下载源:" & Urls.First & ")") - NetRequestByLoader = ReadFile(Temp) - File.Delete(Temp) + Dim Result = FileUtils.ReadAsString(Temp) + FileUtils.Delete(Temp) + Return Result Finally NewTask.Interrupt() End Try @@ -173,29 +174,21 @@ RequestFinished: ''' 不建议用于下载大文件。 ''' Public Sub NetDownloadByClient(Url As String, LocalPath As String, Optional SimulateBrowserHeaders As Boolean = False) - Log($"[Net] 通过网络请求直接下载小文件:{Url} → {LocalPath}") - '初始化文件路径 - Try - DirectoryUtils.Create(LocalPath, isFilePath:=True) - File.Delete(LocalPath) - Catch ex As Exception - Throw New Exception($"预处理下载文件路径失败({LocalPath})", ex) - End Try - '下载 + Logger.Info($"通过网络请求直接下载小文件:{Url} → {LocalPath}") Dim RetryCount As Integer = 0 Retry: Try - File.WriteAllBytes(LocalPath, SendRequest(Url, HttpMethod.Get, SimulateBrowserHeaders:=SimulateBrowserHeaders)) + FileUtils.Write(LocalPath, SendRequest(Url, HttpMethod.Get, SimulateBrowserHeaders:=SimulateBrowserHeaders)) Catch ex As ThreadInterruptedException - File.Delete(LocalPath) + FileUtils.Delete(LocalPath) Throw Catch ex As Exception - File.Delete(LocalPath) + FileUtils.Delete(LocalPath) If RetryCount < 2 Then RetryCount += 1 GoTo Retry End If - Throw New WebException($"通过网络请求直接下载小文件失败({LocalPath})", ex) + Throw New HttpRequestException($"通过网络请求直接下载小文件失败({LocalPath})", ex) End Try End Sub @@ -259,6 +252,7 @@ Retry: HostIp = DNSLookup(Request, CancelToken.Token) If HostIp IsNot Nothing Then IPReliability.GetOrAdd(HostIp, -0.01) '预先降低一点,这样快速的重复请求会使用不同的 IP 以提高成功率 '发送请求 + Directory.CreateDirectory(PathTemp & "Cache\Http\") SyncLock RequestClientLock If RequestClient Is Nothing Then '延迟初始化,以避免在程序启动前加载 CacheCow 导致 DLL 加载失败 RequestClient = CacheCow.Client.ClientExtensions.CreateClient(New CacheCow.Client.FileCacheStore.FileStore(PathTemp & "Cache/Http/"), New HttpClientHandler With { @@ -283,14 +277,14 @@ Retry: Return ResponseBytes Else RecordIPReliability(HostIp, -0.7) - Dim ResponseMessage = If(Encoding, Encoding.UTF8).GetString(ResponseBytes) - Throw New ResponsedWebException( + Dim ResponseMessage = ResponseBytes.GetString(Encoding) + Throw New HttpRequestCodeException( $"错误码 {Response.StatusCode} ({CInt(Response.StatusCode)}),{Method},{Url},{HostIp}" & If(String.IsNullOrEmpty(ResponseMessage), "", vbCrLf & ResponseMessage), Response.StatusCode, ResponseMessage) End If Catch ex As ThreadInterruptedException Throw - Catch ex As ResponsedWebException + Catch ex As HttpRequestException Throw Catch ex As FileNotFoundException '由于 CacheCow 读取缓存失败,然后系统调用不存在的 System.Net.Http.Formatting.resources 抛出(#8150) @@ -299,7 +293,7 @@ Retry: RecordIPReliability(HostIp, -1) If TypeOf ex Is OperationCanceledException OrElse TypeOf ex Is TimeoutException Then 'CancellationToken 超时 Throw New WebException($"连接服务器超时,请稍后再试,或使用 VPN 改善网络环境({Method}, {Url},IP:{HostIp})", WebExceptionStatus.Timeout) - ElseIf ex.IsNetworkRelated Then + ElseIf ex.IsBadNetwork Then Throw New WebException($"网络请求失败,请稍后再试,或使用 VPN 改善网络环境({Method}, {Url},IP:{HostIp})", WebExceptionStatus.Timeout) Else Throw New Exception($"网络请求出现意外异常({Method}, {Url},{HostIp})", ex) @@ -337,12 +331,12 @@ Retry: If WaitHandle.WaitAny(New WaitHandle() {AsyncResult.AsyncWaitHandle, CancelToken.WaitHandle}) Then Throw New TimeoutException("DNS 解析超时") Candidates = Dns.EndGetHostAddresses(AsyncResult).Distinct.ToArray Catch ex As Exception - Log(ex, $"DNS 解析失败({Host})") + Logger.Warn(ex, $"DNS 解析失败({Host})") DNSFailureRecord(Host) = Date.Now Return Nothing End Try If Not Candidates.Any Then - Log($"[Net] DNS 解析无结果({Host})") + Logger.Info($"DNS 解析无结果({Host})") Return Nothing End If '若同时存在 IPv4 和 IPv6 地址,仅选择其中一类(因为 GFW 可能只屏蔽了 IPv4 或 IPv6) @@ -353,7 +347,7 @@ Retry: Dim IPv4Reliability = IPv4Targets.Max(Function(i) Reliabilities(i)) Dim IPv6Reliability = IPv6Targets.Max(Function(i) Reliabilities(i)) If Host = "api.modrinth.com" Then IPv6Reliability -= 0.1 '让 Modrinth 优先使用 IPv4 地址(#6887) - If ModeDebug Then Log($"[Net] DNS IPv4/IPv6 选择({Host}),IPv4 {IPv4Reliability:0.000},IPv6 {IPv6Reliability:0.000}") + Logger.Trace(Function() $"DNS IPv4/IPv6 选择({Host}),IPv4 {IPv4Reliability:0.000},IPv6 {IPv6Reliability:0.000}") Candidates = If(IPv4Reliability >= IPv6Reliability, IPv4Targets, IPv6Targets) End If '选择可靠度最高的 IP @@ -379,27 +373,6 @@ Retry: ) End Sub - ''' - ''' 当 HTTP 状态码不指示成功时引发的异常。 - ''' 附带额外属性,可用于获取远程服务器给予的回复以及 HTTP 状态码。 - ''' - Public Class ResponsedWebException - Inherits WebException - ''' - ''' HTTP 状态码。 - ''' - Public StatusCode As HttpStatusCode - ''' - ''' 远程服务器给予的回复。 - ''' - Public Overloads Property Response As String - Public Sub New(Message As String, StatusCode As HttpStatusCode, Response As String) - MyBase.New(Message) - Me.StatusCode = StatusCode - Me.Response = Response - End Sub - End Class - #End Region #Region "多线程下载引擎" @@ -413,7 +386,7 @@ Retry: ''' Public ReadOnly Property NetTaskThreadLimit As Integer Get - Return Settings.Get("ToolDownloadThread") + 1 + Return Settings.Get(Of Integer)("ToolDownloadThread") + 1 End Get End Property ''' @@ -426,7 +399,7 @@ Retry: Public ReadOnly Property NetTaskSpeedLimitHigh As Long Get If _NetTaskSpeedLimitHigh Is Nothing Then - Dim Setting As Integer = Settings.Get("ToolDownloadSpeed") + Dim Setting As Integer = Settings.Get(Of Integer)("ToolDownloadSpeed") If Setting <= 14 Then _NetTaskSpeedLimitHigh = (Setting + 1) * 0.1 * 1024 * 1024L ElseIf Setting <= 31 Then @@ -822,7 +795,7 @@ Retry: Private _Speed As Long = 0 ''' - ''' 该文件是否由本地文件直接拷贝完成。 + ''' 该文件是否由本地文件直接复制完成。 ''' Public IsCopy As Boolean = False ''' @@ -901,7 +874,7 @@ Retry: Me.LocalPath = LocalPath Me.Check = Checker Me.SimulateBrowserHeaders = SimulateBrowserHeaders - Me.LocalName = GetFileNameFromPath(LocalPath) + Me.LocalName = PathUtils.GetLastPart(LocalPath) End Sub ''' @@ -1003,7 +976,7 @@ StartThread: ''' 每个下载线程执行的代码。 ''' Private Sub Thread(Th As NetThread) - If ModeDebug OrElse Th.DownloadStart = 0 Then Log($"[Download] {LocalName}:开始,起始点 {Th.DownloadStart},{Th.Source.Url}") + Logger.Log($"{LocalName}:开始,起始点 {Th.DownloadStart},{Th.Source.Url}", If(Th.DownloadStart = 0, LogLevel.Info, LogLevel.Trace)) Dim ResultStream As Stream = Nothing, HttpRequest As HttpRequestMessage = Nothing, Response As HttpResponseMessage = Nothing, ResponseStream As Stream = Nothing, CancelToken As CancellationTokenSource = Nothing, HostIp As String = Nothing @@ -1021,22 +994,24 @@ StartThread: If Not Th.IsFirstThread Then HttpRequest.Headers.Range = New Headers.RangeHeaderValue(Th.DownloadStart, Nothing) Dim ContentLength As Long = 0 Response = ThreadClient.SendAsync(HttpRequest, HttpCompletionOption.ResponseHeadersRead, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout) - If Not Response.IsSuccessStatusCode Then Throw New Exception($"错误码 {Response.StatusCode} ({CInt(Response.StatusCode)}),{Th.Source.Url}") '状态码检查 + If Not Response.IsSuccessStatusCode Then '状态码检查 + Throw New HttpRequestCodeException($"错误码 {Response.StatusCode} ({CInt(Response.StatusCode)}),{Th.Source.Url}", Response.StatusCode, Nothing) + End If If State = NetState.Interrupted Then GoTo SourceBreak '快速中断 - If ModeDebug AndAlso Response.RequestMessage.RequestUri.ToString <> Th.Source.Url Then Log($"[Download] {LocalName}:重定向至 {Response.RequestMessage.RequestUri}") + If Response.RequestMessage.RequestUri.ToString <> Th.Source.Url Then Logger.Trace(Function() $"{LocalName}:重定向至 {Response.RequestMessage.RequestUri}") '文件大小校验 ContentLength = Response.Content.Headers.ContentLength.GetValueOrDefault(-1) If ContentLength < 0 Then If FileSize > 1 Then If Th.DownloadStart = 0 Then - Log($"[Download] {LocalName}:文件大小未知,但已从其他下载源获取,不作处理") + Logger.Info($"{LocalName}:文件大小未知,但已从其他下载源获取,不作处理") Else - Log($"[Download] {LocalName}:ContentLength 返回了 {ContentLength},无法确定是否支持分段下载,视作不支持") + Logger.Info($"{LocalName}:ContentLength 返回了 {ContentLength},无法确定是否支持分段下载,视作不支持") GoTo NotSupportRange End If Else FileSize = -1 : IsUnknownSize = True - Log($"[Download] {LocalName}:文件大小未知") + Logger.Info($"{LocalName}:文件大小未知") End If ElseIf Th.IsFirstThread Then If Check IsNot Nothing Then @@ -1048,7 +1023,7 @@ StartThread: End If End If FileSize = ContentLength : IsUnknownSize = False - Log($"[Download] {LocalName}:文件大小 {ContentLength}({FormatFileSize(ContentLength)})") + Logger.Info($"{LocalName}:文件大小 {ContentLength}({FormatFileSize(ContentLength)})") '若文件大小大于 50 M,进行剩余磁盘空间校验 If ContentLength > 50 * 1024 * 1024 Then For Each Drive As DriveInfo In DriveInfo.GetDrives @@ -1084,17 +1059,16 @@ NotSupportRange: ResultStream = Cache Else Th.Temp = $"{PathTemp}Download\{Uuid}_{Th.Uuid}_{RandomInteger(0, 999999)}.tmp" - DirectoryUtils.Create(Th.Temp, isFilePath:=True) - ResultStream = New FileStream(Th.Temp, FileMode.Create, FileAccess.Write, FileShare.Read) + ResultStream = FileUtils.CreateAsStream(Th.Temp) End If '开始下载 CancelToken.Dispose() : CancelToken = New CancellationTokenSource() '重置超时,不再让 CancellationToken 在固定时间后触发(#8488) ResponseStream = Response.Content.ReadAsStreamAsync().GetAwaiter().GetResult() - If Settings.Get("SystemDebugDelay") Then Threading.Thread.Sleep(RandomInteger(50, 3000)) + If Settings.Get(Of Boolean)("SystemDebugDelay") Then Threading.Thread.Sleep(RandomInteger(50, 3000)) Dim ResponseBytes As Byte() = New Byte(16384) {} HttpDataCount = ResponseStream.ReadAsync(ResponseBytes, 0, 16384, CancelToken.Token).GetResultWithTimeout(CancelToken, Timeout) While (IsUnknownSize OrElse Th.DownloadUndone > 0) AndAlso '判断是否下载完成 - HttpDataCount > 0 AndAlso Not IsProgramEnded AndAlso State < NetState.Merging AndAlso (Not Th.Source.IsFailed OrElse Th.Source.SingleThread = Th) + HttpDataCount > 0 AndAlso Not IsProgramEnding AndAlso State < NetState.Merging AndAlso (Not Th.Source.IsFailed OrElse Th.Source.SingleThread = Th) '限速 While NetTaskSpeedLimitHigh > 0 AndAlso NetTaskSpeedLimitLeft <= 0 Threading.Thread.Sleep(16) @@ -1140,19 +1114,22 @@ SourceBreak: If State = NetState.Interrupted OrElse (Th.Source.IsFailed AndAlso Th.Source.SingleThread <> Th) OrElse (Th.DownloadUndone > 0 AndAlso Not IsUnknownSize) Then '被外部中断 Th.State = NetState.Interrupted - Log($"[Download] {LocalName}:中断") + Logger.Info($"{LocalName}:中断") ElseIf HttpDataCount = 0 AndAlso Th.DownloadUndone > 0 AndAlso Not IsUnknownSize Then '服务器无返回数据 Throw New Exception($"返回的 ContentLength 过多:ContentLength 为 {ContentLength},但获取到的总数据量仅为 {Th.DownloadDone}(全文件总数据量 {DownloadDone})") Else '本线程完成 Th.State = NetState.Finished - If ModeDebug Then Log($"[Download] {LocalName}:完成,已下载 {Th.DownloadDone}({Th.DownloadStart}~{Th.DownloadEnd})") + Logger.Trace(Function() $"{LocalName}:完成,已下载 {Th.DownloadDone}({Th.DownloadStart}~{Th.DownloadEnd})") RecordIPReliability(HostIp, 0.5) End If Catch ex As Exception - Log($"[Download] {LocalName}:出错,{If(TypeOf ex Is OperationCanceledException OrElse TypeOf ex Is TimeoutException, - $"已超时({Timeout}ms)", ex.GetDetail())},IP:{HostIp}") + If ex.IsBadNetwork OrElse TypeOf ex Is TaskCanceledException Then + Logger.Info(New TimeoutException($"{LocalName}:超时({Timeout}ms),{ex.Message},IP:{If(String.IsNullOrEmpty(HostIp), "自动", "")}")) + Else + Logger.Info(ex, $"{LocalName}:出错,IP:{HostIp}") + End If RecordIPReliability(HostIp, -0.7) SourceFail(Th, ex, False) Finally @@ -1194,9 +1171,8 @@ SourceBreak: End SyncLock '……后续处理 If IsThisFail Then - Log($"[Download] {LocalName}:下载源被禁用({Th.Source.Id},Range 问题:{IsRangeNotSupported}):{Th.Source.Url}") - Log(ex, $"{If(SourcesOnce.FirstOrDefault?.SingleThread Is Nothing, "", "单线程")}下载源 {Th.Source.Id} 已被禁用", - If(IsRangeNotSupported OrElse ex.Message.Contains("(404)"), NotifyLevel.DevelopOnly, NotifyLevel.DebugModeOnly)) + Logger.Info($"{LocalName}:下载源被禁用({Th.Source.Id},Range 问题:{IsRangeNotSupported}):{Th.Source.Url}") + Logger.Warn(ex, $"{If(SourcesOnce.FirstOrDefault?.SingleThread Is Nothing, "", "单线程")}下载源 {Th.Source.Id} 已被禁用") SyncLock LockSource SourcesOnce.Remove(Th.Source) End SyncLock @@ -1208,7 +1184,7 @@ SourceBreak: ElseIf Not Retried Then '合并失败或首次下载失败,未重试:将所有下载源重新标记为不允许断点续传的下载源,逐个重新尝试下载 '若所有源均不支持 Range,也会走到这里重试 - If Not IsRangeNotSupported Then Log($"[Download] {LocalName}:文件下载失败,正在自动重试……", NotifyLevel.DebugModeOnly) + If Not IsRangeNotSupported Then Logger.Warn($"{LocalName}:文件下载失败,正在自动重试……") Retried = True SyncLock LockSource SourcesOnce.Clear() @@ -1229,14 +1205,14 @@ SourceBreak: End SyncLock Else '失败 - Log($"[Download] {LocalName}:已无可用下载源,下载失败") + Logger.Info($"{LocalName}:已无可用下载源,下载失败") Dim ExampleEx As Exception = Nothing SyncLock LockSource For Each Source As NetSource In Sources - Log("[Download] 已禁用的下载源:" & Source.Url) + Logger.Info($"已禁用的下载源:{Source.Url}") If Source.Ex IsNot Nothing Then ExampleEx = Source.Ex - Log(Source.Ex, "下载源禁用原因", NotifyLevel.DevelopOnly) + Logger.Warn(Source.Ex, "下载源禁用原因") End If Next End SyncLock @@ -1276,26 +1252,26 @@ SourceBreak: Try Retry: '创建文件夹 - DirectoryUtils.Create(LocalPath, isFilePath:=True) - If File.Exists(LocalPath) Then File.Delete(LocalPath) + DirectoryUtils.Create(PathUtils.RemoveLastPart(LocalPath)) + FileUtils.Delete(LocalPath) SyncLock LockChain '合并文件 If IsNoSplit Then '仅有一个线程,从内存中输出 - If ModeDebug Then Log($"[Download] {LocalName}:下载结束,从内存输出文件") + Logger.Trace(Function() $"{LocalName}:下载结束,从内存输出文件") FileUtils.Write(LocalPath, Cache) ElseIf Threads.DownloadDone = DownloadDone AndAlso Threads.Temp IsNot Nothing Then '仅有一个文件,直接复制 - If ModeDebug Then Log($"[Download] {LocalName}:下载结束,仅有一个文件,无需合并") - CopyFile(Threads.Temp, LocalPath) + Logger.Trace(Function() $"{LocalName}:下载结束,仅有一个文件,无需合并") + FileUtils.Copy(Threads.Temp, LocalPath) Else '有多个线程,合并 - If ModeDebug Then Log($"[Download] {LocalName}:下载结束,开始合并文件") - Using MergeFile As New FileStream(LocalPath, FileMode.Create) + Logger.Trace(Function() $"{LocalName}:下载结束,开始合并文件") + Using MergeFile = FileUtils.CreateAsStream(LocalPath) Using AddWriter As New BinaryWriter(MergeFile) For Each Thread As NetThread In Threads If Thread.DownloadDone = 0 OrElse Thread.Temp Is Nothing Then Continue For - Using fs As New FileStream(Thread.Temp, FileMode.Open, FileAccess.Read, FileShare.Read) + Using fs = FileUtils.ReadAsStream(Thread.Temp) Using TempReader As New BinaryReader(fs) AddWriter.Write(TempReader.ReadBytes(Thread.DownloadDone)) End Using @@ -1314,16 +1290,16 @@ Retry: End If End If If CheckResult IsNot Nothing Then - Log($"[Download] {LocalName} 文件校验失败,下载线程细节:") + Logger.Info($"{LocalName} 文件校验失败,下载线程细节:") For Each T As NetThread In Threads - Log($"[Download] - {T.Uuid}#,状态 {GetStringFromEnum(T.State)},范围 {T.DownloadStart}~{T.DownloadEnd},已下载 {T.DownloadDone},未下载 {T.DownloadUndone}") + Logger.Info($"- {T.Uuid}#,状态 {T.State},范围 {T.DownloadStart}~{T.DownloadEnd},已下载 {T.DownloadDone},未下载 {T.DownloadUndone}") Next Throw New Exception(CheckResult) End If '后处理 If Not IsNoSplit Then For Each Thread As NetThread In Threads - If Thread.Temp IsNot Nothing Then File.Delete(Thread.Temp) + If Thread.Temp IsNot Nothing Then FileUtils.Delete(Thread.Temp) Next End If Finish() @@ -1331,7 +1307,7 @@ Retry: Catch ex As Exception RetryCount += 1 If State > NetState.Merging Then Return '通常是因为在合并时被中断了 - Log(ex, $"合并文件出错,第 {RetryCount} 次尝试({LocalName})") + Logger.Warn(ex, $"合并文件出错,第 {RetryCount} 次尝试({LocalName})") '重新尝试合并 If RetryCount < 3 Then Threading.Thread.Sleep(500 * RetryCount) @@ -1339,9 +1315,9 @@ Retry: End If '失败,禁用当前下载源并重启下载 Try - If File.Exists(LocalPath) Then File.Delete(LocalPath) + FileUtils.Delete(LocalPath) Catch exx As Exception - Log(ex, $"删除合并失败的文件出错({LocalPath})") + Logger.Warn(ex, $"删除合并失败的文件出错({LocalPath})") End Try SourceFail(Th, ex, True) Finally @@ -1356,7 +1332,7 @@ Retry: If State >= NetState.Finished Then Return If RaiseEx IsNot Nothing Then Ex.Add(RaiseEx) '凉凉 - Log($"[Download] {LocalName}:已失败,当前状态 {State}") + Logger.Info($"{LocalName}:已失败,当前状态 {State}") State = NetState.Interrupted End SyncLock InterruptInternal() @@ -1374,7 +1350,7 @@ Retry: '确认中断 SyncLock LockState If State >= NetState.Finished Then Return - Log($"[Download] {LocalName}:已中断,当前状态 {State}") + Logger.Info($"{LocalName}:已中断,当前状态 {State}") State = NetState.Interrupted End SyncLock InterruptInternal() @@ -1395,7 +1371,7 @@ Retry: State = NetState.Finished End SyncLock Interlocked.Decrement(NetManager.FileRemain) - If PrintLog Then Log($"[Download] {LocalName}:已完成") + If PrintLog Then Logger.Info($"{LocalName}:已完成") For Each Task In Tasks Task.OnFileFinish(Me) Next @@ -1403,7 +1379,7 @@ Retry: End Class Private Class RangeNotSupportedException - Inherits WebException + Inherits HttpRequestException Public Sub New(Message As String) MyBase.New(Message) End Sub @@ -1451,7 +1427,7 @@ Retry: Set(value As Integer) _FailCount = value If State = LoadState.Loading AndAlso value >= Math.Min(10000, Math.Max(FileRemain * 5.5, NetTaskThreadLimit * 5.5 + 3)) Then - Log("[Download] 由于同加载器中失败次数过多引发强制失败:连续失败了 " & value & " 次", NotifyLevel.DebugModeOnly) + Logger.Warn($"由于同加载器中失败次数过多引发强制失败:连续失败了 {value} 次") On Error Resume Next Dim ExList As New List(Of Exception) For Each File In Files @@ -1492,7 +1468,7 @@ FinishExCatch: _Progress = NewProgress End Sub - Public Sub New(Name As String, FileTasks As List(Of NetFile)) + Public Sub New(Name As String, FileTasks As IEnumerable(Of NetFile)) Me.Name = Name Files = New ConcurrentList(Of NetFile)(FileTasks) End Sub @@ -1526,7 +1502,7 @@ FinishExCatch: File.LocalPath = File.LocalPath.Replace("/", "\") If Not File.LocalPath.Lower.Contains(":\") Then Throw New ArgumentException("输入的本地文件地址不正确:" & File.LocalPath) If File.LocalPath.EndsWithF("\") Then Throw New ArgumentException("请输入含文件名的完整文件路径:" & File.LocalPath) - DirectoryUtils.Create(File.LocalPath, isFilePath:=True) '创建目标文件夹 + DirectoryUtils.Create(PathUtils.RemoveLastPart(File.LocalPath)) '创建目标文件夹 Next '接入下载管理器,获取新开始下载的文件列表 Dim NewFiles = NetManager.Start(Me) @@ -1552,7 +1528,7 @@ FinishExCatch: Dim Folders As New List(Of String) Folders.Add(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\") '总是添加官启文件夹,因为 HMCL 会把所有文件存在这里 Folders.AddRange(McFolderList.Select(Function(f) f.Location)) - Folders = Folders.Distinct.Where(Function(f) Directory.Exists(f)).ToList + Folders = Folders.Distinct.Where(Function(f) DirectoryUtils.Exists(f)).ToList '平均分配到多个检查线程 Dim ThreadCount As Integer = (FilesToCheck.Count \ 40).Clamp(1, 8) '每个线程至少 40 个文件,最多 8 线程 If ThreadCount = 1 Then '只有一个线程,直接执行 @@ -1575,43 +1551,27 @@ FinishExCatch: End Sub Private Sub CheckExistingFiles(Files As List(Of NetFile), FolderList As List(Of String)) Try - If ModeDebug Then Log($"[Download] 文件检查开始,本线程负责的文件数:{Files.Count}") + Logger.Trace(Function() $"文件检查开始,本线程负责 {Files.Count} 个文件,首个文件为 {Files.FirstOrDefault?.LocalName}") '列出 MC 文件夹中的各个版本文件夹 Dim VersionFolders As New List(Of String) For Each McFolder In FolderList - Dim VersionsFolder As New DirectoryInfo(McFolder & "versions\") - If VersionsFolder.Exists() Then - For Each VersionFolder In VersionsFolder.GetDirectories - VersionFolders.Add(VersionFolder.FullName & "\") - Next - End If + For Each VersionFolder In DirectoryUtils.GetDirectories(McFolder & "versions\", True) + VersionFolders.Add(PathUtils.AddSlashSuffix(VersionFolder)) + Next Next '处理每个文件 For Each File As NetFile In Files Dim Target As String = CheckExistingFile(FolderList, VersionFolders, File) - If ModeDebug Then Log($"[Download] 文件检查结果:{File.LocalName} → {Target},当前状态 {File.State}") + Logger.Trace(Function() $"本地文件匹配:{File.LocalName} → {If(Target, "无匹配")},当前状态 {File.State}") If File.State >= NetState.WaitingToDownload Then Continue For '中断 '已找到相同文件 If Target IsNot Nothing Then File.IsCopy = True - Dim RetryCount As Integer = 0 -Retry: Try - If Target <> File.LocalPath Then - Log($"[Download] 复制已存在的文件:{Target} → {File.LocalPath}") - CopyFile(Target, File.LocalPath) - Else - If ModeDebug Then Log($"[Download] 需要下载的文件已存在,并通过校验:{Target}") - End If + FileUtils.Copy(Target, File.LocalPath) File.Finish(False) Continue For - Catch ex As Exception - RetryCount += 1 - Log(ex, $"复制已存在的文件失败,第 {RetryCount} 次重试({Target} → {File.LocalPath})") - If RetryCount < 3 Then - Thread.Sleep(2000) - GoTo Retry - End If + Catch End Try End If '回退到下载 @@ -1628,7 +1588,7 @@ Retry: '目标文件已存在 If File.Check.Check(File.LocalPath) Is Nothing Then Return File.LocalPath '在设置中禁用了复制 - If Settings.Get("SystemDebugSkipCopy") Then Return Nothing + If Settings.Get(Of Boolean)("SystemDebugSkipCopy") Then Return Nothing '没有可用的检查规则,只能开始下载 If File.Check.Hash Is Nothing AndAlso File.Check.ActualSize < 0 Then Return Nothing '大致判断文件类别 @@ -1646,37 +1606,35 @@ Retry: Dim Type = TypeIndexes.MaxBy(Function(kv) kv.Item2).FolderName.TrimStart("\"c) '根据类别进行查找 Static Sizes As New ConcurrentDictionary(Of String, Long) + Static CheckCandidate As Func(Of String, FileChecker, Boolean) = + Function(Candidate, Checker) + '快速进行大小校验 + Dim Length = Sizes.GetOrAdd(Candidate, Function(c) If(FileUtils.Exists(c), FileUtils.GetInfo(c).Length, -1)) + If Checker.ActualSize <> Length Then Return False + '进一步进行 Hash 校验 + Return Checker.Check(Candidate) Is Nothing + End Function Select Case Type Case "assets\", "libraries\" 'assets/libraries:查找 MC 文件夹下的相同路径 For Each Folder In FolderList Dim Candidate = Folder & Type & File.LocalPath.AfterFirst(Type) - If File.Check.Check(Candidate) Is Nothing Then Return Candidate + If CheckCandidate(Candidate, File.Check) Then Return Candidate Next + Return Nothing Case "versions\" '版本 jar 或 json:查找 MC 文件夹下的各个版本文件夹 For Each VersionFolder In VersionFolders - For Each Candidate In Directory.GetFiles(VersionFolder, - "*." & GetFileNameFromPath(File.LocalPath).AfterLast(".").Lower, SearchOption.TopDirectoryOnly) - '快速进行大小校验 - Dim Length = Sizes.GetOrAdd(Candidate, Function(c) New FileInfo(c).Length) - If File.Check.ActualSize <> Length Then Continue For - 'Hash 校验 - If File.Check.Check(Candidate) Is Nothing Then Return Candidate + For Each Candidate In DirectoryUtils.GetFiles(VersionFolder, True, "*." & PathUtils.GetLastPart(File.LocalPath).AfterLast(".").Lower) + If CheckCandidate(Candidate, File.Check) Then Return Candidate Next Next Case Else '社区资源 If File.Check.ActualSize < 0 OrElse File.Check.Hash Is Nothing Then Return Nothing '必须要求指定了文件大小和 Hash For Each Folder In FolderList.Concat(VersionFolders) - Dim TargetFolder = Folder & Type - If Not Directory.Exists(TargetFolder) Then Continue For - For Each Candidate In Directory.GetFiles(TargetFolder) - '快速进行大小校验 - Dim Length = Sizes.GetOrAdd(Candidate, Function(c) New FileInfo(c).Length) - If File.Check.ActualSize <> Length Then Continue For - 'Hash 校验 - If File.Check.Check(Candidate) Is Nothing Then Return Candidate + For Each Candidate In DirectoryUtils.GetFiles(Folder & Type, True) + If CheckCandidate(Candidate, File.Check) Then Return Candidate Next Next End Select @@ -1719,7 +1677,7 @@ Retry: For Each File In Files If File.State <> NetState.Interrupted Then Continue For If File.Sources.All(Function(s) TypeOf s.Ex Is OperationCanceledException OrElse TypeOf s.Ex Is TimeoutException OrElse TypeOf s.Ex Is ThreadInterruptedException) Then Continue For - Dim Detail As String = File.Sources.Select(Function(s) $"{If(s.Ex Is Nothing, "无错误信息。", s.Ex.GetBrief())}({s.Url})").Join(vbCrLf) + Dim Detail As String = File.Sources.Select(Function(s) $"{If(s.Ex Is Nothing, "无错误信息。", s.Ex.GetDisplay(False))}({s.Url})").Join(vbCrLf) [Error] = New Exception("文件下载失败:" & File.LocalPath & vbCrLf & "各下载源的错误如下:" & vbCrLf & Detail, [Error]) '上报 @@ -1736,18 +1694,14 @@ Retry: TaskFile.Interrupt(Me) Next '在退出同步锁后再进行日志输出 - Dim ErrOutput As New List(Of String) - For Each Ex As Exception In ExList - ErrOutput.Add(Ex.GetDetail()) - Next - Log("[Download] " & ErrOutput.Distinct.Join(vbCrLf)) + Logger.Error(New AggregateException(ExList), "下载加载器失败", LogBehavior.None) End Sub Public Overrides Sub Interrupt() SyncLock LockState If State >= LoadState.Finished Then Return State = LoadState.Interrupted End SyncLock - Log("[Download] " & Name & " 已取消!") + Logger.Info($"{Name} 已取消!") '中断所有文件 For Each TaskFile In Files TaskFile.Interrupt(Me) @@ -1823,7 +1777,7 @@ Retry: If SpeedLast.Count >= 10 Then Limit = SpeedLast.Take(10).Average * 0.85 '取近 1 秒的平均速度的 85% If Limit > NetTaskSpeedLimitLow Then NetTaskSpeedLimitLow = Limit - Log("[Download] " & "速度下限已提升到 " & FormatFileSize(Limit)) + Logger.Info($"速度下限已提升到 {FormatFileSize(Limit)}") End If #End Region #Region "刷新下载任务属性" @@ -1832,7 +1786,7 @@ Retry: Next #End Region Catch ex As Exception - Log(ex, "刷新下载公开属性失败") + Logger.Warn(ex, "刷新下载公开属性失败") End Try End Sub Private RefreshStatLast As Long @@ -1889,7 +1843,7 @@ Retry: Next End While Catch ex As Exception - Log(ex, $"下载管理启动线程 {Id} 出错", NotifyLevel.Critical) + Logger.Error(ex, $"下载管理启动线程 {Id} 出错", LogBehavior.AlertThenCrash) End Try End Sub RunInNewThread(Sub() ThreadStarter(0), "NetManager ThreadStarter 0") @@ -1913,7 +1867,7 @@ Retry: End If End While Catch ex As Exception - Log(ex, "下载管理刷新线程出错", NotifyLevel.Critical) + Logger.Error(ex, "下载管理刷新线程出错", LogBehavior.AlertThenCrash) End Try End Sub, "NetManager StatRefresher") End Sub @@ -1929,11 +1883,11 @@ Retry: SyncLock DownloadCacheLock '防止同时开启多个下载任务时重复清理 If Not IsDownloadCacheCleared Then Try - Log("[Net] 开始清理下载缓存") - DeleteDirectory(PathTemp & "Download") - Log("[Net] 下载缓存已清理") + Logger.Info("开始清理下载缓存") + DirectoryUtils.Delete(PathTemp & "Download") + Logger.Info("下载缓存已清理") Catch ex As Exception - Log(ex, "清理下载缓存失败") + Logger.Warn(ex, "清理下载缓存失败") End Try IsDownloadCacheCleared = True End If @@ -1945,12 +1899,12 @@ Retry: Dim OngoingFile As NetFile = Nothing If AllFiles.TryGetValue(File.LocalPath, OngoingFile) AndAlso OngoingFile.State < NetState.Finished Then '该文件正在被另一个任务下载 - If ModeDebug Then Log($"[Download] {File.LocalName}:无需开始,该文件已在下载中,目标 {File.LocalPath}") + Logger.Trace(Function() $"{File.LocalName}:无需开始,该文件已在下载中,目标 {File.LocalPath}") File = OngoingFile '将列表中的文件替换成下载中的文件,即两个任务指向同一个文件;抛弃现在的 File 对象 Task.Files(i) = File Else '常规情况(该文件可能已在其他任务中下载完成,但这并不影响) - If ModeDebug Then Log($"[Download] {File.LocalName}:开始,目标 {File.LocalPath}") + Logger.Trace(Function() $"{File.LocalName}:开始,目标 {File.LocalPath}") AllFiles(File.LocalPath) = File NewFiles.Add(File) Interlocked.Increment(FileRemain) @@ -2021,38 +1975,18 @@ Retry: Try PingResult = (New NetworkInformation.Ping).Send(Ip) Catch ex As Exception - If MakeLog Then Log("[Net] Ping " & Ip & " 失败:" & ex.Message) + If MakeLog Then Logger.Info($"Ping {Ip} 失败:{ex.Message}") Return -1 End Try If PingResult.Status = NetworkInformation.IPStatus.Success Then - If MakeLog Then Log("[Net] Ping " & Ip & " 结束:" & PingResult.RoundtripTime & "ms") + If MakeLog Then Logger.Info($"Ping {Ip} 结束:{PingResult.RoundtripTime}ms") Return PingResult.RoundtripTime Else - If MakeLog Then Log("[Net] Ping " & Ip & " 失败") + If MakeLog Then Logger.Info($"Ping {Ip} 失败") Return -1 End If End Function - ''' - ''' 判断某个 Exception 是否为网络问题所导致。 - ''' - Public Function IsNetworkRelated(Ex As Exception) As Boolean - '提取 Message(不能用 GetDetail,因为堆栈的方法参数中就有 timeout 字样) - Dim Detail As String = "" - Dim InnerEx As Exception = Ex - Detail += InnerEx.Message - Do Until InnerEx.InnerException Is Nothing - InnerEx = InnerEx.InnerException - Detail += InnerEx.Message - Loop - '判断 - If Detail.Contains("(403)") Then Return False - Return { - "(408)", "超时", "timeout", "网络请求失败", "连接尝试失败", "远程主机强迫关闭了", "远程方已关闭传输流", "未能解析此远程名称", - "由于目标计算机积极拒绝", "基础连接已经关闭" - }.Any(Function(k) Detail.ContainsIgnoreCase(k)) - End Function - ''' ''' 设置是否应当在正版登录时校验 SSL 证书。 ''' @@ -2062,7 +1996,7 @@ Retry: Dim Request As HttpWebRequest = TryCast(Sender, HttpWebRequest) If Failure = Net.Security.SslPolicyErrors.None Then Return True '已通过验证 '基于 #3018 和 #5879,只在访问正版登录 API 时跳过证书验证 - Log($"[System] 未通过 SSL 证书验证({Failure}),提供的证书为 {Certificate?.Subject},URL:{Request?.Address}", NotifyLevel.DebugModeOnly) + Logger.Warn($"未通过 SSL 证书验证({Failure}),提供的证书为 {Certificate?.Subject},URL:{Request?.Address}") If Request Is Nothing Then Return Not Enabled ElseIf Request.Address.Host.Contains("xboxlive") OrElse Request.Address.Host.Contains("minecraftservices") Then diff --git a/Plain Craft Launcher 2/Modules/Base/ModValidate.vb b/Plain Craft Launcher 2/Modules/Base/ModValidate.vb index bb34cf7..ac59075 100644 --- a/Plain Craft Launcher 2/Modules/Base/ModValidate.vb +++ b/Plain Craft Launcher 2/Modules/Base/ModValidate.vb @@ -80,7 +80,7 @@ Public Class ValidateRegex Me.ErrorDescription = ErrorDescription End Sub Public Overrides Function Validate(Str As String) As String - If Not RegexCheck(Str, Regex) Then Return ErrorDescription + If Not Str.RegexCheck(Regex) Then Return ErrorDescription Return "" End Function End Class @@ -94,7 +94,7 @@ Public Class ValidateHttp End Sub '用于 XAML 初始化 Public Overrides Function Validate(Str As String) As String If Str.EndsWithF("/") Then Str = Str.Substring(0, Str.Length - 1) - If Not RegexCheck(Str, "^(http[s]?)\://") Then Return "输入的网址无效!" + If Not Str.RegexCheck("^(http[s]?)\://") Then Return "输入的网址无效!" Return "" End Function End Class @@ -247,7 +247,7 @@ Public Class ValidateFolderName Public Property Folder As String Public Property UseMinecraftCharCheck As Boolean = True Public Property IgnoreCase As Boolean = True - Private ReadOnly PathIgnore As IEnumerable(Of DirectoryInfo) + Private ReadOnly PathIgnore As IEnumerable(Of String) Public Sub New() End Sub Public Sub New(Folder As String, Optional UseMinecraftCharCheck As Boolean = True, Optional IgnoreCase As Boolean = True) @@ -255,7 +255,7 @@ Public Class ValidateFolderName Me.IgnoreCase = IgnoreCase Me.UseMinecraftCharCheck = UseMinecraftCharCheck On Error Resume Next - PathIgnore = New DirectoryInfo(Folder).EnumerateDirectories + PathIgnore = DirectoryUtils.GetDirectories(Folder, True) End Sub Public Overrides Function Validate(Str As String) As String Try @@ -277,19 +277,19 @@ Public Class ValidateFolderName Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件夹名不可为 %!", True).Validate(Str) If InvalidStrCheck <> "" Then Return InvalidStrCheck '检查 NTFS 8.3 文件名(#4505) - If RegexCheck(Str, ".{2,}~\d") Then Return "文件夹名不能包含这一特殊格式!" + If Str.RegexCheck(".{2,}~\d") Then Return "文件夹名不能包含这一特殊格式!" '检查文件夹重名 Dim Arr As New List(Of String) If PathIgnore IsNot Nothing Then - For Each Folder As DirectoryInfo In PathIgnore - Arr.Add(Folder.Name) + For Each FolderPath In PathIgnore + Arr.Add(PathUtils.GetLastPart(FolderPath)) Next End If Dim SameNameCheck = New ValidateExceptSame(Arr, "不可与现有文件夹重名!", IgnoreCase).Validate(Str) If Not SameNameCheck = "" Then Return SameNameCheck Return "" Catch ex As Exception - Log(ex, "检查文件夹名出错") + Logger.Warn(ex, "检查文件夹名出错") Return "错误:" & ex.Message End Try End Function @@ -332,10 +332,10 @@ Public Class ValidateFileName Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件名不可为 %!", True).Validate(Str) If InvalidStrCheck <> "" Then Return InvalidStrCheck '检查 NTFS 8.3 文件名(#4505) - If RegexCheck(Str, ".{2,}~\d") Then Return "文件名不能包含这一特殊格式!" + If Str.RegexCheck(".{2,}~\d") Then Return "文件名不能包含这一特殊格式!" '检查文件重名 If ParentFolder IsNot Nothing Then - Dim DirInfo As New DirectoryInfo(ParentFolder) + Dim DirInfo = DirectoryUtils.GetInfo(ParentFolder) If DirInfo.Exists Then Dim SameNameCheck = New ValidateExceptSame(DirInfo.EnumerateFiles("*").Select(Function(f) f.Name), "不可与现有文件重名!", IgnoreCase).Validate(Str) @@ -346,7 +346,7 @@ Public Class ValidateFileName End If Return "" Catch ex As Exception - Log(ex, "检查文件名出错") + Logger.Warn(ex, "检查文件名出错") Return "错误:" & ex.Message End Try End Function @@ -375,9 +375,10 @@ Public Class ValidateFolderPath If LengthCheck <> "" Then Return LengthCheck '检查开头 If Str.StartsWithF("\\Mac\") Then GoTo Fin - For Each Drive As DriveInfo In My.Computer.FileSystem.Drives - If Str.Upper = Drive.Name Then Return "" - If Str.StartsWithF(Drive.Name, True) Then GoTo Fin + For Each Drive In Environment.GetLogicalDrives().Where(Function(p) DirectoryUtils.Exists(p)) + Dim DriveName As String = Drive.Upper.First & ":\" + If Str.Upper = DriveName Then Return "" + If Str.StartsWithF(DriveName, True) Then GoTo Fin Next Return "文件夹路径头存在错误!" Fin: @@ -399,7 +400,7 @@ Fin: Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件夹名不可为 %!").Validate(SubStr) If Not InvalidStrCheck = "" Then Return InvalidStrCheck '检查 NTFS 8.3 文件名(#4505) - If RegexCheck(Str, ".{2,}~\d") Then Return "文件夹名不能包含这一特殊格式!" + If Str.RegexCheck(".{2,}~\d") Then Return "文件夹名不能包含这一特殊格式!" Next Return "" End Function diff --git a/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb b/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb index 879d6d7..15e6f5f 100644 --- a/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb +++ b/Plain Craft Launcher 2/Modules/Base/MyBitmap.vb @@ -72,7 +72,7 @@ Public Class MyBitmap End If Else '使用这种自己接管 FileStream 的方法加载才能解除文件占用 - Using InputStream As New FileStream(FilePathOrResourceName, FileMode.Open, FileAccess.Read, FileShare.Read) + Using InputStream = FileUtils.ReadAsStream(FilePathOrResourceName) '判断是否为 WebP 文件头 Dim Header(1) As Byte InputStream.Read(Header, 0, 2) @@ -97,7 +97,7 @@ Public Class MyBitmap Throw New Exception($"加载 MyBitmap 意外失败({FilePathOrResourceName})", ex) End If Else - Log(ex, $"指定类型有误的 MyBitmap 加载({FilePathOrResourceName})", NotifyLevel.DevelopOnly) + Logger.Warn(ex, $"指定类型有误的 MyBitmap 加载({FilePathOrResourceName})") Exit Try End If End Try @@ -162,7 +162,7 @@ Public Class MyBitmap Public Sub Save(FilePath As String) Dim encoder As BitmapEncoder = New PngBitmapEncoder() encoder.Frames.Add(BitmapFrame.Create(Me)) - Using fileStream As New FileStream(FilePath, FileMode.Create) + Using fileStream = FileUtils.CreateAsStream(FilePath) encoder.Save(fileStream) End Using End Sub diff --git a/Plain Craft Launcher 2/Modules/Base/PclLogger.vb b/Plain Craft Launcher 2/Modules/Base/PclLogger.vb new file mode 100644 index 0000000..eabbf12 --- /dev/null +++ b/Plain Craft Launcher 2/Modules/Base/PclLogger.vb @@ -0,0 +1,54 @@ +Public Class PclLogger + Inherits FileLogger + + ''' + Public Overrides Function Format(Text As String, Level As LogLevel, FilePath As String, Ex As Exception) As String + Text = MyBase.Format(Text, Level, FilePath, Ex) + Text = FilterUserName(FilterAccessToken(Text, "*"c), "*"c) + Return Text + End Function + + ''' + Public Overrides Sub HandleBehavior(RawMessage As String, FormattedMessage As String, Behavior As LogBehavior, Ex As Exception) + If IsProgramEnding Then Return + MyBase.HandleBehavior(RawMessage, FormattedMessage, Behavior, Ex) + Dim BriefText = If(Ex Is Nothing, RawMessage, If(RawMessage Is Nothing, "", $"{RawMessage}:") & Ex.GetDisplay(False)) + BriefText = FilterUserName(FilterAccessToken(BriefText, "*"c), "*"c) + Dim DetailText = If(Ex Is Nothing, RawMessage, If(RawMessage Is Nothing, "", $"{RawMessage}:") & Ex.GetDisplay(True)) + DetailText = FilterUserName(FilterAccessToken(DetailText, "*"c), "*"c) + Select Case Behavior + Case LogBehavior.None + '啥也不干 + Case LogBehavior.ToastIfDebug + If BuildType = BuildTypes.Debug OrElse ModeDebug Then Hint("[调试模式] " & BriefText, HintType.Blue, False) + Case LogBehavior.Toast + Hint(BriefText, HintType.Red, False) + Case LogBehavior.Alert + MyMsgBox(DetailText, "错误", IsWarn:=True) + Case LogBehavior.AlertThenFeedback + If PageSetupSystem.IsLauncherNewest Then + If MyMsgBox(DetailText & vbCrLf & vbCrLf & "是否反馈此问题?如果不反馈,这个问题可能永远无法得到解决!", "错误", "反馈", "取消", IsWarn:=True) = 1 Then Feedback(False, True) + Else + MyMsgBox(DetailText & vbCrLf & vbCrLf & "将 PCL 更新至最新版或许可以解决这个问题……", "错误", IsWarn:=True) + End If + Case LogBehavior.AlertThenCrash + Static FirstTrigger As Boolean = True + If FirstTrigger Then + '首次触发 + FirstTrigger = False + If PageSetupSystem.IsLauncherNewest Then + If MsgBox(DetailText & vbCrLf & vbCrLf & "是否反馈此问题?如果不反馈,这个问题可能永远无法得到解决!", MsgBoxStyle.Critical + MsgBoxStyle.YesNo, "错误") = MsgBoxResult.Yes Then Feedback(False, True) + Else + MsgBox(DetailText & vbCrLf & vbCrLf & "将 PCL 更新至最新版或许可以解决这个问题……", MsgBoxStyle.Critical, "错误") + End If + Else + '多次触发,直接使程序崩溃(这通常代表着在其他线程循环触发严重异常) + Thread.Sleep(2000) + End If + FormMain.EndProgramForce(ProcessReturnValues.Exception) + End Select + '遥测 + If Behavior >= LogBehavior.Toast Then Telemetry("错误日志", "Exception", DetailText) + End Sub + +End Class diff --git a/Plain Craft Launcher 2/Modules/Constants.vb b/Plain Craft Launcher 2/Modules/Constants.vb deleted file mode 100644 index 3e49e29..0000000 --- a/Plain Craft Launcher 2/Modules/Constants.vb +++ /dev/null @@ -1,78 +0,0 @@ -''' -''' 社区资源的类型。 -''' - Public Enum ResourceTypes - ''' - ''' Mod。 - ''' - [Mod] = 1 - ''' - ''' 整合包。 - ''' - ModPack = 2 - ''' - ''' 资源包。 - ''' - ResourcePack = 4 - ''' - ''' 光影包。 - ''' - Shader = 8 - ''' - ''' 数据包。 - ''' - DataPack = 16 - ''' - ''' 服务端插件。 - ''' - Plugin = 32 - ''' - ''' 同时包含数据包以及 Mod。 - ''' - ModOrDataPack = [Mod] Or DataPack - ''' - ''' 允许任意种类,或种类未知。 - ''' - Any = [Mod] Or ModPack Or ResourcePack Or Shader Or DataPack Or Plugin -End Enum - -''' -''' 社区资源的来源平台。 -''' - Public Enum ResourcePlatforms - CurseForge = 1 - Modrinth = 2 - Any = CurseForge Or Modrinth -End Enum - -''' -''' Mod 加载器的类型。 -''' -Public Enum ModLoaderTypes - 'https://docs.curseforge.com/rest-api/#tocS_ModLoaderType - Any = 0 - Forge = 1 - LiteLoader = 3 - Fabric = 4 - Quilt = 5 - NeoForge = 6 -End Enum - -''' -''' 在爱发电中的赞助等级。 -''' -Public Enum DonationRanks - None = 0 - Rank6 = 6 - Rank12 = 12 - Rank23 = 23 - Rank54 = 54 - Rank98 = 98 -End Enum - -Public Module Constants - ''' - ''' 土豆码版本号。 - ''' - Public Const POTATO_VERSION As Char = "1"c -End Module \ No newline at end of file diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb index 03b33f5..16d527e 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModCrash.vb @@ -9,7 +9,7 @@ TempFolder = RequestTaskTempFolder() DirectoryUtils.Create(TempFolder & "Temp\") DirectoryUtils.Create(TempFolder & "Report\") - Log("[Crash] 崩溃分析暂存文件夹:" & TempFolder) + Logger.Info($"崩溃分析暂存文件夹:{TempFolder}") End Sub '1:准备用于分析的 Log 文件 @@ -19,35 +19,30 @@ ''' ''' 从 PCL 捕获到的最后 200 行程序输出。 Public Sub Collect(VersionPathIndie As String, Optional LatestLog As IList(Of String) = Nothing) - Log("[Crash] 步骤 1:收集日志文件") + Logger.Info("步骤 1:收集日志文件") '简单收集可能的日志文件路径 Dim PossibleLogs As New List(Of String) Try - Dim DirInfo As New DirectoryInfo(VersionPathIndie & "crash-reports\") - If DirInfo.Exists Then - For Each File In DirInfo.EnumerateFiles - PossibleLogs.Add(File.FullName) - Next - End If + PossibleLogs.AddRange(DirectoryUtils.GetFiles(VersionPathIndie & "crash-reports\")) Catch ex As Exception - Log(ex, "收集 Minecraft 崩溃日志文件夹下的日志失败") + Logger.Warn(ex, "收集 Minecraft 崩溃日志文件夹下的日志失败") End Try Try - For Each File In New DirectoryInfo(VersionPathIndie).Parent.Parent.EnumerateFiles + For Each File In DirectoryUtils.GetInfo(VersionPathIndie).Parent.Parent.EnumerateFiles If If(File.Extension, "") <> ".log" Then Continue For - PossibleLogs.Add(File.FullName) + PossibleLogs.Add(PathUtils.RemoveExtendedPrefix(File.FullName)) Next Catch ex As Exception - Log(ex, "收集 Minecraft 主文件夹下的日志失败") + Logger.Warn(ex, "收集 Minecraft 主文件夹下的日志失败") End Try Try - For Each File In New DirectoryInfo(VersionPathIndie).EnumerateFiles + For Each File In DirectoryUtils.GetInfo(VersionPathIndie).EnumerateFiles If If(File.Extension, "") <> ".log" Then Continue For - PossibleLogs.Add(File.FullName) + PossibleLogs.Add(PathUtils.RemoveExtendedPrefix(File.FullName)) Next Catch ex As Exception - Log(ex, "收集 Minecraft 隔离文件夹下的日志失败") + Logger.Warn(ex, "收集 Minecraft 隔离文件夹下的日志失败") End Try PossibleLogs.Add(VersionPathIndie & "logs\latest.log") 'Minecraft 日志 PossibleLogs.Add(VersionPathIndie & "logs\debug.log") 'Minecraft Debug 日志 @@ -57,74 +52,75 @@ Dim RightLogs As New List(Of String) For Each LogFile In PossibleLogs Try - Dim Info As New FileInfo(LogFile) + Dim Info = FileUtils.GetInfo(LogFile) If Not Info.Exists Then Continue For Dim Time = Math.Abs((Info.LastWriteTime - Date.Now).TotalMinutes) If Time < 3 AndAlso Info.Length > 0 Then RightLogs.Add(LogFile) - Log("[Crash] 可能可用的日志文件:" & LogFile & "(" & Math.Round(Time, 1) & " 分钟)") + Logger.Info($"可能可用的日志文件:{LogFile}({Math.Round(Time, 1)} 分钟)") End If Catch ex As Exception - Log(ex, "确认崩溃日志时间失败(" & LogFile & ")") + Logger.Warn(ex, $"确认崩溃日志时间失败({LogFile})") End Try Next - If Not RightLogs.Any() Then Log("[Crash] 未发现可能可用的日志文件") + If Not RightLogs.Any() Then Logger.Info("未发现可能可用的日志文件") '将可能可用的日志文件导出 For Each FilePath In RightLogs Try - AnalyzeRawFiles.Add(New KeyValuePair(Of String, String())(FilePath, ReadFile(FilePath).Split(vbCrLf.ToCharArray))) + AnalyzeRawFiles.Add(New KeyValuePair(Of String, String())(FilePath, FileUtils.ReadAsLines(FilePath))) Catch ex As Exception - Log(ex, "读取可能的崩溃日志文件失败(" & FilePath & ")") + Logger.Warn(ex, $"读取可能的崩溃日志文件失败({FilePath})") End Try Next If LatestLog IsNot Nothing AndAlso LatestLog.Any Then Dim RawOutput As String = LatestLog.Join(vbCrLf) - Log("[Crash] 以下为游戏输出的最后一段内容:" & vbCrLf & RawOutput) + Logger.Info($"以下为游戏输出的最后一段内容:{vbCrLf}{RawOutput}") FileUtils.Write(TempFolder & "RawOutput.log", RawOutput) AnalyzeRawFiles.Add(New KeyValuePair(Of String, String())(TempFolder & "RawOutput.log", LatestLog.ToArray)) LatestLog.Clear() End If - Log("[Crash] 步骤 1:收集日志文件完成,收集到 " & AnalyzeRawFiles.Count & " 个文件") + Logger.Info($"步骤 1:收集日志文件完成,收集到 {AnalyzeRawFiles.Count} 个文件") End Sub ''' ''' 从文件路径直接导入日志文件或崩溃报告压缩包。 ''' Public Sub Import(FilePath As String) - Log("[Crash] 步骤 1:自主导入日志文件") + Logger.Info("步骤 1:自主导入日志文件") '尝试视作压缩包解压 Try - Dim Info As New FileInfo(FilePath) + Dim Info = FileUtils.GetInfo(FilePath) If Info.Exists AndAlso Info.Length > 0 AndAlso Not FilePath.EndsWithF(".jar", True) Then - ExtractCompressedFile(FilePath, TempFolder & "Temp\") - Log("[Crash] 已解压导入的日志文件:" & FilePath) + FileUtils.ExtractToDirectory(FilePath, TempFolder & "Temp\") + Logger.Info($"已解压导入的日志文件:{FilePath}") GoTo Extracted End If Catch End Try '并非压缩包 - CopyFile(FilePath, TempFolder & "Temp\" & GetFileNameFromPath(FilePath)) - Log("[Crash] 已复制导入的日志文件:" & FilePath) + FileUtils.Copy(FilePath, TempFolder & "Temp\" & PathUtils.GetLastPart(FilePath)) + Logger.Info($"已复制导入的日志文件:{FilePath}") Extracted: '导入其中的日志文件 - For Each TargetFile As FileInfo In New DirectoryInfo(TempFolder & "Temp\").EnumerateFiles.ToList() + For Each TargetFile As FileInfo In DirectoryUtils.GetInfo(TempFolder & "Temp\").EnumerateFiles Try If Not TargetFile.Exists OrElse TargetFile.Length = 0 Then Continue For Dim Ext As String = TargetFile.Extension.Lower If Ext = ".log" OrElse Ext = ".txt" Then - AnalyzeRawFiles.Add(New KeyValuePair(Of String, String())(TargetFile.FullName, ReadFile(TargetFile.FullName).Split(vbCrLf.ToCharArray))) + AnalyzeRawFiles.Add(New KeyValuePair(Of String, String())( + PathUtils.RemoveExtendedPrefix(TargetFile.FullName), FileUtils.ReadAsLines(TargetFile.FullName))) Else - File.Delete(TargetFile.FullName) + FileUtils.Delete(TargetFile.FullName) End If Catch ex As Exception - Log(ex, "导入单个日志文件失败") + Logger.Warn(ex, "导入单个日志文件失败") End Try Next - Log("[Crash] 步骤 1:自主导入日志文件,收集到 " & AnalyzeRawFiles.Count & " 个文件") + Logger.Info($"步骤 1:自主导入日志文件,收集到 {AnalyzeRawFiles.Count} 个文件") End Sub '2:确认实际用于分析的 Log 文本 @@ -141,25 +137,25 @@ Extracted: ''' 返回是否有足够信息可用于分析。 ''' Public Function Prepare() As Boolean - Log("[Crash] 步骤 2:准备日志文本") + Logger.Info("步骤 2:准备日志文本") '对日志文件进行分类 DirectFile = Nothing Dim AllFiles As New List(Of KeyValuePair(Of AnalyzeFileType, KeyValuePair(Of String, String()))) For Each LogFile In AnalyzeRawFiles - Dim MatchName As String = GetFileNameFromPath(LogFile.Key).Lower + Dim MatchName As String = PathUtils.GetLastPart(LogFile.Key).Lower Dim TargetType As AnalyzeFileType If MatchName.StartsWithF("hs_err") Then TargetType = AnalyzeFileType.HsErr - DirectFile = LogFile + If DirectFile Is Nothing Then DirectFile = LogFile ElseIf MatchName.StartsWithF("crash-") Then TargetType = AnalyzeFileType.CrashReport - DirectFile = LogFile + If DirectFile Is Nothing Then DirectFile = LogFile ElseIf MatchName = "latest.log" OrElse MatchName = "latest log.txt" OrElse MatchName = "debug.log" OrElse MatchName = "debug log.txt" OrElse MatchName = "游戏崩溃前的输出.txt" OrElse MatchName = "rawoutput.log" Then TargetType = AnalyzeFileType.MinecraftLog - If DirectFile Is Nothing Then DirectFile = LogFile + DirectFile = LogFile ElseIf MatchName = "启动器日志.txt" OrElse MatchName = "PCL2 启动器日志.txt" OrElse MatchName = "PCL 启动器日志.txt" OrElse MatchName = "log1.txt" Then If LogFile.Value.Any(Function(s) s.Contains("以下为游戏输出的最后一段内容")) Then TargetType = AnalyzeFileType.MinecraftLog @@ -172,20 +168,20 @@ Extracted: ElseIf MatchName.EndsWithF(".txt", True) Then TargetType = AnalyzeFileType.ExtraReportFile Else - Log("[Crash] " & MatchName & " 分类为 Ignore") + Logger.Info($"{MatchName} 分类为 Ignore") Continue For End If If LogFile.Value.Any Then AllFiles.Add(New KeyValuePair(Of AnalyzeFileType, KeyValuePair(Of String, String()))(TargetType, LogFile)) - Log("[Crash] " & MatchName & " 分类为 " & GetStringFromEnum(TargetType)) + Logger.Info($"{MatchName} 分类为 {TargetType}") Else - Log("[Crash] " & MatchName & " 由于内容为空跳过") + Logger.Info($"{MatchName} 由于内容为空跳过") End If Next '若只有额外日志,则将它们视作 Minecraft 日志 If AllFiles.Any() AndAlso AllFiles.All(Function(p) p.Key = AnalyzeFileType.ExtraLogFile) Then - Log("[Crash] 由于仅发现了额外日志,将它们视作 Minecraft 日志进行分析") + Logger.Info("由于仅发现了额外日志,将它们视作 Minecraft 日志进行分析") AllFiles = AllFiles.Select(Function(p) New KeyValuePair(Of AnalyzeFileType, KeyValuePair(Of String, String()))(AnalyzeFileType.MinecraftLog, p.Value)).ToList End If @@ -205,9 +201,9 @@ Extracted: Dim DatedFiles As New SortedList(Of Date, KeyValuePair(Of String, String()))() For Each File In SelectedFiles Try - DatedFiles.Add(New FileInfo(File.Key).LastWriteTime, File) + DatedFiles.Add(FileUtils.GetInfo(File.Key).LastWriteTime, File) Catch ex As Exception - Log(ex, "获取日志文件修改时间失败") + Logger.Warn(ex, "获取日志文件修改时间失败") DatedFiles.Add(New Date(1900, 1, 1), File) End Try Next @@ -216,12 +212,12 @@ Extracted: OutputFiles.Add(NewestFile.Key) If SelectType = AnalyzeFileType.HsErr Then LogHs = GetHeadTailLines(NewestFile.Value, 200, 100) - Log("[Crash] 输出报告:" & NewestFile.Key & ",作为虚拟机错误信息") - Log("[Crash] 导入分析:" & NewestFile.Key & ",作为虚拟机错误信息") + Logger.Info($"输出报告:{NewestFile.Key},作为虚拟机错误信息") + Logger.Info($"导入分析:{NewestFile.Key},作为虚拟机错误信息") Else LogCrash = GetHeadTailLines(NewestFile.Value, 300, 700) - Log("[Crash] 输出报告:" & NewestFile.Key & ",作为 Minecraft 崩溃报告") - Log("[Crash] 导入分析:" & NewestFile.Key & ",作为 Minecraft 崩溃报告") + Logger.Info($"输出报告:{NewestFile.Key},作为 Minecraft 崩溃报告") + Logger.Info($"导入分析:{NewestFile.Key},作为 Minecraft 崩溃报告") End If Case AnalyzeFileType.MinecraftLog LogMc = "" @@ -229,9 +225,9 @@ Extracted: '创建文件名词典 Dim FileNameDict As New Dictionary(Of String, KeyValuePair(Of String, String())) For Each SelectedFile In SelectedFiles - FileNameDict(GetFileNameFromPath(SelectedFile.Key).Lower) = SelectedFile + FileNameDict(PathUtils.GetLastPart(SelectedFile.Key).Lower) = SelectedFile OutputFiles.Add(SelectedFile.Key) - Log("[Crash] 输出报告:" & SelectedFile.Key & ",作为 Minecraft 或启动器日志") + Logger.Info($"输出报告:{SelectedFile.Key},作为 Minecraft 或启动器日志") Next '选择一份最佳的来自启动器的游戏日志 For Each FileName As String In {"rawoutput.log", "启动器日志.txt", "log1.txt", "游戏崩溃前的输出.txt", "PCL2 启动器日志.txt", "PCL 启动器日志.txt"} @@ -244,13 +240,13 @@ Extracted: LogMc += Line & vbLf ElseIf Line.Contains("以下为游戏输出的最后一段内容") Then HasLauncherMark = True - Log("[Crash] 找到 PCL 输出的游戏实时日志头") + Logger.Info("找到 PCL 输出的游戏实时日志头") End If Next '导入后 500 行 If Not HasLauncherMark Then LogMc += GetHeadTailLines(CurrentLog.Value, 0, 500) LogMc = LogMc.TrimEnd(vbCrLf.ToCharArray) - Log("[Crash] 导入分析:" & CurrentLog.Key & ",作为启动器日志") + Logger.Info($"导入分析:{CurrentLog.Key},作为启动器日志") Exit For Next '选择一份最佳的 Minecraft Log @@ -258,7 +254,7 @@ Extracted: If Not FileNameDict.ContainsKey(FileName) Then Continue For Dim CurrentLog = FileNameDict(FileName) LogMc += GetHeadTailLines(CurrentLog.Value, 1500, 500) - Log("[Crash] 导入分析:" & CurrentLog.Key & ",作为 Minecraft 日志") + Logger.Info($"导入分析:{CurrentLog.Key},作为 Minecraft 日志") Exit For Next '查找 Debug Log @@ -266,7 +262,7 @@ Extracted: If Not FileNameDict.ContainsKey(FileName) Then Continue For Dim CurrentLog = FileNameDict(FileName) LogMcDebug += GetHeadTailLines(CurrentLog.Value, 1000, 0) - Log("[Crash] 导入分析:" & CurrentLog.Key & ",作为 Minecraft Debug 日志") + Logger.Info($"导入分析:{CurrentLog.Key},作为 Minecraft Debug 日志") Exit For Next '兜底 @@ -276,7 +272,7 @@ Extracted: ElseIf FileNameDict.Any() Then '如果都没有找到,则使用第一个文件 Dim CurrentLog = FileNameDict.First.Value LogMc += GetHeadTailLines(CurrentLog.Value, 1500, 500) - Log("[Crash] 导入分析:" & CurrentLog.Key & ",作为兜底日志") + Logger.Info($"导入分析:{CurrentLog.Key},作为兜底日志") Else LogMc = Nothing Throw New Exception("无法找到匹配的 Minecraft Log") @@ -287,21 +283,22 @@ Extracted: '全部丢过去 For Each SelectedFile In SelectedFiles OutputFiles.Add(SelectedFile.Key) - Log("[Crash] 输出报告:" & SelectedFile.Key & ",不用作分析") + Logger.Info($"输出报告:{SelectedFile.Key},不用作分析") Next End Select Catch ex As Exception - Log(ex, "分类处理日志文件时出错") + Logger.Warn(ex, "分类处理日志文件时出错") End Try Next '结束 - Prepare = LogMc IsNot Nothing OrElse LogHs IsNot Nothing OrElse LogCrash IsNot Nothing - If Prepare Then - Log(("[Crash] 步骤 2:准备日志文本完成,找到" & If(LogMc Is Nothing, "", "游戏日志、") & If(LogMcDebug Is Nothing, "", "游戏 Debug 日志、") & If(LogHs Is Nothing, "", "虚拟机日志、") & If(LogCrash Is Nothing, "", "崩溃日志、")).TrimEnd("、") & "用作分析") + Dim Result = LogMc IsNot Nothing OrElse LogHs IsNot Nothing OrElse LogCrash IsNot Nothing + If Result Then + Logger.Info($"{("[Crash] 步骤 2:准备日志文本完成,找到" & If(LogMc Is Nothing, "", "游戏日志、") & If(LogMcDebug Is Nothing, "", "游戏 Debug 日志、") & If(LogHs Is Nothing, "", "虚拟机日志、") & If(LogCrash Is Nothing, "", "崩溃日志、")).TrimEnd("、")}用作分析") Else - Log("[Crash] 步骤 2:准备日志文本完成,没有任何可供分析的日志") + Logger.Info("步骤 2:准备日志文本完成,没有任何可供分析的日志") End If + Return Result End Function ''' ''' 输出字符串的前后某些行,并统一行尾为 vbLf (正则 \n)、删除空行和重复行。 @@ -392,7 +389,7 @@ Extracted: ''' 根据 AnalyzeLogs 与可能的版本信息分析崩溃原因。 ''' Public Sub Analyze() - Log("[Crash] 步骤 3:分析崩溃原因") + Logger.Info("步骤 3:分析崩溃原因") LogAll = If(LogMc, If(LogMcDebug, "")) & If(LogHs, "") & If(LogCrash, "") '1. 精准日志匹配,中/高优先级 @@ -406,21 +403,21 @@ Extracted: Dim Keywords As New List(Of String) '崩溃日志 If LogCrash IsNot Nothing Then - Log("[Crash] 开始进行崩溃日志堆栈分析") + Logger.Info("开始进行崩溃日志堆栈分析") Keywords.AddRange(AnalyzeStackKeyword(LogCrash.BeforeFirst("System Details"))) End If 'Minecraft 日志 If LogMc IsNot Nothing Then - Dim Fatals As List(Of String) = RegexSearch(LogMc, "/FATAL] .+?(?=[\n]+\[)") + Dim Fatals As List(Of String) = LogMc.RegexSearch("/FATAL] .+?(?=[\n]+\[)").ToList If LogMc.Contains("Unreported exception thrown!") Then Fatals.Add(LogMc.Between("Unreported exception thrown!", "at oolloo.jlw.Wrapper")) - Log("[Crash] 开始进行 Minecraft 日志堆栈分析,发现 " & Fatals.Count & " 个报错项") + Logger.Info($"开始进行 Minecraft 日志堆栈分析,发现 {Fatals.Count} 个报错项") For Each Fatal In Fatals Keywords.AddRange(AnalyzeStackKeyword(Fatal)) Next End If '虚拟机日志 If LogHs IsNot Nothing Then - Log("[Crash] 开始进行虚拟机堆栈分析") + Logger.Info("开始进行虚拟机堆栈分析") Dim StackLogs As String = LogHs.Between("T H R E A D", "Registers:") Keywords.AddRange(AnalyzeStackKeyword(StackLogs)) End If @@ -435,7 +432,7 @@ Extracted: GoTo Done End If Else - Log("[Crash] 可能并未安装 Mod,不进行堆栈分析") + Logger.Info("可能并未安装 Mod,不进行堆栈分析") End If '3. 精准日志匹配,低优先级 @@ -444,27 +441,27 @@ Extracted: '输出到日志 Done: If Not CrashReasons.Any() Then - Log("[Crash] 步骤 3:分析崩溃原因完成,未找到可能的原因") + Logger.Info("步骤 3:分析崩溃原因完成,未找到可能的原因") Else - Log("[Crash] 步骤 3:分析崩溃原因完成,找到 " & CrashReasons.Count & " 条可能的原因") + Logger.Info($"步骤 3:分析崩溃原因完成,找到 {CrashReasons.Count} 条可能的原因") For Each Reason In CrashReasons - Log("[Crash] - " & GetStringFromEnum(Reason.Key) & If(Reason.Value.Any, "(" & Reason.Value.Join(";"c) & ")", "")) + Logger.Info($"- {Reason.Key}{If(Reason.Value.Any, "(" & Reason.Value.Join(";"c) & ")", "")}") Next End If End Sub ''' ''' 增加一个可能的崩溃原因。 ''' - Private Sub AppendReason(Reason As CrashReason, Optional Additional As ICollection(Of String) = Nothing) + Private Sub AppendReason(Reason As CrashReason, Optional Additional As IEnumerable(Of String) = Nothing) If CrashReasons.ContainsKey(Reason) Then If Additional IsNot Nothing Then CrashReasons(Reason).AddRange(Additional) CrashReasons(Reason) = CrashReasons(Reason).Distinct.ToList End If Else - CrashReasons.Add(Reason, New List(Of String)(If(Additional, {}))) + CrashReasons.Add(Reason, New List(Of String)(If(Additional, {}).ToList)) End If - Log("[Crash] 可能的崩溃原因:" & GetStringFromEnum(Reason) & If(Additional IsNot Nothing AndAlso Additional.Any, "(" & Additional.Join(";"c) & ")", "")) + Logger.Info($"可能的崩溃原因:{Reason}{If(Additional IsNot Nothing AndAlso Additional.Any, "(" & Additional.Join(";"c) & ")", "")}") End Sub Private Sub AppendReason(Reason As CrashReason, Additional As String) AppendReason(Reason, If(String.IsNullOrEmpty(Additional), Nothing, New List(Of String) From {Additional})) @@ -485,7 +482,7 @@ Done: '崩溃报告分析,高优先级 If LogCrash IsNot Nothing Then If LogCrash.Contains("Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass") Then AppendReason(CrashReason.Java版本过高) - If LogCrash.Contains("Failed loading config file ") Then AppendReason(CrashReason.Mod配置文件导致游戏崩溃, {TryAnalyzeModName(If(RegexSeek(LogCrash, "(?<=Failed loading config file .+ for modid )[^\n]+"), "").TrimEnd(vbCrLf)).First, If(RegexSeek(LogCrash, "(?<=Failed loading config file ).+(?= of type)"), "").TrimEnd(vbCrLf)}) '#7071 + If LogCrash.Contains("Failed loading config file ") Then AppendReason(CrashReason.Mod配置文件导致游戏崩溃, {TryAnalyzeModName(If(LogCrash.RegexSeek("(?<=Failed loading config file .+ for modid )[^\n]+"), "").TrimEnd(vbCrLf)).First, If(LogCrash.RegexSeek("(?<=Failed loading config file ).+(?= of type)"), "").TrimEnd(vbCrLf)}) '#7071 End If '游戏日志分析 @@ -495,7 +492,6 @@ Done: If LogMc.Contains("The driver does not appear to support OpenGL") Then AppendReason(CrashReason.显卡不支持OpenGL) If LogMc.Contains("java.lang.ClassCastException: java.base/jdk") Then AppendReason(CrashReason.使用JDK) If LogMc.Contains("java.lang.ClassCastException: class jdk.") Then AppendReason(CrashReason.使用JDK) - If LogMc.Contains("TRANSFORMER/net.optifine/net.optifine.reflect.Reflector.(Reflector.java") Then AppendReason(CrashReason.OptiFine与Forge不兼容) If LogMc.Contains("java.lang.NoSuchMethodError: 'void net.minecraft.client.renderer.texture.SpriteContents.") Then AppendReason(CrashReason.OptiFine与Forge不兼容) If LogMc.Contains("java.lang.NoSuchMethodError: 'java.lang.String com.mojang.blaze3d.systems.RenderSystem.getBackendDescription") Then AppendReason(CrashReason.OptiFine与Forge不兼容) If LogMc.Contains("java.lang.NoSuchMethodError: 'void net.minecraft.client.renderer.block.model.BakedQuad.") Then AppendReason(CrashReason.OptiFine与Forge不兼容) @@ -515,7 +511,7 @@ Done: If LogMc.Contains("java.lang.RuntimeException: Shaders Mod detected. Please remove it, OptiFine has built-in support for shaders.") Then AppendReason(CrashReason.ShadersMod与OptiFine同时安装) If LogMc.Contains("java.lang.NoSuchMethodError: sun.security.util.ManifestEntryVerifier") OrElse LogMc.Contains("java.lang.NoSuchMethodError: 'void sun.security.util.ManifestEntryVerifier") Then AppendReason(CrashReason.低版本Forge与高版本Java不兼容) If LogMc.Contains("1282: Invalid operation") Then AppendReason(CrashReason.光影或资源包导致OpenGL1282错误) - If LogMc.Contains("signer information does not match signer information of other classes in the same package") Then AppendReason(CrashReason.文件或内容校验失败, If(RegexSeek(LogMc, "(?<=class "")[^']+(?=""'s signer information)"), "").TrimEnd(vbCrLf)) + If LogMc.Contains("signer information does not match signer information of other classes in the same package") Then AppendReason(CrashReason.文件或内容校验失败, If(LogMc.RegexSeek("(?<=class "")[^']+(?=""'s signer information)"), "").TrimEnd(vbCrLf)) If LogMc.Contains("Maybe try a lower resolution resourcepack?") Then AppendReason(CrashReason.材质过大或显卡配置不足) If LogMc.Contains("java.lang.NoSuchMethodError: net.minecraft.world.server.ChunkManager$ProxyTicketManager.shouldForceTicks(J)Z") AndAlso LogMc.Contains("OptiFine") Then AppendReason(CrashReason.OptiFine导致无法加载世界) If LogMc.Contains("Unsupported class file major version") Then AppendReason(CrashReason.Java版本不兼容) @@ -536,18 +532,18 @@ Done: End If End If '确定的 Mod 导致崩溃 - If LogMc.Contains("Caught exception from ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(RegexSeek(LogMc, "(?<=Caught exception from )[^\n]+?")?.TrimEnd((vbCrLf & " ").ToCharArray))) + If LogMc.Contains("Caught exception from ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(LogMc.RegexSeek("(?<=Caught exception from )[^\n]+?")?.TrimEnd((vbCrLf & " ").ToCharArray))) 'Mod 重复 / 前置问题 - If LogMc.Contains("DuplicateModsFoundException") Then AppendReason(CrashReason.Mod重复安装, RegexSearch(LogMc, "(?<=\n\t[\w]+ : [A-Z]:[^\n]+(/|\\))[^/\\\n]+?.jar", RegularExpressions.RegexOptions.IgnoreCase)) - If LogMc.Contains("Found a duplicate mod") Then AppendReason(CrashReason.Mod重复安装, RegexSearch(If(RegexSeek(LogMc, "Found a duplicate mod[^\n]+"), ""), "[^\\/]+.jar", RegularExpressions.RegexOptions.IgnoreCase)) - If LogMc.Contains("Found duplicate mods") Then AppendReason(CrashReason.Mod重复安装, RegexSearch(LogMc, "(?<=Mod ID: ')\w+?(?=' from mod files:)").Distinct.ToList) - If LogMc.Contains("ModResolutionException: Duplicate") Then AppendReason(CrashReason.Mod重复安装, RegexSearch(If(RegexSeek(LogMc, "ModResolutionException: Duplicate[^\n]+"), ""), "[^\\/]+.jar", RegularExpressions.RegexOptions.IgnoreCase)) + If LogMc.Contains("DuplicateModsFoundException") Then AppendReason(CrashReason.Mod重复安装, LogMc.RegexSearch("(?<=\n\t[\w]+ : [A-Z]:[^\n]+(/|\\))[^/\\\n]+?.jar", RegularExpressions.RegexOptions.IgnoreCase)) + If LogMc.Contains("Found a duplicate mod") Then AppendReason(CrashReason.Mod重复安装, If(LogMc.RegexSeek("Found a duplicate mod[^\n]+"), "").RegexSearch("[^\\/]+.jar", RegularExpressions.RegexOptions.IgnoreCase)) + If LogMc.Contains("Found duplicate mods") Then AppendReason(CrashReason.Mod重复安装, LogMc.RegexSearch("(?<=Mod ID: ')\w+?(?=' from mod files:)").Distinct.ToList) + If LogMc.Contains("ModResolutionException: Duplicate") Then AppendReason(CrashReason.Mod重复安装, If(LogMc.RegexSeek("ModResolutionException: Duplicate[^\n]+"), "").RegexSearch("[^\\/]+.jar", RegularExpressions.RegexOptions.IgnoreCase)) If LogMc.Contains("Incompatible mods found!") Then '#5006, #5115 - AppendReason(CrashReason.Mod互不兼容, If(RegexSeek(LogMc, "(?<=Incompatible mods found![\s\S]+: )[\s\S]+?(?=\tat )"), "").BeforeFirst("更多信息:").Replace("Some of your mods are incompatible with the game or each other!", "").Trim((vbCrLf & " ").ToCharArray)) + AppendReason(CrashReason.Mod互不兼容, If(LogMc.RegexSeek("(?<=Incompatible mods found![\s\S]+: )[\s\S]+?(?=\tat )"), "").BeforeFirst("更多信息:").Replace("Some of your mods are incompatible with the game or each other!", "").Trim((vbCrLf & " ").ToCharArray)) End If If LogMc.Contains("Missing or unsupported mandatory dependencies:") Then AppendReason(CrashReason.Mod缺少前置或MC版本错误, - RegexSearch(LogMc, "(?<=Missing or unsupported mandatory dependencies:)([\n\r]+\t(.*))+", RegularExpressions.RegexOptions.IgnoreCase). + LogMc.RegexSearch("(?<=Missing or unsupported mandatory dependencies:)([\n\r]+\t(.*))+", RegularExpressions.RegexOptions.IgnoreCase). Select(Function(s) s.Trim((vbCrLf & vbTab & " ").ToCharArray)).Distinct().ToList()) End If End If @@ -569,19 +565,19 @@ Done: If LogCrash.Contains("java.lang.OutOfMemoryError") Then AppendReason(CrashReason.内存不足) If LogCrash.Contains("Pixel format not accelerated") Then AppendReason(CrashReason.显卡驱动不支持导致无法设置像素格式) If LogCrash.Contains("Manually triggered debug crash") Then AppendReason(CrashReason.玩家手动触发调试崩溃) - If LogCrash.Contains("has mods that were not found") AndAlso RegexCheck(LogCrash, "The Mod File [^\n]+optifine\\OptiFine[^\n]+ has mods that were not found") Then AppendReason(CrashReason.OptiFine与Forge不兼容) + If LogCrash.Contains("has mods that were not found") AndAlso LogCrash.RegexCheck("The Mod File [^\n]+optifine\\OptiFine[^\n]+ has mods that were not found") Then AppendReason(CrashReason.OptiFine与Forge不兼容) 'Mod 导致的崩溃 If LogCrash.Contains("-- MOD ") Then Dim LogCrashMod As String = LogCrash.Between("-- MOD ", "Failure message:") If LogCrashMod.ContainsIgnoreCase(".jar") Then - AppendReason(CrashReason.确定Mod导致游戏崩溃, If(RegexSeek(LogCrashMod, "(?<=Mod File: ).+"), "").TrimEnd((vbCrLf & " ").ToCharArray)) + AppendReason(CrashReason.确定Mod导致游戏崩溃, If(LogCrashMod.RegexSeek("(?<=Mod File: ).+"), "").TrimEnd((vbCrLf & " ").ToCharArray)) Else - AppendReason(CrashReason.Mod加载器报错, If(RegexSeek(LogCrash, "(?<=Failure message: )[\w\W]+?(?=\tMod)"), "").Replace(vbTab, " ").TrimEnd((vbCrLf & " ").ToCharArray)) + AppendReason(CrashReason.Mod加载器报错, If(LogCrash.RegexSeek("(?<=Failure message: )[\w\W]+?(?=\tMod)"), "").Replace(vbTab, " ").TrimEnd((vbCrLf & " ").ToCharArray)) End If End If - If LogCrash.Contains("Multiple entries with same key: ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogCrash, "(?<=Multiple entries with same key: )[^=]+"), "").TrimEnd((vbCrLf & " ").ToCharArray))) - If LogCrash.Contains("LoaderExceptionModCrash: Caught exception from ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogCrash, "(?<=LoaderExceptionModCrash: Caught exception from )[^\n]+"), "").TrimEnd((vbCrLf & " ").ToCharArray))) - If LogCrash.Contains("Failed loading config file ") Then AppendReason(CrashReason.Mod配置文件导致游戏崩溃, {TryAnalyzeModName(If(RegexSeek(LogCrash, "(?<=Failed loading config file .+ for modid )[^\n]+"), "").TrimEnd(vbCrLf)).First, If(RegexSeek(LogCrash, "(?<=Failed loading config file ).+(?= of type)"), "").TrimEnd(vbCrLf)}) + If LogCrash.Contains("Multiple entries with same key: ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(LogCrash.RegexSeek("(?<=Multiple entries with same key: )[^=]+"), "").TrimEnd((vbCrLf & " ").ToCharArray))) + If LogCrash.Contains("LoaderExceptionModCrash: Caught exception from ") Then AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(LogCrash.RegexSeek("(?<=LoaderExceptionModCrash: Caught exception from )[^\n]+"), "").TrimEnd((vbCrLf & " ").ToCharArray))) + If LogCrash.Contains("Failed loading config file ") Then AppendReason(CrashReason.Mod配置文件导致游戏崩溃, {TryAnalyzeModName(If(LogCrash.RegexSeek("(?<=Failed loading config file .+ for modid )[^\n]+"), "").TrimEnd(vbCrLf)).First, If(LogCrash.RegexSeek("(?<=Failed loading config file ).+(?= of type)"), "").TrimEnd(vbCrLf)}) End If End Sub @@ -600,14 +596,14 @@ Done: LogText.Contains("mixin.injection.throwables.") OrElse LogText.Contains(".json] FAILED during )") If Not IsMixin Then Return False 'Mod 名称匹配 - Dim ModName As String = RegexSeek(LogText, "(?<=from mod )[^.\/ ]+(?=\] from)") - If ModName Is Nothing Then ModName = RegexSeek(LogText, "(?<=for mod )[^.\/ ]+(?= failed)") + Dim ModName As String = LogText.RegexSeek("(?<=from mod )[^.\/ ]+(?=\] from)") + If ModName Is Nothing Then ModName = LogText.RegexSeek("(?<=for mod )[^.\/ ]+(?= failed)") If ModName IsNot Nothing Then AppendReason(CrashReason.ModMixin失败, TryAnalyzeModName(ModName.TrimEnd((vbCrLf & " ").ToCharArray))) Return True End If 'JSON 名称匹配 - For Each JsonName In RegexSearch(LogText, "(?<=^[^\t]+[ \[{(])[^ \[{(]+\.[^ ]+(?=\.json)", RegularExpressions.RegexOptions.Multiline) + For Each JsonName In LogText.RegexSearch("(?<=^[^\t]+[ \[{(])[^ \[{(]+\.[^ ]+(?=\.json)", RegularExpressions.RegexOptions.Multiline) AppendReason(CrashReason.ModMixin失败, TryAnalyzeModName(JsonName.Replace("mixins", "mixin").Replace(".mixin", "").Replace("mixin.", ""))) Return True @@ -622,12 +618,12 @@ Done: 'Mixin 崩溃 Dim IsMixin As Boolean = MixinAnalyze(LogMc) '常规信息 - If LogMc.Contains("An exception was thrown, the game will display an error screen and halt.") Then AppendReason(CrashReason.Forge报错, RegexSeek(LogMc, "(?<=the game will display an error screen and halt.[\n\r]+[^\n]+?Exception: )[\s\S]+?(?=\n\tat)")?.Trim(vbCrLf)) - If LogMc.Contains("A potential solution has been determined:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, RegexSearch(If(RegexSeek(LogMc, "(?<=A potential solution has been determined:\n)(\s+ - [^\n]+\n)+"), ""), "(?<=\s+)[^\n]+").Join(vbLf)) - If LogMc.Contains("A potential solution has been determined, this may resolve your problem:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, RegexSearch(If(RegexSeek(LogMc, "(?<=A potential solution has been determined, this may resolve your problem:\n)(\s+ - [^\n]+\n)+"), ""), "(?<=\s+)[^\n]+").Join(vbLf)) - If LogMc.Contains("确定了一种可能的解决方法,这样做可能会解决你的问题:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, RegexSearch(If(RegexSeek(LogMc, "(?<=确定了一种可能的解决方法,这样做可能会解决你的问题:\n)(\s+ - [^\n]+\n)+"), ""), "(?<=\s+)[^\n]+").Join(vbLf)) + If LogMc.Contains("An exception was thrown, the game will display an error screen and halt.") Then AppendReason(CrashReason.Forge报错, LogMc.RegexSeek("(?<=the game will display an error screen and halt.[\n\r]+[^\n]+?Exception: )[\s\S]+?(?=\n\tat)")?.Trim(vbCrLf)) + If LogMc.Contains("A potential solution has been determined:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, If(LogMc.RegexSeek("(?<=A potential solution has been determined:\n)(\s+ - [^\n]+\n)+"), "").RegexSearch("(?<=\s+)[^\n]+").Join(vbLf)) + If LogMc.Contains("A potential solution has been determined, this may resolve your problem:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, If(LogMc.RegexSeek("(?<=A potential solution has been determined, this may resolve your problem:\n)(\s+ - [^\n]+\n)+"), "").RegexSearch("(?<=\s+)[^\n]+").Join(vbLf)) + If LogMc.Contains("确定了一种可能的解决方法,这样做可能会解决你的问题:") Then AppendReason(CrashReason.Fabric报错并给出解决方案, If(LogMc.RegexSeek("(?<=确定了一种可能的解决方法,这样做可能会解决你的问题:\n)(\s+ - [^\n]+\n)+"), "").RegexSearch("(?<=\s+)[^\n]+").Join(vbLf)) If Not IsMixin AndAlso LogMc.Contains("due to errors, provided by ") Then '在 #3104 的情况下,这一句导致 OptiFabric 的 Mixin 失败错判为 Fabric Loader 加载失败 - AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(RegexSeek(LogMc, "(?<=due to errors, provided by ')[^']+"), "").TrimEnd((vbCrLf & " ").ToCharArray))) + AppendReason(CrashReason.确定Mod导致游戏崩溃, TryAnalyzeModName(If(LogMc.RegexSeek("(?<=due to errors, provided by ')[^']+"), "").TrimEnd((vbCrLf & " ").ToCharArray))) End If End If @@ -639,7 +635,7 @@ Done: If LogCrash.Contains("Suspected Mod") Then Dim SuspectsRaw As String = LogCrash.Between("Suspected Mod", "Stacktrace") If Not SuspectsRaw.StartsWithF("s: None") Then 'Suspected Mods: None - Dim Suspects = RegexSearch(SuspectsRaw, "(?<=\n\t[^(\t]+\()[^)\n]+") + Dim Suspects = SuspectsRaw.RegexSearch("(?<=\n\t[^(\t]+\()[^)\n]+") If Suspects.Any Then AppendReason(CrashReason.怀疑Mod导致游戏崩溃, TryAnalyzeModName(Suspects)) End If End If @@ -660,14 +656,14 @@ Done: 'Mod 解析错误(常见于 Fabric 前置校验失败) If LogMc.Contains("Mod resolution failed") Then AppendReason(CrashReason.Mod加载器报错) 'Mixin 失败可以导致大量 Mod 实例创建失败,因此需要放到低优先级中 - If LogMc.Contains("Failed to create mod instance.") Then AppendReason(CrashReason.Mod初始化失败, TryAnalyzeModName(If(RegexSeek(LogMc, "(?<=Failed to create mod instance. ModID: )[^,]+"), If(RegexSeek(LogMc, "(?<=Failed to create mod instance. ModId )[^\n]+(?= for )"), "")).TrimEnd(vbCrLf))) + If LogMc.Contains("Failed to create mod instance.") Then AppendReason(CrashReason.Mod初始化失败, TryAnalyzeModName(If(LogMc.RegexSeek("(?<=Failed to create mod instance. ModID: )[^,]+"), If(LogMc.RegexSeek("(?<=Failed to create mod instance. ModId )[^\n]+(?= for )"), "")).TrimEnd(vbCrLf))) '注意:Fabric 的 Warnings were found! 不一定是崩溃原因,它可能是单纯的警报 End If '崩溃报告分析 If LogCrash IsNot Nothing Then - If LogCrash.Contains(vbTab & "Block location: World: ") Then AppendReason(CrashReason.特定方块导致崩溃, If(RegexSeek(LogCrash, "(?<=\tBlock: Block\{)[^\}]+"), "") & " " & If(RegexSeek(LogCrash, "(?<=\tBlock location: World: )\([^\)]+\)"), "")) - If LogCrash.Contains(vbTab & "Entity's Exact location: ") Then AppendReason(CrashReason.特定实体导致崩溃, If(RegexSeek(LogCrash, "(?<=\tEntity Type: )[^\n]+(?= \()"), "") & " (" & If(RegexSeek(LogCrash, "(?<=\tEntity's Exact location: )[^\n]+"), "").TrimEnd(vbCrLf.ToCharArray) & ")") + If LogCrash.Contains(vbTab & "Block location: World: ") Then AppendReason(CrashReason.特定方块导致崩溃, If(LogCrash.RegexSeek("(?<=\tBlock: Block\{)[^\}]+"), "") & " " & If(LogCrash.RegexSeek("(?<=\tBlock location: World: )\([^\)]+\)"), "")) + If LogCrash.Contains(vbTab & "Entity's Exact location: ") Then AppendReason(CrashReason.特定实体导致崩溃, If(LogCrash.RegexSeek("(?<=\tEntity Type: )[^\n]+(?= \()"), "") & " (" & If(LogCrash.RegexSeek("(?<=\tEntity's Exact location: )[^\n]+"), "").TrimEnd(vbCrLf.ToCharArray) & ")") End If End Sub @@ -679,8 +675,8 @@ Done: '进行正则匹配 Dim StackSearchResults As New List(Of String) - StackSearchResults.AddRange(RegexSearch(ErrorStack, "(?<=\n[^{]+)[a-zA-Z_]+\w+\.[a-zA-Z_]+[\w\.]+(?=\.[\w\.$]+\.)")) - StackSearchResults.AddRange(RegexSearch(ErrorStack, "(?<=at [^(]+?\.\w+\$\w+\$)[\w\$]+?(?=\$\w+\()").Select(Function(s) s.Replace("$", "."))) 'Mixin 堆栈:xxx.xxx.xxxx$xxxx$xxx + StackSearchResults.AddRange(ErrorStack.RegexSearch("(?<=\n[^{]+)[a-zA-Z_]+\w+\.[a-zA-Z_]+[\w\.]+(?=\.[\w\.$]+\.)")) + StackSearchResults.AddRange(ErrorStack.RegexSearch("(?<=at [^(]+?\.\w+\$\w+\$)[\w\$]+?(?=\$\w+\()").Select(Function(s) s.Replace("$", "."))) 'Mixin 堆栈:xxx.xxx.xxxx$xxxx$xxx StackSearchResults = StackSearchResults.Distinct.ToList '检查堆栈开头 @@ -698,10 +694,10 @@ Done: NextStack: Next PossibleStacks = PossibleStacks.Distinct.ToList - Log("[Crash] 找到 " & PossibleStacks.Count & " 条可能的堆栈信息") + Logger.Info($"找到 {PossibleStacks.Count} 条可能的堆栈信息") If Not PossibleStacks.Any() Then Return New List(Of String) For Each Stack As String In PossibleStacks - Log("[Crash] - " & Stack) + Logger.Info($"- {Stack}") Next '检查堆栈关键词 @@ -724,10 +720,10 @@ NextStack: Next Next PossibleWords = PossibleWords.Distinct.ToList - Log("[Crash] 从堆栈信息中找到 " & PossibleWords.Count & " 个可能的 Mod ID 关键词") - If PossibleWords.Any Then Log("[Crash] - " & PossibleWords.Join(", ")) + Logger.Info($"从堆栈信息中找到 {PossibleWords.Count} 个可能的 Mod ID 关键词") + If PossibleWords.Any Then Logger.Info($"- {PossibleWords.Join(", ")}") If PossibleWords.Count > 10 Then - Log("[Crash] 关键词过多,考虑匹配出错,不纳入考虑") + Logger.Info("关键词过多,考虑匹配出错,不纳入考虑") Return New List(Of String) Else Return PossibleWords @@ -738,7 +734,7 @@ NextStack: ''' 根据 Mod 关键词尝试获取实际的 Mod 名称。 ''' 若失败则返回 Nothing。 ''' - Private Function AnalyzeModName(Keywords As List(Of String)) As List(Of String) + Private Function AnalyzeModName(Keywords As IEnumerable(Of String)) As List(Of String) Dim ModFileNames As New List(Of String) '预处理关键词(分割括号) @@ -756,7 +752,7 @@ NextStack: Dim IsFabricDetail As Boolean = Details.Contains("Fabric Mods") '是否为 Fabric 信息格式 If IsFabricDetail Then Details = Details.Replace("Fabric Mods", "¨") - Log("[Crash] 崩溃报告中检测到 Fabric Mod 信息格式") + Logger.Info("崩溃报告中检测到 Fabric Mod 信息格式") End If Details = Details.AfterLast("¨") @@ -765,9 +761,9 @@ NextStack: Dim ModNameLines As New List(Of String) For Each Line In Details.Split(vbLf) If (Line.ContainsIgnoreCase(".jar") AndAlso Line.Length - Line.Replace(".jar", "").Length = 4) OrElse '只有一个 .jar - (IsFabricDetail AndAlso Line.StartsWithF(vbTab & vbTab) AndAlso Not RegexCheck(Line, "\t\tfabric[\w-]*: Fabric")) Then ModNameLines.Add(Line) + (IsFabricDetail AndAlso Line.StartsWithF(vbTab & vbTab) AndAlso Not Line.RegexCheck("\t\tfabric[\w-]*: Fabric")) Then ModNameLines.Add(Line) Next - Log("[Crash] 崩溃报告中找到 " & ModNameLines.Count & " 个可能的 Mod 项目行") + Logger.Info($"崩溃报告中找到 {ModNameLines.Count} 个可能的 Mod 项目行") '获取 Mod ID 与关键词的匹配行 Dim HintLines As New List(Of String) @@ -781,18 +777,18 @@ NextStack: Next Next HintLines = HintLines.Distinct.ToList - Log("[Crash] 崩溃报告中找到 " & HintLines.Count & " 个可能的崩溃 Mod 匹配行") + Logger.Info($"崩溃报告中找到 {HintLines.Count} 个可能的崩溃 Mod 匹配行") For Each ModLine As String In HintLines - Log("[Crash] - " & ModLine) + Logger.Info($"- {ModLine}") Next '从 Mod 匹配行中提取 .jar 文件的名称 For Each Line As String In HintLines Dim Name As String If IsFabricDetail Then - Name = RegexSeek(Line, "(?<=: )[^\n]+(?= [^\n]+)") + Name = Line.RegexSeek("(?<=: )[^\n]+(?= [^\n]+)") Else - Name = RegexSeek(Line, "(?<=\()[^\t]+.jar(?=\))|(?<=(\t\t)|(\| ))[^\t\|]+.jar", RegularExpressions.RegexOptions.IgnoreCase) + Name = Line.RegexSeek("(?<=\()[^\t]+.jar(?=\))|(?<=(\t\t)|(\| ))[^\t\|]+.jar", RegularExpressions.RegexOptions.IgnoreCase) End If If Name IsNot Nothing Then ModFileNames.Add(Name) Next @@ -803,8 +799,8 @@ NextStack: If LogMcDebug IsNot Nothing Then 'Forge: Found valid mod file YungsBetterStrongholds-1.20-Forge-4.0.1.jar with {betterstrongholds} mods - versions {1.20-Forge-4.0.1} - Dim ModNameLines As List(Of String) = RegexSearch(LogMcDebug, "(?<=valid mod file ).*", RegularExpressions.RegexOptions.Multiline) - Log("[Crash] Debug 信息中找到 " & ModNameLines.Count & " 个可能的 Mod 项目行") + Dim ModNameLines = LogMcDebug.RegexSearch("(?<=valid mod file ).*", RegularExpressions.RegexOptions.Multiline) + Logger.Info($"Debug 信息中找到 {ModNameLines.Count} 个可能的 Mod 项目行") '获取 Mod ID 与关键词的匹配行 Dim HintLines As New List(Of String) @@ -814,15 +810,15 @@ NextStack: Next Next HintLines = HintLines.Distinct.ToList - Log("[Crash] Debug 信息中找到 " & HintLines.Count & " 个可能的崩溃 Mod 匹配行") + Logger.Info($"Debug 信息中找到 {HintLines.Count} 个可能的崩溃 Mod 匹配行") For Each ModLine As String In HintLines - Log("[Crash] - " & ModLine) + Logger.Info($"- {ModLine}") Next '从 Mod 匹配行中提取 .jar 文件的名称 For Each Line As String In HintLines Dim Name As String - Name = RegexSeek(Line, ".*(?= with)") + Name = Line.RegexSeek(".*(?= with)") If Name IsNot Nothing Then ModFileNames.Add(Name) Next @@ -833,9 +829,9 @@ NextStack: If Not ModFileNames.Any() Then Return Nothing Else - Log("[Crash] 找到 " & ModFileNames.Count & " 个可能的崩溃 Mod 文件名") + Logger.Info($"找到 {ModFileNames.Count} 个可能的崩溃 Mod 文件名") For Each ModFileName As String In ModFileNames - Log("[Crash] - " & ModFileName) + Logger.Info($"- {ModFileName}") Next Return ModFileNames End If @@ -851,9 +847,9 @@ NextStack: ''' ''' 尝试从关键字获取 Mod 名称,若失败则返回原关键字。 ''' - Private Function TryAnalyzeModName(Keywords As List(Of String)) As List(Of String) - If Not Keywords.Any Then Return Keywords - Return If(AnalyzeModName(Keywords), Keywords) + Private Function TryAnalyzeModName(Keywords As IEnumerable(Of String)) As List(Of String) + If Not Keywords.Any Then Return Keywords.ToList + Return If(AnalyzeModName(Keywords), Keywords.ToList) End Function '4:根据原因输出信息 @@ -866,11 +862,11 @@ NextStack: FrmMain.ShowWindowToTop() Dim Detail As String = GetAnalyzeResult(IsManualAnalyze) Select Case MyMsgBox(Detail, If(IsManualAnalyze, "错误报告分析结果", "Minecraft 出现错误"), - "确定", If(IsManualAnalyze OrElse DirectFile Is Nothing, "", "查看日志"), If(IsManualAnalyze, "", "导出错误报告"), + "确定", If(IsManualAnalyze OrElse DirectFile Is Nothing, "", "查看输出"), If(IsManualAnalyze, "", "导出错误报告"), Button2Action:=If(IsManualAnalyze OrElse DirectFile Is Nothing, Nothing, Sub() - '弹窗选择:查看日志 - If File.Exists(DirectFile.Value.Key) Then + '弹窗选择:查看输出 + If FileUtils.Exists(DirectFile.Value.Key) Then StartProcess(DirectFile.Value.Key) Else Dim FilePath As String = PathTemp & "Crash.txt" @@ -883,17 +879,16 @@ NextStack: Dim FileAddress As String = Nothing Try '获取文件路径 - RunInUiWait(Sub() FileAddress = SelectSaveFile("选择保存位置", "错误报告-" & Date.Now.ToString("G").Replace("/", "-").Replace(":", ".").Replace(" ", "_") & ".zip", "Minecraft 错误报告(*.zip)|*.zip")) - If String.IsNullOrEmpty(FileAddress) Then Return - If File.Exists(FileAddress) Then File.Delete(FileAddress) - DirectoryUtils.Create(FileAddress, isFilePath:=True) + RunInUiWait(Sub() FileAddress = Dialogs.SaveFile("选择保存位置", "错误报告-" & Date.Now.ToString("G").Replace("/", "-").Replace(":", ".").Replace(" ", "_") & ".zip", filter:={("zip", "Minecraft 错误报告")})) + If FileAddress Is Nothing Then Return + FileUtils.Delete(FileAddress) '输出诊断信息 FeedbackInfo() - LogFlush() + Logger.Instance.Flush() '复制文件 If ExtraFiles IsNot Nothing Then OutputFiles.AddRange(ExtraFiles) For Each OutputFile In OutputFiles - Dim FileName As String = GetFileNameFromPath(OutputFile) + Dim FileName As String = PathUtils.GetLastPart(OutputFile) Dim FileEncoding As Encoding = Nothing Select Case FileName Case "LatestLaunch.bat" @@ -905,23 +900,21 @@ NextStack: FileName = "游戏崩溃前的输出.txt" FileEncoding = Encoding.UTF8 End Select - If File.Exists(OutputFile) Then - If FileEncoding Is Nothing Then FileEncoding = GetEncoding(ReadFileBytes(OutputFile)) - Dim FileContent As String = ReadFile(OutputFile, FileEncoding) - FileContent = FilterUserName(FilterAccessToken(FileContent, If(FileName = "启动脚本.bat", "F", "*")), "*") - FileUtils.Write(TempFolder & "Report\" & FileName, FileContent, Encoding:=FileEncoding) - Log($"[Crash] 导出文件:{FileName},编码:{FileEncoding.HeaderName}") - End If + If Not FileUtils.Exists(OutputFile) Then Continue For + Dim FileContent As String = FileUtils.ReadAsString(OutputFile, FileEncoding) + FileContent = FilterUserName(FilterAccessToken(FileContent, If(FileName = "启动脚本.bat", "F", "*")), "*") + FileUtils.Write(TempFolder & "Report\" & FileName, FileContent, FileEncoding) + Logger.Info($"导出错误报告文件:{FileName}") Next '导出报告 - Compression.ZipFile.CreateFromDirectory(TempFolder & "Report\", FileAddress) - DeleteDirectory(TempFolder & "Report\") + FileUtils.CreateZipFromDirectory(FileAddress, TempFolder & "Report\") + DirectoryUtils.Delete(TempFolder & "Report\") Hint("错误报告已导出!", HintType.Green) + OpenExplorer(FileAddress) Catch ex As Exception - Log(ex, "导出错误报告失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "导出错误报告失败") Return End Try - OpenExplorer(FileAddress) End Select '上报 If IsManualAnalyze Then Return diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb index bad8cf1..47d64ac 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModDownload.vb @@ -13,7 +13,7 @@ Instance = New McInstance(Instance.InheritName) Loop Catch ex As Exception - Log(ex, "获取底层继承版本失败") + Logger.Warn(ex, "获取底层继承版本失败") End Try '检查 Json 是否标准 If Instance.JsonObject("downloads") Is Nothing OrElse Instance.JsonObject("downloads")("client") Is Nothing OrElse Instance.JsonObject("downloads")("client")("url") Is Nothing Then @@ -39,7 +39,7 @@ '获取信息 Dim IndexInfo = McAssetsGetIndex(Instance, True, True) Dim IndexAddress As String = McFolderSelected & "assets\indexes\" & IndexInfo("id").ToString & ".json" - Log("[Download] 版本 " & Instance.Name & " 对应的资源文件索引为 " & IndexInfo("id").ToString) + Logger.Info($"版本 {Instance.Name} 对应的资源文件索引为 {IndexInfo("id")}") Dim IndexUrl As String = If(IndexInfo("url"), "") If IndexUrl = "" Then Return Nothing @@ -65,7 +65,7 @@ #Region "下载资源文件" If ShouldIgnoreFileCheck(Instance) Then - Log("[Download] 已跳过所有 Assets 检查") + Logger.Info("已跳过所有 Assets 检查") Else Dim LoadersAssets As New List(Of LoaderBase) '获取资源文件索引地址 @@ -75,7 +75,7 @@ Dim IndexFile = DlClientAssetIndexGet(Instance) If IndexFile Is Nothing Then Task.Output = New List(Of NetFile) - Log("[Download] 未找到版本 " & Instance.Name & " 的合适的资源索引下载地址,游戏 assets 可能缺失", NotifyLevel.DebugModeOnly) + Logger.Warn($"未找到版本 {Instance.Name} 的合适的资源索引下载地址,游戏 assets 可能缺失") ElseIf AssetsIndexBehaviour <> AssetsIndexExistsBehaviour.AlwaysDownload AndAlso IndexFile.Check.Check(IndexFile.LocalPath) Is Nothing Then Task.Output = New List(Of NetFile) Else @@ -96,7 +96,7 @@ Sub(Task As LoaderTask(Of String, List(Of NetFile))) Dim BackAssetsFile As NetFile = DlClientAssetIndexGet(Instance) If BackAssetsFile Is Nothing Then - Log("[Download] 未找到版本 " & Instance.Name & " 的合适的资源索引下载地址,游戏 assets 可能缺失", NotifyLevel.DebugModeOnly) + Logger.Warn($"未找到版本 {Instance.Name} 的合适的资源索引下载地址,游戏 assets 可能缺失") Task.Interrupt() Throw New ThreadInterruptedException End If @@ -105,19 +105,19 @@ BackAssetsFile.LocalPath = TempAddress Task.Output = New List(Of NetFile) From {BackAssetsFile} '检查是否需要更新:每天只更新一次 - If File.Exists(RealAddress) AndAlso Math.Abs((File.GetLastWriteTime(RealAddress).Date - Now.Date).TotalDays) < 1 Then - Log("[Download] 无需更新资源文件索引,取消") + If FileUtils.Exists(RealAddress) AndAlso Math.Abs((FileUtils.GetInfo(RealAddress).LastWriteTime.Date - Now.Date).TotalDays) < 1 Then + Logger.Info("无需更新资源文件索引,取消") Task.Interrupt() End If End Sub)) LoadersAssetsUpdate.Add(New LoaderDownload("后台下载资源文件索引", New List(Of NetFile))) LoadersAssetsUpdate.Add(New LoaderTask(Of List(Of NetFile), String)("后台复制资源文件索引", Sub(Task As LoaderTask(Of List(Of NetFile), String)) - CopyFile(TempAddress, RealAddress) + FileUtils.Copy(TempAddress, RealAddress) McLaunchLog("后台更新资源文件索引成功:" & TempAddress) End Sub)) Dim Updater As New LoaderCombo(Of String)("后台更新资源文件索引", LoadersAssetsUpdate) - Log("[Download] 开始后台检查资源文件索引") + Logger.Info("开始后台检查资源文件索引") Updater.Start() End If '获取资源文件地址 @@ -158,8 +158,8 @@ Public Property AllDrops As List(Of Integer) Get If _AllDrops Is Nothing Then - _AllDrops = Settings.Get("CacheDrops").ToString. - Split(",".ToCharArray, StringSplitOptions.RemoveEmptyEntries).Select(Function(d) CInt(Val(d))).ToList() + _AllDrops = Settings.Get(Of String)("CacheDrops").ToString. + Split(",", True).Select(Function(d) CInt(Val(d))).ToList() End If Return If(_AllDrops.Any, _AllDrops, Nothing) '不要将 _AllDrops 再设为 Nothing,以防止反复获取设置尝试初始化 End Get @@ -191,7 +191,7 @@ ''' Public DlClientListLoader As New LoaderTask(Of String, DlClientListResult)("DlClientList Main", AddressOf DlClientListMain) Private Sub DlClientListMain(Loader As LoaderTask(Of String, DlClientListResult)) - Select Case Settings.Get("ToolDownloadVersion") + Select Case Settings.Get(Of Integer)("ToolDownloadVersion") Case 0 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of String, DlClientListResult), Integer)(DlClientListBmclapiLoader, 30), @@ -211,7 +211,9 @@ '提取所有 Drop 序数 Dim Drops As New List(Of Integer) For Each Version As JObject In Loader.Output.Value("versions") - Dim Drop As Integer = McVersion.VersionToDrop(Version("id")) + Dim Id As String = Version("id").ToString + If Id.Contains("-") Then Continue For + Dim Drop As Integer = McVersion.VersionToDrop(Id) If Drop = 209 Then Continue For Drops.Add(Drop) Next @@ -233,10 +235,10 @@ If Not DlPreferMojang Then Dim DeltaTime = GetTimeMs() - StartTime DlPreferMojang = DeltaTime < 4000 - Log($"[Download] Mojang 官方源加载耗时:{DeltaTime}ms,{If(DlPreferMojang, "可优先使用官方源", "不优先使用官方源")}") + Logger.Info($"Mojang 官方源加载耗时:{DeltaTime}ms,{If(DlPreferMojang, "可优先使用官方源", "不优先使用官方源")}") End If '添加 PCL 特供项 - If File.Exists(PathTemp & "Cache\download.json") Then Versions.Merge(GetJson(ReadFile(PathTemp & "Cache\download.json"))) + If FileUtils.Exists(PathTemp & "Cache\download.json") Then Versions.Merge(GetJson(FileUtils.ReadAsString(PathTemp & "Cache\download.json"))) '返回 Loader.Output = New DlClientListResult With {.IsOfficial = True, .SourceName = "Mojang 官方源", .Value = Json} 'MC 更新提示 @@ -244,16 +246,16 @@ Dim Version As String '快照版 Version = Json("latest")("snapshot") - If Settings.Get("ToolUpdateSnapshot") AndAlso Not Settings.Get("ToolUpdateSnapshotLast") = "" AndAlso - Settings.Get("ToolUpdateSnapshotLast") <> Version AndAlso Not IsHinted Then + If Settings.Get(Of Boolean)("ToolUpdateSnapshot") AndAlso Not Settings.Get(Of String)("ToolUpdateSnapshotLast") = "" AndAlso + Settings.Get(Of String)("ToolUpdateSnapshotLast") <> Version AndAlso Not IsHinted Then IsHinted = True McDownloadClientUpdateHint(Version, Json) End If Settings.Set("ToolUpdateSnapshotLast", If(Version, "Nothing")) '正式版 Version = Json("latest")("release") - If Settings.Get("ToolUpdateRelease") AndAlso Not Settings.Get("ToolUpdateReleaseLast") = "" AndAlso - Settings.Get("ToolUpdateReleaseLast") <> Version AndAlso Not IsHinted Then + If Settings.Get(Of Boolean)("ToolUpdateRelease") AndAlso Not Settings.Get(Of String)("ToolUpdateReleaseLast") = "" AndAlso + Settings.Get(Of String)("ToolUpdateReleaseLast") <> Version AndAlso Not IsHinted Then IsHinted = True McDownloadClientUpdateHint(Version, Json) End If @@ -272,7 +274,7 @@ Dim Versions As JArray = Json("versions") If Versions.Count < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Json.ToString & ")") '添加 PCL 特供项 - If File.Exists(PathTemp & "Cache\download.json") Then Versions.Merge(GetJson(ReadFile(PathTemp & "Cache\download.json"))) + If FileUtils.Exists(PathTemp & "Cache\download.json") Then Versions.Merge(GetJson(FileUtils.ReadAsString(PathTemp & "Cache\download.json"))) '检查是否有要求的版本(#5195) If Not String.IsNullOrEmpty(Loader.Input) Then Dim Id = Loader.Input @@ -313,10 +315,10 @@ For Each Version As JObject In DlClientListLoader.Output.Value("versions") If Version("id") = Id Then Return Version("url").ToString Next - Log($"未发现版本 {Id} 的 json 下载地址,版本列表返回为:{vbCrLf}{DlClientListLoader.Output.Value.ToString}", NotifyLevel.DebugModeOnly) + Logger.Warn($"未发现版本 {Id} 的 json 下载地址,版本列表返回为:{vbCrLf}{DlClientListLoader.Output.Value}") Return Nothing Catch ex As Exception - Log(ex, $"获取版本 {Id} 的 json 下载地址失败") + Logger.Warn(ex, $"获取版本 {Id} 的 json 下载地址失败") Return Nothing End Try End Function @@ -385,7 +387,7 @@ ''' Public DlOptiFineListLoader As New LoaderTask(Of Integer, DlOptiFineListResult)("DlOptiFineList Main", AddressOf DlOptiFineListMain) Private Sub DlOptiFineListMain(Loader As LoaderTask(Of Integer, DlOptiFineListResult)) - Select Case Settings.Get("ToolDownloadVersion") + Select Case Settings.Get(Of Integer)("ToolDownloadVersion") Case 0 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlOptiFineListResult), Integer)(DlOptiFineListBmclapiLoader, 30), @@ -413,9 +415,9 @@ If Result.Length < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Result & ")") Try '获取所有版本信息 - Dim Forge As List(Of String) = RegexSearch(Result, "(?<=colForge'>)[^<]*") - Dim ReleaseTime As List(Of String) = RegexSearch(Result, "(?<=colDate'>)[^<]+") - Dim Name As List(Of String) = RegexSearch(Result, "(?<=OptiFine_)[0-9A-Za-z_.]+(?=.jar"")") + Dim Forge As List(Of String) = Result.RegexSearch("(?<=colForge'>)[^<]*").ToList + Dim ReleaseTime As List(Of String) = Result.RegexSearch("(?<=colDate'>)[^<]+").ToList + Dim Name As List(Of String) = Result.RegexSearch("(?<=OptiFine_)[0-9A-Za-z_.]+(?=.jar"")").ToList If Not ReleaseTime.Count = Name.Count Then Throw New Exception("版本与发布时间数据无法对应") If Not Forge.Count = Name.Count Then Throw New Exception("版本与 Forge 兼容数据无法对应") If ReleaseTime.Count < 10 Then Throw New Exception("获取到的版本数量不足(" & Result & ")") @@ -491,7 +493,7 @@ ''' Public DlForgeListLoader As New LoaderTask(Of Integer, DlForgeListResult)("DlForgeList Main", AddressOf DlForgeListMain) Private Sub DlForgeListMain(Loader As LoaderTask(Of Integer, DlForgeListResult)) - Select Case Settings.Get("ToolDownloadVersion") + Select Case Settings.Get(Of Integer)("ToolDownloadVersion") Case 0 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlForgeListResult), Integer)(DlForgeListBmclapiLoader, 30), @@ -518,7 +520,7 @@ Dim Result As String = NetRequestByClientRetry("https://files.minecraftforge.net/maven/net/minecraftforge/forge/index_1.2.4.html", Encoding:=Encoding.Default, Accept:="text/html", SimulateBrowserHeaders:=True) If Result.Length < 200 Then Throw New Exception("获取到的版本列表长度不足(" & Result & ")") '获取所有版本信息 - Dim Names As List(Of String) = RegexSearch(Result, "(?<=a href=""index_)[0-9.]+((_pre|[_-]snapshot[_-]?)[0-9]?)?(?=.html)") + Dim Names As List(Of String) = Result.RegexSearch("(?<=a href=""index_)[0-9.]+((_pre|[_-]snapshot[_-]?)[0-9]?)?(?=.html)").ToList Names.Add("1.2.4") '1.2.4 不会被匹配上 If Names.Count < 10 Then Throw New Exception("获取到的版本数量不足(" & Result & ")") Loader.Output = New DlForgeListResult With {.IsOfficial = True, .SourceName = "Forge 官方源", .Value = Names} @@ -640,7 +642,7 @@ Public Sub DlForgeVersionMain(Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry))) Dim DlForgeVersionOfficialLoader As New LoaderTask(Of String, List(Of DlForgeVersionEntry))("DlForgeVersion Official", AddressOf DlForgeVersionOfficialMain) Dim DlForgeVersionBmclapiLoader As New LoaderTask(Of String, List(Of DlForgeVersionEntry))("DlForgeVersion Bmclapi", AddressOf DlForgeVersionBmclapiMain) - Select Case Settings.Get("ToolDownloadVersion") + Select Case Settings.Get(Of Integer)("ToolDownloadVersion") Case 0 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)) From { New KeyValuePair(Of LoaderTask(Of String, List(Of DlForgeVersionEntry)), Integer)(DlForgeVersionBmclapiLoader, 30), @@ -669,7 +671,7 @@ Loader.Input.Replace("-", "_") & '兼容 Forge 1.7.10-pre4,#4057 ".html", SimulateBrowserHeaders:=True) Catch ex As Exception - If ex.GetBrief().Contains("(404)") Then + If ex.GetDisplay(False).Contains("(404)") Then Throw New Exception("无") Else Throw @@ -685,14 +687,14 @@ Dim VersionCode = VersionCodes(i) Try '基础信息获取 - Dim Name As String = RegexSeek(VersionCode, "(?<=[^(0-9)]+)[0-9\.]+") + Dim Name As String = VersionCode.RegexSeek("(?<=[^(0-9)]+)[0-9\.]+") Dim IsRecommended As Boolean = VersionCode.Contains("fa promo-recommended") Dim Inherit As String = Loader.Input '分支获取 - Dim Branch As String = RegexSeek(VersionCode, $"(?<=-{Name}-)[^-""]+(?=-[a-z]+.[a-z]{{3}})") + Dim Branch As String = VersionCode.RegexSeek($"(?<=-{Name}-)[^-""]+(?=-[a-z]+.[a-z]{{3}})") If String.IsNullOrWhiteSpace(Branch) Then Branch = Nothing '发布时间获取 - Dim ReleaseTimeOriginal = RegexSeek(VersionCode, "(?<=""download-time"" title="")[^""]+") + Dim ReleaseTimeOriginal = VersionCode.RegexSeek("(?<=""download-time"" title="")[^""]+") Dim ReleaseTimeSplit = ReleaseTimeOriginal.Split(" -:".ToCharArray) '原格式:"2021-02-15 03:24:02" Dim ReleaseDate As New Date(ReleaseTimeSplit(0), ReleaseTimeSplit(1), ReleaseTimeSplit(2), '年月日 ReleaseTimeSplit(3), ReleaseTimeSplit(4), ReleaseTimeSplit(5), '时分秒 @@ -703,17 +705,17 @@ If VersionCode.Contains("classifier-installer""") Then '类型为 installer.jar,支持范围 ~753 (~ 1.6.1 部分), 738~684 (1.5.2 全部) VersionCode = VersionCode.Substring(VersionCode.IndexOfF("installer.jar")) - MD5 = RegexSeek(VersionCode, "(?<=MD5: )[^<]+") + MD5 = VersionCode.RegexSeek("(?<=MD5: )[^<]+") Category = "installer" ElseIf VersionCode.Contains("classifier-universal""") Then '类型为 universal.zip,支持范围 751~449 (1.6.1 部分), 682~183 (1.5.1 ~ 1.3.2 部分) VersionCode = VersionCode.Substring(VersionCode.IndexOfF("universal.zip")) - MD5 = RegexSeek(VersionCode, "(?<=MD5: )[^<]+") + MD5 = VersionCode.RegexSeek("(?<=MD5: )[^<]+") Category = "universal" ElseIf VersionCode.Contains("client.zip") Then '类型为 client.zip,支持范围 182~ (1.3.2 部分 ~) VersionCode = VersionCode.Substring(VersionCode.IndexOfF("client.zip")) - MD5 = RegexSeek(VersionCode, "(?<=MD5: )[^<]+") + MD5 = VersionCode.RegexSeek("(?<=MD5: )[^<]+") Category = "client" Else '没有任何下载(1.6.4 有一部分这种情况) @@ -875,7 +877,7 @@ ''' Public DlNeoForgeListLoader As New LoaderTask(Of Integer, DlNeoForgeListResult)("DlNeoForgeList Main", AddressOf DlNeoForgeListMain) Private Sub DlNeoForgeListMain(Loader As LoaderTask(Of Integer, DlNeoForgeListResult)) - Select Case Settings.Get("ToolDownloadVersion") + Select Case Settings.Get(Of Integer)("ToolDownloadVersion") Case 0 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlNeoForgeListResult), Integer)(DlNeoForgeListBmclapiLoader, 30), @@ -931,7 +933,7 @@ End Sub Private Function GetNeoForgeEntries(LatestJson As String, LatestLegacyJson As String) As List(Of DlNeoForgeListEntry) - Dim VersionNames = RegexSearch(LatestLegacyJson & LatestJson, + Dim VersionNames = (LatestLegacyJson & LatestJson).RegexSearch( "(?<="")(1\.20\.1-)?\d+\.[^\.]+\.\d+(\.\d+)?(-(beta|alpha)(\.\d+)?)?(\+snapshot-\d+)?(?="")") Dim Versions = VersionNames. Where(Function(name) name <> "47.1.82"). '这个版本虽然在版本列表中,但不能下载 @@ -1000,7 +1002,7 @@ ''' Public DlLiteLoaderListLoader As New LoaderTask(Of Integer, DlLiteLoaderListResult)("DlLiteLoaderList Main", AddressOf DlLiteLoaderListMain) Private Sub DlLiteLoaderListMain(Loader As LoaderTask(Of Integer, DlLiteLoaderListResult)) - Select Case Settings.Get("ToolDownloadVersion") + Select Case Settings.Get(Of Integer)("ToolDownloadVersion") Case 0 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlLiteLoaderListResult), Integer)(DlLiteLoaderListBmclapiLoader, 30), @@ -1099,7 +1101,7 @@ ''' Public DlFabricListLoader As New LoaderTask(Of Integer, DlFabricListResult)("DlFabricList Main", AddressOf DlFabricListMain) Private Sub DlFabricListMain(Loader As LoaderTask(Of Integer, DlFabricListResult)) - Select Case Settings.Get("ToolDownloadVersion") + Select Case Settings.Get(Of Integer)("ToolDownloadVersion") Case 0 DlSourceLoader(Loader, New List(Of KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)) From { New KeyValuePair(Of LoaderTask(Of Integer, DlFabricListResult), Integer)(DlFabricListBmclapiLoader, 30), @@ -1170,32 +1172,32 @@ ''' Public Function DlModRequest(Url As String, Optional Method As HttpMethod = Nothing, Optional Content As String = Nothing, Optional ContentType As String = Nothing) As JToken - Dim Urls As New List(Of KeyValuePair(Of String, Integer)) + Dim Urls As New List(Of (Url As String, Timeout As Integer)) Dim McimUrl As String = DlSourceModGet(Url) If McimUrl <> Url Then - Select Case Settings.Get("ToolDownloadMod") + Select Case Settings.Get(Of Integer)("ToolDownloadMod") Case 0 - Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10)) - Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10)) - Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30)) + Urls.Add((McimUrl, 10)) + Urls.Add((McimUrl, 10)) + Urls.Add((Url, 30)) Case 1 - Urls.Add(New KeyValuePair(Of String, Integer)(Url, If(Url.Contains("modrinth"), 20, 10))) '至少 20s,要不然 Modrinth 返回不过来 - Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 10)) - Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30)) - Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 30)) + Urls.Add((Url, If(Url.Contains("modrinth"), 20, 10))) '至少 20s,要不然 Modrinth 返回不过来 + Urls.Add((McimUrl, 10)) + Urls.Add((Url, 30)) + Urls.Add((McimUrl, 30)) Case Else - Urls.Add(New KeyValuePair(Of String, Integer)(Url, If(Url.Contains("modrinth"), 20, 10))) - Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30)) - Urls.Add(New KeyValuePair(Of String, Integer)(McimUrl, 30)) + Urls.Add((Url, If(Url.Contains("modrinth"), 20, 10))) + Urls.Add((Url, 30)) + Urls.Add((McimUrl, 30)) End Select Else - Urls.Add(New KeyValuePair(Of String, Integer)(Url, If(Url.Contains("modrinth"), 20, 10))) - Urls.Add(New KeyValuePair(Of String, Integer)(Url, 30)) + Urls.Add((Url, If(Url.Contains("modrinth"), 20, 10))) + Urls.Add((Url, 30)) End If Dim Exs As String = "" For Each Source In Urls Try - Return GetJson(NetRequestByClient(Source.Key, Method, Content, ContentType, Timeout:=Source.Value * 1000, Encoding:=Encoding.UTF8, RequireJson:=True)) + Return GetJson(NetRequestByClient(Source.Url, Method, Content, ContentType, Timeout:=Source.Timeout * 1000, Encoding:=Encoding.UTF8, RequireJson:=True)) Catch ex As Exception Exs += ex.Message + vbCrLf End Try @@ -1213,7 +1215,7 @@ ''' Public ReadOnly Property DlSourcePreferMojang As Boolean Get - Return Settings.Get("ToolDownloadSource") = 2 OrElse (Settings.Get("ToolDownloadSource") = 1 AndAlso DlPreferMojang) + Return Settings.Get(Of Integer)("ToolDownloadSource") = 2 OrElse (Settings.Get(Of Integer)("ToolDownloadSource") = 1 AndAlso DlPreferMojang) End Get End Property ''' @@ -1227,7 +1229,7 @@ ''' Public ReadOnly Property DlVersionListPreferMojang As Boolean Get - Return Settings.Get("ToolDownloadVersion") = 2 OrElse (Settings.Get("ToolDownloadVersion") = 1 AndAlso DlPreferMojang) + Return Settings.Get(Of Integer)("ToolDownloadVersion") = 2 OrElse (Settings.Get(Of Integer)("ToolDownloadVersion") = 1 AndAlso DlPreferMojang) End Get End Property ''' diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb index 0eaac4f..5032b47 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModJava.vb @@ -79,8 +79,7 @@ ''' 输入 javaw.exe 文件所在文件夹的路径,不限制结尾。 ''' Public Sub New(Folder As String, IsUserImport As Boolean) - If Not Folder.EndsWithF("\") Then Folder += "\" - PathFolder = Folder.Replace("/", "\") + PathFolder = PathUtils.AddSlashSuffix(PathUtils.ForCompare(Folder)) Me.IsUserImport = IsUserImport End Sub @@ -94,18 +93,18 @@ Dim Output As String = Nothing Try '确定文件存在 - If Not File.Exists(PathJava) Then Throw New FileNotFoundException("未找到 java.exe 文件", PathJava) + If Not FileUtils.Exists(PathJava) Then Throw New FileNotFoundException("未找到 java.exe 文件", PathJava) If {"finalshell", "Paranoia File"}.Any(Function(n) PathJava.ContainsIgnoreCase(n)) Then Throw New Exception("不兼容该精简版 Java") '#2249、#8080 - If File.Exists(PathFolder & "pdf-bookmark") Then Throw New Exception("不兼容 PDF Bookmark 的 Java") '#5326 - IsJre = Not File.Exists(PathFolder & "javac.exe") + If FileUtils.Exists(PathFolder & "pdf-bookmark") Then Throw New Exception("不兼容 PDF Bookmark 的 Java") '#5326 + IsJre = Not FileUtils.Exists(PathFolder & "javac.exe") '运行 -version Output = StartProcessAndGetOutput(PathJava, "-version", 15000).Lower If Output = "" Then Throw New ApplicationException("尝试运行该 Java 失败") - If ModeDebug Then Log("[Java] Java 检查输出:" & PathJava & vbCrLf & Output) + Logger.Trace($"Java 检查输出:{PathJava}{vbCrLf}{Output}") If Output.Contains("/lib/ext exists") Then Throw New ApplicationException("无法运行该 Java,请在删除 Java 文件夹中的 /lib/ext 文件夹后再试") If Output.Contains("a fatal error") Then Throw New ApplicationException("无法运行该 Java,该 Java 或系统存在问题") '获取详细信息 - Dim VersionString = If(RegexSeek(Output, "(?<=version "")[^""]+"), If(RegexSeek(Output, "(?<=openjdk )[0-9]+"), "")).Replace("_", ".").Split("-").First + Dim VersionString = If(Output.RegexSeek("(?<=version "")[^""]+"), If(Output.RegexSeek("(?<=openjdk )[0-9]+"), "")).Replace("_", ".").Split("-").First If VersionString.Split(".").Count > 4 Then VersionString = VersionString.Replace(".0.", ".") '#3493,VersionString = "21.0.2.0.2" Do While VersionString.Split(".").Count < 4 If VersionString.StartsWithF("1.") Then @@ -117,7 +116,7 @@ If VersionString = "" Then Throw New ApplicationException($"未找到该 Java 的版本号{If(Output.Length < 500, $"{vbCrLf}输出为:{vbCrLf}{Output}", "")}") Version = New Version(VersionString) If Version.Minor = 0 Then - Log("[Java] 疑似 X.0.X.X 格式版本号:" & Version.ToString) + Logger.Info($"疑似 X.0.X.X 格式版本号:{Version}") Version = New Version(1, Version.Major, Version.Build, Version.Revision) End If Is64Bit = Output.Contains("64-bit") @@ -129,7 +128,7 @@ Catch ex As ThreadInterruptedException Throw ex Catch ex As Exception - Log("[Java] 检查失败的 Java 输出:" & If(PathJava, "Nothing") & vbCrLf & If(Output, "无程序输出")) + Logger.Info($"检查失败的 Java 输出:{If(PathJava, "Nothing")}{vbCrLf}{If(Output, "无程序输出")}") Throw New Exception("检查 Java 失败(" & If(PathJava, "Nothing") & ")", ex) End Try IsChecked = True @@ -165,25 +164,25 @@ Public Sub JavaListInit() JavaList = New List(Of JavaEntry) Try - If Settings.Get("CacheJavaListVersion") < JavaListCacheVersion Then + If Settings.Get(Of Integer)("CacheJavaListVersion") < JavaListCacheVersion Then '不使用缓存 - Log("[Java] 要求 Java 列表缓存更新") + Logger.Info("要求 Java 列表缓存更新") Settings.Set("CacheJavaListVersion", JavaListCacheVersion) Else '使用缓存 - For Each JsonEntry In GetJson(Settings.Get("LaunchArgumentJavaAll")) + For Each JsonEntry In GetJson(Settings.Get(Of String)("LaunchArgumentJavaAll")) JavaList.Add(JavaEntry.FromJson(JsonEntry)) Next End If If Not JavaList.Any() Then - Log("[Java] 初始化未找到可用的 Java,将自动触发搜索", NotifyLevel.DevelopOnly) + Logger.Warn("初始化未找到可用的 Java,将自动触发搜索") JavaSearchLoader.Start(0) Else - Log("[Java] 缓存中有 " & JavaList.Count & " 个可用的 Java:") - JavaList.ForEach(Sub(j) Log($"[Java] - {j}")) + Logger.Info($"缓存中有 {JavaList.Count} 个可用的 Java:") + JavaList.ForEach(Sub(j) Logger.Info($"- {j}")) End If Catch ex As Exception - Log(ex, "初始化 Java 列表失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "初始化 Java 列表失败") Settings.Set("LaunchArgumentJavaAll", "[]") End Try End Sub @@ -205,7 +204,7 @@ '添加特定的 Java Dim JavaPreList As New Dictionary(Of String, Boolean) If McFolderSelected.Split("\").Count > 3 AndAlso Not McFolderSelected.Contains("AppData\Roaming") Then - JavaSearchFolder(GetPathFromFullPath(McFolderSelected), JavaPreList, False, True) 'Minecraft 文件夹的父文件夹(如果不是根目录或 %APPDATA% 的话) + JavaSearchFolder(PathUtils.AddSlashSuffix(PathUtils.RemoveLastPart(McFolderSelected)), JavaPreList, False, True) 'Minecraft 文件夹的父文件夹(如果不是根目录或 %APPDATA% 的话) End If JavaSearchFolder(McFolderSelected, JavaPreList, False, True) 'Minecraft 文件夹 JavaPreList = JavaPreList.Where(Function(j) Not j.Key.Contains(".minecraft\runtime")). @@ -219,9 +218,9 @@ '检查特定的 Java If TargetJavaList.Any Then TargetJavaList = JavaCheckList(TargetJavaList) - Log("[Java] 检查后找到 " & TargetJavaList.Count & " 个特定路径下的 Java:") + Logger.Info($"检查后找到 {TargetJavaList.Count} 个特定路径下的 Java:") For Each Java In TargetJavaList - Log($"[Java] - {Java}") + Logger.Info($"- {Java}") Next End If @@ -232,7 +231,7 @@ '获取版本独立设置中指定的 Java Dim VersionSelect As String = "" If GameInstance IsNot Nothing Then - VersionSelect = Settings.Get("VersionArgumentJavaSelect", Instance:=GameInstance) + VersionSelect = Settings.Get(Of String)("VersionArgumentJavaSelect", Instance:=GameInstance) If VersionSelect.StartsWithF("{") Then Try UserJava = JavaEntry.FromJson(GetJson(VersionSelect)) @@ -242,28 +241,28 @@ Catch ex As Exception UserJava = Nothing Settings.Reset("VersionArgumentJavaSelect", Instance:=GameInstance) - Log(ex, "版本独立设置中指定的 Java 已无法使用,此设置已重置", NotifyLevel.AllUsers) + Logger.Error(ex, "版本独立设置中指定的 Java 已无法使用,此设置已重置", LogBehavior.Toast) End Try End If End If '获取全局设置中指定的 Java - If UserJava Is Nothing AndAlso VersionSelect <> "" AndAlso Settings.Get("LaunchArgumentJavaSelect") <> "" Then + If UserJava Is Nothing AndAlso VersionSelect <> "" AndAlso Settings.Get(Of String)("LaunchArgumentJavaSelect") <> "" Then Try - UserJava = JavaEntry.FromJson(GetJson(Settings.Get("LaunchArgumentJavaSelect"))) + UserJava = JavaEntry.FromJson(GetJson(Settings.Get(Of String)("LaunchArgumentJavaSelect"))) UserJava.Check() Catch ex As ThreadInterruptedException Throw Catch ex As Exception UserJava = Nothing Settings.Reset("LaunchArgumentJavaSelect") - Log(ex, "全局设置中指定的 Java 已无法使用,此设置已重置", NotifyLevel.AllUsers) + Logger.Error(ex, "全局设置中指定的 Java 已无法使用,此设置已重置", LogBehavior.Toast) End Try End If '添加到特定 Java 列表 If UserJava IsNot Nothing Then - Log($"[Java] 用户指定的 Java:{UserJava}") + Logger.Info($"用户指定的 Java:{UserJava}") TargetJavaList.Add(UserJava) End If @@ -294,7 +293,7 @@ RetryGet: '若未找到适合的 Java,尝试触发搜索 If Not AllowedJavaList.Any() AndAlso JavaSearchLoader.State = LoadState.Waiting Then - Log("[Java] 未找到满足条件的 Java,尝试进行搜索") + Logger.Info("未找到满足条件的 Java,尝试进行搜索") JavaSearchLoader.Start(IsForceRestart:=True) GoTo RetryGet End If @@ -304,16 +303,16 @@ RetryGet: '确保指定的 Java 可用 If UserJava Is Nothing Then GoTo ExitUserJavaCheck If AllowedJavaList.Any(Function(j) j.PathFolder = UserJava.PathFolder) Then - Log("[Java] 使用用户指定的 Java:" & UserJava.PathFolder) + Logger.Info($"使用用户指定的 Java:{UserJava.PathFolder}") AllowedJavaList = New List(Of JavaEntry) From {UserJava} GoTo UserPass End If '指定的 Java 不可用,弹窗要求选择 - Log("[Java] 发现用户指定的不兼容 Java:" & UserJava.ToString) - Log($"[Java] 目前实际可用的 Java 列表:") + Logger.Info($"发现用户指定的不兼容 Java:{UserJava}") + Logger.Info($"目前实际可用的 Java 列表:") For Each Java In AllowedJavaList - Log($"[Java] - {Java}") + Logger.Info($"- {Java}") Next Dim Requirement As String = "" Dim ShowRevision As Boolean = False @@ -330,20 +329,20 @@ RetryGet: Requirement = "需要 Java " & If(Left = Right, Left, Left & " ~ " & Right) End If Dim JavaCurrent As String = UserJava.MajorVersion & If(ShowRevision, "." & UserJava.Version.MajorRevision & "." & UserJava.Version.MinorRevision, "") - If GameInstance IsNot Nothing AndAlso Settings.Get("VersionAdvanceJava", GameInstance) Then + If GameInstance IsNot Nothing AndAlso Settings.Get(Of Boolean)("VersionAdvanceJava", GameInstance) Then '直接跳过弹窗 - Log("[Java] 设置中指定了使用 Java " & JavaCurrent & ",但当前版本" & Requirement & ",这可能会导致游戏崩溃!", NotifyLevel.DebugModeOnly) + Logger.Warn($"设置中指定了使用 Java {JavaCurrent},但当前版本{Requirement},这可能会导致游戏崩溃!") AllowedJavaList = New List(Of JavaEntry) From {UserJava} Else Select Case MyMsgBox("你在设置中手动指定了使用 Java " & JavaCurrent & ",但当前" & Requirement & "。" & vbCrLf & "如果强制使用该 Java,可能导致游戏崩溃。" & vbCrLf & - "你也可以将 游戏 Java 设置修改为 自动选择合适的 Java。" & vbCrLf & + "你也可以将 游戏 Java 设置修改为 自动选择。" & vbCrLf & vbCrLf & " - 指定的 Java:" & UserJava.ToString, "Java 兼容性警告", "让 PCL 自动选择", "强制使用该 Java", "取消") Case 1 '让 PCL 自动选择 Case 2 '强制使用指定的 Java - Log("[Java] 已强制使用用户指定的不兼容 Java") + Logger.Info("已强制使用用户指定的不兼容 Java") AllowedJavaList = New List(Of JavaEntry) From {UserJava} Case 3 '取消启动 Throw New Exception(CancelException) @@ -364,7 +363,7 @@ ExitUserJavaCheck: If TargetJavaList.Contains(Java) Then '直接使用指定的 Java AllowedJavaList = New List(Of JavaEntry) From {Java} - Log("[Java] 优先使用特定路径下的 Java:" & Java.ToString) + Logger.Info($"优先使用特定路径下的 Java:{Java}") GoTo UserPass End If Next @@ -372,9 +371,9 @@ UserPass: '对适合的 Java 进行排序 AllowedJavaList = AllowedJavaList.SortByComparison(AddressOf JavaSorter) - Log($"[Java] 排序后的 Java 优先顺序:") + Logger.Info($"排序后的 Java 优先顺序:") For Each Java In AllowedJavaList - Log($"[Java] - {Java}") + Logger.Info($"- {Java}") Next '检查选定的 Java,若测试失败则尝试进行搜索 @@ -384,23 +383,23 @@ UserPass: Catch ex As ThreadInterruptedException Throw Catch ex As Exception - If ex.InnerException IsNot Nothing AndAlso TypeOf (ex.InnerException) Is ThreadInterruptedException Then Throw ex.InnerException - Log(ex, "最终选定的 Java 已无法使用,尝试进行搜索") + If ex.InnerException IsNot Nothing AndAlso TypeOf ex.InnerException Is ThreadInterruptedException Then Throw ex.InnerException + Logger.Warn(ex, "最终选定的 Java 已无法使用,尝试进行搜索") AllowedJavaList = New List(Of JavaEntry) JavaSearchLoader.Start(IsForceRestart:=True) GoTo RetryGet End Try '返回 - Log("[Java] 最终选定的 Java:" & AllowedJavaList.First.ToString) + Logger.Info($"最终选定的 Java:{AllowedJavaList.First}") Return SelectedJava Catch ex As ThreadInterruptedException - Log(ex, "查找符合条件的 Java 时出现加载器中断") + Logger.Warn(ex, "查找符合条件的 Java 时出现加载器中断") Return Nothing Catch ex As Exception If ex.Message = "$$" Then Throw ex - Log(ex, "查找符合条件的 Java 失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "查找符合条件的 Java 失败") Return Nothing End Try End Function @@ -410,9 +409,9 @@ UserPass: Public Function JavaIs64Bit(Optional GameInstance As McInstance = Nothing) As Boolean Try '检查强制指定 - Dim UserSetup As String = Settings.Get("LaunchArgumentJavaSelect") + Dim UserSetup As String = Settings.Get(Of String)("LaunchArgumentJavaSelect") If GameInstance IsNot Nothing Then - Dim UserSetupVersion As String = Settings.Get("VersionArgumentJavaSelect", Instance:=GameInstance) + Dim UserSetupVersion As String = Settings.Get(Of String)("VersionArgumentJavaSelect", Instance:=GameInstance) If UserSetupVersion <> "使用全局设置" Then UserSetup = UserSetupVersion End If If UserSetup <> "" Then @@ -420,7 +419,7 @@ UserPass: Try UserJava = JavaEntry.FromJson(GetJson(UserSetup)) Catch ex As Exception - Log(ex, "版本指定的 Java 信息已损坏,已重置版本设置中指定的 Java") + Logger.Warn(ex, "版本指定的 Java 信息已损坏,已重置版本设置中指定的 Java") Settings.Set("VersionArgumentJavaSelect", "使用全局设置", Instance:=GameInstance) GoTo NoUserJava End Try @@ -435,7 +434,7 @@ NoUserJava: Next Return False Catch ex As Exception - Log(ex, "检查 Java 类别时出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "检查 Java 类别时出错") Settings.Set("LaunchArgumentJavaSelect", "") Return True End Try @@ -444,12 +443,12 @@ NoUserJava: ''' 将 Java 按照适用性排序。 ''' Public Function JavaSorter(Left As JavaEntry, Right As JavaEntry) As Boolean - Dim PathInfo As New DirectoryInfo(PathExeFolder) - Dim PathMcInfo As New DirectoryInfo(McFolderSelected) '1. 尽量在当前文件夹或当前 Minecraft 文件夹 Dim ProgramPathParent As String, MinecraftPathParent As String = "" - ProgramPathParent = If(PathInfo.Parent, PathInfo).FullName - If McFolderSelected <> "" Then MinecraftPathParent = If(PathMcInfo.Parent, PathMcInfo).FullName + Dim PathInfo = DirectoryUtils.GetInfo(PathExeFolder) + ProgramPathParent = PathUtils.RemoveExtendedPrefix(If(PathInfo.Parent, PathInfo).FullName) + Dim PathMcInfo = DirectoryUtils.GetInfo(McFolderSelected) + If McFolderSelected <> "" Then MinecraftPathParent = PathUtils.RemoveExtendedPrefix(If(PathMcInfo.Parent, PathMcInfo).FullName) If Left.PathFolder.StartsWithF(ProgramPathParent) AndAlso Not Right.PathFolder.StartsWithF(ProgramPathParent) Then Return True If Not Left.PathFolder.StartsWithF(ProgramPathParent) AndAlso Right.PathFolder.StartsWithF(ProgramPathParent) Then Return False If McFolderSelected <> "" Then @@ -505,12 +504,12 @@ NoUserJava: #Region "模糊查找可能可用的 Java" '查找环境变量中的 Java - For Each PathInEnv As String In Split((PathEnv & ";" & PathJavaHome).Replace("\\", "\").Replace("/", "\"), ";") + For Each PathInEnv As String In (PathEnv & ";" & PathJavaHome).Replace("\\", "\").Replace("/", "\").Split(";") PathInEnv = PathInEnv.Trim(" """.ToCharArray()) If PathInEnv = "" Then Continue For If Not PathInEnv.EndsWithF("\") Then PathInEnv += "\" '粗略检查有效性 - If File.Exists(PathInEnv & "javaw.exe") Then JavaPreList(PathInEnv) = False + If FileUtils.Exists(PathInEnv & "javaw.exe") Then JavaPreList(PathInEnv) = False Next '查找磁盘中的 Java For Each Disk As DriveInfo In DriveInfo.GetDrives() @@ -530,15 +529,15 @@ NoUserJava: Dim JavaWithoutReparse As New Dictionary(Of String, Boolean) For Each Pair In JavaPreList Dim Folder As String = Pair.Key.Replace("\\", "\").Replace("/", "\") - Dim Info As FileSystemInfo = New FileInfo(Folder & "javaw.exe") + Dim Info As FileSystemInfo = FileUtils.GetInfo(Folder & "javaw.exe") Do If Info.Attributes.HasFlag(FileAttributes.ReparsePoint) Then - Log("[Java] 位于 " & Folder & " 的 Java 包含符号链接") + Logger.Info($"位于 {Folder} 的 Java 包含符号链接") Continue For End If Info = If(TypeOf Info Is FileInfo, CType(Info, FileInfo).Directory, CType(Info, DirectoryInfo).Parent) Loop While Info IsNot Nothing - Log("[Java] 位于 " & Folder & " 的 Java 不含符号链接") + Logger.Info($"位于 {Folder} 的 Java 不含符号链接") JavaWithoutReparse.Add(Pair.Key, Pair.Value) Next If JavaWithoutReparse.Any Then JavaPreList = JavaWithoutReparse @@ -547,7 +546,7 @@ NoUserJava: Dim JavaWithoutInherit As New Dictionary(Of String, Boolean) For Each Pair In JavaPreList If Pair.Key.Contains("java8path_target_") OrElse Pair.Key.Contains("javapath_target_") OrElse Pair.Key.Contains("javatmp") OrElse Pair.Key.Contains("system32") Then - Log("[Java] 位于 " & Pair.Key & " 的 Java 位于特殊路径,不应优先使用") + Logger.Info($"位于 {Pair.Key} 的 Java 位于特殊路径,不应优先使用") Else JavaWithoutInherit.Add(Pair.Key, Pair.Value) End If @@ -558,14 +557,14 @@ NoUserJava: #Region "添加玩家手动导入的 Java" - Dim ImportedJava As String = Settings.Get("LaunchArgumentJavaAll") + Dim ImportedJava As String = Settings.Get(Of String)("LaunchArgumentJavaAll") Try For Each JavaJsonObject In GetJson(ImportedJava) Dim Entry = JavaEntry.FromJson(JavaJsonObject) If Entry.IsUserImport Then JavaPreList(Entry.PathFolder) = True Next Catch ex As Exception - Log(ex, "Java 列表已损坏", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "Java 列表已损坏") Settings.Set("LaunchArgumentJavaAll", "[]") End Try @@ -587,11 +586,11 @@ NoUserJava: JavaList = NewJavaList Catch ex As Exception - Log(ex, "搜索 Java 时出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "搜索 Java 时出错") JavaList = New List(Of JavaEntry) End Try - Log("[Java] Java 搜索完成,发现 " & JavaList.Count & " 个 Java") + Logger.Info($"Java 搜索完成,发现 {JavaList.Count} 个 Java") If FrmSetupLaunch IsNot Nothing Then RunInUi(Sub() FrmSetupLaunch.UpdateJavaComboBox()) If FrmInstanceSetup IsNot Nothing Then RunInUi(Sub() FrmInstanceSetup.RefreshJavaComboBox()) End Sub @@ -600,8 +599,8 @@ NoUserJava: ''' 多线程检查列表中的所有 Java 项。 ''' Private Function JavaCheckList(JavaEntries As List(Of JavaEntry)) As List(Of JavaEntry) - Log("[Java] 开始确认列表 Java 状态,共 " & JavaEntries.Count & " 项") - JavaCheckList = New List(Of JavaEntry) + Logger.Info($"开始确认列表 Java 状态,共 {JavaEntries.Count} 项") + Dim Result = New List(Of JavaEntry) Dim ListLock As New Object '启动检查线程 @@ -611,16 +610,16 @@ NoUserJava: Sub() Try Entry.Check() - If ModeDebug Then Log("[Java] - " & Entry.ToString) + Logger.Trace($"- {Entry}") SyncLock ListLock - JavaCheckList.Add(Entry) + Result.Add(Entry) End SyncLock Catch ex As ThreadInterruptedException Catch ex As Exception If Entry.IsUserImport Then - Log(ex, "位于 " & Entry.PathFolder & " 的 Java 存在异常,将被自动移除", NotifyLevel.AllUsers) + Logger.Error(ex, $"位于 {Entry.PathFolder} 的 Java 存在异常,将被自动移除", LogBehavior.Toast) Else - Log(ex, "位于 " & Entry.PathFolder & " 的 Java 存在异常") + Logger.Warn(ex, $"位于 {Entry.PathFolder} 的 Java 存在异常") End If End Try End Sub) @@ -634,6 +633,7 @@ Wait: For Each CheckThread In CheckThreads If CheckThread.IsAlive Then GoTo Wait Next + Return Result End Function ''' ''' 模糊搜索指定文件夹下的 Java,并只进行粗略的检查。这不会搜索全部路径。 @@ -642,12 +642,12 @@ Wait: ''' 搜索当前文件夹下的全部文件夹(此参数不会传递到子文件夹)。 Private Sub JavaSearchFolder(OriginalPath As String, ByRef Results As Dictionary(Of String, Boolean), Source As Boolean, Optional IsFullSearch As Boolean = False) Try - Log("[Java] 开始" & If(IsFullSearch, "完全", "部分") & "遍历查找:" & OriginalPath) - JavaSearchFolder(New DirectoryInfo(OriginalPath), Results, Source, IsFullSearch) + Logger.Info($"开始{If(IsFullSearch, "完全", "部分")}遍历查找:{OriginalPath}") + JavaSearchFolder(DirectoryUtils.GetInfo(OriginalPath), Results, Source, IsFullSearch) Catch ex As UnauthorizedAccessException - Log("[Java] 遍历查找 Java 时遭遇无权限的文件夹:" & OriginalPath) + Logger.Info($"遍历查找 Java 时遭遇无权限的文件夹:{OriginalPath}") Catch ex As Exception - Log(ex, "遍历查找 Java 时出错(" & OriginalPath & ")") + Logger.Warn(ex, $"遍历查找 Java 时出错({OriginalPath})") End Try End Sub ''' @@ -659,10 +659,9 @@ Wait: Try '确认目录存在 If Not OriginalPath.Exists Then Return - Dim Folder As String = OriginalPath.FullName.Replace("\\", "\") - If Not Folder.EndsWithF("\") Then Folder += "\" + Dim Folder As String = PathUtils.AddSlashSuffix(PathUtils.ForCompare(OriginalPath.FullName)) '若该目录有 Java,则加入结果 - If File.Exists(Folder & "javaw.exe") Then Results(Folder) = Source + If FileUtils.Exists(Folder & "javaw.exe") Then Results(Folder) = Source '查找其下的所有文件夹 '不应使用网易的 Java:https://github.com/Meloong-Git/PCL/issues/1279#issuecomment-2761489121 Static Keywords As String() = { @@ -674,16 +673,16 @@ Wait: "download", "launch", "程序", "path", "version", "baka", "pcl", "zulu", "local", "packages", "4297127d64ec6", "1.", "启动", "jbr"} For Each FolderInfo As DirectoryInfo In OriginalPath.EnumerateDirectories If FolderInfo.Attributes.HasFlag(FileAttributes.ReparsePoint) Then Continue For '跳过符号链接 - Dim SearchEntry = GetFolderNameFromPath(FolderInfo.Name).Lower '用于搜索的字符串 + Dim SearchEntry = PathUtils.GetLastPart(FolderInfo.Name).Lower '用于搜索的字符串 If IsFullSearch OrElse OriginalPath.Name.Lower = "users" OrElse Val(SearchEntry) > 0 OrElse Keywords.Any(Function(w) SearchEntry.Contains(w)) OrElse SearchEntry = "bin" Then JavaSearchFolder(FolderInfo, Results, Source) End If Next Catch ex As UnauthorizedAccessException - Log("[Java] 遍历查找 Java 时遭遇无权限的文件夹:" & OriginalPath.FullName) + Logger.Trace(Function() $"遍历查找 Java 时遭遇无权限的文件夹({OriginalPath.FullName}):{ex.GetDisplay(False)}") Catch ex As Exception - Log(ex, "遍历查找 Java 时出错(" & OriginalPath.FullName & ")") + Logger.Warn(ex, $"遍历查找 Java 时出错({OriginalPath.FullName})") End Try End Sub @@ -704,8 +703,8 @@ Wait: AddHandler JavaDownloadLoader.OnStateChangedThread, Sub(Raw As LoaderBase, NewState As LoadState, OldState As LoadState) If (NewState = LoadState.Failed OrElse NewState = LoadState.Interrupted) AndAlso LastJavaBaseDir IsNot Nothing Then - Log($"[Java] 由于下载未完成,清理未下载完成的 Java 文件:{LastJavaBaseDir}", NotifyLevel.DebugModeOnly) - DeleteDirectory(LastJavaBaseDir) + Logger.Warn($"由于下载未完成,清理未下载完成的 Java 文件:{LastJavaBaseDir}") + DirectoryUtils.Delete(LastJavaBaseDir) ElseIf NewState = LoadState.Finished Then LastJavaBaseDir = Nothing End If @@ -715,7 +714,7 @@ Wait: End Function Private LastJavaBaseDir As String = Nothing '用于在下载中断或失败时删除未完成下载的 Java 文件夹,防止残留只下了一半但 -version 能跑的 Java Private Sub JavaFileList(Loader As LoaderTask(Of String, List(Of NetFile))) - Log("[Java] 开始获取 Java 下载信息") + Logger.Info("开始获取 Java 下载信息") Dim IndexFileStr As String = NetRequestByLoader(DlVersionListOrder( {"https://piston-meta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"}, {"https://bmclapi2.bangbang93.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"} @@ -751,7 +750,7 @@ Wait: Results.Add(New NetFile(DlSourceOrder({Url}, {Url.Replace("piston-data.mojang.com", "bmclapi2.bangbang93.com")}), LastJavaBaseDir & File.Name, Checker)) Next Loader.Output = Results - Log($"[Java] 需要下载 {Results.Count} 个文件,目标文件夹:{LastJavaBaseDir}") + Logger.Info($"需要下载 {Results.Count} 个文件,目标文件夹:{LastJavaBaseDir}") End Sub #End Region diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb index 3eb2307..8b08ab6 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb @@ -68,10 +68,10 @@ ''' ''' 记录启动日志。 ''' - Public Sub McLaunchLog(Text As String) + Public Sub McLaunchLog(Text As String, Optional Level As LogLevel = LogLevel.Info) Text = FilterUserName(FilterAccessToken(Text, "*"), "*") - RunInUi(Sub() FrmLaunchRight.LabLog.Text += $"{vbCrLf}[{GetTimeNow()}] {Text}") - Log("[Launch] " & Text) + If ModeDebug Then RunInUi(Sub() FrmLaunchRight.LabLog.Text += $"{vbCrLf}[{Date.Now:HH':'mm':'ss'.'fff}] {Text}") + Logger.Log(Text, Level) End Sub '启动状态切换 @@ -123,9 +123,9 @@ New LoaderTask(Of Integer, Integer)("结束处理", AddressOf McLaunchEnd) With {.ProgressWeight = 1} } '内存优化 - Select Case Settings.Get("VersionRamOptimize", Instance:=McInstanceSelected) + Select Case Settings.Get(Of Integer)("VersionRamOptimize", Instance:=McInstanceSelected) Case 0 '全局 - If Settings.Get("LaunchArgumentRam") Then '使用全局设置 + If Settings.Get(Of Boolean)("LaunchArgumentRam") Then '使用全局设置 CType(Loaders(2), LoaderCombo(Of String)).Block = False Loaders.Insert(3, New LoaderTask(Of Integer, Integer)("内存优化", AddressOf McLaunchMemoryOptimize) With {.ProgressWeight = 30}) End If @@ -155,7 +155,7 @@ If Not IsSavingBatch Then Telemetry("Minecraft 启动成功", "Version", McInstanceSelected.VersionDisplayName, - "LoginType", GetStringFromEnum(CType(Settings.Get("LoginType"), McLoginType))) + "LoginType", Settings.Get(Of McLoginType)("LoginType").ToString) End If Case LoadState.Interrupted If InterruptHint Is Nothing Then @@ -166,7 +166,7 @@ Case LoadState.Failed Throw LaunchLoader.Error Case Else - Throw New Exception("错误的状态改变:" & GetStringFromEnum(CType(LaunchLoader.State, [Enum]))) + Throw New Exception("错误的状态改变:" & LaunchLoader.State.ToString()) End Select Catch ex As Exception Dim CurrentEx = ex @@ -182,16 +182,14 @@ NextInner: GoTo NextInner Else '没有特殊处理过的错误信息 - McLaunchLog("错误:" & ex.GetDetail()) - Log(ex, - If(IsSavingBatch, "导出启动脚本失败", "Minecraft 启动失败"), NotifyLevel.MsgBox, - If(IsSavingBatch, "导出启动脚本失败", "启动失败")) + McLaunchLog("错误:" & ex.GetDisplay(True)) + Logger.Error(ex, If(IsSavingBatch, "导出启动脚本失败", "Minecraft 启动失败"), LogBehavior.Alert) '上报 If Not IsSavingBatch Then Telemetry("Minecraft 启动失败", "Version", McInstanceSelected.VersionDisplayName, - "LoginType", GetStringFromEnum(CType(Settings.Get("LoginType"), McLoginType)), - "Exception", FilterUserName(FilterAccessToken(ex.GetDetail(), "*"), "*")) + "LoginType", Settings.Get(Of McLoginType)("LoginType").ToString, + "Exception", FilterUserName(FilterAccessToken(ex.GetDisplay(True), "*"), "*")) End If Throw End If @@ -225,7 +223,7 @@ NextInner: #Region "预检测" Private Sub McLaunchPrecheck() - If Settings.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(100, 2000)) + If Settings.Get(Of Boolean)("SystemDebugDelay") Then Thread.Sleep(RandomInteger(100, 2000)) '检查路径 If McInstanceSelected.PathIndie.Contains("!") OrElse McInstanceSelected.PathIndie.Contains(";") Then Throw New Exception("游戏路径中不可包含 ! 或 ;(" & McInstanceSelected.PathIndie & ")") If McInstanceSelected.PathVersion.Contains("!") OrElse McInstanceSelected.PathVersion.Contains(";") Then Throw New Exception("游戏路径中不可包含 ! 或 ;(" & McInstanceSelected.PathVersion & ")") @@ -241,12 +239,12 @@ NextInner: If BuildType = BuildTypes.Release AndAlso CurrentLaunchOptions?.SaveBatch Is Nothing Then '保存脚本时不提示 RunInNewThread( Sub() - Select Case Settings.Get("SystemLaunchCount") + Select Case Settings.Get(Of Integer)("SystemLaunchCount") Case 10, 20, 40, 60, 80, 100, 120, 150, 200, 250, 300, 350, 400, 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000 - If MyMsgBox("PCL 已经为你启动了 " & Settings.Get("SystemLaunchCount") & " 次游戏啦!" & vbCrLf & + If MyMsgBox("PCL 已经为你启动了 " & Settings.Get(Of Integer)("SystemLaunchCount") & " 次游戏啦!" & vbCrLf & "如果 PCL 还算好用的话,能不能考虑赞助一下 PCL……" & vbCrLf & "如果没有大家的支持,PCL 很难在免费、无任何广告的情况下维持数年的更新(磕头)……!", - Settings.Get("SystemLaunchCount") & " 次启动!", "支持 PCL!", "但是我拒绝") = 1 Then + Settings.Get(Of Integer)("SystemLaunchCount") & " 次启动!", "支持 PCL!", "但是我拒绝") = 1 Then OpenWebsite("https://meloong.com/afd/a/LTCat") End If End Select @@ -254,13 +252,13 @@ NextInner: End If '正版购买提示 If CurrentLaunchOptions?.SaveBatch Is Nothing AndAlso '保存脚本时不提示 - Not Settings.Get("HintBuy") AndAlso Settings.Get("LoginType") <> McLoginType.Ms Then - If IsSystemLanguageChinese() Then + Not Settings.Get(Of Boolean)("HintBuy") AndAlso Settings.Get(Of McLoginType)("LoginType") <> McLoginType.Ms Then + If Globalization.CultureInfo.CurrentCulture.Name.StartsWithF("zh") OrElse Globalization.CultureInfo.CurrentUICulture.Name.StartsWithF("zh") Then '中文? RunInNewThread( Sub() - Select Case Settings.Get("SystemLaunchCount") + Select Case Settings.Get(Of Integer)("SystemLaunchCount") Case 3, 8, 15, 30, 50, 70, 90, 110, 130, 180, 220, 280, 330, 380, 450, 550, 660, 750, 880, 950, 1100, 1300, 1500, 1700, 1900 - If MyMsgBox("你已经启动了 " & Settings.Get("SystemLaunchCount") & " 次 Minecraft 啦!" & vbCrLf & + If MyMsgBox("你已经启动了 " & Settings.Get(Of Integer)("SystemLaunchCount") & " 次 Minecraft 啦!" & vbCrLf & "如果觉得 Minecraft 还不错,可以购买正版支持一下,毕竟开发游戏也真的很不容易……不要一直白嫖啦。" & vbCrLf & vbCrLf & "在登录一次正版账号后,就不会再出现这个提示了!", "考虑一下正版?", "支持正版游戏!", "下次一定") = 1 Then @@ -268,7 +266,7 @@ NextInner: End If End Select End Sub, "Buy Minecraft") - ElseIf Settings.Get("LoginType") = McLoginType.Legacy Then + ElseIf Settings.Get(Of McLoginType)("LoginType") = McLoginType.Legacy Then Select Case MyMsgBox("你必须先登录正版账号,才能进行离线登录!", "正版验证", "购买正版", "试玩", "返回", Button1Action:=Sub() OpenWebsite("https://www.xbox.com/zh-cn/games/store/minecraft-java-bedrock-edition-for-pc/9nxp44l49shj")) Case 2 @@ -399,30 +397,30 @@ NextInner: ''' Public Function McLoginName() As String '根据当前登录方式优先返回 - Select Case Settings.Get("LoginType") + Select Case Settings.Get(Of McLoginType)("LoginType") Case McLoginType.Ms - If Settings.Get("CacheMsV2Name") <> "" Then Return Settings.Get("CacheMsV2Name") + If Settings.Get(Of String)("CacheMsV2Name") <> "" Then Return Settings.Get(Of String)("CacheMsV2Name") Case McLoginType.Legacy - If Settings.Get("LoginLegacyName") <> "" Then Return Settings.Get("LoginLegacyName").ToString.BeforeFirst("¨") + If Settings.Get(Of String)("LoginLegacyName") <> "" Then Return Settings.Get(Of String)("LoginLegacyName").ToString.BeforeFirst("¨") Case McLoginType.Nide - If Settings.Get("CacheNideName") <> "" Then Return Settings.Get("CacheNideName") + If Settings.Get(Of String)("CacheNideName") <> "" Then Return Settings.Get(Of String)("CacheNideName") Case McLoginType.Auth - If Settings.Get("CacheAuthName") <> "" Then Return Settings.Get("CacheAuthName") + If Settings.Get(Of String)("CacheAuthName") <> "" Then Return Settings.Get(Of String)("CacheAuthName") End Select '查找所有可能的项 - If Settings.Get("CacheMsV2Name") <> "" Then Return Settings.Get("CacheMsV2Name") - If Settings.Get("CacheNideName") <> "" Then Return Settings.Get("CacheNideName") - If Settings.Get("CacheAuthName") <> "" Then Return Settings.Get("CacheAuthName") - If Settings.Get("LoginLegacyName") <> "" Then Return Settings.Get("LoginLegacyName").ToString.BeforeFirst("¨") + If Settings.Get(Of String)("CacheMsV2Name") <> "" Then Return Settings.Get(Of String)("CacheMsV2Name") + If Settings.Get(Of String)("CacheNideName") <> "" Then Return Settings.Get(Of String)("CacheNideName") + If Settings.Get(Of String)("CacheAuthName") <> "" Then Return Settings.Get(Of String)("CacheAuthName") + If Settings.Get(Of String)("LoginLegacyName") <> "" Then Return Settings.Get(Of String)("LoginLegacyName").ToString.BeforeFirst("¨") Return Nothing End Function ''' ''' 当前是否可以进行登录。若不可以则会返回错误原因。 ''' Public Function McLoginAble() As String - Select Case Settings.Get("LoginType") + Select Case Settings.Get(Of McLoginType)("LoginType") Case McLoginType.Ms - If Settings.Get("CacheMsV2OAuthRefresh") = "" Then + If Settings.Get(Of String)("CacheMsV2OAuthRefresh") = "" Then Return FrmLoginMs.IsVaild() Else Return "" @@ -430,13 +428,13 @@ NextInner: Case McLoginType.Legacy Return FrmLoginLegacy.IsVaild() Case McLoginType.Nide - If Settings.Get("CacheNideAccess") = "" Then + If Settings.Get(Of String)("CacheNideAccess") = "" Then Return FrmLoginNide.IsVaild() Else Return "" End If Case McLoginType.Auth - If Settings.Get("CacheAuthAccess") = "" Then + If Settings.Get(Of String)("CacheAuthAccess") = "" Then Return FrmLoginAuth.IsVaild() Else Return "" @@ -467,32 +465,32 @@ NextInner: Public McLoginLoader As New LoaderTask(Of McLoginData, McLoginResult)("登录", AddressOf McLoginStart, AddressOf McLoginInput, ThreadPriority.BelowNormal) With {.ReloadTimeout = 1, .ProgressWeight = 15, .Block = False} Public Function McLoginInput() As McLoginData Dim LoginData As McLoginData = Nothing - Dim LoginType As McLoginType = Settings.Get("LoginType") + Dim LoginType As McLoginType = Settings.Get(Of McLoginType)("LoginType") Try Select Case LoginType Case McLoginType.Legacy LoginData = PageLoginLegacy.GetLoginData() Case McLoginType.Ms - If Settings.Get("CacheMsV2OAuthRefresh") = "" Then + If Settings.Get(Of String)("CacheMsV2OAuthRefresh") = "" Then LoginData = PageLoginMs.GetLoginData() Else LoginData = PageLoginMsSkin.GetLoginData() End If Case McLoginType.Nide - If Settings.Get("CacheNideAccess") = "" Then + If Settings.Get(Of String)("CacheNideAccess") = "" Then LoginData = PageLoginNide.GetLoginData() Else LoginData = PageLoginNideSkin.GetLoginData() End If Case McLoginType.Auth - If Settings.Get("CacheAuthAccess") = "" Then + If Settings.Get(Of String)("CacheAuthAccess") = "" Then LoginData = PageLoginAuth.GetLoginData() Else LoginData = PageLoginAuthSkin.GetLoginData() End If End Select Catch ex As Exception - Log(ex, "获取登录输入信息失败(" & GetStringFromEnum(LoginType) & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"获取登录输入信息失败({LoginType})") End Try Return LoginData End Function @@ -530,21 +528,22 @@ NextInner: Public McLoginAuthLoader As New LoaderTask(Of McLoginServer, McLoginResult)("Loader Login Auth", AddressOf McLoginServerStart) With {.ReloadTimeout = 1000 * 60 * 10} '主加载函数,返回所有需要的登录信息 - Private McLoginMsRefreshTime As Long = Val(Settings.Get("CacheMsV2OAuthExpires")) 'Minecraft Access Token到期时间 Private Sub McLoginMsStart(Data As LoaderTask(Of McLoginMs, McLoginResult)) Dim Input As McLoginMs = Data.Input Dim LogUsername As String = Input.UserName McLaunchLog("登录方式:正版(" & If(LogUsername = "", "尚未登录", LogUsername) & ")") Data.Progress = 0.05 '检查是否已经登录完成 - If Not Data.IsForceRestarting AndAlso '不要求强行重启 'Input.AccessToken <> "" AndAlso '因为会影响有效期判断(每次启动就刷新,不论是否过期),所以注释掉了 - (McLoginMsRefreshTime > 0 AndAlso GetUnixTimestamp() < McLoginMsRefreshTime) Then '完成时间在有效期内 + Dim ExpiresAt = Settings.Get(Of Long)("CacheMsV2Expires") + If Not Data.IsForceRestarting AndAlso '不要求强行重启 + ExpiresAt > 0 AndAlso ExpiresAt > GetUnixTimestampUtc() Then 'AccessToken 尚未过期 Data.Output = New McLoginResult With {.AccessToken = Input.AccessToken, .Name = Input.UserName, .Uuid = Input.Uuid, .Type = "Microsoft", .ClientToken = Input.Uuid, .ProfileJson = Input.ProfileJson} + McLaunchLog("无需登录,AccessToken 尚未过期") GoTo SkipLogin End If '尝试登录 - Dim OAuthTokens As String() + Dim OAuthTokens As (OAuthAccessToken As String, OAuthRefreshToken As String) If Input.OAuthRefreshToken = "" Then '无 RefreshToken Relogin: @@ -552,44 +551,43 @@ Relogin: Else '有 RefreshToken OAuthTokens = MsLoginStep1Refresh(Input.OAuthRefreshToken) - If OAuthTokens(0) = "Relogin" Then GoTo Relogin '要求重新打开登录网页认证 + If OAuthTokens.OAuthAccessToken = "Relogin" Then GoTo Relogin '要求重新打开登录网页认证 End If If Data.IsInterrupted Then Throw New ThreadInterruptedException Data.Progress = 0.25 If Data.IsInterrupted Then Throw New ThreadInterruptedException - Dim OAuthAccessToken As String = OAuthTokens(0) - Dim OAuthRefreshToken As String = OAuthTokens(1) + Dim OAuthAccessToken As String = OAuthTokens.OAuthAccessToken + Dim OAuthRefreshToken As String = OAuthTokens.OAuthRefreshToken Dim XBLToken As String = MsLoginStep2(OAuthAccessToken) Data.Progress = 0.4 If Data.IsInterrupted Then Throw New ThreadInterruptedException Dim Tokens = MsLoginStep3(XBLToken) Data.Progress = 0.55 If Data.IsInterrupted Then Throw New ThreadInterruptedException - Dim Step4Tokens As String() = MsLoginStep4(Tokens) - Dim AccessToken As String = Step4Tokens(0) - McLoginMsRefreshTime = GetUnixTimestamp() + Step4Tokens(1) 'Token 到期时间,以秒为单位 + Dim LoginResult = MsLoginStep4(Tokens) + ExpiresAt = LoginResult.ExpiresAt Data.Progress = 0.7 If Data.IsInterrupted Then Throw New ThreadInterruptedException - MsLoginStep5(AccessToken) + MsLoginStep5(LoginResult.AccessToken) Data.Progress = 0.85 If Data.IsInterrupted Then Throw New ThreadInterruptedException - Dim Result = MsLoginStep6(AccessToken) + Dim Result = MsLoginStep6(LoginResult.AccessToken) Data.Progress = 0.98 '输出登录结果 Settings.Set("CacheMsV2OAuthRefresh", OAuthRefreshToken) - Settings.Set("CacheMsV2Access", AccessToken) - Settings.Set("CacheMsV2Uuid", Result(0)) - Settings.Set("CacheMsV2Name", Result(1)) - Settings.Set("CacheMsV2ProfileJson", Result(2)) - Settings.Set("CacheMsV2OAuthExpires", McLoginMsRefreshTime) - Dim MsJson As JObject = GetJson(Settings.Get("LoginMsJson")) + Settings.Set("CacheMsV2Access", LoginResult.AccessToken) + Settings.Set("CacheMsV2Uuid", Result.UUID) + Settings.Set("CacheMsV2Name", Result.UserName) + Settings.Set("CacheMsV2ProfileJson", Result.ProfileJson) + Settings.Set("CacheMsV2Expires", LoginResult.ExpiresAt) + Dim MsJson As JObject = GetJson(Settings.Get(Of String)("LoginMsJson")) MsJson.Remove(Input.UserName) '如果更改了玩家名…… - MsJson(Result(1)) = OAuthRefreshToken + MsJson(Result.UserName) = OAuthRefreshToken Settings.Set("LoginMsJson", MsJson.ToString(Newtonsoft.Json.Formatting.None)) - Data.Output = New McLoginResult With {.AccessToken = AccessToken, .Name = Result(1), .Uuid = Result(0), .Type = "Microsoft", .ClientToken = Result(0), .ProfileJson = Result(2)} + Data.Output = New McLoginResult With {.AccessToken = LoginResult.AccessToken, .Name = Result.UserName, .Uuid = Result.UUID, .Type = "Microsoft", .ClientToken = Result.UUID, .ProfileJson = Result.ProfileJson} '结束 - McLaunchLog("微软登录完成") SkipLogin: + McLaunchLog($"微软登录结束,AccessToken 将在 {DateTimeOffset.FromUnixTimeSeconds(ExpiresAt).Date.ToLocalTime} 过期") Settings.Set("HintBuy", True) '关闭正版购买提示 If ThemeUnlock(10, False) Then MyMsgBox("感谢你对正版游戏的支持!" & vbCrLf & "隐藏主题 跳票红 已解锁!", "提示") End Sub @@ -600,20 +598,20 @@ SkipLogin: Data.Progress = 0.05 '尝试登录 If (Not Data.Input.ForceReselectProfile) AndAlso - Settings.Get("Cache" & Input.Token & "Username") = Data.Input.UserName AndAlso - Settings.Get("Cache" & Input.Token & "Pass") = Data.Input.Password AndAlso - Settings.Get("Cache" & Input.Token & "Access") <> "" AndAlso - Settings.Get("Cache" & Input.Token & "Client") <> "" AndAlso - Settings.Get("Cache" & Input.Token & "Uuid") <> "" AndAlso - Settings.Get("Cache" & Input.Token & "Name") <> "" Then + Settings.Get(Of String)("Cache" & Input.Token & "Username") = Data.Input.UserName AndAlso + Settings.Get(Of String)("Cache" & Input.Token & "Pass") = Data.Input.Password AndAlso + Settings.Get(Of String)("Cache" & Input.Token & "Access") <> "" AndAlso + Settings.Get(Of String)("Cache" & Input.Token & "Client") <> "" AndAlso + Settings.Get(Of String)("Cache" & Input.Token & "Uuid") <> "" AndAlso + Settings.Get(Of String)("Cache" & Input.Token & "Name") <> "" Then '尝试验证登录 Try If Data.IsInterrupted Then Throw New ThreadInterruptedException McLoginRequestValidate(Data) GoTo LoginFinish Catch ex As Exception - Log(ex, "验证登录失败") - If IsNetworkRelated(ex) Then Throw New Exception("$登录失败:你的网络环境不佳,导致难以连接到海外服务器。" & vbCrLf & "请稍后再试,或使用加速器、VPN 改善网络环境。") + Logger.Warn(ex, "验证登录失败") + If ex.IsBadNetwork Then Throw New Exception("$登录失败:你的网络环境不佳,导致难以连接到海外服务器。" & vbCrLf & "请稍后再试,或使用加速器、VPN 改善网络环境。") End Try Data.Progress = 0.25 '尝试刷新登录 @@ -623,7 +621,7 @@ Refresh: McLoginRequestRefresh(Data, NeedRefresh) GoTo LoginFinish Catch ex As Exception - McLaunchLog("刷新登录失败:" & ex.GetDetail()) + McLaunchLog("刷新登录失败:" & ex.GetDisplay(True)) If WasRefreshed Then Throw New Exception("二轮刷新登录失败", ex) End Try Data.Progress = If(NeedRefresh, 0.85, 0.45) @@ -633,7 +631,7 @@ Refresh: If Data.IsInterrupted Then Throw New ThreadInterruptedException NeedRefresh = McLoginRequestLogin(Data) Catch ex As Exception - McLaunchLog("登录失败:" & ex.GetDetail()) + McLaunchLog("登录失败:" & ex.GetDisplay(True)) Throw End Try If NeedRefresh Then @@ -649,8 +647,8 @@ LoginFinish: Dim Emails As New List(Of String) Dim Passwords As New List(Of String) Try - If Not Settings.Get("Login" & Input.Token & "Email") = "" Then Emails.AddRange(Settings.Get("Login" & Input.Token & "Email").ToString.Split("¨")) - If Not Settings.Get("Login" & Input.Token & "Pass") = "" Then Passwords.AddRange(Settings.Get("Login" & Input.Token & "Pass").ToString.Split("¨")) + If Not Settings.Get(Of String)("Login" & Input.Token & "Email") = "" Then Emails.AddRange(Settings.Get(Of String)("Login" & Input.Token & "Email").Split("¨")) + If Not Settings.Get(Of String)("Login" & Input.Token & "Pass") = "" Then Passwords.AddRange(Settings.Get(Of String)("Login" & Input.Token & "Pass").Split("¨")) For i = 0 To Emails.Count - 1 Dict.Add(Emails(i), Passwords(i)) Next @@ -662,7 +660,7 @@ LoginFinish: Settings.Set("Login" & Input.Token & "Email", Emails.Join("¨"c)) Settings.Set("Login" & Input.Token & "Pass", Passwords.Join("¨"c)) Catch ex As Exception - Log(ex, "保存启动记录失败", NotifyLevel.AllUsers) + Logger.Error(ex, "保存启动记录失败", LogBehavior.Toast) Settings.Set("Login" & Input.Token & "Email", "") Settings.Set("Login" & Input.Token & "Pass", "") End Try @@ -681,7 +679,7 @@ LoginFinish: Data.Output.ClientToken = Data.Output.Uuid '保存启动记录 Dim Names As New List(Of String) - If Not Settings.Get("LoginLegacyName") = "" Then Names.AddRange(Settings.Get("LoginLegacyName").ToString.Split("¨")) + If Not Settings.Get(Of String)("LoginLegacyName") = "" Then Names.AddRange(Settings.Get(Of String)("LoginLegacyName").ToString.Split("¨")) Names.Remove(Input.UserName) Names.Insert(0, Input.UserName) Settings.Set("LoginLegacyName", Names.Join("¨"c)) @@ -691,10 +689,10 @@ LoginFinish: Private Sub McLoginRequestValidate(ByRef Data As LoaderTask(Of McLoginServer, McLoginResult)) McLaunchLog("验证登录开始(Validate, " & Data.Input.Token & ")") '提前缓存信息,否则如果在登录请求过程中退出登录,设置项目会被清空,导致输出存在空值 - Dim AccessToken As String = Settings.Get("Cache" & Data.Input.Token & "Access") - Dim ClientToken As String = Settings.Get("Cache" & Data.Input.Token & "Client") - Dim Uuid As String = Settings.Get("Cache" & Data.Input.Token & "Uuid") - Dim Name As String = Settings.Get("Cache" & Data.Input.Token & "Name") + Dim AccessToken As String = Settings.Get(Of String)("Cache" & Data.Input.Token & "Access") + Dim ClientToken As String = Settings.Get(Of String)("Cache" & Data.Input.Token & "Client") + Dim Uuid As String = Settings.Get(Of String)("Cache" & Data.Input.Token & "Uuid") + Dim Name As String = Settings.Get(Of String)("Cache" & Data.Input.Token & "Name") '发送登录请求 Dim RequestData As New JObject( New JProperty("accessToken", AccessToken), New JProperty("clientToken", ClientToken), New JProperty("requestUser", True)) @@ -718,16 +716,16 @@ LoginFinish: Data.Input.BaseUrl & "/refresh", HttpMethod.Post, Content:=New JObject( New JProperty("selectedProfile", New JObject( - New JProperty("name", Settings.Get($"Cache{Data.Input.Token}Name")), - New JProperty("id", Settings.Get($"Cache{Data.Input.Token}Uuid")) + New JProperty("name", Settings.Get(Of String)($"Cache{Data.Input.Token}Name")), + New JProperty("id", Settings.Get(Of String)($"Cache{Data.Input.Token}Uuid")) )), - New JProperty("accessToken", Settings.Get($"Cache{Data.Input.Token}Access")), + New JProperty("accessToken", Settings.Get(Of String)($"Cache{Data.Input.Token}Access")), New JProperty("requestUser", True) ).ToString(Newtonsoft.Json.Formatting.None), Headers:={{"Accept-Language", "zh-CN"}}, ContentType:="application/json; charset=utf-8", RequireJson:=True)) '将登录结果输出 - If LoginJson("selectedProfile") Is Nothing Then Throw New Exception("选择的角色 " & Settings.Get("Cache" & Data.Input.Token & "Name") & " 无效!") + If LoginJson("selectedProfile") Is Nothing Then Throw New Exception("选择的角色 " & Settings.Get(Of String)("Cache" & Data.Input.Token & "Name") & " 无效!") Data.Output.AccessToken = LoginJson("accessToken").ToString Data.Output.ClientToken = LoginJson("clientToken").ToString Data.Output.Uuid = LoginJson("selectedProfile")("id").ToString @@ -768,7 +766,7 @@ LoginFinish: If (LoginJson("selectedProfile") Is Nothing OrElse Data.Input.ForceReselectProfile) AndAlso LoginJson("availableProfiles").Count > 1 Then '要求选择档案;优先从缓存读取 NeedRefresh = True - Dim CacheId As String = Settings.Get("Cache" & Data.Input.Token & "Uuid") + Dim CacheId As String = Settings.Get(Of String)("Cache" & Data.Input.Token & "Uuid") For Each Profile In LoginJson("availableProfiles") If Profile("id").ToString = CacheId Then SelectedName = Profile("name").ToString @@ -813,13 +811,13 @@ LoginFinish: McLaunchLog("登录成功(Login, " & Data.Input.Token & ")") Return NeedRefresh Catch ex As Exception - Dim AllMessage As String = ex.GetBrief() - Log(ex, "登录失败原始错误信息", NotifyLevel.Silent) + Dim AllMessage As String = ex.GetDisplay(False) + Logger.Info(ex, "登录失败原始错误信息") '读取服务器返回的错误 - If TypeOf ex Is ResponsedWebException Then + If TypeOf ex Is HttpRequestCodeException Then Dim ErrorMessage As String = Nothing Try - Dim Response = DirectCast(ex, ResponsedWebException).Response + Dim Response = DirectCast(ex, HttpRequestCodeException).Response If Response.ContainsIgnoreCase("errorMessage") Then ErrorMessage = GetJson(Response)("errorMessage").ToString() Catch End Try @@ -852,7 +850,7 @@ LoginFinish: If(Data.Input.UserName.Contains("@"), "", " - 登录账号应为邮箱或统一通行证账号,而非游戏角色 ID。" & vbCrLf) & " - 只注册了账号,但没有加入对应服务器。") End Select - ElseIf ex.IsNetworkRelated() Then + ElseIf ex.IsBadNetwork() Then Throw New Exception("$登录失败:你的网络环境不佳,导致难以连接到海外服务器。" & vbCrLf & "请稍后再试,或使用加速器、VPN 改善网络环境。") ElseIf ex.Message.StartsWithF("$") Then Throw @@ -864,7 +862,7 @@ LoginFinish: End Function '微软登录步骤 1,原始登录:获取 DeviceCode 并开启登录网页 - Private Function MsLoginStep1New(Data As LoaderTask(Of McLoginMs, McLoginResult)) As String() + Private Function MsLoginStep1New(Data As LoaderTask(Of McLoginMs, McLoginResult)) As (OAuthAccessToken As String, OAuthRefreshToken As String) '参考:https://learn.microsoft.com/zh-cn/entra/identity-platform/v2-oauth2-device-code '初始请求 @@ -892,11 +890,11 @@ Retry: ElseIf TypeOf Converter.Result Is Exception Then Throw CType(Converter.Result, Exception) Else - Return Converter.Result + Return (Converter.Result(0), Converter.Result(1)) End If End Function '微软登录步骤 1,刷新登录:从 OAuth Code 或 OAuth RefreshToken 获取 {OAuth AccessToken, OAuth RefreshToken} - Private Function MsLoginStep1Refresh(Code As String) As String() + Private Function MsLoginStep1Refresh(Code As String) As (OAuthAccessToken As String, OAuthRefreshToken As String) McLaunchLog("开始微软登录步骤 1/6(刷新登录)") Dim Result As String @@ -906,12 +904,13 @@ Retry: ContentType:="application/x-www-form-urlencoded", Headers:={{"Accept-Language", "en-US,en;q=0.5"}, {"X-Requested-With", "XMLHttpRequest"}}, ThreadCount:=2) - Catch ex As ResponsedWebException + Catch ex As HttpRequestCodeException '修改错误列表时,同时检查 MyMsgLogin.xaml.vb 中的对应代码 Dim Response = ex.Response If Response.ContainsIgnoreCase("must sign in again") OrElse Response.ContainsIgnoreCase("password expired") OrElse - (Response.Contains("refresh_token") AndAlso Response.ContainsIgnoreCase("is not valid")) Then '#269 - Return {"Relogin", ""} + (Response.Contains("refresh_token") AndAlso Response.ContainsIgnoreCase("is not valid")) OrElse '#269 + Response.ContainsIgnoreCase("expired") Then '#8611 + Return ("Relogin", "") ElseIf Response.Contains("Account security interrupt") Then MyMsgBox("该账号由于安全问题无法登陆,请前往微软账户页获取更多信息。", "登录失败", "我知道了", IsWarn:=True) Throw New Exception("$$") @@ -926,7 +925,7 @@ Retry: Dim ResultJson As JObject = GetJson(Result) Dim AccessToken As String = ResultJson("access_token").ToString Dim RefreshToken As String = ResultJson("refresh_token").ToString - Return {AccessToken, RefreshToken} + Return (AccessToken, RefreshToken) End Function '微软登录步骤 2:从 OAuth AccessToken 获取 XBLToken Private Function MsLoginStep2(AccessToken As String) As String @@ -946,7 +945,7 @@ Retry: Return GetJson(Result)("Token").ToString End Function '微软登录步骤 3:从 XBLToken 获取 {XSTSToken, UHS} - Private Function MsLoginStep3(XBLToken As String) As String() + Private Function MsLoginStep3(XBLToken As String) As (XSTSToken As String, UHS As String) McLaunchLog("开始微软登录步骤 3/6") Dim Request As String = "{ @@ -961,7 +960,7 @@ Retry: Try Result = NetRequestByClientMultiple("https://xsts.auth.xboxlive.com/xsts/authorize", HttpMethod.Post, Content:=Request, ContentType:="application/json", RequireJson:=True) - Catch ex As ResponsedWebException + Catch ex As HttpRequestCodeException '参考 https://github.com/PrismarineJS/prismarine-auth/blob/master/src/common/Constants.js If ex.Response.Contains("2148916227") Then MyMsgBox("该账号似乎已被微软封禁,无法登录。", "登录失败", "我知道了", IsWarn:=True) @@ -992,37 +991,37 @@ Retry: End Try Dim ResultJson As JObject = GetJson(Result) - Return { - ResultJson("Token"), 'XSTSToken - ResultJson("DisplayClaims")("xui")(0)("uhs") 'UHS - } + Return ( + ResultJson("Token").ToString(), 'XSTSToken + ResultJson("DisplayClaims")("xui")(0)("uhs").ToString() 'UHS + ) End Function - '微软登录步骤 4:从 {XSTSToken, UHS} 获取 Minecraft AccessToken - Private Function MsLoginStep4(Tokens As String()) As String() + '微软登录步骤 4:从 {XSTSToken, UHS} 获取 {Minecraft AccessToken, 过期于 (Unix 时间戳)} + Private Function MsLoginStep4(Tokens As (XSTSToken As String, UHS As String)) As (AccessToken As String, ExpiresAt As Integer) McLaunchLog("开始微软登录步骤 4/6") - Dim Request As String = New JObject(New JProperty("identityToken", $"XBL3.0 x={Tokens(1)};{Tokens(0)}")).ToString(0) + Dim Request As String = New JObject(New JProperty("identityToken", $"XBL3.0 x={Tokens.UHS};{Tokens.XSTSToken}")).ToString(0) Dim Result As String Try Result = NetRequestByClientRetry("https://api.minecraftservices.com/authentication/login_with_xbox", HttpMethod.Post, Content:=Request, ContentType:="application/json", RequireJson:=True) - Catch ex As Net.WebException - Dim Message As String = ex.GetBrief() - If Message.Contains("(429)") Then - Log(ex, "微软登录第 4 步汇报 429") - Throw New Exception("$登录尝试太过频繁,请等待几分钟后再试!") - ElseIf Message.Contains("(403)") Then - Log(ex, "微软登录第 4 步汇报 403") - Throw New Exception("$当前 IP 的登录尝试异常。" & vbCrLf & "如果你使用了 VPN 或加速器,请把它们关掉或更换节点后再试!") - Else - Throw - End If + Catch ex As HttpRequestCodeException + Select Case ex.StatusCode + Case 429 + Logger.Warn(ex, "微软登录第 4 步汇报 429") + Throw New Exception("$登录尝试太过频繁,请等待几分钟后再试!") + Case HttpStatusCode.Forbidden + Logger.Warn(ex, "微软登录第 4 步汇报 403") + Throw New Exception("$当前 IP 的登录尝试异常。" & vbCrLf & "如果你使用了 VPN 或加速器,请把它们关掉或更换节点后再试!") + Case Else + Throw + End Select End Try - Return { - GetJson(Result)("access_token").ToString, - GetJson(Result)("expires_in").ToString '以秒为单位 - } + Dim ResultJson As JObject = GetJson(Result) + Return ( + ResultJson("access_token").ToString, + ResultJson("expires_in").ToObject(Of Integer) + GetUnixTimestampUtc() - 1200) '提前 20 分钟视作过期 End Function '微软登录步骤 5:验证微软账号是否持有 MC,这也会刷新 XGP Private Sub MsLoginStep5(AccessToken As String) @@ -1040,41 +1039,41 @@ Retry: Throw New Exception("$$") End If Catch ex As Exception - Log(ex, "微软登录第 5 步异常:" & Result) + Logger.Warn(ex, $"微软登录第 5 步异常:{Result}") Throw End Try End Sub '微软登录步骤 6:从 Minecraft AccessToken 获取 {UUID, UserName, ProfileJson} - Private Function MsLoginStep6(AccessToken As String) As String() + Private Function MsLoginStep6(AccessToken As String) As (UUID As String, UserName As String, ProfileJson As String) McLaunchLog("开始微软登录步骤 6/6") Dim Result As String Try Result = NetRequestByClientMultiple("https://api.minecraftservices.com/minecraft/profile", ContentType:="application/json", ThreadCount:=2, Headers:={{"Authorization", "Bearer " & AccessToken}}, RequireJson:=True) - Catch ex As WebException - Dim Message As String = ex.GetBrief() - If Message.Contains("(429)") Then - Log(ex, "微软登录第 6 步汇报 429") - Throw New Exception("$登录尝试太过频繁,请等待几分钟后再试!") - ElseIf Message.Contains("(404)") Then - Log(ex, "微软登录第 6 步汇报 404") - RunInNewThread( - Sub() - Select Case MyMsgBox("请先创建 Minecraft 玩家档案,然后再重新登录。", "登录失败", "创建档案", "取消") - Case 1 - OpenWebsite("https://www.minecraft.net/zh-hans/msaprofile/mygames/editprofile") - End Select - End Sub, "Login Failed: Create Profile") - Throw New Exception("$$") - Else - Throw - End If + Catch ex As HttpRequestCodeException + Select Case ex.StatusCode + Case 429 + Logger.Warn(ex, "微软登录第 6 步汇报 429") + Throw New Exception("$登录尝试太过频繁,请等待几分钟后再试!") + Case HttpStatusCode.NotFound + Logger.Warn(ex, "微软登录第 6 步汇报 404") + RunInNewThread( + Sub() + Select Case MyMsgBox("请先创建 Minecraft 玩家档案,然后再重新登录。", "登录失败", "创建档案", "取消") + Case 1 + OpenWebsite("https://www.minecraft.net/zh-hans/msaprofile/mygames/editprofile") + End Select + End Sub, "Login Failed: Create Profile") + Throw New Exception("$$") + Case Else + Throw + End Select End Try Dim ResultJson As JObject = GetJson(Result) Dim UUID As String = ResultJson("id").ToString Dim UserName As String = ResultJson("name").ToString - Return {UUID, UserName, Result} + Return (UUID, UserName, Result) End Function '返回符合离线皮肤设置的 UUID @@ -1101,15 +1100,15 @@ Retry: Try If SkinName <> "" AndAlso McInstanceSelected IsNot Nothing AndAlso McInstanceSelected.Version.Vanilla.Major < 20 Then '1.20+ 或快照版不能使用该项(#3746) - Log("[Skin] 由于离线皮肤设置,使用正版 UUID:" & SkinName) + Logger.Info($"由于离线皮肤设置,使用正版 UUID:{SkinName}") Uuid = McLoginMojangUuid(SkinName, False) End If Catch ex As Exception - Log(ex, "皮肤信息获取失败,游戏将以无皮肤的方式启动", NotifyLevel.AllUsers) + Logger.Error(ex, "皮肤信息获取失败,游戏将以无皮肤的方式启动", LogBehavior.Toast) End Try Case 4 '自定义 - Do Until McSkinSex(Uuid) = If(Settings.Get("LaunchSkinSlim"), "Alex", "Steve") + Do Until McSkinSex(Uuid) = If(Settings.Get(Of Boolean)("LaunchSkinSlim"), "Alex", "Steve") If Uuid.EndsWithF("FFFFF") Then Uuid = Uuid.Substring(0, 27) & "00000" Uuid = Uuid.Substring(0, 27) & (Long.Parse(Uuid.Substring(27), Globalization.NumberStyles.AllowHexSpecifier) + 1).ToString("X").PadLeft(5, "0") Loop @@ -1128,7 +1127,7 @@ Retry: If GotJson Is Nothing Then Throw New FileNotFoundException("正版玩家档案不存在(" & Name & ")") Uuid = If(GotJson("id"), "") Catch ex As Exception - Log(ex, "从官网获取正版 Uuid 失败(" & Name & ")") + Logger.Warn(ex, $"从官网获取正版 Uuid 失败({Name})") If Not ThrowOnNotFound AndAlso ex.GetType.Name = "FileNotFoundException" Then Uuid = McLoginLegacyUuid(Name) '玩家档案不存在 Else @@ -1267,7 +1266,7 @@ Retry: End If '统一通行证检测 - If Settings.Get("LoginType") = McLoginType.Nide Then + If Settings.Get(Of McLoginType)("LoginType") = McLoginType.Nide Then '至少 Java 8u101 MinVer = If(New Version(1, 8, 0, 141) > MinVer, New Version(1, 8, 0, 141), MinVer) End If @@ -1330,23 +1329,6 @@ Retry: #End Region -#Region "获取 LWJGL 版本" - Private Function McLaunchGetLwjglVersion(Mc As McInstance) As String - For Each library As McLibToken In McLibListGet(Mc, False) - If String.IsNullOrWhiteSpace(library.OriginalName) Then Continue For - - Dim parts = library.OriginalName.Split(":"c) - If parts.Length >= 3 AndAlso - parts(0).Equals("org.lwjgl", StringComparison.OrdinalIgnoreCase) AndAlso - parts(1).Equals("lwjgl", StringComparison.OrdinalIgnoreCase) Then - Return parts(2) - End If - Next - - Return Nothing - End Function -#End Region - #Region "启动参数" Private McLaunchArgument As String @@ -1367,8 +1349,8 @@ Retry: For Each Replacement In Replacements Arg = Arg.Replace(Replacement.Key, Replacement.Value) Next - '为带空格的参数添加双引号 - If Arg.Contains(" ") AndAlso Not Arg.StartsWithF("""") AndAlso Not Arg.EndsWithF("""") Then + '为带特殊字符的参数添加双引号 + If Arg.IndexOfAny({"&"c, "|"c, "<"c, ">"c, "^"c, " "c}) >= 0 AndAlso Not Arg.StartsWithF("""") AndAlso Not Arg.EndsWithF("""") Then Arg = $"""{Arg.Replace("""", "\""")}""" '转义在原本参数中间的双引号 End If '输出 @@ -1424,20 +1406,21 @@ NextInstance: End If '设置里自定义的参数 - Dim CustomArg As String = Settings.Get("VersionAdvanceJvm", Instance:=McInstanceSelected) - If CustomArg = "" Then CustomArg = Settings.Get("LaunchAdvanceJvm") + Dim CustomArg As String = Settings.Get(Of String)("VersionAdvanceJvm", Instance:=McInstanceSelected) + If CustomArg = "" Then CustomArg = Settings.Get(Of String)("LaunchAdvanceJvm") + If CustomArg <> "" Then CustomArg = ArgumentReplace(CustomArg) '重新分割字符串并去重 Args = DeduplicateJavaArguments(SplitJavaArguments(Args.Join(" "c).Replace("McEmu= ", "McEmu=") & " " & CustomArg).ToList, True) '统一通行证 If McLoginLoader.Output.Type = "Nide" Then - Args.Add("-javaagent:""${pure_directory}\nide8auth.jar""=""" & Settings.Get("VersionServerNide", Instance:=McInstanceSelected) & """") + Args.Add("-javaagent:""${pure_directory}\nide8auth.jar""=""" & Settings.Get(Of String)("VersionServerNide", Instance:=McInstanceSelected) & """") End If 'Authlib-Injector If McLoginLoader.Output.Type = "Auth" Then If McLaunchJavaSelected.MajorVersion >= 6 Then Args.Add("-Djavax.net.ssl.trustStoreType=WINDOWS-ROOT") '信任系统根证书(5252#) - Dim Server As String = Settings.Get("VersionServerAuthServer", Instance:=McInstanceSelected) + Dim Server As String = Settings.Get(Of String)("VersionServerAuthServer", Instance:=McInstanceSelected) Try McLaunchLog($"开始 Authlib Injector Prefetch") Dim Response As String = NetRequestByClientRetry(Server, Encoding:=Encoding.UTF8) @@ -1450,9 +1433,15 @@ NextInstance: End If 'JLW + '修复 Java 18- 在 Windows UTF-8 Beta 模式(非 GBK 编码)下命令行参数乱码的问题(JDK-8272352) Dim UseJLW As Boolean = - Not Settings.Get("LaunchAdvanceDisableJLW") AndAlso Not Settings.Get("VersionAdvanceDisableJLW", McInstanceSelected) AndAlso - McLaunchJavaSelected.MajorVersion <= 18 + Not Settings.Get(Of Boolean)("LaunchAdvanceDisableJLW") AndAlso Not Settings.Get(Of Boolean)("VersionAdvanceDisableJLW", McInstanceSelected) AndAlso + McLaunchJavaSelected.MajorVersion <= 18 AndAlso 'Java 19+ 已经修复了该 Bug + Not IsGBKEncoding AndAlso Not McFolderSelected.IsAsciiOnly() '仅在该环境下才会触发该 Bug + If UseJLW AndAlso CustomArg.Contains("-javaagent") Then + UseJLW = False + McLaunchLog("由于使用自定义 javaagent,已禁用 JLW,这可能导致游戏崩溃!", LogLevel.Warn) + End If If UseJLW Then If McLaunchJavaSelected.MajorVersion >= 9 Then Args.Add("--add-exports") : Args.Add("cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED") @@ -1463,8 +1452,8 @@ NextInstance: 'LUA Dim UseLUA As Boolean = - Not Settings.Get("LaunchAdvanceDisableLUA") AndAlso Not Settings.Get("VersionAdvanceDisableLUA", McInstanceSelected) AndAlso - McLaunchGetLwjglVersion(McInstanceSelected) = "3.4.1" + Not Settings.Get(Of Boolean)("LaunchAdvanceDisableLUA") AndAlso Not Settings.Get(Of Boolean)("VersionAdvanceDisableLUA", McInstanceSelected) AndAlso + McLibListGet(McInstanceSelected, False).Any(Function(e) e.OriginalName = "org.lwjgl:lwjgl:3.4.1") If UseLUA Then Args.Add($"-javaagent:""{ExtractPatch("LUA")}""") McLaunchLog("使用 LUA:" & UseLUA) @@ -1479,8 +1468,8 @@ NextInstance: '1:在 Java 21+ 使用分代 ZGC,20- 使用 G1GC '2:仅 G1GC '3:不指定,玩家自定义 - Dim SetupType As Integer = Settings.Get("LaunchAdvanceGC") - If McInstanceSelected IsNot Nothing AndAlso Settings.Get("VersionAdvanceGC", McInstanceSelected) > 0 Then SetupType = Settings.Get("VersionAdvanceGC", McInstanceSelected) - 1 '去掉默认 + Dim SetupType As Integer = Settings.Get(Of Integer)("LaunchAdvanceGC") + If McInstanceSelected IsNot Nothing AndAlso Settings.Get(Of Integer)("VersionAdvanceGC", McInstanceSelected) > 0 Then SetupType = Settings.Get(Of Integer)("VersionAdvanceGC", McInstanceSelected) - 1 '去掉默认 If SetupType <> 3 Then '确定是使用 G1GC 还是 ZGC Dim UseG1GC As Boolean = False @@ -1490,7 +1479,7 @@ NextInstance: If Is32BitSystem OrElse Environment.OSVersion.Version.Major < 10 OrElse Environment.OSVersion.Version.Build < 17763 Then UseG1GC = True '检查系统兼容性,ZGC 需要 Windows 10 1809+ McLaunchLog($"GC 设置:{SetupType},选取 {If(UseG1GC, "G1GC", "ZGC")},Java 版本:{McLaunchJavaSelected.MajorVersion}") '移除已有的 GC 参数 - Args = Args.Where(Function(a) Not RegexCheck(a, + Args = Args.Where(Function(a) Not a.RegexCheck( "( )*-XX:[+-]?(Use\w+GC|ZGenerational|UseCompactObjectHeaders|G1\w+Percent|G1\w+Size|(Max|Min)(GCPauseMillis|HeapFreeRatio))")).ToList '添加 GC 参数 Args.Add("-XX:+UnlockExperimentalVMOptions") @@ -1586,8 +1575,9 @@ NextInstance: End If '设置里自定义的参数 - Dim CustomArg As String = Settings.Get("VersionAdvanceGame", Instance:=McInstanceSelected) - If CustomArg = "" Then CustomArg = Settings.Get("LaunchAdvanceGame") + Dim CustomArg As String = Settings.Get(Of String)("VersionAdvanceGame", Instance:=McInstanceSelected) + If CustomArg = "" Then CustomArg = Settings.Get(Of String)("LaunchAdvanceGame") + If CustomArg <> "" Then CustomArg = ArgumentReplace(CustomArg) Arg &= " " & CustomArg '把 OptiFineForgeTweaker 放在参数的末尾 @@ -1600,9 +1590,9 @@ NextInstance: McLaunchLog("发现错误的 OptiFineForge TweakClass,目前的游戏参数:" & Arg) Arg = Arg.Replace(" --tweakClass optifine.OptiFineTweaker", "") & " --tweakClass optifine.OptiFineForgeTweaker" Try - FileUtils.Write(McInstanceSelected.PathVersion & McInstanceSelected.Name & ".json", ReadFile(McInstanceSelected.PathVersion & McInstanceSelected.Name & ".json").Replace("optifine.OptiFineTweaker", "optifine.OptiFineForgeTweaker")) + FileUtils.Write(McInstanceSelected.GetJsonPath(), FileUtils.ReadAsString(McInstanceSelected.GetJsonPath()).Replace("optifine.OptiFineTweaker", "optifine.OptiFineForgeTweaker")) Catch ex As Exception - Log(ex, "替换 OptiFineForge TweakClass 失败") + Logger.Warn(ex, "替换 OptiFineForge TweakClass 失败") End Try End If End If @@ -1614,10 +1604,10 @@ NextInstance: Args.AddRange(CurrentLaunchOptions.ExtraGameArgs) '全屏 - If Settings.Get("LaunchArgumentWindowType") = 0 Then Args.Add("--fullscreen") + If Settings.Get(Of Integer)("LaunchArgumentWindowType") = 0 Then Args.Add("--fullscreen") '自动进入服务器 - Dim Server As String = If(String.IsNullOrEmpty(CurrentLaunchOptions.ServerIp), Settings.Get("VersionServerEnter", McInstanceSelected), CurrentLaunchOptions.ServerIp) + Dim Server As String = If(String.IsNullOrEmpty(CurrentLaunchOptions.ServerIp), Settings.Get(Of String)("VersionServerEnter", McInstanceSelected), CurrentLaunchOptions.ServerIp) If Server.Any Then If McInstanceSelected.ReleaseTime > New Date(2023, 4, 4) Then 'QuickPlay @@ -1645,14 +1635,14 @@ NextInstance: '基础参数 Yield ("${classpath_separator}", ";") Yield ("${natives_directory}", GetNativesFolder().TrimEnd("\"c)) - Yield ("${library_directory}", FileUtils.ShortenPath(McFolderSelected & "libraries")) - Yield ("${libraries_directory}", FileUtils.ShortenPath(McFolderSelected & "libraries")) + Yield ("${library_directory}", PathUtils.ToShortPath(McFolderSelected & "libraries")) + Yield ("${libraries_directory}", PathUtils.ToShortPath(McFolderSelected & "libraries")) Yield ("${pure_directory}", PathPure.TrimEnd("\"c)) '由 PCL 添加,这会允许在分割参数并去重后再替换路径,防止路径中的特殊字符影响参数分割和去重 Yield ("${launcher_name}", "PCL") Yield ("${launcher_version}", VersionCode) Yield ("${version_name}", McInstanceSelected.Name) - Yield ("${game_directory}", FileUtils.ShortenPath(Left(McInstanceSelected.PathIndie, McInstanceSelected.PathIndie.Count - 1))) - Yield ("${assets_root}", FileUtils.ShortenPath(McFolderSelected & "assets")) + Yield ("${game_directory}", PathUtils.ToShortPath(Left(McInstanceSelected.PathIndie, McInstanceSelected.PathIndie.Count - 1))) + Yield ("${assets_root}", PathUtils.ToShortPath(McFolderSelected & "assets")) Yield ("${user_properties}", "{}") Yield ("${auth_player_name}", McLoginLoader.Output.Name) Yield ("${auth_uuid}", McLoginLoader.Output.Uuid) @@ -1660,14 +1650,14 @@ NextInstance: Yield ("${access_token}", McLoginLoader.Output.AccessToken) Yield ("${auth_session}", McLoginLoader.Output.AccessToken) Yield ("${user_type}", "msa") '#1221 - Yield ("${primary_jar}", FileUtils.ShortenPath(McInstanceSelected.PathVersion & McInstanceSelected.Name & ".jar")) '#6942 - Yield ("${game_assets}", FileUtils.ShortenPath(McFolderSelected & "assets\virtual\legacy")) '1.5.2 的 pre-1.6 资源索引应与 legacy 合并 + Yield ("${primary_jar}", PathUtils.ToShortPath(McInstanceSelected.PathVersion & McInstanceSelected.Name & ".jar")) '#6942 + Yield ("${game_assets}", PathUtils.ToShortPath(McFolderSelected & "assets\virtual\legacy")) '1.5.2 的 pre-1.6 资源索引应与 legacy 合并 Yield ("${assets_index_name}", McAssetsGetIndexName(McInstanceSelected)) '自定义信息 Dim ArgumentInfo As String - ArgumentInfo = Settings.Get("VersionArgumentInfo", Instance:=McInstanceSelected) - If ArgumentInfo = "" Then ArgumentInfo = Settings.Get("LaunchArgumentInfo") + ArgumentInfo = Settings.Get(Of String)("VersionArgumentInfo", Instance:=McInstanceSelected) + If ArgumentInfo = "" Then ArgumentInfo = Settings.Get(Of String)("LaunchArgumentInfo") If ArgumentInfo = "" Then '若自定义信息为空,则必须从参数中去掉该部分,不然 MC 会显示 ${version_type} 或者一个空字符串 If Arguments.Contains("--versionType") Then Dim Index As Integer = Arguments.IndexOf("--versionType") @@ -1681,14 +1671,14 @@ NextInstance: '窗口尺寸 Dim TargetSize As Size - Select Case Settings.Get("LaunchArgumentWindowType") + Select Case Settings.Get(Of Integer)("LaunchArgumentWindowType") Case 2 '与启动器尺寸一致 Dim Result As Size RunInUiWait(Sub() Result = New Size(GetPixelSize(FrmMain.PanForm.ActualWidth), GetPixelSize(FrmMain.PanForm.ActualHeight))) TargetSize = Result TargetSize.Height -= 29.5 * DPI / 96 '标题栏高度 Case 3 '自定义 - TargetSize = New Size(Math.Max(100, Settings.Get("LaunchArgumentWindowWidth")), Math.Max(100, Settings.Get("LaunchArgumentWindowHeight"))) + TargetSize = New Size(Math.Max(100, Settings.Get(Of Integer)("LaunchArgumentWindowWidth")), Math.Max(100, Settings.Get(Of Integer)("LaunchArgumentWindowHeight"))) Case Else TargetSize = New Size(854, 480) End Select @@ -1705,7 +1695,7 @@ NextInstance: '支持库 Dim Cps As New List(Of String) Dim OptiFineCp As String = Nothing - For Each Library As McLibToken In McLibListGet(McInstanceSelected, True) + For Each Library As McLibEntry In McLibListGet(McInstanceSelected, True) If Library.IsNatives Then Continue For If Library.Name IsNot Nothing AndAlso Library.Name = "optifine:OptiFine" Then OptiFineCp = Library.LocalPath @@ -1714,7 +1704,7 @@ NextInstance: End If Next If OptiFineCp IsNot Nothing Then Cps.Insert(Cps.Count - 2, OptiFineCp) 'OptiFine 的总是需要放到倒数第二位 - Yield ("${classpath}", Cps.Select(Function(c) FileUtils.ShortenPath(c)).Join(";"c)) + Yield ("${classpath}", Cps.Select(Function(c) PathUtils.ToShortPath(c)).Join(";"c)) End Function ''' @@ -1806,14 +1796,14 @@ NextInstance: '解压文件 McLaunchLog("正在解压 Natives 文件") Dim ExistFiles As New List(Of String) - For Each Native As McLibToken In McLibListGet(McInstanceSelected, True) + For Each Native As McLibEntry In McLibListGet(McInstanceSelected, True) If Not Native.IsNatives Then Continue For Dim Zip As ZipArchive Try - Zip = New ZipArchive(New FileStream(Native.LocalPath, FileMode.Open, FileAccess.Read, FileShare.Read)) + Zip = FileUtils.OpenZip(Native.LocalPath) Catch ex As InvalidDataException - Log(ex, "打开 Natives 文件失败(" & Native.LocalPath & ")") - File.Delete(Native.LocalPath) + Logger.Warn(ex, $"打开 Natives 文件失败({Native.LocalPath})") + FileUtils.Delete(Native.LocalPath) Throw New Exception("无法打开 Natives 文件(" & Native.LocalPath & "),该文件可能已损坏,请重新尝试启动游戏") End Try For Each Entry In Zip.Entries @@ -1822,7 +1812,7 @@ NextInstance: '实际解压文件的步骤 Dim FilePath As String = Target & FileName ExistFiles.Add(FilePath) - Dim OriginalFile As New FileInfo(FilePath) + Dim OriginalFile = FileUtils.GetInfo(FilePath) If OriginalFile.Exists Then If OriginalFile.Length = Entry.Length Then If ModeDebug Then McLaunchLog("无需解压:" & FilePath) @@ -1830,10 +1820,10 @@ NextInstance: End If '删除原文件 Try - File.Delete(FilePath) + FileUtils.Delete(FilePath) Catch ex As UnauthorizedAccessException McLaunchLog("删除原 dll 访问被拒绝,这通常代表有一个 MC 正在运行,跳过解压:" & FilePath) - McLaunchLog("实际的错误信息:" & ex.GetDetail()) + McLaunchLog("实际的错误信息:" & ex.GetDisplay(True)) Exit For End Try End If @@ -1846,14 +1836,14 @@ NextInstance: Next '删除多余文件 - For Each FileName As String In Directory.GetFiles(Target) + For Each FileName As String In DirectoryUtils.GetFiles(Target, True) If ExistFiles.Contains(FileName) Then Continue For Try McLaunchLog("删除:" & FileName) - File.Delete(FileName) + FileUtils.Delete(FileName) Catch ex As UnauthorizedAccessException McLaunchLog("删除多余文件访问被拒绝,跳过删除步骤") - McLaunchLog("实际的错误信息:" & ex.GetDetail()) + McLaunchLog("实际的错误信息:" & ex.GetDisplay(True)) Return End Try Next @@ -1863,7 +1853,7 @@ NextInstance: ''' 获取 Natives 文件夹路径,以 \ 结尾。 ''' Private Function GetNativesFolder() As String - Dim Result As String = FileUtils.ShortenPath(McInstanceSelected.PathVersion) & McInstanceSelected.Name & "-natives\" + Dim Result As String = PathUtils.AddSlashSuffix(PathUtils.ToShortPath(McInstanceSelected.PathVersion)) & McInstanceSelected.Name & "-natives\" If Not (IsGBKEncoding OrElse Result.IsAsciiOnly()) Then Result = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\bin\natives\" If Not Result.IsAsciiOnly() Then @@ -1871,7 +1861,7 @@ NextInstance: End If End If DirectoryUtils.Create(Result) '提前创建,这样 DirectoryUtils.Shorten 才有结果(否则在长路径下首次启动 Forge 会崩溃) - Return FileUtils.ShortenPath(Result) + Return PathUtils.AddSlashSuffix(PathUtils.ToShortPath(Result)) End Function #End Region @@ -1881,15 +1871,15 @@ NextInstance: Private Sub McLaunchPrerun() '使用高性能显卡 - If Settings.Get("LaunchAdvanceGraphicCard") Then + If Settings.Get(Of Boolean)("LaunchAdvanceGraphicCard") Then Try SetGPUPreference(McLaunchJavaSelected.PathJava) SetGPUPreference(PathExe) Catch ex As Exception - If IsAdmin() Then - Log(ex, "直接调整显卡设置失败") + If SystemUtils.HasAdminRole() Then + Logger.Warn(ex, "直接调整显卡设置失败") Else - Log(ex, "直接调整显卡设置失败,将以管理员权限重启 PCL 再次尝试") + Logger.Warn(ex, "直接调整显卡设置失败,将以管理员权限重启 PCL 再次尝试") Try If RunAsAdmin($"--gpu ""{McLaunchJavaSelected.PathJava}""") = ProcessReturnValues.TaskDone Then McLaunchLog("以管理员权限重启 PCL 并调整显卡设置成功") @@ -1897,7 +1887,7 @@ NextInstance: Throw New Exception("调整过程中出现异常") End If Catch exx As Exception - Log(exx, "调整显卡设置失败,Minecraft 可能会使用默认显卡运行", NotifyLevel.AllUsers) + Logger.Error(exx, "调整显卡设置失败,Minecraft 可能会使用默认显卡运行", LogBehavior.Toast) End Try End If End Try @@ -1929,14 +1919,14 @@ NextInstance: }" Dim ReplaceJson As JObject = GetJson(ReplaceJsonString) '更新文件 - Dim Profiles As JObject = GetJson(ReadFile(McFolderSelected & "launcher_profiles.json")) + Dim Profiles As JObject = GetJson(FileUtils.ReadAsString(McFolderSelected & "launcher_profiles.json")) Profiles.Merge(ReplaceJson) - FileUtils.Write(McFolderSelected & "launcher_profiles.json", Profiles.ToString, Encoding:=Encoding.GetEncoding("GB18030")) + FileUtils.Write(McFolderSelected & "launcher_profiles.json", Profiles.ToString, encoding:=Encoding.GetEncoding("GB18030")) McLaunchLog("已更新 launcher_profiles.json") Catch ex As Exception - Log(ex, "更新 launcher_profiles.json 失败,将在删除文件后重试") + Logger.Warn(ex, "更新 launcher_profiles.json 失败,将在删除文件后重试") Try - File.Delete(McFolderSelected & "launcher_profiles.json") + FileUtils.Delete(McFolderSelected & "launcher_profiles.json") McFolderLauncherProfilesJsonCreate(McFolderSelected) '构建需要替换的 Json 对象 Dim ReplaceJsonString As String = " @@ -1959,21 +1949,21 @@ NextInstance: }" Dim ReplaceJson As JObject = GetJson(ReplaceJsonString) '更新文件 - Dim Profiles As JObject = GetJson(ReadFile(McFolderSelected & "launcher_profiles.json")) + Dim Profiles As JObject = GetJson(FileUtils.ReadAsString(McFolderSelected & "launcher_profiles.json")) Profiles.Merge(ReplaceJson) - FileUtils.Write(McFolderSelected & "launcher_profiles.json", Profiles.ToString, Encoding:=Encoding.GetEncoding("GB18030")) + FileUtils.Write(McFolderSelected & "launcher_profiles.json", Profiles.ToString, encoding:=Encoding.GetEncoding("GB18030")) McLaunchLog("已在删除后更新 launcher_profiles.json") Catch exx As Exception - Log(exx, "更新 launcher_profiles.json 失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(exx, "更新 launcher_profiles.json 失败") End Try End Try '更新 options.txt Dim SetupFileAddress As String = McInstanceSelected.PathIndie & "options.txt" - If Not File.Exists(SetupFileAddress) Then + If Not FileUtils.Exists(SetupFileAddress) Then 'Yosbr Mod 兼容(#2385):https://www.curseforge.com/minecraft/mc-mods/yosbr Dim YosbrFileAddress As String = McInstanceSelected.PathIndie & "config\yosbr\options.txt" - If File.Exists(YosbrFileAddress) Then + If FileUtils.Exists(YosbrFileAddress) Then McLaunchLog("将修改 Yosbr Mod 中的 options.txt") SetupFileAddress = YosbrFileAddress WriteIni(SetupFileAddress, "lang", "none") '忽略默认语言 @@ -1987,8 +1977,8 @@ NextInstance: '1.11 ~ 12:zh_cn 时正常,zh_CN 时虽然显示了中文但语言设置会错误地显示选择英文 '1.13+ :zh_cn 时正常,zh_CN 时自动切换为英文 Dim CurrentLang As String = ReadIni(SetupFileAddress, "lang", "none") - Dim RequiredLang As String = If(CurrentLang = "none" OrElse Not Directory.Exists(McInstanceSelected.PathIndie & "saves"), '#3844,整合包可能已经自带了 options.txt - If(Settings.Get("ToolHelpChinese"), "zh_cn", "en_us"), CurrentLang.Lower) + Dim RequiredLang As String = If(CurrentLang = "none" OrElse Not DirectoryUtils.Exists(McInstanceSelected.PathIndie & "saves"), '#3844,整合包可能已经自带了 options.txt + If(Settings.Get(Of Boolean)("ToolHelpChinese"), "zh_cn", "en_us"), CurrentLang.Lower) If Not McInstanceSelected.Version.Vaild OrElse McInstanceSelected.Version.Vanilla.Major <= 10 Then '将最后两位改为大写,前面的部分保留 RequiredLang = RequiredLang.Substring(0, RequiredLang.Length - 2) & RequiredLang.Substring(RequiredLang.Length - 2).Upper @@ -2001,12 +1991,12 @@ NextInstance: McLaunchLog($"已将语言从 {CurrentLang} 修改为 {RequiredLang}") End If ''如果是初次设置,一并修改 forceUnicodeFont - 'If Settings.Get("ToolHelpChinese") AndAlso (CurrentLang = "none" OrElse Not Directory.Exists(McInstanceSelected.PathIndie & "saves")) Then + 'If Settings.Get(Of Boolean)("ToolHelpChinese") AndAlso (CurrentLang = "none" OrElse Not DirectoryUtils.Exists(McInstanceSelected.PathIndie & "saves")) Then ' WriteIni(SetupFileAddress, "forceUnicodeFont", "true") ' McLaunchLog("已开启 forceUnicodeFont") 'End If '窗口 - Select Case Settings.Get("LaunchArgumentWindowType") + Select Case Settings.Get(Of Integer)("LaunchArgumentWindowType") Case 0 '全屏 WriteIni(SetupFileAddress, "fullscreen", "true") Case 1 '默认 @@ -2014,24 +2004,22 @@ NextInstance: WriteIni(SetupFileAddress, "fullscreen", "false") End Select Catch ex As Exception - Log(ex, "更新 options.txt 失败", NotifyLevel.AllUsers) + Logger.Error(ex, "更新 options.txt 失败", LogBehavior.Toast) End Try '离线皮肤 Alex 警告 If McInstanceSelected.Version.Vanilla.Major <= 7 AndAlso McInstanceSelected.Version.Vanilla.Major >= 2 AndAlso '1.2 ~ 1.7 McLoginLoader.Input.Type = McLoginType.Legacy AndAlso '离线登录 - (Settings.Get("LaunchSkinType") = 2 OrElse '强制 Alex - (Settings.Get("LaunchSkinType") = 4 AndAlso Settings.Get("LaunchSkinSlim"))) Then '或选用 Alex 皮肤 + (Settings.Get(Of Integer)("LaunchSkinType") = 2 OrElse '强制 Alex + (Settings.Get(Of Integer)("LaunchSkinType") = 4 AndAlso Settings.Get(Of Boolean)("LaunchSkinSlim"))) Then '或选用 Alex 皮肤 Hint("此 Minecraft 版本尚不支持 Alex 皮肤,你的皮肤可能会显示为 Steve!", HintType.Red) End If '离线皮肤资源包 Try Dim ZipFileAddress As String = McInstanceSelected.PathIndie & "resourcepacks\PCL2 Skin.zip" - DirectoryUtils.Create(ZipFileAddress, isFilePath:=True) Dim NewTypeSetup As Boolean = McInstanceSelected.Version.Vanilla.Major >= 13 OrElse McInstanceSelected.Version.Vanilla.Major < 6 - If McLoginLoader.Input.Type = McLoginType.Legacy AndAlso Settings.Get("LaunchSkinType") = 4 AndAlso File.Exists(PathAppdata & "CustomSkin.png") Then - DirectoryUtils.Create(PathTemp) + If McLoginLoader.Input.Type = McLoginType.Legacy AndAlso Settings.Get(Of Integer)("LaunchSkinType") = 4 AndAlso FileUtils.Exists(PathAppdata & "CustomSkin.png") Then Dim MetaFileAddress As String = PathTemp & "pack.mcmeta" Dim PackPicAddress As String = PathTemp & "pack.png" Dim PackFormat As Integer @@ -2088,22 +2076,22 @@ NextInstance: End If Skin.Save(PathExeFolder & "PCL\CustomSkin_Cliped.png") '构建压缩文件 - Using ZipFile As New FileStream(ZipFileAddress, FileMode.Create) - Using ZipAr As New ZipArchive(ZipFile, ZipArchiveMode.Create) - ZipAr.CreateEntryFromFile(MetaFileAddress, "pack.mcmeta") - ZipAr.CreateEntryFromFile(PackPicAddress, "pack.png") - '1.19.3+ 使用复杂版本的替换 - If McInstanceSelected.Version.Vanilla >= New Version(19, 0, 3) Then - For Each SkinName In {"alex", "ari", "efe", "kai", "makena", "noor", "steve", "sunny", "zuri"} - ZipAr.CreateEntryFromFile(PathExeFolder & "PCL\CustomSkin_Cliped.png", - $"assets/minecraft/textures/entity/player/{If(Settings.Get("LaunchSkinSlim"), "slim", "wide")}/{SkinName}.png") - Next - Else - ZipAr.CreateEntryFromFile(PathExeFolder & "PCL\CustomSkin_Cliped.png", "assets/minecraft/textures/entity/" & If(Settings.Get("LaunchSkinSlim"), "alex.png", "steve.png")) - End If - End Using - End Using - File.Delete(PathExeFolder & "PCL\CustomSkin_Cliped.png") + Dim FilesToCompress As New Dictionary(Of String, String) From { + {"pack.mcmeta", MetaFileAddress}, {"pack.png", PackPicAddress}} + If McInstanceSelected.Version.Vanilla >= New Version(19, 0, 3) Then + '1.19.3+ 使用复杂版本的替换 + For Each SkinName In {"alex", "ari", "efe", "kai", "makena", "noor", "steve", "sunny", "zuri"} + FilesToCompress.Add( + $"assets/minecraft/textures/entity/player/{If(Settings.Get(Of Boolean)("LaunchSkinSlim"), "slim", "wide")}/{SkinName}.png", + PathExeFolder & "PCL\CustomSkin_Cliped.png") + Next + Else + FilesToCompress.Add( + $"assets/minecraft/textures/entity/{If(Settings.Get(Of Boolean)("LaunchSkinSlim"), "alex.png", "steve.png")}", + PathExeFolder & "PCL\CustomSkin_Cliped.png") + End If + FileUtils.CreateZipFromFiles(ZipFileAddress, FilesToCompress) + FileUtils.Delete(PathExeFolder & "PCL\CustomSkin_Cliped.png") '更改设置文件 IniClearCache(SetupFileAddress) Dim EnabledResourcePack As String = ReadIni(SetupFileAddress, "resourcePacks", "[]").TrimStart("[").TrimEnd("]") @@ -2128,10 +2116,10 @@ NextInstance: WriteIni(SetupFileAddress, "resourcePacks", Result) End If IgnoreCustomSkin: - ElseIf File.Exists(ZipFileAddress) Then + ElseIf FileUtils.Exists(ZipFileAddress) Then McLaunchLog("正在清空自定义皮肤资源包") '删除压缩文件 - File.Delete(ZipFileAddress) + FileUtils.Delete(ZipFileAddress) '更改设置文件 IniClearCache(SetupFileAddress) Dim EnabledResourcePack As String = ReadIni(SetupFileAddress, "resourcePacks", "[]").TrimStart("[").TrimEnd("]") @@ -2149,16 +2137,16 @@ IgnoreCustomSkin: End If End If Catch ex As Exception - Log(ex, "离线皮肤资源包设置失败", NotifyLevel.AllUsers) + Logger.Error(ex, "离线皮肤资源包设置失败", LogBehavior.Toast) End Try End Sub Private Sub McLaunchCustom(Loader As LoaderTask(Of Integer, Integer)) '获取自定义命令 - Dim CustomCommandGlobal As String = Settings.Get("LaunchAdvanceRun") + Dim CustomCommandGlobal As String = Settings.Get(Of String)("LaunchAdvanceRun") If CustomCommandGlobal <> "" Then CustomCommandGlobal = ArgumentReplace(CustomCommandGlobal) - Dim CustomCommandVersion As String = Settings.Get("VersionAdvanceRun", Instance:=McInstanceSelected) + Dim CustomCommandVersion As String = Settings.Get(Of String)("VersionAdvanceRun", Instance:=McInstanceSelected) If CustomCommandVersion <> "" Then CustomCommandVersion = ArgumentReplace(CustomCommandVersion) '输出 bat @@ -2168,14 +2156,16 @@ IgnoreCustomSkin: "@echo off" & vbCrLf & $"title 启动 - {McInstanceSelected.Name}" & vbCrLf & "echo 游戏正在启动,请稍候。" & vbCrLf & - $"cd /D ""{FileUtils.ShortenPath(McInstanceSelected.PathIndie)}""" & vbCrLf & + $"cd /D ""{PathUtils.ToShortPath(McInstanceSelected.PathIndie)}""" & vbCrLf & CustomCommandGlobal & vbCrLf & CustomCommandVersion & vbCrLf & $"""{McLaunchJavaSelected.PathJava}"" {McLaunchArgument}" & vbCrLf & "echo 游戏已退出。" & vbCrLf & "pause" - FileUtils.Write(If(CurrentLaunchOptions.SaveBatch, PathExeFolder & "PCL\LatestLaunch.bat"), FilterAccessToken(CmdString, "F"), - Encoding:=If(McLaunchJavaSelected.MajorVersion > 8, Encoding.UTF8, Encoding.Default)) + FileUtils.Write( + filePath:=If(CurrentLaunchOptions.SaveBatch, PathExeFolder & "PCL\LatestLaunch.bat"), + text:=FilterAccessToken(CmdString, "F").Replace("%", "%%"), + encoding:=If(McLaunchJavaSelected.MajorVersion > 8, Encoding.UTF8, Encoding.Default)) If CurrentLaunchOptions.SaveBatch IsNot Nothing Then McLaunchLog("导出启动脚本完成,强制结束启动过程") InterruptHint = "导出启动脚本成功!" @@ -2184,7 +2174,7 @@ IgnoreCustomSkin: Return '导出脚本完成 End If Catch ex As Exception - Log(ex, "输出启动脚本失败") + Logger.Warn(ex, "输出启动脚本失败") If CurrentLaunchOptions.SaveBatch IsNot Nothing Then Throw ex '直接触发启动失败 End Try @@ -2200,13 +2190,13 @@ IgnoreCustomSkin: .UseShellExecute = False, .CreateNoWindow = True }) - If Settings.Get("LaunchAdvanceRunWait") Then + If Settings.Get(Of Boolean)("LaunchAdvanceRunWait") Then Do Until CustomProcess.HasExited OrElse Loader.IsInterrupted Thread.Sleep(10) Loop End If Catch ex As Exception - Log(ex, "执行全局自定义命令失败", NotifyLevel.AllUsers) + Logger.Error(ex, "执行全局自定义命令失败", LogBehavior.Toast) Finally If CustomProcess IsNot Nothing AndAlso Not CustomProcess.HasExited AndAlso Loader.IsInterrupted Then McLaunchLog("由于取消启动,已强制结束自定义命令 CMD 进程") '#1183 @@ -2225,13 +2215,13 @@ IgnoreCustomSkin: .UseShellExecute = False, .CreateNoWindow = True }) - If Settings.Get("VersionAdvanceRunWait", Instance:=McInstanceSelected) Then + If Settings.Get(Of Boolean)("VersionAdvanceRunWait", Instance:=McInstanceSelected) Then Do Until CustomProcess.HasExited OrElse Loader.IsInterrupted Thread.Sleep(10) Loop End If Catch ex As Exception - Log(ex, "执行版本自定义命令失败", NotifyLevel.AllUsers) + Logger.Error(ex, "执行版本自定义命令失败", LogBehavior.Toast) Finally If CustomProcess IsNot Nothing AndAlso Not CustomProcess.HasExited AndAlso Loader.IsInterrupted Then McLaunchLog("由于取消启动,已强制结束自定义命令 CMD 进程") '#1183 @@ -2250,9 +2240,9 @@ IgnoreCustomSkin: Dim PathEnv As String = StartInfo.EnvironmentVariables("Path") Dim Paths As New List(Of String) If Not String.IsNullOrEmpty(PathEnv) Then Paths.AddRange(PathEnv.Split(";")) - Paths.Add(FileUtils.ShortenPath(McLaunchJavaSelected.PathFolder)) + Paths.Add(PathUtils.ToShortPath(McLaunchJavaSelected.PathFolder)) StartInfo.EnvironmentVariables("Path") = Paths.Distinct.Join(";"c) - StartInfo.EnvironmentVariables("appdata") = FileUtils.ShortenPath(McFolderSelected) + StartInfo.EnvironmentVariables("appdata") = PathUtils.ToShortPath(McFolderSelected) '设置其他参数 StartInfo.WorkingDirectory = McInstanceSelected.PathIndie @@ -2276,7 +2266,7 @@ IgnoreCustomSkin: '进程优先级处理 Try GameProcess.PriorityBoostEnabled = True - Select Case Settings.Get("LaunchArgumentPriority") + Select Case Settings.Get(Of Integer)("LaunchArgumentPriority") Case 0 '高 GameProcess.PriorityClass = ProcessPriorityClass.AboveNormal Case 2 '低 @@ -2284,7 +2274,7 @@ IgnoreCustomSkin: Case Else '中 End Select Catch ex As Exception - Log(ex, "设置进程优先级失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "设置进程优先级失败") End Try End Sub @@ -2315,8 +2305,8 @@ IgnoreCustomSkin: McLaunchLog("") '获取窗口标题 - Dim WindowTitle As String = Settings.Get("VersionArgumentTitle", Instance:=McInstanceSelected) - If WindowTitle = "" Then WindowTitle = Settings.Get("LaunchArgumentTitle") + Dim WindowTitle As String = Settings.Get(Of String)("VersionArgumentTitle", Instance:=McInstanceSelected) + If WindowTitle = "" Then WindowTitle = Settings.Get(Of String)("LaunchArgumentTitle") WindowTitle = ArgumentReplace(WindowTitle, ReplaceTime:=False) '初始化等待 @@ -2336,15 +2326,15 @@ IgnoreCustomSkin: McLaunchLog("开始启动结束处理") '暂停或开始音乐播放 - If Settings.Get("UiMusicStop") Then - RunInUi(Sub() If MusicPause() Then Log("[Music] 已根据设置,在启动后暂停音乐播放")) - ElseIf Settings.Get("UiMusicStart") Then - RunInUi(Sub() If MusicResume() Then Log("[Music] 已根据设置,在启动后开始音乐播放")) + If Settings.Get(Of Boolean)("UiMusicStop") Then + RunInUi(Sub() If MusicPause() Then Logger.Info("已根据设置,在启动后暂停音乐播放")) + ElseIf Settings.Get(Of Boolean)("UiMusicStart") Then + RunInUi(Sub() If MusicResume() Then Logger.Info("已根据设置,在启动后开始音乐播放")) End If '启动器可见性 - McLaunchLog("启动器可见性:" & Settings.Get("LaunchArgumentVisible")) - Select Case Settings.Get("LaunchArgumentVisible") + McLaunchLog("启动器可见性:" & Settings.Get(Of Integer)("LaunchArgumentVisible")) + Select Case Settings.Get(Of Integer)("LaunchArgumentVisible") Case 0 '直接关闭 McLaunchLog("已根据设置,在启动后关闭启动器") @@ -2362,7 +2352,7 @@ IgnoreCustomSkin: End Select '启动计数 - Settings.Set("SystemLaunchCount", Settings.Get("SystemLaunchCount") + 1) + Settings.Set("SystemLaunchCount", Settings.Get(Of Integer)("SystemLaunchCount") + 1) End Sub diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb index 33b46d8..5833d96 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModMinecraft.vb @@ -7,7 +7,7 @@ ''' Public Property McFolderSelected As String Get - If _McFolderSelected Is Nothing Then SetMcFolder(Settings.Get("LaunchFolderSelect")) '不能使用 McFolderSelected 触发 Set,这会被视为为 Get 设置返回值 + If _McFolderSelected Is Nothing Then SetMcFolder(Settings.Get(Of String)("LaunchFolderSelect")) '不能使用 McFolderSelected 触发 Set,这会被视为为 Get 设置返回值 Return _McFolderSelected End Get Set(Value As String) @@ -17,8 +17,9 @@ Private Sub SetMcFolder(Value As String) '等同 McFolderSelected.Set If _McFolderSelected = Value Then Return _McFolderSelected = Value.Replace("$", PathExeFolder) + _McFolderSelected = PathUtils.AddSlashSuffix(PathUtils.ForCompare(_McFolderSelected)) Settings.Set("LaunchFolderSelect", Value.Replace(PathExeFolder, "$")) - Log("[Minecraft] 当前选择的 Minecraft 文件夹:" & _McFolderSelected) + Logger.Info($"当前选择的 Minecraft 文件夹:{_McFolderSelected}") End Sub Private _McFolderSelected As String ''' @@ -63,18 +64,20 @@ '扫描当前文件夹 Try - If Directory.Exists(PathExeFolder & "versions\") Then CacheMcFolderList.Add(New McFolder With {.Name = "当前文件夹", .Location = PathExeFolder, .Type = McFolder.Types.Vanilla}) - For Each Folder As DirectoryInfo In New DirectoryInfo(PathExeFolder).GetDirectories - If Directory.Exists(Folder.FullName & "versions\") OrElse Folder.Name = ".minecraft" Then CacheMcFolderList.Add(New McFolder With {.Name = "当前文件夹", .Location = Folder.FullName & "\", .Type = McFolder.Types.Vanilla}) + If DirectoryUtils.Exists(PathExeFolder & "versions\") Then CacheMcFolderList.Add(New McFolder With {.Name = "当前文件夹", .Location = PathExeFolder, .Type = McFolder.Types.Vanilla}) + For Each Folder As DirectoryInfo In DirectoryUtils.GetInfo(PathExeFolder).GetDirectories + If DirectoryUtils.Exists(Folder.FullName & "versions\") OrElse Folder.Name = ".minecraft" Then + CacheMcFolderList.Add(New McFolder With {.Name = "当前文件夹", .Location = PathUtils.AddSlashSuffix(PathUtils.ForCompare(Folder.FullName)), .Type = McFolder.Types.Vanilla}) + End If Next Catch ex As Exception - Log(ex, "扫描 PCL 所在文件夹中是否有 MC 文件夹失败") + Logger.Warn(ex, "扫描 PCL 所在文件夹中是否有 MC 文件夹失败") End Try '扫描官启文件夹 Dim MojangPath As String = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\" If (Not CacheMcFolderList.Any OrElse MojangPath <> CacheMcFolderList(0).Location) AndAlso '当前文件夹不是官启文件夹 - Directory.Exists(MojangPath & "versions\") Then '具有权限且存在 versions 文件夹 + DirectoryUtils.Exists(MojangPath & "versions\") Then '具有权限且存在 versions 文件夹 CacheMcFolderList.Add(New McFolder With {.Name = "官方启动器文件夹", .Location = MojangPath, .Type = McFolder.Types.Vanilla}) End If @@ -83,7 +86,7 @@ #Region "读取自定义(Custom)文件夹,可能没有结果" '格式:TMZ 12>C://xxx/xx/|Test>D://xxx/xx/|名称>路径 - For Each Folder As String In Settings.Get("LaunchFolders").ToString.Split({"|"c}, StringSplitOptions.RemoveEmptyEntries) + For Each Folder As String In Settings.Get(Of String)("LaunchFolders").ToString.Split("|"c, True) If Folder = "" Then Continue For If Not Folder.Contains(">") OrElse Not Folder.EndsWithF("\") Then Hint("无效的 Minecraft 文件夹:" & Folder, HintType.Red) @@ -101,10 +104,10 @@ Renamed = True End If Next - If Not Renamed Then CacheMcFolderList.Add(New McFolder With {.Name = FolderName, .Location = FolderPath, .Type = McFolder.Types.Custom}) + If Not Renamed Then CacheMcFolderList.Add(New McFolder With {.Name = FolderName, .Location = PathUtils.AddSlashSuffix(PathUtils.ForCompare(FolderPath)), .Type = McFolder.Types.Custom}) Catch ex As Exception - MyMsgBox("失效的 Minecraft 文件夹:" & vbCrLf & FolderPath & vbCrLf & vbCrLf & ex.GetBrief(), "Minecraft 文件夹失效", IsWarn:=True) - Log(ex, $"无法访问 Minecraft 文件夹 {FolderPath}") + MyMsgBox("失效的 Minecraft 文件夹:" & vbCrLf & FolderPath & vbCrLf & vbCrLf & ex.GetDisplay(False), "Minecraft 文件夹失效", IsWarn:=True) + Logger.Warn(ex, $"无法访问 Minecraft 文件夹 {FolderPath}") End Try Next @@ -127,13 +130,13 @@ For Each Folder As McFolder In CacheMcFolderList McFolderLauncherProfilesJsonCreate(Folder.Location) Next - If Settings.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(200, 2000)) + If Settings.Get(Of Boolean)("SystemDebugDelay") Then Thread.Sleep(RandomInteger(200, 2000)) '回设 McFolderList = CacheMcFolderList Catch ex As Exception - Log(ex, "加载 Minecraft 文件夹列表失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "加载 Minecraft 文件夹列表失败") End Try End Sub @@ -142,7 +145,7 @@ ''' Public Sub McFolderLauncherProfilesJsonCreate(Folder As String) Try - If File.Exists(Folder & "launcher_profiles.json") Then Return + If FileUtils.Exists(Folder & "launcher_profiles.json") Then Return Dim ResultJson As String = "{ ""profiles"": { @@ -157,10 +160,10 @@ ""selectedProfile"": ""PCL"", ""clientToken"": ""23323323323323323323323323323333"" }" - FileUtils.Write(Folder & "launcher_profiles.json", ResultJson, Encoding:=Encoding.GetEncoding("GB18030")) - Log("[Minecraft] 已创建 launcher_profiles.json:" & Folder) + FileUtils.Write(Folder & "launcher_profiles.json", ResultJson, encoding:=Encoding.GetEncoding("GB18030")) + Logger.Info($"已创建 launcher_profiles.json:{Folder}") Catch ex As Exception - Log(ex, "创建 launcher_profiles.json 失败(" & Folder & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"创建 launcher_profiles.json 失败({Folder})") End Try End Sub @@ -168,8 +171,6 @@ #Region "版本处理" - Public Const McInstanceCacheVersion As Integer = 36 - Private _McInstanceSelected As McInstance ''' ''' 当前的 Minecraft 版本。 @@ -179,37 +180,37 @@ Return _McInstanceSelected End Get Set(value As McInstance) - Static _McInstanceSelectedLast = 0 '为 0 以保证与 Nothing 不相同,使得 UI 显示可以正常初始化 + Static _McInstanceSelectedLast As Object = 0 '为 0 以保证与 Nothing 不相同,使得 UI 显示可以正常初始化 If ReferenceEquals(_McInstanceSelectedLast, value) Then Return _McInstanceSelected = value '由于有可能是 Nothing,导致无法初始化,才得这样弄一圈 _McInstanceSelectedLast = value '更新 MC 文件夹所选取的 Minecraft 版本 - Log("[Launch] 当前选择的 Minecraft 版本:" & If(value?.PathVersion, "无")) + Logger.Info($"当前选择的 Minecraft 版本:{If(value?.PathVersion, "无")}") WriteIni(McFolderSelected & "PCL.ini", "Version", If(value?.Name, "")) If value Is Nothing Then Return '重置缓存的下载文件夹 PageDownloadResourceDetail.CachedFolder.Clear() '统一通行证重判 If AniControlEnabled = 0 AndAlso - Settings.Get("VersionServerNide", Instance:=value) <> Settings.Get("CacheNideServer") AndAlso - Settings.Get("VersionServerLogin", Instance:=value) = 3 Then + Settings.Get(Of String)("VersionServerNide", Instance:=value) <> Settings.Get(Of String)("CacheNideServer") AndAlso + Settings.Get(Of Integer)("VersionServerLogin", Instance:=value) = 3 Then Settings.Set("CacheNideAccess", "") - Log("[Launch] 服务器改变,要求重新登录统一通行证") + Logger.Info("服务器改变,要求重新登录统一通行证") End If - If Settings.Get("VersionServerLogin", Instance:=value) = 3 Then - Settings.Set("CacheNideServer", Settings.Get("VersionServerNide", Instance:=value)) + If Settings.Get(Of Integer)("VersionServerLogin", Instance:=value) = 3 Then + Settings.Set("CacheNideServer", Settings.Get(Of String)("VersionServerNide", Instance:=value)) End If 'Authlib-Injector 重判 If AniControlEnabled = 0 AndAlso - Settings.Get("VersionServerAuthServer", Instance:=value) <> Settings.Get("CacheAuthServerServer") AndAlso - Settings.Get("VersionServerLogin", Instance:=value) = 4 Then + Settings.Get(Of String)("VersionServerAuthServer", Instance:=value) <> Settings.Get(Of String)("CacheAuthServerServer") AndAlso + Settings.Get(Of Integer)("VersionServerLogin", Instance:=value) = 4 Then Settings.Set("CacheAuthAccess", "") - Log("[Launch] 服务器改变,要求重新登录 Authlib-Injector") + Logger.Info("服务器改变,要求重新登录 Authlib-Injector") End If - If Settings.Get("VersionServerLogin", Instance:=value) = 4 Then - Settings.Set("CacheAuthServerServer", Settings.Get("VersionServerAuthServer", Instance:=value)) - Settings.Set("CacheAuthServerName", Settings.Get("VersionServerAuthName", Instance:=value)) - Settings.Set("CacheAuthServerRegister", Settings.Get("VersionServerAuthRegister", Instance:=value)) + If Settings.Get(Of Integer)("VersionServerLogin", Instance:=value) = 4 Then + Settings.Set("CacheAuthServerServer", Settings.Get(Of String)("VersionServerAuthServer", Instance:=value)) + Settings.Set("CacheAuthServerName", Settings.Get(Of String)("VersionServerAuthName", Instance:=value)) + Settings.Set("CacheAuthServerRegister", Settings.Get(Of String)("VersionServerAuthRegister", Instance:=value)) End If End Set End Property @@ -231,21 +232,21 @@ Dim ShouldBeIndie = Function() As Boolean '从老的版本独立设置中迁移:-1 未决定,0 使用全局设置,1 手动开启,2 手动关闭 - If Settings.HasSaved("VersionArgumentIndie", Instance:=Me) AndAlso Settings.Get("VersionArgumentIndie", Instance:=Me) > 0 Then - Log($"[Minecraft] 版本隔离初始化({Name}):从老的版本独立设置中迁移") - Return Settings.Get("VersionArgumentIndie", Instance:=Me) = 1 + If Settings.HasSaved("VersionArgumentIndie", Instance:=Me) AndAlso Settings.Get(Of Integer)("VersionArgumentIndie", Instance:=Me) > 0 Then + Logger.Info($"版本隔离初始化({Name}):从老的版本独立设置中迁移") + Return Settings.Get(Of Integer)("VersionArgumentIndie", Instance:=Me) = 1 End If '若版本文件夹下包含 mods 或 saves 文件夹,则自动开启版本隔离 - Dim ModFolder As New DirectoryInfo(PathVersion & "mods\") - Dim SaveFolder As New DirectoryInfo(PathVersion & "saves\") + Dim ModFolder = DirectoryUtils.GetInfo(PathVersion & "mods\") + Dim SaveFolder = DirectoryUtils.GetInfo(PathVersion & "saves\") If (ModFolder.Exists AndAlso ModFolder.EnumerateFiles.Any) OrElse (SaveFolder.Exists AndAlso SaveFolder.EnumerateDirectories.Any) Then - Log($"[Minecraft] 版本隔离初始化({Name}):版本文件夹下存在 mods 或 saves 文件夹,自动开启") + Logger.Info($"版本隔离初始化({Name}):版本文件夹下存在 mods 或 saves 文件夹,自动开启") Return True End If '根据全局的默认设置决定是否隔离 Dim IsRelease As Boolean = State <> McInstanceState.Fool AndAlso State <> McInstanceState.Old AndAlso State <> McInstanceState.Snapshot - Log($"[Minecraft] 版本隔离初始化({Name}):从全局默认设置中({Settings.Get("LaunchArgumentIndieV2")})判断,State {GetStringFromEnum(State)},IsRelease {IsRelease},Modable {Modable}") - Select Case Settings.Get("LaunchArgumentIndieV2") + Logger.Info($"版本隔离初始化({Name}):从全局默认设置中({Settings.Get(Of Integer)("LaunchArgumentIndieV2")})判断,State {State},IsRelease {IsRelease},Modable {Modable}") + Select Case Settings.Get(Of Integer)("LaunchArgumentIndieV2") Case 0 '关闭 Return False Case 1 '仅隔离可安装 Mod 的版本 @@ -260,7 +261,7 @@ End Function Settings.Set("VersionArgumentIndieV2", ShouldBeIndie(), Instance:=Me) End If - Return If(Settings.Get("VersionArgumentIndieV2", Instance:=Me), PathVersion, McFolderSelected) + Return If(Settings.Get(Of Boolean)("VersionArgumentIndieV2", Instance:=Me), PathVersion, McFolderSelected) End Get End Property @@ -269,7 +270,7 @@ ''' Public ReadOnly Property Name As String Get - If _Name Is Nothing AndAlso Not PathVersion = "" Then _Name = GetFolderNameFromPath(PathVersion) + If _Name Is Nothing AndAlso Not PathVersion = "" Then _Name = PathUtils.GetLastPart(PathVersion) Return _Name End Get End Property @@ -366,26 +367,26 @@ GoTo VersionSearchFinish End If '从下载地址中获取版本号 - Dim Regex As String = RegexSeek(If(JsonObject("downloads"), "").ToString, "(?<=launcher.mojang.com/mc/game/)[^/]*") + Dim Regex As String = If(JsonObject("downloads"), "").ToString.RegexSeek("(?<=launcher.mojang.com/mc/game/)[^/]*") If Regex IsNot Nothing Then _Version.VanillaName = Regex GoTo VersionSearchFinish End If '从 Forge 版本中获取版本号 Dim LibrariesString As String = JsonObject("libraries").ToString - Regex = If(RegexSeek(LibrariesString, "(?<=net.minecraftforge:forge:)[0-9]{1,2}.[0-9+.]+"), RegexSeek(LibrariesString, "(?<=net.minecraftforge:fmlloader:)[0-9]{1,2}.[0-9+.]+")) + Regex = If(LibrariesString.RegexSeek("(?<=net.minecraftforge:forge:)[0-9]{1,2}.[0-9+.]+"), LibrariesString.RegexSeek("(?<=net.minecraftforge:fmlloader:)[0-9]{1,2}.[0-9+.]+")) If Regex IsNot Nothing Then _Version.VanillaName = Regex GoTo VersionSearchFinish End If '从 OptiFine 版本中获取版本号 - Regex = RegexSeek(LibrariesString, "(?<=optifine:OptiFine:)[0-9]{1,2}.[0-9+.]+") + Regex = LibrariesString.RegexSeek("(?<=optifine:OptiFine:)[0-9]{1,2}.[0-9+.]+") If Regex IsNot Nothing Then _Version.VanillaName = Regex GoTo VersionSearchFinish End If '从 Fabric 版本中获取版本号 - Regex = RegexSeek(LibrariesString, "(?<=((fabricmc)|(quiltmc)):intermediary:)[^""]*") + Regex = LibrariesString.RegexSeek("(?<=((fabricmc)|(quiltmc)):intermediary:)[^""]*") If Regex IsNot Nothing Then _Version.VanillaName = Regex GoTo VersionSearchFinish @@ -400,22 +401,22 @@ Dim JsonVerName As String = JsonVersion("name").ToString If JsonVerName.Length < 32 Then '因为 wiki 说这玩意儿可能是个 hash,虽然我没发现 _Version.VanillaName = JsonVerName - Log("[Minecraft] 从版本 jar 中的 version.json 获取到版本号:" & JsonVerName) + Logger.Info($"从版本 jar 中的 version.json 获取到版本号:{JsonVerName}") GoTo VersionSearchFinish End If End If '从 JSON 的 ID 中获取 Static Pattern = "(([1-9][0-9]w[0-9]{2}[a-g])|((1|[2-9][0-9])\.[0-9]+(\.[0-9]+)?(-(pre|rc|snapshot-?)[1-9]*| Pre-Release( [1-9])?)?))(_unobfuscated)?" - Regex = RegexSeek(JsonObject("id"), Pattern, RegularExpressions.RegexOptions.IgnoreCase) + Regex = JsonObject("id").ToString.RegexSeek(Pattern, RegularExpressions.RegexOptions.IgnoreCase) If Regex IsNot Nothing Then _Version.VanillaName = Regex GoTo VersionSearchFinish End If '非准确的版本判断警告 - Log("[Minecraft] 无法完全确认 MC 版本号的版本:" & Name) + Logger.Info($"无法完全确认 MC 版本号的版本:{Name}") _Version.Reliable = False '从文件夹名中获取 - Regex = RegexSeek(Name, Pattern, RegularExpressions.RegexOptions.IgnoreCase) + Regex = Name.RegexSeek(Pattern, RegularExpressions.RegexOptions.IgnoreCase) If Regex IsNot Nothing Then _Version.VanillaName = Regex GoTo VersionSearchFinish @@ -424,7 +425,7 @@ Dim JsonRaw As JObject = JsonObject.DeepClone() JsonRaw.Remove("libraries") Dim JsonRawText As String = JsonRaw.ToString - Regex = RegexSeek(JsonRawText, Pattern, RegularExpressions.RegexOptions.IgnoreCase) + Regex = JsonRawText.RegexSeek(Pattern, RegularExpressions.RegexOptions.IgnoreCase) If Regex IsNot Nothing Then _Version.VanillaName = Regex GoTo VersionSearchFinish @@ -433,32 +434,14 @@ _Version.VanillaName = "Unknown" Info = "PCL 无法识别该版本的 MC 版本号" Catch ex As Exception - Log(ex, "识别 Minecraft 版本时出错") + Logger.Warn(ex, "识别 Minecraft 版本时出错") _Version.VanillaName = "Unknown" Info = "无法识别:" & ex.Message End Try #End Region VersionSearchFinish: - '所有带 w 的愚人节版本 - Select Case _Version.VanillaName - Case "15w14a" - _Version.VanillaName = "1.8.3" - Case "20w14∞", "20w14infinite" - _Version.VanillaName = "20w13b" - Case "22w13oneblockatetime" - _Version.VanillaName = "1.18.2" - Case "23w13a_or_b" - _Version.VanillaName = "23w13a" - Case "24w14potato" - _Version.VanillaName = "24w12a" - Case "25w14craftmine" - _Version.VanillaName = "1.21.5-rc1" - Case "26w14a" - _Version.VanillaName = "26.1.1" - End Select '获取版本号 _Version.VanillaName = _Version.VanillaName.Replace("_unobfuscated", "").Replace(" Unobfuscated", "") - _Version.Vanilla = McVersion.NameToVersion(_Version.VanillaName) Return _Version End Get Set(value As McVersion) @@ -477,12 +460,12 @@ VersionSearchFinish: ''' Public Function GetJsonPath() As String Dim JsonPath As String = PathVersion & Name & ".json" - If Not File.Exists(JsonPath) Then + If Not FileUtils.Exists(JsonPath) Then '尝试寻找 JSON 文件 JsonPath = Nothing - For Each JsonCandidatePath In Directory.GetFiles(PathVersion, "*.json") + For Each JsonCandidatePath In DirectoryUtils.GetFiles(PathVersion, True, "*.json") Try - Dim JsonCandidate As JObject = GetJson(ReadFile(JsonCandidatePath)) + Dim JsonCandidate As JObject = GetJson(FileUtils.ReadAsString(JsonCandidatePath)) If Not JsonCandidate.ContainsKey("mainClass") Then Continue For If Not JsonCandidate.ContainsKey("type") Then Continue For If Not JsonCandidate.ContainsKey("id") Then Continue For @@ -495,7 +478,7 @@ VersionSearchFinish: If JsonPath Is Nothing Then Throw New Exception($"未找到版本 JSON 文件:{PathVersion}{Name}.json") Else - Log("[Minecraft] 未找到同名版本 JSON,自动换用 " & JsonPath, NotifyLevel.DebugModeOnly) + Logger.Warn($"未找到同名版本 JSON,自动换用 {JsonPath}") End If End If Return JsonPath @@ -513,16 +496,16 @@ VersionSearchFinish: End Function If _JsonText Is Nothing Then Dim JsonPath As String = GetJsonPath() - _JsonText = ReadFile(JsonPath) + _JsonText = If(FileUtils.TryReadAsString(JsonPath), "") '如果 ReadFile 失败会返回空字符串;这可能是由于文件被临时占用,故延时后重试 If Not FastJsonCheck(_JsonText) Then If RunInUi() Then - Log("[Minecraft] 版本 JSON 文件为空或有误,由于代码在主线程运行,将不再进行重试", NotifyLevel.DebugModeOnly) + Logger.Warn("版本 JSON 文件为空或有误,由于代码在主线程运行,将不再进行重试") GetJson(_JsonText) '触发异常 Else - Log($"[Minecraft] 版本 JSON 文件为空或有误,将在 2s 后重试读取({JsonPath})", NotifyLevel.DebugModeOnly) + Logger.Warn($"版本 JSON 文件为空或有误,将在 2s 后重试读取({JsonPath})") Thread.Sleep(2000) - _JsonText = ReadFile(JsonPath) + _JsonText = FileUtils.ReadAsString(JsonPath) If Not FastJsonCheck(_JsonText) Then GetJson(_JsonText) '触发异常 End If End If @@ -560,14 +543,14 @@ VersionSearchFinish: Dim Id As String = Subjson("id") If Id IsNot Nothing Then '合并 Json - Log("[Minecraft] 合并 HMCL 分支项:" & Id) + Logger.Info($"合并 HMCL 分支项:{Id}") If CurrentObject IsNot Nothing Then CurrentObject.Merge(Subjson) Else CurrentObject = Subjson End If Else - Log("[Minecraft] 存在为空的 HMCL 分支项") + Logger.Info("存在为空的 HMCL 分支项") End If Next _JsonObject = CurrentObject @@ -580,7 +563,7 @@ VersionSearchFinish: Try InstanceNameInheritFrom = If(_JsonObject("inheritsFrom") Is Nothing, "", _JsonObject("inheritsFrom").ToString) If InstanceNameInheritFrom = Name Then - Log("[Minecraft] 自引用的继承版本:" & Name, NotifyLevel.DebugModeOnly) + Logger.Warn($"自引用的继承版本:{Name}") InstanceNameInheritFrom = "" Exit Try End If @@ -602,7 +585,7 @@ Recheck: GoTo Recheck End If Catch ex As Exception - Log(ex, "合并版本依赖项 JSON 失败(" & If(InstanceNameInheritFrom, "null").ToString & ")") + Logger.Warn(ex, $"合并版本依赖项 JSON 失败({If(InstanceNameInheritFrom, "null")})") End Try Catch ex As Exception Throw New Exception("初始化版本 JSON 时失败(" & If(Name, "null") & ")", ex) @@ -638,8 +621,8 @@ Recheck: If Not JsonVersionInited Then JsonVersionInited = True Try - If Not File.Exists($"{PathVersion}{Name}.jar") Then Exit Try - Using JarArchive As New ZipArchive(New FileStream(PathVersion & Name & ".jar", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + If Not FileUtils.Exists($"{PathVersion}{Name}.jar") Then Exit Try + Using JarArchive = FileUtils.OpenZip(PathVersion & Name & ".jar") Dim VersionJson As ZipArchiveEntry = JarArchive.GetEntry("version.json") If VersionJson Is Nothing Then Exit Try Using VersionJsonStream As New StreamReader(VersionJson.Open) @@ -647,7 +630,7 @@ Recheck: End Using End Using Catch ex As Exception - Log(ex, $"从版本 jar 中读取 version.json 失败({PathVersion}{Name}.jar)") + Logger.Warn(ex, $"从版本 jar 中读取 version.json 失败({PathVersion}{Name}.jar)") End Try End If Return _JsonVersion @@ -676,10 +659,19 @@ Recheck: End Property Private _InheritName As String = Nothing + Public Sub ResetIniCache() + IniClearCache(PathIndie & "options.txt") + IniClearCache(PathVersion & "PCL\Setup.ini") + For Each Entry In Settings.Entries.Values + If Entry.Source = Settings.Sources.Instance Then Entry.ValueCache.Remove(PathVersion) + Next + End Sub + ''' ''' 从版本名,或版本文件夹的完整路径初始化(不规定是否以 \ 结尾)。 ''' Public Sub New(Name As String) + Name = PathUtils.RemoveExtendedPrefix(Name) PathVersion = If(Name.Contains(":"), "", McFolderSelected & "versions\") & '补全完整路径 Name & If(Name.EndsWithF("\"), "", "\") '补全右划线 @@ -691,26 +683,16 @@ Recheck: Public Function Check() As Boolean '检查文件夹 - If Not Directory.Exists(PathVersion) Then + If Not DirectoryUtils.Exists(PathVersion) Then State = McInstanceState.Error Info = "未找到版本 " & Name Return False End If - '检查权限 - Try - DirectoryUtils.Create(PathVersion & "PCL\") - CheckPermissionWithException(PathVersion & "PCL\") - Catch ex As Exception - State = McInstanceState.Error - Info = "PCL 没有对该文件夹的访问权限,请右键以管理员身份运行 PCL" - Log(ex, "没有访问版本文件夹的权限") - Return False - End Try '确认 Json 可用性 Try If JsonObject("mainClass") Is Nothing Then Throw New Exception("版本 JSON 中没有 mainClass 项!") '这里也会触发 JsonObject 的 Get 事件 Catch ex As Exception - Log(ex, "版本 JSON 可用性检查失败(" & PathVersion & ")") + Logger.Warn(ex, $"版本 JSON 可用性检查失败({PathVersion})") JsonText = "" JsonObject = Nothing Info = ex.Message @@ -721,24 +703,24 @@ Recheck: Try If String.IsNullOrEmpty(Version.VanillaName) Then Throw New Exception("无法获取版本号,结果为空") Catch ex As Exception - Log(ex, "版本号获取失败(" & Name & ")") + Logger.Warn(ex, $"版本号获取失败({Name})") State = McInstanceState.Error - Info = "版本号获取失败:" & ex.GetBrief() + Info = "版本号获取失败:" & ex.GetDisplay(False) Return False End Try '检查依赖版本 Try If Not InheritName = "" Then - If Not File.Exists(GetPathFromFullPath(PathVersion) & InheritName & "\" & InheritName & ".json") Then + If Not FileUtils.Exists($"{PathUtils.RemoveLastPart(PathVersion)}\{InheritName}\{InheritName}.json") Then State = McInstanceState.Error Info = "需要安装 " & InheritName & " 作为前置版本" Return False End If End If Catch ex As Exception - Log(ex, "依赖版本检查出错(" & Name & ")") + Logger.Warn(ex, $"依赖版本检查出错({Name})") State = McInstanceState.Error - Info = "未知错误:" & ex.GetBrief() + Info = "未知错误:" & ex.GetDisplay(False) Return False End Try @@ -773,8 +755,7 @@ Recheck: 'OptiFine If RealJson.Contains("optifine") Then State = McInstanceState.OptiFine - Version.HasOptiFine = True - Version.OptiFine = If(RegexSeek(RealJson, "(?<=HD_U_)[^"":/]+"), "未知版本") + Version.OptiFine = If(RealJson.RegexSeek("(?<=HD_U_)[^"":/]+"), "未知版本") End If 'LiteLoader If RealJson.Contains("liteloader") Then @@ -784,20 +765,17 @@ Recheck: 'Fabric、Forge If RealJson.Contains("net.fabricmc:fabric-loader") OrElse RealJson.Contains("org.quiltmc:quilt-loader") Then State = McInstanceState.Fabric - Version.HasFabric = True - Version.Fabric = If(RegexSeek(RealJson, "(?<=(net.fabricmc:fabric-loader:)|(org.quiltmc:quilt-loader:))[0-9\.]+(\+build.[0-9]+)?"), "未知版本").Replace("+build", "") + Version.Fabric = If(RealJson.RegexSeek("(?<=(net.fabricmc:fabric-loader:)|(org.quiltmc:quilt-loader:))[0-9\.]+(\+build.[0-9]+)?"), "未知版本").Replace("+build", "") ElseIf RealJson.Contains("minecraftforge") AndAlso Not RealJson.Contains("net.neoforge") Then State = McInstanceState.Forge - Version.HasForge = True - Version.Forge = RegexSeek(RealJson, "(?<=forge:[0-9\.]+(_pre[0-9]*)?\-)[0-9\.]+") - If Version.Forge Is Nothing Then Version.Forge = RegexSeek(RealJson, "(?<=net\.minecraftforge:minecraftforge:)[0-9\.]+") - If Version.Forge Is Nothing Then Version.Forge = If(RegexSeek(RealJson, "(?<=net\.minecraftforge:fmlloader:[0-9\.]+-)[0-9\.]+"), "未知版本") + Version.Forge = RealJson.RegexSeek("(?<=forge:[0-9\.]+(_pre[0-9]*)?\-)[0-9\.]+") + If Version.Forge Is Nothing Then Version.Forge = RealJson.RegexSeek("(?<=net\.minecraftforge:minecraftforge:)[0-9\.]+") + If Version.Forge Is Nothing Then Version.Forge = If(RealJson.RegexSeek("(?<=net\.minecraftforge:fmlloader:[0-9\.]+-)[0-9\.]+"), "未知版本") ElseIf RealJson.Contains("net.neoforge") Then '1.20.1 JSON 范例:"--fml.forgeVersion", "47.1.99" '1.20.2+ JSON 范例:"--fml.neoForgeVersion", "20.6.119-beta" State = McInstanceState.NeoForge - Version.HasNeoForge = True - Version.NeoForge = If(RegexSeek(RealJson, "(?<=orgeVersion"",[^""]*?"")[^""]+(?="",)"), "未知版本") + Version.NeoForge = If(RealJson.RegexSeek("(?<=orgeVersion"",[^""]*?"")[^""]+(?="",)"), "未知版本") End If End Select #End Region @@ -837,8 +815,8 @@ ExitDataLoad: If State = McInstanceState.Fool Then Info = GetMcFoolName(Version.VanillaName) ElseIf State <> McInstanceState.Error Then - If Settings.Get("VersionServerLogin", Instance:=Me) = 3 Then Info += ", 统一通行证验证" - If Settings.Get("VersionServerLogin", Instance:=Me) = 4 Then Info += ", Authlib 验证" + If Settings.Get(Of Integer)("VersionServerLogin", Instance:=Me) = 3 Then Info += ", 统一通行证验证" + If Settings.Get(Of Integer)("VersionServerLogin", Instance:=Me) = 4 Then Info += ", Authlib 验证" End If End If '确定版本收藏状态 @@ -846,7 +824,7 @@ ExitDataLoad: '确定版本显示种类 DisplayType = ReadIni(PathVersion & "PCL\Setup.ini", "DisplayType", McInstanceCardType.Auto) '写入缓存 - If Directory.Exists(PathVersion) Then + If DirectoryUtils.Exists(PathVersion) Then WriteIni(PathVersion & "PCL\Setup.ini", "State", State) WriteIni(PathVersion & "PCL\Setup.ini", "Info", Info) WriteIni(PathVersion & "PCL\Setup.ini", "Logo", Logo) @@ -862,19 +840,20 @@ ExitDataLoad: WriteIni(PathVersion & "PCL\Setup.ini", "VersionVanilla", Version.Vanilla.ToString) End If Catch ex As Exception - Info = "未知错误:" & ex.GetBrief() + Info = ex.GetDisplay(False) Logo = PathImage & "Blocks/RedstoneBlock.png" State = McInstanceState.Error - Log(ex, "加载版本失败(" & Name & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Warn(ex, $"加载版本失败({Name})") Finally IsLoaded = True End Try Return Me End Function Private Function IsSnapshot() As Boolean + Dim jsonType As String = If(JsonObject("type"), "").ToString Return {"w", "snapshot", "rc", "pre", "experimental", "-"}.Any(Function(s) Version.VanillaName.ContainsIgnoreCase(s)) OrElse Name.ContainsIgnoreCase("combat") OrElse - If(JsonObject("type"), "").ToString = "snapshot" OrElse If(JsonObject("type"), "").ToString = "pending" + jsonType = "snapshot" OrElse jsonType = "pending" OrElse jsonType = "fool" End Function Public IsLoaded As Boolean = False @@ -940,7 +919,7 @@ ExitDataLoad: NewItem.Logo = Logo End If Catch ex As Exception - Log(ex, "加载版本图标失败", NotifyLevel.AllUsers) + Logger.Error(ex, "加载版本图标失败", LogBehavior.Toast) NewItem.Logo = "pack://application:,,,/images/Blocks/RedstoneBlock.png" End Try Return NewItem @@ -985,7 +964,17 @@ ExitDataLoad: ''' 原版版本名。 ''' 如 26.1,26.1-snapshot-1,1.12.2,16w01a。 ''' - Public VanillaName As String + Public Property VanillaName As String + Get + Return _VanillaName + End Get + Set(value As String) + If _VanillaName = value Then Return + _VanillaName = value + Vanilla = NameToVersion(_VanillaName) + End Set + End Property + Private _VanillaName As String ''' ''' 可比较的三段式原版版本号。 ''' 对老版本格式,例如 1.20.1,会被转换为 20.0.1。 @@ -1020,22 +1009,26 @@ ExitDataLoad: ''' ''' 该版本是否通过 JSON 安装了 OptiFine。 ''' - Public HasOptiFine As Boolean = False + Public ReadOnly Property HasOptiFine As Boolean + Get + Return OptiFine IsNot Nothing + End Get + End Property ''' ''' OptiFine 版本名,如 C8、C9_pre10。 ''' - Public OptiFine As String = "" + Public OptiFine As String = Nothing ''' ''' 可供比较的 OptiFine 版本序数。 ''' Public ReadOnly Property OptiFineCode As Integer Get - If String.IsNullOrEmpty(OptiFine) OrElse OptiFine = "未知版本" Then Return 0 + If OptiFine Is Nothing OrElse OptiFine = "未知版本" Then Return 0 '字母编号,如 G2 中的 G(7) Dim Result As Integer = Asc(OptiFine.Upper.First) - Asc("A"c) + 1 '末尾数字,如 C5 beta4 中的 5 Result *= 100 - Result += Val(RegexSeek(Right(OptiFine, OptiFine.Length - 1), "[0-9]+")) + Result += Val(Right(OptiFine, OptiFine.Length - 1).RegexSeek("[0-9]+")) '测试标记(正式版为 99,Pre[x] 为 50+x,Beta[x] 为 x) Result *= 100 If OptiFine.ContainsIgnoreCase("pre") Then Result += 50 @@ -1043,7 +1036,7 @@ ExitDataLoad: If Val(Right(OptiFine, 1)) = 0 AndAlso Right(OptiFine, 1) <> "0" Then Result += 1 '为 pre 或 beta 结尾,视作 1 Else - Result += Val(RegexSeek(OptiFine.Lower, "(?<=((pre)|(beta)))[0-9]+")) + Result += Val(OptiFine.Lower.RegexSeek("(?<=((pre)|(beta)))[0-9]+")) End If Else Result += 99 @@ -1057,11 +1050,19 @@ ExitDataLoad: ''' ''' 该版本是否安装了 Forge。 ''' - Public HasForge As Boolean = False + Public ReadOnly Property HasForge As Boolean + Get + Return Forge IsNot Nothing + End Get + End Property ''' ''' 该版本是否安装了 NeoForge。 ''' - Public HasNeoForge As Boolean = False + Public ReadOnly Property HasNeoForge As Boolean + Get + Return NeoForge IsNot Nothing + End Get + End Property ''' ''' 该版本是否安装了 Forge 或 NeoForge。 ''' @@ -1073,20 +1074,20 @@ ExitDataLoad: ''' ''' Forge 版本名,如 31.1.2、14.23.5.2847。 ''' - Public Forge As String = "" + Public Forge As String = Nothing ''' ''' NeoForge 版本名,如 47.1.79、21.0.2-beta、26.1.0.0-alpha.14+snapshot-11。 ''' - Public NeoForge As String = "" + Public NeoForge As String = Nothing ''' ''' 可供比较的类 Forge 版本序数。 ''' Public ReadOnly Property ForgelikeCode As Integer Get If Not HasForgelike Then Return 0 - If (String.IsNullOrEmpty(Forge) OrElse Forge = "未知版本") AndAlso - (String.IsNullOrEmpty(NeoForge) OrElse NeoForge = "未知版本") Then Return 0 - Dim Segments = RegexSearch(If(HasForge, Forge, NeoForge), "\d+") + If (Forge Is Nothing OrElse Forge = "未知版本") AndAlso + (NeoForge Is Nothing OrElse NeoForge = "未知版本") Then Return 0 + Dim Segments = If(HasForge, Forge, NeoForge).RegexSearch("\d+").ToList Select Case Segments.Count Case Is > 4 Return Val(Segments(0)) * 1000000 + Val(Segments(1)) * 10000 + Val(Segments(3)) @@ -1105,11 +1106,15 @@ ExitDataLoad: ''' ''' 该版本是否安装了 Fabric。 ''' - Public HasFabric As Boolean = False + Public ReadOnly Property HasFabric As Boolean + Get + Return Fabric IsNot Nothing + End Get + End Property ''' ''' Fabric 版本名,如 0.7.2.175。 ''' - Public Fabric As String = "" + Public Fabric As String = Nothing 'LiteLoader @@ -1120,13 +1125,26 @@ ExitDataLoad: 'Helpers + ''' + ''' 获取该版本包含的 Mod Loader。 + ''' + Public ReadOnly Property ModLoaders As ModLoaders + Get + Dim Result As ModLoaders = ModLoaders.None + If HasForge Then Result = Result Or ModLoaders.Forge + If HasNeoForge Then Result = Result Or ModLoaders.NeoForge + If HasFabric Then Result = Result Or ModLoaders.Fabric + If HasLiteLoader Then Result = Result Or ModLoaders.LiteLoader + Return Result + End Get + End Property ''' ''' 版本字符串是否符合 Minecraft 原版格式,例如 1.x、26.x。 ''' Public Shared Function IsFormatFit(Version As String) As Boolean If Version Is Nothing Then Return False - If RegexCheck(Version, "^1\.\d") Then Return True - If Val(RegexSeek(Version, "^[2-9]\d\.\d+")) >= 26 Then Return True + If Version.RegexCheck("^1\.\d") Then Return True + If Val(Version.RegexSeek("^[2-9]\d\.\d+")) >= 26 Then Return True Return False End Function ''' @@ -1146,7 +1164,7 @@ ExitDataLoad: If Drop >= 250 Then Return $"{Drop \ 10}.{Drop Mod 10}" ElseIf Drop = 209 Then - Log("[Minecraft] 尝试将旧快照版 Drop 序数转换为版本字符串,这不应该发生!" & vbCrLf & GetStackTrace(), NotifyLevel.DebugModeOnly) + Logger.Warn(New Exception("尝试将旧快照版 Drop 序数转换为版本字符串,这不应该发生!")) Return "1.20" Else Return $"1.{Drop \ 10}" @@ -1155,18 +1173,31 @@ ExitDataLoad: ''' ''' 将版本名转换为可比较的三段式原版版本号。 ''' 对老版本格式,例如 1.20.3,会被转换为 20.0.3。 + ''' 对愚人节版本,返回其基于的正式版版本号。 ''' 若没有版本号,例如旧快照,则为 9999.0.0。 ''' - Public Shared Function NameToVersion(VanillaName As String) As Version - VanillaName = VanillaName.Replace("_unobfuscated", "").Replace(" Unobfuscated", "") - If VanillaName.StartsWithF("1.") Then - Dim Segments = VanillaName.Split(" _-.".ToCharArray) + Public Shared Function NameToVersion(Name As String) As Version + Name = Name.Lower.Replace("_unobfuscated", "").Replace(" Unobfuscated", "") + '愚人节版本 + If Name.StartsWithF("2.0") Then Return NameToVersion("1.5.1") + If Name = "15w14a" Then Return NameToVersion("1.8.3") + If Name.Contains(".rv-pre") Then Return NameToVersion("1.9.2") + If Name.Contains("shareware") Then Return NameToVersion("1.13.2") + If Name.StartsWithF("20w14") AndAlso Name <> "20w14a" Then Return NameToVersion("1.15.2") + If Name.Contains("oneblockatatime") Then Return NameToVersion("1.18.2") + If Name.Contains("23w13a") AndAlso Name <> "20w13a" Then Return NameToVersion("1.19.4") + If Name = "24w14potato" Then Return NameToVersion("1.20.4") + If Name = "25w14craftmine" Then Return NameToVersion("1.21.4") + If Name = "26w14a" Then Return NameToVersion("26.1.1") + '其余版本 + If Name.StartsWithF("1.") Then + Dim Segments = Name.Split(" _-.".ToCharArray) Return New Version( Val(If(Segments.Count >= 2, Segments(1), "0")), 0, Val(If(Segments.Count >= 3, Segments(2), "0"))) - ElseIf RegexCheck(VanillaName, "^[2-9][0-9]\.") Then - Dim Segments = VanillaName.Split(" _-.".ToCharArray) + ElseIf Name.RegexCheck("^[2-9][0-9]\.") Then + Dim Segments = Name.Split(" _-.".ToCharArray) Return New Version( Val(Segments(0)), Val(If(Segments.Count >= 2, Segments(1), "0")), @@ -1240,9 +1271,9 @@ ExitDataLoad: '检测缓存是否需要更新 Dim FolderList As New List(Of String) - If Directory.Exists(PathMc & "versions") Then '不要使用 CheckPermission,会导致写入时间改变,从而使得文件夹被强制刷新 + If DirectoryUtils.Exists(PathMc & "versions") Then '不要使用 CheckPermission,会导致写入时间改变,从而使得文件夹被强制刷新 Try - For Each Folder As DirectoryInfo In New DirectoryInfo(PathMc & "versions").GetDirectories + For Each Folder As DirectoryInfo In DirectoryUtils.GetInfo(PathMc & "versions").GetDirectories FolderList.Add(Folder.Name) Next Catch ex As Exception @@ -1255,7 +1286,7 @@ ExitDataLoad: GoTo OnLoaded End If '有可用版本 - Dim FolderListCheck As Integer = GetHash(McInstanceCacheVersion & "#" & FolderList.Join("#"c)) Mod (Integer.MaxValue - 1) '根据文件夹名列表生成辨识码 + Dim FolderListCheck As Integer = GetHash(Versions.MCINSTANCE_CACHE_VERSION & "#" & FolderList.Join("#"c)) Mod (Integer.MaxValue - 1) '根据文件夹名列表生成辨识码 If Not McInstanceListForceRefresh AndAlso Val(ReadIni(PathMc & "PCL.ini", "InstanceCache")) = FolderListCheck Then '可以使用缓存 Dim Result = InitMcInstanceListWithCache(PathMc) @@ -1268,7 +1299,7 @@ ExitDataLoad: '文件夹列表不符 Reload: McInstanceListForceRefresh = False - Log("[Minecraft] 文件夹列表变更,重载所有版本") + Logger.Info("文件夹列表变更,重载所有版本") WriteIni(PathMc & "PCL.ini", "InstanceCache", FolderListCheck) McInstanceList = InitMcInstanceListWithoutCache(PathMc) End If @@ -1286,7 +1317,7 @@ OnLoaded: If Instance.Name = SavedSelection AndAlso Not Instance.State = McInstanceState.Error Then '使用已储存的选择 McInstanceSelected = Instance - Log("[Minecraft] 选择该文件夹储存的 Minecraft 版本:" & McInstanceSelected.PathVersion) + Logger.Info($"选择该文件夹储存的 Minecraft 版本:{McInstanceSelected.PathVersion}") Return End If Next @@ -1295,18 +1326,18 @@ OnLoaded: If Not McInstanceList.First.Value(0).State = McInstanceState.Error Then '自动选择第一项 McInstanceSelected = McInstanceList.First.Value(0) - Log("[Launch] 自动选择 Minecraft 版本:" & McInstanceSelected.PathVersion) + Logger.Info($"自动选择 Minecraft 版本:{McInstanceSelected.PathVersion}") End If Else McInstanceSelected = Nothing - Log("[Minecraft] 未找到可用 Minecraft 版本") + Logger.Info("未找到可用 Minecraft 版本") End If - If Settings.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(200, 3000)) + If Settings.Get(Of Boolean)("SystemDebugDelay") Then Thread.Sleep(RandomInteger(200, 3000)) Catch ex As ThreadInterruptedException Catch ex As Exception If Loader.IsInterrupted Then Return '#5617 WriteIni(PathMc & "PCL.ini", "InstanceCache", "") '要求下次重新加载 - Log(ex, "加载 .minecraft 版本列表失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "加载 .minecraft 版本列表失败") End Try End Sub @@ -1324,12 +1355,12 @@ OnLoaded: For Each VersionName As String In ReadIni(Folder & "PCL.ini", "CardValue" & (i + 1), ":").Split(":") If VersionName = "" Then Continue For Dim FolderVersions As String = $"{Folder}versions\{VersionName}\" - If File.Exists(FolderVersions & ".pclignore") Then + If FileUtils.Exists(FolderVersions & ".pclignore") Then If IsFirstMcInstanceListLoad Then - Log("[Minecraft] 清理残留的忽略项目:" & FolderVersions) '#2781 - File.Delete(FolderVersions & ".pclignore") + Logger.Info($"清理残留的忽略项目:{FolderVersions}") '#2781 + FileUtils.Delete(FolderVersions & ".pclignore") Else - Log("[Minecraft] 跳过要求忽略的项目:" & FolderVersions) + Logger.Info($"跳过要求忽略的项目:{FolderVersions}") Continue For End If End If @@ -1349,18 +1380,13 @@ OnLoaded: ReadIni(Instance.PathVersion & "PCL\Setup.ini", "VersionVanillaName", "Unknown") <> "Unknown" Then '读取版本信息 Dim VersionInfo As New McVersion With { - .Fabric = ReadIni(Instance.PathVersion & "PCL\Setup.ini", "VersionFabric", ""), - .Forge = ReadIni(Instance.PathVersion & "PCL\Setup.ini", "VersionForge", ""), - .NeoForge = ReadIni(Instance.PathVersion & "PCL\Setup.ini", "VersionNeoForge", ""), - .OptiFine = ReadIni(Instance.PathVersion & "PCL\Setup.ini", "VersionOptiFine", ""), + .Fabric = ReadIni(Instance.PathVersion & "PCL\Setup.ini", "VersionFabric", Nothing), + .Forge = ReadIni(Instance.PathVersion & "PCL\Setup.ini", "VersionForge", Nothing), + .NeoForge = ReadIni(Instance.PathVersion & "PCL\Setup.ini", "VersionNeoForge", Nothing), + .OptiFine = ReadIni(Instance.PathVersion & "PCL\Setup.ini", "VersionOptiFine", Nothing), .HasLiteLoader = ReadIni(Instance.PathVersion & "PCL\Setup.ini", "VersionLiteLoader", False), - .VanillaName = ReadIni(Instance.PathVersion & "PCL\Setup.ini", "VersionVanillaName", "Unknown"), - .Vanilla = New Version(ReadIni(Instance.PathVersion & "PCL\Setup.ini", "VersionVanilla", "0.0.0")) + .VanillaName = ReadIni(Instance.PathVersion & "PCL\Setup.ini", "VersionVanillaName", "Unknown") } - VersionInfo.HasFabric = VersionInfo.Fabric.Any() - VersionInfo.HasForge = VersionInfo.Forge.Any() - VersionInfo.HasNeoForge = VersionInfo.NeoForge.Any() - VersionInfo.HasOptiFine = VersionInfo.OptiFine.Any() Instance.Version = VersionInfo Else Instance.Load() @@ -1375,19 +1401,19 @@ OnLoaded: '校验错误原因是否改变 Dim CustomInfo As String = ReadIni(Instance.PathVersion & "PCL\Setup.ini", "CustomInfo") If Instance.State = McInstanceState.Original OrElse (CustomInfo = "" AndAlso Not OldDesc = Instance.Info) Then - Log("[Minecraft] 版本 " & Instance.Name & " 的错误状态已变更,新的状态为:" & Instance.Info) + Logger.Info($"版本 {Instance.Name} 的错误状态已变更,新的状态为:{Instance.Info}") Return Nothing End If End If '校验未加载的版本 If Instance.Logo = "" Then - Log("[Minecraft] 版本 " & Instance.Name & " 未被加载") + Logger.Info($"版本 {Instance.Name} 未被加载") Return Nothing End If Catch ex As Exception - Log(ex, "读取版本加载缓存失败(" & VersionName & ")", NotifyLevel.DebugModeOnly) + Logger.Warn(ex, $"读取版本加载缓存失败({VersionName})") Return Nothing End Try Next @@ -1396,7 +1422,7 @@ OnLoaded: Next Return Results Catch ex As Exception - Log(ex, "读取版本缓存失败") + Logger.Warn(ex, "读取版本缓存失败") Return Nothing End Try End Function @@ -1404,23 +1430,23 @@ OnLoaded: Dim InstanceList As New List(Of McInstance) #Region "循环加载每个版本的信息" - For Each VersionFolderInfo As DirectoryInfo In New DirectoryInfo(Folder & "versions").GetDirectories + For Each VersionFolderInfo As DirectoryInfo In DirectoryUtils.GetInfo(Folder & "versions").GetDirectories If Not VersionFolderInfo.Exists OrElse Not VersionFolderInfo.EnumerateFiles.Any Then - Log("[Minecraft] 跳过空文件夹:" & VersionFolderInfo.FullName) + Logger.Info($"跳过空文件夹:{VersionFolderInfo.FullName}") Continue For End If If (VersionFolderInfo.Name = "cache" OrElse VersionFolderInfo.Name = "BLClient" OrElse VersionFolderInfo.Name = "PCL") AndAlso - Not File.Exists(VersionFolderInfo.FullName & "\" & VersionFolderInfo.Name & ".json") Then - Log("[Minecraft] 跳过可能不是版本文件夹的项目:" & VersionFolderInfo.FullName) + Not FileUtils.Exists(VersionFolderInfo.FullName & "\" & VersionFolderInfo.Name & ".json") Then + Logger.Info($"跳过可能不是版本文件夹的项目:{VersionFolderInfo.FullName}") Continue For End If Dim VersionFolder As String = VersionFolderInfo.FullName & "\" - If File.Exists(VersionFolder & ".pclignore") Then + If FileUtils.Exists(VersionFolder & ".pclignore") Then If IsFirstMcInstanceListLoad Then - Log("[Minecraft] 清理残留的忽略项目:" & VersionFolder) '#2781 - File.Delete(VersionFolder & ".pclignore") + Logger.Info($"清理残留的忽略项目:{VersionFolder}") '#2781 + FileUtils.Delete(VersionFolder & ".pclignore") Else - Log("[Minecraft] 跳过要求忽略的项目:" & VersionFolder) + Logger.Info($"跳过要求忽略的项目:{VersionFolder}") Continue For End If End If @@ -1530,7 +1556,7 @@ OnLoaded: Catch ex As Exception Results.Clear() - Log(ex, "分类版本列表失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "分类版本列表失败") End Try #End Region #Region "对卡片与版本进行排序" @@ -1634,23 +1660,23 @@ OnLoaded: ''' 要求玩家选择一个皮肤文件,并进行相关校验。 ''' Public Function McSkinSelect() As McSkinInfo - Dim FileName As String = SelectFile("皮肤文件(*.png;*.jpg;*.jpeg;*.webp)|*.png;*.jpg;*.jpeg;*.webp", "选择皮肤文件") + Dim FileName As String = Dialogs.SelectFile("选择皮肤文件", False, filter:={({"png", "jpg", "jpeg", "webp"}, "皮肤文件")}).FirstOrDefault() '验证有效性 - If FileName = "" Then Return New McSkinInfo With {.IsVaild = False} + If String.IsNullOrEmpty(FileName) Then Return New McSkinInfo With {.IsVaild = False} Try Dim Image As New MyBitmap(FileName) If Image.Pic.Width <> 64 OrElse Not (Image.Pic.Height = 32 OrElse Image.Pic.Height = 64) Then Hint("皮肤图片大小应为 64x32 像素或 64x64 像素!", HintType.Red) Return New McSkinInfo With {.IsVaild = False} End If - Dim FileInfo As New FileInfo(FileName) + Dim FileInfo = FileUtils.GetInfo(FileName) If FileInfo.Length > 24 * 1024 Then Hint("皮肤文件大小需小于 24 KB,而所选文件大小为 " & Math.Round(FileInfo.Length / 1024, 2) & " KB", HintType.Red) Return New McSkinInfo With {.IsVaild = False} End If Catch ex As Exception - Log(ex, "皮肤文件存在错误", NotifyLevel.AllUsers) + Logger.Error(ex, "皮肤文件存在错误", LogBehavior.Toast) Return New McSkinInfo With {.IsVaild = False} End Try @@ -1679,9 +1705,9 @@ OnLoaded: Case "Mojang", "Ms" Url = "https://sessionserver.mojang.com/session/minecraft/profile/" Case "Nide" - Url = "https://auth.mc-user.com:233/" & If(McInstanceSelected Is Nothing, Settings.Get("CacheNideServer"), Settings.Get("VersionServerNide", Instance:=McInstanceSelected)) & "/sessionserver/session/minecraft/profile/" + Url = "https://auth.mc-user.com:233/" & If(McInstanceSelected Is Nothing, Settings.Get(Of String)("CacheNideServer"), Settings.Get(Of String)("VersionServerNide", Instance:=McInstanceSelected)) & "/sessionserver/session/minecraft/profile/" Case "Auth" - Url = If(McInstanceSelected Is Nothing, Settings.Get("CacheAuthServerServer"), Settings.Get("VersionServerAuthServer", Instance:=McInstanceSelected)) & "/sessionserver/session/minecraft/profile/" + Url = If(McInstanceSelected Is Nothing, Settings.Get(Of String)("CacheAuthServerServer"), Settings.Get(Of String)("VersionServerAuthServer", Instance:=McInstanceSelected)) & "/sessionserver/session/minecraft/profile/" Case Else Throw New ArgumentException("皮肤地址种类无效:" & If(Type, "null")) End Select @@ -1698,10 +1724,10 @@ OnLoaded: Next Throw New Exception("未从皮肤返回值中找到符合条件的 Property") Catch ex As Exception - Log(ex, "无法完成解析的皮肤返回值,可能是未设置自定义皮肤的用户:" & SkinString, NotifyLevel.DevelopOnly) + Logger.Warn(ex, $"无法完成解析的皮肤返回值,可能是未设置自定义皮肤的用户:{SkinString}") Throw New Exception("皮肤返回值中不包含皮肤数据项,可能是未设置自定义皮肤的用户", ex) End Try - SkinString = Encoding.GetEncoding("utf-8").GetString(Convert.FromBase64String(SkinValue)) + SkinString = Encoding.UTF8.GetString(Convert.FromBase64String(SkinValue)) Dim SkinJson As JObject = GetJson(SkinString.Lower) If SkinJson("textures") Is Nothing OrElse SkinJson("textures")("skin") Is Nothing OrElse SkinJson("textures")("skin")("url") Is Nothing Then Throw New Exception("用户未设置自定义皮肤") @@ -1711,23 +1737,23 @@ OnLoaded: End If '保存缓存 WriteIni(PathTemp & "Cache\Skin\Index" & Type & ".ini", UUID, SkinValue) - Log("[Skin] UUID " & UUID & " 对应的皮肤文件为 " & SkinValue) + Logger.Info($"UUID {UUID} 对应的皮肤文件为 {SkinValue}") Return SkinValue End Function Private ReadOnly McSkinDownloadLock As New Object ''' - ''' 从 Url 下载皮肤。返回本地文件路径,失败将抛出异常。 + ''' 从 Url 下载皮肤,可能会使用缓存。返回本地文件路径,失败将抛出异常。 ''' Public Function McSkinDownload(Address As String) As String - Dim SkinName As String = GetFileNameFromPath(Address) + Dim SkinName As String = PathUtils.GetLastPart(Address) Dim FileAddress As String = PathTemp & "Cache\Skin\" & GetHash(Address) & ".png" SyncLock McSkinDownloadLock - If Not File.Exists(FileAddress) Then + If Not FileUtils.Exists(FileAddress) Then NetDownloadByClient(Address, FileAddress & ".PCLDownloading") - File.Delete(FileAddress) - File.Move(FileAddress & ".PCLDownloading", FileAddress) - Log("[Minecraft] 皮肤下载成功:" & FileAddress) + FileUtils.Delete(FileAddress) + FileUtils.Move(FileAddress & ".PCLDownloading", FileAddress) + Logger.Info($"皮肤下载成功:{FileAddress}") End If Return FileAddress End SyncLock @@ -1762,7 +1788,7 @@ OnLoaded: #Region "支持库文件(Library)" - Public Class McLibToken + Public Class McLibEntry ''' ''' 文件的完整本地路径。 ''' @@ -1832,8 +1858,7 @@ OnLoaded: If OsName = "unknown" Then ElseIf OsName = "windows" Then If Rule("os")("version") IsNot Nothing Then '操作系统版本 - Dim Cr As String = Rule("os")("version").ToString - IsRightRule = IsRightRule AndAlso RegexCheck(OSVersion, Cr) + IsRightRule = IsRightRule AndAlso OSVersion.RegexCheck(Rule("os")("version").ToString) End If Else IsRightRule = False @@ -1865,10 +1890,10 @@ OnLoaded: ''' ''' 递归获取 Minecraft 某一版本的完整支持库列表。 ''' - Public Function McLibListGet(Instance As McInstance, IncludeMainJar As Boolean) As List(Of McLibToken) + Public Function McLibListGet(Instance As McInstance, IncludeMainJar As Boolean) As List(Of McLibEntry) '获取当前支持库列表 - Log("[Minecraft] 获取支持库列表:" & Instance.Name) + Logger.Info($"获取支持库列表:{Instance.Name}") Dim Result = McLibListGetWithJson(Instance.JsonObject) '需要添加原版 Jar @@ -1896,9 +1921,9 @@ OnLoaded: Dim ClientUrl As String, ClientSHA1 As String '判断需求的版本是否存在 '不能调用 RealVersion.Check(),可能会莫名其妙地触发 CheckPermission 正被另一进程使用,导致误判前置不存在 - If Not File.Exists(RealInstance.PathVersion & RealInstance.Name & ".json") Then + If Not FileUtils.Exists(RealInstance.PathVersion & RealInstance.Name & ".json") Then RealInstance = Instance - Log("[Minecraft] 可能缺少前置版本 " & RealInstance.Name & ",找不到对应的 json 文件", NotifyLevel.DebugModeOnly) + Logger.Warn($"可能缺少前置版本 {RealInstance.Name},找不到对应的 json 文件") End If '获取详细下载信息 If RealInstance.JsonObject("downloads") IsNot Nothing AndAlso RealInstance.JsonObject("downloads")("client") IsNot Nothing Then @@ -1909,7 +1934,7 @@ OnLoaded: ClientSHA1 = Nothing End If '把所需的原版 Jar 添加进去 - Result.Add(New McLibToken With {.LocalPath = RealInstance.PathVersion & RealInstance.Name & ".jar", .Size = 0, .IsNatives = False, .Url = ClientUrl, .SHA1 = ClientSHA1}) + Result.Add(New McLibEntry With {.LocalPath = RealInstance.PathVersion & RealInstance.Name & ".jar", .Size = 0, .IsNatives = False, .Url = ClientUrl, .SHA1 = ClientSHA1}) End If Return Result @@ -1917,11 +1942,11 @@ OnLoaded: ''' ''' 获取 Minecraft 某一版本忽视继承的支持库列表,即结果中没有继承项。 ''' - Public Function McLibListGetWithJson(JsonObject As JObject, Optional KeepSameNameDifferentVersionResult As Boolean = False, Optional CustomMcFolder As String = Nothing) As List(Of McLibToken) + Public Function McLibListGetWithJson(JsonObject As JObject, Optional KeepSameNameDifferentVersionResult As Boolean = False, Optional CustomMcFolder As String = Nothing) As List(Of McLibEntry) CustomMcFolder = If(CustomMcFolder, McFolderSelected) '转换为 LibToken - Dim BasicArray As New List(Of McLibToken) + Dim BasicArray As New List(Of McLibEntry) For Each Library As JObject In CType(JsonObject("libraries"), JArray).Children '清理 null 项(BakaXL 会把没有的项序列化为 null,但会被 Newtonsoft 转换为 JValue,导致 Is Nothing = false;这导致了 #409) @@ -1944,7 +1969,7 @@ OnLoaded: LocalPath = McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder) Try If Library("downloads") IsNot Nothing AndAlso Library("downloads")("artifact") IsNot Nothing Then - BasicArray.Add(New McLibToken With { + BasicArray.Add(New McLibEntry With { .OriginalName = Library("name"), .Url = If(Library("downloads")("artifact")("url"), RootUrl), .LocalPath = If(Library("downloads")("artifact")("path") Is Nothing, McLibGet(Library("name"), @@ -1953,18 +1978,18 @@ OnLoaded: .IsNatives = False, .SHA1 = Library("downloads")("artifact")("sha1")?.ToString}) Else - BasicArray.Add(New McLibToken With {.OriginalName = Library("name"), .Url = RootUrl, .LocalPath = LocalPath, .Size = 0, .IsNatives = False, .SHA1 = Nothing}) + BasicArray.Add(New McLibEntry With {.OriginalName = Library("name"), .Url = RootUrl, .LocalPath = LocalPath, .Size = 0, .IsNatives = False, .SHA1 = Nothing}) End If Catch ex As Exception - Log(ex, "处理实际支持库列表失败(无 Natives," & If(Library("name"), "Nothing").ToString & ")") - BasicArray.Add(New McLibToken With {.OriginalName = Library("name"), .Url = RootUrl, .LocalPath = LocalPath, .Size = 0, .IsNatives = False, .SHA1 = Nothing}) + Logger.Warn(ex, $"处理实际支持库列表失败(无 Natives,{If(Library("name"), "Nothing")})") + BasicArray.Add(New McLibEntry With {.OriginalName = Library("name"), .Url = RootUrl, .LocalPath = LocalPath, .Size = 0, .IsNatives = False, .SHA1 = Nothing}) End Try ElseIf Library("natives")("windows") IsNot Nothing Then '有 Windows Natives Dim NativeName As String = Library("natives")("windows") Try If Library("downloads") IsNot Nothing AndAlso Library("downloads")("classifiers") IsNot Nothing AndAlso Library("downloads")("classifiers")(NativeName) IsNot Nothing Then Dim NativeData = Library("downloads")("classifiers")(NativeName) - BasicArray.Add(New McLibToken With { + BasicArray.Add(New McLibEntry With { .OriginalName = Library("name"), .Url = If(NativeData("url"), RootUrl), .LocalPath = If(NativeData("path") Is Nothing, @@ -1977,16 +2002,16 @@ OnLoaded: .SHA1 = NativeData("sha1").ToString}) Else BasicArray.Add( - New McLibToken With {.OriginalName = Library("name"), .Url = RootUrl, .Size = 0, .IsNatives = True, .SHA1 = Nothing, + New McLibEntry With {.OriginalName = Library("name"), .Url = RootUrl, .Size = 0, .IsNatives = True, .SHA1 = Nothing, .LocalPath = McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder). Replace(".jar", $"-{NativeName}.jar"). Replace("${arch}", If(Environment.Is64BitOperatingSystem, "64", "32")) }) End If Catch ex As Exception - Log(ex, "处理实际支持库列表失败(有 Natives," & If(Library("name"), "Nothing").ToString & ")") + Logger.Warn(ex, $"处理实际支持库列表失败(有 Natives,{If(Library("name"), "Nothing")})") BasicArray.Add( - New McLibToken With {.OriginalName = Library("name"), .Url = RootUrl, .Size = 0, .IsNatives = True, .SHA1 = Nothing, + New McLibEntry With {.OriginalName = Library("name"), .Url = RootUrl, .Size = 0, .IsNatives = True, .SHA1 = Nothing, .LocalPath = McLibGet(Library("name"), CustomMcFolder:=CustomMcFolder). Replace(".jar", $"-{NativeName}.jar"). Replace("${arch}", If(Environment.Is64BitOperatingSystem, "64", "32")) @@ -1997,14 +2022,14 @@ OnLoaded: Next '去重 - Dim ResultArray As New Dictionary(Of String, McLibToken) + Dim ResultArray As New Dictionary(Of String, McLibEntry) Dim GetVersion = - Function(Token As McLibToken) As String + Function(Token As McLibEntry) As String '测试例: 'D:\Minecraft\test\libraries\net\neoforged\mergetool\2.0.0\mergetool-2.0.0-api.jar 'D:\Minecraft\test\libraries\org\apache\commons\commons-collections4\4.2\commons-collections4-4.2.jar 'D:\Minecraft\test\libraries\com\google\guava\guava\31.1-jre\guava-31.1-jre.jar - Return GetFolderNameFromPath(GetPathFromFullPath(Token.LocalPath)) + Return PathUtils.GetLastPart(PathUtils.RemoveLastPart(Token.LocalPath)) End Function For i = 0 To BasicArray.Count - 1 Dim Key As String = BasicArray(i).Name & BasicArray(i).IsNatives.ToString @@ -2012,10 +2037,10 @@ OnLoaded: Dim BasicArrayVersion As String = GetVersion(BasicArray(i)) Dim ResultArrayVersion As String = GetVersion(ResultArray(Key)) If BasicArrayVersion <> ResultArrayVersion AndAlso KeepSameNameDifferentVersionResult Then - Log($"[Minecraft] 发现疑似重复的支持库:{BasicArray(i)} ({BasicArrayVersion}) 与 {ResultArray(Key)} ({ResultArrayVersion})") + Logger.Info($"发现疑似重复的支持库:{BasicArray(i)} ({BasicArrayVersion}) 与 {ResultArray(Key)} ({ResultArrayVersion})") ResultArray.Add(Key & GetUuid(), BasicArray(i)) Else - Log($"[Minecraft] 发现重复的支持库:{BasicArray(i)} ({BasicArrayVersion}) 与 {ResultArray(Key)} ({ResultArrayVersion}),已忽略其中之一") + Logger.Info($"发现重复的支持库:{BasicArray(i)} ({BasicArrayVersion}) 与 {ResultArray(Key)} ({ResultArrayVersion}),已忽略其中之一") If CompareVersionGE(BasicArrayVersion, ResultArrayVersion) Then ResultArray(Key) = BasicArray(i) End If @@ -2041,26 +2066,26 @@ OnLoaded: Dim MainJar As NetFile = DlClientJarGet(Instance, True) If MainJar IsNot Nothing Then Result.Add(MainJar) Catch ex As Exception - Log(ex, "版本缺失主 jar 文件所必须的信息", NotifyLevel.DevelopOnly) + Logger.Warn(ex, "版本缺失主 jar 文件所必须的信息") End Try 'Library 文件 Result.AddRange(McLibNetFilesFromTokens(McLibListGet(Instance, False))) '统一通行证文件 - If Settings.Get("VersionServerLogin", Instance:=Instance) = 3 Then + If Settings.Get(Of Integer)("VersionServerLogin", Instance:=Instance) = 3 Then Dim TargetFile As String = PathPure & "nide8auth.jar" Try '测试链接:https://auth.mc-user.com:233/00000000000000000000000000000000/ - Log("[Minecraft] 开始获取统一通行证下载信息") - Dim DownloadInfo = GetJson(NetRequestByClientRetry("https://auth.mc-user.com:233/" & Settings.Get("VersionServerNide", Instance:=Instance), RequireJson:=True)) + Logger.Info("开始获取统一通行证下载信息") + Dim DownloadInfo = GetJson(NetRequestByClientRetry("https://auth.mc-user.com:233/" & Settings.Get(Of String)("VersionServerNide", Instance:=Instance), RequireJson:=True)) Result.Add(New NetFile( Urls:={"https://login.mc-user.com:233/index/jar"}, LocalPath:=TargetFile, Checker:=New FileChecker(Hash:=DownloadInfo("jarHash").ToString))) Catch ex As Exception - If File.Exists(TargetFile) Then - Log(ex, "获取统一通行证下载信息失败") + If FileUtils.Exists(TargetFile) Then + Logger.Warn(ex, "获取统一通行证下载信息失败") Else Throw New Exception("获取统一通行证下载信息失败", ex) End If @@ -2068,10 +2093,10 @@ OnLoaded: End If 'Authlib-Injector 文件 - If Settings.Get("VersionServerLogin", Instance:=Instance) = 4 Then + If Settings.Get(Of Integer)("VersionServerLogin", Instance:=Instance) = 4 Then Dim TargetFile = PathPure & "authlib-injector.jar" Try - Log("[Minecraft] 开始获取 Authlib-Injector 下载信息") + Logger.Info("开始获取 Authlib-Injector 下载信息") Dim DownloadInfo = GetJson(NetRequestByClientRetry( "https://authlib-injector.yushi.moe/artifact/latest.json", BackupUrl:="https://bmclapi2.bangbang93.com/mirrors/authlib-injector/artifact/latest.json", RequireJson:=True)) @@ -2082,8 +2107,8 @@ OnLoaded: DownloadAddress.Replace("authlib-injector.yushi.moe", "bmclapi2.bangbang93.com/mirrors/authlib-injector") }, TargetFile, New FileChecker(Hash:=DownloadInfo("checksums")("sha256").ToString))) Catch ex As Exception - If File.Exists(TargetFile) Then - Log(ex, "获取 Authlib-Injector 下载信息失败") + If FileUtils.Exists(TargetFile) Then + Logger.Warn(ex, "获取 Authlib-Injector 下载信息失败") Else Throw New Exception("获取 Authlib-Injector 下载信息失败", ex) End If @@ -2092,11 +2117,11 @@ OnLoaded: '跳过校验 If ShouldIgnoreFileCheck(Instance) Then - Log("[Minecraft] 设置要求尽量忽略文件检查,这可能会保留有误的文件", NotifyLevel.DebugModeOnly) + Logger.Warn("设置要求尽量忽略文件检查,这可能会保留有误的文件") Result = Result.Where( Function(f) - If File.Exists(f.LocalPath) Then - Log("[Minecraft] 跳过下载的支持库文件:" & f.LocalPath, NotifyLevel.DebugModeOnly) + If FileUtils.Exists(f.LocalPath) Then + Logger.Warn($"跳过下载的支持库文件:{f.LocalPath}") Return False Else Return True @@ -2109,11 +2134,11 @@ OnLoaded: ''' ''' 将 McLibToken 列表转换为 NetFile。 ''' - Public Function McLibNetFilesFromTokens(Libs As List(Of McLibToken), Optional CustomMcFolder As String = Nothing) As List(Of NetFile) + Public Function McLibNetFilesFromTokens(Libs As List(Of McLibEntry), Optional CustomMcFolder As String = Nothing) As List(Of NetFile) CustomMcFolder = If(CustomMcFolder, McFolderSelected) Dim Result As New List(Of NetFile) '获取 - For Each Token As McLibToken In Libs + For Each Token As McLibEntry In Libs '检查器 Dim Checker As FileChecker If Token.Name.ContainsIgnoreCase("labymod") Then @@ -2145,12 +2170,12 @@ OnLoaded: End If If Token.LocalPath.Contains("transformer-discovery-service") Then 'Transformer 文件释放 - If Not File.Exists(Token.LocalPath) Then FileUtils.Write(Token.LocalPath, GetResources("Transformer")) - Log("[Download] 已自动释放 Transformer Discovery Service", NotifyLevel.DevelopOnly) + If Not FileUtils.Exists(Token.LocalPath) Then ExtractResources(Token.LocalPath, "Transformer") + Logger.Warn("已自动释放 Transformer Discovery Service") Continue For ElseIf Token.LocalPath.Contains("optifine\OptiFine") Then 'OptiFine 主 Jar - Dim OptiFineBase As String = Token.LocalPath.Replace(CustomMcFolder & "libraries\optifine\OptiFine\", "").Split("_")(0) & "/" & GetFileNameFromPath(Token.LocalPath).Replace("-", "_") + Dim OptiFineBase As String = Token.LocalPath.Replace(CustomMcFolder & "libraries\optifine\OptiFine\", "").Split("_")(0) & "/" & PathUtils.GetLastPart(Token.LocalPath).Replace("-", "_") OptiFineBase = "/maven/com/optifine/" & OptiFineBase If OptiFineBase.Contains("_pre") Then OptiFineBase = OptiFineBase.Replace("com/optifine/", "com/optifine/preview_") Urls.Add("https://bmclapi2.bangbang93.com" & OptiFineBase) @@ -2174,15 +2199,16 @@ OnLoaded: '文件夹名应该忽略最后一段(client),但文件名需要保留 '参见 #7306(以及 #5376 也是因为这里没有处理好导致的) Dim Splited = Original.Split(":") - McLibGet = If(WithHead, CustomMcFolder & "libraries\", "") & + Dim Result = If(WithHead, CustomMcFolder & "libraries\", "") & $"{Splited(0).Replace(".", "\")}\{Splited(1)}\{Splited(2)}\{Splited.Skip(1).Join("-")}.jar" + Return Result End Function ''' ''' 检查设置,是否应当忽略文件检查? ''' Public Function ShouldIgnoreFileCheck(Instance As McInstance) - Return Settings.Get("VersionAdvanceAssetsV2", Instance:=Instance) OrElse (Settings.Get("VersionAdvanceAssets", Instance:=Instance) = 2) + Return Settings.Get(Of Boolean)("VersionAdvanceAssetsV2", Instance:=Instance) OrElse (Settings.Get(Of Integer)("VersionAdvanceAssets", Instance:=Instance) = 2) End Function #End Region @@ -2214,7 +2240,7 @@ OnLoaded: ' Log("[Minecraft] 无法获取资源文件索引下载地址,使用 assets 项提供的资源文件名:" & AssetsName) ' Return GetJson("{""id"": """ & AssetsName & """}") 'Else - Log("[Minecraft] 无法获取资源文件索引下载地址,使用默认的 legacy 下载地址") + Logger.Info("无法获取资源文件索引下载地址,使用默认的 legacy 下载地址") Return GetJson("{ ""id"": ""legacy"", ""sha1"": ""c0fd82e8ce9fbc93119e40d96d5a4e62cfa3f729"", @@ -2243,7 +2269,7 @@ OnLoaded: Instance = New McInstance(McFolderSelected & "versions\" & Instance.InheritName) Loop Catch ex As Exception - Log(ex, "获取资源文件索引名失败") + Logger.Warn(ex, "获取资源文件索引名失败") End Try Return "legacy" End Function @@ -2279,9 +2305,9 @@ OnLoaded: Try '初始化 - If Not File.Exists($"{McFolderSelected}assets\indexes\{IndexName}.json") Then Throw New FileNotFoundException("未找到 Asset Index", McFolderSelected & "assets\indexes\" & IndexName & ".json") + If Not FileUtils.Exists($"{McFolderSelected}assets\indexes\{IndexName}.json") Then Throw New FileNotFoundException("未找到 Asset Index", McFolderSelected & "assets\indexes\" & IndexName & ".json") Dim Result As New List(Of McAssetsToken) - Dim Json As JObject = GetJson(ReadFile($"{McFolderSelected}assets\indexes\{IndexName}.json")) + Dim Json As JObject = GetJson(FileUtils.ReadAsString($"{McFolderSelected}assets\indexes\{IndexName}.json")) '读取列表 For Each File As JProperty In Json("objects").Children @@ -2294,19 +2320,19 @@ OnLoaded: LocalPath = $"{McFolderSelected}assets\virtual\legacy\{File.Name}" Else '正常 - LocalPath = $"{McFolderSelected}assets\objects\{Left(File.Value("hash").ToString, 2)}\{File.Value("hash")}" + LocalPath = $"{McFolderSelected}assets\objects\{Left(File.Value()("hash").ToString, 2)}\{File.Value()("hash")}" End If Result.Add(New McAssetsToken With { .LocalPath = LocalPath.Replace("/", "\"), .SourcePath = File.Name, - .Hash = File.Value("hash").ToString, - .Size = File.Value("size").ToString + .Hash = File.Value()("hash").ToString, + .Size = File.Value()("size").ToString }) Next Return Result Catch ex As Exception - Log(ex, "获取资源文件列表失败:" & IndexName) + Logger.Warn(ex, $"获取资源文件列表失败:{IndexName}") Throw End Try End Function @@ -2336,13 +2362,13 @@ OnLoaded: Token = AssetsList(i) If ProgressFeed IsNot Nothing Then ProgressFeed.Progress = 0.05 + 0.94 * i / AssetsList.Count '检查文件是否存在 - Dim File As New FileInfo(Token.LocalPath) + Dim File = FileUtils.GetInfo(Token.LocalPath) If File.Exists AndAlso (Token.Size = 0 OrElse Token.Size = File.Length) Then Continue For '文件不存在,添加下载 Result.Add(New NetFile(DlSourceAssetsGet($"https://resources.download.minecraft.net/{Left(Token.Hash, 2)}/{Token.Hash}"), Token.LocalPath, New FileChecker(ActualSize:=If(Token.Size = 0, -1, Token.Size), Hash:=Token.Hash))) Next Catch ex As Exception - Log(ex, "获取版本缺失的资源文件下载列表失败") + Logger.Warn(ex, "获取版本缺失的资源文件下载列表失败") End Try If ProgressFeed IsNot Nothing Then ProgressFeed.Progress = 0.99 Return Result @@ -2382,7 +2408,7 @@ OnLoaded: End If Catch ex As Exception - Log(ex, "Minecraft 更新提示发送失败(" & If(VersionName, "Nothing") & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"Minecraft 更新提示发送失败({If(VersionName, "Nothing")})") End Try End Sub @@ -2407,8 +2433,8 @@ OnLoaded: End If Left = Left.Lower Right = Right.Lower - Dim Lefts = RegexSearch(Left.Replace("快照", "snapshot").Replace("预览版", "pre"), "[a-z]+|[0-9]+") - Dim Rights = RegexSearch(Right.Replace("快照", "snapshot").Replace("预览版", "pre"), "[a-z]+|[0-9]+") + Dim Lefts = Left.Replace("快照", "snapshot").Replace("预览版", "pre").RegexSearch("[a-z]+|[0-9]+").ToList + Dim Rights = Right.Replace("快照", "snapshot").Replace("预览版", "pre").RegexSearch("[a-z]+|[0-9]+").ToList Dim i As Integer = 0 While True '两边均缺失,感觉是一个东西 @@ -2468,7 +2494,7 @@ NextEntry: Public Function FilterAccessToken(Raw As String, FilterChar As Char) As String '打码 "accessToken " 后的内容 If Raw.Contains("accessToken ") Then - For Each Token In RegexSearch(Raw, "(?<=accessToken ([^ ]{5}))[^ ]+(?=[^ ]{5})") + For Each Token In Raw.RegexSearch("(?<=accessToken ([^ ]{5}))[^ ]+(?=[^ ]{5})") Raw = Raw.Replace(Token, New String(FilterChar, Token.Count)) Next End If @@ -2485,12 +2511,12 @@ NextEntry: ''' Public Function FilterUserName(Raw As String, FilterChar As Char) As String If Raw.Contains(":\Users\") Then - For Each Token In RegexSearch(Raw, "(?<=:\\Users\\)[^\\]+") + For Each Token In Raw.RegexSearch("(?<=:\\Users\\)[^\\]+") Raw = Raw.Replace("\Users\" & Token, "\Users\" & New String(FilterChar, Token.Count)) Next End If If Raw.Contains(":/Users/") Then - For Each Token In RegexSearch(Raw, "(?<=:/Users/)[^/]+") + For Each Token In Raw.RegexSearch("(?<=:/Users/)[^/]+") Raw = Raw.Replace("/Users/" & Token, "/Users/" & New String(FilterChar, Token.Count)) Next End If diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb index e5a7d42..98582b4 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb @@ -5,7 +5,7 @@ ''' 弹窗要求选择一个整合包文件并进行安装。 ''' Public Sub ModpackInstall() - Dim File As String = SelectFile("整合包文件(*.rar;*.zip;*.mrpack)|*.rar;*.zip;*.mrpack", "选择整合包压缩文件") '选择整合包文件 + Dim File As String = Dialogs.SelectFile("选择整合包压缩文件", False, filter:={({"rar", "zip", "mrpack"}, "整合包文件")}).FirstOrDefault() '选择整合包文件 If String.IsNullOrEmpty(File) Then Return RunInThread( Sub() @@ -13,7 +13,7 @@ ModpackInstall(File) Catch ex As CancelledException Catch ex As Exception - Log(ex, "手动安装整合包失败", NotifyLevel.MsgBox) + Logger.Error(ex, "手动安装整合包失败", LogBehavior.Alert) End Try End Sub) End Sub @@ -23,7 +23,7 @@ ''' ''' Public Function ModpackInstall(File As String, Optional InstanceName As String = Nothing, Optional Logo As String = Nothing) As LoaderCombo(Of String) - Log("[ModPack] 整合包安装请求:" & If(File, "null")) + Logger.Info($"整合包安装请求:{If(File, "null")}") Dim Archive As ZipArchive = Nothing Dim ArchiveBaseFolder As String = "" Try @@ -33,13 +33,13 @@ '获取整合包种类与关键 Json Dim PackType As Integer = -1 Try - Archive = New ZipArchive(New FileStream(File, FileMode.Open, FileAccess.Read, FileShare.Read)) + Archive = FileUtils.OpenZip(File) '从根目录判断整合包类型 If Archive.GetEntry("mcbbs.packmeta") IsNot Nothing Then PackType = 3 : Exit Try 'MCBBS 整合包(优先于 manifest.json 判断) If Archive.GetEntry("mmc-pack.json") IsNot Nothing Then PackType = 2 : Exit Try 'MMC 整合包(优先于 manifest.json 判断,#4194) If Archive.GetEntry("modrinth.index.json") IsNot Nothing Then PackType = 4 : Exit Try 'Modrinth 整合包 If Archive.GetEntry("manifest.json") IsNot Nothing Then - Dim Json As JObject = GetJson(ReadFile(Archive.GetEntry("manifest.json").Open, Encoding.UTF8)) + Dim Json As JObject = GetJson(Archive.GetEntry("manifest.json").Open().ReadString(Encoding.UTF8)) If Json("addons") Is Nothing Then PackType = 0 : Exit Try 'CurseForge 整合包 Else @@ -50,27 +50,27 @@ If Archive.GetEntry("modpack.zip") IsNot Nothing OrElse Archive.GetEntry("modpack.mrpack") IsNot Nothing Then PackType = 9 : Exit Try '带启动器的压缩包 '从一级目录判断整合包类型 For Each Entry In Archive.Entries - Dim FullNames As String() = Entry.FullName.Split("/") - ArchiveBaseFolder = FullNames(0) & "/" + Dim PathSplits As String() = Entry.FullName.Split("/") + ArchiveBaseFolder = PathSplits(0) & "/" '确定为一级目录下 - If FullNames.Count <> 2 Then Continue For + If PathSplits.Count <> 2 Then Continue For '判断是否为关键文件 - If FullNames(1) = "mcbbs.packmeta" Then PackType = 3 : Exit Try 'MCBBS 整合包(优先于 manifest.json 判断) - If FullNames(1) = "mmc-pack.json" Then PackType = 2 : Exit Try 'MMC 整合包(优先于 manifest.json 判断,#4194) - If FullNames(1) = "modrinth.index.json" Then PackType = 4 : Exit Try 'Modrinth 整合包 - If FullNames(1) = "manifest.json" Then - Dim Json As JObject = GetJson(ReadFile(Entry.Open, Encoding.UTF8)) + If PathSplits(1) = "mcbbs.packmeta" Then PackType = 3 : Exit Try 'MCBBS 整合包(优先于 manifest.json 判断) + If PathSplits(1) = "mmc-pack.json" Then PackType = 2 : Exit Try 'MMC 整合包(优先于 manifest.json 判断,#4194) + If PathSplits(1) = "modrinth.index.json" Then PackType = 4 : Exit Try 'Modrinth 整合包 + If PathSplits(1) = "manifest.json" Then + Dim Json As JObject = GetJson(Entry.Open().ReadString(Encoding.UTF8)) If Json("addons") Is Nothing Then PackType = 0 : Exit Try 'CurseForge 整合包 Else PackType = 3 : ArchiveBaseFolder = "overrides/" : Exit Try 'MCBBS 整合包 End If End If - If FullNames(1) = "modpack.json" Then PackType = 1 : Exit Try 'HMCL 整合包 - If FullNames(1) = "modpack.zip" OrElse FullNames(1) = "modpack.mrpack" Then PackType = 9 : Exit Try '带启动器的压缩包 + If PathSplits(1) = "modpack.json" Then PackType = 1 : Exit Try 'HMCL 整合包 + If PathSplits(1) = "modpack.zip" OrElse PathSplits(1) = "modpack.mrpack" Then PackType = 9 : Exit Try '带启动器的压缩包 Next Catch ex As Exception - If ex.GetDetail(True).Contains("Error.WinIOError") Then + If ex.GetDisplay(True).Contains("Error.WinIOError") Then Throw New Exception("打开整合包文件失败", ex) ElseIf File.EndsWithF(".rar", True) Then Throw New Exception("PCL 无法处理 rar 格式的压缩包,请在解压后重新压缩为 zip 格式再试", ex) @@ -81,25 +81,25 @@ '执行对应的安装方法 Select Case PackType Case 0 - Log("[ModPack] 整合包种类:CurseForge") + Logger.Info("整合包种类:CurseForge") Return InstallPackCurseForge(File, Archive, ArchiveBaseFolder, InstanceName, Logo) Case 1 - Log("[ModPack] 整合包种类:HMCL") + Logger.Info("整合包种类:HMCL") Return InstallPackHMCL(File, Archive, ArchiveBaseFolder) Case 2 - Log("[ModPack] 整合包种类:MMC") + Logger.Info("整合包种类:MMC") Return InstallPackMMC(File, Archive, ArchiveBaseFolder) Case 3 - Log("[ModPack] 整合包种类:MCBBS") + Logger.Info("整合包种类:MCBBS") Return InstallPackMCBBS(File, Archive, ArchiveBaseFolder, InstanceName) Case 4 - Log("[ModPack] 整合包种类:Modrinth") + Logger.Info("整合包种类:Modrinth") Return InstallPackModrinth(File, Archive, ArchiveBaseFolder, InstanceName, Logo) Case 9 - Log("[ModPack] 整合包种类:带启动器的压缩包") + Logger.Info("整合包种类:带启动器的压缩包") Return InstallPackLauncherPack(File, Archive, ArchiveBaseFolder) Case Else - Log("[ModPack] 整合包种类:未能识别,假定为压缩包") + Logger.Info("整合包种类:未能识别,假定为压缩包") Return InstallPackCompress(File, Archive) End Select Finally @@ -111,13 +111,14 @@ '解压文件 Dim RetryCount As Integer = 1 Dim InitialProgress = Loader.Progress - Try Retry: + Try Loader.Progress = InitialProgress - DeleteDirectory(InstallTemp) - ExtractCompressedFile(FileAddress, InstallTemp, ProgressIncrementHandler:=Sub(Delta) Loader.Progress += Delta * ProgressIncrement) + DirectoryUtils.Delete(InstallTemp) + Dim RawProgress As Double = Loader.Progress + FileUtils.ExtractToDirectory(FileAddress, InstallTemp, progressHandler:=Sub(Percentage) Loader.Progress = RawProgress + Percentage * ProgressIncrement) Catch ex As Exception - Log(ex, "第 " & RetryCount & " 次解压尝试失败") + Logger.Warn(ex, $"第 {RetryCount} 次解压尝试失败") '完全不知道为啥会出现文件正在被另一进程使用的问题,总之加个重试 If RetryCount < 5 Then Thread.Sleep(RetryCount * 2000) @@ -134,25 +135,24 @@ Retry: ''' 从整合包的 override 目录复制文件,同时设置 PCL 的配置文件与版本隔离。 ''' 对路径末尾是否为 \ 没有要求。 ''' - Private Sub CopyOverrideDirectory(OverridesFolder As String, VersionFolder As String, Loader As LoaderBase, ProgressIncrement As Double) + Private Sub CopyOverrideDirectory(OverridesFolder As String, VersionFolder As String, Loader As LoaderBase) If Not OverridesFolder.EndsWithF("\") Then OverridesFolder += "\" If Not VersionFolder.EndsWithF("\") Then VersionFolder += "\" '复制文件 - If Directory.Exists(OverridesFolder) Then - Log($"[ModPack] 处理整合包覆写文件夹:{OverridesFolder} → {VersionFolder}") - CopyDirectory(OverridesFolder, VersionFolder, Sub(Delta) Loader.Progress += Delta * ProgressIncrement) + If DirectoryUtils.Exists(OverridesFolder) Then + Logger.Info($"处理整合包覆写文件夹:{OverridesFolder} → {VersionFolder}") + DirectoryUtils.Copy(OverridesFolder, VersionFolder) Else - Log($"[ModPack] 整合包中没有覆写文件夹:{OverridesFolder}") - Loader.Progress += ProgressIncrement + Logger.Info($"整合包中没有覆写文件夹:{OverridesFolder}") End If '设置 ini Dim OverridesIni As String = $"{OverridesFolder}PCL\Setup.ini" Dim VersionIni As String = $"{VersionFolder}PCL\Setup.ini" - If File.Exists(OverridesIni) Then + If FileUtils.Exists(OverridesIni) Then WriteIni(OverridesIni, "VersionArgumentIndie", 1) '开启版本隔离 WriteIni(OverridesIni, "VersionArgumentIndieV2", True) WriteIni(OverridesIni, "IsStar", False) - CopyFile(OverridesIni, VersionIni) '覆写已有的 ini + FileUtils.Copy(OverridesIni, VersionIni) '覆写已有的 ini Else WriteIni(VersionIni, "VersionArgumentIndie", 1) '开启版本隔离 WriteIni(VersionIni, "VersionArgumentIndieV2", True) @@ -178,7 +178,7 @@ Retry: '读取 Json 文件 Dim Json As JObject Try - Json = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "manifest.json").Open)) + Json = GetJson(Archive.GetEntry(ArchiveBaseFolder & "manifest.json").Open().ReadString) Catch ex As Exception Throw New Exception("CurseForge 整合包安装信息存在问题", ex) End Try @@ -194,24 +194,23 @@ Retry: End If '获取 Mod API 版本信息 - Dim ForgeVersion As String = Nothing - Dim NeoForgeVersion As String = Nothing - Dim FabricVersion As String = Nothing + Dim TargetVersion As New McVersion + TargetVersion.VanillaName = Json("minecraft")("version").ToString For Each Entry In If(Json("minecraft")("modLoaders"), {}) Dim Id As String = If(Entry("id"), "").ToString.Lower If Id.StartsWithF("forge-") Then 'Forge 指定 If Id.Contains("recommended") Then Throw New Exception("该整合包版本过老,已不支持进行安装!") - Log("[ModPack] 整合包 Forge 版本:" & Id) - ForgeVersion = Id.Replace("forge-", "") + Logger.Info($"整合包 Forge 版本:{Id}") + TargetVersion.Forge = Id.Replace("forge-", "") ElseIf Id.StartsWithF("neoforge-") Then 'NeoForge 指定 - Log("[ModPack] 整合包 NeoForge 版本:" & Id) - NeoForgeVersion = Id.Replace("neoforge-", "") + Logger.Info($"整合包 NeoForge 版本:{Id}") + TargetVersion.NeoForge = Id.Replace("neoforge-", "") ElseIf Id.StartsWithF("fabric-") Then 'Fabric 指定 - Log("[ModPack] 整合包 Fabric 版本:" & Id) - FabricVersion = Id.Replace("fabric-", "") + Logger.Info($"整合包 Fabric 版本:{Id}") + TargetVersion.Fabric = Id.Replace("fabric-", "") Else 'ElseIf Id.StartsWithF("quilt-") Then NotifyIncompatibleLoader(Id) @@ -227,10 +226,9 @@ Retry: ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6) CopyOverrideDirectory( InstallTemp & ArchiveBaseFolder & If(OverrideHome = "." OrElse OverrideHome = "./", "", OverrideHome), '#5613 - $"{McFolderSelected}versions\{InstanceName}", - Task, 0.4) + $"{McFolderSelected}versions\{InstanceName}", Task) End Sub) With { - .ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s + .ProgressWeight = FileUtils.GetInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s End If '获取 Mod 列表 Dim ModList As New List(Of Integer) @@ -253,17 +251,17 @@ Retry: '如果文件已被删除,则 API 会跳过那一项,导致返回的列表数量小于请求的数量。后面的都是对此的错误处理。 '获取缺失的 fileId 列表 Dim MissingIds = ModList.Except(Task.Output.Select(Function(j) j("id").ToObject(Of Integer))).ToList - Log("[Modpack] 缺失的 fileIds:" & MissingIds.Join("、")) + Logger.Info($"缺失的 fileIds:{MissingIds.Join("、")}") '将 fileId 映射到 projectId Dim Missings = MissingIds.Select(Of (ProjectId As Integer, FileId As Integer))( Function(id) (CType(Json("files").AsEnumerable.First(Function(f) f("fileID").ToObject(Of Integer) = id), JObject)("projectID").ToObject(Of Integer), id)).ToList - Log("[Modpack] 缺失项:" & Missings.Join("、")) + Logger.Info($"缺失项:{Missings.Join("、")}") '尝试获取对应的工程信息 Dim Projects As New List(Of ResourceProject) Try Projects = ResourceProject.FromProjectIds(Missings.Select(Function(e) e.ProjectId.ToString), ResourcePlatforms.CurseForge).ToList Catch ex As Exception - Log(ex, "获取缺失的工程信息失败") + Logger.Warn(ex, "获取缺失的工程信息失败") End Try Dim MissingDesc As New List(Of String) For Each Missing In Missings @@ -312,7 +310,8 @@ Retry: Dim File = ResourceVersion.FromPlatformJson(ModJson, Type) If Not File.DownloadAvailable Then Continue For '实际的添加 - FileList.Add(Id, File.ToNetFile($"{McFolderSelected}versions\{InstanceName}\{TargetFolder}\")) + FileList.Add(Id, File.ToNetFile($"{McFolderSelected}versions\{InstanceName}\{TargetFolder}\", + ResourceVersion.DownloadReason.ModPack, TargetVersion.VanillaName, TargetVersion.ModLoaders)) Task.Progress += 1 / (1 + ModList.Count) Next Task.Output = FileList.Values.ToList @@ -328,10 +327,10 @@ Retry: Dim Request As New McInstallRequest With { .NewInstanceName = InstanceName, .VersionFolder = $"{McFolderSelected}versions\{InstanceName}\", - .MinecraftName = Json("minecraft")("version").ToString, - .ForgeVersion = ForgeVersion, - .NeoForgeVersion = NeoForgeVersion, - .FabricVersion = FabricVersion + .MinecraftName = TargetVersion.VanillaName, + .ForgeVersion = TargetVersion.Forge, + .NeoForgeVersion = TargetVersion.NeoForge, + .FabricVersion = TargetVersion.Fabric } Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request) '构造总加载器 @@ -342,22 +341,22 @@ Retry: Sub(Task As LoaderTask(Of String, String)) '设置图标 Dim VersionFolder As String = $"{McFolderSelected}versions\{InstanceName}\" - If Logo IsNot Nothing AndAlso File.Exists(Logo) Then - File.Copy(Logo, VersionFolder & "PCL\Logo.png", True) + If Logo IsNot Nothing AndAlso FileUtils.Exists(Logo) Then + FileUtils.Copy(Logo, VersionFolder & "PCL\Logo.png") WriteIni(VersionFolder & "PCL\Setup.ini", "Logo", "PCL\Logo.png") WriteIni(VersionFolder & "PCL\Setup.ini", "LogoCustom", "True") - Log("[ModPack] 已设置整合包 Logo:" & Logo) + Logger.Info($"已设置整合包 Logo:{Logo}") End If '删除原始整合包文件 For Each Target As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"} - If File.Exists(Target) Then - Log("[ModPack] 删除原始整合包文件:" & Target) - File.Delete(Target) + If FileUtils.Exists(Target) Then + Logger.Info($"删除原始整合包文件:{Target}") + FileUtils.Delete(Target) End If Next - If File.Exists(FileAddress) AndAlso Path.GetFileNameWithoutExtension(FileAddress) = "modpack" Then - Log("[ModPack] 删除安装整合包文件:" & FileAddress) - File.Delete(FileAddress) + If FileUtils.Exists(FileAddress) AndAlso PathUtils.GetFileNameWithoutExtension(FileAddress) = "modpack" Then + Logger.Info($"删除安装整合包文件:{FileAddress}") + FileUtils.Delete(FileAddress) End If End Sub) With {.ProgressWeight = 0.1, .Show = False}) @@ -383,29 +382,26 @@ Retry: '读取 Json 文件 Dim Json As JObject Try - Json = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "modrinth.index.json").Open)) + Json = GetJson(Archive.GetEntry(ArchiveBaseFolder & "modrinth.index.json").Open().ReadString) Catch ex As Exception Throw New Exception("Modrinth 整合包安装信息存在问题", ex) End Try If Json("dependencies") Is Nothing OrElse Json("dependencies")("minecraft") Is Nothing Then Throw New Exception("Modrinth 整合包未提供 Minecraft 版本信息") '获取 Mod API 版本信息 - Dim MinecraftVersion As String = Nothing - Dim ForgeVersion As String = Nothing - Dim NeoForgeVersion As String = Nothing - Dim FabricVersion As String = Nothing + Dim TargetVersion As New McVersion For Each Entry As JProperty In If(Json("dependencies"), {}) Select Case Entry.Name.Lower Case "minecraft" - MinecraftVersion = Entry.Value.ToString + TargetVersion.VanillaName = Entry.Value.ToString Case "forge" 'eg. 14.23.5.2859 / 1.19-41.1.0 - ForgeVersion = Entry.Value.ToString - Log("[ModPack] 整合包 Forge 版本:" & ForgeVersion) + TargetVersion.Forge = Entry.Value.ToString + Logger.Info($"整合包 Forge 版本:{TargetVersion.Forge}") Case "neoforge", "neo-forge" 'eg. 20.6.98-beta - NeoForgeVersion = Entry.Value.ToString - Log("[ModPack] 整合包 NeoForge 版本:" & NeoForgeVersion) + TargetVersion.NeoForge = Entry.Value.ToString + Logger.Info($"整合包 NeoForge 版本:{TargetVersion.NeoForge}") Case "fabric-loader" 'eg. 0.14.14 - FabricVersion = Entry.Value.ToString - Log("[ModPack] 整合包 Fabric 版本:" & FabricVersion) + TargetVersion.Fabric = Entry.Value.ToString + Logger.Info($"整合包 Fabric 版本:{TargetVersion.Fabric}") Case Else 'Case "quilt-loader" 'eg. 1.0.0 NotifyIncompatibleLoader(Entry.Name) @@ -427,13 +423,11 @@ Retry: ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.5) CopyOverrideDirectory( InstallTemp & ArchiveBaseFolder & "overrides", - McFolderSelected & "versions\" & InstanceName, - Task, 0.4) + McFolderSelected & "versions\" & InstanceName, Task) CopyOverrideDirectory( InstallTemp & ArchiveBaseFolder & "client-overrides", - McFolderSelected & "versions\" & InstanceName, - Task, 0.1) - End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s + McFolderSelected & "versions\" & InstanceName, Task) + End Sub) With {.ProgressWeight = FileUtils.GetInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s '获取下载文件列表 Dim FileList As New List(Of NetFile) For Each File In If(Json("files"), {}) @@ -441,7 +435,7 @@ Retry: If File("env") IsNot Nothing Then Select Case File("env")("client").ToString Case "optional" - If MyMsgBox("是否要下载可选文件 " & GetFileNameFromPath(File("path").ToString) & "?", + If MyMsgBox("是否要下载可选文件 " & PathUtils.GetLastPart(File("path").ToString) & "?", "下载可选文件", "是", "否") = 2 Then Continue For End If @@ -452,10 +446,12 @@ Retry: '添加下载文件 Dim Urls = File("downloads").SelectMany(Function(t) ResourceVersion.ParseCurseForgeDownloadUrls(t.ToString)).ToList Urls.AddRange(Urls.Select(Function(u) DlSourceModGet(u)).ToList) + Urls = ResourceVersion.ParseModrinthTrackArguments(Urls, + ResourceVersion.DownloadReason.ModPack, TargetVersion.VanillaName, TargetVersion.ModLoaders).ToList 'Modrinth 来源追踪信息 Urls = Urls.Distinct.ToList() Dim TargetPath As String = $"{McFolderSelected}versions\{InstanceName}\{File("path")}" - If Not Path.GetFullPath(TargetPath).StartsWithF($"{McFolderSelected}versions\{InstanceName}\", True) Then - MyMsgBox($"整合包的文件路径超出了版本文件夹,请向整合包作者反馈此问题!" & vbCrLf & "错误的文件:" & TargetPath, "文件路径校验失败", IsWarn:=True) + If Not Path.GetFullPath(TargetPath).StartsWithF(Path.GetFullPath($"{McFolderSelected}versions\{InstanceName}\")) Then + MyMsgBox($"整合包的文件路径超出了版本文件夹,请向整合包作者反馈此问题!{vbCrLf}目标:{Path.GetFullPath(TargetPath)}{vbCrLf}错误的文件:{TargetPath}", "文件路径校验失败", IsWarn:=True) Throw New CancelledException End If FileList.Add(New NetFile(Urls, TargetPath, @@ -469,10 +465,10 @@ Retry: Dim Request As New McInstallRequest With { .NewInstanceName = InstanceName, .VersionFolder = $"{McFolderSelected}versions\{InstanceName}\", - .MinecraftName = MinecraftVersion, - .ForgeVersion = ForgeVersion, - .NeoForgeVersion = NeoForgeVersion, - .FabricVersion = FabricVersion + .MinecraftName = TargetVersion.VanillaName, + .ForgeVersion = TargetVersion.Forge, + .NeoForgeVersion = TargetVersion.NeoForge, + .FabricVersion = TargetVersion.Fabric } Dim MergeLoaders As List(Of LoaderBase) = McInstallLoader(Request) '构造总加载器 @@ -483,22 +479,22 @@ Retry: Sub(Task As LoaderTask(Of String, String)) '设置图标 Dim VersionFolder As String = $"{McFolderSelected}versions\{InstanceName}\" - If Logo IsNot Nothing AndAlso File.Exists(Logo) Then - File.Copy(Logo, VersionFolder & "PCL\Logo.png", True) + If Logo IsNot Nothing AndAlso FileUtils.Exists(Logo) Then + FileUtils.Copy(Logo, VersionFolder & "PCL\Logo.png") WriteIni(VersionFolder & "PCL\Setup.ini", "Logo", "PCL\Logo.png") WriteIni(VersionFolder & "PCL\Setup.ini", "LogoCustom", "True") - Log("[ModPack] 已设置整合包 Logo:" & Logo) + Logger.Info($"已设置整合包 Logo:{Logo}") End If '删除原始整合包文件 For Each Target As String In {VersionFolder & "原始整合包.zip", VersionFolder & "原始整合包.mrpack"} - If File.Exists(Target) Then - Log("[ModPack] 删除原始整合包文件:" & Target) - File.Delete(Target) + If FileUtils.Exists(Target) Then + Logger.Info($"删除原始整合包文件:{Target}") + FileUtils.Delete(Target) End If Next - If File.Exists(FileAddress) AndAlso Path.GetFileNameWithoutExtension(FileAddress) = "modpack" Then - Log("[ModPack] 删除安装整合包文件:" & FileAddress) - File.Delete(FileAddress) + If FileUtils.Exists(FileAddress) AndAlso PathUtils.GetFileNameWithoutExtension(FileAddress) = "modpack" Then + Logger.Info($"删除安装整合包文件:{FileAddress}") + FileUtils.Delete(FileAddress) End If End Sub) With {.ProgressWeight = 0.1, .Show = False}) @@ -523,7 +519,7 @@ Retry: '读取 Json 文件 Dim Json As JObject Try - Json = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "modpack.json").Open, Encoding.UTF8)) + Json = GetJson(Archive.GetEntry(ArchiveBaseFolder & "modpack.json").Open().ReadString(Encoding.UTF8)) Catch ex As Exception Throw New Exception("HMCL 整合包安装信息存在问题", ex) End Try @@ -541,9 +537,8 @@ Retry: ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6) CopyOverrideDirectory( InstallTemp & ArchiveBaseFolder & "minecraft", - McFolderSelected & "versions\" & InstanceName, - Task, 0.4) - End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s + McFolderSelected & "versions\" & InstanceName, Task) + End Sub) With {.ProgressWeight = FileUtils.GetInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s '构造游戏本体安装加载器 If Json("gameVersion") Is Nothing Then Throw New Exception("该 HMCL 整合包未提供游戏版本信息,无法安装!") Dim Request As New McInstallRequest With { @@ -577,13 +572,13 @@ Retry: '读取 Json 文件 Dim PackJson As JObject, PackInstance As String Try - PackJson = GetJson(ReadFile(Archive.GetEntry(ArchiveBaseFolder & "mmc-pack.json").Open, Encoding.UTF8)) - PackInstance = ReadFile(Archive.GetEntry(ArchiveBaseFolder & "instance.cfg").Open, Encoding.UTF8) + PackJson = GetJson(Archive.GetEntry(ArchiveBaseFolder & "mmc-pack.json").Open().ReadString(Encoding.UTF8)) + PackInstance = Archive.GetEntry(ArchiveBaseFolder & "instance.cfg").Open().ReadString(Encoding.UTF8) Catch ex As Exception Throw New Exception("MMC 整合包安装信息存在问题", ex) End Try '获取版本名 - Dim InstanceName As String = If(RegexSeek(PackInstance, "(?<=\nname\=)[^\n]+"), "") + Dim InstanceName As String = If(PackInstance.RegexSeek("(?<=\nname\=)[^\n]+"), "") Dim Validate As New ValidateFolderName(McFolderSelected & "versions") If Validate.Validate(InstanceName) <> "" Then InstanceName = "" If InstanceName = "" Then InstanceName = MyMsgBoxInput("输入版本名称", "", "", New ObjectModel.Collection(Of Validate) From {Validate}) @@ -597,15 +592,14 @@ Retry: ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.55) CopyOverrideDirectory( InstallTemp & ArchiveBaseFolder & ".minecraft", - McFolderSelected & "versions\" & InstanceName, - Task, 0.4) + McFolderSelected & "versions\" & InstanceName, Task) '读取 MMC 设置文件(#2655) Try Dim MmcSetupFile As String = InstallTemp & ArchiveBaseFolder & "instance.cfg" - If File.Exists(MmcSetupFile) Then + If FileUtils.Exists(MmcSetupFile) Then '将其中的等号替换为冒号,以符合 ini 文件格式 Dim Lines As New List(Of String) - For Each Line In ReadFile(MmcSetupFile).Split(vbCrLf.ToCharArray, StringSplitOptions.RemoveEmptyEntries) + For Each Line In FileUtils.ReadAsLines(MmcSetupFile, True) If Not Line.Contains("=") Then Continue For Lines.Add(Line.BeforeFirst("=") & ":" & Line.AfterFirst("=")) Next @@ -620,42 +614,42 @@ Retry: Replace("$INST_DIR\", "{verpath}").Replace("$INST_DIR", "{verpath}"). Replace("$INST_ID", "{name}").Replace("$INST_NAME", "{name}") WriteIni(SetupFile, "VersionAdvanceRun", PreLaunchCommand) - Log("[ModPack] 迁移 MultiMC 版本独立设置:启动前执行命令:" & PreLaunchCommand) + Logger.Info($"迁移 MultiMC 版本独立设置:启动前执行命令:{PreLaunchCommand}") End If End If If ReadIni(MmcSetupFile, "JoinServerOnLaunch", False) Then Dim ServerAddress As String = ReadIni(MmcSetupFile, "JoinServerOnLaunchAddress").Replace("\""", """") WriteIni(SetupFile, "VersionServerEnter", ServerAddress) - Log("[ModPack] 迁移 MultiMC 版本独立设置:自动进入服务器:" & ServerAddress) + Logger.Info($"迁移 MultiMC 版本独立设置:自动进入服务器:{ServerAddress}") End If If ReadIni(MmcSetupFile, "IgnoreJavaCompatibility", False) Then WriteIni(SetupFile, "VersionAdvanceJava", True) - Log("[ModPack] 迁移 MultiMC 版本独立设置:忽略 Java 兼容性警告") + Logger.Info("迁移 MultiMC 版本独立设置:忽略 Java 兼容性警告") End If Dim Logo As String = ReadIni(MmcSetupFile, "iconKey", "") - If Logo <> "" AndAlso File.Exists($"{InstallTemp}{ArchiveBaseFolder}{Logo}.png") Then + If Logo <> "" AndAlso FileUtils.Exists($"{InstallTemp}{ArchiveBaseFolder}{Logo}.png") Then WriteIni(SetupFile, "LogoCustom", True) WriteIni(SetupFile, "Logo", "PCL\Logo.png") - CopyFile($"{InstallTemp}{ArchiveBaseFolder}{Logo}.png", $"{McFolderSelected}versions\{InstanceName}\PCL\Logo.png") - Log($"[ModPack] 迁移 MultiMC 版本独立设置:版本图标({Logo}.png)") + FileUtils.Copy($"{InstallTemp}{ArchiveBaseFolder}{Logo}.png", $"{McFolderSelected}versions\{InstanceName}\PCL\Logo.png") + Logger.Info($"迁移 MultiMC 版本独立设置:版本图标({Logo}.png)") End If 'JVM 参数 Dim JvmArgs As String = ReadIni(MmcSetupFile, "JvmArgs", "") If JvmArgs <> "" Then If ReadIni(MmcSetupFile, "OverrideJavaArgs", False) Then WriteIni(SetupFile, "VersionAdvanceJvm", JvmArgs) - Log("[ModPack] 迁移 MultiMC 版本独立设置:JVM 参数(覆盖):" & JvmArgs) + Logger.Info($"迁移 MultiMC 版本独立设置:JVM 参数(覆盖):{JvmArgs}") Else - JvmArgs += " " & Settings.Get("LaunchAdvanceJvm") + JvmArgs += " " & Settings.Get(Of String)("LaunchAdvanceJvm") WriteIni(SetupFile, "VersionAdvanceJvm", JvmArgs) - Log("[ModPack] 迁移 MultiMC 版本独立设置:JVM 参数(追加):" & JvmArgs) + Logger.Info($"迁移 MultiMC 版本独立设置:JVM 参数(追加):{JvmArgs}") End If End If End If Catch ex As Exception - Log(ex, $"读取 MMC 配置文件失败({InstallTemp}{ArchiveBaseFolder}instance.cfg)") + Logger.Warn(ex, $"读取 MMC 配置文件失败({InstallTemp}{ArchiveBaseFolder}instance.cfg)") End Try - End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s + End Sub) With {.ProgressWeight = FileUtils.GetInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s '构造版本安装请求 If PackJson("components") Is Nothing Then Throw New Exception("该 MMC 整合包未提供游戏版本信息,无法安装!") Dim Request As New McInstallRequest With {.NewInstanceName = InstanceName, .VersionFolder = $"{McFolderSelected}versions\{InstanceName}\"} @@ -674,7 +668,7 @@ Retry: 'Case "org.quiltmc.quilt-loader" 'eg. 1.0.0 Case Else If UID.StartsWithF("org.lwjgl") Then '#8210 - Log("[ModPack] 已跳过 LWJGL 项:" & UID) + Logger.Info($"已跳过 LWJGL 项:{UID}") Else NotifyIncompatibleLoader(UID) End If @@ -710,7 +704,7 @@ Retry: Dim Json As JObject Try Dim Entry = If(Archive.GetEntry(ArchiveBaseFolder & "mcbbs.packmeta"), Archive.GetEntry(ArchiveBaseFolder & "manifest.json")) - Json = GetJson(ReadFile(Entry.Open, Encoding.UTF8)) + Json = GetJson(Entry.Open().ReadString(Encoding.UTF8)) Catch ex As Exception Throw New Exception("MCBBS 整合包安装信息存在问题", ex) End Try @@ -731,15 +725,14 @@ Retry: ExtractModpackFiles(InstallTemp, FileAddress, Task, 0.6) CopyOverrideDirectory( InstallTemp & ArchiveBaseFolder & "overrides", - McFolderSelected & "versions\" & InstanceName, - Task, 0.4) + McFolderSelected & "versions\" & InstanceName, Task) 'JVM 参数 If Json("launchInfo") IsNot Nothing Then Dim LaunchInfo As JObject = Json("launchInfo") If LaunchInfo.ContainsKey("javaArgument") Then WriteIni(SetupFile, "VersionAdvanceJvm", String.Join(" ", LaunchInfo("javaArgument"))) If LaunchInfo.ContainsKey("launchArgument") Then WriteIni(SetupFile, "VersionAdvanceGame", String.Join(" ", LaunchInfo("launchArgument"))) End If - End Sub) With {.ProgressWeight = New FileInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s + End Sub) With {.ProgressWeight = FileUtils.GetInfo(FileAddress).Length / 1024 / 1024 / 6, .Block = False}) '每 6M 需要 1s '构造加载器 If Json("addons") Is Nothing Then Throw New Exception("该 MCBBS 整合包未提供游戏版本附加信息,无法安装!") Dim Addons As New Dictionary(Of String, String) @@ -787,9 +780,9 @@ Retry: Private Function InstallPackLauncherPack(FileAddress As String, Archive As Compression.ZipArchive, ArchiveBaseFolder As String) As LoaderCombo(Of String) '获取解压路径 MyMsgBox("接下来请选择一个空文件夹,它会被安装到这个文件夹里。", "安装", "继续", ForceWait:=True) - Dim TargetFolder As String = SelectFolder("选择安装目标(必须是一个空文件夹)") - If String.IsNullOrEmpty(TargetFolder) Then Throw New CancelledException - If Directory.GetFileSystemEntries(TargetFolder).Length > 0 Then Hint("请选择一个空文件夹作为安装目标!", HintType.Red) : Throw New CancelledException + Dim TargetFolder As String = Dialogs.SelectFolder("选择安装目标(必须是一个空文件夹)", False).FirstOrDefault + If TargetFolder Is Nothing Then Throw New CancelledException + If Not DirectoryUtils.IsEmpty(TargetFolder) Then Hint("请选择一个空文件夹作为安装目标!", HintType.Red) : Throw New CancelledException '解压 Dim Loader As New LoaderCombo(Of String)("解压压缩包", { New LoaderTask(Of String, Integer)("解压压缩包", @@ -799,42 +792,42 @@ Retry: Thread.Sleep(400) '避免文件争用 '查找解压后的 exe 文件 Dim Launcher As String = Nothing - For Each ExeFile In Directory.GetFiles(TargetFolder, "*.exe", SearchOption.TopDirectoryOnly) + For Each ExeFile In DirectoryUtils.GetFiles(TargetFolder, True, "*.exe") Dim Info = FileVersionInfo.GetVersionInfo(ExeFile) - Log($"[Modpack] 文件 {ExeFile} 的产品名标识为 {Info.ProductName}") + Logger.Info($"文件 {ExeFile} 的产品名标识为 {Info.ProductName}") If Info.ProductName = "Plain Craft Launcher" Then Launcher = ExeFile - Log($"[Modpack] 发现整合包附带的 PCL 启动器:{ExeFile}") + Logger.Info($"发现整合包附带的 PCL 启动器:{ExeFile}") ElseIf (Info.ProductName.ContainsIgnoreCase("Launcher") OrElse Info.ProductName.Contains("启动")) AndAlso Not Info.ProductName = "Plain Craft Launcher Admin Manager" Then If Launcher Is Nothing Then Launcher = ExeFile - Log($"[Modpack] 发现整合包附带的疑似第三方启动器:{ExeFile}") + Logger.Info($"发现整合包附带的疑似第三方启动器:{ExeFile}") End If End If Next Task.Progress = 0.95 '尝试使用附带的启动器打开 If Launcher IsNot Nothing Then - Log("[Modpack] 找到压缩包中附带的启动器:" & Launcher) + Logger.Info($"找到压缩包中附带的启动器:{Launcher}") If MyMsgBox($"整合包里似乎自带了启动器,是否换用它继续安装?{vbCrLf}即将打开:{Launcher}", "换用整合包启动器?", "换用", "不换用") = 1 Then StartProcess(Launcher, "--wait") '要求等待已有的 PCL 退出 - Log("[Modpack] 为换用整合包中的启动器启动,强制结束程序") + Logger.Info("为换用整合包中的启动器启动,强制结束程序") FrmMain.EndProgram(False) Return End If Else - Log("[Modpack] 未找到压缩包中附带的启动器") + Logger.Info("未找到压缩包中附带的启动器") End If '加入文件夹列表 - Dim InstanceName As String = GetFolderNameFromPath(TargetFolder) + Dim InstanceName As String = PathUtils.GetLastPart(TargetFolder) DirectoryUtils.Create(TargetFolder & ".minecraft\") PageSelectLeft.AddFolder( TargetFolder & ".minecraft\" & ArchiveBaseFolder.Replace("/", "\").TrimStart("\"), '格式例如:包裹文件夹\.minecraft\(最短为空字符串) InstanceName, False) '调用 modpack 文件进行安装 - Dim ModpackFile = Directory.GetFiles(TargetFolder, "modpack.*", SearchOption.AllDirectories).First - Log("[Modpack] 调用 modpack 文件继续安装:" & ModpackFile) + Dim ModpackFile = DirectoryUtils.GetFiles(TargetFolder, "modpack.*").First + Logger.Info($"调用 modpack 文件继续安装:{ModpackFile}") ModpackInstall(ModpackFile) End Sub) }) @@ -859,20 +852,20 @@ Retry: Next If Match Is Nothing Then Throw New Exception("文件结构不匹配,这可能不是 Minecraft 客户端压缩包?") '没有匹配 Dim ArchiveBaseFolder As String = Match.Value.Replace("/", "\").TrimStart("\") '格式例如:包裹文件夹\.minecraft\(最短为空字符串) - Log("[ModPack] 检测到压缩包的 .minecraft 根目录:" & ArchiveBaseFolder & ",命中的版本名:" & Match.Groups(1).Value) + Logger.Info($"检测到压缩包的 .minecraft 根目录:{ArchiveBaseFolder},命中的版本名:{Match.Groups(1).Value}") '获取解压路径 MyMsgBox("接下来请选择一个空文件夹,它会被安装到这个文件夹里。", "安装", "继续", ForceWait:=True) - Dim TargetFolder As String = SelectFolder("选择安装目标(必须是一个空文件夹)") - If String.IsNullOrEmpty(TargetFolder) Then Throw New CancelledException + Dim TargetFolder As String = Dialogs.SelectFolder("选择安装目标(必须是一个空文件夹)", False).FirstOrDefault + If TargetFolder Is Nothing Then Throw New CancelledException If TargetFolder.Contains("!") OrElse TargetFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Red) : Throw New CancelledException - If Directory.GetFileSystemEntries(TargetFolder).Length > 0 Then Hint("请选择一个空文件夹作为安装目标!", HintType.Red) : Throw New CancelledException + If Not DirectoryUtils.IsEmpty(TargetFolder) Then Hint("请选择一个空文件夹作为安装目标!", HintType.Red) : Throw New CancelledException '解压 Dim Loader As New LoaderCombo(Of String)("解压压缩包", { New LoaderTask(Of String, Integer)("解压压缩包", Sub(Task As LoaderTask(Of String, Integer)) ExtractModpackFiles(TargetFolder, FileAddress, Task, 0.95) '加入文件夹列表 - PageSelectLeft.AddFolder(TargetFolder & ArchiveBaseFolder, GetFolderNameFromPath(TargetFolder), False) + PageSelectLeft.AddFolder(TargetFolder & ArchiveBaseFolder, PathUtils.GetLastPart(TargetFolder), False) Thread.Sleep(400) '避免文件争用 RunInUi(Sub() FrmMain.PageChange(FormMain.PageType.InstanceSelect)) End Sub) diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb b/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb index 371dd9e..1935c28 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModWatcher.vb @@ -33,13 +33,13 @@ HasRunningMinecraft = False FrmMain.BtnExtraShutdown.ShowRefresh() '音乐播放 - If Settings.Get("UiMusicStop") Then - RunInUi(Sub() If MusicResume() Then Log("[Music] 已根据设置,在结束后开始音乐播放")) - ElseIf Settings.Get("UiMusicStart") Then - RunInUi(Sub() If MusicPause() Then Log("[Music] 已根据设置,在结束后暂停音乐播放")) + If Settings.Get(Of Boolean)("UiMusicStop") Then + RunInUi(Sub() If MusicResume() Then Logger.Info("已根据设置,在结束后开始音乐播放")) + ElseIf Settings.Get(Of Boolean)("UiMusicStart") Then + RunInUi(Sub() If MusicPause() Then Logger.Info("已根据设置,在结束后暂停音乐播放")) End If '启动器可见性 - Select Case Settings.Get("LaunchArgumentVisible") + Select Case Settings.Get(Of Integer)("LaunchArgumentVisible") Case 2 '直接关闭 If TriggerLauncherShutdown Then @@ -105,7 +105,7 @@ Loop WatcherLog("Minecraft 日志监控已退出") Catch ex As Exception - Log(ex, "Minecraft 日志监控主循环出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "Minecraft 日志监控主循环出错") State = MinecraftState.Ended End Try End Sub, "Minecraft Watcher PID " & PID) @@ -174,7 +174,7 @@ End If End If Catch ex As Exception - Log(ex, "输出 Minecraft 日志失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "输出 Minecraft 日志失败") End Try End Sub Public LatestLog As New Queue(Of String) @@ -186,6 +186,7 @@ '加入预存储 LatestLog.Enqueue(Text) If LatestLog.Count >= 501 Then LatestLog.Dequeue() + Logger.Trace(Text) '进度处理 If LogProgress < 1 Then WatcherLog("日志 1/5:已出现日志输出") @@ -265,7 +266,7 @@ MinecraftWindow = TryGetMinecraftWindow() Catch ex As ComponentModel.Win32Exception '拒绝访问(#1062) - Log(ex, "由于反作弊或安全软件拦截,PCL 无法操作游戏窗口", NotifyLevel.AllUsers) + Logger.Error(ex, "由于反作弊或安全软件拦截,PCL 无法操作游戏窗口", LogBehavior.Toast) IsWindowFinished = True End Try If MinecraftWindow Is Nothing Then Return @@ -277,7 +278,7 @@ WatcherLog($"Minecraft 窗口已加载:{MinecraftWindowName}({MinecraftWindowHandle.ToInt64})") IsWindowFinished = True '最大化 - If Settings.Get("LaunchArgumentWindowType") = 4 Then + If Settings.Get(Of Integer)("LaunchArgumentWindowType") = 4 Then RunInNewThread( Sub() Try @@ -287,7 +288,7 @@ ShowWindow(WindowHandle, 3) WatcherLog($"已最大化 Minecraft 窗口:{MinecraftWindowHandle.ToInt64}") Catch ex As Exception - Log(ex, "最大化 Minecraft 窗口时出现错误") + Logger.Warn(ex, "最大化 Minecraft 窗口时出现错误") End Try End Sub, "MinecraftWindowMaximize") End If @@ -297,7 +298,7 @@ End If IsWindowAppeared = True Catch ex As Exception - Log(ex, "检查 Minecraft 窗口失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "检查 Minecraft 窗口失败") End Try End Sub ''' @@ -305,10 +306,10 @@ ''' Nothing 代表未找到。 ''' Private Function TryGetMinecraftWindow() As KeyValuePair(Of IntPtr, String)? - TryGetMinecraftWindow = Nothing + Dim Result = Nothing EnumWindows( Sub(hwnd As IntPtr, lParam As Integer) - If TryGetMinecraftWindow IsNot Nothing Then Return + If Result IsNot Nothing Then Return '检查类名 Dim str As New StringBuilder(512) GetClassName(hwnd, str, str.Capacity) @@ -327,13 +328,13 @@ Try If Process.GetProcessById(ProcessId).StartTime < GameProcess.StartTime Then Return '需要是此后启动的进程 Catch ex As Exception - Log(ex, "枚举 Minecraft 窗口进程失败") + Logger.Warn(ex, "枚举 Minecraft 窗口进程失败") Return End Try '返回 - TryGetMinecraftWindow = New KeyValuePair(Of IntPtr, String)(hwnd, WindowText) + Result = New KeyValuePair(Of IntPtr, String)(hwnd, WindowText) End Sub, 0) - Return TryGetMinecraftWindow + Return Result End Function Private Delegate Sub EnumWindowsSub(hwnd As IntPtr, lParam As Integer) Private Declare Function EnumWindows Lib "user32" (hWnd As EnumWindowsSub, lParam As Integer) As Boolean @@ -363,7 +364,7 @@ Analyzer.Output(False, New List(Of String) From {Instance.PathVersion & Instance.Name & ".json", PathExeFolder & "PCL\Log1.txt", PathExeFolder & "PCL\LatestLaunch.bat"}) Catch ex As Exception - Log(ex, "崩溃分析失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "崩溃分析失败") End Try End Sub, "Crash Analyzer") End Sub @@ -376,7 +377,7 @@ If Not GameProcess.HasExited Then GameProcess.Kill() WatcherLog("已强制结束 Minecraft 进程") Catch ex As Exception - Log(ex, "强制结束 Minecraft 进程失败", NotifyLevel.AllUsers) + Logger.Error(ex, "强制结束 Minecraft 进程失败", LogBehavior.Toast) End Try End Sub diff --git a/Plain Craft Launcher 2/Modules/ModEvent.vb b/Plain Craft Launcher 2/Modules/ModEvent.vb index b3d67bd..57bf00d 100644 --- a/Plain Craft Launcher 2/Modules/ModEvent.vb +++ b/Plain Craft Launcher 2/Modules/ModEvent.vb @@ -175,7 +175,7 @@ Public Class CustomEvent ''' Public Shared Sub Raise(Type As EventType, Arg As String) If Type = EventType.None Then Return - Log($"[Control] 执行自定义事件:{Type}, {Arg}") + Logger.Info($"执行自定义事件:{Type}, {Arg}") If Arg Is Nothing Then Arg = "" Dim Args As String() = Arg.Split("|") Try @@ -196,7 +196,7 @@ Public Class CustomEvent '确认实际路径 Dim ActualPaths = GetAbsoluteUrls(Args(0), Type) Dim Location = ActualPaths(0), WorkingDir = ActualPaths(1) - Log($"[Control] 打开类自定义事件实际路径:{Location},工作目录:{WorkingDir}") + Logger.Info($"打开类自定义事件实际路径:{Location},工作目录:{WorkingDir}") '执行 If Type = EventType.打开帮助 Then PageOtherHelp.EnterHelpPage(Location) @@ -210,7 +210,7 @@ Public Class CustomEvent StartProcess(Info) End If Catch ex As Exception - Log(ex, "执行打开类自定义事件失败", NotifyLevel.MsgBox) + Logger.Error(ex, "执行打开类自定义事件失败", LogBehavior.Alert) End Try End Sub) @@ -289,7 +289,7 @@ Public Class CustomEvent Try Select Case Args.Length Case 1 - PageOtherTest.StartCustomDownload(Args(0), GetFileNameFromPath(Args(0))) + PageOtherTest.StartCustomDownload(Args(0), PathUtils.GetLastPart(Args(0))) Case 2 PageOtherTest.StartCustomDownload(Args(0), Args(1)) Case Else @@ -328,7 +328,7 @@ Public Class CustomEvent MyMsgBox("未知的事件类型:" & Type & vbCrLf & "请检查事件类型填写是否正确,或者 PCL 是否为最新版本。", "事件执行失败") End Select Catch ex As Exception - Log(ex, $"事件执行失败({Type}, {Arg})", NotifyLevel.MsgBox) + Logger.Error(ex, $"事件执行失败({Type}, {Arg})", LogBehavior.Alert) End Try End Sub @@ -346,7 +346,7 @@ Public Class CustomEvent '获取文件名 Dim RawFileName As String Try - RawFileName = GetFileNameFromPath(RelativeUrl) + RawFileName = PathUtils.GetLastPart(RelativeUrl) If Not RawFileName.EndsWithF(".json", True) Then Throw New Exception("未指向 .json 后缀的文件") Catch ex As Exception Throw New Exception("联网帮助页面须指向一个帮助 JSON 文件,并在同路径下包含相应 XAML 文件!" & vbCrLf & @@ -356,7 +356,7 @@ Public Class CustomEvent End Try '下载文件 Dim LocalTemp As String = RequestTaskTempFolder() & RawFileName - Log("[Event] 转换网络资源:" & RelativeUrl & " -> " & LocalTemp) + Logger.Info($"转换网络资源:{RelativeUrl} -> {LocalTemp}") Try NetDownloadByClient(RelativeUrl, LocalTemp) NetDownloadByClient(RelativeUrl.Replace(".json", ".xaml"), LocalTemp.Replace(".json", ".xaml")) @@ -377,25 +377,25 @@ Public Class CustomEvent If RelativeUrl.Contains(":\") Then '绝对路径 Location = RelativeUrl - Log("[Control] 自定义事件中由绝对路径" & Type & ":" & Location) - ElseIf File.Exists(PathExeFolder & "PCL\" & RelativeUrl) Then + Logger.Info($"自定义事件中由绝对路径{Type}:{Location}") + ElseIf FileUtils.Exists(PathExeFolder & "PCL\" & RelativeUrl) Then '相对 PCL 文件夹的路径 Location = PathExeFolder & "PCL\" & RelativeUrl - Log("[Control] 自定义事件中由相对 PCL 文件夹的路径" & Type & ":" & Location) - ElseIf File.Exists(PathExeFolder & "PCL\Help\" & RelativeUrl) Then + Logger.Info($"自定义事件中由相对 PCL 文件夹的路径{Type}:{Location}") + ElseIf FileUtils.Exists(PathExeFolder & "PCL\Help\" & RelativeUrl) Then '相对 PCL 本地帮助文件夹的路径 Location = PathExeFolder & "PCL\Help\" & RelativeUrl WorkingDir = PathExeFolder & "PCL\Help\" - Log("[Control] 自定义事件中由相对 PCL 本地帮助文件夹的路径" & Type & ":" & Location) - ElseIf Type = EventType.打开帮助 AndAlso File.Exists(PathTemp & "Help\" & RelativeUrl) Then + Logger.Info($"自定义事件中由相对 PCL 本地帮助文件夹的路径{Type}:{Location}") + ElseIf Type = EventType.打开帮助 AndAlso FileUtils.Exists(PathTemp & "Help\" & RelativeUrl) Then '相对 PCL 自带帮助文件夹的路径 Location = PathTemp & "Help\" & RelativeUrl WorkingDir = PathTemp & "Help\" - Log("[Control] 自定义事件中由相对 PCL 自带帮助文件夹的路径" & Type & ":" & Location) + Logger.Info($"自定义事件中由相对 PCL 自带帮助文件夹的路径{Type}:{Location}") ElseIf Type = EventType.打开文件 OrElse Type = EventType.执行命令 Then '直接使用原有路径启动程序 Location = RelativeUrl - Log("[Control] 自定义事件中直接" & Type & ":" & Location) + Logger.Info($"自定义事件中直接{Type}:{Location}") Else '打开帮助,但是格式不对劲 Throw New FileNotFoundException("未找到 EventData 指向的本地 xaml 文件:" & RelativeUrl, RelativeUrl) @@ -408,7 +408,7 @@ Public Class CustomEvent ''' 弹出安全确认弹窗。返回是否继续执行。 ''' Private Shared Function EventSafetyConfirm(Message As String) As Boolean - If Settings.Get("HintCustomCommand") Then Return True + If Settings.Get(Of Boolean)("HintCustomCommand") Then Return True Select Case MyMsgBox(Message & vbCrLf & "请在确认没有安全隐患后再继续。", "执行确认", "继续", "继续且今后不再要求确认", "取消") Case 1 Return True diff --git a/Plain Craft Launcher 2/Modules/ModMain.vb b/Plain Craft Launcher 2/Modules/ModMain.vb index f8f2a0a..70afc56 100644 --- a/Plain Craft Launcher 2/Modules/ModMain.vb +++ b/Plain Craft Launcher 2/Modules/ModMain.vb @@ -133,11 +133,11 @@ Public Module ModMain End If '结束处理 EndHint: - If CurrentHint.Log Then Log("[UI] 弹出提示:" & CurrentHint.Text) + If CurrentHint.Log Then Logger.Info($"弹出提示:{CurrentHint.Text}") HintWaiting.RemoveAt(0) Loop Catch ex As Exception - Log(ex, "显示弹出提示失败", NotifyLevel.Silent) + Logger.Info(ex, "显示弹出提示失败") End Try End Sub Private Sub HideAllHint() @@ -256,7 +256,7 @@ EndHint: MsgBox(Caption, MsgBoxStyle.OkOnly + If(IsWarn, MsgBoxStyle.Critical, MsgBoxStyle.Question), Title) Converter.Result = 1 End If - Log("[Control] 主窗体加载完成前出现意料外的等待弹窗:" & Button1 & "," & Button2 & "," & Button3, NotifyLevel.DebugModeOnly) + Logger.Warn($"主窗体加载完成前出现意料外的等待弹窗:{Button1},{Button2},{Button3}") Else Try FrmMain.DragStop() @@ -267,7 +267,7 @@ EndHint: ComponentDispatcher.PopModal() End Try End If - Log("[Control] 普通弹框返回:" & If(Converter.Result, "null")) + Logger.Info($"普通弹框返回:{If(Converter.Result, "null")}") Return Converter.Result Else '不进行等待,直接返回 @@ -298,7 +298,7 @@ EndHint: Finally ComponentDispatcher.PopModal() End Try - Log("[Control] 输入弹框返回:" & If(Converter.Result, "null")) + Logger.Info($"输入弹框返回:{If(Converter.Result, "null")}") Return Converter.Result End Function ''' @@ -321,7 +321,7 @@ EndHint: Finally ComponentDispatcher.PopModal() End Try - Log("[Control] 选择弹框返回:" & If(Converter.Result, "null")) + Logger.Info($"选择弹框返回:{If(Converter.Result, "null")}") Return Converter.Result End Function @@ -354,7 +354,7 @@ EndHint: If FrmMain.PanMsg.Visibility <> Visibility.Collapsed Then FrmMain.PanMsg.Visibility = Visibility.Collapsed End If Catch ex As Exception - Log(ex, "处理等待中的弹窗失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "处理等待中的弹窗失败") End Try End Sub @@ -488,8 +488,8 @@ EndHint: ''' Public Sub New(FilePath As String) RawPath = FilePath - Dim JsonData As JObject = GetJson(ArgumentReplace(ReadFile(FilePath), AddressOf EscapeUtils.XmlEscape)) - If JsonData Is Nothing Then Throw New FileNotFoundException("未找到帮助文件:" & FilePath, FilePath) + If Not FileUtils.Exists(FilePath) Then Throw New FileNotFoundException("未找到帮助文件:" & FilePath, FilePath) + Dim JsonData As JObject = GetJson(ArgumentReplace(FileUtils.ReadAsString(FilePath), AddressOf EscapeUtils.XmlEscape)) '加载常规信息 If JsonData("Title") IsNot Nothing Then Title = JsonData("Title") @@ -508,13 +508,13 @@ EndHint: Next '加载事件信息 If If(JsonData("IsEvent"), False) Then - EventType = [Enum].Parse(GetType(CustomEvent.EventType), JsonData("EventType").ToString) + EventType = JsonData("EventType").ToObject(Of CustomEvent.EventType) EventData = If(JsonData("EventData"), "") IsEvent = True Else Dim XamlAddress As String = FilePath.Lower.Replace(".json", ".xaml") - If File.Exists(XamlAddress) Then - XamlContent = ReadFile(XamlAddress) + If FileUtils.Exists(XamlAddress) Then + XamlContent = FileUtils.ReadAsString(XamlAddress) IsEvent = False Else Throw New FileNotFoundException("未找到帮助条目 .json 对应的 .xaml 文件(" & XamlAddress & ")") @@ -577,42 +577,42 @@ EndHint: Try Dim IgnoreList As New List(Of String) '读取自定义文件 - If Directory.Exists(PathExeFolder & "PCL\Help\") Then - For Each File In EnumerateFiles(PathExeFolder & "PCL\Help\") - Select Case File.Extension.Lower - Case ".helpignore" + If DirectoryUtils.Exists(PathExeFolder & "PCL\Help\") Then + For Each File In DirectoryUtils.GetFiles(PathExeFolder & "PCL\Help\") + Select Case PathUtils.GetExtension(File) + Case "helpignore" '加载忽略列表 - Log("[Help] 发现 .helpignore 文件:" & File.FullName) - For Each Line In ReadFile(File.FullName).Split(vbCrLf.ToCharArray) + Logger.Info($"发现 .helpignore 文件:{File}") + For Each Line In FileUtils.ReadAsLines(File, True) Dim RealString As String = Line.BeforeFirst("#").Trim If String.IsNullOrWhiteSpace(RealString) Then Continue For IgnoreList.Add(RealString) - If ModeDebug Then Log("[Help] > " & RealString) + Logger.Trace($"> {RealString}") Next - Case ".json" - FileList.Add(File.FullName) + Case "json" + FileList.Add(File) End Select Next End If - Log("[Help] 已扫描 PCL 文件夹下的帮助文件,目前总计 " & FileList.Count & " 条") + Logger.Info($"已扫描 PCL 文件夹下的帮助文件,目前总计 {FileList.Count} 条") '读取自带文件 - For Each File In EnumerateFiles(PathTemp & "Help") + For Each File In DirectoryUtils.GetFiles(PathTemp & "Help") '跳过非 json 文件与以 . 开头的文件夹 - If File.Extension.Lower <> ".json" OrElse File.Directory.FullName.Replace(PathTemp & "Help", "").Contains("\.") Then Continue For + If PathUtils.RemoveLastPart(File).Replace(PathTemp & "Help", "").Contains("\.") OrElse PathUtils.GetExtension(File) <> "json" Then Continue For '检查忽略列表 - Dim RealPath As String = File.FullName.Replace(PathTemp & "Help\", "") + Dim RealPath As String = File.Replace(PathTemp & "Help\", "") For Each Ignore In IgnoreList - If RegexCheck(RealPath, Ignore) Then - If ModeDebug Then Log("[Help] 已忽略 " & RealPath & ":" & Ignore) + If RealPath.RegexCheck(Ignore) Then + Logger.Trace($"已忽略 {RealPath}:{Ignore}") GoTo NextFile End If Next - FileList.Add(File.FullName) + FileList.Add(File) NextFile: Next - Log("[Help] 已扫描缓存文件夹下的帮助文件,目前总计 " & FileList.Count & " 条") + Logger.Info($"已扫描缓存文件夹下的帮助文件,目前总计 {FileList.Count} 条") Catch ex As Exception - Log(ex, "检查帮助文件夹失败", NotifyLevel.MsgBox) + Logger.Error(ex, "检查帮助文件夹失败", LogBehavior.Alert) End Try If Loader.IsInterrupted Then Return @@ -622,9 +622,9 @@ NextFile: Try Dim Entry As New HelpEntry(FilePath) Dict.Add(Entry) - If ModeDebug Then Log("[Help] 已加载的帮助条目:" & Entry.Title & " ← " & FilePath) + Logger.Trace($"已加载的帮助条目:{Entry.Title} ← {FilePath}") Catch ex As Exception - Log(ex, "初始化帮助条目失败(" & FilePath & ")", NotifyLevel.MsgBox) + Logger.Error(ex, $"初始化帮助条目失败({FilePath})", LogBehavior.Alert) End Try Next @@ -634,7 +634,7 @@ NextFile: Loader.Output = Dict Catch ex As Exception - Log(ex, "帮助列表初始化失败") + Logger.Warn(ex, "帮助列表初始化失败") Throw End Try End SyncLock @@ -643,13 +643,12 @@ NextFile: ''' 尝试解压内置帮助文件。 ''' Public Sub HelpTryExtract() - If Settings.Get("SystemHelpVersion") <> VersionCode OrElse Not File.Exists(PathTemp & "Help\启动器\备份设置.xaml") Then - DeleteDirectory(PathTemp & "Help") - DirectoryUtils.Create(PathTemp & "Help") - FileUtils.Write(PathTemp & "Cache\Help.zip", GetResources("Help")) - ExtractCompressedFile(PathTemp & "Cache\Help.zip", PathTemp & "Help") + If Settings.Get(Of Integer)("SystemHelpVersion") <> VersionCode OrElse Not FileUtils.Exists(PathTemp & "Help\启动器\备份设置.xaml") Then + DirectoryUtils.Delete(PathTemp & "Help") + ExtractResources(PathTemp & "Cache\Help.zip", "Help") + FileUtils.ExtractToDirectory(PathTemp & "Cache\Help.zip", PathTemp & "Help") Settings.Set("SystemHelpVersion", VersionCode) - Log("[Help] 已解压内置帮助文件,目前状态:" & File.Exists(PathTemp & "Help\启动器\备份设置.xaml"), NotifyLevel.DebugModeOnly) + Logger.Warn($"已解压内置帮助文件,目前状态:{FileUtils.Exists(PathTemp & "Help\启动器\备份设置.xaml")}") End If End Sub @@ -663,7 +662,7 @@ NextFile: If _IsAprilEnabled Is Nothing Then _IsAprilEnabled = Date.Now.Month = 4 AndAlso Date.Now.Day = 1 AndAlso - Settings.Get("AprilDoneYear") <> Date.Now.Year '成功后同年内则不再触发 + Settings.Get(Of Integer)("AprilDoneYear") <> Date.Now.Year '成功后同年内则不再触发 End If Return _IsAprilEnabled.Value End Get @@ -774,7 +773,7 @@ NextFile: End If Catch ex As Exception - Log(ex, "愚人节移动出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "愚人节移动出错") End Try End Sub @@ -790,7 +789,7 @@ NextFile: PostMessage(Handle, 400 * 16 + 2, 0, 0) SetForegroundWindow(Handle) '不在这里放不行,神秘 WinAPI,建议别动 Catch ex As Exception - Log(ex, "设置窗口置顶失败", NotifyLevel.AllUsers) + Logger.Error(ex, "设置窗口置顶失败", LogBehavior.Toast) End Try End Sub Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ClassName As String, WindowName As String) As IntPtr @@ -808,19 +807,19 @@ NextFile: Using ReadOnlyKey = My.Computer.Registry.CurrentUser.OpenSubKey(REG_KEY, False) If ReadOnlyKey IsNot Nothing Then If REG_VALUE = ReadOnlyKey.GetValue(Executeable)?.ToString() Then - Log($"[System] 无需调整显卡设置:{Executeable}") + Logger.Info($"无需调整显卡设置:{Executeable}") Return End If Else '创建父级键 - Log($"[System] 需要创建显卡设置的父级键") + Logger.Info($"需要创建显卡设置的父级键") My.Computer.Registry.CurrentUser.CreateSubKey(REG_KEY) End If End Using '写入新设置 Using WriteKey = My.Computer.Registry.CurrentUser.OpenSubKey(REG_KEY, True) WriteKey.SetValue(Executeable, REG_VALUE) - Log($"[System] 已调整显卡设置:{Executeable}") + Logger.Info($"已调整显卡设置:{Executeable}") End Using End Sub @@ -829,12 +828,16 @@ NextFile: ''' Public Function ArgumentReplace(Text As String, Optional EscapeHandler As Func(Of String, String) = Nothing, Optional ReplaceTime As Boolean = True) As String If Text Is Nothing OrElse Not Text.Contains("{") Then Return Text - '预处理 + '预处理(注意,文件夹必须以 \ 结尾) Static Replacer As Func(Of String, String) = Function(s As String) As String If s Is Nothing Then Return "" If EscapeHandler Is Nothing Then Return s - If s.Contains(":\") Then s = FileUtils.ShortenPath(s) + If s.Contains(":\") Then + Dim IsFolder = s.EndsWithF("\") OrElse s.EndsWithF("/") + s = PathUtils.ToShortPath(s) + If IsFolder Then s = PathUtils.AddSlashSuffix(s) + End If Return EscapeHandler(s) End Function '基础 @@ -844,10 +847,10 @@ NextFile: Text = Text.Replace("{pcl_build_type}", Replacer(BuildType.ToString)) Text = Text.Replace("{pcl_branch}", Replacer(VersionBranchMain)) Text = Text.Replace("{identify}", Replacer(Identify)) - Text = Text.Replace("{path}", Replacer(PathExeFolder)) + Text = Text.Replace("{path}", Replacer(PathUtils.CurrentFolder)) Text = Text.Replace("{path_with_name}", Replacer(PathExe)) Text = Text.Replace("{path_temp}", Replacer(PathTemp)) - Text = Text.ReplaceOnDemand("{pcl_md5}", Function() Replacer(GetFileMD5(PathExe))) + Text = Text.Replace("{pcl_md5}", Function() Replacer(HashUtils.ComputeFromFile(PathExe, HashUtils.HashMethod.Md5))) '时间 If ReplaceTime Then '在窗口标题中,时间会被后续动态替换,所以此时不应该替换 Text = Text.Replace("{date}", Replacer(Date.Now.ToString("yyyy'/'M'/'d"))) @@ -915,12 +918,12 @@ NextFile: IsTaskTempCleared = True IsTaskTempClearing = True Try - Log("[System] 开始清理任务缓存文件夹") - DeleteDirectory($"{OsDrive}ProgramData\PCL\TaskTemp\") - DeleteDirectory($"{PathTemp}TaskTemp\") - Log("[System] 已清理任务缓存文件夹") + Logger.Info("开始清理任务缓存文件夹") + DirectoryUtils.Delete($"{OsDrive}ProgramData\PCL\TaskTemp\") + DirectoryUtils.Delete($"{PathTemp}TaskTemp\") + Logger.Info("已清理任务缓存文件夹") Catch ex As Exception - Log(ex, "清理任务缓存文件夹失败") + Logger.Warn(ex, "清理任务缓存文件夹失败") Finally IsTaskTempClearing = False End Try @@ -955,6 +958,52 @@ NextFile: Return ResultFolder End Function +#End Region + +#Region "反馈与遥测" + + '反馈 + Public Sub Feedback(Optional ShowMsgbox As Boolean = True, Optional ForceOpenLog As Boolean = False) + On Error Resume Next + FeedbackInfo() + If ForceOpenLog OrElse (ShowMsgbox AndAlso MyMsgBox("若你在汇报一个 Bug,请点击 打开文件夹 按钮,并上传 Log(1~5).txt 中包含错误信息的文件。" & vbCrLf & "游戏崩溃一般与启动器无关,请不要因为游戏崩溃而提交反馈。", "反馈提交提醒", "打开文件夹", "不需要") = 1) Then + OpenExplorer(PathExeFolder & "PCL\Log1.txt") + End If + OpenWebsite("https://github.com/Meloong-Git/PCL/issues/") + End Sub + ''' + ''' 在日志中输出系统诊断信息。 + ''' + Public Sub FeedbackInfo() + On Error Resume Next + Logger.Info($"诊断信息:{vbCrLf}" & + "操作系统:" & My.Computer.Info.OSFullName & "(32 位:" & Is32BitSystem & ")" & vbCrLf & + "剩余内存:" & Int(My.Computer.Info.AvailablePhysicalMemory / 1024 / 1024) & " M / " & Int(My.Computer.Info.TotalPhysicalMemory / 1024 / 1024) & " M" & vbCrLf & + "DPI:" & DPI & "(" & Math.Round(DPI / 96, 2) * 100 & "%)" & vbCrLf & + "MC 文件夹:" & If(McFolderSelected, "Nothing") & vbCrLf & + "文件位置:" & PathExeFolder) + End Sub + + '遥测 + Public Sub Telemetry([Event] As String, ParamArray Datas As String()) + If BuildType = BuildTypes.Debug Then Return '开发版不上传遥测 + If Not Settings.Get(Of Boolean)("SystemSystemTelemetry") Then Return '用户关闭了遥测 + If Not ClsBaseUrl.StartsWithF("http") Then Return '开源版没有设置遥测地址 + RunInNewThread( + Sub() + Try + Logger.Info($"匿名数据上报:{[Event]}") + Dim Url As String = $"{ClsBaseUrl}&Event={EscapeUtils.UrlEscape([Event])}" + For i = 0 To Datas.Length - 1 Step 2 + Url &= "&" & EscapeUtils.UrlEscape(Datas(i)) & "=" & EscapeUtils.UrlEscape(Datas(i + 1).ReplaceLineEndings(vbLf, mergeMultiple:=True)) + Next + NetRequestByClient(Url, MakeLog:=False) + Catch ex As Exception + Logger.Warn(ex, "匿名数据上报失败") + End Try + End Sub, "Telemetry", ThreadPriority.Lowest) + End Sub + #End Region Public DragControl = Nothing @@ -970,7 +1019,7 @@ NextFile: If ThemeDontClick = 2 Then ThemeRefresh() #End Region Catch ex As Exception - Log(ex, "短程主时钟执行异常", NotifyLevel.Critical) + Logger.Error(ex, "短程主时钟执行异常", LogBehavior.AlertThenCrash) End Try Timer4Count += 1 If Timer4Count = 4 Then @@ -980,7 +1029,7 @@ NextFile: If ThemeNow = 12 Then ThemeRefresh() #End Region Catch ex As Exception - Log(ex, "中程主时钟执行异常", NotifyLevel.DebugModeOnly) + Logger.Warn(ex, "中程主时钟执行异常") End Try End If Timer150Count += 1 @@ -999,7 +1048,7 @@ NextFile: End Sub) #End Region Catch ex As Exception - Log(ex, "长程主时钟执行异常", NotifyLevel.Critical) + Logger.Error(ex, "长程主时钟执行异常", LogBehavior.AlertThenCrash) End Try End If End Sub @@ -1012,7 +1061,7 @@ NextFile: Thread.Sleep(50 * 0.98) Loop Catch ex As Exception - Log(ex, "程序主时钟出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "程序主时钟出错") End Try End Sub, "Timer Main") If Not IsAprilEnabled Then Return @@ -1028,7 +1077,7 @@ NextFile: Thread.Sleep(1) Loop Catch ex As Exception - Log(ex, "愚人节主时钟出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "愚人节主时钟出错") End Try End Sub, "Timer Main Fool") End Sub diff --git a/Plain Craft Launcher 2/Modules/ModMusic.vb b/Plain Craft Launcher 2/Modules/ModMusic.vb index 4640185..ea9dcf8 100644 --- a/Plain Craft Launcher 2/Modules/ModMusic.vb +++ b/Plain Craft Launcher 2/Modules/ModMusic.vb @@ -24,22 +24,21 @@ Public Module ModMusic If MusicAllList Is Nothing Then MusicAllList = New List(Of String) DirectoryUtils.Create(PathExeFolder & "PCL\Musics\") - For Each File In EnumerateFiles(PathExeFolder & "PCL\Musics\") + For Each File In DirectoryUtils.GetFiles(PathExeFolder & "PCL\Musics\") '文件夹可能会被加入 .ini 文件夹配置文件、一些乱七八糟的 .jpg 文件啥的 - Dim Ext As String = File.Extension.Lower - If {".ini", ".jpg", ".txt", ".cfg", ".lrc", ".db", ".png"}.Contains(Ext) Then Continue For - MusicAllList.Add(File.FullName) + If {"ini", "jpg", "txt", "cfg", "lrc", "db", "png"}.Contains(PathUtils.GetExtension(File)) Then Continue For + MusicAllList.Add(File) Next End If '打乱顺序播放 - MusicWaitingList = If(Settings.Get("UiMusicRandom"), New List(Of String)(MusicAllList).Shuffle().ToList, New List(Of String)(MusicAllList)) + MusicWaitingList = If(Settings.Get(Of Boolean)("UiMusicRandom"), New List(Of String)(MusicAllList).Shuffle().ToList, New List(Of String)(MusicAllList)) If PreventFirst IsNot Nothing AndAlso MusicWaitingList.FirstOrDefault = PreventFirst Then '若需要避免成为第一项的为第一项,则将它放在最后 MusicWaitingList.RemoveAt(0) MusicWaitingList.Add(PreventFirst) End If Catch ex As Exception - Log(ex, "初始化音乐列表失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "初始化音乐列表失败") End Try End Sub ''' @@ -47,16 +46,18 @@ Public Module ModMusic ''' 如果没有,可能会返回 Nothing。 ''' Private Function DequeueNextMusicAddress() As String + Dim Result As String '初始化,确保存在音乐 If MusicAllList Is Nothing OrElse Not MusicAllList.Any() OrElse Not MusicWaitingList.Any() Then MusicListInit(False) '出列下一个音乐,如果出列结束则生成新列表 If MusicWaitingList.Any() Then - DequeueNextMusicAddress = MusicWaitingList(0) + Result = MusicWaitingList(0) MusicWaitingList.RemoveAt(0) Else - DequeueNextMusicAddress = Nothing + Result = Nothing End If - If Not MusicWaitingList.Any() Then MusicListInit(False, DequeueNextMusicAddress) + If Not MusicWaitingList.Any() Then MusicListInit(False, Result) + Return Result End Function #End Region @@ -81,7 +82,7 @@ Public Module ModMusic If MusicState = MusicStates.Pause Then FrmMain.BtnExtraMusic.Logo = Logo.IconPlay FrmMain.BtnExtraMusic.LogoScale = 0.8 - ToolTipText = "已暂停:" & Path.GetFileNameWithoutExtension(MusicCurrent) + ToolTipText = "已暂停:" & PathUtils.GetFileNameWithoutExtension(MusicCurrent) If MusicAllList.Count > 1 Then ToolTipText += vbCrLf & "左键恢复播放,右键播放下一曲。" Else @@ -90,7 +91,7 @@ Public Module ModMusic Else FrmMain.BtnExtraMusic.Logo = Logo.IconMusic FrmMain.BtnExtraMusic.LogoScale = 1 - ToolTipText = "正在播放:" & Path.GetFileNameWithoutExtension(MusicCurrent) + ToolTipText = "正在播放:" & PathUtils.GetFileNameWithoutExtension(MusicCurrent) If MusicAllList.Count > 1 Then ToolTipText += vbCrLf & "左键暂停,右键播放下一曲。" Else @@ -103,7 +104,7 @@ Public Module ModMusic If FrmSetupUI IsNot Nothing Then FrmSetupUI.MusicRefreshUI() Catch ex As Exception - Log(ex, "刷新背景音乐 UI 失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "刷新背景音乐 UI 失败") End Try End Sub) End Sub @@ -121,7 +122,7 @@ Public Module ModMusic Case MusicStates.Play MusicPause() Case Else - Log("[Music] 音乐目前为停止状态,已强制尝试开始播放", NotifyLevel.DebugModeOnly) + Logger.Warn("音乐目前为停止状态,已强制尝试开始播放") MusicRefreshPlay(False) End Select End If @@ -133,14 +134,14 @@ Public Module ModMusic Public Sub MusicControlNext() If MusicAllList.IsSingle Then MusicStartPlay(MusicCurrent) - Hint("重新播放:" & GetFileNameFromPath(MusicCurrent), HintType.Green) + Hint("重新播放:" & PathUtils.GetLastPart(MusicCurrent), HintType.Green) Else Dim Address As String = DequeueNextMusicAddress() If Address Is Nothing Then Hint("没有可以播放的音乐!", HintType.Red) Else MusicStartPlay(Address) - Hint("正在播放:" & GetFileNameFromPath(Address), HintType.Green) + Hint("正在播放:" & PathUtils.GetLastPart(Address), HintType.Green) End If End If MusicRefreshUI() @@ -196,7 +197,7 @@ Public Module ModMusic Else Try MusicStartPlay(Address, IsFirstLoad) - If ShowHint Then Hint("背景音乐已刷新:" & GetFileNameFromPath(Address), HintType.Green, False) + If ShowHint Then Hint("背景音乐已刷新:" & PathUtils.GetLastPart(Address), HintType.Green, False) Catch End Try End If @@ -204,7 +205,7 @@ Public Module ModMusic MusicRefreshUI() Catch ex As Exception - Log(ex, "刷新背景音乐播放失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "刷新背景音乐播放失败") End Try End Sub ''' @@ -212,7 +213,7 @@ Public Module ModMusic ''' Private Sub MusicStartPlay(Address As String, Optional IsFirstLoad As Boolean = False) If Address Is Nothing Then Return - Log("[Music] 播放开始:" & Address) + Logger.Info($"播放开始:{Address}") MusicCurrent = Address RunInNewThread(Sub() MusicLoop(IsFirstLoad), "Music", ThreadPriority.BelowNormal) End Sub @@ -226,13 +227,13 @@ Public Module ModMusic If MusicState = MusicStates.Play Then RunInThread( Sub() - Log("[Music] 已暂停播放") + Logger.Info("已暂停播放") MusicNAudio?.Pause() MusicRefreshUI() End Sub) Return True Else - Log($"[Music] 无需暂停播放,当前状态为 {MusicState}") + Logger.Info($"无需暂停播放,当前状态为 {MusicState}") Return False End If End Function @@ -241,12 +242,12 @@ Public Module ModMusic ''' Public Function MusicResume() As Boolean If MusicState = MusicStates.Play OrElse Not MusicAllList.Any() Then - Log($"[Music] 无需继续播放,当前状态为 {MusicState}") + Logger.Info($"无需继续播放,当前状态为 {MusicState}") Return False Else RunInThread( Sub() - Log("[Music] 已恢复播放") + Logger.Info("已恢复播放") Try MusicNAudio?.Play() Catch 'https://github.com/Meloong-Git/PCL/pull/5415#issuecomment-2751135223 @@ -285,20 +286,20 @@ Public Module ModMusic Try Reader = New AudioFileReader(MusicCurrent) Catch ex As Exception - Log(ex, "使用 AudioFileReader 加载音频文件失败,换用 MediaFoundationReader 重试", NotifyLevel.DevelopOnly) + Logger.Warn(ex, "使用 AudioFileReader 加载音频文件失败,换用 MediaFoundationReader 重试") Reader = New MediaFoundationReader(MusicCurrent) End Try CurrentWave.Init(Reader) CurrentWave.Play() '第一次打开的暂停 - If IsFirstLoad AndAlso Not Settings.Get("UiMusicAuto") Then CurrentWave.Pause() + If IsFirstLoad AndAlso Not Settings.Get(Of Boolean)("UiMusicAuto") Then CurrentWave.Pause() MusicRefreshUI() '停止条件:播放完毕或变化 Dim PreviousVolume = 0 While CurrentWave.Equals(MusicNAudio) AndAlso Not CurrentWave.PlaybackState = PlaybackState.Stopped - If Settings.Get("UiMusicVolume") <> PreviousVolume Then + If Settings.Get(Of Integer)("UiMusicVolume") <> PreviousVolume Then '更新音量 - PreviousVolume = Settings.Get("UiMusicVolume") + PreviousVolume = Settings.Get(Of Integer)("UiMusicVolume") #Disable Warning BC40008 '类型或成员已过时 CurrentWave.Volume = PreviousVolume / 1000 #Enable Warning BC40008 '类型或成员已过时 @@ -311,7 +312,7 @@ Public Module ModMusic '当前音乐已播放结束,继续下一曲 If CurrentWave.PlaybackState = PlaybackState.Stopped AndAlso MusicAllList.Any Then MusicStartPlay(DequeueNextMusicAddress) Catch ex As Exception - Log(ex, "播放音乐出现内部错误(" & MusicCurrent & ")", NotifyLevel.DevelopOnly) + Logger.Warn(ex, $"播放音乐出现内部错误({MusicCurrent})") If TypeOf ex Is NAudio.MmException AndAlso ex.Message.Contains("AlreadyAllocated") Then Hint("你的音频设备正被其他程序占用。请在关闭占用的程序后重启 PCL,才能恢复音乐播放功能!", HintType.Red) Thread.Sleep(1000000000) @@ -322,9 +323,9 @@ Public Module ModMusic End If If Not (MusicCurrent.EndsWithF(".wav", True) OrElse MusicCurrent.EndsWithF(".mp3", True) OrElse MusicCurrent.EndsWithF(".flac", True)) OrElse ex.Message.Contains("0xC00D36C4") Then '#5096:不支持给定的 URL 的字节流类型。 (异常来自 HRESULT:0xC00D36C4) - Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 可能不支持此音乐格式,请将格式转换为 .wav、.mp3 或 .flac 后再试", HintType.Red) + Hint("播放音乐失败(" & PathUtils.GetLastPart(MusicCurrent) & "):PCL 可能不支持此音乐格式,请将格式转换为 .wav、.mp3 或 .flac 后再试", HintType.Red) Else - Log(ex, "播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & ")", NotifyLevel.AllUsers) + Logger.Error(ex, $"播放音乐失败({PathUtils.GetLastPart(MusicCurrent)})", LogBehavior.Toast) End If '将播放错误的音乐从列表中移除 MusicAllList.Remove(MusicCurrent) diff --git a/Plain Craft Launcher 2/Modules/ModSecret.vb b/Plain Craft Launcher 2/Modules/ModSecret.vb index 66c47f3..0809517 100644 --- a/Plain Craft Launcher 2/Modules/ModSecret.vb +++ b/Plain Craft Launcher 2/Modules/ModSecret.vb @@ -150,7 +150,7 @@ Friend Module ModSecret Application.Current.Resources("ColorObjectBg1") = CType(ColorBg1, Color) ThemeRefreshMain() Catch ex As Exception - Log(ex, "刷新主题颜色失败", NotifyLevel.AllUsers) + Logger.Warn(ex, "刷新主题颜色失败", NotifyLevel.AllUsers) End Try End Sub Public Sub ThemeRefreshMain() @@ -166,7 +166,7 @@ Friend Module ModSecret FrmMain.PanTitle.Background = Brush FrmMain.PanTitle.Background.Freeze() '主页面背景 - If Settings.Get("UiBackgroundColorful") Then + If Settings.Get(Of Boolean)("UiBackgroundColorful") Then Brush = New LinearGradientBrush With {.EndPoint = New Point(0.1, 1), .StartPoint = New Point(0.9, 0)} Brush.GradientStops.Add(New GradientStop With {.Offset = -0.1, .Color = New MyColor().FromHSL2(ColorHue - 15, ColorSat * 0.8, 91)}) Brush.GradientStops.Add(New GradientStop With {.Offset = 0.4, .Color = New MyColor().FromHSL2(ColorHue, ColorSat * 0.8, 91)}) @@ -219,16 +219,16 @@ Friend Module ModSecret ''' Public ServerConfig As JObject - Public ServerLoader As New LoaderTask(Of Integer, Integer)("PCL 配置更新", Sub() Log("[Server] 该版本中不包含更新通知功能……"), Priority:=ThreadPriority.BelowNormal) With + Public ServerLoader As New LoaderTask(Of Integer, Integer)("PCL 配置更新", Sub() Logger.Info("该版本中不包含更新通知功能……"), Priority:=ThreadPriority.BelowNormal) With {.ReloadTimeout = 1000 * 60 * 60} '超时 1 小时 #End Region #Region "赞助等级" - Public ReadOnly Property DonationRank As DonationRanks + Public ReadOnly Property CurrentRank As DonationRank Get - Return DonationRanks.None + Return DonationRank.None End Get End Property diff --git a/Plain Craft Launcher 2/Modules/Resource/ResourceFile.vb b/Plain Craft Launcher 2/Modules/Resource/LocalResourceFile.vb similarity index 88% rename from Plain Craft Launcher 2/Modules/Resource/ResourceFile.vb rename to Plain Craft Launcher 2/Modules/Resource/LocalResourceFile.vb index e912580..a38028e 100644 --- a/Plain Craft Launcher 2/Modules/Resource/ResourceFile.vb +++ b/Plain Craft Launcher 2/Modules/Resource/LocalResourceFile.vb @@ -1,7 +1,7 @@ ''' ''' 本地的社区资源文件。 ''' -Public Class ResourceFile +Public Class LocalResourceFile #Region "文件信息" @@ -13,7 +13,7 @@ Public Class ResourceFile Me.File = FileInfo End Sub Public Sub New(FullName As String) - Me.New(New FileInfo(FullName)) + Me.New(FileUtils.GetInfo(FullName)) End Sub ''' @@ -48,7 +48,7 @@ Public Class ResourceFile ''' ''' 在初始化结束之后,任何信息被后续更新时触发此事件。 ''' - Public Event OnUpdate(sender As ResourceFile) + Public Event OnUpdate(sender As LocalResourceFile) ''' ''' 可读名称。 @@ -57,7 +57,7 @@ Public Class ResourceFile Public Property Display As String Get If _Display Is Nothing Then _Display = ProjectVersion?.Display - If _Display Is Nothing Then _Display = Path.GetFileNameWithoutExtension(File.FullName) + If _Display Is Nothing Then _Display = PathUtils.GetFileNameWithoutExtension(File.FullName) Return _Display End Get Set(value As String) @@ -97,7 +97,7 @@ Public Class ResourceFile Return _Version End Get Set(value As String) - If _Version IsNot Nothing AndAlso RegexCheck(_Version, "[0-9.\-]+") Then Return + If _Version IsNot Nothing AndAlso _Version.RegexCheck("[0-9.\-]+") Then Return If value IsNot Nothing AndAlso value.ContainsIgnoreCase("version") Then value = "version" '需要修改的标识 _Version = value End Set @@ -118,16 +118,15 @@ Public Class ResourceFile Dim Jar As ZipArchive = Nothing Try '基础可用性检查 - If File.FullName.Length < 2 Then Throw New FileNotFoundException("错误的 Mod 文件路径(" & If(File.FullName, "null") & ")") - If Not IO.File.Exists(File.FullName) Then Throw New FileNotFoundException("未找到 Mod 文件(" & File.FullName & ")") + If Not FileUtils.Exists(File.FullName) Then Throw New FileNotFoundException("未找到 Mod 文件(" & File.FullName & ")") '打开 Jar 文件 - Jar = New ZipArchive(New FileStream(File.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)) + Jar = FileUtils.OpenZip(File.FullName) '信息获取 LoadMetadataFromJar(Jar) Catch ex As UnauthorizedAccessException - Log(ex, $"Mod 文件由于无权限无法打开({File.FullName})", NotifyLevel.DevelopOnly) + Logger.Warn(ex, $"Mod 文件由于无权限无法打开({File.FullName})") Catch ex As Exception - Log(ex, $"Mod 文件无法打开({File.FullName})", NotifyLevel.DevelopOnly) + Logger.Warn(ex, $"Mod 文件无法打开({File.FullName})") Finally If Jar IsNot Nothing Then Jar.Dispose() End Try @@ -140,7 +139,7 @@ Public Class ResourceFile Dim InfoEntry As ZipArchiveEntry = Jar.GetEntry("mcmod.info") Dim InfoString As String = Nothing If InfoEntry IsNot Nothing Then - InfoString = ReadFile(InfoEntry.Open()) + InfoString = InfoEntry.Open().ReadString() If InfoString.Length < 15 Then InfoString = Nothing End If If InfoString Is Nothing Then Exit Try @@ -157,7 +156,7 @@ Public Class ResourceFile Description = InfoObject("description") Version = InfoObject("version") Catch ex As Exception - Log(ex, $"读取 mcmod.info 时出现未知错误({File.FullName})", NotifyLevel.DevelopOnly) + Logger.Warn(ex, $"读取 mcmod.info 时出现未知错误({File.FullName})") End Try #End Region #Region "尝试使用 fabric.mod.json" @@ -166,7 +165,7 @@ Public Class ResourceFile Dim FabricEntry As ZipArchiveEntry = Jar.GetEntry("fabric.mod.json") Dim FabricText As String = Nothing If FabricEntry IsNot Nothing Then - FabricText = ReadFile(FabricEntry.Open(), Encoding.UTF8) + FabricText = FabricEntry.Open().ReadString(Encoding.UTF8) If Not FabricText.Contains("schemaVersion") Then FabricText = Nothing End If If FabricText Is Nothing Then Exit Try @@ -179,7 +178,7 @@ GotFabric: '加载成功 GoTo Finished Catch ex As Exception - Log(ex, "读取 fabric.mod.json 时出现未知错误(" & File.FullName & ")", NotifyLevel.DevelopOnly) + Logger.Warn(ex, $"读取 fabric.mod.json 时出现未知错误({File.FullName})") End Try #End Region #Region "尝试使用 mods.toml" @@ -188,13 +187,13 @@ GotFabric: Dim TomlEntry As ZipArchiveEntry = Jar.GetEntry("META-INF/mods.toml") Dim TomlText As String = Nothing If TomlEntry IsNot Nothing Then - TomlText = ReadFile(TomlEntry.Open()) + TomlText = TomlEntry.Open().ReadString() If TomlText.Length < 15 Then TomlText = Nothing End If If TomlText Is Nothing Then Exit Try '文件标准化:统一换行符为 vbLf,去除注释、头尾的空格、空行 Dim Lines As New List(Of String) - For Each Line In TomlText.ReplaceLineEndings(vbLf).Split(vbLf) '统一换行符 + For Each Line In TomlText.SplitLines(True) If Line.StartsWithF("#") Then '去除注释 Continue For ElseIf Line.Contains("#") Then @@ -268,7 +267,7 @@ GotFabric: '加载成功 GoTo Finished Catch ex As Exception - Log(ex, $"读取 mods.toml 时出现未知错误({File.FullName})", NotifyLevel.DevelopOnly) + Logger.Warn(ex, $"读取 mods.toml 时出现未知错误({File.FullName})") End Try #End Region #Region "尝试使用 fml_cache_annotation.json" @@ -277,7 +276,7 @@ GotFabric: Dim FmlEntry As ZipArchiveEntry = Jar.GetEntry("META-INF/fml_cache_annotation.json") Dim FmlText As String = Nothing If FmlEntry IsNot Nothing Then - FmlText = ReadFile(FmlEntry.Open(), Encoding.UTF8) + FmlText = FmlEntry.Open().ReadString(Encoding.UTF8) If Not FmlText.Contains("Lnet/minecraftforge/fml/common/Mod;") Then FmlText = Nothing End If If FmlText Is Nothing Then Exit Try @@ -305,7 +304,7 @@ Got: '加载成功 GoTo Finished Catch ex As Exception - Log(ex, $"读取 fml_cache_annotation.json 时出现未知错误({File.FullName})", NotifyLevel.DevelopOnly) + Logger.Warn(ex, $"读取 fml_cache_annotation.json 时出现未知错误({File.FullName})") End Try #End Region Return '没能成功获取任何信息 @@ -316,7 +315,7 @@ Finished: Try Dim MetaEntry As ZipArchiveEntry = Jar.GetEntry("META-INF/MANIFEST.MF") If MetaEntry IsNot Nothing Then - Dim MetaString As String = ReadFile(MetaEntry.Open()).Replace(" :", ":").Replace(": ", ":") + Dim MetaString As String = MetaEntry.Open().ReadString().Replace(" :", ":").Replace(": ", ":") If MetaString.Contains("Implementation-Version:") Then MetaString = MetaString.Substring(MetaString.IndexOfF("Implementation-Version:") + "Implementation-Version:".Count) MetaString = MetaString.Substring(0, MetaString.IndexOfAny(vbCrLf.ToCharArray)).Trim @@ -324,7 +323,7 @@ Finished: End If End If Catch ex As Exception - Log($"获取 META-INF 中的版本信息失败({File.FullName})", NotifyLevel.DevelopOnly) + Logger.Warn($"获取 META-INF 中的版本信息失败({File.FullName})") Version = Nothing End Try End If @@ -408,7 +407,7 @@ Finished: ''' Public ReadOnly Property HasUpdate As Boolean Get - Return Not Settings.Get("UiHiddenFunctionModUpdate") AndAlso Not Settings.Get("VersionAdvanceDisableModUpdate", Instance:=PageInstanceLeft.Instance) AndAlso UpdateFile IsNot Nothing + Return Not Settings.Get(Of Boolean)("UiHiddenFunctionModUpdate") AndAlso Not Settings.Get(Of Boolean)("VersionAdvanceDisableModUpdate", Instance:=PageInstanceLeft.Instance) AndAlso UpdateFile IsNot Nothing End Get End Property @@ -421,13 +420,13 @@ Finished: '读取缓存 Dim CacheKey As String = GetHash($"{EnabledFullName}-{File.LastWriteTime.ToLongTimeString}-{File.Length}-C") Dim Cached As String = ReadIni(PathTemp & "Cache\ModHash.ini", CacheKey) - If Cached <> "" AndAlso RegexCheck(Cached, "^\d+$") Then '#5062 + If Cached <> "" AndAlso Cached.RegexCheck("^\d+$") Then '#5062 _CurseForgeHash = Cached Return _CurseForgeHash End If '读取文件 Dim data As New List(Of Byte) - For Each b As Byte In ReadFileBytes(File.FullName) + For Each b As Byte In FileUtils.ReadAsBytes(File.FullName) If b = 9 OrElse b = 10 OrElse b = 13 OrElse b = 32 Then Continue For data.Add(b) Next @@ -481,7 +480,7 @@ Finished: Return _ModrinthHash End If '计算 SHA1 - _ModrinthHash = GetFileSHA1(File.FullName) + _ModrinthHash = HashUtils.ComputeFromFile(File.FullName, HashUtils.HashMethod.Sha1) '写入缓存 WriteIni(PathTemp & "Cache\ModHash.ini", CacheKey, _ModrinthHash) End If @@ -498,7 +497,7 @@ Finished: Return File.FullName End Function Public Overrides Function Equals(obj As Object) As Boolean - Dim Target = TryCast(obj, ResourceFile) + Dim Target = TryCast(obj, LocalResourceFile) Return Target IsNot Nothing AndAlso File.FullName = Target.File.FullName End Function diff --git a/Plain Craft Launcher 2/Modules/Resource/ResourceFileLoader.vb b/Plain Craft Launcher 2/Modules/Resource/LocalResourceLoaders.vb similarity index 62% rename from Plain Craft Launcher 2/Modules/Resource/ResourceFileLoader.vb rename to Plain Craft Launcher 2/Modules/Resource/LocalResourceLoaders.vb index 53253c2..2d8ddca 100644 --- a/Plain Craft Launcher 2/Modules/Resource/ResourceFileLoader.vb +++ b/Plain Craft Launcher 2/Modules/Resource/LocalResourceLoaders.vb @@ -1,15 +1,14 @@ -Public Module ResourceFileLoader - Private Const ResourceFileCacheVersion As Integer = 16 +Public Module LocalResourceLoaders '加载 Mod 列表 - Public McModLoader As New LoaderTask(Of String, List(Of ResourceFile))("Mod List Loader", AddressOf McModLoad) - Private Sub McModLoad(Loader As LoaderTask(Of String, List(Of ResourceFile))) + Public LocalResourceLoader As New LoaderTask(Of String, List(Of LocalResourceFile))("LocalResourceLoader", AddressOf LocalResourceFileLoad) + Private Sub LocalResourceFileLoad(Loader As LoaderTask(Of String, List(Of LocalResourceFile))) Try RunInUiWait(Sub() If FrmInstanceMod IsNot Nothing Then FrmInstanceMod.Load.ShowProgress = False) '等待 Mod 更新完成 If PageInstanceMod.UpdatingInstanceModFolders.Contains(Loader.Input) Then - Log($"[Mod] 等待 Mod 更新完成后才能继续加载 Mod 列表:" & Loader.Input) + Logger.Info($"等待 Mod 更新完成后才能继续加载 Mod 列表:{Loader.Input}") Try RunInUiWait(Sub() If FrmInstanceMod IsNot Nothing Then FrmInstanceMod.Load.Text = "正在更新 Mod") Do Until Not PageInstanceMod.UpdatingInstanceModFolders.Contains(Loader.Input) @@ -23,15 +22,15 @@ End If '获取 Mod 文件夹下的可用文件列表 - Dim ModFileList As New List(Of FileInfo) - If Directory.Exists(Loader.Input) Then + Dim ModFileList As New List(Of String) + If DirectoryUtils.Exists(Loader.Input) Then Dim RawName As String = Loader.Input.Lower - For Each File As FileInfo In EnumerateFiles(Loader.Input) - If File.DirectoryName.Lower & "\" <> RawName Then + For Each File In DirectoryUtils.GetFiles(Loader.Input) + If File.BeforeLast("\").Lower & "\" <> RawName Then '仅当 Forge 1.13- 且文件夹名与版本号相同时,才加载该子文件夹下的 Mod If Not (PageInstanceLeft.Instance IsNot Nothing AndAlso PageInstanceLeft.Instance.Version.HasForge AndAlso PageInstanceLeft.Instance.Version.Vanilla.Major < 13 AndAlso - File.Directory.Name = $"1.{PageInstanceLeft.Instance.Version.Vanilla.Major}.{PageInstanceLeft.Instance.Version.Vanilla.Build}") Then + PathUtils.GetLastPart(PathUtils.RemoveLastPart(File)) = $"1.{PageInstanceLeft.Instance.Version.Vanilla.Major}.{PageInstanceLeft.Instance.Version.Vanilla.Build}") Then Continue For End If End If @@ -44,7 +43,7 @@ FullName.EndsWithF(".jar.old", True) OrElse FullName.EndsWithF(".zip.old", True) OrElse FullName.EndsWithF(".litemod.old", True) Then Return True Return False End Function - If IsModFile(File.FullName) Then ModFileList.Add(File) + If IsModFile(File) Then ModFileList.Add(File) Next End If @@ -52,29 +51,29 @@ Dim CachePath As String = PathTemp & "Cache\LocalMod.json" Dim Cache As New JObject Try - Dim CacheContent As String = ReadFile(CachePath) + Dim CacheContent As String = FileUtils.TryReadAsString(CachePath) If Not String.IsNullOrWhiteSpace(CacheContent) Then Cache = GetJson(CacheContent) - If Not Cache.ContainsKey("version") OrElse Cache("version").ToObject(Of Integer) <> ResourceFileCacheVersion Then - Log($"[Mod] 本地 Mod 信息缓存版本已过期,将弃用这些缓存信息", NotifyLevel.DebugModeOnly) + If Not Cache.ContainsKey("version") OrElse Cache("version").ToObject(Of Integer) <> Versions.LOCAL_MOD_CACHE_VERSION Then + Logger.Warn($"本地 Mod 信息缓存版本已过期,将弃用这些缓存信息") Cache = New JObject End If End If Catch ex As Exception - Log(ex, "读取本地 Mod 信息缓存失败,已重置") + Logger.Warn(ex, "读取本地 Mod 信息缓存失败,已重置") Cache = New JObject End Try - Cache("version") = ResourceFileCacheVersion + Cache("version") = Versions.LOCAL_MOD_CACHE_VERSION '加载 Mod 列表 - Dim ModList As New List(Of ResourceFile) - For Each ModFile As FileInfo In ModFileList + Dim ModList As New List(Of LocalResourceFile) + For Each ModFile In ModFileList If Loader.IsInterrupted Then Return - Dim ModEntry As New ResourceFile(ModFile) - Dim DumpMod As ResourceFile = ModList.FirstOrDefault(Function(m) m.EnabledName = ModEntry.EnabledName) '存在两个文件,名称相同,但一个启用一个禁用 + Dim ModEntry As New LocalResourceFile(ModFile) + Dim DumpMod As LocalResourceFile = ModList.FirstOrDefault(Function(m) m.EnabledName = ModEntry.EnabledName) '存在两个文件,名称相同,但一个启用一个禁用 If DumpMod IsNot Nothing Then - Dim DisabledMod As ResourceFile = If(DumpMod.IsEnabled, ModEntry, DumpMod) - Log($"[Mod] 重复的 Mod 文件:{DumpMod.File.Name} 与 {ModEntry.File.Name},已忽略 {DisabledMod.File.Name}", NotifyLevel.DebugModeOnly) + Dim DisabledMod As LocalResourceFile = If(DumpMod.IsEnabled, ModEntry, DumpMod) + Logger.Warn($"重复的 Mod 文件:{DumpMod.File.Name} 与 {ModEntry.File.Name},已忽略 {DisabledMod.File.Name}") If DisabledMod Is ModEntry Then Continue For Else @@ -83,7 +82,7 @@ End If ModList.Add(ModEntry) Next - Log($"[Mod] 共发现 {ModList.Count} 个 Mod") + Logger.Info($"共发现 {ModList.Count} 个 Mod") '排序 ModList = ModList.OrderBy(Function(m) m.File.Name).ToList @@ -94,33 +93,24 @@ '开始联网加载 'TODO: 添加信息获取中提示 - McModDetailLoader.Start(New KeyValuePair(Of List(Of ResourceFile), JObject)(ModList, Cache), IsForceRestart:=True) + LocalResourceOnlineLoader.Start((ModList, Cache, PageInstanceLeft.Instance.Version), IsForceRestart:=True) Catch ex As Exception - Log(ex, "Mod 列表加载失败", NotifyLevel.DebugModeOnly) + Logger.Warn(ex, "Mod 列表加载失败") Throw End Try End Sub '联网加载 Mod 详情 - Public McModDetailLoader As New LoaderTask(Of KeyValuePair(Of List(Of ResourceFile), JObject), Integer)("Mod List Detail Loader", AddressOf McModDetailLoad) - Private Sub McModDetailLoad(Loader As LoaderTask(Of KeyValuePair(Of List(Of ResourceFile), JObject), Integer)) - Dim Mods As New List(Of ResourceFile) - Dim Cache As JObject = Loader.Input.Value - Static GetTargetModLoaders As Func(Of List(Of ModLoaderTypes)) = - Function() As List(Of ModLoaderTypes) - Dim Loaders As New List(Of ModLoaderTypes) - If PageInstanceLeft.Instance.Version.HasForge Then Loaders.Add(ModLoaderTypes.Forge) - If PageInstanceLeft.Instance.Version.HasNeoForge Then Loaders.Add(ModLoaderTypes.NeoForge) - If PageInstanceLeft.Instance.Version.HasFabric Then Loaders.Add(ModLoaderTypes.Fabric) - If PageInstanceLeft.Instance.Version.HasLiteLoader Then Loaders.Add(ModLoaderTypes.LiteLoader) - If Not Loaders.Any() Then Loaders.AddRange({ModLoaderTypes.Forge, ModLoaderTypes.NeoForge, ModLoaderTypes.Fabric, ModLoaderTypes.LiteLoader, ModLoaderTypes.Quilt}) - Return Loaders - End Function + Public LocalResourceOnlineLoader As New LoaderTask(Of (ModList As List(Of LocalResourceFile), Cache As JObject, Target As McVersion), Integer)("LocalResourceOnlineLoader", AddressOf LocalResourceOnlineLoad) + Private Sub LocalResourceOnlineLoad(Loader As LoaderTask(Of (ModList As List(Of LocalResourceFile), Cache As JObject, Target As McVersion), Integer)) + Dim Mods As New List(Of LocalResourceFile) + Dim Cache As JObject = Loader.Input.Cache + Dim ModLoaders = Loader.Input.Target.ModLoaders '读取缓存,获取需要更新的 Mod 列表 - For Each ModEntry As ResourceFile In Loader.Input.Key + For Each ModEntry As LocalResourceFile In Loader.Input.ModList If Loader.IsInterrupted Then Return - Dim CacheKey = ModEntry.ModrinthHash & PageInstanceLeft.Instance.Version.VanillaName & GetTargetModLoaders().Join("") + Dim CacheKey = ModEntry.ModrinthHash & Loader.Input.Target.VanillaName & ModLoaders If Cache.ContainsKey(CacheKey) Then ModEntry.FromJson(Cache(CacheKey)) '如果缓存中的信息在 6 小时以内更新过,则无需重新获取 @@ -128,18 +118,17 @@ End If Mods.Add(ModEntry) Next - Log($"[Mod] 有 {Mods.Where(Function(m) m.Project Is Nothing).Count} 个 Mod 需要联网获取信息,{Mods.Where(Function(m) m.Project IsNot Nothing).Count} 个 Mod 需要更新信息") + Logger.Info($"有 {Mods.Where(Function(m) m.Project Is Nothing).Count} 个 Mod 需要联网获取信息,{Mods.Where(Function(m) m.Project IsNot Nothing).Count} 个 Mod 需要更新信息") If Not Mods.Any Then - Loader.Input.Key.Where(Function(m) m.Version Is Nothing).ForAll(Sub(m) m.LoadMetadataFromJar()) '从 JAR 中获取缺失的版本信息(下面有另一个分支) + Loader.Input.ModList.Where(Function(m) m.Version Is Nothing).ForAll(Sub(m) m.LoadMetadataFromJar()) '从 JAR 中获取缺失的版本信息(下面有另一个分支) Return End If '获取作为检查目标的加载器和版本 '此处不应向下扩展检查的 MC 小版本,例如 Mod 在更新 1.16.5 后,对早期的 1.16.2 版本发布了修补补丁,这会导致 PCL 将 1.16.5 版本的 Mod 降级到 1.16.2 - Dim TargetMcVersion As McVersion = PageInstanceLeft.Instance.Version - Dim ModLoaders = GetTargetModLoaders() + Dim TargetMcVersion As McVersion = Loader.Input.Target Dim VanillaVersion = TargetMcVersion.VanillaName '开始网络获取 - Log($"[Mod] 目标加载器:{ModLoaders.Join("/")},版本:{VanillaVersion}") + Logger.Info($"目标加载器:{ModLoaders},版本:{VanillaVersion}") Dim EndedThreadCount As Integer = 0, IsFailed As Boolean = False Dim CurrentTaskThread As Thread = Thread.CurrentThread '从 Modrinth 获取信息 @@ -150,16 +139,16 @@ Dim ModrinthHashes = Mods.Select(Function(m) m.ModrinthHash).ToList() Dim ModrinthVersion As JObject = DlModRequest("https://api.modrinth.com/v2/version_files", HttpMethod.Post, $"{{""hashes"": [""{ModrinthHashes.Join(""",""")}""], ""algorithm"": ""sha1""}}", "application/json") - Log($"[Mod] 从 Modrinth 获取到 {ModrinthVersion.Count} 个本地 Mod 的对应信息") + Logger.Info($"从 Modrinth 获取到 {ModrinthVersion.Count} 个本地 Mod 的对应信息") '步骤 2:尝试读取工程信息缓存,构建其他 Mod 的对应关系 If ModrinthVersion.Count = 0 Then Return - Dim ModrinthMapping As New Dictionary(Of String, List(Of ResourceFile)) + Dim ModrinthMapping As New Dictionary(Of String, List(Of LocalResourceFile)) For Each Entry In Mods If Not ModrinthVersion.ContainsKey(Entry.ModrinthHash) Then Continue For If ModrinthVersion(Entry.ModrinthHash)("files")(0)("hashes")("sha1") <> Entry.ModrinthHash Then Continue For Dim ProjectId = ModrinthVersion(Entry.ModrinthHash)("project_id").ToString If ResourceProject.Cache.ContainsKey(ProjectId) AndAlso Entry.Project Is Nothing Then Entry.Project = ResourceProject.Cache(ProjectId) '读取已加载的缓存,加快结果出现速度 - If Not ModrinthMapping.ContainsKey(ProjectId) Then ModrinthMapping(ProjectId) = New List(Of ResourceFile) + If Not ModrinthMapping.ContainsKey(ProjectId) Then ModrinthMapping(ProjectId) = New List(Of LocalResourceFile) ModrinthMapping(ProjectId).Add(Entry) '记录对应的 ProjectVersion Dim File = ResourceVersion.FromPlatformJson(ModrinthVersion(Entry.ModrinthHash), ResourceTypes.Mod) @@ -170,7 +159,7 @@ End If Next If Loader.IsInterruptedWithThread(CurrentTaskThread) Then Return - Log($"[Mod] 需要从 Modrinth 获取 {ModrinthMapping.Count} 个本地 Mod 的工程信息") + Logger.Info($"需要从 Modrinth 获取 {ModrinthMapping.Count} 个本地 Mod 的工程信息") '步骤 3:获取工程信息 If Not ModrinthMapping.Any() Then Return Dim ModrinthProject As JArray = DlModRequest( @@ -181,16 +170,20 @@ Entry.Project = Project Next Next - Log($"[Mod] 已从 Modrinth 获取本地 Mod 信息,继续获取更新信息") + Logger.Info($"已从 Modrinth 获取本地 Mod 信息,继续获取更新信息") '步骤 4:获取更新信息 + If ModLoaders = ModLoaders.None Then + Logger.Warn("该 Minecraft 版本没有可用的 Mod 加载器,不获取 Mod 更新信息") + Return + End If Dim ModrinthUpdate As JObject = DlModRequest("https://api.modrinth.com/v2/version_files/update", HttpMethod.Post, $"{{""hashes"": [""{ModrinthMapping.SelectMany(Function(l) l.Value.Select(Function(m) m.ModrinthHash)).Join(""",""")}""], ""algorithm"": ""sha1"", - ""loaders"": [""{ModLoaders.Join(""",""").Lower}""],""game_versions"": [""{VanillaVersion}""]}}", "application/json") + ""loaders"": [""{ModLoaders.Flags.Join(""",""").Lower}""],""game_versions"": [""{VanillaVersion}""]}}", "application/json") For Each Entry In Mods If Not ModrinthUpdate.ContainsKey(Entry.ModrinthHash) OrElse Entry.ProjectVersion Is Nothing Then Continue For Dim UpdateFile = ResourceVersion.FromPlatformJson(ModrinthUpdate(Entry.ModrinthHash), ResourceTypes.Mod) If Not UpdateFile.DownloadAvailable Then Continue For - If ModeDebug Then Log($"[Mod] 本地文件 {Entry.ProjectVersion.FileName} 在 Modrinth 上的最新版为 {UpdateFile.FileName}") + Logger.Trace(Function() $"本地文件 {Entry.ProjectVersion.FileName} 在 Modrinth 上的最新版为 {UpdateFile.FileName}") If Entry.ProjectVersion.ReleaseDate >= UpdateFile.ReleaseDate OrElse Entry.ProjectVersion.Hash = UpdateFile.Hash Then Continue For '设置更新日志与更新文件 If Entry.UpdateFile IsNot Nothing AndAlso UpdateFile.Hash = Entry.UpdateFile.Hash Then '合并 @@ -202,9 +195,9 @@ Entry.UpdateFile = UpdateFile End If Next - Log($"[Mod] 从 Modrinth 获取本地 Mod 信息结束") + Logger.Info($"从 Modrinth 获取本地 Mod 信息结束") Catch ex As Exception - Log(ex, "从 Modrinth 获取本地 Mod 信息失败") + Logger.Warn(ex, "从 Modrinth 获取本地 Mod 信息失败") IsFailed = True Finally EndedThreadCount += 1 @@ -215,90 +208,92 @@ Sub() Try '步骤 1:获取 Hash 与对应的工程 ID - Dim CurseForgeHashes As New List(Of UInteger) + Dim Hashes As New List(Of UInteger) For Each Entry In Mods - CurseForgeHashes.Add(Entry.CurseForgeHash) + Hashes.Add(Entry.CurseForgeHash) If Loader.IsInterruptedWithThread(CurrentTaskThread) Then Return Next Dim CurseForgeRaw As JContainer = DlModRequest("https://api.curseforge.com/v1/fingerprints/432", HttpMethod.Post, - $"{{""fingerprints"": [{CurseForgeHashes.Join(",")}]}}", "application/json")("data")("exactMatches") - Log($"[Mod] 从 CurseForge 获取到 {CurseForgeRaw.Count} 个本地 Mod 的对应信息") - '步骤 2:尝试读取工程信息缓存,构建其他 Mod 的对应关系 + $"{{""fingerprints"": [{Hashes.Join(",")}]}}", "application/json")("data")("exactMatches") + Logger.Info($"从 CurseForge 获取到 {CurseForgeRaw.Count} 个本地 Mod 的对应信息") If Not CurseForgeRaw.Any() Then Return - Dim CurseForgeMapping As New Dictionary(Of Integer, List(Of ResourceFile)) + + '步骤 2:尝试读取工程信息缓存,构建其他 Mod 的对应关系 + Dim ProjectIdToLocalFiles As New Dictionary(Of Integer, List(Of LocalResourceFile)) For Each Project In CurseForgeRaw Dim ProjectId = Project("id").ToString Dim Hash As UInteger = Project("file")("fileFingerprint") For Each Entry In Mods If Entry.CurseForgeHash <> Hash Then Continue For If ResourceProject.Cache.ContainsKey(ProjectId) AndAlso Entry.Project Is Nothing Then Entry.Project = ResourceProject.Cache(ProjectId) '读取已加载的缓存,加快结果出现速度 - If Not CurseForgeMapping.ContainsKey(ProjectId) Then CurseForgeMapping(ProjectId) = New List(Of ResourceFile) - CurseForgeMapping(ProjectId).Add(Entry) + ProjectIdToLocalFiles.AddIntoValueCollection(ProjectId, Entry) '记录对应的 ProjectVersion Dim File = ResourceVersion.FromPlatformJson(Project("file"), ResourceTypes.Mod) If Entry.ProjectVersion Is Nothing OrElse Entry.ProjectVersion.ReleaseDate < File.ReleaseDate Then Entry.ProjectVersion = File Next Next If Loader.IsInterruptedWithThread(CurrentTaskThread) Then Return - Log($"[Mod] 需要从 CurseForge 获取 {CurseForgeMapping.Count} 个本地 Mod 的工程信息") + Logger.Info($"需要从 CurseForge 获取 {ProjectIdToLocalFiles.Count} 个本地 Mod 的工程信息") + If Not ProjectIdToLocalFiles.Any() Then Return + '步骤 3:获取工程信息 - If Not CurseForgeMapping.Any() Then Return Dim CurseForgeProject = DlModRequest("https://api.curseforge.com/v1/mods", HttpMethod.Post, - $"{{""modIds"": [{CurseForgeMapping.Keys.Join(",")}]}}", "application/json")("data") - Dim UpdateFileIds As New Dictionary(Of Integer, List(Of ResourceFile)) 'FileId -> 本地 Mod 文件列表 + $"{{""modIds"": [{ProjectIdToLocalFiles.Keys.Join(",")}]}}", "application/json")("data") + Dim UpdateFileIds As New Dictionary(Of Integer, List(Of LocalResourceFile)) 'FileId -> 本地 Mod 文件列表 Dim FileIdToProjectSlug As New Dictionary(Of Integer, String) For Each ProjectJson In CurseForgeProject If ProjectJson("isAvailable") IsNot Nothing AndAlso Not ProjectJson("isAvailable").ToObject(Of Boolean) Then Continue For '设置 Entry 中的工程信息 Dim Project As New ResourceProject(ProjectJson) - For Each Entry In CurseForgeMapping(Project.Id) '倒查防止 CurseForge 返回的内容有漏 - If Entry.Project IsNot Nothing AndAlso Entry.Project.Platform = ResourcePlatforms.Modrinth Then - Entry.Project = Entry.Project '再次触发修改事件 - Continue For + Dim TargetLoaders As ModLoaders = ModLoaders.None + For Each LocalFile In ProjectIdToLocalFiles(Project.Id) '倒查防止 CurseForge 返回的内容有漏 + If LocalFile.Project?.Platform = ResourcePlatforms.Modrinth Then + LocalFile.Project = LocalFile.Project '再次触发修改事件 + Else + LocalFile.Project = Project + TargetLoaders = TargetLoaders Or LocalFile.Project.ModLoaders End If - Entry.Project = Project Next + TargetLoaders = TargetLoaders And ModLoaders '与目标 MC 版本的加载器取交集 '查找或许版本更新的文件列表 - If ModLoaders.IsSingle Then - Dim NewestVersion As String = Nothing - Dim NewestFileIds As New List(Of Integer) - For Each IndexEntry In ProjectJson("latestFilesIndexes") - If IndexEntry("modLoader") Is Nothing OrElse ModLoaders.Single <> IndexEntry("modLoader").ToObject(Of Integer) Then Continue For 'ModLoader 唯一且匹配 - Dim IndexVersion As String = IndexEntry("gameVersion") - If IndexVersion <> VanillaVersion Then Continue For 'MC 版本匹配 - '由于 latestFilesIndexes 是按时间从新到老排序的,所以只需取第一个;如果需要检查多个 releaseType 下的文件,将 > -1 改为 = 1,但这应当并不会获取到更新的文件 - If NewestVersion IsNot Nothing AndAlso CompareVersion(NewestVersion, IndexVersion) > -1 Then Continue For '只保留最新 MC 版本 - If NewestVersion <> IndexVersion Then - NewestVersion = IndexVersion - NewestFileIds.Clear() - End If - NewestFileIds.Add(IndexEntry("fileId").ToObject(Of Integer)) - Next - For Each FileId In NewestFileIds - If Not UpdateFileIds.ContainsKey(FileId) Then UpdateFileIds(FileId) = New List(Of ResourceFile) - UpdateFileIds(FileId).AddRange(CurseForgeMapping(Project.Id)) - FileIdToProjectSlug(FileId) = Project.Slug - Next - End If + If ModLoaders = ModLoaders.None Then Continue For '无法判断 MC 版本使用的加载器,跳过更新检查 + Dim LatestFiles = ProjectJson("latestFilesIndexes").Where( + Function(Entry) + 'Mod Loader 匹配 + If Entry("modLoader") Is Nothing Then Return False + Dim EntryLoader As ModLoaders = Resource.FromCurseForgeModLoaderType(Entry("modLoader").ToObject(Of Integer)) + If Not TargetLoaders.HasFlag(EntryLoader) Then Return False + 'MC 版本匹配 + Dim EntryVersion As String = Entry("gameVersion") + Return EntryVersion IsNot Nothing AndAlso EntryVersion = VanillaVersion + End Function). + MaxByAll(Function(Entry) Entry("gameVersion").ToString, New VersionComparer) '只保留最新的 MC 版本 + For Each Entry In LatestFiles + Dim FileId = Entry("fileId").ToObject(Of Integer) + If Not UpdateFileIds.ContainsKey(FileId) Then UpdateFileIds(FileId) = New List(Of LocalResourceFile) + UpdateFileIds(FileId).AddRange(ProjectIdToLocalFiles(Project.Id)) + FileIdToProjectSlug(FileId) = Project.Slug + Next Next - Log($"[Mod] 已从 CurseForge 获取本地 Mod 信息,需要获取 {UpdateFileIds.Count} 个用于检查更新的文件信息") - '步骤 4:获取更新文件信息 + Logger.Info($"已从 CurseForge 获取本地 Mod 信息,需要获取 {UpdateFileIds.Count} 个用于检查更新的文件信息") If Not UpdateFileIds.Any() Then Return + + '步骤 4:获取更新文件信息 Dim CurseForgeFiles = DlModRequest("https://api.curseforge.com/v1/mods/files", HttpMethod.Post, $"{{""fileIds"": [{UpdateFileIds.Keys.Join(",")}]}}", "application/json")("data") - Dim UpdateFiles As New Dictionary(Of ResourceFile, ResourceVersion) + Dim UpdateFiles As New Dictionary(Of LocalResourceFile, ResourceVersion) For Each FileJson In CurseForgeFiles Dim File = ResourceVersion.FromPlatformJson(FileJson, ResourceTypes.Mod) If Not File.DownloadAvailable Then Continue For - For Each Entry As ResourceFile In UpdateFileIds(File.Id) + For Each Entry As LocalResourceFile In UpdateFileIds(File.Id) If UpdateFiles.ContainsKey(Entry) AndAlso UpdateFiles(Entry).ReleaseDate >= File.ReleaseDate Then Continue For UpdateFiles(Entry) = File Next Next For Each Pair In UpdateFiles - Dim Entry As ResourceFile = Pair.Key + Dim Entry As LocalResourceFile = Pair.Key Dim UpdateFile As ResourceVersion = Pair.Value - If ModeDebug Then Log($"[Mod] 本地文件 {Entry.ProjectVersion.FileName} 在 CurseForge 上的最新版为 {UpdateFile.FileName}") + Logger.Trace(Function() $"本地文件 {Entry.ProjectVersion.FileName} 在 CurseForge 上的最新版为 {UpdateFile.FileName}") If Entry.ProjectVersion.ReleaseDate >= UpdateFile.ReleaseDate OrElse Entry.ProjectVersion.Hash = UpdateFile.Hash Then Continue For '设置更新日志与更新文件 If Entry.UpdateFile IsNot Nothing AndAlso UpdateFile.Hash = Entry.UpdateFile.Hash Then '合并 @@ -309,16 +304,17 @@ Entry.UpdateFile = UpdateFile End If Next - Log($"[Mod] 从 CurseForge 获取 Mod 更新信息结束") + + Logger.Info($"从 CurseForge 获取 Mod 更新信息结束") Catch ex As Exception - Log(ex, "从 CurseForge 获取本地 Mod 信息失败") + Logger.Warn(ex, "从 CurseForge 获取本地 Mod 信息失败") IsFailed = True Finally EndedThreadCount += 1 End Try End Sub, "Mod List Detail Loader CurseForge") '从 JAR 中获取缺失的版本信息(上面有另一个分支) - Loader.Input.Key.Where(Function(m) m.Version Is Nothing).ForAll(Sub(m) m.LoadMetadataFromJar()) + Loader.Input.ModList.Where(Function(m) m.Version Is Nothing).ForAll(Sub(m) m.LoadMetadataFromJar()) '等待线程结束 Do Until EndedThreadCount = 2 Thread.Sleep(10) @@ -326,11 +322,12 @@ Loop '保存缓存 Mods = Mods.Where(Function(m) m.Project IsNot Nothing).ToList() - Log($"[Mod] 联网获取本地 Mod 信息完成,为 {Mods.Count} 个 Mod 更新缓存") + Logger.Info($"联网获取本地 Mod 信息完成,为 {Mods.Count} 个 Mod 更新缓存") If Not Mods.Any() Then Return + If Loader.IsInterrupted Then Return For Each Entry In Mods Entry.OnlineDataLoaded = Not IsFailed - Cache(Entry.ModrinthHash & VanillaVersion & ModLoaders.Join("")) = Entry.ToJson() + Cache(Entry.ModrinthHash & VanillaVersion & ModLoaders) = Entry.ToJson() Next FileUtils.Write(PathTemp & "Cache\LocalMod.json", Cache.ToString(If(ModeDebug, Newtonsoft.Json.Formatting.Indented, Newtonsoft.Json.Formatting.None))) '刷新边栏 @@ -342,4 +339,4 @@ End If End Sub -End Module \ No newline at end of file +End Module diff --git a/Plain Craft Launcher 2/Modules/Resource/ResourceProject.vb b/Plain Craft Launcher 2/Modules/Resource/ResourceProject.vb index aefb0cd..c99b76e 100644 --- a/Plain Craft Launcher 2/Modules/Resource/ResourceProject.vb +++ b/Plain Craft Launcher 2/Modules/Resource/ResourceProject.vb @@ -52,9 +52,9 @@ Public Class ResourceProject ''' Public ReadOnly DownloadCount As Integer ''' - ''' 支持的 Mod 加载器列表。可能为空。 + ''' 所有支持的 Mod 加载器。可能为 。 ''' - Public ReadOnly Loaders As List(Of ModLoaderTypes) + Public ReadOnly ModLoaders As ModLoaders = ModLoaders.None ''' ''' 描述性标签的内容。已转换为中文。 ''' @@ -133,11 +133,7 @@ Public Class ResourceProject Website = Data("Website") LastUpdate = Data("LastUpdate") DownloadCount = Data("DownloadCount") - If Data.ContainsKey("ModLoaders") Then - Loaders = CType(Data("ModLoaders"), JArray).Select(Function(t) CType(t.ToObject(Of Integer), ModLoaderTypes)).ToList - Else - Loaders = New List(Of ModLoaderTypes) - End If + If Data.ContainsKey("ModLoaders") Then ModLoaders = Data("ModLoaders").ToObject(Of Integer) Tags = CType(Data("Tags"), JArray).Select(Function(t) t.ToString).ToList If Data.ContainsKey("LogoUrl") Then LogoUrl = Data("LogoUrl") If Data.ContainsKey("Drops") Then @@ -181,12 +177,12 @@ Public Class ResourceProject Types = ResourceTypes.DataPack End If 'FileIndexes / VanillaMajorVersions / ModLoaders - Loaders = New List(Of ModLoaderTypes) + ModLoaders = ModLoaders.None Dim Files As New List(Of KeyValuePair(Of Integer, List(Of String))) 'FileId, GameVersions For Each File In If(Data("latestFiles"), New JArray) Dim NewFile = ResourceVersion.FromPlatformJson(File, Types) If Not NewFile.DownloadAvailable Then Continue For - Loaders.AddRange(NewFile.Loaders) + ModLoaders = ModLoaders Or NewFile.ModLoaders Dim GameVersions = File("gameVersions").ToObject(Of List(Of String)) If Not GameVersions.Any(Function(v) McVersion.IsFormatFit(v)) Then Continue For Files.Add(New KeyValuePair(Of Integer, List(Of String))(File("id"), GameVersions)) @@ -198,7 +194,6 @@ Public Class ResourceProject CurseForgeFileIds = Files.Select(Function(f) f.Key).Distinct.ToList Drops = Files.SelectMany(Function(f) f.Value). Select(Function(v) McVersion.VersionToDrop(v)).Where(Function(v) v <> 209).Distinct.OrderByDescending(Function(v) v).ToList - Loaders = Loaders.Distinct.OrderBy(Of Integer)(Function(t) t).ToList 'Tags Tags = New List(Of String) For Each Category In If(Data("categories"), New JArray). '镜像源 API 可能丢失此字段 (4267#issuecomment-2254590831) @@ -303,24 +298,17 @@ Public Class ResourceProject End Select 'Tags & ModLoaders Tags = New List(Of String) - Loaders = New List(Of ModLoaderTypes) - If Data.ContainsKey("loaders") Then - For Each Category In Data("loaders").Select(Function(t) t.ToString) - Select Case Category - Case "forge" : Loaders.Add(ModLoaderTypes.Forge) - Case "fabric" : Loaders.Add(ModLoaderTypes.Fabric) - Case "quilt" : Loaders.Add(ModLoaderTypes.Quilt) - Case "neoforge" : Loaders.Add(ModLoaderTypes.NeoForge) - End Select + ModLoaders = ModLoaders.None + For Each Category In If(Data("loaders")?.Select(Function(t) t.ToString), {}).Concat(Data("categories").Select(Function(t) t.ToString)) + For Each Loader In EnumUtils.GetAllFlags(Of ModLoaders)() + If Category = Loader.ToString.Lower Then + ModLoaders = ModLoaders Or Loader + Exit For + End If Next - End If + Next For Each Category In Data("categories").Select(Function(t) t.ToString) Select Case Category - '加载器 - Case "forge" : Loaders.Add(ModLoaderTypes.Forge) - Case "fabric" : Loaders.Add(ModLoaderTypes.Fabric) - Case "quilt" : Loaders.Add(ModLoaderTypes.Quilt) - Case "neoforge" : Loaders.Add(ModLoaderTypes.NeoForge) Case "datapack" : Types = ResourceTypes.DataPack '共用 Case "technology" : Tags.Add("科技") @@ -388,12 +376,11 @@ Public Class ResourceProject Case "vanilla" : Tags.Add("原版可用") End Select Next - If Types = ResourceTypes.DataPack AndAlso Loaders.Any Then Types = ResourceTypes.DataPack Or ResourceTypes.Mod + If Types = ResourceTypes.DataPack AndAlso ModLoaders <> ModLoaders.None Then Types = ResourceTypes.DataPack Or ResourceTypes.Mod #End Region End If If Not Tags.Any() Then Tags.Add("其他") Tags.Sort() - Loaders.Sort() End If '保存缓存 Cache(Id) = Me @@ -454,7 +441,7 @@ Public Class ResourceProject Json("Website") = Website Json("LastUpdate") = LastUpdate Json("DownloadCount") = DownloadCount - If Loaders IsNot Nothing AndAlso Loaders.Any Then Json("ModLoaders") = New JArray(Loaders.Select(Function(m) CInt(m))) + If ModLoaders <> ModLoaders.None Then Json("ModLoaders") = ModLoaders Json("Tags") = New JArray(Tags) If LogoUrl IsNot Nothing Then Json("LogoUrl") = LogoUrl If Drops.Any Then Json("Drops") = New JArray(Drops) @@ -514,13 +501,13 @@ Public Class ResourceProject End If '获取 Mod 加载器描述 Dim ModLoaderDescriptionFull As String, ModLoaderDescriptionPart As String - Dim ModLoadersForDesc As New List(Of ModLoaderTypes)(Loaders) - If Settings.Get("ToolDownloadIgnoreQuilt") Then ModLoadersForDesc.Remove(ModLoaderTypes.Quilt) + Dim ModLoadersForDesc = ModLoaders.Flags().ToList() + If Settings.Get(Of Boolean)("ToolDownloadIgnoreQuilt") Then ModLoadersForDesc.Remove(ModLoaders.Quilt) Select Case ModLoadersForDesc.Count Case 0 - If Loaders.IsSingle Then - ModLoaderDescriptionFull = "仅 " & Loaders.Single.ToString - ModLoaderDescriptionPart = Loaders.Single.ToString + If ModLoadersForDesc.IsSingle Then + ModLoaderDescriptionFull = "仅 " & ModLoadersForDesc.Single.ToString + ModLoaderDescriptionPart = ModLoadersForDesc.Single.ToString Else ModLoaderDescriptionFull = "未知" ModLoaderDescriptionPart = "" @@ -530,10 +517,10 @@ Public Class ResourceProject ModLoaderDescriptionPart = ModLoadersForDesc.Single.ToString Case Else Dim NewestDrop As Integer = If(Drops.Any, Drops.First, 9999) - If Loaders.Contains(ModLoaderTypes.Forge) AndAlso - (NewestDrop < 140 OrElse Loaders.Contains(ModLoaderTypes.Fabric)) AndAlso - (NewestDrop < 200 OrElse Loaders.Contains(ModLoaderTypes.NeoForge)) AndAlso - (NewestDrop < 140 OrElse Loaders.Contains(ModLoaderTypes.Quilt) OrElse Settings.Get("ToolDownloadIgnoreQuilt")) Then + If ModLoadersForDesc.Contains(ModLoaders.Forge) AndAlso + (NewestDrop < 140 OrElse ModLoadersForDesc.Contains(ModLoaders.Fabric)) AndAlso + (NewestDrop < 200 OrElse ModLoadersForDesc.Contains(ModLoaders.NeoForge)) AndAlso + (NewestDrop < 140 OrElse ModLoadersForDesc.Contains(ModLoaders.Quilt) OrElse Settings.Get(Of Boolean)("ToolDownloadIgnoreQuilt")) Then ModLoaderDescriptionFull = "任意" ModLoaderDescriptionPart = "" Else @@ -596,7 +583,7 @@ Public Class ResourceProject If TranslatedName = RawName Then '没有中文翻译 '将所有名称分段 - Dim NameLists = TranslatedName.Split({" | ", " - ", "(", ")", "[", "]", "{", "}"}, StringSplitOptions.RemoveEmptyEntries). + Dim NameLists = TranslatedName.Split({" | ", " - ", "(", ")", "[", "]", "{", "}"}, True). Select(Function(s) s.Trim(" /\".ToCharArray)).Where(Function(w) Not String.IsNullOrEmpty(w)) If NameLists.IsSingle Then GoTo NoSubtitle '查找其中的缩写、Forge/Fabric 等版本标记 @@ -608,7 +595,7 @@ Public Class ResourceProject '缩写 SubtitleList.Add(Name) ElseIf {"neoforge", "forge", "fabric", "quilt"}.Any(Function(l) LowerName.Contains(l)) AndAlso - Not RegexCheck(LowerName.Replace("neoforge", "").Replace("forge", "").Replace("fabric", "").Replace("quilt", ""), "[a-z]+") Then '去掉关键词后没有其他字母 + Not LowerName.Replace("neoforge", "").Replace("forge", "").Replace("fabric", "").Replace("quilt", "").RegexCheck("[a-z]+") Then '去掉关键词后没有其他字母 'Forge/Fabric 等版本标记 SubtitleList.Add(Name) Else @@ -631,7 +618,7 @@ Public Class ResourceProject If Suffix <> "" Then EnglishName = EnglishName.Replace(" - " & Suffix, "") EnglishName = EnglishName.Replace(Title, "").Trim("("c, ")"c, " "c) '中段的额外信息截取 - SubtitleList = EnglishName.Split({" | ", " - ", "(", ")", "[", "]", "{", "}"}, StringSplitOptions.RemoveEmptyEntries). + SubtitleList = EnglishName.Split({" | ", " - ", "(", ")", "[", "]", "{", "}"}, True). Select(Function(s) s.Trim(" /".ToCharArray)).Where(Function(w) Not String.IsNullOrEmpty(w)).ToList If SubtitleList.Count > 1 AndAlso Not SubtitleList.Any(Function(s) s.Lower.Contains("forge") OrElse s.Lower.Contains("fabric") OrElse s.Lower.Contains("quilt")) AndAlso '不是标注 XX 版 @@ -690,16 +677,16 @@ NoSubtitle: '来自不同的网站 If Platform = Project.Platform Then Return False 'Mod 加载器一致 - If Loaders.Count <> Project.Loaders.Count OrElse Loaders.Except(Project.Loaders).Any() Then Return False + If ModLoaders <> Project.ModLoaders Then Return False '若不为光影,则要求 MC 版本一致 - If Types <> ResourceTypes.Shader AndAlso (Drops.Count <> Project.Drops.Count OrElse Drops.Except(Project.Drops).Any()) Then Return False + If Types <> ResourceTypes.Shader AndAlso Drops.Ordered.SequenceEqual(Project.Drops.Ordered) Then Return False '最近更新时间差距在一周以内 If Math.Abs((LastUpdate - Project.LastUpdate).TotalDays) > 7 Then Return False 'MCMOD 翻译名 / 原名 / 描述文本 / Slug 的英文部分相同 If TranslatedName = Project.TranslatedName OrElse RawName = Project.RawName OrElse Description = Project.Description OrElse GetRaw(Slug) = GetRaw(Project.Slug) Then - Log($"[Resource] 将 {RawName} ({Slug}) 与 {Project.RawName} ({Project.Slug}) 认定为相似工程") + Logger.Info($"将 {RawName} ({Slug}) 与 {Project.RawName} ({Project.Slug}) 认定为相似工程") '如果只有一个有 DatabaseEntry,设置给另外一个 If WikiEntry Is Nothing AndAlso Project.WikiEntry IsNot Nothing Then WikiEntry = Project.WikiEntry If WikiEntry IsNot Nothing AndAlso Project.WikiEntry Is Nothing Then Project.WikiEntry = WikiEntry diff --git a/Plain Craft Launcher 2/Modules/Resource/ResourceSearcher.vb b/Plain Craft Launcher 2/Modules/Resource/ResourceSearcher.vb index 5fb3308..a286cfc 100644 --- a/Plain Craft Launcher 2/Modules/Resource/ResourceSearcher.vb +++ b/Plain Craft Launcher 2/Modules/Resource/ResourceSearcher.vb @@ -40,8 +40,10 @@ Public Tag As String = "" ''' ''' 筛选 Mod 加载器类别。 + ''' 代表不筛选。 + ''' 对于 Modrinth 请求,支持多个枚举值。 ''' - Public ModLoader As ModLoaderTypes = ModLoaderTypes.Any + Public ModLoaders As ModLoaders = ModLoaders.None ''' ''' 筛选 MC 版本。 ''' @@ -82,7 +84,7 @@ Address += "&classId=12" End Select If Tag <> "" Then Address += "&categoryId=" & Tag.BeforeFirst("/") - If ModLoader <> ModLoaderTypes.Any AndAlso Not IgnoreModLoaderFilter Then Address += "&modLoaderType=" & CType(ModLoader, Integer) + If ModLoaders <> ModLoaders.None AndAlso Not IgnoreModLoaderFilter Then Address += "&modLoaderType=" & Resource.ToCurseForgeModLoaderType(ModLoaders.Flags.First) If Not String.IsNullOrEmpty(GameVersion) Then Address += "&gameVersion=" & GameVersion If Not String.IsNullOrEmpty(SearchText) Then Address += "&searchFilter=" & EscapeUtils.UrlEscape(SearchText) If Storage.CurseForgeOffset > 0 Then Address += "&index=" & Storage.CurseForgeOffset @@ -97,11 +99,13 @@ Dim Address As String = $"https://api.modrinth.com/v2/search?limit={RESULT_PAGE_SIZE}&index=relevance" If Not String.IsNullOrEmpty(SearchText) Then Address += "&query=" & EscapeUtils.UrlEscape(SearchText) If Storage.ModrinthOffset > 0 Then Address += "&offset=" & Storage.ModrinthOffset - 'facets=[["categories:'game-mechanics'"],["categories:'forge'"],["versions:1.19.3"],["project_type:mod"]] + 'facets=[["categories:'game-mechanics'"],["categories:'forge',categories:'fabric'"],["versions:1.19.3"],["project_type:mod"]] Dim Facets As New List(Of String) Facets.Add($"[""project_type:{Type.ToString.Lower}""]") If Not String.IsNullOrEmpty(Tag) Then Facets.Add($"[""categories:'{Tag.AfterLast("/")}'""]") - If ModLoader <> ModLoaderTypes.Any AndAlso Not IgnoreModLoaderFilter Then Facets.Add($"[""categories:'{GetStringFromEnum(ModLoader).Lower}'""]") + If ModLoaders <> ModLoaders.None AndAlso Not IgnoreModLoaderFilter Then + Facets.Add($"[""categories:'{ModLoaders.Flags.Select(Function(f) f.ToString.Lower).Join("',categories:'")}'""]") + End If If Not String.IsNullOrEmpty(GameVersion) Then Facets.Add($"[""versions:'{GameVersion}'""]") Address += "&facets=[" & String.Join(",", Facets) & "]" Return Address @@ -112,7 +116,7 @@ Dim request = TryCast(obj, SearchRequest) Return request IsNot Nothing AndAlso Type = request.Type AndAlso TargetResultCount = request.TargetResultCount AndAlso - Tag = request.Tag AndAlso ModLoader = request.ModLoader AndAlso Sources = request.Sources AndAlso + Tag = request.Tag AndAlso ModLoaders = request.ModLoaders AndAlso Sources = request.Sources AndAlso GameVersion = request.GameVersion AndAlso SearchText = request.SearchText End Function Public Shared Operator =(left As SearchRequest, right As SearchRequest) As Boolean @@ -122,7 +126,7 @@ Return Not left = right End Operator Public Overrides Function GetHashCode() As Integer - Return (Type, Tag, ModLoader, GameVersion, SearchText, Sources).GetHashCode() + Return (Type, Tag, ModLoaders, GameVersion, SearchText, Sources).GetHashCode() End Function End Class @@ -164,19 +168,19 @@ #Region "前置检查" If Storage.Results.Count >= Request.TargetResultCount Then - Log($"[Resource] 已有 {Storage.Results.Count} 个结果,多于所需的 {Request.TargetResultCount} 个结果,结束处理") + Logger.Info($"已有 {Storage.Results.Count} 个结果,多于所需的 {Request.TargetResultCount} 个结果,结束处理") Return ElseIf Not Request.CanContinue Then If Not Storage.Results.Any() Then Throw New Exception("没有符合条件的结果") Else - Log($"[Resource] 已有 {Storage.Results.Count} 个结果,少于所需的 {Request.TargetResultCount} 个结果,但无法继续获取,结束处理") + Logger.Info($"已有 {Storage.Results.Count} 个结果,少于所需的 {Request.TargetResultCount} 个结果,但无法继续获取,结束处理") Return End If End If '拒绝 1.13- Quilt(这个版本根本没有 Quilt) - If Request.ModLoader = ModLoaderTypes.Quilt AndAlso CompareVersion(If(Request.GameVersion, "1.15"), "1.14") = -1 Then + If Request.ModLoaders = ModLoaders.Quilt AndAlso CompareVersion(If(Request.GameVersion, "1.15"), "1.14") = -1 Then Throw New Exception("Quilt 不支持 Minecraft " & Request.GameVersion) End If @@ -186,10 +190,10 @@ Dim RawSearchText As String = If(Request.SearchText, "").Trim RawSearchText = RawSearchText.Lower - Log("[Resource] 工程列表搜索原始文本:" & RawSearchText) + Logger.Info($"工程列表搜索原始文本:{RawSearchText}") Dim IsChineseSearch As Boolean = - RegexCheck(RawSearchText, "[\u4e00-\u9fbb]") AndAlso Not String.IsNullOrEmpty(RawSearchText) AndAlso + RawSearchText.RegexCheck("[\u4e00-\u9fbb]") AndAlso Not String.IsNullOrEmpty(RawSearchText) AndAlso (Request.Type = ResourceTypes.Mod OrElse Request.Type = ResourceTypes.DataPack) '目前仅对 Mod 和数据包进行中文搜索,注意整合包的名称可能已经有中文了 Dim CurseForgeAltSearchText As String = Nothing, ModrinthAltSearchText As String = Nothing, ModrinthSlugs As New List(Of String) '从中文转为英文的替代搜索内容 If IsChineseSearch Then @@ -231,7 +235,7 @@ Function(Entry) New SearchEntry(Of WikiEntry) With { .Item = Entry, .SearchSource = New List(Of SearchSource) From { - New SearchSource(Entry.ChineseName.BeforeFirst(" (").Split({"/"c}, StringSplitOptions.RemoveEmptyEntries), 1), '部分 Mod 有别名 + New SearchSource(Entry.ChineseName.BeforeFirst(" (").Split("/"c, True), 1), '部分 Mod 有别名 New SearchSource(Entry.ChineseName.AfterFirst(" (") & Entry.CurseForgeSlug, 0.5)} }).ToList Dim CurseForgeSearchResults = Search(CurseForgeSearchEntries, RawSearchText, 100, 0.25) @@ -244,7 +248,7 @@ MaxBy(Function(s) s.Item.Popularity) '然后从中选择最受欢迎的那一个 '后处理 CurseForgeAltSearchText = ExtractWords(CurseForgeTarget, ResourcePlatforms.CurseForge).Join(" ") - Log("[Resource] 中文搜索关键词(CurseForge):" & CurseForgeAltSearchText, NotifyLevel.DebugModeOnly) + Logger.Warn($"中文搜索关键词(CurseForge):{CurseForgeAltSearchText}") End If End If 'Modrinth @@ -255,7 +259,7 @@ Function(Entry) New SearchEntry(Of WikiEntry) With { .Item = Entry, .SearchSource = New List(Of SearchSource) From { - New SearchSource(Entry.ChineseName.BeforeFirst(" (").Split({"/"c}, StringSplitOptions.RemoveEmptyEntries), 1), '部分 Mod 有别名 + New SearchSource(Entry.ChineseName.BeforeFirst(" (").Split("/"c, True), 1), '部分 Mod 有别名 New SearchSource(Entry.ChineseName.AfterFirst(" (") & Entry.ModrinthSlug, 0.5)} }).ToList Dim ModrinthSearchResults = Search(ModrinthSearchEntries, RawSearchText, 100, 0.25) @@ -270,7 +274,7 @@ Next Next ModrinthAltSearchText = WordWeights.MaxBy(Function(w) w.Value).Key - Log("[Resource] 中文搜索关键词(Modrinth):" & ModrinthAltSearchText, NotifyLevel.DebugModeOnly) + Logger.Warn($"中文搜索关键词(Modrinth):{ModrinthAltSearchText}") '直接请求工程 ModrinthSlugs = ModrinthSearchResults.Take(100).Select(Function(r) r.Item.ModrinthSlug).ToList End If @@ -295,7 +299,7 @@ NextPage: '在 1.14-,部分老 Mod 没有设置支持的加载器,因此添加 Forge 筛选就会出现遗漏 '所以,在发起请求时不筛选加载器,然后在返回的结果中自行筛除不是 Forge 的 Mod - Dim IgnoreModLoaderFilter = Request.ModLoader = ModLoaderTypes.Forge AndAlso McVersion.VersionToDrop(Request.GameVersion) < 140 + Dim IgnoreModLoaderFilter = Request.ModLoaders = ModLoaders.Forge AndAlso McVersion.VersionToDrop(Request.GameVersion) < 140 Try 'CurseForge 搜索 @@ -307,21 +311,22 @@ NextPage: Try '获取工程列表 Dim CurseForgeUrl As String = Request.GetCurseForgeAddress(If(CurseForgeAltSearchText, RawSearchText), IgnoreModLoaderFilter) - Log("[Resource] 开始 CurseForge 搜索:" & CurseForgeUrl) + Logger.Info($"开始 CurseForge 搜索:{CurseForgeUrl}") Dim RequestResult As JObject = DlModRequest(CurseForgeUrl) Dim ProjectList As New List(Of ResourceProject) For Each JsonEntry As JObject In RequestResult("data") Dim Project As New ResourceProject(JsonEntry) If Request.Type = ResourceTypes.ResourcePack AndAlso Project.Tags.Contains("数据包") Then Continue For 'CurseForge 将一些数据包分类成了资源包 + If Request.Type <> ResourceTypes.Any AndAlso Not Project.Types.HasFlag(Request.Type) Then Continue For '过滤分区不匹配的搜索结果(#8265) ProjectList.Add(Project) Next '更新结果 ProjectList.ForEach(Sub(p) RawResults.Add(p)) Storage.CurseForgeOffset += RequestResult("data").Count Storage.CurseForgeTotal = RequestResult("pagination")("totalCount").ToObject(Of Integer) - Log($"[Resource] 从 CurseForge 搜索到了 {ProjectList.Count} 个工程(总计已获取 {Storage.CurseForgeOffset} 个,共 {Storage.CurseForgeTotal} 个)") + Logger.Info($"从 CurseForge 搜索到了 {ProjectList.Count} 个工程(总计已获取 {Storage.CurseForgeOffset} 个,共 {Storage.CurseForgeTotal} 个)") Catch ex As Exception - Log(ex, "CurseForge 搜索失败") + Logger.Warn(ex, "CurseForge 搜索失败") Storage.CurseForgeTotal = -1 Errors.Add((ex, ResourcePlatforms.CurseForge)) End Try @@ -337,7 +342,7 @@ NextPage: Sub() Try Dim ModrinthUrl As String = Request.GetModrinthAddress(If(ModrinthAltSearchText, RawSearchText), IgnoreModLoaderFilter) - Log("[Resource] 开始 Modrinth 搜索:" & ModrinthUrl) + Logger.Info($"开始 Modrinth 搜索:{ModrinthUrl}") Dim RequestResult As JObject = DlModRequest(ModrinthUrl) Dim ProjectList As New List(Of ResourceProject) For Each JsonEntry As JObject In RequestResult("hits") @@ -347,9 +352,9 @@ NextPage: ProjectList.ForEach(Sub(p) RawResults.Add(p)) Storage.ModrinthOffset += RequestResult("hits").Count Storage.ModrinthTotal = RequestResult("total_hits").ToObject(Of Integer) - Log($"[Resource] 从 Modrinth 搜索到了 {ProjectList.Count} 个工程(总计已获取 {Storage.ModrinthOffset} 个,共 {Storage.ModrinthTotal} 个)") + Logger.Info($"从 Modrinth 搜索到了 {ProjectList.Count} 个工程(总计已获取 {Storage.ModrinthOffset} 个,共 {Storage.ModrinthTotal} 个)") Catch ex As Exception - Log(ex, "Modrinth 搜索失败") + Logger.Warn(ex, "Modrinth 搜索失败") Storage.ModrinthTotal = -1 Errors.Add((ex, ResourcePlatforms.Modrinth)) End Try @@ -365,7 +370,7 @@ NextPage: Sub() Try Dim ModrinthUrl As String = $"https://api.modrinth.com/v2/projects?ids=[""{ModrinthSlugs.Join(""",""")}""]" - Log("[Resource] 开始 Modrinth 直接获取:" & ModrinthUrl) + Logger.Info($"开始 Modrinth 直接获取:{ModrinthUrl}") Dim ProjectList As New List(Of ResourceProject) For Each JsonEntry As JObject In DlModRequest(ModrinthUrl) Dim Project As New ResourceProject(JsonEntry) @@ -373,18 +378,18 @@ NextPage: If Request.Type <> ResourceTypes.Any AndAlso Not Project.Types.HasFlag(Request.Type) Then Continue For If Not String.IsNullOrEmpty(Request.Tag) AndAlso Not JsonEntry("categories").Any(Function(c) c.ToString = Request.Tag.AfterLast("/")) Then Continue For 'Project.Tags 已经转换成中文了,只能从 json 判 - If Request.ModLoader <> ModLoaderTypes.Any AndAlso Not IgnoreModLoaderFilter AndAlso - Not Project.Loaders.Any(Function(m) m = Request.ModLoader) Then Continue For + If Request.ModLoaders <> ModLoaders.None AndAlso Not IgnoreModLoaderFilter AndAlso + Not Project.ModLoaders.Flags.Intersect(Request.ModLoaders.Flags).Any() Then Continue For If Not String.IsNullOrEmpty(Request.GameVersion) AndAlso Not Project.UnsafeGameVersions.Any(Function(d) d = Request.GameVersion) Then Continue For ProjectList.Add(Project) Next '更新结果 ProjectList.ForEach(Sub(p) RawResults.Add(p)) - Log($"[Resource] 从 Modrinth 直接获取到了 {ProjectList.Count} 个工程") + Logger.Info($"从 Modrinth 直接获取到了 {ProjectList.Count} 个工程") ModrinthSlugs.Clear() '防止重试/加载下一页时重复获取 Catch ex As Exception - Log(ex, "Modrinth 直接获取失败") + Logger.Warn(ex, "Modrinth 直接获取失败") Errors.Add((ex, ResourcePlatforms.Modrinth)) End Try If Task.Progress < 0.75 Then Task.Progress += 0.25 '可能重复加载多页,所以不能直接给够 @@ -397,9 +402,9 @@ NextPage: If Task.IsInterrupted Then Return '会自动触发 Finally 以清理线程 Next - '筛除不是 Forge 的 Mod + '仅保留兼容 Forge 的 Mod,或老版本中没有标注任何 Mod Loader 的 Mod If IgnoreModLoaderFilter Then - RawResults = RawResults.Where(Function(p) Not p.Loaders.Any() OrElse p.Loaders.Contains(ModLoaderTypes.Forge)).ToList + RawResults.KeepIf(Function(p) p.ModLoaders = ModLoaders.None OrElse p.ModLoaders.HasFlag(ModLoaders.Forge)) End If '确保存在结果 @@ -446,19 +451,19 @@ NextPage: Not Storage.Results.Any(Function(b) r.IsLike(b))).ToList '加入列表 RealResults.AddRange(RawResults) - Log($"[Resource] 去重、筛选后累计新增结果 {RealResults.Count} 个(目前已有结果 {Storage.Results.Count} 个)") + Logger.Info($"去重、筛选后累计新增结果 {RealResults.Count} 个(目前已有结果 {Storage.Results.Count} 个)") #End Region #Region "检查结果数量,如果不足且可继续,会继续加载下一页" If RealResults.Count + Storage.Results.Count < Request.TargetResultCount Then - Log($"[Resource] 总结果数需求最少 {Request.TargetResultCount} 个,仅获得了 {RealResults.Count + Storage.Results.Count} 个") + Logger.Info($"总结果数需求最少 {Request.TargetResultCount} 个,仅获得了 {RealResults.Count + Storage.Results.Count} 个") If Request.CanContinue AndAlso Not Errors.Any Then '如果有某个源失败则不再重试,这时候重试可能导致无限循环 - Log("[Resource] 将继续尝试加载下一页") + Logger.Info("将继续尝试加载下一页") GoTo NextPage Else - Log("[Resource] 无法继续加载,将强制结束") + Logger.Info("无法继续加载,将强制结束") End If End If @@ -493,7 +498,7 @@ NextPage: Scores(Result) = If(Result.WikiId > 0, 0.2, 0) + Math.Log10(Math.Max(Result.DownloadCount, 1) * GetDownloadCountMult(Result)) / 9 SearchEntries.Add(New SearchEntry(Of ResourceProject) With {.Item = Result, .SearchSource = New List(Of SearchSource) From { - New SearchSource(If(IsChineseSearch, Result.TranslatedName, Result.RawName).Split({"/"c}, StringSplitOptions.RemoveEmptyEntries), 1), + New SearchSource(If(IsChineseSearch, Result.TranslatedName, Result.RawName).Split("/"c, True), 1), New SearchSource(Result.Description, 0.05)}}) Next Dim SearchResult = Search(SearchEntries, RawSearchText, 10000, -1) diff --git a/Plain Craft Launcher 2/Modules/Resource/ResourceVersion.vb b/Plain Craft Launcher 2/Modules/Resource/ResourceVersion.vb index b2aa514..201a4d2 100644 --- a/Plain Craft Launcher 2/Modules/Resource/ResourceVersion.vb +++ b/Plain Craft Launcher 2/Modules/Resource/ResourceVersion.vb @@ -36,10 +36,9 @@ Public Class ResourceVersion ''' Public Version As String ''' - ''' 支持的 Mod 加载器列表。 - ''' 可能为空列表,不为 Nothing。 + ''' 所有支持的 Mod 加载器列表。可能为 。 ''' - Public Loaders As List(Of ModLoaderTypes) + Public ModLoaders As ModLoaders = ModLoaders.None ''' ''' 支持的游戏版本列表。类型包括:"26.1.5","26.1","26.1 预览版","1.18.5","1.18","1.18 预览版","21w15a","未知版本"。 ''' @@ -158,11 +157,10 @@ Public Class ResourceVersion .GameVersions = New List(Of String) From {"未知版本"} End If 'ModLoaders - .Loaders = New List(Of ModLoaderTypes) - If RawVersions.Contains("forge") Then .Loaders.Add(ModLoaderTypes.Forge) - If RawVersions.Contains("fabric") Then .Loaders.Add(ModLoaderTypes.Fabric) - If RawVersions.Contains("quilt") Then .Loaders.Add(ModLoaderTypes.Quilt) - If RawVersions.Contains("neoforge") Then .Loaders.Add(ModLoaderTypes.NeoForge) + .ModLoaders = ModLoaders.None + For Each Loader In EnumUtils.GetAllFlags(Of ModLoaders)() + If RawVersions.Contains(Loader.ToString.Lower) Then .ModLoaders = .ModLoaders Or Loader + Next #End Region Else #Region "Modrinth" @@ -183,14 +181,13 @@ Public Class ResourceVersion 'Loaders '结果可能混杂着 Mod、数据包和服务端插件 Dim RawLoaders As List(Of String) = Data("loaders").Select(Function(v) v.ToString).ToList - .Loaders = New List(Of ModLoaderTypes) + .ModLoaders = ModLoaders.None If .ResourceType.HasFlag(ResourceTypes.Mod) OrElse .ResourceType.HasFlag(ResourceTypes.DataPack) Then If RawLoaders.Intersect({"bukkit", "folia", "paper", "purpur", "spigot"}).Any() Then .ResourceType = ResourceTypes.Plugin 'Veinminer Enchantment 同时支持服务端与 Fabric If RawLoaders.Contains("datapack") Then .ResourceType = ResourceTypes.DataPack - If RawLoaders.Contains("forge") Then .Loaders.Add(ModLoaderTypes.Forge) : .ResourceType = ResourceTypes.Mod - If RawLoaders.Contains("neoforge") Then .Loaders.Add(ModLoaderTypes.NeoForge) : .ResourceType = ResourceTypes.Mod - If RawLoaders.Contains("fabric") Then .Loaders.Add(ModLoaderTypes.Fabric) : .ResourceType = ResourceTypes.Mod - If RawLoaders.Contains("quilt") Then .Loaders.Add(ModLoaderTypes.Quilt) : .ResourceType = ResourceTypes.Mod + For Each Loader As ModLoaders In EnumUtils.GetAllFlags(Of ModLoaders)() + If RawLoaders.Contains(Loader.ToString.Lower) Then .ModLoaders = .ModLoaders Or Loader : .ResourceType = ResourceTypes.Mod + Next Else '使用传入的类别,不作修改(#8377) End If @@ -212,8 +209,8 @@ Public Class ResourceVersion ElseIf .GameVersions.Count > 1 Then .GameVersions = .GameVersions.SortByComparison(AddressOf CompareVersionGE).ToList If .ResourceType = ResourceTypes.ModPack Then .GameVersions = New List(Of String) From { .GameVersions(0)} '整合包理应只 “支持” 一个版本 - ElseIf RawVersions.Any(Function(v) RegexCheck(v, "[0-9]{2}w[0-9]{2}[a-z]")) Then - .GameVersions = RawVersions.Where(Function(v) RegexCheck(v, "[0-9]{2}w[0-9]{2}[a-z]")).ToList + ElseIf RawVersions.Any(Function(v) v.RegexCheck("[0-9]{2}w[0-9]{2}[a-z]")) Then + .GameVersions = RawVersions.Where(Function(v) v.RegexCheck("[0-9]{2}w[0-9]{2}[a-z]")).ToList Else .GameVersions = New List(Of String) From {"未知版本"} End If @@ -230,7 +227,7 @@ Public Class ResourceVersion Dim TargetProject = ResourceProject.FromProjectId(ProjectId, Platform) '获取项目对象的文件列表 If Not ProjectFilesCache.ContainsKey(ProjectId) Then - Log("[Resource] 开始获取项目版本列表:" & ProjectId) + Logger.Info($"开始获取项目版本列表:{ProjectId}") Dim ResultJsonArray As JArray = Nothing If Platform = ResourcePlatforms.CurseForge Then For RetryCount As Integer = 0 To 2 @@ -247,10 +244,10 @@ Public Class ResourceVersion ResultJsonArray = ResultJson("data") Exit For ElseIf RetryCount < 2 Then - Log($"[Resource] CurseForge 返回的资源版本列表存在缺失,即将进行第 {RetryCount + 1} 次重试", NotifyLevel.DebugModeOnly) '#6224 - Log($"[Resource] 返回的原始内容如下:{vbCrLf}{ResultJson}") + Logger.Warn($"CurseForge 返回的资源版本列表存在缺失,即将进行第 {RetryCount + 1} 次重试") '#6224 + Logger.Info($"返回的原始内容如下:{vbCrLf}{ResultJson}") Else - Log($"[Resource] CurseForge 返回的资源版本列表存在缺失,返回的原始内容如下:{vbCrLf}{ResultJson}") + Logger.Info($"CurseForge 返回的资源版本列表存在缺失,返回的原始内容如下:{vbCrLf}{ResultJson}") Throw New Exception("CurseForge 返回的资源版本列表存在缺失") End If Next @@ -266,7 +263,7 @@ Public Class ResourceVersion '加载前置信息 Dim Dependencies As List(Of String) = Result.SelectMany(Function(f) f.RawDependencies).Distinct().ToList If Dependencies.Any Then - Log($"[Resource] 项目 {ProjectId} 中需要加载的前置:{Dependencies.Join(",")}") + Logger.Info($"项目 {ProjectId} 中需要加载的前置:{Dependencies.Join(",")}") For Each DependencyProject In ResourceProject.FromProjectIds(Dependencies, TargetProject.Platform) For Each File In Result If File.RawDependencies.Contains(DependencyProject.Id) AndAlso DependencyProject.Id <> ProjectId AndAlso Not File.Dependencies.Contains(DependencyProject.Id) Then @@ -290,16 +287,16 @@ Public Class ResourceVersion Public Shared Function FromCacheJson(Data As JObject) As ResourceVersion Dim Result As New ResourceVersion With Result - .ResourceType = CType(Data("ResourceType").ToObject(Of Integer), ResourceTypes) + .ResourceType = Data("ResourceType").ToObject(Of ResourceTypes) .Id = Data("Id").ToString .Display = Data("DisplayName").ToString If Data.ContainsKey("Version") Then .Version = Data("Version").ToString .ReleaseDate = Data("ReleaseDate").ToObject(Of Date) .DownloadCount = Data("DownloadCount").ToObject(Of Integer) - .ReleaseType = CType(Data("ReleaseType").ToObject(Of Integer), ReleaseTypes) + .ReleaseType = Data("ReleaseType").ToObject(Of ReleaseTypes) If Data.ContainsKey("FileName") Then .FileName = Data("FileName").ToString If Data.ContainsKey("DownloadUrls") Then .DownloadUrls = Data("DownloadUrls").ToObject(Of List(Of String)) - If Data.ContainsKey("ModLoaders") Then .Loaders = Data("ModLoaders").ToObject(Of List(Of ModLoaderTypes)) + If Data.ContainsKey("ModLoaders") Then .ModLoaders = Data("ModLoaders").ToObject(Of ModLoaders) If Data.ContainsKey("Size") Then .Size = Data("Size").ToObject(Of Integer) If Data.ContainsKey("Hash") Then .Hash = Data("Hash").ToString If Data.ContainsKey("GameVersions") Then .GameVersions = Data("GameVersions").ToObject(Of List(Of String)) @@ -320,7 +317,7 @@ Public Class ResourceVersion .Add("DisplayName", Display) .Add("ReleaseDate", ReleaseDate) .Add("DownloadCount", DownloadCount) - .Add("ModLoaders", New JArray(Loaders.Select(Function(m) CInt(m)))) + .Add("ModLoaders", ModLoaders) .Add("GameVersions", New JArray(GameVersions)) .Add("ReleaseType", CInt(ReleaseType)) If FileName IsNot Nothing Then .Add("FileName", FileName) @@ -383,10 +380,35 @@ Public Class ResourceVersion ''' 获取下载信息。 ''' ''' 目标本地文件夹,或完整的文件路径。会自动判断类型。 - Public Function ToNetFile(LocalFileOrFolder As String) As NetFile - Return New NetFile(DownloadUrls, LocalFileOrFolder & If(LocalFileOrFolder.EndsWithF("\"), FileName, ""), New FileChecker(Hash:=Hash, ActualSize:=Size), SimulateBrowserHeaders:=True) + Public Function ToNetFile(LocalFileOrFolder As String, + Optional TrackDownloadReason As DownloadReason? = Nothing, Optional TrackGameVersion As String = Nothing, Optional TrackLoader As ModLoaders = ModLoaders.None) As NetFile + Return New NetFile( + ParseModrinthTrackArguments(DownloadUrls, TrackDownloadReason, TrackGameVersion, TrackLoader), + LocalFileOrFolder & If(LocalFileOrFolder.EndsWithF("\"), FileName, ""), + New FileChecker(Hash:=Hash, ActualSize:=Size), + SimulateBrowserHeaders:=True) End Function ''' + ''' 添加 Modrinth 追踪参数。 + ''' + Public Shared Iterator Function ParseModrinthTrackArguments(Urls As List(Of String), Optional TrackDownloadReason As DownloadReason? = Nothing, Optional TrackGameVersion As String = Nothing, Optional TrackLoader As ModLoaders = ModLoaders.None) As IEnumerable(Of String) + Dim Arguments As New Dictionary(Of String, String) + If TrackDownloadReason IsNot Nothing Then Arguments.Add("mr_download_reason", TrackDownloadReason.ToString.Lower) + If TrackGameVersion IsNot Nothing Then Arguments.Add("mr_game_version", TrackGameVersion) + If TrackLoader.Flags.Any Then Arguments.Add("mr_loader", TrackLoader.Flags.First.ToString.Lower) + Dim Argument = Arguments.Select(Function(a) $"{a.Key}={a.Value}").Join("&") + For Each Url In Urls + If Not Url.ContainsIgnoreCase("cdn.modrinth.com/") Then Yield Url + Yield $"{Url}{If(Url.Contains("?"), "&", "?")}{Argument}" + Next + End Function + Public Enum DownloadReason + Standalone + Dependency + ModPack + Update + End Enum + ''' ''' 重新整理 CurseForge 的下载地址。 ''' Public Shared Function ParseCurseForgeDownloadUrls(Url As String) As List(Of String) diff --git a/Plain Craft Launcher 2/Modules/Resource/WikiEntry.vb b/Plain Craft Launcher 2/Modules/Resource/WikiEntry.vb index cc72002..f5f9981 100644 --- a/Plain Craft Launcher 2/Modules/Resource/WikiEntry.vb +++ b/Plain Craft Launcher 2/Modules/Resource/WikiEntry.vb @@ -42,33 +42,32 @@ Public Class WikiEntry If Cache IsNot Nothing Then Return Cache '实际加载 Cache = New List(Of WikiEntry) - Dim Data As String - Using Archive As New ZipArchive(New MemoryStream(GetResources("ModData")), ZipArchiveMode.Read) - Data = ReadFile(Archive.GetEntry("moddata.txt").Open(), Encoding.UTF8) - End Using Dim i As Integer = 0 - For Each Line In Data.ReplaceLineEndings(vbLf).Split(vbLf) + Dim DataLines As List(Of String) = DirectCast(My.Resources.ResourceManager.GetObject("ModData"), String).SplitLines().ToList() + Dim Ranks = DataLines.Last.Split("|") + DataLines.RemoveAt(DataLines.Count - 1) + For Each Line In DataLines i += 1 If Line = "" Then Continue For For Each EntryData As String In Line.Split("¨") Dim Entry = New WikiEntry Dim Splited = EntryData.Split("|") - Entry.Popularity = Val(Splited(0)) - If Splited(1).StartsWithF("@") Then + If Splited(0).StartsWithF("@") Then Entry.CurseForgeSlug = Nothing - Entry.ModrinthSlug = Splited(1).Replace("@", "") - ElseIf Splited(1).EndsWithF("@") Then - Entry.CurseForgeSlug = Splited(1).TrimEnd("@") + Entry.ModrinthSlug = Splited(0).Replace("@", "") + ElseIf Splited(0).EndsWithF("@") Then + Entry.CurseForgeSlug = Splited(0).TrimEnd("@") Entry.ModrinthSlug = Entry.CurseForgeSlug - ElseIf Splited(1).Contains("@") Then - Entry.CurseForgeSlug = Splited(1).Split("@")(0) - Entry.ModrinthSlug = Splited(1).Split("@")(1) + ElseIf Splited(0).Contains("@") Then + Entry.CurseForgeSlug = Splited(0).Split("@")(0) + Entry.ModrinthSlug = Splited(0).Split("@")(1) Else - Entry.CurseForgeSlug = Splited(1) + Entry.CurseForgeSlug = Splited(0) Entry.ModrinthSlug = Nothing End If Entry.Id = i - If Splited.Count >= 3 Then + Entry.Popularity = Val(Ranks(i - 1)) + If Splited.Count >= 2 Then Entry.ChineseName = Splited.Last If Entry.ChineseName.Contains("*") Then '处理 * Entry.ChineseName = Entry.ChineseName.Replace("*", diff --git a/Plain Craft Launcher 2/My Project/AssemblyInfo.vb b/Plain Craft Launcher 2/My Project/AssemblyInfo.vb index bd05db8..08bc312 100644 --- a/Plain Craft Launcher 2/My Project/AssemblyInfo.vb +++ b/Plain Craft Launcher 2/My Project/AssemblyInfo.vb @@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices ' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 ' 方法是按如下所示使用“*” - - + + diff --git a/Plain Craft Launcher 2/My Project/Resources.Designer.vb b/Plain Craft Launcher 2/My Project/Resources.Designer.vb index 98cacdb..ebbb5e9 100644 --- a/Plain Craft Launcher 2/My Project/Resources.Designer.vb +++ b/Plain Craft Launcher 2/My Project/Resources.Designer.vb @@ -181,12 +181,25 @@ Namespace My.Resources End Property ''' - ''' 查找 System.Byte[] 类型的本地化资源。 + ''' 查找类似 + '''22107|industrial-craft@|工业时代2 (Industrial Craft 2) + '''21532|@redpower2-core|红石力量2 (RedPower2) + '''22036|buildcraft@|建筑 (BuildCraft) + '''22074|forestry@|林业* + '''21995|railcraft@railcraft-reborn|铁路*¨21996|railcraft-reborn|铁路 (Railcraft) + ''' + ''' + '''22054|@ee2|等价交换2 (Equivalent Exchange 2) + ''' + '''21655|touhou-item-mod|辉夜姬的五难题 (五つの難題MOD+ ~ Touhou Items) + '''20236|secretroomsmod|密室 (SecretRoomsMod) + '''20521|the-camping-mod|野营* + '''20056|usefulfood|有用的食物 (UsefulFood) + '''20021|powerconverters-portablejims-fork|能源转换 (PowerConverters)¨20022|powerconverters|能源 [字符串的其余部分被截断]"; 的本地化字符串。 ''' - Friend ReadOnly Property ModData() As Byte() + Friend ReadOnly Property ModData() As String Get - Dim obj As Object = ResourceManager.GetObject("ModData", resourceCulture) - Return CType(obj,Byte()) + Return ResourceManager.GetString("ModData", resourceCulture) End Get End Property @@ -240,16 +253,6 @@ Namespace My.Resources End Get End Property - ''' - ''' 查找 System.Byte[] 类型的本地化资源。 - ''' - Friend ReadOnly Property System_ValueTuple() As Byte() - Get - Dim obj As Object = ResourceManager.GetObject("System.ValueTuple", resourceCulture) - Return CType(obj,Byte()) - End Get - End Property - ''' ''' 查找 System.Byte[] 类型的本地化资源。 ''' diff --git a/Plain Craft Launcher 2/My Project/Resources.resx b/Plain Craft Launcher 2/My Project/Resources.resx index 43985a0..436e62f 100644 --- a/Plain Craft Launcher 2/My Project/Resources.resx +++ b/Plain Craft Launcher 2/My Project/Resources.resx @@ -155,7 +155,7 @@ ..\..\PCLCS\bin\MeloongCore.Wpf.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - ..\Resources\moddata.zip;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + ..\Resources\moddata.txt;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8 ..\Resources\NAudio.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 @@ -172,9 +172,6 @@ ..\Resources\System.Net.Http.Formatting.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - ..\Resources\System.ValueTuple.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - ..\Resources\transformer.jar;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 diff --git a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb index 5cfde04..8c1edae 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/ModDownloadLib.vb @@ -29,7 +29,7 @@ LoadersLib.Add(New LoaderTask(Of String, List(Of NetFile))("分析原版支持库文件(副加载器)", Sub(Task As LoaderTask(Of String, List(Of NetFile))) Thread.Sleep(50) '等待 JSON 文件实际写入硬盘(#3710) - Log("[Download] 开始分析原版支持库文件:" & VersionFolder) + Logger.Info($"开始分析原版支持库文件:{VersionFolder}") Task.Output = McLibNetFilesFromInstance(New McInstance(VersionFolder)) End Sub) With {.ProgressWeight = 1, .Show = False}) LoadersLib.Add(New LoaderDownload("下载原版支持库文件(副加载器)", New List(Of NetFile)) With {.ProgressWeight = 13, .Show = False}) @@ -47,7 +47,7 @@ End Try '顺手添加 Json 项目 Try - Dim InstanceJson As JObject = GetJson(ReadFile(VersionFolder & InstanceName & ".json")) + Dim InstanceJson As JObject = GetJson(FileUtils.ReadAsString(VersionFolder & InstanceName & ".json")) InstanceJson.Add("clientVersion", Id) FileUtils.Write($"{VersionFolder}{InstanceName}.json", InstanceJson.ToString) Catch ex As Exception @@ -158,8 +158,8 @@ Try Dim Id = Version.Title Dim JsonUrl = Version.Tag("url").ToString - Dim VersionFolder As String = SelectFolder() - If Not VersionFolder.Contains("\") Then Return + Dim VersionFolder As String = Dialogs.SelectFolder("选择目标文件夹", False).FirstOrDefault + If VersionFolder Is Nothing Then Return VersionFolder = VersionFolder & Id & "\" '重复任务检查 @@ -180,8 +180,8 @@ '分析服务端 JAR 文件下载地址 Dim Instance As New McInstance(VersionFolder) If Instance.JsonObject("downloads") Is Nothing OrElse Instance.JsonObject("downloads")("server") Is Nothing OrElse Instance.JsonObject("downloads")("server")("url") Is Nothing Then - File.Delete(VersionFolder & Id & ".json") - If Not New DirectoryInfo(VersionFolder).GetFileSystemInfos.Any() Then DeleteDirectory(VersionFolder) + FileUtils.Delete(VersionFolder & Id & ".json") + If Not DirectoryUtils.GetInfo(VersionFolder).GetFileSystemInfos.Any() Then DirectoryUtils.Delete(VersionFolder) Task.Output = New List(Of NetFile) Hint($"Mojang 没有给 Minecraft {Id} 提供官方服务端下载,没法下,撤退!", HintType.Red) Thread.Sleep(2000) '等玩家把上一个提示看完 @@ -207,7 +207,7 @@ pause" FileUtils.Write(VersionFolder & "Launch Server.bat", Bat, Encoding:=If(Encoding.Default.Equals(Encoding.UTF8), Encoding.UTF8, Encoding.GetEncoding("GB18030"))) '删除版本 JSON - File.Delete(VersionFolder & Id & ".json") + FileUtils.Delete(VersionFolder & Id & ".json") End Sub) With {.ProgressWeight = 0.5, .Show = False}) '下载服务端文件 Loaders.Add(New LoaderDownload("下载服务端文件", New List(Of NetFile)) With {.ProgressWeight = 5}) @@ -219,7 +219,7 @@ pause" FrmMain.BtnExtraDownload.ShowRefresh() FrmMain.BtnExtraDownload.Ribble() Catch ex As Exception - Log(ex, "开始 Minecraft 服务端下载失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "开始 Minecraft 服务端下载失败") End Try End Sub Public Sub McDownloadMenuSave(sender As Object, e As RoutedEventArgs) @@ -234,8 +234,8 @@ pause" Try Dim Id = Version.Title Dim JsonUrl = Version.Tag("url").ToString - Dim VersionFolder As String = SelectFolder() - If Not VersionFolder.Contains("\") Then Return + Dim VersionFolder As String = Dialogs.SelectFolder("选择目标文件夹", False).FirstOrDefault + If VersionFolder Is Nothing Then Return VersionFolder = VersionFolder & Id & "\" '重复任务检查 @@ -264,7 +264,7 @@ pause" FrmMain.BtnExtraDownload.ShowRefresh() FrmMain.BtnExtraDownload.Ribble() Catch ex As Exception - Log(ex, "开始 Minecraft 下载失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "开始 Minecraft 下载失败") End Try End Sub ''' @@ -323,7 +323,7 @@ pause" ElseIf Id.StartsWithF("rd-") Then WikiName = "Java版Pre-classic_" & Id Else - Log("[Error] 未知的版本格式:" & Id & "。", NotifyLevel.MsgBoxAndFeedback) + Logger.Error($"未知的版本格式:{Id}。") Return End If OpenWebsite("https://zh.minecraft.wiki/w/" & WikiName.Replace("_experimental-snapshot-", "-exp")) @@ -336,8 +336,8 @@ pause" Private Sub McDownloadOptiFineSave(DownloadInfo As DlOptiFineListEntry) Try Dim Id As String = DownloadInfo.InstanceName - Dim Target As String = SelectSaveFile("选择保存位置", DownloadInfo.FileName, "OptiFine Jar (*.jar)|*.jar") - If Not Target.Contains("\") Then Return + Dim Target As String = Dialogs.SaveFile("选择保存位置", DownloadInfo.FileName, filter:={("jar", "OptiFine Jar")}) + If Target Is Nothing Then Return '重复任务检查 For Each OngoingLoader In LoaderTaskbar.ToList() @@ -353,7 +353,7 @@ pause" FrmMain.BtnExtraDownload.Ribble() Catch ex As Exception - Log(ex, "开始 OptiFine 下载失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "开始 OptiFine 下载失败") End Try End Sub Private Sub McDownloadOptiFineInstall(BaseMcFolderHome As String, Target As String, Task As LoaderTask(Of List(Of NetFile), Boolean), UseJavaWrapper As Boolean) @@ -380,7 +380,7 @@ pause" End SyncLock '添加 Java Wrapper 作为主 Jar Dim Arguments As String - If UseJavaWrapper AndAlso Not Settings.Get("LaunchAdvanceDisableJLW") Then + If UseJavaWrapper AndAlso Not Settings.Get(Of Boolean)("LaunchAdvanceDisableJLW") Then Arguments = $"-Doolloo.jlw.tmpdir=""{PathPure.TrimEnd("\")}"" -Duser.home=""{BaseMcFolderHome.TrimEnd("\")}"" -cp ""{Target}"" -jar ""{ExtractPatch("JavaWrapper")}"" optifine.Installer" Else Arguments = $"-Duser.home=""{BaseMcFolderHome.TrimEnd("\")}"" -cp ""{Target}"" optifine.Installer" @@ -395,14 +395,14 @@ pause" .CreateNoWindow = True, .RedirectStandardError = True, .RedirectStandardOutput = True, - .WorkingDirectory = FileUtils.ShortenPath(BaseMcFolderHome) + .WorkingDirectory = PathUtils.ToShortPath(BaseMcFolderHome) } If Info.EnvironmentVariables.ContainsKey("appdata") Then Info.EnvironmentVariables("appdata") = BaseMcFolderHome Else Info.EnvironmentVariables.Add("appdata", BaseMcFolderHome) End If - Log("[Download] 开始安装 OptiFine:" & Target) + Logger.Info($"开始安装 OptiFine:{Target}") Dim TotalLength As Integer = 0 Dim process As New Process With {.StartInfo = Info} Dim LastResult As String = "" @@ -415,17 +415,17 @@ pause" outputWaitHandle.[Set]() Else LastResult = e.Data - If ModeDebug Then Log("[Installer] " & LastResult) + Logger.Trace(LastResult) TotalLength += 1 Task.Progress += 0.9 / 7000 End If Catch ex As ObjectDisposedException Catch ex As Exception - Log(ex, "读取 OptiFine 安装器信息失败") + Logger.Warn(ex, "读取 OptiFine 安装器信息失败") End Try Try If Task.State = LoadState.Interrupted AndAlso Not process.HasExited Then - Log("[Installer] 由于任务取消,已中止 OptiFine 安装") + Logger.Info("由于任务取消,已中止 OptiFine 安装") process.Kill() End If Catch @@ -439,17 +439,17 @@ pause" errorWaitHandle.[Set]() Else LastResult = e.Data - If ModeDebug Then Log("[Installer] " & LastResult) + Logger.Trace(LastResult) TotalLength += 1 Task.Progress += 0.9 / 7000 End If Catch ex As ObjectDisposedException Catch ex As Exception - Log(ex, "读取 OptiFine 安装器错误信息失败") + Logger.Warn(ex, "读取 OptiFine 安装器错误信息失败") End Try Try If Task.State = LoadState.Interrupted AndAlso Not process.HasExited Then - Log("[Installer] 由于任务取消,已中止 OptiFine 安装") + Logger.Info("由于任务取消,已中止 OptiFine 安装") process.Kill() End If Catch @@ -507,10 +507,10 @@ pause" PageData = NetRequestByClientRetry("https://optifine.net/adloadx?f=" & DownloadInfo.FileName, Encoding:=New UTF8Encoding(False), Accept:="text/html", SimulateBrowserHeaders:=True) Task.Progress = 0.8 - Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0)) - Log("[Download] OptiFine " & DownloadInfo.DisplayName & " 官方下载地址:" & Sources.Last) + Sources.Add("https://optifine.net/" & PageData.RegexSearch("downloadx\?f=[^""']+").First) + Logger.Info($"OptiFine {DownloadInfo.DisplayName} 官方下载地址:{Sources.Last}") Catch ex As Exception - Log(ex, "获取 OptiFine " & DownloadInfo.DisplayName & " 官方下载地址失败") + Logger.Warn(ex, $"获取 OptiFine {DownloadInfo.DisplayName} 官方下载地址失败") End Try '构造文件请求 Task.Output = New List(Of NetFile) From {New NetFile(Sources.ToArray, Target, New FileChecker(MinSize:=300 * 1024))} @@ -522,43 +522,43 @@ pause" 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] OptiFine 安装正在等待原版文件下载完成") + If TargetLoaders.Any Then Logger.Info("OptiFine 安装正在等待原版文件下载完成") Do While TargetLoaders.Any AndAlso Not Task.IsInterrupted TargetLoaders = TargetLoaders.Where(Function(l) l.State <> LoadState.Finished).ToList Thread.Sleep(50) Loop If Task.IsInterrupted Then Return - '拷贝原版文件 + '复制原版文件 If Not IsCustomFolder Then Return SyncLock VanillaSyncLock - Dim ClientName As String = GetFolderNameFromPath(ClientFolder) + Dim ClientName As String = PathUtils.GetLastPart(ClientFolder) DirectoryUtils.Create(McFolder & "versions\" & DownloadInfo.Inherit) - If Not File.Exists(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json") Then - CopyFile($"{ClientFolder}{ClientName}.json", $"{McFolder}versions\{DownloadInfo.Inherit}\{DownloadInfo.Inherit}.json") + If Not FileUtils.Exists(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json") Then + FileUtils.Copy($"{ClientFolder}{ClientName}.json", $"{McFolder}versions\{DownloadInfo.Inherit}\{DownloadInfo.Inherit}.json") End If - If Not File.Exists(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar") Then - CopyFile($"{ClientFolder}{ClientName}.jar", $"{McFolder}versions\{DownloadInfo.Inherit}\{DownloadInfo.Inherit}.jar") + If Not FileUtils.Exists(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar") Then + FileUtils.Copy($"{ClientFolder}{ClientName}.jar", $"{McFolder}versions\{DownloadInfo.Inherit}\{DownloadInfo.Inherit}.jar") End If End SyncLock End Sub) With {.ProgressWeight = 0.1, .Show = False}) '安装(新旧方式均需要原版 Jar 和 Json) If IsNewerVersion Then - Log("[Download] 检测为新版 OptiFine:" & DownloadInfo.Inherit) + Logger.Info($"检测为新版 OptiFine:{DownloadInfo.Inherit}") Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("安装 OptiFine(方式 A)", Sub(Task As LoaderTask(Of List(Of NetFile), Boolean)) Dim BaseMcFolderHome As String = RequestTaskTempFolder() Dim BaseMcFolder As String = BaseMcFolderHome & ".minecraft\" Try '准备安装环境 - If Directory.Exists(BaseMcFolder & "versions\" & DownloadInfo.Inherit) Then - DeleteDirectory(BaseMcFolder & "versions\" & DownloadInfo.Inherit) + If DirectoryUtils.Exists(BaseMcFolder & "versions\" & DownloadInfo.Inherit) Then + DirectoryUtils.Delete(BaseMcFolder & "versions\" & DownloadInfo.Inherit) End If DirectoryUtils.Create(BaseMcFolder & "versions\" & DownloadInfo.Inherit & "\") McFolderLauncherProfilesJsonCreate(BaseMcFolder) - CopyFile(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json", + FileUtils.Copy(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json", BaseMcFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".json") - CopyFile(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar", + FileUtils.Copy(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar", BaseMcFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar") Task.Progress = 0.06 '进行安装 @@ -568,7 +568,7 @@ Retry: McDownloadOptiFineInstall(BaseMcFolderHome, Target, Task, UseJavaWrapper) Catch ex As Exception If UseJavaWrapper Then - Log(ex, "使用 JavaWrapper 安装 OptiFine 失败,将不使用 JavaWrapper 并重试") + Logger.Warn(ex, "使用 JavaWrapper 安装 OptiFine 失败,将不使用 JavaWrapper 并重试") UseJavaWrapper = False GoTo Retry Else @@ -577,27 +577,23 @@ Retry: End Try Task.Progress = 0.96 '复制文件 - File.Delete(BaseMcFolder & "launcher_profiles.json") - CopyDirectory(BaseMcFolder, McFolder) + FileUtils.Delete(BaseMcFolder & "launcher_profiles.json") + DirectoryUtils.Copy(BaseMcFolder, McFolder) Task.Progress = 0.98 '清理文件 - File.Delete(Target) - DeleteDirectory(BaseMcFolderHome) + FileUtils.Delete(Target) + DirectoryUtils.Delete(BaseMcFolderHome) Catch ex As Exception Throw New Exception("安装 OptiFine(方式 A)失败", ex) End Try End Sub) With {.ProgressWeight = 8}) Else - Log("[Download] 检测为旧版 OptiFine:" & DownloadInfo.Inherit) + Logger.Info($"检测为旧版 OptiFine:{DownloadInfo.Inherit}") Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)("安装 OptiFine(方式 B)", Sub(Task As LoaderTask(Of List(Of NetFile), Boolean)) Try - '新建版本文件夹 - DirectoryUtils.Create(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") + FileUtils.Copy(McFolder & "versions\" & DownloadInfo.Inherit & "\" & DownloadInfo.Inherit & ".jar", VersionFolder & Id & ".jar") Task.Progress = 0.7 '建立 Json 文件 Dim InheritInstance As New McInstance(McFolder & "versions\" & DownloadInfo.Inherit) @@ -663,10 +659,10 @@ Retry: PageData = NetRequestByClientRetry("https://optifine.net/adloadx?f=" & DownloadInfo.FileName, Encoding:=New UTF8Encoding(False), Accept:="text/html", SimulateBrowserHeaders:=True) Task.Progress = 0.8 - Sources.Add("https://optifine.net/" & RegexSearch(PageData, "downloadx\?f=[^""']+")(0)) - Log("[Download] OptiFine " & DownloadInfo.DisplayName & " 官方下载地址:" & Sources.Last) + Sources.Add("https://optifine.net/" & PageData.RegexSearch("downloadx\?f=[^""']+").First) + Logger.Info($"OptiFine {DownloadInfo.DisplayName} 官方下载地址:{Sources.Last}") Catch ex As Exception - Log(ex, "获取 OptiFine " & DownloadInfo.DisplayName & " 官方下载地址失败") + Logger.Warn(ex, $"获取 OptiFine {DownloadInfo.DisplayName} 官方下载地址失败") End Try Task.Progress = 0.9 '构造文件请求 @@ -753,8 +749,8 @@ Retry: Private Sub McDownloadLiteLoaderSave(DownloadInfo As DlLiteLoaderListEntry) Try Dim Id As String = DownloadInfo.Inherit - Dim Target As String = SelectSaveFile("选择保存位置", DownloadInfo.FileName.Replace("-SNAPSHOT", ""), "LiteLoader 安装器 (*.jar)|*.jar") - If Not Target.Contains("\") Then Return + Dim Target As String = Dialogs.SaveFile("选择保存位置", DownloadInfo.FileName.Replace("-SNAPSHOT", ""), filter:={("jar", "LiteLoader 安装器")}) + If Target Is Nothing Then Return '重复任务检查 For Each OngoingLoader In LoaderTaskbar.ToList() @@ -796,7 +792,7 @@ Retry: FrmMain.BtnExtraDownload.Ribble() Catch ex As Exception - Log(ex, "开始 LiteLoader 安装器下载失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "开始 LiteLoader 安装器下载失败") End Try End Sub @@ -920,10 +916,10 @@ Retry: Public Sub McDownloadForgelikeSave(Info As DlForgelikeEntry) Try - Dim Target As String = SelectSaveFile("选择保存位置", $"{Info.LoaderName}-{Info.Inherit}-{Info.VersionName}.{Info.FileExtension}", - $"{Info.LoaderName} 安装器 (*.{Info.FileExtension})|*.{Info.FileExtension}") + Dim Target As String = Dialogs.SaveFile("选择保存位置", $"{Info.LoaderName}-{Info.Inherit}-{Info.VersionName}.{Info.FileExtension}", + filter:={(Info.FileExtension, $"{Info.LoaderName} 安装器")}) + If Target Is Nothing Then Return Dim DisplayName As String = $"{Info.LoaderName} {Info.Inherit} - {Info.VersionName}" - If Not Target.Contains("\") Then Return '重复任务检查 For Each OngoingLoader In LoaderTaskbar.ToList() @@ -962,7 +958,7 @@ Retry: FrmMain.BtnExtraDownload.Ribble() Catch ex As Exception - Log(ex, $"开始 {Info.LoaderName} 安装器下载失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"开始 {Info.LoaderName} 安装器下载失败") End Try End Sub @@ -990,7 +986,7 @@ Retry: End SyncLock '添加 Java Wrapper 作为主 Jar Dim Arguments As String - If UseJavaWrapper AndAlso Not Settings.Get("LaunchAdvanceDisableJLW") Then + If UseJavaWrapper AndAlso Not Settings.Get(Of Boolean)("LaunchAdvanceDisableJLW") Then Arguments = $"-Doolloo.jlw.tmpdir=""{PathPure.TrimEnd("\")}"" -cp ""{PathTemp}Cache\forge_installer.jar;{Target}"" -jar ""{ExtractPatch("JavaWrapper")}"" com.bangbang93.ForgeInstaller ""{McFolder}" Else Arguments = $"-cp ""{PathTemp}Cache\forge_installer.jar;{Target}"" com.bangbang93.ForgeInstaller ""{McFolder}" @@ -1007,7 +1003,7 @@ Retry: .RedirectStandardOutput = True } Dim LoaderName As String = If(IsNeoForge, "NeoForge", "Forge") - Log($"[Download] 开始安装 {LoaderName}:" & Arguments) + Logger.Info($"开始安装 {LoaderName}:{Arguments}") Dim process As New Process With {.StartInfo = Info} Dim LastResults As New Queue(Of String) Using outputWaitHandle As New AutoResetEvent(False) @@ -1024,11 +1020,11 @@ Retry: End If Catch ex As ObjectDisposedException Catch ex As Exception - Log(ex, $"读取 {LoaderName} 安装器信息失败") + Logger.Warn(ex, $"读取 {LoaderName} 安装器信息失败") End Try Try If Task.State = LoadState.Interrupted AndAlso Not process.HasExited Then - Log($"[Installer] 由于任务取消,已中止 {LoaderName} 安装") + Logger.Info($"由于任务取消,已中止 {LoaderName} 安装") process.Kill() End If Catch @@ -1047,11 +1043,11 @@ Retry: End If Catch ex As ObjectDisposedException Catch ex As Exception - Log(ex, $"读取 {LoaderName} 安装器错误信息失败") + Logger.Warn(ex, $"读取 {LoaderName} 安装器错误信息失败") End Try Try If Task.State = LoadState.Interrupted AndAlso Not process.HasExited Then - Log($"[Installer] 由于任务取消,已中止 {LoaderName} 安装") + Logger.Info($"由于任务取消,已中止 {LoaderName} 安装") process.Kill() End If Catch @@ -1071,7 +1067,7 @@ Retry: process.Dispose() '检查是否安装成功:最后 5 行中是否有 true(true 可能在倒数数行,见 #832) If LastResults.Reverse().Take(5).Any(Function(l) l = "true") Then Return - Log(LastResults.Join(vbCrLf)) + Logger.Warn(LastResults.Join(vbCrLf)) Dim LastLines As String = "" For i As Integer = Math.Max(0, LastResults.Count - 5) To LastResults.Count - 1 '最后 5 行 LastLines &= vbCrLf & LastResults(i) @@ -1084,13 +1080,10 @@ Retry: Private Sub ForgelikeInjectorLine(Content As String, Task As LoaderTask(Of Boolean, Boolean)) 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.18 @@ -1117,10 +1110,10 @@ Retry: Case "Injecting profile" Task.Progress = 0.91 Case Else - If ModeDebug Then Log("[Installer] " & Content) + Logger.Trace(Content) Return End Select - Log("[Installer] " & Content) + Logger.Info(Content) End Sub ''' @@ -1197,18 +1190,18 @@ Retry: '安装(仅在新版安装时需要原版 Jar) If IsNeoForge OrElse LoaderVersion.BeforeFirst(".") >= 20 Then - Log($"[Download] 检测为{If(IsNeoForge, " Neo", "新版 ")}Forge:" & LoaderVersion) - Dim Libs As List(Of McLibToken) = Nothing + Logger.Info($"检测为{If(IsNeoForge, " Neo", "新版 ")}Forge:{LoaderVersion}") + Dim Libs As List(Of McLibEntry) = Nothing Loaders.Add(New LoaderTask(Of String, List(Of NetFile))($"分析 {LoaderName} 支持库文件", 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, FileAccess.Read, FileShare.Read)) + Installer = FileUtils.OpenZip(InstallerAddress) 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)) + Dim Json As JObject = GetJson(Installer.GetEntry("install_profile.json").Open().ReadString) + Dim Json2 As JObject = GetJson(Installer.GetEntry("version.json").Open().ReadString) Json.Merge(Json2) '获取 Lib 下载信息 Libs = McLibListGetWithJson(Json, True) @@ -1221,17 +1214,17 @@ Retry: Dim OriginalName As String = Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).BeforeFirst("@") Dim Address = McLibGet(OriginalName).Replace(".jar", "." & Json("data")("MOJMAPS")("client").ToString.Trim("[]".ToCharArray()).Split("@")(1)) Dim ClientMappings As JToken = RawJson("downloads")("client_mappings") - Libs.Add(New McLibToken With { + Libs.Add(New McLibEntry With { .IsNatives = False, .LocalPath = Address, .OriginalName = OriginalName, .Url = ClientMappings("url"), .Size = ClientMappings("size"), .SHA1 = ClientMappings("sha1")}) - Log($"[Download] 需要下载 Mappings:{ClientMappings("url")} (SHA1: {ClientMappings("sha1")})") + Logger.Info($"需要下载 Mappings:{ClientMappings("url")} (SHA1: {ClientMappings("sha1")})") End If Task.Progress = 0.8 '去除其中的原始 Forgelike 项 For i = 0 To Libs.Count - 1 If Libs(i).LocalPath.EndsWithF($"{LoaderName.Lower}-{Inherit}-{LoaderVersion}.jar") OrElse Libs(i).LocalPath.EndsWithF($"{LoaderName.Lower}-{Inherit}-{LoaderVersion}-client.jar") Then - Log($"[Download] 已从待下载 {LoaderName} 支持库中移除:" & Libs(i).LocalPath, NotifyLevel.DebugModeOnly) + Logger.Warn($"已从待下载 {LoaderName} 支持库中移除:{Libs(i).LocalPath}") Libs.RemoveAt(i) Exit For End If @@ -1240,7 +1233,6 @@ Retry: Catch ex As Exception Throw New Exception($"获取{If(IsNeoForge, " Neo", "新版 ")}Forge 支持库列表失败", ex) Finally - '释放文件 If Installer IsNot Nothing Then Installer.Dispose() End Try End Sub) With {.ProgressWeight = 1}) @@ -1249,13 +1241,10 @@ Retry: Sub(Task As LoaderTask(Of List(Of NetFile), Boolean)) #Region "Forgelike 文件" If IsCustomFolder Then - For Each LibFile As McLibToken In Libs + For Each LibFile As McLibEntry In Libs Dim RealPath As String = LibFile.LocalPath.Replace(McFolderSelected, McFolder) - If Not File.Exists(RealPath) Then - DirectoryUtils.Create(RealPath, isFilePath:=True) - CopyFile(LibFile.LocalPath, RealPath) - End If - If ModeDebug Then Log($"[Download] 复制的 {LoaderName} 支持库文件:" & LibFile.LocalPath) + If Not FileUtils.Exists(RealPath) Then FileUtils.Copy(LibFile.LocalPath, RealPath) + Logger.Trace($"复制的 {LoaderName} 支持库文件:{LibFile.LocalPath}") Next End If #End Region @@ -1264,22 +1253,22 @@ Retry: 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] {LoaderName} 安装正在等待原版文件下载完成") + If TargetLoaders.Any Then Logger.Info($"{LoaderName} 安装正在等待原版文件下载完成") Do While TargetLoaders.Any AndAlso Not Task.IsInterrupted TargetLoaders = TargetLoaders.Where(Function(l) l.State <> LoadState.Finished).ToList Thread.Sleep(50) Loop If Task.IsInterrupted Then Return - '拷贝原版文件 + '复制原版文件 If Not IsCustomFolder Then Return SyncLock VanillaSyncLock - Dim ClientName As String = GetFolderNameFromPath(ClientFolder) + Dim ClientName As String = PathUtils.GetLastPart(ClientFolder) DirectoryUtils.Create(McFolder & "versions\" & Inherit) - If Not File.Exists(McFolder & "versions\" & Inherit & "\" & Inherit & ".json") Then - CopyFile(ClientFolder & ClientName & ".json", McFolder & "versions\" & Inherit & "\" & Inherit & ".json") + If Not FileUtils.Exists(McFolder & "versions\" & Inherit & "\" & Inherit & ".json") Then + FileUtils.Copy(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") + If Not FileUtils.Exists(McFolder & "versions\" & Inherit & "\" & Inherit & ".jar") Then + FileUtils.Copy(ClientFolder & ClientName & ".jar", McFolder & "versions\" & Inherit & "\" & Inherit & ".jar") End If End SyncLock #End Region @@ -1288,12 +1277,12 @@ Retry: Sub(Task As LoaderTask(Of Boolean, Boolean)) Dim Installer As ZipArchive = Nothing Try - Log($"[Download] 开始进行 Forgelike 安装:" & InstallerAddress) + Logger.Info($"开始进行 Forgelike 安装:{InstallerAddress}") '记录当前文件夹列表(在新建目标文件夹之前) - Dim OldList = New DirectoryInfo(McFolder & "versions\").EnumerateDirectories.Select(Function(i) i.FullName).ToList() + Dim OldList = DirectoryUtils.GetDirectories(McFolder & "versions\", True).ToList() '解压并获取信息 - Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open, FileAccess.Read, FileShare.Read)) - Dim Json As JObject = GetJson(ReadFile(Installer.GetEntry("install_profile.json").Open)) + Installer = FileUtils.OpenZip(InstallerAddress) + Dim Json As JObject = GetJson(Installer.GetEntry("install_profile.json").Open().ReadString) '新建目标版本文件夹 DirectoryUtils.Create(VersionFolder) Task.Progress = 0.04 @@ -1305,23 +1294,23 @@ Retry: Retry: Try '释放 Forge 注入器 - FileUtils.Write(PathTemp & "Cache\forge_installer.jar", GetResources("ForgeInstaller")) + ExtractResources(PathTemp & "Cache\forge_installer.jar", "ForgeInstaller") Task.Progress = 0.06 '运行注入器 ForgelikeInjector(InstallerAddress, Task, McFolder, UseJavaWrapper, IsNeoForge) Task.Progress = 0.97 Catch ex As Exception If UseJavaWrapper Then - Log(ex, $"使用 JavaWrapper 安装 {LoaderName} 失败,将不使用 JavaWrapper 并重试") + Logger.Warn(ex, $"使用 JavaWrapper 安装 {LoaderName} 失败,将不使用 JavaWrapper 并重试") UseJavaWrapper = False GoTo Retry Else Throw New Exception($"运行 {LoaderName} 安装器失败", ex) End If End Try - '拷贝新增的版本 Json - Dim DeltaList = New DirectoryInfo(McFolder & "versions\").EnumerateDirectories. - SkipWhile(Function(i) OldList.Contains(i.FullName)).ToList() + '复制新增的版本 Json + Dim DeltaList = DirectoryUtils.GetDirectories(McFolder & "versions\", True). + SkipWhile(Function(i) OldList.Contains(i)).Select(Function(f) DirectoryUtils.GetInfo(f)).ToList() If DeltaList.Count > 1 Then '它可能和 OptiFine 安装同时运行,导致增加的文件不止一个(这导致了 #151) '也可能是因为 Forge 安装器的 Bug,生成了一个名字错误的文件夹,所以需要检查文件夹是否为空 @@ -1329,62 +1318,61 @@ Retry: End If If DeltaList.Count = 1 Then '如果没有新增文件夹,那么预测的文件夹名就是正确的 - '如果只新增 1 个文件夹,那么拷贝 json 文件 + '如果只新增 1 个文件夹,那么复制 json 文件 Dim JsonFile As FileInfo = DeltaList(0).EnumerateFiles.First() - FileUtils.Write(VersionFolder & NewInstanceName & ".json", ReadFile(JsonFile.FullName)) - Log($"[Download] 已拷贝新增的版本 JSON 文件:{JsonFile.FullName} -> {VersionFolder}{NewInstanceName}.json") + FileUtils.Copy(JsonFile.FullName, VersionFolder & NewInstanceName & ".json") + Logger.Info($"已复制新增的版本 JSON 文件:{JsonFile.FullName} -> {VersionFolder}{NewInstanceName}.json") ElseIf DeltaList.Count > 1 Then '新增了多个文件夹 - Log($"[Download] 有多个疑似的新增版本,无法确定:{DeltaList.Select(Function(d) d.Name).Join(";")}") + Logger.Info($"有多个疑似的新增版本,无法确定:{DeltaList.Select(Function(d) d.Name).Join(";")}") Else '没有新增文件夹 - Log("[Download] 未找到新增的版本文件夹") + Logger.Info("未找到新增的版本文件夹") End If Catch ex As Exception Throw New Exception($"安装新 {LoaderName} 版本失败", ex) Finally '清理文件 Try - If Installer IsNot Nothing Then Installer.Dispose() - If File.Exists(InstallerAddress) Then File.Delete(InstallerAddress) + Installer?.Dispose() + FileUtils.Delete(InstallerAddress) Catch ex As Exception - Log(ex, $"安装 {LoaderName} 清理文件时出错") + Logger.Warn(ex, $"安装 {LoaderName} 清理文件时出错") End Try End Try End Sub) With {.ProgressWeight = 10}) Else - Log("[Download] 检测为非新版 Forge:" & LoaderVersion) + Logger.Info($"检测为非新版 Forge:{LoaderVersion}") Loaders.Add(New LoaderTask(Of List(Of NetFile), Boolean)($"安装 {LoaderName}(方式 B)", Sub(Task As LoaderTask(Of List(Of NetFile), Boolean)) Dim Installer As ZipArchive = Nothing Try '解压并获取信息 - Installer = New ZipArchive(New FileStream(InstallerAddress, FileMode.Open, FileAccess.Read, FileShare.Read)) + Installer = FileUtils.OpenZip(InstallerAddress) Task.Progress = 0.2 - Dim Json As JObject = GetJson(ReadFile(Installer.GetEntry("install_profile.json").Open)) + Dim Json As JObject = GetJson(Installer.GetEntry("install_profile.json").Open().ReadString) Task.Progress = 0.4 '新建版本文件夹 DirectoryUtils.Create(VersionFolder) Task.Progress = 0.5 If Json("install") Is Nothing Then '中版:Legacy 方式 1 - Log("[Download] 开始进行 Forge 安装,Legacy 方式 1:" & InstallerAddress) + Logger.Info($"开始进行 Forge 安装,Legacy 方式 1:{InstallerAddress}") '建立 Json 文件 - Dim JsonVersion As JObject = GetJson(ReadFile(Installer.GetEntry(Json("json").ToString.TrimStart("/")).Open)) + Dim JsonVersion As JObject = GetJson(Installer.GetEntry(Json("json").ToString.TrimStart("/")).Open().ReadString) JsonVersion("id") = NewInstanceName FileUtils.Write(VersionFolder & NewInstanceName & ".json", JsonVersion.ToString) Task.Progress = 0.6 '解压支持库文件 Installer.Dispose() - ExtractCompressedFile(InstallerAddress, InstallerAddress & "_unrar\") - CopyDirectory(InstallerAddress & "_unrar\maven\", McFolder & "libraries\") - DeleteDirectory(InstallerAddress & "_unrar\") + FileUtils.ExtractToDirectory(InstallerAddress, InstallerAddress & "_unrar\") + If DirectoryUtils.Exists(InstallerAddress & "_unrar\maven\") Then DirectoryUtils.Copy(InstallerAddress & "_unrar\maven\", McFolder & "libraries\") + DirectoryUtils.Delete(InstallerAddress & "_unrar\") Else '旧版:Legacy 方式 2 - Log("[Download] 开始进行 Forge 安装,Legacy 方式 2:" & InstallerAddress) + Logger.Info($"开始进行 Forge 安装,Legacy 方式 2:{InstallerAddress}") '解压 Jar 文件 Dim JarAddress As String = McLibGet(Json("install")("path"), CustomMcFolder:=McFolder) - If File.Exists(JarAddress) Then File.Delete(JarAddress) FileUtils.Write(JarAddress, Installer.GetEntry(Json("install")("filePath")).Open) Task.Progress = 0.9 '建立 Json 文件 @@ -1398,10 +1386,10 @@ Retry: Try '清理文件 If Installer IsNot Nothing Then Installer.Dispose() - If File.Exists(InstallerAddress) Then File.Delete(InstallerAddress) - If Directory.Exists(InstallerAddress & "_unrar\") Then DeleteDirectory(InstallerAddress & "_unrar\") + FileUtils.Delete(InstallerAddress) + DirectoryUtils.Delete(InstallerAddress & "_unrar\") Catch ex As Exception - Log(ex, "非新版方式安装 Forge 清理文件时出错") + Logger.Warn(ex, "非新版方式安装 Forge 清理文件时出错") End Try End Try End Sub) With {.ProgressWeight = 1}) @@ -1422,7 +1410,7 @@ Retry: If Entries.Any Then FreshVersion = Entries(0) Else - Log("[System] 未找到可用的 Forge 版本") + Logger.Info("未找到可用的 Forge 版本") End If Dim RecommendedVersion As DlForgeVersionEntry = Nothing For Each Entry In Entries @@ -1522,7 +1510,7 @@ Retry: RunInNewThread( Sub() Try - Log("[Download] 刷新 Forge 推荐版本缓存开始") + Logger.Info("刷新 Forge 推荐版本缓存开始") Dim Result As String = NetRequestByClientRetry("https://bmclapi2.bangbang93.com/forge/promos", RequireJson:=True) If Result.Length < 1000 Then Throw New Exception("获取的结果过短(" & Result & ")") Dim ResultJson As JContainer = GetJson(Result) @@ -1539,9 +1527,9 @@ Retry: '保存 Dim CacheJson As String = "{" & RecommendedList.Join(",") & "}" FileUtils.Write(PathTemp & "Cache\ForgeRecommendedList.json", CacheJson) - Log("[Download] 刷新 Forge 推荐版本缓存成功") + Logger.Info("刷新 Forge 推荐版本缓存成功") Catch ex As Exception - Log(ex, "刷新 Forge 推荐版本缓存失败") + Logger.Warn(ex, "刷新 Forge 推荐版本缓存失败") End Try End Sub, "ForgeRecommendedRefresh") End Sub @@ -1553,16 +1541,16 @@ Retry: Public Function McDownloadForgeRecommendedGet(McVersion As String) As String Try If McVersion Is Nothing Then Return Nothing - Dim List As String = ReadFile(PathTemp & "Cache\ForgeRecommendedList.json") - If List Is Nothing OrElse List = "" Then - Log("[Download] 没有 Forge 推荐版本缓存文件") + Dim List As String = FileUtils.TryReadAsString(PathTemp & "Cache\ForgeRecommendedList.json") + If String.IsNullOrEmpty(List) Then + Logger.Info("没有 Forge 推荐版本缓存文件") Return Nothing End If Dim Json As JObject = GetJson(List) If Json Is Nothing OrElse (Not If(McVersion, "").Contains(".")) OrElse Not Json.ContainsKey(McVersion) Then Return Nothing Return If(Json(McVersion), "").ToString Catch ex As Exception - Log(ex, "获取 Forge 推荐版本失败(" & If(McVersion, "null") & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"获取 Forge 推荐版本失败({If(McVersion, "null")})") Return Nothing End Try End Function @@ -1587,7 +1575,7 @@ Retry: End If Next Else - Log("[System] 未找到可用的 NeoForge 版本", NotifyLevel.DebugModeOnly) + Logger.Warn("未找到可用的 NeoForge 版本") End If '显示各个版本 If FreshStableVersion IsNot Nothing Then @@ -1674,10 +1662,10 @@ Retry: Public Sub McDownloadFabricLoaderSave(DownloadInfo As JObject) Try Dim Url As String = DownloadInfo("url").ToString - Dim FileName As String = GetFileNameFromPath(Url) - Dim Version As String = GetFileNameFromPath(DownloadInfo("version").ToString) - Dim Target As String = SelectSaveFile("选择保存位置", FileName, "Fabric 安装器 (*.jar)|*.jar") - If Not Target.Contains("\") Then Return + Dim FileName As String = PathUtils.GetLastPart(Url) + Dim Version As String = PathUtils.GetLastPart(DownloadInfo("version").ToString) + Dim Target As String = Dialogs.SaveFile("选择保存位置", FileName, filter:={("jar", "Fabric 安装器")}) + If Target Is Nothing Then Return '重复任务检查 For Each OngoingLoader In LoaderTaskbar.ToList() @@ -1701,7 +1689,7 @@ Retry: FrmMain.BtnExtraDownload.Ribble() Catch ex As Exception - Log(ex, "开始 Fabric 安装器下载失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "开始 Fabric 安装器下载失败") End Try End Sub @@ -1860,7 +1848,7 @@ Retry: Case LoadState.Finished Hint(Loader.Name & "成功!", HintType.Green) Case LoadState.Failed - Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Red) + Hint(Loader.Name & "失败:" & Loader.Error.GetDisplay(False), HintType.Red) Case LoadState.Interrupted Hint(Loader.Name & "已取消!", HintType.Blue) End Select @@ -1875,7 +1863,7 @@ Retry: Hint(Loader.Name & "成功!", HintType.Green) 'TODO: 自动选择安装成功的版本 Case LoadState.Failed - MyMsgBox(Loader.Error.GetDetail, Loader.Name & "失败", IsWarn:=True) + MyMsgBox(Loader.Error.GetDisplay(True), Loader.Name & "失败", IsWarn:=True) Case LoadState.Interrupted Hint(Loader.Name & "已取消!", HintType.Blue) Case LoadState.Loading @@ -1889,15 +1877,15 @@ Retry: Thread.Sleep(1000) '防止存在尚未完全释放的文件,导致清理失败(例如整合包安装) If Loader.State = LoadState.Failed OrElse Loader.State = LoadState.Interrupted Then '删除版本文件夹 - If Directory.Exists(Loader.Input & "saves\") OrElse Directory.Exists(Loader.Input & "versions\") Then - Log("[Download] 由于版本已被独立启动,不清理版本文件夹:" & Loader.Input, NotifyLevel.DevelopOnly) + If DirectoryUtils.Exists(Loader.Input & "saves\") OrElse DirectoryUtils.Exists(Loader.Input & "versions\") Then + Logger.Warn($"由于版本已被独立启动,不清理版本文件夹:{Loader.Input}") Else - Log("[Download] 由于下载失败或取消,清理版本文件夹:" & Loader.Input, NotifyLevel.DevelopOnly) - DeleteDirectory(Loader.Input) + Logger.Warn($"由于下载失败或取消,清理版本文件夹:{Loader.Input}") + DirectoryUtils.Delete(Loader.Input) End If End If Catch ex As Exception - Log(ex, "下载失败或取消后清理版本文件夹失败") + Logger.Warn(ex, "下载失败或取消后清理版本文件夹失败") End Try End Sub @@ -1920,7 +1908,7 @@ Retry: Catch ex As CancelledException Return False Catch ex As Exception - Log(ex, "开始合并安装失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "开始合并安装失败") Return False End Try End Function @@ -1934,7 +1922,7 @@ Retry: '获取参数 Dim VersionFolder As String = McFolderSelected & "versions\" & Request.NewInstanceName & "\" - If Directory.Exists(TempMcFolder) Then DeleteDirectory(TempMcFolder) + If DirectoryUtils.Exists(TempMcFolder) Then DirectoryUtils.Delete(TempMcFolder) Dim OptiFineFolder As String = Nothing If Request.OptiFineVersion IsNot Nothing Then If Request.OptiFineVersion.Contains("_HD_U_") Then Request.OptiFineVersion = "HD_U_" & Request.OptiFineVersion.AfterLast("_HD_U_") '#735 @@ -1964,7 +1952,7 @@ Retry: Dim ModsTempFolder As String = TempMcFolder & "mods\" Dim OptiFineAsMod As Boolean = Request.OptiFineEntry IsNot Nothing AndAlso Modable '选择了 OptiFine 与任意 Mod 加载器 If OptiFineAsMod Then - Log("[Download] OptiFine 将作为 Mod 进行下载") + Logger.Info("OptiFine 将作为 Mod 进行下载") If Request.LiteLoaderEntry IsNot Nothing Then OptiFineFolder = ModsTempFolder & Request.MinecraftName & "\" '#8147 Else @@ -1973,15 +1961,15 @@ Retry: End If '记录日志 - If OptiFineFolder IsNot Nothing Then Log("[Download] OptiFine 缓存:" & OptiFineFolder) - If ForgeFolder IsNot Nothing Then Log("[Download] Forge 缓存:" & ForgeFolder) - If NeoForgeFolder IsNot Nothing Then Log("[Download] NeoForge 缓存:" & NeoForgeFolder) - If FabricFolder IsNot Nothing Then Log("[Download] Fabric 缓存:" & FabricFolder) - If LiteLoaderFolder IsNot Nothing Then Log("[Download] LiteLoader 缓存:" & LiteLoaderFolder) - Log("[Download] 对应的原版版本:" & Request.MinecraftName) + If OptiFineFolder IsNot Nothing Then Logger.Info($"OptiFine 缓存:{OptiFineFolder}") + If ForgeFolder IsNot Nothing Then Logger.Info($"Forge 缓存:{ForgeFolder}") + If NeoForgeFolder IsNot Nothing Then Logger.Info($"NeoForge 缓存:{NeoForgeFolder}") + If FabricFolder IsNot Nothing Then Logger.Info($"Fabric 缓存:{FabricFolder}") + If LiteLoaderFolder IsNot Nothing Then Logger.Info($"LiteLoader 缓存:{LiteLoaderFolder}") + Logger.Info($"对应的原版版本:{Request.MinecraftName}") '重复版本检查 - If File.Exists($"{VersionFolder}{Request.NewInstanceName}.json") Then + If FileUtils.Exists($"{VersionFolder}{Request.NewInstanceName}.json") Then Hint("版本 " & Request.NewInstanceName & " 已经存在!", HintType.Red) Throw New CancelledException End If @@ -1991,11 +1979,11 @@ Retry: LoaderList.Add(New LoaderTask(Of Integer, Integer)("添加忽略标识", Sub() FileUtils.Write(VersionFolder & ".pclignore", "用于临时地在 PCL 的版本列表中屏蔽此版本。")) With {.Show = False, .Block = False}) 'Fabric API If Request.FabricApi IsNot Nothing Then - LoaderList.Add(New LoaderDownload("下载 Fabric API", New List(Of NetFile) From {Request.FabricApi.ToNetFile(ModsTempFolder)}) With {.ProgressWeight = 3, .Block = False}) + LoaderList.Add(New LoaderDownload("下载 Fabric API", New List(Of NetFile) From {Request.FabricApi.ToNetFile(ModsTempFolder, ResourceVersion.DownloadReason.Dependency, Request.MinecraftName, ModLoaders.Fabric)}) With {.ProgressWeight = 3, .Block = False}) End If 'OptiFabric If Request.OptiFabric IsNot Nothing Then - LoaderList.Add(New LoaderDownload("下载 OptiFabric", New List(Of NetFile) From {Request.OptiFabric.ToNetFile(ModsTempFolder)}) With {.ProgressWeight = 3, .Block = False}) + LoaderList.Add(New LoaderDownload("下载 OptiFabric", New List(Of NetFile) From {Request.OptiFabric.ToNetFile(ModsTempFolder, ResourceVersion.DownloadReason.Dependency, Request.MinecraftName, ModLoaders.Fabric)}) With {.ProgressWeight = 3, .Block = False}) End If '原版 Dim ClientLoader = New LoaderCombo(Of String)("下载原版 " & Request.MinecraftName, McDownloadClientLoader(Request.MinecraftName, Request.MinecraftJson, Request.NewInstanceName)) With {.Show = False, .ProgressWeight = 39, @@ -2038,19 +2026,19 @@ Retry: MergeJson(VersionFolder, VersionFolder, OptiFineFolder, OptiFineAsMod, ForgeFolder, Request.ForgeVersion, NeoForgeFolder, Request.NeoForgeVersion, FabricFolder, LiteLoaderFolder) Task.Progress = 0.2 '迁移文件 - If Directory.Exists(TempMcFolder & "libraries") Then CopyDirectory(TempMcFolder & "libraries", McFolderSelected & "libraries") + DirectoryUtils.Copy(TempMcFolder & "libraries", McFolderSelected & "libraries") Task.Progress = 0.8 '创建 Mod 和资源包文件夹 Dim ModsFolder = New McInstance(VersionFolder).PathIndie & "mods\" '版本隔离信息在此时被决定 - If Directory.Exists(ModsTempFolder) Then - CopyDirectory(ModsTempFolder, ModsFolder) + If DirectoryUtils.Exists(ModsTempFolder) Then + DirectoryUtils.Copy(ModsTempFolder, ModsFolder) ElseIf Modable Then DirectoryUtils.Create(ModsFolder) - Log("[Download] 自动创建 Mod 文件夹:" & ModsFolder) + Logger.Info($"自动创建 Mod 文件夹:{ModsFolder}") End If Dim ResourcepacksFolder = New McInstance(VersionFolder).PathIndie & "resourcepacks\" DirectoryUtils.Create(ResourcepacksFolder) - Log("[Download] 自动创建资源包文件夹:" & ResourcepacksFolder) + Logger.Info($"自动创建资源包文件夹:{ResourcepacksFolder}") End Sub) With {.ProgressWeight = 2, .Block = True}) '补全文件 If Request.OptiFineEntry IsNot Nothing OrElse (Request.ForgeVersion IsNot Nothing AndAlso Request.ForgeVersion.BeforeFirst(".") >= 20) OrElse Request.NeoForgeVersion IsNot Nothing OrElse Request.FabricVersion IsNot Nothing OrElse Request.LiteLoaderEntry IsNot Nothing Then @@ -2060,7 +2048,7 @@ Retry: LoaderList.Add(New LoaderCombo(Of String)("下载游戏支持库文件", LoadersLib) With {.ProgressWeight = 8}) End If '删除忽略标识 - LoaderList.Add(New LoaderTask(Of Integer, Integer)("删除忽略标识", Sub() File.Delete(VersionFolder & ".pclignore")) With {.Show = False}) + LoaderList.Add(New LoaderTask(Of Integer, Integer)("删除忽略标识", Sub() FileUtils.Delete(VersionFolder & ".pclignore")) With {.Show = False}) '总加载器 Return LoaderList End Function @@ -2069,7 +2057,7 @@ Retry: ''' 将多个版本 JSON 进行合并,如果目标已存在则直接覆盖。失败会抛出异常。 ''' Private Sub MergeJson(OutputFolder As String, MinecraftFolder As String, Optional OptiFineFolder As String = Nothing, Optional OptiFineAsMod As Boolean = False, Optional ForgeFolder As String = Nothing, Optional ForgeVersion As String = Nothing, Optional NeoForgeFolder As String = Nothing, Optional NeoForgeVersion As String = Nothing, Optional FabricFolder As String = Nothing, Optional LiteLoaderFolder As String = Nothing) - Log("[Download] 开始进行版本合并,输出:" & OutputFolder & ",Minecraft:" & MinecraftFolder & + Logger.Info($"开始进行版本合并,输出:{OutputFolder},Minecraft:{MinecraftFolder}" & If(OptiFineFolder IsNot Nothing, ",OptiFine:" & OptiFineFolder, "") & If(ForgeFolder IsNot Nothing, ",Forge:" & ForgeFolder, "") & If(NeoForgeFolder IsNot Nothing, ",NeoForge:" & NeoForgeFolder, "") & @@ -2083,78 +2071,78 @@ Retry: Dim OutputJar As String, MinecraftJar As String #Region "初始化路径信息" If Not OutputFolder.EndsWithF("\") Then OutputFolder += "\" - OutputName = GetFolderNameFromPath(OutputFolder) + OutputName = PathUtils.GetLastPart(OutputFolder) OutputJsonPath = OutputFolder & OutputName & ".json" OutputJar = OutputFolder & OutputName & ".jar" If Not MinecraftFolder.EndsWithF("\") Then MinecraftFolder += "\" - MinecraftName = GetFolderNameFromPath(MinecraftFolder) + MinecraftName = PathUtils.GetLastPart(MinecraftFolder) MinecraftJsonPath = MinecraftFolder & MinecraftName & ".json" MinecraftJar = MinecraftFolder & MinecraftName & ".jar" If HasOptiFine Then If Not OptiFineFolder.EndsWithF("\") Then OptiFineFolder += "\" - OptiFineName = GetFolderNameFromPath(OptiFineFolder) + OptiFineName = PathUtils.GetLastPart(OptiFineFolder) OptiFineJsonPath = OptiFineFolder & OptiFineName & ".json" End If If HasForge Then If Not ForgeFolder.EndsWithF("\") Then ForgeFolder += "\" - ForgeName = GetFolderNameFromPath(ForgeFolder) + ForgeName = PathUtils.GetLastPart(ForgeFolder) ForgeJsonPath = ForgeFolder & ForgeName & ".json" End If If HasNeoForge Then If Not NeoForgeFolder.EndsWithF("\") Then NeoForgeFolder += "\" - NeoForgeName = GetFolderNameFromPath(NeoForgeFolder) + NeoForgeName = PathUtils.GetLastPart(NeoForgeFolder) NeoForgeJsonPath = NeoForgeFolder & NeoForgeName & ".json" End If If HasLiteLoader Then If Not LiteLoaderFolder.EndsWithF("\") Then LiteLoaderFolder += "\" - LiteLoaderName = GetFolderNameFromPath(LiteLoaderFolder) + LiteLoaderName = PathUtils.GetLastPart(LiteLoaderFolder) LiteLoaderJsonPath = LiteLoaderFolder & LiteLoaderName & ".json" End If If HasFabric Then If Not FabricFolder.EndsWithF("\") Then FabricFolder += "\" - FabricName = GetFolderNameFromPath(FabricFolder) + FabricName = PathUtils.GetLastPart(FabricFolder) FabricJsonPath = FabricFolder & FabricName & ".json" End If #End Region Dim OutputJson As JObject, MinecraftJson As JObject, OptiFineJson As JObject = Nothing, ForgeJson As JObject = Nothing, NeoForgeJson As JObject = Nothing, LiteLoaderJson As JObject = Nothing, FabricJson As JObject = Nothing #Region "读取文件并检查文件是否合规" - Dim MinecraftJsonText As String = ReadFile(MinecraftJsonPath) + Dim MinecraftJsonText As String = If(FileUtils.TryReadAsString(MinecraftJsonPath), "") If Not MinecraftJsonText.StartsWithF("{") Then Throw New Exception("Minecraft json 有误,地址:" & MinecraftJsonPath & ",前段内容:" & MinecraftJsonText.Substring(0, Math.Min(MinecraftJsonText.Length, 1000))) MinecraftJson = GetJson(MinecraftJsonText) If HasOptiFine Then - Dim OptiFineJsonText As String = ReadFile(OptiFineJsonPath) + Dim OptiFineJsonText As String = If(FileUtils.TryReadAsString(OptiFineJsonPath), "") If Not OptiFineJsonText.StartsWithF("{") Then Throw New Exception("OptiFine json 有误,地址:" & OptiFineJsonPath & ",前段内容:" & OptiFineJsonText.Substring(0, Math.Min(OptiFineJsonText.Length, 1000))) OptiFineJson = GetJson(OptiFineJsonText) End If If HasForge Then - Dim ForgeJsonText As String = ReadFile(ForgeJsonPath) + Dim ForgeJsonText As String = If(FileUtils.TryReadAsString(ForgeJsonPath), "") If Not ForgeJsonText.StartsWithF("{") Then Throw New Exception("Forge json 有误,地址:" & ForgeJsonPath & ",前段内容:" & ForgeJsonText.Substring(0, Math.Min(ForgeJsonText.Length, 1000))) ForgeJson = GetJson(ForgeJsonText) End If If HasNeoForge Then - Dim NeoForgeJsonText As String = ReadFile(NeoForgeJsonPath) + Dim NeoForgeJsonText As String = If(FileUtils.TryReadAsString(NeoForgeJsonPath), "") If Not NeoForgeJsonText.StartsWithF("{") Then Throw New Exception("NeoForge json 有误,地址:" & NeoForgeJsonPath & ",前段内容:" & NeoForgeJsonText.Substring(0, Math.Min(NeoForgeJsonText.Length, 1000))) NeoForgeJson = GetJson(NeoForgeJsonText) End If If HasLiteLoader Then - Dim LiteLoaderJsonText As String = ReadFile(LiteLoaderJsonPath) + Dim LiteLoaderJsonText As String = If(FileUtils.TryReadAsString(LiteLoaderJsonPath), "") If Not LiteLoaderJsonText.StartsWithF("{") Then Throw New Exception("LiteLoader json 有误,地址:" & LiteLoaderJsonPath & ",前段内容:" & LiteLoaderJsonText.Substring(0, Math.Min(LiteLoaderJsonText.Length, 1000))) LiteLoaderJson = GetJson(LiteLoaderJsonText) End If If HasFabric Then - Dim FabricJsonText As String = ReadFile(FabricJsonPath) + Dim FabricJsonText As String = If(FileUtils.TryReadAsString(FabricJsonPath), "") If Not FabricJsonText.StartsWithF("{") Then Throw New Exception("Fabric json 有误,地址:" & FabricJsonPath & ",前段内容:" & FabricJsonText.Substring(0, Math.Min(FabricJsonText.Length, 1000))) FabricJson = GetJson(FabricJsonText) End If @@ -2169,7 +2157,7 @@ Retry: If(NeoForgeJson IsNot Nothing, If(NeoForgeJson("minecraftArguments"), " ").ToString, " ") & " " & If(LiteLoaderJson IsNot Nothing, If(LiteLoaderJson("minecraftArguments"), " ").ToString, " ") '分割参数字符串 - Dim RawArguments As List(Of String) = AllArguments.Split(" ").Where(Function(l) l <> "").Select(Function(l) l.Trim).ToList + Dim RawArguments As List(Of String) = AllArguments.Split(" ", True).Select(Function(l) l.Trim).ToList Dim SplitArguments As New List(Of String) For i = 0 To RawArguments.Count - 1 If RawArguments(i).StartsWithF("-") Then @@ -2224,11 +2212,8 @@ Retry: #Region "保存" FileUtils.Write(OutputJsonPath, OutputJson.ToString) - If MinecraftJar <> OutputJar Then '可能是同一个文件 - If File.Exists(OutputJar) Then File.Delete(OutputJar) - CopyFile(MinecraftJar, OutputJar) - End If - Log("[Download] 版本合并 " & OutputName & " 完成") + FileUtils.Copy(MinecraftJar, OutputJar) + Logger.Info($"版本合并 {OutputName} 完成") #End Region End Sub @@ -2250,23 +2235,23 @@ Retry: ''' "LUA" 或 "JavaWrapper"。 Public Function ExtractPatch(Patch As String) As String Dim PatchPath As String = $"{PathPure}{Patch}.jar" - Log($"[Java] 选定的 {Patch} 路径:{PatchPath}") + Logger.Info($"选定的 {Patch} 路径:{PatchPath}") Static Lock As New Object SyncLock Lock '避免 OptiFine 和 Forge 安装时同时释放导致冲突 Try - FileUtils.Write(PatchPath, GetResources(Patch)) + ExtractResources(PatchPath, Patch) Catch ex As Exception - If File.Exists(PatchPath) Then + If FileUtils.Exists(PatchPath) Then '因为未知原因可能变为只读文件(#4243) - Log(ex, $"{Patch} 文件释放失败,但文件已存在,将在删除后尝试重新生成", NotifyLevel.DevelopOnly) + Logger.Warn(ex, $"{Patch} 文件释放失败,但文件已存在,将在删除后尝试重新生成") Try - File.Delete(PatchPath) - FileUtils.Write(PatchPath, GetResources(Patch)) + FileUtils.Delete(PatchPath) + ExtractResources(PatchPath, Patch) Catch ex2 As Exception - Log(ex2, $"{Patch} 文件重新释放失败,将尝试更换文件名重新生成", NotifyLevel.DevelopOnly) + Logger.Warn(ex2, $"{Patch} 文件重新释放失败,将尝试更换文件名重新生成") PatchPath = $"{PathPure}{Patch}2.jar" Try - FileUtils.Write(PatchPath, GetResources(Patch)) + ExtractResources(PatchPath, Patch) Catch ex3 As Exception Throw New FileNotFoundException($"释放 {Patch} 最终尝试失败", ex3) End Try diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb index d612db3..3b57d39 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadInstall.xaml.vb @@ -525,7 +525,7 @@ Next '自动选择版本 If VersionWaitingSelect Is Nothing Then Exit Try - Log("[Download] 自动选择 MC 版本:" & VersionWaitingSelect) + Logger.Info($"自动选择 MC 版本:{VersionWaitingSelect}") For Each Version As JObject In Versions If Version("id").ToString <> VersionWaitingSelect Then Continue For Dim Item = McDownloadListItem(Version, Sub() @@ -535,7 +535,7 @@ Return Next Catch ex As Exception - Log(ex, "可视化安装版本列表出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "可视化安装版本列表出错") End Try End Sub ''' @@ -627,7 +627,7 @@ PanOptiFine.Children.Add(OptiFineDownloadListItem(Version, AddressOf OptiFine_Selected, False)) Next Catch ex As Exception - Log(ex, "可视化 OptiFine 安装版本列表出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "可视化 OptiFine 安装版本列表出错") End Try End Sub @@ -689,7 +689,7 @@ PanLiteLoader.Children.Add(LiteLoaderDownloadListItem(Version, AddressOf LiteLoader_Selected, False)) Next Catch ex As Exception - Log(ex, "可视化 LiteLoader 安装版本列表出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "可视化 LiteLoader 安装版本列表出错") End Try End Sub @@ -763,7 +763,7 @@ PanForge.Children.Add(ForgeDownloadListItem(Version, AddressOf Forge_Selected, False)) Next Catch ex As Exception - Log(ex, "可视化 Forge 安装版本列表出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "可视化 Forge 安装版本列表出错") End Try End Sub @@ -821,7 +821,7 @@ PanNeoForge.Children.Add(NeoForgeDownloadListItem(Version, AddressOf NeoForge_Selected, False)) Next Catch ex As Exception - Log(ex, "可视化 NeoForge 安装版本列表出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "可视化 NeoForge 安装版本列表出错") End Try End Sub @@ -883,7 +883,7 @@ CardFabric.SwapControl = PanFabric CardFabric.SwapType = 12 Catch ex As Exception - Log(ex, "可视化 Fabric 安装版本列表出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "可视化 Fabric 安装版本列表出错") End Try End Sub @@ -926,8 +926,8 @@ If Part = TargetName Then Return True Next '将版本名分割语素(例如 1.16.4/5) - Dim Lefts = RegexSearch(FabricApiName.BeforeFirst("]"), "[a-z/]+|[0-9/]+") - Dim Rights = RegexSearch(TargetName.BeforeFirst("]"), "[a-z/]+|[0-9/]+") + Dim Lefts = FabricApiName.BeforeFirst("]").RegexSearch("[a-z/]+|[0-9/]+").ToList + Dim Rights = TargetName.BeforeFirst("]").RegexSearch("[a-z/]+|[0-9/]+").ToList '对每段进行判断 Dim i As Integer = 0 While True @@ -946,7 +946,7 @@ End While Return True Catch ex As Exception - Log(ex, "判断 Fabric API 版本适配性出错(" & FabricApiName & ", " & VanillaName & ")") + Logger.Warn(ex, $"判断 Fabric API 版本适配性出错({FabricApiName}, {VanillaName})") Return False End Try End Function @@ -984,7 +984,7 @@ For Each Version In DlFabricApiLoader.Output If IsFabricApiCompatible(Version) Then If Not Version.Display.StartsWithF("[") Then - Log("[Download] 已特判修改 Fabric API 显示名:" & Version.Display, NotifyLevel.DebugModeOnly) + Logger.Warn($"已特判修改 Fabric API 显示名:{Version.Display}") Version.Display = "[" & VanillaName & "] " & Version.Display End If Versions.Add(Version) @@ -1002,11 +1002,11 @@ If Not AutoSelectedFabricApi Then AutoSelectedFabricApi = True Dim Item As MyListItem = MyVirtualizingElement.TryInit(PanFabricApi.Children(0)) - Log($"[Download] 已自动选择 Fabric API:{Item.Title}") + Logger.Info($"已自动选择 Fabric API:{Item.Title}") FabricApi_Selected(Item, Nothing) End If Catch ex As Exception - Log(ex, "可视化 Fabric API 安装版本列表出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "可视化 Fabric API 安装版本列表出错") End Try End Sub @@ -1035,7 +1035,7 @@ If VanillaName Is Nothing Then Return False Return ModFile.GameVersions.Contains(VanillaName) Catch ex As Exception - Log(ex, "判断 OptiFabric 版本适配性出错(" & VanillaName & ")") + Logger.Warn(ex, $"判断 OptiFabric 版本适配性出错({VanillaName})") Return False End Try End Function @@ -1095,10 +1095,10 @@ If AutoSelectedOptiFabric OrElse VanillaDrop >= 140 AndAlso VanillaDrop <= 150 Then Return '1.14~15 不自动选择 AutoSelectedOptiFabric = True Dim Item As MyListItem = MyVirtualizingElement.TryInit(PanOptiFabric.Children(0)) - Log($"[Download] 已自动选择 OptiFabric:{Item.Title}") + Logger.Info($"已自动选择 OptiFabric:{Item.Title}") OptiFabric_Selected(Item, Nothing) Catch ex As Exception - Log(ex, "可视化 OptiFabric 安装版本列表出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "可视化 OptiFabric 安装版本列表出错") End Try End Sub @@ -1125,7 +1125,7 @@ Private Sub BtnStart_Click() Handles BtnStart.Click '确认版本隔离 If (SelectedForge IsNot Nothing OrElse SelectedNeoForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) AndAlso - (Settings.Get("LaunchArgumentIndieV2") = 0 OrElse Settings.Get("LaunchArgumentIndieV2") = 2) Then + (Settings.Get(Of Integer)("LaunchArgumentIndieV2") = 0 OrElse Settings.Get(Of Integer)("LaunchArgumentIndieV2") = 2) Then If MyMsgBox("你尚未开启版本隔离,多个 MC 版本会共用同一个 Mod 文件夹。" & vbCrLf & "因此,游戏可能会因为读取到与当前版本不符的 Mod 而崩溃。" & vbCrLf & "推荐先在 设置 → 启动选项 → 默认版本隔离 中开启版本隔离!", "版本隔离提示", "取消下载", "继续") = 1 Then diff --git a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.vb index 8adb758..73f0d0d 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/PageDownloadLeft.xaml.vb @@ -53,7 +53,7 @@ PageChangeRun(PageGet(ID)) PageID = ID Catch ex As Exception - Log(ex, "切换分页面失败(ID " & ID & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"切换分页面失败(ID {ID})") Finally AniControlEnabled -= 1 End Try diff --git a/Plain Craft Launcher 2/Pages/PageDownload/Resource/MyResourceItem.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/Resource/MyResourceItem.xaml.vb index f0a733d..3c3df5a 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/Resource/MyResourceItem.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/Resource/MyResourceItem.xaml.vb @@ -79,7 +79,7 @@ If IsMouseDown Then RaiseEvent Click(sender, e) If e.Handled Then Return - Log("[Control] 按下资源工程列表项:" & LabTitle.Text) + Logger.Info($"按下资源工程列表项:{LabTitle.Text}") End If End Sub Private Sub MyResourceItem_Click(sender As MyResourceItem, e As EventArgs) Handles Me.Click @@ -89,20 +89,20 @@ For Each Card As MyCard In FrmDownloadResourceDetail.PanResults.Children If Card.Title <> "" AndAlso Not Card.IsSwapped Then Titles.Add(Card.Title) Next - Log("[Resource] 记录当前已展开的卡片:" & String.Join("、", Titles)) + Logger.Info($"记录当前已展开的卡片:{String.Join("、", Titles)}") FrmMain.PageCurrent.Additional(1) = Titles End If '打开详情页 Dim TargetType As ResourceTypes Dim TargetInstance As String = Nothing - Dim TargetLoader As ModLoaderTypes = ModLoaderTypes.Any + Dim TargetLoader As ModLoaders = ModLoaders.None If FrmMain.PageCurrent.Page = FormMain.PageType.Download Then '从下载页进入 Select Case FrmMain.PageCurrentSub Case FormMain.PageSubType.DownloadMod TargetType = ResourceTypes.Mod TargetInstance = FrmDownloadMod.Content.Loader.Input.GameVersion - TargetLoader = FrmDownloadMod.Content.Loader.Input.ModLoader + TargetLoader = FrmDownloadMod.Content.Loader.Input.ModLoaders Case FormMain.PageSubType.DownloadPack TargetType = ResourceTypes.ModPack TargetInstance = FrmDownloadPack.Content.Loader.Input.GameVersion diff --git a/Plain Craft Launcher 2/Pages/PageDownload/Resource/PageDownloadCompDetail.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/Resource/PageDownloadCompDetail.xaml.vb index 9a80d22..628146c 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/Resource/PageDownloadCompDetail.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/Resource/PageDownloadCompDetail.xaml.vb @@ -1,12 +1,28 @@ Public Class PageDownloadResourceDetail Private ResourceItem As MyResourceItem = Nothing + ''' + ''' 当前页面应展示的内容类别。 + ''' 若当前页面是在查看前置时进入,则为 Any;这也能用于指示当前是否在查看前置。 + ''' + Private TargetResourceType As ResourceTypes + Private Project As ResourceProject + Private TargetVersion As String + Private TargetLoaders As ModLoaders + Public Sub LoadPageArguments() Handles Me.Loaded + Project = FrmMain.PageCurrent.Additional(0) + TargetVersion = FrmMain.PageCurrent.Additional(2) + TargetLoaders = CType(FrmMain.PageCurrent.Additional(3), ModLoaders) + If TargetLoaders <> ModLoaders.None AndAlso Not TargetLoaders.Flags.IsSingle Then TargetLoaders = TargetLoaders.Flags.First() '强制取第一个 + TargetResourceType = FrmMain.PageCurrent.Additional(4) + End Sub + #Region "加载器" Private ResourceFileLoader As New LoaderTask(Of Integer, List(Of ResourceVersion))( "Resource File", Sub(Task) - LoadTargetFromAdditional() + LoadPageArguments() Dim Result = ResourceVersion.FromProjectId(Project.Id, Project.Platform) If Task.IsInterrupted Then Return Task.Output = Result @@ -14,22 +30,9 @@ '初始化加载器信息 Private Sub PageDownloadResourceDetail_Inited(sender As Object, e As EventArgs) Handles Me.Initialized - LoadTargetFromAdditional() + LoadPageArguments() PageLoaderInit(Load, PanLoad, PanMain, CardIntro, ResourceFileLoader, AddressOf Load_OnFinish) End Sub - Public Sub LoadTargetFromAdditional() Handles Me.Loaded - Project = FrmMain.PageCurrent.Additional(0) - TargetInstance = FrmMain.PageCurrent.Additional(2) - TargetLoader = FrmMain.PageCurrent.Additional(3) - TargetType = FrmMain.PageCurrent.Additional(4) - End Sub - Private Project As ResourceProject - Private TargetInstance As String, TargetLoader As ModLoaderTypes - ''' - ''' 当前页面应展示的内容类别。 - ''' 若当前页面是在查看前置时进入,则也可能为 Any。 - ''' - Private TargetType As ResourceTypes '自动重试 Private Sub Load_State(sender As Object, state As MyLoading.MyLoadingState, oldState As MyLoading.MyLoadingState) Handles Load.StateChanged Select Case ResourceFileLoader.State @@ -37,7 +40,7 @@ Dim ErrorMessage As String = "" If ResourceFileLoader.Error IsNot Nothing Then ErrorMessage = ResourceFileLoader.Error.Message If ErrorMessage.Contains("不是有效的 json 文件") Then - Log("[Resource] 下载的文件 json 列表损坏,已自动重试", NotifyLevel.DebugModeOnly) + Logger.Warn("下载的文件 json 列表损坏,已自动重试") PageLoaderRestart() End If End Select @@ -75,13 +78,13 @@ '筛选类型相同的结果(Modrinth 会返回 Mod、服务端插件、数据包混合的列表) Private Function GetResults() As List(Of ResourceVersion) Dim Results As List(Of ResourceVersion) = ResourceFileLoader.Output - Select Case TargetType + Select Case TargetResourceType Case ResourceTypes.Any Results = Results.Where(Function(r) r.ResourceType <> ResourceTypes.Plugin).ToList Case ResourceTypes.Shader, ResourceTypes.ResourcePack '不筛选光影和资源包,否则原版光影会因为是资源包格式而被过滤(#6473) Case Else - Results = Results.Where(Function(r) r.ResourceType = TargetType).ToList + Results = Results.Where(Function(r) r.ResourceType = TargetResourceType).ToList End Select Return Results End Function @@ -132,10 +135,10 @@ GroupDone: Next '自动选择 Dim ToCheck As MyRadioButton = Nothing - If TargetInstance <> "" Then - Dim TargetFile = Results.FirstOrDefault(Function(v) v.GameVersions.Contains(TargetInstance)) + If TargetVersion <> "" Then + Dim TargetFile = Results.FirstOrDefault(Function(v) v.GameVersions.Contains(TargetVersion)) If TargetFile IsNot Nothing Then - Dim TargetGroup = GetGroupedVersionName(TargetInstance, GroupedDrop, GroupedOld) + Dim TargetGroup = GetGroupedVersionName(TargetVersion, GroupedDrop, GroupedOld) For Each Button As MyRadioButton In PanFilter.Children If Button.Text <> TargetGroup Then Continue For ToCheck = Button @@ -153,12 +156,11 @@ GroupDone: Private Sub UpdateFilterResult() Dim Results = GetResults() - Dim TargetCardName As String = If(TargetInstance <> "" OrElse TargetLoader <> ModLoaderTypes.Any, - $"{If(TargetLoader <> ModLoaderTypes.Any, TargetLoader.ToString & " ", "")}{TargetInstance}(所选版本)", "") + Dim TargetCardName As String = If(TargetVersion <> "" OrElse TargetLoaders <> ModLoaders.None, + $"{If(TargetLoaders <> ModLoaders.None, TargetLoaders.ToString & " ", "")}{TargetVersion}(所选版本)", "") '归类到卡片下 Dim Dict As New SortedDictionary(Of String, List(Of ResourceVersion))(New CardSorter(TargetCardName)) Dict.Add("其他", New List(Of ResourceVersion)) - Dim SupportedLoaders As New List(Of Integer)([Enum].GetValues(GetType(ModLoaderTypes))) For Each Version As ResourceVersion In Results For Each GameVersion In Version.GameVersions '检查是否符合版本筛选器 @@ -168,12 +170,12 @@ GroupDone: Dim VerName As String = GetGroupedVersionName(GameVersion, False, False) '遍历加入的加载器列表 Dim Loaders As New List(Of String) - If Project.Loaders.Count > 1 AndAlso '工程至少有两个加载器 + If Project.ModLoaders.Flags.Count > 1 AndAlso '工程至少有两个加载器 Version.ResourceType = ResourceTypes.Mod AndAlso '是 Mod McVersion.IsFormatFit(VerName) Then '不是 “快照版本” 之类的 - For Each Loader In Version.Loaders - If Loader = ModLoaderTypes.Quilt AndAlso Settings.Get("ToolDownloadIgnoreQuilt") Then Continue For - If SupportedLoaders.Contains(Loader) Then Loaders.Add(Loader.ToString & " ") + For Each Loader In Version.ModLoaders.Flags + If Loader = ModLoaders.Quilt AndAlso Settings.Get(Of Boolean)("ToolDownloadIgnoreQuilt") Then Continue For + Loaders.Add(Loader.ToString & " ") Next End If If Not Loaders.Any() Then Loaders.Add("") '保底加一个空的,确保它在一张卡片里 @@ -186,11 +188,11 @@ GroupDone: Next Next '添加筛选的版本的卡片 - If TargetCardName <> "" AndAlso (VersionFilter Is Nothing OrElse GetGroupedVersionName(TargetInstance, GroupedDrop, GroupedOld).StartsWithF(VersionFilter)) Then + If TargetCardName <> "" AndAlso (VersionFilter Is Nothing OrElse GetGroupedVersionName(TargetVersion, GroupedDrop, GroupedOld).StartsWithF(VersionFilter)) Then Dict.Add(TargetCardName, New List(Of ResourceVersion)) For Each Version As ResourceVersion In Results - If Version.GameVersions.Contains(TargetInstance) AndAlso - (TargetLoader = ModLoaderTypes.Any OrElse Version.Loaders.Contains(TargetLoader)) Then + If Version.GameVersions.Contains(TargetVersion) AndAlso + (TargetLoaders = ModLoaders.None OrElse TargetLoaders.Flags.Intersect(Version.ModLoaders.Flags).Any) Then '检查是否符合版本筛选器 If VersionFilter IsNot Nothing AndAlso Not Version.GameVersions.Any(Function(v) GetGroupedVersionName(v, GroupedDrop, GroupedOld) = VersionFilter) Then Continue For @@ -205,16 +207,16 @@ GroupDone: If Not Pair.Value.Any() Then Continue For If Pair.Key = TargetCardName.Replace("(所选版本)", "") Then Continue For '增加卡片 - Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = If(TargetType = ResourceTypes.ModPack, 9, 8)} '9 是安装,8 是另存为 + Dim NewCard As New MyCard With {.Title = Pair.Key, .Margin = New Thickness(0, 0, 0, 15), .SwapType = If(TargetResourceType = ResourceTypes.ModPack, 9, 8)} '9 是安装,8 是另存为 Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value} NewCard.Children.Add(NewStack) NewCard.SwapControl = NewStack PanResults.Children.Add(NewCard) - '确定卡片是否展开 + '确定卡片是否默认展开 If Pair.Key = TargetCardName OrElse (FrmMain.PageCurrent.Additional IsNot Nothing AndAlso '#2761 CType(FrmMain.PageCurrent.Additional(1), List(Of String)).Contains(NewCard.Title)) Then - MyCard.StackInstall(NewStack, If(TargetType = ResourceTypes.ModPack, 9, 8), Pair.Key) '9 是安装,8 是另存为 + MyCard.StackInstall(NewStack, If(TargetResourceType = ResourceTypes.ModPack, 9, 8), Pair.Key) '9 是安装,8 是另存为 Else NewCard.IsSwapped = True End If @@ -228,15 +230,15 @@ GroupDone: CType(PanResults.Children(0), MyCard).IsSwapped = False End If '替代提示 - If Project.Types = ResourceTypes.ModOrDataPack AndAlso (TargetType = ResourceTypes.Mod OrElse TargetType = ResourceTypes.DataPack) Then + If Project.Types = ResourceTypes.ModOrDataPack AndAlso (TargetResourceType = ResourceTypes.Mod OrElse TargetResourceType = ResourceTypes.DataPack) Then HintAlternative.Visibility = Visibility.Visible - HintAlternative.Text = If(TargetType = ResourceTypes.Mod, + HintAlternative.Text = If(TargetResourceType = ResourceTypes.Mod, "以下是该项目的 Mod 版本。点击这里查看其数据包版本。", "以下是该项目的数据包版本。点击这里查看其 Mod 版本。") Else HintAlternative.Visibility = Visibility.Collapsed End If Catch ex As Exception - Log(ex, "可视化工程下载列表出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "可视化工程下载列表出错") End Try End Sub Private Function GetGroupedVersionName(Name As String, GroupedByDrop As Boolean, FoldOld As Boolean) As String @@ -303,16 +305,18 @@ GroupDone: Dim Loaders As New List(Of LoaderBase) Dim Target As String = $"{McFolderSelected}versions\{InstanceName}\原始整合包.{If(Project.Platform = ResourcePlatforms.CurseForge, "zip", "mrpack")}" Dim LogoFileAddress As String = ResourceItem.PathLogo.ActualSource - Loaders.Add(New LoaderDownload("下载整合包文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 10, .Block = True}) + Loaders.Add(New LoaderDownload("下载整合包文件", { + File.ToNetFile(Target, ResourceVersion.DownloadReason.Standalone, File.GameVersions.FirstOrDefault, File.ModLoaders) + }) With {.ProgressWeight = 10, .Block = True}) Loaders.Add(New LoaderTask(Of Integer, Integer)("准备安装整合包", - Sub() ModpackInstall(Target, InstanceName, If(IO.File.Exists(LogoFileAddress), LogoFileAddress, Nothing))) With {.ProgressWeight = 0.1}) + Sub() ModpackInstall(Target, InstanceName, If(FileUtils.Exists(LogoFileAddress), LogoFileAddress, Nothing))) With {.ProgressWeight = 0.1}) '启动 Dim Loader As New LoaderCombo(Of String)(LoaderName, Loaders) With {.OnStateChanged = Sub(MyLoader) Select Case MyLoader.State Case LoadState.Failed - Hint(MyLoader.Name & "失败:" & MyLoader.Error.GetBrief(), HintType.Red) + Hint(MyLoader.Name & "失败:" & MyLoader.Error.GetDisplay(False), HintType.Red) Case LoadState.Interrupted Hint(MyLoader.Name & "已取消!", HintType.Blue) Case LoadState.Loading @@ -326,7 +330,7 @@ GroupDone: FrmMain.BtnExtraDownload.Ribble() Catch ex As Exception - Log(ex, "下载资源整合包失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "下载资源整合包失败") End Try End Sub '资源下载;整合包另存为 @@ -356,13 +360,13 @@ GroupDone: End Select Dim IsInstanceSuitable As Func(Of McInstance, Boolean) = Nothing '获取资源所需的加载器 - Dim AllowedLoaders As New List(Of ModLoaderTypes) - If File.Loaders.Any Then - AllowedLoaders = File.Loaders - ElseIf Project.Loaders.Any Then - AllowedLoaders = Project.Loaders + Dim AllowedLoaders As ModLoaders = ModLoaders.None + If File.ModLoaders <> ModLoaders.None Then + AllowedLoaders = File.ModLoaders + ElseIf Project.ModLoaders <> ModLoaders.None Then + AllowedLoaders = Project.ModLoaders End If - Log($"[Resource] {Desc}要求的加载器种类:" & If(AllowedLoaders.Any(), AllowedLoaders.Join(" / "), "无要求")) + Logger.Info($"{Desc}要求的加载器种类:{AllowedLoaders}") '判断某个版本是否符合资源要求 IsInstanceSuitable = Function(Instance As McInstance) @@ -403,21 +407,16 @@ GroupDone: End Function) Then Return False End If '加载器 - If Not AllowedLoaders.Any() Then Return True '无要求 - If AllowedLoaders.Contains(ModLoaderTypes.Forge) AndAlso Instance.Version.HasForge Then Return True - If AllowedLoaders.Contains(ModLoaderTypes.Fabric) AndAlso Instance.Version.HasFabric Then Return True - If AllowedLoaders.Contains(ModLoaderTypes.NeoForge) AndAlso Instance.Version.HasNeoForge Then Return True - If AllowedLoaders.Contains(ModLoaderTypes.LiteLoader) AndAlso Instance.Version.HasLiteLoader Then Return True - Return False + Return AllowedLoaders = ModLoaders.None OrElse AllowedLoaders.Flags.Intersect(Instance.Version.ModLoaders.Flags).Any End Function '获取常规资源默认下载位置 If CachedFolder.ContainsKey(File.ResourceType) Then DefaultFolder = CachedFolder(File.ResourceType) - Log($"[Resource] 使用上次下载时的文件夹作为默认下载位置:{DefaultFolder}") + Logger.Info($"使用上次下载时的文件夹作为默认下载位置:{DefaultFolder}") ElseIf McInstanceSelected IsNot Nothing AndAlso IsInstanceSuitable(McInstanceSelected) Then DefaultFolder = $"{McInstanceSelected.PathIndie}{SubFolder}" DirectoryUtils.Create(DefaultFolder) - Log($"[Resource] 使用当前版本作为默认下载位置:{DefaultFolder}") + Logger.Info($"使用当前版本作为默认下载位置:{DefaultFolder}") Else '查找所有可能的版本 Dim NeedLoad As Boolean = McInstanceListLoader.State <> LoadState.Finished @@ -426,21 +425,21 @@ GroupDone: LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\", WaitForExit:=True) End If Dim SuitableInstanceList = McInstanceList.Values.SelectMany(Function(l) l).Where(Function(v) IsInstanceSuitable(v)). - Select(Function(v) New DirectoryInfo($"{v.PathIndie}{SubFolder}")) + Select(Function(v) DirectoryUtils.GetInfo($"{v.PathIndie}{SubFolder}")) If SuitableInstanceList.Any Then Dim SelectedInstance = SuitableInstanceList. OrderByDescending(Function(Dir) If(Dir.Exists, Dir.LastWriteTimeUtc, Date.MinValue)). '先按文件夹更改时间降序 ThenByDescending(Function(Dir) If(Dir.Exists, Dir.GetFiles().Length, -1)). '再按文件夹中的文件数量降序 First() - DefaultFolder = SelectedInstance.FullName + DefaultFolder = PathUtils.RemoveExtendedPrefix(SelectedInstance.FullName) DirectoryUtils.Create(DefaultFolder) - Log($"[Resource] 使用适合的游戏版本作为默认下载位置:{DefaultFolder}") + Logger.Info($"使用适合的游戏版本作为默认下载位置:{DefaultFolder}") Else DefaultFolder = McFolderSelected If NeedLoad Then Hint($"当前 MC 文件夹中没有找到合适的版本!") Else - Log("[Resource] 由于当前版本不兼容,使用当前的 MC 文件夹作为默认下载位置") + Logger.Info("由于当前版本不兼容,使用当前的 MC 文件夹作为默认下载位置") End If End If End If @@ -452,7 +451,7 @@ GroupDone: Else Dim ChineseName As String = Project.TranslatedName.BeforeFirst(" (").BeforeFirst(" - "). Replace("\", "\").Replace("/", "/").Replace("|", "|").Replace(":", ":").Replace("<", "<").Replace(">", ">").Replace("*", "*").Replace("?", "?").Replace("""", "").Replace(": ", ":") - Select Case Settings.Get("ToolDownloadTranslateV2") + Select Case Settings.Get(Of Integer)("ToolDownloadTranslateV2") Case 0 FileName = $"【{ChineseName}】{File.FileName}" Case 1 @@ -470,17 +469,18 @@ GroupDone: Sub() '弹窗要求选择保存位置 Dim Target As String - Target = SelectSaveFile("选择保存位置", FileName, - Desc & "文件|" & - If(File.ResourceType = ResourceTypes.Mod, - If(File.FileName.EndsWithF(".litemod"), "*.litemod", "*.jar"), - If(File.FileName.EndsWithF(".mrpack"), "*.mrpack", "*.zip")), DefaultFolder) - If Not Target.Contains("\") Then Return + Dim Ext As String = If(File.ResourceType = ResourceTypes.Mod, + If(File.FileName.EndsWithF(".litemod"), "litemod", "jar"), + If(File.FileName.EndsWithF(".mrpack"), "mrpack", "zip")) + Target = Dialogs.SaveFile("选择保存位置", FileName, DefaultFolder, {(Ext, Desc & "文件")}) + If Target Is Nothing Then Return '构造步骤加载器 - Dim LoaderName As String = Desc & "下载:" & Path.GetFileNameWithoutExtension(Target) & " " - If Target <> DefaultFolder Then CachedFolder(File.ResourceType) = GetPathFromFullPath(Target) + Dim LoaderName As String = Desc & "下载:" & PathUtils.GetFileNameWithoutExtension(Target) & " " + If Target <> DefaultFolder Then CachedFolder(File.ResourceType) = PathUtils.RemoveLastPart(Target) Dim Loaders As New List(Of LoaderBase) - Loaders.Add(New LoaderDownload("下载文件", New List(Of NetFile) From {File.ToNetFile(Target)}) With {.ProgressWeight = 6, .Block = True}) + Loaders.Add(New LoaderDownload("下载文件", { + File.ToNetFile(Target, If(TargetResourceType = ResourceTypes.Any, ResourceVersion.DownloadReason.Dependency, ResourceVersion.DownloadReason.Standalone)) + }) With {.ProgressWeight = 6, .Block = True}) '启动 Dim Loader As New LoaderCombo(Of Integer)(LoaderName, Loaders) With {.OnStateChanged = AddressOf LoaderStateChangedHintOnly} Loader.Start(1) @@ -489,7 +489,7 @@ GroupDone: FrmMain.BtnExtraDownload.Ribble() End Sub) Catch ex As Exception - Log(ex, "保存资源文件失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "保存资源文件失败") End Try End Sub, "Download Resource Detail Save") End Sub @@ -506,8 +506,8 @@ GroupDone: 'Mod / 数据包 互相跳转 Private Sub HintAlternative_Click() Handles HintAlternative.Click - TargetType = If(TargetType = ResourceTypes.Mod, ResourceTypes.DataPack, ResourceTypes.Mod) - FrmMain.PageCurrent.Additional(4) = TargetType '加载器会从这里重新拿数据 + TargetResourceType = If(TargetResourceType = ResourceTypes.Mod, ResourceTypes.DataPack, ResourceTypes.Mod) + FrmMain.PageCurrent.Additional(4) = TargetResourceType '加载器会从这里重新拿数据 PageLoaderRestart(IsForceRestart:=True) End Sub @@ -522,7 +522,7 @@ GroupDone: If Not Deps.Any() Then Return Deps = Deps.Where( Function(dep) - If Not ResourceProject.Cache.ContainsKey(dep) Then Log($"[Resource] 未找到 ID {dep} 的前置信息", NotifyLevel.DebugModeOnly) + If Not ResourceProject.Cache.ContainsKey(dep) Then Logger.Warn($"未找到 ID {dep} 的前置信息") Return ResourceProject.Cache.ContainsKey(dep) End Function).ToList '添加开头间隔 diff --git a/Plain Craft Launcher 2/Pages/PageDownload/Resource/PageResource.xaml b/Plain Craft Launcher 2/Pages/PageDownload/Resource/PageResource.xaml index 2103e75..91343a8 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/Resource/PageResource.xaml +++ b/Plain Craft Launcher 2/Pages/PageDownload/Resource/PageResource.xaml @@ -49,9 +49,10 @@ - + - + + diff --git a/Plain Craft Launcher 2/Pages/PageDownload/Resource/PageResource.xaml.vb b/Plain Craft Launcher 2/Pages/PageDownload/Resource/PageResource.xaml.vb index 6175515..431ae1a 100644 --- a/Plain Craft Launcher 2/Pages/PageDownload/Resource/PageResource.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageDownload/Resource/PageResource.xaml.vb @@ -74,7 +74,7 @@ Public Class PageResource Public Shared TargetName As String = Nothing '在点击 MyResourceItem 时会获取 Loader 的输入,以使资源详情页面可以应用相同的筛选项 - Public Loader = ResourceSearcher.GetLoader(AddressOf LoaderInput) + Public Loader As LoaderTask(Of ResourceSearcher.SearchRequest, Integer) = ResourceSearcher.GetLoader(AddressOf LoaderInput) Private Sub PageResource_Loaded(sender As Object, e As EventArgs) Handles Me.Loaded Static IsFirstLoaded As Boolean = False @@ -126,7 +126,7 @@ Public Class PageResource .SearchText = TextSearchName.Text .GameVersion = GameVersion .Tag = ComboSearchTag.SelectedItem.Tag - .ModLoader = If(PageType = ResourceTypes.Mod, Val(ComboSearchLoader.SelectedItem.Tag), ModLoaderTypes.Any) + .ModLoaders = If(PageType = ResourceTypes.Mod, Val(ComboSearchLoader.SelectedItem.Tag), ModLoaders.None) .Sources = CType(Val(ComboSearchSource.SelectedItem.Tag), ResourcePlatforms) End With Return Request @@ -144,14 +144,14 @@ Public Class PageResource '结果 UI 化 Private Sub Load_OnFinish() Try - Log($"[Resource] 开始可视化{TypeNameSpaced}列表,已储藏 {Storage.Results.Count} 个结果,当前在第 {Page + 1} 页") + Logger.Info($"开始可视化{TypeNameSpaced}列表,已储藏 {Storage.Results.Count} 个结果,当前在第 {Page + 1} 页") '列表项 PanProjects.Children.Clear() Dim Index As Integer = Math.Min(Page * PAGE_SIZE, Storage.Results.Count - 1) For Each Result In Storage.Results.GetRange(Index, Math.Min(Storage.Results.Count - Index, PAGE_SIZE)) PanProjects.Children.Add(Result.ToResourceItem( ShowMcVersionDesc:=Loader.Input.GameVersion Is Nothing, - ShowLoaderDesc:=Loader.Input.ModLoader = ModLoaderTypes.Any AndAlso (PageType = ResourceTypes.Mod OrElse PageType = ResourceTypes.ModPack))) + ShowLoaderDesc:=Loader.Input.ModLoaders = ModLoaders.None AndAlso (PageType = ResourceTypes.Mod OrElse PageType = ResourceTypes.ModPack))) Next '页码 CardPages.Visibility = If(Storage.Results.Count > 40 OrElse @@ -177,7 +177,7 @@ Public Class PageResource '强制返回顶部 ScrollToTop() Catch ex As Exception - Log(ex, $"可视化{TypeNameSpaced}列表出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"可视化{TypeNameSpaced}列表出错") End Try End Sub @@ -188,7 +188,7 @@ Public Class PageResource Dim ErrorMessage As String = "" If Loader.Error IsNot Nothing Then ErrorMessage = Loader.Error.Message If ErrorMessage.Contains("不是有效的 json 文件") Then - Log($"[Download] 下载的{TypeNameSpaced}列表 json 文件损坏,已自动重试", NotifyLevel.DebugModeOnly) + Logger.Warn($"下载的{TypeNameSpaced}列表 json 文件损坏,已自动重试") CType(Parent, MyPageRight).PageLoaderRestart() End If End Select @@ -208,7 +208,7 @@ Public Class PageResource CardPages.IsEnabled = False Page = NewPage FrmMain.BackToTop() - Log($"[Download] {TypeName}:切换到第 {Page + 1} 页") + Logger.Info($"{TypeName}:切换到第 {Page + 1} 页") RunInThread( Sub() Thread.Sleep(100) '等待向上滚的动画结束 diff --git a/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml b/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml index 445f44b..ac889ca 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml +++ b/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml @@ -3,7 +3,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:PCL;assembly=" x:Name="PanBack" Height="44" - RenderTransformOrigin="0.5,0.5" Background="{StaticResource ColorBrushSemiTransparent}" SnapsToDevicePixels="True"> + RenderTransformOrigin="0.5,0.5" Background="{StaticResource ColorBrushSemiTransparent}" SnapsToDevicePixels="True" Cursor="Hand"> diff --git a/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.vb b/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.vb index 0b225fc..2e3fd21 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageInstance/MyLocalModItem.xaml.vb @@ -61,11 +61,11 @@ Public Class MyLocalModItem End Property '相关联的 Mod - Public Property Entry As ResourceFile + Public Property Entry As LocalResourceFile Get Return Tag End Get - Set(value As ResourceFile) + Set(value As LocalResourceFile) Tag = value End Set End Property @@ -80,7 +80,7 @@ Public Class MyLocalModItem If IsMouseDown Then RaiseEvent Click(sender, e) If e.Handled Then Return - Log("[Control] 按下本地 Mod 列表项:" & LabTitle.Text) + Logger.Info($"按下本地 Mod 列表项:{LabTitle.Text}") End If End Sub @@ -203,7 +203,7 @@ Public Class MyLocalModItem AniStop("MyLocalModItem Checked " & Uuid) End If Catch ex As Exception - Log(ex, "设置 Checked 失败") + Logger.Warn(ex, "设置 Checked 失败") End Try End Set End Property @@ -335,9 +335,9 @@ Public Class MyLocalModItem BtnUpdate.Visibility = Visibility.Collapsed End If '标题与描述 - Dim DescFileName As String = Path.GetFileNameWithoutExtension(Entry.File.FullName) + Dim DescFileName As String = Entry.File.Name.BeforeLast(".") Dim NewDescription As String - If Settings.Get("ToolModLocalNameStyle") = 1 Then + If Settings.Get(Of Integer)("ToolModLocalNameStyle") = 1 Then '标题显示文件名,详情显示译名 '标题 Title = DescFileName diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.vb b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.vb index 17b2ac8..286ab23 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceExport.xaml.vb @@ -25,7 +25,7 @@ Public Class PageInstanceExport AniControlEnabled -= 1 End Sub Public Sub RefreshAll() Implements IRefreshable.Refresh - Log($"[Export] 刷新导出页面") + Logger.Info($"刷新导出页面") HintOptiFine.Visibility = If(PageInstanceLeft.Instance.Version.HasOptiFine, Visibility.Visible, Visibility.Collapsed) CurrentInstance = PageInstanceLeft.Instance.PathVersion TextExportName.Text = "" @@ -56,7 +56,7 @@ Public Class PageInstanceExport Private Sub ReloadSubOptions(Panel As StackPanel, AcceptCompressedFile As Boolean, AcceptFolder As Boolean, ParamArray Folders As String()) Panel.Children.Clear() For Each Folder In Folders - Dim TargetFolder As New DirectoryInfo(PageInstanceLeft.Instance.PathIndie & Folder) + Dim TargetFolder = DirectoryUtils.GetInfo(PageInstanceLeft.Instance.PathIndie & Folder) If Not TargetFolder.Exists() Then Continue For '查找文件夹下的对应项 If AcceptCompressedFile Then @@ -98,14 +98,14 @@ Public Class PageInstanceExport Return False End Try End Function - Dim PathInfo As New DirectoryInfo(PageInstanceLeft.Instance.PathIndie) + Dim PathInfo = DirectoryUtils.GetInfo(PageInstanceLeft.Instance.PathIndie) AllEntries.AddRange(PathInfo.EnumerateFiles().Select(Function(f) f.Name)) For Each SubFolder In PathInfo.EnumerateDirectories().Where(IsValidDirectory) AllEntries.Add($"{SubFolder.Name}\") AllEntries.AddRange(SubFolder.EnumerateFiles().Select(Function(f) $"{SubFolder.Name}\{f.Name}")) AllEntries.AddRange(SubFolder.EnumerateDirectories().Where(IsValidDirectory).Select(Function(d) $"{SubFolder.Name}\{d.Name}\")) Next - Log($"[Export] 共发现 {AllEntries.Count} 个可行的二级文件/文件夹") + Logger.Info($"共发现 {AllEntries.Count} 个可行的二级文件/文件夹") '确认选项是否应该被显示 Dim IsVisible = Function(TargetOption As ExportOption) As Boolean @@ -121,16 +121,16 @@ Public Class PageInstanceExport Try If AllEntries.Any(Function(Entry) Entry Like Rule) Then Return True Catch ex As Exception - Log(ex, $"错误的规则:{Rule}", NotifyLevel.AllUsers) + Logger.Error(ex, $"错误的规则:{Rule}", LogBehavior.Toast) Return False End Try '粗略检查所有级 Rule = Rule.Trim("*?".ToCharArray) - If Rule.Split({"\"c}, StringSplitOptions.RemoveEmptyEntries).Count >= 3 Then + If Rule.Split("\"c, True).Count >= 3 Then If Rule.EndsWithF("\") Then - Return IsValidDirectory(New DirectoryInfo(PageInstanceLeft.Instance.PathIndie & Rule)) '文件夹有效 + Return IsValidDirectory(DirectoryUtils.GetInfo(PageInstanceLeft.Instance.PathIndie & Rule)) '文件夹有效 Else - Return File.Exists(PageInstanceLeft.Instance.PathIndie & Rule) '文件有效 + Return FileUtils.Exists(PageInstanceLeft.Instance.PathIndie & Rule) '文件有效 End If Else Return False @@ -303,8 +303,8 @@ Public Class PageInstanceExport '保存配置文件 Private Sub ExportConfig() Handles BtnAdvancedExport.Click Try - Dim ConfigPath As String = SelectSaveFile("选择文件位置", "export_config.txt", "整合包导出配置(*.txt)|*.txt", Settings.Get("CacheExportConfig")) - If String.IsNullOrEmpty(ConfigPath) Then Return + Dim ConfigPath As String = Dialogs.SaveFile("选择文件位置", "export_config.txt", Settings.Get(Of String)("CacheExportConfig"), {("txt", "整合包导出配置")}) + If ConfigPath Is Nothing Then Return Settings.Set("CacheExportConfig", ConfigPath) Dim ConfigLines As New List(Of String) 'ini 段 @@ -343,19 +343,19 @@ Public Class PageInstanceExport Hint("已保存配置文件:" & ConfigPath, HintType.Green) OpenExplorer(ConfigPath) Catch ex As Exception - Log(ex, "保存配置失败", NotifyLevel.MsgBox) + Logger.Error(ex, "保存配置失败", LogBehavior.Alert) End Try End Sub '读取配置文件 Private Sub ImportConfig() Handles BtnAdvancedImport.Click Try - Dim ConfigPath As String = SelectFile("整合包导出配置(*.txt)|*.txt", "选择配置文件", Settings.Get("CacheExportConfig")) + Dim ConfigPath As String = Dialogs.SelectFile("选择配置文件", False, Settings.Get(Of String)("CacheExportConfig"), {({"txt"}, "整合包导出配置")}).FirstOrDefault() If String.IsNullOrEmpty(ConfigPath) Then Return Settings.Set("CacheExportConfig", ConfigPath) - Dim Segments As String() = ReadFile(ConfigPath).Split(Sperator) + Dim Segments As String() = FileUtils.ReadAsString(ConfigPath).Split(Sperator) 'ini 段 Dim Ini As New Dictionary(Of String, String) - For Each Line In Segments(0).Split(vbCrLf.ToCharArray()) + For Each Line In Segments(0).SplitLines(True) Line = Line.Trim If Line = "" OrElse Line.StartsWithF("#") OrElse Line.StartsWithF("=") Then Continue For Dim Index As Integer = Line.IndexOfF(":") @@ -369,17 +369,17 @@ Public Class PageInstanceExport If Not CheckAdvancedInclude.Checked Then CheckAdvancedModrinth.Checked = Ini.GetOrDefault("ModrinthUploadMode", False) '#7979,加个特判 ConfigPackPath = Ini.GetOrDefault("PackPath", Nothing) '导出内容段 - RulesOverrides = Segments(1).ReplaceLineEndings(vbLf, mergeMultiple:=True).Split(vbLf).ToList + RulesOverrides = Segments(1).SplitLines(True).ToList '追加内容段 If Segments.Length > 2 Then - ExtraFiles = Segments(2).ReplaceLineEndings(vbLf, mergeMultiple:=True).Split(vbLf).ToList + ExtraFiles = Segments(2).SplitLines(True).ToList Else ExtraFiles = Nothing End If '结束 Hint("已读取配置文件:" & ConfigPath, HintType.Green) Catch ex As Exception - Log(ex, "读取配置失败", NotifyLevel.MsgBox) + Logger.Error(ex, "读取配置失败", LogBehavior.Alert) End Try End Sub @@ -412,23 +412,23 @@ Public Class PageInstanceExport If Not String.IsNullOrWhiteSpace(ConfigPackPath) AndAlso (Not ConfigPackPath.EndsWithF("\") AndAlso Not ConfigPackPath.EndsWithF("/")) Then Try - DirectoryUtils.Create(ConfigPackPath, isFilePath:=True) + DirectoryUtils.Create(PathUtils.RemoveLastPart(ConfigPackPath)) PackPath = ConfigPackPath - Log($"[Export] 使用配置文件中指定的导出路径:{ConfigPackPath}") + Logger.Info($"使用配置文件中指定的导出路径:{ConfigPackPath}") Catch ex As Exception - Log(ex, $"无法使用配置文件中指定的导出路径({ConfigPackPath})", NotifyLevel.DebugModeOnly) - If MyMsgBox($"指定的路径:{ConfigPackPath}{vbCrLf}{vbCrLf}{ex.GetDetail}", "无法使用配置文件中指定的导出路径", "确定", "取消") = 2 Then Return + Logger.Warn(ex, $"无法使用配置文件中指定的导出路径({ConfigPackPath})") + If MyMsgBox($"指定的路径:{ConfigPackPath}{vbCrLf}{vbCrLf}{ex.GetDisplay(True)}", "无法使用配置文件中指定的导出路径", "确定", "取消") = 2 Then Return End Try End If If PackPath Is Nothing Then - Dim Extensions As New List(Of String) - Extensions.Add("压缩文件(*.zip)|*.zip") - If Not CheckOptionsPcl.Checked Then Extensions.Add("Modrinth 整合包文件(*.mrpack)|*.mrpack") - PackPath = SelectSaveFile("选择导出位置", - PackName & If(String.IsNullOrEmpty(TextExportVersion.Text), "", " " & TextExportVersion.Text), Extensions.Join("|")) - Log($"[Export] 手动指定的导出路径:{PackPath}") + Dim Extensions As New List(Of (Extension As String, Display As String)) + Extensions.Add(("zip", "压缩文件")) + If Not CheckOptionsPcl.Checked Then Extensions.Add(("mrpack", "Modrinth 整合包文件")) + PackPath = Dialogs.SaveFile("选择导出位置", + PackName & If(String.IsNullOrEmpty(TextExportVersion.Text), "", " " & TextExportVersion.Text), filter:=Extensions) + Logger.Info($"手动指定的导出路径:{PackPath}") End If - If String.IsNullOrEmpty(PackPath) Then Return + If PackPath Is Nothing Then Return '缓存所需参数 Dim CacheFolder = RequestTaskTempFolder() @@ -441,7 +441,7 @@ Public Class PageInstanceExport Dim IncludePCLCustom As Boolean = IncludePCL AndAlso CheckOptionsPclCustom.Checked Dim AllRules = StandardizeLines(GetAllRules(), True).ToList() Dim AllExtraFiles = StandardizeLines(GetExtraFileLines(), False).ToList() - Log($"[Export] 准备导出整合包,共有 {AllRules.Count} 条规则,{AllExtraFiles.Count} 条追加内容行") + Logger.Info($"准备导出整合包,共有 {AllRules.Count} 条规则,{AllExtraFiles.Count} 条追加内容行") '构造步骤加载器 Dim Loaders As New List(Of LoaderBase) @@ -452,7 +452,7 @@ Public Class PageInstanceExport Loaders.Add(New LoaderTask(Of Integer, Integer)("下载 PCL 正式版", Sub(Loader As LoaderTask(Of Integer, Integer)) DownloadLatestPCL(Loader) - CopyFile(PathTemp & "Latest.exe", CacheFolder & "Plain Craft Launcher.exe") + FileUtils.Copy(PathTemp & "Latest.exe", CacheFolder & "Plain Craft Launcher.exe") End Sub) With {.ProgressWeight = 0.5, .Block = False}) End If @@ -460,9 +460,9 @@ Public Class PageInstanceExport #Region "复制文件" - Loaders.Add(New LoaderTask(Of Integer, List(Of ResourceFile))("复制导出内容", - Sub(Loader As LoaderTask(Of Integer, List(Of ResourceFile))) - Loader.Output = New List(Of ResourceFile) + Loaders.Add(New LoaderTask(Of Integer, List(Of LocalResourceFile))("复制导出内容", + Sub(Loader As LoaderTask(Of Integer, List(Of LocalResourceFile))) + Loader.Output = New List(Of LocalResourceFile) '复制版本文件 Dim Progress As Integer = 0 Dim SearchFolder As Action(Of DirectoryInfo) @@ -471,7 +471,7 @@ Public Class PageInstanceExport '文件夹:进一步搜索 For Each SubFolder In Folder.EnumerateDirectories("*", SearchOption.TopDirectoryOnly) '跳过部分又没用文件又多的文件夹,加快搜索 - If Folder.FullName = PathIndie AndAlso {"assets", "versions", "libraries"}.Contains(SubFolder.Name) Then Continue For + If {"assets", "versions", "libraries"}.Contains(SubFolder.Name) AndAlso PathIndie = PathUtils.RemoveExtendedPrefix(Folder.FullName) Then Continue For If {"structureCacheV1", ".fabric", ".git", "avatar-cache", "cosmetic-cache"}.Contains(SubFolder.Name) Then Continue For SearchFolder(SubFolder) Next @@ -486,12 +486,12 @@ Public Class PageInstanceExport Next If Not ShouldKeep Then Continue For Dim TargetPath As String = OverridesFolder & RelativePath - CopyFile(Entry.FullName, TargetPath) + FileUtils.Copy(Entry.FullName, TargetPath) '若为压缩包,考虑联网获取路径 If CheckHostedAssets AndAlso {".zip", ".rar", ".jar", ".disabled", ".old"}.Contains(Entry.Extension.Lower) AndAlso {"mods", "packs", "openloader", "resource"}.Any(Function(s) RelativePath.Contains(s)) Then - Dim ModFile As New ResourceFile(TargetPath) + Dim ModFile As New LocalResourceFile(TargetPath) Dim Unused = ModFile.ModrinthHash '提前计算 Hash Unused = ModFile.CurseForgeHash Loader.Output.Add(ModFile) @@ -504,21 +504,21 @@ Public Class PageInstanceExport End If Next End Sub - SearchFolder(New DirectoryInfo(PathIndie)) - Log($"[Export] 复制 overrides 文件完成,有 {Loader.Output.Count} 个文件需要联网检查") + SearchFolder(DirectoryUtils.GetInfo(PathIndie)) + Logger.Info($"复制 overrides 文件完成,有 {Loader.Output.Count} 个文件需要联网检查") Loader.Progress = 0.95 '复制追加内容到根目录 Dim BaseFolder As String = If(IncludePCL, CacheFolder, CacheFolder & "modpack\") For Each Line In AllExtraFiles If Line.EndsWithF("\") OrElse Line.EndsWithF("/") Then - If Directory.Exists(Line) Then - CopyDirectory(Line, BaseFolder & GetFolderNameFromPath(Line) & "\") + If DirectoryUtils.Exists(Line) Then + DirectoryUtils.Copy(Line, BaseFolder & PathUtils.GetLastPart(Line) & "\") Else Hint($"未找到配置文件中指定的文件夹:{Line}", HintType.Red) End If Else - If File.Exists(Line) Then - CopyFile(Line, BaseFolder & GetFileNameFromPath(Line)) + If FileUtils.Exists(Line) Then + FileUtils.Copy(Line, BaseFolder & PathUtils.GetLastPart(Line)) Else Hint($"未找到配置文件中指定的单个文件:{Line}", HintType.Red) End If @@ -526,19 +526,19 @@ Public Class PageInstanceExport Next Loader.Progress = 0.97 '复制 PCL 版本设置 - CopyDirectory(McVersion.PathVersion & "PCL\", OverridesFolder & "PCL\") + If DirectoryUtils.Exists(McVersion.PathVersion & "PCL\") Then DirectoryUtils.Copy(McVersion.PathVersion & "PCL\", OverridesFolder & "PCL\") WriteIni(OverridesFolder & "PCL\Setup.ini", "IsStar", False) '复制 PCL 本体(正式版) - If BuildType = BuildTypes.Release AndAlso IncludePCL Then CopyFile(PathExe, CacheFolder & "Plain Craft Launcher.exe") + If BuildType = BuildTypes.Release AndAlso IncludePCL Then FileUtils.Copy(PathExe, CacheFolder & "Plain Craft Launcher.exe") '复制 PCL 个性化内容 If IncludePCLCustom Then - If Directory.Exists(PathExeFolder & "PCL\Pictures\") Then CopyDirectory(PathExeFolder & "PCL\Pictures\", CacheFolder & "PCL\Pictures\") - If Directory.Exists(PathExeFolder & "PCL\Musics\") Then CopyDirectory(PathExeFolder & "PCL\Musics\", CacheFolder & "PCL\Musics\") - If Directory.Exists(PathExeFolder & "PCL\Help\") Then CopyDirectory(PathExeFolder & "PCL\Help\", CacheFolder & "PCL\Help\") - If File.Exists(PathExeFolder & "PCL\Custom.xaml") Then CopyFile(PathExeFolder & "PCL\Custom.xaml", CacheFolder & "PCL\Custom.xaml") - If File.Exists(PathExeFolder & "PCL\Setup.ini") Then CopyFile(PathExeFolder & "PCL\Setup.ini", CacheFolder & "PCL\Setup.ini") - If File.Exists(PathExeFolder & "PCL\hints.txt") Then CopyFile(PathExeFolder & "PCL\hints.txt", CacheFolder & "PCL\hints.txt") - If File.Exists(PathExeFolder & "PCL\Logo.png") Then CopyFile(PathExeFolder & "PCL\Logo.png", CacheFolder & "PCL\Logo.png") + If DirectoryUtils.Exists(PathExeFolder & "PCL\Pictures\") Then DirectoryUtils.Copy(PathExeFolder & "PCL\Pictures\", CacheFolder & "PCL\Pictures\") + If DirectoryUtils.Exists(PathExeFolder & "PCL\Musics\") Then DirectoryUtils.Copy(PathExeFolder & "PCL\Musics\", CacheFolder & "PCL\Musics\") + If DirectoryUtils.Exists(PathExeFolder & "PCL\Help\") Then DirectoryUtils.Copy(PathExeFolder & "PCL\Help\", CacheFolder & "PCL\Help\") + If FileUtils.Exists(PathExeFolder & "PCL\Custom.xaml") Then FileUtils.Copy(PathExeFolder & "PCL\Custom.xaml", CacheFolder & "PCL\Custom.xaml") + If FileUtils.Exists(PathExeFolder & "PCL\Setup.ini") Then FileUtils.Copy(PathExeFolder & "PCL\Setup.ini", CacheFolder & "PCL\Setup.ini") + If FileUtils.Exists(PathExeFolder & "PCL\hints.txt") Then FileUtils.Copy(PathExeFolder & "PCL\hints.txt", CacheFolder & "PCL\hints.txt") + If FileUtils.Exists(PathExeFolder & "PCL\Logo.png") Then FileUtils.Copy(PathExeFolder & "PCL\Logo.png", CacheFolder & "PCL\Logo.png") End If End Sub) With {.ProgressWeight = 5}) @@ -546,11 +546,11 @@ Public Class PageInstanceExport #Region "联网检查" - Loaders.Add(New LoaderTask(Of List(Of ResourceFile), Dictionary(Of ResourceFile, List(Of String)))("联网获取文件信息", - Sub(Loader As LoaderTask(Of List(Of ResourceFile), Dictionary(Of ResourceFile, List(Of String)))) - Loader.Output = New Dictionary(Of ResourceFile, List(Of String)) - If Not CheckHostedAssets Then Log($"[Export] 要求跳过联网获取步骤") : Return - If Not Loader.Input.Any Then Log($"[Export] 没有需要联网检查的文件,跳过联网获取步骤") : Return + Loaders.Add(New LoaderTask(Of List(Of LocalResourceFile), Dictionary(Of LocalResourceFile, List(Of String)))("联网获取文件信息", + Sub(Loader As LoaderTask(Of List(Of LocalResourceFile), Dictionary(Of LocalResourceFile, List(Of String)))) + Loader.Output = New Dictionary(Of LocalResourceFile, List(Of String)) + If Not CheckHostedAssets Then Logger.Info($"要求跳过联网获取步骤") : Return + If Not Loader.Input.Any Then Logger.Info($"没有需要联网检查的文件,跳过联网获取步骤") : Return '分平台获取下载地址 Dim EndedThreadCount As Integer = 0, FailedExceptions As New List(Of Exception) @@ -569,9 +569,9 @@ Public Class PageInstanceExport '写入下载地址 Loader.Output.AddIntoValueCollection(ModFile, ModrinthRaw(ModFile.ModrinthHash)("files")(0)("url")) Next - Log($"[Export] 从 Modrinth 获取到 {ModrinthRaw.Count} 个本地资源项的对应信息") + Logger.Info($"从 Modrinth 获取到 {ModrinthRaw.Count} 个本地资源项的对应信息") Catch ex As Exception - Log(ex, "从 Modrinth 获取本地 Mod 信息失败") + Logger.Warn(ex, "从 Modrinth 获取本地 Mod 信息失败") FailedExceptions.Add(ex) Finally EndedThreadCount += 1 @@ -592,16 +592,16 @@ Public Class PageInstanceExport Dim File As JObject = ResultJson("file") If String.IsNullOrEmpty(File("downloadUrl")) Then Continue For '查找对应的文件 - Dim ModFile As ResourceFile = Loader.Input.FirstOrDefault(Function(m) m.CurseForgeHash = File("fileFingerprint").ToObject(Of UInteger)) + Dim ModFile As LocalResourceFile = Loader.Input.FirstOrDefault(Function(m) m.CurseForgeHash = File("fileFingerprint").ToObject(Of UInteger)) If ModFile Is Nothing Then Continue For '写入下载地址 For Each Address In ResourceVersion.ParseCurseForgeDownloadUrls(File("downloadUrl").ToString) Loader.Output.AddIntoValueCollection(ModFile, Address) Next Next - Log($"[Export] 从 CurseForge 获取到 {CurseForgeRaw.Count} 个本地资源项的对应信息") + Logger.Info($"从 CurseForge 获取到 {CurseForgeRaw.Count} 个本地资源项的对应信息") Catch ex As Exception - Log(ex, "从 CurseForge 获取本地 Mod 信息失败") + Logger.Warn(ex, "从 CurseForge 获取本地 Mod 信息失败") FailedExceptions.Add(ex) Finally EndedThreadCount += 1 @@ -633,17 +633,17 @@ Public Class PageInstanceExport #Region "生成压缩包" - Loaders.Add(New LoaderTask(Of Dictionary(Of ResourceFile, List(Of String)), Integer)("生成压缩包", - Sub(Loader As LoaderTask(Of Dictionary(Of ResourceFile, List(Of String)), Integer)) + Loaders.Add(New LoaderTask(Of Dictionary(Of LocalResourceFile, List(Of String)), Integer)("生成压缩包", + Sub(Loader As LoaderTask(Of Dictionary(Of LocalResourceFile, List(Of String)), Integer)) '整理文件列表 Dim Files As New JArray For Each Pair In Loader.Input - Dim ModFile As ResourceFile = Pair.Key + Dim ModFile As LocalResourceFile = Pair.Key Files.Add(New JObject From { - {"path", ModFile.File.FullName.AfterFirst(OverridesFolder).Replace("\", "/")}, - {"hashes", New JObject From {{"sha1", ModFile.ModrinthHash}, {"sha512", GetFileSHA512(ModFile.File.FullName)}}}, + {"path", PathUtils.RemoveExtendedPrefix(ModFile.File.FullName).AfterFirst(OverridesFolder).Replace("\", "/")}, + {"hashes", New JObject From {{"sha1", ModFile.ModrinthHash}, {"sha512", HashUtils.ComputeFromFile(ModFile.File.FullName, HashUtils.HashMethod.Sha512)}}}, {"downloads", New JArray(Pair.Value.OrderBy(Function(u) u.Contains("modrinth.com")))}, '不优先选择 Modrinth - {"fileSize", New FileInfo(ModFile.File.FullName).Length} + {"fileSize", ModFile.File.Length} }) ModFile.File.Delete() Next @@ -662,25 +662,22 @@ Public Class PageInstanceExport {"files", Files}, {"dependencies", Dependencies} } - File.WriteAllText(CacheFolder & "modpack\modrinth.index.json", ResultJson.ToString(Newtonsoft.Json.Formatting.Indented)) + FileUtils.Write(CacheFolder & "modpack\modrinth.index.json", ResultJson.ToString(Newtonsoft.Json.Formatting.Indented)) '打包 - DirectoryUtils.Create(PackPath, isFilePath:=True) - If File.Exists(PackPath) Then File.Delete(PackPath) If IncludePCL Then '首次压缩整合包 - ZipFile.CreateFromDirectory(CacheFolder & "modpack\", CacheFolder & "modpack.mrpack") + FileUtils.CreateZipFromDirectory(CacheFolder & "modpack.mrpack", CacheFolder & "modpack\") Loader.Progress = 0.5 - DeleteDirectory(CacheFolder & "modpack\") + DirectoryUtils.Delete(CacheFolder & "modpack\") Loader.Progress = 0.6 '二次压缩整合包 - ZipFile.CreateFromDirectory(CacheFolder, PackPath) + FileUtils.CreateZipFromDirectory(PackPath, CacheFolder) Loader.Progress = 0.9 Else '直接压缩整合包 - ZipFile.CreateFromDirectory(CacheFolder & "modpack\", PackPath) + FileUtils.CreateZipFromDirectory(PackPath, CacheFolder & "modpack\") Loader.Progress = 0.8 End If - DeleteDirectory(CacheFolder, True) OpenExplorer(PackPath) End Sub) With {.ProgressWeight = 6}) diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceLeft.xaml.vb index b0d3654..7448c84 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceLeft.xaml.vb @@ -65,7 +65,7 @@ PageChangeRun(PageGet(ID)) PageID = ID Catch ex As Exception - Log(ex, "切换分页面失败(ID " & ID & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"切换分页面失败(ID {ID})") Finally AniControlEnabled -= 1 End Try diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceMod.xaml.vb b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceMod.xaml.vb index 7708fba..408e591 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceMod.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceMod.xaml.vb @@ -29,7 +29,7 @@ ''' Public Sub ReloadModList(Optional ForceReload As Boolean = False) If Not LoaderRun(If(ForceReload, LoaderFolderRunType.ForceRun, LoaderFolderRunType.RunOnUpdated)) Then Return - Log("[System] 已刷新 Mod 列表") + Logger.Info("已刷新 Mod 列表") Filter = FilterType.All PanBack.ScrollToHome() SearchBox.Text = "" @@ -42,10 +42,10 @@ Try ResourceProject.Cache.Clear() ResourceVersion.ProjectFilesCache.Clear() - File.Delete(PathTemp & "Cache\LocalMod.json") - Log("[Mod] 由于点击刷新按钮,清理本地 Mod 信息缓存") + FileUtils.Delete(PathTemp & "Cache\LocalMod.json") + Logger.Info("由于点击刷新按钮,清理本地 Mod 信息缓存") Catch ex As Exception - Log(ex, "强制刷新时清理本地 Mod 信息缓存失败") + Logger.Warn(ex, "强制刷新时清理本地 Mod 信息缓存失败") End Try If FrmInstanceMod IsNot Nothing Then FrmInstanceMod.ReloadModList(True) '无需 Else,还没加载刷个鬼的新 FrmInstanceLeft.ItemMod.Checked = True @@ -53,15 +53,13 @@ End Sub Private Sub LoaderInit() Handles Me.Initialized - PageLoaderInit(Load, PanLoad, PanAllBack, Nothing, McModLoader, AddressOf LoadUIFromLoaderOutput, AutoRun:=False) + PageLoaderInit(Load, PanLoad, PanAllBack, Nothing, LocalResourceLoader, AddressOf LoadUIFromLoaderOutput, AutoRun:=False) End Sub Private Sub Load_Click(sender As Object, e As MouseButtonEventArgs) Handles Load.Click - If McModLoader.State = LoadState.Failed Then - LoaderRun(LoaderFolderRunType.ForceRun) - End If + If LocalResourceLoader.State = LoadState.Failed Then LoaderRun(LoaderFolderRunType.ForceRun) End Sub Public Function LoaderRun(Type As LoaderFolderRunType) As Boolean - Return LoaderFolderRun(McModLoader, PageInstanceLeft.Instance.PathIndie & "mods\", Type) + Return LoaderFolderRun(LocalResourceLoader, PageInstanceLeft.Instance.PathIndie & "mods\", Type) End Function #End Region @@ -78,7 +76,7 @@ Private Sub LoadUIFromLoaderOutput() Try '判断应该显示哪一个页面 - If McModLoader.Output.Any() Then + If LocalResourceLoader.Output.Any() Then PanBack.Visibility = Visibility.Visible PanEmpty.Visibility = Visibility.Collapsed Else @@ -88,7 +86,7 @@ End If '修改缓存 ModItems.Clear() - For Each ModEntity As ResourceFile In McModLoader.Output + For Each ModEntity As LocalResourceFile In LocalResourceLoader.Output ModItems(ModEntity.EnabledName) = McModListItem(ModEntity) Next '显示结果 @@ -96,10 +94,10 @@ SearchBox.Text = "" '这会触发结果刷新,所以需要在 ModItems 更新之后,详见 #3124 的视频 RefreshUI() Catch ex As Exception - Log(ex, "加载 Mod 列表 UI 失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "加载 Mod 列表 UI 失败") End Try End Sub - Private Function McModListItem(Entry As ResourceFile) As MyLocalModItem + Private Function McModListItem(Entry As LocalResourceFile) As MyLocalModItem AniControlEnabled += 1 Dim NewItem As New MyLocalModItem With {.SnapsToDevicePixels = True, .Entry = Entry, .ButtonHandler = AddressOf McModContent, .Checked = SelectedMods.Contains(Entry.EnabledName)} @@ -145,7 +143,7 @@ ''' Public Sub RefreshUI() If PanList Is Nothing Then Return - Dim ShowingMods = If(IsSearching, SearchResult, If(McModLoader.Output, New List(Of ResourceFile))).Where(Function(m) CanPassFilter(m)).ToList + Dim ShowingMods = If(IsSearching, SearchResult, If(LocalResourceLoader.Output, New List(Of LocalResourceFile))).Where(Function(m) CanPassFilter(m)).ToList '重新列出列表 AniControlEnabled += 1 If ShowingMods.Any() Then @@ -178,7 +176,7 @@ Dim AnyCount As Integer = 0 Dim EnabledCount As Integer = 0 Dim UpdateCount As Integer = 0 - For Each ModItem In If(IsSearching, SearchResult, If(McModLoader.Output, New List(Of ResourceFile))) + For Each ModItem In If(IsSearching, SearchResult, If(LocalResourceLoader.Output, New List(Of LocalResourceFile))) AnyCount += 1 If ModItem.HasUpdate Then UpdateCount += 1 If ModItem.IsEnabled Then EnabledCount += 1 @@ -206,7 +204,7 @@ Dim HasUpdate As Boolean = False Dim HasEnabled As Boolean = False Dim HasDisabled As Boolean = False - For Each ModEntity In McModLoader.Output + For Each ModEntity In LocalResourceLoader.Output If Not SelectedMods.Contains(ModEntity.EnabledName) Then Continue For If ModEntity.HasUpdate Then HasUpdate = True If ModEntity.IsEnabled Then HasEnabled = True @@ -274,7 +272,7 @@ DirectoryUtils.Create(PageInstanceLeft.Instance.PathIndie & "mods\") OpenExplorer(PageInstanceLeft.Instance.PathIndie & "mods\") Catch ex As Exception - Log(ex, "打开 Mods 文件夹失败", NotifyLevel.MsgBox) + Logger.Error(ex, "打开 Mods 文件夹失败", LogBehavior.Alert) End Try End Sub @@ -289,7 +287,7 @@ ''' 安装 Mod。 ''' Private Sub BtnManageInstall_Click(sender As Object, e As MouseButtonEventArgs) Handles BtnManageInstall.Click, BtnHintInstall.Click - Dim FileList = SelectFiles("Mod 文件(*.jar;*.litemod;*.disabled;*.old)|*.jar;*.litemod;*.disabled;*.old", "选择要安装的 Mod") + Dim FileList = Dialogs.SelectFile("选择要安装的 Mod", True, filter:={({"jar", "litemod", "disabled", "old"}, "Mod 文件")}) If Not FileList.Any Then Return InstallMods(FileList) End Sub @@ -301,7 +299,7 @@ Dim Extension As String = FilePathList.First.AfterLast(".").Lower '检查文件扩展名 If Not {"jar", "litemod", "disabled", "old"}.Any(Function(t) t = Extension) Then Return False - Log("[System] 文件为 jar/litemod 格式,尝试作为 Mod 安装") + Logger.Info("文件为 jar/litemod 格式,尝试作为 Mod 安装") '检查回收站:回收站中的文件有错误的文件名 If FilePathList.First.Contains(":\$RECYCLE.BIN\") Then Hint("请先将文件从回收站还原,再尝试安装!", HintType.Red) @@ -321,21 +319,21 @@ Install: Try For Each ModFile In FilePathList - Dim NewFileName = GetFileNameFromPath(ModFile).Replace(".disabled", "").Replace(".old", "") + Dim NewFileName = PathUtils.GetLastPart(ModFile).Replace(".disabled", "").Replace(".old", "") If Not NewFileName.Contains(".") Then NewFileName += ".jar" '#4227 - CopyFile(ModFile, Instance.PathIndie & "mods\" & NewFileName) + FileUtils.Copy(ModFile, Instance.PathIndie & "mods\" & NewFileName) Next If FilePathList.IsSingle Then - Hint($"已安装 {GetFileNameFromPath(FilePathList.First).Replace(".disabled", "").Replace(".old", "")}!", HintType.Green) + Hint($"已安装 {PathUtils.GetLastPart(FilePathList.First).Replace(".disabled", "").Replace(".old", "")}!", HintType.Green) Else Hint($"已安装 {FilePathList.Count} 个 Mod!", HintType.Green) End If '刷新列表 If FrmMain.PageCurrent = FormMain.PageType.InstanceSetup AndAlso FrmMain.PageCurrentSub = FormMain.PageSubType.InstanceMod Then - LoaderFolderRun(McModLoader, Instance.PathIndie & "mods\", LoaderFolderRunType.ForceRun) + LoaderFolderRun(LocalResourceLoader, Instance.PathIndie & "mods\", LoaderFolderRunType.ForceRun) End If Catch ex As Exception - Log(ex, "复制 Mod 文件失败", NotifyLevel.MsgBox) + Logger.Error(ex, "复制 Mod 文件失败", LogBehavior.Alert) End Try End If Return True @@ -435,7 +433,7 @@ Install: ''' ''' 检查该 Mod 项是否符合当前筛选的类别。 ''' - Private Function CanPassFilter(CheckingMod As ResourceFile) As Boolean + Private Function CanPassFilter(CheckingMod As LocalResourceFile) As Boolean Select Case Filter Case FilterType.All Return True @@ -462,18 +460,18 @@ Install: '启用 / 禁用 Private Sub BtnSelectED_Click(sender As MyIconTextButton, e As RouteEventArgs) Handles BtnSelectEnable.Click, BtnSelectDisable.Click - EDMods(McModLoader.Output.Where(Function(m) SelectedMods.Contains(m.EnabledName)), + EDMods(LocalResourceLoader.Output.Where(Function(m) SelectedMods.Contains(m.EnabledName)), Not sender.Equals(BtnSelectDisable)) ChangeAllSelected(False) End Sub - Private Sub EDMods(ModList As IEnumerable(Of ResourceFile), IsEnable As Boolean) + Private Sub EDMods(ModList As IEnumerable(Of LocalResourceFile), IsEnable As Boolean) Dim IsSuccessful As Boolean = True For Each ModE In ModList.ToList Dim ModEntity = ModE '仅用于去除迭代变量无法修改的限制 Dim NewPath As String = Nothing If ModEntity.IsEnabled AndAlso Not IsEnable Then '禁用 - NewPath = ModEntity.File.FullName & If(File.Exists(ModEntity.File.FullName & ".old"), ".old", ".disabled") + NewPath = PathUtils.RemoveExtendedPrefix(ModEntity.File.FullName) & If(FileUtils.Exists(ModEntity.File.FullName & ".old"), ".old", ".disabled") ElseIf Not ModEntity.IsEnabled AndAlso IsEnable Then '启用 NewPath = ModEntity.EnabledFullName @@ -482,36 +480,36 @@ Install: End If '重命名 Try - If File.Exists(NewPath) Then - If File.Exists(ModEntity.File.FullName) Then + If FileUtils.Exists(NewPath) Then + If FileUtils.Exists(ModEntity.File.FullName) Then '同时存在两个名称的 Mod - If GetFileMD5(ModEntity.File.FullName) <> GetFileMD5(NewPath) Then - MyMsgBox($"目前同时存在启用和禁用的两个 Mod 文件:{vbCrLf} - {NewPath}{vbCrLf} - {ModEntity.File.FullName}{vbCrLf}{vbCrLf}注意,这两个文件的内容并不相同。{vbCrLf}在手动删除或重命名其中一个文件后,才能继续操作。", "存在文件冲突") + If HashUtils.ComputeFromFile(ModEntity.File.FullName, HashUtils.HashMethod.Md5) <> HashUtils.ComputeFromFile(NewPath, HashUtils.HashMethod.Md5) Then + MyMsgBox($"目前同时存在启用和禁用的两个 Mod 文件:{vbCrLf} - {PathUtils.GetLastPart(NewPath)}{vbCrLf} - {ModEntity.File.Name}{vbCrLf}{vbCrLf}注意,这两个文件的内容并不相同。{vbCrLf}在手动删除或重命名其中一个文件后,才能继续操作。", "存在文件冲突") Continue For End If Else '已经重命名过了 - Log("[Mod] Mod 的状态已被切换", NotifyLevel.DebugModeOnly) + Logger.Warn("Mod 的状态已被切换") Continue For End If End If - File.Delete(NewPath) - File.Move(ModEntity.File.FullName, NewPath) + FileUtils.Delete(NewPath) + FileUtils.Move(ModEntity.File.FullName, NewPath) Catch ex As FileNotFoundException - Log(ex, $"未找到需要重命名的 Mod({If(ModEntity.File.FullName, "null")})", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"未找到需要重命名的 Mod({If(ModEntity.File.FullName, "null")})") ReloadModList(True) Return Catch ex As Exception - Log(ex, $"重命名 Mod 失败({If(ModEntity.File.FullName, "null")})") + Logger.Warn(ex, $"重命名 Mod 失败({If(ModEntity.File.FullName, "null")})") IsSuccessful = False End Try '更改 Loader 中的列表 - Dim NewModEntity As New ResourceFile(NewPath) + Dim NewModEntity As New LocalResourceFile(NewPath) NewModEntity.FromJson(ModEntity.ToJson) - If McModLoader.Output.Contains(ModEntity) Then - Dim IndexOfLoader As Integer = McModLoader.Output.IndexOf(ModEntity) - McModLoader.Output.RemoveAt(IndexOfLoader) - McModLoader.Output.Insert(IndexOfLoader, NewModEntity) + If LocalResourceLoader.Output.Contains(ModEntity) Then + Dim IndexOfLoader As Integer = LocalResourceLoader.Output.IndexOf(ModEntity) + LocalResourceLoader.Output.RemoveAt(IndexOfLoader) + LocalResourceLoader.Output.Insert(IndexOfLoader, NewModEntity) End If If SearchResult IsNot Nothing AndAlso SearchResult.Contains(ModEntity) Then '#4862 Dim IndexOfResult As Integer = SearchResult.IndexOf(ModEntity) @@ -538,7 +536,7 @@ Install: '更新 Private Sub BtnSelectUpdate_Click() Handles BtnSelectUpdate.Click - Dim UpdateList As List(Of ResourceFile) = McModLoader.Output.Where(Function(m) SelectedMods.Contains(m.EnabledName) AndAlso m.HasUpdate).ToList() + Dim UpdateList As List(Of LocalResourceFile) = LocalResourceLoader.Output.Where(Function(m) SelectedMods.Contains(m.EnabledName) AndAlso m.HasUpdate).ToList() If Not UpdateList.Any() Then Return UpdateMods(UpdateList) ChangeAllSelected(False) @@ -547,9 +545,9 @@ Install: ''' 记录正在进行 Mod 更新的 mods 文件夹路径。 ''' Public Shared UpdatingInstanceModFolders As New List(Of String) - Public Sub UpdateMods(ModList As IEnumerable(Of ResourceFile)) + Public Sub UpdateMods(ModList As IEnumerable(Of LocalResourceFile)) '更新前警告 - If Not Settings.Get("HintUpdateMod") OrElse ModList.Count >= 15 Then + If Not Settings.Get(Of Boolean)("HintUpdateMod") OrElse ModList.Count >= 15 Then If MyMsgBox($"新版本 Mod 可能不兼容旧存档或者其他 Mod,这可能导致游戏崩溃,甚至永久损坏存档!{vbCrLf}如果你在游玩整合包,请千万不要自行更新 Mod!{vbCrLf}{vbCrLf}在更新前,请先备份存档,并检查 Mod 的更新日志。{vbCrLf}如果更新后出现问题,你也可以在回收站找回更新前的 Mod。", "Mod 更新警告", "我已了解风险,继续更新", "取消", IsWarn:=True) = 1 Then Settings.Set("HintUpdateMod", True) Else @@ -561,7 +559,7 @@ Install: ModList = ModList.ToList() '防止刷新影响迭代器 Dim FileList As New List(Of NetFile) Dim FileCopyList As New Dictionary(Of String, String) - For Each Entry As ResourceFile In ModList + For Each Entry As LocalResourceFile In ModList Dim File As ResourceVersion = Entry.UpdateFile If Not File.DownloadAvailable Then Continue For '确认更新后的文件名 @@ -590,8 +588,8 @@ Install: End If '添加到下载列表 Dim TempAddress As String = PathTemp & "mods\" & Entry.File.Name.Replace(CurrentReplaceName, NewestReplaceName) '需要下载到 mods 文件夹,以便重复文件检查时识别 - Dim RealAddress As String = GetPathFromFullPath(Entry.File.FullName) & Entry.File.Name.Replace(CurrentReplaceName, NewestReplaceName) - FileList.Add(File.ToNetFile(TempAddress)) + Dim RealAddress As String = Path.Combine(PathUtils.RemoveLastPart(Entry.File.FullName), Entry.File.Name.Replace(CurrentReplaceName, NewestReplaceName)) + FileList.Add(File.ToNetFile(TempAddress, ResourceVersion.DownloadReason.Update, PageInstanceLeft.Instance.Version.VanillaName, PageInstanceLeft.Instance.Version.ModLoaders)) FileCopyList(TempAddress) = RealAddress Next '构造加载器 @@ -601,31 +599,31 @@ Install: InstallLoaders.Add(New LoaderTask(Of Integer, Integer)("替换旧版 Mod 文件", Sub() Try - For Each Entry As ResourceFile In ModList - If File.Exists(Entry.File.FullName) Then - My.Computer.FileSystem.DeleteFile(Entry.File.FullName, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin) + For Each Entry As LocalResourceFile In ModList + If FileUtils.Exists(Entry.File.FullName) Then + FileUtils.Delete(Entry.File.FullName, True) Else - Log($"[Mod] 未找到更新前的 Mod 文件,跳过对它的删除:{Entry.File.FullName}", NotifyLevel.DebugModeOnly) + Logger.Warn($"未找到更新前的 Mod 文件,跳过对它的删除:{Entry.File.FullName}") End If Next For Each Entry As KeyValuePair(Of String, String) In FileCopyList - If File.Exists(Entry.Value) Then - My.Computer.FileSystem.DeleteFile(Entry.Value, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin) - Log($"[Mod] 更新后的 Mod 文件已存在,将会把它放入回收站:{Entry.Value}", NotifyLevel.DebugModeOnly) + If FileUtils.Exists(Entry.Value) Then + FileUtils.Delete(Entry.Value, True) + Logger.Warn($"更新后的 Mod 文件已存在,将会把它放入回收站:{Entry.Value}") End If - If Directory.Exists(GetPathFromFullPath(Entry.Value)) Then - File.Move(Entry.Key, Entry.Value) - FinishedFileNames.Add(GetFileNameFromPath(Entry.Value)) + If DirectoryUtils.Exists(PathUtils.RemoveLastPart(Entry.Value)) Then + FileUtils.Move(Entry.Key, Entry.Value) + FinishedFileNames.Add(PathUtils.GetLastPart(Entry.Value)) Else - Log($"[Mod] 更新后的目标文件夹已被删除:{Entry.Value}", NotifyLevel.DebugModeOnly) + Logger.Warn($"更新后的目标文件夹已被删除:{Entry.Value}") End If Next Catch ex As OperationCanceledException - Log(ex, "替换旧版 Mod 文件时被主动取消") + Logger.Warn(ex, "替换旧版 Mod 文件时被主动取消") End Try End Sub)) '结束处理 - Dim Loader As New LoaderCombo(Of IEnumerable(Of ResourceFile))("Mod 更新:" & PageInstanceLeft.Instance.Name, InstallLoaders) + Dim Loader As New LoaderCombo(Of IEnumerable(Of LocalResourceFile))("Mod 更新:" & PageInstanceLeft.Instance.Name, InstallLoaders) Dim PathMods As String = PageInstanceLeft.Instance.PathIndie & "mods\" Loader.OnStateChanged = Sub() @@ -634,35 +632,35 @@ Install: Case LoadState.Finished Select Case FinishedFileNames.Count Case 0 '一般是由于 Mod 文件被占用,然后玩家主动取消 - Log($"[Mod] 没有 Mod 被成功更新") + Logger.Info($"没有 Mod 被成功更新") Case 1 Hint($"已成功更新 {FinishedFileNames.Single}!", HintType.Green) Case Else Hint($"已成功更新 {FinishedFileNames.Count} 个 Mod!", HintType.Green) End Select Case LoadState.Failed - Hint("Mod 更新失败:" & Loader.Error.GetBrief(), HintType.Red) + Hint("Mod 更新失败:" & Loader.Error.GetDisplay(False), HintType.Red) Case LoadState.Interrupted Hint("Mod 更新已中止!", HintType.Blue) Case Else Return End Select - Log($"[Mod] 已从正在进行 Mod 更新的文件夹列表移除:{PathMods}") + Logger.Info($"已从正在进行 Mod 更新的文件夹列表移除:{PathMods}") UpdatingInstanceModFolders.Remove(PathMods) '清理缓存 RunInNewThread( Sub() Try For Each TempFile In FileCopyList.Keys - If File.Exists(TempFile) Then File.Delete(TempFile) + FileUtils.Delete(TempFile) Next Catch ex As Exception - Log(ex, "清理 Mod 更新缓存失败") + Logger.Warn(ex, "清理 Mod 更新缓存失败") End Try End Sub, "Clean Mod Update Cache", ThreadPriority.BelowNormal) End Sub '启动加载器 - Log($"[Mod] 开始更新 {ModList.Count} 个 Mod:{PathMods}") + Logger.Info($"开始更新 {ModList.Count} 个 Mod:{PathMods}") UpdatingInstanceModFolders.Add(PathMods) Loader.Start() LoaderTaskbarAdd(Loader) @@ -670,49 +668,45 @@ Install: FrmMain.BtnExtraDownload.Ribble() ReloadModList(True) Catch ex As Exception - Log(ex, "初始化 Mod 更新失败") + Logger.Warn(ex, "初始化 Mod 更新失败") End Try End Sub '删除 Private Sub BtnSelectDelete_Click() Handles BtnSelectDelete.Click - DeleteMods(McModLoader.Output.Where(Function(m) SelectedMods.Contains(m.EnabledName))) + DeleteMods(LocalResourceLoader.Output.Where(Function(m) SelectedMods.Contains(m.EnabledName))) ChangeAllSelected(False) End Sub - Private Sub DeleteMods(ModList As IEnumerable(Of ResourceFile)) + Private Sub DeleteMods(ModsToDelete As IEnumerable(Of LocalResourceFile)) Try Dim IsSuccessful As Boolean = True Dim IsShiftPressed As Boolean = My.Computer.Keyboard.ShiftKeyDown '确认需要删除的文件 - ModList = ModList.SelectMany( - Function(Target As ResourceFile) + Dim ModList = ModsToDelete.SelectMany( + Function(Target As LocalResourceFile) If Target.IsEnabled Then - Return {Target.File.FullName, Target.File.FullName & If(File.Exists(Target.File.FullName & ".old"), ".old", ".disabled")} + Return {Target.File.FullName, Target.File.FullName & If(FileUtils.Exists(Target.File.FullName & ".old"), ".old", ".disabled")} Else Return {Target.File.FullName, Target.EnabledFullName} End If - End Function).Distinct.Where(Function(m) File.Exists(m)).Select(Function(m) New ResourceFile(m)).ToList() + End Function).Distinct.Where(Function(m) FileUtils.Exists(m)).Select(Function(m) New LocalResourceFile(m)).ToList() '实际删除文件 For Each ModEntity In ModList '删除 Try - If IsShiftPressed Then - ModEntity.File.Delete() - Else - My.Computer.FileSystem.DeleteFile(ModEntity.File.FullName, FileIO.UIOption.OnlyErrorDialogs, FileIO.RecycleOption.SendToRecycleBin) - End If + FileUtils.Delete(ModEntity.File.FullName, Not IsShiftPressed) Catch ex As OperationCanceledException - Log(ex, "删除 Mod 被主动取消") + Logger.Warn(ex, "删除 Mod 被主动取消") ReloadModList(True) Return Catch ex As Exception - Log(ex, $"删除 Mod 失败({ModEntity.File.FullName})", NotifyLevel.MsgBox) + Logger.Error(ex, $"删除 Mod 失败({ModEntity.File.FullName})", LogBehavior.Alert) IsSuccessful = False End Try '取消选中 SelectedMods.Remove(ModEntity.EnabledName) '更改 Loader 和 UI 中的列表 - McModLoader.Output.Remove(ModEntity) + LocalResourceLoader.Output.Remove(ModEntity) SearchResult?.Remove(ModEntity) ModItems.Remove(ModEntity.EnabledName) Dim IndexOfUi As Integer = PanList.Children.IndexOf(PanList.Children.OfType(Of MyLocalModItem).FirstOrDefault(Function(i) i.Entry.Equals(ModEntity))) @@ -743,10 +737,10 @@ Install: End If End If Catch ex As OperationCanceledException - Log(ex, "删除 Mod 被主动取消") + Logger.Warn(ex, "删除 Mod 被主动取消") ReloadModList(True) Catch ex As Exception - Log(ex, "删除 Mod 出现未知错误", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "删除 Mod 出现未知错误") ReloadModList(True) End Try LoaderRun(LoaderFolderRunType.UpdateOnly) @@ -765,16 +759,12 @@ Install: Public Sub Info_Click(sender As Object, e As EventArgs) Try - Dim ModEntry As ResourceFile = CType(If(TypeOf sender Is MyIconButton, sender.Tag, sender), MyLocalModItem).Entry + Dim ModEntry As LocalResourceFile = CType(If(TypeOf sender Is MyIconButton, sender.Tag, sender), MyLocalModItem).Entry '加载失败信息 If ModEntry.Project IsNot Nothing Then '跳转到 Mod 下载页面 FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.ResourceDetail, - .Additional = {ModEntry.Project, New List(Of String), PageInstanceLeft.Instance.Version.VanillaName, - If(PageInstanceLeft.Instance.Version.HasForge, ModLoaderTypes.Forge, - If(PageInstanceLeft.Instance.Version.HasNeoForge, ModLoaderTypes.NeoForge, - If(PageInstanceLeft.Instance.Version.HasFabric, ModLoaderTypes.Fabric, ModLoaderTypes.Any))), - ResourceTypes.Mod}}) + .Additional = {ModEntry.Project, New List(Of String), PageInstanceLeft.Instance.Version.VanillaName, PageInstanceLeft.Instance.Version.ModLoaders, ResourceTypes.Mod}}) Else '获取信息 Dim ContentLines As New List(Of String) @@ -805,7 +795,7 @@ Install: End If End If Catch ex As Exception - Log(ex, "获取 Mod 详情失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "获取 Mod 详情失败") End Try End Sub '打开文件所在的位置 @@ -814,7 +804,7 @@ Install: Dim ListItem As MyLocalModItem = sender.Tag OpenExplorer(ListItem.Entry.File.FullName) Catch ex As Exception - Log(ex, "打开 Mod 文件位置失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "打开 Mod 文件位置失败") End Try End Sub '删除 @@ -837,12 +827,12 @@ Install: Return Not String.IsNullOrWhiteSpace(SearchBox.Text) End Get End Property - Private SearchResult As List(Of ResourceFile) + Private SearchResult As List(Of LocalResourceFile) Public Sub SearchRun() Handles SearchBox.TextChanged If IsSearching Then '构造请求 - Dim QueryList As New List(Of SearchEntry(Of ResourceFile)) - For Each Entry As ResourceFile In McModLoader.Output + Dim QueryList As New List(Of SearchEntry(Of LocalResourceFile)) + For Each Entry As LocalResourceFile In LocalResourceLoader.Output Dim SearchSources As New List(Of SearchSource) SearchSources.Add(New SearchSource(Entry.Display, 1)) SearchSources.Add(New SearchSource(Entry.File.Name, 1)) @@ -858,7 +848,7 @@ Install: If Entry.Project.Description <> Entry.Description Then SearchSources.Add(New SearchSource(Entry.Project.Description, 0.4)) SearchSources.Add(New SearchSource(String.Join("", Entry.Project.Tags), 0.2)) End If - QueryList.Add(New SearchEntry(Of ResourceFile) With {.Item = Entry, .SearchSource = SearchSources}) + QueryList.Add(New SearchEntry(Of LocalResourceFile) With {.Item = Entry, .SearchSource = SearchSources}) Next '进行搜索 SearchResult = Search(QueryList, SearchBox.Text, MaxBlurCount:=6, MinBlurSimilarity:=0.35).Select(Function(r) r.Item).ToList diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceModDisabled.xaml.vb b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceModDisabled.xaml.vb index 07f8f20..83c7128 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceModDisabled.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceModDisabled.xaml.vb @@ -9,7 +9,7 @@ End Sub Public Sub BtnDownload_Loaded() Handles BtnDownload.Loaded - Dim NewVisibility = If((Settings.Get("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow) OrElse If(FrmSelectRight Is Nothing, False, FrmSelectRight.ShowHidden), Visibility.Collapsed, Visibility.Visible) + Dim NewVisibility = If((Settings.Get(Of Boolean)("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow) OrElse If(FrmSelectRight Is Nothing, False, FrmSelectRight.ShowHidden), Visibility.Collapsed, Visibility.Visible) If BtnDownload.Visibility <> NewVisibility Then BtnDownload.Visibility = NewVisibility PanMain.TriggerForceResize() diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml.vb b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml.vb index 59f6f7b..173a216 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceOverall.xaml.vb @@ -65,13 +65,13 @@ WriteIni(McFolderSelected & "PCL.ini", "InstanceCache", "") '要求刷新缓存 LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\") Catch ex As Exception - Log(ex, "修改版本分类失败(" & PageInstanceLeft.Instance.Name & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"修改版本分类失败({PageInstanceLeft.Instance.Name})") End Try Reload() '更新 “打开 Mod 文件夹” 按钮 Else '改为隐藏 Try - If Not Settings.Get("HintHide") Then + If Not Settings.Get(Of Boolean)("HintHide") Then If MyMsgBox("确认要从版本列表中隐藏该版本吗?隐藏该版本后,它将不再出现于 PCL 显示的版本列表中。" & vbCrLf & "此后,在版本列表页面按下 F11 才可以查看被隐藏的版本。", "隐藏版本提示",, "取消") <> 1 Then ComboDisplayType.SelectedIndex = 0 Return @@ -82,7 +82,7 @@ WriteIni(McFolderSelected & "PCL.ini", "InstanceCache", "") '要求刷新缓存 LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\") Catch ex As Exception - Log(ex, "隐藏版本 " & PageInstanceLeft.Instance.Name & " 失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"隐藏版本 {PageInstanceLeft.Instance.Name} 失败") End Try End If End Sub @@ -97,7 +97,7 @@ Reload() LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\") Catch ex As Exception - Log(ex, "版本 " & PageInstanceLeft.Instance.Name & " 描述更改失败", NotifyLevel.MsgBox) + Logger.Error(ex, $"版本 {PageInstanceLeft.Instance.Name} 描述更改失败", LogBehavior.Alert) End Try End Sub @@ -109,51 +109,29 @@ Dim OldPath As String = PageInstanceLeft.Instance.PathVersion '修改此部分的同时修改快速安装的版本名检测* Dim NewName As String = MyMsgBoxInput("重命名版本", "", OldName, New ObjectModel.Collection(Of Validate) From { - New ValidateFolderName(McFolderSelected & "versions", IgnoreCase:=False), New ValidateExceptSame(OldName & "_temp", "不能使用该名称!")}) + New ValidateFolderName(McFolderSelected & "versions", IgnoreCase:=False)}) If String.IsNullOrWhiteSpace(NewName) Then Return Dim NewPath As String = McFolderSelected & "versions\" & NewName & "\" - '获取临时中间名,以防止仅修改大小写的重命名失败 - Dim TempName As String = NewName & "_temp" - Dim TempPath As String = McFolderSelected & "versions\" & TempName & "\" - Dim OnlyChangedCase As Boolean = NewName.Lower = OldName.Lower '重新读取版本 JSON 信息,避免 JsonObject 中已被合并的项被重新存储 Dim JsonObject As JObject Dim OldJsonPath As String = PageInstanceLeft.Instance.GetJsonPath() Try - JsonObject = GetJson(ReadFile(OldJsonPath)) + JsonObject = GetJson(FileUtils.ReadAsString(OldJsonPath)) Catch ex As Exception - Log(ex, "在重命名读取 json 时失败") + Logger.Warn(ex, "在重命名读取 json 时失败") JsonObject = PageInstanceLeft.Instance.JsonObject End Try '重命名主文件夹 - Directory.Move(OldPath, TempPath) - Directory.Move(TempPath, NewPath) + DirectoryUtils.Move(OldPath, NewPath) '清理 ini 缓存 - IniClearCache(PageInstanceLeft.Instance.PathIndie & "options.txt") - IniClearCache(PageInstanceLeft.Instance.PathVersion & "PCL\Setup.ini") + PageInstanceLeft.Instance.ResetIniCache() '重命名 jar 文件与 natives 文件夹 '不能进行遍历重命名,否则在版本名很短的时候容易误伤其他文件(#6443) - If Directory.Exists($"{NewPath}{OldName}-natives") Then - If OnlyChangedCase Then - Directory.Move($"{NewPath}{OldName}-natives", $"{NewPath}{OldName}natives_temp") - Directory.Move($"{NewPath}{OldName}-natives_temp", $"{NewPath}{NewName}-natives") - Else - DeleteDirectory($"{NewPath}{NewName}-natives") - Directory.Move($"{NewPath}{OldName}-natives", $"{NewPath}{NewName}-natives") - End If - End If - If File.Exists($"{NewPath}{OldName}.jar") Then - If OnlyChangedCase Then - File.Move($"{NewPath}{OldName}.jar", $"{NewPath}{OldName}_temp.jar") - File.Move($"{NewPath}{OldName}_temp.jar", $"{NewPath}{NewName}.jar") - Else - File.Delete($"{NewPath}{NewName}.jar") - File.Move($"{NewPath}{OldName}.jar", $"{NewPath}{NewName}.jar") - End If - End If + If DirectoryUtils.Exists($"{NewPath}{OldName}-natives") Then DirectoryUtils.Move($"{NewPath}{OldName}-natives", $"{NewPath}{NewName}-natives") + If FileUtils.Exists($"{NewPath}{OldName}.jar") Then FileUtils.Move($"{NewPath}{OldName}.jar", $"{NewPath}{NewName}.jar") '替换版本设置文件中的路径 - If File.Exists(NewPath & "PCL\Setup.ini") Then - FileUtils.Write(NewPath & "PCL\Setup.ini", ReadFile(NewPath & "PCL\Setup.ini").Replace(OldPath, NewPath)) + If FileUtils.Exists(NewPath & "PCL\Setup.ini") Then + FileUtils.Write(NewPath & "PCL\Setup.ini", FileUtils.ReadAsString(NewPath & "PCL\Setup.ini").Replace(OldPath, NewPath)) End If '更改已选中的版本 If ReadIni(McFolderSelected & "PCL.ini", "Version") = OldName Then @@ -162,10 +140,10 @@ '更新版本 Json Try JsonObject("id") = NewName + FileUtils.Delete(NewPath & PathUtils.GetLastPart(OldJsonPath)) FileUtils.Write(NewPath & NewName & ".json", JsonObject.ToString) - File.Delete(NewPath & GetFileNameFromPath(OldJsonPath)) Catch ex As Exception - Log(ex, "重命名版本 json 失败") + Logger.Warn(ex, "重命名版本 json 失败") End Try '刷新与提示 Hint("重命名成功!", HintType.Green) @@ -174,7 +152,7 @@ Reload() LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\") Catch ex As Exception - Log(ex, "重命名版本失败", NotifyLevel.MsgBox) + Logger.Error(ex, "重命名版本失败", LogBehavior.Alert) End Try End Sub @@ -184,17 +162,17 @@ '选择 自定义 时修改图片 Try If ComboDisplayLogo.SelectedItem Is ItemDisplayLogoCustom Then - Dim FileName As String = SelectFile("常用图片文件(*.png;*.jpeg;*.jpg;*.gif;*.webp)|*.png;*.jpeg;*.jpg;*.gif;*.webp", "选择图片") - If FileName = "" Then + Dim FileName As String = Dialogs.SelectFile("选择图片", False, filter:={({"png", "jpeg", "jpg", "gif", "webp"}, "常用图片文件")}).FirstOrDefault() + If String.IsNullOrEmpty(FileName) Then Reload() '还原选项 Return End If - CopyFile(FileName, PageInstanceLeft.Instance.PathVersion & "PCL\Logo.png") + FileUtils.Copy(FileName, PageInstanceLeft.Instance.PathVersion & "PCL\Logo.png") Else - File.Delete(PageInstanceLeft.Instance.PathVersion & "PCL\Logo.png") + FileUtils.Delete(PageInstanceLeft.Instance.PathVersion & "PCL\Logo.png") End If Catch ex As Exception - Log(ex, "更改自定义版本图标失败(" & PageInstanceLeft.Instance.Name & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"更改自定义版本图标失败({PageInstanceLeft.Instance.Name})") End Try '进行更改 Try @@ -207,7 +185,7 @@ Reload() LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\") Catch ex As Exception - Log(ex, "更改版本图标失败(" & PageInstanceLeft.Instance.Name & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"更改版本图标失败({PageInstanceLeft.Instance.Name})") End Try End Sub @@ -220,7 +198,7 @@ McInstanceListForceRefresh = True LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\") Catch ex As Exception - Log(ex, "版本 " & PageInstanceLeft.Instance.Name & " 收藏状态更改失败", NotifyLevel.MsgBox) + Logger.Error(ex, $"版本 {PageInstanceLeft.Instance.Name} 收藏状态更改失败", LogBehavior.Alert) End Try End Sub @@ -258,8 +236,8 @@ Private Sub BtnManageScript_Click() Handles BtnManageScript.Click Try '弹窗要求指定脚本的保存位置 - Dim SavePath As String = SelectSaveFile("选择脚本保存位置", "启动 " & PageInstanceLeft.Instance.Name & ".bat", "批处理文件(*.bat)|*.bat") - If SavePath = "" Then Return + Dim SavePath As String = Dialogs.SaveFile("选择脚本保存位置", "启动 " & PageInstanceLeft.Instance.Name & ".bat", filter:={("bat", "批处理文件")}) + If SavePath Is Nothing Then Return '检查中断(等玩家选完弹窗指不定任务就结束了呢……) If McLaunchLoader.State = LoadState.Loading Then Hint("请在当前启动任务结束后再试!", HintType.Red) @@ -267,14 +245,14 @@ End If '生成脚本 If McLaunchStart(New McLaunchOptions With {.SaveBatch = SavePath, .Instance = PageInstanceLeft.Instance}) Then - If Settings.Get("LoginType") = McLoginType.Legacy Then + If Settings.Get(Of McLoginType)("LoginType") = McLoginType.Legacy Then Hint("正在导出启动脚本……") Else Hint("正在导出启动脚本……(注意,使用脚本启动可能会导致登录失效!)") End If End If Catch ex As Exception - Log(ex, "导出启动脚本失败(" & PageInstanceLeft.Instance.Name & ")", NotifyLevel.MsgBox) + Logger.Error(ex, $"导出启动脚本失败({PageInstanceLeft.Instance.Name})", LogBehavior.Alert) End Try End Sub @@ -300,7 +278,7 @@ Case LoadState.Finished Hint(Loader.Name & "成功!", HintType.Green) Case LoadState.Failed - Hint(Loader.Name & "失败:" & Loader.Error.GetBrief(), HintType.Red) + Hint(Loader.Name & "失败:" & Loader.Error.GetDisplay(False), HintType.Red) Case LoadState.Interrupted Hint(Loader.Name & "已取消!", HintType.Blue) End Select @@ -310,7 +288,7 @@ FrmMain.BtnExtraDownload.ShowRefresh() FrmMain.BtnExtraDownload.Ribble() Catch ex As Exception - Log(ex, "尝试补全文件失败(" & PageInstanceLeft.Instance.Name & ")", NotifyLevel.MsgBox) + Logger.Error(ex, $"尝试补全文件失败({PageInstanceLeft.Instance.Name})", LogBehavior.Alert) End Try End Sub @@ -324,13 +302,8 @@ If(IsHintIndie, vbCrLf & "由于该版本开启了版本隔离,删除版本时该版本对应的存档、资源包、Mod 等文件也将被一并删除!", ""), "版本删除确认", , "取消",, IsHintIndie OrElse IsShiftPressed) Case 1 - IniClearCache(PageInstanceLeft.Instance.PathIndie & "options.txt") - IniClearCache(PageInstanceLeft.Instance.PathVersion & "PCL\Setup.ini") - If IsShiftPressed Then - DeleteDirectory(PageInstanceLeft.Instance.PathVersion) - Else - FileIO.FileSystem.DeleteDirectory(PageInstanceLeft.Instance.PathVersion, FileIO.UIOption.AllDialogs, FileIO.RecycleOption.SendToRecycleBin) - End If + PageInstanceLeft.Instance.ResetIniCache() + DirectoryUtils.Delete(PageInstanceLeft.Instance.PathVersion, Not IsShiftPressed) Hint("已删除版本 " & PageInstanceLeft.Instance.Name & "!", HintType.Green) Case 2 Return @@ -338,9 +311,9 @@ LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\") FrmMain.PageBack() Catch ex As OperationCanceledException - Log(ex, "删除版本 " & PageInstanceLeft.Instance.Name & " 被主动取消") + Logger.Warn(ex, $"删除版本 {PageInstanceLeft.Instance.Name} 被主动取消") Catch ex As Exception - Log(ex, "删除版本 " & PageInstanceLeft.Instance.Name & " 失败", NotifyLevel.MsgBox) + Logger.Error(ex, $"删除版本 {PageInstanceLeft.Instance.Name} 失败", LogBehavior.Alert) End Try End Sub diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml index f330262..f370b20 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml @@ -36,7 +36,7 @@ - + @@ -250,7 +250,7 @@ ToolTip="是否使用 Java Launch Wrapper 修复 Java 18- 在中文路径下可能无法正常启动的问题。 详见:https://github.com/00ll00/java_launch_wrapper" /> + ToolTip="是否使用 LWJGL Unsafe Agent 修复 LWJGL 3.4.1 的一个性能问题。 详见:https://github.com/HMCL-dev/lwjgl-unsafe-agent" /> diff --git a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.vb b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.vb index 9930e15..484ade2 100644 --- a/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageInstance/PageInstanceSetup.xaml.vb @@ -28,17 +28,17 @@ '启动参数 Dim _unused = PageInstanceLeft.Instance.PathIndie '触发自动判定 - ComboArgumentIndieV2.SelectedIndex = If(Settings.Get("VersionArgumentIndieV2", Instance:=PageInstanceLeft.Instance), 0, 1) + ComboArgumentIndieV2.SelectedIndex = If(Settings.Get(Of Boolean)("VersionArgumentIndieV2", Instance:=PageInstanceLeft.Instance), 0, 1) RefreshJavaComboBox() '服务器 - ComboServerLogin.SelectedIndex = Settings.Get("VersionServerLogin", Instance:=PageInstanceLeft.Instance) + ComboServerLogin.SelectedIndex = Settings.Get(Of Integer)("VersionServerLogin", Instance:=PageInstanceLeft.Instance) ComboServerLoginLast = ComboServerLogin.SelectedIndex UpdateServerLoginUI() '高级设置 - If Settings.Get("VersionAdvanceAssets", Instance:=PageInstanceLeft.Instance) = 2 Then - Log("[Setup] 已迁移老版本的关闭文件校验设置") + If Settings.Get(Of Integer)("VersionAdvanceAssets", Instance:=PageInstanceLeft.Instance) = 2 Then + Logger.Info("已迁移老版本的关闭文件校验设置") Settings.Reset("VersionAdvanceAssets", Instance:=PageInstanceLeft.Instance) Settings.Set("VersionAdvanceAssetsV2", True, Instance:=PageInstanceLeft.Instance) End If @@ -46,10 +46,10 @@ SettingService.RefreshSettings(Me) '游戏内存 - OnVersionRamTypeChanged(Settings.Get("VersionRamType", Instance:=PageInstanceLeft.Instance)) + OnVersionRamTypeChanged(Settings.Get(Of Integer)("VersionRamType", Instance:=PageInstanceLeft.Instance)) Catch ex As Exception - Log(ex, "重载版本独立设置时出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "重载版本独立设置时出错") End Try End Sub @@ -65,10 +65,10 @@ Settings.Reset("VersionArgumentJavaSelect", Instance:=PageInstanceLeft.Instance) JavaSearchLoader.Start(IsForceRestart:=True) - Log("[Setup] 已初始化版本独立设置") + Logger.Info("已初始化版本独立设置") Hint("已初始化版本独立设置!", HintType.Green, False) Catch ex As Exception - Log(ex, "初始化版本独立设置失败", NotifyLevel.MsgBox) + Logger.Error(ex, "初始化版本独立设置失败", LogBehavior.Alert) End Try Reload() @@ -219,7 +219,7 @@ ''' Public Shared Function GetRam(Instance As McInstance, Optional Is32BitJava As Boolean? = Nothing) As Double '跟随全局设置 - If Settings.Get("VersionRamType", Instance:=Instance) = 2 Then + If Settings.Get(Of Integer)("VersionRamType", Instance:=Instance) = 2 Then Return PageSetupLaunch.GetRam(Instance, True, Is32BitJava) End If @@ -229,7 +229,7 @@ '使用当前版本的设置 Dim RamGive As Double - If Settings.Get("VersionRamType", Instance:=Instance) = 0 Then + If Settings.Get(Of Integer)("VersionRamType", Instance:=Instance) = 0 Then '自动配置 Dim RamAvailable As Double = Math.Round(My.Computer.Info.AvailablePhysicalMemory / 1024 / 1024 / 1024 * 10) / 10 '确定需求的内存值 @@ -240,7 +240,7 @@ If Instance IsNot Nothing AndAlso Not Instance.IsLoaded Then Instance.Load() If Instance IsNot Nothing AndAlso Instance.Modable Then '可安装 Mod 的版本 - Dim ModDir As New DirectoryInfo(Instance.PathIndie & "mods\") + Dim ModDir = DirectoryUtils.GetInfo(Instance.PathIndie & "mods\") Dim ModCount As Integer = If(ModDir.Exists, ModDir.GetFiles.Count(Function(f) {".jar", ".zip", ".litemod"}.Contains(f.Extension.Lower)), 0) RamMininum = 0.5 + ModCount / 150 RamTarget1 = 1.5 + ModCount / 90 @@ -285,7 +285,7 @@ PreFin: RamGive = Math.Round(Math.Max(RamGive, RamMininum), 1) Else '手动配置 - Dim Value As Integer = Settings.Get("VersionRamCustom", Instance:=Instance) + Dim Value As Integer = Settings.Get(Of Integer)("VersionRamCustom", Instance:=Instance) If Value <= 12 Then RamGive = Value * 0.1 + 0.3 ElseIf Value <= 25 Then @@ -374,10 +374,10 @@ PreFin: '初始化列表 ComboArgumentJava.Items.Clear() ComboArgumentJava.Items.Add(New MyComboBoxItem With {.Content = "跟随全局设置", .Tag = "使用全局设置"}) - ComboArgumentJava.Items.Add(New MyComboBoxItem With {.Content = "自动选择合适的 Java", .Tag = "自动选择"}) + ComboArgumentJava.Items.Add(New MyComboBoxItem With {.Content = "自动选择(推荐)", .Tag = "自动选择"}) '更新列表 Dim SelectedItem As MyComboBoxItem = Nothing - Dim SelectedBySetup As String = Settings.Get("VersionArgumentJavaSelect", Instance:=PageInstanceLeft.Instance) + Dim SelectedBySetup As String = Settings.Get(Of String)("VersionArgumentJavaSelect", Instance:=PageInstanceLeft.Instance) Try For Each Java In JavaList.ToList().OrderByDescending(Function(v) v.MajorVersion) Dim ListItem = New MyComboBoxItem With {.Content = Java.ToString, .ToolTip = Java.PathFolder, .Tag = Java} @@ -389,7 +389,7 @@ PreFin: Next Catch ex As Exception Settings.Set("VersionArgumentJavaSelect", "使用全局设置", Instance:=PageInstanceLeft.Instance) - Log(ex, "更新版本设置 Java 下拉框失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "更新版本设置 Java 下拉框失败") End Try '更新选择项 If SelectedItem Is Nothing AndAlso JavaList.Any Then @@ -424,15 +424,15 @@ PreFin: If "使用全局设置".Equals(SelectedJava) Then '选择 “自动” Settings.Set("VersionArgumentJavaSelect", "使用全局设置", Instance:=PageInstanceLeft.Instance) - Log("[Java] 修改版本 Java 选择设置:跟随全局设置") + Logger.Info("修改版本 Java 选择设置:跟随全局设置") ElseIf "自动选择".Equals(SelectedJava) Then '选择 “自动” Settings.Set("VersionArgumentJavaSelect", "", Instance:=PageInstanceLeft.Instance) - Log("[Java] 修改版本 Java 选择设置:自动选择") + Logger.Info("修改版本 Java 选择设置:自动选择") Else '选择指定项 Settings.Set("VersionArgumentJavaSelect", CType(SelectedJava.ToJson(), JObject).ToString(Newtonsoft.Json.Formatting.None), Instance:=PageInstanceLeft.Instance) - Log("[Java] 修改版本 Java 选择设置:" & SelectedJava.ToString) + Logger.Info($"修改版本 Java 选择设置:{SelectedJava}") End If RefreshRam(True) End Sub diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb index 815a933..39a4f0f 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/MyMsgLogin.xaml.vb @@ -20,7 +20,7 @@ Data = Converter.Content Init() Catch ex As Exception - Log(ex, "登录弹窗初始化失败", NotifyLevel.AllUsers) + Logger.Error(ex, "登录弹窗初始化失败", LogBehavior.Toast) End Try End Sub @@ -35,9 +35,9 @@ AaDouble(Sub(i) TransformRotate.Angle += i, -TransformRotate.Angle, 300, 60, New AniEaseOutFluent(AniEasePower.Weak)) }, "MyMsgBox " & Uuid) '记录日志 - Log("[Control] 登录弹窗:" & LabTitle.Text & vbCrLf & LabCaption.Text) + Logger.Info($"登录弹窗:{LabTitle.Text}{vbCrLf}{LabCaption.Text}") Catch ex As Exception - Log(ex, "登录弹窗加载失败", NotifyLevel.AllUsers) + Logger.Error(ex, "登录弹窗加载失败", LogBehavior.Toast) End Try End Sub Private Sub Close() @@ -123,8 +123,8 @@ Return Catch ex As Exception '修改错误列表时,同时修改 ModLaunch.MsLoginStep1Refresh 中的对应代码 - If TypeOf ex Is ResponsedWebException Then - Dim Response = CType(ex, ResponsedWebException).Response + If TypeOf ex Is HttpRequestCodeException Then + Dim Response = CType(ex, HttpRequestCodeException).Response If Response.Contains("authorization_declined") Then Finished(New Exception("$你拒绝了 PCL 申请的权限……")) Return @@ -147,7 +147,7 @@ End If If UnknownFailureCount <= 2 Then UnknownFailureCount += 1 - Log(ex, $"登录轮询第 {UnknownFailureCount} 次失败") + Logger.Warn(ex, $"登录轮询第 {UnknownFailureCount} 次失败") Thread.Sleep(2000) Else Finished(New Exception("登录轮询失败", ex)) diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb index 36c928d..25af47c 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb @@ -14,7 +14,7 @@ ToolTip = If(_Address = "", "加载中", "点击更换皮肤(右键查看更多选项)") End Set End Property - Public Loader As LoaderTask(Of EqualableList(Of String), String) + Public Loader As LoaderTask(Of (String, String), String) '控件动画 Private Sub PanSkin_MouseEnter(sender As Object, e As MouseEventArgs) Handles Me.MouseEnter @@ -44,7 +44,7 @@ Public Sub BtnSkinSave_Click() Handles BtnSkinSave.Click Save(Loader) End Sub - Public Shared Sub Save(Loader As LoaderTask(Of EqualableList(Of String), String)) + Public Shared Sub Save(Loader As LoaderTask(Of (String, String), String)) Dim Address = Loader.Output If Not Loader.State = LoadState.Finished Then Hint("皮肤正在获取中,请稍候!", HintType.Red) @@ -52,19 +52,20 @@ Return End If Try - Dim FileAddress As String = SelectSaveFile("选取保存皮肤的位置", GetFileNameFromPath(Address), "皮肤图片文件(*.png)|*.png") + Dim FileAddress As String = Dialogs.SaveFile("选取保存皮肤的位置", PathUtils.GetLastPart(Address), filter:={("png", "皮肤图片文件")}) + If FileAddress Is Nothing Then Return If FileAddress.Contains("\") Then - File.Delete(FileAddress) + FileUtils.Delete(FileAddress) If Address.StartsWithF(PathImage) Then Dim Image As New MyBitmap(Address) Image.Save(FileAddress) Else - CopyFile(Address, FileAddress) + FileUtils.Copy(Address, FileAddress) End If Hint("皮肤保存成功!", HintType.Green) End If Catch ex As Exception - Log(ex, "保存皮肤失败", NotifyLevel.AllUsers) + Logger.Error(ex, "保存皮肤失败", LogBehavior.Toast) End Try End Sub Private Sub BtnSkinSave_Checked(sender As MyMenuItem, e As RoutedEventArgs) Handles BtnSkinSave.Checked @@ -79,14 +80,14 @@ '检查文件存在 Address = Loader.Output If String.IsNullOrEmpty(Address) Then Throw New Exception("皮肤加载器 " & Loader.Name & " 没有输出") - If Not Address.StartsWithF(PathImage) AndAlso Not File.Exists(Address) Then Throw New FileNotFoundException("皮肤文件未找到", Address) + If Not Address.StartsWithF(PathImage) AndAlso Not FileUtils.Exists(Address) Then Throw New FileNotFoundException("皮肤文件未找到", Address) '加载 Dim Image As MyBitmap Try Image = New MyBitmap(Address) Catch ex As Exception '#2272 - Log(ex, $"皮肤文件已损坏:{Address}", NotifyLevel.AllUsers) - File.Delete(Address) + Logger.Error(ex, $"皮肤文件已损坏:{Address}", LogBehavior.Toast) + FileUtils.Delete(Address) Return End Try ImgBack.Tag = Address @@ -113,9 +114,9 @@ End If '脸层 ImgBack.Source = Image.Clip(Scale * 8, Scale * 8, Scale * 8, Scale * 8) - Log("[Skin] 载入头像成功:" & Loader.Name) + Logger.Info($"载入头像成功:{Loader.Name}") Catch ex As Exception - Log(ex, "载入头像失败(" & If(Address, "null") & "," & Loader.Name & ")", NotifyLevel.AllUsers) + Logger.Error(ex, $"载入头像失败({If(Address, "null")},{Loader.Name})", LogBehavior.Toast) End Try End Sub ''' @@ -134,7 +135,7 @@ ''' ''' 刷新皮肤缓存。 ''' - Public Shared Sub RefreshCache(Optional sender As LoaderTask(Of EqualableList(Of String), String) = Nothing) + Public Shared Sub RefreshCache(Optional sender As LoaderTask(Of (String, String), String) = Nothing) Dim HasLoaderRunning As Boolean = False For Each SkinLoader In PageLaunchLeft.SkinLoaders If SkinLoader.State = LoadState.Loading Then @@ -150,9 +151,9 @@ Try Hint("正在刷新头像……") '清空缓存 - Log("[Skin] 正在清空皮肤缓存") - If Directory.Exists(PathTemp & "Cache\Skin") Then DeleteDirectory(PathTemp & "Cache\Skin") - If Directory.Exists(PathTemp & "Cache\Uuid") Then DeleteDirectory(PathTemp & "Cache\Uuid") + Logger.Info("正在清空皮肤缓存") + If DirectoryUtils.Exists(PathTemp & "Cache\Skin") Then DirectoryUtils.Delete(PathTemp & "Cache\Skin") + If DirectoryUtils.Exists(PathTemp & "Cache\Uuid") Then DirectoryUtils.Delete(PathTemp & "Cache\Uuid") IniClearCache(PathTemp & "Cache\Skin\IndexMs.ini") IniClearCache(PathTemp & "Cache\Skin\IndexNide.ini") IniClearCache(PathTemp & "Cache\Skin\IndexAuth.ini") @@ -163,7 +164,7 @@ Next Hint("已刷新头像!", HintType.Green) Catch ex As Exception - Log(ex, "刷新皮肤缓存失败", NotifyLevel.MsgBox) + Logger.Error(ex, "刷新皮肤缓存失败", LogBehavior.Alert) End Try End Sub) End If @@ -177,8 +178,8 @@ Sub() Try '更新缓存 - WriteIni(PathTemp & "Cache\Skin\IndexMs.ini", Settings.Get("CacheMsV2Uuid"), SkinAddress) - Log($"[Skin] 已写入皮肤地址缓存 {Settings.Get("CacheMsV2Uuid")} -> {SkinAddress}") + WriteIni(PathTemp & "Cache\Skin\IndexMs.ini", Settings.Get(Of String)("CacheMsV2Uuid"), SkinAddress) + Logger.Info($"已写入皮肤地址缓存 {Settings.Get(Of String)("CacheMsV2Uuid")} -> {SkinAddress}") '刷新控件 For Each SkinLoader In {PageLaunchLeft.SkinMs, PageLaunchLeft.SkinLegacy} SkinLoader.WaitForExit(IsForceRestart:=True) @@ -186,7 +187,7 @@ '完成提示 Hint("更改皮肤成功!", HintType.Green) Catch ex As Exception - Log(ex, "更改正版皮肤后刷新皮肤失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "更改正版皮肤后刷新皮肤失败") End Try End Sub) End Sub @@ -255,7 +256,7 @@ Retry: Next SelectedIndex = MyMsgBoxSelect(SelectionControl, "选择披风", "确定", "取消") Catch ex As Exception - Log(ex, "获取玩家皮肤列表失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "获取玩家皮肤列表失败") End Try End Sub) If SelectedIndex Is Nothing Then Return @@ -278,7 +279,7 @@ Retry: McLoginMsLoader.Output.ProfileJson = SkinData.ToString() End If Catch ex As Exception - Log(ex, "更改披风失败", NotifyLevel.AllUsers) + Logger.Error(ex, "更改披风失败", LogBehavior.Toast) Finally IsChanging = False End Try diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb index 9d75b37..4cc0d20 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchLeft.xaml.vb @@ -23,39 +23,39 @@ Sub() '自动整合包安装:准备 Dim PackInstallPath As String = Nothing - If File.Exists(PathExeFolder & "modpack.zip") Then PackInstallPath = PathExeFolder & "modpack.zip" - If File.Exists(PathExeFolder & "modpack.mrpack") Then PackInstallPath = PathExeFolder & "modpack.mrpack" + If FileUtils.Exists(PathExeFolder & "modpack.zip") Then PackInstallPath = PathExeFolder & "modpack.zip" + If FileUtils.Exists(PathExeFolder & "modpack.mrpack") Then PackInstallPath = PathExeFolder & "modpack.mrpack" If PackInstallPath IsNot Nothing Then - Log("[Launch] 需自动安装整合包:" & PackInstallPath, NotifyLevel.DebugModeOnly) + Logger.Warn($"需自动安装整合包:{PackInstallPath}") PageSelectLeft.CreateMcFolderInCurrentPath() McFolderListLoader.WaitForExit() End If '确认 Minecraft 文件夹存在 - If McFolderSelected = "" OrElse Not Directory.Exists(McFolderSelected) Then + If McFolderSelected = "" OrElse Not DirectoryUtils.Exists(McFolderSelected) Then '无效的文件夹 If McFolderSelected = "" Then - Log("[Launch] 没有已储存的 Minecraft 文件夹") + Logger.Info("没有已储存的 Minecraft 文件夹") Else - Log("[Launch] Minecraft 文件夹无效,该文件夹已不存在:" & McFolderSelected, NotifyLevel.DebugModeOnly) + Logger.Warn($"Minecraft 文件夹无效,该文件夹已不存在:{McFolderSelected}") End If McFolderListLoader.WaitForExit(IsForceRestart:=True) McFolderSelected = McFolderList.First.Location End If - If Settings.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(500, 3000)) + If Settings.Get(Of Boolean)("SystemDebugDelay") Then Thread.Sleep(RandomInteger(500, 3000)) '自动整合包安装 If PackInstallPath IsNot Nothing Then Try Dim InstallLoader = ModpackInstall(PackInstallPath) - Log("[Launch] 自动安装整合包已开始:" & PackInstallPath) + Logger.Info($"自动安装整合包已开始:{PackInstallPath}") InstallLoader.WaitForExit() If InstallLoader.State = LoadState.Finished Then - Log("[Launch] 自动安装整合包成功,清理安装包:" & PackInstallPath) - If File.Exists(PackInstallPath) Then File.Delete(PackInstallPath) + Logger.Info($"自动安装整合包成功,清理安装包:{PackInstallPath}") + FileUtils.Delete(PackInstallPath) End If Catch ex As CancelledException - Log(ex, "自动安装整合包被用户取消:" & PackInstallPath) + Logger.Warn(ex, $"自动安装整合包被用户取消:{PackInstallPath}") Catch ex As Exception - Log(ex, "自动安装整合包失败:" & PackInstallPath, NotifyLevel.MsgBox) + Logger.Error(ex, $"自动安装整合包失败:{PackInstallPath}", LogBehavior.Alert) End Try End If '确认 Minecraft 版本存在 @@ -63,14 +63,14 @@ Dim Instance As McInstance = If(Selection = "", Nothing, New McInstance(Selection)) If Instance Is Nothing OrElse Not Instance.PathVersion.StartsWithF(McFolderSelected) OrElse Not Instance.Check() Then '无效的版本 - Log("[Launch] 当前选择的 Minecraft 版本无效:" & If(Instance Is Nothing, "null", Instance.PathVersion), If(IsNothing(Instance), NotifyLevel.Silent, NotifyLevel.DebugModeOnly)) + Logger.Info($"当前选择的 Minecraft 版本无效:{If(Instance Is Nothing, "null", Instance.PathVersion)}", If(IsNothing(Instance), LogBehavior.None, LogBehavior.ToastIfDebug)) If Not McInstanceListLoader.State = LoadState.Finished Then LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\", WaitForExit:=True) If Not McInstanceList.Any() OrElse McInstanceList.First.Value(0).Logo.Contains("RedstoneBlock") Then Instance = Nothing - Log("[Launch] 无可用 Minecraft 版本") + Logger.Info("无可用 Minecraft 版本") Else Instance = McInstanceList.First.Value(0) - Log("[Launch] 自动选择 Minecraft 版本:" & Instance.PathVersion) + Logger.Info($"自动选择 Minecraft 版本:{Instance.PathVersion}") End If End If RunInUi( @@ -85,7 +85,7 @@ End Sub, "Version Check", ThreadPriority.AboveNormal) '改变页面 - Dim LoginType As McLoginType = Settings.Get("LoginType") + Dim LoginType = Settings.Get(Of McLoginType)("LoginType") If LoginType = McLoginType.Legacy OrElse LoginType = McLoginType.Ms Then CType(FindName("RadioLoginType" & LoginType), MyRadioButton).Checked = True RefreshPage(False, False) @@ -99,7 +99,7 @@ ''' Public Sub PageChangeToLaunching() '修改登陆方式 - Select Case Settings.Get("LoginType") + Select Case Settings.Get(Of McLoginType)("LoginType") Case McLoginType.Legacy LabLaunchingMethod.Text = "离线登录" Case McLoginType.Ms @@ -257,7 +257,7 @@ PageCurrent = Type Return PageNew Catch ex As Exception - Log(ex, "切换登录分页失败(" & GetStringFromEnum(CType(Type, [Enum])) & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"切换登录分页失败({Type})") Return PageNew End Try End Function @@ -270,17 +270,17 @@ Dim Type As PageType Dim LoginPageType As Integer If McInstanceSelected IsNot Nothing Then - LoginPageType = Settings.Get("VersionServerLogin", Instance:=McInstanceSelected) + LoginPageType = Settings.Get(Of Integer)("VersionServerLogin", Instance:=McInstanceSelected) '缓存当前版本的页面种类,下一次打开 McInstanceSelected 为空时才能加载出正确的页面 Settings.Set("LoginPageType", LoginPageType) Else - LoginPageType = Settings.Get("LoginPageType") + LoginPageType = Settings.Get(Of Integer)("LoginPageType") End If Select Case LoginPageType Case 0 '正版或离线 UnknownType: If RadioLoginType5.Checked Then - If Settings.Get("CacheMsV2Access") = "" Then + If Settings.Get(Of String)("CacheMsV2Access") = "" Then Type = PageType.Ms Else Type = PageType.MsSkin @@ -295,7 +295,7 @@ UnknownType: RadioLoginType5.Visibility = Visibility.Visible RadioLoginType0.Visibility = Visibility.Visible Case 1 '仅正版 - If Settings.Get("CacheMsV2Access") = "" Then + If Settings.Get(Of String)("CacheMsV2Access") = "" Then Type = PageType.Ms Else Type = PageType.MsSkin @@ -315,7 +315,7 @@ UnknownType: PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonOffline) LabTypeOne.Text = "离线登录" Case 3 '统一通行证 - If Settings.Get("CacheNideAccess") = "" Then + If Settings.Get(Of String)("CacheNideAccess") = "" Then Type = PageType.Nide Else Type = PageType.NideSkin @@ -326,7 +326,7 @@ UnknownType: PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonCard) LabTypeOne.Text = "统一通行证登录" Case 4 'Authlib-Injector - If Settings.Get("CacheAuthAccess") = "" Then + If Settings.Get(Of String)("CacheAuthAccess") = "" Then Type = PageType.Auth Else Type = PageType.AuthSkin @@ -335,16 +335,16 @@ UnknownType: PanType.Visibility = Visibility.Collapsed PanTypeOne.Visibility = Visibility.Visible PathTypeOne.Data = (New GeometryConverter).ConvertFromString(Logo.IconButtonCard) - LabTypeOne.Text = If(McInstanceSelected Is Nothing, Settings.Get("CacheAuthServerName"), Settings.Get("VersionServerAuthName", Instance:=McInstanceSelected)) + LabTypeOne.Text = If(McInstanceSelected Is Nothing, Settings.Get(Of String)("CacheAuthServerName"), Settings.Get(Of String)("VersionServerAuthName", Instance:=McInstanceSelected)) If LabTypeOne.Text = "" Then LabTypeOne.Text = "第三方登录" Case Else - Log("[Control] 未知的登录页面:" & LoginPageType, NotifyLevel.AllUsers) + Logger.Error($"未知的登录页面:{LoginPageType}", LogBehavior.Toast) GoTo UnknownType End Select '刷新页面 If PageCurrent = Type Then Return PageChange(Type, Anim).Reload(KeepInput) - Dim Control As MyRadioButton = FindName("RadioLoginType" & Settings.Get("LoginType")) + Dim Control As MyRadioButton = FindName("RadioLoginType" & Settings.Get(Of McLoginType)("LoginType")) If Control IsNot Nothing Then Control.Checked = True End Sub Private Sub RadioLoginType_Change(sender As Object, raiseByMouse As Boolean) Handles RadioLoginType0.Check, RadioLoginType5.Check @@ -356,21 +356,21 @@ UnknownType: #Region "皮肤" '微软正版皮肤 - Public Shared SkinMs As New LoaderTask(Of EqualableList(Of String), String)("Loader Skin Ms", AddressOf SkinMsLoad, AddressOf SkinMsInput, ThreadPriority.AboveNormal) - Private Shared Function SkinMsInput() As EqualableList(Of String) + Public Shared SkinMs As New LoaderTask(Of (String, String), String)("Loader Skin Ms", AddressOf SkinMsLoad, AddressOf SkinMsInput, ThreadPriority.AboveNormal) + Private Shared Function SkinMsInput() As (String, String) '获取名称 - Return New EqualableList(Of String) From {Settings.Get("CacheMsV2Name"), Settings.Get("CacheMsV2Uuid")} + Return (Settings.Get(Of String)("CacheMsV2Name"), Settings.Get(Of String)("CacheMsV2Uuid")) End Function - Private Shared Sub SkinMsLoad(Data As LoaderTask(Of EqualableList(Of String), String)) + Private Shared Sub SkinMsLoad(Data As LoaderTask(Of (String, String), String)) '清空已有皮肤 '如果在输入时清空皮肤,若输入内容一样则不会执行 Load 方法,导致皮肤不被加载 RunInUi(Sub() If FrmLoginMsSkin IsNot Nothing AndAlso FrmLoginMsSkin.Skin IsNot Nothing Then FrmLoginMsSkin.Skin.Clear()) '获取 Url - Dim UserName As String = Data.Input(0) - Dim Uuid As String = Data.Input(1) + Dim UserName As String = Data.Input.Item1 + Dim Uuid As String = Data.Input.Item2 If UserName = "" Then Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png" - Log("[Minecraft] 获取微软正版皮肤失败,ID 为空") + Logger.Info("获取微软正版皮肤失败,ID 为空") GoTo Finish End If Try @@ -383,15 +383,15 @@ UnknownType: Data.Output = "" Return Catch ex As Exception - If ex.GetBrief.Contains("(429)") Then + If ex.GetDisplay(False).Contains("(429)") Then Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png" - Log("[Minecraft] 获取正版皮肤失败(" & UserName & "):获取皮肤太过频繁,请 5 分钟后再试!", NotifyLevel.AllUsers) - ElseIf ex.GetBrief.Contains("未设置自定义皮肤") Then + Logger.Error($"获取正版皮肤失败({UserName}):获取皮肤太过频繁,请 5 分钟后再试!", LogBehavior.Toast) + ElseIf ex.GetDisplay(False).Contains("未设置自定义皮肤") Then Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png" - Log("[Minecraft] 用户未设置自定义皮肤,跳过皮肤加载") + Logger.Info("用户未设置自定义皮肤,跳过皮肤加载") Else Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png" - Log(ex, "获取微软正版皮肤失败(" & UserName & ")", NotifyLevel.AllUsers) + Logger.Error(ex, $"获取微软正版皮肤失败({UserName})", LogBehavior.Toast) End If End Try Finish: @@ -404,39 +404,39 @@ Finish: End Sub '离线皮肤 - Public Shared SkinLegacy As New LoaderTask(Of EqualableList(Of String), String)("Loader Skin Legacy", AddressOf SkinLegacyLoad, AddressOf SkinLegacyInput, ThreadPriority.AboveNormal) - Private Shared Function SkinLegacyInput() As EqualableList(Of String) + Public Shared SkinLegacy As New LoaderTask(Of (String, String), String)("Loader Skin Legacy", AddressOf SkinLegacyLoad, AddressOf SkinLegacyInput, ThreadPriority.AboveNormal) + Private Shared Function SkinLegacyInput() As (String, String) '根据类型判断输入 - Dim Type As Integer = Settings.Get("LaunchSkinType") + Dim Type As Integer = Settings.Get(Of Integer)("LaunchSkinType") Select Case Type Case 0 - If FrmLoginLegacy IsNot Nothing AndAlso FrmLoginLegacy.IsReloaded Then - Return New EqualableList(Of String) From {0, If(FrmLoginLegacy.ComboName.Text.Trim, "")} - ElseIf Settings.Get("LoginLegacyName") = "" Then - Return New EqualableList(Of String) From {0, ""} + If FrmLoginLegacy?.IsReloaded Then + Return ("0", If(FrmLoginLegacy.ComboName.Text.Trim, "")) + ElseIf Settings.Get(Of String)("LoginLegacyName") = "" Then + Return ("0", "") Else - Return New EqualableList(Of String) From {0, If(Settings.Get("LoginLegacyName").ToString.BeforeFirst("¨"), "")} + Return ("0", If(Settings.Get(Of String)("LoginLegacyName").ToString.BeforeFirst("¨"), "")) End If Case 3 - Return New EqualableList(Of String) From {3, Settings.Get("LaunchSkinID")} + Return ("3", Settings.Get(Of String)("LaunchSkinID")) Case Else - Return New EqualableList(Of String) From {Type} + Return (Type.ToString, "") End Select End Function - Private Shared Sub SkinLegacyLoad(Data As LoaderTask(Of EqualableList(Of String), String)) + Private Shared Sub SkinLegacyLoad(Data As LoaderTask(Of (String, String), String)) '清空已有皮肤 RunInUi(Sub() If FrmLoginLegacy IsNot Nothing AndAlso FrmLoginLegacy.Skin IsNot Nothing Then FrmLoginLegacy.Skin.Clear()) '获取 Url - Select Case Data.Input(0) + Select Case CInt(Data.Input.Item1) Case 0 '默认 - Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(Data.Input(1))) & ".png" + Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(Data.Input.Item2)) & ".png" Case 1 'Steve UseDefault: Data.Output = PathImage & "Skins/Steve.png" Case 2 'Alex Data.Output = PathImage & "Skins/Alex.png" Case 3 '正版 - Dim ID As String = Data.Input(1) + Dim ID As String = Data.Input.Item2 Try If ID.Count < 2 Then Data.Output = PathImage & "Skins/Steve.png" @@ -453,16 +453,16 @@ UseDefault: Data.Output = "" Return Catch ex As Exception - If ex.GetBrief.Contains("(429)") Then + If ex.GetDisplay(False).Contains("(429)") Then Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(ID)) & ".png" - Log("获取离线登录使用的正版皮肤失败(" & ID & "):获取皮肤太过频繁,请 5 分钟后再试!") + Logger.Info($"获取离线登录使用的正版皮肤失败({ID}):获取皮肤太过频繁,请 5 分钟后再试!") Else Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(ID)) & ".png" - Log(ex, "获取离线登录使用的正版皮肤失败(" & ID & ")") + Logger.Warn(ex, $"获取离线登录使用的正版皮肤失败({ID})") End If End Try Case 4 '自定义 - If Not File.Exists(PathAppdata & "CustomSkin.png") Then + If Not FileUtils.Exists(PathAppdata & "CustomSkin.png") Then Hint("未找到离线皮肤自定义文件,可能它已被删除。PCL 将使用默认的 Steve 皮肤!") Settings.Set("LaunchSkinType", 1) GoTo UseDefault @@ -478,21 +478,21 @@ UseDefault: End Sub '统一通行证皮肤 - Public Shared SkinNide As New LoaderTask(Of EqualableList(Of String), String)("Loader Skin Nide", AddressOf SkinNideLoad, AddressOf SkinNideInput, ThreadPriority.AboveNormal) - Private Shared Function SkinNideInput() As EqualableList(Of String) + Public Shared SkinNide As New LoaderTask(Of (String, String), String)("Loader Skin Nide", AddressOf SkinNideLoad, AddressOf SkinNideInput, ThreadPriority.AboveNormal) + Private Shared Function SkinNideInput() As (String, String) '获取名称 - Return New EqualableList(Of String) From {Settings.Get("CacheNideName"), Settings.Get("CacheNideUuid")} + Return (Settings.Get(Of String)("CacheNideName"), Settings.Get(Of String)("CacheNideUuid")) End Function - Private Shared Sub SkinNideLoad(Data As LoaderTask(Of EqualableList(Of String), String)) + Private Shared Sub SkinNideLoad(Data As LoaderTask(Of (String, String), String)) '清空已有皮肤 '如果在输入时清空皮肤,若输入内容一样则不会执行 Load 方法,导致皮肤不被加载 RunInUi(Sub() If FrmLoginNideSkin IsNot Nothing AndAlso FrmLoginNideSkin.Skin IsNot Nothing Then FrmLoginNideSkin.Skin.Clear()) '获取 Url - Dim UserName As String = Data.Input(0) - Dim Uuid As String = Data.Input(1) + Dim UserName As String = Data.Input.Item1 + Dim Uuid As String = Data.Input.Item2 If UserName = "" Then Data.Output = PathImage & "Skins/" & McSkinSex(McLoginLegacyUuid(UserName)) & ".png" - Log("[Minecraft] 获取统一通行证皮肤失败,ID 为空") + Logger.Info("获取统一通行证皮肤失败,ID 为空") GoTo Finish End If Try @@ -505,15 +505,15 @@ UseDefault: Data.Output = "" Return Catch ex As Exception - If ex.GetBrief.Contains("(429)") Then + If ex.GetDisplay(False).Contains("(429)") Then Data.Output = PathImage & "Skins/Steve.png" - Log("[Minecraft] 获取统一通行证皮肤失败(" & UserName & "):获取皮肤太过频繁,请 5 分钟后再试!", NotifyLevel.AllUsers) - ElseIf ex.GetBrief.Contains("未设置自定义皮肤") Then + Logger.Error($"获取统一通行证皮肤失败({UserName}):获取皮肤太过频繁,请 5 分钟后再试!", LogBehavior.Toast) + ElseIf ex.GetDisplay(False).Contains("未设置自定义皮肤") Then Data.Output = PathImage & "Skins/Steve.png" - Log("[Minecraft] 用户未设置自定义皮肤,跳过皮肤加载") + Logger.Info("用户未设置自定义皮肤,跳过皮肤加载") Else Data.Output = PathImage & "Skins/Steve.png" - Log(ex, "获取统一通行证皮肤失败(" & UserName & ")", NotifyLevel.AllUsers) + Logger.Error(ex, $"获取统一通行证皮肤失败({UserName})", LogBehavior.Toast) End If End Try Finish: @@ -526,21 +526,21 @@ Finish: End Sub 'Authlib-Injector 皮肤 - Public Shared SkinAuth As New LoaderTask(Of EqualableList(Of String), String)("Loader Skin Auth", AddressOf SkinAuthLoad, AddressOf SkinAuthInput, ThreadPriority.AboveNormal) - Private Shared Function SkinAuthInput() As EqualableList(Of String) + Public Shared SkinAuth As New LoaderTask(Of (String, String), String)("Loader Skin Auth", AddressOf SkinAuthLoad, AddressOf SkinAuthInput, ThreadPriority.AboveNormal) + Private Shared Function SkinAuthInput() As (String, String) '获取名称 - Return New EqualableList(Of String) From {Settings.Get("CacheAuthName"), Settings.Get("CacheAuthUuid")} + Return (Settings.Get(Of String)("CacheAuthName"), Settings.Get(Of String)("CacheAuthUuid")) End Function - Private Shared Sub SkinAuthLoad(Data As LoaderTask(Of EqualableList(Of String), String)) + Private Shared Sub SkinAuthLoad(Data As LoaderTask(Of (String, String), String)) '清空已有皮肤 '如果在输入时清空皮肤,若输入内容一样则不会执行 Load 方法,导致皮肤不被加载 RunInUi(Sub() If FrmLoginAuthSkin IsNot Nothing AndAlso FrmLoginAuthSkin.Skin IsNot Nothing Then FrmLoginAuthSkin.Skin.Clear()) '获取 Url - Dim UserName As String = Data.Input(0) - Dim UUID As String = Data.Input(1) + Dim UserName As String = Data.Input.Item1 + Dim UUID As String = Data.Input.Item2 If UserName = "" Then Data.Output = PathImage & "Skins/Steve.png" - Log("[Minecraft] 获取 Authlib-Injector 皮肤失败,ID 为空") + Logger.Info("获取 Authlib-Injector 皮肤失败,ID 为空") GoTo Finish End If Try @@ -553,15 +553,15 @@ Finish: Data.Output = "" Return Catch ex As Exception - If ex.GetBrief.Contains("(429)") Then + If ex.GetDisplay(False).Contains("(429)") Then Data.Output = PathImage & "Skins/Steve.png" - Log("[Minecraft] 获取 Authlib-Injector 皮肤失败(" & UserName & "):获取皮肤太过频繁,请 5 分钟后再试!", NotifyLevel.AllUsers) - ElseIf ex.GetBrief.Contains("未设置自定义皮肤") Then + Logger.Error($"获取 Authlib-Injector 皮肤失败({UserName}):获取皮肤太过频繁,请 5 分钟后再试!", LogBehavior.Toast) + ElseIf ex.GetDisplay(False).Contains("未设置自定义皮肤") Then Data.Output = PathImage & "Skins/Steve.png" - Log("[Minecraft] 用户未设置自定义皮肤,跳过皮肤加载") + Logger.Info("用户未设置自定义皮肤,跳过皮肤加载") Else Data.Output = PathImage & "Skins/Steve.png" - Log(ex, "获取 Authlib-Injector 皮肤失败(" & UserName & ")", NotifyLevel.AllUsers) + Logger.Error(ex, $"获取 Authlib-Injector 皮肤失败({UserName})", LogBehavior.Toast) End If End Try Finish: @@ -575,7 +575,7 @@ Finish: '全部皮肤加载器 '需要放在其中元素的后面,否则会因为它提前被加载而莫名其妙变成 Nothing - Public Shared SkinLoaders As New List(Of LoaderTask(Of EqualableList(Of String), String)) From {SkinMs, SkinLegacy, SkinNide, SkinAuth} + Public Shared SkinLoaders As New List(Of LoaderTask(Of (String, String), String)) From {SkinMs, SkinLegacy, SkinNide, SkinAuth} #End Region @@ -616,7 +616,7 @@ Finish: CurrentState = 0 Else If McInstanceSelected Is Nothing Then - If Settings.Get("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow Then + If Settings.Get(Of Boolean)("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow Then CurrentState = 1 Else CurrentState = 2 @@ -632,28 +632,28 @@ Finish: BtnLaunchState = CurrentState Select Case CurrentState Case 0 - Log("[Minecraft] 启动按钮:正在加载 Minecraft 版本") + Logger.Info("启动按钮:正在加载 Minecraft 版本") FrmLaunchLeft.BtnLaunch.Text = "正在加载" FrmLaunchLeft.BtnLaunch.IsEnabled = False FrmLaunchLeft.LabVersion.Text = "正在加载中,请稍候" FrmLaunchLeft.BtnVersion.IsEnabled = False FrmLaunchLeft.BtnMore.Visibility = Visibility.Collapsed Case 1 - Log("[Minecraft] 启动按钮:无 Minecraft 版本,下载已禁用") + Logger.Info("启动按钮:无 Minecraft 版本,下载已禁用") FrmLaunchLeft.BtnLaunch.Text = "启动游戏" FrmLaunchLeft.BtnLaunch.IsEnabled = False FrmLaunchLeft.LabVersion.Text = "未找到可用的游戏版本" FrmLaunchLeft.BtnVersion.IsEnabled = True FrmLaunchLeft.BtnMore.Visibility = Visibility.Collapsed Case 2 - Log("[Minecraft] 启动按钮:无 Minecraft 版本,要求下载") + Logger.Info("启动按钮:无 Minecraft 版本,要求下载") FrmLaunchLeft.BtnLaunch.Text = "下载游戏" FrmLaunchLeft.BtnLaunch.IsEnabled = True FrmLaunchLeft.LabVersion.Text = "未找到可用的游戏版本" FrmLaunchLeft.BtnVersion.IsEnabled = True FrmLaunchLeft.BtnMore.Visibility = Visibility.Collapsed Case 3 - Log("[Minecraft] 启动按钮:Minecraft 版本:" & McInstanceSelected.PathVersion) + Logger.Info($"启动按钮:Minecraft 版本:{McInstanceSelected.PathVersion}") FrmLaunchLeft.BtnLaunch.Text = "启动游戏" FrmLaunchLeft.BtnVersion.IsEnabled = True FrmLaunchLeft.BtnLaunch.IsEnabled = True @@ -662,7 +662,7 @@ Finish: End Select ExitRefresh: '功能隐藏 - FrmLaunchLeft.BtnVersion.Visibility = If(Not PageSetupUI.HiddenForceShow AndAlso Settings.Get("UiHiddenFunctionSelect"), Visibility.Collapsed, Visibility.Visible) + FrmLaunchLeft.BtnVersion.Visibility = If(Not PageSetupUI.HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenFunctionSelect"), Visibility.Collapsed, Visibility.Visible) If CurrentState = 3 Then FrmLaunchLeft.BtnMore.Visibility = FrmLaunchLeft.BtnVersion.Visibility End If @@ -679,7 +679,7 @@ ExitRefresh: If Not McLaunchProcess.HasExited Then McLaunchProcess.Kill() End If Catch ex As Exception - Log(ex, "取消启动结束进程失败", NotifyLevel.AllUsers) + Logger.Error(ex, "取消启动结束进程失败", LogBehavior.Toast) End Try End If End Sub @@ -708,7 +708,7 @@ ExitRefresh: Next LabLaunchingStage.Text = "已完成" Catch ex As Exception - Log(ex, "获取是否启动完成失败,可能是由于启动状态改变导致集合已修改") + Logger.Warn(ex, "获取是否启动完成失败,可能是由于启动状态改变导致集合已修改") Return End Try LabLaunchingTitle.Text = If(IsLaunched OrElse McLaunchLoaderReal.State = LoadState.Finished, @@ -733,7 +733,7 @@ ExitRefresh: Next End If Catch ex As Exception - Log(ex, "获取 Minecraft 启动下载器失败,可能是因为启动被取消") + Logger.Warn(ex, "获取 Minecraft 启动下载器失败,可能是因为启动被取消") HasLaunchDownloader = False End Try LabLaunchingDownload.Text = FormatFileSize(NetManager.Speed) & "/s" @@ -769,7 +769,7 @@ ExitRefresh: End If AniStart(AnimList, "Launching Progress") Catch ex As Exception - Log(ex, "刷新启动信息失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "刷新启动信息失败") End Try End Sub Private ShowProgress As Double = 0 diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb index c19c221..c30354a 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLaunchRight.xaml.vb @@ -9,7 +9,7 @@ Public Class PageLaunchRight '快照版提示 PanHint.Visibility = (BuildType <> BuildTypes.Release AndAlso VersionBranchMain = "Official" AndAlso - DonationRank < DonationRanks.Rank23 AndAlso Not CType(Settings.Get("HintSnapshot"), Boolean)).ToVisibility + CurrentRank < DonationRank.Rank23 AndAlso Not Settings.Get(Of Boolean)("HintSnapshot")).ToVisibility End Sub #Region "主页" @@ -25,25 +25,25 @@ Public Class PageLaunchRight RefreshReal() End SyncLock Catch ex As Exception - Log(ex, "加载 PCL 主页自定义信息失败", If(ModeDebug, NotifyLevel.MsgBox, NotifyLevel.AllUsers)) + Logger.Error(ex, "加载 PCL 主页自定义信息失败", If(ModeDebug, LogBehavior.Alert, LogBehavior.Toast)) End Try End Sub) End Sub Private Sub RefreshReal() Dim Content As String = Nothing, Url As String = Nothing - Select Case Settings.Get("UiCustomType") + Select Case Settings.Get(Of Integer)("UiCustomType") Case 1 '加载本地文件 - Log("[Page] 主页自定义数据来源:本地文件") - Content = ReadFile(PathExeFolder & "PCL\Custom.xaml") 'ReadFile 会进行存在检测 + Logger.Info("主页自定义数据来源:本地文件") + Content = FileUtils.TryReadAsString(PathExeFolder & "PCL\Custom.xaml") Case 2 '联网下载 - Url = Settings.Get("UiCustomNet") + Url = Settings.Get(Of String)("UiCustomNet") Case 3 '预设 - Select Case Settings.Get("UiCustomPreset") + Select Case Settings.Get(Of Integer)("UiCustomPreset") Case 0 - Log("[Page] 主页预设:你知道吗") + Logger.Info("主页预设:你知道吗") Content = " @@ -52,7 +52,7 @@ Public Class PageLaunchRight 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"" /> " Case 1 - Log("[Page] 主页预设:回声洞") + Logger.Info("主页预设:回声洞") Content = " @@ -61,64 +61,67 @@ Public Class PageLaunchRight 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"" /> " Case 2 - Log("[Page] 主页预设:Minecraft 新闻") + Logger.Info("主页预设:Minecraft 新闻") Url = "https://mcnews.meloong.com" Case 3 - Log("[Page] 主页预设:简单主页") + Logger.Info("主页预设:简单主页") Url = "https://pclhomeplazaoss.lingyunawa.top:26994/d/Homepages/MFn233/Custom.xaml" Case 4 - Log("[Page] 主页预设:每日整合包推荐") + Logger.Info("主页预设:每日整合包推荐") Url = "https://pclsub.sodamc.com/" Case 5 - Log("[Page] 主页预设:Minecraft 皮肤推荐") + Logger.Info("主页预设:Minecraft 皮肤推荐") Url = "https://forgepixel.com/pcl_sub_file" Case 6 - Log("[Page] 主页预设:OpenBMCLAPI 仪表盘 Lite") + Logger.Info("主页预设:OpenBMCLAPI 仪表盘 Lite") Url = "https://pcl-bmcl.milu.ink/" Case 7 - Log("[Page] 主页预设:主页市场") + Logger.Info("主页预设:主页市场") Url = "https://pclhomeplazaoss.lingyunawa.top:26994/p/Homepages/Homepage.Market/Custom.xaml" Case 8 - Log("[Page] 主页预设:更新日志") + Logger.Info("主页预设:更新日志") Url = "https://pclhomeplazaoss.lingyunawa.top:26994/d/Homepages/Joker2184/UpdateHomepage.xaml" Case 9 - Log("[Page] 主页预设:PCL 新功能说明书") + Logger.Info("主页预设:PCL 新功能说明书") Url = "https://raw.gitcode.com/WForst-Breeze/WhatsNewPCL/raw/main/Custom.xaml" Case 10 - Log("[Page] 主页预设:OpenMCIM Dashboard") + Logger.Info("主页预设:OpenMCIM Dashboard") Url = "https://files.mcimirror.top/PCL" Case 11 - Log("[Page] 主页预设:杂志主页") + Logger.Info("主页预设:杂志主页") Url = "http://118.195.192.193:26995/d/magazine-homepage-pcl/Custom.xaml" Case 12 - Log("[Page] 主页预设:PCL GitHub 仪表盘") - Url = "https://ddf.pcl-community.org/Custom.xaml" + Logger.Info("主页预设:PCL GitHub 仪表盘") + Url = "https://ddf.pcl-community.top/Custom.xaml" Case 13 - Log("[Page] 主页预设:PCL 更新摘要") + Logger.Info("主页预设:PCL 更新摘要") Url = "https://raw.gitcode.com/ENC_Euphony/PCL-AI-Summary-HomePage/raw/master/Custom.xaml" Case 14 - Log("[Page] 主页预设:今日新闻热点") + Logger.Info("主页预设:今日新闻热点") Url = "https://pcl.wyc-w.top/index.xaml" Case 15 - Log("[Page] 主页预设:Minecraft 芝士站") + Logger.Info("主页预设:Minecraft 芝士站") Url = "https://www.xxag.top/mkss" + Case 16 + Logger.Info("主页预设:整合包推荐引擎") + Url = "https://qawsedrftgyhujiko.fun/pcl2/Custom.xaml" End Select End Select '联网下载 If Not String.IsNullOrWhiteSpace(Url) Then - If Url = Settings.Get("CacheSavedPageUrl") AndAlso File.Exists(PathTemp & "Cache\Custom.xaml") Then + If Url = Settings.Get(Of String)("CacheSavedPageUrl") AndAlso FileUtils.Exists(PathTemp & "Cache\Custom.xaml") Then '缓存可用 - Log("[Page] 主页自定义数据来源:联网缓存文件") - Content = ReadFile(PathTemp & "Cache\Custom.xaml") + Logger.Info("主页自定义数据来源:联网缓存文件") + Content = FileUtils.TryReadAsString(PathTemp & "Cache\Custom.xaml") '后台更新缓存 - OnlineLoader.Start(New Tuple(Of String, Boolean)(Url, False)) + OnlineLoader.Start((Url, False)) Else '缓存不可用 - Log("[Page] 主页自定义数据来源:联网全新下载") + Logger.Info("主页自定义数据来源:联网全新下载") Hint("正在加载主页……") RunInUiWait(Sub() LoadContent(Nothing)) '在加载结束前清空页面 Settings.Set("CacheSavedPageVersion", "") - OnlineLoader.Start(New Tuple(Of String, Boolean)(Url, True)) '下载完成后将会再次触发更新 + OnlineLoader.Start((Url, True)) '下载完成后将会再次触发更新 Return End If End If @@ -128,10 +131,10 @@ Public Class PageLaunchRight Private RefreshLock As New Object '联网获取主页文件 - Private OnlineLoader As New LoaderTask(Of Tuple(Of String, Boolean), Integer)("下载主页", AddressOf OnlineLoaderSub) With {.ReloadTimeout = 10 * 60 * 1000} - Private Sub OnlineLoaderSub(Task As LoaderTask(Of Tuple(Of String, Boolean), Integer)) - Dim Address As String = Task.Input.Item1 '#3721 中连续触发两次导致内容变化 - Dim ShouldRefresh As Boolean = Task.Input.Item2 + Private OnlineLoader As New LoaderTask(Of (Address As String, ShouldRefresh As Boolean), Integer)("下载主页", AddressOf OnlineLoaderSub) With {.ReloadTimeout = 10 * 60 * 1000} + Private Sub OnlineLoaderSub(Task As LoaderTask(Of (Address As String, ShouldRefresh As Boolean), Integer)) + Dim Address As String = Task.Input.Address '#3721 中连续触发两次导致内容变化 + Dim ShouldRefresh As Boolean = Task.Input.ShouldRefresh Try '替换自定义变量与设置 Address = ArgumentReplace(Address, AddressOf WebUtility.HtmlEncode) @@ -150,26 +153,26 @@ Public Class PageLaunchRight Try Version = NetRequestByClientRetry(VersionAddress) If Version.Length > 1000 Then Throw New Exception($"获取的主页版本过长({Version.Length} 字符)") - Dim CurrentVersion As String = Settings.Get("CacheSavedPageVersion") + Dim CurrentVersion As String = Settings.Get(Of String)("CacheSavedPageVersion") If Version <> "" AndAlso CurrentVersion <> "" AndAlso Version = CurrentVersion Then - Log($"[Page] 当前缓存的主页已为最新,当前版本:{Version},检查源:{VersionAddress}") + Logger.Info($"当前缓存的主页已为最新,当前版本:{Version},检查源:{VersionAddress}") Return End If - Log($"[Page] 需要下载联网主页,当前版本:{Version},检查源:{VersionAddress}") + Logger.Info($"需要下载联网主页,当前版本:{Version},检查源:{VersionAddress}") Catch exx As Exception - Log(exx, $"联网获取主页版本失败", NotifyLevel.DevelopOnly) - Log($"[Page] 无法检查联网主页版本,将直接下载,检查源:{VersionAddress}") + Logger.Warn(exx, $"联网获取主页版本失败") + Logger.Info($"无法检查联网主页版本,将直接下载,检查源:{VersionAddress}") End Try '实际下载 Dim FileContent As String = NetRequestByClientRetry(Address) - Log($"[Page] 已联网下载主页,内容长度:{FileContent.Length},来源:{Address}") + Logger.Info($"已联网下载主页,内容长度:{FileContent.Length},来源:{Address}") Settings.Set("CacheSavedPageUrl", Address) Settings.Set("CacheSavedPageVersion", Version) FileUtils.Write(PathTemp & "Cache\Custom.xaml", FileContent) '若内容变更则要求刷新 If LoadedContentHash <> FileContent.GetHashCode() AndAlso ShouldRefresh Then Refresh() Catch ex As Exception - Log(ex, $"下载主页失败({Address})", If(ModeDebug, NotifyLevel.MsgBox, NotifyLevel.AllUsers)) + Logger.Error(ex, $"下载主页失败({Address})", If(ModeDebug, LogBehavior.Alert, LogBehavior.Toast)) End Try End Sub @@ -178,7 +181,7 @@ Public Class PageLaunchRight ''' 必须在 UI 线程调用。 ''' Public Sub ForceRefresh() Implements IRefreshable.Refresh - Log("[Page] 要求强制刷新主页") + Logger.Info("要求强制刷新主页") ClearCache() '实际的刷新 If FrmMain.PageCurrent.Page = FormMain.PageType.Launch Then @@ -194,10 +197,10 @@ Public Class PageLaunchRight ''' Private Sub ClearCache() LoadedContentHash = -1 - OnlineLoader.Input = New Tuple(Of String, Boolean)("", True) + OnlineLoader.Input = ("", True) Settings.Set("CacheSavedPageUrl", "") Settings.Set("CacheSavedPageVersion", "") - Log("[Page] 已清空主页缓存") + Logger.Info("已清空主页缓存") End Sub ''' @@ -214,7 +217,7 @@ Public Class PageLaunchRight '实际加载内容 PanCustom.Children.Clear() If String.IsNullOrWhiteSpace(Content) Then - Log($"[Page] 实例化:清空主页 UI,来源为空") + Logger.Info($"实例化:清空主页 UI,来源为空") Return End If Dim LoadStartTime As Date = Date.Now @@ -223,16 +226,16 @@ Public Class PageLaunchRight Do While Content.Contains("xmlns") Content = Content.RegexReplace("xmlns[^""']*(""|')[^""']*(""|')", "").Replace("xmlns", "") '禁止声明命名空间 Loop - Content = "" & Content & "" - Log($"[Page] 实例化:加载主页 UI 开始,最终内容长度:{Content.Count}") + Content = "" & Content & "" + Logger.Info($"实例化:加载主页 UI 开始,最终内容长度:{Content.Count}") PanCustom.Children.Add(GetObjectFromXML(Content)) '加载计时 Dim LoadCostTime = (Date.Now - LoadStartTime).Milliseconds - Log($"[Page] 实例化:加载主页 UI 完成,耗时 {LoadCostTime}ms") + Logger.Info($"实例化:加载主页 UI 完成,耗时 {LoadCostTime}ms") If LoadCostTime > 3000 Then Hint($"主页加载过于缓慢(花费了 {Math.Round(LoadCostTime / 1000, 1)} 秒),请向主页作者反馈此问题,或暂时停止使用该主页") End SyncLock Catch ex As Exception - Log(ex, "加载失败的主页内容:" & vbCrLf & Content) + Logger.Warn(ex, $"加载失败的主页内容:{vbCrLf}{Content}") OnLoadContentFailed(ex) End Try End Sub @@ -240,12 +243,12 @@ Public Class PageLaunchRight ''' 加载主页失败时调用。 ''' Private Sub OnLoadContentFailed(ex As Exception) - If ModeDebug OrElse Settings.Get("UiCustomType") = 1 Then - Log(ex, "加载主页失败") - If MyMsgBox(If(TypeOf ex Is UnauthorizedAccessException, ex.Message, $"主页内容编写有误,请根据下列错误信息进行检查:{vbCrLf}{ex.GetBrief}"), + If ModeDebug OrElse Settings.Get(Of Integer)("UiCustomType") = 1 Then + Logger.Warn(ex, "加载主页失败") + If MyMsgBox(If(TypeOf ex Is UnauthorizedAccessException, ex.Message, $"主页内容编写有误,请根据下列错误信息进行检查:{vbCrLf}{ex.GetDisplay(False)}"), "加载主页失败", "重试", "取消") = 1 Then ForceRefresh() Else - Log(ex, "加载主页失败", NotifyLevel.AllUsers) + Logger.Error(ex, "加载主页失败", LogBehavior.Toast) End If End Sub ''' diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.vb index 5ddda26..fd7272f 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuth.xaml.vb @@ -5,20 +5,20 @@ ''' Public Sub Reload(KeepInput As Boolean) '记住密码 - CheckRemember.Checked = Settings.Get("LoginRemember") + CheckRemember.Checked = Settings.Get(Of Boolean)("LoginRemember") If KeepInput AndAlso Not IsFirstLoad Then '避免第一次就以 KeepInput 的方式加载,导致文本框里没东西 '保留输入,只刷新下拉框列表 Dim Input As String = ComboName.Text - ComboName.ItemsSource = If(Settings.Get("LoginAuthEmail") = "", Nothing, Settings.Get("LoginAuthEmail").ToString.Split("¨")) + ComboName.ItemsSource = If(Settings.Get(Of String)("LoginAuthEmail") = "", Nothing, Settings.Get(Of String)("LoginAuthEmail").Split("¨")) ComboName.Text = Input Else '不保留输入,刷新列表后自动选择第一项 - If Settings.Get("LoginAuthEmail") = "" Then + If Settings.Get(Of String)("LoginAuthEmail") = "" Then ComboName.ItemsSource = Nothing Else - ComboName.ItemsSource = Settings.Get("LoginAuthEmail").ToString.Split("¨") - ComboName.Text = Settings.Get("LoginAuthEmail").ToString.BeforeFirst("¨") - If Settings.Get("LoginRemember") Then TextPass.Password = Settings.Get("LoginAuthPass").ToString.BeforeFirst("¨").Trim + ComboName.ItemsSource = Settings.Get(Of String)("LoginAuthEmail").Split("¨") + ComboName.Text = Settings.Get(Of String)("LoginAuthEmail").BeforeFirst("¨") + If Settings.Get(Of Boolean)("LoginRemember") Then TextPass.Password = Settings.Get(Of String)("LoginAuthPass").BeforeFirst("¨").Trim End If End If IsFirstLoad = False @@ -27,7 +27,7 @@ ''' 获取当前页面的登录信息。 ''' Public Shared Function GetLoginData() As McLoginServer - Dim Server As String = If(IsNothing(McInstanceSelected), Settings.Get("CacheAuthServerServer"), Settings.Get("VersionServerAuthServer", Instance:=McInstanceSelected)) & "/authserver" + Dim Server As String = If(IsNothing(McInstanceSelected), Settings.Get(Of String)("CacheAuthServerServer"), Settings.Get(Of String)("VersionServerAuthServer", Instance:=McInstanceSelected)) & "/authserver" If FrmLoginAuth Is Nothing Then Return New McLoginServer(McLoginType.Auth) With {.Token = "Auth", .BaseUrl = Server, .UserName = "", .Password = "", .Description = "Authlib-Injector", .Type = McLoginType.Auth} Else @@ -55,10 +55,10 @@ If AniControlEnabled = 0 Then Settings.Set("CacheAuthAccess", "") End Sub Private Sub ComboName_SelectionChanged(sender As MyComboBox, e As SelectionChangedEventArgs) Handles ComboName.SelectionChanged - If sender.SelectedIndex = -1 OrElse Not Settings.Get("LoginRemember") Then + If sender.SelectedIndex = -1 OrElse Not Settings.Get(Of Boolean)("LoginRemember") Then TextPass.Password = "" Else - TextPass.Password = Settings.Get("LoginAuthPass").ToString.Split("¨")(sender.SelectedIndex).Trim + TextPass.Password = Settings.Get(Of String)("LoginAuthPass").ToString.Split("¨")(sender.SelectedIndex).Trim End If End Sub Private Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckRemember.Change @@ -71,15 +71,15 @@ End Sub Private Sub Btn_Click(sender As Object, e As EventArgs) Handles BtnLink.Click If BtnLink.Content = "注册账号" Then - OpenWebsite(If(McInstanceSelected IsNot Nothing, Settings.Get("VersionServerAuthRegister", Instance:=McInstanceSelected), Settings.Get("CacheAuthServerRegister"))) + OpenWebsite(If(McInstanceSelected IsNot Nothing, Settings.Get(Of String)("VersionServerAuthRegister", Instance:=McInstanceSelected), Settings.Get(Of String)("CacheAuthServerRegister"))) Else - Dim Website As String = If(McInstanceSelected IsNot Nothing, Settings.Get("VersionServerAuthRegister", Instance:=McInstanceSelected), Settings.Get("CacheAuthServerRegister")) + Dim Website As String = If(McInstanceSelected IsNot Nothing, Settings.Get(Of String)("VersionServerAuthRegister", Instance:=McInstanceSelected), Settings.Get(Of String)("CacheAuthServerRegister")) OpenWebsite(Website.Replace("/auth/register", "/auth/forgot")) End If End Sub '切换注册按钮可见性 Private Sub ReloadRegisterButton() Handles Me.Loaded - Dim Address As String = If(McInstanceSelected IsNot Nothing, Settings.Get("VersionServerAuthRegister", Instance:=McInstanceSelected), Settings.Get("CacheAuthServerRegister")) + Dim Address As String = If(McInstanceSelected IsNot Nothing, Settings.Get(Of String)("VersionServerAuthRegister", Instance:=McInstanceSelected), Settings.Get(Of String)("CacheAuthServerRegister")) BtnLink.Visibility = If(String.IsNullOrEmpty(New ValidateHttp().Validate(Address)), Visibility.Visible, Visibility.Collapsed) End Sub diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb index e0bc0dd..2d79030 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginAuthSkin.xaml.vb @@ -12,17 +12,17 @@ ''' 刷新页面显示的所有信息。 ''' Public Sub Reload(KeepInput As Boolean) - TextName.Text = Settings.Get("CacheAuthName") - TextEmail.Text = Settings.Get("CacheAuthUsername") - TextEmail.Visibility = If(Settings.Get("UiLauncherEmail"), Visibility.Collapsed, Visibility.Visible) + TextName.Text = Settings.Get(Of String)("CacheAuthName") + TextEmail.Text = Settings.Get(Of String)("CacheAuthUsername") + TextEmail.Visibility = If(Settings.Get(Of Boolean)("UiLauncherEmail"), Visibility.Collapsed, Visibility.Visible) PageLoginLegacy_Loaded() End Sub ''' ''' 获取当前页面的登录信息。 ''' Public Shared Function GetLoginData() As McLoginServer - Dim Server As String = If(IsNothing(McInstanceSelected), Settings.Get("CacheAuthServerServer"), Settings.Get("VersionServerAuthServer", Instance:=McInstanceSelected)) & "/authserver" - Return New McLoginServer(McLoginType.Auth) With {.Token = "Auth", .BaseUrl = Server, .UserName = Settings.Get("CacheAuthUsername"), .Password = Settings.Get("CacheAuthPass"), .Description = "Authlib-Injector", .Type = McLoginType.Auth} + Dim Server As String = If(IsNothing(McInstanceSelected), Settings.Get(Of String)("CacheAuthServerServer"), Settings.Get(Of String)("VersionServerAuthServer", Instance:=McInstanceSelected)) & "/authserver" + Return New McLoginServer(McLoginType.Auth) With {.Token = "Auth", .BaseUrl = Server, .UserName = Settings.Get(Of String)("CacheAuthUsername"), .Password = Settings.Get(Of String)("CacheAuthPass"), .Description = "Authlib-Injector", .Type = McLoginType.Auth} End Function Private Sub PageLoginAuthSkin_MouseEnter(sender As Object, e As MouseEventArgs) Handles PanData.MouseEnter @@ -46,7 +46,7 @@ Private Sub BtnEdit_Click(sender As Object, e As EventArgs) Handles BtnEdit.Click If McLoginLoader.State = LoadState.Loading Then - Log("[Launch] 要求更换角色,但登录加载器繁忙", NotifyLevel.DebugModeOnly) + Logger.Warn("要求更换角色,但登录加载器繁忙") If TypeOf McLoginLoader.Input Is McLoginServer AndAlso CType(McLoginLoader.Input, McLoginServer).ForceReselectProfile Then Hint("正在尝试更换,请稍候!") Else @@ -65,7 +65,7 @@ McLoginLoader.WaitForExit(Data, IsForceRestart:=True) RunInUi(Sub() Reload(True)) Catch ex As Exception - Log(ex, "更换角色失败", NotifyLevel.AllUsers) + Logger.Error(ex, "更换角色失败", LogBehavior.Toast) End Try End Sub) End Sub @@ -78,7 +78,7 @@ End Sub Private Sub Skin_Click(sender As Object, e As MouseButtonEventArgs) Handles Skin.Click - Dim Address As String = If(McInstanceSelected IsNot Nothing, Settings.Get("VersionServerAuthRegister", Instance:=McInstanceSelected), Settings.Get("CacheAuthServerRegister")) + Dim Address As String = If(McInstanceSelected IsNot Nothing, Settings.Get(Of String)("VersionServerAuthRegister", Instance:=McInstanceSelected), Settings.Get(Of String)("CacheAuthServerRegister")) If String.IsNullOrEmpty(New ValidateHttp().Validate(Address)) Then OpenWebsite(Address.Replace("/auth/register", "/user/closet")) End Sub diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb index bd8016a..7bbb4f9 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginLegacy.xaml.vb @@ -18,15 +18,15 @@ Public Class PageLoginLegacy If KeepInput AndAlso IsReloaded Then '避免第一次就以 KeepInput 的方式加载,导致文本框里没东西 '保留输入,只刷新下拉框列表 Dim Input As String = ComboName.Text.Trim - ComboName.ItemsSource = If(Settings.Get("LoginLegacyName") = "", Nothing, Settings.Get("LoginLegacyName").ToString.Split("¨")) + ComboName.ItemsSource = If(Settings.Get(Of String)("LoginLegacyName") = "", Nothing, Settings.Get(Of String)("LoginLegacyName").Split("¨")) ComboName.Text = Input Else '不保留输入,刷新列表后自动选择第一项 - If Settings.Get("LoginLegacyName") = "" Then + If Settings.Get(Of String)("LoginLegacyName") = "" Then ComboName.ItemsSource = Nothing Else - ComboName.ItemsSource = Settings.Get("LoginLegacyName").ToString.Split("¨") - ComboName.Text = Settings.Get("LoginLegacyName").ToString.BeforeFirst("¨").Trim + ComboName.ItemsSource = Settings.Get(Of String)("LoginLegacyName").ToString.Split("¨") + ComboName.Text = Settings.Get(Of String)("LoginLegacyName").ToString.BeforeFirst("¨").Trim End If End If IsReloaded = True @@ -36,7 +36,7 @@ Public Class PageLoginLegacy ''' Public Shared Function GetLoginData() As McLoginData Dim UserName As String = If(FrmLoginLegacy Is Nothing, "", FrmLoginLegacy.ComboName.Text.Replace("¨", "").Trim) - Return New McLoginLegacy With {.UserName = UserName, .SkinType = Settings.Get("LaunchSkinType"), .SkinName = Settings.Get("LaunchSkinID")} + Return New McLoginLegacy With {.UserName = UserName, .SkinType = Settings.Get(Of Integer)("LaunchSkinType"), .SkinName = Settings.Get(Of String)("LaunchSkinID")} End Function ''' ''' 当前页面的登录信息是否有效。 @@ -62,12 +62,12 @@ Public Class PageLoginLegacy End If End Sub Private Sub ComboLegacy_TextChanged(sender As Object, e As TextChangedEventArgs) Handles ComboName.TextChanged - If Settings.Get("LaunchSkinType") = 0 Then PageLaunchLeft.SkinLegacy.Start(IsForceRestart:=True) - HintChinese.Visibility = If(RegexCheck(ComboName.Text, "^[0-9A-Za-z_]*$"), Visibility.Collapsed, Visibility.Visible) + If Settings.Get(Of Integer)("LaunchSkinType") = 0 Then PageLaunchLeft.SkinLegacy.Start(IsForceRestart:=True) + HintChinese.Visibility = If(ComboName.Text.RegexCheck("^[0-9A-Za-z_]*$"), Visibility.Collapsed, Visibility.Visible) RunInUi(Sub() PanMain.InvalidateMeasure(), True) '由于 WPF 的 Bug,它不一定会自动更新 HintChinese 的大小(#6627) End Sub Private Sub Skin_Click() Handles Skin.Click - If (Settings.Get("UiHiddenPageSetup") OrElse Settings.Get("UiHiddenSetupLaunch")) AndAlso Not PageSetupUI.HiddenForceShow Then + If (Settings.Get(Of Boolean)("UiHiddenPageSetup") OrElse Settings.Get(Of Boolean)("UiHiddenSetupLaunch")) AndAlso Not PageSetupUI.HiddenForceShow Then Hint("启动设置已被禁用!", HintType.Red) Else FrmMain.PageChange(FormMain.PageType.Setup, FormMain.PageSubType.SetupLaunch) '切换到皮肤设置页面 diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb index f5192dd..7d70de1 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMs.xaml.vb @@ -9,7 +9,7 @@ ComboAccounts.Items.Clear() ComboAccounts.Items.Add(New MyComboBoxItem With {.Content = "添加新账号"}) Try - Dim MsJson As JObject = GetJson(Settings.Get("LoginMsJson")) + Dim MsJson As JObject = GetJson(Settings.Get(Of String)("LoginMsJson")) For Each Account In MsJson Dim Item As MyListItem = CType(FindResource("ComboBoxItemTemplateWithDelete"), DataTemplate).LoadContent() Item.Tag = Account.Value.ToString @@ -18,7 +18,7 @@ ComboAccounts.Items.Add(Item) Next Catch ex As Exception - Log(ex, $"微软登录信息出错,登录信息已被重置({Settings.Get("LoginMsJson")})", NotifyLevel.AllUsers) + Logger.Error(ex, $"微软登录信息出错,登录信息已被重置({Settings.Get(Of String)("LoginMsJson")})", LogBehavior.Toast) Settings.Set("LoginMsJson", "{}") End Try '如果不保留输入,刷新列表后自动选择第一项 @@ -37,7 +37,7 @@ ''' 获取当前页面的登录信息。 ''' Public Shared Function GetLoginData() As McLoginMs - If FrmLoginMs Is Nothing Then Return New McLoginMs With {.OAuthRefreshToken = Settings.Get("CacheMsV2OAuthRefresh"), .UserName = Settings.Get("CacheMsV2Name")} + If FrmLoginMs Is Nothing Then Return New McLoginMs With {.OAuthRefreshToken = Settings.Get(Of String)("CacheMsV2OAuthRefresh"), .UserName = Settings.Get(Of String)("CacheMsV2Name")} Dim Result As McLoginMs = Nothing RunInUiWait( Sub() @@ -92,9 +92,9 @@ ElseIf ex.Message.StartsWithF("$") Then Hint(ex.Message.TrimStart("$"), HintType.Red) ElseIf TypeOf ex Is Security.Authentication.AuthenticationException AndAlso ex.Message.Contains("SSL/TLS") Then - Log(ex, "正版登录验证失败,请考虑在 [设置 → 其他] 中关闭 [在正版登录时验证 SSL 证书],然后再试。" & vbCrLf & vbCrLf & "原始错误信息:", NotifyLevel.MsgBox) + Logger.Error(ex, $"正版登录验证失败,请考虑在 [设置 → 其他] 中关闭 [在正版登录时验证 SSL 证书],然后再试。{vbCrLf}{vbCrLf}原始错误信息:", LogBehavior.Alert) Else - Log(ex, "正版登录尝试失败", NotifyLevel.MsgBox) + Logger.Error(ex, "正版登录尝试失败", LogBehavior.Alert) End If Finally RunInUi( diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb index ae4df57..7230cf4 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginMsSkin.xaml.vb @@ -12,7 +12,7 @@ ''' 刷新页面显示的所有信息。 ''' Public Sub Reload(KeepInput As Boolean) - TextName.Text = Settings.Get("CacheMsV2Name") + TextName.Text = Settings.Get(Of String)("CacheMsV2Name") '皮肤在 Loaded 加载 End Sub ''' @@ -20,9 +20,9 @@ ''' Public Shared Function GetLoginData() As McLoginMs If McLoginMsLoader.State = LoadState.Finished Then - Return New McLoginMs With {.OAuthRefreshToken = Settings.Get("CacheMsV2OAuthRefresh"), .UserName = Settings.Get("CacheMsV2Name"), .AccessToken = Settings.Get("CacheMsV2Access"), .Uuid = Settings.Get("CacheMsV2Uuid"), .ProfileJson = Settings.Get("CacheMsV2ProfileJson")} + Return New McLoginMs With {.OAuthRefreshToken = Settings.Get(Of String)("CacheMsV2OAuthRefresh"), .UserName = Settings.Get(Of String)("CacheMsV2Name"), .AccessToken = Settings.Get(Of String)("CacheMsV2Access"), .Uuid = Settings.Get(Of String)("CacheMsV2Uuid"), .ProfileJson = Settings.Get(Of String)("CacheMsV2ProfileJson")} Else - Return New McLoginMs With {.OAuthRefreshToken = Settings.Get("CacheMsV2OAuthRefresh"), .UserName = Settings.Get("CacheMsV2Name")} + Return New McLoginMs With {.OAuthRefreshToken = Settings.Get(Of String)("CacheMsV2OAuthRefresh"), .UserName = Settings.Get(Of String)("CacheMsV2Name")} End If End Function @@ -49,6 +49,7 @@ Settings.Set("CacheMsV2ProfileJson", "") Settings.Set("CacheMsV2Uuid", "") Settings.Set("CacheMsV2Name", "") + Settings.Set("CacheMsV2Expires", 0L) McLoginMsLoader.Interrupt() FrmLaunchLeft.RefreshPage(False, True) End Sub @@ -88,14 +89,18 @@ Retry: Thread.Sleep(10) Loop If McLoginMsLoader.State = LoadState.Failed Then Throw New Exception("登录失败", McLoginMsLoader.Error) - Dim AccessToken As String = Settings.Get("CacheMsV2Access") - Dim Uuid As String = Settings.Get("CacheMsV2Uuid") - Dim Result As String = NetRequestByClientRetry("https://api.minecraftservices.com/minecraft/profile/skins", HttpMethod.Post, - Content:=New Net.Http.MultipartFormDataContent From { - {New Net.Http.StringContent(If(SkinInfo.IsSlim, "slim", "classic")), "variant"}, - {New Net.Http.ByteArrayContent(ReadFileBytes(SkinInfo.LocalFile)), "file", GetFileNameFromPath(SkinInfo.LocalFile)} - }, - Headers:={{"Authorization", "Bearer " & AccessToken}, {"Accept", "*/*"}, {"User-Agent", "MojangSharp/0.1"}}) + Dim AccessToken As String = Settings.Get(Of String)("CacheMsV2Access") + Dim Uuid As String = Settings.Get(Of String)("CacheMsV2Uuid") + Dim Result As String = Nothing + ResilientUtils.Retry( 'MultipartFormDataContent 在一次请求后就会被 Dispose,所以不能直接 Retry(#8397) + Sub() + Result = NetRequestByClient("https://api.minecraftservices.com/minecraft/profile/skins", HttpMethod.Post, + Content:=New Net.Http.MultipartFormDataContent From { + {New Net.Http.StringContent(If(SkinInfo.IsSlim, "slim", "classic")), "variant"}, + {New Net.Http.ByteArrayContent(FileUtils.ReadAsBytes(SkinInfo.LocalFile)), "file", PathUtils.GetLastPart(SkinInfo.LocalFile)} + }, + Headers:={{"Authorization", "Bearer " & AccessToken}, {"Accept", "*/*"}, {"User-Agent", "MojangSharp/0.1"}}) + End Sub, 3) If Result.Contains("request requires user authentication") Then Hint("正在重新登录,将在登录后自动更改皮肤……") McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True) @@ -105,7 +110,7 @@ Retry: Return End If '获取新皮肤地址 - Log("[Skin] 皮肤修改返回值:" & vbCrLf & Result) + Logger.Info($"皮肤修改返回值:{vbCrLf}{Result}") Dim ResultJson As JObject = GetJson(Result) If ResultJson.ContainsKey("errorMessage") Then Throw New Exception(ResultJson("errorMessage").ToString) '#5309 For Each Skin As JObject In ResultJson("skins") @@ -116,15 +121,15 @@ Retry: Next Throw New Exception("未知错误(" & Result & ")") Catch ex As Exception - If TypeOf ex Is OperationCanceledException OrElse TypeOf ex Is TimeoutException Then + If ex.IsBadNetwork Then Hint("更改皮肤失败:连接皮肤服务器超时,请稍后再试,或使用 VPN 改善网络环境", HintType.Red) - ElseIf TypeOf ex Is ResponsedWebException AndAlso CType(ex, ResponsedWebException).StatusCode = HttpStatusCode.Unauthorized Then - Log(ex, "更改皮肤时遭遇 401 错误", NotifyLevel.DevelopOnly) + ElseIf TypeOf ex Is HttpRequestCodeException AndAlso CType(ex, HttpRequestCodeException).StatusCode = HttpStatusCode.Unauthorized Then + Logger.Warn(ex, "更改皮肤时遭遇 401 错误") Hint("正在重新登录,将在登录后自动更改皮肤……") McLoginMsLoader.Start(GetLoginData(), IsForceRestart:=True) GoTo Retry Else - Log(ex, "更改皮肤失败", NotifyLevel.AllUsers) + Logger.Error(ex, "更改皮肤失败", LogBehavior.Toast) End If Finally IsChanging = False diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNide.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNide.xaml.vb index f26b59b..74ebbaf 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNide.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNide.xaml.vb @@ -5,20 +5,20 @@ ''' Public Sub Reload(KeepInput As Boolean) '记住密码 - CheckRemember.Checked = Settings.Get("LoginRemember") + CheckRemember.Checked = Settings.Get(Of Boolean)("LoginRemember") If KeepInput AndAlso Not IsFirstLoad Then '避免第一次就以 KeepInput 的方式加载,导致文本框里没东西 '保留输入,只刷新下拉框列表 Dim Input As String = ComboName.Text - ComboName.ItemsSource = If(Settings.Get("LoginNideEmail") = "", Nothing, Settings.Get("LoginNideEmail").ToString.Split("¨")) + ComboName.ItemsSource = If(Settings.Get(Of String)("LoginNideEmail") = "", Nothing, Settings.Get(Of String)("LoginNideEmail").ToString.Split("¨")) ComboName.Text = Input Else '不保留输入,刷新列表后自动选择第一项 - If Settings.Get("LoginNideEmail") = "" Then + If Settings.Get(Of String)("LoginNideEmail") = "" Then ComboName.ItemsSource = Nothing Else - ComboName.ItemsSource = Settings.Get("LoginNideEmail").ToString.Split("¨") - ComboName.Text = Settings.Get("LoginNideEmail").ToString.BeforeFirst("¨") - If Settings.Get("LoginRemember") Then TextPass.Password = Settings.Get("LoginNidePass").ToString.BeforeFirst("¨").Trim + ComboName.ItemsSource = Settings.Get(Of String)("LoginNideEmail").Split("¨") + ComboName.Text = Settings.Get(Of String)("LoginNideEmail").BeforeFirst("¨") + If Settings.Get(Of Boolean)("LoginRemember") Then TextPass.Password = Settings.Get(Of String)("LoginNidePass").BeforeFirst("¨").Trim End If End If IsFirstLoad = False @@ -27,7 +27,7 @@ ''' 获取当前页面的登录信息。 ''' Public Shared Function GetLoginData() As McLoginServer - Dim Server As String = If(IsNothing(McInstanceSelected), Settings.Get("CacheNideServer"), Settings.Get("VersionServerNide", Instance:=McInstanceSelected)) + Dim Server As String = If(IsNothing(McInstanceSelected), Settings.Get(Of String)("CacheNideServer"), Settings.Get(Of String)("VersionServerNide", Instance:=McInstanceSelected)) If FrmLoginNide Is Nothing Then Return New McLoginServer(McLoginType.Nide) With {.Token = "Nide", .UserName = "", .Password = "", .Description = "统一通行证", .Type = McLoginType.Nide, .BaseUrl = "https://auth.mc-user.com:233/" & Server & "/authserver"} Else @@ -55,10 +55,10 @@ If AniControlEnabled = 0 Then Settings.Set("CacheNideAccess", "") End Sub Private Sub ComboName_SelectionChanged(sender As MyComboBox, e As SelectionChangedEventArgs) Handles ComboName.SelectionChanged - If sender.SelectedIndex = -1 OrElse Not Settings.Get("LoginRemember") Then + If sender.SelectedIndex = -1 OrElse Not Settings.Get(Of Boolean)("LoginRemember") Then TextPass.Password = "" Else - TextPass.Password = Settings.Get("LoginNidePass").ToString.Split("¨")(sender.SelectedIndex).Trim + TextPass.Password = Settings.Get(Of String)("LoginNidePass").Split("¨")(sender.SelectedIndex).Trim End If End Sub Private Sub CheckBoxChange(sender As MyCheckBox, e As Object) Handles CheckRemember.Change @@ -71,7 +71,7 @@ End Sub Private Sub Btn_Click(sender As Object, e As EventArgs) Handles BtnLink.Click If BtnLink.Content = "注册账号" Then - OpenWebsite("https://login.mc-user.com:233/" & Settings.Get("VersionServerNide", Instance:=McInstanceSelected) & "/register") + OpenWebsite("https://login.mc-user.com:233/" & Settings.Get(Of String)("VersionServerNide", Instance:=McInstanceSelected) & "/register") Else OpenWebsite("https://login.mc-user.com:233/account/login") End If diff --git a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNideSkin.xaml.vb b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNideSkin.xaml.vb index dfe5ffa..c8367c8 100644 --- a/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNideSkin.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLaunch/PageLoginNideSkin.xaml.vb @@ -12,17 +12,17 @@ ''' 刷新页面显示的所有信息。 ''' Public Sub Reload(KeepInput As Boolean) - TextName.Text = Settings.Get("CacheNideName") - TextEmail.Text = Settings.Get("CacheNideUsername") - TextEmail.Visibility = If(Settings.Get("UiLauncherEmail"), Visibility.Collapsed, Visibility.Visible) + TextName.Text = Settings.Get(Of String)("CacheNideName") + TextEmail.Text = Settings.Get(Of String)("CacheNideUsername") + TextEmail.Visibility = (Not Settings.Get(Of Boolean)("UiLauncherEmail")).ToVisibility '皮肤在 Loaded 加载 End Sub ''' ''' 获取当前页面的登录信息。 ''' Public Shared Function GetLoginData() As McLoginServer - Dim Server As String = If(IsNothing(McInstanceSelected), Settings.Get("CacheNideServer"), Settings.Get("VersionServerNide", Instance:=McInstanceSelected)) - Return New McLoginServer(McLoginType.Nide) With {.Token = "Nide", .UserName = Settings.Get("CacheNideUsername"), .Password = Settings.Get("CacheNidePass"), .Description = "统一通行证", .Type = McLoginType.Nide, .BaseUrl = "https://auth.mc-user.com:233/" & Server & "/authserver"} + Dim Server As String = If(IsNothing(McInstanceSelected), Settings.Get(Of String)("CacheNideServer"), Settings.Get(Of String)("VersionServerNide", Instance:=McInstanceSelected)) + Return New McLoginServer(McLoginType.Nide) With {.Token = "Nide", .UserName = Settings.Get(Of String)("CacheNideUsername"), .Password = Settings.Get(Of String)("CacheNidePass"), .Description = "统一通行证", .Type = McLoginType.Nide, .BaseUrl = "https://auth.mc-user.com:233/" & Server & "/authserver"} End Function Private Sub PageLoginNideSkin_MouseEnter(sender As Object, e As MouseEventArgs) Handles PanData.MouseEnter @@ -51,7 +51,7 @@ End Sub Private Sub Skin_Click(sender As Object, e As MouseButtonEventArgs) Handles Skin.Click - OpenWebsite("https://login.mc-user.com:233/" & If(IsNothing(McInstanceSelected), Settings.Get("CacheNideServer"), Settings.Get("VersionServerNide", Instance:=McInstanceSelected)) & "/skin") + OpenWebsite("https://login.mc-user.com:233/" & If(IsNothing(McInstanceSelected), Settings.Get(Of String)("CacheNideServer"), Settings.Get(Of String)("VersionServerNide", Instance:=McInstanceSelected)) & "/skin") End Sub End Class diff --git a/Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb b/Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb index 7014f98..5b795ae 100644 --- a/Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageLink/PageLinkMain.xaml.vb @@ -25,7 +25,7 @@ Public Class PageLinkMain If LinkState = NewState Then Return Dim OldState = LinkState LinkState = NewState - Log($"[Link] 主状态由 {GetStringFromEnum(OldState)} 变更为 {GetStringFromEnum(NewState)}") + Logger.Info($"主状态由 {OldState} 变更为 {NewState}") '触发状态切换 RunInUi( Sub() @@ -51,7 +51,7 @@ Public Class PageLinkMain Case LoadState.Finished ChangeState(LinkStates.Finished) Case LoadState.Failed - Telemetry("联机失败", "Exception", FilterUserName(Loader.Error.GetDetail, "*")) + Telemetry("联机失败", "Exception", FilterUserName(Loader.Error.GetDisplay(True), "*")) ChangeState(LinkStates.Failed) End Select End Sub @@ -109,7 +109,7 @@ Public Class PageLinkMain NetworkName = $"P{ServerPort.ConvertRadix(16).PadLeft(4, "0"c)}-{GenerateRandomCode()}" NetworkSecret = GenerateRandomCode() DiscoverNodeID = -1 - Log($"[Link] 尝试创建房间,网络名 {NetworkName},网络密码 {NetworkSecret},端口 {ServerPort}") + Logger.Info($"尝试创建房间,网络名 {NetworkName},网络密码 {NetworkSecret},端口 {ServerPort}") '启动 ChangeState(LinkStates.Loading) End Sub @@ -135,7 +135,7 @@ Public Class PageLinkMain Return End If Code = FixCodeFormat(Code) - Log($"[Link] 实际使用的邀请码:{Code}") + Logger.Info($"实际使用的邀请码:{Code}") '基础信息 IsServerSide = False ServerPort = Code.Substring(1, 4).Upper.ConvertRadix(16, 10) @@ -146,7 +146,7 @@ Public Class PageLinkMain Else DiscoverNodeID = Code.Substring(20, 3).Upper.ConvertRadix(16, 10) End If - Log($"[Link] 尝试加入房间,网络名 {NetworkName},网络密码 {NetworkSecret},端口 {ServerPort},发现节点 {DiscoverNodeID}") + Logger.Info($"尝试加入房间,网络名 {NetworkName},网络密码 {NetworkSecret},端口 {ServerPort},发现节点 {DiscoverNodeID}") '启动 LastCode = Code ChangeState(LinkStates.Loading) @@ -229,15 +229,15 @@ Public Class PageLinkMain UpdateProgressBar(1) '显示错误信息 LabLoadTitle.Text = FailReason - Dim Brief As String = LinkLoader.Error.GetBrief + Dim Brief As String = LinkLoader.Error.GetDisplay(False) Dim InnerEx As Exception = LinkLoader.Error If InnerEx.Message.StartsWithF("$") Then Brief = InnerEx.Message Do Until InnerEx.InnerException Is Nothing InnerEx = InnerEx.InnerException If InnerEx.Message.StartsWithF("$") Then Brief = InnerEx.Message Loop - LabLoadDesc.Text = If(Brief.StartsWithF("$"), Brief.TrimStart("$"), LinkLoader.Error.GetDetail) - Log(LinkLoader.Error, LabLoadTitle.Text) + LabLoadDesc.Text = If(Brief.StartsWithF("$"), Brief.TrimStart("$"), LinkLoader.Error.GetDisplay(True)) + Logger.Warn(LinkLoader.Error, LabLoadTitle.Text) End Sub '=============================== @@ -247,7 +247,7 @@ Public Class PageLinkMain Private Sub UpdateLoadingPage(Title As String, FailBrief As String) If FailReason = FailBrief & "失败" Then Return FailReason = FailBrief & "失败" - Log("[Link] 开始步骤:" & Title) + Logger.Info($"开始步骤:{Title}") RunInUiWait( Sub() If FrmLinkMain Is Nothing OrElse Not FrmLinkMain.LabLoadDesc.IsLoaded Then Return @@ -451,21 +451,21 @@ Public Class PageLinkMain Case Reflection.ProcessorArchitecture.Arm Architecture = "arm64" Case Else - Log($"[Link] CPU 是不支持的 {Architecture} 架构,这可能会导致联机模块无法启动!", NotifyLevel.DebugModeOnly) + Logger.Warn($"CPU 是不支持的 {Architecture} 架构,这可能会导致联机模块无法启动!") Architecture = "arm64" End Select - Log("[Link] CPU 架构:" & Architecture) + Logger.Info($"CPU 架构:{Architecture}") Telemetry("联机开始") '检查 EasyTier 版本 UpdateLoadingPage("正在检查联机模块版本……", "检查联机模块版本") - If Not (File.Exists(PathEasyTier & "联机模块 CLI.exe") AndAlso File.Exists(PathEasyTier & "联机模块.exe") AndAlso - File.Exists(PathEasyTier & "Packet.dll")) Then + If Not (FileUtils.Exists(PathEasyTier & "联机模块 CLI.exe") AndAlso FileUtils.Exists(PathEasyTier & "联机模块.exe") AndAlso + FileUtils.Exists(PathEasyTier & "Packet.dll")) Then Settings.Set("LinkEasyTierVersion", -1) End If - Dim LocalVersion As Integer = Settings.Get("LinkEasyTierVersion") + Dim LocalVersion As Integer = Settings.Get(Of Integer)("LinkEasyTierVersion") ServerVersion = ServerConfig("Link")("EasyTierVersion") Dim RequiredFiles As New List(Of NetFile) - Log($"[Link] EasyTier 本地版本:{LocalVersion},需求版本:{ServerVersion}") + Logger.Info($"EasyTier 本地版本:{LocalVersion},需求版本:{ServerVersion}") If LocalVersion < ServerVersion Then RequiredFiles.Add(New NetFile( ServerConfig("Link")("Downloads").Select(Function(UrlEntry) UrlEntry.ToString.Replace("{arch}", Architecture)), @@ -481,28 +481,26 @@ Public Class PageLinkMain Private Sub InitLaunch(Task As LoaderTask(Of Integer, Integer)) '解压文件 UpdateLoadingPage("正在解压联机模块……", "解压联机模块") - If File.Exists(PathEasyTier & "EasyTier.zip") Then + If FileUtils.Exists(PathEasyTier & "EasyTier.zip") Then '解压 Dim ExtractPath As String = RequestTaskTempFolder() - ExtractCompressedFile(PathEasyTier & "EasyTier.zip", ExtractPath, - ProgressIncrementHandler:=Sub(Progress) Task.Progress += Progress * 0.05) - Dim ExtractedPath As String = New DirectoryInfo(ExtractPath).EnumerateDirectories.FirstOrDefault?.FullName - Log("[Link] 联机模块解压时的临时路径:" & ExtractedPath) - CopyDirectory(ExtractedPath, PathEasyTier) + FileUtils.ExtractToDirectory(PathEasyTier & "EasyTier.zip", ExtractPath, + progressHandler:=Sub(Percentage) Task.Progress = Percentage * 0.05) + DirectoryUtils.Copy(DirectoryUtils.GetDirectories(ExtractPath).First, PathEasyTier) '重命名 - File.Delete(PathEasyTier & "联机模块.exe") - File.Move(PathEasyTier & "easytier-core.exe", PathEasyTier & "联机模块.exe") - File.Delete(PathEasyTier & "联机模块 CLI.exe") - File.Move(PathEasyTier & "easytier-cli.exe", PathEasyTier & "联机模块 CLI.exe") + FileUtils.Delete(PathEasyTier & "联机模块.exe") + FileUtils.Move(PathEasyTier & "easytier-core.exe", PathEasyTier & "联机模块.exe") + FileUtils.Delete(PathEasyTier & "联机模块 CLI.exe") + FileUtils.Move(PathEasyTier & "easytier-cli.exe", PathEasyTier & "联机模块 CLI.exe") '清理 - File.Delete(PathEasyTier & "EasyTier.zip") + FileUtils.Delete(PathEasyTier & "EasyTier.zip") Settings.Set("LinkEasyTierVersion", ServerVersion) End If Task.Progress = 0.07 '获取节点列表 UpdateLoadingPage("正在获取节点列表……", "获取节点列表") Dim RawPeers As List(Of String) - Dim CustomPeers As String = Settings.Get("LinkCustomPeer") + Dim CustomPeers As String = Settings.Get(Of String)("LinkCustomPeer") If String.IsNullOrWhiteSpace(CustomPeers) Then If DiscoverNodeID = -2 AndAlso Not IsServerSide Then Panic("未填写自定义节点设置", $"$你必须在 {vbLQ}自定义节点{vbRQ} 设置中填写与房主相同的内容,{vbCrLf}才能进入该房间!") @@ -512,7 +510,7 @@ Public Class PageLinkMain Else If DiscoverNodeID <> -2 AndAlso Not IsServerSide Then Hint("房主可能没有使用自定义节点设置,请确认你们的自定义节点设置是否一致!") RawPeers = CustomPeers.Split(",,".ToCharArray).Select(Function(p) p.Trim).Where(Function(p) Not String.IsNullOrEmpty(p)).ToList() - Log("[Link] 使用自定义节点:" & CustomPeers) + Logger.Info($"使用自定义节点:{CustomPeers}") End If Task.Progress = 0.13 '获取空闲端口 @@ -539,7 +537,7 @@ Public Class PageLinkMain For Each Peer As String In RawPeers Arguments += $" -p=""{Peer}""" Next - If Settings.Get("LinkLatencyMode") = 1 Then Arguments += " --latency-first" + If Settings.Get(Of Integer)("LinkLatencyMode") = 1 Then Arguments += " --latency-first" '启动进程 ProcessStart(Arguments) Task.Progress = 0.15 @@ -553,7 +551,7 @@ Public Class PageLinkMain '查找目标节点 Dim Ping = GetPeerPing() If Ping > 0 Then - Log($"[Link] 已与目标建立连接,当前 Ping 为 {Ping:0.0}ms") + Logger.Info($"已与目标建立连接,当前 Ping 为 {Ping:0.0}ms") Telemetry("联机成功", "Server", IsServerSide, "NAT", NATType) Exit Do '退出循环 End If @@ -616,7 +614,7 @@ Public Class PageLinkMain Try RawNodes = GetJson(NetRequestByClient("https://uptime.easytier.cn/api/nodes?page=1&per_page=1000", RequireJson:=True)) Catch exx As Exception - Log(exx, "从源站获取节点列表失败,将使用 CDN 缓存") + Logger.Warn(exx, "从源站获取节点列表失败,将使用 CDN 缓存") RawNodes = GetJson(NetRequestByClientRetry("https://easytier.meloong.com/?page=1&per_page=1000", RequireJson:=True)) IsFallbackRawList = True End Try @@ -654,18 +652,18 @@ ForcedPass: ElseIf DiscoverNodeID > 0 Then '>0:作为加入者,根据 ID 选择对应的发现节点;如果没有,使用回退发现节点 SelectedDiscoverNode = Nodes.FirstOrDefault(Function(n) n("id").ToObject(Of Integer) = DiscoverNodeID) If SelectedDiscoverNode Is Nothing Then - Log($"[Link] 未找到 ID {DiscoverNodeID} 的发现节点", NotifyLevel.DebugModeOnly) + Logger.Warn($"未找到 ID {DiscoverNodeID} 的发现节点") Panic("房间已过期", "请让房主重新创建房间!") Throw New ThreadInterruptedException End If End If If SelectedDiscoverNode Is Nothing Then '使用回退发现节点 SelectedDiscoverNode = New JObject From {{"address", FallbackDiscoverAddress}, {"id", FallbackDiscoverID}} - Log("[Link] 将使用回退发现节点", NotifyLevel.DebugModeOnly) + Logger.Warn("将使用回退发现节点") End If FinalPeers.Add(SelectedDiscoverNode("address").ToString()) FinalDiscoverID = SelectedDiscoverNode("id").ToObject(Of Integer) - Log($"[Link] 发现节点:{SelectedDiscoverNode("address")} (ID: {FinalDiscoverID})") + Logger.Info($"发现节点:{SelectedDiscoverNode("address")} (ID: {FinalDiscoverID})") '选取中继节点 If ModeDebug OrElse Not IsServerSide Then '房主只连接发现节点,不连接中继节点 Dim RelayCount As Integer = ServerConfig("Link")("RandomPeer").ToObject(Of Integer) @@ -676,7 +674,7 @@ ForcedPass: Catch ex As ThreadInterruptedException Throw Catch ex As Exception - Log(ex, "获取节点列表失败,联机质量可能受到影响", NotifyLevel.AllUsers) + Logger.Error(ex, "获取节点列表失败,联机质量可能受到影响", LogBehavior.Toast) FinalPeers.AddRange(ServerConfig("Link")("Peers").Select(Function(p) p.ToString)) If FinalDiscoverID <= 0 Then FinalPeers.Add(FallbackDiscoverAddress) @@ -716,16 +714,16 @@ ForcedPass: If ProcessObject.Id = ProcessCore?.Id Then Continue For If ProcessObject.ProcessName <> "联机模块" AndAlso ProcessObject.ProcessName <> "联机模块 CLI" Then Continue For Try - Log("[Link] 停止残留的联机模块,PID:" & ProcessObject.Id & ",进程名:" & ProcessObject.ProcessName) + Logger.Info($"停止残留的联机模块,PID:{ProcessObject.Id},进程名:{ProcessObject.ProcessName}") ProcessObject.Kill() ProcessObject.Close() Catch exx As Exception - Log(exx, $"结束进程失败({ProcessObject.ProcessName},PID {ProcessObject.Id})") + Logger.Warn(exx, $"结束进程失败({ProcessObject.ProcessName},PID {ProcessObject.Id})") End Try Next '关闭由自身启动的进程 If ProcessCore IsNot Nothing AndAlso Not ProcessCore.HasExited Then - Log("[Link] 停止所启动的联机模块,PID:" & ProcessCore.Id) + Logger.Info($"停止所启动的联机模块,PID:{ProcessCore.Id}") ProcessCore.Kill() ProcessCore.Close() ProcessCore = Nothing @@ -734,7 +732,7 @@ ForcedPass: ProcessOutputHandle?.Dispose() ProcessErrorHandle?.Dispose() Catch ex As Exception - Log(ex, "停止联机模块失败") + Logger.Warn(ex, "停止联机模块失败") End Try End Sub ''' @@ -770,7 +768,7 @@ ForcedPass: .StandardOutputEncoding = Encoding.UTF8, .StandardErrorEncoding = Encoding.UTF8 } - Log("[Link] 正在启动 EasyTier:" & Arguments) + Logger.Info($"正在启动 EasyTier:{Arguments}") ProcessCore = New Process With {.StartInfo = Info} Dim LogLineHandler = Function(sender As Object, e As DataReceivedEventArgs, Handle As AutoResetEvent) @@ -782,7 +780,7 @@ ForcedPass: ProcessLogLine(e.Data) Catch unused As ObjectDisposedException Catch ex As Exception - Log(ex, "读取 EasyTier 信息失败") + Logger.Warn(ex, "读取 EasyTier 信息失败") End Try Return Nothing End Function @@ -796,15 +794,15 @@ ForcedPass: End Sub Private Sub ProcessLogLine(Line As String) '记录日志 - Log("[EasyTier] " & Line) + Logger.Info(Line) LogHistory.Enqueue(Line) If LogHistory.Count >= 10 Then LogHistory.Dequeue() '检查日志内容 If Line.ContainsIgnoreCase("new peer connection added") Then - Log("[Link] 已建立连接:" & If(RegexSeek(Line, "(?<=remote_addr.+?"")[^""}]{3,}"), Line), NotifyLevel.DebugModeOnly) + Logger.Warn($"已建立连接:{If(Line.RegexSeek("(?<=remote_addr.+?"")[^""}]{3,}"), Line)}") Update() ElseIf Line.ContainsIgnoreCase("peer connection removed") Then - Log("[Link] 已断开连接:" & If(RegexSeek(Line, "(?<=remote_addr.+?"")[^""}]{3,}"), Line), NotifyLevel.DebugModeOnly) + Logger.Warn($"已断开连接:{If(Line.RegexSeek("(?<=remote_addr.+?"")[^""}]{3,}"), Line)}") Update() End If End Sub @@ -919,7 +917,7 @@ ForcedPass: Dim CliResult = StartProcessAndGetOutput(PathEasyTier & "联机模块 CLI.exe", $"-o json -p 127.0.0.1:{RPCPort} peer", 2000, Encoding:=Encoding.UTF8, PrintLog:=False) '解析 If Not CliResult.Contains("lat_ms") Then Throw New Exception("CLI 调用失败:" & vbCrLf & CliResult) - If GetUuid() Mod If(ModeDebug, 23, 103) = 0 Then Log("[EasyTier] CLI 输出抽样:" & vbCrLf & CliResult) + If GetUuid() Mod If(ModeDebug, 23, 103) = 0 Then Logger.Info($"CLI 输出抽样:{vbCrLf}{CliResult}") Dim NewPeers As New List(Of Peer) For Each Line As JObject In CType(GetJson(CliResult), JArray) Try @@ -930,14 +928,14 @@ ForcedPass: NewPeers.Add(Peer) End If Catch exx As Exception - Log(exx, $"错误的信息({Line})") + Logger.Warn(exx, $"错误的信息({Line})") End Try Next '完成 Peers = NewPeers FailCount = 0 Catch ex As Exception - Log(ex, "获取节点信息失败") + Logger.Warn(ex, "获取节点信息失败") If LinkState = LinkStates.Finished Then FailCount += 1 If FailCount >= 4 Then Panic("获取节点信息失败", ex.Message) @@ -1011,7 +1009,7 @@ ForcedPass: '每 200ms 更新进度条 If LinkState = LinkStates.Loading Then RunInUi(AddressOf UpdateProgressBar) Catch ex As Exception - Log(ex, "联机模块主时钟出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "联机模块主时钟出错") Thread.Sleep(10000) End Try Loop @@ -1060,7 +1058,7 @@ ForcedPass: Else HintFinish.Text = "你或者房主的网络环境不太好," End If - If String.IsNullOrWhiteSpace(Settings.Get("LinkCustomPeer")) Then + If String.IsNullOrWhiteSpace(Settings.Get(Of String)("LinkCustomPeer")) Then HintFinish.Text &= "正使用社区节点进行中继。" Else HintFinish.Text &= "正通过自定义节点进行中继。" @@ -1102,7 +1100,7 @@ ForcedPass: SocketFlags.None, New IPEndPoint(IPAddress.Loopback, 4445)) Catch ex As Exception - Log(ex, "广播联机房间端口失败") + Logger.Warn(ex, "广播联机房间端口失败") End Try End If End Sub diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml index 676eae0..3f37fce 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherAbout.xaml @@ -117,30 +117,16 @@ - - - - + - - + - - + - - - - - - - - - @@ -154,104 +140,45 @@ - + + + + + + + + + + - - - - - - - + + - + - - - - - - - - - - + - - - - - + - + + - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -286,99 +213,72 @@ + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + - - - - - - - - - + + - - + - - + - + - + + + + - - + + + + - + + - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -411,126 +311,77 @@ - + + + + + + + + + + + + - - - - - - + + + - - - - + + + - - + - - - - - - - + - + - - - - - - + + - - - - - - - + + - - + - - + - + + - - - + + - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -565,80 +416,60 @@ + + + + + + + + + + + + + - + + + - - - - - - + - - + + + - - - - - - - - - - + - + + - + + - - - - - - - - - - - - - - - - - - - - - - - - @@ -654,49 +485,40 @@ - - + + + + + + + + + + + - - - - - + - - - - - + + + - - - - - - - - - - - - @@ -704,63 +526,55 @@ - + + + - - - - + - - + + + - - + + - - - - - - - + + + - - + - - - - + + + + - - - - - + - + - + + diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb index 79dcb3d..fa073d2 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelp.xaml.vb @@ -61,7 +61,7 @@ Next Catch ex As Exception - Log(ex, "加载帮助列表 UI 失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "加载帮助列表 UI 失败") End Try End Sub @@ -76,7 +76,7 @@ EnterHelpPage(Entry) End If Catch ex As Exception - Log(ex, "处理帮助项目点击时发生意外错误", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "处理帮助项目点击时发生意外错误") End Try End Sub Public Shared Sub EnterHelpPage(Location As String) @@ -90,7 +90,7 @@ If FrmHelpDetail.Init(Entry) Then FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.HelpDetail, .Additional = {Entry, FrmHelpDetail}}) Else - Log("[Help] 已取消进入帮助项目,这一般是由于 xaml 初始化失败,且用户在弹窗中手动放弃", NotifyLevel.DebugModeOnly) + Logger.Warn("已取消进入帮助项目,这一般是由于 xaml 初始化失败,且用户在弹窗中手动放弃") End If End Sub) End Sub) @@ -105,20 +105,11 @@ If FrmHelpDetail.Init(Entry) Then FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.HelpDetail, .Additional = {Entry, FrmHelpDetail}}) Else - Log("[Help] 已取消进入帮助项目,这一般是由于 xaml 初始化失败,且用户在弹窗中手动放弃", NotifyLevel.DebugModeOnly) + Logger.Warn("已取消进入帮助项目,这一般是由于 xaml 初始化失败,且用户在弹窗中手动放弃") End If End Sub) End Sub) End Sub - Public Shared Function GetHelpPage(Location As String) As PageOtherHelpDetail - If Not HelpLoader.State = LoadState.Finished Then HelpLoader.WaitForExit(GetUuid) - Dim FrmHelpDetail As New PageOtherHelpDetail - If FrmHelpDetail.Init(New HelpEntry(Location)) Then - Return FrmHelpDetail - Else - Throw New Exception("已取消进入帮助项目,这一般是由于 xaml 初始化失败,且用户在弹窗中手动放弃") - End If - End Function ''' ''' 搜索帮助。 diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb index 3936805..03464cd 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherHelpDetail.xaml.vb @@ -22,14 +22,14 @@ Do While Content.Contains("xmlns") Content = Content.RegexReplace("xmlns[^""']*(""|')[^""']*(""|')", "").Replace("xmlns", "") '禁止声明命名空间 Loop - Content = "" & Content & "" + Content = "" & Content & "" Me.Entry = Entry PanCustom.Children.Clear() PanCustom.Children.Add(GetObjectFromXML(Content)) Return True Catch ex As Exception - Log("[System] 自定义信息内容:" & vbCrLf & Content) - Log(ex, "加载帮助 XAML 文件失败", NotifyLevel.MsgBox) + Logger.Info($"自定义信息内容:{vbCrLf}{Content}") + Logger.Error(ex, "加载帮助 XAML 文件失败", LogBehavior.Alert) Return False End Try End Function diff --git a/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml.vb index 8a3f3af..b78b4fb 100644 --- a/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageOther/PageOtherLeft.xaml.vb @@ -5,9 +5,9 @@ Private Sub PageOtherLeft_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded '是否处于隐藏的子页面 Dim IsHiddenPage As Boolean = False - If ItemHelp.Checked AndAlso Settings.Get("UiHiddenOtherHelp") Then IsHiddenPage = True - If ItemAbout.Checked AndAlso Settings.Get("UiHiddenOtherAbout") Then IsHiddenPage = True - If ItemTest.Checked AndAlso Settings.Get("UiHiddenOtherTest") Then IsHiddenPage = True + If ItemHelp.Checked AndAlso Settings.Get(Of Boolean)("UiHiddenOtherHelp") Then IsHiddenPage = True + If ItemAbout.Checked AndAlso Settings.Get(Of Boolean)("UiHiddenOtherAbout") Then IsHiddenPage = True + If ItemTest.Checked AndAlso Settings.Get(Of Boolean)("UiHiddenOtherTest") Then IsHiddenPage = True If PageSetupUI.HiddenForceShow Then IsHiddenPage = False '若页面错误,或尚未加载,则继续 If IsLoad AndAlso Not IsHiddenPage Then Return @@ -16,9 +16,9 @@ PageSetupUI.HiddenRefresh() '选择第一个未被禁用的子页面 If IsPageSwitched Then Return - If Not Settings.Get("UiHiddenOtherHelp") Then + If Not Settings.Get(Of Boolean)("UiHiddenOtherHelp") Then ItemHelp.SetChecked(True, False, False) - ElseIf Not Settings.Get("UiHiddenOtherAbout") Then + ElseIf Not Settings.Get(Of Boolean)("UiHiddenOtherAbout") Then ItemAbout.SetChecked(True, False, False) Else ItemTest.SetChecked(True, False, False) @@ -37,9 +37,9 @@ Public Sub New() InitializeComponent() '选择第一个未被禁用的子页面 - If Not Settings.Get("UiHiddenOtherHelp") Then + If Not Settings.Get(Of Boolean)("UiHiddenOtherHelp") Then PageID = FormMain.PageSubType.OtherHelp - ElseIf Not Settings.Get("UiHiddenOtherAbout") Then + ElseIf Not Settings.Get(Of Boolean)("UiHiddenOtherAbout") Then PageID = FormMain.PageSubType.OtherAbout Else PageID = FormMain.PageSubType.OtherTest @@ -83,7 +83,7 @@ PageChangeRun(PageGet(ID)) PageID = ID Catch ex As Exception - Log(ex, "切换分页面失败(ID " & ID & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"切换分页面失败(ID {ID})") Finally AniControlEnabled -= 1 End Try @@ -131,7 +131,12 @@ e.Handled = True End Sub Public Shared Sub TryFeedback() - If Not CanFeedback(True) Then Return + If False.Equals(PageSetupSystem.IsLauncherNewest) Then + If MyMsgBox($"你的 PCL 不是最新版,因此无法提交反馈。{vbCrLf}请在更新后,确认该问题在最新版中依然存在,然后再提交反馈。", "无法提交反馈", "更新", "取消") = 1 Then + UpdateCheckByButton() + End If + Return + End If Select Case MyMsgBox("在提交新反馈前,建议先搜索反馈列表,以避免重复提交。" & vbCrLf & "如果无法打开该网页,请使用 VPN 改善网络环境。", "反馈", "提交新反馈", "查看反馈列表", "取消") Case 1 diff --git a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb index 3cbb64a..adc4958 100644 --- a/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSelectLeft.xaml.vb @@ -81,14 +81,14 @@ End Sub NewItem.Buttons = {NewIconButton} FrmSelectLeft.PanList.Children.Add(NewItem) - Log("[Minecraft] 有效的 Minecraft 文件夹:" & Folder.Name & " > " & Folder.Location) + Logger.Info($"有效的 Minecraft 文件夹:{Folder.Name} > {Folder.Location}") Next '标题文本 FrmSelectLeft.PanList.Children.Add(New TextBlock With {.Text = "添加或导入", .Margin = New Thickness(13, 18, 5, 4), .Opacity = 0.6, .FontSize = 12}) '确认创建按钮状态 - If Not Directory.Exists(PathExeFolder & ".minecraft\") Then + If Not DirectoryUtils.Exists(PathExeFolder & ".minecraft\") Then Dim ItemCreate As New MyListItem With {.IsScaleAnimationEnabled = False, .Type = MyListItem.CheckType.Clickable, .Title = "新建 .minecraft 文件夹", .Height = 34, .ToolTip = "在 PCL 当前所在文件夹下创建新的 .minecraft 文件夹", .LogoScale = 0.9, @@ -138,7 +138,7 @@ End If Catch ex As Exception - Log(ex, "构建 Minecraft 文件夹列表 UI 出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "构建 Minecraft 文件夹列表 UI 出错") Finally LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.RunOnUpdated, MaxDepth:=1, ExtraPath:="versions\") '刷新版本列表 End Try @@ -155,8 +155,8 @@ End If Try '获取输入 - NewFolder = SelectFolder() - If NewFolder = "" Then Return + NewFolder = Dialogs.SelectFolder("选择 Minecraft 文件夹", False).FirstOrDefault + If NewFolder Is Nothing Then Return If NewFolder.Contains("!") OrElse NewFolder.Contains(";") Then Hint("Minecraft 文件夹路径中不能含有感叹号或分号!", HintType.Red) : Return '要求输入显示名称 Dim SplitedNames As String() = NewFolder.TrimEnd("\").Split("\") @@ -168,7 +168,7 @@ '添加文件夹 AddFolder(NewFolder, NewName, True) Catch ex As Exception - Log(ex, "添加文件夹失败(" & NewFolder & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"添加文件夹失败({NewFolder})") End Try End Sub ''' @@ -190,15 +190,15 @@ End If '检查实际的 Minecraft 文件夹位置(没有问题,或是在子文件夹中) If Not CheckPermission(FolderPath & "versions\") Then - For Each Folder As DirectoryInfo In New DirectoryInfo(FolderPath).GetDirectories - If CheckPermission(Folder.FullName & "\versions\") Then - FolderPath = Folder.FullName & "\" + For Each Folder In DirectoryUtils.GetDirectories(FolderPath) + If CheckPermission(Folder & "\versions\") Then + FolderPath = Folder & "\" Exit For End If Next End If '判断是否已经添加过,若添加过则直接修改自定义名 - Dim Folders As New List(Of String)(Settings.Get("LaunchFolders").ToString.Split("|")) + Dim Folders As New List(Of String)(Settings.Get(Of String)("LaunchFolders").Split("|")) Dim IsAdded As Boolean = False Dim IsReplace As Boolean = False For i = 0 To Folders.Count - 1 @@ -229,10 +229,10 @@ If ShowHint Then Hint("文件夹 " & DisplayName & " 已添加!", HintType.Green) '检查是否为根目录整合包,自动关闭版本隔离 '1. 根目录中存在数个 Mod - Dim ModFolder As New DirectoryInfo(FolderPath & "mods\") + Dim ModFolder = DirectoryUtils.GetInfo(FolderPath & "mods\") If Not (ModFolder.Exists AndAlso ModFolder.EnumerateFiles.Count >= 3) Then Return '2. 版本数较少,可能为整合包 - Dim VersionFolderInfo As New DirectoryInfo(FolderPath & "versions\") + Dim VersionFolderInfo = DirectoryUtils.GetInfo(FolderPath & "versions\") If Not (VersionFolderInfo.Exists AndAlso VersionFolderInfo.EnumerateDirectories.Count <= 3) Then Return '3. 能够找到可安装 Mod 的版本 For Each VersionFolder In VersionFolderInfo.EnumerateDirectories @@ -240,15 +240,15 @@ Instance.Load() If Not Instance.Modable Then Continue For '4. 该版本的隔离文件夹下不存在 mods - Dim ModIndieFolder As New DirectoryInfo(Instance.PathVersion & "mods\") + Dim ModIndieFolder = DirectoryUtils.GetInfo(Instance.PathVersion & "mods\") If ModIndieFolder.Exists AndAlso ModIndieFolder.EnumerateFiles.Any Then Return '满足以上全部条件则视为根目录整合包 Settings.Set("VersionArgumentIndie", 2, Instance:=Instance) Settings.Set("VersionArgumentIndieV2", False, Instance:=Instance) - Log("[Setup] 已自动关闭单版本隔离:" & Instance.Name, NotifyLevel.DebugModeOnly) + Logger.Warn($"已自动关闭单版本隔离:{Instance.Name}") Next Catch ex As Exception - Log(ex, "向文件夹列表中添加新文件夹失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "向文件夹列表中添加新文件夹失败") End Try End Sub) End Sub @@ -265,11 +265,11 @@ End Sub Public Shared Sub CreateMcFolderInCurrentPath() McFolderSelected = PathExeFolder & ".minecraft\" - If Not Directory.Exists(McFolderSelected) Then + If Not DirectoryUtils.Exists(McFolderSelected) Then DirectoryUtils.Create(McFolderSelected & "versions\") McFolderLauncherProfilesJsonCreate(McFolderSelected) End If - AddFolder(McFolderSelected, GetFolderNameFromPath(PathExeFolder), False) + AddFolder(McFolderSelected, PathUtils.GetLastPart(PathExeFolder), False) End Sub '右键菜单 @@ -282,12 +282,10 @@ Select Case MyMsgBox("是否需要清理 PCL 在该文件夹中的配置文件?" & vbCrLf & "这包括各个版本的独立设置(如自定义图标、第三方登录配置)等,对游戏本身没有影响。", "配置文件清理", "删除", "保留", "取消") Case 1 '删除配置文件 - If File.Exists(Target.Location & "PCL.ini") Then File.Delete(Target.Location & "PCL.ini") - If Directory.Exists(Target.Location & "versions\") Then - For Each InstanceInfo In New DirectoryInfo(Target.Location & "versions\").EnumerateDirectories - If Directory.Exists(InstanceInfo.FullName & "\PCL\") Then DeleteDirectory(InstanceInfo.FullName & "\PCL\", True) - Next - End If + FileUtils.Delete(Target.Location & "PCL.ini") + For Each Instance In DirectoryUtils.GetDirectories(Target.Location & "versions\", True) + DirectoryUtils.Delete(Path.Combine(Instance, "PCL"), True) + Next Case 2 '不删除 Case 3 @@ -299,7 +297,7 @@ Hint(If(Target.Type = McFolder.Types.Custom, "文件夹 " & DeletedName & " 已从列表中移除!", "文件夹名称已复原!"), HintType.Green) McFolderListLoader.Start(IsForceRestart:=True) Catch ex As Exception - Log(ex, "从列表中移除游戏文件夹失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "从列表中移除游戏文件夹失败") End Try End Sub Public Sub Delete_Click(sender As Object, e As RoutedEventArgs) @@ -320,11 +318,11 @@ '删除文件夹 Try Hint("正在" & DeleteText & "文件夹 " & Target.Name & "!", HintType.Blue) - DeleteDirectory(Target.Location) + DirectoryUtils.Delete(Target.Location) If DeleteText = "清空" Then DirectoryUtils.Create(Target.Location) Hint("已" & DeleteText & "文件夹 " & Target.Name & "!", HintType.Green) Catch ex As Exception - Log(ex, DeleteText & "文件夹 " & Target.Name & " 失败", NotifyLevel.AllUsers) + Logger.Error(ex, $"{DeleteText}文件夹 {Target.Name} 失败", LogBehavior.Toast) Finally '刷新列表 McFolderListLoader.Start(IsForceRestart:=True) @@ -337,7 +335,7 @@ ''' Private Shared Function RemoveFolderFromSetup(Target As McFolder) As String Dim DeletedName As String = Nothing - Dim Folders = Settings.Get("LaunchFolders").ToString.Split({"|"c}, StringSplitOptions.RemoveEmptyEntries).ToList + Dim Folders = Settings.Get(Of String)("LaunchFolders").Split("|"c, True).ToList For Each Folder In Folders.ToList If Not Folder.EndsWithF(Target.Location) Then Continue For DeletedName = Folder.BeforeFirst(">") @@ -371,7 +369,7 @@ New ObjectModel.Collection(Of Validate) From {New ValidateNullOrWhiteSpace, New ValidateLength(1, 30), New ValidateExcept({">", "|"})}) If String.IsNullOrWhiteSpace(NewName) Then Return '修改自定义名 - Dim Folders As New List(Of String)(Settings.Get("LaunchFolders").ToString.Split("|")) + Dim Folders As New List(Of String)(Settings.Get(Of String)("LaunchFolders").Split("|")) Dim IsAdded As Boolean = False For i = 0 To Folders.Count - 1 Dim FolderCurrent As String = Folders(i) @@ -394,7 +392,7 @@ Settings.Set("LaunchFolders", Folders.Join("|")) McFolderListLoader.Start(IsForceRestart:=True) Catch ex As Exception - Log(ex, "重命名文件夹失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "重命名文件夹失败") End Try End Sub diff --git a/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb b/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb index 93e6911..f70231f 100644 --- a/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSelectRight.xaml.vb @@ -102,7 +102,7 @@ Else LabEmptyTitle.Text = "无可用版本" LabEmptyContent.Text = "未找到任何版本的游戏,请先下载任意版本的游戏。" & vbCrLf & "若有已存在的游戏,请在左边的列表中选择添加文件夹,选择 .minecraft 文件夹将其导入。" - BtnEmptyDownload.Visibility = If(Settings.Get("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow, Visibility.Collapsed, Visibility.Visible) + BtnEmptyDownload.Visibility = If(Settings.Get(Of Boolean)("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow, Visibility.Collapsed, Visibility.Visible) End If Else PanBack.Visibility = Visibility.Visible @@ -110,7 +110,7 @@ End If Catch ex As Exception - Log(ex, "将版本列表转换显示时失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "将版本列表转换显示时失败") End Try End Sub Public Shared Sub McInstanceListContent(sender As MyListItem, e As EventArgs) @@ -204,13 +204,8 @@ If(IsHintIndie, vbCrLf & "由于该版本开启了版本隔离,删除版本时该版本对应的存档、资源包、Mod 等文件也将被一并删除!", ""), "版本删除确认", , "取消",, True) Case 1 - IniClearCache(Instance.PathIndie & "options.txt") - IniClearCache(Instance.PathVersion & "PCL\Setup.ini") - If IsShiftPressed Then - DeleteDirectory(Instance.PathVersion) - Else - FileIO.FileSystem.DeleteDirectory(Instance.PathVersion, FileIO.UIOption.AllDialogs, FileIO.RecycleOption.SendToRecycleBin) - End If + Instance.ResetIniCache() + DirectoryUtils.Delete(Instance.PathVersion, Not IsShiftPressed) Hint("版本 " & Instance.Name & " 已删除!", HintType.Green) Case 2 Return @@ -238,14 +233,14 @@ LoaderFolderRun(McInstanceListLoader, McFolderSelected, LoaderFolderRunType.ForceRun, MaxDepth:=1, ExtraPath:="versions\") End If Catch ex As OperationCanceledException - Log(ex, "删除版本 " & Instance.Name & " 被主动取消") + Logger.Warn(ex, $"删除版本 {Instance.Name} 被主动取消") Catch ex As Exception - Log(ex, "删除版本 " & Instance.Name & " 失败", NotifyLevel.MsgBox) + Logger.Error(ex, $"删除版本 {Instance.Name} 失败", LogBehavior.Alert) End Try End Sub Public Sub BtnEmptyDownload_Loaded() Handles BtnEmptyDownload.Loaded - Dim NewVisibility = If((Settings.Get("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow) OrElse ShowHidden, Visibility.Collapsed, Visibility.Visible) + Dim NewVisibility = If((Settings.Get(Of Boolean)("UiHiddenPageDownload") AndAlso Not PageSetupUI.HiddenForceShow) OrElse ShowHidden, Visibility.Collapsed, Visibility.Visible) If BtnEmptyDownload.Visibility <> NewVisibility Then BtnEmptyDownload.Visibility = NewVisibility PanLoad.TriggerForceResize() diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml index 32c52ff..4b73f27 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml @@ -8,7 +8,7 @@ - + @@ -29,7 +29,6 @@ - + Grid.Row="4" Grid.ColumnSpan="2" Text="PCL" Grid.Column="1" ToolTip="注意:Mojang 于 Minecraft 26.1 移除了该设置,因此该设置在新版本中无效。 该信息会显示在游戏主界面的左下角,与 F3 调试页面的左上角。 你可以用替换标记来动态改变其内容,在 更多 → 帮助 中搜索 “替换标记” 以了解用法。"> @@ -106,21 +105,24 @@ - - - - - - + + + - - - - + + + + + + @@ -291,7 +293,7 @@ + ToolTipService.Placement="Right" ToolTip="是否使用 LWJGL Unsafe Agent 修复 LWJGL 3.4.1 的一个性能问题。 详见:https://github.com/HMCL-dev/lwjgl-unsafe-agent" /> diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb index 78ed4a8..c736b25 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLaunch.xaml.vb @@ -27,10 +27,10 @@ UpdateRamType() UpdateJavaComboBox() Catch ex As NullReferenceException - Log(ex, "启动设置项存在异常,已被自动重置", NotifyLevel.MsgBox) + Logger.Error(ex, "启动设置项存在异常,已被自动重置", LogBehavior.Alert) Reset() Catch ex As Exception - Log(ex, "重载启动设置时出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "重载启动设置时出错") End Try End Sub Public Sub Reset() @@ -42,7 +42,7 @@ JavaSearchLoader.Start(IsForceRestart:=True) Hint("已初始化启动设置!", HintType.Green) Catch ex As Exception - Log(ex, "初始化启动设置失败", NotifyLevel.MsgBox) + Logger.Error(ex, "初始化启动设置失败", LogBehavior.Alert) End Try Refresh() End Sub @@ -57,7 +57,7 @@ Private Sub RadioSkinType3_Check(sender As Object, e As RouteEventArgs) Handles RadioSkinType4.PreviewCheck If Not (AniControlEnabled = 0 AndAlso e.RaiseByMouse) Then Return '已有图片则不再选择 - If File.Exists(PathAppdata & "CustomSkin.png") Then Return + If FileUtils.Exists(PathAppdata & "CustomSkin.png") Then Return '没有图片则要求选择 Dim SkinInfo As McSkinInfo = McSkinSelect() If Not SkinInfo.IsVaild Then @@ -70,9 +70,8 @@ '返回是否成功改变 Private Function ChangeSkin(SkinInfo As McSkinInfo) As Boolean Try - '拷贝文件 - File.Delete(PathAppdata & "CustomSkin.png") - CopyFile(SkinInfo.LocalFile, PathAppdata & "CustomSkin.png") + '复制文件 + FileUtils.Copy(SkinInfo.LocalFile, PathAppdata & "CustomSkin.png") '将单层皮肤扩展到双层 Dim Bitmap As New MyBitmap(PathAppdata & "CustomSkin.png") If Bitmap.Pic.Width = 64 AndAlso Bitmap.Pic.Height = 32 Then @@ -81,15 +80,15 @@ Using g As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(NewBitmap) g.DrawImageUnscaled(Img, New System.Drawing.Point(0, 0)) End Using - File.Delete(PathAppdata & "CustomSkin.png") + FileUtils.Delete(PathAppdata & "CustomSkin.png") NewBitmap.Save(PathAppdata & "CustomSkin.png") End If '更新设置 Settings.Set("LaunchSkinSlim", SkinInfo.IsSlim) - ChangeSkin = True + Return True Catch ex As Exception - Log(ex, "改变离线皮肤失败", NotifyLevel.MsgBox) - ChangeSkin = False + Logger.Error(ex, "改变离线皮肤失败", LogBehavior.Alert) + Return False Finally '设置当前显示 PageLaunchLeft.SkinLegacy.Start(IsForceRestart:=True) @@ -97,11 +96,11 @@ End Function Private Sub BtnSkinDelete_Click(sender As Object, e As EventArgs) Handles BtnSkinDelete.Click Try - File.Delete(PathAppdata & "CustomSkin.png") + FileUtils.Delete(PathAppdata & "CustomSkin.png") RadioSkinType0.SetChecked(True, True) Hint("离线皮肤已清空!", HintType.Green) Catch ex As Exception - Log(ex, "清空离线皮肤失败", NotifyLevel.MsgBox) + Logger.Error(ex, "清空离线皮肤失败", LogBehavior.Alert) End Try End Sub Private Sub BtnSkinSave_Click(sender As Object, e As EventArgs) Handles BtnSkinSave.Click @@ -115,7 +114,7 @@ PageLaunchLeft.SkinLegacy.Start() '设置 UI 改变 If FrmSetupLaunch Is Nothing Then Return - Select Case Settings.Get("LaunchSkinType") + Select Case Settings.Get(Of Integer)("LaunchSkinType") Case 0, 1, 2 '默认 FrmSetupLaunch.PanSkinID.Visibility = Visibility.Collapsed FrmSetupLaunch.PanSkinChange.Visibility = Visibility.Collapsed @@ -135,7 +134,7 @@ Public Shared Sub UpdateRamType() If FrmSetupLaunch?.SliderRamCustom Is Nothing Then Return - FrmSetupLaunch.SliderRamCustom.IsEnabled = Settings.Get("LaunchRamType") = 1 + FrmSetupLaunch.SliderRamCustom.IsEnabled = Settings.Get(Of Integer)("LaunchRamType") = 1 End Sub ''' @@ -278,7 +277,7 @@ '------------------------------------------ Dim RamGive As Double - If Settings.Get("LaunchRamType") = 0 Then + If Settings.Get(Of Integer)("LaunchRamType") = 0 Then '自动配置 Dim RamAvailable As Double = Math.Round(My.Computer.Info.AvailablePhysicalMemory / 1024 / 1024 / 1024 * 10) / 10 '确定需求的内存值 @@ -289,7 +288,7 @@ If Instance IsNot Nothing AndAlso Not Instance.IsLoaded Then Instance.Load() If Instance IsNot Nothing AndAlso Instance.Modable Then '可安装 Mod 的版本 - Dim ModDir As New DirectoryInfo(Instance.PathIndie & "mods\") + Dim ModDir = DirectoryUtils.GetInfo(Instance.PathIndie & "mods\") Dim ModCount As Integer = If(ModDir.Exists, ModDir.GetFiles.Count(Function(f) {".jar", ".zip", ".litemod"}.Contains(f.Extension.Lower)), 0) RamMininum = 0.5 + ModCount / 150 RamTarget1 = 1.5 + ModCount / 90 @@ -334,7 +333,7 @@ PreFin: RamGive = Math.Round(Math.Max(RamGive, RamMininum), 1) Else '手动配置 - Dim Value As Integer = Settings.Get("LaunchRamCustom") + Dim Value = Settings.Get(Of Integer)("LaunchRamCustom") If Value <= 12 Then RamGive = Value * 0.1 + 0.3 ElseIf Value <= 25 Then @@ -359,10 +358,10 @@ PreFin: If ComboArgumentJava Is Nothing Then Return '初始化列表 ComboArgumentJava.Items.Clear() - ComboArgumentJava.Items.Add(New MyComboBoxItem With {.Content = "自动选择合适的 Java", .Tag = "自动选择"}) + ComboArgumentJava.Items.Add(New MyComboBoxItem With {.Content = "自动选择(推荐)", .Tag = "自动选择"}) '更新列表 Dim SelectedItem As MyComboBoxItem = Nothing - Dim SelectedBySetup As String = Settings.Get("LaunchArgumentJavaSelect") + Dim SelectedBySetup As String = Settings.Get(Of String)("LaunchArgumentJavaSelect") Try For Each Java In JavaList.ToList().OrderByDescending(Function(v) v.MajorVersion) Dim ListItem = New MyComboBoxItem With {.Content = Java.ToString, .ToolTip = Java.PathFolder, .Tag = Java} @@ -374,7 +373,7 @@ PreFin: Next Catch ex As Exception Settings.Set("LaunchArgumentJavaSelect", "") - Log(ex, "更新设置 Java 下拉框失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "更新设置 Java 下拉框失败") End Try '更新选择项 If SelectedItem Is Nothing AndAlso JavaList.Any Then SelectedItem = ComboArgumentJava.Items(0) '选中 “自动选择” @@ -403,11 +402,11 @@ PreFin: If "自动选择".Equals(SelectedJava) Then '选择 “自动” Settings.Set("LaunchArgumentJavaSelect", "") - Log("[Java] 修改 Java 选择设置:自动选择") + Logger.Info("修改 Java 选择设置:自动选择") Else '选择指定项 Settings.Set("LaunchArgumentJavaSelect", CType(SelectedJava.ToJson(), JObject).ToString(Newtonsoft.Json.Formatting.None)) - Log("[Java] 修改 Java 选择设置:" & SelectedJava.ToString) + Logger.Info($"修改 Java 选择设置:{SelectedJava}") End If RefreshRam(True) End Sub @@ -419,16 +418,16 @@ PreFin: Return End If '选择 Java - Dim JavaSelected As String = SelectFile("javaw.exe|javaw.exe", "选择 bin 文件夹中的 javaw.exe 文件") - If JavaSelected = "" Then Return - JavaSelected = GetPathFromFullPath(JavaSelected) + Dim JavaSelected As String = Dialogs.SelectFile("选择 bin 文件夹中的 javaw.exe 文件", False, filter:={({"exe"}, "javaw.exe")}).FirstOrDefault() + If String.IsNullOrEmpty(JavaSelected) Then Return + JavaSelected = PathUtils.AddSlashSuffix(PathUtils.RemoveLastPart(JavaSelected)) Try '验证 Java 可用 Dim NewEntry As New JavaEntry(JavaSelected, True) NewEntry.Check() '加入列表 Dim JavaNewList As New JArray From {NewEntry.ToJson} - For Each JsonEntry In GetJson(Settings.Get("LaunchArgumentJavaAll")) + For Each JsonEntry In GetJson(Settings.Get(Of String)("LaunchArgumentJavaAll")) Dim Entry = JavaEntry.FromJson(JsonEntry) If Entry.PathFolder = NewEntry.PathFolder Then Continue For JavaNewList.Add(JsonEntry) @@ -438,7 +437,7 @@ PreFin: JavaSearchLoader.Start(IsForceRestart:=True) Hint("已将该 Java 加入 Java 列表!", HintType.Green) Catch ex As Exception - Log(ex, "该 Java 存在异常,无法使用", NotifyLevel.MsgBox, "异常的 Java") + Logger.Error(ex, "该 Java 存在异常,无法使用", LogBehavior.Alert) Return End Try End Sub @@ -488,7 +487,7 @@ PreFin: If Not CheckArgumentRam.Checked Then Return If MyMsgBox("内存优化会显著延长启动耗时,建议仅在内存不足时开启。" & vbCrLf & "如果你在使用机械硬盘,这还可能导致一小段时间的严重卡顿。" & - If(IsAdmin(), "", $"{vbCrLf}{vbCrLf}每次启动游戏,PCL 都需要申请管理员权限以进行内存优化。{vbCrLf}若想自动授予权限,可以右键 PCL,打开 属性 → 兼容性 → 以管理员身份运行此程序。"), + If(SystemUtils.HasAdminRole(), "", $"{vbCrLf}{vbCrLf}每次启动游戏,PCL 都需要申请管理员权限以进行内存优化。{vbCrLf}若想自动授予权限,可以右键 PCL,打开 属性 → 兼容性 → 以管理员身份运行此程序。"), "提醒", "确定", "取消") = 2 Then CheckArgumentRam.Checked = False End If diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.vb index ad03d94..fd91326 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLeft.xaml.vb @@ -5,10 +5,10 @@ Private Sub PageSetupLeft_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded '是否处于隐藏的子页面 Dim IsHiddenPage As Boolean = False - If ItemLaunch.Checked AndAlso Settings.Get("UiHiddenSetupLaunch") Then IsHiddenPage = True - If ItemUI.Checked AndAlso Settings.Get("UiHiddenSetupUi") Then IsHiddenPage = True - If ItemSystem.Checked AndAlso Settings.Get("UiHiddenSetupSystem") Then IsHiddenPage = True - If ItemLink.Checked AndAlso Settings.Get("UiHiddenSetupLink") Then IsHiddenPage = True + If ItemLaunch.Checked AndAlso Settings.Get(Of Boolean)("UiHiddenSetupLaunch") Then IsHiddenPage = True + If ItemUI.Checked AndAlso Settings.Get(Of Boolean)("UiHiddenSetupUi") Then IsHiddenPage = True + If ItemSystem.Checked AndAlso Settings.Get(Of Boolean)("UiHiddenSetupSystem") Then IsHiddenPage = True + If ItemLink.Checked AndAlso Settings.Get(Of Boolean)("UiHiddenSetupLink") Then IsHiddenPage = True If PageSetupUI.HiddenForceShow Then IsHiddenPage = False '若页面错误,或尚未加载,则继续 If IsLoad AndAlso Not IsHiddenPage Then Return @@ -17,13 +17,13 @@ PageSetupUI.HiddenRefresh() '选择第一个未被禁用的子页面 If IsPageSwitched Then Return - If Not Settings.Get("UiHiddenSetupLaunch") Then + If Not Settings.Get(Of Boolean)("UiHiddenSetupLaunch") Then ItemLaunch.SetChecked(True, False, False) - ElseIf Not Settings.Get("UiHiddenSetupUi") Then + ElseIf Not Settings.Get(Of Boolean)("UiHiddenSetupUi") Then ItemUI.SetChecked(True, False, False) - ElseIf Not Settings.Get("UiHiddenSetupSystem") Then + ElseIf Not Settings.Get(Of Boolean)("UiHiddenSetupSystem") Then ItemSystem.SetChecked(True, False, False) - ElseIf Not Settings.Get("UiHiddenSetupLink") Then + ElseIf Not Settings.Get(Of Boolean)("UiHiddenSetupLink") Then ItemLink.SetChecked(True, False, False) Else ItemLaunch.SetChecked(True, False, False) @@ -42,13 +42,13 @@ Public Sub New() InitializeComponent() '选择第一个未被禁用的子页面 - If Not Settings.Get("UiHiddenSetupLaunch") Then + If Not Settings.Get(Of Boolean)("UiHiddenSetupLaunch") Then PageID = FormMain.PageSubType.SetupLaunch - ElseIf Not Settings.Get("UiHiddenSetupUi") Then + ElseIf Not Settings.Get(Of Boolean)("UiHiddenSetupUi") Then PageID = FormMain.PageSubType.SetupUI - ElseIf Not Settings.Get("UiHiddenSetupSystem") Then + ElseIf Not Settings.Get(Of Boolean)("UiHiddenSetupSystem") Then PageID = FormMain.PageSubType.SetupSystem - ElseIf Not Settings.Get("UiHiddenSetupLink") Then + ElseIf Not Settings.Get(Of Boolean)("UiHiddenSetupLink") Then PageID = FormMain.PageSubType.SetupLink Else PageID = FormMain.PageSubType.SetupLaunch @@ -115,7 +115,7 @@ PageID = ID Catch ex As Exception - Log(ex, "切换分页面失败(ID " & ID & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"切换分页面失败(ID {ID})") Finally AniControlEnabled -= 1 End Try diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml.vb index ab1ce35..18da614 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupLink.xaml.vb @@ -23,10 +23,10 @@ Public Sub Reset() Try SettingService.ResetSettings(Me) - Log("[Setup] 已初始化联机页设置") + Logger.Info("已初始化联机页设置") Hint("已初始化联机页设置!", HintType.Green, False) Catch ex As Exception - Log(ex, "初始化联机页设置失败", NotifyLevel.MsgBox) + Logger.Error(ex, "初始化联机页设置失败", LogBehavior.Alert) End Try Reload() End Sub diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb index 044c96e..f674a86 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupSystem.xaml.vb @@ -30,10 +30,10 @@ Public Sub Reset() Try SettingService.ResetSettings(Me) - Log("[Setup] 已初始化启动器页设置") + Logger.Info("已初始化启动器页设置") Hint("已初始化启动器页设置!", HintType.Green, False) Catch ex As Exception - Log(ex, "初始化启动器页设置失败", NotifyLevel.MsgBox) + Logger.Error(ex, "初始化启动器页设置失败", LogBehavior.Alert) End Try Reload() End Sub @@ -58,7 +58,7 @@ End Sub Private Sub SliderDownloadThread_PreviewChange(sender As Object, e As RouteEventArgs) Handles SliderDownloadThread.PreviewChange If SliderDownloadThread.Value < 100 Then Return - If Not Settings.Get("HintDownloadThread") Then + If Not Settings.Get(Of Boolean)("HintDownloadThread") Then Settings.Set("HintDownloadThread", True) MyMsgBox("如果设置过多的下载线程,可能会导致下载时出现非常严重的卡顿。" & vbCrLf & "一般设置 64 线程即可满足大多数下载需求,除非你知道你在干什么,否则不建议设置更多的线程数!", "警告", "我知道了", IsWarn:=True) @@ -109,12 +109,12 @@ Public Shared Function IsLauncherNewest() As Boolean? Try '确认服务器公告是否正常 - Dim ServerContent As String = ReadFile(PathTemp & "Cache\Notice.cfg") + Dim ServerContent As String = If(FileUtils.TryReadAsString(PathTemp & "Cache\Notice.cfg"), "") If ServerContent.Split("|").Count < 3 Then Return Nothing '确认是否为最新 Return ServerContent.Split("|")(If(BuildType = BuildTypes.Release, 2, 1)) <= VersionCode Catch ex As Exception - Log(ex, "确认启动器更新失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "确认启动器更新失败") Return Nothing End Try End Function diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml index 27793fc..26d04da 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml @@ -269,11 +269,11 @@ - + - + @@ -282,6 +282,7 @@ + diff --git a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb index badce41..84f1c3e 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/PageSetupUI.xaml.vb @@ -54,19 +54,19 @@ '主页 OnMainPageTypeChanged() Catch ex As NullReferenceException - Log(ex, "个性化设置项存在异常,已被自动重置", NotifyLevel.MsgBox) + Logger.Error(ex, "个性化设置项存在异常,已被自动重置", LogBehavior.Alert) Reset() Catch ex As Exception - Log(ex, "重载个性化设置时出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "重载个性化设置时出错") End Try End Sub Public Sub Reset() Try SettingService.ResetSettings(Me) - Log("[Setup] 已初始化个性化设置!") + Logger.Info("已初始化个性化设置!") Hint("已初始化个性化设置", HintType.Green, False) Catch ex As Exception - Log(ex, "初始化个性化设置失败", NotifyLevel.MsgBox) + Logger.Error(ex, "初始化个性化设置失败", LogBehavior.Alert) End Try Refresh() End Sub @@ -97,7 +97,7 @@ End Sub Private Sub BtnBackgroundClear_Click(sender As Object, e As EventArgs) Handles BtnBackgroundClear.Click If MyMsgBox("即将删除背景图片文件夹中的所有文件。" & vbCrLf & "此操作不可撤销,是否确定?", "警告",, "取消", IsWarn:=True) = 1 Then - DeleteDirectory(PathExeFolder & "PCL\Pictures") + DirectoryUtils.Delete(PathExeFolder & "PCL\Pictures") BackgroundRefresh(False, True) Hint("背景图片已清空!", HintType.Green) End If @@ -113,10 +113,9 @@ '获取可用的图片文件 DirectoryUtils.Create(PathExeFolder & "PCL\Pictures\") Dim Pic As New List(Of String) - For Each File In EnumerateFiles(PathExeFolder & "PCL\Pictures\") - If File.Extension.Lower <> ".ini" AndAlso File.Extension.Lower <> ".db" Then '文件夹可能会被加入 .ini 和 thumbs.db - Pic.Add(File.FullName) - End If + For Each File In DirectoryUtils.GetFiles(PathExeFolder & "PCL\Pictures\") + Dim Extension As String = PathUtils.GetExtension(File) + If Extension <> "ini" AndAlso Extension <> "db" Then Pic.Add(File) '文件夹可能会被加入 .ini 和 thumbs.db Next '加载 If Not Pic.Any() Then @@ -133,18 +132,16 @@ If Refresh Then Dim Address As String = RandomOne(Pic) Try - Log("[UI] 加载背景图片:" & Address) + Logger.Info($"加载背景图片:{Address}") FrmMain.ImgBack.Background = New MyBitmap(Address) FrmMain.ImgBack.Visibility = Visibility.Visible FrmMain.UpdateBackgroundAndTitleBar() - If IsHint Then Hint("背景图片已刷新:" & GetFileNameFromPath(Address), HintType.Green, False) + If IsHint Then Hint("背景图片已刷新:" & PathUtils.GetLastPart(Address), HintType.Green, False) Catch ex As Exception If ex.Message.Contains("参数无效") Then - Log("刷新背景图片失败,该图片文件可能并非标准格式。" & vbCrLf & - "你可以尝试使用画图打开该文件并重新保存,这会让图片变为标准格式。" & vbCrLf & - "文件:" & Address, NotifyLevel.MsgBox) + Logger.Error($"刷新背景图片失败,该图片文件可能并非标准格式。{vbCrLf}你可以尝试使用画图打开该文件并重新保存,这会让图片变为标准格式。{vbCrLf}文件:{Address}", LogBehavior.Alert) Else - Log(ex, "刷新背景图片失败(" & Address & ")", NotifyLevel.MsgBox) + Logger.Error(ex, $"刷新背景图片失败({Address})", LogBehavior.Alert) End If End Try End If @@ -152,27 +149,26 @@ End If Catch ex As Exception - Log(ex, "刷新背景图片时出现未知错误", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "刷新背景图片时出现未知错误") End Try End Sub '顶部栏 Private Sub BtnLogoChange_Click(sender As Object, e As EventArgs) Handles BtnLogoChange.Click - Dim FileName As String = SelectFile("常用图片文件(*.png;*.jpg;*.jpeg;*.gif;*.webp)|*.png;*.jpg;*.jpeg;*.gif;*.webp", "选择图片") - If FileName = "" Then Return + Dim FileName As String = Dialogs.SelectFile("选择图片", False, filter:={({"png", "jpg", "jpeg", "gif", "webp"}, "常用图片文件")}).FirstOrDefault() + If String.IsNullOrEmpty(FileName) Then Return + Dim TargetPath As String = PathExeFolder & "PCL\Logo.png" Try - '拷贝文件 - File.Delete(PathExeFolder & "PCL\Logo.png") - CopyFile(FileName, PathExeFolder & "PCL\Logo.png") + '复制文件 + FileUtils.Copy(FileName, TargetPath) '设置当前显示 FrmMain.ImageTitleLogo.Source = Nothing '防止因为 Source 属性前后的值相同而不更新 (#5628) - FrmMain.ImageTitleLogo.Source = PathExeFolder & "PCL\Logo.png" + FrmMain.ImageTitleLogo.Source = TargetPath Catch ex As Exception If ex.Message.Contains("参数无效") Then - Log("改变标题栏图片失败,该图片文件可能并非标准格式。" & vbCrLf & - "你可以尝试使用画图打开该文件并重新保存,这会让图片变为标准格式。", NotifyLevel.MsgBox) + Logger.Error($"改变标题栏图片失败,该图片文件可能并非标准格式。{vbCrLf}你可以尝试使用画图打开该文件并重新保存,这会让图片变为标准格式。{vbCrLf}文件:{TargetPath}", LogBehavior.Alert) Else - Log(ex, "设置标题栏图片失败", NotifyLevel.MsgBox) + Logger.Error(ex, "设置标题栏图片失败", LogBehavior.Alert) End If FrmMain.ImageTitleLogo.Source = Nothing End Try @@ -181,50 +177,48 @@ If Not (AniControlEnabled = 0 AndAlso e.RaiseByMouse) Then Return Refresh: '已有图片则不再选择 - If File.Exists(PathExeFolder & "PCL\Logo.png") Then + Dim TargetPath As String = PathExeFolder & "PCL\Logo.png" + If FileUtils.Exists(TargetPath) Then Try FrmMain.ImageTitleLogo.Source = Nothing '防止因为 Source 属性前后的值相同而不更新 (#5628) - FrmMain.ImageTitleLogo.Source = PathExeFolder & "PCL\Logo.png" + FrmMain.ImageTitleLogo.Source = TargetPath Catch ex As Exception If ex.Message.Contains("参数无效") Then - Log("调整标题栏图片失败,该图片文件可能并非标准格式。" & vbCrLf & - "你可以尝试使用画图打开该文件并重新保存,这会让图片变为标准格式。", NotifyLevel.MsgBox) + Logger.Error($"改变标题栏图片失败,该图片文件可能并非标准格式。{vbCrLf}你可以尝试使用画图打开该文件并重新保存,这会让图片变为标准格式。{vbCrLf}文件:{TargetPath}", LogBehavior.Alert) Else - Log(ex, "调整标题栏图片失败", NotifyLevel.MsgBox) + Logger.Error(ex, "调整标题栏图片失败", LogBehavior.Alert) End If FrmMain.ImageTitleLogo.Source = Nothing e.Handled = True Try - File.Delete(PathExeFolder & "PCL\Logo.png") + FileUtils.Delete(TargetPath) Catch exx As Exception - Log(exx, "清理错误的标题栏图片失败", NotifyLevel.MsgBox) + Logger.Error(exx, "清理错误的标题栏图片失败", LogBehavior.Alert) End Try End Try Return End If '没有图片则要求选择 - Dim FileName As String = SelectFile("常用图片文件(*.png;*.jpeg;*.jpg;*.gif;*.webp)|*.png;*.jpeg;*.jpg;*.gif;*.webp", "选择图片") - If FileName = "" Then + Dim FileName As String = Dialogs.SelectFile("选择图片", False, filter:={({"png", "jpeg", "jpg", "gif", "webp"}, "常用图片文件")}).FirstOrDefault() + If String.IsNullOrEmpty(FileName) Then FrmMain.ImageTitleLogo.Source = Nothing e.Handled = True Else Try - '拷贝文件 - File.Delete(PathExeFolder & "PCL\Logo.png") - CopyFile(FileName, PathExeFolder & "PCL\Logo.png") + FileUtils.Copy(FileName, TargetPath) GoTo Refresh Catch ex As Exception - Log(ex, "复制标题栏图片失败", NotifyLevel.MsgBox) + Logger.Error(ex, "复制标题栏图片失败", LogBehavior.Alert) End Try End If End Sub Private Sub BtnLogoDelete_Click(sender As Object, e As EventArgs) Handles BtnLogoDelete.Click Try - File.Delete(PathExeFolder & "PCL\Logo.png") + FileUtils.Delete(PathExeFolder & "PCL\Logo.png") RadioLogoType1.SetChecked(True, True) Hint("标题栏图片已清空!", HintType.Green) Catch ex As Exception - Log(ex, "清空标题栏图片失败", NotifyLevel.MsgBox) + Logger.Error(ex, "清空标题栏图片失败", LogBehavior.Alert) End Try End Sub @@ -242,7 +236,7 @@ Refresh: PanMusicDetail.Visibility = Visibility.Visible BtnMusicClear.Visibility = Visibility.Visible CardMusic.Title = "背景音乐(" & - EnumerateFiles(PathExeFolder & "PCL\Musics\").Count(Function(f) Not {".ini", ".jpg", ".txt", ".cfg", ".lrc", ".db", ".png"}.Contains(f.Extension.Lower)) & + DirectoryUtils.GetFiles(PathExeFolder & "PCL\Musics\").Count(Function(f) Not {"ini", "jpg", "txt", "cfg", "lrc", "db", "png"}.Contains(PathUtils.GetExtension(f))) & " 首)" Else PanMusicVolume.Visibility = Visibility.Collapsed @@ -264,16 +258,16 @@ Refresh: Thread.Sleep(200) '删除文件 Try - DeleteDirectory(PathExeFolder & "PCL\Musics") + DirectoryUtils.Delete(PathExeFolder & "PCL\Musics") Hint("背景音乐已删除!", HintType.Green) Catch ex As Exception - Log(ex, "删除背景音乐失败", NotifyLevel.MsgBox) + Logger.Error(ex, "删除背景音乐失败", LogBehavior.Alert) End Try Try DirectoryUtils.Create(PathExeFolder & "PCL\Musics\") RunInUi(Sub() MusicRefreshPlay(False)) Catch ex As Exception - Log(ex, "重建背景音乐文件夹失败", NotifyLevel.MsgBox) + Logger.Error(ex, "重建背景音乐文件夹失败", LogBehavior.Alert) End Try End Sub) End If @@ -290,14 +284,14 @@ Refresh: '主页 Private Sub BtnCustomFile_Click(sender As Object, e As EventArgs) Handles BtnCustomFile.Click Try - If File.Exists(PathExeFolder & "PCL\Custom.xaml") Then + If FileUtils.Exists(PathExeFolder & "PCL\Custom.xaml") Then If MyMsgBox("当前已存在布局文件,继续生成教学文件将会覆盖现有布局文件!", "覆盖确认", "继续", "取消", IsWarn:=True) = 2 Then Return End If - FileUtils.Write(PathExeFolder & "PCL\Custom.xaml", GetResources("Custom")) + ExtractResources(PathExeFolder & "PCL\Custom.xaml", "Custom") Hint("教学文件已生成!", HintType.Green) OpenExplorer(PathExeFolder & "PCL\Custom.xaml") Catch ex As Exception - Log(ex, "生成教学文件失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "生成教学文件失败") End Try End Sub Private Sub BtnCustomRefresh_Click() Handles BtnCustomRefresh.Click @@ -314,7 +308,7 @@ Refresh: End Sub Public Shared Sub OnMainPageTypeChanged() If FrmSetupUI Is Nothing Then Return - Select Case CInt(Settings.Get("UiCustomType")) + Select Case CInt(Settings.Get(Of Integer)("UiCustomType")) Case 0 '无 FrmSetupUI.PanCustomPreset.Visibility = Visibility.Collapsed FrmSetupUI.PanCustomLocal.Visibility = Visibility.Collapsed @@ -326,7 +320,7 @@ Refresh: FrmSetupUI.PanCustomLocal.Visibility = Visibility.Visible FrmSetupUI.PanCustomNet.Visibility = Visibility.Collapsed FrmSetupUI.HintCustom.Visibility = Visibility.Visible - FrmSetupUI.HintCustomWarn.Visibility = If(Settings.Get("HintCustomWarn"), Visibility.Collapsed, Visibility.Visible) + FrmSetupUI.HintCustomWarn.Visibility = If(Settings.Get(Of Boolean)("HintCustomWarn"), Visibility.Collapsed, Visibility.Visible) FrmSetupUI.HintCustom.Text = $"从 PCL 文件夹下的 Custom.xaml 读取主页内容。{vbCrLf}你可以手动编辑该文件,向主页添加文本、图片、常用网站、快捷启动等功能。" CustomEventService.SetEventType(FrmSetupUI.HintCustom, CustomEvent.EventType.None) Case 2 '联网 @@ -334,7 +328,7 @@ Refresh: FrmSetupUI.PanCustomLocal.Visibility = Visibility.Collapsed FrmSetupUI.PanCustomNet.Visibility = Visibility.Visible FrmSetupUI.HintCustom.Visibility = Visibility.Visible - FrmSetupUI.HintCustomWarn.Visibility = If(Settings.Get("HintCustomWarn"), Visibility.Collapsed, Visibility.Visible) + FrmSetupUI.HintCustomWarn.Visibility = If(Settings.Get(Of Boolean)("HintCustomWarn"), Visibility.Collapsed, Visibility.Visible) FrmSetupUI.HintCustom.Text = $"从指定网址联网获取主页内容。服主也可以用于动态更新服务器公告。{vbCrLf}如果你制作了稳定运行的联网主页,可以点击这条提示投稿,若合格即可加入预设!" CustomEventService.SetEventType(FrmSetupUI.HintCustom, CustomEvent.EventType.打开网页) CustomEventService.SetEventData(FrmSetupUI.HintCustom, "https://github.com/Meloong-Git/PCL/discussions/2528") @@ -435,56 +429,56 @@ Refresh: If FrmMain.PanTitleSelect Is Nothing OrElse Not FrmMain.PanTitleSelect.IsLoaded Then Return Try '顶部栏 - If Not HiddenForceShow AndAlso Settings.Get("UiHiddenPageDownload") AndAlso Settings.Get("UiHiddenPageLink") AndAlso Settings.Get("UiHiddenPageSetup") AndAlso Settings.Get("UiHiddenPageOther") Then + If Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenPageDownload") AndAlso Settings.Get(Of Boolean)("UiHiddenPageLink") AndAlso Settings.Get(Of Boolean)("UiHiddenPageSetup") AndAlso Settings.Get(Of Boolean)("UiHiddenPageOther") Then '顶部栏已被全部隐藏 FrmMain.PanTitleSelect.Visibility = Visibility.Collapsed Else '顶部栏未被全部隐藏 FrmMain.PanTitleSelect.Visibility = Visibility.Visible - FrmMain.BtnTitleSelect1.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenPageDownload"), Visibility.Collapsed, Visibility.Visible) - FrmMain.BtnTitleSelect2.Visibility = Visibility.Collapsed 'If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenPageLink"), Visibility.Collapsed, Visibility.Visible) - FrmMain.BtnTitleSelect3.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenPageSetup"), Visibility.Collapsed, Visibility.Visible) - FrmMain.BtnTitleSelect4.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenPageOther"), Visibility.Collapsed, Visibility.Visible) + FrmMain.BtnTitleSelect1.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenPageDownload"), Visibility.Collapsed, Visibility.Visible) + FrmMain.BtnTitleSelect2.Visibility = Visibility.Collapsed 'If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenPageLink"), Visibility.Collapsed, Visibility.Visible) + FrmMain.BtnTitleSelect3.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenPageSetup"), Visibility.Collapsed, Visibility.Visible) + FrmMain.BtnTitleSelect4.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenPageOther"), Visibility.Collapsed, Visibility.Visible) End If '功能 FrmLaunchLeft.RefreshButtonsUI() If FrmSetupUI IsNot Nothing Then - FrmSetupUI.CardSwitch.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenFunctionHidden"), Visibility.Collapsed, Visibility.Visible) + FrmSetupUI.CardSwitch.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenFunctionHidden"), Visibility.Collapsed, Visibility.Visible) End If '设置子页面 If FrmSetupLeft IsNot Nothing Then - FrmSetupLeft.ItemLaunch.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenSetupLaunch"), Visibility.Collapsed, Visibility.Visible) - FrmSetupLeft.ItemUI.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenSetupUi"), Visibility.Collapsed, Visibility.Visible) - FrmSetupLeft.ItemLink.Visibility = Visibility.Collapsed 'If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenSetupLink"), Visibility.Collapsed, Visibility.Visible) - FrmSetupLeft.ItemSystem.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenSetupSystem"), Visibility.Collapsed, Visibility.Visible) + FrmSetupLeft.ItemLaunch.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenSetupLaunch"), Visibility.Collapsed, Visibility.Visible) + FrmSetupLeft.ItemUI.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenSetupUi"), Visibility.Collapsed, Visibility.Visible) + FrmSetupLeft.ItemLink.Visibility = Visibility.Collapsed 'If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenSetupLink"), Visibility.Collapsed, Visibility.Visible) + FrmSetupLeft.ItemSystem.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenSetupSystem"), Visibility.Collapsed, Visibility.Visible) '隐藏左边选择卡 Dim AvaliableCount As Integer = 0 - If Not Settings.Get("UiHiddenSetupLaunch") Then AvaliableCount += 1 - If Not Settings.Get("UiHiddenSetupUi") Then AvaliableCount += 1 - 'If Not Settings.Get("UiHiddenSetupLink") Then AvaliableCount += 1 - If Not Settings.Get("UiHiddenSetupSystem") Then AvaliableCount += 1 + If Not Settings.Get(Of Boolean)("UiHiddenSetupLaunch") Then AvaliableCount += 1 + If Not Settings.Get(Of Boolean)("UiHiddenSetupUi") Then AvaliableCount += 1 + 'If Not Settings.Get(Of Boolean)("UiHiddenSetupLink") Then AvaliableCount += 1 + If Not Settings.Get(Of Boolean)("UiHiddenSetupSystem") Then AvaliableCount += 1 FrmSetupLeft.PanItem.Visibility = If(AvaliableCount < 2 AndAlso Not HiddenForceShow, Visibility.Collapsed, Visibility.Visible) End If '更多子页面 Dim OtherAvaliableCount As Integer = 0 - If Not Settings.Get("UiHiddenOtherHelp") Then OtherAvaliableCount += 1 - If Not Settings.Get("UiHiddenOtherAbout") Then OtherAvaliableCount += 1 - If Not Settings.Get("UiHiddenOtherTest") Then OtherAvaliableCount += 1 - If Not Settings.Get("UiHiddenOtherFeedback") Then OtherAvaliableCount += 1 - If Not Settings.Get("UiHiddenOtherVote") Then OtherAvaliableCount += 1 + If Not Settings.Get(Of Boolean)("UiHiddenOtherHelp") Then OtherAvaliableCount += 1 + If Not Settings.Get(Of Boolean)("UiHiddenOtherAbout") Then OtherAvaliableCount += 1 + If Not Settings.Get(Of Boolean)("UiHiddenOtherTest") Then OtherAvaliableCount += 1 + If Not Settings.Get(Of Boolean)("UiHiddenOtherFeedback") Then OtherAvaliableCount += 1 + If Not Settings.Get(Of Boolean)("UiHiddenOtherVote") Then OtherAvaliableCount += 1 If FrmOtherLeft IsNot Nothing Then - FrmOtherLeft.ItemHelp.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenOtherHelp"), Visibility.Collapsed, Visibility.Visible) - FrmOtherLeft.ItemFeedback.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenOtherFeedback"), Visibility.Collapsed, Visibility.Visible) - FrmOtherLeft.ItemVote.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenOtherVote"), Visibility.Collapsed, Visibility.Visible) - FrmOtherLeft.ItemAbout.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenOtherAbout"), Visibility.Collapsed, Visibility.Visible) - FrmOtherLeft.ItemTest.Visibility = If(Not HiddenForceShow AndAlso Settings.Get("UiHiddenOtherTest"), Visibility.Collapsed, Visibility.Visible) + FrmOtherLeft.ItemHelp.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenOtherHelp"), Visibility.Collapsed, Visibility.Visible) + FrmOtherLeft.ItemFeedback.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenOtherFeedback"), Visibility.Collapsed, Visibility.Visible) + FrmOtherLeft.ItemVote.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenOtherVote"), Visibility.Collapsed, Visibility.Visible) + FrmOtherLeft.ItemAbout.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenOtherAbout"), Visibility.Collapsed, Visibility.Visible) + FrmOtherLeft.ItemTest.Visibility = If(Not HiddenForceShow AndAlso Settings.Get(Of Boolean)("UiHiddenOtherTest"), Visibility.Collapsed, Visibility.Visible) '隐藏左边选择卡 FrmOtherLeft.PanItem.Visibility = If(OtherAvaliableCount < 2 AndAlso Not HiddenForceShow, Visibility.Collapsed, Visibility.Visible) End If If OtherAvaliableCount = 1 AndAlso Not HiddenForceShow Then - If Not Settings.Get("UiHiddenOtherHelp") Then + If Not Settings.Get(Of Boolean)("UiHiddenOtherHelp") Then FrmMain.BtnTitleSelect4.Text = "帮助" - ElseIf Not Settings.Get("UiHiddenOtherAbout") Then + ElseIf Not Settings.Get(Of Boolean)("UiHiddenOtherAbout") Then FrmMain.BtnTitleSelect4.Text = "关于" Else FrmMain.BtnTitleSelect4.Text = "百宝箱" @@ -499,7 +493,7 @@ Refresh: '备注 If FrmSetupUI IsNot Nothing Then FrmSetupUI.CardSwitch.Title = If(HiddenForceShow, "功能隐藏(已暂时关闭,按 F12 以重新启用)", "功能隐藏") Catch ex As Exception - Log(ex, "刷新功能隐藏项目失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "刷新功能隐藏项目失败") End Try End Sub @@ -514,7 +508,7 @@ Refresh: CheckHiddenSetupUI.Checked = True Else '关闭 - If Settings.Get("UiHiddenSetupLaunch") AndAlso Settings.Get("UiHiddenSetupUi") AndAlso Settings.Get("UiHiddenSetupSystem") AndAlso Settings.Get("UiHiddenSetupLink") Then + If Settings.Get(Of Boolean)("UiHiddenSetupLaunch") AndAlso Settings.Get(Of Boolean)("UiHiddenSetupUi") AndAlso Settings.Get(Of Boolean)("UiHiddenSetupSystem") AndAlso Settings.Get(Of Boolean)("UiHiddenSetupLink") Then CheckHiddenSetupLaunch.Checked = False CheckHiddenSetupSystem.Checked = False CheckHiddenSetupLink.Checked = False @@ -524,7 +518,7 @@ Refresh: End Sub Private Sub HiddenSetupSub() Handles CheckHiddenSetupLaunch.Change, CheckHiddenSetupSystem.Change, CheckHiddenSetupLink.Change, CheckHiddenSetupUI.Change '设置子页面 - If Settings.Get("UiHiddenSetupLaunch") AndAlso Settings.Get("UiHiddenSetupUi") AndAlso Settings.Get("UiHiddenSetupSystem") AndAlso Settings.Get("UiHiddenSetupLink") Then + If Settings.Get(Of Boolean)("UiHiddenSetupLaunch") AndAlso Settings.Get(Of Boolean)("UiHiddenSetupUi") AndAlso Settings.Get(Of Boolean)("UiHiddenSetupSystem") AndAlso Settings.Get(Of Boolean)("UiHiddenSetupLink") Then '已被全部隐藏 CheckHiddenPageSetup.Checked = True Else @@ -543,8 +537,8 @@ Refresh: CheckHiddenOtherHelp.Checked = True Else '关闭 - If Settings.Get("UiHiddenOtherHelp") AndAlso Settings.Get("UiHiddenOtherAbout") AndAlso Settings.Get("UiHiddenOtherTest") AndAlso - Settings.Get("UiHiddenOtherVote") AndAlso Settings.Get("UiHiddenOtherFeedback") Then + If Settings.Get(Of Boolean)("UiHiddenOtherHelp") AndAlso Settings.Get(Of Boolean)("UiHiddenOtherAbout") AndAlso Settings.Get(Of Boolean)("UiHiddenOtherTest") AndAlso + Settings.Get(Of Boolean)("UiHiddenOtherVote") AndAlso Settings.Get(Of Boolean)("UiHiddenOtherFeedback") Then CheckHiddenOtherAbout.Checked = False CheckHiddenOtherTest.Checked = False CheckHiddenOtherFeedback.Checked = False @@ -555,7 +549,7 @@ Refresh: End Sub Private Sub HiddenOtherSub(sender As Object, user As Boolean) Handles CheckHiddenOtherHelp.Change, CheckHiddenOtherAbout.Change, CheckHiddenOtherTest.Change '更多子页面(有具体内容的) - If Settings.Get("UiHiddenOtherHelp") AndAlso Settings.Get("UiHiddenOtherAbout") AndAlso Settings.Get("UiHiddenOtherTest") Then + If Settings.Get(Of Boolean)("UiHiddenOtherHelp") AndAlso Settings.Get(Of Boolean)("UiHiddenOtherAbout") AndAlso Settings.Get(Of Boolean)("UiHiddenOtherTest") Then '已被全部隐藏 CheckHiddenPageOther.Checked = True Else @@ -564,7 +558,7 @@ Refresh: End If '修改无具体内容的项 If Not user Then Return - If Settings.Get("UiHiddenOtherHelp") AndAlso Settings.Get("UiHiddenOtherAbout") AndAlso Settings.Get("UiHiddenOtherTest") Then + If Settings.Get(Of Boolean)("UiHiddenOtherHelp") AndAlso Settings.Get(Of Boolean)("UiHiddenOtherAbout") AndAlso Settings.Get(Of Boolean)("UiHiddenOtherTest") Then CheckHiddenOtherFeedback.Checked = True CheckHiddenOtherVote.Checked = True End If @@ -572,8 +566,8 @@ Refresh: Private Sub HiddenOtherNet(sender As Object, user As Boolean) Handles CheckHiddenOtherFeedback.Change, CheckHiddenOtherVote.Change '更多子页面(无具体内容的) If Not user Then Return - If Settings.Get("UiHiddenOtherHelp") AndAlso Settings.Get("UiHiddenOtherAbout") AndAlso Settings.Get("UiHiddenOtherTest") AndAlso - (Not Settings.Get("UiHiddenOtherFeedback") OrElse Not Settings.Get("UiHiddenOtherVote")) Then + If Settings.Get(Of Boolean)("UiHiddenOtherHelp") AndAlso Settings.Get(Of Boolean)("UiHiddenOtherAbout") AndAlso Settings.Get(Of Boolean)("UiHiddenOtherTest") AndAlso + (Not Settings.Get(Of Boolean)("UiHiddenOtherFeedback") OrElse Not Settings.Get(Of Boolean)("UiHiddenOtherVote")) Then CheckHiddenOtherAbout.Checked = False CheckHiddenOtherTest.Checked = False CheckHiddenOtherHelp.Checked = False diff --git a/Plain Craft Launcher 2/Pages/PageSetup/Settings.vb b/Plain Craft Launcher 2/Pages/PageSetup/Settings.vb index 7388540..a6c2148 100644 --- a/Plain Craft Launcher 2/Pages/PageSetup/Settings.vb +++ b/Plain Craft Launcher 2/Pages/PageSetup/Settings.vb @@ -1,5 +1,5 @@ Public Class Settings - Private Shared ReadOnly Entries As Dictionary(Of String, Setting) = (New List(Of Setting) From { + Public Shared ReadOnly Entries As Dictionary(Of String, Setting) = (New List(Of Setting) From { New Setting("Identify", "", Source:=Sources.Registry), New Setting("WindowHeight", 550), New Setting("WindowWidth", 900), @@ -27,7 +27,7 @@ New Setting("SystemHighestBetaVersionReg", 0, Source:=Sources.Registry, Encrypted:=True), New Setting("SystemHighestAlphaVersionReg", 0, Source:=Sources.Registry, Encrypted:=True), New Setting("SystemHelpVersion", 0, Source:=Sources.Registry), - New Setting("SystemDebugMode", False, Source:=Sources.Registry), + New Setting("SystemDebugMode", False, Source:=Sources.Registry, OnChanged:=Sub() Logger.Instance.MinLevel = If(ModeDebug, LogLevel.Trace, LogLevel.Info)), New Setting("SystemDebugAnim", 9, Source:=Sources.Registry), New Setting("SystemDebugDelay", False, Source:=Sources.Registry), New Setting("SystemDebugSkipCopy", False, Source:=Sources.Registry), @@ -47,11 +47,11 @@ New Setting("CacheMsName", "", Source:=Sources.Registry, Encrypted:=True), New Setting("CacheMsV2Migrated", False, Source:=Sources.Registry), New Setting("CacheMsV2OAuthRefresh", "", Source:=Sources.Registry, Encrypted:=True), - New Setting("CacheMsV2OAuthExpires", 0, Source:=Sources.Registry), New Setting("CacheMsV2Access", "", Source:=Sources.Registry, Encrypted:=True), New Setting("CacheMsV2ProfileJson", "", Source:=Sources.Registry, Encrypted:=True), New Setting("CacheMsV2Uuid", "", Source:=Sources.Registry, Encrypted:=True), New Setting("CacheMsV2Name", "", Source:=Sources.Registry, Encrypted:=True), + New Setting("CacheMsV2Expires", 0L, Source:=Sources.Registry, Encrypted:=True), New Setting("CacheNideAccess", "", Source:=Sources.Registry, Encrypted:=True), New Setting("CacheNideClient", "", Source:=Sources.Registry, Encrypted:=True), New Setting("CacheNideUuid", "", Source:=Sources.Registry, Encrypted:=True), @@ -193,12 +193,12 @@ New Setting("VersionServerAuthServer", "", Source:=Sources.Instance) }).ToDictionary(Function(e) e.Key) - Private Enum Sources + Public Enum Sources Normal Registry Instance End Enum - Private Class Setting + Public Class Setting Public Key As String Public Encrypted As Boolean Public DefaultValue As Object @@ -220,7 +220,7 @@ Me.Type = If(Value, "").GetType Me.OnChanged = OnChanged Catch ex As Exception - Log(ex, "初始化设置项失败", NotifyLevel.MsgBoxAndFeedback) '#5095 的 fallback + Logger.Error(ex, "初始化设置项失败") '#5095 的 fallback End Try End Sub @@ -228,10 +228,11 @@ ''' 读取过的设置的缓存,若从未读取过则为 Nothing。 ''' 若为版本独立设置,键为版本路径;否则,键为空字符串。 ''' - Private ValueCache As New Dictionary(Of String, Object) + Public ValueCache As New ConcurrentDictionary(Of String, Object) Public Function GetCache(Instance As McInstance) Dim Key As String = If(Source = Sources.Instance, Instance.PathVersion, "") - Return If(ValueCache.ContainsKey(Key), ValueCache(Key), Nothing) + Dim Result = Nothing + Return If(ValueCache.TryGetValue(Key, Result), Result, Nothing) End Function Public Sub [Set](Value As Object, Instance As McInstance) Dim Key As String = If(Source = Sources.Instance, Instance.PathVersion, "") @@ -243,12 +244,13 @@ ''' Public Sub Save(Optional Instance As McInstance = Nothing) Dim Value As String = GetCache(Instance) + Logger.Trace($"保存设置:{Key} = {Value}{If(Instance Is Nothing, "", $"(实例:{Instance?.PathVersion})")}") If Encrypted Then Try If Value Is Nothing Then Value = "" Value = SecretEncrypt(Value, "PCL" & Identify) Catch ex As Exception - Log(ex, "加密设置失败:" & Key, NotifyLevel.DevelopOnly) + Logger.Warn(ex, $"加密设置失败:{Key}") End Try End If Select Case Source @@ -281,7 +283,7 @@ '触发改变事件(必须在保存之后,以保证 VersionServerLogin 之类的在事件中读取到的是最新的值) If Entry.OnChanged IsNot Nothing Then Entry.OnChanged.Invoke(Value) Catch ex As Exception - Log(ex, "设置设置项时出错(" & Key & ", " & Value & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"设置设置项时出错({Key}, {Value})") End Try End Sub ''' @@ -336,7 +338,7 @@ Try GotValue = SecretDecrypt(GotValue, "PCL" & Identify) Catch ex As Exception - Log(ex, "解密设置失败:" & Key, NotifyLevel.DevelopOnly) + Logger.Warn(ex, $"解密设置失败:{Key}") GotValue = Entry.DefaultValue Entry.Set(Entry.DefaultValue, Instance) Entry.Save(Instance) @@ -345,11 +347,14 @@ End If Entry.Set(CTypeDynamic(GotValue, Entry.Type), Instance) Catch ex As Exception - Log(ex, "读取设置失败:" & Key, NotifyLevel.AllUsers) + Logger.Error(ex, $"读取设置失败:{Key}", LogBehavior.Toast) Entry.Set(CTypeDynamic(Entry.DefaultValue, Entry.Type), Instance) End Try Return Entry.GetCache(Instance) End Function + Public Shared Function [Get](Of T)(Key As String, Optional Instance As McInstance = Nothing) As T + Return [Get](Key, Instance) + End Function ''' ''' 获取某个未经加密的设置项的值。 ''' 若该设置项经过了加密,则会抛出异常。 @@ -385,7 +390,7 @@ '触发改变事件 If Entry.OnChanged IsNot Nothing Then Entry.OnChanged.Invoke(Entry.DefaultValue) Catch ex As Exception - Log(ex, "重置设置项时出错(" & Key & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"重置设置项时出错({Key})") End Try End Sub diff --git a/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.vb b/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.vb index 8e134d5..9009ce8 100644 --- a/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.vb +++ b/Plain Craft Launcher 2/Pages/PageSpeedLeft.xaml.vb @@ -55,7 +55,7 @@ #End Region Catch ex As Exception - Log(ex, "下载管理左栏监视出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "下载管理左栏监视出错") End Try If FrmSpeedRight Is Nothing OrElse FrmSpeedRight.PanMain Is Nothing Then Return Try @@ -63,7 +63,7 @@ TaskRefresh(Loader) Next Catch ex As Exception - Log(ex, "下载管理右栏监视出错", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "下载管理右栏监视出错") End Try End Sub Public Sub TaskRefresh(Loader As LoaderBase) @@ -78,7 +78,7 @@ If Val(Card.Tag) = NewValue Then Return Card.Tag = NewValue If Card.Children.Count <= 3 Then - Log("[Watcher] 元素不足的卡片:" & Loader.Name, NotifyLevel.DebugModeOnly) + Logger.Warn($"元素不足的卡片:{Loader.Name}") Return End If Card = Card.Children(3) @@ -90,7 +90,7 @@ Card.Children.Clear() Card.Children.Add(GetObjectFromXML("")) Dim Tb As TextBlock = GetObjectFromXML("") - Tb.Text = Loader.Error.GetDetail() + Tb.Text = Loader.Error.GetDisplay(True) AddHandler Tb.MouseLeftButtonDown, Sub(sender As TextBlock, e As EventArgs) ClipboardSet(sender.Text, False) @@ -106,7 +106,7 @@ #Region "进度不同,更新卡片" Try If Card.Children.Count < LoaderList.Count * 2 Then - Log($"[Watcher] 刷新下载管理卡片 {Loader.Name} 失败:卡片中仅有 {Card.Children.Count} 个子项,要求至少有 {LoaderList.Count * 2} 个子项", NotifyLevel.DebugModeOnly) + Logger.Warn($"刷新下载管理卡片 {Loader.Name} 失败:卡片中仅有 {Card.Children.Count} 个子项,要求至少有 {LoaderList.Count * 2} 个子项") Exit Try End If Dim Row As Integer = 0 @@ -133,12 +133,12 @@ Row += 1 Next Catch ex As Exception - Log(ex, $"刷新下载管理卡片 {Loader.Name} 失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"刷新下载管理卡片 {Loader.Name} 失败") End Try #End Region End Select Catch ex As Exception - Log(ex, "更新下载管理显示失败(" & Loader.State.ToString & ")", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, $"更新下载管理显示失败({Loader.State})") End Try ElseIf Not (Loader.State = LoadState.Interrupted OrElse Loader.State = LoadState.Finished) Then Try @@ -177,13 +177,13 @@ Try Card = GetObjectFromXML(CardXAML) Catch ex As Exception - Log(ex, "新建下载管理卡片失败") - Log("出错的卡片内容:" & vbCrLf & CardXAML) + Logger.Warn(ex, "新建下载管理卡片失败") + Logger.Info($"出错的卡片内容:{vbCrLf}{CardXAML}") Throw End Try FrmSpeedRight.PanMain.Children.Insert(0, Card) RightCards.Add(Loader.Name, Card) - Log($"[Watcher] 新建下载管理卡片:{Loader.Name}") + Logger.Info($"新建下载管理卡片:{Loader.Name}") '添加取消按钮 Dim Cancel As New MyIconButton With {.Name = "BtnCancel", .Logo = "F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z", .Height = 20, .Margin = New Thickness(0, 10, 10, 0), .LogoScale = 1.1, .HorizontalAlignment = HorizontalAlignment.Right, .VerticalAlignment = VerticalAlignment.Top} Card.Children.Add(Cancel) @@ -193,7 +193,7 @@ AniDispose(Card, True, Sub() If FrmSpeedRight.PanMain.Children.Count = 0 AndAlso FrmMain.PageCurrent = FormMain.PageType.DownloadManager Then FrmMain.PageBack()) RightCards.Remove(Loader.Name) LoaderTaskbar.Remove(Loader) - Log($"[Taskbar] 关闭下载管理卡片:{Loader.Name},且移出任务列表") + Logger.Info($"关闭下载管理卡片:{Loader.Name},且移出任务列表") RunInThread(Sub() Loader.Interrupt()) End Sub '如果已经失败,再刷新一次,修改成失败的控件 @@ -203,11 +203,11 @@ End If #End Region Catch ex As Exception - Log(ex, "添加下载管理卡片失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "添加下载管理卡片失败") End Try End If Catch ex As Exception - Log(ex, "刷新下载管理显示失败", NotifyLevel.MsgBoxAndFeedback) + Logger.Error(ex, "刷新下载管理显示失败") End Try End Sub Public Sub TaskRemove(Loader As Object) @@ -218,7 +218,7 @@ Dim Card As Grid = RightCards(Loader.Name) FrmSpeedRight.PanMain.Children.Remove(Card) RightCards.Remove(Loader.Name) - Log($"[Watcher] 移除下载管理卡片:{Loader.Name}") + Logger.Info($"移除下载管理卡片:{Loader.Name}") End Sub) End If End Sub diff --git a/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj b/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj index fe462e1..e2e7950 100644 --- a/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj +++ b/Plain Craft Launcher 2/Plain Craft Launcher 2.vbproj @@ -8,7 +8,7 @@ WinExe PCL Plain Craft Launcher 2 - v4.6.2 + v4.8 Custom false @@ -170,11 +170,6 @@ - - False - Resources\System.ValueTuple.dll - False - @@ -210,14 +205,14 @@ - - + + - + @@ -753,7 +748,6 @@ - @@ -905,9 +899,6 @@ - - - @@ -916,7 +907,7 @@ {d22bbf3c-2177-0208-4e29-8466aa41ac6f} MeloongCore - + {2dffe2a0-1101-816b-d240-f644b2d74a68} MeloongCore.Wpf @@ -942,6 +933,7 @@ + \ No newline at end of file diff --git a/Plain Craft Launcher 2/Resources/Ookii.Dialogs.Wpf.dll b/Plain Craft Launcher 2/Resources/Ookii.Dialogs.Wpf.dll index 29accf8e619bcf213832f8dd9e5d1723ce425b46..a38f004c06e999dfa32b4dbb739da08a143a40ba 100644 GIT binary patch literal 105472 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 KdkA+y3H%!Z)K0qq literal 107696 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 K$@>0I=>Gujxk;!1 diff --git a/Plain Craft Launcher 2/Resources/moddata.txt b/Plain Craft Launcher 2/Resources/moddata.txt new file mode 100644 index 0000000..4faf89c --- /dev/null +++ b/Plain Craft Launcher 2/Resources/moddata.txt @@ -0,0 +1,27010 @@ + +industrial-craft@|工业时代2 (Industrial Craft 2) +@redpower2-core|红石力量2 (RedPower2) +buildcraft@|建筑 (BuildCraft) +forestry@|林业* +railcraft@railcraft-reborn|铁路*¨railcraft-reborn|铁路 (Railcraft) + + +@ee2|等价交换2 (Equivalent Exchange 2) + +touhou-item-mod|辉夜姬的五难题 (五つの難題MOD+ ~ Touhou Items) +secretroomsmod|密室 (SecretRoomsMod) +the-camping-mod|野营* +usefulfood|有用的食物 (UsefulFood) +powerconverters-portablejims-fork|能源转换 (PowerConverters)¨powerconverters|能源转换 (PowerConverters) + + +modular-forcefield-system|模块化力场系统* +minechem-recompile|化学 (MineChem) - 非官方重编译版¨minechem-archive|化学 (MineChem)¨73373|化学 (MineChem) +iron-chests@|更多箱子*¨iron-chests-for-fabric@cyberanner-ironchest|更多箱子 (Iron Chests)¨iron-chests-fabric@|更多箱子 (Iron Chests) +balkons-weaponmod|更多武器 (Balkon's WeaponMod) +advanced-machines|高级机械 (AdvancedMachines) - Chocohead版¨@advanced-machines-uuum|高级机械 (AdvancedMachines) - Immibis版 +advanced-solar-panels|高级太阳能* +nuclear-control-2|核电控制2* + +better-dungeons|更好的地牢/寻找巧克力 (Better Dungeons / Chocolate Quest) +flans-mod-5-5-2|Flan 的枪械 (Flan's Mod) + + + +ee3|等价交换3 (Equivalent Exchange 3) +minefactory-reloaded|我的工厂 (MineFactory) + +render-player-api|玩家渲染API (Render Player API)¨renderplayerapi|玩家渲染API (Render Player API) +player-api|玩家API (Player API)¨playerapi|玩家API (Player API) + + + + + +not-enough-items-1-8@nei|NEI物品管理器 (Not Enough Items)¨notenoughitems|NEI物品管理器 (Not Enough Items) + + + +custom-npcs|自定义NPC (Custom NPCs) +millenaire|千年村庄 (Millénaire) +clay-soldiers-mod|粘土士兵* +mo-creatures|更多生物 (Mo' Creatures) + +extrabiomesxl|更多生态群系 (ExtraBiomesXL) + + + + +tale-of-kingdoms|王国* + + + + + +the-twilight-forest|暮色森林* + +portal-gun|传送枪* +simpleores@|简单矿石 (SimpleOres) +smart-moving|灵活动作*¨smart-moving-reboot|灵活动作 (Smart Moving) +easycrafting|轻松合成 (Easy Crafting) + + + + +computercraft@|电脑 (Computer Craft) + +inventory-tweaks|R键整理* + +minecraft-minions|召唤奴仆* +ender-storage@|末影存储*¨ender-storage-1-8|末影存储 (Ender Storage) + + + +forge-nbtedit-for-1-7-10|内置NBT编辑器 (In-Game NBTEdit) + + + + +rotarycraft|旋转工艺 (RotaryCraft) + +applied-energistics-1@ae1|应用能源* + + + + +Universal-Electricity|通用电力* +@btwce|比狼好 (Better Than Wolves)¨@better-than-wolves|比狼好 (Better Than Wolves) +aether@|天境 (The Aether) +@miscperipherals|电脑外设 (MiscPeripherals) + +assassincraft-assassins-creed-mod|刺客信条 (AssassinCraft) + +custom-recipes|自定义合成表* +minecraft-comes-alive-mca|虚拟人生/凡家物语 (Minecraft Comes Alive) + + +forge-essentials-74735@forge-essentials + +translocators-1-8@translocators|转运器 (Translocators)¨translocators|转运器* +craftguide|G键合成表 (CraftGuide) + +biomes-o-plenty@|超多生物群系 (Biomes O' Plenty) + + +enhanced-portals-3|增强传送门3* +compact-solars|压缩太阳能阵列 (CompactSolars / Compact Solar Arrays) +bibliocraft|收藏馆 (BiblioCraft) +natura|自然* +atomic-science|原子科学* + +atum|阿图姆:沙漠之旅/亚图姆:金沙之旅 (Atum 2: Return to the Sands) +blockphysics_by_id_miner|方块物理学 (BlockPhysics) + + +remain-in-motion|运动红石机构 (Remain in Motion) + +openperipheralcore|开放式电脑外设 (OpenPeripheral) - 核心¨openperipheraladdons|开放式电脑外设 (OpenPeripheral) - 附加¨openperipheralintegration|开放式电脑外设 (OpenPeripheral) - 联动 +modular-powersuits@modularpowersuits|模块化动力套装* + + + + +@immibis-microblocks|Immibis的小方块 (Immibis's Microblocks) + + +@redlogic|红石逻辑 (RedLogic) +powercraft-2|能量工厂 (Power Craft) +obsidiplates|黑曜石压力板 (ObsidiPlates) +@infinitubes|终极管道 (InfiniTubes) +flatsigns|平置牌子 (FlatSigns) +switches|按钮开关* +artifice|工匠的手艺* + +archimedes-ships|阿基米德之舟 (Archimedes' Ships) +cubebots|立方体机器人 (CubeBots) +truss-mod|桁架* +mutant-creatures-mod|突变生物 (Mutant Creatures) + +logistics-pipes@|物流管道* + + +magic-bees|魔法蜜蜂* +carpenters-blocks|木匠方块 (Carpenter's Blocks) +mystcraft|神秘岛*¨@mystcraft|神秘岛 (Mystcraft) - Archived + + + +minesweeper-mod|扫雷 (Minesweeper) +minechess|国际象棋 (MineChess) + + + +@factorization|工厂化/因式分解 (Factorization) + + + + +project-red-base|红石计划 (ProjectRed) - 基础¨project-red-illumination|红石计划:照明 (Project Red - Illumination)¨project-red-core@|红石计划 (ProjectRed) + +dimensionaldoors@|次元门 (Dimensional Doors) +chickenchunks@chicken-chunks|区块载入器 (ChickenChunks)¨chicken-chunks-1-8|区块载入器 (ChickenChunks) +dlt2|动态蓄水槽 (Dynamic Liquid Tanks) + +webdisplays-remasterd|内置网页浏览器 (WebDisplays) +morph|变身* + + +extracells2|更多存储单元2 (Extra Cells 2) + + +billund-223258|乐高 (Billund) +alchemyplusplus|炼金++ (AlchemyPlusPlus) +better-bows|更好弓箭系统 (Better Archery) +mumblelink|Mumble语音链接* +ender-io@enderio|末影接口 (Ender IO) + +simcraft-minecraft|模拟人生 (Simcraft) + +electrodynamics@|电动力学* +elite-armageddon¨mc-1-6-4-solar-apocalypse +mekanism@|通用机械* + + +magic-crusade-rpg-mod|魔法远征:魔法十字军 (Magic Crusade) +invasions|入侵 (Invasion) +mb-battlegear-2|挖矿与砍杀:双持与战备 2 (Mine & Blade: Battlegear 2) + +galacticraft-legacy@|星系 (GalactiCraft) + + + +journeymap@|旅行地图 (JourneyMap) + +equivalent-exchange-classic|等价交换经典版* +underground-biomes|科学地质*¨undergroundbiomesconstructs|科学地质 (Underground Biomes) +fpsplus-lagfixes|FPS优化 (FPS Plus) +ars-magica-2|魔法艺术2* + +highlands|高地* +doggy-talents|小狗天才* +plasmacraft|电浆工艺 (PlasmaCraft) + +fossils@fossils-and-archeology-revival|考古与化石 (Fossils and Archeology Revival) +glenns-gases|格林的气体 (Glenn's Gases) +the-lord-of-the-rings-mod-legacy|魔戒:传承 (The Lord of the Rings Mod: Legacy) +thaumic-tinkerer|神秘工匠* + + + +xycraft +chococraft@|陆行鸟 (ChocoCraft) +pams-harvestcraft@|潘马斯农场 (Pam's HarvestCraft) + +opis + +openblocks|开放式方块 (OpenBlocks) + + + + +randomcraft-v0-1-0|随机工艺 (RandomCraft) +dragon-mounts|龙坐骑/龙骑士* +animal-bikes|动物坐骑* + + +electro-magic-tools|电力魔法工具 (Electro-Magic Tools) +forbidden-magic|禁忌魔法* +mobtalker2|怪物交谈2 (MobTalker 2) +icbm-classic@icbm|洲际导弹 (ICBM)¨icbm|洲际导弹 (ICBM) - 已停更 +thaumic-infusion|神秘注魔* +thaumic-exploration|神秘探险* +deconstruction-table|解构工作台* + + +kcs-growable-ores@|可生长矿石 (Kc's Growable Ores / B0bGary's Growable Ores) + + + + +waila|高亮信息拓展 (What am I looking at) +chaoscraft-2|混沌工艺 (ChaosCraft) +scenter-mod|矿物追踪 (Scenter) + +ex-nihilo|无中生有*¨ex-nihilo-2|无中生有 (Ex Nihilo) +reactorcraft|反应堆工艺 (ReactorCraft) +bctools|BC扩展:更多工具 (Buildcraft Tools) +additional-buildcraft-objects|更多管道* +foundry|金属工坊* +gravitation-suite|重力装甲* +redstone-arsenal@|红石兵工厂* +big-reactors|大型反应堆* + +endertanks@|末影水槽 (Ender Tanks)¨endertanks-fabric|末影水槽 (Ender Tanks) +applied-energistics-2@ae2|应用能源2* +hopper-ducts|漏斗管道* +autofish|自动钓鱼* +mrcrayfish-furniture-mod|MrCrayfish 的家具 (MrCrayfish's Furniture Mod) +wireless-redstone-cbe|无线红石 (Wireless Redstone)¨wr-cbe-universal|无线红石 (Wireless Redstone) + + +per-fabrica-ad-astra-geologica|自合成至星辰:真实地理 (Per Fabrica Ad Astra: Geologica) + +redstone-furnace|红石炉* +pneumaticcraft@pneumaticcraft-repressurized|气动工艺 (PneumaticCraft: Repressurized)¨pneumaticcraft-repressurized|气动工艺 (PneumaticCraft: Repressurized) + +thirst-mod|饮水* +tubes|管道 (Tubes!) +pchan3-steamship-steamboat-pirates|飞艇与汽船 (SteamShip - SteamBoat and Pirates) + +betterfarming|农业增强 (Better Farming) + +lots-of-food|更多食物 (Lots of Food) + + +aquaculture@|水产业2/水产品2 (Aquaculture 2) +project-bench|高级工作台* + +apples-plus|更多苹果 (Apples+) + +qcraft|量子物理 (QCraft) + +mad-science|疯狂科学* + +enviromine|更多生存要素 (EnviroMine) + +the-erebus|混沌之地* + +lucky-block|幸运方块* +dynamic-lights|动态光源* +yarr-cute-mob-models-remake-abandoned@cute-mob-models|怪物娘化 (Yarr Cute Mob Models - Remake)¨yarr-cute-mob-models-remake|怪物娘化 (Yarr Cute Mob Models - Remake)¨cute-mob-models|怪物娘化 (Yarr Cute Mob Models - Remake) +monster-hunter-frontier-craft|怪物猎人边境工艺* +zombie-awareness@|僵尸意识* +remote-io|远程接口 (Remote IO) +electrical-age|电力时代* + + +minor-alchemy|小型炼金术* + + + + + +mcicraft|MCI工艺 (MCI Craft) + + +engineers-toolbox|工程师工具箱 (Engineer's Toolbox) +e-tools-redstone-powered-tools|电子工具:红石供电工具 (E-Tools: Redstone Powered Tools) + +modular-systems|模块化系统* + +traincraft|火车工业* +hydraulicraft|液压工艺* +utilities3|流体能量 (Utilities³) + + +metallurgy|冶金* + +school-mod-forge-1-14|学校 (School Mod) +witchery|巫术* +growthcraft|生长工艺 (GrowthCraft)¨growthcraft-community-edition|生长工艺 (GrowthCraft) +gregtech-5-unofficial|格雷科技5 (GregTech 5) + +mantle@|地幔* +customoregen|自定义矿物生成 (Custom Ore Generation) +littlemaidmobx|女仆 (LittleMaidMob) +botania@|植物魔法*¨botania-fabric|植物魔法 (Botania) +alternate-terrain-generation|交替性地形生成* +gendustry|基因工业* + + + + +betterfonts|更好的字体 (BetterFonts) +zelda-sword-skills|塞尔达剑技 (ZELDA SWORD SKILLS) + +minemenu|我的菜单 (MineMenu) +symcalc|对称度运算仪* + + +jabba|更好的储物桶 (Just Another Better Barrel Attempt) +mcheli-minecraft-helicopter-mod|MC直升机 (MC Helicopter Mod) +ex-aliquo + +steves-carts-2|史蒂夫矿车2 (Steve's Carts 2) +mariculture|海洋物语* +evilcraft@|邪恶工艺 (EvilCraft) +projecte|等价交换重制版 (ProjectE) +falling-meteors-mod|陨石 (Falling Meteors) + + + + + +glacia-dimension|冰河时代 (Glacia) +water-power|水力科技* +realtrainmod|真实火车 (RealTrainMod) +applemilktea2|苹果奶茶2 (AppleMilkTea2) +ihouse|我的房屋 (iHouse) +flaxbeards-steam-power@|FSP蒸汽动力 (Flaxbeard's Steam Power) + +steves-factory-manager|史蒂夫工厂管理 (Steve's Factory Manager) + + +thaumcraftgates|奥法管道 (ThaumcraftGates) +thaumcraft-recipes|神秘合成* +player-heads-forge|玩家死亡掉头 (Player Heads) +notenoughkeys|更好的按键控制 (Not Enough Keys) + +pet-bats|宠物蝙蝠* + +crafting-pillar-mod|合成柱* +ultratech|次元科技 (UltraTech) +@advanced-repulsion-systems|高级排斥系统 (Advanced Repulsion Systems) +atomicstrykers-infernal-mobs|稀有精英怪 (AtomicStryker's Infernal Mobs) +applecore|苹果核 (AppleCore) + + + +thaumic-energistics|神秘能源* + +chisel|凿子* +nuclearcraft-mod@nuclearcraft|核电工艺 (NuclearCraft) +opencomputers@|开放式电脑 (Open Computers) +elemental-stones|元素之石* + +waila-nbt|万用高亮显示 (Waila NBT) +thaumcraft-node-tracker|神秘节点追踪* +geochests|箱载世界* +parachutemod|降落伞 (Parachute) +gem-buffs-infinite-potion-effects|宝石效果/增益宝石 (Gem Buffs) +rftools@|RF工具箱 (RFTools) +atomicstrykers-magic-yarn|AtomicStryker的魔法线 (AtomicStryker's Magic Yarn) + +teds-old-world-gen-mod|怀旧地形 (Old World Gen) + +academycraft|超能力/学园都市 (AcademyCraft) + +the-spice-of-life|生活调味料 (The Spice of Life) + + + +storage-drawers@storagedrawers|储物抽屉* +wintercraft-gruntpie224|冬天的世界 (Wintercraft) + + +shincollecraft|深海舰队收藏 (ShinColle)¨shincolle|深海舰队收藏 (ShinColle) + +unicode-font-fixer|通用字体修复 / Unicode 字体修复* +lanteacraft|星际之门 (LanteaCraft) +matteroverdrive-17-edition|超能物质 (Matter Overdrive)¨matteroverdrive-legacy|超能物质 (Matter Overdrive) +tainted-magic|污秽魔法* +minetweaker3 +treecapitator|砍树* +insta-house|即时建造* +multi-page-chest|多页箱子 (Multi-Page Chest) + +draconic-evolution@|龙之进化/龙之研究* +galacticraft-add-on-more-planets@more-planets|更多行星 (More Planets) +thermal-foundation@|热力基本* + + +ding@|界面进入提醒* +ender-utilities@|末影设备* +magical-crops|魔法作物* +headcrumbs|更多头颅* +ex-astris|星辉生万物* +xelitez-frostcraft|冰冻工艺 (FrostCraft) +hardcore-ender-expansion@|极限末地生存* +more-fun-quicksand-mod|更多流沙* +fastcraft|快速工艺 (FastCraft) +forgeautoshutdown-1-12-2@forgeautoshutdown + +sao-ui|刀剑神域UI (Sword Art Online UI / SAO UI) +extratic|匠魂扩展 (Extra TiC) +dimensional-pockets|四次元口袋 (DimensionalPockets) +joint-block-1-7-10|机器方块 (JointBlock) +security-craft@|安全工艺* +buildcraft-additions|建筑扩充* +bedrockium-mod|基岩工艺* +blocksteps +thaumic-horizons@|神秘视界* +modtweaker@ +lootbags|战利品 (Loot Bags) +compact-lava-generator|高级地热发电机* +project-zulu|祖鲁* + +chinacraft|华夏文明 (ChinaCraft) + + +betterbeginnings-mod|更好的开局 (Better Beginnings) +utility-mobs|工具怪物* +hunger-overhaul|饥饿改革* +jei@|JEI物品管理器 (Just Enough Items) +jeiaddons +magneticraft|磁场工艺 (MagnetiCraft) +chromaticraft|缤纷纪元 (ChromatiCraft) +immersive-engineering@immersiveengineering|沉浸工程* +armourers-workshop@|时装工坊 (Armourer's Workshop) +plants-to-ores|植物矿石* +slash|命令强化* +et-futurum|把未来带回现实* +cooking-for-blockheads@|傻瓜烹饪/懒人厨房 (Cooking for Blockheads)¨cooking-for-blockheads-fabric|傻瓜烹饪/懒人厨房 (Cooking for Blockheads) + +psi@ +good-nights-sleep|夜眠梦境/晚安的梦境 (Good Night's Sleep) +binnies-mods@|宾尼的模组合集 (Binnie's Mods) +baubles|饰品栏* +more-swords-mod@|更多剑 (MoreSwords) +thaumic-bases|神秘基础学*¨thaumic-bases-unofficial|神秘基础学 (Thaumic Bases) +essentialcraft-3|源质魔法3 (EssentialCraft 3) + +hardcore-questing-mode@hqm|困难任务* +unidict@|矿辞统一 (UniDict) +thermal-dynamics@|热动力学* +zoology|动物学* +plant-mega-pack-reupload|植物世界 (Plant Mega Pack) +thaumic-revelations|神秘启示录* + +warp-book|传送书* +ex-compressum@|压缩工具* +simply-jetpacks|简易喷气背包* +blood-arsenal|血液兵工厂* +sim-u-kraft-old|模拟城市 (Sim-U-Kraft) +superheroes-unlimited|超级英雄无限* +oceancraft-mod|海洋世界 (Oceancraft) + + +witching-gadgets|巫师宝具* + +buildcraft-compat@|建筑兼容* +extrabotany|额外植物学 (ExtraBotany) +botania-unofficial|植物魔法非官方版 (Botania Unoffical) +angry-pixel-the-betweenlands-mod|交错次元 (The Betweenlands) +real-first-person-render|真实的第一人称 (Real First Person 2) + + +custom-stuff-3|自定义物品3* +lockdown|地图生成锁定* +avaritia|无尽贪婪*¨avaritia-1-10|无尽贪婪 (Avaritia) + +essential-thaumaturgy|源质神秘学* +abyssalcraft|深渊国度 (AbyssalCraft) +calculator|运算工艺* +sextiarysector2 +warpdrive|曲率驱动 (WarpDrive) +futurepack@|飞向未来 (Futurepack Mod) +hbms-nuclear-tech-mod@ntm|HBM的核科技 (HBM's Nuclear Tech Mod) +agricraft@|农业工艺 (AgriCraft) +arcane-engineering|奥法工程学* +immersive-integration +ae2-stuff +minetweaker-recipemaker|可视化合成表编辑器 (MineTweaker RecipeMaker) +thaumic-dyes|神秘染料* +gadomancy|魔像秘经* +inventory-pets|背包宠物* +levels|装备等级* +keeping-inventory +orespawn|矿石菌种 (OreSpawn) +reliquary-reincarnations@|圣遗物 (Reliquary Reincarnations (Reliquary) / Xeno's Reliquary)¨reliquary|圣遗物 (Reliquary Reincarnations* / Xeno's Reliquary) +mo-bends@mobends|更多弯曲 (Mo' Bends) +quark@|夸克* + +official-divinerpg@divinerpg|神圣RPG (DivineRPG) +harvest-festival|丰收物语* +tough-as-nails@|意志坚定* +non-update|不再有更新* +clayium|粘土工业* +better-storage|更好的储存* +davincis-vessels|达芬奇之舟/达芬奇的船* +bspkrscore|bspkrs核心 (bspkrsCore)¨bspkrscore-updated|bspkrs核心 (bspkrsCore) +techguns|科技枪* +iron-backpacks|特殊背包* +openmodularturrets|开放式炮台 (OpenModularTurrets) +technomancy|量子魔法* +quantumflux|量子通量 (QuantumFlux) +blocksniffer|方块探测 (Block Sniffer) +dragonapi +electricraft|电力工艺 (ElectriCraft) +candycraft|糖果世界 (CandyCraft) + +minefantasy2|我的幻想2 (MineFantasy2) + +rails-of-war|铁路战争 (Rails of War) +actually-additions@|实用拓展* +galaxy-space-addon-for-galacticraft@galaxy-space|星空 (Galaxy Space) +latiao-craft|辣条工艺* + +meteorcraft|陨石工艺 (MeteorCraft) +iguanas-tinker-tweaks|匠魂增强* +arrow-cam|箭矢视角 (Arrow Cam Mod) +tea-the-story|茶风·纪事 (Tea the Story)¨2668920|茶风·纪事 (Tea the Story) - 资源包-音乐补充包 +techreborn@|科技复兴 (Tech Reborn) +infusinbrewing|注魔酿造 (Infusion Brewing) +jurassicraft|侏罗纪时代 (JurassiCraft) +eternal-singularity|永恒奇点* +codechicken-lib-1-8@codechicken-lib +codechicken-core-1-8@codechicken-core|鸡块核心 (CodeChickenCore)¨codechickencore|鸡块核心 (CodeChickenCore) +automagy|自动化魔法* +aobd-singularities|AOBD的奇点 (AOBD Singularities) +universal-singularities|通用奇点* +academy-monster|超能力怪物* +sonar-core|声呐核心* +armorstatushud|耐久信息显示 (ArmorStatusHUD) +wanionlib@ +llibrary¨llibrary-legacy + + + + + + + + + + + +environmental-tech@|环境科技* + +magic-cookies|魔法饼干* +thaumic-potatoes|神秘土豆* +torcherino@|加速火把* +craftable-nether-star +veinminer|连锁采矿/矿脉矿工 (Vein Miner) + +another-one-bites-the-dust + +mine-mine-no-mi@|恶魔果实 (Mine Mine no Mi) +advanced-rocketry|高级火箭* +vics-modern-warfare-mod|维克的现代战争 (Vic's Modern Warfare Mod) +chance-cubes@|机会方块* +gun-customization +endercore@|末影核心 (EnderCore) +brandons-core@ +cofh-core@|CoFH核心 (CoFH Core) +statuseffecthud|状态信息显示 (StatusEffectHUD) +lambdalib +redstonic|红石电子* +libvulpes +ye-gamol-chattels|伊加墨的财产* +ivtoolkit +wolf-armor-and-storage|狼铠 (Wolf Armor and Storage) +better-records|更好的播放器* +worldedit|创世神 (WorldEdit) + + +worldeditcui¨worldeditcui-fabric@worldedit-cui +ztones + +dummycore¨dummycore-unofficial +extra-utilities|更多实用设备* +openmodslib|开放式模组库 (OpenModsLib) +embers|余烬* +neat@|极简血量显示*¨neat-fabric-quilt|极简血量显示 (Neat) +mob-properties|怪物属性* +ganys-surface|Gany的世界 (Gany's Surface) + +ezstorage|EZ存储 (EZStorage) +ichunutil@ +intangible + +forge-multipart-cbe@cb-multipart¨forge-multi-part +the-titans-mod|泰坦生物 (The Titans)¨the-titans-legacy|泰坦生物 (The Titans) - 旧 +enchiridion +stimmedcow-nomorerecipeconflict|合成冲突消除 (NoMoreRecipeConflict) +tinker-i-o|工匠接口 (Tinker I/O) +woot|生物工厂* + +thermal-expansion|热力膨胀* +realistic-terrain-generation|真实地形生成*¨realistic-terrain-generation-plus|真实地形生成 (Realistic Terrain Generation) - RTG 原作者继续开发的分支 +mob-rebirth@|怪物重生* +diseasecraft|疾病 (Disease Craft) +zombie-infection|僵尸感染* +astral-sorcery|星辉魔法* +neotech|全新科技 (NeoTech) +apocalypse-mod|启示录 (Apocalypse) +bookshelf-api-library + +movingworld +botania-garden-of-glass@gardenofglass|水晶花园 (Garden of Glass) +@tubestuff|RP增强 (Tube Stuff) +tiny-progressions|微型自动化* + +baubles-stuff|更多首饰* +thaumaturgical-knowledge|神秘奥义* +advanced-thaumaturgy-2|高等神秘学 (Advanced Thaumaturgy) +INpureCore +atomicstrykers-battle-towers|战斗高塔 (AtomicStryker's Battle Towers) +reborncore@|重生核心 (Reborn Core) +steves-carts-reborn@|史蒂夫矿车:重生 (Steve's Carts Reborn) +refined-relocation|简单分类* +gilded-games-util +dangerrpg|危险RPG (Danger RPG) +malisisdoors|更多门 (MalisisDoors) + +jaffa-foods-a-harvestcraft-addon|更多有趣的食物 (Just Another Fun Food Addon) +thermal-smeltery|热力冶炼厂* + +malisiscore +valkyrielib@ +waila-harvestability +mixed-magic|混合魔法* +hwyla@ +crafttweaker@ + +real-time-chat-translation-mod|实时聊天翻译* + +practical-logistics-2|实用物流监控2* +energyadditions|高级能源 (EnergyAdditions) +advanced-generators@|高级发电机* +bdlib + +pressure-pipes|压力管道* +onlinepictureframe|在线相框显示 (OnlinePictureFrame) +super-circuit-maker|超级电路* +switch-bow +minecolonies@|模拟殖民地 (MineColonies) + +mcjtylib@ +mcmultipart +aroma1997s-dimensional-world|Aroma1997的维度世界 (Aroma1997's Dimensional World) +project-73926|超级合成框架 (Super Crafting Frame) +akashic-tome@|阿卡什宝典* +morph-o-tool@|变形工具 (Morph-o-Tool) +decocraft@|装饰工艺* +refined-storage@|精致存储* +deep-resonance@|深度共振* + + + +clockwork-phase|时之沙* + +autoreglib@ +roots|根源魔法* +guide-api|指南 (Guide-Api)¨@guide-api-legacy|指南 (Guide-Api) - Archive +fraghappy-reborn +genetics-reborn|基因重生* + +router-reborn|路由重生* + +coroutil@ +vanilla-magic|原生魔法* +taoism|御灵* +essentialcraft-4-unofficial|源质魔法4非官方版 (EssentialCraft 4 Unofficial) +celestial-craft|天体* +lost-thaumaturgy|失落神秘 (Pengu's Lost Thaumaturgy) +compact-machines|更多空间/压缩空间* + +ex-nihilo-omnia|无中生有-世间万物* +last-sword-you-will-ever-need-mo@the-last-sword-you-will-ever-need-mod|最终之剑 (The Last Sword You Will Ever Need Mod) +the-last-sword-you-will-ever-need-reboot@|最终之剑:重生* + +ftb-library-legacy-forge|FTB Library(旧版) (FTB Library (Forge) (Legacy)) + + +thaumic-potatoes-2|神秘土豆2* +extraplanets|额外行星 (Extra Planets) + +xtracraft-mod|X工艺 (XtraCraft Mod) + +formivore-generators-walled-city-great-wall-ca|城墙城市生成 (Cellular Automata Generator/Great Wall Mod/Walled City Generator) + +voltz-engine +blocklings|方块酱* + + + +magia-naturalis@|自然魔法* +sbm-wooden-shears|木剪刀 (Wooden Shears) + +schools-of-magic|魔法学院 (Schools of Magic) +aether-aspects|天境要素扫描* +arcane-arteries|奥法献祭学* +thaumic-palmistry +one-click-crafting|一键合成 (One click crafting) +essential-thaumaturgy-unofficial|源质神秘学(非官方版)* +wireless-crafting-terminal|无线合成终端* +waila-plugins|Waila 插件* +appleskin@|苹果皮 (AppleSkin) +tcbotaniaexoflame|奥术投射 (TCBotaniaExoflame) +thaumic-equivalence|奥法置换* +thaumcraft-research-helper|神秘研究小助手* +thaumic-upholstry|神秘装饰* +thaumic-expansion|神秘膨胀* +nodal-mechanics|节点力学* +transmute-liquids-addon-for-thaumcraft-4|液体嬗变 (Transmute Liquids) +thaumores|奥能矿物 (ThaumOres) +notenoughthaumcrafttabs|无限神秘标签页 (Not Enough Thaumcraft Tabs) +natures-compass@|自然罗盘/生物群系指南针 (Nature's Compass) +warp-theory|神秘扭曲学* +hammer-lib@|锤子核心 (Hammer Core/Hammer Lib) + +thermal-casting|热力铸造室* +thermal-smeltery-redux|热力冶炼厂重置版* +brcore +industrial-expansion-te-addon|工业扩充(TE附属) (Industrial Expansion [TE Addon]) + + +spmodapi +quantum-pack|量子工具包* +netherores|下界矿石 (NetherOres) +tesla|特斯拉 (TESLA) +vanillafoodpantry-mod|食品储藏室 (VanillaFoodPantry Mod) +the-elysium|极乐世界* +ice-and-fire-dragons@|冰火传说 (Ice and Fire) + +yabba +useful-nullifiers|实用销毁器* +xtones@ +xnet@ +wireless-crafting-grid|无线合成网络* + +top-addons +torchmaster@|火炬大师* +zerocore@ +sleeping-bag|睡袋* +the-one-probe@|检测器* + +simply-jetpacks-2|简易喷气背包2* +snad@|子沙* +storage-drawers-extras +solar-flux-reborn@|日光通量:重制版* +simple-void-world|简单虚空世界* +shetiphiancore@¨shetiphiancore-fabric +shadowmc +scannable@|扫描器* +rebornstorage@|存储重置 (Reborn Storage) +quantumstorage|量子存储 (QuantumStorage) +p455w0rds-library +mtlib + +open-glider|滑翔翼* +mputils +shadowfacts-forgelin +eleccore +infinitylib@ +dark-utilities@ +flux-networks|通量网络* +flat-colored-blocks-forge|平滑色块 (Flat Colored Blocks)¨flat-colored-blocks-fabric|平滑色块 (Flat Colored Blocks) +jei-bees|JEI 蜜蜂 (JEI Bees) +chisels-bits|雕凿工艺 (Chisels & Bits)¨chisels-bits-for-fabric|雕凿工艺 (Chisels & Bits) +architecturecraft|建筑师工艺 (Architecture Craft) +chameleon@texel-chameleon|变色龙* +mrtjpcore +cyclops-core@ +netherportalfix@|下界传送门修正 (NetherPortalFix)¨netherportalfix-fabric|下界传送门修正 (NetherPortalFix) +rftools-dimensions@|RF工具:维度 (RFTools Dimensions) +signals|信号* +extreme-reactors|极限反应堆*¨@extreme-reactors|极限反应堆 (Extreme Reactors) - 仅 2.4.9 及以下,长期未更新 +environmental-lunartech@environmental-lunar-tech|ET:月光发电 (Environmental Lunar Tech) +angel-ring-to-bauble|可装备的天使指环* +mob-grinding-utils|刷怪塔实用设备* +rftools-control@|RF工具:控制 (RFTools Control) +immersive-petroleum@immersivepetroleum|沉浸原油* +more-shearables|更多的剪刀用途* +gregtech-gt-gtplusplus + + + + +yam-core + + +teletoro|远程传送 (TeleToro) + +re-zero-kara-hajimeru-isekai-seikatsu|RE:从零开始的异世界 (Re: Zero kara hajimeru isekai seikatsu) +minewatch +thaumcraft-inventory-scanning|神秘时代物品栏扫描* +cyclic@|循环* + +redstoneplusplus|红石++ (Redstone++) +ctm|连接纹理 (ConnectedTexturesMod) +simulated-nights|夜晚模拟* +ftb-utilities|FTB 实用工具 (FTB Utilities) +just-enough-characters@justenoughcharacters|通用拼音搜索* + +redstone-flux +cofh-world +ancient-warfare-2|古代战争2 (Ancient Warfare2) +integrated-dynamics@|动态联合/集成动力* +common-capabilities@ +jingames-dragon-block-c|龙珠C (Dragon Block C) +tan-campfire-spit|意志坚定-篝火烤架 (TAN Campfire Spit) +super-solar-panels|超级太阳能发电机* +ngtlib +geomastery|征服大地* +afsu-mod + +lightningcraft|雷电工艺 (LightningCraft) +just-enough-resources-jer@ +morpheus +wall-jump|飞檐走壁*¨wall-jump-fabric|飞檐走壁 (Wall Jump) +condensed-block-mod-reborn|凝结成块* +refined-avaritia +weather-storms-tornadoes@|局部气候&风暴 (Weather, Storms & Tornadoes) +new-things +survivalist|生存主义* +mystic-divination|秘契占星术* +cofh-lib +tabula-rasa +cofhtweaks +ender-io-zoo@enderio-zoo|末影动物园 (Ender IO Zoo/Ender Zoo)¨ender-zoo|末影动物园 (Ender IO Zoo/Ender Zoo) - 独立的 Ender Zoo +simple-usage-log|简易日志* +omnis-core +auto-paths|自动路径* +react +shared-resource-packs|共享资源包* +i-know-what-im-doing@|我知道我在干什么 (I Know What I'm Doing) +leather-works|皮革加工厂* +cyberware|机械改造* +thermal-cultivation@|热力农业* +better-builders-wands|更好的建筑之杖 (Better Builder's Wands) +jaopca@ +chickens|更多鸡* +tragicmc2|悲惨世界2 (TragicMC 2) +mobdrip + +customskinloader@|万用皮肤补丁 (CustomSkinLoader) +saltymod|盐 (SaltyMod) +immersive-tech|沉浸科技 (Immersive Technology) - 已停更¨mct-immersive-technology@|沉浸科技 (Immersive Technology) + +funky-locomotion +compatlayer@|版本兼容 (CompatLayer) +wopper|木制漏斗* +gorgecore|食用强化 (GorgeCore) +chineseworkshop|中式工坊 (Chinese Workshop) +modular-routers@|模块化路由器* +darkcore|暗黑核心* +tardis-mod|时间和空间的相对维度 (TARDIS MOD) + + +another-one-bites-the-dust-berry-bushes +gokistats|天赋技能树 (GokiStats) + +tropicraft@|热带世界* + + +sumsang|亖圼* +moblocks +creepypasta-1-0-0|蠕动意面 (CreepyPasta) +grue|格鲁* + +googlyeyes|金鱼眼 (GooglyEyes) +lycanites-mobs|恐怖生物* +back-to-eco|生态回归 (Back to Eco) +world-of-warcraft|魔兽世界* +the-witcher-adventure|猎魔人* +fancy-battleaxes@|华丽战斧* +zora-no-densha|Zora的电车 (Zora no Densha) +roguelike-dungeons@roguelikedungeons|冒险地牢* +first-aid@firstaid|急救/医疗护理* +bonfires@|篝火* +immersive-craft@|沉浸工艺* +aroma1997core +tatw +hostile-mobs-and-girls|敌对生物和女孩们 (Hostile Mobs and Girls) +better-hud|更好的HUD (Better HUD) +custom-stuff-4|自定义物品4* +powered-thingies|特斯拉科技 (Tesla Powered Thingies) + +mcmusicplayer#t1:description +obsidian-suite +wizards-of-lua|Lua魔导师 (Wizards of Lua) +mystical-agriculture@|神秘农业* +vampirism-become-a-vampire@vampirism|吸血鬼/血族传说 (Vampirism) +plants-vs-zombies-mod|植物大战僵尸 (Plants VS Zombies) +itemphysic@|物品物理掉落 (ItemPhysic) - 完整版¨itemphysic-lite@|物品物理掉落 (ItemPhysic) - 轻量版 +minenautica +improved-extraction|矿物获取改进* +ecology-mod|生态* +cakeisalie-mod|蛋糕是个谎言 (CakeIsALie) +ex-nihilo-adscensio|无中生有:Adscensio* +bookshelf@bookshelf-lib + +random-things|随意作品* + +netherex@|下界拓展 (NetherEX) +engender-mod|召唤师 (The Engender Mod) +better-questing|更好的任务* + + +ct-mortar +ct-watercan +totemic@fenns_totemic|图腾* +grimoire-of-alice|爱丽丝的魔法书 (Grimoire of Alice) +journey-to-gensokyo|幻想乡之旅 (Journey to Gensokyo) +danmakucore|弹幕核心 (DanmakuCore) +angel-of-vengeance|复仇天使 (Angel of Vengeance) +tammodized +ex-nihilo-creatio|无中生有:创世 (Ex Nihilo: Creatio) +thaumcraft|神秘时代* +colossal-chests@|巨型箱子* +auto-pickup|自动拾取* +mc-mods-u-want|背包编辑器 (All-U-Want) +potion-core|药水核心* +solar-expansion +blue-power|蓝石力量* +redstone-armory|红石军械库* +qmunitylib +quest-for-blue-name +the-last-smith@|最后的太刀匠人* +mineamp|我的音乐 (MineAmp) +quiverbow|Quiver Bow - 官方原版¨quiverbow-restrung|Quiver Bow - 重制版 +cookiecore +farseek +meecreeps@|使命必达先生 (MeeCreeps) +streams|溪流* + +blockcraftery|方块工匠* +bedrockores@|基岩矿簇 (Bedrock Ores) +chat-bubbles|聊天泡泡* +refined-storage-addons@|精致存储附属* +foamfix-optimization-mod@foamfix|泡沫修复 (FoamFix) +industrial-foregoing@|工业先锋* +expanded-armory|扩展装备* +voxelmap|体素地图 (VoxelMap) + + +mowzies-mobs@|Mowzie的生物 (Mowzie's Mobs) +thaumcraft-mob-aspects +magical-psi +starcraft-mod-scmc|星际争霸2 (StarCraft II in MineCraft) +covens-reborn +grappling-hook-mod@|抓钩* +tabbychat-2 + +yoyos|悠悠球* +cd4017be-library +iberia +reforged@|重铸* +cavern|洞穴* +block-drops-jei-addon +iron-tanks|更多储罐* +colorutility#t1:description|颜色代码 (ColorUtility) +digimobs|数码宝贝* +storage-boats-mod|存储船 (Storage Boat Mod) +mo-withers|更多凋灵 (Mo' Withers) +jingames-naruto-c|火影忍者C (Naruto C) +the-autologin-mod-for-authme-server|自动登录 (AutoLogin) +roost|鸡窝* +croparia@|矿石作物/魔种之咏* +simple-corn|简单玉米* +thaumic-jei@ +tinkers-steelworks|匠魂炼钢厂 (Tinkers' Steelworks)¨tinkers-steelworks-fork|匠魂炼钢厂 (Tinkers' Steelworks) +unicode-font-extension|Unicode 字体扩展* +placeable-items|可放置物品* +compendium|工匠防御 (Compendium / Tinkers' Defense) +sg-craft|格雷的星门 (Greg's SG Craft)¨stargate-network|格雷的星门 (Greg's SG Craft) +damage-indicators-mod|伤害显示 (Damage Indicators) +torohealth-damage-indicators|ToroHealth 伤害显示 (ToroHealth Damage Indicators) +omni-ocular +wrapup@ +nuclear-physics +wither-skeleton-tweaks|凋灵骷髅调整* +heat-and-climate|热量与气候* +customthings|自定义物品 (CustomThings) +exgregilo|格雷矿筛 (ExGregilo) +placebo@ +plants + +chinjufumod|镇守府 (ChinjufuMod +JapaneseBlock) +track-api@ +immersive-railroading@|沉浸铁路* +foodcraft-reloaded|食物工艺重置版 (FoodCraft Reloaded) +custom-main-menu|自定义主菜单* + +wildycraft + + +my-little-mob-grinder|小怪物粉碎机* +resource-loader|资源加载* +no-sleeping-allowed|禁止睡觉* +playersdropheads|玩家掉落头颅 (PlayersDropHeads) +memory-bar +toxicrain|有毒的雨 (ToxicRain) + + +cannibalism|割肉小刀/同类相食* +quick-consume|快速消耗* +planting-dirt-for-saplings@auto-planter|自动植树机 (Auto Planter / Planting dirt for saplings) + +custom-crosshair-mod@|自定义准星* +better-blink|更好的传送* +biobomb|生物炸弹 (BioBomb) +ender-hopper|末影漏斗* +mine-souls|黑魂战斗* +radixcore + +familiar-fauna|熟悉的动物* + +tinkers-tool-leveling|匠魂工具升级 (Tinkers' Tool Leveling) + +ingame-info-xml|游戏信息显示XML版 (InGame Info XML) + +lovelyrobot|萌化机器人 (LovelyRobot) +tameable-arachne|萌化女妖* +skillable +lunatriuscore +spin-to-win|旋转剑技 (Spin to Win) +soft-blocks|柔软方块* +heartblock|生命方块 (HeartBlock) +spawncontroller|自定义怪物生成 (SpawnController) +wearable-backpacks@wearablebackpacks|可穿戴背包* +heart-drop|生命汲取* +omlib|开放式炮台库 (OMLib) +dynamictrees@|动态的树 / 有活力的树 (Dynamic Trees) +merry-christmas|圣诞箱子 (Merry Christmas!) +cloud-control|可控制的云* +zombie-ore|矿石僵尸* +meanmobs|残忍怪物 (MeanMobs) +zyins-hud + +rough-tweaks|难度调整* + +the-disenchanter-mod|祛魔台 (The Disenchanter) +carry-on@|搬运* +better-than-llamas@|更好看的羊驼*¨better-than-llamas-fabric|更好看的羊驼 (Better Than Llamas) +dynamic-surroundings@dynamicsurroundingsfabric|动态环境/动态环绕*¨dynamic-surroundings-fabric-edition|动态环境/动态环绕 (Dynamic Surroundings) +alfheim@|亚尔夫海姆* +mob-battle-mod@|生物大乱斗*¨mob-battle-mod-fabric|生物大乱斗 (Mob Battle Mod) +smooth-font|平滑字体* + +reskillable +betteroffhand|更好的副手 (BetterOffhand) +entity-spring|实体弹簧* +compatskills +avaritia-tweaks +mjrlegendslib +dye-it-yourself|自动染色* +piston-expansion|活塞拓展* +underwater-rails|水下铁轨* +trebuchet +particlelib|粒子库 (ParticleLib) +star-miner|星际矿工 (Starminer) + +jglrxavpoks-uncrafting-table|jglrxavpok的拆解台 (jglrxavpok's Uncrafting Table) +rustic@|乡村* +netherutils +bonsai-trees|盆栽* + + +misty-world@|朦胧世界* + + +beta-kathairis|卡塞瑞斯 (Kathairis / Kether)¨kathairis-alive|卡塞瑞斯 (Kathairis / Kether) +manametal@|魔法金属 (ManaMetalMod) +avaritiaddons|无尽收容 / 更多空间箱子* +base +immersive-cables|沉浸线缆* + +better-title-screen|更好的标题页* +sound-filters|声音滤波器* +lambda-craft|半条命 (LambdaCraft) +vivecraft@¨vivecraft-forge-extensions +super-sound-muffler|超级消音器* +armorplus@|装备扩充 (ArmorPlus) +inspirations@|灵感* +tree-growing-simulator|跳舞树成长* + +personal-cars +thermal-innovation@|热力革新* +bewitchment-legacy@bewitchment|巫师之路 (Bewitchment)¨bewitchment|巫师之路* +better-foliage|更好的树叶* +creative-plus|创造+* +just-a-few-fish|只是一些鱼 (Just a Few Fish) +ynot +serene-seasons@|静谧四季/季节* +realm-of-the-dragons-rotd|龙之领域 (Realm Of The Dragons) +rockhounding-mod-core|地质探秘/岩石狩猎 (RockHounding) - Mod核心-几乎没有添加物品,相当于前置¨rockhounding-mod-chemistry|地质探秘/岩石狩猎 (RockHounding) - 化学分包-添加了大量机器与金属元素¨rockhounding-mod-rocks|地质探秘/岩石狩猎 (RockHounding) - 岩石分包-添加了大量岩石与有关装饰方块¨rockhounding-mod-surface|地质探秘/岩石狩猎 (RockHounding)¨rockhounding-mod-ore-tiers|地质探秘/岩石狩猎 (RockHounding)¨rockhounding-fluid-pipeline|地质探秘/岩石狩猎 (RockHounding)¨rockhounding-mod|地质探秘/岩石狩猎 (RockHounding) +fancy-block-particles|梦幻方块效果* +thaumic-katana|神秘之日本刀* +the-aether-ii@aether-ii|天境二 (The Aether II) +visibleraygenerator|永久光发电机 (VisibleRay Generator) +mmmmmmmmmmmm@|试验假人 (MmmMmmMmmMmm / Target Dummy) +aromabackup|存档备份 (AromaBackup) + +orbis-lib +the-eight-fabled-blades|八大传说之刃* +malisisblocks +useful-interior|有用的内饰* +taiga-tinkers-alloying-addon|匠魂合金附加 (Tinkers Alloying Addon) +version-checker|模组更新检测* +planar-artifice|镜面艺术: 传承 (Planar Artifice: Continuation) + +Requiem|安魂曲 (Requiem/Dissolution/Tartaros) +slashblade-in-tfc|古刀传 (Slash Blade in TFC) +mlp-mythical-creatures-updated-to-1-7-10|神话生物 (Mythical Creatures) +metamorph|变形* +reactioncraft-3-rebirth|世界反应3:重置 (Reactioncraft 3: Rebirth) +pewter|魔法匠魂* +redstone-repository-revolved|红石军械库重制版* +spawncommands-spawn-commands-teleport|传送指令 (Spawn Commands Teleport) +server-properties-for-lan@|简单联机 (Server.Properties for LAN) + +jaopcaadditions|JAOPCA附属 (JAOPCAAdditions) +cloche-call +mouse-tweaks|鼠标手势*¨@mouse-tweaks|鼠标手势 (Mouse Tweaks) - 仅部分 +jargca|JAOPCA神秘农业附属 (Just A Resource Generation Compatibility Attempt) +sky-resources|空岛资源2 (Sky Resources2) +hexxit-gear|Hexxit 装备*¨hexxit-gear-restored|Hexxit 装备 (Hexxit Gear) + +magic-clover|幸运四叶草* +inventory-crafting-grid|背包工作台* +kleeslabs@|更好地破坏半砖 (KleeSlabs)¨kleeslabs-fabric|更好地破坏半砖 (KleeSlabs) + +gregtechce|格雷科技社区版 (GregTech Community Edition) +blur@blur-plus|界面背景模糊*¨blur-fabric|界面背景模糊 (Blur) +fast-leaf-decay|树叶快速腐烂* +enable-cheats|开启作弊模式* +findit|找到它 (Findit!) +wearable-blocks|可穿戴的方块* + + +swissarmyknife|瑞士军刀 (SwissArmyKnife) +ender-io-addons|末影接口拓展 (Ender IO Addons) +historicized-medicine|历史化医学* +infinity-item-editor@|无尽物品编辑器* +extra-rails|更多功能铁轨* +gregtania +origin +minecraft-transport-simulator@immersive-vehicles|沉浸车辆 (Immersive Vehicles) +chest-transporter|搬箱器* +i18nupdatemod@|自动汉化更新 (I18nUpdateMod) +realistic-item-drops|真实物品掉落* +pixelmon@|像素宝可梦 重铸 (Pixelmon Reforged) +controlling@|键位冲突显示*¨controlling-for-fabric|键位冲突显示 (Controlling) + + +simpleleather|腐肉烧皮革 (SimpleLeather) +sync|克隆* +chiseled-me|超级变变变* +progressive-automation-early-miner|进阶自动化 (Progressive Automation) +matmos|真实环境音效 (MAtmos) +ye-olde-tanks|水箱* +improving-minecraft|改善的世界*¨improving-minecraft-fork|改善的世界 (Improving Minecraft) - 他人的非官方重上传 +wawla@|Wawla高亮显示 (What Are We Looking At) +lightarea|点亮区域 (LightArea) +@replaymod|录像回放 (Replay Mod) +stellar-sky|群星璀璨* +stellar-api|恒星API (Stellar API) +nei-addons|NEI扩充 (NEI Addons) +cucumber@ +hunting-dimension@|狩猎维度* +runes-of-wizardry|符文魔法 (Runes-of-Wizardry) + +coffee-workshop|咖啡工坊* +in-game-account-switcher@|游戏内账号切换 (In-Game Account Switcher) +consecration@|圣化* +ignitehud@ignite-hud|燃点HUD (Ignite HUD) +mrcrayfishs-gun-mod|MrCrayfish的枪 (MrCrayfish's Gun Mod) +bloodmoon|血月* +obfuscate +runic-dungeons|符文地牢 (Runic Dungeon) +poop|屎 (Poop Mod) +slurp|啜饮* +tough-expansion|意志坚定:热力附属* +mystical-agradditions@|神秘农业扩展* +vanillafix@|原版修复 (VanillaFix) +just-enough-harvestcraft|更多潘马斯配方查询 (Just Enough HarvestCraft) +charcoal-pit-4@charcoal_pit¨charcoal-pit-3¨charcoal-pit +uncomplication|IC2exp还原* +the-wings-of-alfheim-1-7-10|亚尔夫海姆之翼 (The Wings of Alfheim) + + +mubble¨mubble-forge +libraryex|MineEx 通用库 (LibraryEx) +industrial-wires|工业线缆* +mystagrad-cloche-compat +waitingtime|加载页面游戏 (WaitingTime) +dragontech|龙之科技/龙鳞实验版 (DragonTech / Dragon Scales EX / DragonScales) + +gravityfalls-mod|怪诞小镇 (Gravity Falls) +tfcbotania|TFC植物魔法 (TFCBotania) +no-recipe-guide|没有合成指南* +takumi-craft|爬行者世界/苦力怕世界* +the-mists-of-riov|神秘世界 (The Mists of RioV Mod) + +nsr-no-respawn-screen|无重生屏幕 (No Respawn Screen) +more-bees|蜜蜂拓展* +evilnotchlib +tpalette-forge|调色板 (TPalette)¨tpalette|调色板 (TPalette) - 文件覆盖 + +career-bees|职业蜜蜂* + +level-up|升级!重置 (Level Up!Reloaded) +level-up-legacy|升级!前版 (Level Up!Legacy) +moar-boats|模块化船* +numina@|模块化动力装甲前置* +tinkers-complement@|匠魂补充 (Tinkers' Complement) +everlastingabilities@everlasting-abilities|永恒能力 (Everlasting Abilities) +abyssalcraft-heads|深渊国度头颅 (AbyssalCraft Heads) +overlord@|不死者之王* +multifarm-crops|多功能农场兼容* +forestry-fermenter-addon|更多生物质* +dakimakura-mod|抱枕* + +rift +crop-eating-animals|动物自动喂食 (Crop-Eating Animals) +refraction|折射* + +librarianlib@|图书馆 (LibrarianLib) +creeper-confetti@|烟花苦力怕* +funnels|液体漏斗* +advent-of-ascension-nevermine@adventofascension|虚无世界 (Nevermine) +toroquest|托罗探索 (Toro Quest) + +rikmulds-core-mod +just-enough-pattern-banners +primitive-mobs|远古生物 / 原始生物* +realistic-cobwebs@ +simpleharvest|简单收获 (Simple Harvest) +mrcrayfishs-device-mod|MrCrayfish 的设备 (MrCrayfish's Device Mod) +block-armor|方块盔甲* +stockpile|储物桶* +loot-slash-conquer +candy-world|糖果世界* + +creativecore@ +instantunify|瞬间统一 (InstantUnify) + +mobdrops|更多掉落 (MobDrops) +states|城邦* +modular-machinery|模块化机械* +compositegear|复合齿轮/复合装甲 (Composite Gear) +kiwi@¨kiwi-fabric +cuisine|料理工艺 🍳 (Cuisine 🍳) +world-control|世界控制* + +tree-chopper|砍树* +the-lost-cities@|失落的城市* + + + +simple-underground-biomes|简单地下生物群系* +zen-foundry|禅:金属工坊 🌋 (Zen: Foundry 🌋) + + +beyondspace +animationapi +realbench|更好的工作台 (RealBench) +primalcore|原始核心 (PrimalCore) +primal-tech|原始科技* +antique-atlas@|古式地图* + +xray-1-13-rift-modloader +overloaded|超限存储* +power-tools|现代工具* + +enchanting-plus@|高级附魔台* +stick-of-death|死亡之棍 (The Stick Of Death) +godweapons|神的武器 (Gods' Weapons) +sekwah41s-naruto-mod|sekwah41的火影忍者 (sekwah41's Naruto Mod) +constructs-armory@|匠魂盔甲 (Construct's Armory) + +undertale-mod|传说之下* +globe|水晶球* +super-stick-sword|超级木棍剑 (Super Stick sword) +mekanism-generators@|通用机械发电机* +spider-queen|蜘蛛女王* +baublelicious|美妙饰品* +void-monster +shields-plus|更多盾牌* +ghost-buster +culinary-construct@|自定义三明治* +armoreablemobs|怪物装备自定义 (ArmoreableMobs) + + +advanced-inventory + + +pollution-of-the-realms|环境污染/领域的污染 (Pollution of the Realms) + +heat-and-climate-lib +waystones@|传送石碑/指路石*¨waystones-fabric|传送石碑/指路石 (Waystones) +thaumic-calculations|神秘计算器* +pams-weee-flowers|潘马斯花园 (Pam's Weee! Flowers) + + +paragliders@|滑翔伞* +ender-io-endergy@enderio-endergy|末影接口:管道拓展 (Ender IO:Endergy) +bwm-suite +ambience-music-mod|环境音乐 (Ambience) +almost-enough-items|AEI物品管理器* +mtutils +gravestone-mod@|墓碑 (GraveStone) +atlas-extras +horse-power|马力* +better-with-addons +tesla-core-lib|特斯拉核心* +voidscape|虚空工艺 (Voidscape/VoidCraft) +stygian-end-biome-expansion|末地:生物群系扩展 (Stygian End: Biome Expansion) +wooden-furnace|木制熔炉* +moreplates|更多金属板 (More Plates) +morelibs +game-stages@|游戏阶段* + +silents-gems@|寂静宝石 (Silent's Gems) +silent-lib@ +silents-gems-tic-support|寂静宝石:匠魂支持 (Silent's Gems: TiC Support) +lit-little-insignificant-things +gemulation +silents-gems-extra-parts|寂静宝石:额外部件 (Silent's Gems: Extra Parts) +fun-ores|趣味矿石* +solar-furnaces|简易太阳能 (Simple Solar Panels) +vanilladeathchest@|原版死亡箱子 (Vanilla Death Chest)¨vanilladeathchest-fabric|原版死亡箱子 (Vanilla Death Chest) +arachnophobia|蜘蛛恐惧症* +abyssalcraft-integration|深渊国度联动 (AbyssalCraft Integration) +prefab@|预制建筑*¨prefab-fabric|预制建筑 (Prefab) +haunch-hud +absent-by-design@ +no-nv-flash@|无夜视闪烁 (No Night Vision Flashing) +arcade-mod|街机* +asmodeuscore@ +building-gadgets|建筑小帮手* +dooglamoo-worlds|Dooglamoo的世界* +scp-lockdown@|SCP基金会:封锁 (SCP: Lockdown) +middle-earth-thaumaturgy|中土神秘学 (Middle-Earth Thaumaturgy) +structpro-mod-fast-schematic-spawning-system|自然神殿 (Structpro) +betterfps|更好的FPS (BetterFPS) +sky-compression +reap-mod@|收获 (Reap) +geolosys@|地质矿脉* +patchouli@|帕秋莉手册*¨patchouli-fabric|帕秋莉手册 (Patchouli) +jeid +gases-framework +ranged-pumps@|范围泵* +bagginses|背包* +ic2-classic@ic2classic|工业时代2经典版 (IC2 Classic) +opencubicchunks@cubicchunks +cubicworldgen@cwg +rally-health@ +open-terrain-generator|开放式地形生成器* + +noshelter|无庇护所 (NoShelter) +epic-siege-mod|史诗攻城 (Epic Siege) +furnace-overhaul|熔炉改革* + +architecturecraft-tridev@architecture-craft|建筑师工艺重置版 (ArchitectureCraft - TridentMC Version) +ore-farm|矿石农场* + + +plethora-peripherals@ +simple-flight|简单的飞行* +factory-tech|工厂科技 (FactoryTech) + + +mysticallib +crissaegrim + + +traverse-reforged@traverse-legacy|遍历 (Traverse)¨traverse@|遍历* +winter-wonder-land|霏雪寄语之地* +road-stuff@|道路* +ae2wtlib +real-filing-cabinet|仿真档案柜* +hycrafthds-wtf-ic2-addon|WTF 工业拓展 (WTF Ic2 Addon) +u-team-core@ +ftb-quests-forge|FTB 任务 (FTB Quests)¨ftb-quests-fabric|FTB 任务 (FTB Quests) +texfix@|材质修复 (TexFix) +mapmakers-gadgets|地图作者小帮手 (Mapmaker's Gadgets) +travellers-gear|旅者之器 (Traveller's Gear) +ceramics@|陶瓷器* +sjap@|拔刀剑日系附属包 (SlashBlade Japanese Addon Pack) + +planet-progression|星球研究* +space-advanced-addon-for-galactic-craft-3 +decimation-zombie-apocalypse|僵尸启示录 (Decimation) +rift-mod-list@|Rift 模组列表* +forgeendertech +new-tardis-mod + +advanced-chimneys|高级烟囱* +regeneration|神秘博士 - 再生 (Doctor Who - Regeneration​) +stevekungs-lib +make-zoom-zoom|更快的加载 (MakeZoomZoom) +minecraft-virtual-machines|Minecraft虚拟机* +cavern2|洞穴 II (Cavern II) +notenoughids|增加ID上限 (NotEnoughIDs) +avaritia-recipe-generator|可视化无尽配方编辑器* +trapcraft|陷阱* +mod-name-tooltip|模组名称显示* +gpick-2|进化之镐2 (GPickaxe 2) +cxlibrary + +integrated-tunnels@|集成管道* +unmending|经验不修补* +the-creeping-nether@creeping-nether|蔓延的下界* +random-psideas|Psi随想 (Random PSIdeas) +expetrum|真实世界 (ExPetrum) +equivalent-energistics|等价能源学 (Equivalent Energistics / Equivalent Energistics (LTS))¨equivalent-energistics-patched|等价能源学 (Equivalent Energistics / Equivalent Energistics (LTS)) - (LTS)patch 版 +thedragonlib@ +repose|自动上坡* +botanic-additions|植物学拓展* + +veggieway-fabric|素食之道 (The Veggie Way)¨the-veggie-way|素食之道* +gargoyles-mod|石像鬼 (Gargoyles) +hydrophobia|恐水症* +dimensional-edibles|维度食物* +passable-leaves|叶间穿行* +swingthroughgrass|穿草攻击 (SwingThroughGrass) +steves-bizarre-adventure|史蒂夫的奇妙冒险 (Steve's Bizarre Adventure) +animania|动物谷:基础 (Animania Base) +endertweaker +cofh-vanilla-tools + +rarmor|功能装甲* +immersive-io|沉浸接口 (Immersive IO) +tickratechanger|运算变速 (TickrateChanger) +botania-needs-these-things|植物魔法需要它! (Botania Needs These Things!) +nocubes¨no-cubes-reloaded¨@nocubes +orelib +tick-dynamic|动态Tick (Tick-Dynamic) +surge@|潮涌* +more-avaritia +ai-improvements@|AI改进 (AI Improvements) +project-ex|等价交换升级 (FTB Project EX/ExtendedExchange)¨extendedexchange|等价交换升级 (FTB Project EX/ExtendedExchange) + +xaeros-world-map@|Xaero的世界地图 (Xaero's World Map) +wizardry-mod|巫师艺术 (Wizardry) +fastfurnace|熔炉性能优化 (FastFurnace) +fastworkbench|工作台性能优化 (FastWorkbench) +unbreaken|工具保护 (UnbreakEn) +bitcoin|比特币* +hungering-darkness +roots-classic|根源魔法经典版* +embers-rekindled@embers|余烬复刻版* +vending-machines-revamped|自动贩卖机* +thaumic-alchemy|神秘炼金学* + +move-plus|移动方式增强* +future-minecraft|未来的版本 (FutureVersions) +contenttweaker@ +from-the-ground-up|白手起家* +clumps@|经验机制改革* +dynamic-surroundings-huds|动态环境:信息显示 (Dynamic Surroundings: HUDs) +crafting-tweaks@|合成辅助*¨crafting-tweaks-fabric|合成辅助 (Crafting Tweaks) +limelib +sparks-hammers|重锤火花* +deadly-monsters|致命怪物* +vanillaautomation|原版自动化 (VanillaAutomation) +tickprofiler|Tick分析器 (TickProfiler) +vanilla-immersion|立体工具方块* +earthworks|土方工程* +terraqueous@|地灵云心/海树山花*¨terraqueous-fabric|地灵云心/海树山花 (Terraqueous) +initial-inventory@|自定义初始物品* +interaction-wheel@ +water-strainer|滤水器* +tinkers-skyblock|匠魂空岛 (Tinkers' Skyblock) +diet-hoppers|漏斗碰撞箱修复* +xl-food-mod|超多食物 (XL Food Mod) +soot|烟尘* +hp-spells|哈利·波特:法术 (Harry Potter Spells) +recurrent-complex|自然建筑生成* +capabilityproxy@capability-proxy|功能代理 (CapabilityProxy) +reauth¨reauth-fabric +autoverse@ +transprot|运输* +default-world-generator-port +better-questing-standard-expansion|更好的任务-基础扩展 (Better Questing - Standard Expansion) +exchangers|方块交换器* +flexible-tools|灵活的工具* +dimensional-control|维度控制* +valkyrien-skies@|瓦尔基里天空* +item-scroller@|物品滚轮* +better-advancements@|更好的进度* +lucraft-core +progressive-bosses@|进化的 BOSS*¨fabric-progressive-bosses|进化的 BOSS (Progressive Bosses) +persistent-bits@ +rc-roads|真实公路 (RC Roads) +emoticons|动作表情* +simple-diving-gear|简单的潜水装备* +just-enough-energistics-jee +ironman|钢铁侠 (IronMan) +chunk-animator@chunkanimator|区块加载动画* +craftstudio-api + +fisks-superheroes-2@fiskheroes|菲斯克的超级英雄 (Fisk's Superheroes) + +aiot-botania@|植物魔法全能工具 (AIOT Botania) +botania-tweaks|植物魔法调整* +albedo +natures-aura@|自然灵气 (Nature's Aura) + +void-island-control +ic2-nei-crop-plugin|IC2育种模拟器/杂交模拟器 (IC2 Crop-Breeding Plugin) +better-storage-too|更好的储存2* +manaita-plus|更好的砧板* +bartworks|巴特的作品 (bartworks) + +placeable-motor|可放置马达* +exo-craft@ +simple-login|简单登录* +grim-pack|Grim的Mod整合* +artisan-worktables|工匠之作/工匠工作台* +ptrlib@ +creeper-awareness|爬行者意识* +what-fluid-fix +blue-skies@|蔚蓝浩空* +project-vibrant-journeys@|活力之旅 (Project: Vibrant Journeys) +bed-bugs|修复卡床* +biometweaker|生物群系修改器 (BiomeTweaker) +actuallycomputers|实用电脑 (ActuallyComputers) +fence-overhaul|斜栅栏* +zombie-players|僵尸玩家* +exotic-birds|珍奇鸟类* +charset +biometweakercore|生物群系修改器扩展 (BiomeTweakerCore) +trashcans-reborn +CompactDrawers +blockdispenser|发射器放置方块 (BlockDispenser) +redstone-paste|爬墙红石/粘性红石* +dynamic-trees-traverse-compat|动态的树:遍历附属 (Dynamic Trees - Traverse Compat) +charset-lib +betternether@|更好的下界 (BetterNether) +time-machine-mod|时光机 (Time Machine) + +upsizer-mod|更大的堆叠数量* +fence-jumper|越过栅栏* +enchantments-exchanger|便携附魔替换台* +additional-enchanted-miner@ +treasure-bags|宝藏袋* +stevecraft-by-owenpsteve2|史蒂夫工艺 (SteveCraft) +hunger-games|饥饿游戏 (The Hunger Games) +tfctech-addon|群峦工业 (TFCTech Addon) +yunomakegoodmap +organic-creepers|苦力怕蕨* + + + +industrial-renewal@|工业复兴* +draconicadditions|龙之进化拓展 (Draconic Additions) + +hated-mobs|令人讨厌的生物* + +mekanica|通用机械:DZ版* +littletiles@|LT小方块 (LittleTiles) +extended-crafting@|合成拓展* +prodigy-tech|奇才妙械* + +item-filters@|物品过滤器 (Item Filters​)¨item-filters-fabric|物品过滤器 (Item Filters​) +eblib +notenoughcodecs +future-mc@|未来的MC (Future MC) +rope-bridge|索桥* +sbm-oil-ore|油矿石 (Oil Ore) +redstone-minus-redstone|红石减红石* +more-furnaces|更多熔炉* +integrated-crafting|集成合成学* +integrated-terminals@|集成终端* +mekanism-tools@|通用机械工具* +roboticparts|机械改造1.12+ (Robotic Parts) +rewired +oh-the-biomes-youll-go@biomesyougo|你将去的生物群系 (Oh The Biomes You'll Go)¨oh-the-biomes-youll-go-fabric|你将去的生物群系 (Oh The Biomes You'll Go) +vertically-stacked-dimensions|垂直堆叠的世界* + +malisisswitches +automated-redstone|自动化红石* +thuts-elevators|Thutmose的电梯 (Thut's Elevators) +additional-resources +sky-orchards|天空果园* +mdxlib +wireless-utilities|无线设备* +tometinkers +tinkers-slashblade|刀锻冶匠魂 (Tinker's SlashBlade) +audio-death|死亡音效* +deep-mob-learning|深度怪物学习* + +tofucraftreload@|豆腐工艺重制版 (TofuCraftReload) +electroblobs-wizardry|巫术学 (Electroblob's Wizardry) +moarsigns|更多告示牌 (MoarSigns) +kamen-rider-craft|假面骑士工艺* +avaritia-io|无尽贪婪:接口 (Avaritia IO) +dense-neutron-collectors|致密中子态素收集器*¨dense-neutron-collectors-1-7|致密中子态素收集器 (Dense Neutron Collectors) +pubgmc-mod +mobultion|进化怪物 (mobultion) +waddles +project-intelligence|PI文档* +thutcore +resource-pack-organizer@|资源包管理器* +morcant-ore|莫桑矿石* +force-void-world|强制虚空世界* +i-am-very-smart-forge|我很聪明 (I Am Very Smart)¨i-am-very-smart|我很聪明* +far-from-home|背井离乡* +cotton +oxygen-teleportation +oxygen-core|氧气核心* +lead-villagers|带领村民* +delta-hard-mode|Delta 困难模式* +id-squeezer-tweak +food-ores|食物矿石* +sit@bl4cks-sit|席地而坐*¨sit-fabric|席地而坐 (Sit) + + + +cplpibalds-tweaks|CplPibald的微调 (CplPibald's Tweaks) +ore-biome|矿石生态群系* +farm-adventure|农场冒险* +the-shadow-world|暗影世界 (Shadow World) +project-306141|加帕里公园 (JapariCraftMod) +mchorses-mclib +musiccraft-mod|音乐工艺 (MusicCraft mod) +hardcore-darkness|真实的黑夜* +cola-craft|可乐工艺* + +backstab|背刺* +dynamic-stealth|动态潜行* + + +roughly-enough-items@rei|REI物品管理器* +modmenu@|模组菜单 (Mod Menu) +architectury-quilt +illuminations¨illuminations-forge +mappy +mouse-wheelie@|急速滚轮* +mrcrayfishs-vehicle-mod|MrCrayfish的载具 (MrCrayfish's Vehicle Mod) +cc-tweaked|CC: Tweaked - 已过时¨@cc-tweaked +aliensvspredator|异形大战铁血战士 (AliensVsPredator) +dragon-murder + +birds-nests|鸟巢* +minecraft-animated +refined-machinery|精致机械* + +magicalsculpture|魔法雕像 (MagicalSculpture) +ash-another-simple-hud|另一个简单的HUD (Another Simple HUD) +custom-selection-box-port|自定义选择框 (Custom Selection Box)¨customselectionbox|自定义选择框 (Custom Selection Box) +librikka-api +not-enough-wands@|更多魔杖* +deep-mob-learning-blood-magic-addon|深度怪物知识-血魔法插件 (Deep Mob Learning - Blood Magic Addon) +informed-load|更多加载信息* +huajiage-infinite-galaxy|滑稽纪元II:无尽星河 (Huaji Age II:Infinite Galaxy) + +cqrepoured@chocolate-quest-repoured|寻找巧克力重铸版 (Chocolate Quest Repoured) +fabricproxy@|Fabric 群组支持 (FabricProxy) +ex-sartagine|锅具* +xaeros-minimap|Xaero的小地图 (Xaero's Minimap) - 默认版(功能完整)¨xaeros-minimap-fair-play-edition|Xaero的小地图 (Xaero's Minimap) - 公平竞争版(功能部分缺失,已停更)¨@xaeros-minimap|Xaero的小地图 (Xaero's Minimap) - 完整版¨@xaeros-minimap-fair|Xaero的小地图 (Xaero's Minimap) - 公平竞争版(已停更) +everlastingabilities-potioncore|永恒能力-药水核心 (EverlastingAbilities-PotionCore) +optifabric +the-emerald-haven|翡翠天堂* + +simple-grinder@simplegrinder|简易研磨机* +redstone-gauges-and-switches|红石测量与开关 (Gauges and Switches) +apotheosis|神化* +lighting-wand@|照明魔杖 🌟 (Lighting Wand 🌟)¨lighting-wand-fabric|照明魔杖 🌟 (Lighting Wand 🌟) +terrarium@|地球* +climatic-biomes +howling-moon|狼人* +hostile-worlds-invasions|敌对世界-入侵 (Hostile Worlds - Invasions) +simple-storage-network|简单存储* +2973537|虚无世界1 (Eternal Isles) +scaling-health@ +minecoprocessors|微处理器* + +difficult-life +mekanismores|通用机械矿石 (MekanismOres) +pyrotech|火种科技* +rats@|老鼠* +serversync|服务器同步 (ServerSync) + +auxilium-equivalence|等价交换辅助 (Auxilium Equivalence / Auxilium) +bionisation-4|细菌病毒 (Bionisation)¨bionisation-3|细菌病毒 (Bionisation)¨bionisation-2|细菌病毒 (Bionisation)¨bionisation|细菌病毒*¨@bionisation-4|细菌病毒 (Bionisation) +tiny-mob-farm|迷你刷怪场* +soulus +sanlib + + +travelers-backpack@travelersbackpack|旅行者背包 (Traveler's Backpack)¨travelers-backpack-fabric|旅行者背包 (Traveler's Backpack) +gregtech-classic|格雷科技经典版 (GregTech Classic) +aperture +combo-armors|组合装甲 (IC2ComboArmors) + +nonausea|没有反胃 (NoNausea) +communism-mod|苏维埃工坊* +mirror +ping +the-legends-mod +bad-wither-no-cookie-reloaded¨bad-wither-no-cookie-reloaded-fabric +giacomos-fishing-net +the-hospital-mod|医院Mod*¨hospital-mod-facilities-pack|医院Mod (The Hospital Mod)¨hospital-mod-theatres-pack|医院Mod (The Hospital Mod)¨hospital-mod-pharmacy-pack|医院Mod (The Hospital Mod) +more-charcoal|更多木炭* +born-in-a-barn@ + +better-animations-collection@|更好的动物动作* + +quality-tools|工具品质* +toolscombine|工具组合 (Tools Combine) +pollutant-pump|污染泵* +infinite-pollution-filter|无限污染过滤器* +jei-hider +fastflyblockbreaking|飞行速破 (FastFlyBlockBreaking) + +planttech-2|植物科技2 (PlantTech 2) +toast-control|消息框控制* + +cocoa-magic|可可工艺* +betterportals|更好的传送门 (Better Portals) +classic-combat@|经典战斗* + +less-lag|较少的滞后* +goodbye-grass|没有草丛 (Grassta la Vista) +phosphor@|磷*¨phosphor-forge|磷 (Phosphor) +clay-bucket|粘土桶* +extra-anvils|更多铁砧 / 更多砧* +glassential|精致玻璃*¨glassential-fabric|精致玻璃 (Glassential) +tinkers-addons@|匠魂拓展 (Tinkers' Addons) +barrels-drums-storage-more|桶,圆桶,存储 & 更多 (Barrels, Drums, Storage & More) +wings|翅膀* +up-and-down-and-all-around|颠倒世界* +lost-souls@|失落的灵魂* +intelligent-energistics|智能能源* +ender-compass|末影指南针* +ic2-tweaker +thaumic-gadgets|神秘宝具* +multi-mine|多人开采* +extra-foam-for-liteloader@|Liteloader 修复 (Extra Foam For LiteLoader) +embersified|余烬能量转换* + +thaumic-grid|神秘网络* +back-tools|工具后置 / 后背工具展示* +mapwriter-2|地图作者2* +dartcraft-reloaded|达特工艺重置版* + +ceu +fantastic-lib@ +dm2|龙骑士2 (Dragon Mounts 2) +tiquality +loot-capacitor-tooltips|电容信息显示* +classic-bars|经典状态条* + +overground-ores|地表矿石* +touhou-little-maid@|车万女仆* + +eureka +lazy-ae2|懒人AE2 (Lazy AE2) +libnine +equaldragons +berries +infinity-gauntlet-mod|无限手套 (Infinity Gauntlet) +mighty-ender-chicken|强大的末影鸡* +malisisadvert|广告牌 (MalisisAdvert) +ido|移动 (Idō) +bat-happy-mod|🦇蝙蝠快乐MOD (🦇 Bat Happy Mod) +viescraft-airships|维斯工艺-飞艇! (ViesCraft - Airships!) +the-ultimate-dimension|究极次元* +advanced-mortars|更好的研钵* + +crafttweaker-utils + + +fps-reducer@|FPS减速器 (FPS Reducer) +freelook@freelook-og|自由视角 (FreeLook) +spacecraftx@spacecraftx-reloaded|航天高科X (SpaceCraftX)¨spacecraftx-reloaded|航天高科X (SpaceCraftX) + +bamboo-everything@|竹子制品*¨bamboo-everything-fabric|竹子制品 (Bamboo Everything) +nofog@no_fog|没有雾 (NoFog) +essentia-brazier|源质火盆* +antipotionmod-1-12-2|无药水效果 (AntiPotionMod) +quark-oddities@|夸克-奇思妙想* +fast-food|快餐* +more-carrots|更多的萝卜* +d-maneuver-gear@3d_maneuver_gear|3D立体机动装置 (3D Maneuver Gear) +weapon-craftery|武器工匠* +bobos-supermarket|Bobo的超市 (Bobo's supermarket) +even-more-apples|更多的苹果 (More Apples) +lucky-beans|幸运豆* +cooked +afaoe +birds-foods +morexfood@ +yummy|美味* +spice-of-life-carrot-edition|生活调味料:胡萝卜版 (Spice of Life: Carrot Edition) +refined-exchange +rs-requestify|精致存储:请求者 (Refined Storage: Requestify) +pizzacraft@|披萨工艺 (PizzaCraft) +super-factory-manager@|超级工厂管理器* +sakura|樱* +sips|更多液体容器* +gregs-construct|格雷与匠魂 (Greg's Construct) +ultra-awesome-tools-mod|超级工具 (Super Tools / Ultra Awesome Tools Mod) + +locks|锁* +special-mobs|特殊怪物* +adorn-for-forge@adorn¨adorn +missingbits +@quickcarpet + +locky +baubleshud + + + + +extra-golems|更多傀儡* +craftablecreativemodifier|可合成的创造模式强化头颅 (CraftableCreativeModifier) +ruins-structure-spawning-system|遗迹 (Ruins) +armory-expansion|匠魂盔甲扩展* +wg-block-replacer|方块生成替换器 (WorldGen Block Replacer) +multi-mob-core + +structurize|结构化* + +improvable-skills@|技能进阶 (Improvable Skills 3) + +bounding-box-outline-reloaded@bbor|自然生成建筑结构显示* +sauceconstruct +colorful-hearts@|更美观的血条 (Health Overlay / Colorful Hearts)¨health-overlay-fabric|更美观的血条 (Health Overlay / Colorful Hearts)¨health-overlay|更美观的血条 (Health Overlay / Colorful Hearts) +auto-feeder-helmet|自动进食头盔* +cc-tweaked-fabric +simple-farming|简单农业* +bigger-packets-please +lockyz-extra-dimensions-mod@ledm|更多维度世界* +psi-combat-magic +dtphc|动态的树:潘马斯附属 (Dynamic Trees - Pam's Harvestcraft Compat) +largefluidtank@large-fluid-tank|大型储罐 (Large Fluid Tank)¨largefluidtank-fabric|大型储罐 (Large Fluid Tank) +tumbleweed@|风滚草* +cubicdynamictreescompat +thermallogistics|热力物流学 (Thermal Logistics) +bithop +swordskillsapi +dynamic-sword-skills|动态剑技* +magical-instruments|魔法乐器* +enderspawn|末影龙再生成 (EnderSpawn) +animus +scootys-scp-lockdown-extras|SCP重型收容区扩展 (SCP: Lockdown Heavy Containment Zone Expansion) +modern-glass-doors|时尚玻璃门* +lemonlib|柠檬库 (LemonLib) +statues-rechiseled|雕像:重置 (Statues: Rechiseled) +trashslot@|垃圾槽 (TrashSlot)¨trashslot-fabric-edition|垃圾槽 (TrashSlot) +player-plates-forge|更多压力板 (Player Plates)¨player-plates-fabric|更多压力板 (Player Plates) +just-sleep|我就睡个觉* +auto-network-lib +click-machine|自动连点器* +mystical-adaptations|更好的神秘农业* +reinforcedtools|强化工具 (ReinforcedTools) +killing-fall +more-dogs|更多狗狗* +snow-variants|更好的雪* +searchable-chests|箱子搜索栏* +bad-mobs@ +mc-paint@mcpaint|涂鸦 (MC Paint) +goprone|匍匐前进 (GoProne)¨goprone-fabric|匍匐前进 (GoProne) +ceiling-torch@|倒置火把* +air-hop@|多段跳*¨air-hop-fabric|多段跳 (Air Hop) +better-combat-mod|更好的战斗* +ftb-money|FTB 交易 (FTB Money) +restricted-portals|传送门限制* +vampirelib@ +ingameconfigmanager|游戏内配置器 (InGameConfigManager) +playerrevive@|玩家救援 (PlayerRevive) +farlands|边境之地 (FarLands) +inworldcrafting|世界合成 (InWorldCrafting) +food-editor|食物编辑器* +custom-starter-gear|自定义初始装备* +ct-tinycoal|CT 小型煤炭 (CT TinyCoal) +tweaker-gui +crafttweaker-editor|CraftTweaker 编辑器 (CraftTweaker Editor) +unforgiving-void@|不那么仁慈的虚空* +moretweaker +riteclicker-mod|小石子 (RiteClicker Mod) + +forgiving-void@|仁慈的虚空*¨forgiving-void-fabric|仁慈的虚空 (Forgiving Void) +bread-craft|面包工艺* +alchemistry|炼金化学*¨alchemistry-fabric|炼金化学 (Alchemistry) +damage-control|伤害控制* +prestige|成就点* + + +energy-converters|能量桥接器* +signpost|路标* +diagonal-panes|对角线玻璃板* +forgelin +alchemylib +exp-ore-block-mod|经验矿石 (Exp Ore Mod) +more-glowstone|更多荧石* +yukarilib +gregic-additions +instantlava|无限岩浆 (InstantLava) + + +enchantment-descriptions@|附魔描述* +streak|残影* +dttc|动态的树:神秘时代附属 (Dynamic Trees - Thaumcraft Compat) +dtbop@dynamic-trees-biomes-o-plenty|动态的树:超多生物群系附属 (Dynamic Trees - Biomes O' Plenty Compat) +dynamic-trees-compatibility-for-climatic-biomes|动态的树:气候生态群系附属 (Dynamic Trees Compatibility for Climatic Biomes) +capability-adapter|ME功能适配器 (ME Capability Adapter) +tf2-stuff-mod|军团要塞2 (TF2 stuff mod) +mob-control-wands|怪物控制魔杖* + +athenaeum¨athenaeum-1-16 +ore-excavation@|矿石挖掘* +stone-chests|石箱子* +kjlib|KJ库 (KJLib) +iron-chest-minecarts|更多箱子矿车* +nether-chest|下界箱子* +mob-kill-messages|击杀信息通知* + +betterdispenser|能喂食的发射器 (BetterDispenser) +shulkerboxdisplay|潜影盒显示器 (ShulkerBoxDisplay) +mycommands|我的命令 (MyCommands) + + + +hearth-well + +tea-and-biscuits|茶和饼干* +controllable|手柄控制*¨controllable-fabric|手柄控制 (Controllable) +genetic-animals@|遗传动物* +stone-chest|石头箱子* +iron-shulker-boxes@|更多潜影盒* +mob-dismemberment|怪物肢解* +zoo-wild-animals-rebuild|野生动物园:重制版 (Zoo & Wild Animals Rebuilt) +kottle +customdrones|自定义无人机 (CustomDrones) +call-to-battle-2-authentic-world-war-2-experience|战争召唤2 (Call To Battle 2)¨call-to-battle-the-wwii-mod|战争召唤2 (Call To Battle 2) - 远古 +some-like-it-dry +yungs-better-caves@|YUNG 的洞穴优化 (YUNG's Better Caves)¨yungs-better-caves-fabric|YUNG 的洞穴优化 (YUNG's Better Caves) +resynth|神农科技* +flatworld|开山棒 (Flat World) +pymtech|皮姆科技 (PymTech) +corail-tombstone|Corail 的墓碑 (Corail's Tombstone) + + +arcane-archives|奥术档案馆* +divineweapon|神兵 (DivineWeapon) +camera-obscura|朝花夕拾* +animales|动物扩充* +armor-underwear-mod|盔甲内衬* +assisted-progression|进度小助手* +more-buckets@|更多桶* +laggoggles|延迟监视 (LagGoggles) +the-weirding-gadget|古怪装置* +energysynergy|能源协同 (EnergySynergy) +mine-and-slash-reloaded@mine-and-slash|挖矿与砍杀 (Mine and Slash) + +monster-swarm|怪物云集* +SimplePipes@simple-pipes + +amecs@ +world-primer + +bookworm +openeye|错误报告器 (OpenEye) +let-sleeping-dogs-lie@|嘘,别吵醒狗狗*¨let-sleeping-dogs-lie-for-fabric|嘘,别吵醒狗狗 (Let Sleeping Dogs Lie) + +super-ores|超级矿石* +gravelminer@|沙砾终结者 (GravelMiner)¨gravelminer-fabric|沙砾终结者 (GravelMiner) +client-tweaks@|客户端微调*¨client-tweaks-fabric|客户端微调 (Client Tweaks) +single-use-crafting-table-mod|一次性工作台 (Single-Use Crafting Table Mod) +get-back-to-home|回家 (Get Back to Home) +expanded-equivalence@|等价扩展* +schematica +scp-craft-decline|SCPCraft - 下降 (SCPCraft - Decline) +tetra@ +minestrappolation-5 +underwater-biome|深海生态* +create@|机械动力*¨create-fabric@|机械动力 (Create) +super-tnt-port|超级 TNT (Super TNT Mod) + +energeticsheep@energetic-sheep|脉冲羊 (EnergeticSheep) +ensorcellation@|万象* +inventory-sorter|物品分拣* +speedster-heroes|闪电侠* + +curios@¨curios-fabric +village-spawn-point@|村庄出生点*¨village-spawn-point-fabric|村庄出生点 (Village Spawn Point) +spawnercraft|刷怪笼合成 (SpawnerCraft) +openfm|开放电台 (OpenFM) +the-dalek-mod@dalek-mod¨daleks +modular-diversity|模块化多样性* +botanic-bonsai|植物魔法盆栽* +modular-magic|模块化魔法* + +magic-kingdoms-mod|魔法王国 (Magic Kingdoms Mod/Schools of Magic Mod) +zollern-galaxy|卓伦星系* +macaws-bridges@|Macaw的桥梁 (Macaw's Bridges) + +trample-stopper|防止踩踏*¨trample-stopper-fabric|防止踩踏 (Trample Stopper) +macaws-roofs@|Macaw的屋顶 (Macaw's Roofs) +shadows-of-greg|格雷之影 (Shadows of Greg) +loottabletweaker@ +rockycore +tree-tweaker +worleys-caves|沃利的洞穴 (Worley's Caves) +additional-structures@|失落废墟 (Additional Structures/Rex's Additional Structures)¨additional-structures-fabric|失落废墟 (Additional Structures/Rex's Additional Structures) + + + + +enhancedvisuals@|增强视觉效果 / 拓展视觉效果 (EnhancedVisuals) +potion-fingers-redux|药剂环/药水指环 (Potion Rings) +balloon-sheep|气球羊* +farming-for-blockheads@|农场贸易 (Farming for Blockheads)¨farming-for-blockheads-fabric|农场贸易 (Farming for Blockheads) +oreexcavation-integration|矿物开凿 (Ore Excavation Integration) +engineers-workshop|工程师工作站* +the_legend_of_the_brave|勇者传说 (The Legend of The Brave) +twerk-sim-2k16 +fart-generator|屁能发电机 (Fart Energy Generator) +ex-nihilo-fabrico|无中生有:Fabrico* +holoinventory|物品显示/物品清单 (HoloInventory) +reactor-stuff|反应堆材料* +traitors-better-swampland-mod|更好的沼泽 (Traitor's Better Swamplands Mod) +soviet-abandoned-lab-mod@soviet-era|苏维埃风格装饰 (Soviet Era) + +charm@¨charm-reforged +village-names@|村庄名字* +advanced-rocketry-tweaker +alternating-flux|交变磁通* +projectextended|等价交换扩展 (ProjectExtended) +tfc-metallum|群峦合金 (TFC:Metallum) +reactor-turbines-mod-for-ic2 +mutant-beasts|突变生物重置版* +jei-integration@|JEI扩展 (JEI Integration) +funny-fruit|滑稽果 (FunnyFruit) +life-tech|生命工艺* +exponential-power|指数能源* +girl-armor-mod|女式盔甲 (V-Girl Armor Mod) + +nomadic-tents|游牧帐篷* +zetta-industries|泽它重工* +kekztech +by-the-gods|神迹* +bee-angry-est|愤怒的蜜蜂 (Bee Angry-est) +titanium@|钛* +chemlib¨chemlib-fabric +carrots-lib|胡萝卜库 (Carrots Library) +no-hostiles-around-campfire@|围火无怪*¨no-hostiles-around-campfire-fabric|围火无怪 (No Hostiles Around Campfire) +healing-campfire@|治愈营火*¨healing-campfire-fabric|治愈营火 (Healing Campfire) +minetunes +jetif|物品丢入流体 (Just Enough Throwing In Fluids) +rftools-base@|RF工具:基础 (RFTools Base) +flopper@|流体漏斗* +exhausted-stamina|竭力攻击* +staminaplus|耐力值 (StaminaPlus) +enhanced-armaments|增强装备* +spatialcompat|空间兼容 (SpatialCompat) +extended-reach +no-recipe-book|没有配方书* +darknesslib +tfcraft@terrafirmacraft|群峦传说 (TerraFirmaCraft) +redstone-control|红石控制* +snow-real-magic@|雪!真实的魔法!⛄ (Snow! Real Magic! ⛄)¨snow-real-magic-fabric|雪!真实的魔法!⛄ (Snow! Real Magic! ⛄) +comforts@|舒适用品*¨comforts-fabric|舒适用品 (Comforts) +plasmacannon|等离子炮 (PlasmaCannon) +plasmaengines|等离子引擎 (PlasmaEngines) +bonny-food +emerging-technology-hydroponics|新兴技术 (Emerging Technology) + + +twilightopia-phantasy|暮托邦之梦 (Twilightopia) +engineers-decor|工程师的装饰 (Engineer's Decor) +engineers-tools|工程师的工具 (Engineer's Tools) +wesleys-roguelike-dungeons@|Wesley的冒险地牢 (Wesley's Roguelike Dungeons) +xp-tome@|经验之书* +varied-commodities +tinkers-things|匠魂扩增 (Tinkers' Things) +just-enough-buttons|更多的按钮* +clock-hud|时间显示器 (Clock HUD) +tektopia|桃花源记/特克托皮亚 (TekTopia) + + +fabric-language-kotlin@ +ftb-backups-forge|FTB备份 (FTB Backups) +cyclopstek|独眼巨人 (CyclopsTek) + +champions@|冠军/强敌* +danger-lies-ahead|前路危机* +croploadcore +defiled-lands|污秽之地* +arcanum|奥秘* +random-enchants|随机附魔* +much-more-spiders-v2|更多种类的蜘蛛 (Much More Spiders) +compressed-items +no-tree-punching@|无树可撸* +harvest-festival-legacy@|丰收物语移植版* +friendlymobs|友好的怪物 (FriendlyMobs) +simplecore-api@|简单前置 (SimpleCore API / SimpleCoreLib) +topography|地形* +jei-villagers|JEI村民交易查看 (JEI Villagers) +bnbgamingcore +igauntlet|灭霸手套 (IGauntlet) +alcatrazcore +debugserverinfo +the-midnight@|午夜* +moolands|奶牛世界* +egg-craft|蛋工艺* +tinkersextras +poke-lucky|宝可梦幸运方块 (PokeLucky) +usefultnt|更有用的TNT (UsefulTNT) + +crow-flight|乌鸦坐飞机* +findme@|东寻西觅 (FindMe) +minecraft-transit-railway@|我的世界铁路* +random-loot-mod@randomloot|随机战利品* + +tinkers-aether|天境工匠* +mine-and-slash-auto-compatibility|挖矿与砍杀自动兼容 (Mine and Slash Auto Compatibility) +metallurgy-core|冶金核心 (MetallurgyCore) +blank-planet +betterachievements|更好的成就 (Better Achievements) +extra-bows|更多的弓* +forgotten-relics|失落遗物学* +ore-core@|矿石核心* +ordinary-coins|普通硬币* +peanut-mod|花生! (Peanuts!) + +in-game-wiki-mod +betterbedrockgen|更好的基岩 (Better Bedrock Gen) +wsbim-legacy-blocks-and-items +storage-items-mod +what-should-be-in-mc-wsbim +bluestone +effortless-building@ +ic2-classic-tweaker +Ic2c-Crop-Overrides|IC2经典版作物覆盖 (IC2C Crop Overrides) +ic2c-extras|工业时代2经典版拓展 (IC2C Extras) +advanced-solars-classic|高级太阳能经典版* +power-chisels|能量凿子* +ic2c-custom-soils +homing-exp-orbs|经验球归航* +enchantmentglint|自定义附魔光效 (Jabelar's Truly Magical Enchantment Glints) +floricraft|花卉工艺* +weisscore +glibys-physics|Gliby的物理 (Gliby's Physics) +electro-magic-tools-ic2-classic|电子神秘工具 (Electro-Thaumic Tools - IC2 Classic) +forceasciifont|强制ASCII字体 (ForceASCIIFont) +skewers|烤串* +get-in-the-bucket-mod@|进入水桶*¨get-in-the-bucket-mod-fabric|进入水桶 (Get In The Bucket Mod) +fertilization|施肥*¨fertilization-fabric|施肥 (Fertilization) +additional-banners@|更多旗帜* +dropt +the-elven-forest|精灵森林 (The Elven Forest​) +the-beneath|深渊世界* +not-enough-characters|NEI 拼音搜索* + +mine-addons-2 +terrafirmacraftplus|群峦传说 + (Terrafirmacraft +) +quick-consume-2|快速摄入2* +mctitle +mgui@mutil +sublib +dense-ores|致密矿石* +archisections +cavecontrol|洞穴控制 (Cave Control) +expandedredstone|红石扩展 (Expanded Redstone) +legacycraft|传统工艺 (LegacyCraft) +geostrata +territoryzone +loottweaks +critterpet +condensedores +treeclimbing +more-electric-tools|更多电力装置* +wireless-fluid-terminal|无线流体终端 (AE2 Wireless Fluid Terminal) +wireless-interface-terminal|无线接口终端 (AE2 Wireless Interface Terminal) +wireless-pattern-terminal|无线样板终端* +better-questing-rf-expansion|更好的任务-RF拓展 (Better Questing - RF Expansion) +hurt-animation-remover +more-cauldrons|更多炼药锅* +parabox +sky-grid +forbidden-arcanus@|禁忌与奥秘 (Forbidden and Arcanus) +mysticalmechanics|奇械学 (Mystical Mechanics API) +backpacked|背包*¨backpacked-fabric|背包 (Backpacked) +starsh|星舰 (StarShip) +tweakeroo@ +integrated-rest@ +citadel@ +screenshot-browser|内置截图管理器* + + +curio-of-undying@charm-of-undying|不死图腾插槽/不死图腾槽位 (Curio of Undying / Trinket of Undying / Charm of Undying)¨curio-of-undying-fabric|不死图腾插槽/不死图腾槽位 (Curio of Undying / Trinket of Undying / Charm of Undying) +explorercraft-worldexpansion|探险者 (Explorercraft) + +enigmatic-legacy@|神秘遗物* +end-reborn@endorium|末地:重生 (Endorium)¨end-rebellion|末地:重生 (Endorium) + +ezstorage-2|EZ存储2 (EZStorage 2) +more-chickens|更多鸡扩展* +eoa-fa|魔戒:第一纪元 (Eras of Arda: The First Age Legacy submod) +the-rc-mod +rubybyimxiaoanag|红宝石 (Ruby) +jojo-hamon-era@|JoJo: 波纹时代 (JoJo: Hamon Era) + +OpenSecurity|开放式安全* +the-legend-era|传说纪元* +level-up-hp-forge|生命提升 (Level Up HP)¨level-up-hp|生命提升 (Level Up HP) +more-planet-extras +randompatches@|随意修复 (RandomPatches)¨randompatches-fabric|随意修复 (RandomPatches) +ships-mod|船* +tfc-metric|公制重量转换 (TFC Metric) + + + +tfc-additions|群峦附加 (TFC-Additions) +raolcraft-w +litematica@|投影*¨litematica-forge|投影 (Litematica) +telepastries|传送蛋糕 (TelePastries) +heroesexpansion|超级英雄拓展 (HeroesExpansion) +attributefix@|属性修复 (AttributeFix) +dynamic-transport|动态运输* +tool-builder|铸器师* +bountifulbaubles|丰富的饰品 (Bountiful Baubles)¨bountifulbaubles-fabric|丰富的饰品 (Bountiful Baubles) + +manacraft|魔能工艺 (ManaCraft) + + + + +forge-backpacks|更多背包 (Backpacks) +repurpose +unlimited-chisel-works@ +kfc +rainbow-oak-trees|彩虹橡树* +spawntabletweaker|生成调整 (SpawnTableTweaker) +large-ore-deposits|大型矿床* +gregtech6-unofficial|格雷科技6非官方版 (GregTech 6 Unofficial) +mahou-tsukai@|魔法使* + +moar-tinkers +baubley-heart-canisters@|心之容器* +jaopcasingularities@|JAOPCA奇点 (JAOPCA Singularities) + +labymod + + +guidebook +lithium@|锂*¨lithium-forge|锂 (Lithium) +left-2-mine|求生之路* +worldeditcui-forge-edition-2 +world-book +uppers|倒置漏斗* +spartan-weaponry@|斯巴达的武器* +malilib@¨malilib-forge +infraredstone +incorporeal|幻想多媒体* +amun-ra + +mysterious-mountain-lib@mmlib|妖怪之山通用库 (MysteriousMountainLib) +loottweaker +rediscovered@|特性重现* + + +baubles-reborn|饰品栏重置版* +pams-brewcraft|潘马斯酿造工艺 (Pam's Brewcraft) +dirtcraft|泥土工艺 (DirtCraft) +minihud@|迷你HUD (MiniHUD) +potato-craft|土豆工艺* + +bed-patch + +data-loader-forge¨data-loader + +simply-light|更好的灯* +lightning-bolt-mod|雷电攻击* +spartan-and-fire|斯巴达之冰与火 (Spartan and Fire) + +beacons-for-all@¨beacons-for-all-fabric + +more-flowers|更多功能花* + +buzzier-bees@ + +lollipop|棒棒糖* +enemyz|敌意显示* +thaumic-restoration|神秘复辟* + + +primal-boat|原始船舶* +eyes-in-the-darkness +thaumic-augmentation|神秘进阶* +lost-magic|失落的魔法* +thaumic-arcana +thaumic-wonders|神秘奇境* +crimson-warfare +terra-1-to-1-minecraft-world-project +multiverse-pouch|多元宇宙袋* + +electroblobs-wizardry-twilight-forest-spell-pack|巫术学:暮色森林法术包 (Electroblob's Wizardry: Twilight Forest Spell Pack) +blockbuster +fishs-undead-rising|Fish的不死崛起/Fish的亡灵崛起 (Fish's Undead Rising) +cloth-config@¨cloth-config-legacy +just-map¨just-map-unlimited|Just Map - 无限制 +too-realistic-inventory|真实背包 (Realistic Inventory) +mob-farm|生物农场* +acceleratorcraft|加速器工艺 (AcceleratorCraft) +minecraft-spongebob-squarepants-mod-for-the-1-7-10 +utility-worlds|实用世界* +goblin-traders|哥布林商人*¨goblintraders-fabric|哥布林商人 (Goblin Traders) +divine-favor|神的恩惠* +volumetric-flask|量瓶* +loot-bag-mod|战利品包* + +minecraft-dungeons-mod|我的世界地下城* + +seasonal-bees|季节性蜜蜂* +carpet@|地毯* +handmadegunsmodex|自定义枪械 (HandmadeGuns) +equivalent-additions@|等价拓展* +mixinbootstrap@ +powah +natural-pledge|自然誓约* +more-berries@|更多浆果* +zeiyocraft +time-stages|阶段时间* +additional-events +artemislib + +easy-retrogen|简易重生成* +extraplayerrenderer@|额外玩家渲染 (Extra Player Renderer) +rwbym +libnonymous +shattered-moon +tinkersurvival@|匠魂生存 (Tinkers' Survival) +portablecraft|便携物品 (PortableCraft) + +better-than-bunnies@|给兔子戴上礼帽*¨better-than-bunnies-fabric|给兔子戴上礼帽 (Better Than Bunnies) +arcane-essentials|奥术精要* +the-aurorian@|极光幽境* +egg-auto-hatch|鸡蛋自动孵化* +performant|性能优化* +tube-transport-system|管道传输系统* + +transmutation-alchemy¨transmutation-alchemy-revival +extra-spells-electroblobs-wizardry|额外咒语 (Extra Spells) +ancient-spellcraft|古代咒法* +moving-elevators@ +interstellar-exoplanets@|星际:系外行星 (Interstellar: Exoplanets) +infini-tic +extra-disks@|更多磁盘* +optiforge +magic-seeds-for-electroblobs-wizardry|巫术学魔法种子 (Magic seeds for Electroblobs Wizardry) +extra-alchemy@extraalchemy|扩展炼药* +beyond-the-veil|帷幕彼端* +maple-syrup|枫糖* +blood-particles|血液粒子效果* +nyx +lieutenant@ +matthews-difficulty-mod +old-combat-system|旧版战斗系统* +vampires-need-umbrellas@ +hypnotics|安眠药 (hypnotics) +villager-market|村民市场* + +linear|线性放置* +immersive-portals-for-forge@immersiveportals|沉浸式传送门 (Immersive Portals)¨immersive-portals-mod|沉浸式传送门 (Immersive Portals) +universalbestiary +autumnity@|秋原* +worldgeneration-profiler +chunk-in-a-globe|球内区块* +dragon-mounts-legacy@|龙骑士:传承 (Dragon Mounts: Legacy) +fruit-trees@fruitful-fun|妙趣果园 🍊 (Fruitful Fun 🍊) +journey-into-the-light-mod@jitl|光明之旅·神之本质 (Journey Into the Light · Essence of the Gods) +kitchen-mod|厨房 (The Kitchen Mod)¨the-kitchen-mod-knife-and-fork|厨房 (The Kitchen Mod) - Bug 修复版 +more-dungeons|更多地牢* +voyage +idealland|理想境* + + +second-screen + +fastasyncworldedit-forge +arcanecraft|奥法工艺 (ArcaneCraft) +retrobees +beebetteratbees|育蜂指南 (BeeBetterAtBees) +inverted-enchantments|负魔书 (InvertedEnchantments) +general-laymans-aesthetic-spying-screen-glass +diy_title|自定义名称前后缀 (diy_title) +tooltweaks|禁用原版工具 (ToolTweaks) +atop|超多生物群系护甲 (Armor for Biomes O' Plenty) +tinkers-forging|工匠锻造 (Tinker's Forging) +gravity-gun|重力枪* +mekanism-additions@|通用机械附加* +signpicture|告示牌图片 (Sign Picture) +vampirism-integrations@|吸血鬼联动* +gottschcore@ +not-enough-crashes@notenoughcrashes|崩溃优化*¨not-enough-crashes-forge|崩溃优化 (Not Enough Crashes) +crash-to-main-menu|崩溃返回主菜单* +tinkers-jei + +better-questing-quest-book@|更好的任务-任务书 (Better Questing - Quest Book) +engineers-doors|工程师的门 (Engineer's Doors) +tps-generator|TPS发电机 (TPS Generator) +better-drowning@|更好的溺水* +bibliotheca +kubejs@¨kubejs-fabric +tickcentral +lowocalizatiwn +redlib +modern-ui@|现代化 UI (Modern UI) +auto-config-updated-api +medieval-madness|中世纪的疯狂* + +caelus@¨caelus-fabric +xeocore +wtbw_lib +dev-world-fabric +threecore +moddirector +function-api +targetingapi +re-targetingapi + +dominionlib + +endergetic@|末地拓展 (The Endergetic Expansion) +swamp-expansion@ +galactictweaks@ +dungeon-tactics|地牢战术* +villagers-nose|村民的鼻子 (Villager's Nose) +dungeons2|自定义地牢 2 (Dungeons 2) +lang_tool|加长工具 (lang_tool) + + +emojiful@ +item-compatibility +aether-lost-content@|天境:遗失之物 (Aether: Lost Content Addon) +gunpowderlib +nuclearcraft-overhauled@|核电工艺:重制版 (NuclearCraft: Overhauled) +nei-lotr|魔戒NEI插件 (NEI LotR) + +adventure-backpack|探索者背包* +speed-illusion +supertic|匠魂药水效果 (SuperTiC) +the-bumblezone-forge@the-bumblezone|蜜蜂领域/黄蜂领域 (The Bumblezone)¨the-bumblezone-fabric@|蜜蜂领域/黄蜂领域 (The Bumblezone) +beesourceful +middle-earth-industry|中洲工业 (Middle-Earth Industry) +thut-wearables +after-the-drizzle|细雨田园 (After the Drizzle) +cmdcam@|CMD 指令摄影机 (CMDCam) +climate-control-geographicraft@geographicraft|气候控制 / 地理世界 (Climate Control / Geographicraft) + +cosmetic-armor-reworked|时装盔甲重置版* + +efab¨@efab +potion-of-bees@|蜂群药水 (Potion of Bees)¨potion-of-bees-fabric|蜂群药水 (Potion of Bees) +wyrmroost@|猛龙之居* +productivebees@|资源蜜蜂 (Productive Bees) +gkolivers-super-tic + +songs-of-war-mod|战争之歌 (Songs of War) +fluidict +squidcraft@|鱿鱼工艺 (SquidCraft) +clothesline|晾衣绳 (ClothesLine)¨clothesline-fabric|晾衣绳 (ClothesLine) +siege +fermion-core +omnitranslation|万能翻译 (OmniTranslation) +the-egg-came-first|先有蛋* +nuclearcraft-helper|核电助手 (NuclearCraft Helper) +the-hive-more-bee-content +tinkersmiddleearth|中洲匠魂 (Tinker's Middleearth) +inventory-pause +snowy-leaves|霜花叶* +materialis@ +tesseract@|超立方体* +carrier-bees|物流蜜蜂* +tinkers-reforged@|工匠再锻* +mystical-world|魔幻世界* +recipes-for-all|配方书全解锁 (Recipes for All) +gregicality +the-lord-of-the-rings-mod-renewed|魔戒:复兴 (The Lord of the Rings Mod: Renewed) +modelloader +animal-crops@|动物作物* +terrafirmacraftneiplugin +furenikusroads@furenikus-roads|Fureniku的路 (Fureniku's Roads) +patchouli-quests|帕秋莉任务手册* +extraacademy|学园附属 (ExtraAcademy) +iitemrenderer-reborn +time-overhaul|时间改革* +steamweapon|梗多武器 (StemWeapon) +counter-guns + +gregtech-chill-edition|格雷科技轻松版 (GregTech: Chill Edition) +custom-player-model-cpm|自定义玩家模型 (Custom Player Model)¨custom-player-model-cpm-remake|自定义玩家模型 (Custom Player Model) +roughly-enough-resources +so-many-enchantments@|更多附魔* + +sisser +hxcenchants|多样化附魔 (HxCEnchants) +better-dropped-items|更好的掉落物* +hxc-core +surrounding-indicators@ +gobber-fabric|戈伯2 (Gobber2) +gobber|戈伯* +iblis|恶魔* + +the-king-of-the-villagers|村民之王 (The King of the Villagers) +bring-me-the-rings +bloomful@ +pick-pocketer|扒手* +terraforged +rad-metabolosis +mmd-orespawn +tragicmc3|悲惨世界3 (TragicMC 3) + +not-enough-rtgs|更多RTG (Not Enough RTGs) +qmd|量子块动力学 (Quantum Minecraft Dynamics) +environmental-rads +fission-based-neutron-collector|裂变能中子素收集器* +trinity|三位一体* +macaws-windows@|Macaw 的窗户 (Macaw's Windows) +music-player|音乐播放器* +csokicraftutil +large-enchants +angrysun|炙热太阳 (AngrySun) +its-not-long-enough|与现实相同的昼夜交替 (It's Not Long Enough) +sunscreen-gel|防晒霜* +muya1-7-10|姆亚核心 (MuyaCore) +macaws-furniture@|Macaw的家具 (Macaw's Furniture) +macaws-doors@|Macaw 的门 (Macaw's Doors) +blueprint@ +geyser-mod +not-enough-pets@|更多宠物* +potionextension +torchslabs-mod|更好的火把放置 (Torch Slabs Mod) +routerrebornlib +the-magic-doorknob@ +ultimate-skyblock-generator +everyone-poops-dung-fertilizer|肥料 (Everyone Poops - Dung Fertilizer) +ascension-of-the-divine +nebulaecraft +inventory-overlay|背包显示* +ic2magma +iridium-source|铱矿产* +frogcraft-rebirth|青蛙化工:重生 (FrogCraft: Rebirth) +coaxium-mod-1-12-2-ic2-addon|科亚烯 (Coaxium Mod) +energy-control|能源控制* +gulliver-reborn + +rationcraft@ +default-options@¨default-options-fabric +ender-mail@|末影邮递* +more-overlays|更多叠加层* +stefinus-3d-guns-mod|3D枪械 (New Stefinus Guns)¨stefinus-3d-guns-mod-s3dgm|3D枪械 (New Stefinus Guns) + +moderncraft-core +lang_magic|言灵 (lang_magic) +noexpensive@|不昂贵 (NoExpensive) +rough-mobs-revamped|粗暴的怪物重置版* +fullbright|充满光明* +backpacks|背包! (Backpacks!) + +living-enchantment|生命附魔* +karat-garden|克拉的花园* + +bard-mania +shulkerboxtooltip@|潜影盒提示框 (Shulker Box Tooltip) + +crafting-dead-official|行尸走肉 (Crafting Dead)¨crafting-dead-legacy|行尸走肉 (Crafting Dead) +lord-craft + + +stupid-things +more-gems-fabric|更多宝石 (More Gems) +minewars +gregicadditionscompatibility +combined-potions|组合药水* +plusticminusbad +baileys-dailies +joshuas-christmas-mod +enderio-fluxified@ +skizzik + + +sandbag|沙袋* +tinkers-arsenal +garbage-energy|废品能源炉* +quirky-generators +megaloot|超级战利品 (MegaLoot) + +mad-villagers|疯狂的村民* +logical-drops|逻辑工艺 (Logical Craft / Logical Drops) +drone-craft +water-source|水源* + +hungteens-plants-vs-zombies-mod@pangteens-plants-vs-zombies|HungTeen的植物大战僵尸 (HungTeen's Plants vs Zombies Mod) +pams-desertcraft|潘马斯沙漠工艺 (Pam's DesertCraft) +pams-bonecraft|潘马斯骨头工艺 (Pam's BoneCraft) +thermal-singularities|热力奇点* +minejurassic +terraria-craft@terrariacraft|泰拉瑞亚世界 (TerrariaCraft 🌳) +colytra@|鞘翅胸甲*¨colytra-fabric|鞘翅胸甲 (Colytra) +insects|昆虫* +sound-reloader|声音重载* +tool-belt|工具皮带* +argentina-food-mod|阿根廷的食物* +pet-names@|宠物名字*¨pet-names-fabric|宠物名字 (Pet Names) +collective@¨collective-fabric +giselbaers-durability-viewer@durabilityviewer|耐久指示器 (Durability Viewer) +more-cookies|更多饼干* +apple-carrot|苹果胡萝卜* +eat-yo-veg +bountiful@|赏金*¨bountiful-fabric|赏金 (Bountiful) +betterenchantment|更好的附魔 (BetterEnchantment) +purified-flesh-mod@|纯净的腐肉* +gotminecraftmod@|权力的游戏 (Game of Thrones Mod) +nosleep|禁止睡觉 (No Sleep) +minersadvantage|矿工的优势 (MinersAdvantage) + +simple-backpack-fabric|简单背包 (Simple Backpack) + +gas-conduits|气体导管* +handgun-from-terraria +more-discs-mod|更多唱片 (More discs mod) +edible-honeycombs +emerald-and-ruby +craftable-nametag|可合成的命名牌* +dyeable-flower-pots|染色花盆 (More Flower Pots / Dyeable Flower Pots)¨more-flower-pots|染色花盆 (More Flower Pots / Dyeable Flower Pots) +graffiti|涂鸦* +bunny-boots +backported-flora +eat-eggs +wool-plates|羊毛压力板* +more-berry-uses|更多浆果用途* +elemental-blades|元素之刃 (Elemental Blades / Elementium) +beyond-earth@|飞越地球 (Beyond Earth/Space-BossTools)¨beyond-earth-fabric|飞越地球 (Beyond Earth/Space-BossTools) +simple-planes@|简单飞机*¨simple-planes-fabric|简单飞机 (Simple Planes) +world-tooltips|掉落物信息显示* +extra-arcane-knowledge-electroblobs-wizardry|额外巫术知识 (Extra Arcane Knowledge) +bacteriums|细菌重置版 (Bacterium)¨bacterium|细菌重置版* +pillagers|掠夺者* +guard-villagers@|警卫村民* +simple-machinery|简单机器* + +bridge-maker@|桥梁制造者* +craft-your-saddle +no-pvp-cooldown +never-break|损坏防护* +simple-villager-spawn-egg +banana-decor-forge +immersive-metal|沉浸金属* +coffee-time +drink-mod|饮料模组* +more-zombie-villagers@|更多僵尸村民*¨more-zombie-villagers-fabric|更多僵尸村民 (More Zombie Villagers) +naturally-charged-creepers@|自然生成闪电苦力怕*¨naturally-charged-creepers-fabric|自然生成闪电苦力怕 (Naturally Charged Creepers) +skinport|皮肤移植 (SkinPort) +dynamic-surroundings-soundcontrol|动态环境:音效控制 (Dynamic Surroundings: SoundControl) + +chop-down-updated +aegis-weapon-system-mod|宙斯盾作战系统-战舰模组 (Aegis Weapon System -Warship's Mod) +advanced-hook-launchers|高级钩爪发射器* +vampire-magic +fantasyunderworld|江湖行 (fantasyunderworld) +stacc +a-riot-of-colour-craft|五彩斑斓工艺 (a riot of colour craft) +crop-dusting|排气施肥* +dynamic-surroundings-mobeffects|动态环境:生物效果 (Dynamic Surroundings: MobEffects) +dynamic-surroundings-environs|动态环境:周边环境 (Dynamic Surroundings: Environs) +recipe-stages@|配方阶段* +attack-on-minecraft@wingsoffreedom|自由之翼 (Wings of Freedom) +cavern-miner|洞穴:矿工 (Cavern: Miner) +vanilla-tools|原版工具+ (Vanilla Plus Tools) +server-tab-info@ +letsencryptcraft +creeperhost-minetogether@ + +fullscreen-windowed-borderless-for-minecraft|窗口化全屏 (Fullscreen Windowed (Borderless) for Minecraft) +nocurse|不诅咒 (NoCurse) +pretty-beaches@¨pretty-beaches-fabric +qing_gong|轻功 (qing_gong) +remnants|腐败* + +pane-in-the-glass +dynamic-dynamos|能源炉动画* +trophy-slots + +replanting-crops@|补种农作物*¨replanting-crops-fabric|补种农作物 (Replanting Crops) +complex-crops|复杂作物* +screenshot-to-clipboard@|截图到剪贴板 (Screenshot to Clipboard)¨screenshot-to-clipboard-fabric|截图到剪贴板 (Screenshot to Clipboard) +hide-armor|隐藏盔甲* +hunterillager@hunters-return|邪猎者 (HunterIllager) + +pocket-apocalypse-mod|便携式天灾* +compass|指南针 (compass) +tinkers-evolution@|匠魂进化 (Tinkers' Evolution) +tinkers-exporter|匠魂数据导出器* +farlanders@the-farlanders|更多末影人 (The Farlanders) +vials|瓶瓶罐罐* +advanced-lightsabers|高级光剑* +fall_attack|下落击杀 (fall_attack) +swimsuit|泳装 (swimsuit) +more-overlays-updated@ +dothack-hack-weapons +immersive-energy|沉浸能源* +crimson-moon|绯红之月* +mobs-attempt-parkour@ +identity|化身*¨identity-on-forge|化身 (Identity) +industrial-revolution@|工业革命* +art-of-alchemy|炼金艺术 (Art of Alchemy) +lan-server-properties@|自定义局域网联机* + +immersive-intelligence@|沉浸智能* +analyzeio +wool-buttons@|羊毛按钮* +total-tinkers|统合匠艺* + +thaumic-wands|神秘法杖* +japanese-food-mod|日式料理* +pandoras-creatures|潘多拉生物* +status-tags|名称标签状态栏* +just-enough-dimensions@|维度配置* +multishot@|延时摄影* +tweakers-construct|匠魂调整* +valhelsia-structures + + +just-enough-reactors +aoa-infobundle|虚无世界信息包 (AoA InfoBundle) +mana-and-artifice|魔法艺术3:巧工魔艺 (Mana and Artifice) - 官方主要渠道¨@mana-and-artifice|魔法艺术3:巧工魔艺 (Mana and Artifice) + + +slab-helper|半砖小帮手* +no-jumping-allowed|禁止跳跃* +swan-boats|天鹅船* +primal-winter@|原始寒冬* +better-burning@|更好的燃烧机制* +compact-void-miners|紧凑型虚空采矿机* +probe +mekanism-fluxified|“通量”机械* +stepup|平滑自动上坡 (StepUp) +sodium@|钠* + +netherlicious +yungs-better-mineshafts-forge@yungs-better-mineshafts|YUNG 的矿井优化 (YUNG's Better Mineshafts)¨yungs-better-mineshafts-fabric|YUNG 的矿井优化 (YUNG's Better Mineshafts)¨yungs-better-mineshafts-neoforge|YUNG 的矿井优化 (YUNG's Better Mineshafts) +terrible-chest|可怕的箱子/可怖箱子* +spartan-shields@|斯巴达之盾* +silent-gear@|寂静装备* + +simple-smeltery-accelerator|匠魂冶炼炉加速器* +portality +natural-absorption|伤害吸收天赋* +unique-enchantments|独特的附魔* +tombstone-revived|墓碑:复生 (Tombstone: Revived) +travelers-backpack-integrations|旅行者背包集成 (Traveler's Backpack Integrations) +Baby-Mobs|Baby生物* +compressedblock|压缩方块 (Compressed Block) +wildnature|狂野自然 (Wild Nature) +novam-terram +terrafirmathings|群峦作品 (Terra Firma Things) + +simpledifficulty|坚定意志 (SimpleDifficulty) +minema +tfctech-unofficial|群峦工业非官方版 (TFCTech Unofficial) +@ee1|等价交换 (Equivalent Exchange) +invmove@|边拿边走 (InvMove)¨invmove-fabric|边拿边走 (InvMove)¨invmove-forge|边拿边走 (InvMove) +autofish-for-forge|自动钓鱼Forge版 (AutoFish for (Neo)Forge) +industrial-upgrade@industrialupgrade|工业升级* +rpgstats@ +datapackrecipemaker|数据包配方助手 (Datapack Recipe Maker) +never-needed-or-wanted +ama-damage-indicator + +magic-circle|阵法* +crash-utilities@ +eldritch-mobs@ +farmers-delight@|农夫乐事 (Farmer's Delight)¨farmers-delight-fabric@|农夫乐事 (Farmer's Delight) +artifacts@|奇异饰品*¨artifacts-fabric|奇异饰品 (Artifacts) + +dynamictreestfc@|动态的树:群峦传说附属 (Dynamic Trees TFC) + +dynamic-trees-the-twilight-forest|动态的树:暮色森林附属 (Dynamic Trees-The Twilight Forest) +drp-global-datapack@globalpacks|全局数据包 (Global Packs/Global Data & Resourcepacks) +mob-farm-nerfer +blood-in-the-water +bio-technik + + +astromine-fabric|天体矿工 (Astromine - Machines n' Space!) +rustic-thaumaturgy|神秘乡村* + +thallium|铊* +haema@ +evil-ores +unsuspicious-stew@|炖菜解谜/炖菜效果显示* +tfc-seasonal +imblockerfabric@imblocker|输入法冲突修复 (IMBlockerFabric) +saomclib +survival-utilities|生存工具* +slashblade|拔刀剑 (SlashBlade) +portal-blocks-2-0|传送门方块 (Portal Blocks) +slimecraft-add-tools-etc +mechanized-steam-power|机械化蒸汽动力* +moreswordonline|动漫神域 (SwordCraftOnline) +camera-mod@|照相机* +heartdrops|生命汲取 (Heart Drops) +observerlib +zen-summoning +campanion-forge@campanion|野营物品 (Campanion)¨campanion|野营物品* - Farbic +wolves-with-armor|狼铠*¨wolves-with-armor-forge|狼铠 (Wolves With Armor) +get-exp-for-everything|万物皆可获得经验 (Get exp for everything) +jei-enchantment-info|JEI 附魔信息 (JEI Enchantment Info) + +project-red-fabrication@|红石计划:制作 (Project Red - Fabrication) +project-red-integration|红石计划:集成 (Project Red - Integration) + +project-red-world|红石计划:探索 (Project Red - World) +project-red-compat|红石计划:兼容性 (Project Red - Compat) +canvas-renderer@canvas|Canvas 渲染器* + +coolfood|冷饮 (CoolFood) +infinitevillagertrading@|无限村民交易 (InfiniteVillagerTrading) +infinite-trading@|无限交易*¨infinite-trading-fabric|无限交易 (Infinite Trading) +better-loading-screen@custom-loading-screen|自定义加载画面 (Custom Loading Screen) +extended-lights-mod|灯具拓展 (Extended Lights) +more-swords-legacy@|更多剑:传承* +the-undergarden@|深暗之园* +mc-modsure|诱惑 (Allure) + +glibys-voice-chat-reloaded|Gliby的语音聊天重置版 (Gliby's Voice Chat Reloaded) +greater-eye-of-ender-fabric|高级末影之眼 (Greater Eye of Ender)¨greater-eye-of-ender-forge|高级末影之眼 (Greater Eye of Ender) +project-red-mechanical|红石计划:机械 (Project Red - Mechanical) +neon-craft-mod|霓虹灯艺* +arrows-ignite-tnt +enderite-mod-for-forge@enderite-mod|末影合金 (Enderite Mod)¨enderite-mod-for-fabric|末影合金 (Enderite Mod) +dynamic-trees-industrial-craft-2|动态的树:工业2附属 (Dynamic Trees - Industrial Craft 2) +dynamic-trees-tinkers-construct|动态的树:匠魂附属 (Dynamic Trees - Tinker's Construct) +ex-nihilo-sequentia@exnihilosequentia|无中生有:传承 (Ex Nihilo: Sequentia) +toms-storage@|汤姆的简易存储 (Tom's Simple Storage Mod)¨toms-storage-fabric|汤姆的简易存储 (Tom's Simple Storage Mod) +fishing-real@|更真实的钓鱼* +maessentials +lingering-loot +ugraded-netherite@upgraded-netherite|下界合金增强 (Upgraded Netherite) + +inventory-profiles|一键背包整理* +slimevoid-library +kotlin-for-forge@ +fabric-zero +towers-of-the-wild|旷野之塔* +sausagecore|香肠核心 (SausageCore) +shadowlands@|暗影之地* +polymorph@|多态合成*¨polymorph-fabric|多态合成 (Polymorph) +scalable-cats-force@ +otyacraft-engine@ +omega-craft-mod +custom-ports|自定义局域网端口 (Custom LAN Ports) +decorative-blocks@|装饰方块* +music-layer +colored-lux|彩色照明* +corsair-mccue@ +right-click-clear|右键文本清除* +wtfs-expedition-cavebiomes-ores-trees-and-tweaks +guide-api-village-and-pillage@guide-api +drcyanos-lootable-bodies|可拾取尸体 (DrCyano's Lootable Bodies) +simply-cats@ +pams-harvestcraft-2-crops@|潘马斯农场2 - 作物 (Pam's HarvestCraft 2 - Crops) +base-metals|基础金属* + +mmdlib +just-poop-mod|屎! (Poop Mod!) +costumes|服装* +eyemod-phone +upgrade-aquatic@|碧海新生* +tfc-ambiental +macaws-trapdoors@|Macaw 的活板门 (Macaw's Trapdoors) +zenutil + +better-beacon-effect|更好的信标效果* +netherite-horse-armor@netherite_horse_armor|下界合金马铠* +tacocraft-fabric +lootr@¨lootr-fabric +biolib@bio-library +scavenge@ + +heaven-earth-ring|乾坤戒指* + +pams-harvestcraft-2-food-extended@|潘马斯农场2 - 食物拓展 (Pam's HarvestCraft 2 - Food Extended) + +pams-harvestcraft-2-trees@|潘马斯农场2 - 果树 (Pam's HarvestCraft 2 - Trees) +better-minecart-rotation-forge¨minecart-direction-follow +modern-metals|现代金属* +blockrenderer¨block-renderer +blockus@ +conjurers-cookbook +color-unchained +aportingcore|移植核心 (APortingCore) +ywlib +sweet-potato|烤地瓜 (Sweet Potato Mod) +redstone-lantern|红石灯笼* +culinaire@|烹饪* +furbishcraft + + +ambientsounds@|自然音效 (AmbientSounds) +ordinary-firearms|普通枪械2 (Ordinary Firearms 2) +territory|领地 (MineTerritory) +better-ping-display@|更好的延迟显示*¨better-ping-display-fabric@|更好的延迟显示 (Better Ping Display) +turned-the-changed-mod +survival-tweaks|生存微调* +melon-slabs@|西瓜台阶* +lambdynamiclights@|Lambd的动态光源 (LambDynamicLights) +realistic-torches@|真实火把* + +durability-viewer|耐久显示器* + + + +ground-item-highlighting|地面物品高光显示* + +real-survivor@realsurvivor|幸存者 (RealSurvivor) +armor-toughness-bar|盔甲韧性显示* +block-meter +time-to-live@timetolive +dual-hotbar-1-12-2|双重快捷栏1.12.2 (Dual Hotbars 1.12.2) +cha-s@|可合成的马铠和鞍 (Craftable Horse Armour & Saddle) +dual-hotbar|双重快捷栏 (Dual Hotbars) +travellers-boots@ + +cofh-vanilla-satchels +betteranimalsplus|更多动物 (Better Animals Plus) +packagedauto@|封包合成 (PackagedAuto) +packagedexcrafting@|封包合成拓展 (PackagedExCrafting) + +compactstorage@compact-storage|紧凑存储 (compactstorage) +useful-backpacks@|实用背包* +conquest-reforged@|征服者* +steelseries-gamesense +pizzaatimes-timber-mod +tellme@ +minerva-library + + + +edit-sign@editsign|编辑告示牌* +logistical-automation +dynamic-view|动态视距*¨dynamic-view-fabric|动态视距 (Dynamic View) + +instrumental-mobs@|乐器怪物* +finder-compass +spacering|储物戒 (SpaceRing) +doot¨trumpet-skeleton-redooted¨trumpet-skeleton-fabric + +emotes +oc-sensors +fabric-for-fabric +storage-tech +thaumic-periphery|神秘外饰* +embellishcraft@|装饰工艺 (EmbellishCraft) +open-loader@|开放式加载* +deep-mob-learning-refabricated@|深度怪物学习:重制版 (Deep Mob Learning: Refabricated) +ftb-ultimine-forge|连锁破坏 (FTB Ultimine)¨ftb-ultimine-fabric|连锁破坏 (FTB Ultimine) +server-translation-api¨server-translations +image2map@ +corpse@|遗体* +ring-of-the-miner-fabric|矿工戒指 (Ring of the Miner)¨ring-of-the-miner-forge|矿工戒指 (Ring of the Miner) +instant-bubble-studio|瞬息气泡工坊* + + + + + +kaleido + +crock-pot|烹饪锅* + + + + + + + + +together-forever +iron-furnaces@|更多熔炉*¨iron-furnaces-fabric|更多熔炉 (Iron Furnaces) + +lenient-creepers@|仁慈的苦力怕* +treasure2|寻宝记2 (Treasure2!) +@autoreconnector-fabric|自动断线重连 (AutoReconnector-Fabric) + +structure-gel-api@ +the-conjurer@|魔术师* +ganys-nether|Gany的下界 (Gany's Nether) +ganys-end|Gany的末地 (Gany's End) +epic-fight-mod@epic-fight|史诗战斗 (Epic Fight) +attack-missed|攻击闪避* +lava-monsters@|熔岩怪* +tumat +riddle-chests|谜题箱* + +totem-plus|图腾增强* +blockmeterfabric@blockmeter|方块计量表 (Block Meter Fabric) + +fluid-drawers|储液抽屉* +creepypastacraft-reborn|蠕动意面重置版 (CreepyPastaCraft Reborn) +itemzoom|物品缩放 (ItemZoom) +light-overlay@|亮度覆盖* +smallerfpsincrements +regex-filters|正则表达式过滤器* + +fluidsystem@|流体系统 (FluidSystem) +falling-tree@fallingtree|伐树 (FallingTree) +untranslated-items|物品名称双语同屏* +particle-culling@|粒子渲染机制优化* +aggressive-chickens +entity-culling@|实体渲染机制优化* +hammerandvil|锻造锤与锤锻台 (HammerAndVil) + +simply-backpacks|简易背包* + +better-placement|更好的放置* +fat-cat|大资本家* +waystones2waypoints|传送石碑路径点 (Waystones2Waypoints) +beta-days@|B测往昔* +trajectory-preview|弹道预览*¨trajectory-preview-fabric|弹道预览 (Trajectory Preview) +xp-spawner-control|刷怪笼经验控制* +mob-spawner-control|刷怪箱控制与修改* +refined-pipes|精致管道* +singularities|奇点* +better-spawner-control@|更好的刷怪笼控制*¨better-spawner-control-fabric|更好的刷怪笼控制 (Better Spawner Control) +crying-ghasts@|哭泣的恶魂*¨crying-ghasts-fabric|哭泣的恶魂 (Crying Ghasts) +dynamic-fps@|动态 FPS (Dynamic FPS) +compact-ores|致密矿石* +thaumic-additions@|神秘领域 (Thaumcraft Addition) +fabric-disable-custom-worlds-advice@dcwa|禁用自定义世界警告 (Disable Custom Worlds Advice) +leaf-decay|树叶速腐Fabric版* +fast-furnace-for-fabric|熔炉性能优化 Fabric 版 (Fast Furnace for Fabric) +diggus-maximus@|连锁挖掘* +super-sentai-craft@|超级战队工艺* +wildly-eat|狼吞虎咽* +gotta-climb-fast|快速爬梯 (Gotta Climb Fast!) +can-i-mine-this-block@|我­­ 能 挖 它 吗? (cAn i MiNe thIS bLOCk?) +rotten-creatures@rottencreatures|腐烂生物* +fairy-lights|圣诞彩灯* +packmode +dank-null +avaritia-complement +better-questing-triggerer +Broken-Wings + +compacter@|压缩者* + +not-enough-potions +framed-compacting-drawers|镶框压缩抽屉* +discordsuite +mikes-mods-library +Teslafied +shurlin|仙灵* +mob-amputation|怪物截肢* +packguard +wtfs-texturegeneratorlib +more-totems-of-undying@|更多的不死图腾* +dungeon-crawl@dungeoncrawl +tesslocator|超立方转运器* +iblis-headshots|爆头击杀* +bee-barker +sky-bonsais|天空盆栽* + +origins@|起源 (Origins (Fabric)) +alexiillib +feed-a-friend + + +the-legend-of-herobrine@ +extra-origins@|起源扩展* +caves-and-cliffs +miner-golems|矿工傀儡* +bakadanmaku@|直播弹幕模组 (BakaDanmaku) +online-card|网络卡片* +felling|连锁砍树* +extra-player-render|额外玩家渲染 (Extra Player Renderer) +fabric-api@ +coloredlanterns|多彩灯笼 (ColoredLanterns) +ae2-fluid-crafting|AE2流体合成套件 (AE2 Fluid Crafting) +cardinal-energy|能量基本* +travel-anchors@|旅行锚* +bnbgaminglib +triumph +overloaded-armor-bar@|护甲上限突破*¨overloaded-armor-bar-fabric|护甲上限突破 (Overloaded Armor Bar) +toomanydanyores +glass-pipe|玻璃管道* +origins-classes@|起源:职业 (Origins: Classes) +plonk@|世界内物品放置* +baritone-simply +potionsmaster|魔药大师 (Potions Master) +tinkered-hegemony@|匠器主导* +better-impaling@|更好的穿刺附魔* +caliper +botanical-machinery@|植物机械* +demagnetize|消磁* + + + + +cinderscapes@|余烬奇景* +tfc-homestead +tfctinkers|群峦与匠魂 (TFC Tinkers) +thick-font-fix + +dynamic-trees-traverse|动态的树:遍历附属 (Dynamic Trees - Traverse) +mcmt-multithreading@mcmtfabric¨mcmtfabric +bwm-core +ice-ice-baby|冰术师* +hardlib +bilingualname|物品名称双语显示 (BilingualName) +chlorine|氯* + +bedrock-miner@|基岩矿工* +reasonable-realism|合理的现实主义* +passable-foliage@|叶间穿行 🌳 (Passable Foliage 🌳)¨passable-foliage-fabric|叶间穿行 🌳 (Passable Foliage 🌳) +betterend@|更好的末地 (BetterEnd) +armor-chroma|盔甲颜色显示* +interactions|自定义交互事件* +lods-of-emone|很多钱 (Lods of Emone) +fabric-language-scala +fluid-physics-forge|流体物理 (Fluid Physics)¨fluid-physics|流体物理* +zettai-grimoires +runorama|全景截图背景* +item-stages@|物品阶段* +rocksalt +cazfps-the-dead-sea|死亡之海 (CAZfps The Dead Sea) +pouch-of-unknown|未知之袋 (Pouch of Unknown) +wizardry-fates +the-mighty-architect +phosphophyllite +biggerreactors +ftb-teams-forge|FTB 团队 (FTB Teams)¨ftb-teams-fabric|FTB 团队 (FTB Teams) +waveaway|挥挥手 (WaveAway) +no-advancements|移除进度机制* +tfc_rocksplus|群峦岩石 (TFC Rocksplus) +mars-mod-reborn +ftb-library-forge¨ftb-library-fabric +crossroads-mc@crossroads|交错道途 (Crossroads) +config-checker@modpack-configuration-checker|整合包配置检测 (Modpack Configuration Checker) +thaumic-speedup +armor-curve|盔甲曲线修改* +ambience-extras|环境音乐:附加 (Ambience - Extras) +additions-mod +extracpus|更多CPU (Extra CPUs) +extra-crafting-storage + +underground-city-engineering@|地下城市工程* +essentials@essentialsmod +soul-shards-respawn +soul-shards-the-old-ways + +the-flying-things +ftb-ranks¨ftb-ranks-fabric +ftb-chunks-forge|FTB 区块 (FTB Chunks)¨ftb-chunks-fabric|FTB 区块 (FTB Chunks) +ftb-essentials +silveroak-outpost|银橡前哨* +pehkui@ +jeitweaker@ +yungs-law +libx@ +atmospheric@|悠然一派* +monospace-font|等宽字体 (Monospace font) + +mana-liquidizer@|魔力液化器* +neapolitan@|那不勒斯风味* +clear-despawn@cleardespawn¨clear-despawn-fabric +tinkers-modifier-modifier|匠魂强化修改 (Tinkers' Modifier Modifier) +randomtweaks|随意微调 (RandomTweaks) +zettai-magic +strawgolem-reborn@straw-golem|稻草傀儡重制版 (Straw Golem Reborn)¨straw-golem-reborn|稻草傀儡重制版* +rare-ice@|冰中有宝* +create-integration +the-magic-mirror@|魔镜* + +boatload@|额外船只 (Boatload / Extra Boats)¨extra-boats@|额外船只 (Extra Boats / Boatload) +outvoted@|落选生物* + +attribute|属性修复 - Fabric版 (Attribute Fix {FABRIC}) +packmodemenu|PackMode 菜单 (PackModeMenu) +simple-gamemodes|游戏模式短指令* +uniq|流体统一/物品统一 (UniQ) + +harder-ores|更难的矿物处理* +rune-craft@runecraft +geckolib@ +memory-cleaner-mod|内存自动清理* +ore-flowers|矿物花卉* +aqua-creepers|水下苦力怕 (Aqua Creepers!) +extrastorage@|更多存储 (ExtraStorage) +thermal-locomotion@|热力运输* +external-tweaker +morebiomesxl +notes@|笔记* +stare-till-they-grow|盯到它们熟为止! (Stare Till They Grow!) +vm-computers|虚拟电脑 (VM Computers) +inventory-free|无物品栏 (Inventory-Free) + +randompatches-integration +bubble-column-elevator-backport|1.13水域机制 (1.13 Bubble Columns for 1.12) +basic-nether-ores@|基础下界矿石* +nuclearcraft-reactor-builder|核电工艺反应堆建造机 (NuclearCraft Reactor Builder) +pams-harvestcraft-2-food-core@|潘马斯农场2 - 食物核心 (Pam's HarvestCraft 2 - Food Core) +eki-lib +@immibis-core +nodami|伤害免疫机制移除 (No Damage Immunity) +astrological-sorcery@|星占魔法* +efab-ct-bindings +golden-hopper|金漏斗* +wizardry-golems|巫术傀儡* + + +devtech|GTCEu-CrT开发套件* + + + + + +jurassic-world-reborn-mod@jurassic-reborn|侏罗纪重生 (Jurassic Reborn) + +cardboard@ +enchanting-with-thaumcraft|神秘附魔学* +crimson-revelations|血腥启示 (Crimson Revelation) +environmental-core@ +bigger-crafting-tables@biggercraftingtables +covers-everywhere|万用覆盖板* +mo-villages|更多村庄 (Mo' Villages) +inventoryneko +loading-screens|自定义加载画面* +ofms-crisis-ridden|OFMS:危机重重 (OFMS:crisis-ridden) +dupefix-project +ore-control|矿物控制* +twitch-chat-integration|Twitch信息显示* + + +avaritia-lite|无尽贪婪精简版* +packmenu + +console-experience|原主机版界面特性* + + +mite-reborn|MITE:重生 (MITE:Reborn) +detailed-technology|细节科技* +oreberries|矿莓* +stone-block-utilities +mystical-creations +multiconnect@ +art-of-alchemy-memoriam|炼金艺术:纪念版 (Art of Alchemy: Memoriam) +blockphysics|方块物理 (BlockPhysics) +stoneblock-dimensions +charging-gadgets|充电设备* +integration-foregoing|工业先锋集成附属* +enderfuge|末影熔炉* +calm-down-zombie-guy +universal-mod-core@|通用模组核心* +suspended-server|挂起服务器* +starlight-forge@|星光 (Starlight)¨starlight@|星光*¨starlight-neoforge@|星光 (Starlight) +research-table|研究台 🔬 (Research Table 🔬) +shoulder-surfing-reloaded@|越肩视角重制* +aqua-acrobatics|水游技艺* +silents-mechanisms|寂静机械 (Silent Mechanisms) +project-potman|背锅人计划 (ProjectPotman) +nbt-crafting@|数据包 NBT 合并* +diregoo +ogdragon|OG龙+ (OGDragon+) +sevtweaks +journeymapstages|旅行地图阶段控制 (JourneyMapStages) +textile-backup@textile_backup|Textile 备份* +goopers +mob-drops|自定义生物战利品 (Mob Drops Your Way) + +alexs-mobs@|Alex 的生物 (Alex's Mobs) +mc-mods-stackable@all-stackable|可堆叠物品自定义 (All Stackable) +thermal-mj|热力MJ支持 (Thermal MJ) +ctd-core@ +time-speed-mod|Minecraft地球自转/真实昼夜循环 (Вращение Земли Майнкрафтская (Accurate day/night-cycles Mod)) + +mineral-tracker +carpet-extra@|Carpet 拓展* + +viafabric@ +double-slabs@|双重台阶* +tools-and-armor-bop|超多生物群系:旧工具和装甲 (Tools And Armor - BOP) +centralized-materials|集中材料* +server-sided-chunk-loader|服务器端区块加载器* +fluid-cows|流体牛 (Fluid cows) +shulkerboxviewer +gameinfo|游戏信息 (GameInfo) +arcaea|Arcaea韵律源点* +advanced-tfc-tech|进阶群峦科技 (Advanced TFC Tech) +enriched@|原版增强 (Enriched/Vanilla Enhanced) +satisforestry +asmc@ +simple-generators@|简易发电机* +tfc-bonsai|群峦盆栽 (TFC Bonsai) +tfc-drying-rack|群峦晾干架 (TFC Drying Rack) + +lumen|流明 (Lumen 🔥) +openblocks-elevator@elevatormod|开放式电梯 (OpenBlocks Elevator / ElevatorMod) +crafttweaker-integration|CrT集成 (CraftTweaker Integration) + +spiders-2-0|蜘蛛行为增强 (Spiders 2.0) + +hammer-metals|锤子材料* +bunch-of-biomes|生物群系扩充 (Bunch Of Biomes!) + +better-slimes|更好的史莱姆* +windowlogging|玻璃板贴合* +the-time-stop-mod|时间静止* + +vanilla-hammers@|原版材质锤*¨vanilla-hammers-forge|原版材质锤 (Vanilla Hammers) +imblocker@imblocker-original|输入法冲突修复 (IMBlocker) +hardcore-map-reset +tfc-aged-drinks|群峦陈酿 (TFC Aged Drinks) + +youtubers-lucky-blocks|YouTuber的幸运方块 (Youtuber's Lucky Blocks) +wandering-trapper|流浪猎人* +chocolate-fix +thaumcraft-4-scrolling@tc4tweaks +orderly +water-control-extreme +variant16x +endremastered@endrem|末地:创世 (End Remastered)¨endremastered-fabric|末地:创世 (End Remastered) + +unique-crops|独特作物* +yungs-api@¨yungs-api-fabric¨yungs-api-neoforge +dawn +assembly-line-machines|装配线* +netherending-ores +Flex-FOV|扭曲视野* +hooked@|抓钩* +createtweaker@ +iTorch + +gullivern +nbt-manipulator + + +sulfur-and-potassium-make-more-gunpowder +statues@|雕像* +advanced-mining-dimension@|先进的采矿维度* +time-travel-mod|时间旅行* +backslotaddon@|背用武器拓展 (BackSlotAddon) +optifabric-1-8-9 + +gt6-ore-helper|GT6 矿石助手 (GT6 Ore Helper) +applied-integrations|应用集成* + +inventory-hud-forge@inventoryhudplus|物品栏HUD+ (Inventory HUD+) + +langsplit@ +legacy-fabric-api@ +krypton@|氪* +mana-gear +not-enough-enchantments +bon-appetit-forge|祝您好胃口 (Bon Appetit)¨bon-appetit-fabric|祝您好胃口 (Bon Appetit) +gugu-utils@|咕咕工具 (GuGu Utils) +scuba-gear@|潜水装备* +avatar-mod-2-out-of-the-iceberg|降世神通:突破冰山 (Avatar Mod 2: Out of the Iceberg) +@hydrogen|氢 (Hydrogen) +lazydfu@|DFU载入优化 (LazyDFU) + +ridable-ender-pearls|可骑乘末影珍珠* +gildedarmor@|镀金盔甲 (GildedArmor) +deadly-book|致命书本* +speedy-hoppers|极速漏斗* +indium@|铟* + + +go-fish|一起钓鱼吧!* +more-player-models|更多玩家模型* +loot-overhaul +miners-helmet@|矿工头盔 (Miner's Helmet) +lightweight-blood-mechanics|轻量级流血机制* +kbackup-fabric +smooth-boot@smoothboot-fabric|流畅加载*¨smooth-boot-forge@smooth-boot|流畅加载 (Smooth Boot) + +netherite-plus-mod@|下界合金拓展* +chunkpregenerator|区块预生成器 (Chunk-Pregenerator) +antighost@|幽灵方块同步修复 (AntiGhost) + +backslot@|背用武器 (BackSlot) +minecraftcapes-mod@minecraftcapes + +spartan-weaponry-arcana|斯巴达奥法* + +greek-fantasy|希腊幻想* +architectury-api@ + + +createaddition@|机械动力:创想附加 (Create Crafts & Additions) +smithee +dragon-egg-replicator|龙蛋复制器* + +elemental-ingots-ei|元素锭 (Elemental Ingots) +solargeneration@|太阳能发电机 (Solar Generation) +enchant-with-mob@enchantwithmob + +worldstatecheckpoints +dungeons-plus@ +liquid-enchanting|药水附魔* +shutup-experimental-settings|禁用实验性设置警告 (Shutup Experimental Settings!) +datafixerslayer +hexcraft +police-mod|警察* +enhanced-celestials@|月亮事件*¨enhanced-celestials-fabric|月亮事件 (Enhanced Celestials) +resourceful-bees@|缤纷蜜蜂* +held-item-info@|手持物品信息* +cleancut@|干净利落 (CleanCut) +plus-tweaks +global-gamerules@|全局游戏规则 (Global GameRules) + +save-my-stronghold-fabric¨save-my-stronghold +physics-mod@physicsmod|真实物理* +bluemap +dregora|德雷戈拉* +k4lib +deadly-end-phantoms +spice-of-life-potato-edition|生活调味料:马铃薯版 (Spice of Life: Potato Edition) +easiervillagertrading@|简单村民交易 (EasierVillagerTrading)¨easiervillagertrading-2|简单村民交易 (EasierVillagerTrading) +wwta@|聊天栏时间显示 (When Was That Again) +ars-nouveau@|新生魔艺* +eidolon|幻梦* +rats-ratlantis|老鼠:鼠西洲 (Rats: Ratlantis) +wthit@¨wthit-forge +modern-industrialization@|现代工业化* +chunk-pregenerator-fabric@fabricquilt-chunk-pregenerator|区块预生成器(Fabric) (Fabric Chunk Pregenerator) +jumploader +unloader +better-animal-models|更真实的动物* +@mine-little-pony|我的小马驹 (Mine Little Pony) + +druidcraft|德鲁伊工艺* +berry-good@ +savage-and-ravage@|残暴与掠夺 (Savage & Ravage) +jade@|玉 🔍 (Jade 🔍) +somnia@|梦醒时分 (Somnia Awoken) +industrial-reborn@ +mo-structures-forge@mo-structures|更多自然生成结构 (Mo' Structures)¨mo-structures|更多自然生成结构 (Mo' Structures) +wallpapercraft-a-fresh-roll|墙纸创造 (Wallpapercraft - A Fresh Roll) + + + +unionlib@ +botany-trees@|植树盆栽* +better-third-person@ +survive@|生存要素* +wallpapercraft-a-fresh-roll-stairs|墙纸创造:楼梯 (Wallpapercraft - A Fresh Roll (Stairs!)) +wallpapercraft-a-fresh-roll-slabs|墙纸创造:台阶 (Wallpapercraft - A Fresh Roll (Slabs!)) +wallpapercraft-a-fresh-roll-walls|墙纸创造:围墙 (Wallpapercraft - A Fresh Roll (Walls!)) +compact-crafting +assembly-lines@|装配线* +botany-pots@|植物盆栽* +callable-horses|召之马来* + +ultimate-solar-panels +slight-gui-modifications@|界面微调 ('Slight' Gui Modifications) +elemental-craft@|元素工艺* +just-another-rotten-flesh-to-leather-mod@jrftl|腐肉换皮革 (Just Another Rotten Flesh to Leather Mod) +spatial-harvesters-forge@spatial-harvesters-fabric¨spatial-harvesters-fabric +emotecraft@|表情工艺*¨emotecraft-forge|表情工艺 (Emotecraft) +pattysmorestuff@ +hats|帽子* +smoother-bedrock|平滑基岩层* +c2me-fabric@|C^2M 引擎 (C^2M-Engine/Concurrent Chunk Management Engine)¨@c2me-neoforge|C^2M 引擎 (C^2M-Engine/Concurrent Chunk Management Engine) +datapack-anvil@dpanvil +nuclear-science@|核科学* +glaretorch|强光火把 (Glare Torch) +mrcrayfishs-jumping-castle-mod|MrCrayfish的充气城堡 (MrCrayfish's Jumping Castle) +exposer +to-the-bat-poles +cc-restitched@ +wearables|可穿戴设备* +@advancedfurnace|先进熔炉 (Advanced Furnace) + +better-weather|更好的天气*¨better-weather-fabric|更好的天气 (Better Weather) +ultimate-car-mod@|终极汽车* +craft-time|耗时合成 (Craft Takes Time) +betterf3@|更好的F3 (BetterF3) + +the-abyss-chapter-ii|深渊:第二章 (The Abyss: Chapter II / The Abyss II - The Other Side) +mapper-base@ +bedrockify@bedrockIfy + +rftools-power@|RF工具:能量 (RFTools Power) +pipez@ +coins-je@ + +beenfo@|蜂巢信息* +chest-building-blocks +zycraft +quitconfirm|退出前确认 (QuitConfirm) +ruined-equipment@ +clickthrough@|穿牌开箱 (ClickThrough) +dynamic-sound-filters@|动态声音滤波器* +binniepatcher +subterranean-wilderness + +construction-wand@|建筑手杖* +squeedometer + +forgery@fabrication¨fabrication +mcdj +boost-boots +better-sodium-video-settings-button@|更好的钠视频设置按钮* + +artisan-worktables-1-16|工匠之作2 / 工匠工作台2 (Artisan Worktables 2 / Artisan Worktables 1.16) +thermal-solars +supplementaries@|锦致装饰* +more-fuels-mod + +pointless-tech-collective +revampedwolf@ +bedrock-b-gone@ + +elemental-creepers-og@elemental-creepers|元素爬行者 (Elemental Creepers)¨elemental-creepers|元素爬行者* +gymcraft +infernal-expansion@|地狱扩展* + + +configurable-mob-potion-effects@|怪物药水效果自定义*¨configurable-mob-potion-effects-fabric|怪物药水效果自定义 (Configurable Mob Potion Effects) +sapience +netherite-nuggets-fabric@netherite-nuggets|下界合金粒 (Netherite Nuggets)¨netherite-nuggets-forge|下界合金粒 (Netherite Nuggets) +eroding-stone-entities@¨eroding-stone-entities-fabric +direbats-forge@direbats¨direbats-fabric +advanced-electric-tools|高级电动工具* + +backpacker + +ynet +simple-drawers|简单的抽屉* +charmonium¨charmonium-reforged@charmonium +xnicex@ +krate +chickensshed@|鸡棚重置版 (ChickensShed) +chickenshed +expanded-storage@|扩展存储*¨expanded-storage-fabric|扩展存储 (Expanded Storage)¨expanded-storage-forge|扩展存储 (Expanded Storage) +project-mmo@ +abnormals-delight@ +jojos-bizarre-survival + +somnus@ +lost-trinkets|遗失饰物* +lookingglass +environmental@|自然环境* + +golden-airport-pack-immersive-vehicles-content + +hole-filler-mod@|洞口填充器 (Hole Filler) + +simply-tea@|简单的茶! (Simply Tea!) +buttermilk +diet@|均衡饮食* +brazilian-fields|巴西风情* +ae2-extras|AE2 附加 (AE2 Extras) +animalium|动物* +mob-origins@moborigins|生物起源* +better-default-biomes|更好的默认生物群系* +kaimyentity|KAI我的实体 (KAIMyEntity) +tablechair|桌椅 (TableChair) +when-dungeons-arise@|地牢浮现之时*¨when-dungeons-arise-fabric|地牢浮现之时 (When Dungeons Arise) +animal-feeding-trough@animal_feeding_trough|动物喂养槽* +wiki-zoomer@ +personality@personality! +mc-modsurement@allurement! +dwarf-miner-totem|矮人矿工* +yungs-better-portals|YUNG 的传送门机制重构 (YUNG's Better Portals) +german-road-signs-mod|德国交通标志* +iguana-in-a-blanket@iguana|真实调整 (Iguana in a Blanket) +anthill-inside@anthillinside|蚂蚁物流* +nei-integration +uncrafting-grinder|分解磨床* +emendatus-enigmatica@emendatusenigmatica + + + +jousting@|马术* +bamboo-blocks@ +scape-and-run-parasites@scapeandrunparasites|逃逸:寄生体 (Scape and Run: Parasites) +just-enough-drags|更多JEI拖拽* +exnihilo-automation|无中生有:自动化 (Exnihilo: Automation) +world-handler-command-gui|世界管理器:图形交互 (World Handler - Command GUI) +entityculling@|实体渲染机制优化 (Entity Culling) + +tea-kettle|茶壶* +enhanced-block-entities@ebe|方块实体优化* +gun-customization-infinity +dungeons-gear|地下城装备* +integrated-nbt|NBT 联合 (Integrated NBT) +pillagers-plus + + + +abundance@ + + +just-enough-calculation +mythicbotany@|神话植物学 (MythicBotany) +improved-mobs@|怪物增强*¨improved-mobs-fabric|怪物增强 (Improved Mobs) +limitless|无上限附魔* +vpn-blocker|禁用VPN (VPN Blocker) +premium-wood@ +tenshilib@¨tenshilib-fabric +randomportals|随意传送门 (RandomPortals) +configured|配置界面*¨configured-fabric|配置界面 (Configured) + +jellyfishing@|抓水母* +accurate-block-placement +pro-placer@|放置专家* +farmers-delight-compats +farmers-tea|农夫的茶 (Farmer's Tea) +farmers-delight-integration +magical-psi-redux +anvil-fix@|铁砧修复* +no-increasing-repair-cost@ +wool-temples@|羊毛神殿* +exp-bottling|经验装瓶 (EXP Bottling) +buildersaddition@ +gt-remastered|格雷科技重制版 (GT: Remastered) +tips@|提示* +Interactio +advancement-book|进度之书* +drawers-tooltip@|抽屉提示* +paradise-lost@|天境:重生* + +@gregfood|格雷的食物 (GregFood) +more-jellyfish@|更多水母* +easy-ladders +beta-dannys-expansion +inventory-tweaks-renewed +arrp@|高级运行时资源包 (Advanced Runtime Resource Packs) +tougher-glass-forge¨tougher-glass-fabric +differentiate +cookie-core-fabric +image-world-generator|图片地图转换器* +inductive-logistics|集成物流* + +automatic-path + +morevanillalib@ +vanilla-excavators@¨vanilla-excavators-forge +dynagear +morevanillatools@|更多原版工具 (MoreVanillaTools) +colorful-health-bar +tipline +ultimate-plane-mod@|终极飞机* +simple-voice-chat@|简单的语音聊天* +not-enough-milk +ewewukeks-musket-mod@musket-mod|ewewukek 的火枪模组 (ewewukek's Musket mod) + +irisshaders@iris +@dimthread|世界多线程化 (DimensionalThreading) +chambers|处理仓* + +sodium-extra@|钠 · 扩展* +grind-enchantments@|砂轮增强* +voice-chat|语音聊天* + +xnet-gases@ +filing-cabinets-refurbished + +dropz@ +figura@ + +autopilot¨autopilot-fabric +applied-energistics-2-wireless-terminals@|AE2无线终端* +appliedenergisticstweaker +sleeping-bags@|睡袋* +mass-inscriber + +random-title|随机标题* +astikorcarts +@invsync|背包同步 (InvSync) +jea@|JEI进度 (Just Enough Advancements) +et-futurum-requiem|把未来带回现实* - <2.7.0¨@etfuturum|把未来带回现实 (Et Futurum Requiem) - ≥2.4.0 +better-op|更好的 OP* +fastworkbench-minus-replacement +crimson-compass|绯红指南针* +tinkers-construct@|匠魂 (Tinkers' Construct) +ryoramas-terraria-mod +steves-workshop +upgraded-ender-chests@|高级末影箱* +ydm-ygo-dueling-mod-ii +versioner|整合包版本工具* + +engineers-workshop-reborn + +@immersivecursedness|沉浸传送门服务端版 (Immersive Cursedness) + +crimson-xp-charm|经验护符 (Crimson XP Charm) +locatebiome +enderman-evolution +sophisticated-backpacks@|精妙背包* +age-of-exile +whoosh +gregtech-intergalactical|泛银河系格雷科技 (GregTech Intergalactical) +catalogue|模组目录*¨catalogue-fabric|模组目录 (Catalogue) +libblockattributes + +dungeons-of-exile +lots-more-food-forge@lots-more-food¨lots-more-food-fabric + +necromancy +library-of-exile@ + +variegated +chest-cavity@|胸腔* +extended-note-block|音符盒扩展 (Extended Noteblocks) +hbms-nuclear-tech-mod-reloaded|HBM的核科技重制版 (Hbm's Nuclear Tech Mod Reloaded) +loading-timer@|加载时长显示* +ocrocketry +chime-fabric@chime +witherite@|凋灵合金* +mermod-fabric@mermod¨mermaid-tail-mod|人鱼尾*¨mermod-neoforge +astromine-core|天体矿工:核心 (Astromine: Core) +dungeondq +dynamic-trees-integrated-dynamics|动态的树:动态联合/集成动力附属 (Dynamic Trees - Integrated Dynamics) +skyblock-builder@|空岛建立者* +antiportals@|反传送门 (AntiPortals) +trash-cans@|垃圾桶* +mattdahepic-core +mob-farm-helpers-forge|刷怪塔小帮手 (Mob Farm Helpers)¨mob-farm-helpers-fabric|刷怪塔小帮手 (Mob Farm Helpers) +metal-bushes|金属灌木* + + +the-vanilla-experience +flower-seeds@flowerseeds + + + +astemirs-forest-craft +astromine-foundations|天体矿工:基础 (Astromine: Foundations) +create-stuff-additions@|机械动力:物品附加 (Create Stuff 'N Additions) +slab-machines@|台阶型设备* +more-create-stuffs|更多机械动力物品* +rsinfinitybooster@|RS 无限范围增幅卡 (RSInfinityBooster) +cuneiform +terraincognita +cloth-api +ingameime|游戏内输入法 (IngameIME) +yungs-better-strongholds@|YUNG 的要塞优化 (YUNG's Better Strongholds)¨yungs-better-strongholds-fabric|YUNG 的要塞优化 (YUNG's Better Strongholds)¨yungs-better-strongholds-neoforge|YUNG 的要塞优化 (YUNG's Better Strongholds) +mojangdark|暗色加载 (MojangDark) +astromine-technologies|天体矿工:科技 (Astromine: Technologies) +astromine-transportations|天体矿工:运输 (Astromine: Transportaions) +azuredooms-chunk-loader +creeper-spores@|苦力怕孢子* +more-dragon-eggs|更多的龙蛋* +more-red@|更多红石* + + + +ex-nihilo-sequentia-mekanism-addon|无中生有:传承 - 通用机械扩展 (Ex Nihilo: Sequentia - Mekanism Addon) +panorama@swd-panorama|全景图* +bgcore +induction-charger +tiered-forge@tiered¨tiered +c-o-m-b-a-t +burden-of-time@ +gamemenumodoption@|游戏菜单模组设定 (Game Menu Mod Option) +game-menu-remove-gfarb@gamemenuremovegfarb|游戏菜单移除GFARB (Game Menu Remove GFARB) +randomdeathmessage|随机死亡消息 (RandomDeathMessage) +ex-nihilo-sequentia-ae2-addon@|无中生有:传承 - 应用能源2扩展 (Ex Nihilo: Sequentia - AE2 Addon) +sweetmagic|甜蜜与魔法 (SweetMagic) +astromine-discoveries|天体矿工:探索 (Astromine: Discoveries) +azuredooms-angel-ring@|AzureDoom的天使指环 (AzureDooms Angel Ring) +togglelib|列车手柄库 (ToggleLib) +regrowth@|再生* +mobs-main-menu + +chaos-awakens@|混沌觉醒* +hot-or-not +playerpig +tumble-dryer +cat-jammies@ +rhino@|犀牛* +fastsuite|配方性能优化 (FastSuite) +twerkitmeal|跳舞生长一切 (Twerk To Grow All The Things) +thermal-integration@|热力集成* +piggybanks|存钱罐* +in-control@ +mystical-agriculture-refabricated|神秘农业:Fabric版 (Mystical Agriculture: Refabricated) +pedestals +aerial-affinity¨aerial-affinity-fabric +communism-life-and-art|共产主义:生活与艺术 (Communism:Life and Art) +project-war-dance@|战舞计划 (Project: War Dance) +faster-ladder-climbing@|更快的爬梯* +infinitymending@|无限+经验修补 (InfinityMending) +better-than-mending@|更好的经验修补* +elenai-dodge-2@ + +taterzens-forge@taterzens¨taterzens +dragons-survival|龙之生存 (Dragon Survival) +@legacy-mod-menu +no-lan-cheats@|禁用局域网作弊 (No LAN Cheats) +dashloader@|疾速加载 (DashLoader) +caveworld-2|洞穴世界* + +break-progress|破坏进度* +item-model-fix@|物品模型修复* + +additional-pipes-for-buildcraft|附加管道 (Additional Pipes for Buildcraft) +lolasm +rftools-utility@|RF工具:实用设备 (RFTools Utility) +ctm-fabric|连接纹理Fabric版 (ConnectedTexturesMod for Fabric) +whats-that-slot@ +pmmo-and-nbt-compat +techstacks-heavy-machinery-mod +enhanced-mushrooms@|蘑菇增强*¨enhanced-mushrooms-fabric|蘑菇增强 (Enhanced Mushrooms) +versatile-portals|通用传送门* +spawn-egg-recipes|刷怪蛋配方注册* +configurable-extra-mob-drops@|可配置的额外怪物掉落*¨configurable-extra-mob-drops-fabric|可配置的额外怪物掉落 (Configurable Extra Mob Drops) +enhanced-mob-spawners@|刷怪笼增强* + +autorun +animania-farm|动物谷:农场* +animania-extra|动物谷:额外动物 (Animania Extra Animals) +animania-cats-dogs|动物谷:猫猫狗狗 (Animania Cats & Dogs) +better-foliage-renewed@|更好的树叶重制版* +block-swap@¨block-swap-fabric +basalt-walker@|玄武岩行者* + +endless-ocean-adventures|无尽海洋:冒险 (Endless Ocean: Adventures)¨endless-oceans-adventures-fabric|无尽海洋:冒险 (Endless Ocean: Adventures) +bpm +stone-circles +phase-potion|相位药水* +marblegates-exotic-enchantment-flowing-agony@flowing-agony|白门的奇异附魔:苦痛长河 (MarbleGate's Exotic Enchantment: Flowing Agony) +measurements@ +visible-armor-slots|可见装备槽*¨visible-armor-slots-unofficial|可见装备槽 (Visible Armor Slots)¨armor-slots-in-other-inventories|可见装备槽 (Visible Armor Slots) +moon-and-space-dimensions-fabric|星际次元 (Space Dimensions / Moon and Space Dimensions)¨space-dimensions-forge|星际次元 (Space Dimensions / Moon and Space Dimensions) + +winged@ +@slideshow-fabric|幻灯片 (Slide Show) +mob-stages|生物阶段* +refooled@ +@better-nether-beta|更好的下界:Beta版 (BetterNether Beta) +fabric-seasons@ +dehydration@|脱水* +easy-villagers@|村民物品化/简单村民* +largebar +tis-3d@tis3d +entity-nan-health-fix|假死修复 (Entity NaN Health Fix) +ferritecore-fabric@ferrite-core|铁氧体磁芯 (FerriteCore)¨ferritecore|铁氧体磁芯 (FerriteCore) +thaumcraft-research-patcher +masterful-machinery@ +minecraft-earth-mod@earth-mobs-mod|Derec 的地球生物 (Derec's Earth Mobs) +scotts-essential +drawerfps|储物抽屉渲染配置 (DrawerFPS) + +cursed-earth¨cursed-earth-fabric +sll|逆向交易 (sɹǝƃɐllᴉΛ) +lagmeter|延迟表 (LagMeter) +hexxit-gear-2@hexxit-gear-r|Hexxit 装备 2 (Hexxit Gear R) +scootys-plants-vs-zombies|Scooty的植物大战僵尸重生 (Scootys Plants Vs. Zombies Regrown) + + + +custom-machinery@ +bonsai-tree-crops +rpgz@ + + +@stationapi +scavenge-timing-addon +cull-particles|粒子渲染机制优化*¨cull-particles-fabric|粒子渲染机制优化 (Cull Particles) +majos-broom|魔女的扫帚 (Majo's broom) +seamless-loading-screen@|无缝加载界面*¨seamless-loading-screen-forge|无缝加载界面 (Seamless Loading Screen) +curios-quark-oddities-backpack|夸克背包饰品* +nature-expansion + + +electromagnetic-coherence +amaleafs-expantion-world-mod +the-elemelon-mod|元素西瓜* +dcsp|钻石压缩 (Diamonds Compressor SP) +corpse-complex@ +modularvoicechat|模块化语音聊天 (ModularVoiceChat) +elytra-slot@|鞘翅插槽 / 鞘翅槽位 (Curious Elytra / Elytra Trinket / Elytra Slot)¨elytra-slot-fabric|鞘翅插槽 / 鞘翅槽位 (Curious Elytra / Elytra Trinket / Elytra Slot) + +tconstructcompatible|匠魂兼容 (TConstructCompatible) + +incubation@ + +abyssmana|奈落魔法学 (AbyssMana) + +create-goggles@ + +coloured-tooltips@|彩色提示框* +magicraft-magic|魔法材料 (Magical Materials) +glowstone-ores|荧石矿石* +more-wires +alexandrite-and-more +endgame-materials|终局材料* +more-cobblestone|更多圆石* +wild-netherwart|野生地狱疣* +the-periodic-table-mod|元素周期表 (The Periodic Table) +adamantium-in-minecraft +forgerocks +ballistix@|弹道学* +wireless-industry +spice-of-life-tonio-edition|生活调味料:托尼欧版 (Spice of Life: Tonio Editon) +husk-spawn@|尸壳生成微调*¨husk-spawn-fabric|尸壳生成微调 (Husk Spawn) +artisan-tools-1-16|工匠工具 (Artisan Tools) +yttr@ +wisla +mixin-0-7-0-8-compatibility@mixincompat|兼容Mixin0.7-0.8 (Mixin 0.7-0.8 Compatibility) +farplanetwo|远平面2 (Far Plane Two) +xenoclus-one +satako-library@satako¨satako-fabric +unique-enchantments-utils|独特的附魔:效用扩展 (Unique Enchantments - Utils) +forge-ae2-additional-opportunity@ae2ao¨ae2ao¨legacy-ae2-additional-opportunity +iconexporter@icon-exporter +curious-shulker-boxes@shulker-box-slot|潜影盒插槽/潜影盒槽位 (Shulker Box Slot)¨curious-shulker-boxes-fabric|潜影盒插槽/潜影盒槽位 (Shulker Box Slot) +xenoclus-2 +darker-depths@|深岩之下* +terracraft-journey +solar-cooker@|太阳灶* + +create-addon +boat-contraptions +ender-rift|末影裂缝* + +splashanimation +continue-button@|继续按钮* +chem-craft|化学工艺* +time-in-a-bottle-standalone|时间之瓶 (Time in a bottle standalone) + +compressed-grass|压缩草* +applepie|苹果派 (ApplePie) +doles-mod +ex-nihilo-sequentia-thermal-addon@|无中生有:传承 - 热力扩展 (Ex Nihilo: Sequentia - Thermal Addon) +ex-naturae@|无中生有:传承 - 植物魔法扩展* +ex-nihilo-sequentia-tinkers-addon|无中生有:传承 - 匠魂扩展 (Ex Nihilo: Sequentia - Tinkers Addon) +iron-jetpacks@¨iron-jetpacks-fabric + +playtime-counter-fabric|游戏时长计数器 (Playtime Counter) +entity-banners|实体旗帜* +curious-jetpacks +curious-armor-stands@¨curious-armor-stands-fabric +trinkets-fabric@trinkets +occultism@|神秘学* +stray-spawn@|流浪者生成微调*¨stray-spawn-fabric|流浪者生成微调 (Stray Spawn) +mooshroom-spawn@|哞菇生成微调*¨mooshroom-spawn-fabric|哞菇生成微调 (Mooshroom Spawn) +cardinal-components@cardinal-components-api + + +integrated-proxy|集成代理器* +a-cobblestone-crafting-table|圆石工作台* +colored-iron +final-kobold +ears@|耳朵* +wildfires-female-gender-mod-forge@female-gender¨wildfires-female-gender-mod-fabric +consistencyplus@ +modularwarfare|模块化战争/模块化武装 (ModularWarfare) +mputils-basic-tools +the-agartha-mod@squiggless-agartha-mod +falling-with-style|花式降落* +valhelsia-core@ + +alwayseat|吃不停 (AlwaysEat) + + + +aquarium|深海* +mixin-booter@mixinbooter + +jrds-moneymod +skeletdimension|骷髅维度 (SkeletDimension) +sushigocrafting@|巧制寿司 (Sushi Go Crafting) +shrines-structures@shrines +valhelsia-tweaks +lazierae2@|懒人AE2 1.16+ (Lazier AE2) +magical-crops-core +magical-crops-decorative +magical-crops-armoury + +simpleeco|简单经济 (SimpleEconomy) +vistas@ + +fish-in-planks +fish-on-the-line@¨fish-on-the-line-fabric +fish-traps|鱼栅* +combustive-fishing@ +fabric-survival-island@survival-island +sonicraft@|索尼克工艺 (SoniCraft) +islands@ +origins-forge@|起源非官方Forge版 (Origins (Forge)) +magic-feather +alet@a-little-extra-tiles +netheriteplus +the-survivalists-mod +campfire-overhaul +shatter +electric-self-balance-scooters|电动平衡车 (Electric Self-balance Scooters) +rats-mischief@ +dream-rng +wandering-trader-improvements + +wasteland-reborn|不毛之地:重生* +skds-core +endertech|末影科技 (Ender Tech) +enderpig-mod|末影猪* + +no-no-ai-spawn|镇压前端召唤 (No No-AI Spawn) +atomic-bomb-1-16|枪,炮,原子弹! (Guns, Rockets and Atomic Explosions) +se-sign-shop|简单经济:牌子商店 (SE: Sign Shop) + +fancymenu@¨fancymenu-fabric +halogen|卤素* +zetamod@zetaforged|泽塔 (ZetaForged / Zeta's Mod) + + +wholetreeaxe +fabrishot@|高清截图Fabric* +materialisation|物质化*¨materialisation3|物质化 (Materialisation) +recipebuffers|配方缓冲 (RecipeBuffers) + +portal-gun-fabric|传送枪 Fabric* +incendium@ +@new-frontier-craft +cooperative-advancements@|合作进度*¨cooperative-advancements-fabric|合作进度 (Cooperative Advancements) +lightstones +openbackup +fat-experience-orbs@|肥胖经验球* +better-pipes|更好的管道* +truetype-font-replacement +fluidlogged-api@ +spark@|火花 (spark) +mco +guardians-galore +cogwheel-tweaker +ultra-amplified-mod@ultra-amplified-dimension|超大群系维度 (Ultra Amplified Dimension)¨ultra-amplified-dimension-fabric@|超大群系维度 (Ultra Amplified Dimension) +classical-art|经典艺术*¨classical-art-fabric|经典艺术 (Classical Art) +emc-baubles|等价饰品 (EMC Baubles) + +lag-removal +gender + +ticktock@servertick + +fps-reducre-for-fabric|FPS减速器(Fabric) (FPS Reducer (For Fabric)) +art-artillery|艺术?火炮! (Art? Artillery!) +minemenufabric@|我的菜单 Fabric 版 (MineMenuFabric) +@tabtps +afkpeace@ + +secret-rooms-fabric@ +smooth-chunks@|平滑区块加载* +saturationoverflow|饱和度溢出 (SaturationOverflow) + +phantom-blood@phantomblood|幻影之血* + +searchable-containers|可搜索容器* + + +integrated-additions|集成扩展* +matchlock-guns|火绳枪* +fabric-autoswitch@autoswitch|自动切换工具 (AutoSwitch) +inventory-profiles-next@|一键背包整理Next* +drill|钻头* +ore-tree|矿物树* +ferdinands-flowers +clear-water@|清澈的水* +applied-energistics-2-wireless-terminals-forge|AE2无线终端Forge版* +ferroustry +village-employment@|村庄就业* + +deathlog@|死亡日志* +automatic-elytra|自动鞘翅* +axolotl-bucket-fix@|美西螈桶修复* +xks-decoration@|XK的装饰 (XK's Decoration) +endgame-materials-addons|更多终局材料* +ravage-and-cabbage@ +stackup@ +simple-anti-x-ray@sax +breakme@ +mod-info-command@mod-info-cmd +hexxit-gear-fabric@hexxitgear +buffed-tools|属性工具* +thaumcraft-nei-plugin|神秘时代NEI插件 (Thaumcraft NEI Plugin) +moarrecipes|更多的配方 (MoarRecipes) +luminium +better-nether-map-port@better-nether-map + +iguanatweaks-reborn@|生存重构/蜥蜴微调重生 (Survival Reimagined / IguanaTweaks Reborn) +enter-the-void|进入虚空* +tensura-mod-that-time-i-got-reincarnated-as-a-slime@tensura-mod|关于我转生变成史莱姆这档事 (Tensura Mod -That time I got reincarnated as a Slime) + +speedometer@speedometer-cafeteria|速度表* +falling-leaves-forge@fallingleavesforge|落叶 (Falling Leaves (NeoForge/Forge)) + + +custom-entity-models-cem@cem|自定义实体模型 (Custom Entity Models) +tweakmyclient@ +lovely-snails@lovely_snails|可爱蜗牛* + +clipboard|备忘录* +crimson-nbt-tags + +water-physics-overhaul@wpo +netherless +auto-ore-dictionary-converter@aodc +elytraboosters@elytra-boosters +cobblegenrandomizer@ +unified-resources +wooden-buckets|木桶* +no-nether-portals|没有下界传送门* +beehivetooltips|蜂巢提示框 (BeehiveTooltips) +buddycards@|巴迪卡牌* +extended-caves@expanded-caves¨expanded-caves + +inventorio@¨inventorio-forge +more-curios-totems-of-undying +selene@moonlight +compatibilitylayerforcustomskinloader|万用皮肤补丁兼容层 (CompatibilityLayerForCustomSkinLoader) +no-potion-shift +no-potion-offset +demonslayer@orca-kimetsu-no-yaiba|鬼灭之刃 (Kimetsu no Yaiba) +nautilium|鹦鹉螺* +auto-attack|自动攻击* +tamagotti + +signal|讯号* +realistic-horse-genetics@|真实马匹遗传* +timeless-and-classic-guns@timeless-and-classics-guns|永恒枪械工坊 (Timeless and Classics Guns) +tool-progression|工具进阶* + + +a-paimon|派蒙* +@bh-creative +music-maker-mod|Music Maker Mod - 其中有同一作者的三个,包括此¨@music-maker-mod +penguin-lib +flywheel@|飞轮* + +coralreef|珊瑚礁 (CoralReef) + +simply-seasons|简单季节* +bclib@ +actually-baubles|实用拓展饰品* +alexs-mobs-battle-music@alexs-mobs-extra-music +lava-waders-bauble|熔岩魔靴饰品* +hardcore-revival@|硬核复活*¨hardcore-revival-fabric|硬核复活 (Hardcore Revival) +additional-guns|更多的枪* +oh-my-minecraft-client@ +wooden-armors-stone-armor@woodenarmor|木制盔甲 (Wooden Armors Mod) + +insanelib@ +daydreamer +phantomfaces|幻灵接口* +improved-villagers|改进的村民* +equipment-compare@|装备比较*¨equipment-compare-fabric|装备比较 (Equipment Compare) + +PickupWidely + +lilliputian +sampler +custom-splash-screen@|自定义加载界面* +masa-gadget@¨@masa-gadget-dev|Masa Gadget - 测试版 +meet-your-fight@|迎战* +hot-or-not-plus +macaws-furniture-tfc +tfc-florae@ +tfc-elementia +infinity-water-bucket|无限水桶* +tfc-caffeine-addon +tfc-cellars-add-on +boats-and-beeps +konkrete@¨konkrete-fabric +xp-from-harvest@|收获经验 (XP From Harvest) +modern-beta@modern-beta-forge¨modern-beta-forge +tfcflux +tfc-medicinal +water-flasks + +structure-world +macaws-lights-and-lamps@|Macaw的灯 (Macaw's Lights and Lamps) +terrarian-slimes@ +create-gears|机械动力:齿轮附加* +simple-big-backpack +croptopia|作物盛景* +firmalife@ +supermartijn642s-core-lib@ +cherished-worlds@|存档置顶*¨cherished-worlds-fabric|存档置顶 (Cherished Worlds) +ironfist|铁拳* + +simply-acceleration|简单加速* +creeper-habitats +husbandry +its-the-little-things +fruitful@|硕果累累*¨fruitful-fabric|硕果累累 (Fruitful) +environmental-energy@|环境科技-发电机* +nakranoths-herdcraft|群兽行为 (Nakranoth's Herdcraft) +lambdabettergrass@|Lambd 的更好的草方块 (LambdaBetterGrass) +@client-commands +bright-ore|矿石高亮* +chinese-style-sword@arsenal-core|中式剑 (Arsenal Core) + +heroic-armory|英雄武器* +colossal-battery|巨型电池 (ColossalBattery) +industrial-meat + +extra-generators@|额外发电机* +horticulture|园艺* +mr-pineapples-food-mod + + +legacyvault +shopaholic + +ok-zoomer@ +untitled-duck-mod-forge@untitled-duck-mod|无题鸭 (Untitled Duck)¨untitled-duck-mod-fabric|无题鸭 (Untitled Duck) +v-tweaks@ +fairenchanting|公平附魔 (FairEnchanting) +bedspreads@¨bedspreads-fabric +piglib@ +nether-portal-spread@¨nether-portal-spread-fabric +x-hp@ + +mr-pineapples-toy-guns +magickcore@|魔法核心 (MagickCore) +feywild|仙灵荒野* +The-final-sword|最终之剑重置版 (The final sword) + +gog-skybox + +lemon-lib@lemonlib +custom-entity-models-kaimyentity-reborn|自定义玩家和实体模型 / KAI我的实体:重生 (Custom Player & Entity Models/KAIMyEntity-Reborn) +miniutilities|迷你实用设备 (Mini Utilities) +stumble-upon-campsites|邂逅:营地 (Stumble Upon: Campsites) +nomad-books|游牧之书* +yungs-extras@¨yungs-extras-fabric¨yungs-extras-neoforge +stoneholm-forge@stoneholm|地下村庄 (Stoneholm, Underground Villages)¨stoneholm|地下村庄 (Stoneholm, Underground Villages) + +inspecio@ +special-ai|特殊AI (Special AI) +dream-waifu-mod|梦中情人 (Dream Waifu mod) +help-wanted|求助* +off-hand-combat|副手战斗*¨off-hand-combat-fabric|副手战斗 (Off Hand Combat) +reaping@|收割* +gilding|镀金* +grims-transportables|格里姆的便捷交通工具 (Grim's Transportables) +reroll|刷新附魔* +tax-free-levels@|免税附魔* +portable-dimensions|便携式传送门* +stone-age-by-yanny +terra-world-generator@terra + +omnis|灾厄村民拓展* +omnis-backpacks +superhotmc +bag-of-yurting@|帐篷袋 (Bag of Yurting) +better-combat-rebirth|更好的战斗:重生* +iron-and-gold-from-1-17|来自 1.17 的铁和金 (iron and gold from 1.17) +immersive-cooking@|沉浸烹饪* +structured-crafting@ +random-shulker-colours@|随机潜影贝颜色*¨random-shulker-colours-fabric|随机潜影贝颜色 (Random Shulker Colours) +create-automated +random-sheep-colours@|随机绵羊颜色*¨random-sheep-colours-fabric|随机绵羊颜色 (Random Sheep Colours) +sleep-sooner@|早点睡*¨sleep-sooner-fabric|早点睡 (Sleep Sooner) +respawning-shulkers@|潜影贝重生*¨respawning-shulkers-fabric|潜影贝重生 (Respawning Shulkers) +respawn-delay@|延迟重生*¨respawn-delay-fabric|延迟重生 (Respawn Delay) +realistic-bees@|真实的蜜蜂* +recast@|持续钓鱼*¨recast-fabric|持续钓鱼 (Recast) +softer-hay-bales@|柔软的干草块*¨softer-hay-bales-fabric|柔软的干草块 (Softer Hay Bales) +portable-jukebox-forge|便携式唱片机 (Portable Jukebox)¨portable-jukebox-fabric|便携式唱片机 (Portable Jukebox) +spiders-produce-webs@|蜘蛛吐网*¨spiders-produce-webs-fabric|蜘蛛吐网 (Spiders Produce Webs) +assassins-creed-blocklegend|刺客信条:方块传奇 (Assassin's Creed Blocklegend) +gravestone-mod-graves|墓碑坟墓 (Gravestone mod Graves) +the-earth-mod|地球* +lifts@|电梯* +corail-recycler|Corail的回收站* +move-minecarts@|可移动的矿车* +inventory-totem@|更好的图腾*¨inventory-totem-fabric|更好的图腾 (Inventory Totem) +lava-picker-upper|熔岩收集器* +nethers-exoticism@ +everpotion@|永恒药水 ⚗️ (EverPotion ⚗️)¨everpotion-fabric|永恒药水 ⚗️ (EverPotion ⚗️) +quick-shulker@quickshulker|快捷潜影盒* +respawnable-pets@|宠物可重生* +schmucks@|小阿呆 (Schmucks!) +automatic-doors@|自动门*¨automatic-doors-fabric|自动门 (Automatic Doors) +configurable-despawn-timer@ +chunkmap@|区块加载小地图 (ChunkMap) +inventory-tabs +bottle-your-xp@|装瓶你的经验*¨bottle-your-xp-fabric|装瓶你的经验 (Bottle Your Xp) +gravestone-mod-extended|墓碑坟墓 - 拓展 (Gravestone mod - Extended) +better-enchanted-books@|更好的附魔书* +easy-steel-forge|简单的钢 (Easy Steel & More) +fabric-waystones@fwaystones|Fabric 版传送石碑 (Wraith Waystones / Fabric Waystones) + + +dark-enchanting@|暗黑附魔* + +better-wandering-traders|更好的流浪商人* +superflat-world-no-slimes@|没有史莱姆的超平坦世界*¨superflat-world-no-slimes-fabric|没有史莱姆的超平坦世界 (Superflat World No Slimes) +scorge + +beaconoverhaul@|信标改革 (Beacon Overhaul) +contact|往来* +blockshifter¨blockshifter-forge + +vanilla-builders-extension + +big-beacons|大信标* +wooden-hopper@|木漏斗* + +ages-api +fancyhud@spiffyhud¨spiffy-hud-fabric +advanced-compass|高级指南针* +salutem +the-sol|太阳系* +better-beds@|更好的床* +world-lives-mod +lib + +just-some-chocolate|只是一些巧克力 (Just some Chocolate) + +vacuum-horizon +unique-enchantments-battle|独特的附魔:战斗扩展 (Unique Enchantments - Battle) +balanced-enchanting|平衡附魔* +pipe|管道* +simple-ambients + + + +modern-loading-screen|现代加载界面* + +dong-dongs-random-creation@|冬冬的随意创作 (Dong Dong's random creation) + +transliterationlib + +rpmtw-update-mod@|RPMTW平台模組 (RPMTW Platform Mod) +farsight-spyglasses +not-enough-animations@|更多动画* +better-beacon|更好的信标与潮涌核心 (Better Beacon / Conduit) + +dungeon-now-loading@|地牢进行时* +simple-emerald-tools-fabric¨easy-emerald-tools +cold-sweat@|冷汗* +witchery-rewitched|巫术:重生 (Witchery: Rewitched) +majou-densetsu-3d|魔城传说3D (Majou Denetsu 3D) +icarus-wings@|伊卡洛斯之翼* +keyboard-wizard|按键精灵* +piscary + +storage-cabinet|储藏柜* +first-person-model@|更真实的第一人称模型 (First-person Model) +randore@¨randore-forge +rising-uppercut|上勾拳* +jackie-chan-s-weapon|成龙的武器 (Jackie Chan's weapon) +explorers-compass@|探险者指南针 (Explorer's Compass) +gravestones@|墓碑* +crafting-dead-survival|行尸走肉:生存 (Crafting Dead: Survival) +redstone-control-2|红石控制2* +csenchants +mystical-customization@ + + +fmprojecte-fmpe|等价交换重制-EMC上限扩展版 (FMProjectE) + +ibe-editor@ +exotic-critters +archers-paradox@|弓箭手悖论 (Archer's Paradox) +dynamic-trees-neapolitan|动态的树:那不勒斯风味附属 (Dynamic Trees - Neapolitan) + +randomite-classic + +wilds +roughly-searchable@ +cull-leaves@|树叶渲染优化* +dynamic-trees-atum-2|动态的树:阿图姆2附属 (Dynamic Trees - Atum 2) +randomtweaker + + +steamworld + +falling-leaves-fabric@fallingleaves|落叶 (Falling Leaves (Fabric)) +craftable-creative-ability|可合成的创造能力强化* +not-enough-energistics +terracore + +seeker-compass@ +ghosts-explosives +power-drop@|蓄力投掷* +yungs-better-dungeons@|YUNG 的地牢优化 (YUNG's Better Dungeons)¨yungs-better-dungeons-fabric|YUNG 的地牢优化 (YUNG's Better Dungeons)¨yungs-better-dungeons-neoforge|YUNG 的地牢优化 (YUNG's Better Dungeons) + +ore-controller +morechickens@|更多鸡 (MoreChickens) +ghosts-explosives-2 +weapon-throw@|武器投掷*¨weaponthrowlite|武器投掷 (Weapon Throw) +more-villagers|更多村民*¨more-villagers-fabric|更多村民 (More Villagers) +dungeons-mobs|地下城生物* + + + + + + + + +uusi-aurinko|新日* + + + + + + + + + + +chronicler-the-key-of-stellaris|历史记录者·星之匙 (Chronicler: The Key of Stellaris) + +neubulaeko-slime|星云子史莱姆* + + + + +fantasysoup +just-enough-professions-jep@|JEI工作方块 (Just Enough Professions) + +paimonfood|应急食品 (PaimonFood) +plumed-belt +better-with-minecolonies@ +calemis-utilities|Calemi的实用设备 (Calemi's Utilities) +botanical-cowardice +travelers-titles@|旅人标题 (Traveler's Titles)¨travelers-titles-fabric|旅人标题 (Traveler's Titles)¨travelers-titles-neoforge|旅人标题 (Traveler's Titles)¨traveler-titles|旅人标题 (Traveler's Titles) +expand-chinese-sword|中式剑拓展 (Arsenal Integration) + +littleframes@littlepictureframes|小画 (LittlePictureFrames) +lavalogged-blocks@|岩浆充填 (Lavalogged blocks) +awoken-world +gt4-reimagined|格雷科技4:重构想 (GregTech 4 Reimagined) +camouflaged-creepers +ore-tweaker@ +openpython +jei-lotr +capes@ +attack-speed-enchantment|攻击速度附魔* +natures-minerals@ +balm@¨balm-fabric +resource-hogs|资源猪 (Resourse Hogs) +advanced-xray|高级透视 (Advanced XRay)¨advanced-xray-fabric-edition|高级透视 (Advanced XRay) + +ring-of-attraction-forge|吸引戒指 (Ring of Attraction)¨ring-of-attraction-fabric|吸引戒指 (Ring of Attraction) +customhud@|自定义HUD (CustomHud) +deadly-world|致命世界* +fastdecay@ +essential-commands@ +caves-and-cliffs-backport +that-future-mod-glow-squid-axolotl-moobloom-etc +diamond-buildcraft|钻石装饰* +@apocalypse-rebooted|启示录重制 (Apocalypse Rebooted) +mcwifipnp@|更高级联机设置 (LAN World Plug-n-Play) +requious-frakto + + + +capsule@ +isometric-renders@|等轴渲染* + +enchanting-secretaire|附魔记录* +sync-fabric@|克隆(Fabric) (Sync (Fabric)) +tale-of-kingdoms-a-new-conquest@|王国:新征程 (Tale of Kingdoms: A new Conquest) + +schwarz@|黑* +megane-forge@¨megane@ +crusade@ +vending-machine|售货机* +modernxl +taiga2@|匠魂合金附加2 (Tinkers Alloying Addon Port) +chunkgenlimited|区块生成限制 (ChunkGenLimiter) +more-crafting-tables-for-forge@more-crafting-tables|更多工作台 (More Crafting Tables for Forge!) +repurposed-structures@repurposed-structures-forge|结构变体*¨repurposed-structures-fabric@|结构变体 (Repurposed Structures) +ezpas +electrona +@mcg +reasonable-sorting@|合理排序* +chat-heads@|聊天头像* +hidden-armor|隐藏盔甲* +majruszs-progressive-difficulty@|Majrusz的进阶难度 (Majrusz's Progressive Difficulty) +pharmacist|药师* +kappa@ +equivalent-integrations|等价集成* +keep-equipment|保留装备* +herobrines-origin|Herobrine 的起源 (Herobrine's Origin) +the-abyss|深渊:远古 (The Abyss: Legacy) +sekiro-sense-symbols +lurker|Cold的潜伏者 (Colds: Lurker) +cavebiomeapi@¨cavebiomeapi-fabric +extended-block-shapes@extshape|扩展方块形状*¨extended-block-shapes-blockus@extshape_blockus|扩展方块形状 (Extended Block Shapes) +passive-mobs@passivemobs +sponsor|赞助者* + + +between-ores +black-hole|黑洞* +more-and-more-minerals|越来越多的矿物 (more and more minerals) +permafrost + +scootys-plants-vs-zombies-2|Scooty的植物大战僵尸2 (Scooty's Plant Vs. Zombies 2) +better-furnaces-reforged@|更好的熔炉重铸版 (BetterFurnaces Reforged) + + +schools-of-magic-second-semester|魔法学校:第二学期 (Schools of Magic: Second Semester) +dark-loading-screen@|深色加载界面* +hals-exploration-mod@hals%20exploration%20mod +farmers-delight-cookbook-addon|农夫乐事:烹饪书拓展 (Farmer's Delight Cookbook Addon) +heads-down-display@head-down-display +mrcrayfish-more-furniture-mod|MrCrayfish 的更多家具 (MrCrayfish's More Furniture Mod) +multi-world + +terralith@ +overworld-two-forge¨overworld-two +xl-packets|XL数据包 (XL Packets)¨xl-packets-fabric|XL数据包 (XL Packets) +rftools-storage@|RF工具:存储 (RFTools Storage) +rftools-builder@|RF工具:建造机 (RFTools Builder) + +nethers-delight@|下界乐事 (Nether's Delight) +farmers-extra-foods|农夫的拓展食物 (Farmer's Extra Foods) +tinkers-delight|工匠乐事 (Tinker's Delight) + +@flashfreeze +majruszs-accessories@|Majrusz的配件 (Majrusz's Accessories) +water-2-mana + + +craft-and-hunt|狩猎工艺 (Craft and Hunt) +tmats +the-afterlight|隐光之域* +tinkers-planner|匠魂蓝图 (Tinker's Planner) +playing-cards|扑克牌* +rainbow-oak-trees-2|彩虹橡树2* +mapfrontiers@|地图边界 (MapFrontiers) +customizable-elytra@|可自定义鞘翅*¨customizable-elytra-fabric|可自定义鞘翅 (Customizable Elytra) +puzzles-lib@¨puzzles-lib-fabric +unique-enchantments-base|独特的附魔:基础* +ore-stages|矿石阶段* +krays-magic-candles +thaumcraft-localization-optimizer|神秘时代本地化优化* +drink-beer-fabric|喝啤酒啦 (Drink Beer)¨drink-beer-forge|喝啤酒啦 (Drink Beer) +emerald-tools-armour +hidden-recipe-book@|隐藏配方书* +kibe@|羊肉面饼实用设备 (Kibe Utilities) +poisoncraft|毒药工艺 (PoisonCraft) +detail-armor-bar-forge@detail-armor-bar|细节盔甲 (Detail Armor Bar)¨detail-armor-bar|细节盔甲* +wings-horns-hooves-the-ultimate-unicorn-mod +project-rankine@rankine|兰金计划* +tinkers-mechworks@ +qdc-core-4-0@qdc-core-4.0|量子拆解工艺 (Quantum Dis-Assembly Craft)¨qdc-quantum-dis-assembly-craft|量子拆解工艺 (Quantum Dis-Assembly Craft) - 旧 +william-wythers-overhauled-overworld@wwoo +infinite-music +cobbler|可靠的潜影贝工厂 (Shulker's Faithful Factories/Cobbler) +nether-fast-transport-layer +the-outer-end@ +hamncheese@ +buzzy-drones +morevanillaarmor@|更多原版盔甲 (MoreVanillaArmor) + +eternal-tales@|永恒传说* +oh-the-biomes-youll-go-fixes|你将去的生物群系修复版 (Oh The Biomes You'll Go Fixes) +wild-world + +miskatonic-mysteries¨miskatonic-mysteries-legacy +harvesters-night|收割者之夜 (Harvester's Night) +slotlock@|锁定槽 (SlotLock) + +panorama-tweaker@ +simple-tomb|简单坟墓* +modern-life@|摩登生活* +paxi-fabric@paxi¨paxi¨paxi-neoforge +@elemental-reaction|原神-起源 (Genshin_Elemental_Reaction) +waveycapes@wavey-capes|飘扬披风 (Wavey Capes) +skin-layers-3d@3dskinlayers|3D 皮肤层 (Skin Layers 3D) +mc-mods-the-discs|唱片大全 (All the Discs) +cryptic-cosmos +bayou-blues@|长沼蓝调*¨bayou-blues-fabric|长沼蓝调 (Bayou Blues) +hex-lands|六边形地貌* +fixrtm +serene-tweaks +ScalingGuis|界面缩放 (ScalingGUIs) +ide-better-command-block-forge-editor|更好的命令方块 (Better Command Block IDE)¨ide-better-command-block-fabric-editor|更好的命令方块 (Better Command Block IDE) +breakfree@|自由破坏 (Break Free) +tinkers-mechworks-fork +extended-nether-backport +borderless@borderless-window|无边框全屏 (Borderless Window) +lifted-restrictions-structure-block|更好的结构方块 (Better Structure Block) +entity-model-json|实体模型 JSON (Entity Model JSON) +death-coords|死亡坐标显示* + +never-enough-currency|货币多多* +never-enough-currency-lite|货币多多:精简版* +create-chunkloading +name-pain@namepain +wireless-chargers@|无线充电器* +bouncier-beds@|弹力床*¨bouncier-beds-fabric|弹力床 (Bouncier Beds) +hexlands-ii|六边形地貌 2 (HexLands II) +gold-in-river-mod|河中淘金* + +lorespawn|怪物巢穴* +creatuures +fabrics-biome-api-reforged@fb-api-reforged +stalwart-dungeons@|坚固地牢* +maidens-marvelous-materials +nekoration@|猫咪装饰* +tomb-many-graves-2 +fins-and-tails|鳍和尾巴 (Fins and Tails) +smarter-farmers-farmers-replant@|更聪明的农夫 (Smarter Farmers / Farmers Replant) +peculiars@|独特风味* +draggable-resource-packs@draggable-lists|可拖动列表/可拖动资源包 (Draggable Lists/Draggable Resource Packs) +fastchest|快速箱子渲染 (FastChest) - 已不再更新¨@fastchest|快速箱子渲染 (FastChest) - 在此处更新 +yuushya-townscape@|方块小镇* +architects-palette@|建筑师的调色板 (Architect's Palette)¨architects-palette-fabric@|建筑师的调色板 (Architect's Palette) +whisperwoods@|低语之森* +dimensional-dungeons@|维度地牢* +bosses-of-mass-destruction@|祸乱鬼魅 (Bosses of Mass Destruction) +neoelfeos-medieval-pub-decoration +dustrial-decor@dustrial-decor-forge +feders-scarecrows|Feder的稻草人 (Feder's Scarecrows) +zetter@zetter-painting-mod +mystical-pumpkins|神秘南瓜* +skinned-lanterns@skinned-lanterns-fabric|灯笼皮肤*¨skinned-lanterns-fabric|灯笼皮肤 (Skinned Lanterns) +scarecrows@|稻草人* +seasonals@|季节风味* +mimi-mod@mimi +blocktuner@|音符盒调音助手 (BlockTuner) +caged-mobs@|笼中生物* +advanced-rifles +tome-of-blood|血之宝典 (Tome of Blood) +blockfront-world-war-ii@blockfront|方块前线 (BlockFront) +archaic-guns +blockcarpentry +survival-overhaul +raining-cats-and-dogs|猫狗雨 (Raining Cats and Dogs) +melt + +stuff-a-sock-in-it@|日志过滤器* +supermartijn642s-config-lib@ +small-ships@ +sound-engine-reloader|重新加载声音* +crystal-caves +increasemobs +scarecrows-territory@|稻草人领域 (Scarecrows' Territory) + +dungeons-mod¨dungeons-mod-lite +loot-beams@|战利品光束 (Loot Beams: Relooted!) +theurgy@ +better-badlands|恶地改善* + +the-mysthical-reworked +villagers-and-monsters-mod-legency +repair-chests|修损宝盒* + +relics-of-gaming|游戏遗物* +modular-controller|模块化控制器* + +Item-Collectors@item-collectors +gamemodeoverhaul@|旧版指令 (GamemodeOverhaul) + +dash@ +minecraft-dungeons-content@dungeons-content|地下城内容 (Dungeons Content) +old-beacon|旧信标* +oc2|开放式电脑 II (OpenComputers II) +botany-pots-tiers@|更好的植物盆栽* +compatchedstorage|紧凑存储修复 (ComPatchedStorage) +iseedragons +psionic-peripherals +malum@|灵灾* +mc-modsomancy@allomancy|镕金术 (Allomancy) +steamcraft2 +boilerplate +meldexuns-crystalic-void +recipes-and-more +llama-steeds-forge@llama-steeds|骑羊驼 (Llama Steeds)¨llama-steeds|骑羊驼* +levellib@657400 +enigmatic-graves +boat-item-view-forge@boat-item-view|边划边看 (Boat Item View)¨boat-item-view|边划边看* +forge-creeper-heal-unofficial|Forge 苦力怕坑修复[非官方版] (Forge Creeper Heal [Unofficial]) +desolation-forge@desolation|荒芜 (Desolation)¨desolation|荒芜* +ma-astral +zaraklib +chipped@ + +mending-for-1-7-10|给老版本的经验修补 (Mending for Older Version) +unreachable-fantasy-mod +ai-reducer|AI减速器 (AI Reducer) +simple-teleporters|简易传送器*¨simple-teleporters-fabric|简易传送器 (Simple Teleporters) +killmods@657399 +big-brain@ +adaptive-performance-tweaks@|适应性性能调整*¨@adaptive-performance-tweaks-core|适应性性能调整 (Adaptive Performance Tweaks) - 模块化版核心¨@adaptive-performance-tweaks-items|适应性性能调整 (Adaptive Performance Tweaks) - 模块化版物品优化¨@adaptive-performance-tweaks-gamerules|适应性性能调整 (Adaptive Performance Tweaks) - 模块化版游戏规则优化¨@adaptive-performance-tweaks-player|适应性性能调整 (Adaptive Performance Tweaks) - 模块化版玩家优化¨@adaptive-performance-tweaks-spawn|适应性性能调整 (Adaptive Performance Tweaks) - 模块化版生物生成优化 +rltweaker +multibags|多重背包 (MultiBags) +lavalib +ftb-banners-forge +overpowered-armor-bar +tinkers-rapier|匠魂西洋剑 (Tinkers' Rapier) +earth-reworked|土方工程重制版* +cinderscapes-reforged@|余烬奇景Forge版* +better-diving|水世界/更好的潜水* +auto-sprint|自动冲刺:一键切换 (Auto Sprint : key toggle) +nebula-rpg +betternether-reforged|更好的下界Forge版 (BetterNether Reforged) +item-stitching-fix@|物品模型修复移植版* +blood-and-madness +afraid-of-the-dark +ores-above-diamonds|超越钻石* +crafting-automat +ingotter +presence-footsteps@|脚步声* +walk-the-air|凌空微步 (Walk the air) +castle-dungeons@castle +mobs-properties-randomness¨@mobs-properties-randomness|Mobs Properties Randomness - 未及时更新,不全 +iguana-tweaks|蜥蜴微调* +enhanced-ai@ +vulcanite|软碲铜 (vulcanite)¨vulcanite-fabric|软碲铜 (vulcanite) +ziheasymodding +path-to-dirt@ +dirt2path +carbonado +strange +tfctweaker +scaling-feast@ +delete-item +stexcraft-1-12-2-mod +longerdays +mob-heads|生物头颅* +compass-coords@ +neverdark +stats-keeper¨stats-keeper-fabric +vanillatweaks@ +bacodifficulty +immersiveposts@|沉浸长杆 (Immersive Posts) +fyres-youwilldiemod|必死无疑 (The "You Will Die" Mod) +old-walking-animation@|旧版行走动画* +enders-magic|末影魔法 (Ender's magic) +anvil-patch-lawful +elegant-networking +gemsplusplus|宝石++ (GemsPlusPlus) +defaultsettings|默认设置 (DefaultSettings)¨defaultsettings-fabric|默认设置 (DefaultSettings) +draylars-battle-towers|Draylar的战斗高塔 (Draylar's Battle Towers) + +leos-craftable-chainmail|可制作的锁链甲 (Leo's Craftable Chainmail) +time-to-die +better-survival-mod|更好的生存* + +tschipplib +the-deep-dark-ocean-dimension +online-picture-frame@modern-online-picture-frames|在线相框显示2 (Modern Online Picture Frame) +pyromancer|炽焰术师* +mekanism-fission-recipe@ +macaws-fences-and-walls@|Macaw的栅栏与墙 (Macaw's Fences and Walls) + +lunae-silva + +rainbow6|我的六号 (Rainbow6:Minesiege) +friendlyendermite@friendermite|友好的末影螨 (FriendlyEndermite) +food-expansion|食物扩展* +forgotten-items|被遗忘的物品* +food-expansion-reimagined@|食物扩展:重构想 (Food Expansion: Reimagined) +redstone-igniter +enchanting-tweaks +thrown-slime + +inventory-auto-fill +queen-bee@|蜂后* +better-barrels +enderbeetles +customport +more-sound-config +undead-expansion +hourglass@|沙漏* +relics-mod@|遗物 (Relics) +comfortable-nether|舒适下界* +arcanecraft-ii|奥法工艺2 (ArcaneCraft II) +presence-footsteps-forge@resence-footsteps-forge|脚步声Forge版 (Presence Footsteps (Forge)) +aardvarks-weird-wonderful-wild + + +little-delicacy-cafes +ee3-helper +save-your-pets|拯救你的宠物* +main-menu-scale +potion-fingers +reload-audio-driver-rad|音频驱动重载 (Reload Audio Driver)¨reload-audio-driver-fabric|音频驱动重载 (Reload Audio Driver) +shieldbreak@ +holiday-helper +fabric-tickratechanger-mod|Fabric版运算变速 (Fabric TickRateChanger) +observable@|可视性能侦测* +disenchantment-edit-table|祛魔编辑台* + +cit-resewn@ +lazy-language-loader@ +clef +zettai-magic-2 + +wotw-mod|世界之战 (The War of the Worlds Mod) + + + +simple-camp-fire|简单营火* +biome-locator|生物群系定位器* +extra-coals +dark-caverns|暗黑深穴* + + + +milk-all-the-mobs@¨milk-all-the-mobs-fabric +roadrunner +pokecube-aoi +grim-statues|Grim的雕像* +oauth@¨oauth-fabric +omaypaty-japan-mod +demon-slayer-mod-kimetu-no-yaiba|鬼灭之刃 (DEMON SLAYER MOD) +tipthescales@ +xplosives-mod +arkys-environment +candylands +elements-of-power +aquafina +way-through-dimension +journeymap-integration@ + +damage-tint@|伤害色调* +mo-spells +prehistoric-flora|史前自然 (Prehistoric Nature)¨prehistoric-nature@|史前自然* +blade-works|剑制 (Blade Works/nikgub_'s Blades+) +create-confectionery@|机械动力:甜食* + + + +rotten-piglins-mod|腐朽猪灵 (Rotten Piglins) +ex-nihilo-random|无中生有:随想 (Ex Nihilo: Random) + + +fabrictailor@|离线皮肤切换 (Fabric Tailor) +ambientworld +@custom-raid|自定义袭击 (Custom Raid) +apple-trees-revived|苹果树:复生* +potatos-lucky-block|马铃薯幸运方块 (Potato's Lucky block) +even-more-tnt +fun-tnt|有趣的TNT (Fun TNT) + +chileancraft|智利工艺 (Chilean Craft) +canals|水渠* + +underground-loot-crates|地下战利品箱* + +smooth-scrolling-everywhere|平滑滚动*¨smooth-scrolling-everywhere-fabric|平滑滚动 (Smooth Scrolling Everywhere) +sword-blocking@|持剑格挡* +better-mount-hud@|更好的骑乘 HUD (Better Mount HUD) +fire-overlay-controller@|火焰叠加层调整* + +particle-rain@|粒子雨* +sodium-reforged|镁 (Magnesium / Sodium Reforged) +phosphor-reforged|硫 (Sulfuric/Phosphor Reforged) +hydrogen-reforged|氦 (Helium) +xl-food-mod-plus|超多食物+ (XL Food Mod+) + +mcbot@|群服互联🔗 (McBot🔗) +ice-and-fire-dragonseeker +reeses-sodium-options@|Reese的钠视频界面 (Reese's Sodium Options) +continuity@ +airportmod +better-gui-scaling@betterguiscaling|更好的界面缩放 (Better GUI Scaling / Better UI Scale) +titles@|头衔* +skiing +cave-biomes +tatami +final-fantasy-12-mod +mojangster@|加载界面动画 (Mojangster (Animated Loading Screen)) +anvil-tweaks +asphaltmod|沥青 (Asphalt Mod) + +reroll-forge|刷新附魔Forge版 (Reroll-Forge) +swordenlarger|剑模型扩大 (SwordEnlarger) +castle-in-the-sky-the-fairytale-of-laputa|天空之城 (Castle in the Sky) +dimensionalores|维度矿石 (DimensionalOres)¨dimore|维度矿石 (DimensionalOres) +illagers@illagers+|更多的灾厄村民 (Illagers+) + + + +villagers-follow-emeralds-fabric@|村民跟随绿宝石 (Villagers follow Emeralds) + +diabloloot|暗黑破坏神战利品 (DiabloLoot - Bosses Update) +yggdrasil|世界树* +ftb-dripper-forge +forge-snad|子沙1.14+ (Snad)¨fabric-snad|子沙1.14+ (Snad) + +opentoall + +net-music@|网络音乐机* +torchbowmod@|火把弓 (TorchBowMod) +esencia +weirdmobs@ydms-weirdmobs +enchantment-level-language-patch@enchlevel-langpatch|附魔等级语言补丁 (EnchLevel-LangPatch) +open-to-lan +simple-translation@|简单翻译* +fx-control@|效果控制 (Fx control) +what-are-you-voting-for@ +steam-powered-create@create-steam-powered|蒸汽动力 (Create: Steam Powered) +creepers-burn@CreepersBurn + +pretty-game-enhhancing-gobblet-pgeg-remake|魔法森林重置版 (Pretty, Game-Enhhancing Gobblet Remake) + +kvc-equipment|蛋挞君的原版补全装备篇 (KVCEquipment) +mooshroomcraft|哞菇工艺* +unearthed|出土*¨unearthed-fabric|出土 (Unearthed) +terrestria@¨terrestria-reforged +simplex-terrain-generation|Simplex地形生成器* +enderscape@|末影之景* +goblin-traders-fabric@|哥布林商人Fabric版 (Goblin Traders (Fabric)) +lakeside@|湖畔* +chenziqius-originality|CHENZIQIU的创意 (CHENZIQIU's Originality) +mc-modsoy-forgery@alloy-forgery|合金冶炼炉 (Alloy Forgery) +mechanical-tech@|机械科技* +hadesgame|阴间游戏 (HadesGame) +one-block-forge + +human-reborn@ +additional-additions-forge@addadd|额外扩展 (Additional Additions)¨additional-additions|额外扩展* +earlygame@ +happiness-is-a-warm-gun@ + +kvc-blocks|蛋挞君的原版补全方块篇 (KVCBlocks) +enigtech2-util +environmental-creepers@|环保型苦力怕* + +look-at-that +advanced-peripherals@advancedperipherals|高级外设* +nether-chest-fabric@nether-chest +@essentialaddons +levelz@ +betterend-re-forked|更好的末地Forge重铸版 (BetterEnd Reforked) +mining-gadgets|采矿小工具*¨mining-gadgets-fabric|采矿小工具 (Mining Gadgets) +ponderjs +majrusz-library@ +ydms-coppergolem@ydms-copper-golem|YDM的铜傀儡 (YDM's CopperGolem) +chococraft-3 +chococraft-plus@ +travel-huts +expandability +squirrels|松鼠* +ftb-power-pots|FTB 电力植物盆 (FTB Power Pots) +the-graveyard-forge@|墓园 (The Graveyard)¨the-graveyard-fabric@|墓园 (The Graveyard) +nether-agriculture@netheragriculture|下界农业* +conjuring@ +awesome-dungeon-forge@awesome-dungeon¨awesome-dungeon-fabric¨awesome-dungeon-neoforge +out-of-sight@ +decorative-blocks-modded-compat|装饰方块模组兼容 (Decorative Blocks modded compat) +camp-chair@ +size-matters +chalk@chalk-mod|粉笔* +chalk-fabric@chalk +@modmanager|模组管理器 (Mod Manager) +yarcf@|合成冲突消除 (Yet Another Recipe Conflict Fixer) +drones +ticbc + +meetle +tarot|塔罗* +forcecraft@|力量工艺 (ForceCraft) +right-click-harvest@|右击收割 (Right-Click-Harvest) +custom-content-packs +cake-chomps@¨cake-chomps-fabric +distant-horizons@distanthorizons +betterp2p@|更好的P2P支持 (Better P2P) +ob-aquamirae|海灵物语 (Aquamirae)¨aquamirae-fabric|海灵物语 (Aquamirae)¨@aquamirae|海灵物语 (Aquamirae) +nuclear-tfc +just-more-cakes@|只是更多的蛋糕! (Just More Cakes!)¨just-more-cakes-fabric|只是更多的蛋糕! (Just More Cakes!) +image-mod@ +reinforced-barrels@|增强木桶* +spyglass-zoom|望远镜变焦* +npc-variety-port@npc-variety|NPC变体 (NPC Variety) +just-enough-effects +incorporeal-2-rhododendrite|幻想多媒体2 (Incorporeal 2 + Rhododendrite) + +einsteins-library@ +worldshape +rslargepatterns|精致存储大样板 (Refined Storage Large Patterns) +gendustry-jei-addon +statement@ +mutant-more@|更多突变生物*¨new-mutant-more@|更多突变生物 (Mutant More) + +just-enough-keg +paleolithic-revolution +better-shields|更好的盾牌* +yungs-bridges@|YUNG 的桥 (YUNG's Bridges)¨yungs-bridges-fabric|YUNG 的桥 (YUNG's Bridges)¨yungs-bridges-neoforge|YUNG 的桥 (YUNG's Bridges) +project-red-transmission@|红石计划:传导 (ProjectRed - Transmission) +day-dream@ +savage-ender-dragon|更凶猛的末影龙* + +age-of-weapons@age-of-weapons-reforged|武器时代 (Age of Weapons) +drawerstorage-keychain|抽屉钥匙扣 (DrawerStorage Keychain) +fracdustry@|分形工业 (Fractal Industry) +magical-forest|魔法森林* +skin-swapper@skinswapper|皮肤更换器* + + +owo-lib@ +picturesign@ +divine-missions|神圣任务* +gregsieves|格雷筛子 (GregSieves) +gregtech-food-option@|格雷科技食物优选 (GregTech Food Option) +converting-industrial-wires|工业线缆:转化版* +tinkers-oredict-cache|匠魂矿辞缓存 (Tinkers OreDict Cache) +mentalillness|精神病 (Mental illness) +better-magnesium-video-settings-button|更好的镁视频设置按钮* +adventurez@ +mobz +villagerquests@|村民任务 (VillagerQuests) +environmentz@ + +homing-ender-eye@|回归之眼* +magical-crops-regrowth-1-16-5|魔法作物:重生 (Magical Crops: Regrowth) +voidz@ +mining-master@ + +victus@ +lots-of-food-revived|更多食物:复生 (Lots of Food Revived) +dontstarve|不要饿死2 (DontStarve2) +steves-universe-space-mod +candy-world-recaramelized|糖果世界:重制版 (Candy World - ReCaramelized) +carrier|搬运* + +undo|撤销! (Undo!) +unnamed-animal-mod|无名动物模组* +camels|骆驼* +food-effects@ +item-borders@|物品边框*¨item-borders-fabric|物品边框 (Item Borders) +iceberg@|冰山*¨iceberg-fabric|冰山 (Iceberg) + + +enhanced-farming@|增强农业* + + +lava-clear-view@|熔岩下清晰视野*¨lava-clear-view-fabric|熔岩下清晰视野 (Lava Clear View) +global-xp@ +universal-graves@ + +more-bows-restrung@|更多弓:重振旗鼓! (More Bows: Restrung!) +nimble-fabric@nimble|灵活 (Nimble)¨nimble|灵活* +metal-barrels@|金属储物桶* + + + +motiono + +vanillarecipe|香草食谱 (VanillaRecipe) + + +fantastic-fish-alpha-v1-4|神奇的鱼 (Fantastic Fish) + + +more-mounted-storages|更多存储挂载* +minecraft-comes-alive-reborn@|凡家物语:重生 (MCA Reborn) +noodles-apex|面条的Apex系列 (Noodles'Apex Series) +ftb-beast-coin-miner|货币矿机 (Beast Coin Miner) +scape-and-run-parasites-addon-by-nocube +vanilla-degus|八齿鼠* +ksyxis@ +metallurgy-4-reforged|冶金4:重铸 (Metallurgy 4: Reforged) +harder-natural-healing@ +extra-bit-manipulation +spartan-weaponry-twilight-forest@|斯巴达的武器:暮色森林 (Spartan Weaponry: Twilight Forest) +iris-reforged +additional-lanterns@|更多灯笼* +bottled-air@|瓶装空气*¨bottled-air-fabric|瓶装空气 (Bottled Air) +fabricproxy-lite@ +abyssal-depths +tomes|秘典* +budschies-morph-mod@ +pswg|帕尔奇的星球大战 (Parzi's Star Wars Mod)¨parzis-star-wars-mod|帕尔奇的星球大战 (Parzi's Star Wars Mod) +aquatic-abyss +slimier-slimes +stupid-weapon +slime-carnage|史莱姆杀戮* +portal-tags +eden-ring@eden-ring-reforked|伊甸星环* +placement-tweaks|放置调整* +kimetsu-animation-demon-slayer-animation|鬼灭动作 (Kimetsu Animation) +hals-enhanced-biomes +improvedbackpacks|改良背包 (Improved Backpacks) +ender-skills|末影技能* +useful-railroads@|实用铁轨* +voluminous-energy@voluminous_energy +flaminco +simple-graves + + +wi-zoom@|WI变焦 (WI Zoom) +forge-carpet@ + +fabric-tree-chopper@|砍树* +i-see-lava@ +dual-riders +refined-relocation-2|简单分类2* +ftb-sluice +sky-villages-forge@sky-villages|天空村庄 (Sky Villages)¨sky-villages-fabric|天空村庄 (Sky Villages) +gui-clock@¨gui-clock-fabric-version +hand-over-your-items@¨hand-over-your-items-fabric +koopas-critters@ +krypton-reforged|氪Forge版* +item-counter|物品计数器* + +reality-check-real-life-timer +retail + +time-core-lib + +mclogin +rereskillable +kubejs-blood-magic +kubejs-create@ +kubejs-ui-forge +kubejs-thermal@ +kubejs-immersive-engineering@ +kubejs-mekanism@ +starter-kit@|初始套件*¨starter-kit-fabric|初始套件 (Starter Kit) + +stacker@ +gcm +ocean-floor-clay-sand-and-dirt +linfox-stacked-dimensions-warden-edition +experience-bottler +gregicality-ore-addon|Gregicality矿物拓展* +gregtech-battery-buffer-driver-for-opencomputers|格雷科技电池箱的开放式电脑驱动 (GregTech Battery Buffer Driver for OpenComputers) +orimod +htm@ +gtce-inventory|格雷物品管道 (GregTech CE Inventory Pipes) +mechtech|机械工程 (MechTech) +gregtech-energistics|格雷能源 (GregTech Energistics) +empatic +nukepowered-utils +gtce2oc|格雷科技开放式电脑兼容 (gtce2oc) +azure-rpg-items|Azure的RPG风格物品 (Azure RPG Items) +mine-and-slash-expansion|挖矿与砍杀拓展 (Mine and Slash - Expansion Mods) +devil-may-cry-weapons|鬼泣武器* +craft-to-exile-custom-uniques|放逐之路定制物品 (Craft to Exile Custom Uniques) +terraria-arsenal|泰拉瑞亚装备* +world-of-warcraft-weapons|魔兽世界装备 (World of Warcraft Weapons) +mcdoom@|MC 毁灭战士 (MCDoom) +bleach-weapons|死神装备* +behgameon +into-the-maelstrom|冒险漩涡* +create-deco@¨create-deco-fabric +warp-pipes +fertile-farmland|沃壤千里* +luckperms@ +inv-view@invview +ftb-industrial-contraptions|FTB工业奇械 (FTB Industrial Contraptions) +more-respawn-anchors|更多重生锚*¨more-respawn-anchors-forge|更多重生锚 (More Respawn Anchors) +werewolves-become-a-beast@werewolves|狼人 (Werewolves) +omnipotent-card@|万用卡牌* + +does-it-tick@ +public-gui-announcement@|公开GUI显示 (Public GUI Announcement) +wet-lava-sponge +ripples-of-the-past¨@ripples-of-the-past|Ripples of the Past - 最新版(包括公开测试版) + +cursor-mod@cursormod|自定义光标* +amplified-nether@|放大化下界* +oreberries-replanted@|矿莓重制版* + +eye-contact-prohibited|禁止眼神交流! (Eye contact prohibited) + +modular-assembly|模块化组装* +healer@ +calcium|钙* +from-the-shadows +l_ender-s-cataclysm@l_enders-cataclysm|灾变 (L_Ender 's Cataclysm) +brighter-block-light|亮光 (Brighter) +pick-up-notifier@|拾取提示*¨pick-up-notifier-fabric|拾取提示 (Pick Up Notifier) + +talkbubbles@ +servux@ +config-menus-forge@forge-config-screens +saplanting@|落苗生根* +login +edible-bugs +farsight¨farsight-fabric + +atlantis@|亚特兰蒂斯* +gaia-dimension +pwem@ +akisephilas-bosses + + +fluffys-farming +aquatic-odyssey-mod +vanilla-cookbook@vanillacookbook|原版烹饪书* +edible-nether-wart|可食用下界疣* +plasmo-voice@|Plasmo 语音* +armor-sound-tweak|盔甲音效调整* +hexerei@|魔法巫师* +morerefinedstorage@ +give-me-water-or-give-me-death +lost-and-found +better-fps-render-distance¨better-fps-render-distance-fabric +armor-chroma-for-fabric@|盔甲颜色显示Fabric版 (Armor Chroma for Fabric) +ore-reeds|矿石甘蔗* +connected-glass@ +blockui +storage-racks +Dung-Pipe +extra-armor|更多盔甲* +pig-poop +stupid-horse-stand-still +ceramic-bucket@|陶瓷桶* +durability101@ +ceramic-shears@|陶瓷剪刀* +torch-bandolier@|火把弹药袋* +rapid-leaf-decay@ +netherite-horse-armor-mod|下界合金马铠* +ambient-environment@ +glass-cutter@ +dicemc-tiered-armors +tetranomicon +more-observers|更多侦测器* +villagers-respawn@|村民重生* +hot-swappable-armor|热切换护甲 (Hot-Swappable Armor) +advancement-plaques@|进度牌匾*¨advancement-plaques-fabric|进度牌匾 (Advancement Plaques) + +minceraft-mod +alexs-delights|Alex乐事 (Alex's Delights) +better-bedrock-generator¨better-bedrock-generator-fabric +prehistoric-fauna@|史前生物* +better-conduit-placement@|更好的潮涌核心放置*¨better-conduit-placement-fabric|更好的潮涌核心放置 (Better Conduit Placement) +death-counter@death-counter-ichun|死亡计数器*¨death-counter-for-fabric|死亡计数器 (Death Counter) +dimension-stages@|维度阶段* +passive-dragon +i-want-to-die-at-home +morevanillaweapons@|更多原版武器 (MoreVanillaWeapons) +ore-tree-reborn|矿物树:重制 (Ore Tree:Reborn)¨ore-tree-reborn-fabric|矿物树:重制 (Ore Tree:Reborn) +player-tracking-compass@ + +tooltipfix@|信息提示修复 (ToolTipFix) +extended-noteblock-forge|音符盒扩展 (Extended Noteblock)¨extended-noteblock-fabric|音符盒扩展 (Extended Noteblock) +ore-prospecting-stick-forge|探矿之戒 (Rings Of Prospecting)¨ore-prospecting-stick-fabric|探矿之戒 (Rings Of Prospecting) +worldedit-express-forge¨worldedit-express-fabric +awesome-dungeon-edition-ocean-forge@awesome-dungeon-edition-ocean¨awesome-dungeon-edition-ocean-fabric +pistorder@ +escape-rope-pokemon-item-forge +awesome-flooring-forge@¨awesome-flooring-fabric@ +medievial-entity-forge@medieval-entity-forge|中世纪生物 (Medieval Entity)¨medievial-entity-fabric@medieval-entity-fabric|中世纪生物 (Medieval Entity) +upgraded-shulkers|更多潜影盒* + +bobby@|服务器区块缓存* +boosted-brightness@|亮度增强* +effective@¨effective-forge + +voidtotem@|虚空图腾 (Void Totem)¨voidtotem-fabric|虚空图腾 (Void Totem) +tool-leveling-plus@tool-leveling|工具升级 (Tool Leveling+)¨tool-leveling-plus-fabric|工具升级 (Tool Leveling+) +mythicmetals@|神话金属 (Mythic Metals) +creeper-firework@|烟花苦力怕* +second-chance@second-chance-forge¨second-chance-forge +promenade@ +london-underground@the-tube|伦敦地铁 (MTR London Underground Addon) +dynamiclights-reforged@sodium-dynamic-lights|钠/Embeddium:动态光源 (Sodium/Embeddium Dynamic Lights) +the-wild-mod@|荒野更新* +tuff-depth|凝灰岩深度* +minefantasy-reforged|我的幻想重铸版 (MineFantasy Reforged) + +framework¨framework-fabric + + +anointed-items@ +golden-age-combat@|黄金时代的战斗* +magnesium-extras|钠/Embeddium:附属 (Sodium/Embeddium Extras) - 全部¨@sodium-extras|钠/Embeddium:附属 (Sodium/Embeddium Extras) +chest-tracker@|箱子追踪* +advancementinfo@|进度信息展示 (AdvancementInfo) +animatica@ +mc-mods-dimension-height-increase|全维度建筑高度提升 (All Dimension Height Increase) +merchant-markers@|商人标记*¨merchant-markers-fabric|商人标记 (Merchant Markers) +loot-bag|战利品袋子* +miner-watcher|矿工监视者* +memento-mori-remember-death|人终有一死/记住死亡 (Memento Mori / Remember Death) +not-enough-gamerules@¨not-enough-gamerules-fabric +@jsonem|Json格式化实体模型 (Json Entity Models) +speedrunigt@ +archmagus +slimyboyos@ +fireplace-lib@¨fireplace-lib-forge +immersive-geology@|沉浸地质学* +wool-tweaks@|羊毛调整*¨wool-tweaks-fabric|羊毛调整 (Wool Tweaks) +tools-complement@ +adventtic +questionably-immersive +long-fall-boots +total-darkness +true-darkness@ +starlight-x-create +grand-economy +chinacraft2|华夏文明2 (ChinaCraft2) +interactic@ +fnars-roguelike-dungeons|冒险地牢-Fnar版 (Roguelike Dungeons -- Fnar's Edition) +playerex +data-attributes +hardcore-buoyance +gregtech-ce-unofficial@|格雷科技社区版:非官方版 (GregTech CE: Unofficial) +eggtab-fabric|独立刷怪蛋列表 (Egg Tab)¨eggtab-forge|独立刷怪蛋列表 (Egg Tab) +always-a-wither-skull@|必得凋灵骷髅头颅 (Always a Wither Skull)¨always-a-wither-skull-fabric|必得凋灵骷髅头颅 (Always a Wither Skull) +anvil-restoration@|铁砧修复*¨anvil-restoration-fabric|铁砧修复 (Anvil Restoration) +hide-hands@|隐藏主副手*¨hide-hands-fabric|隐藏主副手 (Hide Hands) +better-beacon-placement@|更好的信标放置*¨better-beacon-placement-fabric|更好的信标放置 (Better Beacon Placement) +dead-totems +functional-storage@|功能性存储* +the-wild-update|荒野更新 1.19 (The Wild Update 1.19) +archeology@|考古学 (CapsLock Archeology) + +trinkets-and-baubles@|饰品与小玩意 (Trinkets and Baubles) + +rope-ladders|绳梯* +skewers-updated|烤串更新版* +keep-my-soil-tilled@|保持肥沃*¨keep-my-soil-tilled-fabric|保持肥沃 (Keep My Soil Tilled) +double-doors@|双开门*¨double-doors-fabric|双开门 (Double Doors) +expanded-armor-enchanting@|盔甲附魔扩展* +expanded-weapon-enchanting@|武器附魔扩展* +expanded-axe-enchanting@|斧附魔扩展* +expanded-trident-enchanting@|三叉戟附魔扩展* +urns +pylons@ +on-soul-fire@ +wizard-staff +kambrik@ +additional-bars@additionalbars|更多的栏杆*¨additional-bars-fabric|更多的栏杆 (Additional Bars) +leap@ +cameraoverhaul@ +enchantment-id-extender@eide +creeper-overhaul@|苦力怕改革 / 苦力怕革新* +cool-elytra-roll@ +camera-overhaul-forge +blame¨blame-fabric +patboxs-banhammer@banhammer +terraformed-api-reforged +multiblocktweaker +good-ol-currency +macaws-bridges-atmospheric|Macaw 的桥梁:悠然一派附属 (Macaw's Bridges - Atmospheric) +leadvillagers +fabric-shield-lib@fabricshieldlib +frys-things-guns-and-more +quickbind|功能集成 (Quick Bind) +ompd|开放式模块化被动防御 (Open Modular Passive Defense) +basic-shields-fabric@ +borderless-mining@ +ledger@ +pet-owner@petowner +spartan-hud-baubles|斯巴达饰品栏HUD (Spartan HUD: Baubles) +mekanism-matter|通用机械:物质拓展* +inzhefop-core + + +legendary-tooltips@|传说提示框*¨legendary-tooltips-fabric|传说提示框 (Legendary Tooltips) +myrtrees + +tiny-redstone + +icarus@ +the-splash-milk@|喷溅牛奶 (Splash Milk) +fastbench-for-fabric|工作台性能优化Fabric版 (FastBench for Fabric) +mob-buckets-fabric|生物桶 (Mob Buckets) + + +enchantable +glass-doors|玻璃门* +glasscutter|玻璃切割器 (Glass Cutter) +upgradable-crystal-tools +no-dragon-cheese +glassware|玻璃制品* +milk-plus@milk_plus +modifiers|重铸* +customnpc-plus@|自定义NPC+ (CustomNPC+) +ingredient-extension-api@ + +wireless-networks +compass-manhunt@ +exlines-furniture@ +tinkers-archery|工匠箭术 (Tinkers' Archery) +designer-modeling|设计师建模* + +netherite-horse-armor-fabric|下界合金马铠 (Netherite Horse Armor) +netherite-elytra|下界合金鞘翅* + +more-tcon@moar-tcon|更多匠魂材料 (Moar TCon) +exlines-emerald-equipment@emerald-equipment +exlines-candy-mod +renamer|代号名称* + +the-herobrine-mod-1-7-10 +aquatic-armors +immersive-industry|沉浸工业* +lightmans-currency@¨lightmans-currency-fabric +hellfire-fireball-launcher|地狱火:火焰弹发射器 (Hellfire: Fireball Launcher)¨hellfire-fireball-launcher-fabric|地狱火:火焰弹发射器 (Hellfire: Fireball Launcher) +guild@ +endless-deep-space|无尽深空* - 已弃用¨@endless-deep-space|无尽深空 (Endless Deep Space) + +dynamic-trees-for-sakura|动态的树:樱附属 (Dynamic Trees for Sakura) +advanced-fishing + +bettertabs@ +classy-hats|时髦帽子* +bedbreakbegone@ +bq-multiblock-structure-integration@|更好的任务 - 多方块与结构扩展 (Better Questing - Multiblock and Structure Integration) +bqtweaker@ +hypnos@ +collision-damage@ +project-74246@doomlike-dungeons|毁灭地牢 (Doomlike Dungeons) +dynamic-trees-defiled-lands|动态的树:污秽之地附属 (Dynamic Trees - Defiled Lands) +xaero-map-addition@ +lambdacontrols@|Lambd 的控制优化 (LambdaControls) +ducky-mod +craftgr@|幻想乡电台 (CraftGR) +quartz +mc-mods-the-blocks +mc-modsthemodium +ato +just-enough-effect-descriptions-jeed@|JEI药水效果 (Just Enough Effect Descriptions) +hostile-neural-networks +mo-cakes|更多蛋糕 (Mo' Cake) +fishing-made-better|更好的钓鱼* +neon-craft-ultimate|霓虹灯艺2 (Neon Craft Ultimate/Neon Craft 2 Mod) +architects-dream|建筑师之梦 (Architect's Dream) +ignition-enderbags +correlated@ +enderbags +no-mob-spawning-on-trees|树枝树干不刷怪 (No Mob Spawning on Trees) +rf-lux@ + +@roughly-enough-characters + +easy-normal-and-magic-foods +tiefix@ +more-chat-history@morechathistory|更多聊天记录* +phosphor-reloaded|磷重制版* + +pigstep-backport +agadars-brewing-api + + +ae-shield|奕 秉甲* + +giant-player-boss|巨人玩家 Boss* +set-bonus@ +tntutils@ +giant-swords|巨剑* +terrablender@¨terrablender-fabric¨terrablender-neoforge +commandhelper|命令助手 (CommandHelper) +bilibili + +creatures@frikinzis-fauna +mcdw@|我的世界:地下城武器 (MC Dungeons Weapons) + +beta-creepers + +macaws-paintings@|Macaw的画 (Macaw's Paintings) +dyenamics +multi-piston +blood-magic@|血魔法* +resolutioncontrol@resolution-control-plus|分辨率控制 (Resolution Control/ResolutionControl+)¨resolution-control|分辨率控制 (Resolution Control/ResolutionControl+) +wdl|世界下载器 (World Downloader) + + +domum-ornamentum +methodicalmilking + +save-and-load-inventories@¨save-and-load-inventories-fabric +forge-config-api-port-fabric@forge-config-api-port +pams-cookables +end-metals +vitality +featured-servers +oldjavawarning@|旧Java警告 (OldJavaWarning) +mercurius +mc-mods-the-swords +pams-simple-recipes +bow-infinity-fix@|无限附魔修复* + +enchanting-infuser-forge@enchanting-infuser|附魔灌注台 (Enchanting Infuser) +menumobs|主菜单生物渲染 (MenuMobs) + +tiny-skeletons-forge@tiny-skeletons|小骷髅变种 (Tiny Skeletons)¨tiny-skeletons-fabric|小骷髅变种 (Tiny Skeletons) + +matter-overdrive-community-edition@moce|超能物质 (Matter Overdrive) +cavetweaks|洞穴调整 (CaveTweaks) +cosmetic-armor-fabric@cosmetic-armor|时装盔甲 (Cosmetic Armor) + + +crimson-chickens +drippy-loading-screen@|自定义游戏加载界面*¨drippy-loading-screen-fabric|自定义游戏加载界面 (Drippy Loading Screen) +extreme-sound-muffler@extreme_sound_muffler¨extreme-sound-muffler-fabric-official +dragonloot@|龙战利品 (DragonLoot) +wtfcore +ore-remover +betweenlands-redstone +more-peripherals@ +ageing-spawners@ +loot-extra|战利品表拓展 (LootExtra) +cloud-boots-mod@cloud-boots|云靴 (Cloud Boots) +better-compatibility-checker@ +fastfurnace-minus-replacement +harvest +craftpresence@ +stonecutter-recipe-tags@stonecutter_recipe_tags +customnpcsreborn|自定义NPC:重生 (Custom NPCs Reborn) + +brassamberbattletowers|BrassAmber 战斗高塔 (BrassAmber BattleTowers) +jags +sedna +fog-tweaker +open-elevator-fabric|Fabric版开放式电梯 (OpenElevator (Fabric)) + +nullscape-end-reborn@nullscape|空无之景 (Nullscape) +brutal-bosses-dungeon +guerrilla-vs-command-mod-high-difficulty-addition|游击队员vs突击队员 (Guerrilla vs Command) +super-tools-reloaded-reloaded|超级工具重置版重制版 (Super Tools Reloaded-Reloaded) +lychee@¨lychee-fabric +morepaths +extended-mushrooms@ +shear-madness +missing-pieces +hatchery +alexs-delight +creatures-and-beasts@|动物和野兽 (Creatures and Beasts) +dead-guys-deep-dark +towers-of-the-wild-reworked|旷野之息高塔:重制 (Towers of the Wild: Reworked) +towers-of-the-wild-reloaded|旷野之塔:重置 (Towers of the Wild: Reloaded) +bansoko|创可贴 (Bansoukou) + +inventory-backpack@inventory-backpack-mod + + +reinforced-shulker-boxes@|增强潜影盒* +fastopenlinksandfolders|快速打开链接和文件夹 (FastOpenLinksAndFolders) +reinforced-chests@|增强箱子* +biome-staff +dynamic-trees-quark@|动态的树:夸克附属 (Dynamic Trees - Quark) +radium-reforged@radium|镭* +backpackmod@ + +untamedwilds|不羁野性 (Untamed Wilds) +advancements-tracker@|进度追踪器概览 (Advancements Tracker and Overview) +no-null-processors + +ma-enchants|Ma 附魔* +bits-and-chisels@ +trading-post@|交易站*¨trading-post-fabric|交易站 (Trading Post) +phantasmic@ +furnus +permanent-light-generator@plg|恒久光发电机*¨permanent-light-generator-fabric|恒久光发电机 (Permanent Light Generator) + +immortuos-calyx +claim-chunk +dicemc-money-mod@money-sign-shops +client-command-aliases +interactive-corporea|交互多媒体* +just-another-auto-clicker + +better-sneak|更好的潜行* +crapping-copper|压缩升级铜* +botany-pots-ore-planting@|植物盆栽矿石种植* + +satin-api@ +easy-magic@|简易附魔台* +enlightend@|末地启明 (Enlightend/Enlightened End/Nourished End) +rubidium@|铷* +cultural-delights@|多元乐事* + +jer-integration|JER集成 (JER Integration) +just-enough-beacons|JEI信标* +windowed-fullscreen + +helpful-hitboxes-forge¨helpful-hitboxes-fabric +vein-mining@|连锁采集*¨vein-mining-fabric|连锁采集 (Vein Mining) +ars-creo@ +it-fell-from-the-sky + + + + + + + +lyonheart@ +genshin-12|原神12* +ae-additions-extra-cells-2-fork@ae-additions +silent-addons +ars-arsenal +gps-mod-stalker-mod +extended-armor-bars +atom-economy|基石-经济 (Atom-Economy) +just-enough-piglin-bartering|JEI猪灵以物易物* + +@aftersans53228-fabric-road|暗访谈的Fabric道路 (aftersans53228's fabric roads) +primal-magick@|原初魔法* +ore-creeper@|矿石苦力怕* +panthalassa|泛古洋* +stardew-armory|星露谷武器*¨stardew-armory-fabric|星露谷武器 (Stardew Armory) +no-more-nether-desert-edition +blaze-gear|烈焰装备* +@aier|反内能革命 (Anti-internal Energy Revolution) +rhodonite-tools-armour +more-minecarts +corn-delight@|玉米乐事*¨corn-delight-fabric@|玉米乐事 (Corn Delight) + + +blast-craft@blastcraft|防爆工艺 (Blastcraft) +zdgx@|mod自动更新 (zdgx-AutoUpdateMod) + + +ore-highlight|矿石发亮* +sodium-shadowy-path-blocks@|钠 · 土径阴影* + +polymer@ +elytra-bombing|鞘翅轰炸*¨elytra-bombing-fabric|鞘翅轰炸 (Elytra Bombing) +cuboiddroids-support-mod + + + +litematica-tool|投影工具* +frozen-up|千里冰封* +carpet-tis-addition@ + +more-banner-features@|更多旗帜功能* +horsestatsvanilla@|马匹状态 (Horse Stats Vanilla) +biome-id-extender +rereskillable-reborn +rereskillable-rereforked +tetra-pak +ars-magica-legacy@ +compressium +talking-villagers|会说话的村民* +artifality@ +boat-container@|箱船* +delogger +just-another-vanilla-addon-java|迫真原版增强 (Just Another Vanilla Addon) +spectrite-mod|彩虹 (Spectrite) +genshin-nature@|原神:自然* +power-utilities-remastered@power-utilities|能源转换重制* +create-gear-addon +gun-mod-tl + +energymeter@ +headindex@|头颅菜单 (Head Index) +quantum-generators@|量子发电机* +simply-quarries@|简易采石场* +lethal-peaceful + + +storage-drawers-crafting-recipe +enhanced-attack-indicator@|增强攻击提示器* +parasites-addon-overlast|寄生兽:末世扩展 (OverLast) +cancel-block-update@|取消方块更新* +franciscofunari@medieval-craft-(structures)|中世纪工艺 (Medieval Craft) +d3core +green-thumb-v1-2-03 +greenthumb +tfc-adventure|群峦冒险 (TFC+ Adventure) +just-zoom-forge@just-zoom +server-holograms@holograms|全息图 (Holograms) + +eidolons-hexblades|幻梦咒剑 (Eidolon's Hexblades) +monke-madness +put-ingot-down|把锭放在地上吧! (Put Ingot Down!) +torchtools +lottweaks +quests-additions-fabric|任务拓展 (Quests Additions)¨quests-additions|任务拓展* +custom-mob-spawner|自定义生物生成器* +rpg-hud@¨rpg-hud-fabric +the-wild-update-concept-mod + +sinocate@|肴馔 (SinoCate) +oreregen|再生矿石 (OreRegen) +eidolon_tweaker + +herodotusutils@herodotus-utils +platypuses +hostile-villages|敌对村庄* +throwability|投掷* +biomeinfo@|生物群系信息 (BiomeInfo)¨biomeinfo-fabric|生物群系信息 (BiomeInfo) +clickable-advancements|可点击的进度* +factory0-resources +epic-knights-armor-and-weapons@epic-knights-shields-armor-and-weapons|史诗骑士:盾牌,盔甲和武器 (Epic Knights: Shields, Armor and Weapons) +youre-an-expert-harry|你是个专家,哈利! (You're an Expert, Harry!) +dragon-mounts-3|龙骑士3* +viaforge@ +happy-trails|快乐小径* +naturesaura_tweaker +death-finder@|死亡溯源*¨death-finder-fabric|死亡溯源 (Death Finder) + +portable-craft|便携工艺* +@polypack_host +etched@ +caves-cliffs-backport-additions +cobblefordays@ +admin-shop@shop|官方商店* +vanillamagic|纯净魔法 (Vanilla Magic) +deep-mob-learning-simulacrum +oculus@ +simple-planes-tfc +mishang-urban-construction@|迷上城建* +@cursed-legacy-api +phi@ +ae2-utilities|AE2实用设备 (AE2 Utilities) + +epic-psi +missingmagic +enchanting-convergence +magical-psideas-model-replacer +psio + + + + + +copper-pot@|铜锅! (Copper Pot!) + + +viarewind +viabackwards +thaumic-isorropia +loading-manager@loadingmgr|更多加载信息* +psitools +psionic-upgrades +psionicolor@ +reskillable-psi-compat +zettai-psi +psicaster +tweakermore@ +legacy-display@ +the-backrooms +creatures-of-the-snow@creatures-from-the-snow-fabric|雪地里的生物! (Creatures From The Snow!)¨creatures-from-the-snow-forge|雪地里的生物! (Creatures From The Snow!) +collisions-lib@ +wooled-boots@|羊毛靴子* +zawa-evolved@|野生动物园:进化 (Zoo and Wild Animals: Evolved) +bongo@|宾果游戏* +impersonate@ +calemi-core@ccore + + +visual-workbench@|可视化工作台*¨visual-workbench-fabric|可视化工作台 (Visual Workbench) +stylish-effects@¨stylish-effects-fabric +death-compass-forge|死亡指南针 (Death Compass)¨death-compass-fabric|死亡指南针 (Death Compass) +portable-stonecutter|便携式切石机* + +enchanted-book-redesign@¨enchanted-book-redesign-fabric +quick-hotbar +modular-augment +lumberjack +better-mods-button@|更好的模组按钮* + +advancement-frames@ + +dynmapforge +spellbind@|物品魔法* + +bumpkinbatch +beekeeper|养蜂人* +some-assembly-required@ +ladylucs-critters-mod +@modmenu-beta + +better-signs +@macula +@howmanyitems +@howmanyitems-fabric + +@glass-config-api +@translated-legacy + + + +create-irrigation +delete-worlds-to-trash-forge@delete-worlds-to-trash¨delete-worlds-to-trash-fabric + + +simple-magnets@|简易磁铁* +guns-without-roses@|枪炮“没”瑰* +buddycards-expansions|巴迪卡牌扩展* +zettai-ars +cant-sleep-clowns-will-eat-me@|夜不能寐 (Can't Sleep Clowns Will Eat Me) +colony-cards|殖民地卡牌* +autoharvest|自动收获 (AutoHarvest) +realistic-block-physics@ +domestication-innovation@|驯养革新* +snuffles@|魄罗* +flan-forge@flan¨flan +awesome-dungeon-the-end-forge@awesome-dungeon-the-end¨awesome-dungeon-the-end-fabric +tehnuts-torcherino +library-ferret-forge@library-ferret¨library-ferret-fabric¨library-ferret-neoforge +awesome-dungeon-nether-forge@awesome-dungeon-nether¨awesome-dungeon-nether-fabric +ae2-extended-life|应用能源非官方延续版 (AE2 Unofficial Extended Life) + +refined-cooking@|精致厨房* +jade-addons@jade-addons-forge¨jade-addons-fabric@ +feature-nbt-deadlock-be-gone@ + +real-infinity-bow-allow-inf-mending|真正的无限弓 (Real Infinity Bow) +drink-it-forge|喝! (Drink It!) +foxlib +tails +howling-moon-rebooted-forge¨howling-moon-rebooted-fabric + + +@dustrial-decor +furnish@furnish-furniture +iammusicplayer@iam-music-player + +pirates|海盗* +comics-bubbles-chat@ +fabric-extended-armor-bars-forked +eating-animation-forge@eating-animations|进食动画 (Eating Animation)¨eating-animation-fabric@eating-animation|进食动画 (Eating Animation) +waterdripsound@dripsounds¨dripsounds@waterdripsound +better-horse-hud|更好的骑马 HUD* +thermopolium|汤饮铺* + + +orderly-fabric-2-0 + +entity-texture-features-fabric@entitytexturefeatures|实体纹理特性 (Entity Texture Features) +sculk-plus +creeper-confetti-fabric|烟花苦力怕Fabric版* +double-jump-attribute@ +overweight-farming@ +healthcare@ +betterloadingscreen|加载画面改良 (Better Loading Screen) +fabric-title-changer@ +window-title-changer + +@betterlight + + +@bushyleaves +robins-ruby-mod + + +just-needed@justneeded¨just-needed-fabric +nodami-remake|伤害免疫机制移除重制版 (NoDamIRemake) +had-enough-items@|HEI物品管理器* +worldinfo +@bang +block-helper@ +@class-loader-fixer +@font-fixer +gregicprobe + +travelers-index + +dimension-data-fix|维度数据修复* +gtce-bees|GTCE 蜜蜂 (GTCE Bees) + + +armory-expansion-bits-and-pieces +electrostatic-tinkers-toys@ +banhammer +slabgen +potioncraft +atlas-lib@ +blood-smeltery@ +tinkers-memes +tinkers-golems-addon +tinkers-addons-fork +reagenchant + +sim-u|模拟城市/模拟大都市 + +thorium@|钍* +creative-one-punch@ +radon@|氡* +ars-omega +game-stages-conditions +tinkers-construct-tool-leveling-with-random +odd-water-mobs +glowsquids-begone@ +theundead@the-undead-revamped|祸乱亡灵 (THE UNDEAD REVAMPED) +framedblocks@|框架方块 (FramedBlocks) +nekos-enchanted-books@ +istc|我说了算 (I Said The Calculation) + +dracovita-farm-life +no-enchant-cap@ + +artisan-automation|工匠自动化* +enchanted-wolves + +rain-growth@rain +scape-and-run-monstress|逃逸:魔物娘 (Scape and Run: Monstress) +raised@ +resetchunks@ + + +moreblocksforyou +trident-return +bettertridentreturn +multibeds@¨multibeds-fabric +enhanced-armaments-reload|增强装备重制版* +entangled@ + +createplus@ +custom-fluid-mixin@ +slender-reimagined +doors-by-ichun +slender-man-mod¨the-original-slenderman-mod-working|Slender Man - 他人的非官方重上传 +cookielicious|曲奇佳味* +the-forbidden|禁忌者* +memory-usage-screen@ +evergreenhud@ +nuit@ +@level-border +@fvt +blue_skies_tcon +tdv-tweaks + +picture-in-picture-pip +guilt-trip +parcool@|跑酷! (ParCool!) +legacy-mc-kotlin +minimepets +ugly-scoreboard-fix@ + + + +railcrafttweaker +pig-grinder +photoreal +keygrip-mocap-mod + +attachable-grinder +hat-stand +chunk-copy-fabric@ +inventory-home|回归箱* +nether-hexed-kingdom + +@paimonfoodreborn|应急食品:重制 (PaimonFood:Reborn) +talking-ben-mod +in-backpack-eat@inbackpackeat|背包内食用 (In-backpack Eat) +with-thursday|相约星期四 (WithThursday!) +smooth-swapping@|平滑转移*¨smooth-swapping-forge@smooth-swapping-forge-updated|平滑转移 (Smooth Swapping) +tinkering-with-blood-magic +tinker-toolcasts +thermal-tinkering +deuf-duplicate-entity-uuid-fix +corundum-meadows +millenaire-extended-inuits +mct-smeltery-io +opencomputers-drivers-for-tinkers-construct +oedldoedl-construct +millenaire-extended-byzantine +millenaire-extended-normans +millenaire-extended-indians +millenaire-extended-maya +oedldoedl-core +oedldoedl-resources +oedldoedl-gear +disguiseheads@ +simple-tcon +enchanted-tooltips@ +stackablepotions-forge@stackablepotions¨stackablepotions +mobifier¨mobifier-fabric +art-of-forging-a-tetra-addon|锻造之艺 (Art of Forging) +harder-staged-difficulty +material-changer +tree-harvester@¨tree-harvester-fabric +itemfx +mekanism-ce@mekanism-community-edition|通用机械:社区版 (Mekanism Community Edition)¨mekanism-1-12-2-ce|通用机械:社区版 (Mekanism Community Edition) + +property-modifier +grimoire-of-tetra +prehistoric-delight-by-nocube|史前乐事 (Prehistoric Delight) + +simple-stations +ars-elemental-elemental-spell-foci|元素魔艺 (Ars Elemental) +too-many-glyphs +create-cafe@|机械动力:咖啡馆* +@worldbordercolor +ic2-rpg|工业RPG (IC2 RPG) +drop-the-meat@dropthemeat|肉多多 (Drop the Meat) +better-invisibility|更好的隐身* +tweakerplus@ +autorun-fabric@autorun +fpv-drone +campfire-backport@ +skip-transitions@ +just-load@ +cheese-dragon +boatjump@ + +torched +nyfs-quivers@|Nyf的箭袋 (Nyf's Quivers) +party-parrots@¨party-parrots-fabric +patina-pipeworks|古铜管道* +brewevolution|酿造进化🍺 (Brewevolution 🍺) +devil-fruits|恶魔果实* + +trail-mix +multiplayer-server-pause-forge@multiplayer-server-pause|多人服务器暂停 (Multiplayer Server Pause)¨multiplayer-server-pause-fabric|多人服务器暂停 (Multiplayer Server Pause) +noshelter-reborn|无庇护所:重生 (NoShelter Reborn) +initial-spawn-dimension +the-one-probe-fabric +gehenna-super-spooky-nether-overhaul-for-forge +draconicminus +hygiene +worldeditcui-forge-edition-3 +external-view-reload +fluid-drawers-legacy|储液抽屉:遗产* +my-server-is-compatible@ +medieval-siege-machines@|中世纪攻城机器* +leapoffaith-forge|信仰之跃 (Leap of Faith) +top-plus +refined-storage-fluxified@ +quit-confirm +compressedcreativity@|压缩动力 (Compressed Creativity) +applied-mekanistics@|应用能源:通用机械附属* +craftdumper +immersive-weathering-fabric@immersive-weathering|沉浸式风化 (Immersive Weathering)¨immersive-weathering-forge|沉浸式风化 (Immersive Weathering) +replay-mod-for-forge +bigtrees +absolutely-not-a-zoom-mod@anazm|绝对不是一个缩放模组* +glymworld-lush-caves +colored-crafting-stations +harvest-scythes +croptosis +weeping-angels-mod@weeping-angels¨the-lonely-assassins +hardcore-item-stages +game-stages-viewer +mpm-lotr|更多玩家模型:魔戒兼容 (MPM LOTR) +guard-villagers-fabric@guard-villagers-(fabricquilt)|警卫村民Fabric版 (Guard Villagers (Fabric)) + +item-highlighter@|物品高亮*¨item-highlighter-fabric|物品高亮 (Item Highlighter) + +environmental-armor@¨origins-environmental-armor-1-18-1-port + +health-levels@ +the-comfort-zone@ + +mekatweaker +smithing-in-the-90s +embellished-enchanting + +better-snowball-fight-fabric|更好的打雪仗 (Better Snowball Fight) +onastick-forge@onastick¨onastick +tradernpcs +more-pads|更多Pad* +texture-dump +spartan-weaponry-ice-and-fire@|斯巴达的武器:冰火传说 (Spartan Weaponry: Ice and Fire) +hefty-crops@ +@strangefuelsmod|奇奇怪怪的燃料 (Strange Fuels Mod) +custom-player-models@|自定义玩家模型 (Customizable Player Models)¨custom-player-models-fabric|自定义玩家模型 (Customizable Player Models) +extrachampions|强敌扩充 (ExtraChampions) + + + +another-origins-mod +just-another-void-dimension +player-weight-mod|玩家重量* +chunk-loaders@|区块加载器* +tinkerstages +@oneboxatatime +eccentric-tome@|怪奇宝典*¨eccentric-tome-updated|怪奇宝典 (Eccentric Tome) +arnicalib + +gregicality-multiblocks@ +@forcecloseworldloadingscreen|强制关闭加载屏幕 (kennytv's epic force close loading screen mod for fabric) +the-box-trot@ +better-biome-blend@|更好的生物群系过渡* +forever-enough-items|FEI物品管理器* +chess|象棋* - 此已不受支持¨@chinesechess|象棋 (Chess) - >=3.0 +immersive-fx +ydms-weapon-master@weaponmaster|YDM的武器大师 (YDM's Weapon Master) +galacticrafttweaker +moreleads@|拴绳增强 (More Leads) + +simple-discord-rpc@ + +excore +messmod@ +log4j2-jndi-exploit-fix +woodcutter¨woodcutter-forge +origins-classes-forge@|起源:职业非官方Forge版 (Origins: Classes (Forge)) +tool-stats@ +thatched +fumo-mod +basement-origins +no-weak-attack +bettas|搏鱼* +baby-fat|婴儿肥* +quickplant|顷刻吐芽 (QuickPlant)¨quickplant-fabric|顷刻吐芽 (QuickPlant) +infinite-dungeons +wpo-addon-mod +just-the-binding-of-isaac-pills +pendant-of-life +the-binding-of-isaac-tears-mod +humbling-bundle@|慈善捆绑包* +grindstone-sharper-tools@¨grindstone-sharper-tools-fabric +nutritious-milk@¨nutritious-milk-fabric|Nutritious Milk - 文件 +extract-poison@¨extract-poison-fabric +zombie-villagers-from-spawner@¨zombie-villagers-from-spawner-fabric +vine-climber +healing-soup@¨healing-soup-fabric +idas@|地牢建筑统合 (Integrated Dungeons and Structures) +mob-sunscreen@ +@dontstarvereborn|不要饿死:重生 (Don't Starve: Reborn) +decorative-winter +looot@ + +block-event-separator@ +no-damage-immunity-reload|伤害免疫机制移除重制版* +sheve +chromatic-currents@ +dropfullcarts +are-you-blind +alwayseat-reload|吃不停重制版 (AlwaysEat Reload) + +tps-hud-fabric + +orcz +sandwichable@ +@shelve-refabricated +mod-erate-loading-screen@moderate-loading-screen +shrink_@shrink +cable-tiers@ +jumbo-furnace@ +no-villager-death-messages@ +tank-null +trajans-tanks-forge¨trajans-tanks-fabric-wip +colds-easy-paxel-lite + +smooth-chunk-save|平滑区块保存* +rigoranthus-emortis +jei-utilities|JEI实用设备 (JEI Utilities) +plummet +stackone-mod|禁止堆叠 (StackOne) +spectrum@|光谱世界* +kitteh6660s-morecraft +angel-ring|天使指环* +debugify@ +nomowanderer@ +mc-modsthecompressed +cave-enhancements@ +creative-apiary|创造蜂场* +creative-crafter@ +mcmod-search-reborn|MC百科资料搜索-重生 (MCMOD Search Reborn) +proxy-server@ +multithreaded-noise +spelling-table-mod|拼写台* + +advancedchatcore@AdvancedChatCore +dirt-deco +multiblocked +arcanus-legacy@ +armor-weight +mc-mods-the-tweaks +runelic@ +alexs-cloud-storage@|云存储 (Cloud Storage) +visuality@|可视性* +ecologics@|丰富的生态* +mob-scarecrows +trolls-community +g4mespeed@ +ogres-community +goblin-community +kobolds-community +mutant-villager +pick-your-poison +illager-expansion-fabric¨@illager-expansion-forked|Illager Expansion - 由ZekeSmith创建的备份¨@illager-expansion-polymer|Illager Expansion - 现,由Patbox制作¨@illager-expansion-rematch|Illager Expansion - Safro 制作的修复版 +immersive-armors@|沉浸式盔甲* +seeds@ +unusual-drill +frosted-friends@ +hover-pets|飘浮宠物* +ic2-patcher +useless-sword@|朴华之剑* +jei-professions +atm-additions +extra-tags|额外标签* +advancedchatlog@AdvancedChatLog +crafting-station|合成站* +sons-of-sins@|七罪之子* +advancedchathud@AdvancedChatHUD +fuzes-relics +chirpys-wildlife@wildlife-fabric +megaparrot@ +nourish +village-box|村庄盒子* +waila-stages +steves-vanilla + +duckling@ +wandering-bag@wandering-bags +friends-and-foes-forge@|同伴与对手 (Friends & Foes)¨friends-and-foes@|同伴与对手 (Friends & Foes) +dynamic-trees-the-betweenlands|动态的树:交错次元附属 (Dynamic Trees - The Betweenlands) + +pyrologer-and-friends +tree-hollows@|树洞* +solar-apocalypse-refabricated@solar-apocalypse¨@solar-apocalypse-reforged +icommonlib@icommon +chunky-pregenerator@chunky|预生成区块 (Chunky)¨chunky-pregenerator-forge|预生成区块 (Chunky) +beast-slayer|上古凶灵/远古野兽 (Ancient Beasts/Beast Slayer) +easyauth@ +depth@ +slimy-stuff@ +netheriteroad|下界之路 (Netherite Road) +organics +qsl@ +kaliastyle|卡利亚式附魔 (CarianStyle) + +wmitaf@ +depth-meter|深度计* +omni-hopper@omnihopper +jumpy-boats@ + +carpetclient@ + +dynamic-trees-vampirism|动态的树:吸血鬼附属 (Dynamic Trees - Vampirism) +transcend|超越* + +connectible-chains@connectiblechains¨connectible-chains-forge + +birds-nests-fabric|鸟巢 Fabric 版 (Birds Nests (Fabric)) +hot-or-not-tfc +eye-of-dragons +paperdoll@|纸娃娃 (PaperDoll) +little-logistics@ +show-me-what-you-got@ +herdspanic@ +extrasounds@ +brooms +the-stormlight-archive-mod|飓光志* +extrae +projecte-integration@|等价兼容 (ProjectE Integration) +mekajs +antique-dragons@ +badpackets@ + +undead-army +ironagefurniture +minekeamod +aeble +trident-mod|三叉戟 (Trident) +custom-professions@custom-villager-professions|自定义村民职业 (Custom Villager Professions)¨custom-villager-professions-fabric|自定义村民职业 (Custom Villager Professions) + +nextspring|化作春泥更护花 (NextSpring)¨nextspring-fabric|化作春泥更护花 (NextSpring) +psionic-utilities@psiutils +lucent@ +togglesneak +iron-apples +actually-additions-fluxified@ +dank-storage¨dank-storage-fabric +pixelgamewizards-banded-torches +dynamic-trees-byg|动态的树:你将去的生物群系附属 (Dynamic Trees - Oh The Biomes You'll Go) + +comfort-magic +colored-lights-fabric +biomes-far-away +better-runtime-resource-pack@brrp|更好的运行时资源包* +ends-delight@|末地乐事 (End's Delight) +natures-starlight +mc-modsoygery@alloygery +custom-game-rules +lava-walker@lavawalker +pretty-pipes|更好的管道* +@death-flashback|死亡回溯 (Death Flashback) +victorymod +cryptic-assets-pack +dynamicregistries@ +among-us-mobs +among-us|在我们之中* +universal-ores-fabric@universal_ores + +project-copper +pirates-and-looters-mod +@mudrock|泥岩 (Mudrock) +itemchat + +resident-evil-8-mod@resident-evil-84|生化危机8 (Resident Evil 8) +solar-forge +colored-allays|染色悦灵* + +phantasm@ends-phantasm +emerald-craft-mod@emerald-craft|绿宝石工艺* +roughly-enough-professions-rep@|REI工作方块 (Roughly Enough Professions) +sophisticated-core@|精妙核心* +edibles@¨edibles-fabric +reach-fix@ +lootjs-forge@lootjs +chat-sounds@chatsounds +advancement-screenshot@¨advancement-screenshot-fabric +mc-mods-loot-drops@all-loot-drops +disc-jockey@ +better-taskbar@|更好的任务栏* +storage-network + + +snr-more-metal +gate-of-babylon|王之财宝 (Gate of Babylon) + +evocation +the-illusioners-cabin +gw-pillager-outpost +mercs-and-menaces +illage-and-spillage +more-illagers +probably-chests +illager-plushies¨illager-plushies-fabric +pillageplunder +extended-illagers-mod +midnightcontrols@ +wonderful-enchantments@majruszs-enchantments +a-lot-of-useless-stuff +lankaster-origins@lankasters-origins + + +priority-target|优先目标* +advanced-botany|高级植物学* +charred +incorporeal-3@|幻想多媒体3* + + +oxygen|氧* +immersive-combat@|沉浸式战斗* +@essentialclient +mystical-index@ +combat-commons +corail-woodcutter + +nolocalizationconflict|本地化冲突消除 (NoLocalizationConflict) +enhanced-celestials-mobifier-integration¨enhanced-celestials-mobifier-integration-fabric +twilightdecor +midas-hunger-fabric@midas-hunger +firesafety|安全用火 (FireSafety) +pretty-pistons +more-beautiful-trapdoors@ +project-expansion@ +the-corners@ +deep-mob-learning-reforged|深度怪物学习:重铸 (Deep Mob Learning: Reforged) +zenith@ +extended-drawers@ +equippable-utilities@utilities +never-enough-currency-2@never-enough-currency-2-(forge)|货币多多2*¨never-enough-currency-fabric|货币多多2 (Never Enough Currency 2) +quartz-chests|石英箱子* +frozen-delight|冰封乐事* + +clean-creative-mod +this-rocks@|这就是石粒! (This Rocks!)¨this-rocks-forge@|这就是石粒! (This Rocks!) +motschens-puddles@puddles +dense-ores-reborn|致密矿石:重生* + +tfctreatedwood|群峦·防腐木 (TFC Treated Wood) +retro64¨retro64-fabric +double-hotbar@|双重快捷栏* +lavatech|熔岩科技 (Lava Tech) +pineapple-psychic@|凤梨通灵术* +fragile-torches +@time-changer +come-closer +creeper-chain-reaction +tiffitlib +sanity + +dynamic-trees-the-aether-legacy@dynamic-trees-aether|动态的树:天境附属 (Dynamic Trees - The Aether Legacy) +dynamic-trees-cuisine|动态的树:料理工艺附属 (Dynamic Trees - Cuisine) +ancient-classes +bigger-stacks@biggerstacks +silence@|快速静音 (Silence!) +dynamic-trees-extra-utilities-2|动态的树:更多实用设备2附属 (Dynamic Trees - Extra Utilities 2) +platforms@¨platforms-fabric +easierchests@|简便箱子 (EasierChests) +crackers-wither-storm-mod@|Cracker的凋灵风暴 (Cracker's Wither Storm Mod) +ore-canes-mod +spartan-defiled +mcmtfabricce@mcmtce|Minecraft多线程增强Mod兼容性增强分支 (Minecraft Multi-Threading Mod Fabric Port Compatibility Enhancement) +dynamic-trees-roots|动态的树:根源魔法附属* +dynamic-trees-voyage|动态的树:Voyage 附属 (Dynamic Trees - Voyage) +mystical-biomes + +forgero@ +disenchantingforge¨disenchantingfabric +redstone-pen@redstonepen|红石笔* +ae2-things-forge@ae2things¨ae2things +avaritia-endless|无尽贪婪·伪* +dynamic-trees-jurassicraft|动态的树:侏罗纪时代附属 (Dynamic Trees - JurassiCraft) +dynamic-trees-natures-aura|动态的树:自然灵气附属 (Dynamic Trees - Nature's Aura) +dynamictreesplus@|动态的树:拓展 (Dynamic Trees Plus) +dynamic-trees-forbidden-arcanus|动态的树:禁忌与奥秘附属 (Dynamic Trees - Forbidden And Arcanus) +dynamic-trees-terraforged|动态的树:TerraForged 附属 (Dynamic Trees - TerraForged) +dynamic-trees-corvus|动态的树:Corvus 附属 (Dynamic Trees - Corvus) +dynamic-trees-mystical-biomes|动态的树:Mystical Biomes 附属 (Dynamic Trees - Mystical Biomes) +corvus +goat-horns-copper-horns|山羊角与铜制号角 (Goat Horns & Copper Horns) +mystical-powers + +damp|受潮* +wooden-bucket@|木桶* +compressed-barrels@compressed_barrels|压缩木桶* + +advanced-netherite@|高级下界合金*¨advanced-netherite-fabric|高级下界合金 (Advanced Netherite) +re-avaritia@|无尽贪婪:重生 (Re:Avaritia) +simply-conveyors-more|简易传送带 (Simply Conveyors & More) +porting-lib@porting_lib +expanded-delight@|扩充乐事* +spell-bundle +nightmareesm +simply-no-shading@ +hexcasting@hex-casting|咒法学 (Hex Casting) +paucal@ +uneffectual@ +loot +crafting-dead-immerse|行尸走肉:沉浸 (Crafting Dead: Immerse) + +extended-clouds@ +distinct-damage-descriptions@ +technicalities-lib +fantasys-furniture@fantasy-furniture|Fantasy的家具 (Fantasy's Furniture) +touhou-spell-card-additional|东方符卡附加包 (Touhou Spell Card Additional Pack) +registrator +apexcore@ +magiclib@|魔法类库 (MagicLib) - 正式版¨magiclib-dev|魔法类库 (MagicLib) - 开发版¨@magiclib-dev|魔法类库 (MagicLib) - 测试版 +cull-less-leaves@|更好的树叶渲染优化* +@ex-stellae|繁星之凝 (Ex Stellae) +with-craft|手工艺 (With Crafts) +fluidconverters|流体转化器 (FluidConverters) +multiblock-stages + +metallurgylegend|冶金传奇 (Metallurgy Legend) +waterskin +realism-thirst +dungeons-libraries + +@fabricated-forge +raknetify@ +vmp-fabric@¨vmp-forge@ +flotage@|漂浮物* +dynamic-trees-for-hungteens-plants-vs-zombies-mod|动态的树:HungTeen的植物大战僵尸附属 (Dynamic Trees for PVZ) +antidrop@|防丢 (AntiDrop) +elemental-items + +onekeyminer@|一键矿工 (OneKeyMiner) +boathud@ +ninjaxxs-needs +pixelmon-gui-blocks + +more-mekanism-processing@ +item-banning@ +probejs@ +impaled@|更多三叉戟 (Impaled🔱) +laserio +villager-tools@ + +mcsa +no-resource-pack-warnings@ +take-it-slow@ +slime-mimic@slime-mimic-mod + + + +ldlib@ +shimmer@shimmer!|微光* +ducts +@baguette + +nosiphus-furniture-mod +tf2-engineer-buildings-mod +kubejs-botania +advancements-enlarger +better-muffling|更好的消音器* +lightest-lamps@¨lightest-lamps-fabric +bigbuckets|大铁桶 (Big Buckets)¨bigbuckets-fabric|大铁桶 (Big Buckets) +dimstorage@|维度存储 (DimStorage) +spawner-imbuer@ + +unnamed-delight|无名乐事* + +monsters-girls-mushroom-update +ftb-tutorial-mod-forge +mc-terrain-editor +extra-gems@extragems|额外的宝石 (ExtraGems) +various-world@ +better-impaling-forge@|更好的穿刺Forge版* +bucketlib@ +aquatic-torches@|水下火把* +better-sponges|更好的海绵* +easyexcavate +wooden-shears@|木剪刀* +brick-furnace@|砖熔炉* +brick-hopper@|砖漏斗* +human-companions +odysseyhud +colorblindness@ +aether-addon +moonstonemod@moonstone|月之石 (MoonStone)¨@moonfabric|月之石 (MoonStone) + +server-redirect|服务器重定向* +city-blocks|城市方块* +useful-hats@|有用的帽子* + +modern-splash@|高版本加载界面* +babel +cultural-treasures-paintings|文化瑰宝 - 画作与乐曲 (Cultural Treasures - Paintings and Music) +kitchen-karrot@|胡萝卜厨房* +servercore@ +ivan-carpet-addition@ +food-funk +wumpleutil +twilight-delight@twilightdelight|暮色乐事* +recruits@villager-recruits +the-true-backrooms +webstreamer@ +op-items-tab +thaumisc|神秘杂项学* + + +treechop@|HT 的砍树 (HT's TreeChop) +idwtialsimmoedm@ +entity-collision-fps-fix@¨entity-collision-fps-fix-fabric +hollowwoods + +dynamic-crosshair@dynamiccrosshair|动态准星* +raiders +better-animals-plus-plus +block-overlay-fix +mini-effects@¨mini-effects-fabric +nature-overhaul +ae2-fluid-crafting-rework@ae2-fluid-crafting|AE2流体合成套件重置 (AE2 Fluid Crafting Rework) + + +moreculling@ +better-village-forge@better-village|更好的村庄 (Better Villages)¨better-village-fabric|更好的村庄 (Better Villages)¨better-village-neoforge|更好的村庄 (Better Villages) +trinkets-curios-theme@ +banilla-claws@¨banilla-claws-forge@banilla-claws-neoforge + +transparent-cosmetics@ +emerald-geodes@more-geodes|更多晶洞 (More Geodes / More Geodes Reforged)¨more-geodes-reforged@|更多晶洞 (More Geodes / More Geodes Reforged) +right-click-get-crops@ +oh-my-gourd@ +better-block-sounds@bbs + +v0ids-smart-backpacks|V0id 的智能背包 (V0id's Smart Backpacks) + +winterly@|银装素裹* +forgetmechunk@¨forgetmechunk-forge +@moremusic + +better-f1|更好的F1* +removehudbutnothand +tool-part-stages + +iron-backpacks-redone|特殊背包重做版* +b0bgarys-biome-remover-v-1-0-0-1|B0bGary的生物群系禁用器 (B0bGary's Biome Remover) +dualwielding@|双持 (DualWielding) +malum-quilt@ +memoryleakfix|内存泄漏修复 (Memory Leak Fix) - 已停止支持¨@memoryleakfix|内存泄漏修复 (Memory Leak Fix) +@axolotlviewer +@compact-chat|紧凑聊天 (Compact Chat) +language-reload@ + + +@beer +sound-categories@ +@unsuspicious-stew%22 +preventer@ +@wpit +starflight-innovation +powah-rearchitected@powah +@mouserate-framerate +pickup-notifications@ +@practical-barrels +better-rocks +horse-combat-controls@ +libgui +simply-houses@ +yungs-better-desert-temples@|YUNG 的沙漠神殿优化 (YUNG's Better Desert Temples)¨yungs-better-desert-temples-fabric|YUNG 的沙漠神殿优化 (YUNG's Better Desert Temples)¨yungs-better-desert-temples-neoforge|YUNG 的沙漠神殿优化 (YUNG's Better Desert Temples) +modern-dynamics@|现代动力学* +doggo-mod@ +tan-huge-trees@tans-huge-trees +@wiangdtbisadtn|草我本来不想这么做的但是我这么做了啊啊啊啊啊啊啊啊啊啊啊啊啊啊 (Wait I Am Not Gonna Do This But I Somehow Accidentally Did This Nooooooooooooooo) +yungs-better-witch-huts@|YUNG 的沼泽小屋优化 (YUNG's Better Witch Huts)¨yungs-better-witch-huts-fabric|YUNG 的沼泽小屋优化 (YUNG's Better Witch Huts)¨yungs-better-witch-huts-neoforge|YUNG 的沼泽小屋优化 (YUNG's Better Witch Huts) +panorama-creator|全景图创建器* +ui-input-undo-fabric@¨ui-input-undo-forge@ +paimeng|应急食物 (PaiMeng) +nyfs-quivers-expanded + +zoomify@ +golemania@ +vulkanmod@ +sledgehammer +quilt-loading-screen|Quilt 加载画面* - 不再更新¨@quilt-loading-screen|Quilt 加载画面 (Quilt Loading Screen) +amethyst-imbuement@|紫晶魔艺* +emi@ +nuclear-contraptions +fire-crafting@firecrafting|烈焰配方* +tooltiptweaks@|提示框微调 (Tooltip Tweaks) + +more-babies@ +@save-my-bed +data-reload@ +winver@ +armor-visibility@ + +the-chicken-came-first|先有鸡* + +hardcore-dungeons +block-relocation-forge¨block-relocation +norecipebook-fabric@norecipebook|没有配方书Fabric版 (NoRecipeBook (Fabric)) +@sort +fpsdisplay@ +@where-items-owo +microdurability@ +indicatia@ +fishy-delight-a-farmers-delight-add-on +simple-delights|简单乐事* +color-me-outlines@|为轮廓上色* +nbttooltips@ + +upstream¨upstream-fabric +astemirs-fireflies + +ender-crop@|末影作物* +modupdater +fivehead@5head + +attained-drops|可种植掉落物* +attained-drops-2|可种植掉落物 2* + +auth-me@ +refinedcreativeinventory@|创造模式物品栏重制 (RefinedCreativeInventory) + +runesword +jcm@|常磐装饰 (Joban Client Mod) +autopackager +dynamx@ +mob-cards +mavm@ +@waxednotwaxed +hidden-names@|隐藏名称* +doph@|远程命中提示 (Ding On Projectile Hit) +keybinds@ +hat-list@hatlist +nmuk@ +raven-brews-core@ +raven-coffee@raven-coffee-mod|Raven 咖啡* +cqc +geode +realistic-spiders|真实的蜘蛛* +@timedisplay|时间显示 (Time Display) +biome-particle-weather@biome_particle_weather +ftb-backups-2|FTB备份2 (FTB Backups 2) +darkkore@ + + +illagers-wear-armor@ +hudium@ +ocean-world@|海洋的世界* +cobblegen@ +zombie-extreme +modularmovements|模块化动作 (Modular Movements) +uncle-js +wither-bones|凋灵之骨* +sleep-warp@ +diagonal-fences@ +jumpy-boats-fabric|跳跃的船(Fabric/Quilt) (Jumpy Boats(Fabric/Quilt)) +dyeable-redstone-signal@|染色红石信号* +velocity-based-damage +no-telemetry@ +@fullbright + +create-chromatic-return|机械动力:异彩化合物 (Create: Chromatic Return) +coffee-spawner +timber-mod@timber-mod-by-mycf¨@timber-by-mycf-(server-side) +sophisticated-storage@|精妙存储* +advanced-lootable-weapons +what-the-bucket@ +quickhomes +real-time-clock +tardim@ + + +luckytnt@lucky-tnt-mod¨lucky-tnt-mod-archive|Lucky TNT - 的愚人节特殊 +gamma-utils@|伽玛工具* +pickle-tweaks@ +dps-chaoscraft@ +@cc-polymer +moyai@ +mega-meteors-mod +gravity-generator|重力发电机 (GravityGenerator) +mcmouser@ +mixinbootstraplegacy +freecam + +animationrecorder|动图记录 (AnimationRecorder) +ingame-biome-map-exporter|群系地图一键导出 (Ingame Biome Map) +fishing-overhaul@fishingoverhaul +kronhud¨@kronhud|KronHUD - 不全 +shared-ender-chest|共享末影箱* +no-beacon-beams|无信标光柱* +farmers-respite|农夫暇事 (Farmer's Respite) +fabricae-ex-nihilo@ +crafting-mania +loot-goblins@|战利品哥布林* +skylib@ +dt3|不要饿死3 (DontStarve3) - 暂停更新¨@dt3|不要饿死3 (DontStarve3) +tbscclick +modern-elevators-and-escalators@|现代电梯与扶梯 (Modern Elevators and Escalators) + +extra-inventory +chroma-concrete +dracovita-delight-a-farmers-delight-add-on +gobber-delight-a-farmers-delight-add-on|戈伯乐事 (Gobber Delight) + + +extinguish-by-uss_shenzhou|灭 (Extinguish) +biome-makeover-forge@biome-makeover|生物群系改造 (Biome Makeover)¨biome-makeover|生物群系改造* +throwable-blocks +ancient-warfare-3@ancient-warfare|古代战争3* +no-chat-reports@|禁用聊天举报* +valleycraft@ +no-xp-bar +towers-of-the-wild-additions@ +world-of-pure-imagination|想象界 (World of Pure Imagination) +connectivity +more-useful-villagers + +@symbol-chat|符号聊天 (Symbol Chat) +@forcegl20 +hyle + +advanced-solar-panels-patcher +no-recipe-book-reborn@norecipebookreborn|没有配方书重制版* + + +shulker-tooltip@ + + + +midnightlib@ + +just-backpacks +doubledoors +@mod-remapping-api +tic-tooltips +ydms-wizarding-world-of-harry-potter +lucraft-id-extender +modern-flat-colored-blocks + + +flat-bedrock@ + +dans-crafting-tweaks|合成辅助非官方版 (Crafting Tweaks Unofficial) +handle-cane|手杖* + +mega-cells@mega|MEGA存储单元 (MEGA Cells) +structory +enchlevel-langpatch-config2|附魔等级语言补丁 - 配置扩展 (EnchLevel-LangPatch Config IV) +instant-unify|瞬间统一+ (InstantUnify+) +sneaky-farts +just-enough-recipe-integrations@jeri +hanami +is-a-mod-by-vazkii +inputfix|输入修正 (InputFix) +inventory-tabs-updated@ +ez-mod-lib@ezmodlib +armor-toughness-bar-updated +colorful-health-bar-updated + +wizardry-necromancers-delight +wizardryutils +xp-orb-clump +inventory-weight +time-reverse +nether-tears|下界遗泪 (NetherTears) + + +safaricraft +applied-botanics-addon@applied-botanics|应用能源:植物魔法附属* +overloaded-armor-bar-updated +delightful@ +wizardry-tales + +tamedrespawn|驯兽重生 (TamedRespawn) + +dumplings-delight@|饺子乐事* +thermal_extra@thermal-extra +nether-sky-block@|下界空岛* +arte-magicum + +ocean-blender@|海洋搅拌机 (OceanBlender) +buildcraft-fluxified +brewin-and-chewin@|饮酒作乐 (Brewin' And Chewin') +infinite-source-of-water@ +dramatic-doors@ +recipe-gui +autotechno@ +villager-hats-mod@villager-hats +custom-damage-particles@|自定义伤害粒子* +@aei|AEI物品管理器 (Always Enough Items) +cyan-warrior-swords-mod@ +plant-in-a-jar@ +solid-mobs@solid_mobs +naturalist@|自然主义* +c3h6n6o6@|环三亚甲基三硝胺 (Cyclotrimethylenetrinitramine) +syncmatica@|共享原理图* +zephs-hammers@zephshammers +zephs-excavators@zephsexcavators +@delayedreports +@technomodel +cat-herder +command-creative-tab +umu-backpack@ + +short-stacks +smooth-boot-reloaded@|流畅加载重置版* +stone-crafting-table +lodestonelib@ +witherturnsskeletons@ +twilight-forest-the-lost-blocks@ +the-nexus-deep-dark-dimension +jepp|JEI绘画预览 (Just Enough Painting Previews) + +create-curios +ctm-refabricated¨@ctm-refabricated +placeable-pumpkin-pie|可放置南瓜派* +birch-forest-upgrade|白桦林更新* +ok-zoomer-forge +@koro-utils-lib|科洛的工具库 (Koro Utils Lib) +cosmicnpcs +skinrestorer@ +hitchhike +sonic-deflect@ +mpkmod +supernatural-creatures +food-rebalanced +psi-unofficial|Psi 非官方版* +time-core@ +@searchable-containers-retraversal|可搜索容器:重遍历 (Searchable Containers: Retraversal) +unusual-squad-into-the-void@intothevoid +create-chromaticreturn@create-chromatic-return +powertool@|电动工具 (PowerTool) +keymap@|键盘映射* +actually-useful-stonecutter@ +itemphysic-lite-fabric|物品物理掉落:轻量版 - Fabric (ItemPhysic Lite - Fabric) +forgotten-treasures +player-health-indicators@playerhealthindicators +displaycase@|陈列柜 (Display Case) +auto-look +grimoire-of-gaia@|盖亚魔典 (Grimoire of Gaia) +ftb-jar-mod-forge|FTB 玻璃罐 (FTB Jar Mod) +dimensional-paintings@|维度绘画* +item-recycler|物品回收机* +linsapi@ +titlechanger@mctitlechanger|标题切换器 (TitleChanger) +adobe-blocks-2 +menacing-monsters +packing-tape +nyctophobia-forge@nyctophobia¨the-graveyard-biomes-fabric + +cammies-minecart-tweaks@ +renderlib@ +nothirium@ +advancedchatbox@AdvancedChatBox +quick-pick +advancements-debug@ +randomium-ore@ +degradeexplodedblocks + +zeras-scps +enderite-lieonlion@ +advancedchatfilters@AdvancedChatFilters +advancedchatmacros@AdvancedChatMacros +aof-emotes +grasslessdirtbackport +dazzle-2@ +smaller-nether-portals@¨smaller-nether-portals-fabric +basic-aiots@ +pokeball@|精灵球 (PokeBall) + +gravitychanger@ +building-wands@ +advancedchat@AdvancedChat +aiots-expanded-fabric +moremcmeta@¨moremcmeta-fabric +starry-skies@starryskies +flesh2leather-forge¨flesh2leather-fabric +fall-damage-indicator +aww-man-achievement-mod +fire-extinguisher@|灭火器* +farmers-knives@ +sullys-mod@sullysmod +magicaldecorations +moss-and-monsters +detonation +@rpgdurability|RPG装备耐久 (RPG Durability) +coal-processing-machine +joy-of-painting@|绘画之乐 (Joy of Painting) +warden-loot-forge¨warden-loot +@vmwcr|维克的现代战争补充合成表 (Crafting Recipes of Vic's Modern Warfare Mod) + + +optifine-checker@|高清修复检测 (OptiFine Checker) +paintings@paintings++ +builtin-servers@ +extractinator@|提炼机* +choicetheorems-overhauled-village@ct-overhaul-village +blast@ +no-indium@ +windsweptmod@windswept +immersive-paintings@|沉浸画框* +melon-wireless-redstone@wireless-redstone +automated-crafting@ +op-tab@optab +easy-piglins@|简易猪灵* +waterlogged-redstone +prehistoric-flora-integration +better-bad-omen +can-you-trash-it +croptopias-chocolaterie-forge@croptopia-chocolaterie|作物盛景:巧克力工坊 (Croptopia's Chocolaterie)¨croptopias-chocolaterie-fabric|作物盛景:巧克力工坊 (Croptopia's Chocolaterie) +crawl@|爬行* +chisel-reborn@ +roost-ultimate@roostultimate +cammies-wearable-backpacks@ + +parrying +back-in-slime-slime-blocks-for-1-7 + +create-alloyed@|合金 / 机械动力:合金 (Alloyed / Create: Alloyed) +verdure@|郁郁葱葱* + + +the-ori-mod +coxinha-utilities@ + +dragon-fire-mod + + + +sandy-ores|沙子矿石* +rainbowify@ +be-quiet-please|请安静* +prehistoric-revival-a-prehistoric-fauna-add-on@|史前复生 (Prehistoric Revival - A Prehistoric Fauna Add-On) +had-enough-characters +medieval-origins + + +elytra-chestplate-swapper@|鞘翅/胸甲切换 (Elytra/Chestplate Swapper) +the-ends-flora +apollos-additional-structures + +chimes@ + +endless-ocean-aquatic-adventures +ic2-no + +origins-plus-plus@|起源++ (Origins++) + +mcda@|我的世界:地下城盔甲 (MC Dungeons Armors) + +sun-burns +battle-tools +jobsplus@ +towns-and-towers-structure-add-on@towns-and-towers +drg-flares-forge¨drg-flares +simple-uncrafting-table-fabric@simple-uncrafting-table +caracal-mod@caracal_mob +rough-tweaks-revamped@ +the-wild-backport@wildbackport +unvoted-shelved@unvoted +yeos-mobs +infohud@ +haruhiism|春日主义* +withcoffee|咖啡相伴/天堂之路 (WithCoffee) +emeraldstuff +grass-slabs-carpets-stairs +not-mutually-exclusive@|不冲突* +builders-delight-forge@builders-delight +miners-minerals@ +days-to-mine@7-days-to-mine|七日杀 (7 Days to Mine) +pieces-of-ore + +@fix-keyboard-on-linux +lockdown-additions +scp-lockdown-extras +player-tabs +cie +easy-mob-farm@ +material-elements +raised-clouds@ +music-triggers@|音乐触发器* +sneaky-screens@ +inmis@¨inmis-forge + + +rechiseled@ +durability-tooltip@ +oreganized-mod|井然有矿* - 旧版¨oreganized|井然有矿 (Oreganized Mod) - 2.0+ 版¨@oreganized|井然有矿 (Oreganized Mod) +riding-utilities +compact-help-command@¨compact-help-command-fabric + +miners-lung|矿工之肺 (Miner's Lung) +greenery@|绿色植物🌿 (Greenery🌿) +butchers-delight@|屠夫乐事 (Butcher's Delight) +large-meals-an-add-on-for-farmers-delight +explorers-delight@ +the-irregular-chef@irregular-chef +compat-o-plenty@compatoplenty +snow-pig@snowpig|雪猪*¨snow-pig-fabric@snowpig-fabric|雪猪 (Snow Pig) +wandering-collector@ + + + +skull-craft@|头颅工艺* +re-chiseled-compat +auto-leveling +packed-inventory@ + +crafting-on-a-stick@ +endlessids@ + +compact-machines-fabric@cpm-fabric|压缩空间 Fabric (Compact Machines - Fabric) +cycle-paintings@¨cycle-paintings-fabric + +fire-spread-tweaks@¨fire-spread-tweaks-fabric +anger-management +easy-elytra-takeoff@¨easy-elytra-takeoff-fabric +stack-refill@¨stack-refill-fabric +light-meals@|轻食物语* +lost-and-fished@lost-fished|失而钓得 (Lost and Fished) +custom-backgrounds|自定义背景* +ydms-allay@|YDM的悦灵 (YDM's Allay) +starmaker@ +@swdheftpywaed|对不起,我们没有充足的资金为您提供一只末影龙 (Sorry We Don't Have Enough Funds To Provide You With An Ender Dragon) +simply-snow +areas@¨areas-fabric +emberroot-zoo +mctimeextendsfabric +l2library@ +unstructured +colorful-cut +@fake-floader +environmental-materials@ +horse-tweaks +auto-workstations-fabric@auto-workstations|自动化工作站 (Auto Workstations) +l2-backpack@l2backpack|莱特兰-背包* + +@mbp +capybara-uam¨unnamed-animal-mod-capybara-only +just-enough-petroleum +diamethysts@diamethysts!|紫晶钻! (Diamethysts!) +twigs¨@twigs|Twigs - 停更 + + + + +fplib@ +spongemixins¨@spongemixin1710 +nock-enough-arrows +every-compat@|泛用兼容:木材 (Every Compat (Wood Good)) +offline-mode +ghastly-wail@ +immersive-weapons#c71@immersive-weapons|沉浸式武器 (Immersive Weapons) + +clear-skies@ + +ShretNether +pling@ +justthetips + +notenoughitems-gtnh@notenoughitems-unofficial|NEI物品管理器非官方版 (NotEnoughItems Unofficial) + +sketchbook-attributes +better-combat-by-daedelus@better-combat¨better-combat-backport +custom-stars|自定义星星* + +ice-and-fire-tweaker@ +soaring-clouds +lapis-stays-in-the-enchanting-table +goodall +freecam-by-zergatul + +macaws-bridges-oh-the-biomes-youll-go|Macaw 的桥梁:你将去的生物群系附属 (Macaw's Bridges - Oh The Biomes You'll Go)¨macaws-byg-bwg@|Macaw 的桥梁:你将去的生物群系附属 (Macaw's Bridges - Oh The Biomes You'll Go)¨@macaws-bridges-oh-the-biomes-youll-go|Macaw 的桥梁:你将去的生物群系附属 (Macaw's Bridges - Oh The Biomes You'll Go) - 原, +macaws-fences-oh-the-biomes-youll-go@|Macaw 的栅栏与墙:你将去的生物群系附属 (Macaw's Fences - Oh The Biomes You'll Go) +alternate-current@ +no-unused-chunks@ +no-fade@ +radioactive-universe + +completeconfig@ +fixmyspawnr@ +l2-artifacts@l2artifacts|莱特兰-古遗物* +critters-and-companions@ +memorytester +colormatic@ + +fogbox@ +@hopper +lots-of-shields +timestopclock|Mega的时间静止 (MegaTimeStopMod) +umu-little-maid@ +loot-games|战利品游戏* + +ydms-scorpions@|YDM的蝎子 (YDM's Scorpions) +auto-reconnect +text-damage-indicators +recall +monster-coin +dotcoin-mod@dot-coin-mod¨dot-coin-mod-fabric +super-potato|超级土豆* +custom-fog@ + +oc-xnet-driver + + + +ydms-glare@|YDM的怒目怪 (YDM's Glare) +caupona@|分茶* +ydms-iceologer@|YDM的冰术师 (YDM's Iceologer) +fabric-sculk-worm +apex-guns|Apex 枪械工艺* + + +hwyla-addon-horse-info +postal-pigeons +swagoween +no-lag-tickratechanger@ +alcocraft-beer-and-stuff +simplevillagers@ + +autoreconnect@ +twelvefold-better-combat@|更好的战斗* +dusk +copper-craft|铜制工艺* +extrabotany2|额外植物学重置版 (ExtraBotany2) +terramine@ +aeinfinitybooster@ +endertech-infinity@ +more-frogs-fabric@morefrogs|更多青蛙 (More Frogs) + + +create-big-cannons@|机械动力:火炮* +fastanim@ +rubidium-extra@|铷 · 扩展 (Embeddium (Rubidium) Extra) +less-feature|更少的特性 (Less Features) +mores-forge@mores¨mores-fabric +tactical-fishing@ +token-enchanter@ +igiexteneded|IGI 信息扩展 (IGIExteneded) + +landofsignals@ +lootbeams@ + +stepupnext@stepup +simple-bbq@|简易烧烤 (Simple BBQ) +mythic-mounts-forge@mythic-mounts¨mythic-mounts +spice-of-life-sweet-potato-edition|生活调味料:红薯版 (Spice of Life: Sweet Potato Edition) +@reality-city-construction|真实城市建设模组 (Reality City Construction) +sneak-through-berries@ +winter-overhaul@|冬季改革* +offlineskins|离线皮肤 (OfflineSkins)¨offlineskins-fabric|离线皮肤 (OfflineSkins) + +@xdi8aho-mod|灯纟火 (Xdi8Aho Mod) + +another-furniture@|别样家具* + + +rayon@ +ponder@ +ender-logistics|末影物流* + + + +megaplanets +cosmic-horizons-gc-addon +ultris-boss-expansion +bedfix +mo-glass@ +flans-mod-global-firestorm +turtlemancy@ + + + +goblins-dungeons +optigui@ +@eeeee|咏e (eeemod) +background-music-selector@bgmselector|背景音乐选择器* +dynamic-surrounding-resurrected + +spells-shields@ + +player-companions@ +technical-engineering-3|科能工程3* + +extra-utilities-reborn|更多实用设备:重生* + + +chatflow +auto-third-person@|自动第三人称* +flowery-structures@ +chat-up +flowery-core@flowerycore +level-hp +sanguine-arsenal|幻梦:血染武装 (Eidolon's Sanguine Arsenal) +automobility@|飞车奇匠* + + +ftb-quests-localization-keys + +unlit-realistic-torch-remake|真实火把:重置 (Realistic Torch Remake) +chunk-saving-fix|区块保存修复* +fullscreeno@ +@xibao-plus-plus|喜报++ (Xibao Plus Plus) +piglin-proliferation@ +the-binding-of-isaac-style-consumables +guns-rpg +configuration@ + + +natural-decoration +spice-of-fabric@ +better-climbing@|更好的攀爬* +dog-yeeter +mc122477fix@ +armors-hud-revived-liteloader-only +living-things@|自然生物* +beautify-decorate@beautify|美化! (Beautify!) +Voodoo@voodoo +notenoughluck|更多幸运 (NotEnoughLuck) + +@hideplayers|隐藏玩家 (HidePlayers) +mixintrace@ +bancis-enchantments +@maze|迷宫 (Maze) + + +skylands-fabric@skylands +jjthunder-overhauled-world-generation +betterblockoutline@ +@sodium-crash-fix|Sodium 临时崩溃修复 (Sodium Crash Fix) +scift@ +@ping-me +@tool-rods +the-squid-game-mod +datapack-portals@datapackportals|数据包传送门* +more-beautiful-walls@ +iris-flywheel-compat@iris-flw-compat +prism-lib@¨prism-fabric + +map-atlases-forge@map-atlases|地图册 (Map Atlases)¨map-atlases|地图册* +@eprr|额外玩家渲染Rift版 (ExtraPlayerRenderer-Rift) + + + +smartbrainlib@ +twilight-tweaks +aureus-simple-slabs +just-mob-heads@¨just-mob-heads-fabric +squid-game-mod + +quantum-querry-plus|量子采石场增强 (Quantum Quarry Plus) +food-enhancements|食物扩增* +@bindgg +create-ore-excavation@|机械动力:矿石开掘* +just-player-heads@¨just-player-heads-fabric +survivalplus-lightsabers|生存加光剑 (SurvivalPlus Lightsabers)¨survivalplus-lightsabers-fabric|生存加光剑 (SurvivalPlus Lightsabers) +fclib +primitive-utilities +guglecarpetaddition@gca|Gugle的Carpet附加包 (GugleCarpetAddition) +survivalplus|生存加 (SurvivalPlus)¨survivalplus-fabric|生存加 (SurvivalPlus) +mrp-library +bypass-anvil-restriction +no-early-loading-progress + +block-runner-forge@block-runner¨block-runner +quick-paths@¨quick-paths-fabric +solar-energy +restored-earth + + +pig-pen-cipher@ +luckyblock-fabric@luckyblocks|幸运方块 (Lucky Blocks) +@smeltingtouch +things-fabric@things|杂七杂八的东西 (Things) +exlines-snorkel-mod@snorkel +two-players-one-horse@ +headshot-forge +left-hanging@ +stars_carrier|星光的载具 (stars_carrier) + +aetherworks|天华之作 (AetherWorks) +slice-and-dice@ +textrues-rubidium-options@|TexTrue的铷视频界面 (TexTrue's Rubidium Options) + + +rubber-duck|橡皮鸭*¨@rubber-duck|橡皮鸭 (Rubber Duck) - 已归档 +unlimited-dragon-eggs-fabric@unlimited-dragon-eggs +moreplayermodels-plus@moreplayermodels+|更多玩家模型+ (MorePlayerModels+) +@actioninventory + +custom-void|自定义虚空* +create-jetpack@|机械动力:喷气背包* +entity-outliner +@sharpness6 +no-name-tags@|隐藏名称标签* +ranged-wireless-redstone +potato-canon-plus-forge +unusual-end@unusual_end|不同寻常的末地* +solar-flux|日光通量* + +custom-background-color@cbc|自定义背景颜色* +simple-shulker-preview@ +bygone-nether@|逝去的下界*¨bygone-nether-fabric|逝去的下界 (Bygone Nether) +@clickopener +kokoalinux-backport +mechanical-clothesline|机械晾衣绳* +loading-progress-bar@|加载进度条* +intercontinental-ballistic-redux +planefix +quick-leaf-decay +simple-trophies +thaumic-computers +@sliderclicksoundfix +instant-massive-structures-ims +hunger-remover@ +rad-enchants +plus-the-end +runic@ +broken-discs +forgedfabric@ +create-extended-flywheels@extended-flywheels|机械动力:更多飞轮 (Create: Extended Flywheels)¨create-extended-flywheels-fabric|机械动力:更多飞轮 (Create: Extended Flywheels) +piggy-bank +deeperdarker@|幽邃黑暗 (Deeper And Darker) + +remote-gui-opener-forge + +illagers-pillagers +guard-illagers +moon-light-illager +the-woodland-update +a-foe-on-fire +hunting-delight|狩猎乐事 (Hunting delight) +more-barrels|更多桶* +origins-accessibilities@|起源:通行 (Origins: Accessibilities) +@minerslunchbox|矿工的午餐盒 (Miner's Lunchbox) +fuelcanister@fuel-canister + + +f5-begone@ +smartvision@ + + +no-more-purple@ + +content-creator-integration@¨content-creator-integration-fabric +defaultworldtype@|默认世界类型 (Default World Type) +no-nether +miniatures +ad-astra@ +big-items-duh@ +scape-and-run-parasite-vaccine +doge-mod +ice-fire-katanas +@pressalttomeow +@cma|地毯-MCT拓展 (Carpet MCT Addition) +brvsb@|更好的铷视频设置按钮 (Better Rubidium Video Settings Button) +roughly-enough-trades@ +simple-quarry@ +magitek-mechs|Magitek Mechs - 已停用¨@magitek-mechs +infectum +nocubes-sea-dwellers +show-me-your-skin@ +invulnerable-pigs +t88@ +k-turrets@¨k-turrets-fabric +nevertooexpensive +max-enchant-x@ +visible-toggle-sprint@ +let-me-despawn@lmd +glsl-panorama@ +feyfriends@ +mccalc@ +nekeys +crafted-forge@crafted¨crafted +cursery +mirage-orb +galacticborn-origin@ +extra-recipe|更多配方* + + +custom-window-title@|自定义窗口标题* + +crated-foods-farmers-delight +damage-tilt +upgraded-core¨@upgraded-core|Upgraded Core - 不全 +upgraded-netherite-ultimerite@|下界合金增强:终极 (Upgraded Netherite : Ultimerite) +upgraded-netherite-items@|下界合金增强:物品 (Upgraded Netherite : Items) +upgraded-netherite-creativerite|下界合金增强:创造 (Upgraded Netherite : Creativerite) +elementary-ores + +minecraft-dark-souls|黑暗之魂 (MC: Dark Souls) +dontmineit@ +tmp@ +feytweaks@ +show-yourself@ +convenient-name-tags@ +anakus-status-bars¨anakus-status-bars-forge +minemenu-refabricated +cfl@ +creative-fly@ +why-does-my-glass-sound-like-that@wdmgslt +itemwallet@ +way-much-faster-oxidize@|更快铜锈蚀* + +emi-trades-villager-trading-emi-plugin@emitrades|EMI村民交易 (EMI Trades) + +sim-u-kraft-reloaded|模拟城市重置版 (Sim-U-Kraft Reloaded) +create-factory@ +horseinboat@ +upgraded-tools@|下界合金增强:工具* +tools-for-caves-and-cliffs +betterendsky@better-end-sky + +infinity-with-mending@|无限与经验修补* +infinity-craft +hookshot@ +custom-spawns +create-misc-and-things@|机械动力:实用物件 (Create : Misc & Things) +low-fire@ +infinity-buttons@infinitybuttons|无限按钮* +i-know-what-im-doing-fabric +skin-hotkey@ +dyeable-fishing-lines-fabric@dyeable-fishing-lines¨dyeable-fishing-lines-forge + +reciperemover@ +roughly-enough-loot-tables@ +fld@ +lostcities-tfc +snowed-fabric +player-blink +better-command-block-ui@bettercommandblockui +create-experienced +gotta-go-fast + + +mad-particle@|疯狂粒子* +fabrihud@ +shiny-horses@ +nyx-rotn-edition + +playeranimator@ +apathy-mod@apathy +auudio-forge@auudio¨auudio-fabric + +easy-shulker-boxes@¨easy-shulker-boxes-fabric + +qu-enchantments@ +ironchests@ +piercing-paxels@piercingpaxels +icy-incitement@icyincitement +visible-librarian-trades +unlimited-chisel-works-tfc1@ +enchantedshulkers@|附魔潜影盒 (EnchantedShulkers) +noits-simple-sorting +colds-gauntlets +level-one@ +wilder-wild@ +paintings-with-dragons +more-redstone-lamps|更多红石灯* +placeable|可放置植物 (Placeable Plants) +tfc-hot-or-not@ +quick-elytra@ +other-berries +itank +snowy-spirit@ +no-tutorial-toasts@ +experience-ores +anvil-player-heads-fabric@anvil-player-heads¨anvil-player-heads +artisan-integrations +seemyname +biomes-o-plenty-tools +bedrockcraft@ +better-mobgriefing-gamerule +frozen-fiend +minefall +gateways-to-eternity|永恒之门 (Gateways to Eternity) +gate-of-babylon-additions@|王之财宝附加 (Gate of Babylon Additions) +hephaestus-fabric@hephaestus|匠神 (Hephaestus) +crafting-bench@ +morebeeinfo@|更多蜜蜂信息 (MoreBeeInfo) +bq-forestry|更好的任务 - 林业扩展 (Better Questing - Forestry) + +create-infinidrill + + +@scrollable-tooltips +attribute-tooltip-fix@ + +no-slow-down|不减速* +crumbs@¨crumbs-fabric +italians-delight +immersivemc@|沉浸式MC (ImmersiveMC) +mc-vr-api@ +exordium@ +fabric-launchpads¨zihlaunchpads + +thermal-innovation-cyclic-compat +@bee-fix|蜜蜂修复 (Bee Fix) +noel-christmas-mod +moar-fps@moarfps +flighthud +meal-api@mealapi +seed-drop +fishery-expansion@fishery + +arrowcamfabric +overpowered-mending@overpoweredmending +woof@wolves-of-other-furs +instant-blocks@¨instant-blocks-fabric +better-sprinting@|更好的疾跑* +rpglevels +snow-under-trees@ +elytra-physics@|鞘翅物理* +scout@ +zenstages + +wondrous-wilds@ +truly-treasures@ +where-is-it@ +relicex@ +led@|发光二极管 (Light Emitting Diode) +i-dont-need-stone|再见 圆石 (I DON'T Need Stone) +@libgui-forge +colorize@ +no-magic-milk@ +powered-food +spirit@ + +elytra-bounce@ +no-report-button@nrb|无举报按钮* +mana-wizardry +aileron@ +devworld@ + +immersive-weapons-compatibility-bridge@ +gameidiots-craftable-wizardry-items +craft-hacks +serene-seasons-harvestcraft2-compat|静谧四季 - 潘马斯农场 2:作物兼容 (Serene Seasons - Pam's HarvestCraft 2: Crops Compat) +goat + +simple-autofish +think-before-drop@thinkbeforedrop|丢弃物品保护* +omo +mushroom-additions + +project-the-void|项目 -虚空- (Project the Void) +ice-and-fire-rotn-edition|冰火传说:RotN 版 (Ice and Fire: RotN Edition) +minescript@ +no-capes@|禁用披风* +apocalypsecraft +mcree_highnoons-enchantments|McRee_HighNoon的附魔 (McRee_HighNoon's Enchantments) +canary@ +better-give@ +zonkos-monsters +tetratic-combat +fastload@ +dramatictrees@dtree +robinhood@ +trajans-core +stop-hiding + +simple-world-timer +recursive-resources@recursiveresources +inventory-actions +lavafishing@|熔岩钓鱼 (Lava Fishing) +haunted-harvest@ +dungeonsenhanced@dungeons-enhanced +create-crystal-clear@|机械动力:晶莹剔透 (Create: Crystal Clear) +@create-crystal-clear-fabric +fix-experience-bug@ +@minecraft024|24点 (Minecraft024) + + + + +it-takes-a-pillage@¨it-takes-a-pillage-fabric + +get-it-together-drops@ +fire-n-blood +chunknogobyebye +beaming-drops@loot-beams-backport|掉落物光束 (Beaming drops / Loot Beams Backport) +protocharset@protocharset-rift +the-hordes@ + +inventory-management@ +soul-fired@soul-fire-d +faithfulbackrooms@ +ex-machinis@¨ex-machinis-divitiae-deorum@ +goety@|诡厄巫法* +torch-hit@ + +we-got-runners@we-got-runners! +@cabricality-utils +dynamic-trees-croptopia +medieval-music +gempire@ + +sbm-bone-torch +linkmyitem +sprout@ +resourceful-lib@ + + + +marg +cozy@ +better-piglin-trade@|更好的猪灵交易* +model-gap-fix@modelfix + +posture +little-ants@|小蚂蚁* +hardcore-torches@|硬核火把*¨hardcore-torches-forge|硬核火把 (Hardcore Torches) +auto-torch@|自动火把* +nightlights@|小夜灯 (Night Lights) +angry-mobs@ +onlylooking +the-birdwatching-mod +giant-ai +unlit-campfire@ +xl-packets-renewed +nameplate@ +rpgdifficulty@ +tooltiprareness@|稀有度提示框 (TooltipRareness) +@minimotd-reforged +combat-roll@|战斗翻滚* +project-brazier@ +over-enchanted@overenchanted +creeper-overhaul-firework|烟花苦力怕改革* +spartan-weaponry-bewitchment@|斯巴达的武器:巫师之路 (Spartan Weaponry - Bewitchment) +no-water-spread +shoppy +cathedral + +meowing +dogwhistle + +@onlylooking-fabric + + +wilder-wilds +@ae2-unpowered +better-respawn@|更好的重生* +essentialgui@ +elementary-staffs@ +dragon-fight-config +infused-foods@ +what-meme +shiny-gear +would-you-shut-up-man +weaker-spiderwebs@¨weaker-spiderwebs-fabric +netherbarrels +wooden-elytra|木制鞘翅* +construction-site-deco@construction +wthit-harvestability@ +habitat +@emicompat +harmonicenchantments|调和附魔 (HarmonicEnchantments) + + +custom-cards|自定义卡牌* +biome-cards|群系卡牌* +bombinghud +astral-dimension +followers-teleport-too@¨followers-teleport-too-fabric +@citycraft|城市工艺 (City Craft) +odysseymod +libipn@ +hulsealib +blues-dynamic-lights +gtc-expansion@ +nether-depths-upgrade@|炽海生机* +cloud-factory +disc-holders-dj +@econ +keepmum|三缄其口 (KeepMum) +saturn@ +stackable +do-a-barrel-roll@ +fantasys-dice@fantasy-dice|Fantasy的骰子 (Fantasy's Dice) +@ukulib +@betterhurtcam +itemresistance@ +distinguished-potions@ +@enhanced-weather +just-enough-immersive-multiblocks@jei-multiblocks +adapaxels@ +fabrizoom@ +json-things +@origins-randomiser +simply-swords@|简易刀剑* +neokuayue@|跨越 (KuaYue) + +summoningrituals@|召唤仪式 (Summoning Rituals) +no-rest +you-died@|你死了* +hotbarcycle@ +hungry-in-peaceful-mode|无中生饥* +auto-respawn-mod +cave-generator|洞穴生成器* +console-filter +customized-dungeon-loot@ +customquests +portal-cubed|Portal Cubed / Thinking With Portatos - 无法¨@portal-cubed +pehkui-resizer +kaffees-dual-ride@kaffees_dual_ride +@sfreeze +portable-hole@ +betterteamchat@ +logic-chips|逻辑芯片* +quit@ + +nears@ +obsidianui@ +walk-jog-run@ +conveyor-belts-fabric@conveyor-belts|传送带 (Conveyor Belts) +create-sifting@|机械动力:筛子* +player-name-tweaks|角色名调整 (PlayerNameTweaks) +dat-modding-api +rangefinder-hud@rangefinderhud +prelaws-blocky-siege@luckys-blocky-siege +modget@ +@babies-forever +no-leaf-decay@ +mysteriumlib@ +@inrealtime +furnace-recycle@|熔炉回收*¨furnace-recycle-fabric|熔炉回收 (Furnace Recycle) + +wild-lands@ + +noenchanting +gregtech-experimental@ +@cooldown-totem +almost-bedtime@ +catlib +@mythicbotany_tweaker +polaroid-camera@polaroidcamera|宝丽来相机* +dig + +dimensional_ores +devices-mod@ +dynamistics +eguilib +glacidus + + +compat-makeover +@deferred-registries +@nametagping +map-in-slot@ +hungertweaker +knob-control +daedalus-labyrinth +tip-the-gui|界面尺寸设置优化 (GUI Scale) +copper-overhaul@ +epic-fight-nbt-integration +login-protection|登录保护* +swem@|星虫马术 (Star Worm Equestrian Mod) +metal-barrels-legacy|金属储物桶:传承 (Metal Barrels: Legacy) +inventoryfullalert@ +lead-beyond|引向超越* +dyeallthethings@ +swampier-swamps@¨swampier-swamps-fabric +weather-settings|更好的天气控制 (Weather settings) +shutdowner +shield-mechanics|盾牌机制优化 (Tactical Shield Overhaul / Shield Mechanics) +sun-and-moon-celestial-configuration@celestial-config +chatsound +advancedshader|光影前向兼容 (AdvancedShader) +the-wools@|羊毛! (The Wools!) +fabric-enchantments +glued@ +tinkers-craft|工匠创意 (Tinkers' Craft) +tinker-leveling +gtce-tj-edition|格雷科技社区版:TJ版 (GregTech Community Edition: TJ Edition) +upc@ +gregicality-tjfork +@flagslib +create-mechanical-extruder@ +no-debug-5-you +packagedavaritia@|封包无尽贪婪 (PackagedAvaritia) +pillar +resound +mob-plaques@ +corail-scanner +space-ambient-addon-for-galacticraft@space-ambient +spiked-foods +auraddons +auracontrol +contenttweaker-registry-orderer +the-otherside +pogo-sticks +tickrate-changer|运算变速* +camcord@ +modern-keybinding@modernkeybinding|现代化按键绑定 (Modern KeyBinding)¨modern-keybinding-fabric|现代化按键绑定 (Modern KeyBinding) +make-bubbles-pop@make_bubbles_pop +couplings@ +mambience@ +elytra-aeronautics@¨elytra-aeronautics-forge + +infinitory@ +loud-leads|拴绳音效* +music-duration-reducer +telepistons@ +mariums-soulslike-weaponry@|Marium的魂类武器 (Marium's Soulslike Weaponry) +lets-go-herping +modularui@ +inventory-bogo-sorter@inventory-bogosorter +gregtech-sieves|格雷矿石筛子 (GregTech Sieves) +dynamic-trees-gregtech-ceu-rubber-tree|动态的树:格雷科技社区版:非官方版附属 (Dynamic Trees - GregTech CEu) +fertility + +tcintegrations@ +underground-villages@ +spook +broglis-owls +pluto@ + +youre-in-grave-danger@yigd +reds-better-biomes-fabric-forge +reds-more-structures +rotn-tweaker +cannot-build-over-lava-source-blocks +quark-rotn-edition|夸克:RotN 版 (Quark: RotN Edition) +inmisaddon@ +pineapple-delight@|凤梨乐事* +woodworks@ +informational-accessories|信息饰品* +nyfs-spiders@ +illager-additions +idolizing +evocation-and-annihilation +more-golems +kebabs-crowns +rerereskillable@ +hedgehogs|刺猬* +@pendulum +yacl@ +keyboard-wizard-legacy@keywizardlegacy|按键精灵旧版 (Keyboard Wizard: Legacy) +queen-cats-dogs@ +additional-lights|更多光源* +in-time-presence +mob-vote-2022-forge¨mob-vote-2022 +curious-lands +cpmsvcc@|自定义玩家模型的简单的语音聊天兼容 (Customizable Player Models Simple Voice Chat compat) +pettable@ +create-enchantment-industry@|机械动力:附魔工业 (Create: Enchantment Industry)¨cei-fabric-legacy@|机械动力:附魔工业 (Create: Enchantment Industry) +enchanted-witchcraft@ +wyml + +bunch-o-bugs +useless-reptile@ +technomancy-2|量子魔法2 (Technomancy2) +quickstore|快速贮藏重制版 (QuickStoreRemake) +your-items-are-safe@¨your-items-are-safe-fabric +techemistry +the-missing-villages +continents +yungs-better-ocean-monuments@|YUNG 的海底神殿优化 (YUNG's Better Ocean Monuments)¨yungs-better-ocean-monuments-fabric|YUNG 的海底神殿优化 (YUNG's Better Ocean Monuments)¨yungs-better-ocean-monuments-neoforge|YUNG 的海底神殿优化 (YUNG's Better Ocean Monuments) +echoing-depths + +advanced-finders +maple-forest|枫林* +@legacyinputpatch|Legacy Fabric 输入补丁 (LegacyInputPatch) +droplight +xanders-sodium-options¨@xanders-sodium-options|Xander's Sodium Options - 已归档 +entity-view-distance@ +creeper-ai-updated@ +sihywtcamd@difficulty +sihywtcamc@combat +why-stacks-of-16@ +jumpquilt +oh-how-the-crafting-has-tabled + +roughly-enough-items-hacks@ +piglin-expansion|猪灵扩展* +@nes +dreadsteel|悚怖钢* +auto-hud@autohud +camera-utils@ + +roughly-enough-items-server-component@ +daves-building-extended¨daves-building-extended-fabric +@rechiseled-bookshelves +dimensional-pockets-ii@|四次元口袋2 (Dimensional Pockets II) + +@calculatorrinf-uwu +black-hole-storage|黑洞存储* +hudtweaks@ +mod-button +opt-carpet-addition@ +trees-do-not-float@ +cosmos-library@ +groovyscript@ + +potion-ring-reforged@|药剂环重铸 (Potion Rings - REFORGED)¨potion-ring-reforged-fabric|药剂环重铸 (Potion Rings - REFORGED) +scp-overtime@ +chubby-stuff-fabric +better-brightness-slider@ +open-parties-and-claims@ +loading-screen-tips@loadingscreentips +better-tips +immediatelyfast@ +opac-fabric-create-support@ +steel-for-fabric@steel|钢 (Steel) +mekanism-tweaks@ +changed-minecraft-mod@ +hello-crosshair@ + +bendy-lib@ +enchantment-transfer-forge@enchantment-transfer +golden-crops +lil-wings@ + + +@scp-sharp +scary-mobs-and-bosses +elytra-replace|鞘翅替换* +mt-garden-arsenal-forge|MT:花园军火库 (MT: GardenArsenal)¨mt-gardenarsenal-fabric|MT:花园军火库 (MT: GardenArsenal) +visual-overhaul@ +drawerfps-legacy|储物抽屉渲染配置:遗产 (DrawerFPS Legacy) +status-effect-timer@statuseffecttimer +logical-zoom@ + +the-space-age-mod|太空时代* +touhou-origins@|起源:东方 Project 附加包* +earth-mobs@earthmobs|地球生物* + +simplemetals-tin +just-enough-keys¨just-enough-keys-fabric +why-am-i-on-fire@ +bouncing-balls-api@|弹跳球 API (Bouncing Balls API) +bouncing-balls@|弹跳球* +teletubbies-mod@teletubbies|天线宝宝* +almost-unified@ +draw-bridge +creative-fireworks +invertedbed +time-arrow +catch-me-if-you-can-cmiyc +mc-modsis-one-way-glass|Alli的单向玻璃 (Alli's One Way Glass) +sanguis +ender-trigon@ +litlaunch +puzzle@ +why-am-i-on-fire-refoxed + +@tdfp|暮色乐事:冰雪豪饮 (Twilight Delight: Frozen Pride) +ftb-pack-companion +teams-stages +kiwi-boi@ +rubidium-toolkit@|铷 · 工具箱* +advanced-combat|高级战斗装备* +advanced-combat-revitalized@|高级战斗装备重置 (Advanced Combat (Revitalized)) +totemic-overhaul + +battlecorrection@|战斗修正 (BattleCorrection) +midnightcontrols-extra@ +i-wanna-skate@ +tectonic@ +born-in-chaos@borninchaos|生于混沌 (Born in Chaos) +eureka-ships@eureka +goofy-goober +time-stop-clock-mod@|时之钟 (Time Stop Clock) +dynamic-asset-generator@dynamic_asset_generator +excavated-variants@excavated_variants + + +survival-light-blocks + +garden-stuff|园林组合* +forgottenrecipes +corgilib@ +moms-love@|母爱 (Mom's Love) +food-effect-tooltips@foodeffecttooltips|食物效果显示* +@resounding +hbm-fixes +status-effect-bars@ +monsters-in-the-closet@ +recipe-unlocker@recipes +metamorph-max|变形拓展* +kubejs-tinkers-construct + +ghost@ +better-stats@|更好的统计信息界面 (Better Statistics Screen) + + + + +abyssalblocks|深渊国度幸运方块 (AbyssalBlocks) +archon@ +stackie +@cullclouds +@superfancyclouds +stage-tabels +temporal-dynamics +villagertradingban +enchantment-machine@enchantmentmachine +yosbr@ +minefortress-rts@minefortress +onebar@|单条 (OneBar) +berdinskiybears-armor-hud + + +tiered-tooltips +rgb-blocks-forge|调色方块 (RGB Blocks) + +quicksand-fabric@quicksand|流沙 (Quicksand) +better-durability@|更好的耐久度* +passthrough-signs@ +excorrelation@ +packet-size-doubler +@packet-size-double-forge +arachnophobia-mode-for-minecraft@arachnophobia-mode +villagerconfig@|村民配置 (Villager Config) +jasm@speedometer +paginated-advancements@paginatedadvancements|分页进度 (Paginated Advancements & Custom Frames) +@backport-gamerules +structures-compass +swiss-cheese +vitalize@ +i18n-nlts@i18nupdatemod-nlts|自动汉化更新非长期支持版 (I18nUpdateMod Non-LTS) +ingame-info-xml-serene-seasons +ingame-info-xml-addon-serene-seasons + + +staff-of-building|建筑之杖 (Staff of Building) +dark-mode-everywhere@|夜间模式无处不在* +custom-shop|自定义商店 (CustomShop) +another-liquid-milk@ +dark-mode-everywhere-fabric@|夜间模式无处不在Fabric版 (Dark Mode Everywhere - Fabric) + +bartering-station@|易物站* +dark-paintings@ + +filtpick@|拾取筛 (FiltPick) + +deepslatecutting@ +easy-anvils@|简易铁砧* +leaves-be-gone@ +recipe-cache|配方缓存* +mob-catcher +@quiltgoslighlyfasterlol + + +guns-rpg-waystone-addon +biospheres-fabric|现代生物圈 (Modern Biospheres) +better-snowball-fight@|更好的打雪仗* +feathers@ +brb@|更好的配方书 (Better Recipe Book) +boatoverhaul-forge|行船机制修改 (Boat Overhaul)¨boatoverhaul-fabric|行船机制修改 (Boat Overhaul) +sculk-warden +better-questing-gamestages-expansion@|更好的任务-游戏阶段扩展 (Better Questing - Gamestages Expansion) +omega-chips@ +youdroppedthis@ + + +toomanyorigins@ +evil-regeneration@ +food-treasure-box|食物宝盒* +revolution +apugli¨@apugli +harvest-season +@ic2fix +@extended-bookshelves +cocoainput +chargers@ +@axolotl-buckets + +recipe-book-is-pain@rbip +@one-bad-apple + +with-json@ovo +mystical-nature|神秘自然* +@formula-addition-fabric|配方追加 (Formula addition) +randomlib +@kinventory +pullup@|飞行警报* +id-primeval@primeval +colorfulazaleas@colorful-azaleas|杜鹃缤纷 (Colorful Azaleas) +pigeon-post@ +hunted-api + +bigger-structures + +find-my-friends@ +@legacy-lazydfu +fallout-wastelands + + +@letitsnow +dons-lightning-rod-mod +rainglow@ +nethers-delight-fabric|下界乐事(Fabric 版) (Nether's Delight (Fabric)) +quicksand-neoforge@|流沙(NeoForge) (Quicksand (NeoForge)) +axolotl-bucket-fix-forge@|美西螈桶修复 Forge 版 (Axolotl Bucket Fix (Forge)) +scape-and-run-parasites-survival-addon-by-nocube +scape-and-run-parasites-nests-addon-by-nocube +@emiffect +villagers-sell-animals +teal-bricks +bodacious-berries@berries|多汁浆果 (bodacious berries) +@the-bag-of-holding|手袋 (Bag Of Holding) +rgb-chat + +diamond-caliber +@emi_farmersdelight +world-stripper@ +dayz-remastered|DayZ 重制版 (DayZ Remastered) +visuality-reforged@visuality-forge|可视性:重铸 (Visuality: Reforged) +ease-out-night-vision@no-night-vision-flickering +athelas|阿塞拉斯* +more-beautiful-buttons@¨more-beautiful-buttons-fabric +aoa-end-realmstone + +adaptive-tooltips@ +variantbarrels@variant-barrels +variant-crafting-tables-fabric@variant-crafting-tables +immersive-structures@ +avaritia-port-fabric +explorify +variant-bookshelves-fabric@variant-bookshelves +variant-tiered-shields-fabric@variant-shields +libertys-villagers@libertyvillagers|自由村民 (Liberty's Villagers) + +rough-mobs-2|粗暴的怪物2* +barren-isles +korgelin +variant-composters-fabric@variant-composters +variant-grindstones-fabric@variant-grindstones +custom-villager-trades-new|自定义村民交易 (Custom Villager Trades) +spice-of-life-apple-pie-edition@|生活调味料:苹果派版 (Spice of Life: Apple Pie Edition) +xp-obelisk@|经验方尖碑 (XP Obelisk) +enhanced-searchability@|搜索增强* +compact-ui@ +lets-do-wine@lets-do-vinery|葡园酒香 (Let's do Wine / Vinery) +wealthyandgrowth@ +subtitle-highlight@|字幕高亮* +clockhud@clock-hud + +variant-lanterns-fabric@variant-lanterns +lanterns-bow@ +auto-crouch@ +my-village-pack@my_village_pack +variant-sticks-stuff@¨@variant-sticks-and-stuff +multiple-server-lists@ +superflat-biomes +combat-music@ +yuoenchants|Yuo的更多附魔 (YuoEnchants) +hibernal-herbs@ +better-resource-pack-sorting@ +sound-physics-remastered@|物理声效重制版* +@fix-quark-3951|Quark3951号issue修复 (FixQuark3951) +starcoffee +seed-finder-mod@seedfindermod +potato-food + +compassplus +create-industry@create-tfmg|机械动力:工业长路 (Create: Industry/Create: The Factory Must Grow) +simple-splash-screen@ +unusual-prehistory-forge@ +biospheres|生物圈 (Biosphere) +qkl@ + +dynamic-trees-tech-reborn|动态的树:科技复兴附属 (Dynamic Trees - Tech Reborn) + +daylight-mobs-reborn@ + +toast-manager +explosives-i-approve +miners-delight-plus@miners-delight|矿工乐事 (Miner's Delight / Miner's Delight +) +igniting-arrows +rise-of-the-animagus +lost-books +shingeki-no-kyojin-attack-on-titan +helicopters-madness@ +fanon-mutant-entities +technical-enchant@technical-enchant%2B|更多附魔重置版 (TechnicalEnchant+) +naturally-spawning-vex +better-game-menu@ + +seasonhud@¨seasonhud-fabric@ +stack-to-nearby-chests@|堆叠到附近的箱子 (Stack to Nearby Chests) +gmod-title-screen@ +create-steam-n-rails@|机械动力:汽鸣铁道 (Create: Steam 'n' Rails) +neutron +applied-cooking@|应用厨房* +@litematica-printer|投影打印机 (Litematica Printer) +recipe-printer@ +botarium@ +qfapi-and-qsl-biomefix-1-18-2@qsl-biomefix + +@cotton + +honey-expansion-add-on-for-farmers-delight|蜂蜜拓展 (Honey Expansion) +moguns@mo-guns +dayz-minecraft +infusion-table@|灌注祛魔台* +backroomtastic +xps-things|经验之谈 (XP's Things) +gravityapi@gravity-api +fabric-super-secret-settings@super-secret-revival +item-alchemy-fabric@item-alchemy +bat-elytra@|蝙蝠鞘翅* +super-secret-settings@ + +@plumeconfig +geophilic@ +critter-fights +hypothermic@ +nosecrets|不秘密 (NoSecrets) +extra-creeper-types +loot-casket +farmers-bundle-of-joy +musical-allays@ +pure-chaos-chaos-awakens +flatter-entities@ +daves-potioneering@ +last-days-of-humanity-tweaks +space-bosstools-giselle-addon +@ser|刷怪蛋配方 (Spawn Eggs Recipes) +mined-rider-kuuga +inventory-essentials@¨inventory-essentials-fabric +astral-additions|星辉附加* +simple-copper-pipes@¨simple-copper-pipes-forge +advanced-nbt-tooltips@|高级NBT提示框 (Advanced NBT Tooltips) +follow-me@ +stabx-modern-guns@ +justhammers@just-hammers|锤子合集 (JustHammers) +reinforced-deepslate-crafting|强化深板岩的合成* +jaopcacustom|JAOPCA自定义 (JAOPCA Custom) +friendly-fire@ +companion@¨companion-fabric +sebastrnlib@ +what-music-is-this + +elemental-combat|元素战斗* +roasted@|烘烤* +lotr-attack-indicator-addon@lotr-attack-indicator|魔戒攻击指示器 (LOTR Attack Indicator Addon) +steels-delight +lotr-pouch-viewer-addon@lotr-pouch-viewer|魔戒袋子内容展示 (LOTR Pouch Viewer Addon) +fastfood-delight|快餐乐事 (FastFood Delight) +festive-delight@|节日乐事* +project-arsenal +bathroom-blocks@|浴室方块* +galosphere@ +lazydfu-agent|DFU 禁用器 (Lazydfu-agent) + + +nether-mushroom-stew|下界蘑菇煲* +shibapi +galosphere-delight-a-farmers-delight-add-on +strong-crops@ +vegetarian-delight|素食乐事* +resourceful-config@ +coppers-delight +enderites-delight +simply-steel-forge + +wilder-world@ +advanced-solar-materials +@survival-tooltips +@notifyme +@damagedarrows +modulargolems@modular-golems|傀儡装配 (Modular Golems) +tooltip-scroll-fabric@tooltip-scroll +legoatooms-golden-berries@golden_berries +nyfcore +call-of-the-wild|荒野之声 (Call of the Wild) +more-lapis-lazuli@ +slimefun-essentials@ +decoration-delight|装饰乐事 (Decoration Delight: Refurbished) +@havio-cookbook|Havio的烹饪书 (Havio's Cookbook) +formidablefarmland@ + +survivality@ +dynamic-crosshair-compat@dynamiccrosshaircompat|动态准星兼容* +litewolfcore +vineyard-mod +@affectionate +mo-colors@ +peek@ +fancy-dyes@ + +extra-mod-integrations@ +mod-settings@ +dont-disappear-on-me@dont-dissapear +fastquit@|快速退出 (FastQuit) +violeta-cannons +war-of-valor + +no-tool-break +motionblur-fabric@motionblur|动态模糊 (Motion Blur) +epic-paladins +brazier@|生灵火盆* +stackcalc-revived@ +with-thursday-delight|乐在星期四* +osmiummod@osmium|锇 (Osmium) +@command-gui-buttons +wagyourminimap@ +chunks-fade-in@|区块淡入动画 (Chunks fade in) +sword-displays|刀剑展示架* +slabfishs-delights +saltymod-expanded@ +masonry-blocks +@sqlib +mssql-jdbc +packages@|自定义包裹* +giant-spawn@¨giant-spawn-fabric +@mtr-nte|纸板箱的交通扩展 (Nemo's Transit Expansion) +serene-shrubbery@ +gardens-of-the-dead@|死亡花园 (Gardens of the Dead) +pirate-hats|海盗帽子* +decor4fabric +mob-skills +clay-no-more-balanced|黏土不再制衡* +blossom@ +whipdashing@ +potiontimestacker-forge@timestacker +breezy@ +heart-balance@ +throwabletorch-fabric@throwabletorch¨throwabletorch +potion-descriptions¨potion-descriptions-fabric +half-doors@halfdoors +decor4forge + +mineterrariabosses +biomes-in-jars-forge@biomes-in-jars|群系罐子 (Biomes in Jars)¨biomes-in-jars-fabric|群系罐子 (Biomes in Jars) +@bocchitheblock +craftable-potion-combinations@craftablepotioncombinations +polylib@ +@creeper-fire-charge-fix|苦力怕火焰弹修复 (Creeper Fire Charge Fix) +tags-binder@ +fastcaps +throwable-fluids@ +time-in-a-bottle@|时间之瓶 Fabric 版 (Time in a Bottle (Fabric)) +upgraded-netherite-spartan-weaponry|下界合金增强:斯巴达的武器 (Upgraded Netherite : Spartan Weaponry) +simple-jams +nethers-cruelty + +atom-sweep|基石-清理 (Atom-Sweep) +the-gold-rush +optifabric-origins@ +lng-deco +darkrpg-reborn|黑暗 RPG:重生 (DarkRPG: REBORN) +modpack-manager@|模组管理器* +rocket-connector +hot-and-cold +donthityourfriend +drink-beer-unofficial-clockwerk-edition +novacraft@ + + +better-hurt-timer +drink-beer-refill@|喝啤酒啦:再来一杯* +minecraft-style-paintings +potato-cooking +@conveniented-forge-tags +clienttime +mcpitanlibarch@ + +manure@|粪便*¨manure-fabric|粪便 (Manure) +well@ + +enderling-invaders@ +proton +zetter-gallery@zetter-gallery-share-paintings +hedge-magic@ +arcane-additions@arcaneadditions|奥术增补* + +instrument@instrument%2B%2B|更多乐器 (Instrument++) +rpg-gods + +mob-crossing +just-enough-vehicles + +max-health-fix@ +synlib@ +tell-me-my-items@ +pollen +mavapi@ +player-hopper@ +guaranteed-villager-conversion +windchimes@|风铃* + +diamond-ingots@|钻石锭* + +inventory-sorting@ +mine-piece@orca-mine-piece +mine-piece-animation +hbms-nuclear-tech-mod-extended-edition +custom-skyboxes +breedable-killer-rabbit@|可繁殖的杀手兔*¨breedable-killer-rabbit-fabric|可繁殖的杀手兔 (Breedable Killer Rabbit) +bqenergyexpansion +magic-and-wand|法术与法杖 (Magic&Wand) +re-ftbqkeys@|FTB任务本地化键:重置 (Re-FTBQLocalizationKeys) +enchantment-sort|附魔排序* +wrapfix|换行修复 (WrapFix) +gem-crabs|宝石蟹* +create-rainbow-compound@rainbowcompound|机械动力:彩虹化合物 (Create: Rainbow Compound) +inmis-back-pack-mod-retextured +thonkutil +xp-storage@ +xp-storage-trinkets@ +carpet-layers@ +itemswapper@ +caxton@ +treasure2-wizardry-loot-pack +laser-creeper-robot-dino-riders-from-space|来自外太空的激光爬行者机器恐龙骑士* +paladins-furniture@|Paladin的家具 (Paladin's Furniture) +compact-status-effects|迷你状态效果配置*¨compact-status-effects-forge|迷你状态效果配置 (Compact Status Effects) + +end-goblin-traders-fabric|末地哥布林商人 (End Goblin Traders) +@mikulib + +playersync@|玩家数据同步 (PlayerSync) +create-more-potatoes@|机械动力:更多土豆 (Create: More potatoes)¨create-more-potatoes-fabric|机械动力:更多土豆 (Create: More potatoes) +primitive-beasts +raided@ +moisturization-fabric@moisturization +treasure2-twilight-forest-loot-pack +sanity-and-insanity +crops-love-rain@ +till-zombies-tear-us-apart +difficult-raids@ + +gag@ +bleach-awaken-by-deephantom15 +kleiders-custom-renderer-api@ +chefs-delight-fabric@chefs-delight¨chefs-delight-forge + +mcgltf@ +add-potion-into-your-food|给您下药了 (Add Potion into Your Food) + +@chunk-bordium +thaumic-energistics-extended-life|神秘能源延续版* +create-ender-transmission@|机械动力:末影传输 (Create: Ender Transmission) +horror-elements-mod +create-extended-cogs@extended-cogwheels|机械动力:更多齿轮 (Create: Extended Cogwheels)¨create-extended-cogwheels-fabric|机械动力:更多齿轮 (Create: Extended Cogwheels) +create-connected-block-textures + +cccbridge@ +liquid-burner@ + +create-electric-stonks +create-mounted-storages|机械动力:更多存储挂载 (Create: Mounted Storages) +minecells@|我的细胞 (Mine Cells - Dead Cells Mod) +@heatwaves|热浪 (Heatwaves) +steves-mini-pouch +infinite-abyss@ +@ktice +creator-overlays@creatoroverlays +maplecraft +invutils@ +@withfire-upgraded|手工艺:升级版 (With Crafts: Upgraded) +@usage-ticker +distant-worlds@ + +@advanced-vanilla-logistics +simple-flashlight-port@flashlight +alwaysopenwater@|始终开放水域 (AlwaysOpenWater) +quest-plaques@|任务牌匾* + +video-player@|视频播放器* +stendhal@ +dynamic-surroundings-remastered-fabric-edition@dynamicsurroundings_remasteredfabric +terraplusplus +blahaj@|布罗艾 (Blåhaj) +tinkers-levelling-addon@ +terramap@ + +villagemarkermod-for-liteloader +@show-durability|显示耐久 (Show Durability) +disable-enderman-picking-up-blocks@|禁用末影人搬运* +beautified-chat-server@¨beautified-chat-server-fabric +beautified-chat-client@¨beautified-chat-client-fabric + +axes-are-weapons@ +@curse%2B|诅咒+ (Curse+) +optifine-capes + +immersive-aircraft@|沉浸式飞机* +default-world-generator + +pasterdream|帕斯特之梦 (PasterDream) +animalistic +@qdresloader + +fabricskyboxes-interop@nuit-interop +old-inventorism +title-fix@title-fix-mod|标题修复* +create-alloyed-guns + +luna-slimes@ +special-drops +forgebrainlib +render-360 + +async-locator@ +minemention@|提及 (MineMention) +umapyoi@|马儿蹦跳*¨@umapyoi-fabric|马儿蹦跳 (Umapyoi) +origins-full-moon|起源:满月 (Origins: Full Moon) +codechickenlib-unofficial@ +codechickencore-unofficial@|鸡块核心非官方版 (CodeChickenCore Unofficial) +permafrost-biome + +ambient-additions@ambientadditions +sweep|扫雷 (Minesweeper) + +sekclib +betweenlands-storage +ore-stone-variants +food-effect-tooltips-forge@|食物效果显示Forge版 (Food Effect Tooltips (Forge)) +alexs-armoury + +dynamic-crops@ +super-chocolate-maker|超级巧克力制造* +naturalized + +rsls@ +emi-loot@ + +backhand@ +@stones-cookbook|Stone的烹饪书 (Stone's Cookbook) + +farmers-delight-jei-plugin@just-enough-farmers-recipes +keybind-fix@ +tales-of-villagers-the-infiltrators|村民之书:渗透者 (Tales of Villagers: The Infiltrators) +@morecullingextra +carpet-fixes@ +er-core|ER 核心 (ER Core) +rings-of-ascension@|提升戒指 (Rings of Ascension)¨fabric-rings-of-ascension|提升戒指 (Rings of Ascension) + + + +blanket@ +convenient-curios-container@convenient_curios_container +moogs-voyager-structures@ + +extra-aoa-info|额外虚无世界信息 (Extra AoA Info) +opulence@ +lonely-biome|孤独的生物群系* +lamps + +generic-ecosphere +wired-redstone@wiredredstone +pixelgalaxy +hopper|漏斗+ (Hopper+) +excalibur-the-mighty-sword +undergarden-paths@|深园小径* +undergarden-tetra-patch|深暗之园:Tetra 兼容 (Undergarden/Tetra Patch) +uncrafter@ +@pebblegetter + +pangea-ultima +@fpspluslf|FPS优化Legacy Fabric版 (FPS Plus Legacy Fabric) +table-top-craft@¨table-top-craft-fabric +ddyc@ +@stonecutter-damage +shipping@ +structureutils +@cloudmusic|云音乐 (CloudMusic) +i-like-wood +macaws-furnitures-biomes-o-plenty@|Macaw 的家具:超多生物群系附属 (Macaw's Furnitures - Biomes O' Plenty) +macaws-furnitures-oh-the-biomes-youll-go@|Macaw 的家具:你将去的生物群系附属 (Macaw's Furnitures - Oh The Biomes You'll Go) +armiger +news-pillagers +rangers-haven +heyberryshutup@ +destroy-on-death@ +@yes-steve-model|是,史蒂夫模型 (Yes Steve Model) +macaws-roofs-oh-the-biomes-youll-go@|Macaw 的屋顶:你将去的生物群系附属 (Macaw's Roofs - Oh The Biomes You'll Go) +macaws-roofs-biomes-o-plenty|Macaw 的屋顶:超多生物群系附属 (Macaw's Roofs - Biomes O' Plenty)¨macaws-terraformersmc@¨@macaws-roofs-biomes-o-plenty|Macaw 的屋顶:超多生物群系附属 (Macaw's Roofs - Biomes O' Plenty) - 原, +configured-feature-saplings@ +coyote-time@ + +macaws-bridges-modding-legacy|Macaw 的桥梁:Modding Legacy 附属 (Macaw's Bridges - Modding Legacy) +macaws-bridges-aurora@macaws-aurora|Macaw 的桥梁:Aurora 附属 (Macaw's Bridges - Aurora) +betterlands +koremods@ +heart-of-ender@ +heart-of-spartan@ +macaws-fences-biomes-o-plenty|Macaw 的栅栏与墙:超多生物群系附属 (Macaw's Fences - Biomes O' Plenty)¨@macaws-fences-biomes-o-plenty|Macaw 的栅栏与墙:超多生物群系附属 (Macaw's Fences - Biomes O' Plenty) - 原, +endemic@ +lucys-sloths +@gdtweaker +drop-the-rock-no-tree-punching-compat@ +macaws-bridges-abnormals@macaws-abnormals|Macaw 的桥梁:Abnormals 附属 (Macaw's Bridges - Abnormals) +macaws-bridges-shroomed|Macaw 的桥梁:Shroomed 附属 (Macaw's Bridges - Shroomed) + +shroomed +rlcraft-structures-not-official@rlcraft-structures-%28not-official%29 +moving-sunflowers +lunar-mana-generator|月光魔能制造器* +ost-overhaul@ +chunk-by-chunk@chunkbychunk +beyond-planets-core|飞越群星:核心 (Planeteer - Core) +webdisplays@|内置网页浏览器 (WebDisplays) +mcef@|Minecraft Chromium 嵌入式框架 (Minecraft Chromium Embedded Framework) + + + + +the-monk-mod +expanded-enderchest@ +text-utilities@ + +memorysweep@|内存清扫 (Memory Sweep) +@explosive-enhancement|爆炸动画增强 (Explosive Enhancement) +autostereogram@ +bounced|Bounced! - 不活跃¨@bounced +identifier-translation@|标识符翻译* +vanity@vanity-core +reid@ +its-been-twelve-years +riftlin +sorcerium@ +zeropoint +campful + +well-rested@ +raw-input-1-12-2@raw-input +spider-pig +jingames-hair-c@hair-c +map-tooltip@ +planetoid +golem-tweaks +yummy-foods +home-system-forge +geta-footwear +catwalks-inc +firework-rocket-duration +@chatwalk +emcstage@ + + + +@broken-lead-warner|拴绳断裂警告 (Broken Lead Warner) +@alwayzsteve|永远史蒂夫 (Alwayzsteve) +vanilla-vistas +menulogue +archaicfix¨@archaicfix +ekac@|糕蛋 (ekaC) +byg-plus|你将去的生物群系+ (Oh The Biomes You'll Go Plus) +farmers-compats +@map-compass + +space-research-addon-for-galacticraft3 +patchoulibutton|帕秋莉手册按钮 (PatchouliButton) +sonorama +vanity-dungeons-pack +divinerpg-processing-compat +weapon-master@|武器大师* +your-ideas|你的想法* +vanity-ancient-tool-variants@ +motion-capture-mod-mocap@motion-capture|动作捕捉 (Motion Capture) +wormhole-portals@wormhole|虫洞 (Wormhole) +dragon-magic-and-relics@|神龙魔法与遗物* +yummy-foods-forked +content-creator +fullblock-energistics@ +youmatter@ +vanity_battle_axes +markdownmanual@|Markdown 手册(Markdown Manual) +powershot@ +@crockpot-tweaker +automatic-tool-swap@ +knight-quest-reforged@knight-quest¨knight-quest-fabric¨knight-quest +modernfix@|现代化修复 (ModernFix) +blades-plus +homeostatic@|稳态* +super-saturation|超级饱和度* +rpg-rpgae|RPG天启进化 (RPGApocalypticEvolution) + +dungeon-difficulty@ +cazfps-chronicles +unstable-tools@unstable|不稳定金属工具* +tech-reborn-patchouli +biome-bundle +moon-phase-info@ +@fabwork + +advanced-tweakery +creeper-hector +tightened-village-security +@mcr_blahaj|布罗艾扩展版 (Blahaj Expanded) +@blahaj-reforged|布罗艾:重铸 (Blåhaj - Reforged) +buddingcrystals +dynamic-trees-tectonic|动态的树:Tectonic附属 (Dynamic Trees - Tectonic) +prp +@moonphaseinfo%2B +harvest-day|丰收之日* +hungteens-lib@pangteens-lib +more-tool|更多工具* +@ex-hud +@hoarding|囤积 (Hoarding) + +optifine-crash-fix + +wyrmroost-patch|猛龙之居补丁* +travelers-dream +thaumic-travelers-dream +@gasstation + +aetherium-ashen-armor +smoothmenu|平滑菜单 (Smooth Menu) +@cabricality-mod +unusual-fish@unusual-fish-mod|独特鱼类 (Unusual Fish Mod) +obscure-tooltips@ + + +otg-tutorial-world +otg-skylands +fxs-rail-optimization@rail-optimization +morejs@ + +@moresnowballls|更多雪球 (MoreSnowballs) +valkyrien-skies-control@ +the-end-expanded-mod-ice-and-fire-addon +vault-patcher@|保险库补丁* +projectile-damage-attribute@ +noteable@ +deftulib@ +trofers@ +obscure-api@¨obscure-api-fabric + +death-punishment@|死亡惩罚* +inventory-tabs-forge +reaper@ +containersearcher@csearcher + + +screencapper@ +valkyrien-skies-world@ +lucky-tnt-lib@ +waffles-placeable-foods@ +otg-the-void +otg-flatlands +otg-dungeons +@light-meals-quilted +gtnhlib@ +sculpt@ +levelhearts@ +bring-back-luck@bringbackluck¨forge-bring-back-luck +teleport-master@|传送命令* +@mufog|锻造 (Mufog) +betterparry@|更好的格挡 (BetterParry) +rltweaker2 +thaumcraft-aspect-creator@|神秘时代要素创建器* +vanity_katanas +pixels-character-models@|Pixel 的角色模型 (Pixel's Character Models) +l2-complements@|莱特兰-扩充* +epicfight-auto-shouldersurfing +zsrarity +zenscroll +zentraits +l2-archery@l2archery|莱特兰-弓艺* +vanity-metallurgical +minespaceex +gregious-maximus +shut-up-model-loader +cultural-delights-fabric@|多元乐事(Fabric 版) (Cultural Delights [Fabric]) +collectors-reap@ +bones-and-swords +vanity-shedds-mystical-toolsets-pack +emc-builders-wand + +vanity-charcutier +hunger-in-peace + +lexicon@¨lexicon-fabric +scaffolding-drops-nearby@¨scaffolding-drops-nearby-fabric +fuel-info@ +glacier-ice +gtnhmixins@ +dawn-to-dusk +open-tower-defence@|开放式塔防* +mtr-station-decoration@station-decoration|MTR车站装饰 (Station Decoration) +perviaminvenire + +silverbirch@silver-birch + +flame-sweeping@|烈焰横扫* +creepypastas-mod +more-slab +landk-brick +kubejs-offline@|KubeJS 离线文档 (KubeJS Offline Documentation) + +ex-nihilonatureminerals|无中生有:传承 - Nature's Minerals 扩展 (Ex Nihilo: Sequentia - Nature's Minerals Addon) + + +memory-settings|内存设置* +tiny-item-animations@ +more-plates-revamped@|更多金属板重置版* +extended-slabs-plus@ +brewin-and-chewin-fabric@|饮酒作乐 Fabric 版 (Brewin' And Chewin' [Fabric]) +particular +longer-login-times +broglis-plants@ +rlmixins@ +simplehats@simple-hats|简单帽子 (Simple Hats) +timeoutout-fabric@timeoutout +fabric-furnaces + +mixinbooterlegacy +basalt-walker-reborn|玄武岩行者:重生 (Basalt Walker : Reborn) +create-industrial-chemistry@|机械动力:工业化学 (Create: Industrial Chemistry) + +@flaming|火焰熊熊 (Flaming) +cruelars-triforcemod + +@morespawneggs|更多刷怪蛋 (MoreSpawnEggs) +beautify-refabricated@|美化!重织 (Beautify: Refabricated) + +manatweaks +chicken-nugget +goldfish-myth +rezombies +wound@|外伤* +survival-campfire@ +eyes-mod@eye-blocks + +colorful-rods|缤纷彩烛* +xp-plus + +jaffas +no-holds-barred-halloween-mod + + +@post-join-leave-message|发送加入信息与离开信息到网址 (Post Server Join & Leave Messages to URL) +advanced-extended-creative-mode@act +even-more-creatures-mod +eerie-entities +better-weather-revived + +rlcombat@|更好的战斗-RLCraft版 (RLCombat) +botanical-addons +@scoreboards-backup|计分板备份 (Scoreboards Backup) +hodgepodge@ +fast-projectile-fix +edivadlib@ +systeams|热力系列:蒸汽锅炉 (Thermal Systeams) +waymaker@ + +dmod +extra-redstone-craft|更多红石合成* +farmers-respite-fabric|农夫暇事(Fabric 版) (Farmer's Respite (Fabric)) +wizards@|魔法师 (Wizards (RPG Series)) +basketcase +primal-lib +biomes-youll-go-1-12-2-fixed|你将去的生物群系修复版 (Biomes You'll Go Fixed) +rune-crafting@runes|符文 (Runes) +controlled-random +leos-bosses|Leo的Boss (Leo's Bosses) +leos-illagers + +modularmachinery-community-edition@|模块化机械:社区版 (Modular Machinery: Community Edition) +wearable-backpacks-rlcraft-edition@|可穿戴背包-RLCraft版 (Wearable Backpacks: RLCraft Edition) +spartan-fire-rlcraft-edition@spartan-and-fire-rlcraft-edition|斯巴达之冰与火-RLCraft版 (Spartan and Fire: RLCraft Edition) +frame-void-patch-mc-59363@frame-void-patch-(mc-59363) +archprp@|帕秋莉手册加载补丁跨平台版 (Patchouli Resource Patch - Arch/Architectured Patchouli Resource Patch) +clear-skies-forge-port +spell-power@ + +morecrashinfo|更多崩溃报告信息 (MoreCrashInfo) +epicfight-saopack|史诗战斗:ACG附属包 (EpicFight ACG AddonPack) +screenshot-viewer@|截图查看器* +gml@ +@futurepack-additions|飞向未来附加 (Futurepack Additions) +bee-fix|蜜蜂修复* +spawner-fix|刷怪笼漏洞修复 (Spawner Bug Fix) +block-limit-fix@block_limit_fix +nochatlag@|聊天无卡顿 (NoChatLag) +spell-engine@|法术引擎* +spellblade-next@spellblades-and-such +netherite-road-2@|下界之路2* +@tileentity-reset-fix +notenoughrecipebook@ +urushi-mod|漆 (Urushi) +nicephore¨nicephore-fabric¨@nicephore +terraria-paintings¨terraria-paintings-fabric +minegooseduck +floating-islands + +@qwq-library +scorched-guns@scorched-guns-2 + +fred-qol@fred +mekanism-ce-unofficial|通用机械社区版:非官方 (Mekanism CE Unofficial) +guntopia-legend-of-the-guns +slots-checker@ +carpet-ams-addition@¨@carpet-ams-addition-legacy +pixelmon-gameshark +hidden-creepers-creepers-pretend-to-be-other-mobs +ob-core +ob-pandorica +no-weather-effects@ +ob-tooltips +hekate-lib +loot-journal@¨loot-journal-neoforge¨loot-journal-fabric + + + + + + + + + + + + + + + + + +structure-floater-fabric +applecore-unofficial@|苹果核非官方版* +drilling-veins@ +server-chat-history@|服务端聊天历史* +scriptor-magicae@|字符魔法师* +json-entity-models-jems@|JSON实体模型 (JSON Entity Models) + + + +rain-of-hell + +suggestion-provider-fix@suggestionproviderfix +worldblender@¨world-blender-fabric@worldblender-fabric +no-oceans|无海洋的世界* +monoblocks +tinkers-things-json@tinkers-things|匠魂杂物 (Tinkers' Things) +free-cam@freecam +workings@ +@mod-loading-screen|模组加载屏幕 (Mod Loading Screen) +lucky-cases +atmosfera@ +feruchemy-allomancy|藏金术 (Feruchemy) +alivecombat@|战斗生机 (AliveCombat) +dialog|对话框* + + + + + + + + + + + +fix-selected-item-text +dregora-o-plenty +integrated-api@ +the-betweenlands-eternal-melodies|交错次元:永恒旋律 (The Betweenlands: Eternal Melodies) + +frozen-apocalypse@|冰封启示录* +whymap@ +craftify@ +overgrown-cities-fabric +night-config-fixes@ +standardconfigs +armor-adjustment|盔甲调整* +enchanting-max_level@enchanting.max_level +fixbookgui@ +custom-explosions|自定义爆炸* +datapacks-screen|数据包屏幕 (Datapack Screen) +pandoras-box@|潘多拉的魔盒 (Pandora's Box) +boss-rifts +random-teleport-altar +syncpotioneffects +aobd-ore-chunks +evasive-items@ +spagheters-enchants +factory-api@ +tempad@|任意门* +structure-void-toggle@|结构空位切换* +@cactusfix +morezombies|更多僵尸 (More Zombies) +mushroom-quest@ +chowder-express@ +mod-browser|模组浏览器* +fastback@ +copper-hopper@|铜漏斗* +oxidized@ +ping-wheel@ +dark-waters@ +sneak-tweak@ + +serene-seasons-fix@|静谧四季修复* +cross-dim-commands|跨维度指令 (Cross-Dim Commands) +temporary-spawners@ +slyde@ +phonos@ +spelunkery@ +@endless_cake|无尽的蛋糕 (Endless Cake) +rusticated +invmovecompats@|边拿边走兼容 (InvMoveCompats) +@tinkerers-smithing +hesperus|燐* +inventory-hotswap +corail-backpack +chomper|食人花* +flamelib + +better-planting@ +superfancyclouds-refabricated@|超级华丽云:重织版 (SuperFancyClouds: Refabricated) + +pet-tracker +@splashfox|狐狸加载界面 (SplashFox) +tap-tab@ +mekanism-ce-tools|通用机械工具:社区版 (Mekanism Community Edition: TOOLS) +mekanism-ce-generators|通用机械发电机:社区版 (Mekanism Community Edition: GENERATORS) + +@nbt-data-exporter|NBT数据导出 (NBT Data Exporter) +more-mobgriefing-options@ +cobalt-mod-think-blue@cobalt-mod +graphutil@ + +comfy-sky@|舒适空岛* +entropy@ +ngv-forge@ngv¨ngv-fabric +world-of-wonder@ + +full-brightness-toggle@ +@your-ideas|你的想法 (Your Ideas) +nohurtcam@ +arrows-break-torches@arrowsbreaktorches|箭矢破坏火把* +golden-delicacies +hightiercrops +commandspy@ +slimyfloor +daily-dad@|每日冷笑话* - 客户端版¨daily-dad-server@|每日冷笑话 (Daily Dad) - 服务端版 +good-ending@ + +creeper-nuggets +coherent-villages + + +terrains +bugtorched-curseforged|BugTorch - 他人的非官方上传¨@bugtorch +better-tridents@|更好的三叉戟* +undead-unleashed@ +missing-wilds@|遗落荒野*¨missing-wilds-forge|遗落荒野 (Missing Wilds) + +stellar-fluid-conduits|恒星流体导管* +advancement-locator +universal-tweaks@|通用修改* + +@succ +welcome-to-the-jungle|丛林传说 (Welcome to the Jungle) + + +transparent@ +hopperplus-instant-hoppers +sbm-merpig +lwjgl3ify@ + +mine-treasure +creates-delight@|机械动力乐事 (Create's Delight) +mo-villager@mo-villagers|更多村民 (Mo' Villager) + +logunspam + +chatimage@|聊天栏图片显示 (ChatImage) +@treasurehunt|寻宝 (TreasureHunt) +no-tema-stahp +labels@|存储标签 (Storage Labels) +@qdaa + +better-creeper-mod|更好的苦力怕 (Better Creeper) +regions-unexplored@|未至之地* + +rancraft-penguins + +more-mob-variants@|更多生物变种* +experience-rings|经验指环* +deeper-oceans|更深的海洋* +im-crossover-ic2 +libjf@ + +hopper-xtreme +maleks-infinity-gauntlet +malum-skyland|灵灾空岛 (Maland) +betweencards + + + + + +google-chat@ +resclone@ +tame-them-all + +little-contraptions + +convenient-decor@|精简锦饰* +mixin-conflict-helper@ +create-decoration-casing +create-brass-coated|机械动力:黄铜覆壳 (Create: Brass Coated) +sculked@ +better-mob-spawner|更好的刷怪笼* +planeteer-dimensions|飞越群星:维度 (Planeteer - Dimensions) +planeteer-machines|飞越群星:机器 (Planeteer - Machines) +create-central-kitchen@|机械动力:中央厨房 (Create: Central Kitchen) +jamd +ninezeros-gun-mod-addon +donthurtthatboat@ +@horsebuff +enchanting-table-descriptions@|附魔台描述* +harvest-with-ease@ +trade-refresh@|交易刷新* +create-molten-geodes +thats-a-lot-of-items +nether-skeletons@netherskeletons + +penguins +rocket-squids + +wood-stuff +magmafurnace-weapons-bosses-and-more +monstersregulararmy +why-does-my-food-taste-like-that +iron-generators +elytra-swapper-forge|鞘翅切换* +ftb-team-islands-forge + +market-crates|集市板条箱* +industrial-renewal-port|工业复兴移植版* +tfcm@|群峦合金非官方版 (TFC Metallum U) +tnt-time-mod +drunken-mug +cartoonish-horde-library@villainous-horde-manager +limited-lives@|有限生命*¨limited-lives-fabric|有限生命 (Limited Lives) +universe-box@ +invtweaks-emu-for-ipn@ + +create-compact-exp|机械动力:压缩经验* + + + +heat-and-processing +skytheorylib +ad-astra-giselle-addon@ +shift-scroll-fix@ +gim|原神农业 (Genshin Impact Cropper) +oxygen-daily-rewards +structure-compass@|结构指南针* +cold-snap-horde@ +tis-the-season + +@baubles-expanded +cobblehaters +mob-captains|怪物队长* + +@sound-track +snowballing +winter-essentials@winter_essentials +embeddium-extras@|镁/铷附属:土豆版 (Magnesium/Rubidium Extra: Potato Editon*) +@realistic-cruelty|真实残忍 (Realistic Cruelty) +trapper-pelts@ +workshops-of-doom@ +create-mechanical-spawner@|机械动力:动力刷怪笼* + +amethyst-core@ +fzzy-core@ +tnt-breaks-bedrock@ +from-the-north@ +spruce-willis-the-xmas-tree@ +sweet-potato-core-spc|地瓜核心 (Sweet Potato Core) +merge-enchantments@ +turkey|火鸡* + +snowy-weaponry@ +dungeon-mobs-reborn +quickteleports +powerfuljs +memoryclear-refabricated@memory-clear-refabricated|内存清理:重织 (Memory Clear : Refabricated) +villager-comfort|村民舒适度* +ender-quarry|末影采石场* + + +mythic-upgrades-fabric@mythic-upgrades¨mythic-upgrades-forge +fat-chicken + +snowmancy@ +@roadchina|道路中国 (Road China) + +@immersive-snow + +functional_tfc@ +better-end-potato-edition|更好的末地:土豆版* +bossbar-stack@ +origins-umbrellas@|起源:雨伞 (Origins: Umbrellas) +tfc_decoration +shroom-dealers@shroom-dealers! +nbtedit +burlap-sack|粗麻布袋* + + +animalnet +biome-backlog +doespotatotick@does-potato-tick|远物停载:土豆版 (Does Potato Tick?) + +welcome-to-meadow@lets-do-meadow|青青草甸 ([Let's do] Meadow / Cheese!)¨@lets-do-cheese|青青草甸 ([Let's do] Meadow / Cheese!) +universal-enchants-forge@universal-enchants|通用附魔 (Universal Enchants)¨universal-enchants-fabric|通用附魔 (Universal Enchants) +aa-farmer-compat + + + +better-crates + +vanillaicecreamfix@ +actually-unbreaking-forge@actually-unbreaking¨actually-unbreaking-fabric +handcrafted@|精巧手艺* +no-nether-teleport@ +crasher|崩溃机* + +easywhitelist@|简易白名单 (EasyWhitelist) +clayworks@ +miniscaled@ +lost-cities-potato-edition|失落的城市:土豆版 (Lost Cities: Potato Edition) +endless-noend +matmos-2@matmos-ambient-sound +tfc-item-barrels + +villagersplus-forge@villagersplus¨villagersplus-fabric +data-criteria@ +japanese-emoji-commands +attack-on-christmas + +voxel-latest +the-printer@ + +flying-cullers@ +timeless-power@ +create-deco-fabric-fixed +calibrated@ +frozen-memories +atlantis-api@ +nutritional-balance +profession-lock + +spectrum-jetpacks@ +difficult-caves + +spartanlands-rereforged +red-pandas@ + +simple-cobblestone-generator-forge +floral-flair-fabric¨floral-flair +vertical-slabs-compat@ +ruins@philips-ruins +cobblemon@|方块宝可梦* +mysterious-biomes + +head-in-the-clouds@ +fdmc +rpg-style-more-weapons@rpg_style_more_weapons + + +easy-experience + +full-turtle-armor@ + + +thip@tokusatsu-hero-instrumentality-project|特摄英雄补完计划 (Tokusatsu Hero Instrumentality Project) + + +spyglass-astronomy@ +mchalo@ +darkmenu-darkrpg-legacy-menu@darkrpg-menu + +rl-artifacts|奇异饰品-RLCraft版 (RLArtifacts) +azurelib@ +harder-monster-boats-finer-boat-control@harder-monster-boats +spyglass-improvements@|望远镜改进* +vanilla-zoom@|原版缩放* +time-in-a-bottled +improved-end@ +raw-block-smelting +nocubes-better-blast-furnace +bugjump@ +cluttered@ +digitality + +nautral-decor-mod@natural-decor-mod + +cobbled-deepslate-generator +female-villagers|女性村民* + +subaquatic@ +leos-sans +@damagevignette +no-irom-farm +amethyst-tools-mod@ +@grate-blocks +lush-forests + +retraining@ +ender-ore@enderore +ars-instrumentum +easier-sleeping@ +harder-farther +custom-signposts +galactic-research@ +mining-dimensions-fabric +bejs +screenjs +pioneer +@sha1runtime +night-vision-enchantment-forge@night-vision-enchantment +galactic-computers@ +mini-cites +ad-tetra@ad-tetra! +chest-cavity-forge-port@|胸腔Forge版 (Chest Cavity - Forge Port) +entity-lagfix-lag-fix +audioplayer@ +vibes@ +disco@ +the-mcxr-core@mcxr-core +mcxr-play@ +beneath-the-wetlands@ + +add-on-the-abyss-beginning +reusable-rockets@ +item-info +florist +omni +frostrealm@ +nameless-trinkets@ +unsafe-spawns + +bubbles@pop +nan-health-fixer@|假死修复:土豆版 (Potato NaN Health Fix) +@voxelmap-updated +blood-and-stuff@ +yungs-better-nether-fortresses@|YUNG 的下界要塞优化 (YUNG's Better Nether Fortresses)¨yungs-better-nether-fortresses-fabric|YUNG 的下界要塞优化 (YUNG's Better Nether Fortresses)¨yungs-better-nether-fortresses-neoforge|YUNG 的下界要塞优化 (YUNG's Better Nether Fortresses) +squidless + +enders-delight@|末影乐事 (Ender's Delight) +decostorage@decorative-storage +mahogany +aspen +unmending-potato-edition|经验不修补:土豆版* +mc-modsens-rocket-launcher-arl|简易火箭筒 (Allen's Rocket Launcher) +@item-tributes +assorted-discoveries +not-so-shrimple-forge +valkyrien-computers@ + +gems-jewels +@angling +dimensional-sync-fixes@|维度同步修复* +exhaustion-fatigue@ +chainmail-bucket@ +preciseblockplacing +accurate-block-placement-reforged +carpet-tctc-addition@ + +plushie-mod@plushie +shield-expansion@ +many-systems +barbarians|野蛮人* +minecraft-startup-sound-aka-mojaaaaaang +realistic-terrain-generation-unofficial|真实地形生成非官方版* +combat-enchantments@combatenchantments|战斗附魔* +fastentitytransfer@ +chalice + +one-twenty-update +minecraft-middle-ages@days-in-the-middle-ages +gibmemojangstudio +redwolf-music-expansion@ +@nameprotect +gliders@ +@no-teleport-cooldown +riding-partners@|双人骑行* +rpgskillable +extra-discs@ +propertyerizer +waxable-coral@|涂蜡珊瑚* +@fireframe|火焰框架 (FireFrame) +goated@ +morebread@ + + + +ice-prevents-crop-growth@ +@gold-coins-mod +glowing-ores|矿石发光* + +falsetweaks@ +metaworlds-unofficial@metaworldsunofficial|元世界:非官方版* +tslateffectslib@ +tslatentitystatus-tes@tslatentitystatus +rounds-invisible-frames@invisible-frames-mod +elytra-capes@elytracapes +config-swapper +viafabricplus@ +menu-companions +entity-render-distance-extender@erde +rpg-stamina|RPG 耐力 (RPG Stamina) +mjs-animations +deepslate-generator +hairy-zombies + +footprintparticle@|脚印粒子 (FootprintParticle) +tabbychat +@leafculling +unimixins@ +nei-lotr-fa|魔戒:第一纪元 NEI 插件 (NEI LOTR FA) +nogravity-mod@nogravity|零重力 (NoGravity) +milk-of-magnesium +@slumber +nei-recipe-handlers +nox-a-mob-and-difficulty-overhaul@nox +christmas-festivity +tameable-beasts@ +cute-hermit-crabs¨cute-hermit-crabs-fabric + +receiver-mod +chargepads|充电座 (ChargePads) +snow-real-magic-potato-edition|雪!真实的魔法!(土豆版)* + +ravenous-void +immersive-engineering-blueprint-tweaker@iebpt +mob-compack +kore-sample +multiworld + +peat-zombie +ragna-goblin-updated|Ragna Goblin - 新¨ragna-goblin|Ragna Goblin - 旧(不再更新) +demogorgon@ +haunted-fields +health-command@ +splash-logo-color-fix +frv-tools +bombs-bandits +immersive-cavegen@icg +villager-brute +exspiravit-magicae +equiped +limited-chunkloading +custom-villager-trades-forge@custom-villager-trades|自定义村民交易 (Custom Villager Trades)¨custom-villager-trades-fabric|自定义村民交易 (Custom Villager Trades) +dungeons-more-mod +ancient-trees +extraskills +scotts-tweaks +kore-sample-l +book-wyrms@ +nakaroths-herdcraft-l|群兽行为L* +mystical-oak-tree@ +ancient-trees-l +butchercraft@|屠宰工艺* +zombie-invasion@ +clay-soldiers-reborn +geore@ +mt-claysoldiers2-forge +safekeystring|安全键位名 (SafeKeyString) +loadingtips +gear-o-plenty +regional-water +battle-text +music-choices + +chemcraft-snowfall|落雪 (Snowfall) +closed-captions|隐藏式字幕* +dont-pick-up +easy-breeding|简单繁殖* + +chemcraft-core + +bonsai-man-mod|盆栽人* + +pet-cemetery@ +chemcraft-geocraft + +steamagerevolution|蒸汽时代革命 (SteamAgeRevolution) + +brewcraft +zombie-awareness-freeze-fix|僵尸意识冻结修复* +integrated-stronghold¨@integrated-stronghold|Integrated Stronghold - 未及时更新 +grass-overhaul@ +@purpurclient +alkimicraft-part-i-project-oasis +wild-caves-3|洞穴装饰3 (WildCaves 3) +modest-mining@ +vanilla-compats +vending-block|自动售货机 (Vending block)¨vending-block-1-5|自动售货机 (Vending block) + +vending-block-revived|自动售货机:重生* +assortment + +opotato|哦,土豆!* +contingameime@|游戏内输入法续更版 / 游戏内输入法 Forge 重置版 (ContingameIME / IngameIME-Forge / IngameIME-Forged) +ccastroadds +aerial-hell@ +swashbucklers@ +style +eatable-livestock +hunger-strike@|绝食* +extrabuttons@extra-buttons|更多按钮 (ExtraButtons) +big-doors +blockshot@ +jump-over-fences-forge@jump-over-fences +luppiis-ladders + +anthropophagy@ +ambient-structures +minegicka-iii|魔能3 (Minegicka III) +hopo-better-underwater-ruins + +just-another-crafting-bench +tiny-ents + + + +nei-emmaitar +magicrafted-rings-of-power + +skybox-loader-forge +easy-feed@mcf-easyfeed|简单饲养 (Easy feeding) +create-buffers-beams +small-boats-mod +redev@ +wands-and-wizardry +geore-nouveau@ +crimsonsteves-more-mobs +the-ulterlands +mt-lotr +asjcore@ +bane-tooltips|克星信息显示* +lava-crystal +literal-sky-block +@literal-sky-block-fabric +aniskin +mob-stacker@ +mob-stacker-integration@ +mob-stacker-farming@ +lightspeedmod@lightspeed +coffee-delight@|咖啡乐事* +simple-sculk-dimension-deeper-dark +no-more-inifinite-water@finite-water +choo-choo-craft +eco-mobs +classic-hostiles +chalk-fabric-colorful-addon@chalk-colorful-addon +@asielib +food-bosses-reheated +dreamland-biomes +@bedrockjukebox|基岩版唱片机 (BedrockJukebox) +environmental-expansion +neutrality +bygone-land +the-amazing-world-of-mobs +falloutcraft@ +botania-additions|植物魔法附加* +dragonrealm +ydms-ducks-mod@the-ducks +arthropod-reborn +the-undefeatables@undefeatables +durts-nether-dungeons@nether-dungeons + +health-and-hunger-tweaks +@create-track-map +improved-hoes +orehider@ +full-grown-crop-marker@ + + +luggage|行李箱* + +slime-breeder-advanced +ahznbs-naruto-mod@ahznbs-shinobicraft +delightful-mining + +@beancoin + +trimmable-tools +@tablesaw|锯木台 (Tablesaw) +glowglass@ +mc-mods-the-fan-made-discs@all-the-fan-made-discs +from-the-fog +more-ladders@ +reblured@ +spellbound-weapons + +sword-parry@ +@create-ruins +@minegpt +respiteful@|闲暇风味* +useful-slime@¨useful-slime-fabric +kelvins-better-player-animations + + +tfc-casting-with-channels +tfc-create +max-health-fixer +gjeb@ +bundled-delight@ + +travellerstoasts@ + +@ijo-pona-poki +sk1llful@|身怀绝技 (Skillful) +salt@ +monobank@ +sooty-chimneys@ +areas-undefined +trivialthoughts|魔金琐想 (TrivialThoughts) +tfc-delight +myssyheads-sculk-adventures +waystone-towers@ +smitheesfoundry@ + +beach-slimes +rideable-ravagers@|可骑乘的劫掠兽* +splatcraft@|斯普拉遁* +beneath-the-snow +sea-creeps@ +skills-v|技能:香草 (Skills: Vanilla) + +flower-foxes +pack-it-up@ +mine-trading-cards-open-source-edition@mine-trading-cards +chainsaw-man-csm|电锯人 (Chainsaw Man) +superior-shields@ +alternative-world-save-location@ +skills-firearms|技能:枪械 (Skills: Firearms) +tx-loader@ +Reacharound@reacharound +variety-aquatic|Variety Aquatic - 已被续作替代¨@variety-aquatic +blocks-booster@ + +tfc-cast-iron-grill@|群峦铸铁烤架 (TFC Cast Iron Grill) +tfc_metalwork|群峦金属加工 (TFC Metalwork) +@gan_delight|赣味乐事与家常菜 (Gan Delight Reborn) + + +furniture-compatibility-for-macaw-tfc|Macaw的家具:群峦传说附属 (Furniture Compatibility for Macaw/TFC) +roof-compatibility-for-tfc-macaw|Macaw的屋顶:群峦传说附属 (Roof Compatibility for TFC/Macaw) + +tfc-supplementaries|群峦锦致装饰 (TFC Supplementaries) +tfc-ie-crossover|群峦传说:沉浸工程兼容附属 (TFC + IE Crossover) +bridging-mod@ +geode-plus@|晶洞+ (Geode+)¨geodeplus-backport|晶洞+ (Geode+) +cursed-difficulty@ + + +algane +dawn-of-time@|时之黎明 (Dawn of Time) +kubejs-projecte@ +biome-backport +infernal-geode +geode-o-plenty +the-banished@ +pufflos +wizardry-the-next-generation + +lagbgon +doodads-fabric +subject-three-sweet-dreams@|科目三:甜蜜的梦 (Subject Three: Sweet Dreams) +ocd-shaders-mod +create-shrunk +cherish +the-lost-castle@|失落城堡*¨the-lost-castle-fabric|失落城堡 (The Lost Castle) +llamarama|羊驼!* +simple-conveyors +itemupgrader-core +itemupgrader +screenfx@ +dense-ores-abundant@dense-ores +tinkers-thinking@|工匠巧思 (Tinkers' Thinking) +simple-musket@ +cash-ores@ +stacked-dimensions +@unlimited-maxhealth +floral-enchantment@¨floral-enchantment-fabric +newworld@new_world +@more-stats +notifmod@ +wallfence +ezwastelands +zombie-survival-kit|末日生存工具包* +kobolds@|狗头人! (Kobolds!) +supernatural@|超自然* +better-ladder-placements@|Salju的梯子 (Salju's Ladders) +magic-mirrors-forge + +abundant-atmosphere@ +swampex +bamboo-combat@ +nicer-skies@ +bed-benefits@ +accurate-maps@ +incantationem@ +rebind-narrator@ +earth2java@¨earth2java-mobs +fairy-dragons +turned-changed-extension +immediatelyfast-reforged@ +magic-mirror +magic-mirror-fabric@magic-mirror +chassis@ + +fast-doll@fastdoll +better-lily-pads@|更好的睡莲* +mo-zombies-wave@ +almost-all-the-ores +@Geyser +supplementaries-squared@ +changed-addon-plus@ +functional-armor-trim + +belly-button¨belly-button-fabric +raptor-chickens +@stygian-endunoffical|幽冥末地:非官方版 (Stygian End:Unoffical) +craftheraldry +pfaeffs-mod +a-bad-experience +the-nectar-mod +heavy-boulders +witherbold +jewelcraft@|珠宝工艺* +corrupted-souls +cinnamon +tfc-fight +sbm-magic-mirror +farmers-delight-heat-compats +tofu-delight@tofudelight|豆腐乐事* +gencreator +dangeonplus +end-upgrade +bufferfish +florescence +mobcages +you-win-button +tea-anyone +envirorot +the-seasons-mod|四季模组* + +the-realistic-leaves-mod +untitled-swans-forge +playdate@ +molotov +another-weapons +@elytra-toggle +compression +compressor@ + +hexal@|咒法拓展* + +create-encased@|机械动力:封装工艺* +treeplacer@ +death-knell@ +moreiotas@ +numismatic-overhaul@|货币学拓展 (Numismatic Overhaul/Numismatic Overhaul: Reforged(forge))¨numismatic-overhaul-reforged|货币学拓展 (Numismatic Overhaul/Numismatic Overhaul: Reforged(forge)) +hexbound-fork@|咒法组构学 (Hexbound)¨@hexbound|咒法组构学 (Hexbound) - 原- +vanity-druid-pack +vanity-farcrs-colossal-weapons@vanity-colossal-weapons +debris-chunk-raw-netherite-scrap@raw-netherite-scrap|残骸碎块 (Debris Chunk) +malum-vestis +culllessleaves-reforged@cull-less-leaves-reforged|更好的树叶渲染优化重铸版 (CullLessLeaves Reforged) +biome-music|生物群系音乐* +agers-earthquake-generator +vanity-black-gold +vanity-bone-pack +what-that-wolfhouse|那是什么?仓库管理员! (What That? Wolfhouse!) +click-for-hot-chicks@ +vanity-molten-pack +vanity-spartan-pack +woods-and-mires@ +suggestion-tweaker@ +Additional-Redstone@additional-redstone +heartstone@ +dyed@ +wireless-redstone@wirelessredstone + +vanity-steel-pack +vanity-viking +horse-expert@ +snow-under-trees-remastered@ +oceans-delight@|海洋乐事 (Ocean's Delight) +transcending-trident@¨transcending-trident-fabric +snow-under-trees-fabric +precision-enchanter@ +immersivethunder@ +top-extras|TOP 附加 (TOP Extras) + +potatweaker +effect-tooltips@ + +variant-crafting-tables +endless-biomes@ + +chatimg|图片聊天 (chatImg) +throwable-explosives@ +@skillmmo +archeon@ +chattoggle@ +enchancement@ + +useful-spyglass@ + + +nff-girls +launchgui +villager-armor-layer@|村民盔甲显示* +wasabi@ +magnet-craft|磁铁工艺* +item-obliterator@ +you-shall-not-spawn@ +hell-on-earth +zombie-friends@ +@stone-craft|石头工艺 (Stone Craft) +trade-cycling@ +illager-revolution@ +extra-trades +blood-particles-mod +@two-weeks-hud +fazcraft-mod@fazcraft +mod-menu-no-more@ +@slime-craft +way2wayfabric@ +cloche-profit-peripheral +l2weaponry@|莱特兰-武器 (L2 Weaponry) + +@rhodium|铑 (Rhodium) +zoom-o-matic@ +@broken-tool +fishing-ruler@ +command-relay@ +beasts-bosses + +the-one-probe-community-edition@|检测器-社区版* +packageddraconic@|封包龙之进化 (PackagedDraconic) +imitationcore +big-sip@ +floating +@blast-travel +skygrid@ +disable-new-world-creation-screen-forge@disable-new-create-world-menu-forge¨disable-new-world-creation-screen-fabric@disable-new-create-world-menu-fabric +packagedmekemicals@|封包通用化学品 (PackagedMekemicals) +packagedastral@|封包星辉魔法 (PackagedAstral) +mekanism-advancedgenerators@mekanism-moresolarpanels|通用机械-更多太阳能板 (Mekanism Advanced Generators / Mekanism-MoreSolarPanels) +paperandquill + +sneaky-curses-forge@sneaky-curses¨sneaky-curses-fabric +magnum-torch-forge@magnum-torch|卓越火炬 (Magnum Torch)¨magnum-torch-fabric|卓越火炬 (Magnum Torch) +universal-bone-meal@|通用骨粉*¨universal-bone-meal-fabric|通用骨粉 (Universal Bone Meal) +@bottle-of-gender + +leave-my-bars-alone@|改进的骑乘HUD* +mc-mods-enchantments-for-trade +i-need-block +spiky-spikes@ +straw-statues@|稻草雕像* +linear-xp +save-gear-on-death +curtain@|窗帘* +rrls@|移除重载界面 (Remove Reloading Screen) +entity-model-features@|实体模型特性* +forgestory +armor-statues@ + +world-of-bosses + + +mirabilis-vanilla-biome-overhaul +energized-power@ +carpenter +tolerable-creepers +anchor +locksmith +mystical-machinery|神秘机械* +life-steal-enchantment +more-wandering-trades|更多流浪商人交易* +mineralas@ +ecospherical-expansion@ +ecospherical-depths +arrhys-simple-currency +better-wandering-trader@better-wandering-traders +interdimensional-wireless-transmitter@|创造无线发送器* +cozy-home@ +inventory-crafter + +maxs-armory|Max 的武器库 (Max's Armory) +nefs-farm-decoration +create-armory@ +dangerous-wasps +createfabricreibugfix@|机械动力 Fabric 版 REI 配方显示修复 (Create&REIBugFix / CreateFabric&REIBugFix) +seasontweaks + + +@automessenger + + +padoru@ + +snow-coated +miracle-berry +locked-chests +maxs-armory-expansion|Max 的扩展武器库 (Max's Armory Expansion) + +remove-mouseover-highlight@ +apocalyptic-fortress@ + + +unbreakabler +trails-and-tales-fabric¨trails-and-tales-1-20¨various-update-1-20-backport +tinkers-bounce-pad@|匠魂弹跳板*¨tinkers-bounce-pad-fabric@|匠魂弹跳板 (Tinkers Bounce Pad) +enderio-unofficial|末影接口非官方版 (EnderIO Unofficial) + +dimensional-gravity + + +bring-color-to-my-skies +portal-dungeons + +radiant-gear@¨radiant-gear-fabric +create-teleporters@|机械动力:传送器 (Create : Teleporters) +enchantato +floating-block@floating-cube|浮空立方体 (Floating Cube) +curious-lanterns@ +river-redux@ +restrictions@ +create-modern-train-parts@modern-train-parts + +targetato +messagetweaker + + +tskimi-seirans-fruit-wine@tskimiseirans-fruit-wine|月见清兰的果酒 (Tskimi Seiran's Fruit Wine) +graduated-cylinders@|刻度量筒* + +fps-monitor@ +athena@athena-ctm +calm-mornings@ +fog-looks-good-now@ +guarding@ +cats-expanded@ +modular-bosses +experience-obelisk@cognition +here-be-no-dragons +gnumus-settlement +fading-night-vision +mru@ +mute@mute-mod +simple-knives +iron-fishing-rods +cave-rats +@squeedometer + +sky-structures +mannequins +simple-mango@ +betterdrawhoveringtext|更好的工具信息显示 (betterDrawHoveringText) + +badges-by-harmex@cobblebadges2 +terrarian-arsenal +zombie-veterinarian|僵尸科兽医* +just-enough-sculk-sensor +hearth-and-home@ +better-leveling|更好的升级* +applied-mana|应用魔法* +boundless-flux + +@axolotlclient +energy-nodes +fog@ +thirst-was-taken@|口渴* + +unlimited-fluidity +e4mc@ +late-game-golems@ +iter-rpg + +oceanic-expanse@|海洋拓展* + + +origins-vampire|起源:吸血鬼 (Origins: Vampire) + +bad-to-the-bone¨bad-to-the-bone-fabric +workers@villager-workers + +sculk-horde@|幽匿部落* +stratospherical-expansion@ +lets-do-candlelight-farm-charm-compat@lets-do-candlelight-farmcharm-compat|烛火晚宴 ([Let's Do] Candlelight) - [作者推荐]2.0.0+¨candlelight-lets-do-a-candlelight-dinner@lets-do-candlelight|烛火晚宴 ([Let's Do] Candlelight) - Legacy版,作者已停止维护 +let-me-play-iris@ +dimensional-depths +create-molten-vents@ +everything-as-a-hat@ + +world-border-expander +htmltech +extra-tan@ +diamond-economy@|钻石经济* +texels-paintings@ +tinkers-expansion +revelationary@ +fullstack-watchdog@ + +adventure-apparatus +neruina@ +kawaii-dishes@ + +keep-my-hand@ +no-lan-cheating@nolancheating +goat-horn-block-mod@placeable-goat-horns|可放置山羊角 (Placeable Goat Horns) + +metallics-arts|金属技艺* +actions-of-stamina + +disenchanting-book +stackdeobf@ + +portfolio|Portfolio - 仅版¨@portfolio +@nvidium +merequester@ +invade|入侵* +frame-api@ + +realisticclouds +arcane-world +tiled-cauldron +manyideas-christmas@ +overflowing-bars@ +kokoalinux +medievalweapons@|中世纪武器 (MedievalWeapons) +completionists-index@ +stoneworks@ + +mob-lassos@|生物套索* +mutant-monsters@ + +@physics-toys +tarot-cards@|塔罗牌* + +chatmove@ +@forgedloaderapi +public-transport-mod +mineral-chance@ +random-bone-meal-flowers@ +now-playing-forge@now-playing¨now-playing +end-portal-recipe@|末地传送门配方* +crying-portals@ +dragon-drops-elytra@|末影龙掉落鞘翅* +name-tag-tweaks@|命名牌调整* +funky-yoyo@funkyyoyo +pierce-arrow@ +tool-sharpening +@ktfruaddon|群峦救援-非官方版扩展 (kTFRUAddon) +pigsteel@pigsteel-fabric¨pigsteel-forge@ + + + + +flowermap@|花卉地图 (Flower Map) +hopo-better-mineshaft + +reforgium@ +spoorn-weapon-attributes@ + +fabrc-legacy-fixes@legacy-fabric-fixes + + + +moa-decor-bath + +stealing-the-villagers-forge@¨stealing-the-villagers-fabric@ +spoorn-armorattributes@spoorn-armor-attributes +connectedness@ +epic-samurais@|史诗武士 (Epic Samurai's / Samurai Dynasty)¨epic-samurais-fabric@epic-samruais-fabric|史诗武士 (Epic Samurai's / Samurai Dynasty) +sandwiches-n-more +enchantments-plus-fabric@enchantments-plus +purpeille@ +carpet-sky-additions@ +spice-of-life-carrot-edition-unofficial|生活调味料:胡萝卜非官方版 (SOL - Carrot Unofficial) +ender-dragon-egg-respawn-fabric +personal-space|私人维度* +held-item-tooltips@|手持物品信息显示* +minecraft-shark-mod +forgotten-delight@ + +enhancedlootbags +recipe-reshaper@ +hellish-blahaj@|布罗艾 Hellish 版 (Hellish Blåhaj) +amber-jade@|琥珀 (Amber) +mafglib@ +@fast-minecart +ae2_tools +create-compats +dont-drop-it@ +nicemod-new-blocks@nicemod +forgematica@|全息蓝图 (Forgematica / Litematica-Forge) +framland +blahaj-legacy|布罗艾:旧版 (Blåhaj:Legacy) - 无法访问¨@blahaj-legacy|布罗艾:旧版 (Blåhaj:Legacy) +deep-aether@|深入天境* +the-forgotten-dimensions@ +@the-sink|水槽 (The Sink) + +@stairjumper +watchdog-anti-cheat@watchdog-anticheat +villagers-drop-emeralds-on-death@ +neydis-dragons +colourful-goats +perfect-spawn + +infinity-pickaxe +biome-spawn-point@ +smallbiomes +enhanced-block-entities-reforged-unofficial +hopo-better-ruined-portals +wearthat@ +portable-crafting-table@|便携工作台* +structory-towers +everything-is-a-hat +skeletal-remains@ +tidbits +terrible-chest-potato-edition|可怖箱子:土豆版* +@dryinglava +advancedreborn@advanced-reborn +blue-archive-halos +@totemcounter + +@mana-visualizer +mhcraft +irons-spells-n-spellbooks@|Iron的法术与魔法书 (Iron's Spells 'n Spellbooks) +infernal-enchantments +reimagined-world-menu@ +origins-assassin +peculia@ +koratio +promans-origins +mermaid-mythical-origins +werewolf-mythical-origins +fairy-mythical-origins +elf-mythical-origins +dragon-mythical-origins +budget-fire-aspect +facehugger +vine-boom-moments +lotta-blocks@ +snip-those-tags +zombie-variants-forge +nights-of-sorrow +simple-spells +auditory@ + +trulios-compilation + +realms-button-remover@ +manyideas-doors@ +end-origins +extra-classes-origins +wire-decoration|电线装饰* +optimizationsandtweaks@ + +tabfaces@ +mob-armor-mod-v2 +umbral-skies +recipes-library@ +dimension-access-manager@ +witherborn-origin +origins-gravity-enforcer +snuffles-fabric@|魄罗Fabric版 (Snuffles (Fabric)) +manyideas-halloween@ +selectable-painting@ +boat-break-fix@ +advanced-movement +totem-overhaul +mobs-no-render@ + +covenants-choose-your-purpose +insatiable +odd-organisms +rotten-eggs +cc-rt +manyideas-core@ +multi-builder-tool@|多方块构建工具* +ender-storage-1-12-continuation@ender-storage-continuation|末影存储:延续版 (Ender Storage continuation) +snail-mail +ancient-rituals +colorful-anvils@colorfulanvils +ecofriendly +torchkey@ +torch-key-forge@ +just-rose-gold +revolt-of-the-mobs + +improved-vanilla@ +upgraded-netherite-aetherite +betterwithpatches@ + +pickable-orbs@pickable-health-orbs +mobneutralizer + + +@echoes-of-the-past +cloud-rider +@assemblymod +treasure2-bones +ender-pearl-swap +jer-ore-integration +adorkable-dogs-pocky|DK狗的Pocky (Adorkable dog's Pocky) + +realistic-explosion-physics@ +nitwitification@ +mutated-items@ + +homespun@ +primitive-start@ +throwing-dynamites@throwing-dynamite +paladins-and-priests@ +cataclysm-heaven-burner@|灾变:焚天神兵 (Cataclysm: Heaven Burner) +echo-chest@|回响箱子* + +nether-chested@|下界箱子* +plenty-plates@ +simple-sponge +new-paper-doll@paper-doll +ender-zoology@|末影动物学* +vectorientation@ +seven-days-to-fix-parasitus +dtm-integrations +@hdskins +bushier-flowers@ +create-gravity +cataclysm-boss-bar@|灾变Boss血条显示* +unusual-gifts +building-blocks-overhaul + +tick-info +primal-stage@primalstage +spontaneous-replace@|自然更替 (Spontaneous-Replace) +pixel-loader|像素加载器2 (pixel loader2) +kubejs-ars-nouveau@ +cataclysmweaponery@cataclysm-weaponery +twilight-paintings +twilight-origins +cpmoscc@|自定义玩家模型OSC兼容 (Customizable Player Models OSC Compat) +twilight-forest-portal-catalyst|暮色森林传送门催化石* +better-fog +tool-upgrades@|工具升级* +visiblebarriers@ +aether-gravitation@|天境之引* +@sublanguage|首选语言 (Sublanguage) +nff-services +better-potion-visuals@ +modern-warfare-cubed@|现代战争方块化* +extraordinary-extra-totems +@squidfriends +beachparty@lets-do-beachparty|沙滩派对 (Let's Do Beachparty) + +s33r-more-food@ +froglight-backport + + +exquisito@|末域奇馔* +species@ +cles-battleitems|战斗物品 (Cle's BattleItems) +unu-parts-pack@ +spleaves@ +modernworldcreation@modern-world-creation +enchant-the-rainbow@ +@muffins-songkran +fixed-anvil-repair-cost@ +sleep-tight@ +random-crafting@|随机合成表* +fallout-inspired-power-amor +infinitefluids|无限流体 (InfiniteFluids) +upd8r@|整合包更新检查工具* +old-guns-mod +@vlzoomer + +vanilla-teleporters +aquatic-frontiers@ +lands-of-icaria@ +wta@ +@gtnh-no-nerf +pickable-villagers@ +pickable-piglins@ +book-of-blocks-fabric@mc-book-of-blocks +create-blue-skies-compat +dawncraft-mobs +dawncraft-tweaks + +netherracked +the-toolkits@ +immersive-structures-ii-nether-edition + +mossier-deepslate@ +celestial@ + +quest-giver +@hextweaks|咒法调整 (HexTweaks) +insects-recrafted@ +better-boilers +aether-plus +crafttweaker-sixik-utils-aoa3-nevermine +aether-expansion +barrels-2012@ +@libzoomer +tfc-sample-drill +tfc-tng-rosia¨tfc-rosia +aether-additions +custom-portal-api-forge@customportalapi|自定义传送门 API Forge 版 (Custom Portal API [Forge]) +jaopca-extras@ + +enclosure@ + + +isleofberk@isle-of-berk|博克岛 (Isle of Berk) +patpatpat@¨patpatpat-fabric + +wildberries + +kubejs-powah@ +@hexkinetics|咒法动力学 (HexKinetics) + +sand_box@sandbox +sublime +spells-shields-x-tinkers-construct + +mowzies-mobs-the-broken-blade|断刃 (Mowzie's Mobs: The Broken Blade) +water-source-ex|水源EX (Water Source EX) +tinkers-calibration-tic3|匠魂校准 (Tinkers' Calibration) +yamatomoveset-epicfight-addon +engineers-delight@ +tinkers-disassembler +piseks-tinkers-enchantments +tinkering-with-embers +mob-despawn-timers +tfc-towerheat +tfc-toohotaroundhere +flower-patch@ +quickcure@quick-cure¨quickcure-fabric@quick-cure-fabric +spoiled@ +entity-specific-damage-invulnerability@ +hungryanimals +opolis-utilities@ +better-breeding +frostiful@|霜冻* +camo-creepers@ +coupons@ +simple-bracers +baby-delight +strategic-enchanting +forged-in-fire +lumy-skin-patch +@le0s-spoons +redstone-clock@ +anti-mob-griefing +nbtedit-reborn@|游戏内NBT编辑器重制版 (In-game NBTEdit Reborn) + +the-filler-update@ +custom-machinery-create@ +@rightproperguiscale +armor-trims@ +revised-phantoms@ +choruslib|ChorusLib - 无文件¨@choruslib +frogs-can-eat-any-hostile-mob +artificial-thunder +rp-renames@ +openblocks-trophies@ +@shrug-it-off +@f3-t-everywhere + +lootbag-patches + +stargate-journey@sgjourney|星门之旅* +xaero-arrow-fix|Xaero Arrow Fix - 无法¨@xaeroarrowfix +ornamental +xaero-zoom-out@xaero-zoomout +minecard + +ydms-custom-camera-view@ +gravitational-modulating-additional-unit +edgerunner@edgerunner-feature-fix|边缘行者* +nbt-autocomplete@ +smells-fishy@entity-rain +primogem-craft@2primogem-craft|原石工艺 (Primogems Craft) +benched@ +kubejs-tfc@ +precision-prospecting@ +potatoos-custom-structure-for-hbms-nuclear-tech +fabric-seasons-terraformers-compat@ +fabric-seasons-extras@|Fabric Seasons: 拓展 (Fabric Seasons: Extra) +better-f3-plus@ +fabric-seasons-delight-compat@ +fabric-seasons-terralith-compat@ +marigolds@ +fabric-seasons-croptopia-compat@ +fabric-seasons-byg-compat@ +sassot@ +easyhopper@easy-hopper|轻松漏斗 (Easy Hopper) +progressive-archery@ +nonconflictkeys@|全键无冲 (NonConflictKeys)¨nonconflictkeys-fabric|全键无冲 (NonConflictKeys) +armor-restitched@ +@pillager-queen + +nmpr@ +sprinklerz@ +our-villager-discounts@ +easydropper|轻松投掷 (Easy Dropper) +varied-adventure +kubejs-delight@ +block-physics-overhaul +searchlight-forge|探照灯 (Searchlight (& Wall Lights))¨searchlight|探照灯 (Searchlight (& Wall Lights)) +ancient-manuscripts@|远古手稿* +gazebos@ +scoreboard-get-time|记分板获取时间 (scoreboard get time) +modern-keywizard|现代化按键精灵 (Modern KeyWizard) +chunk-sending-forge-fabric + +limitless-structure-blocks + +advanced-spawn-control +overworld-mirror@ +no-sonic-boom-togglable@toggleable-sonic-boom +quicksort@ +fake-player@fake-players +@lootbeams-fabric|战利品光束Fabric版 (LootBeamsFabric) +continuumation +ai-art-deco-1|AI装饰一号 (AI Art Deco 1) +@occlusion-culling-fix-sodium +easy-dungeons|简易地牢* +the-morbid-harvester-reborn-reborn|变态的凋灵收割者 (The Morbid Reborn Reborn) +ars-armiger +bettergolem +@end-poem-extension|终末之诗扩展补丁 (End Poem Extension) +trampledisabler-fabric +spotting|索敌* +advanced-tfc-tech-unofficial@|进阶群峦科技非官方版 (Advanced TFC Tech Unofficial) +pineapple-tags|凤梨标签* +impostore@ +effishiency@ +glumbis +prehistoric-nature-fossils +peeled +butterflys +@forgedapi + +be-style-wither@ +campfire@ +ars-enderstorage +@ftbchecker +mythicmetals-decorations@ +metallurgychisel +sooty-chimneys-fabric@ +arboria +mekanism-evolution + +chiseledadditions +@tinkers_ingenuity|工匠匠心 (Tinkers Ingenuity) +gregtech-4|格雷科技4移植版 (GregTech 4 Rewritten) +lacrimis +productive-villagers@ +canned-goods@ +itemchat-fabric@itemchat + +crafttweaker-sixik-utils-ftb-quest +wares@ +difficult-spawners +recoil-shotgun@ +stratum|Stratum - 无法¨@stratum +observed@ +ex-sartagine-requiem@ +giant-pacman-1-16-5 +item-banning-fabric +erroring-entity-remover@ +mclo-gs +pink-expansion +polluted-earth-reborn +kitsus-forgecraft +stat-check +hit-indication@ +multipart-machines-farming + + +tru-first-person-mod +reduced-music-delay +agers-giant-junkyard-dimension +jsmacros@ +great-big-world@¨@great-big-world-old +armored-mobs +astrological@ +end-expansion-the-lamented-islands@ + + + +@compromise|折衷 (Compromise) +brute-force-rendering-culling@|野蛮渲染剔除 (Brute force Rendering Culling) +no-additional-repair-cost +cave-dust@|洞穴尘埃* +nocubes-better-grindstone +create-weaponry +nocubes-chinchillas +create-applied-kinetics@|机械动力:应用机械 (Create: Applied Kinetics) +nocubes-zombie-mobs +create-gourmet +medical +yellowbrosss-extras +simply-caterpillar@ +cataclysm-delight +old-combat-mod@ +pipe-connector@ +diamethyst-arrows@ +cherry-blossom-grotto + + +parties +pots-and-mimics-rpg +gemspark@ +otakomod@ +wall-jumping +new-life +reeves-furniture@furnitury +@undying|不朽 (Undying) +creatania +boat-rocked@boat-rocket +proficiency-honest-work +warrior-rage@ + +pokefood@ +armor-souls-reforged + +aether-redux@the-aether-redux|天境:新生代 (The Aether: Redux) + +staaaaaaaaaaaack@ +thanks-i-have-rei@tihr + +satchels|挎包* +matex +weapons-of-the-apocalypse +tis-advanced@ +love-me-love-my-wolf|爱屋及呜 (Love me love my wolf) +toroquest-revamped + +tis-create@ +tektopia-trader +worldtime@ +beasts +alphabet-speedrun@|自定义速通挑战 (αβspeedrun) +@symlink-check|符号链接拦截 (Symlink Check) +tis-stringify + +dismount-entity@¨dismount-entity-fabric +dyeable-compasses@|染色指南针* +supercompression|超级压缩 (Super Compression) +better-hungteen-s-plants-vs-zombies|更好的 HTPVZ (Better HungTeen's Plants vs. Zombies) +piglinsafety|猪灵:多喝岩浆 (PiglinSafety) +gatewayer +bocchud@|孤独HUD (BoccHUD / MiniHUD-Forge) +arrowcollector@arrow-collector|你返箭吗 (Arrow Collector) +saplingslayer|鸽子衔枝 (SaplingSlayer) +quality-quails +hydration@ + +halohud@ +resourcify@|资源下载机* +ioclias@ +twilights-flavors-delight@twilight-delight|暮色风味乐事 (Twilight's Flavors & Delight) +clean-f3@ +enchanted-lib +architect-tools-converter-1-7-10|建筑师工具 - 转换器 (Architect Tools - Converter) + +@librarian-trade-finder +server-resourcepack-checker@server-resource-pack-checker +main-menu-credits@ +photon@photon-editor|光子* +voice-chat-interaction@ +replay-voice-chat@ +ships-mod-unofficial|船:非官方版 (Cuchaz Ships Unofficial) + +storage-overhaul +chorus-warps +aureate-reliquary +submerged-explosions@ +netherite-items +aim-plus +reckless-drilling +tick-stasis@ +azure-paxels@ + +no-angled-brackets +alien-apocalypse +server-utilities +su-addon-silk-spawners +su-addon-quests +harder-hardcore +argentinasdelight@argentinas-delight|阿根廷乐事 (Argentina's Delight) +colonies +everythingcopper@|万物皆铜 (Everything is Copper) +passive-endermen@|被动型末影人* + +elemental-aspects +dune +lithereal@ +mobs-genus +ore-extension +extradelight@|额外乐事 (ExtraDelight) +shady-alchemist +ender-knight +bubbleland +cake-cow + +shrimps +projecte-aether-addon +coal-additions +fungi-stew +grenade-launcher +illness +structural-statues + +wild-bushes +mutant-wolf +curses-naturals + +straighten-up@ +twilight-catalist|暮色催化石* +extra-moas +corruptional +enablemultiplayermode@ +wizardy-delight@wizardry-delight + + +tinyallies@ +mc-mods-da-nuggets +random-recipes +starks|史塔克一家* +easy-paper +modern-ruins-pack +tetras-delight +@kekkai|结界 (Kekkai) +avaritia-reset-version|无尽贪婪重置版* +archeology-plus@ +mobification +trimseffects@ +tough-glass@ +celestisynth@|天神剑技* +golems-plus-plus@ +more-axolotls@more-axolotl +perfect-accuracy@ +@perfect-accuracy-forge +@swingthrough +log-begone@ +@transferable-pets +@bone-blocks +woodster@ +deaths-mark +sweet-boreal@ +fuzzymobs +@beslandia +@ars-magica-25|魔法艺术2.5 (Ars Magica 2.5) +delightful-froge@ +enhancedsnowman@enhanced-snowmen +new-world-height-and-depth@shattered-world-limits +@inertiaanticheat + +scroll-of-harvests@ +@scripts-chunk-loaders +clean-tooltips@ + +quick-save@quicksave|快速存档&快速读档 (QSave&QLoad) +iron-bows-forge¨iron-bows-fabric + +filtered-chests + + +antixray@anti-xray¨antixray-forge +special-strength +armorpoints@ +easy-enchanting@|轻松附魔* +elitia +cosmetic-wings +deepspace|深空 (DeepSpace) +death-backup@|死亡备份* +bear-with-me +create-diesel-generators@|机械动力:柴油动力 (Create: Diesel Generators) +vintagefix@ + +nostalgic-tweaks@ +suspicious-sand-maker +create-cobblemon-industrialized@ +create-pixelfactory +ies-tweaks +haunt-furnace@ +player-ladder@ +orb-of-origin-plus@ + +firework-minecart-mod@ +soots-sandwichcraft +rpg-origins +@zombie-lag-fix +classic-minecraft-icon@ +@the-binding-of-isaac-useful-items +@trivia +some-useful-ores +@stardew-valley-mod +rainy-harvest +mythic-mobs@mobs-of-mythology +lost-features@lostfeatures +bagus-lib@ + +@better-doors +server-pack-unlocker-forge@server-pack-unlocker¨server-pack-unlocker +x-enchant@x-enchantment + +@blahaj-remake +pamps-simple-edition +@babyzombie-drops + +better-chiseled-bookshelves|更好的雕纹书架* +@shorks +@missing-vanilla-recipes +alcocraft@ +silences-defense-tower + +mowlib + +advanced-backups|高级备份* +not-just-biomes@ +agricultural-enhancements@|农业增强* + + +lorrys-sword-breakers|罗毅的锏 (Lorry's sword breakers) +ramel@ + +chat-tools@|聊天工具箱* +amys-rftl +cutepenguins|可爱的企鹅 (Cute Penguins) +hellions-sniffer@hellions-sniffer+ + +hybrid-flowers|杂交花* + + +methane¨@methane +mushroom-villagers +@litematica-server-paster +s33r-butterfly-paintings@ +@more-statistics +villager-see-villager-do@ +industrybase|工业基石 (IndustryBase) +silent-river-in-the-nether|炎液断蒸* +ramel-reforged +sulfar-mod +apple-cows +gardening-tools@ +nether-ores-plus +river-treasures +lumbers-axe + +immunity-enchantments +better-fishing-rods +book-fishing +more-villager-trades +custom-world-icons@|自定义世界图标* +trims-begone@trims-begone! +haste-enchantment +workshop-for-handsome-adventurer +desert-upgrade +ocean-recovery +more-armor-trims|更多盔甲纹饰* +mc-mods-the-trims@allthetrims +@bamboo-sign-editor|告示牌编辑器 (Bamboo Sign Editor) +revival-orb@ +stackable-trims@ +keepcuriosinventory|饰品栏优化 (KeepCuriosInventory) +megachicken@mega-chicken +s33r-iris-azalea-mod +difficultyplus@difficulty+ +black-lung@blacklung +friends-and-foes-beekeeper-hut-forge@¨friends-and-foes-beekeeper-hut-fabric@ +friends-and-foes-flowery-mooblooms-forge@¨friends-and-foes-flowery-mooblooms-fabric@ +random-looting@|随机战利品表* +kubejs-botany-pots@ +irons-rpg-tweaks¨@irons-rpg-tweaks|Iron's Rpg Tweaks - 未及时更新 +@enchantips +tokenable-decoration +emogg@ +festival-delicacies@|节日佳肴* +elytra-trims@ +benefits-of-reading|雕纹书架注魔/阅页读著 (Benefits of Reading) +gothic-rpg@ +arcadian-dream@|幻想之梦* + +dungeon-and-taverns|地下城与酒馆 (Dungeons and Taverns) +elytra-trims-extensions@ +fallingblocks +fabric-musica +growmeal@ +moa-decor-art + + +easier-armor-trim-duplication@ +steppy@ +new-thin-air@thin-air|稀薄的空气 (Thin Air) +the-armory +xannoszs-better-minecarts|Xannosz的更好的矿车 (Xannosz's Better Minecarts) +meliusvanish@vanish +tooltip-tool-tips@ +sanity-descent-into-madness@ +no-darkness-effect-mod@no-darkness-effect|无黑暗效果 (No darkness effect) +@seamless-loading-screen-renewed +armorskin@ +@translucent-glass +simple-health-bar@ +plenty-of-golems +@hit_particles +@durability-viewer-updated|耐久指示器更新版 (Durability Viewer Updated) +puffish-skills@skills +better-archeology@|更好的考古学* +fake-people|假人* +apoca-mobs + +@snow-sniffer +responsive-shields@responsiveshields +beehave@|蜜蜂信息显示* + +sign-clipboard@ +nocubes-better-frogs +essential-permissions@vanilla-permissions +create-dreams-desires@create-dreams-and-desires|机械动力:梦想与欲望 (Create: Dreams & Desires) +trails-and-tales@trails-and-tales-plus + +stackable127@ + + +wanderer-profession + +cataclysmic-combat@ +persona + +create-air-forge +@gravity-pads + + +inhibited@ +china-railway-facilities|中国铁路设施 +sekc-physics¨sekc-physics-fabric +@artificial-lightning-mod +do-api@ +@pythonmc +@tp-chat-cmd|TP 聊天命令 (TP Chat Command) +grabby-mobs@ +pandas-falling-trees@ +iron-ender-chests@ +delightful-creators-forge@delightful-creators|动力乐事 (Delightful Creators)¨delightful-creators-fabric|动力乐事 (Delightful Creators) +deathbutthree@death-but-three|逝不过三 (Death But Three) + +comparties|组队兼容* +dusty-decorations@ +simple-double-jump +simple-ore-generation|简单的矿石生成* +save-the-monument +snifferiety@ +light-the-night +tweakerge@ +terrafirmaships@ +better-ocelots +actually-useful-smithing-table@ +denyblocks +sculk-horn@-sculk-horn +ydms-red-panda@ +overworld-piglins@ +waveapi@ +modlist +panorama-screens@ +campfire-spawn-and-tweaks@ +ghostz@ +better-totem-of-undying@¨better-totem-of-undying-fabric +modonomicon@|模组秘典* +moreyoyos + +onetwenty-1-20-backport@trailstales-backport +xtra-arrows@ +secrets-of-forging-revelations-a-tetra-addon@secrets-of-forging-revelations +trolldom +@made-in-china|中国制造 (Made In China) +soundlimitextends +artemis-flower-pots +sculky-bits +minecolonies-for-computercraft +flame-sweeping-potato-edition|烈焰横扫:土豆版* +skinned-carts@ +quick-effect@quickeffect +block-log + +equipmentbenediction@equipment-benediction|装备祝福 (Equipment Benediction) +@gms|现代游戏模式选择器 (Modern Gamemode Switcher) +dimension-localized-inventories +skillcraft-modpack-tool +modern-inhibited +ghostjump|死者为大 (GhostJump) +@notsoessential +worldsalads-opulence + +wyrms-of-nyrus@wyrms +pearfection@ +enderchests@¨enderchests-fabric +dragon-rider +createutilities@create-utilities|机械动力:实用物品 (Create Utilities) + +creeperhost-presents-chickens +inet@ +safefall|你安星好啦* +my-beloved-icon@ +mob-catcher-fabric +tetra-enlarged +fruit-delight@|果品乐事* +@idletweaks +tagmod +passive-skill-tree|被动技能树* +villagertradefix@ + + +bullet-chat|弹幕聊天* +fishermans-trap@fishermens-trap +removebats@|禁止蝙蝠生成 (RemoveBats) +nabba +enchantdemon|附恶魔 (EnchantDemon) + + +create-alchemists-industry@ + + +stellarity + + +@modern-sound +@polished-gui +mc-mods-bark-all-bite +lively-forests + +dynamic-fullbright@ +@modularwarfare-shining|模块化武装:烨熠 (ModularWarfare-Shining) +dont-clear-chat-history@dcch +difficulty-locker +virus-disease-mod +this-boat-is-mine@|这是我的船! (This boat is MINE!) +pandas-extra-details@ +ebs-wildfire@ + + +bobby-forge +matter-transporter +tall-flower-pots@ + +too-fast@ + +fast-paintings@ +personality-rp@personality + + +@fabric-yaml-configuration +comfy-beds@ +twerk-crop-dusting-mod-fabric +extra-damage-enchantments@ +lemon-core +rightclickharvest@ +planters-forge@planters +passive-charms@ + + +linkart-updated@linkart +jamlib@ +globalization@ +renewable-spore-blossoms +@paragraphs + +@scoreboard-helper|记分板助手 (Scoreboard Helper) + + + + + + + + + + +mobs-info@mobsinfo|生物信息* +ngrok-api@ + + +@swordunsheather|利刃出鞘:重铸 (Sword Unsheathe Reforged) +rpgloot +@sus-saver + +dynamic-fps-reforged@ +utility-belt@ +cultivatecraft +rpgloot-patched +fluidlogged@ +create-foundry +cobblemon-fight-or-flight@ + +ender-magnet|末影磁铁* +dead-guys-hallucination-nightmare + + +simple-hot-air-balloons +toomuchrain@ +thirst-was-remade@|口渴-重制* +ies-tweaks-fabric@ +brown-mooshrooms +whetstones@ +@better-log4j-config +@harvest +wooden-hoppers +skeleton-horse-spawn@|骷髅马生成微调*¨skeleton-horse-spawn-fabric|骷髅马生成微调 (Skeleton Horse Spawn) +configanytime@ +faster-crouching@ +yeetusexperimentus@yeetus-experimentus +xbob@|准星摇晃 (Crosshair Bobbing) +zombie-horse-spawn@|僵尸马生成微调*¨zombie-horse-spawn-fabric|僵尸马生成微调 (Zombie Horse Spawn) +tinkers-katanas|匠魂武士刀 (Tinkers' Katanas) +fbp +yeetem-potions@ +incapacitated@ +@fys|锻汝砧上 (Forge Yourself) +@mcopper|梧桐物语 (MCopper) +no-ranged-knockback +industrial-agriculture +macaws-bridges-sajevius|Macaw 的桥梁:Sajevius 附属 (Macaw's Bridges - Sajevius) +@getwebbed +@water-resistance-potion +the-predators +create-structures +ivycore@ +more-immersive-wires@ +ventur-origin@venturorigin + +@sodium-blendingregistry +waterphysics +ece-enhanced-celestial-enhancement|月亮事件扩展:第二月亮 (ECE - Enhanced Celestial Enhancement: The Second Moon) +plants-vs-zombies-cubed@pvzcubed +moa-decor +moa-decor-toys +moa-decor-cookery +moa-decor-science +create-guardian-beam-defense +antisocial@ +expanding-technologies@expandingtechnologies +despawning-eggs-hatch@ +mob-death-messages +chunkapi@ +@betterwaystonesmenu +big-fish@ +nulltal@ +caffeinefilled@ +pet-transfer-trade-your-pets@pet-pass-trade-your-pets! +lets-do-bakery-farm-charm-compat@lets-do-bakery-farmcharm-compat|馥郁烘焙 (Let's Do: Bakery) - [作者推荐]2.0.0+¨lets-do-bakery@|馥郁烘焙 (Let's Do: Bakery) - Legacy版,作者已停止维护 +searchables@ +dixtas-armory@ +ingamestats@ +hanger-system-overhaul +isaidnosnow@ +jarsauth|客户端管理 (JarsAuth) - 此已不受支持¨@jarsauth|客户端管理 (JarsAuth) - >= 4.0 +autoelytrapanic@ +more-crossbows-cj +multipart-machines-cooking + + +thepeebrain-dream-dimension +@chaos-world|混沌世界 (Chaos World) +ochetgenyo@ +qcraft-reimagined@qcraft|量子物理重构 (qCraft Reimagined) + +@todo-list|待办事项 (TODO List) +@arst-armor-hud +spice-of-life-onion@|生活调味料:洋葱版 (Spice of Life Onion) +effect-berries@ +tinkersworld + + +ragdoll-corpses|布娃娃尸体* +floatingruins|浮空遗迹 (FloatingRuins) + +creeper-backguard@creeperbackguard +audio-extension-for-fancymenu-forge@audio-extension-for-fancymenu¨audio-extension-for-fancymenu-fabric +stay-warm-together +aeroblender@ +ancient-aether@|亘古天境* +artisticcraft@ +lavaboat_mod|熔岩船 (LavaBoat) +sophisticated-wolves|精致的狼 (Sophisticated wolves) +enderio-alloys +dynamic-music +@item-hunt +dynamo +create-sabers +liveworldgen +split-shulker-boxes@ +tinkers-leveling +curios-compat +@cloudbackup|云备份 (CloudBackup) +serverpingerfixer@ +@world-days +such-a-delight +create-compressed@ +emoji-type@ +soul-bound-enchantment@soulbound-enchantment|灵魂绑定 (SoulBound) +tower-defense-units +barrier-block-mod|屏障方块* +@simplehealthorbs +misctweaks_ +dynamic-music-updated@ +spartan-netherite +climb-ladders-fast +custom-machinery-mekanism@ +@touhou-tweaks|东方改进 (Touhou Tweaks) + + +noraidtotems@ +@snowballs_plus +bagus-mob@ +chat-twix@ +shulker-meat +accurate-block-placement-reborn@ +favorite-items + +smart-villagers-follow-emeralds@|见钱眼开* + +@villager-pickup +step-it-up@stepitup +fantasy-trees|奇幻树* + +remodified|你再造! (Remodifier) + + +better-fusion-reactor-for-mekanism@ +growableores@¨growableores-ore-cane-forge¨growableores-ore-cane-neoforge +golemsarefriends@ + + +keep-command-history@keepcommandhistory + + +generatorgalore@ +map-shirts@ +fireproof-boats@ +dyenamicsandfriends + + +fusion-connected-textures@ +bluebox +hunger-reworked +armor-status-hud-renewed|耐久信息显示:重生 (Armor Status HUD Renewed) +boblib +placeable-mobs@placeble-mobs +potion-blender@ +t6-auto-attack-mod@t6-auto-attack +forceasciifont-backport +vmtranslationupdate@vmupdate|VM汉化更新 (VMTranslationUpdateMod) +trample-no-more@ + +jeremyseq-damage-indicator@jeremyseqs-damage-indicator + +digs-dnd-origins +superior-flat +fungal-infection-spore@fungal-infectionspore|真菌感染:孢子 (Fungal Infection:Spore) +easy-tweak@ + +netherless-quartz +@maple-api +reforged-fabric-api¨@reforged-fabric-api +caffeinated@ +buildcraft-rf@ +gilded-ingot@ +chatpatches@|聊天补丁 (Chat Patches) +burning-furnace@ +shadowizardlib@ +ants-unleashed@ +@seaborgium +gold-fish +pipeplus@ + + +deuf-refabricated@ + +runic-items@ +twist|诡变* +@serverlistbufferfixer +oil-refinery +themangonewadvent +@worthy-food + + +better-nether-continuation@betternether-continuation|更好的下界延续 (BetterNether Continuing) +stygian-end-continuation|末地:生物群系扩展延续* +skill-slots@|技能槽*¨skill-slots-fabric|技能槽 (Skill Slots) +novam-terram-continuation +@jade-feet|玉足 (Jade Feet) + +cutting-edge +xp-from-harvest-reworked@ +papi-project +eventhorizon|事件视界 (EventHorizon) +mob-options +mod-sets@|模组集* + + +hold-that-chunk@ +dark-matter@ +@steal_dogs|偷狗 (Steal Dogs) +faster-random@ + + +simply-steel-continued@ +simple-corinthium +chidori-origins-collection@ +enhancedp2p|增强的P2P (EnhancedP2P) +custom-de-upgrade-recipes|自定义 DE 升级配方 (Custom DE Upgrade Recipes) +mode-switch +better-clouds-forge +@better-clouds +@easymapdownload +@dynamic-difficulty|动态难度 (Dynamic Difficulty) +client-crafting|客户端合成* +anvil-repairing@ +headcrabs +kubejs-industrial-foregoing|KubeJS工业先锋 (KubeJS Industrial Foregoing) +gensokyo-ontology@|幻想存有论* +recipe-book-delight@|配方书乐事* +chest-hoppers|箱子漏斗* +@gravy-delight +ubes-delight@|香芋乐事 (Ube's Delight) +torcherino-unofficial@torcherino(unofficial)|加速火把非官方版 (Torcherino(Unofficial)) +more-bows-and-arrows@ +xp-shop +acclaimed-origins@ +replanter@ +zombie-infection-vaccine +simple-achievements +achievement-books|成就书* +villager-enchanter|村民附魔师 (VillagerEnchanter) +invocore-utility-mod@ +saljus-quill@ + +derelict +@charged-charms +custom-villagers|自定义村民* +turtlematic@ +remove-base-origins +@cobblemon-delights|方块宝可梦乐事 (Cobblemon Delights) +redirector@|异引定址*¨redirectionor-retro|异引定址 (Redirector) +villager-mantle-fix|村民帽子修复* +rechiseled-create@ +xaeroplus@|Xaero的地图增强 (XaeroPlus) +cosmetic-nametags@ +thirdlife-rts@ +real-peaceful-mode@|真正的和平模式* +niftyblocks@ +elfs-dark-dimension +xaeros-minimap-world-map-waystones-compability@xaeros-minimap-world-map-waystones-compatibility-forge +jagms-kiwis@ +@masaadditions +improved-trident@ +mystic-bows +forgiving-world +skill-cloaks@skillcloaks +swordinthestone@ +lazy-ae2-patch|懒人AE2补丁 (Lazy AE2 Patch) + +yamato-gun-mod@yamato-gun + +ars-mage-fight + +epic-sanji +kubejs-entity-events-extension +mc-dungeons-enchanting@|我的世界:地下城附魔 (MC Dungeons Enchanting) +rei-custom-command@|REI自定义命令 (REI Custom Command) +copperative@|铜心协力* +growable-storage-cells +growable-cells-2 +cinchcraft@ +day-counter@ag-day-counter +makecold|冷境 (MakeCold) + + +sculk-redstone-components@sculkredstonecomponents +toggle-enchantments@ +unbreakable-enchantment-forge@unbreakable-enchantment +immersive-portal-gun@portal-gun|沉浸式传送枪* +tac-craft-tactical-armor-pack +@flexible-arms|灵巧双手 (Flexible Arms) +boat-tweaks@|船只调整* +new-effect-descriptions@effect-insights +diagonal-windows@ + +illager-invasion@|灾厄侵扰* + + +@touhou-origins-blessings + +altorigingui@ +dynamic-trees-pams-harvestcraft-2|动态的树:潘马斯农场2 - 果树附属 (Dynamic Trees Pam's Harvestcraft 2: Trees) +dynamic-trees-hexerei|动态的树:魔法巫师附属 (Dynamic Trees - Hexerei) +minium-stone@ + +@fastrtp +tech-decorators@|科技装饰商* +dynamic-trees-ars-nouveau|动态的树:新生魔艺附属 (Dynamic Trees - Ars Nouveau) + +@kazzmons-magecraft +metal-bundles@|高级收纳袋* + + +tidal-towns|潮汐小镇* +blossom-blade + +cute-kiwi-birds-new-animal +moremobheads@ +ouchies@ +@traditional-asphalt +thaumic-boots@thaumic_boots +carpeted-stairs@ +just-enough-archaeology@ +bedrock_world + +world-preview@|世界预览* +not-enough-trinket-slots-nets +the-five-nights-at-freddys-mod@|玩具熊的五夜后宫 (The Five Nights at Freddy's Mod) +easylan@|自定义LAN局域网联机服务器 (EasyLAN) +pelagic-prehistory +minerally@ +better-jukeboxes +patboxs-brewery@brewery + +stackable-stew-and-soup +mindful-darkness@ +@sbet +nature-arise@ +compression-bag|压缩袋 (CompressionBag) +more-beautiful-torches@ +quality-crops +@individual-keep-inventory +permanent-sponges@ +hang-glider@ +@auto-twerk +block-beams@ +adorabuild-structures@ + +moogs-end-structures@mes-moogs-end-structures +@brew-guide +one-click-crafting-fabric@oneclickcrafting +@genshin-ui +fenomena-structures@phenomena-structures +first-join-message@ +expansive-weaponry +wabi-sabi-structures-forge¨wabi-sabi-structures-fabric +jobsaddon@ +@partyaddon + +loading-backgrounds@|加载背景* +cuisine-delight@|料理乐事* +iron-bookshelves@ +@dimensional-expansion +danger-close@ +hardcore-wither +get-off-my-lawn-reserved@goml-reserved + +dangerousstonecutter@ +normal-damage@ +ftb-xmod-compat +crabbers-delight@|蟹农乐事 (Crabber's Delight) +slot-cycler@ +resource-pack-overrides@ +respawning-animals@|动物重生* +arcane-lanterns@ + +crashma@ + +blackwolf-library@¨blackwolf-library-fabric +blues-scape-and-run-bosses +gigeresque@ +lookaround +projectileimmunityfix +@betterzoom +player-visibility@ +bag-of-holding-forge@bag-of-holding + + + +fish-of-thieves@ +qualitys-delight +arrows-info +godly-vampirism +itemlocks@ +pick-block-pro@|选择方块专业版* +skin-and-bones +pet-armor@ +maxs-deco|Max的装饰 (Max's deco) +more-nugget@|更多矿物粒*¨more-nugget-fabric|更多矿物粒 (More Nugget) - Farbic, +dual-swords@ +organizable-play-screens@ +labelling-containers@ +inventory-pause-forge@ +ready-player-fun@ +condensed-creative@ +leaves-us-in-peace@ +yellow-snow@ +no-tnt-griefing@ +monster-plus@monsterplus +ilmusu-enchantments@ilmusuenchantments + +desired-servers@ +attributizer@ +reactive@|反应炼金术 (Reactive Alchemy) +simple-deepslate +minunrpg +more-sheep-wools +maturi-delight@|祭典乐事* + +forgified-fabric-api@ +artisanat@ +devmode +better-trims@bettertrims +@doggo-mod-overhauled +traders-nightmare +command-block-ide@ + +green-thing-mod +lmft@ +peripheralium@ +resource-switcher@|资源切换器 (ResourceSwitcher) +serializationisbad@ +clutter@ +no-enchantment-cap-1-12-2-backport +survivingtheaftermath|劫后余生 (Surviving The Aftermath) +dimension-viewer@ +foodmodmorefood@more-food|更多食物 (More Food) +tfcgyres-orehints +badstdout@ + +multiworld-mod@multiworld +miaooo +pipeblocker@ +moa-decor-lights +craft-saddles-forge-1-16-5@craftsaddles + +@elytra-fix +@ho-library + +riskofrainmod@riskofrain-mobs|雨中冒险 (Risk of Rain Mod) + +baddie-mobs-uwu +beacons-revisioned@ +silence-mobs@ + +utilitix@ + +tiny-coal@ +replaymod-for-forge-reborn +flib@ + +copper-revisioned@ +frozen-fish|冻鱼 (FrozenFish) +fine-tuned-calibration@finetunedcalibration +third-person-maps@ +carpet-minitweaks@minitweaks + +time-in-a-bottle-forge@time-in-a-bottle-universal +seared-ladder-backport@seared-ladder-(backport) +wall-jumped@ +red-core@ + +record-days-survived@ +veinminer-companion +flightem|我要骑着你飞* +@leashable-players +snowballs-freeze-mobs@ +guinea-pigs@guineapigs + + +vault-research +the-chaser +bandaging +enchanted-charms@ +nether-api@ +mother-silverfish +mcretector@ + +little-botanics +ex-pattern-provider@extended-ae|AE2扩展 (ExtendedAE) +@integrated-circuit +creative-disk +engineers-construct +@botools|假人映射 (Botools) +witch-mobility +gravestones-die-classy + + + +@pebbles-begone +eternal-eats +zombiegame|僵尸游戏 (Zombie Game) +effect-overhaul|Effect Overhaul / Lucid Library - ,已被作者继任顶替¨lucid-library|Effect Overhaul / Lucid Library - ,已被作者继任顶替 +casualness-delight@|随意乐事* + +eidolon-rebrewed@ +fruity-random-teleport|紫颂果味随机传送* +pipe-master-2000|管道专家 2000 (Pipe Master 2000 / Pipe Googles) +command-macros@|命令宏* +@shwetro|上海地铁装饰组件 (MTR Shanghai Wetro Addon) +yuushya-modelling@|方块建模* +tactical-aid@|战术医疗* +@clear-enchanting +fishing-bobber-detector@create-fishing-bobber-detector +@unfix-mc-181190|村民折扣叠加 (Unfix MC-181190) +create-balanced-flight +brewin-and-chewin-remastered +cupboard +mcinstance-loader@ +pre-fish-feed|打窝* +armor-trim-item-fix@ +waffles-moss@ +delightful-cuisine-for-woodheads +towers-of-the-wild-modded@totw-modded|旷野之息高塔 : 再重制 (Towers of the Wild Modded) + +waffles-terracotta-plaster@ +watermedia@ +@inverse-phantoms +@cactus-storage + +etcetera + + +garnished@create-garnished|机械动力:装食 (Create: Garnished) +just-a-well@ +siberiamod +spacetime|空之翼 (SpaceTime) + + + +grappling-hook-restitched@grappling-hook-mod-fabric +@minceraft-title +mob-animations +platter@ +i-want-that-back +presence-not-required +wnboi@ + +@biome-compass +eye-collector-mod + +cozy-foods-milk-tea +opolis-miners@ +netherite-but-cheaper +@fabric-hammers +items-displayed-fabric@items-displayed|物品陈列 (Items Displayed)¨items-displayed-forge@|物品陈列 (Items Displayed) +wood-converter +hammer-mod + +realisticsleepfabric@stevesrealisticsleep +zombies-actually-siege +hex-gloop@hexgloop|咒法凝浆* +the-void +the-shadowlands +bloxys-structures@ +enhanced-hordes +niftycarts@ +wither-dimension-whitelist +@hexlink + +usefulfood-reborn@|有用的食物 重生 (UsefulFood Reborn)¨usefulfood-community|有用的食物 重生 (UsefulFood Reborn) +ancient-warfare-2-tweaked@ +cuffed@|监禁* +rockn-roller@rocknroller +bodies-bodies@ +potionparticlepack@|药水粒子包 (Potion Particle Pack) +deep-blood-evolution +better-horses-mod|更好的马* +potion-bundles@|药水捆* +kofi-table@ +better-mcdonalds-mod@ +@itemframesplus +sinytra-connector@connector|信雅互联* +noclip@ +diamond-in-the-rough-as-in-obsidian@diamond-in-the-rough +factioncraft@ +better-ender +mlmanimator +playlist@ +@villagers-far-from-home +cultivationcraft|异道修仙 (CultivationCraft) + +@carpet-las-addition +@whoami|我是谁? (Who am i?) +verticality-hotbar@verticality +the-slender-man +automodpack@ +bella-quilt@bella +simply-skills@ + + + +cctv-craft@cctvcraft +redeco@|重铸家具 (Re:Deco) +pocket-storage +animated-player-mod|动画化玩家* +its-thirst@ +infernal-damage-indicators + +@just-enough-speed +remion|soul-like armors: medieval weapons & armors - 旧版,¨soul-like-armors-medieval-weapons-armors|soul-like armors: medieval weapons & armors - 重置版, +@elytratime + +squaremap +roots-classic-fabric +justenoughbreeding@ +simple-drills@ +peculiarpieces@ +sdm-loot-stages@loot-stages|战利品阶段 (SDM Loot Stages) +player-stages|玩家阶段* +generation-stages|生成阶段* +ars-oscura|黑暗魔艺* - 无文件¨ars-ocultas@|黑暗魔艺 (Ars Oscura) +bobby-reforged|服务器区块缓存-重铸* +shut-up-gl-error@ +no-spider@ +terracart-reloaded@ +dme +fruit-stack@|果栈丰萦* +gregtech-drawers +marine-iguana|海鬣蜥* +stonks@ +dirtnt@|泥土TNT (DirTNT) +equipable-twilight-forest-charms-tfc|可装备的暮色森林符咒 (Equipable Twilight Forest Charms) +buriedwrecks@buried-wrecks +zapsconverter|Zaps 转换器 (Zaps Convertor) +amethyst-update +angel-block|天使方块* +angel-block-renewed@ +da-bomb@ +quickstack +@bhs|黑洞储存 (Black Hole Storage) +collectors-album@ +head-name-fix@headfix +hostile-delight@unusualdelight|异趣乐事/宿敌乐事 (Unusual Delight*) +vivecraft-compat@|ViveCraft兼容 (ViveCraft Compat) +wildlife-expanded-skunk@ +keepheadnames@ +ydms-fennec-fox@ +ydms-ostrich@ +curse-of-the-warden@ +chatanimation@|聊天动画 (ChatAnimation) +mobvote-rascal@rascal +spotiforge +indypets@ +minecraft-legends-golems +create-sandpaper-overhaul@ +vintage-gregtech +ydms-vulture@ + +locked-slots +wildlife-expanded-snakes@ +jline-for-minecraft-dedicated-server@jline4mcdsrv +blocklingcollection +trenzalore + + + + +creo-lib@ +highlight@ +lost-libraries +@plant-pearl + +sensible-sleep +@hollows-tweaks +eastward-journeys@ + +omotions@ +invisible-frames +ultimatebackportmod@ubm + + +true-ending +@sorted-enchants|附魔排序 (Sorted Enchants) +constructs-armory-1-18-2-port@construct-armory-updated + +@videotape +@enchantmenttweaker +let-me-sleep +forge-tooltip-texts-scroller¨fabric-tooltip-texts-scroller +well-behaved-mobs + + +ancient-realms +@remove-terralith-intro-message +gambling-style +animated-recipe-book + +@packetunlimited +bloxys-bosses +more-bows-cj +@snowballs-hit-players|雪球可以击退玩家 (Snowballs Hit Players) +tectonic-bop|Tectonic:超多生物群系兼容 (Tectonic + Biomes O' Plenty compat) +tech-enhanced +gilded-netherite-cj-edition +enderite-cj-edition@ + +dangerous-oceans +@mc-249136-fix|MC-249136 修复 (MC-249136 Fix) +@featherfallflying +@lidar +anvil-never-too-expensive@ante +crossbow-mod@crossbow|弩 (Crossbow) +@place-item + +controlify@ +@bedrodium +xbbs-hot-air-balloon-fantasy@|XBB的热气球幻想 (XBB's hot air balloon fantasy) +netherite-horse-armor-cj +polydex@ +plenty-of-armors@ +spatialio-compat +@mica +heavy-armor +moss-layers@|苔藓层* +lunchboxes +@autofish-chao +strawgolem|稻草傀儡 (Straw Golem) +@shifting-wares +dynamic-trim@ +trade-uses@ +ambient-fireflies@ +nb_mod + +stacked-armor-trims@ +@final-beta +better-trim-tooltips@ +totally-enough-pain@ +custom-village|村民调教* +animaticareforged +shear-cows +fps-boost@fps-boost-tct +afkfish@ + +@rend +more-trails-more-tales@ +good-tea@|馥郁良茶* +screen-size +botany-ores@ +@cauldron-fix|炼药锅修复 (Cauldron Fix) +foods-plants-cooking-with-mindthemoods +@customgui|自定义 GUI (Custom GUI) +keebszs-battletowers-fabric@keebszs-battletowers +as-a-creeper|×的和你爆了 (As a creeper) + +smarterwanderers +extended-crafting-nomifactory-edition|合成拓展:延续版 (Extended Crafting:Nomifactory Edition) +@meal-api-addon + +easy-config-button +@kahur +@modloadermp +maple@|枫* +seamless@ +bundle-enchantments +real-time-mod@ +chromatic-arsenal +ore-visual-detector +dank-null-no_rce@danknull-rce +kubejs-additions@ + + + +betterdays@ +@seedy-place +extradetails +signed-paintings@ +inenchantment-reconstruction|负魔与改造 (Inenchantment & Reconstruction) + +nae2|Neeve的AE2:EL附加工具 (Neeve's AE2: Extended Life Additions) +the-microworld +vionta +hammer-animations@ + +blueflame@ +nocubes-craftable-music-discs +enderlicious +quarry-reborn + + +morematerials@ +foodmod-for-fabric@food +cursed-mod-for-fabric@cursed +weaponized-baseball +epic-paragliders-but-sekiro|史诗狼之伞* +visualores@ +d-furnace +flickerfix@|闪烁修复 (FlickerFix) +@spongesucc +@phosphor-legacy +random-crits +simple-enchantments +simple-weapons-for-better-combat@ +wither-drops-netherite-templates +@spineless +immersive-melodies@|沉浸式奏乐* +theobsidianboat +dragon-survival-compatibility@|龙之生存:兼容* +bettercookedaxolotls@ +stateobserver@ +mighty-mail¨mighty-mail-fabric +nature-architect-plants-and-decorations +better-berries-redux +kurisus-passable-leaves@passable-leaves|叶间穿梭 (Passable Leaves) + +armorful@ + +@osl +fix-gpu-memory-leak|修复GPU内存泄漏 (fix GPU memory leak) +cake-delight@cakedelight|蛋糕乐事* +autoslabs@ +@kabo-village-marker +ootn +@signal +i-see-what-you-did-there@ +hit-streak@ +new-slab-variants@ +blue-archive-banner-and-shield-patterns +mimic-mod@mimic +bocchium +despawntweaker + +on1chest@|唯一箱子 (Only Need One Chest) +landmines@|地雷* + +packed-up-backpacks@ +valhelsia-furniture@ + +dimension-remote +bring-decay@ +rendertypecache +autotag@ +libz@ +autotools@minecraft_autotools|自动工具 (AutoTools) +@threadtweak +nbt-editor@ + +@betterendsky + +dimtpcmd|维度传送指令 (DimtpCmd) +fast-ip-ping@ +better-anvil@ +bloxys-misc +@find +@elytra-recast +tieredz@ +more-creepers|更多苦力怕* + + +cryptic-registry@ +level-text-fix@ +binnies-mods-patched@ +cyanide@|氰化物*¨cyanide-fabric|氰化物 (Cyanide) +@particlesenhanced +@atum +@worldpreview + +prehistoric-nature-precambrian-dimension +@mc-260949-fix +pro-sniper|专业狙击手* +aether-gear-expansion +aether-enhanced-extinguishing@ +@recipebookmasscraft +create-new-age@|机械动力:电气时代 (Create: New Age) +@universal-trading +@sauces|涂酱 (Sauces) + + + +nekoui + +xpteleporters-2|经验传送器 (XPTeleporters 2) +centered-plants@|植物居中* +showkeybinds@ +@lostera-coremod +advanced-tooltips@ + + +prehistoric-nature-cambrian-dimension +@mushroom-mod +better-end-sky¨better-end-sky-fabric +valkyrie@ +soaring-structures-2|Soaring Structures 2 - 完整版¨soaring-structures-2-clean-version-fabric|Soaring Structures 2 - 轻量版 +prehistoric-nature-ordovician-dimension +fadeless@ +create-tweaked-controllers@|机械动力:高级遥控器 (Create: Tweaked Controllers) + +auto-elytra@ +villager-names@villager-names-serilum +bedrockwaters@ +@antishulkerdupe +hourai-elixir@ +convivium|会饮* +prehistoric-nature-silurian-dimension +grass-seeds@ +minecraft-dungeons-weaponry@dungeons-weaponry +ahznbs-naruto-mod-addon +random-village-names@¨random-village-names-fabric +mooshroom-tweaks@ +grinners-ents +log-cleaner@ +lunar@ +cosmetics@cosmetica + +@abi +interiors@|机械动力:内饰 (Create: Interiors) +souls +real-seasons +eternal-winter@ +move-boats@ +omnom@ +forest-x-reborn@ +exlines-bark-carpets@bark-carpets +exlines-more-carpets +srsl@|星骸秘遗 (Star Remains Secret Legacy) +unearthed-journey@|出土之旅* +prehistoric-nature-devonian-dimension +mwtis-stone-expansion@stone-expansion +smooth-entity-light +title-fixer@ +exstrangefood-reborn|更多奇怪的食物:重生 (ExStrangeFood:Reborn) +frog-legs +ohoy-scallywag +ylf-your-flying-pet +bedrock-edition-features|"基岩"特性 (Bedrock Editon Features) +simply-hot-springs +magma-monsters +mystics-biomes@ +super-block-world@ +create-train-additions@ +enchantery@ +replant-swamp-trees|Replant Swamp Trees - 仅有老旧的¨@replant-swamp-trees +vehiclefix@ +firework-frenzy@ +prehistoric-nature-carboniferous-dimension +cammies-combat-tweaks@ +chorus-gormandizers@ +enemy-expansion +clear-void@|清澈虚空* +the-arcaneum +@mixmetica +mutant-mobs-mod +prehistoric-nature-permian-dimension +@phosphorlegacyforge +stairdoors-extended@ +into-the-rend +buff-frog-mod +asphere +autoclick-machine|自动连点器(Fabric) (Click Machine (Fabric)) +harvestcraft-tweaker +the-legend-of-the-mudman +mutagenesis +nether-update-backport +l2hostility@|莱特兰-恶意 (L2Hostility) +packagedthaumic@|封包神秘时代 (PackagedThaumic) +cat-eyes-night-vision-toggle-mod +vtdownloader@ +smithing-mod + +the-doppelganger@ +rail-wand +tin-ore@tinore +dark-elves-of-underdark +titan-biomes +depth-striders@ +endercage@|末影笼* +mutationcraft@ +aftershock@ +limitless-concert@limitless_concert|永无止境: 音乐会* +realm-rpg-dragon-wyrms +prehistoric-nature-triassic-dimension +flower-power +vr-combat@ +embeddium@ +no-arrows-in-you@ +@unicopia|奇幻小马国 (Unicopia) +ryans-zombies +lights-out-2 +leafper-creeping-and-cute +the-john-mod-reborn@john_mod_reborn + +apothic-attributes + + +wall-jump-txf@ +@fastmove +@genshincraft|原的世界 (Genshin Craft) +and-there-was-only-one-bed@ +hex@ +legend-of-dreemland-drakonboos +hanew-village +battle-allays +@lootbeamsfabricupdated +styled-chat@ +infiniteinvo +playerex-reimagine +startup-timer +cc-mb@|纸带八音盒 (Music Box) +oryls-adventures +elden-craft +ruok@|钌 (RuOK) +deep-dark-regrowth +textrues-embeddium-options@|TexTrue 的 Embeddium 视频界面 (TexTrue's Embeddium Options) +silent-mine +headhunter-mod@shadows-formidable-foes-the-headhunter +yungs-better-jungle-temples@|YUNG的丛林神庙优化 (YUNG's Better Jungle Temples)¨yungs-better-jungle-temples-fabric|YUNG的丛林神庙优化 (YUNG's Better Jungle Temples)¨yungs-better-jungle-temples-neoforge|YUNG的丛林神庙优化 (YUNG's Better Jungle Temples) +forlorn-beasts +harpiccore-mod +poonggis-add-more-bosses + +simpletweaker +@no-spawning-on-ice-highways + +zens-mmorpg + +enchantment-lore@ +zenrecipereload|配方热重载 (ZenRecipeReload) +lovable-chest +critters-cryptids +deathquotes-death-quotes +saphyre + +gameblocks@ +initial-house@|初始房屋* +livingchest + +skibidi-toilet-stevebidop +better-impaling-fabric +vanadium-mod@vanadium|钒 (Vanadium) +loginar-storage@ +jewelry@ +elytra-drag@ +night-vision-flash-be-gone + +ancient-return@ +mc-modsayed +honkai-star-rail-12|星铁12* +torchflower-relit@ +fexs-random-stuff-mod +k9@k9-mod +the-digimod-beta@the-digimod|方块数码宝贝 (The Digimod) +ex-deorum@|无中生有:神赐* +entity-detectors@ +@horse-armor-stand +decorative-blocks-fork|装饰方块(分叉版) (Decorative Blocks (Fork)) +above-and-below@ + +freeze-it-and-heat-it@|冷汗:食物冷冻与加热 (Freeze It, and Heat It!) +@keybindsgalore+(hvb007) +never-full +nemos-blooming-blossom@ +legacies-and-legends@ + + +your-log-saw-something-last-night@ +tubes-reloaded@ + + +natures-spirit@|自然之灵 (Nature's Spirit) +@natrium +bossominium@ +@sort-extension +hostile-water-monsters +slabs-layers@slabs-layers+ +history-of-middle-earth-legacy|中洲历史:传承 (History of Middle-earth: Legacy) +hostile-humans@ +classic-and-simple-status-bars@cssb|经典且简易的状态栏 (Classic and simple status bars) +@turtle-charging-station +your-reputation@¨your-reputation-wthit@¨your-reputation-jade@ +futurediary|未来日记 (FutureDiary) +infiniverse@ +use-item-on-block-event@ +genshin-instruments@ +genshin-elementreactions +chatshot@ +cropchance|IC2作物信息 (CropChance) + +freelook-fabric@freelook +respawn@ +infiniverse-utils +coreextensions@|核心拓展 (CoreExtensions) +@fast-items|快速掉落物 (Fast Items) +toad-terror +modern-industrialization-sound-addon@ +achievements-optimizer@ +automessage@auto-message +ftb-quests-optimizer@ +gfarm@ +ryoamiclights@ +patchouli-rofl-edition +alfheim-lighting-engine@ +even-more-instruments@evenmoreinstruments +more-red-computercraft-integration + +no-invincibility-frames +moderncreator@modern-creator +better-questing-unofficial|更好的任务非官方版* +p455w0rds-ae2-wireless-terminals-patch +spoiledz@ +boss-music-mod +yippee +friends-forever|永恒的伙伴* +de-extinction-mod +custom-world-generation@|自定义世界生成* +cataclysm-tweaks +euphoria-patches@ +poke-ball|精灵球 (pokeballhv) +aquamirae-mod-music@aquamirae-mod-extra-music +deathmatch +@smooth-scroll|平滑滚动 (Smooth Scrolling) +toad-terror-battle-music + + +fusion@ +machines@ +tenms-discs +netherrocks@ +invasion-code-red +efw-forgotten-place +@vulkanite-mod +yungs-better-end-island@|YUNG 的末地岛屿优化 (YUNG's Better End Island)¨yungs-better-end-island-fabric|YUNG 的末地岛屿优化 (YUNG's Better End Island)¨yungs-better-end-island-neoforge|YUNG 的末地岛屿优化 (YUNG's Better End Island) + +bellsandwhistles@ +daniinatorul +uuid-offline +vanilla-cubed@|原版立方* + + + + + +longer-chat-history@ +@secret-spectator +shoot-glass@ +modification-of-critical-hit@|暴击改革* +improved-damage-framework@idf +@shulker+ +biome-tag-villagers@ +combat-bash@ +@simpleprivatechest +marbleds-villager-hats@ + +connector-extras@ +akkamaddis-simple-tungsten|Simple Tungsten - 新 +just-enough-beacons-reforged@ + +akkamaddis-additions@akkamaddis-simple-tungsten¨simple-cobalt|Simple Cobalt - 新 +akkamaddis-ashenwheat@ +prehistoriclegacy@prehistoric-legacy +redyed +enchantmentdisabler@enchantment-disabler +miners-glasses|矿工眼镜 (Miner's Glasses) +relics-and-alchemy@ +@greate +advanced-world-selection +accelerated-decay@ + +zots-only-silver@ +iceandfire-rlcraft|冰火传说-RLCraft版 (I&F:RLCraft Edition) +bqutweaker@ + +the-arbiter|调停者* +builders-construct + +timelessivy|永恒常春藤 (TimelessIvy) +akkamaddis-hadite-coal|Hadite Coal - 新 + +akkamaddis-arsenic-and-lace|Arsenic and Lace - 新 + +xiyus-exchanted-book@xiyus-enchanted-book|饩雨的附魔书 (Xiyu's Enchanted Book) +la-abuelita@abuelita +rotted-forge@rotted +rustic-furniture-compat +@no-realms-button|Realms按钮移除 (No Realms Button) +@benchantments +epic-fight-indestructible|坚不可摧 (Epic Fight - Indestructible) + + + + +catwalks-llc@ +divine-quest-rpg +@carpet-org-addition +simply-headshots +random-structure-land + +random-mobs-land +clean-swing-through-grass +shrug-it-off-stb-edition@ +enchantsmith@ +snifferent +jei-recipe-history@ +@yeet +macaws-paths-and-pavings@|Macaw 的小径和路面 (Macaw's Paths and Pavings) +chiseled-bookshelf-visualizer@ +elytra-skins@ +mcv-biome-makeover-lieonlion@ +more-chest-variants-lieonlion@ +more-crafting-tables-mct@more-crafting-tables-lieonlion +@cobblemon-quests +akkamaddis-classical-alchemy|Classical Alchemy - 新 +@big-pony|彩虹大马 (Big Pony) +qraftyfied +theft-mod@theft +akkamaddis-golden-glitter@ +@obsidianbucket +enhanced-annihilation-planes +akkamaddis-simple-cthon@ +@heads-hurt-too! +pooping-animals +good-boy@ +nethers-overhaul@ +better-battle-towers|战斗高塔,启动!* + + +@axiom + +lilac@ +colorful-enchantment|自定义附魔光效 (Custom Colorful Enchantment) +rusticwitchcraft + +sterling-and-black|Sterling and Black - 新 + + +boss-and-magic-raid-compat +animated-mobs@boss-and-magic + +backlytra|鞘翅* +neapolitans-quality +rustic-bop-woods +hedgehoggery +yawctys-giant-squids +no-durability +potion-of-armor@ +@wmf +tenebrous-lands@ +super-better-grass +configurable-boss-bars@ +nuclearcraft-neoteric@ +beastly-beacons +creeplets@ +thermoo@ +restapi@rest-api +@advanced-ui-scale +@umines +health-disease|健康&疾病 (health&disease) + + +@hd-skins + +sundew +undead-boxers +aesthetics@ + + +chinese-festivals@|中国节* +ultramarine@|群青* + +@cargo + +dragon-nest-forge-fabric +geode-creatures +haraldsbetterstructures +squake +ae2-uel-extended@|应用能源2非官方拓展 (AE2 Unofficial Extended) +terraria-calamity-mod|泰拉瑞亚灾厄 (Terraria Calamity) +darkrtp-rtp-random-teleport@darkrtp +cute-bears +additional-fruits@ +bigger-better-end-cities@|更大更好的末地城* +@some-peripherals +reden@ +sparse-structures@sparsestructures +persistentcooldowns|物品冷却持久化 (Persistent Cooldowns) +@command_extractor +advancement-based-spawning@ + +heroic-armory-legacy +yungs-menu-tweaks@|YUNG 的菜单调整 (YUNG's Menu Tweaks)¨yungs-menu-tweaks-neoforge|YUNG 的菜单调整 (YUNG's Menu Tweaks)¨yungs-menu-tweaks-fabric|YUNG 的菜单调整 (YUNG's Menu Tweaks) +entity-distance-1-12-2@entity-distance-1.12.2|实体距离 (Entity Distance) +coolesthardcore@coolest-hardcore +taxcastlepillager +pesky-pirates@ +subterrestrial@ +illusioners-tower +bad-npcs +darkfeather-golden-feather@darkfeather +darkspawn-teleport-to-spawn@darkspawn +darksmelting-smelt-armor-and-tools@darksmelting +fast-build +digi-applimobs|数码宝贝宇宙应用怪兽* +duckies +dimension-crystals@ +mechanical-crafting +@enhancedbookwriting +player-events@ +mushlings +sky-tribes + +recipe-enhancements +oceanopolis@ + +pumpkillagers-quest@ + + + +waterlogged-chests +realm-rpg-fallen-adventurers@ +useful-bats +goat-food +mobile-beacon-1-18-forge +durabuilt +cavemans +balloon-box +campfire-resting@ +fizzle +foamflower +grimoire-api +cristel-lib@ +more-sleeps@sleepquality|睡眠质量 / 更多睡眠 (Sleep Quality / More Sleeps) +o-coracao-da-selva +creative-experience +more-than-50 +underground-jungle@underground-worlds +forge-soul-like-armors-reworked +meds-and-herbs@ +soul-like-monsters-epic-fight-addon +souls-like-parry +tcdcommons@ + +autotranslation@|自动翻译 (AutoTranslation) +villages-and-pillages@ +nohurtcam-plus@nohurtcam+ +darker-souls + +@spooky-bats +swutms-extra-dungeons@ +swutms-extra-desert@ +@refill-chests + +@cookeymod +@useful-brush +@horse-spawn +tw-resurrection +@dice +any-lanterns@any-lanterns! +horse-tack +darkmobs-increase-mob-difficulty@darkmobs +@apollo-the-parrot +mob-variants +galvanization +biome-grass-available@ +pigment@ +sunrise-sunset-audio@ +halloween-nighmare +lookin-sharp@|锋芒毕露 (Lookin' sharp) +halloween-luckyblocks +spooky-halloween +isle-of-berk-variant-loader@ +spooky-arms +qraftys-end-villages +bed-is-not-too-far-away@ +@enderman-tweaks + + + +decoration-and-furniture + +formations@ +formations-overworld@ +formations-nether@ +halloween-spirit +glitches-halloween +rei-collapsible-entries@ + + +kubevs@ + +halloween-expansion-food +fishy-business-more-fish@fishy-business + +@parry +crab-mob-vote-2023 + + +enderswords@ + +lemons-halloween +moon-reborn +the-witching-hour +hallows-eve@ +@chroma-world-border +just-sword-blocking + + +@blissful-butterflies +mltpojectmonster|銘洛天的怪物增强 (MLTPojectMonster) +@relics-of-the-sky|空岛遗物 (Relics of the Sky) + +ae2-stuff-extended@ +butchers-delight-foods@ +better-falling@ +dmcloot +simply-stacked-dimensions +@what-are-you-voting-for-2023 +@what-are-you-voting-for-2022 +immersive-electrocution +additional-compression +team-projecte|等价交换团队 (Team ProjectE) +torcherino-community-edition@torcherino-ce|加速火把社区版* + +enchantgiver +diabolical-delights@ +ore-growth@ +@real-arrow-tip +dnt-ancient-city-overhaul + +cropariaplus +soularia@ +stemaria@ +spelunkers-charm-ii +structure-essentials-forge-fabric + +tiny-pals@ +@amethyst-craft|紫水晶工艺 (Amethyst Craft) +weapons-of-miracles-epicfight@weapons-of-miracles|奇迹武器 (Weapons of Miracles) + +@hsrpaths + +mcdar@|我的世界:地下城法器 (MC Dungeons Artifacts) +dnt-stronghold-overhaul +dnt-swamp-hut-overhaul +jaopcagt@ +smidgeon-o-bliss|片刻满足 (Smidgeon O' Bliss) +cable-flux@12.3.5 +jet-and-elias-armors + + + + +dragon-ice + +abnorlex-and-cryptids-delight +tf2-stuff-reloaded|军团要塞2重制版 (TF2 Stuff - Reloaded) +time-in-a-bottle-curio-support +absolute-ultracraft@ +more-layered-blocks@ +hybrid-aquatic@|混合水生* +spectre-creep +resource-chickens|资源鸡* + +storage-crate@|板条箱* +oculus-particle-fix@ +urkaz-moon-tools@ +the-midnight-lurker@ +realm-rpg-imps-demons +multiverse@multiverse_mod + + +strangecreatures +bovines-and-buttercups@ +mooblooms@ + +water-walking-fix@ +water-walking-fix-forge@ +@chicken-nerf +@explosive-breeding +squished@ +russtales-forge +trident-alter +disenchanter@ +minecraft-dungeons-artifacts@dungeons-artifacts +uniquedungeons +@cobbledex +cobblemon-info@ +enderman-overhaul@|末影人革新* +cloak-dagger@cloak-and-dagger +oworld2create|别创建新世界! (OWorld2Create)¨oworld2create-refoxed|别创建新世界! (OWorld2Create) +dungeons-in-dimensions +infernal-bugz +@cobblemon-gts +cobblepedia@ + +@cobblemon-integrations +fruitstack-jei-support@|果栈丰萦JEI支持* +dungeons-artifacts +the-monkey-bomb@ +@cobblemon-hunt +ancient-animals +beavery@ +qraftys-halloween-villages +vemerioraptor +technique-to-kill-thrasher|毙鲨技 (technique to kill thrasher) +the-open-sauce-toast-killer@ +@chicken-nerf-reforged +regex-search@ +better-wake-up-position@|更好的起床位置 (Better Wake-up Position) +railroad-blocks@ + +fossilmon@ +opack2reload|资源包惰性重载/抑验怠载 (0Pack2Reload/OPack2Reload) +wits@ +@motleys-music-discs + +husks-drop-sand@ +patched@ +@snakewheel-attack! + + +configurable-falls@ +just-enough-mekanism-multiblocks@ +throwableslimeball|可投掷黏液球/圆液多掷 (ThrowableSlimeball) +death-note|死亡笔记* + +icicle + + + +surface-mushrooms@ +dont-void-arrows@ +potion-cauldron@ +hippo-keystrokes@ +spiritcaller-backport + +kindled + +mushroom-trees + +@skeleton-creeper|骷髅苦力怕 (Skeleton Creeper) +better-chunk-loading-forge-fabric + + + + +mushroomified +soul-like-boss-epic-fight-addon +moderately-enough-effect-descriptions-meed-a-jeed-addon@moderately-enough-effect-descriptions-(meed)-jeed-addon¨@moderately-enough-effect-descriptions-meed|Moderately Enough Effect Descriptions - 新,未及时更新 +alexs-caves@|Alex 的洞穴 (Alex's Caves) +bow-spam-be-gone@ +lmdcraft +hardcore-survival@|硬核生存* + + +dynamic-village@ +@even-better-archeology + +jammies@ +dj-villager +ars-energistique@ +chatimages@chatimageN|聊天图片 (ChatImages) +create-more-drill-heads@|机械动力:更多钻头 (Create: More Drill Heads) +create-liquid-fuel@|机械动力:液体燃料 (Create: Liquid Fuel) +@rays-cool-armor +eeeabs-mobs@eeeab-s-mobs|EEEAB的生物 (EEEAB's Mobs) +@obfuscated-accessibility +regional-chat@ +zenith-attributes@ +@smartygui + + +selectlative|选择性成就共享* +better-compressed-blocks@ +fakerlib@ + +potion-id-packet-fixer@potion-fix +omniwand@|全能魔杖* + + + +key-binding-patch@|按键绑定补丁* +packet-fixer@ +new-xenchant@ +more-brewable-potions@ + +forge-cit +@diamethyst-golem +you-are-seeing-dungeons@ + +just-leveling@ +create-edible-belts +tact +paimon|派蒙!*¨paimon-fabric|派蒙! (Paimon) +@cesium|铯 (Cesium Storage Format) +salvage-furnace@ +eager-beavers@ +laendli-transport +witchs-artifacts +the-pumpkin-challenge@ +loot-crates-plus@loot+ + +fuji@|藤* +legendary-origins@ +flow@ +lit-it-up@ +lucky-cat|招财猫* +mc-mods-the-wizard-gear +better-tools-and-armor@ +berrfect@|完莓无缺* +mazemanicore +uncanney-valley +@cannibal-conundrum +@glass-carpet +@quality-sounds +dolt-compat +embeddium-extension +wakes@ +create-immersive-portal-integration +dangers-in-the-darkness +spookycraft +kelpie@ +@viavanillaplus +dead-mans-abyss +the-leagues-of-the-dead +centered-crosshair@ +@create-fabric-sodium-fix +realm-rpg-creep-crop +fexcraft-common-library + +x-autofish@x+-autofish|自动钓鱼XPlus版 (XPlus AutoFish) +befixment@bewitchment-rei +more-magic@ +cheat-command +@screenshot-organisation +pumpkinpal + +johnnys-biological-notes@johnnys-biological-notes-1.0-beta|Johnny的生物笔记 (Johnny's biological notes) +autodrop@ +mutation-rerun + +@compactspawners + +corundum-guardian-reborn +autofire-bow-enchant + + +rideableravagers@ +passive-searchbar|被动搜索栏 (Passive SearchBar) +flower-mimics@ +vegan-delight@|纯素乐事* +bloodmooncmsfix-bmcmsfix +evoodooers +giant-overhaul +@torohealth-damage-indicators-updated +boliviamod +leawind-third-person@|Leawind 的第三人称 (Leawind's Third Person) +fabled-weaponry +lazurite@ +lets-do-nethervinery@|下界葡园 (Let's Do: NetherVinery) +shinnyladders|发光梯子/洇荧登纵 (Shinny Ladders) +macaws-holidays@ +unions-upgrade-scrolls +torohealth-unofficial +rebindallthekeys@rebind-all-the-keys +pocketwatch2@pocketwatch +pick-blockstate@pickblockstate +@epcore|满同态核心 (Epimorphism Core) +oh-my-sherd +archaeology-banners@ +mobvote-2023-crab@ +totem-curse + +zombies-are-real +timeless-and-classics-guns-lesraisins-append-pack@lesraisins-weapon|TaC:绿葡萄附属包 (TaC:LesRaisins Append Pack) +permanent-chat-logs@permanent-chatlogs|聊天记录保存 (Permanent ChatLogs) +mob-strength@ +catastrophemod +@water-generators|水发电机 (Water Generators) +fishes-undead-rise-ye +nameless-servers@ +noisium@ +@embedded_assets +creative-library@ +independent-gizmo@ +jackocache@ +creepy-creepers +modular-item-api@¨truly-modular-arsenal@¨truly-modular-archery@¨truly-modular-armory@ + +@actionhunger +trafficcraft@ +banilla-hammers@ +everyxhotpot@every-x-hotpot|一起火锅 (EveryXHotpot)¨everyx-hotpot|一起火锅 (EveryXHotpot) +@hira-hira +tierability@ +soul-collector@ +@jime +@nota + +@lighty +echo@ +@shieldindicator + +lanthanum@|镧* +charge-thrower + +champions-ashes|王者遗灰 (Champion's Ashes) + +jade-addons-ic2classic@ic2cjadeaddon +sit1@sit! +monnef-core +robs-floating-islands@ + +glasses@|眼镜* + +gem-crabs-1-19 +berrybush-magic +archers@ +@packrule-menus|数据包/游戏规则菜单 (Datapack/Gamerule Menus) +inventory-backups +rideablepolarbears@ +cobblemon-lucky-blocks +egg-delight@|鸡蛋乐事* +portable-nether¨portable-nether-fabric +@resourceful-block-sounds + +the-starved-stalker@ +toms-peripherals@ +croptopia-delight@ +@no-mining-cooldown +futuristic-decor|次元科技装饰方块* + +spyglass-of-curios@|饰品望远镜 (Spyglass of Curios) + + + +ssr +petal@ +creatures-of-runeterra@cor +from-another-world@ +pumpkin-moon@ +zombie-onslaught@ +neighborly +natural-progressions@natural-progression +charged-explosives@ +pulver@ +@allow-editing-player-data +apple-crates@ + +betterend-forge-port|更好的末地 Forge 版 (BetterEnd (Forge)) +the-corpse-stalker-cave-dweller-mod +ciscos-armoury +portable-mobs +deserts-and-dunes +@mcfc +box-of-horrors@the-box-of-horrors +chat-colours@ +mekanism-weapons|通用机械武器 (Mekanism: Weapons) +vanilla-reflex@ +flighthud-reborn|鞘翅飞行抬头显示:重生 (FlightHUD: Reborn) +celestial-enchantments|星月附魔* +clearsky|洁净天空 (ClearSky) +educate-nitwit +damage-spawns-mobs +decorative-sniffer-egg@ +gilded-sherds@ +camps-castles-carriages +rainbow-reef@ +advancement-no-more@ +aqua-geode + +medieval-buildings@ + + +@you-thief-remastered-edition + +more-slabs-stairs-and-walls@ +caves-canyons +dragon-mounts-legacy-continued@|龙骑士重制版延续* +chloride-mod@chloride +aggro-indicator@aggroindicator +haveasoltime@ +tothestars@ +translater@ +localized-chat@ +prominent-create +bad-lightning-no-cookie +equipment-standard@|装备标准 (EquipmentStandard) +terra-armory@ +advanced-enchantments@|进阶附魔* +oaks-nature@ +geophilic-reforged +lglegacy@|延迟监视:移植版 (LagGogglesLegacy) +smooth-scrolling-refurbished@ +medieval-weapons-pack@ +celestial-artifacts|星月遗物* + +perfect-mob-farm +smart-render¨smartrender +power-adapters@ +silk-api@|丝绸开发库 (Silk API) +@mediaworks|媒质工程 (Mediaworks) +chestesp +@ruthenium|钌 (Ruthenium) + +spirit-walker@ +gcyr@ +gregtechceu-modern@|格雷科技现代版 (GregTechCEu Modern) +@intarsia|咒术器具 (Intarsia) +instant-village-building + +nbt@ + +separated-leaves@separatedleaves +pangteens-immortal-adventure@|PangTeen的平凡冒险 (PangTeen's Immortal Adventure) +simple-shops@simpleshops|简单商店* +forgiving-border|仁慈的世界边界 (ForgivingBorder) +snow-mercy + +@blocky-bubbles +airdrop-supply|空投供应* +refined-proxy + +pickable-pets@ +snow-mercy-forge + + +bouncestyles@ +@better-beds-reforged +untamed-delight|不羁乐事* +monster-no-armor-in-slar + +dancing-hoppers@|舞动的漏斗* +anvil-crafting@|铁砧配方* +ender-chested@ +@skull-vision +prefabricated-structures@ +rebirth@rebirth-paintings +amethyst-tools-2|紫水晶工具2 (Amethyst Tools Mod 1.2x) +mob-pets|驯兽师* + +ultimate-compression@ + +farming-in-rain +bosses-of-mass-destruction-forge@|祸乱鬼魅 [FORGE] (Bosses of Mass Destruction [FORGE]) +armor-set-bonuses@¨armor-set-bonuses-fabric +nemos-creatures@ +immersive-jungles@ + +weather-2-remastered|局部气候&风暴 - 重置版 (Weather 2 - Remastered) + +phantoms-of-the-end +diamond-and-emerald-farming-mod +blood-and-gore +nonetherportal@no-nether-portal +necronomicon@ +showcase-item@ +eldritch-end@ + +quit-or-not +spelled-mobs +let-fish-love +exposure@|拾光定影* +@fast-portals +pick-up-me-please@pickup-me +bouncy-creepers +simple-death-chest@ +@enhancer-mod +headphones +you-are-the-zombie +self-damage-knife + +coin-craft +speedy-ladders +@youaremyhatnow + + +fruits-delight@|果园乐事* + +destruction-difficulty@destructiond|破坏困难* + +villagers-follow-emeralds +dredge@ +create-creating-space@creating-space +asmc-performance-patch +mrcrayfishs-gun-mod-unofficial|MrCrayfish的枪:非官方版 (MrCrayfish's Gun Mod: Unofficial) +@fish-tanks +ram-compat@ +@wcsm|中国式学校 (Chinese School Mod) - 非官方版0.1.x(此由作者提供)¨@0.0.1|中国式学校 (Chinese School Mod) +zombies-reworked-forge@zombies-reworked +legendary-monsters@|传奇怪物* +catontoasts-mobs +combatify@ +go-fish-updated|一起钓鱼吧!(更新版) (Go Fish (updated)) + +what-are-they-up-to@ +fumofumo|Fumo - 仅 16.0.0+¨@fumo +@elytraplus +mcaic@ +@zombification +@stutterfix +extrasounds-forge@extrasoundsforge +resource-mod-loader|资源模载器* +regrown +carcass@ +@humility-afm +let-me-use-it|亿用得纵 (Let Me Use It!) +epic-fight-impactful@ +grassnotfloating|浮的古原草送别 (GrassNotFloating) + + + +thermite@ +restriction +collision-fix@ + +dynamic-name-tags@ +@profundis +ctlib@ctlibmod + +building-packs +styled-sidebars@ +cut-and-colored@ +the-fence-unleashed@fency +@touch-up +@gipples-galore + +wood-enjoyer@|入木三分* +@coreextensions-foodapi|核心拓展-食物 (Coreextensions-Food-API) +dynamic-darker-souls +fade-in-chunks@ +@durability-guard +sorceryfight +better-lava-bucket +just-outdoor-stuffs@ +croptopia-additions@ +corniergun +better-flight-forge@betterflight + +farmers-delight-cookbook-reforged@|农夫乐事:烹饪书重制版 (Farmer's Delight: CookBook Reforged) +applications@ +k-clear-lag +@hexdim|咒法维度 (Hexxy Dimensions) +simple-backups@|简单备份* +sky-guis@ +botaniverse@|寰宇植物学* +betterer-p2p +recall-staffs + +enercell|能量电池* +default-world-generator-ssp +homyatos-explosives@ +infchest@|无限箱子 (Inf Chest) +@squashed +unremovableeffects@unremovable-effects +traders-in-disguise-the-illager-assassin-project@ +cherished-items +verdantvibes@|绿意盎然 (VerdantVibes) +crafting-manipulator +beware-the-rain +the-sasquatch +potion-pizzas@potionpizzas|药水披萨* +pot-breaker@|砸罐子* +disabletools@disable-tools|禁用工具 (Disable Tools) +@humility-se + +push-everything-away@|推开一切* +create-power-loader@|机械动力:动力加载器 (Create: Power Loader)¨create-power-loader-fabric@|机械动力:动力加载器 (Create: Power Loader) + +epiceldenringweaponsarmorandmobs +restart-server@ +sakura-cherry-additions +pillagers-gun|掠夺者的枪 (Pillager's Gun) +hammers-and-smithing + +tetra-booster-pack@withering-boon-for-tetra +everlasting-skins +decorated-pot-minecart|饰纹陶罐矿车* +legacy-console-sounds@ +eye-spy@ +sonicraft-demons@ +@speech-manager-by-command-scoreboard|计分板禁言管理器 (Minecraft Command Speech Manager) +flans-mod-reloaded|Flan的枪械重制版 (Flan's Mod: Reloaded) +mod-whitelist@|模组白名单* +simpledeserteagle|简单沙鹰 (Simple Desert Eagle) +dungeons-towers@dungeons+-towers +dungeons-more-spawners@dungeons+-more-spawners +@nether-depths-mod +technical-cores|机巧核心* +minetraps@|我的陷阱 (MineTraps) +@fabricated-rift +honey-sticky-piston +ore-discovery-broadcast@ +alchemists-garden +opolis-strainers@bbl-strainers +book-eater@ +rotom-phone-cobblemon@ +@world-comment|随处随笔 (World Comment) +ultramarine-refabricated|群青:重织* +long-nbt-killer +@curio-attribute|饰品属性 (CurioAttribute) +consistent-aim|持久瞄准/移眼盯住* + +arrow-pointers@ +bareback-horse-riding@ +what-the-gecko@ +forgotten-pots-forge +explorations@ + +redstone-lamps-plus +wool-collection@|羊毛装饰方块 (The Wool Collection) +@more-automation +random-mob-sizes@|随机生物模型大小* +unexperienced + +balanced-crates@ + +ducky-periphs@ +@norefreshscroll +furnitura@ +create-ad-astra-compat@ + +walkie-talkie@ +geotagged-screenshots@ +@wafflesscythes + +@legacy-optifabric +oneironaut@ + +celestial-core|星月核心* + +colorablefox|可染色狐狸/色绘你狐革 (Colorable Fox) +archeology-api +rpg-parties@ +astikor-carts-tfc@tfc-astikor-carts +nanexs-mobs +no-feather-trample@ +embers-extended-life@embers-unofficial-extended-life|余烬非官方延续版 (Embers Unofficial Extended Life) +terrafirmajousting@ + +jujutsu-animation +craftable-elytra +francium@francium-optimization|钫* +dragonwingselytra +universal-grid@|通用终端* + +antique-atlas-reborn +ars-artifice@ +draconic-energy +hamsters-plus@hamsters +@you-bandit! +eugenes-lance@ +thorium-reactors@|钍反应堆* +eugenes-guan-dao@ + +eugenes-wealthy-plains-village +lets-do-herbal-brews@lets-do-herbalbrews|煨茶酝露 (HerbalBrews) +enchant-icon@|附魔标签* +vintage-delight@|腌渍乐事* +@hotshot +biospherical-expansion@ +@serendustry +create-connected@|机械动力:创意传动 (Create: Connected) +@rgml-quilt +hbms-nuclear-tech-hamster-reloaded +noxesium@ + +infinity-cave|无限洞穴* +surface-lush-caves +geologic-expansion@|地质拓展* +cpas@ + +awesome-magic@awesome_magic +christmas-dweller@ +create-curio-goggles@ +@cobbleloots +dontusecommand@|请别用指令 (DontUseCommand) +beans-backpacks@beans-backpacks-3¨@beans-backpacks + +randomjs@ +piston-push@ +erinium-automation +angelica@ +explosiont +spider-caves@ +cams-lights + +lemon-kindom-artifacts|柠檬王国:传说之物 (Lemon Kindom: Artifacts) +when-dungeons-arise-seven-seas@|地牢浮现之时 - 海洋扩展 (When Dungeons Arise - Seven Seas) +mob-battle-extra +lios-overhauled-villages@ +lost-relics@ +provihealth@provis-health-bars +metabolism@|新陈代谢* +adv-js|Advancement JS - 更新较慢¨@advancementjs +teleportcraft@ +frights-delight@|惊悚乐事 (Fright's Delight) +travelers-compass@|旅行者指南针 (Traveler's Compass) +@artemis-thin-logs +configjs@ +hardrock-tools-materials@ +animals-trap +armor-damage-scaling-forge-fabric +hornet +exotelcraft@ +jujutsu-kaisen-gt +@updated-hud +mapwriter + + + +clickmanaita + + +command-toast|指令面包机* +@hex-research|咒法研究 (Hex Research) +cwg-far-plane-view +firmacivilization@firmaciv|群峦传说:航海文明 (Firma: Civilization) +catbop-things +player-mobs@ +@create-trimmed +tinkers-caramel +ctrl-q@ +rug@ +glowing-tools@|发光工具* +horsing-around@ +herd-mentality@ +doggy-talents-next@ + + +motobox@ +pottery-additional-pots@pottery +better-dogs-x-doggy-talents-next +@villagertimetable +towntalk +cumulus@ +epherolib@ +icterine@ +notrample +industrial-foregoing-souls@ +fuelgoeshere@ +initial-dimension +youkais-homecoming@youkaishomecoming|妖怪们的归家 (Youkai's Homecoming) +utilitarian@ +classic-sword-blocking|剑之格挡* +@flutterandflounder + +jojo-world-of-stands@ +ash-api@ + +stylecolonies +hyperbox@ +respite-creators-fabric@ +simple-pizzas@|简单比萨* +rapscallions-and-rockhoppers@ +pescatore@ +apocalypse-now@ +cenozoic-nightmare-the-horror-of-prehistory + +quickbackupmulti@|多槽位备份 (QuickBackupMulti) +slashblade-japanese-addon-pack-reforked|拔刀剑日系附属重置版 (SlashBlade Japanese Addon Pack Reforked) +@create-fabric-fixes +@command-block-sceptre|命令方块权杖 (Command Sceptre) +crate-delight-forge@crate-delight|装箱乐事 (Crate Delight)¨crate-delight-fabric|装箱乐事 (Crate Delight) +cultural-creators-forge-create-and-cultural@cultural-crators¨cultural-creators-fabric-create-and-cultural +shuffle@ +probejs-legacy +create-destroy@destroy|坍毁化合 (Destroy) +flourish@ +pitch-dark@ +survival-debug-stick +cerbons-api-forge@cerbons-api +arcane-apprentices +kirara +nether-gold +create-interactive@interactive|机械动力:交互学 (Create: Interactive) +this-tsunami@ +blendium@ +awakened-bosses +survive-in-the-winter-frontier@misc_twf|冬境边域:生存法则 (Survive in the Winter Frontier) +toneko@tonekomod +goldelight +cosmos-portals +cc-vs@ + +item-despawn-timer@ +@is-this-mod-legit +aylyth@ +no-shade@ +dimthreads@ +jonns-trophies@ +it-follows-exclamation@it-follows! +@loggerhead-luminancies +asteorbar@|Asteor的状态栏和血量显示 (AsteorBar) +better-f1-reborn@|更好的F1重制版* +create-tipsy-n-dizzy@create-tipsy-n-high +ars-expanded-combat@ec-ars-compat +@revamped-piles +@fluiwid +revamped-phantoms@revamped_phantoms +defaultserverlist@ +green-delights|翠绿乐事* +@modmenu-ornithe +lost-city +digestive + + +inventory-binds@ + +octo-lib@ +farmers-plus¨farmers-utils|Farmer's Plus - 旧 +architects-friend +bagus-cosmetic@ +floatingitems + +tetracelium@ +fugue@ +create-food@ + + +a-block-of-charcoal|木炭块 (A Block of Charcoal) +a-block-of-flint|燧石块 (A Block of Flint) +tome-of-blood-rebirth@ +chatutils@ + +asgard-shield-reloaded@ +gobble-core +expanded-combat@ + +fancy-chests@ + +glore@ +pi-privateisland|私人空岛 (PrivateIsland) +i-didnt-mean-it-that-way@ +finitewater@ +serverstop¨serverstop-fabric +glassential-renewed@ +tanukidecor|狸猫装饰 (Tanuki Decor) + +cit-reforged +ultreonlib@ +undergarden-delight@|深暗之园乐事* +medieval-deco@ + + +limi|轻量化模组名称显示 (Lightweight Mod Indicator) +jtlunlocker +ae2-stuff-unofficial +@error422 +harder-underground|更难的地下* +harder-wildlife|更难的野生动物* +harder-farming|更难的农作* +waterproof +entityculling-unofficial@entitycullingunofficial|实体渲染机制优化:非官方版 (EntityCulling Unofficial) +@sync-projecte-knowledge + +eventtweaker +craft-vania +lotrextracoins-for-1-7-10|额外魔戒银币 ([Legacy] LotRExtraCoins) +genst +ae2-network-analyser +mxtune +customui|自定义UI (CustomUI) +deadly-monsters-patched +glodium@ +aether-delight|天境乐事* + +dungeonz@ +cazfps-axolotls +easy-breeding-tfc +paperfixes@ + +fishing-bot +progression-tweaks +whitelistfixer@ +fleshz@ + +depths-of-madness +tree-lib +@moehreag-legacy-lwjgl3 +real-camera@|真实相机* +unofficial-mod-name-tooltip-backport|模组名称显示:非官方版 (Mod Name Tooltip Unofficial) +custom-health-bar@ +lotrimprovements|魔戒改进 (LOTR Improvements) +mousekeyinventoryfix@ +visible-offhand@|可见副手* +phosphorcrashfix@phosphor-crash-fix +sound-physics-remixin|籁* +hextended-staves@ +aquaculture-delight@|水产乐事* +vics-point-blank@ +occultism-kubejs@ +tetra-extras@ +anilink +overworld-netherite-ore@ +@rebindmykeys +keybind-description-fix +kappas-forgelin +flesh-mod + + +create-bitterballen@ +glowing-illagers@ +heads@ +epicdmcbossdante +step@ +wildist@ +hiccups-legacy +slave-knight-gael +gwyndolin-dark-souls-boss +mceconomy2 +forgeservertools|服务器工具-核心 (ServerTools-CORE) +@replay-fps +quark-delight|夸克乐事* +mmm-lib +@crabmtr-transit-plus + +create-design-n-decor@ + +enviromine-lite@|更多生存要素:精简版 (EnviroMine Lite) +knaves-needs@ +azurelib-armor@ +@container-tooltips +magical-jewelry +epicsoulsbosses +epic-puss-in-boots +soul-like-npc +epic-empires@ + + + + +prefabricated@ +artorias-epicfight-addon +soul-like-demons-plus-epic-fight-monsters +dark-spirit-dark-souls-system-epic-fight-addon +soul-like-mobs +untranslateditemsaddon-alsofluids@untranslateditems-alsofluids +better-quest-pop-up@ +@simple-hud-utilities +kiln-fabric@kiln +tetra-niche-materials +the-accurate-backrooms +create-trains-on-trains@ +@campfire-torches-plus +@armor-rack +flux-networks-fabric@flux-network-fabric +@surface +poof-sounds@ +crash-pipe@ +gradeus-epic-fight-addon-soul-like-boss +zombie-more@zombies-more +gunscraft|枪械工艺 (Guns Craft) +audino@ +tabbychat-unofficial@ +odyssey-quests@ +flapjacks-economy +@onion-onion +relics-vivid-light-addon@ +tofucreate@tofu-create +luminite-sunilite +better-formatting-code +@apeeling +@bubble-boots +silkablooie@ +@belly-flop +@milky-way +@pet-shop +bed-is-never-too-far-away +create-oxidized@create_oxidized + +green-soul +everyxdance@|一起跳舞! (EveryXDance) +applied-flux@appflux|应用通量* + +tics-delight@tinkers-delight|匠魂乐事 (Tinkers' Delight / TiC's Delight) +unnamed-desert-structures@unnamed-desert +bloomingnature@lets-do-bloomingnature|绽芳自然 (Let's Do: BloomingNature) +waila-inhibitors@ +thingamabobs-and-doohickeys +waila-events@ +march-of-the-ents|恩特的进军* +rndtp +in-world-buoyancy +@simply-starminer +macos-input-fixes@|MacOS 输入修复 (MacOS Input Fixes) +@maxhealthfixfixfix +@astronomical + +@millet-delight|小米乐事 (Millet Delight) +telos@|终焉* +magical-torches@ +dynamical-compass@ +better-questing-lord-of-the-rings-addon|更好的任务-魔戒扩展 (Better Questing - Lord of the Rings addon) +dimension-teleport@ +better-azalea +tetratic-combat-expanded@ + +more-beautiful-slabs@ +tools-complement-create@create-complement + +biome-beans +cats-workshop +soulless-steeds +openblocks-elevator-fabric@ +aurorasdecorations@ +choups-drakvyrn-mod +abyssal-decor + +reddens-stone-lanterns@|Redden的石灯笼 (Redden's Stone Lanterns) +heaven-burns-red|红烧天堂* + +apotheosis-modern-ragnarok|神化:现代诸神黄昏 (Apotheosis Modern Ragnarok: Zero) +@bedgoboom +block-properties|方块属性* +custom-chest-loot|自定义战利品箱* +resource-pandas@ +sniffs-weapons@ +maxlermod +seed-protect +bow-overhaul|弓箭改革* +zelda-sword-skills-addon|塞尔达剑技 - 拓展 (Zelda Sword Skills - Addon) +narrus-yeetus@ +login-shield +blockinteraction|禁止右键方块 (BlockInteractionMod) +linkart-fabric +leftist-potions@ +more-delight-fabric@more-delight|多趣乐事 (More Delight)¨more-delight-forge|多趣乐事 (More Delight) +mceconomy3 +@antique-atlas-4 +pollution|污染* +tinted-campfires@ +additionalstatus +epic-knights-slavic-armory +create-copies-cats@ +chat-signing-hider@ +gamma-creatures@ +multipart-machines-mining +high-version-better-structure-block|更好的结构方块1.20.1 + +@creeper-multidrop +the-man-from-the-fog@|雾中人*¨the-man-from-the-fog-fabric@|雾中人 (The Man From The Fog) +sawmill@universal-sawmill|锯木机* +@savemod +@dudewhatsmygpu +create-wizardry@ +netherite-extras@ +wfs-cave-overhaul@ + + +cit-resewn-jsonlagpatch@ +geckoanimfix@ + +mekanismecoenergistics@mekanism-eco-energistics +waila-blacklist|Waila 黑名单 (WAILA Blacklist) +item-blacklist|物品黑名单* +continue@ +the-dawn-era@|黎明纪元* + +tridents-n-stuff@ +create-hand-crafting@ +@canary-safety +@softer-pastels +@rainbethunder +create-easy-structures@ +sound@ +skinshuffle@ +reboot-lovelyrobot@|萌化机器人:重启 (Reboot LovelyRobot) + + + + +farmers-delight-tfc@ +even-more-realistic-ore-veins +ad-astra-extra +underground-bunkers@ +minemath@ +weapon-leveling@ +rather-more-potions|稍多药水* +museum-curator@|琳琅满目* +pixel-hud@ +@immibis-macroblocks +@heater +natures-melody@|自然旋律 (Nature's Melody) +astemirlib@ +create-unbreakable-tools@create_unbreakable +timeless-heroes@superhero +sky-origins@sky +glitchcore@ +light-level-overlay-reloaded|简明直观的光照提示* +eirin-yagokoros-pharmacy@eirin-yagokoro-pharmacy|蓬莱药局 (Eirin Yagokoro's Pharmacy) + +tfc-ore-excavation +tac-interact-key|TAC交互优化 (TAC Interact Key) +@cement + +@igfileeditor +tide@|潮汐* +taiga-replant-replant|匠魂合金附加二次重栽版 (TAIGA Replant Replant) +nether-warlord-boss +loot-bundles@ +optifine-check +tfc-ie-minerals +looking-at + +rftools-continuation +better-with-everything@ +create-clockwork@ +lomlib + +@old-and-new +sparkly-pants@ +nether-sheep@|暗黑羊* + +light-level-description +set-home-waypoints +leaky +curse-of-pandora@|潘多拉之咒 (Curse of Pandora) +champions-rotn-edition +tempest@ +simpledifficulty-for-underdog +@proxy-compatible-forge +tally-master +hexagonal-heresy +hardcore-spelunking +dark-menagerie +icarus-mod +ars-knightsnmages@epic-knightsnmages¨epic-knightsnmages-fabric +hotai|绷带* +zeta@ +taxtowncitizen +killer-rabbit-transformation@killer-bunny-tweaks|转化杀手兔 (Killer Bunny Tweaks) +bronze-viking + +astikor-carts-redux@astikorcarts-redux +third-person-shooting@third-person-shooting-zero|第三人称射击:零 (Third Person Shooting: Zero) +sight|视域* +@the-first-city +threetag-palladium@|钯 (Palladium) + + + +permanent-status-effect@permanent_status_effect|永久状态效果* + +world-play-time@ +ikwila-i-know-what-im-looking-at +experienced-crops@experienced_crops +medieval-seedbags +fusionutil + +@compact-machines-infinite|压缩空间:无限 (Compact Machines: Infinite) +thaumic-sanity +tfc-thermal-deposits@tfc-volcanoes +animals-trap-for-tfc + +zzzzz-custom-configs +weird-happenings +nbc-heroes@ +melody@ +cut-through@ + +anvilfixreborn@anvil-fix-reborn|铁砧修复重生 (Anvil Fix Reborn) + +apothic-curios +hbm-ntm-lucky-blocks +thaumtweaks +no-baby-zombies@ +combat-nouveau@ +@hanging-on + +@lazy-mystical|神秘农业:懒人 (Lazy Mystical) +udlede@|港口* +hammer-time +hammerz +@pickup|物品框交互优化 (Pickup) +livingadventuretrails +suggestions-api@ +colorful-subtitles@ +dashing-dashboard +mod-control|模组控制* +extended-potions +dimension-inventorys|维度物品栏* +dimension-rules|维度规则* +erroring-entity-remover-reforged@eer-reforged +@vs-tournament|瓦尔基里天空:竞赛 (VS: Tournament Continued) +fabricated-exchange@ +more-variants-and-biomes +badoptimizations@ + +genshinimpactmod +diagonal-walls@ +gravestones-die-classy-updated +osog-city-cars +immersive-vehicles-iav-parts-pack +tfmg-virtual-oil-deposit|工业长路:虚拟油田 (TFMG: Virtual Oil Deposit) +@alinlib +croparia-if@|矿石魔种 (矿石作物/魔种之咏 IF版) (Croparia-IF) + +@actionlib +simple-close-button@ + + +godzilla-rising +create-netherless@ +noguievolution@no-gui-evolution|沉浸进化 (NoGuiEvolution) +baseball-bats +tfc-weather + +conrad@ + +nendermoo +forgedcarpet@ +framed +gear-core@ +hideasterisk@hidemodded|隐藏“已修改” (HideModded) +monster-eggs@ +rain-shield@|驱雨盾* +cerbons-better-beacons@ +@funny-roulette +@worldeditcui-forge +better-loot@ +trique-api@ +lets-do-addon-structures +create-recycle-everything +tfc-ambiental-second-edition@ +@somemusicdiscs +gimmetime +@fuzzy +helpfixer +@litemoretica +@shiftingwares-villagerconfig-addon +@colored-lamps +@expansive-lighting +drippedout@dripped-out +easter-rabbit-life@ +sticker-frames@ +tnt-slimes@ +armored-redstone@ +bismuth-colors@bismuth-2|铋 (Bismuth) +killbind@ +universal-clock-hud@ +portaldupebegone@ +@teabridge +missions@ +votemission@ +immersive-vehicles-automobilwerke-schwikau-veb +cheesemaking +cardiac@ +materialtweaker@ +whirlwind@ +warden-tools@ +royal-guard|皇家守卫* +@the-mighty-architectury +themoreloyaltrident@|更忠诚的三叉戟/移运兜转 (TheMoreLoyalTrident) +notenoughresources +elenai-dodge +xenon@xenon-forge|氙* +riftstorm-rpg +data-api +better-babies +morecreativetabs-forge-fabric@morecreativetabs + +@shove! +sunflower-delight@|向日葵乐事* +mystias-izakaya@mystiasizakaya|夜雀乐事* +carpet-everything + +lets-do-brewery-farm-charm-compat@lets-do-brewery-farmcharm-compat|盛节精酿 (Let's Do Brewery) - [作者推荐]2.0.0+¨lets-do-brewery@|盛节精酿 (Let's Do Brewery) - Legacy,作者已停止维护 +hephaestusplus@ +re-dimension-stages|维度阶段重制版 (Re-Dimension Stages) +lemoned@lemoned-(farmers-delight) +@horizonlimit +fallen-paladins-and-priests + +@rgb +@virtualpump +everymole@ +mutant-iceologer@mutant-iceologer-mod +@days-gone +@extra-loot|额外战利品 (Extra Loot) +relics-of-gaming-continued@|游戏遗物:延续* +endermen-plus@ +tiptapshow@ +villager-gunners + +epic-fight-infernal-gainer +prodigy-mechanics +just-an-end-anchor@ + +memory-usage-title@|标题显示内存* +string-utilities@|字符串工具* + +sweeper-maid@|清洁女仆* +more-enchantments_|更多附魔 (More Enchantments) +bow-scope + +fpv20 +molten-metal +selling-bin@ +tomtarus-cobblemon-farmers-delight-tweaks +cobblemon-o-plenty +tomtarus-cobblemon-immersive-engineering-tweaks +abuseless-hardcore@ +@wizstacks32 +tconjei@ +new-xp-ore +@not-responding +nocubes-wilderness + +copper-great-swords +@better-falling-block-particles +zume@ +mobtimizations@ +illager-trader@ +@damagenumbers +toolendxp +spiritmancy@ +create-vintage-improvements@ + +dragon-craft-quest +sword-of-gods +horse-stonks@ + +pillarger@ +ars-additions@ +visualsound +@cyclic-crash-fixer +lavender-api@lavender + +cheatutils-by-zergatul +jump-sounds@ +kirin@ +llamapalooza +instant-drown +acsguis +game-phase@|游戏阶段* +no-zombie-pandemic +witcheroo@ +totallybalancedcreativeflying + +heterorustichromia +video-extension-for-fancymenu-forge¨video-extension-for-fancymenu-fabric +easy-npc@ + +the-dawn-era-delight@|黎明纪元乐事* +dynamic-craft +startinginventory +wireless-speakers|无线扬声器* +sagerfx@|SA特效 (SagerFX) +@noteit +jewelrycraft-2|珠宝工艺2* +fallflyinglib +enchantable-spike + +xaeros-map-chest-tracker-integration@ +warden-horn@ +too-many-efficiency-losses +srp-addon-cotesia-glomerata@|SRP:寄生蜂 (Scape and Run Parasites Addon: Cotesia Glomerata) + +damage-lock|磁场天锁* + +modular-materials@modularmaterials|模块化材料* +minepal +custom-portals@|自定义传送门* +dirty-lens@ +@improved-anvils +styled-player-list@styledplayerlist +create-love-war@ + +chainmailed@ +serious-player-animations@ +abridged@ +hexvr@ +hearths +prey-effect +venturer@ +wheres-my-wither-storm +alexs-mobs-interaction@|Alex 的生物:交互* + + + + +myworldgen +medieval-buildings-end-edition@ + +orpheus@ +create-sweets-and-treats@ +klsts-beyond-netherite + +refined-polymorphism@ +cave-dweller +dweller-dweller@dwellerdweller +thermals-delight +@advanced-hud +better-farmers-combat + +simple-butchery¨@simple-butchery|Simple Butchery - 被设置为无法检索列出 +butchery@ + +enchantment-reveal@ + +copycats@|机械动力:伪装方块+ (Create: Copycats+) +the-great-alchemical-compendium@ +desperate-measures@ +block-slabs-mod +roost-re-hatched +lifedrain +mediethings +gastrolimital-bypass@no_player_limit + +epic-core-api@|史诗核心API (Epic Core API) + +infinityrpg +super-water-block +@stop-repeating-command-block|停!循环型命令方块 (Stop Repeating Command Block) + +pressure|压强* +amendments@ +piglin-army +decorative-ladders@ +more-foods + +modern-delight@|现代乐事* +better-main-menu@bettermainmenu + +more-wizards@more-wizards-more-magic-series +oldresearch@ +ascension-megamons@ +simply-sulphur@ +fabric-hider +custom-cursor@ +the-man-from-the-void +simpletms-tms-and-trs-for-cobblemon@ +cobblemizer@ +worldtools@ +particle-blocker@particles +vehicle-hunger-bar@ +spooky-scary-halloween + + + +sandbox-bootstrap +tetra-toolbooster +ad-astra-proxima-plus +ad-astra-extra-additions@ +infinite-fluid-bucket@|无限流体桶* + +@voxy +vmod|VMod - 停更¨@vmod +minestuck + +star-wars-planets-ad-astra@star-wars-planets +amethyst-equipment@ +the-whisperer + +epic-vinland-saga +cat_jam@ +remastered-structure +spacore +fancyvideo-api +goatman-jar-v2-dweller@the-goatman-dwller + +mineral-overhaul-shellstone-tuff +clear-gpu-cache@|清除GPU缓存* +stalker-creepers +the-ghoul-remastered@ +@transitmanager +integrated-scripting@ +@nyc-mtr +@mtr-utility +creativetabsearch@|创造物品栏检索 (CreativeTabSearch) +moonbetween@|在月亮之间 (Moon Between) +tetrachord-lib@|四弦琴* +screenshot-sharing|屏幕截图分享/移影睹展 (ScreenshotSharing) +leaf-pile@|落叶堆* +uwufied@ +sit-chill +blueprintvoid@create-blueprint-void|机械动力:蓝图空位 (Create:Blueprint Void) + +mo-creatures-legacy@ +sticky-hands +pandalib@ +inventory-spam +@mineproc +slime-merger +configurable-cane +hex-keys@hexkeys +sky-lands@ + +vocalized +@kaleidos|森罗万象 (Kaleidos) + + + +kubejs-irons-spells@isskjs +revelationaryjs@ +arche +caverns-and-chasms@ + + +mixinbooster@ +block-crafting@|方块合成* +zombplayer@ +knighys-mystical-creatures +sign-button +startinv@ +@server-replay +ftb-stoneblock-companion +ash-of-sin-custom-anti-enchantment-entity|罪业余烬:自定义反附魔实体 (Ash Of Sin: Custom Anti Enchantment Entity) +ash-of-sin-anti-high-level-enchantment|罪业余烬:反高级附魔 (Ash Of Sin: Anti High Level Enchantment) +ash-of-sin-custom-anti-item-entity|罪业余烬:自定义反物品实体 (Ash Of Sin: Custom Anti Item Entity) +ash-of-sin-custom-anti-seat-entity|罪业余烬:自定义反坐垫实体 (Ash Of Sin: Custom Anti Seat Entity) +ash-of-sin-custom-entity-anti-effect|罪业余烬:自定义实体反状态效果 (Ash Of Sin: Custom Entity Anti Effect) +ash-of-sin-custom-entity-effect|罪业余烬:自定义实体状态效果 (Ash Of Sin: Custom Entity Effect) +ash-of-sin-custom-entity-item|罪业余烬:自定义实体装备 (Ash Of Sin: Custom Entity Item) +ash-of-sin-eternal-entity|罪业余烬:永恒实体 (Ash Of Sin: Eternal Entity) + +fundamental@ +wendigo-jar-dweller +the-super-god-road@|超神之路 (TheSuperGodRoad) +@backrooms + + +storage-delight-forge@storage-delight|存储乐事 (Storage Delight)¨storage-delight-fabric|存储乐事 (Storage Delight) +lightshield@|光之护盾 (LightShield) +sophisticated-core-unofficial-fabric-port@sophisticated-core-(unofficial-fabric-port)|精妙核心(非官方 Fabric 移植) (Sophisticated Core (Unofficial Fabric port)) +sophisticated-backpacks-unofficial-fabric-port@sophisticated-backpacks-(unoffical-fabric-port)|精妙背包 (Sophisticated Backpacks) - 非官方 Fabric 版 +red-power + +@minihud-extra +sophisticated-storage-unofficial-fabric-port@sophisticated-storage-(unofficial-fabric-port)|精妙存储(非官方 Fabric 移植) (Sophisticated Storage (Unofficial Fabric port)) +@oldoredrops +rage-mod@|兴怒* +@disable-all-structures +composite-material|复合材料* +timerecorder@|光阴:莉拉提娅 (TimeRecorder) +bettersmithingtable@ +trajectory-estimation@|弹道估计* +@foxcore|狐狐核心 (FoxCore) + + + + + + +iron-repair-kits@ +@susinsert +critters-n-crawlers@ + +epic-stats +brew-chew@brewn-chew +@lummobs +create-ratatouille@|机械动力:齿轮与麦穗 (Create: Ratatouille) +jains-desserts@ +@drizzleproof +@thief-tweaks +the-long-story@ +simple-hud-enhanced@ +vocalized-ayachinene-voice-pack|Vocalized 绫地宁宁语音包 (VocalizedAyachiNeneVoicePack) +the-between-awakens +emc-interface@ +csgo-box|Csgo 箱子 (CsgoBox) +create-oppenheimered@|机械动力:原子计划 (Create: Oppenheimered) +dimension-update-fixer@ +dont-keep-vanishing-items@ +ore-processing-for-tfc +creativepagejump@|创造物品栏页码跳转 (CreativePageJump) +april-fools@ +exmoxl|极墨核心 (exmoxl) + +armortip@ +true-herobrine@ +oam-by-choupiclou2007@ore-and-more-(oam) +squat-grow@ +backported-wolves@ +betweenlands-extended-config + +deeper-caves@deeper_caves + + + +arborfirmacraft@arborfirmacraft-(afc)|林海传说 (ArborFirmaCraft) +enchanting-with-tfc +tfc-vessel-tooltip@ +nether-gold-ore +natural-nether-portals +@vanillapotions+ +@wait-of-the-world + +hotbaaaar@|忄夬扌疌木兰 (HotBaaaar) +ui@ui-lib +random-item@random-items|随机物品* +lucky-clover@lucky-clover! +@better-portals|更好的传送门 (Better Portals) +social-distance@|社交距离* +gt@gtnn +hunger-plus@|饥饿+* +melee-ex-machina-meexma@melee-ex-machina + +arc@ +cores@ + +citymod-traffic-and-life@citymod|我的城市:交通与生活 (CityMod:Traffic and life) +too-hard-to-dig@|隐岩砥凿 (Too Hard to Dig) +simplecobblestonegenerator@simple-cobble-gen +natural-baby-animals +essence-mod@essence +shield-expansion-expansion@ + +alexs-caves-trimmed +totem-of-immortality@ +crystalline-ender-eye|晶化末影之眼* +ars-caelum@ +elytra-chestplates|鞘翅之甲* +variants-and-ventures@|变种与冒险 (Variants & Ventures) +horseshoes@|马掌* +questlines@ +endofherobrine@ +thirstcanteen@thirst-canteen|口渴-水壶 (ThirstCanteen) +thaumic-energistics-extended-life-fork|神秘能源延续版分支* + + +prehistoric-nature-decorations +tinyfoes +pyradium +anvilcraft@|铁砧工艺:重力科技 (AnvilCraft) +tiny-mob-farm-remastered@|迷你刷怪场:重制* +create-aquatic-ambitions@|机械动力:瀚海雄心 (Create: Aquatic Ambitions) +ffl-trinkets-compat +kaleidios-guns +mc-vr-playground +cosmopolis-mod@cosmopolis +caveopolis-mod@caveopolis_mod +flexipause@ +geysers@|间歇泉* +@moar-enchantments +@lose-your-touch +man-of-many-planes@ +caliber-lib@ +kriforfab@ +multiscoreboard@|多重计分板 (MultiScoreboard) +@minerally-me! +@cover-them-in-armor +jerotes-village@jerotes-village-second-round-world|Jerotes村庄-二轮世界 (Jerotes Village - Second Round World) +@a-cold-day-in-the-nether +translucencyfix@ +create-ponder@|机械动力:思索* +mopeds + +advanced-shulkerboxes@ + + +visible-shield-cooldown@|可视化盾牌冷却* +mns-moogs-nether-structures@ +bunker-down +just-enough-guns@ +buildify@ +@big-globe +dragon-finder +respackopts@ +fortuitous-feasts@ +monazite@|独居石* +music-control@|音乐控制* +stellarcore|星核 (StellarCore) + +ash-of-sin-custom-entity-attack-effect|罪业余烬:自定义实体攻击状态效果 (Ash Of Sin: Custom Entity Attack Effect) +ash-of-sin-soul-like-boss-battle|罪业余烬:类魂BOSS战 (Ash Of Sin: Soul Like Boss Battle) +wh40kmc-project + +pixelmon-bank|Pixelmon 银行* +@loosen-litematica +wsmc +no-gui-chest@|沉浸箱子* + +filedirector@ +extra-compat@extracompat +eu-converter@ +royal-variations@royalvariations + +temporal-api@ +@underworld-magic-craftsmanship|幽法工艺 (Underworld Magic Craftsmanship) + +callable-horse-unofficial-fabric-port|召之马来 Fabric版 (CallableHorse Unofficial Fabric port) +@better-combat-experience|更好的战斗体验 (Better Combat Experience) +shiny-horses-forge-enchantable-horse-armor@shiny-horses-forge +spartan-weaponry-simpleores|斯巴达的武器:简单矿石 (Spartan Weaponry: SimpleOres) + +dye-depot@ + +@autoharvest|自动收获-重制 (AutoHarvest-RE) +@nyan-cat-loading +homeward-bound@ +sword-blocking-mechanics@ +electric-mace@ +mace-backport|重锤移植 (Mace Port) +@steve-eat-stew +imaginary +kuvalich@|赤毒玄骸 (KuvaLich) +ae2-import-export-card@|AE2输入输出卡 (AE2 Import Export Card) +@magick-experience + +@repairable-disc-11 + +@fabric-permissions-api +@khinkali-mod +configured-defaults@ +bens-sharks@ +@eqsequipset|装备预设 (EquipSet) +torches-in-water|水中火把 (Torches in Water) +@olderskins|还原旧皮肤 (OlderSkins) + +pigs-with-fireworks +infinityspell|无限魔咒 (InfinitySpell) +multipart-machines-grinding +ash-of-sin-custom-anti-high-atk-entity|罪业余烬:自定义反高攻击力实体 (Ash Of Sin: Custom Anti High ATK Entity) + +@bioforge +quad@ + +@removewelcomescreen|移除欢迎界面 (RemoveWelcomeScreen) + + + +makit-better +macaws-for-terrafirmacraft + + + +@blahaj-of-undying +corals-tfc@ +tfc-aged-alcohol +tfc-improved-badlands@ +@russian-metro-addon +winter-massacre +ghostlys@ghostly|幽灵 (Ghostly) +tectonic-tweak +forge-essentials-client@ +@world-host + +spit-splat@|唾溅兽* +maced|重锤一击* +nether-villager-trader +@no-exp-enchanting-reimagined +odyssey-claims@ +odyssey-allies@ +giacomos-travelogue +giacomos-maps +descension + +@startup-time|启动时间 (Startup Time) + + +toggledpickup|拾取控制 (Toggled Pickup) +farmers-delight-refabricated@|农夫乐事:重织 (Farmer's Delight Refabricated) +village-nullifier-terralith-mod + +structure-credits@¨structure-credits-fabric-version +i-wanna-travel +simple-unbreakable-tools +cat-loaf@ +copper-tuff-backport-fabric +@f3scale +giacomos-teleport +giacomos-farmland +back-weapon-slot +chested-companions +create-train-perspective-fix@ +create-metalwork-fabric@create-metalwork + +tragicmc|悲惨世界1 (TragicMC) +auditory-continued@ + +create-more-copycats@ +farlands-reborn@ + + +momento@ +odyssey-roles@ + +waystones-jawsawn-fork|传送石碑:Jawsawn版* +nautilium-spirits@|鹦鹉螺重置版* + +@telluriumforge +aquatweaks|水下微调 (AquaTweaks) +aquatweaks-compat|水下微调:兼容 (AquaTweaks Compat) +@potions-re-glint +simpletextoverlay@ +bountiful-fares|丰饶食记* - 2.0.0 及以上¨@bountiful-fares|丰饶食记 (Bountiful Fares) +@ancient-debris-tweak|远古残骸微调 (Ancient Debris Tweak) + + +deer-jar-dweller +anti-id-conflict|反ID冲突* +confighelper|配置助手 (config helper) +better-boat|更好的船* +weighted-inventories|物品栏重量* +detected-setblock-be-gone@dsbg +@hexical +tabula-minecraft-modeler +glow-sticks@|荧光棒* +alt-hud + +furniture-expanded@ +celestora@ +geckolib-unofficial-1-7-10@geckolib-unofficial|Geckolib:非官方版 (Geckolib-Unofficial) +cnpc-custom-model-addon@customnpc-plus-gecko-addon|自定义NPC+: Gecko 附属 (CNPC+ Gecko Addon) +cnpc-armorers-workshop-addon@customnpc-plus-aw-addon|自定义NPC+ :时装工坊附属 (CNPC+ Armorer's Workshop Addon) + +fusion-smithing@|融锻* +leos-loot-bag@loot-bag|战利品袋 (Loot Bag) +adventure-dimensions|冒险维度* +simple-dimensions|简单维度* +portals-gui@|传送门GUI* +interworlds-splashscreens@|进入维度加载界面* +@creative-menu-tweaks +vampires-delight@|血族乐事 (Vampire's Delight) +thats-my-bed@ +caligo@ +@sharpenedswords + +donut-and-mochi +ducky@ducky! +lost-idols +simple-trashcan@ +darwin-water-ambience@ +decorative-wooden-lattices@ +apotheotic-additions +lithosphere + +build-your-campfire +biome-decoration-fix +simply-tools@ +immersive-snowgen@isg|沉浸式雪生成* +the-wandering-gambler +cheatdetector@|作弊检测器 (CheatDetector) +just-another-spawner +stack-size-edit-fabric@stack-size-edit +@remote-resource-pack|远程资源包 (Remote Resource Pack) + +battery-shield|电池护盾* +giacomos-chat-fix +giacomos-compass +giacomos-experience-drainer +@frank +load-my-resources-forge@load-my-resources¨load-my-resources-fabric +apotheotic-creation@apotheoticcreation + + +eiorecipesteinductionsmelter + +ash-of-sin-better-ai|罪业余烬:更好的AI (Ash Of Sin: Better AI) +dimensional-cake-rebuilt@dimensional-cake-rebaked +medieval-village-dimension +create-big-contraptions@big-contraptions +gtnhs-forgelin@ +rose-gold-equipment@ + +pantheonsent@ +@yukkuri + + +@moddetectionpreventer +dramatic-spawning +mc-mods-mobs-attack-villagers +cicada@ + +immersive-cvm +no-gui-fd@|沉浸乐事 (No Gui FD) +custom-credits@ +fishing-life|钓鱼生活 (FishingLife) + +@crystalcarpetaddition +hoes-are-scythes@ +@pehkuirandomsize +chat-ping@ping-santa + +damage-number|伤害数字显示* + +mineshot-reforged|高清截图Forge* +krysztal-language-scala@ +filters-api@ + +flavored@ +huesodewiki +platos-transporters +plushie-reeker-mod +semi-hardcore +placeables@ +bigbanana|🍌大香蕉🍌 (BigBanana) +@dabaosword|大宝刀 (DabaoSword) +look-eye-of-cthulhu@look +@salmonberry-addition +pet-collecting@ +@yummy_glass + +totallybalancedfallflying +giacomos-experience-seedling +@server-notify +config-api¨@config-api|Config API - 缺少部分 +nethers-delight-refabricated@|下界乐事:重织* +@pumpkin-pie-delight +runiclib@ +dragon-mounts-more-dragons@|龙骑士附属:更多龙 (Dragon Mounts: More Dragons) + + +hey-wiki@ +turf@ +ad-extendra@ad_extendra +smava +zwieback +random-respawn +@telluriums-random-stuff +per-aspera@ +spice-of-life-valheim-edition@mKalCkNV +tfc-paths +binkers-bonstruct +ranged-weapon-api@ +numismatics@ + + +canned-foods-and-drinks +alexs-caves-dimension +villager-contracts@ +better-agriculture +soul-shards-respawn-patched +tfc-finger-in-the-wind +immersive-craft-patched +jockeys@ +disguiselib@ +@mtr-resource-protector|MTR 资源包保护工具 (MTR Resource Protector) +station-architecture + +enchantmentrequirements@enchantment-requirements +enchantment-enhancements@ +mo-enchantments +soul-like-enchantment + +@blockbench-import-library +mrcrayfish-furniture-mod-rebuilt +btfixes +vmfixes +pillar-patched +novalogin|新星登录 (Nova Login) +tfc-desire-paths@ +tfc-ore-washing + +tfc-canes +lhmob-difficulty-increase|变强的怪物 (LH Mob Difficulty Increase) +@zombies-are-real-reforged +from-the-shadow-reborn +@life-crystals + +the-slumbering-omen@|沉睡的预兆* + + +ftb-guides-forge¨ftb-guides-legacy-forge|FTB Guides - 旧版 +@titaniumod|钛 (Titanium) +caelum@ +clearspam +ad-astra-rocketed@ +soulbound-quilt@soulbound +tinyinv@¨tinyinv-fabric +animationjs@ +raids-backport +crossbows-backport +tfc-caelum@ +epic-compat-parcool@ +loqui@ +real-worlds + +dragonlib@ +andromeda@|群星* + +@superauth|超级授权 (SuperAuth) +mobdisguises@ +inventory-generators +creating-space-gravity-addon +alexs-caves-torpedoes@alexscaves-torpedoes|Alex 的洞穴:物品 & 鱼雷 (Alex's Caves: Stuff & Torpedoes) + + +@slavic-cuisine +tfc-tumbleweed@ +tfc-barrens@ +chiselse-bits-for-tfc@chisels-bits-for-tfc +tfc-fresh-water-everywhere@ +tfc-more-swords +galleria@ +constructs-casting@ +tinkers-innovation@tinkersinnovation|工匠创新 (Tinkers' Innovation) + +delicious-delights +@vietnamsdelight +harvest-tweaks +decay-2012 +tfc-grooming-station +terrafirmagregtech-ores +blaze-map@ +epic-knights-japanese-armory +tfcpyros-adjustedgen +astikor-carts-tfc-florae +exp-counter-fabric-forge-neoforge@exp-counter +lightwithin@ +the-slenderman-mod@the-slenderman +flanchanmod + +cartography +laser-bridges-doors@laser-bridges-and-doors +lukis-grand-capitals@ +fabric-create-netherless +create-connected-fabric@ + +wastify@ +starter-structure@|初始建筑* + +mobblocker@ +giacomos-foundry +@blocky-bass +@toms-mobs +@homoium +alex-cave-addon + + +iced-lava@ +fabric-core-mods +the-tropics-telepastry +carrot-apple|胡萝卜苹果* +baked-delight|烘烤乐事* +create-basic-additions@ +horse-stats-and-more +giacomos-hud-overlays-configurator +giacomos-map-coloring +ec-epic-fight-compat@ec-ef-compat +easy-npc-epic-fight@ +puffish-attributes@attributes +pufferfishs-unofficial-additions@ +smart-completion +additional-attributes@ +@hexed + + + +suicide-key + +uranus@ +annotationlib@ +@waxed +nether-overload +ender-relay@ender-relay-ff +enchanted-effects +emi-create-schematics@ +the-silence@ +infinite-music-fabric@infinite-music +kakapos@ +@tome-reader +scary-creepers@ +@show-my-skin-parts +sn0wfrogs-capybaras@sn0wfrogscapybaras +enemybanner@|敌怪旗 (EnemyBanner) + +souls-egg +barely-enough-enchantments +tool-kit@ +@filament +lijms-expanse@ +tinker-delight@tinkers-construct-delight|匠魂乐事 (Tinkers Delight/Tinkers Construct Delight) +barbeques-delight@|烧烤乐事 (Barbeque's Delight) +coffeecraft-by-blockbrothers@coffeecraft +hearty-meals@ +@minecar-drill + +enderfake +@alwaysonline + +@awakenedsilverfish|蠹虫觉醒了 (AwakenedSilverfish) +rawore-on-1-12-2@rawore_on_1.12.2|1.12.2的粗矿 (rawOre_on_1.12.2) +entityjs@ +poem-of-star-wars@ +@hex-ways +vanity-aesthetic-armory@ +@muffins-thais-delight +@moreusefulcopper|更有用的铜 (MoreUsefulCopper) + +animals-plus +giacomos-map-merging +giacomos-spyglass-10-90x15 + +@la-cucaracha +grieflogger@ + +the-quest-of-entity-303 +pineapple-mending|经验修补:凤梨版* +@quick-chat|快捷聊天 (Quick Chat) +magic-vibe-decorations@ +valentines-blessing@valentines-blessing-lilypads-roses +decent-biomes@ +d-placeable-food-fabric-forge@3d-placeable-food +fan-shaped-cake@fan-shaped-cake-mod +bitter-brews@ +richards-coffee-tea-mod@richards-coffee-and-tea-mod +ribes-adventures@ + +@cell +packed-up@ +hexcircus@hex-circus +diamond-chest-shops@ + +better-clouds-reforged +excessive-building@ +modchu_modchulib +@samhackers-command-gui +no-slime-in-flat-world@ +icarae-origin@ + +@consoles + +fsit@ +carbon-config@ +productivetrees@ +@tsa-concrete +@tsa-planks +@tsa-stone +stellarview@ +biome-cows@ +simple-stopwatch +liolib@ +giacomos-better-dye +ash-of-sin-custom-anti-trap-cage-entity|罪业余烬:自定义反捕捉笼实体 (Ash Of Sin: Custom Anti Trap Cage Entity) +elementus@ +dedicated-bud + +vanity-twilight-zone@|Vanity:晨昏线 (Vanity: Twilight Zone) +tfc-barrels +melter@ +armour +speedometer-and-more +ash-of-sin-anti-same-modifier|罪业余烬:反重复修饰符 (Ash Of Sin: Anti Same Modifier) +giacomos-automatable-cauldrons +giacomos-bookshelf +no-outbreaks@ +nemos-woodcutter@ +command-button + +you-cheated-first|是你先开的 (You cheated first) + +exp-ore@|经验矿石* +@hexpigmentplus +starcrop +the-social + +goety-mythical-addon +huge-structure-blocks@ +calamity-sn +bodyhygiene +cafes-birding@ +kafs-valentine-special@ +create-deepfried@|机械动力:油炸 (Create: Deepfried) +sleepable-create +create-railways-navigator@|机械动力:铁路导航* +speed-drifter@speed_drifters|MC飞车 (MCSpeed) + +rearmour +lionfish-api@ + +avaritia-universal +slash-blade-tweaker +guns-without-roses-additions@ +cleanview¨cleanview-fabric +built@ +diyotweaks +extra-spell-attributes@extra-rpg-attributes +@create-contraption-creatures +immersive-vehicles-iv-mts-texel-arsenal-pack +creature-whisperer + + +create-molten-metals@ +create-optical|机械动力:光学*¨@create-optical|机械动力:光学 (Create Optical) - 不全 +@farmers-delight-plus + + + +mob-battle-music@|战斗音乐* +concerto@|协奏曲/一起听* + +@invisible-frames-for-forge +factions-and-curiosities@|派系与奇遇* +@anyfps +create-amazing-trading@ + + +westeroscraft-worldeditcui + +durability-display@ +hardrock-samples-tfc +@invhud_configurable|物品栏HUD+ 药水显示支持 (InvHUD_Configurable) + + +treps-cars@ + +back-up-beds@ + + + + + +mountain-sea-and-continent-two|山海大陆 (Mountain Sea and Continent) + +vinery-tfc +tkbs-campfires + + +whispers-of-the-wendigo@ +quartz-elevator@ +elytra-utilities@¨elytra-utilities-fabric +davids-furniture|大卫的家具 (David's Furniture) +kubejs-natures-aura@ +fancymenu-system-interactions-addon@ +control-engineering@ +wooden-furnace-fabric@woodenfurnace +jjthunder-to-the-max +telepass@ +offhandbanning|禁手令 (Off Hand Banning) +fantasy-craft|幻想工艺 (FantasyCraft) +breeding-potion@|繁殖药水* +servuxforged@ +loading-tips|加载提示 (Loading Tips / Pineapple Tips) +@highernether|更高的下界 (Higher Nether) +better-one-block|更好的单方块* +the-fletching-table-mod@ +create-militarized@ + +customemoji|自定义表情 (CustomEmoji) +sword-soaring|史诗战斗:御剑凌虚 (Epic Fight - Sword Soaring) +bigger-ae2@ +scalar¨scalar-legacy +trials-chambers-backport|Trials Chambers - 仅最终¨@trials-chambers-backport +blus-sign-pack-mts-iv +alexs-mediumcore@ +sherdsapi@ +@kontraption|精致机械 (Kontraption) +musketeer-illager + +daker-acg|Daker ACG工艺 (DakerACG) +bananarangs@ +remorphed@ +particle-core@ +fermiumbooter@ +ytech@ +better-biome-reblend@bbrb +mcterra@ +siren-head-the-arrival +classic-musical-discs@ +music-notification@ +orechidendium|影矿兰 (Orechid Endium) +bones +my-nethers-delight@ +localizator@ +scorchful@|焦土* +marbleds-api-mapi@ + +magma-bucket|岩浆桶* +ropes +paniclecraft +cpmpvc@|自定义玩家模型Plasmo语音兼容 (Customizable Player Models Plasmo Voice compat) +ydms-gunblades-mod@ydms-gunblades +warp-pads@warppads +marbleds-arsenal@ +@inventory-tabs +mob-spawning-fix|生物生成修复* +lh-miracle-road|奇迹之路之魂系加点 (LH Miracle Road) + +compatskills-fork +reskillable-fork + +@subtick +electroblobs-wizardry-continuation|巫术学:延续 (Electroblob's Wizardry Continuation) +agricraft-continuation|农业工艺:延续* +create-nuke@ +egg-particle-fix|鸡蛋粒子修复* +chicken-chunk-patcher +achievement-detection-fix@|成就检测修复* +@auto-night-vision|自动夜视 (Auto Night Vision) +@chais-inventory-sorter + + +@myceliumlib|菌丝 (Mycelium Lib) + +cataclysmic-illagers +witcherypatch@|巫术补丁 (WitcheryPatch) +pin +simple-pings@ +great-scrollable-tooltips@ +waterframes@ +eugenes-whistle-spur|友止殷的马哨和马刺 (Eugene's Whistle & Spur) +quickquark|畅启速始/夸克疾速启动 (QuickQuark) +minecraft-mineralogy +seed-delight@|种子乐事* +transmog@|幻化* +nuclear-guitars +cubic-racers +lotr-ucp|魔戒非官方兼容性补丁 (LOTR UCP) +delightful-sandwiches@ +shader-fixer@|光影修复 (Shader fixer) +resiever@ +cartload@ +stewing-baking@|炖与烤 (Stewing & Baking) +am2playground@ +astrocraft-mod@astrocraft + +neat-shaders-fix@|极简血量显示 - 光影修复版 (Neat - Shaders-Fix) +worldtooltips-continuation@|掉落物信息显示 - 延续版 (WorldTooltips - Continuation) +ars-repairing|新生魔艺:修复纤维强化* +options-enforcer@ +macaws-bridges-biome-o-plenty@|Macaw 的桥梁:超多生物群系附属 (Macaw's Bridges - Biomes O' Plenty) +renhider@ +itemframeremover@|物品展示框移除器 (ItemFrameRemover) +@legacy-debug-pause +trick-or-treat +ninjin-entities-by-hedaox@ninjinentities +dangerrpg-continuation@|危险RPG:延续 (DangerRPG Continuation) +zelda-sword-skills-continuation@|塞尔达剑技:延续* +@forgotten-relics-unofficial|失落遗物学:非官方版 (Forgotten Relics Unofficial) +mc-mods-enhanced|截图增强 (Screenshots Enhanced) +the-rings-of-power@|力量之戒/魔戒众戒 (The Rings of Power) + +@fancy-delight +@salt-fabric +suspicious-zombification@ + +ivtoolkit-arcana-rpg-continuation-edition|IvToolkit:延续 (IvToolkit Arcana Rpg Continuation Edition) + +@byzh-picgen|byzh's 麦块画图 (BYZH's Picgen) +tropicraft-continuation|热带世界:延续* +battle-tower-continuation|战斗高塔:延续* +kswitch@ +tfc-lumberjack +tfc-better-stone-tools +protons-additions@ +kinetic-anti-cheat@kac +where-are-the-ores@ +underp-hangables@ +doggy-talent-continuation@doggy-talents-continuation|小狗天才:延续 (Doggy Talents Continuation) +mod-observer@ +mineralogy-continuation@ +ubc-ore-registrar|科学地质:矿石注册 (UBC Ore Registrar) +genesis-2d|创世纪 (Genesis) +@non-update-reloaded|不再有更新重制版 (NonUpdate Reloaded) +radiation-zone|辐辽地带* + +adventure-backpacks-patched|探索者背包:延续* +@thaumcraftaltarcull + +bhops@ +from-spores +just-dire-things +hit-feedback@|攻击反馈* +@hasoook +middle-earth@|中洲 (Middle-earth) +windows-keyboard-fixes-fixes-sticky-keys@|Windows 键盘修复 - 粘滞键 (Windows Keyboard Fixes - Fixes sticky keys) +statuesmod-fix@statuesmodfix|雕像模组-修复 (StatuesMod Fix) +@numericaltabping +ninjinentities-unofficial@|Ninjin Entities-非官方版 (ninjinentities-Unofficial) +sanguine-arsenal-reforged|血染武装重铸版* +respawn-obelisks@ +flintandsteel-improve@ +forge-zombie-plague-mod-2-wip@zombie-plague-2-hardcore-zombie-apocalypse|僵尸瘟疫2 (Zombie Plague 2) +colored-grasses +more-default-options +@livelydanmaku|缤纷弹幕 (LivelyDanmaku) + +treecapitator-updated|砍树更新版* +@offhandlights|副手光源 (Offhand Lights) +dental-handbook@|牙科手册* +prehistoric-nature-jurassic-dimension + +many-more-structures@¨many-more-structures-depricated@more-structures +mobs-are-friends@ +polytone@ +@calcium-fps|钙 (Calcium) +delightful-burgers@ +cinderloe-project +lotweakr|魔戒微调 (LOTweakR) +lotr-renewed-extended@|魔戒:复兴拓展 (LOTR: Renewed Extended) +lotr-companions-renewed-addon|魔戒:同伴 (LOTR: Companions) +dvs|自定义魔戒小建筑 (DVS) +mffs +lotr-extended|魔戒大陆拓展 (LOTR Extended) +bitcrafting +fart-shit-pee +statuseffecthud-updated|状态信息显示更新版 (StatusEffectHUD Updated) +capejs@ +advanced-machines-patcher|高级机械补丁* +@immersive-tooltip|沉浸式提示框 (Immersive:Tooltip) + +sound-controller@ +cagerium +advanced-inventory-mod@ +rolling-down-in-the-deep@ +dwarven-realm|矮人诸国* +renewed-eras-of-arda-addon|阿尔达纪元:复兴 (Eras of Arda: Renewed Addon (First and Second Age)) +legendary-item@|魔戒传说物品* +lotr-middleearth-tweaks@middleearth-tweaks|中洲微调 (MiddleEarth Tweaks) +thaumcraft-integration@ +reach-display@ +gravitation-suite-patcher +anti-rat-dungeon +modchu_defaultmodelset +create-storage@fxnt-create-storage +avaritia-item|无尽特效物品* +kingdom-of-rin-regions@regions +durability-speed-legacy-backport +inventory-on-death-mod +berries-cherries-delight@berries-and-cherries +silents-delight@|幽匿乐事 (Silent's Delight) +darwin-sprinting-system@|达尔文疾跑系统* +camera-overhaul-reforged@ +monolib@ +@pyrofrost +animal-armor-trims@ + +better-safe-bed@ +modchu_models +ice-and-fire-spellbooks@ +exlines-fishing@ +cavernous-delight +@steep-surface-fix + +arthropocolypse@ +@kaleido + + +combat-skill|战斗技巧* +life-is-precious|生命是宝贵的 (Life is precious) + +advanced-skills@|进阶技能* +nuts-delight +vegetables-delight@ +enderpack@ +ingame-mod-configs|游戏内模组配置 (InGame Mod Configs) +playertag|玩家标签 (PlayerTag) +hide-names|隐藏名称* +camo-suits|迷彩套装* +vtubruh-lotr-mobs-new@vtubruh-lotr-mobs|Vtubruh的魔戒生物 (vtubruh LOTR Mobs) + + +@create-more-features +armadillo-scute-armor@ +new-shield-variants@ + + +way-much-faster-oxidize-reborn@ +bn-blood-particles@ +bn-weapons@ +ecotones@ +froglins +create-armor-trim +slashblade-resharped@|拔刀剑:重锋 (SlashBlade: Resharped) +spawn-mod@|生机遍布 (Spawn) +@smooth-swapping-1.20.4-port|平滑转移 1.20.4 移植 (Smooth Swapping 1.20.4 Port) +@create-tab-fix +scape-and-run-origins@srp-origins +origins-extra-keybinds@origins-extra-keybinds-fabric +epic-knights-addon@ + +@arknights-skadi-orca-plushie|【明日方舟】斯卡蒂的虎鲸抱枕 ([Arknights] Skadi Orca Plushie) +sona-survival-101|唢呐生存指南* +@more_villagers +cult-of-the-wither +clochetweaks + + +@multiproto +frostbytes-improved-inventory@ +mekanism-extras@mekanism_extra|通用机械:扩展* +leaf-beds@ +unidentified-enchantments@unidentified_enchantments +protection-pixel@|机素防护 (Create: Protection Pixel) + + +createdpcompat@ + +lava-waterblock +im-tired|我很疲倦 (I'm Tired) +constant-music@ +supercore +extreme-reactors-create-compat +modchu_playerformlittlemaid +totally-lit@ +mo-shiz-mod +aetheric-tetranomicon + +arda-addon|阿尔达拓展* +@potionwarning +a-good-place@ +aether-protect-your-moa@ +advanced-rocketry-2@advanced-rocketry-reworked +compostimprove@ +superb-steeds@ +coal-piece + + +@mechmonstrosity|机械巨兽 (MechMonstrosity) +slash-illager@ +@create-spawnerboxer|机械动力:拳击刷怪笼 (Create: SpawnerBoxer) +skeletalband|骷髅乐队乐谱 (SkeletalBand) +alexs-caves-entropy|Alex 的洞穴:熵 (Alex's Caves:Entropy) +mekanism-explosives|通用机械:炸药* +@minimal-coords-hud + + + +avaritiareborn@|无尽贪婪:复兴 (AvaritiaReborn) +cherry-shrimp@ +pick-command@|俺拾的指令* +regalliv +extra-addition-s@extra-additions + +@amethyst-shield|紫水晶盾 (Amethyst Shield) +@plateplate|板板 (PlatePlate) + + +@difficulty-tweak|难度调整 (Difficulty Tweak) + +@herbal-delight + + +@compatlib|旧版本兼容工具 (LegacyCompatibilityUtils / CompatLib) +warriors-of-past-epoch +the-ghast-cow@ +@alternate-current-unofficial +birds-on-a-wire +no-hurt-animation +incense +wild-lands-2 +hullabaloo@ +invinci-dogs-ssp +@noglow|禁止发光 (noglow) +timeless-and-classics-zero@|永恒枪械工坊:零 (Timeless and Classics Zero) + +@concentration|专注 (Concentration) +terra-curio@|泰拉饰品* + +cobblemon-counter@ +cobblemon-move-inspector@ +cobblemon-spawn-notification@ +cobblemon-pokenav@ +cobblemontrainers@ +the-ink-arena@ + +epicfight-integration|史诗战斗·集成 (EpicFight Integration) +@stop-spiders-from-climbing +kubejs-enderio@ +polymorphic-energistics@ +war-of-the-ring-mc|魔戒大战 (The War of the Ring MC) +redstone-clock-mod@|红石钟 (Redstone Clock) +create-cobblestone@ +@another-pickaxe +selfexpression@ +electricalcraft +@elecfurn +what-is-stone-colorful-caves@what-is-stone-(colorful-caves) +vtones +heavy-inventories|物品负重* +vs-addition@|瓦尔基里:附加 (VS Addition) +gravity-torch@ +lifesteal-forge-fabric@lifesteal-mian +mores-by-its-infinite +dragonite-gear +lets-do-addon-fluids@ + + +@just-glowing-buttons +rats-hats +biome-reactors +mystical-agriculture-tiered-crystals@ +tpaplusplus@tpa++ +warlerys-hq +call-of-yucutan@|尤卡坦的呼唤 (Call of Yucatán) +redman@|红超人 +lets-do-addon-compat@ + +worldeditcui-forge-edition +slime-delight|黏液乐事* +darkcap@ +@ryoamium +quality-equipment +seals +nocubes-better-smoker +@shutdown-on-death +mekanism-energistics +ae2-network-visualiser +ahznb-sword-plus +anbu-bingo-book-for-ahznbs-shinobicraft +ahznbs-naruto-mod-reroll +xycraft-override +xycraft-machines +xycraft-world +battlemusic@ + +@embyui +engineered-golems +axifier@ +renderjs@ +@enchantment-compat +dehand@ +jadecolonies +@cobblemon-mike-skills +diamond-star-combat@ +modern-ae2-additions@ +create-metallurgy@|机械动力:冶金学 (Create: Metallurgy) +@client-info-fix +the-shy-guy +@tea-time +@cobbreeding +myths-and-legends-cobblemon-addon@cobblemon-myths-and-legends-sidemod +@rctmod +create-klinks-n-klangs@klinksnklangs +mo-than-enough-guns@ + +forge-creeper-heal|Forge 苦力怕坑修复* + + +@momos-skiphand|莫莫的折跃之手 (Momo's SkipHand) +curse-of-disintegration +adventure-backport|冒险模式向后移植* +@oreganized-refabricated|井然有矿:重织 (Oreganized Refabricated) +yosby +@zundamod +common-network@ +addurdisc@|自定义唱片 (AddurDisc/Add your disc) +enigmatic-addons@|神秘遗物扩展* + +@bloodscythe +ddgourmetbattles@dungeons-delight-gourmet-battles +stronger-potions@|更强的药水* + + +@particular + +reforgedplay-mod|录像回放:重置 (ReForgedPlay) +sqript +natures-delight@|生灵乐事 (Nature's Delight) +reimagining-potatoes@ +@legacy-resource-pack-adapter +insane-stamina +bren@ +@power-hud +plushables@|毛绒玩偶* + + + +@rcspeedbuild +@staff-of-the-king-orange|橙王的权杖 (Staff of the King Orange) + +path-under-gates +ojs-guilds +command-macro-key@|命令宏键* +realm-rpg-quests-rewards +@roadworks +unlucky-tnt@ +fastboot@ + +tardis-refined@|改良的TARDIS (TARDIS Refined) +ocean-villager-trader@ +@precise-manufacturing|机械动力:精制工艺 (Create: Precise Manufacturing) +@create-new-age-alexs-caves-integration +create-kryeit@ +animationoverhaul@ +starbunclemania + + +display-qien@ +@village-healthcare +cubic-villager|村民立方* +@morecursors|更多光标 (MoreCursors) +true-infinity +nukateams-gun-lib@ntgl +fantastic-biomes-cave +nukacraft@thenukacraft +enchantment-limiter +emi-ores@ +@bread-skin-mite|面包皮 (Bread Skin) +extra-gore +chassiscore@ +@spit-splat-fabric|唾溅兽 Fabric 版 (Spit Splat [Fabric]) +linweiyun-mod@moderation +normalcore@ +appliede@ +waystones-teleport-pets@ +@sneaky-link +create-mortar@ +forgelin-continuous@ +@ripples-of-the-past-killer-queen-addon|RotP:杀手皇后附属 (Ripples of the Past: Killer Queen Addon) +ninjin-knockback-dbc-by-hedaox +wings-3 +dstathud@ +opticmanager@ +ribbits@ +@actually-camel + + + +raws-visual-keybinder +synthetic-products|合成配方* + +scoreboard-tweaks@scoreboardtweaks +rsinfinitewireless +rustic-engineer@ +artsandcrafts@ +mermaid-legend|人鱼传说* +endcake|末影蛋糕 (EndCake) + +@mcsudo + +scp-remake +@scp-fallen-foundation + +create-heat-js@ +createaddoncompatibility@ +more-difficulty-levels +alternacraft +sheep-squeak@ +fabric-simple-animated-guns +a-v-a-in-minecraft@a.v.a-alliance-of-valiant-arms-guns +coordinates-display@|坐标显示* +@acrylicraft|亚克力窗口 (AcryliCraft) +towelette@ +shc-pvz-zengarden@ +unusual-foods-delight|奇食乐事 (Unusual food's Delight) +re-fruitful +dark-rites-2 +advitam-addon-for-requiem@memento-mori +potheads + +skyfall-meteorites@ +fancyclear +pathfinders-spade +legacy-minecraft@legacy4j +festive-creepers +essential-features +piston-control-forge¨piston-control + +blahaj-restitched@|布罗艾重制版* +@tabbychat-2-reforged +lithostitched@ +pogfish +launch-time@|启动耗时* +killer-table +trading-table +winter-decorations +fancy-snowy-weather +winter-ambience +dralards-rock-candy-mod + + + +explosion-breaks-no-block@|爆炸不破坏方块* +via-romana@ +lithic-coins +dynamic-trees-for-natures-spirit@|动态的树:自然之灵附属 (Dynamic Trees for Nature's Spirit) +gore-edition +christmas-wish-in-a-bottle +chiseled-bricks +unethly-origin@ +dimensional-totem@ +placeable-gunpowder +library-for-ar-reworked@arlib + + + + +craftdev-core +costume + +borzoi-dogs@ + +nether-exorcism@nethers-exorcism +integrated-villages@ +taxdeepvillager +@voxelprints-desert +music-on-demand +leadable-bats +canes-wonderful-spiders + + +scribble@ +text-formatting-everywhere@ +extended-item-information +mod-sound-volume-options@mod-volume-options + +teams-hud +@tpm|传送管理器 (TeleportManager) +@camera-obscura +wzorescanner +@potion-recipes +wither-totem@wither-skeleton-totems +@player-bones + +more-apples-hyj|更多苹果 (More Apples) +fancy-enchantments@|奇异附魔* +ash-of-sin-adventure-dimension|罪业余烬:冒险维度 (Ash Of Sin: Adventure Dimension) +push-forward@|猪突猛进* +ymn@|你现在是我的了! (You're Mine Now!) +thermal-endergy@ +mekanism-turrets-fences@mekanism-turrets +nuka-cola-classic +draconic-machinery +@voxelprints-halloween +iap-gobber@ +iap-botania@ +iap-industrial-foregoing@ +iap-silents-gems@iap-powah + +iap-omega-craft +iap-mekanism +industrial-agriculture-plugin-silents-mechanisms + +roads-and-roofs-tfc@ +taxvillagearchitect +taxoceanarchitect +nethers-flora + +microcosm +chinese-flying-island-tower@ +@netherite-tools-for-crackers-witherstorm-mod +better-maces +jack-o-launcher +the-otherworld-mod +craftingxp@ + +dmmttba@ +fzzy-config@ +no-shield-delay@ +musicpower@|音乐之力 (MusicPower) +macrocraft@ +camerapture@ +simple-voice-radio@simple-radio + +adorned +fence-on-slab@fence_on_slab +monochromatic-blocks@ + + + +archaicfixfix +inventive-inventory@ +boxlib@ +the-shattered-goddess-mokels-bossfight-saphyra +resource-explorer@resource_explorer +@patcher +autoreconnectrf@ +disable-accessibility-screen@ +@fly-high + +@fly-apple|飞苹果 (Fly Apple) + +@hoyoi +rogues-and-warriors@ + + + +tfc-support-indicator@ +tfc-poisoned-drinks +smartercontraptionstorage@smarter-contraption-storage|智能动态结构存储 (SmarterContraptionStorage) +lexiconfig@ + +@advancementsfullscreen|进度全屏 (AdvancementsFullscreen) +luckys-wardrobe@luckyowls-wardrobe +@forkkit +more-affordable-than-ever-never-too-expensive@more-affordable-than-ever +what-am-i + +@camoverlay +autoplant|自动种植 (AutoPlant) +@skip-backup-screen +@polysprint +@crashpatch +@vanillahud +@damagetint +@polyblur +@colorsaturation +@hitbox +lains-random-creation|LAIN的随意创作 (Lain's random creation) +autochefs-delight@ + +bindcommands@ +short-grass@ +stairs-but-chairs@ +yumo-compactmachines-por@|压缩空间:产量推演 (yumo compactmachines por) +dynamic-trees-for-fruit-trees|动态的树:妙趣果园 🍊附属 (Dynamic Trees for Fruitful Fun 🍊) +dynamic-trees-for-better-end|动态的树:更好的末地附属 (Dynamic Trees for BetterEnd) +dynamic-trees-autumnity|动态的树:秋原附属 (Dynamic Trees - Autumnity) +dynamic-trees-for-bloomingnature|动态的树:绽芳自然附属 (Dynamic Trees for BloomingNature) +dynamic-trees-terralith@|动态的树:Terralith附属 (Dynamic Trees - Terralith) +dynamic-trees-for-meadow|动态的树:青青草甸附属 (Dynamic Trees for Meadow) +dynamic-trees-for-beachparty|动态的树:沙滩派对附属 (Dynamic Trees for Beachparty) +dynamic-trees-for-vinery|动态的树:葡园酒香附属 (Dynamic Trees for Vinery) +tfc-aesthetics@tfc-plus-aesthetics +smooth-gui@ +offershud@ +perspektive@ +ore-harvester@ +flightassistant@ +biomefog@ +edgeless-chat-screen@|无边界聊天框* +villager-death-messages@ +@smooth-skies +clist@ +tothestarsremake@|ToTheStars重制版 (ToTheStarsRemake) +galacticraft-gravity +dragon-mounts-even-more-dragons|龙骑士附属:附加龙 (Dragon Mounts: Even More Dragons) +xplus-contingameime@|游戏内输入法 XPlus 版 (XPlus ContingameIME) +@watersource2|水源 2 (Water Source 2) +radomraidspawn|随机袭击生成 (Random Raid Spawn) +enigmatic-legacy-legacy|神秘遗物经典版* + +nco-java-legacy-lib +forge-souls-like-universe@souls-like-universe + + + +neutral-animals@ +create-upgraded-armor +fbp-renewed@ +chat-impressive-animation@|聊动魅影* + +pianocraft@ +jazzymusicality@musicality +@boids +buckshotroulette@|恶魔轮盘赌 (BuckshotRoulette) +customnpcs-unofficial@|自定义NPC 非官方版 (CustomNPCs Unofficial) +@fast-trading +simple-wooden-pipes +simplywalk@ +persistent-stuff@ +lan-operators@ +compatdatapacks@ +the-luminous-mod@ + + +burst-door-open@|破门而入* + + +chain-suspension-forge@chain-suspension¨chain-suspension +cui@ +emi-enchanting@ +clientsort@ +immersive-ui@ + +curios-continuation@ +@minekimi +blind-accessibility@minecraft-access +enchanting-tree@enchantingtree +dragon-enchants +item-placer@ +expandedworld +monster-hunter-villager@ +jcraft-eyes-of-ender@jojo-eyes-of-ender +@return-dirt-background + +@reset-keys-confirmation-screen +idle-boost@ +bettergrassify@|更好的草地 (BetterGrassify) +lightweight-inventory-sorting@ +@stonecutter-gui-remastered +@loom-gui-remastered +unseaworthy@ +@chromaanvils +thermal-and-space@ +create-curios-jetpack@ +epic-knights-antique-legacy@ +viking-samurai-knight-items +barely-simple-staffs@barely-simple-staff + + +alexs-caves-delight@ +alexs-caves-adventure@ +divine-weaponry + +hook@hoook|抓钩* +fix-guard|格挡修复 (FixGuard) +@greg-caves|格雷的洞穴 (Greg Caves) +better-mob-combat@ +mob-player-animator@ +depression@|抑郁症* +more-rpg-classes@ +minimalism-leaf-decay@minimalism_leaf_decay|极简快速落叶* +biome-modifier-for-fabric@|Fabric版群系编辑器 (Biome Modifier for Fabric) +chunkloader-simple +apollyon +worldweaver@ +netherite-compass@|下界合金指南针* +the-darkness-will-find-you@ +silent-screenshots@ +cr3stal-updatet@crestal +toggle-subtitles@ +ok-boomer-zoom@ok-boomer + +forcegl2-0-remapped@forcegl2.0-remapped + +rendi@|重生:伤害免疫机制移除 (ReNDI) +create-questing@ +@create-train-perspective +elainalike@|魔女之绘 重生:重生 (ElainaLike Reborn: Reborn) +take-back-your-sword@|收回你的剑!* + + + +travel-friendly-food-fabric-forge@travel-friendly-food +stardew-valley-food@ +minecolonies-compatibility +bettergamma@ +more-lectern-variants@ +@ase +lush-cave-trader@ +oceans-enhancements@ +xp-jellies@ +aromatic@ +onekeyminer-nf@onekeyminer_nf|一键连锁(Neo)Forge (OneKeyMiner(Neo)Forge) + +retargetato@|约谊敌众 (ReTargetato) +iceandfire-ce@|冰火传说社区版 (IceAndFire Community Edition) +tomanos-vehicle-mod +ancient-sands@ +hs-bosses +chubby-mobs@ +repair-gem|修复宝石* +better-weaponry-compatible-with-better-combat@better-weaponry +disable-front-perspective@ + + +thaumcraft-6-aspects-for-jei@ +@up-and-away + +@ripples-of-the-past-hermit-purple-addon|RotP:紫色隐者附属 (Ripples of the Past: Hermit Purple Addon) +nc-steam-additions@nuclearcraft-steam-additions +aura-cascade|气场流注* +rac-compat@ +spartan-weaponry-addon-toolkit@ +smsn@|救救我的答辩网络 (Save My Shaky Network) +sneaky-tree-growing-forge@sneaky-tree-growing¨sneaky-tree-growing-fabric +hungry-zombies +@gravity-gourds +usa-delight@ +experience-farm +dandi2k8s-ad-extendra@ad_extendra-continuation¨ad-extendra-dandi2k8-version +nebulus-juice-trader@ +cthulhu-fishing@ +large-super-potato|大型超级马铃薯* +@craft-time +the-orcs +made-in-abyss-shroombears +squinkers +mokels-bossfight-kinora +@create-high-pressure +create-framed@|机械动力:多彩边框 (Create: Framed) +trackwork@|驱动工艺* +oritech@ +the-impossible-library@ +perspective-mod-redux@ +more-cartography-tables@ +more-barrel-variants@ +wheelbarrow@ +simple-automation +better-paragliders@ +fallen-wizards-more-magic-series@ + +@whiffowisp +mango-cats +tax-tree-giant@tree-giant +taxskyvillager +compostable-rotten-flesh +villager-in-a-bucket@ +nebulus-trader-for-the-desert +nebulus-jungle-trader@nebulus-trader-for-the-jungle +mushroom-villager-trader@ +nebulus-better-portals@ +resource-ghouls +avaritianeo@|无尽贪婪Neo (AvaritiaNeo) +create-legacy@ +@create-bronze-age +wind-bottle@|风瓶 (wind bottle) +lc-tech@ +minecolonies-tweaks +text-placeholder-api@placeholder-api|文本占位符 API (Text Placeholder API) +@gravity-api-fork + +@tt20 +kasugalib@ +@c2h6s-tinker|乙硫基匠魂 (C2H6S Tinker) +encounter-mob-ai-tweaker|遭遇/长驱速弑 (Encounter) +kubejs-mekanism-unofficial +@mediaplayer|媒体播放器 (MediaPlayer) +bakery-villager-trader@ +nebulus-trader-for-the-plains +mokels-more-spiders + +exposure-catalog@ +skinchanger@ + +@halflifemenu +sitting@sitting+ +forgotten-east@ +brazil-legends@ + +custom-item-despawn-duration@|自定义掉落物消失时间* +your-items-to-new-worlds@ +enhanced-boss-bars@enhanced-boss-bars-mod|更好的Boss血条* +cutetrade@ + +smoothmenu-refabricated@|平滑菜单:重制版 (SmoothMenu Refabricated) + +toexistingstacks|添加到现有堆叠 (ToExistingStacks) +@postmortal-particles +@give-me-a-new-splash-text +@less-annoying-fire +treasuredistance +affinity@ +chaos-moon +@healthindicator +@small-chisel|小凿子 (Small chisel) +@auto-sprint-fix +lets-do-emi-compat@ +health-indicator@health-indicators +aiming-fix@ +compasshud@|指南针HUD (CompassHUD) +mini-boss-boss-bars@ +berserker-rpg-class@ +fromanotherlibrary@ +mounted-pearl-bring-your-mount-along-when-you +biome-id-fixer +immortal-coral@ +immersive-guns@ +guns-plusplus +additional-rpg-jewelry@ +mekanism-ad-astra-ores@ +question-ducks-ambient-fireflies +travelerz@ +the-rise-of-minerals|矿石崛起* +gregtech-steam-additions +gregtech-nomifactory-edition +create-ethium@ethium +create-contraption-terminals@|机械动力:动态终端* + +strata-recipes +strayed-fates-forsaken +snowyleavesplus@ +shield-overhaul@ +g-weapons-mod-gargantuan-weapons-mods|G武器 (G-Weapons) +backtools@|工具后置/后背工具展示:重制版 (BackTools) +epic-fight-guandao-moveset|史诗战斗:关刀 (Epic Fight - Guandao Moveset) +epicfight-dual-greatsword +spell-checker@ +sparkle@ +@visible-traders +villagers-inventory +removehud@ +@orthocamera|正交相机 (OrthoCamera) +third-person-crosshair-fabric +@hitrange +black-moon@ +dynamic-fire-overlay@ +firorize@ +smoke-extender +@nohotbarlooping +@higher-chat +mekanism-cardboard-tooltip@ +durability-notifier@ +gregtech-extended-chemistry +centrifuge-tiers +distant-friends@ +the-world-of-herobrine +primal-storage@primalstorage +@potioncorereloaded|药水核心重制 (PotionCoreReloaded) +yamazakura-reforked|山樱之刃重置版 (Yamazakura reforked) + + +apothic-spawners|神化刷怪笼* + +sinocore|华夏核心 (SinoCore) +tinted-dyes@ +dynamic-trees-ecologics@|动态的树:丰富的生态附属 (Dynamic Trees - Ecologics) +craftablecapes@|可合成的披风 (Craftable Capes) +tamago@ +@clickthrough2.0 + +open-computer-resurrected +advancements-reloaded@ +oc2r +eu-p2p-tunnel@eup2p|EU能源P2P通道 (EU P2P Tunnel) +@hold-onto-everything +ardagrass@ +geocluster@ + +@knives-construct + +updating-world-icon@ +shared-resources@ +tech-dimension@ +tilt-break@ +item-frament@ +water-vision@ +randomized-default-fireworks@randomizeddefaultfireworks +glowing-torchflower@ +@clock-hud-renew +cameranoclip +barriers-dont-block-rain@ +no-render@ + +runningshoes|跑鞋 (Running Shoes) +fluid-void-fading@fluidvoidfading +@movement-in-gui +glowing-eyes@ +youarch +true-darkness-fabric@ +esf-entity-sound-features@esf|实体声音特性 (Entity Sound Features) +nomoreglowingpots@ +smooth-particles@ + +unloaded-activity@ +improperui@ +neverenoughanimation@ +reds-stagger-parry +additional-placements@¨additional-placements-fabric@ +akicaters-shelves@akicaters-shelf-mod +refurbished-furniture|MrCrayfish 的家具:重制 (MrCrayfish's Furniture Mod: Refurbished) +improved-stations-forge¨improved-stations¨improved-stations-for-1-19 +elemental-wizards-rpg-class@elemental-wizards-rpg +pov-that-one-short-friend +onward-and-upward +weapon-case-loot|武器箱战利品* +mace-but-3d@ +@healthindicators +smoothcoasters@ +do-a-flip@ +@no-death-animation +veindigging@ +too-many-entities@ + + + + +datapack-breakpoint@datapack-debugger|断点调试 (Datapack Debugger) + + +frosted-heart|冬季救援:寒霜之心 (The Winter Rescue: Frosted Heart) +create-planetary-tweaks@cp-tweaks +entris@ +@sushi-bar +lumi@lumi1710 +pet-the-frog@frog-petting +ex-nihilo-extras@ +cycle-title-screen-splash@ +hide-invisible-armor@ +inventory-tweaks-refoxed@ +bigshot@ +more-immersive-aircraft +legendary-survival-overhaul@|传说生存* +mineral-delight +not-just-sandwich@notjustsandwich +fantasyfood|幻想食物 (FantasyFood) +mc-modsthefood@allthefood +villager-names-fabric@villager-names +trial-vault-restock@trialchamberrestock +hot-green-fire +phantom-flames +darktitlebar@ +cubes-without-borders@ +block-parry-dodge +fargos-talismans@|Fargo的护身符 (Fargo's Talismans) +toostrongmonster +simplystronger +tacz-durability¨@tacz-durability|TACZ: Durability - 停更 +bigger-lightning-storms +eternal-limbo +legoman +petcreepers-mod +tugkandemans-weaponry@ + + + + + + + +@noanysus +rekusaeater@|Re艹 (ReKusaEater) +jsg@ +@potion-mixing|药水混合 (Potion Mixing) +sandfilter@|砂滤器 (Sand Filter) +resaplingslayer@|雁雅得枝 (ReSaplingslayer) +cerberu@|狱牙抵战 (Cerberus) +remoreloyaltrident@|远亦得珍 (ReMoreloyaltrident) +potionlevelfix@|药水等级修复/药引对注 (PotionLevelFix) +reunmending@|以验垫砧 (ReUnmending) +reghostjump@|引殃髑至 (ReGhostJump) +rebroken-blade@|隐影刀珍 (Mowzie's Mobs: ReBroken Blade) +attackagain@|又御刀追/追击 (AttackAgain) +@sectionsign +@allow-chat +retro-damage-indicators@ +@impropers-3d-minimap +beddium@ +create-thermal-compat +create-lagless@ +create-ironworks@ +@create-vibrant-vaults|机械动力:炫彩金库 (Create: Vibrant Vaults) +steam-power +kevs-library@ +remove-purpleprison-ads +timeoutfixes +forgeskyboxes@ +customfishing|随液钓趣 (CustomFishing) +metr0polis|Métropolis. - 已不再更新¨@metropolis +crust@ + +sc-structurecraft@structurecraft +minehop@|Minehop - 主¨minehoplite@ +placeabletools +rlfoliage@ +bc-remastered +@deepdrilling +copperworks + + +miner-villager +villager-venture +alekiships@ +alekishipsbop@ +antique-trading-ship@ +small-horse-stable@|小型马厩* +shrek-the-ogre@shrek + +the-anomaly@the-anomaly-rephased +desert-behemoths-sandworms@desert-behemoths-sandworms! + +vermintide-rising +armor-of-the-ages@|时代铠甲 (Armor of the Ages) + + + +@betterf3-stationapi +ftb-quest-localizer|FTB Quest 本地化 (FTB Quest Localizer) +modpack-update-checker@ +minimotd-fabric +effecttimerplus@ +thaumic-concilium@|神秘议会* +equivalentexchange + +coral-up@ +plushie-buddies@ +@the-aethers-delight +@wheelchairs +dnt-pillager-outpost-overhaul +mage-flame@ +@totem-party-popper +@powerless-refined-storage +forgotten-graves@ +day-zombies +morecoal|更多煤炭 (More Coal) +jjku + +immersive-combat-feathers +ghosties-monocle +ender-dragon-loot +epic-terrain|史诗地形* - 史诗地形(实验版) +oh-the-trees-youll-grow@ +oh-the-biomes-weve-gone@|我们走过的生物群系 (Oh The Biomes We've Gone) +dblockbusterdisplays@ + + +@waygl +no-sneaking-over-magma@ +harmonia@wasabiwhisper-harmonia +configurable-head-drop@ +@connectored-c2me-(c2me-fork-for-connector)|C^3M 引擎 (Connectored Concurrent Chunk Management Engine) +structure-expansion@ +armored-doggo@ +the-newest-goatman +epic-mob-siege-nightmare +jupiter@ +airport +just-dandy@ +@uk-roads +my-totem-doll@my_totem_doll +void-power-for-fabric|虚空动力 (Void Power) + +dis-enchanting-table@ + + +gt-top-addition|格雷信息显示拓展 (GT TOP Addition) +gt-steam-tech|格雷蒸汽科技 (GT Steam Tech) +simpleanimator@ +tianjin-metro@|天津地铁* +modular-flower-pots|模组化花盆* +repurposed-structures-floralis-compat-mod|结构变体:Floralis 兼容模组 (Repurposed Structures - Floralis Compat Mod) + +balanced-shield@ +more-potion-effects@|更多药水效果* +jungle-villages +truecherry +@revamped-trades +creeper-fireworks@creeper-fireworks-mod|烟花苦力怕 (Creeper Fireworks Mod) +@word-overflow +chatnotify@ +serverutilities-gtnh +nbt-tool + + + + + +twintails@|双马尾 (TwinTails)¨twin-tails|双马尾 (TwinTails) +gt-wireless|格雷无线科技 (GT Wireless) +forcejava21@|强制 Java21 (ForceJava21) +blessings@|祝福* +crafted-core@ +call-from-the-depths|深渊召唤*¨@call-from-the-depths|深渊召唤 (Call From The Depths) - 落后 更新不及时 +@clover-fabric|四叶草Fabric版 (Clover Fabric) +champions-unofficial@|冠军/强敌再续* +aetherworks-refracted@ +eidolon-repraised@eidolonrepraised|幻梦:再颂 (Eidolon : Repraised) +create-northstar@|机械动力:北极星 (Create: Northstar) +create-pattern-schematics@|机械动力:模式蓝图 (Create: Pattern Schematics) +magic-merchant +aether-villages@|天境村庄* +tricky-trials@tricky-trials-1.21 + + +the-boys-minecraft|黑袍:新世界 (The Boys : New world) + + +better-creative-tabs-forge-neoforge|更好的创造标签页 (Better Creative Mode Tabs/Better Creative Tabs) +more-upgrade@moreupgradetemplate|更多锻造模板 (MoreUpgrade) + + +avaritia-unofficial +stellaris@|群星* +command-o-matic + +realistic-physics@ +cia@|自定义物品属性 (Custom Item Attributes) +item-wheel@ +data-attributes-directors-cut@ +better-walls@betterwalls +the-pillager-legion +the-frozen-kingdom +stardew-fishing@ +lets-do-a-jumpscare@letsdoajumpscare + + +the-quackening +better-trial-chambers@ +coldsweat-tfc +deeper-nether-biomes +adventurers-beyond@ +mss-moogs-soaring-structures@ +goblins-tyranny@|哥布林的统治* +no-32768-limit@|没有32768限制* + + + + +reairdrop-supply@|空投供应:重生 (ReAirdrop Supply) +@minequery|MC宝 (MineQuery)¨@minequery-legacy|MC宝 (MineQuery) + +@simply-create-model-mod|简单动力 (Simply Create Model) +mountains-poem@|青丘辞 (Mountain's Poem) +@playtime-reborn|游戏时长计数器:重生 (Playtime Reborn) +@flavorimmerseddaily|烟火凡人心 (Flavor Immersed Daily) +moon-between-medicine|在月亮之间:药学拓展 (Moon Between : medicine) +craftable-chainmail-reborn|可制作的锁链甲:重生* + +thaumcraftfix|神秘时代6修复 (Thaumcraft Fix) + +extended-industrialization@ +small-tetra-additions +lets-do-furniture@|家居装饰 ([Let's Do] Furniture) +tesseract-api-neoforge@tesseract-api +tickrate-api +spectrelib + +tfc-artisanal + +@the-real-time|现实时间 + +dragonoptifix|DragonBlockC 与 OptiFine 的兼容修复 (DragonOptiFix) +effortless@|轻松建造 (Effortless Structure) +@barriers-dont-block-rain-1.21 + +@nochathide +inventory-tweaks-extrafoamy +automatic-infinite-elytra@ +re-translator@ +yank-it-out@ +vintage-kubejs@ +emi-professions-emip@emi-professions-(emip) +improved-grindstone +@starlight-legacy +themetip@ +woodwalkers@ +peaceful-moon@ +to-tweaks-irons-spells@ +horde-moon@ + +laser-mod-2 +mekanism-lasers@ +wizards-reborn@ +tinkervillager|工匠村民 (Tinker Villager) +customnpc-contentback@cnpc-items +debug-stick +useful-bat +runic-inscription +bamboo-stuff@ +@moai-update +junk-drawers@ +playerex-directors-cut@ +lets-do-camping@|摇曳露营 ([Let's Do] Camping) +@startuptime-unoffical|启动时间非官方版 (StartupTime Unoffical) +serverconfig-updater +@epiczoomer + +agenta@ + +more-beehive-variants@ + +persistent-creative-inventory@ +lets-do-wildernature@|野性自然 ([Let's Do] WilderNature) +@quitconfirm +@ressourcepackcommand + +neodymium-unofficial@nd1710|钕:非官方版* +@carbon-performance|碳 (Carbon) +coloredglowlib@ +@better-snow-coverage|更好的雪覆盖 (Better Snow Coverage) + +trade-enchantment-display@|交易附魔显示* +eternal-starlight@|永恒星光* +astral-patch|星辉补丁* +fast-scrolling-fabric@fast-scrolling¨fast-scrolling +galoblender-updated +more-tetra-materials@ +ageing-mobs@ +warm-ice-block +smoke-signals@ +wunderreich@ + +ames-mobs-renew +refreshdisplaylists +vulkanmod-android-libs +@black-bar-concealer +building-shift@ +mob-ai-tweaks@ +the-masquerade-illager-boss@the-masquerade-(illager-boss) +better-armory-x +sweetys-horse-armor-tweaks@ +fired-pots@ +under-the-moon@|驻月夜下 (Under the Moon) +coffeegs-colorful-world +jeb_-wool@|jeb_羊毛 (jeb_ Wool) +illage-and-spillage-finally-ported@illage-and-spillage-respillaged +more-runes-more-magic-series@|更多符文 (More Runes) +battlemages-more-magic-series@ +eidolon-rebrewed-data-recipes +elemental-metals-magical-metallurgy-series@fallen-paladins-and-priests +dragonsteel-more-magic-series@ +dragon-scale@ +scholar@ +@elytraswimfix +tacz-bullet-proof-enchant-add-on@¨tacz-bullet-proof-enchant-fabric-add-on +no-screen-bobbing@viewbobbingmod +more-spell-attributes-more-magic-series@ +minos-particle-presets +somewhat-hardcore-fabric-forge@you-die-you-lose-a-heart +@blurred-window +player-list-heads +@antighost-fork +environs-mod + + +unique-magic + + +epic-projectile-reflection|史诗弹射物反射 +zombie-island +stratagems@ +solar-hardcore@ +i-hate-flesh-reborn-ihfr@i-hate-flesh-reborn-(ihfr) + +@particle-unlimit|粒子上限解除 (Particle Unlimit) +aaa-particles@ +@anno +compass3d@ +@clockin +diggus-maximus-reborn@|连锁挖掘重制版* +satisfying-buttons@ +item-on-chest-fabric@item-on-chest +industrialreborn@ +ntm-space@ntmspace|HBM的核科技航天 (HBM's Nuclear Tech Mod Space) + +several-food-craft@ +cakes-cosmetics@ +boks-butterflies@ +immersive-winds@ +reef-redux@ +simple-quiver@ +too-many-paintings-forge-fabric@too-many-paintings +building-but-better@ +exchange-fuels@ +more-craftings-of-runes@ +mega-evolve +pixeltweaks@ +hrbs-drills@ +index-librorum-prohibitorum@index|禁书目录 (Index-Librorum-Prohibitorum) +bft +heartbond@ +breakerplacer@ +iron-ladders@|更多梯子* +crumbs-deepslate-button|Crumbs 的深板岩按钮 (Crumbs' Deepslate Button) + +cl0uds-paxels +unique-weaponry@ + +boss-keys + +mace-variants +shortswords@new-short-swords +bbs-mod@ +monocle@monocle-iris +move-ui@ +terrafly +achievements-mod-200@mysticrift-achievements + +saturation-plus@ +mod-and-resource-pack-checker-abras-additions +createstuffadditions-fix +warden-slayer-enchantment@wardenslayerenchantment +mods-optimizer@ +glowy-players-renewed@|玩家高亮:重置版* + +epic-fight-kenjis-combat-forms +mekanism-unleashed@|通用机械:解放* + +easy-cake|简易蛋糕* +weave-craft +morefarming@|更多农耕 (MoreFarming) +iron-bushes +forestry-community-edition@|林业:社区版 (Forestry: Community Edition) + +specified-spawning +kubejs-create-for-fabric-1-20-1 +portable-spawners +bettertime@better_time|长期熟时/求闻时记/更好的时间 (BetterTime) + + + + +lets-do-farm-charm@|沉浸农艺 ([Let's Do] Farm & Charm) + +hunters-moon@ +miners-moon@ +ender-moon@ +extreme-horde-moon@ +spider-moon@ +@breed-parrots-with-seeds +persistent-parrots@ +@ultimate-autototem +anti-mob-cheese@anti-mob-farm +bad-horse-fix@ +vanilla-nei-fix + +fconfiglib@ +satin-free-wakes@ +blue-archive-paintings|Sensei的珍藏* + +lunar-nether +yeehaw-towns@ +@copperrails + +mana-unification@ +immersive-energistics@ +specialised-cells@ +random-chunks@ +unique-commands@ + + +flood@ +block-prints + + +justleveling-x-ironspell@|法有所归 (Just Leveling x IronSpell) + +hugme@|抱抱我! (HugMe!) + +coins-ll@coins! +purediscstrickytrials@ +tinkers-in-the-sky +create-tank-defenses@|机械动力:坦克防御* +potato-update@potato-update-backport +twilight-forest-fixes@ +dietary-statistics +day-zombies-rebooted +viewboboptions@ +ender-pearl-anti-disappear@ender-pearl-ad + +create-dynamic-lights@ +decorative-tin +blended-compat@ +hold-easy-place@|保持简单放置* + + + +endlesscompat|无尽贪婪·伪附属 (EndlessCompat) +spartan-and-fire-lightning-edition|斯巴达之冰与火-雷电版 (Spartan and Fire - Lightning Edition) +the-twilight-forest-deforestation-edition|暮色森林 - Deforestation 版 (The Twilight Forest - Deforestation Edition) + +minieffects-legacy-extended-life +call-to-battle-ww2-vehicles-addon +thaumic_funnel@ +ynet-an-xnet-fork +rosatech +nutrition-gtceu@ +nutrition-unofficial-extended-life@|营养学非官方延续版* +manametalmod-tweaks-m3-t@manametalmod-tweaks|魔金微调 (ManaMetalMod Tweaks) +ae2-crafting-tree|合成树 (AE2: Crafting Tree) +client-automatic-doors@client_automatic_doors|客户端自动门* + +@chais-build-tools +forge-relocation +forge-relocation-fmp-plugin +@fish-lib +forgedapi-fork@ +prioninfection +dark-shadow-monster@|暗影怪物* +the-mi-alliance-invasion +fancy-health-bar@ +@no-join-leave-messages +data-trades@ + +draconic-alchemy +fancymenu-animation-maker-tool +jmx@imx +@elytra-rebalance +another-dyeable-shulkers@|可染色潜影贝* + +@thatskyinteractions +@tinker-transplant|匠魂移植 (Tinker Transplant) +chisatos-more-redstone@|Chisato的更多红石 (Chisato's More Redstone) +assetmover@ +duclib@ + +orecrop|矿石作物 (OreCrop) +@vinurl +nutritionz@ +xxl-packets@ +uncharted +mcfetch@ +reignited-hud@ +more-crafter-variants@ +sharingan-addon-ahznbs-naruto-mod +create-tacz-automation@ +tacz-plus-timeless-and-classics-feature-addon@tacz-plus +fibers-guns-pack-for-tacz +@splinecart +beams@ +discarnate@ +@fishmc +mob-armor-trims@naturally-trimmed +bubbles-a-baubles-fork +arst-motion-blur@ +@mpalladium|钯 (Palladium) +firehud@ +@elytra-autopilot + +personal-worlds@ +pearltickets +cobweb@ +progression +stop-repeating-command-block-reborn@|停!循环型命令方块:重生* +parry-us@parry!|予以刀振/格挡! (Parry) + +frycooks-delight@|油炸乐事 (Frycook's Delight) +advancedae@|高级AE (AdvancedAE) + +pretty-pipes-fluids@|更好的管道:流体 (Pretty Pipes: Fluids) +webstone@ +rotatable-blocks +treasure-seas@|宝藏海* +ambidextrous +@always-sprint +tea-the-story-recount|茶风·纪事:追叙 (Tea the Story : Recount) +xp-challenge@|经验挑战 (XP Challenge) +@styled-renaming +simple-block-overlay@ +@helpfull-action-bar +repeatable-trial-vaults@ +fast-async-world-save-forge-fabric +@chat-magic + +unlimitedelytra@|无限鞘翅 (UnlimitedElytra) +recrafted-creatures +reciperesearch|合成配方研究 (RecipeResearch) +thaumon@|神秘再饰* +create-firearms-patch|机械动力火器补丁 (Create Firearms Patch(kinetic pixel)) +create-eureka +forsaken-corpses@ +cat-variant-eggs@ +more-colorful@morecolorful|更加多彩的世界* +void-island-control-2-0 +fishing-rod-fix@ +@additionalentityattributes +@additionalentityattributes-forge +kubejs-sanity + +journeymap-web-map@|旅行地图:网络地图 (JourneyMap Web Map) +rain-should-extinguish-campfires@ +@mob-death-sounds +gauntlets@ + + +thrown@|扔!* +tacz-npcs-also-vpb@tacz-npcs +@scape-and-run-parasites-addon-immalleable-generator|逃逸:无适应性发生器 (Scape and Run Parasites Addon: Immalleable Generator) + + + +hotdog-delight +lets-do-addon-corn-expansion@|玉食俱馩 ([Let's Do Addon] Corn Expansion) + +@client-maps +dragon-gear-renewed +@archers-plushies +@hephaestus-expansion +create-structures-arise@ +kilt@ +gregtech-extended-chemistry-extended +ulv-covers-modern +farmers-structures + +@minecartspeeddisplay|矿车速度显示 (MinecartSpeedDisplay) +crossstitch@ + +free-camera-api@|自由相机API (FreeCameraAPI) +@flashback +bloodmagic-meteors-jei-support|血魔法陨星显示 (BloodMagic Meteors JEI Support) +limited-damage-indicator-particle@|伤害粒子限制* +netherite-extension@netheriteextension|下界合金拓展续作* +immersive-farming@|沉浸农业* +@vpb-too-many-guns +death-angels|死亡天使* +the-pale-hound +monsters-girls@ +monsters-girls-secrets-of-mermaids +dios-tiny-ore@ +defence-craft + +copper-equipment@exlines-copper-equipment +terramity@ + + + +neptune-lib@neptune +sign-edit-lite@signeditlite|告示牌编辑轻量版* +@book-formatting +@morewaterlogging + +@customspyglassmagnificationoverlay|自定义望远镜覆盖层 (CustomSpyglassMagnificationOverlay) +@chatting +@crosshair + +respawning-structures-forge-fabric +@sticky-honey +horseman@ +@easyplacefix|轻松放置修复 (EasyPlaceFix) +screenshot-flash@flash|一闪 (Screenshot Flash / Flash) +warp-zone@ +faded-widgets@|淡出界面* +knowledges@|知识库* +panda-genetics-tweak +colourful-llamas +@chens-japanese-decoration + +create-halitosis-create-halitosis@create-halitosis +create-unify@ +create-more-sand-papers@create-more-sandpapers +sawmill-house@ +kaboom-moon +hardcore-revive-mod@ + + +petrols-parts@|Petrol 的机件 (Petrol's Parts) +slavic-delight@ +aquamirae-delight@|海灵乐事* +dumplings-delight-rewrapped@ +my-nethers-delight-refabricated@ +@polyweather +shadow-x-axolotl-buckets-plus +daily-shop@ + + + + +growable-goodies +petrolpark-library@petrolpark|Petrolpark 的库 (Petrolpark's Library) + +ancient-reforging@ +stackmob-fabric@ +itemindicator@ +kenshiro-mod|北斗神拳* +roamers +@legacycaneditsign +title-screen-mobs@ + +antiblocksrechiseled@ + +end-ores +tnt-expanded +glimmering-tales@|微光纪事* +fluid-interaction-tweaker|自定义流体交互* +kubejs-extended-crafting +kubejs-addon-blood-magic +custom-portal-builder@ +biome-difficulty +@viaaprilfools +tfc-weld-button@ +tfc-regrowing-forests@ +ccdbridge@ +welcome-message@ +auto-attack-rebirth +lotas@ +tasmod@ + +betterfly@|飞起来! (BetterFly) +@leashedplayer|可拴玩家 (LeashedPlayer) +melodymagic@|旋律魔法 (MelodyMagic) +scaling-mob-difficulty-fork|知时修倍* +trajectoryprojections@trajectory|弹道预测 (Trajectory) +accessories@ +onewholibs@1wholibs +nucleus@nucleus_pauljoda +@equator +accessories-cc-layer@ +accessories-tc-layer@ +@confetti-lib + + +material-replication@ +rsj@ +irikana|伊利康纳* +mts-iv-aq-studios-himars +immersive-vehicles-iv-mts-lindqvist@lav +immersive-vehicles-iv-mts-zroskyan-ordinary +petroleums-wigs +revenge-mark|遗怨待战 / 复仇标记* + + + + +@create-coggle +create-enchantable-machinery@¨create-enchantable-machinery-fabric +bad-eyes|近视眼* +bad-dreams@|噩梦* +turtlebois-rpg-classes +through-the-lily-pads-gently@ +decofirmacraft@ +@dusty +@beeg-smol +scaling-mobs@scaling-mob-difficulty +multiline-mastery@ +@confetti-stuff +pirates-treasures +ars-nouveau-delight@ +crossbow-enchants@ +extendeddrawersaddon@ +minecolonies-letsdo +earlystage@ +smitherz@ +additionz@ +bjornlib@ + + +skewers-reflavored|串起酥食/烤串:再调味* +linear-xp-forge|验依定值/线性经验 (Linear Xp Curve) + + +dumplings-delight-reload@|饺子乐事:重启* +auto-switch-elytra@autoswitchelytra|自动切换鞘翅* +gregtech-placeable-emitters@ + + + + +zakuro@|榴* +dropoff +upgraded-totems +@player-chains +anti-creative-drift@ +damage-incorporated@ + + + + +exmodifier@|极墨重锻-革故鼎新 (ExModifier) + +@creepersburn-reborn +lazy-dfu-forge|DFU载入优化 [FORGE] (Lazy DataFixerUpper(LazyDFU) [FORGE]) + +creaturechat@ +helldivers-spread-democracy@helldivers-2-spread-democracy + +variant-tools-and-weaponry-more-weapons@ +mgrr@ +arcanemysteries@arcane-mysteries +botanic-pledge@botanicpledge +rediculous-ore-generation@ +witchy-wearables +simple-delights-recooked|重启爽食/简单乐事:再烹饪* +braziliandelight@|巴西乐事 (Brazilian Delight) +applied-energistics-delight@ +extra-meat +peculiar-primordials@ +time-wind-forge@time-wind¨time-wind +@mcbrowser +additional-trims +upgraded-trims +water-balloon@ +cataclysm-spellbooks@ +call-of-drowner@|溺亡者之嚎 (Call of Drowner) + +endofdays|终焉之日-重铸 (PrejectZ) + +fastfood-delight-unofficial|重启速食/快餐乐事非官方版 (FastFood Delight Unofficial) +faster-fly-block-breaking|飞行速速破* +upgraded-additional-trims +create-let-the-adventure-begin@ +bountiful-critters@ +flashlight-mcowners +smartpot@|智能锅 (SmartPot) + + +merciful-void|渊佑堕者/慈悲的虚空* +gsic2|星空工业 (GSIC2) +open-energistics +@the-friends-mod +@construction-wand-fabric +osmiumspacetiers +bodyguard@ +@quick-menu|快捷菜单 (Quick Menu) +lazrs-lib@ +cute-words-chat-replacer|雅言订正/聊天内容替换 (Cute Words) + + +hotbath|热水澡 (Hot Bath) +@no-double-sneak +tfc-hammer-time@ +tfc-better-stone-age +battery-status-info@batterystatusinfo +mineteam@mine-team +@nocreativemode|禁用创造模式 (NoCreativeMode) +@darktitlebar-forge +croaklib@¨@croaklib-dep + +nbt-copy@ + +more-totem-effects +bakeyourbread@bake-your-bread +modern-debugify +recipe-essentials-forge-fabric +zombie-villager-control|催起死尸/僵尸村民控制* +@1.8-pvp-mod +@blackscreenquiet|黑屏安静 (BlackScreenQuiet) + +@too-many-shortcuts +better-horse-movement +tct-core@ +obscure-tooltips-fix + +@notica + +zhonglv-12et@|钟吕十二律 (ZhongLv-12ET) + + +just-another-random-spawn|遥缘调址/随机出生点* +@kaimyentity-c|KAI我的实体-C (KAIMyEntity-C) +realistic-mobs|Realistic Mobs - 无法文件¨@realistic-mobs +fullthrottle-alchemist +fullthrottle-nei +creature-compendium@ +desert-update@desert_update +ancient-elements@ancient-elements-mod +left-behind@ +corrupted-witherskeleton-boss-mod + +mca-api + +sodium-leaf-culling@sodiumleafculling|钠:树叶剔除* +homing-xp-orb|引验导追/归航经验球* +multiblocked2@ +armorstatushud-updated|耐久信息显示更新版 (ArmorStatusHUD Updated) +tfc-better-blast-furnace +tfc-textile@ +tfc-woodworking@ +tfc-auroras@auroras +greg-paintings@ +gtmthings +create-trading-floor@|机械动力:交易站点 (Create: Trading Floor) +@fishy-create-stuffs|Yu的机械动力附属 (Fishy Create Stuffs) +biolith@ +hungrier@ + +furnace-pickaxe-mod +camouflage-doors-and-trapdoor@ +dense-metals +actually-subtractions@ +mechanical-botania +puddles +yoyousukes-kabutoaddon-for-ahzs-shinobicraft +illager-world-war +guns-craft-adventurers-arsenal|枪械工艺:冒险者的武器库 (Guns Craft Adventurer's Arsenal) +@seven-deadly-sins-origins +difficult-raids-stronghold-survival-edition@difficult-raids-compatibility-edition +subnautica-flow +cardinal-sins +unwrecked-ships-forge¨unwrecked-ships-fabric +revamped-shipwrecks-mod +christmas-culinary-desires-decorations@christmas-culinary-desires-(-decorations) +@florum-sporum +unofficial-bosses-of-mass-destruction-dungeon + + +@more-things|更多物品 (MoreThings) + +explosionvisualizer@|爆炸信息显示 (ExplosionVisualizer) +@more-vanilla-foods|更多原版食物 (More Vanilla Foods) +let-me-feed-you|吃取送食/玩家喂食 (Let Me Feed You!) + +drg-laser-pointer@|深岩银河激光指示器 (DRG Laser Pointer) +spawner-head +medieval-core-mod +darkmining@ + +@visualkeys +sodium-extra-information@ +@bulk-villager-trading +omniscience +illusion-onslaught +rar-compat@ +wards +moremcmeta-emissive-forge@moremcmeta-emissive¨moremcmeta-emissive-fabric +@fantazia +falling-attack +lesraisins-armor@ +goety-spillage@ +waifucraft +sign-to-chat|阅言得知/聊天栏读取告示牌 (Sign to Chat) +rainimatormod@ +realistic-airdrop|真实空投* +keepers-of-the-stones-ii@keepers-of-the-stones-2 +woodencog|Wooden Cog - 最新(已由Manwe_b接手)¨wooden-cog|Wooden Cog - 已不再更新¨@woodencog +shadow-x-blocks-plus +pet-essence@ + +watson@ + +emerald-matcha-craft-v3|翠茶工藝 (Emerald Matcha Craft) +cctv-camera +trash-compactor@ +rustic-delight@|乡村乐事* +total-assault¨@total-assault|Total Assault - 已弃用 +sky-breaker|天穹突破* +@scala3std + +@hoofprint +better-controls@ +@optibye +kubejei +actually-harvest@ +city-craft@rexs-city-craft + +eggs-better-vanilla-food@eggs-better-food +shelf-mod@ +nebulus-cherryblossom-tree@nebulus-cherry-blossom-tree +ftb-rickety-water-wheel +cobblegen-galore +@ringles-gun-turret +create-sky-village +create-crushing@ +cushy-pillows|舒适枕头* +ice-and-fire-patcher@iaf-patcher|冰火传说随意修复* +goety-revelation@|诡厄巫法:启示录 (Goety: Revelation) +the-mandela-catalogue-alternates@ +the-craftela-catalogue +the-ceilands@|垂顶之地* +@sharowings-better-dungeons +snowbound@snow_bound +opencomputers-icbm-classic-addon¨icbm-opencomputers|Opencomputers ICBM-Classic Addon - 教程文档 +@ad-astra-pandoras-frontier +cosmic-horizons@cosmic-horizons-cosmos +shadow-x-netherite-scrap-from-piglin-brutes|猪灵蛮兵掉落下界合金碎片 (Netherite Scrap From Piglin Brutes) + +better-modlist-neoforge@better-modlist|更好的模组列表 (Better ModList) +sky-aesthetics@ +headshot-bonus|已无可惧 / 简单爆头* +enchantlevelbrek@enchantmentlevelbreak|附魔等级上限突破2 (EnchantmentLevelBreak) +the-ruler@ +biome-borders-revived-liteloader-only +chunkborders|区块边界 (ChunkBorders) +burnt@ +goatman@ + +armor-damage-limit@|甲哇!/盔甲耐久损失限制* +knight-bodyguard-forge|骑士保镖 (Knight Bodyguard) +deeper-depths +unseens-nether-backport + +shadow-x-adventures-plus +adventures-in-time@ait +elementalist +@craft-slime-fabric|制作黏液球 (Craft Slime Fabric) +shadow-x-unactivated-totems +cagebox + +rechiseled-ae2@ +archeological@archeologicalmod +clarity +backpacked-world-of-color@ +nofov +cobalt-custom-chunk-renderer@cobaltmod|钴 (Cobalt) +spartacus-army-uniform +soviet-army-uniform@ +german-uniforms-ww2 +fantasy-ending|梦幻终焉 (FantasyEnding) + + +tameable@ +slashblade-gamerelic|游戏扩增·异界之刃 (SlashBladeGameRelic) +theovergrowth +jadens-nether-expansion@ + +configurable@ + +@chatpositiondisplay|聊天框坐标显示 (ChatPositionDisplay) + + +@forge-early-loading-screen-fabric|Forge 加载屏幕移植 ((Neo)Forge Early Loading Screen for Fabric) +@ebe-forge + +patpat +modern-life-patch@modernlifepatch|摩登生活补丁* +@ivr +rusticdelight-refabricated@|乡村乐事:重织 (RusticDelight: Refabricated) +scape-and-run-meshi@|逃逸:寄生饭 (Scape and Run: Meshi) +@bad-apple-world-preset +gastronomy-works@ +@create-air-fabric +@clockwork-additions +colorfulwater +yungs-cave-biomes@|YUNG的洞穴生物群系 (YUNG's Cave Biomes)¨yungs-cave-biomes-fabric|YUNG的洞穴生物群系 (YUNG's Cave Biomes) +@legacy-command-registry|旧式命令注册 (Legacy Command Registry) +@screensaver|屏保 (Screensaver) +@startuptone|启动提示音 (StartupTone) + + + +va-11-hall-a-drinks|Vall-11 Hall-A饮品 (Vall-11 Hall-A Drinks) +bettergive-reborn@bettergivereborn +blur-server-address@ +foodvariations@|生活调味料:经典版 (Spice of Life: Classic Edition) +pizza-delight@pizzadelight +simplefog@ +@butter +tnt-plus-mod|TNT Plus - 所有¨@tnt-plus-mod + +@kelvins-better-player-animations-(port) +tokusatsurecord|特摄唱片 (Tokusatsu Record) + +origins-backgrounds-forge¨origins-backgrounds +cataclysm-apotheosis-addon +cave-dweller-reimagined¨cave-dweller-reimagined-fabric +out-of-combat|脱战 (Out of Combat) +soulfragment|灵魂碎片 (Soul Fragment) + +create-peaceful@ +baby-players +dynaores|动态粗矿 (Dynamic Raw Ores) +mc-mods-arrows-infinity-fix +bundles-backport +its-magispelling-time + +@windows-starting-overlay|Windows启动界面 (WindowsStartingOverlay) +@dontsneakprogress|偷跑禁止 (DontSneakProgress) +@unkindled +recipe-generator@ +@carbonfltr +argonmod@|氩 (Argon) +foggypalegarden@ +@items-stack +arkane-domains + +yakumoblade|幻想之刃 (yakumoblade) +no-random-drop-offset|垂直落下/移除掉落随机偏移* +croptopias-chocolaterie-unofficial|巧克力工坊:非官方版 (Croptopia's Chocolaterie Unofficial) +epic-fight-wukong-moveset|史诗战斗:悟空 (Epic Fight - Wukong Moveset) + +petphrasex@|口癖X (PetPhraseX) + +dust-and-ash|尘与烬 (Dust and Ash) +@particle-interactions +@trial-spawner-timer|试炼刷怪笼计时器 (Trial Spawner Timer) + +slashblade-resharped-renderfix-patch@|拔刀剑:重锋 渲染修复补丁 (SlashBlade Resharped RenderFix Patch) +@invulnerable-wheat +skin3d-but-not-cubic@skins3d-but-not-cubic +leavesly@ +create-totem-factory@ +snad-redstone-edition@|子沙:红石版 (Snad: Redstone Edition) +@party-flames +subtle-effects@ +@dma +cc-wasm +legacy-patch + +@glowup +@customsavedirs +just-enough-magiculture +ae2-jei-integration +entangled-fix +@customdurabilitybar + +scape-and-run-revenants +warden-s-domain +more-wardens +hidden-realm@ +spells-gone-wrong@ +wandrous@ +cnpc-dbc-addon@customnpc-plus-dbc-addon +salmons-genesis +the-afterdark +endlesssword|无尽拔刀剑 (Endless Sword) +bh3|崩坏3 + +loaded-mods-checker@loadedmodschecker|存档模组核对* +i-have-slept@|朕已安寝 (I have slept) +@itemstackpromax|物品堆叠ProMax (ItemStackProMax) +item-split-bug-fix|物品分裂修复* +spontaneous-replace-cobwebbed@|自然更替:蛛丝网迹 (Spontaneous-Replace: Cobwebbed) +modernconverter +frozify@ +potato-library +swisscaves@ +title-screen-blobcat@ +punching-creepers@ +ancient-curses +resettleable-traders-forge-fabric@resettleable-traders|流浪商人安家 (Resettleable Traders) +ihearttfc@ +itemphysic-1-7-10-unofficial@itemphysic-1.7.10-unofficial|物品物理掉落非官方版 (ItemPhysic Legacy Unofficial) +jei-area-fixer +ars-elixirum-forge@ars-elixirum¨ars-elixirum-neoforge¨ars-elixirum +gold-nugget-recycling +sodium-options-api@ +@totom-register + +crazyae@|疯狂的AE (CrazyAE) +ae2-crafting-tree-legacy|AE2合成树-传统版 (AE2CT-Legacy) +ae2-alchemistry-addon + +novaultlimit@ +game-discs@|游戏光碟* +luncheon-meat-s-delight@|午餐肉乐事 (Luncheon Meat 'S Delight) + +vanilla-plus-resourceful-tools¨resource-tools-fabric +create-horse-power@ +ars-technica +plustic-reforged@ +spawners-plus@spawners_plus|刷怪笼拓展 (Spawners+) +dracolotl@ + +sacks-n-such@ + + +camellialib@|山茶花核心 (CamelliaLib) +cameliaarmory@|花朵武器库 (FlowerArmory) + +moonrise@moonrise-opt +corpsecomplex-unofficial@ +@starlish +languagereloadunofficial@ +mekanism-covers@ +enchanted-wilderness-elegant-countryside@enchanted-wilderness-elegant-countryside.|雅致乡下 (Elegant Countryside) +better-durability-reforged|更好的耐久度:重铸* +fast-tpa|我来助你! (Fast TPA) +cherry-on-1-12-2@cherry_on_1.12.2|1.12.2的樱花 (Cherry_on_1.12.2) +scape-and-spartan-parasites|寄体斯巴达 (Scape and Spartan: Parasites) +@ripples-of-the-past-extra-stands-addon +the-knocker@ +vll-r-mystery +scp-origin +sniffers-delicacies +fix-changed +valkyrien-pirates@|瓦尔基里海盗* +pathogen +chrysalis@ +alekis-ridiculously-simple-roofs@alekiroofs +@trails +rainboows@ +particle-effects@ +rple@ +reign-of-nether-rts-in-minecraft@reign-of-nether-rts|下界之治 (Reign of Nether RTS)¨7119668|下界之治 (Reign of Nether RTS) - 官方收录 PVP 对战地图包 +the-secret-doors + +immersive-vehicles-iv-mts-veb-iav-improved-2000|“改进-2000” +tame-tools@|驯兽工具* +@bia +vounierns-turrets +seafarer-forge +zombies-plus-frenzied-horde@ +@tetrismc +ecliptic-seasons@|节气* +xibaoxx@|喜报 ×× (XiBao ××) + + +murasama-daker|鬼妖村正 (Murasama) +particle-storm|粒子风暴* +@2d-minecraft +till-it-breaks-updated@ +debark@ +till-it-breaks@ +end-reborn-expansion@end-reborn +@origins-genshin + + +the-glitched-one +progression-reborn@ + +@simple-info-display +@automaticmemories +zoom-camera@ +dpi-fix +@item-information-display|物品信息显示 (Item Information Display) +almanac-lib@almanac + +remove-blindness|移除失明 (Remove Blindess) - 不全¨@remove-blindess|移除失明 (Remove Blindess) +simplerpgcore@ +droppable-villager-trades@ +stackupper@ +colorful-orbs@ +@idmxd +modernxl-2-in-survival +creepercollateral +findmyitemsandfluids +@numeric-experience-info +aquapatch +aviator-dreams@ +macaws-stairs@|Macaw的楼梯与露台 (Macaw's Stairs) +cross-stitch-colours@ +gaming-deco@ +reactive-music@|韵律回响* +easel-does-it@ +rbasamoyais-betsy-ross@betsy-ross +@contingameimesuper|游戏内输入法Super (ContingameIMESuper) + + + + +dropped-item-tweaks@droppeditemtweaks|掉落物调整* +movingquickly|禁用快速移动检查 (MovingQuickly) +@soup-api +@tsa-decorations +@autofarm-mod +gelato-galore-2@|意式冰淇淋盛宴* +dyeable-jack-olanterns@ +white-pumpkins@ +dawn-of-the-flood@ +deatbutthreereload@|逝不过三:重开 (Death But Three Reload) +common-weapons +ore-silverfish-mod@ +gtbcs-spellbooks +project-lambda + + + + + +@pretty-hitboxes-create-addition|可配置的碰撞箱显示-机械动力功能附加 (Pretty Hitbox-Create Addition) +watersource-reborn@|水源:重生 (WaterSource: Reborn) +locks-unofficial@|锁:非官方版 (Locks-Unofficial) +epicfight-improve@epicfight_improve|史诗战斗:改进 (EpicFight:Improve) +just-in-nether@ +jinghui@|镜回 (JingHui) +@ripples-of-the-past-mandom-addon|RotP:男人领域附属 (Ripples of the Past: Mandom Addon) +@auto-gg +better-brightness-slider-respawn@ + +@playergyro +animatica-foxified@ +mcchatgpt@ +@aimobs +ambiances@aurae|氛围! (Aurae!) +screw-your-items@ +mace-port +bloodlines +vampiric-ageing-a-vampirism-addon +extra-enchantments-and-curses@|更多附魔和诅咒 (Extra Enchantments and Curses) +enchanting-tweaker@enchanting-tweaks +just-a-lot-more-enchantments@ +alessandrvs-enchantments@alessandrv-enchantments +armor-abilities@ +sleepy-hollows@|沉眠空谷* + +nametag-tweaks@nametagtweaks|名称标签调整 (Nametag (Display) Tweaks) +@sodium-no-alerts +headshot-respawn@|爆头:重生 (Head Shot Respawn) +leafdecaystopper|树叶腐烂抑制器 (Leaf Decay Stopper) +animated-loading-screen@ +@rotp_whitesnake|RotP:白蛇附属 (Whitesnake Addon (Ripples of the Past)) +@ripples-of-the-past-made-in-heaven-addon|RotP:天堂制造附属 (Ripples of the Past: Made in Heaven Addon) +@ripples-of-the-past-c-moon-addon|RotP:新月附属 (Ripples of the Past: C-Moon Addon) +imbued-gear@ +tacz-js@ +ipla@ +bcg-util +sciophobia@|全局自定义文本阴影渲染* +lithic-addon-mod +light-blocks-from-1-17@ +light-and-shadow@ +excavein@ +spanish-delight-a-farmers-delight-add-on@spanish-delight|西班牙乐事 (Spanish Delight) +ars-nouveaus-flavors-delight@arsdelight|新生乐事 (Ars Nouveau's Flavors & Delight / Ars Delight) +oceanic-delight@|海之乐事* +the-player +kelka-craftable-animals@craftableanimals +super-hyper +wans-ancient-beasts@wab|Wan的远古异兽 (Wan's Ancient Beasts) +invocations-spell-engine@invocations +gearifiers@ +recall-potion-neoforge@|回忆药水 (Recall Potion) +flowing-fluids@ +frights-and-foliage@ +blorfstone +filinkus-s-huge-tools +necromancer-mod +e_kedis-electronics +uprade-yourself + +smelting-touch-enchantment +shinobiorigins-utils +unifine +trailier-tales@ +mixinjs-coremod +mcwen +rank-system|评分系统* +@creative-one-punch-forge +bundle-inventory@ +scroll-tweaks@scrolltweaks|鼠标滚轮调整* +st@server-tools|服务器工具 (Server Tools) +ride-every-thing@|骑乘一切* +cit-resewn-neopatcher@ +legendary-creatures|传说生物* +@meowcraft-mod + + + + +frozenlib@ +clientblock@ +eventjs +backup-manager@ +the-root-of-fear@ +the-modifiger@ +keypreset@|键位预设 (KeyPreset) +@tweakeroo-features-menu +sanity-prequel@|理智:前传 (Sanity: Prequel) +ayame-paperdoll@|Ayame 纸娃娃 (Ayame PaperDoll) +@registry-helper-lib +@carpet-permissions +passive-shield@|被动盾牌* +trap-expansion +roost-2-flying-higher +amber-lib@amber +liteminer@ +@lvlz-better-nether +@lvlz-better-end +cc-shops@ +modular-machinery-reborn@ +flare@ +rs-crafting-monitor-in-grid@ +@photonics +lambdynamiclights-unofficial-neoforge@ + +@heracles-button +voicecontrol|声控* +hex-ars-linker@|咒法魔艺链接 (Hex-Ars Linker) +bingolobby@|宾果游戏大厅 (BingoLobby) +worldedit-legacy@worldedit-legacy-enhanced +@nohealthbar +asm-fixes-j-a-f-m +moestweaks +prickle@ +farming-3x3@ +trickery@ +kebab@bogismokkebab +farmers-croptopia@ +mc-mods-trees-drop-apples +infinite-dimensions@ + +mofus-broken-constellations@mofus-better-end-mofus-broken-constellation +starlance@ +beneath@ +@simple-client-base|简易客户端:基础 (SimpleClientBase) + + +ultimate-enchantment@|终极附魔* +ron-settings +backpack-display@|背包物品内容显示* +horrrs-pvz|Horrrs的植物大战僵尸* +@optibabric +item-restrictions@ +vintage-animations@ +the-one-who-watches@ +scp-ultimate +herobrines-omen +sws-wukong +dragns-valiant-vehicles@dragns-valiant-vehicles! + +create-ad-astra-compatibility +create-mechanical-chicken@ +zbgt@ +casinocraft +@mql-tir5d-turtle +toadlib|ToadLib - 不全¨@toadlib + + +crosshair-tweaks@crosshairtweaks|十字准星调整* +what-did-i-just-kill@ +scalablelux@ +weather-changer@ +iron-nugget-recycling +@picohud +re-exposer@|Exposer 重置版 (Re-Exposer) +gtmoreoreprocessing@ +computercraftedu +bibliocraft-legacy@ +simple-clouds@ + + +furniture-modcraft@several-furniture-craft + +spellblades-and-such-hexblade + +sons-of-sins-organs-additions|七罪之子:器官添加 (Sons Of Sins: Organs Additions) +sons-of-sins-organs-museum|七罪之子:器官博物馆 (Sons of Sins: Organ Museum) +mobs-of-sins-alexs-mobs-integration-forge|七罪之子: Alex的生物集成 (Mobs of Sins: Alex's Mobs Integration [Forge]) +stitched-sins|缝合的罪* + + +the-sculpture|SCP-173,雕像 (SCP-173,The Sculpture) +goop@ +neepmeat@ + + + +@huangsheng1s-more-monster|更多怪物 (HuangSheng1's More Monster) +creeping-woods +@zac +dragon-mounts-2@|龙骑士2 (DragonMounts2) +life-fruits@|生命果* +ati-structures +fantasy-armor@fantasy_armor|幻想铠甲* +beautiful-enchanted-books@beautiful-enchanted-books-mod-edition + + +void-fog@voidfog +@legacy-rocket-model|旧版火箭模型 (Legacy Rocket Model) + + + +tinker-i-o-ce|工匠接口社区版 (Tinker I/O CE) +more-shield-variants@ + +bendy-items +paladins-oath + +roundabout-the-jojo-mod@roundabout_the_jojo_mod + + +enviromine-continuation@|更多生存要素:延续 (EnviroMine continuation) +@toffys-hooks +mutants-buff + +@blockplayer|玩家方块模型 (BlockPlayer) +terrablenderfix@ +craterlib@ +@caramel-chat +spark-unforged@ +pack-mode-reborn +mc-mods-the-wood-weve-got@all-the-wood-weve-got +bibliowoods-legacy@ +hydrological@ +unilib@ + +modchu_playerformlittlemaidfml +quiet|迁噪碍音/玩家禁言* +galacticraft-compatibility@|星系兼容* +@bettertab +modular-machinery-reborn-mekanism@ + +dawn-of-time-roa-edition +buildpaste¨buildpaste-for-fabric +mutils@ +better-campfires@|更好的营火* +@mtr-renfe-addon +gt-community-additions@ +more-create-burners|机械动力:更多燃烧室* +create-logistics@ +create-pneumatic-equipment@ +collisiondamage|碰撞伤害 (CollisionDamage) +@absolutely-proprietary +tensura-reincarnated@|关于我转生变成史莱姆这档事:转生 (Tensura: Reincarnated) +transformer|奥特化身:无限 (Becomes Ultraman:Infinity) +henshin|变身* +ridiculous-world + +quartz_craft@|石英工艺 (Quartz_Craft) +cursed-stare@ +legendblade|传世之刃 (LegendBlade) +@hypothermic-reforged +scape-and-run-parasites-extra@|逃逸:寄生体扩展 (Scape and Run: Parasites Extra) +lauchs-shutters@shutters +golden-foods@ +@alexscaves-delight +@spmreborn|烤地瓜:重生 (Sweet Potato Reborn) +dragon-fight-config-endergetic-addon +hour-clock-24@|24小时制 (24Hourclock) + + +celestial-forge|星月再锻* +mahjongcraft@|麻将工艺 (MahjongCraft) +formidulus@ +ames-stranger-things +herobrine-origins +milkable-blazes¨@milkable-blazes|Milkable Blazes - 已归档 +@rotp-stone-legacy|RotP:暗之遗物 (Stone Legacy (Ripples of the Past addon)) +furniture-beetle@ +mekanism-x-create-northstar@|通用机械:北极星 (Mekanism x Create: Northstar) +@createz +create-smart-crafter@ +create-fuel-and-water-information@create-fuel-water-information +thematic@ +more-composter-variants@ +more-fletching-tables@ +more-grindstone-variants@ +more-bed-variants@ +more-loom-variants@ +more-feeding-trough-variants@ +more-smoker-variants@ +manascore@ +ames-mobs-configuration|AME生物配置 (Ame's Mobs' Configuration) +display-delight@ +realistic-torches-roa-edition +explorers-compass-edited|探险者指南针 修改 (Explorer's Compass Edited) + +@slime +x-backup@ +iron-barrels-forge@iron-barrels +spectral-decorations@ + + +trims-on-tools@ +galacticraft-automatic-resources|星系自动资源* + +@lx-light-assist-tool|轻辅助工具 (light assist tool) + + +roberts-building-pack|Robert的建筑扩展包 (Robert's Building Pack) +arcanus@ +ultimate-chess@ +sparkweave@ +visualjs +lights-out +a-night-stalker +the-faceless-duo +scape-and-run-parasites-meteorite@|逃逸:祸从天降 (Scape and Run: Parasites Meteorite) +cravencrafts-bloody-bits@ + +@carcrash|撞车 (CarCrash) + +fastlang +min-3-hall-a@ +modular-machinery-reborn-energistics@ +tweaks-for-galactic-science +java-version-checker +chatcopyrite +chat-boost|聊天增强* +terracart +noteblock-backport@ +scape-and-run-parasite-dimension@srdimension|逃逸:寄染之世 (Scape and Run: Dimension) +hexdebug@|咒术调试 (HexDebug) +paths-of-sin@ +@mapperplugin +@enchantment-decomposition|附魔分解 (Enchantment Dismantling) +hide-key-binding@|隐藏按键绑定* + +inline@ +fluffy-fur@ + + +head-cutter|玩家剪头* +salty-s-realistic-forging@saltys-realistic-forging +@vs-wakes-compat +@vs-crumbles +@vs-ship-in-a-bottle +rustic-pancakes@ +ice-and-fire-delight@|冰火传说乐事 (Ice and Fire Delight) +additional-dragons +enigmatic-unity +ephemera@ +theurgy-kubejs@ +immersive-lanterns@ +txnilib@ +default-key-setup@|默认按键配置* +the-man-king +create-arms-race@ +powered-flashlight@ +vmc-mc@virtual-motion-capture-for-minecraft +@hexcellular +hex-conjuring@|咒术构筑* +hexjs@ +craftsense@ + +zenkorium-creatures +zhengelss-techguns-addon@zhengelss_techguns_addon +more-artifacts@ + +tfcgenviewer@ +terra-math@ +lukis-crazy-chambers +tumbleweed-wasteland +irons-jewelry|Iron的宝石与饰品 (Iron's Gems 'n Jewelry) +atlas-api +loading-screen-messages +@pipesounds +nemos-invertory-sorting@nemos-inventory-sorting +@better-ux +@hudmini +ribs-panning +hotkettles@ +gift-drop@ +dragns-livestock-overhaul@ +storage-drawers-unofficial@|储物抽屉非官方版* + +centrifuge-tiers-reproduced@ +dense-mekanism@ +simple-missles@ +galosphere-spellbooks@ +discerning-the-eldritch|窥玄探秘* +@hexcassettes +wardens-plus +ender-wyrmlings + + +new-classic-battle-towers +chitin-equipment@|甲壳装备* +mowzies-cataclysm@|Mowzie的灾变 (Mowzie's Cataclysm) +stardew-fishing-fabric@ +piglin-slayer@ +cataclysm-tools@ +witherite-gear +faunus@ +oo-ee-a-e-a@ +@translator|翻译器 (Translator) + + +sodium-embeddium-options-mod-compat@sodium-options-mod-compat +secureseed-reborn@ +creative-eats +mazerooms@ +friendly-chests@ +@chitinous_ties +brewable-dragons-breath@|龙息可酿造 (Brewable Dragon's Breath) +flerovium@|鈇* + + +gathering-torches-become-sunlight|薪火,造炬成阳* + +@morechathistory-neoforge|更多聊天记录-NeoForge (MoreChatHistoryNeoForge) +no-arrows-in-you-respawn@no-arrows-in-yourespawn + +glowcase@ +hitbox-api@ +@polynametag +broken-nametags@ +@compostable-flesh +a-cute-little-crock-pot@ +@bountifulharvest|感恩节乐事 (Bountiful Harvest) +wasteland-grocers +arcane-tablet +@unflavoured-pipes +curvy-pipes@ + + +classic-bar-legacy|经典状态条 延续版* +glowing-eyeblossom@ +openlink@|开放式联机 (OpenLink) +@vs-grapples +@mydriasis +no-mob-spawning-on-plants@ + +durability-rework@ +more-villagers-re-employed@ +similsax-transtructors +tcw-bedrock-breaker +apothic-reforge-tokens +advanced-skills-remastered@|进阶技能:重制版 (Advanced Skills: Remastered) +monsters-and-dungeons +cultivate-the-eternal-realm@ +too-much-bosses +valoria@ +glowroot@ +@instaminable-deepslate + +greedy-bag +naughthirium@ +chunkpurge|区块清除 (ChunkPurge) +kubejs-tfmg@ +gauges-and-switches-ported +mifa@ +tis-vs@ +pistronics-2 + + +gladius-combat-evolved +hungry-chests +better-withered-mobs@ +pkgbadges@ +@carbasa +countereds-settlement-roads@ +countereds-terrain-slabs@ + +explosive-enhancement-reforged@explosive-enhancement-forge +tmtravlrs-arrow-trails|Tmtravlr的箭矢轨迹 (Tmtravlr's Arrow Trails) +biome-replacer@|群系替换器*¨biome-replacer-neoforge@|群系替换器 (Biome Replacer) +custom-suspicious-stew|自定义谜之炖菜* +@child-folder-mod-scanner|子文件夹Mod扫描器 (Child Folder Mod Scanner) + +@create-stress-debug +create-kart +@barometry + +menufpsunlocker@ +bogged-spawn@|沼骸生成微调* +unicode-fix@ +insanity +sepals@ +frustum-culling-advanced + + +star-meow-craft|星喵工艺* +@defile +vanishmod@ +@eat-it +f1-y-f5-mod@perspective-lock +meddlebootstrap +mc-modstheleaks +walk-overhaul +no-strip@ +mcplus-remastered|MCPlus:重置版 (MCPlus Remastered) +instant-classic-houses +hexparse@ +betterraid|更好的劫掠 (BetterRaid) +villagermetafix +create-better-villager@create-better-villagers +mc-modsjs@filesjs +robotic-parts-first-aid-compat +craftingpad-fabric@craftingpad + +exlines-sushi-mod@sushimod|寿司 (Sushi Mod) +demanding-saplings@ +coastal-waves@ +@no-swimming + +stone-zone@|泛用兼容:石材 (Every Compat*) + +a-man-with-plushies@ +enchantmentransfer@|附魔转移 (Enchantment Transfer) + + + +@async +@mtr-ante|无名的纸板箱交通拓展 (Aphrodite's Nemo's Transit Expansion) +touchcontroller@|触摸控制器 (TouchController) + +let-me-click-and-send@ + +careful-cast-corrector-ccc +lagbgon-revived@ +project-steam +extended-crafting-terminals-for-applied +sweety-archeo@sweety-archaeology + +chamber-clarity-tac-z@tacz-chamber-clarity +techguns-ce@techguns|科技枪-社区版 (Techguns-CE) + +@jdinpack +selfexpression-slim@ +nothing-dimension@ +@glassitemframes +portable-stations +new-world-mod@ + + + + +book-scroll@ +@journalmod|日志模组 (Journal Mod) +@autotool-ks|自动工具 (AutoTool) +@fakevanilla + + + + +qualia-carpet-addition@qca +mouse-tweaks-unofficial|鼠标手势非官方版* +baubles-lts +elysium-api@ +noisethreader@ +@no-bats +antibat@ +illage-and-spell-age +origincore|起源核心* + +pet-connect|收容宠物* +heaven-destiny-moment|天命时刻* +industrial-foregoing-extra-upgrades|工业先锋:更多升级 (Industrial Foregoing: Extra Upgrades) +growableores-extension@|甘蔗转换机 (GrowableOres Extension) +oneiricconcept@|梦华构想 (OneiricConcept) +simelectricity +somnia-refreshed@ +terramoment|泰拉时刻 (TerraMoment) +miners-diary-beyond-village +biggerchathistory +unifier +compass-ribbon@ + +@elytra-hud +creeper-drops-tnt +visual-novel-framework@ +@experience-progress +yapping-tooltips@ +bird-nests@birdnest +tfc-purified-water +@exparticle|粒子扩展 (ExParticle) +@entity-render-disabler +quick-right-click@ +alchimiae-magicae@|炼金魔法师 (Alchimicae Magicae) +thaumic-forever +gregfluxology|GTCEu/GTM能源拓展* +create-crowns@ +@create-modular-tools +ae2-wireless-terminal-lts +@cme-is-bad|并发修改什么的不要鸭 (CME is Bad) +enchantment-harmony@|和谐相处的附魔书 (EnchantmentHarmony) +quick-refine|快捷锻刀* +rubinated-nether@|耀红下界* +cornucopia-bypizza573@cornucopiabypizza573|丰饶之角 (Cornucopia) +epic-fight-bow-tweak@ + +jjkutilities +crystal-chronicles@ + +water-particles-render-fix +ray-trace-library +delayed-thunder@ +book-and-quick-save@ +keybaordjs@keyboardjs +better-eating-mod@better-eating + +@heart-effects +@global-wind +botaniavisualizer + +manavisualizer +easierworldcreator@ewc +kubejs-diesel-generators@ +create-slugma@ +cobblemonrider@cobblemonrider1.5 +cobbledex@cobblemon-pokedex + +item-descriptions@ +item-production-lib + +connectedtexturesmod-backport +@litematica-printer-easyplace-extension|投影打印机 (Litematica-Printer-Easyplace-Extension) +elegant-architecture@|雅致画栋* +extended-workbench-reborn|扩展工作台重置版* + +@stans-deathshot +pathunderfencegates@ + +latiao-craft-2@|辣条工艺 2* +canned@ +mushroooms@ +tacz-compatibility +@baablu-natural-disasters +@tacz-tweaks +un-saddle +@item-landing-sound +rehooked@ + + + +better-night-vision@betternightvision|更好的夜视* + + + + + + + +vanilla-anvil-repair +tiered-depths +tooltip-tweaker +editableedibles@ + +@mcdr-command-fabric +betterbuilderswandsfix@ +pigzilla@ +pale-garden-backport@ +seasons-greetings@ +ex-nihilo-coloratus|无中生有:多彩 (Ex Nihilo: Coloratus) +granular-mob-griefing +@dashloader-portinglib-compat +fermiumbooter2mixinbooter +immersive-optimization@ + +tab-tweaks@tabtweaks +fermiumasm@ +mc-mods-mobs-out-of-the-pool +clipboardplus@clipboard +misty-world-unveiled +balkons-weaponmod-legacy@|更多武器:传承 (Balkon's WeaponMod: Legacy) +betterendforge-backport +epic-fight-mod-rapier-moveset-addon +legendary-warriors +scape-and-run-holiday@|逃逸:节日 (Scape and Run: Holiday) +crimson-steves-mutant-mobs@ + +tactical-imbuements +puppy-paws@ +ae2-mega-things +solar-flux-reboot +solar-flux-additions +anvil-cell-workbench +@ultimate-furnace +create-sifting-fabric@ +create-magics@ +@crypto +@polyfactory +buildcraft-legacy@legacy-buildcraft + +wither-storm-delight|风暴乐事* + +x1000-botania@1000x-botania +angel-ring-classic|天使指环经典版* + +better-animations-collection-revived-2 +scape-and-run-parasites-tweaker +scape-and-run-parasites-medical-addon +durability-overhaul@ +quick-hotkeys@quick_hotkeys +@alwayschristmasday|永远的圣诞节 (AlwaysChristmasDay) +@strongluck|强运 (StrongLuck) + +uncrafted@ +mcjtylib-refilmed@ +nanny@ +resource-library@ +resource-config-api@ +@threatengl +hybridfix@|混合修复 (HybridFix) +@disable-portal-checks +eat-eat-eat|吃吃吃* +@recipe-stages-js|配方阶段 (Recipe Stages JS) +create-morerecipes +portable-craft-bench +portable-tables@ptables +@flux-network-fork-neoforge +resource-backpacks@ +etherology@ +snackpirates-aeromancy-additions@aeromancy-additions +apothic-enchanting|神化附魔* +maidsoul-kitchen@|女仆厨房* +refinedtools@ +programmed-circuit-card@ +ae2-toogleable-view-cell@ae2-toggleable-viewcell|AE2可切换显示元件 (AE2 Toggleable ViewCell) +@cobblemon-armors +letmorefishlove@ +l_ender-s-delight@l_enders-cataclysm-delight +ofaw-of-faith-and-war-1237|信仰与战争1237 (Of Faith and War 1237) +lotmoresteves + +legendary-armory-zelda-mod@legendary-armory +hot-update-1-23-by-gt@hot-and-hotter +management-wanted@ +perception@ +fancy-vfx@ + +pretty-rain@ +alchemancy +flavorful +heavy-fallings@ +erudite-tweaks +keymap-presets@ +mekanism-no-thanks-nbt@ +@loot-beams-up +@tekst +ledger-databases@ +@enderman-death-silence +infectious-zombie-apocalypse +xiaoanfc@|小安的农业核心 (Xiaoan's Farming Core) +@enchant-golden-apple-reborn|附魔金苹果重生 (Enchant Golden Apple Reborn) +cursor-mod-reload@|自定义光标:重生 (Custom Cursor: Reload) + +celestial-overhaul|星月改革* +simple-faqi@|简单法器 (Simple FaQi) +redes-coins|Rede的硬币 (Rede's Coins) +@teleport-commands|传送指令 (Teleport Commands) +@generic-code-library +cosmeticarmours@ +ooo-jar@000.jar +spawner-tweaks +mob-brawlers +@transformhandlers +player-totem@ +@screenshot-uploader +cute-companions-ducks +loot-n-explore@ +epic-knights-ice-and-fire +medieval-origins-revival@ +construction-sticks@|建筑棒* +sophisticated-storage-in-motion@|精妙物流 (Sophisticated Storage in Motion) +imgur-display@ +extra-sponges@extrasponges|更多海绵* +more-wolf-armors@|更多狼铠* +not-enough-rocks@ +pedestal@ +@snowball-and-egg-knockback +forestry-worktable-display +accessorify@ +high-quality-crops|高品质作物* +immortal-enchantment@|不死附魔* +awesome-storage|魔法存储* +@wallpaper + +@modify-player-data +idcv@|ID冲突查看器 (ID Conflicts Viewer) +eaglemixins +kubejs-thermal-augments +@minopp + + + + +camera-anim@|相机大师* +mekanism-upgrades-reborn|通用机械升级突破:重生 (Mekanism Upgrades: Reborn) + +epic-fight-x-irons-spells-animation-fix@ +epic-fight-x-wings-reborn-animation-fix +ef-bs@battle_arts +alshanexs-familiars@ +feur-skyland@ +balkons-expansion + +ascendant-mobs@ +duarm|羽化盔甲 (DuArm) +bomd-addon +create-the-air-war@|机械动力:空战 (Create: The Air War) +bew76@ +block-swapper@ +@simplemap|简易地图 (SimpleMap) +@oneconfig +iron-chest-unofficial@|更多箱子非官方版* +notenoughids-unofficial-1-7-10@notenoughids-unofficial|增加ID上限非官方版 (NotEnoughIDs Unofficial) +@shutdown + +tornado-mod-classic@weather-and-tornadoes-classic|局部气候&风暴经典版 (Weather and Tornadoes Classic) +strange-berries@ +jeffs-cursed-walking-structures +terra-entity@|泰拉生物* +not-interested@ +@new-soviet + +gt5r +ragexs-nuclear-tech|Ragex的核科技 (Ragex's Nuclear Tech) +civcraft +create-springs-loaded +mekanism-the-factory-must-grow-compatibility@mekanism-tfmg-compat +cfm-refurbished-circuit-breaker +diving-bell-for-tfc + +piglin-safety-reburn|猪灵 多喝岩浆:重生 (Piglin Safety: Reburn) +papers-please|请出示证件 (Papers, Please) +the-twilight-forest-unofficial@|暮色森林非官方版* +somnia-awoken-gui-beautify|梦醒时分 - GUI美化 (Somnia Awoken - GUI Beautify) +redstonecraft@redstonecrafts|红石工艺 (RedStoneCraft) +mowzies-mobs-baubles|Mowzie 的生物饰品 (Mowzie's Mobs' Baubles) + + +dungeons-and-combat +@blossomlib +mod-erate-loading-screen-forge@ +fastquit-forge@ +ingame-info-reborn|游戏信息显示复兴版 (InGame Info Reborn) +@overlay-mod +bedisnottoofarawayrefoxed|就要睡觉 (Bed Is Not Too Far Away Refoxed) +goopreforged@ + +@crimes-against-the-jvm +better-split-stack +sdm-engine-core@sdm-core +sdm-stages@sdm-gamestages + + +huh-fabric@huh|哼? (Huh?) +@acme-admin-tools +custom-nausea@¨custom-nausea-fabric +accesstransformerjs + +checklist + + + + +puncher@ +sensible-stackables +rei-addons-ic2classic +@blossomtpa +@lithium-raycast-fix +@yet-another-minecraft-bingo +tools-attack|工具也横扫!* +darkster-epic-guns-tacz-epicfight +epic-tweaks@ +epic-fight-x-gliders + + +familiar-faces@ +eyes-in-the-dark + +jellyfishing-delight@|抓水母乐事* + +carrot-rarity@ +more-husbandry +chest-with-legs@ +biodiverse@ +railway-wires +bullseye|靶心* + + +create-mob-spawners@ +salvation-archives-lobotomy +rlcraft-parasited +dregora-rl +underneath +@leaf-me-alone +rocket-mons@rocket-mons-cobblemon +farsighted-mobs@ +@hev-suit-voice-system¨@h.e.v-suit-voice-system +astral-sorcery-anti-anti-fake-player-asaafp@astral-sorcery-anti-anti-fake-player +apotheosis-ascended@ +@better-than-wolves-legacy-unofficial +warium@ +@ait_plus +fabulous-fletching +universal-wrench@ +@bottle-ship|瓶中船 (Bottle Ship) +smallblueslimes-ladders +doomsday-decoration|末日装饰* +overclocked-watches@ +portable-wardrobes-easy-armor-swap + + + +eternalappetite@|永恒食欲 (Eternal Appetite) + +platform@ +wandering-cocoa@|流浪的可可豆* + +no-more-potion-particles@ +larion-world-generation@larion-worldgen +blueprint-texture-issue-fix +transparentcapespatch@|透明披风修复 (TransparentCapesPatch) + + +saltyfish-vehicle@ + +tacz-leawinds-third-person-compat@ + + +gtmaid|血汗工厂 (GTMaid) + +@damage-tilt-fix +illager-raid-music@ +@apron +@coordinated-compass +prinegorerouse|尼格洛兹·旧日重铸/尼格洛兹·万神重归* +feur-extension-desert@ +scape-and-run-parasites-quark@|逃逸:疫染夸克 (Scape and Run: Parasites Quark) +infested-swarms-and-spiders@ +integrated-cataclysm + + + + +@searchworldenhance +colonies-maid-citizen@|殖民地女仆市民* +relictium@ +royal-city-gladiolus-sweep|王城剑兰-清理* +@inventory-blur +personal-cloud-storage@|个人云存储* +floral-herb-blade|花草世界/花草剑* +@omni-mobs +@him +steve-anomaly@the-anomaly +integrated-simply-swords +obsidian-equipment@ + + + +the-deep-void@(mortius)-the-deep-void + +cataclysm-incinerators-try-hard@incinerators-try-hard|灾变:武器技参数配置/冒火的剑 (Cataclysm: Weapon Skill Config/ Incinerator's Try Hard) +scp-apollyon-scp-apollyon +trickster@ +pale-garden +shulker-enchantments@ +xenotech@ +sewing-kit +zephyr@zephyr-mod +create-radars@|机械动力:雷达 (Create: Radars) +create-more-additions@ + + +minecart-turning-reforged@minecart-turning¨@minecart-turning-reforged +offlimits@ +apotheosis-threat +@string-duper-fix-remover +@superresolution|超分辨率 (Super Resolution) +special-model-loader@ +vs-ship-handler@ + + +dice-rebuild@ +lets-do-apple-wood@lets-do-addon-apple-wood +ascended-quark@ +enchanted-vertical-slabs@ +@better-ladders +would@|木韵自然* + +gendustry-community-edition@|基因工业:社区版 (Gendustry: Community Edition) +ae2fix@|AE2修复 (AE2Fix) + + +betterenddelight@|更好的末地乐事 (BetterEndDelight) + +@spanish-delight-refabricated +crate-delight-croptopia@|装箱乐事:作物盛景 (Crate Delight: Croptopia) +foodspoiling@ +natura-legacy +pepsied-potted-farms + + + + + +riding-partners-reforged@riding-partnersreforged|双人骑行:重铸 (Riding Partners:Reforged) + +cat-healing +plumbob +@variants-cit + +@more-enchantments-soybeani-more-enchantments|豆浆更多附魔 (More Enchantments by Soybeani) + +@clearviews +@immersive_weapons_sounds +epic-fight-invincible@epic-fight-invincible-lib|无坚不摧 (Epic Fight - Invincible) +ore-dict-re-order +electrostatics +@radiocraft +evil-captcha@ + + + +fpsmatch@|通用射击游戏比赛框架 (FPSMatch) +mythic-charms@|神话护符* + + + +minecraft-add@|原版补充* +stacked-blocks@|捆扎方块* +stacked-blocks-farmers-delight@|捆扎方块:农夫乐事 (Stacked Blocks: Farmer's Delight) +fowlplay@ + +ender-totem +diversity@faewufs-diversity +tonsofenchants + + +cave-root + +whos-there-ghost-players@ +the-cuckoo-clock +final-samurai +classic-battle-towers@|经典战斗高塔* +sihywtcamd-extensions@difficulty-extensions + +@heart-crystals +partialhearts@ +@the-abyss-runtime +cosy-critters@ +omnilib@ +astages +@aloria-loading +@parentalcontrols +jason-bot|Jason机器人* + +fly-in-the-sky|高空飞行 (Fly in the sky) +@smartelytra|智能鞘翅 (SmartElytra) +momotinker|墨工坊 (momotinker) +electrostaticsre|每日任务 (ElectrostaticsRE) + +brooms-unofficial|扫帚:非官方版* +fishing-dangers +distinctpaintings@ +@search-on-mcmod|MC百科搜索 (Search on MCMOD) +infinite-lava-renewed +@better-fabric-console|更好的 Fabric 控制台 (Better Fabric Console) +mine-tooltips +fastchest-reforged@ +@better-caves-archaic|古早洞穴优化 (Better Caves Archaic) + +alexis-64-food +cosmetic-armor-revitalized-fabric@ +@ambience-v2 +umapyoi-addon-pack@umapyoi-addon|马儿蹦跳:拓展包 (Umapyoi:Addon Pack) +the-god-of-roadkill +@visual-snowy-leaves +verdant@verdant-mod|葱茏绿意* +grounded@ +gallery@mod + +lost-cities-survive-the-dead-edition + + +power-of-the-void|虚空之力 (Power of the Void) +aerlune-rpg + +hitboxbackport@ +fsmm@ +create-pantographs-and-wires@ +footwork-api@footwork +@halplibe +warmachinelib@|战争机器库 (WarMachineLib) + +crash-assistant@|崩溃助手* + + +inventorytweak@|库存调整 (InventoryTweak) +@miss +legendary-tabs|传说选项卡* +sky-breaker-blue-skies-limit-remover-1-18-2|天穹突破_1.18.2 (Sky Breaker_1.18.2) + + + + +@mxa-tools|MX的工具A (MXA Tools) +cloudertinker|浮云工坊 (Clouder Tinker) +xiyus-lucky-block|饩雨的幸运方块 (Xiyu's Lucky Block) +@epicfight_oldsolar|史诗战斗:旧版solar (EpicFight_oldsolar) +reskillable-reimagined +renaissance-core@ +@startup-chime|启动音效 (Startup Chime) +carpet-takeneko-addition@tnca|竹猫的地毯扩展* +chain-mod +speedrunmod +insta-boom +infinite-night +nether-lake +@create-cards +create-powerlines +emerald-nugget +what-dah-dog-doin-tetra-compat +endbiome +jasons-fly-mod +conium@ +yellowtext@ + +healight@ +@body-health-system +savemykeybinds@ +nomenublur@ + +more-loot-tables@ +noteblocks +@crunchy-crunchy-advancements +chainvein@ +mobs-on-rails@ +@no-ones-view-model +gravestone-x-curios-api-compat@ +nolijium@ +eventslib +etst-lib|乙硫醇的匠魂词条库 (EtST Lib)¨@etstlib|乙硫醇的匠魂词条库 (EtST Lib) - 更新可能较慢 +orbs-of-crafting +@leonmtrmod|Leon轨道交通Mod + + + + + +whatimpressing@|正击何键 (What I'm Pressing) + + +stackcraft@ +@extremeview +@materialexcavator +@startinthenether +mekanismmixinhelp +simple-warp-commands|简单传送指令 (Simple warp commands) +@mojangfix +tatercart@ +irons-spell-book-mob-attribute-addon +epic-fightexsilium-gladius|EpicFight—放逐之刃 (Epic Fight — Exsilium Gladius) +kamenriderweaponcraft@|假面骑士武器大全集 (KamenRiderWeaponCraft) + +advancearmy@|先遣部队 (Advance Army) +@blood-blade +@mineimpact|方神 (MineImpact) +jadens-nether-expansion-delight@ + +archery-expansion@ +jjsk + +@so-crazy-try|趣亦合成 (So Crazy Try) +ash-of-sin-overlord|罪业余烬:不死者之王 (Ash Of Sin: Overlord) +carbon-strip-craft-augmented-edition@|碳条工艺:加强版 (Carbon Strip Craft:Augmented Edition) +@ripples-of-the-past-bad-company-addon|RotP:极恶中队附属 (Ripples of the Past: Bad Company Addon) +true-prime-piece +maxims-core|箴言与本源 (Maxims&Core) +arphex@ +cubic-combat-simulator + +webmapview@|网页地图浏览 (webmapview) +f3-is-my-shawty +ollamachat@ +potion-stacker +@betterweather +better-gamemode +better-command +fishermans-haven@ +bakeries@bakeries-renyigesai|烘焙坊* + +female-plastic-surgery-bust-limit-tweaker + +feur-pet-hat-forge@feur-pet-hat +feur-dimensional-skyland@ +feur-colors@ +feur-statue@ +feur-builder@ +feur-elytra-wings@ +feur-magic-more-enchantments-xp-bottle-forge@feur-magic +veggies-delight@|蔬菜乐事* + +ramadan-delight@|斋月乐事* + + +potion-core-reborn|药水核心:重生* + +rolling-gate@|卷帘门* +bettertab@better-tab|更好的Tab (BetterTab) +let-me-see-see-your-code@let-me-see-see-(your-code)|让我看看 (LetMeSeeSee(YourCode)) +put-mana-in|手充魔力* +ars-botania + +baublesex +custom-block-highlight@|自定义方块高亮* +tinkers-simple +threedmusket +rtmmetro|真实火车:地铁扩展 (RTMMetro) + + + +lobotomy +parrot-power +fortune-ores-2 + + +feur-dungeon-spawner@ +feur-extension-fossil@ +feur-extension-jungle@ +cybernetic-system|赛博系统* + + +liquid-dirt +liquid-blocks@ +apothic-combat@ +toms-trading-network@ +somanyapples|超多苹果 (So Many Apples) +static-block +cherryvillage +ductwork@|管道* +cooldown-coordinator@ +librarianlib-continuous@ +luna@ +loot-integrations +realtimescale + +crafting-recipe-exporter + +extra-apoth-compat +pathtracker@ +elytra-protection +skip-sleep +stony-cliffs-are-cool +simple-ender-things +mimecraft-mod +warden-sword +arch-bows@ +fancy-trinkets@|精美的小饰品* +block-n-zapping@ +cgs@ +dynamic-trees-jadens +dynamic-trees-croptopia-new@dynamic-trees-croptopia +stacksonstacks +more-of-all@ + + +chiikawa|吉伊卡哇* +tolkien-tweaks +tolkien-tweaks-mobs-edition +soulplied-energistics +valarian-conquest@ +mowzies-mobs-respawner +crafting-station-jei-edition@|合成站:JEI版 (Crafting Station: JEI Edition) +more-waterlogging +the-ancient-trinkets-index@ +straw-golem-rebaled-ported@ +haybale-1-20-1@haybale-ported +gtbcs-spelllib +haybale@ + +creative-eating-reforged|创造也能吃* +@better-mod-list-button-fix|Better ModList 按钮修复 (Better Mod List Button Fix) +krypton-foxified@|氪 NeoForge 版* +proximity-text-chat@ +justleveling-fork@ + +redirected@ +asynchronous-reprojection@ +not-enough-keybinds@ +daily-deliveries@ +vehicular-movement-light +vehicular-movement +onysdvehicles@onysd-vehicles + +zunpet-forge|Zun号非官方NeoForge/Forge版 (ZUNPet NeoForge/Forge) +more-hitboxes@|更多碰撞箱* + +shipwreck-fix|沉船修复/沉船卡顿优化* + +narcissus-farewell|水仙辞* +mcmod-splash-plus-plus|百科闪烁标语++ (MCMod Splashes PlusPlus) - 部分常用¨@mcmod-splashes-plusplus|百科闪烁标语++ (MCMod Splashes PlusPlus) - 全 +random-enchants-2|随机附魔 2* +sparkle-reforge@|火花:重铸 (Sparkle: Reforge) +led-lighting +not-enough-stuff +iron-fence +bricks +additional-records +firefly-bush +spring-update-snapshot-to-old-versions +@godot-signal-system-lib + +leons-minecraft-dungeons-paintings-mod +miscellaneous-additions@ +rupters-figure-mod-doors +sophisticated-backpack-storage-emerald-upgrade@sophisticated-backpackstorage-emerald-upgrade +sophisticatedinjections@ +immortalers-delight@|千古乐事* + +createnuclear@|机械动力:原子核动 (Create Nuclear) +keepthatinventoryopen@ +falcons-single-person-sleep +realisticsleep + +avaritia-1-1x-unofficial|无尽贪婪 1.1x 非官方延续版 (Avaritia 1.1x Unofficial Extended Life) +lightsaberx +prime-punch-one-punch-mod +rpgmana¨arch-rpgmana@ +opposite-dimensions +migamigos +@cloudmusicroom|云音乐房间 / 服内一起听音乐与点歌 (CloudMusicRoom) +theonesmeagle +witchery-companion@ +@tpa-utilities +@maplink + +addonslib@ +siliconedolls@silicone-dolls|硅胶玩偶 (SiliconeDolls) +@authshield|认证防护 (AuthShield) + +redstone-armoury-minus-thermal +elytras-plus +ae2uel-wireless-universal-terminal|无线通用终端 (AE2UEL Wireless Universal Terminal) +presents +create-picky-waterwheels@create-picky-wheels + +@green-screen +fancy-lamps +resizing-potion +miku +advanced-smelter@|荒古炼金炉 (Advanced Alchemical Furnace) +extended-tinker|匠魂扩张* + + +bedsheet@|床单 (BedSheet) +despawn-tweaks@ +planetguylib +@fabric-kotlin-extensions +crafting-table-plus@ +@replay-export +@loot4everyone +containerfix +cool-rain@coolrain +queqiao|鹊桥 (QueQiao) +lexikon@ + +idmid@ +simple-concrete@ +chunk-activity-tracker@ +lets-do-lilis-lucky-lures@ +craftformers-prime@ +@pumpkinmoon +@vbe +arts-by-kev-mod-2023@ +the-lion-king-mod +epic-terrain-compatible|史诗地形兼容版* +the-beginning +create-simple-ore-doubling@ +create-low-heated@ +planetguy_gizmos +@thirdpersonfix-babric +@retrocommands +@mana-peeper +retro-sophisticated-backpacks|复古精妙背包* +grid@ +emienchants@ +random-complement|随意补充 (RandomComplement) +thedulling +batsword +unidye@ +obs-overlay@ + +cwhitelist@ + +raw-mouse-input-blessed-edition@|原始鼠标输入 - 祝福版 (Raw Mouse Input - Blessed Edition) + +@hidetags +grass-kiss@ +attack-through-grass@ +structurify@ +netherite-beacons-forge@netherite-beacons¨netherite-beacons +esoteric-reforging-forge +dimensional-leap@ +replant-it@replant-it! +trail-tales-delight@trailtales-delight|樱途旅事 (Trail&Tales Delight) +pams-harvestcraft-2-fantasy +alexs-caves-rad-fork@ +hongbao-red-envelope@red-envelope|红包 (HongBao: Red Envelope) + +sortilege@ + +lazymodder + + +minecraft-skill-tree +skill-tree-mod + + +easy-shulker-access +@ysbb|森罗物语 (Kaleidoscope Mod) +torch-slabs-renewed|更好的火把放置重制版* + +wormhole-artifact@ + + + + +create-diamond-factory@ +create-realism@ +create-sound-of-steam@ + +big-explosives@ +ice-cream-creepers +aquatic-craft +village-taverns@|乡村酒馆* +f-a-rebirth-and-expand-genesis +fossils-archeology-origins@fossilsarchaeology-origins|考古与化石:起源 (Fossils & Archeology Origins) +faunify@ + +wills-hedgehogs +cryptography@metaphysics +@spasm +sketch@ +@envirosoundbeta +@keybindsgaloreplus + +@smoothbeta +no-fall +@kyoyu|共有 (Kyoyu) +scopic +memory-leak-fix-unofficial-remastered +@distance-traveled-calculation + +valkyrien-skies-control-craft@control-craft|控制学 (Control Craft) +reforbidden-magic@|禁忌魔法:重生 (ReForbidden Magic) +moses-mod +craftable-animals|可合成动物* +avaritia-1-1x-kedition +@more_avaritia|更多无尽物品 (MoreAvaritia) +the-block-box@|方块百宝箱* +the-dirtbike-mod +ore-seeds + +mana-visualizer +custom-tnt-igniter + + + +jaiz@jaizmod +harder-illage-and-spillage +dagercraft@|旧超神之路 (DagerCraft) +@deus-ex-minecraft-s-conspiracy|杀出重围 (Deus Ex Minecraft's Conspiracy) +thaumic-staff|神秘法杖* +thaumic-bases-mystical-rose-rework|神秘基础学玫瑰重制* +rhyme-pvz@|PVZ:润 (Rhyme PVZ) +ichorium-kit +reforgotten-relics@|失落遗物学:重生 (ReForgotten Relics) +in-your-world@ +warpapocalypse@warp-apocalypse + +arcane-arteries-kedition|奥法献祭学非官方版* +thaumic-tinkerer-unofficial@|神秘工匠非官方版* + +asyncparticles@|异步粒子 (AsyncParticles) +@dragonfly-model-library +@terrainapi +mnmutils +betterend-elytra-fix@ +player-swap +@configurable-everything +no-hearts-ui@ + + +old-loading-progress-bar@|旧版加载进度条* +raw-tp-chat-command@raw-tp-chat-cmd +@waterplayer +@home-utilities +multiplayer-button@ + +@kelui +brick-lib +@no-slow-motion|无拘速行 (No Slow Motion) +@minecartsloadchunks +guideme@ +neoculus@ +chatwithmobs|与生物聊天 (ChatWithMobs) +@kiss-mod +extra-armor-info@ +feature-recycler@ +ore-hammer@ + +exp-chest +sophisticated-backpack-allthemodium-tier +sophisticated-storage-allthemodium-tier +the-amazing-world-of-mobs-renovated@theamazingworldofmobs +ash-of-sin-tempest|罪业余烬:特恩佩斯特 (Ash Of Sin: Tempest) + +@cauldronfix|铁锅工艺 (Cauldronfix) +spelunker@ +lil-tater-reloaded@ltr +no-modern-industrialization-efficiency +@emitechreborn +@better-mipmaps +showmyskin@ +rhizo +deimos-fabric-forge-neoforge@deimos + +excavation|挖掘* +basic-end-ores|基础末地矿石* +@portable-crafting + +simple-bbq-unofficial|简易烧烤非官方版 (Simple BBQ Unofficial) + +eggy-goodness +@slide-show-pro|幻灯片:增强 (Slide Show Pro) +alternative-twilight@alternative_twilight|暮色:另类* + + +pepsied-item-glow +create-bigger-storage@ +tacz-create + +terrific-trash-cans + +colourful_portals_mod +gud_coolers +suppergerrie2s-drone-mod +data-essence@ + +nautec@|海蓝科技 (NauTec) + +thorny-bush-protection@ +gudlib +reflex-antilag@ +tfc-nei + +nolan +@repeater-sound +audio-hotkeys@ +voicechat-soundboard@ +@the-moon-bta +ftb-ocean-mobs +fake-ores + +@mystical +crackedzombie + +error-404-not-found-horror-entity@error-404-not-found +amelet-totem + + +tbone +fastfurnace-decreased|熔炉性能优化-- (FastFurnace--) + +@cdnperspective3d +@volume-fix +chorus-fruit-drops-nearby@|紫颂果集中掉落* +better-first-aid-visual +tpms@|传送命令·简 (Teleport Master Simplified) +@scoreboard-overhaul + +tensura-mysticism@ +furnection@lyivxs-furniture|LYIVX的家具* +@colourful-portals-reimagined + +craft-of-the-wild-cotw +piglands-mod +vanilla-extension +floating-items-mod-datapack +butterfly-mania +@rensumo_enchanted_books_addition|Rensumo 的附魔书附加包 (Rensumo Enchanted Books Addition) +kbi-mmd +sowdispenser +metalchests +jumppad +obsidian-boat|黑曜石船* +moderner-beta@ +the-animals-plus +create-fluid-stuffs|机械动力:流体附加 (Create:Fluid Stuffs) +create-goggle-placement-lieonlion@ +minecraft-multi-purpose-mod +kubeloader@ +updatefixerupper +configurable-data-fixers@ +lenient-death@ +short-circuit@ +tensura-kumodesu +tinkers-advanced@|前沿匠艺系列 (Tinkers' Advanced) - 前沿匠艺-拆分前¨tinkers-advanced-core@|前沿匠艺系列 (Tinkers' Advanced) - 前沿匠艺-核心¨tinkers-advanced-materials@|前沿匠艺系列 (Tinkers' Advanced) - 前沿匠艺-材料¨tinkers-advanced-tools|前沿匠艺系列 (Tinkers' Advanced) - 前沿匠艺-工具¨tinkers-advanced-utilities|前沿匠艺系列 (Tinkers' Advanced) - 前沿匠艺-实用 +more-structure-processors@ +quick-stack-to-nearby-chests@quickstack|快速堆叠 (QuickStack / Quick Stack To Nearby Chests) + +@kallfix +yggdrasilproxy@yggdrasil-proxy + +thaumic-meme|神秘吐槽* +starlightxae|星光xAE2修复 (StarlightxAE) + +@levelclear +@drops-into-shulker +ftb-team-dimensions +epicfight-resurrection|史诗战斗-重生 (EpicFight : Resurrection) +epic-fight-dual-axes +epic-fight-dual-spears +realistic-fire-spread@ +palehell +elainasbroom|伊蕾娜的扫帚 (Elaina's Broom) +extinction-z@ +pomkots-mechs@ + +replication@ +better-sugar-cane|更好的甘蔗* +apogee@ +btrultima-tensura +dragon-block-c-additions +twilight-forest-final-boss +generations-structures@ +oceanic-realms +zoomers-extended-apotheosis +the-god@ +relics-rpg@ +macaws-quark@ +macaws-sajevius@ +macaws-biomes-o-plenty@ + + + +macaws-modding-legacy@ +fancy-spawn-eggs + + + +@no-more-serverconfig|不再有服务器配置 (NoMoreServerconfig) +@queryinfo +ftb-pause-menu-api + +modifyjs@ +@bettershields|更好的盾牌 (BetterShields) +@better-selection + +ytgld-better-beacon@better-ytgld-orb-beacon|亚特格拉德的信标 (Ytgld : Better Beacon) +colorfultools +colorful-armor +ibench +crafting-table-on-a-stick|手持工作台 (Crafting Table on a Stick) + +villager-anti-doors +liquipacks +create-advanced-crafting +create-stone-generators@ +create-cold-sweat@|机械动力:冷汗 (Create: Cold Sweat) +another-unbreakable-enchantment@ +passive-piglins +void-miners +gwycraft-a-colored-blocks-mod +creative-sandbox|创造沙盒* +signboard-preview@|告示牌预览 (SignBoard Preview) + +hexoverpowered@ +hexflow@ + +@chihayaannos-steel-sheet|MyGO!!!!!:千早爱音的前置装甲方案 (Chihaya Anno's steel sheet) +moremekasuitmodules|更多 MekaSuit 模块 (MoreMekaSuitModules) +eternal-attributes@ + +easy-pickings +relics-in-chaos@relic-in-chaos +archers-expansion@ +witcher-rpg-class@ +forcemaster-rpg-class@ +death-knights@ + +immersive-slumber@|沉浸睡眠 (ImmersivelySleep) +bountifulbaubles-reforked@bountifulbaublesreforked|丰富的饰品:重铸 (BountifulBaubles:Reforked) +@anvil-uses|铁砧使用次数显示 (Anvil Uses) +@lucidity-mod|我的视界 (Lucidity) +@mekanismmoremodules|通用机械:更多单元 (Mekanism: More Modules) +@better-armor-swap + +the-man-from-the-shadow@the-man-from-the-shadow-(horror) + + + + +arcanmira +comparties-reborn|组队兼容:重生* +tape-stop@|停碟* +persistent-inventory-search@ +@no-multiplayer-menu +@litematica-enderchest-materials +@mob-protect +only-bags@ +the-broken-script-official@the-broken-script +torojimas-buildhelper@torojima_s_buildhelper +expanded-armory-legacy@|扩展装备:传承 (Expanded Armory: Legacy) +loquat-forge@loquat¨loquat +@waterbeds +@customhealthhud +@fix-horizontal-camera-lag +create-cyber-goggles@|机械动力:赛博护目镜 (Create: Cyber Goggles) +mekanism-elements|通用机械:元素* +bots-lib@ + +botaniaoverpowered@ +@simple_no_survival|蓟县生存 (Simple ? Survival) + + +auto-pillar-generator@|一键柱子生成* +vanilla-delight@vanilla-delights +jade-vs@ + +vics-modern-warfare-patched|维克的现代战争(修复版) (Vic's Modern Warfare (Patched)) +waterframesbackported + +tweakeroo-update-port +xkballs-auto-translate@|xkball的自动汉化 (xkball's Auto Translate) + +block-replacement-mc1-7-10 +@mekanismqq + +confluence@|汇流来世 (Confluence: Otherworld) + + +@trinkets-client-optional +data-packs-helper|数据包助手* +@gokiskills|技能专精 (GokiSkills) + +tconstructjs|有头脑的工匠 (TConstructJs) +maid-storage-manager@|女仆仓管* +@mystias_izakaya|夜雀食堂 (Mystia's Izakaya) +lush-scented-paradise|芬芳茶园* + +hold-my-items@ +achievement-extreme +advancement-extreme +recipe-machine-stages-zs-js +configurable-keepinventory +better-chat@betterchat +mekalus-oculus-fork-with-fixed-mekanism-mekasuit +view-emc +fortitude@ +experience-ore|经验矿石* +passive-torch +productive-metalworks +better-leveling-respawn|更好的升级:重铸 (Better Leveling: Reforge) +drive-by-wire@|线缆控制 (Drive-By-Wire) +spirit-of-fight@|战魂 (Spirit of Fight) +grim-bleak@grim-and-bleak +carrymyboss +ranged-damage-limit|远域挡招/远程伤害保护* +magichem|魔法炼金 (MagiChem) +iglee-library@ +component-model-hider + +@dont-cut-tripwire +extra-achievements +keybindjs@ +@autototem +@totem-cooldown +sound-physics-legacy|物理声效:遗产* +astatine|砹* + +marblegates-exotic-enchantment-reborn@marblegates-exotic-enchantment-flowing-agony-reborn|白门的奇异附魔:苦痛长河:重生 (MarbleGate's Exotic Enchantment: Flowing Agony: Reborn) + +@beta-1.7.3-music-discs +@spawn-eggs|刷怪蛋 (Spawn Eggs) + +create-waystones-recipes@ +mekanistic-routers@ +just-healerblock +ftb-stuff-things +infinibows +tacz-labs@ +@mineshock-cybernightmare|网络奇兵 (MineSHOCK: CyberNightmare) +make-a-wish +archaeological-research-exploration@archaeological_research_exploration|考古研究:探寻 (Archaeological Research:Exploration) +forgotten-nunchakus +create-big-cannons-advanced-technologies@|机械动力火炮:先进技术 (Create Big Cannons: Advanced Technologies) +quality-food@ +snekcraft@ +hearth-and-harvest@|暖灶丰年 (Hearth and Harvest) + + + +wjys|无尽药水 (WJYS) +schematicpreview@|原理图预览 (SchematicPreview) + +@collect-emerald|聚灵石 (Collect Emerald) +sakura-tinker|魂樱工匠* +@appspec +heart-crystal|心之水晶* +default-skin@ +letyourfriendeating@let-your-friend-eating!|让你的朋友吃! (Let Your Friend Eating!) + +ftb-jei-extras +shader-reload@ +simple-menu@ +@asahi +keybindspurger@ +iguana-lib@ +map-making-tools|地图制作工具* + +turkeyutil +drcyanos-wonderful-wands-wizarding-robes +dragon-survival-griffin-addon +rpg-skillpower@rpgsp +unknown-null +slime-origin +@slime-origin +slime-origin-remastered@slimeorigin +alchemy-kingdom|炼金王国* +tcondiadema|匠魂领域 (TconDiadema) + + +tome-of-knowledge-sharing + + + + + + +archers-helicopter@|阿辰的直升机 (Archer's Helicopter) +fels-machine-guns-wwi +fels-machine-guns-wwii +steamatic-locomotion +dungeon-revival +new-order +create-more-recipes-addon@ +cbc-nuclear@ +smarter-zombies@smart-zombies + + +libguifoxified@ + +valkyrien-relogs@ +@section-31|简单监控 (Section 31) +chatalert +aaa-particles-world@ +pick-up-tnt@ +ymadditions@ +immersive-machinery@ +xp-synthesiser@ +oredictionaryconverter +cbc-modern-warfare@cbcmodernwarfare|机械动力火炮:现代战争 (CBC: Modern Warfare) +shulker-charm@ +villager-license|村民证件* +description-tags +harvestwithdispenser +sound-physics-fabric|物理声效 Fabric 版* +cleanroom-relauncher@ +fast-item-frames@ +hammering@ +vanity-elementals +fmprojecte-advanced-alchemy-fmpeaa +peex +animal-origins@ +narutoto-ninja-world +the-ender-scrolls-skyrimcraft-the-revival@the-ender-scrolls-skyrimcraft|末影卷轴 - 天际工艺 (The Ender Scrolls - Skyrimcraft) +kingdom-of-rin-mobs +scape-and-run-parasites-mutant-beasts|逃逸:寄染突变体 (Scape and Run: Parasites Mutant Beasts) +alexscavesexemplified@alexs-caves-exemplified +akutolib +@glass-networking +@always-more-items +@mostlymodernrecipes-stationapi +toomuchloot +toomuchtime +cs2-box|CS2箱子 (CS2 Box) +edit-mob-drops@ + +tea-aroma@|茶香* + + + +overpowered-inventory +bbrains-umfixes + +foodstats@|食物增强 (foodstats) +hxchud +sorted-enchantments@|排序附魔* +assassins-creed-parkour-mod|刺客信条跑酷 (Assassin's Creed Parkour Mod) +critter-armory@ +the-harvest +better-minoshroomtaur|Better 米诺菇* +moobloom|哞菇与哞花 (Mooblooms and Mooshrooms) +mooblooms-and-mooshrooms-bop-edition|哞菇与哞花BoP版 (Mooblooms and Mooshrooms (BoP Edition)) +the-pure-suffering-mod +dooglamoo-jr-archaeology|Dooglamoo 的考古学 (Dooglamoo Jr. Archaeology) +legionary +voiceless-survival@|寂静求生* +fabulous-blades@fabulous-blade + +prism-plan|棱镜计划* +ae2cc-bridge@ae2cc +ae2-mousetweaks-fix@ +ae2-qol-recipes@ +cyberspace@ + +displayed@|展示 (Display) +engineered-compatibility@ +create-abyss-catalysis@createabysscatalysis|机械动力:深渊催化 (Create: AbyssCatalysis) + +@worlddownloaderlegacy|世界下载器旧版 Forge (WorldDownloaderLegacy) +level-up-rpg-skills-more + +@creeper-healing +render-control|渲染控制* +chemical-tweaker +health-bar +see-the-rarities-str|查看稀有度 (See The Rarities) +craftpilot@ +@game-of-reborn|复活赛 (Game of Reborn) +rough-blade|无锋道* +@dota.rg +@appledog|苹狗 (Appledog) +superb-warfare@|卓越前线* + +aetherworks-extended-life@aetherworks-unofficial-extended-life +pomkots-mechs-extension-pack@ +@monkey-utils +some-more-blocks@ + +projecte-advanced-alchemy +nff-girls-grimoire-of-gaia-extension|NFF: Girls - 盖亚魔典扩展 (NFF: Girls - Grimoire of Gaia Extension) +replicore@|复制核心 (RepliCore) +create-reforged-foundations@ + +@jgfe|我踏马吃吃吃! (Just Go Fxxking Eat) +better-experience@better-experience-of-confluence|更好的体验* + +thdilos-fox-origin@|ThDilos的狐狸起源 (ThDilos Fox Origin) +narutofix@|火影修复 (NarutoFix) +sbr-i-need-more-enchantment@slashblade-resharped-i-need-more-enchantment|重锋:施魔更哥 (SlashBlade Resharped: I need more Enchantment!!!) +configurable-health|可配置的生命值* +create-better-fps@createbetterfps +create-security-program@ +furnies@ +cobblefurnies@ +thdilos-fox-origin-expanded@|ThDilos的狐狸起源拓展 (ThDilos Fox Origin Expanded) +potion-sauce@ +copious-dogs-reforged +@slot-customization-api +hqm-keybind@ +zoomer-simple-zoom + +curioenchantment|饰品附魔 (CurioEnchantment) +wall-jump-continuation +armor-stand-shift-swap@ +moveui-forged@ +harvest-level-config +brewing-helper@ +theatrical@ +etlib|淬火煉刀通用库 (Emberthral) + +tacz-addon@taczaddon +@heartcanister|心之容器 (Heart Canisters) +gunswithoutroses-expansions@gunswithoutrosesexpansion-s|枪炮“没”瑰:扩展 (Guns Without Roses : Expansions) +ati-structures-datapack-vanilla +create-backpack-pixel|机素背包 (Create: Backpack Pixel) +crazy-alloy +spellbound-enchantments@spellbound + + +ultramarine-rekindled|群青:重明* +fortunas-anvil +create-deep-dark@ +create-ranged@ +create-enlightend@ +create-winery@ +create-filters-anywhere@ +create-cheese@ +create-copper-zinc@ +create-ultimate-factory@ + +lyivxs-core@ +exclusions-lib@ +json-paintings@ +keybind-unconflict@ +apothic-compats +apothic-materials +pepsied-easy-multi-item-sorter +tetra-apotheosis-fix@ +ron-timer +empty-air-bubbles +bundles-throw-potions +ftb-team-bases +raworesmelting@ +dpt@ +potion-effect-enchantment +mythical-origins +assorted-armaments@|百般武艺* + +spanksters-craft +heavenlyabyss +slashblade-twin-attack|拔刀剑:连携攻击 (SlashBlade Twin Attack) +dungeon-crawl-dimensional-patch +apothic-supplementaries-enchanting +apothic-amendments-enchanting +apothic-mutant-heads +apothic-science-moa-stats +ye-gamol-chattels-reborn@ + + +mme@my-more-enchantments|我的更多附魔 (My More Enchantments) +@some-little-enchant|一些小附魔 (Some Little Enchant) +minepulse@|一脉相挖 (Mine Pulse) + + +trinkets-and-baubles-reforked@|饰品与小玩意:重铸 (Trinkets and Baubles Reforked) +@mace_expand|绵阳的重锤拓展 (SunSheep's MaceExpand) + +astral-dimensions-create-compats +cbc-more-shells@|机械动力火炮:武器拓展 (CBC Military Supplement) +create-tools-n-weapons +create-factory-logistics@create_factory_logistics|机械动力:流体物流* +wiidudes-custom-origin-mod@wiidudes-custom-origins +wolfkin-origin@ +horrorgins@ + +aspects-origins-addon@aspects +@origins-minus +hapi-pillager@ +@stop-picking +pepsied-super-hopper +pepsied-item-catcher +pepsied-auto-harvest +@bulk-compost +centered-item-frames@|物品展示框居中* +undergarden-botany-pots-compats + + +bbl-flight-blocks@ +mjs-raw-ores +create-gunpowder-crafting +luminax@ +cable-facades@ +ezstorage-new@ezstorage|简易存储 (Simple Storage) +@tmwin|问君何所需 (TellMeWhatINeed) +elrols-gui-elevator +backrooms-found-footage@minecraft-found-footage +exposure-polaroid@ +surpass@|超限* +fallingalchemy|坠落炼金 (FallingAlchemy) + +fluxloading@ +inventory-swapping@ +seamless-trading@ +sophisticated-auto-walk +mmmmmmmmmmmmpatch|试验假人补丁 (MmmMmmMmmMmmPatch) +global-datapacks@datapacks +world-guard@ +more-murphy-pumpkins|更多南瓜 (morepumpkins) +tetradelight + + +heroes-of-might-and-magic-3@ +another-changed +randomly-tp|随意传送 (Freely/Randomly TP) +illager-war-trireme + +hominid +anvians-lib@ +@creo-api +amblekit@ + +nocubes-better-fletching-table +better-fletching-table@|更好的制箭台* +jsconfig@jsconf +@lightspeed-boat|光速船 (Lightspeed Boat) +nomissingmods +urban-decor@ +nospawnzone +keybind-bundles@ + +cloudflared@ +@aikoyori-tweaks +flowingfluidfixer +absolutely-stuffed-uncapped-hunger-saturation +gluttony-oversaturation-overeat +overeat +oversaturation + +etheria@ + +legends-of-slugterra@ +gussdx-decoration + +projectiles@ +space-patrol-delta +@neomtr|纸板箱特色我的世界铁路 (NeoMTR) +@contigency-contract-lite|轻量合约 (Contigency Contract Lite) +assorted-lib@ +taterlib@ + +nocapes@ +inventory-sorter-configurable@ +smartcursor|智能指针 (SmartCursor) +wither-spawn-animation@ +@boom-enchantment +prioritiser +engineered-schematics@ +@mojangfix-stationapi-edition +@nedologin + +@sprint-on-ctrl +kill-counter-kill-streak-announcer-mob-death|连杀计数 (Kill Counter) +calm-down-dog@ +keybinding-hider@|按键绑定隐藏器 (KeyBinding Hider) +darkerer@ +no-more-sleep-problems@ +configbackuper@ + + +inhrtburys-gilding|Inhrtbury 的镀金 (Inhrtbury's gilding) +@tree-miner|矿树节 (Tree Miner) +beyond-dimensions@beyonddimensions|超越维度* +throughput-quest|ME吞吐量检测任务* + +lord-of-the-rings-qualities-of-middle-earth|魔戒:中洲特质 (Lord of the Rings: Qualities of Middle-Earth) +lord-of-the-rings-qualities-of-middle-earth-1-7-10|魔戒-中洲特质:传承 (Lord of the Rings – Qualities of Middle-earth: Legacy) +happy-ghast-backported +happy-ghast-backport@happy-ghast +snowy-tents@ +nuhayuponosiks-bosses +goety-cataclysm@|诡厄灾变* +cave-delight@|洞穴乐事* +@forkcart +silentgear-compat +timeless-ivy-reborn@|永恒常春藤:重生 (Timeless Ivy:Reborn) +simply-more@simplymore +wetland-whimsy@|奇湿妙想* + + +@deputy-placement-switch|求你别放了 (NoG8Put) +ileafcore +dirt-tools-and-armor@|泥土工具与盔甲 (Dirt Tools and Armor) +thaumic-rings-of-power|神秘众戒* +lotr-valkyrien-compat|魔戒:瓦尔基里兼容 (Lotr+Valkyrien Compat) +improvedcrashreports@ +colorful-paradise@ +oracle-index@ +come-back-my-villagers@ +screenshot-with-coords@|带标截图 (Screenshot with Coords) + +ccddi-damage-indicator@ccddi +lidar +@segmented +goety-gotta-summon-em-all@goety-gotta-summon-em-all!|诡法的混沌拓展 (Goety: gotta summon em all!) +aerlune-rpg-2 +origin-furs@ +grounded-origins-forge@groundedorigins¨grounded-origins-fabric +@sand-and-gravel-are-forbidden-to-fall|禁止下落 (Nofall) +tinkers-tool-leveling-2@|匠魂工具升级2* +remodifier-reborn|你别造了!!!* +exporbrecall@|经验球召回 (ExpOrbRecall) +functional-economy@functionaleconomy|功能性钱币 (FunctionalEconomy) +ranckors-rings-of-power|Ranckor的力量之戒 (Ranckor's Rings of Power) +lotr-improvements-lite|魔戒改进:轻量版 (LOTR Improvements Lite) + + +astounding +carpets-core@ +carpet-variants@ +@mineable-unmineable +tetra-addition +styled-boss-bar-api@|自定义Boss栏 (Styled Boss Bar API) + +random-enchant-fix@ +immersive-armor-hud@|沉浸式盔甲 HUD (Immersive Armor HUD) + +yeast-n-feast@ + +vampirism-tinker|血族工匠 (VampirismTinker) + +essentia-pipes@|源质管道* +msp-backpacks +simple-block-breaker@ +salis-arcana@ +thaumic-mixins +sanguimancypatch +sanguimancy +jungle-villager-trader@ +origin-furs-unofficial-forge-fork@origin-furs-unofficial-forge-port +ephemeral-wither-skulls@|消逝的凋灵之首* +fox-friend@|狐友* + +simple-difficulty-reforged +create-recycling-everything-neo + +aquaticamod +hell-ntegrations +@mcmod-more-food-enchantment|更多的附魔食物 (More Food Enchantment) +mapletree|枫树* +drink-it-refoxed|喝!重生 (Drink It! Refoxed) + +galospheric-delight@ +growmeal-fabric@growmeal-(fabric) + +katharite-slimes@slimes-of-kathare +botania-ceu +magic-from-the-east@ +blatapi@ +@materials-lib +cavelib@ +economy-api@ + + +no-enchantment-cap-level@ +create-ultimine@ +serene-wild@ +kitchen-decorations +refined-storage-curios-integration@ +refined-storage-trinkets-integration@ +refined-storage-emi-integration@|精致存储 - EMI 集成 (Refined Storage - EMI Integration) +refined-storage-rei-integration@|精致存储 - REI 集成 (Refined Storage - REI Integration) +refined-storage-jei-integration@|精致存储 - JEI 集成 (Refined Storage - JEI Integration) +refined-storage-mekanism-integration@|精致存储 - 通用机械集成 (Refined Storage - Mekanism Integration) + + + +lukis-ancient-cities +ungebauts-wildlife@ +changed-mcreator-slop +forgotten-battle-towers +@back-at-it-again +summer-cottage@ +marius0x-furniture +youssefs-currency@youssefs_currency +bibliobiomes-legacy@ +sniffers-delight@sniffers_delight +easters-delight@|复活节乐事 (Easter's Delight) + + + +better-carryon-maid|更好的女仆搬运* +tensura-no-game-no-life@tensurano-game-no-life|转生:游戏人生 (Tensura: No Game No Life) +summoner-scrolls@ +refined-storage-quartz-arsenal@ +create-advanced-logistics@createadvlogistics +create-electric-drive +@lachryvisions +the-heaven-sword-and-dragon-saber|倚天屠龙 (The Heaven Sword and Dragon Saber) +dreamtinker@|工匠幻梦 (DreamTinker) + + +wolfs-enchantment-lib|狼王的附魔库 (Wolf's Enchantment Lib) +@caoplus|槽 (CaoPlus) +disturb-not-my-dream@|勿扰吾梦 / 起床气* +@contigency-shop-lite|轻量兑换所 (Exchange Site Lite) +lootbagsrenewal@lootbags|战利品袋重制版 (LootBagsRenewal) + + +autoswaplowdurabilityelytra|自动鞘翅替换 (AutoSwapLowDurabilityElytra) +no-elytra-equip@elytras-disabled +no-elytra +title-changer@ +clickthrough-plus@clickthrough+|穿牌开箱+ (ClickThrough Plus) +itemzoomer@ +@surveystones +particular-reforged@ +cloud-revive@cloud_revive|云生* +paranoia|偏执狂* +thaumic-brewing|神秘酿造学* +aether-treasure-reforging@ +animations@ +@pet-necropolis +paddle-boats +true-darkness-elementriy + + +sophisticated-storage-create-integration@ + +@removespeeddetection|移除服务端速度检测消息 (RemoveSpeedDetection) +shared-advancements@ +@polytime +golden-meadows +ssmlegacy@ +super-sound-muffler-revived +current-game-music-track@ +create-mobile-packages@|机械动力:无人机物流 (Create: Mobile Packages) +create-cardboarded-conveynience@ +blacksmith-weapon|铁匠武器 (Blacksmith_Weapon) + +mrqx-s-slashblade-core@mrqx%60s-slashblade-core|墨染琴弦的拔刀剑核心 (mrqx's Slashblade Core) +goldblade|神刀 (GodBlade) + +shanghai-metro-line-one-mod@|上海地铁一号线* + +thetrackers@|全追踪 (TheTrackers) +cat-burger|猫猫汉堡* +mineral-backpacks@ +@furry_bohe|兽薄荷 (Furry Bohe) +narcissusfarewell-reflorescence|水仙辞:重绽 (NarcissusFarewell: Reflorescence) + +bibliocraft-bibliowoods-forestry-edition +bibliocraft-bibliowoods-biomes-oplenty-edition +bibliocraft-bibliowoods-natura-edition +bibliocraft-bibliowoods-terrafirmacraft-edition +bibliocraft-bibliowoods-highlands-edition +bibliocraft-bibliowoods-extrabiomesxl-edition +@blockprintr + + +assorted-tools@ +assorted-core@ +tlotd@ +infinity-golem-boss-fight-beta@infinity-golem-boss-fight-(beta) +actually-divisions@ +extra-trinkets@ +portable-tanks +happier-ghasts@ +tinker-in-caves|洞穴工匠 (Tinker in Caves) +@better-tfcr|更好的群峦:重生 (Better TFCR) + +mobreaker|坚壁重构* +man-from-the-fogs-delight|雾中人乐事 (Man From The Fog's Delight) +forsaken-items@|被遗忘的物品:重生 (Forsaken Items Reforked) +@soybean-fun-item|豆浆你提我造 (Soybean Fun Item) +epic-fight-mesh-model|史诗战斗网格模型模组* +monster-of-the-night-skies@ +spooky-doors@ +@mclientapi +moffs-addonapi-dynload@addonapi +@shiv +@tab-list +dokimobs@|萌化生物 (DokiMobs) +bookling-gear@ +neuracraft@ +moves-like-mafuyu@|高速企鹅* + +vanillin@flw-vanillin +chain-mining-reforged@chainminingreforged|连锁采集重铸* +hrtffix@|HRTF修复 (HRTF Fix) +iammusicplayer-renewed@iam-music-player-renewed +misc-tweaks@misctweaks +ftb-filter-system +neonium@ +@super-fast-math + + +simple-loot-viewer@ + +greg-tech-chisel|凿子 GTNH 版 (Chisel - GTNH / Greg Tech Chisel) +baubles-expanded-gtnh|饰品栏 GTNH 版 (Baubles-Expanded-GTNH) +gregs-tinkering +metaworlds-mixins|元世界 - Mixin 重制版 (MetaWorlds - Mixins) +create-cobblemon-potion@|宝可梦动力药水* + +jarjar@ +javascriptjs@ +blood-n-particles-mod +@sstool|绵阳的特效工具 (Sun Sheep's Tool) +xiaofanweis-items|小烦维的物品 (xiaofanwei's items[Iron's Spellbooks and Terra Curios]) + +easycolony-addon-for-minecolonies|简易殖民地 (Easycolony) +blades-derby@|骐骥刀剑风云* + +create-simple-generator@|机械动力:简单发电机 (Create: Simple Generator) +sophisticated-backpacks-create-integration@ +ticex-tinkers-construct-ex@ticex +eternal-starlight-vanilla-ores@eternal-starlight-vo +supercritical +supercritical-gtqt +gtconsolidate@ +implosionnobomb@ +villager-golem-healer@ +yakurum-mod +@fantasytools +metaworlds-mod|元世界 / 变幻世界* +create-dragons-plus@|机械动力:龙+ (Create: Dragons Plus) +appliances@appliances-mod +@twelvefold-booter +omniconfig@ + +@linearxp-legacy|线性经验值 (LinearXP) +@better-thunder|更好的雷声 (Better Thunder) +@enhanced-packet-compression|增强数据包压缩 (Enhanced Packet Compression) +gnetum@ +accessible-step@ +terrastorage-icons +terrastorage@ +@euphoria-companion +jump-bridge-mod +huskhomes +blahajasm@ +mireoles-gtceu-additions@ +expanded-ae +modular-machinery-reborn-ars-nouveau@ +bonsai-crops@|盆栽作物* +playing-cards-chips|扑克牌与筹码 (Playing Cards & Chips) +enderdrives@ +lucky77 + +i-dont-see-you@ + +epic-fight-valour-guard +sweet-calamity@ +vanillabackport@ +stylish-stiles@ +stylish-stiles-renewed@ +undermod@mystronics-undermod +spitting-image@ +@repo-heads + +@create-blueprint-tweaks|机械动力蓝图微调 (Blueprint Tweaks: A Create Addon) +mob-journal@|生物图鉴* + +sdm-shop@ +economy-coins-bills-and-gems +multi-hotbar-core +multi-hotbar|多重快捷栏 (Multi-Hotbar) +properties-panel@propertiespanel|属性面板* +whimcraft@|奇思妙想 (WhimCraft) +recipeconflict-fixer|合成冲突消除:修复版 (RecipeConflict Fixer) +dooglamoo-painter-mod|Dooglamoo 的绘画* +notafreaks-plushies@ +enchanting-vanilla@|原韵新生* + + +quest-items-rpg@quest-items +experimental-mobs +advanced-combat-patched|高级战斗装备修复版* +@authproxy +ezstorage-2-patch|EZ 存储 2 补丁 (EZStorage 2 Patch) +squake-patched +immersive-hotbar@ +create-classic-blaze-enchanter@|机械动力:经典烈焰人附魔室 (Create: Classic Blaze Enchanter) + +ifpatcher@|工业先锋补丁 (IFPatcher) +sakura-orihime|樱:织姬 (Sakura-Orihime) + +tinkers-antique|匠魂怀古 (Tinkers' Antique) +ex-fusile +better-player-respawn + + +another-experiment-researcher +spiders-1-999 +villager-comfort-updated|村民舒适度更新版* +flight-affinity@ +emcgadgets + +@minecraft-engineer-edition +@eyelib +custom-armor-bar@ +roughly-enough-input-methods@ +pirates-doom@ +techrebornjei@|科技复兴JEI (TechRebornJEI) +little-joys@ +blasting-raw-metal-blocks-into-blocks-fabric-forge@blasting-raw-metal-blocks-into-blocks + +@re_mob-control-wands|重制:怪物控制魔杖 (Re: Mob Control Wands) + +nekoration-reborn|猫咪装饰:重生 (Nekoration-Reborn) +mine-reputation@|失去的声望* +ruined-lighthouse +frogs-medieval-paintings +bad-apple@ +podium-sodium@podium +compressed-create-recipes +aether-overworld-ores@ +slashbalde-useful-addon|拔刀剑实用扩展* + +powerutilites-unofficial|电力转换非官方版 (PowerUtilites Unofficial) +@gameruleplease +custom-fov@custom-fov-illusive¨custom-fov-fabric +apotheosis-x-irons-spellbooks-compat +customtab@ +nightmares|噩梦* +graveyards +sky-arena@demis-sky-arena +progressive-mechanics-library@ +@shy + + +tradepreview@|交易预览 (TradePreview) +enhanced-celestials-shader-support@|月亮事件光影支持* +incendium-biomes-only +thaumic-tweaks@ +selectivebounds@ +@bactromod +@exit-on-startup|一启动就退出 (Exit On Startup) +@kotlin-for-forge-unofficial +@circlemc +nearbymobchecker@ +gputape@ +@limitless-anvil|铁砧限制修复 (Limitless Anvil) +carry-on-extend@|搬运:拓展* +kaleidoscope-doll@|森罗物语:玩偶* +kamen-tinker|蓝钢匠艺/假面匠艺* +agritech-automated-crops@ +@pots-idea|脑洞瓦工 (Pot's Idea) +kogtyv-tav@|Kogtyv 的城镇与村庄 (kogtyv-Towny and Village) +gothic-church|哥特式教堂* +sky-whale-ship@ + +no-mans-land@|无人之境 (No Man's Land) +bindable-mana-pool@|可绑定魔力池* +@blood-mending +craziness-awakened@craziness-awakened-(orespawn-remake) +mischief-illagers@ + +dynamic-trees-caverns-and-chasms|动态的树:Caverns & Chasms 附属 (Dynamic Trees - Caverns & Chasms) + + +apex-a-proper-equipment-expansion +dimension-of-caves|Alex的洞穴维度 (Dimension of Caves) +herobrine-a-friend@ +stattweaker@ + + +atsassistmod +@i-cant-believe-its-not-1215 +@slbcf|服务器列表缓冲崩溃修复版 (ServerlistBufferCrashFixer) +dynamic-tooltips|动态提示框* + +mixed-litter@ +groovyduvet@ +create-egg-production@createegg-production|机械动力:鸡蛋产线 (Create: Egg Production) +create-fishery-industry@|机械动力:渔业 (Create: Fishery Industry) +create-rustic-structures@|机械动力:乡村结构 (Create: Rustic Structures) +slightly-newer-art-of-forging +custom-treasure-maps@ +evolved-mekanism@|通用机械:进化* + +brain-delight|脑子乐事* +villager-library|村民图书馆* +trade-enchant-overhaul +more-additional-paintings@ +simplebackport@ +biomebeats@ +decorative-core@ +@key-bindings-keeper|按键绑定不减 (Key Bindings Keeper) +@mekanism-output-faster|通用机械加速输出 (Mekanism Output Faster) +@infinite-capacity-cell|无限容量元件 (Infinite Capacity Cell) +@mcutilities +pickuptorches@ + +pointblank-magazines-vpb +pointblank-projectiles-vpb +deathly-hallows@|死亡圣器* +tetra-loopback@ +appliedenergisticsoddities +tweakermoreforge@ +vs2-cbc-armor-blocks +create-integrated-farming@|机械动力:集成农业 (Create: Integrated Farming) +ring-of-blink-forge|闪现戒指 (Ring of Blink) +golem-overhaul@|傀儡革新* +voile@ +title-tweaks@titletweaks +ugoblock|动块 (UgoBlock) + + +scriptasm + + +aimbot|瞄准修正 (Aim Bot) +@server-chat-log-history +hud-compass + +familiar-friends@|亲密伙伴* +golem-spawn-animation@ +realistic-night-vision +stackable-items + +discrafted@ +survival-plus-plus@ +server-plus-plus@ +happier-ghast@|更好的快乐恶魂 (Better Happy Ghast) +bhgc@|更好的快乐恶魂控制 (Better Happy Ghast Control) +@dominatus +unfocused@ +jerotes-warehouse@|Jerotes实用仓库* +happy-ghast-legacy@ +spider-jockey@ +digger-helmet@ +acecraft + +@familiar-magic +lumenized|流光溢彩* +chili-bullet-weapons@ +applied-web-terminal@|AE网络终端* +@dusts-keymap +itemzoommore +@noitemtooltips +shuttfup|Stfu - 已停更¨@shuttfup +baublesreforked@|饰品重铸 (BaublesReforked) +@wills-lively-villages +tmrv@ + +twilight-treehouses@ +improved-rails@|更好的铁轨(可转弯の动力铁轨!) (Improved Rail (TURNABLE POWERED RAILS)) +redstone-signal-bind-wand@|非Create版无线红石* + +@ingametranslator|游戏内聊天翻译 (In game Translator) +carnivorous-plants-addition +mekanism-curios +tetra-compat +hex-casting-additions +ghasts-crash + +futurecherry@|未来的樱花 (FutureCherry) +food-fix +mining-speed-tooltips@ +smithing-template-viewer@ +picks-of-power@ + +super-hot +chill-thrill +pyrellium@ +luminous-nether@ +brush-mining-machine|刷矿机 (Ore Generator) + +@night_vision_amulet|夜视护符 (NightVisionAmulet) +set-effects|套装效果* +tramways@ +projecte-kubejs +actually-additions-v2-unofficial|实用拓展 V2 咖啡版 (Actually Additions V2 Coffee Edition) +create-ender-link@ +progressive-tweaks +portable-blueprints@ +carrasconlib@ +blockparticlespawning@|方块粒子生成 (Block Particle Spawning) + + + +aether-dragon-dragon-survival-addon +tundra-dragon-dragon-survival-add-on +naturalist-delight +civilizations@ +block-factory-biomes@block-factorys-biomes +underwater-swim-fix-mc-220390@underwater-swim-fix-(mc-220390)|水下游泳修复 (Underwater Swim Fix (MC-220390)) +scaffolding-backported +hold-my-items-reforged@ + +distraction-free-recipes¨@distraction-free-recipes|Distraction Free Recipes - 未及时更新 +seeking-immortals-nightmare@|月之石:噩梦之章/求仙者:噩梦之章 (Moonstone :Nightmare/Seeking Immortals : Nightmare) +enchanted-crystal-arrow|魔法水晶箭 (Enchanted Crystal Arrows) +touhou-danmaku-kagura-core|东方弹幕神乐核心 (Touhou Danmaku Kagura core) +hah-ueuh@hah!-ueuh +eternal-nether@|永恒下界* + + + +gui-followers@¨gui-followers-fabric +omnidirectional-sound-ods@omnidirectional-sound-(ods) + +diligentstalker@|勤劳跟踪狂 (Diligent Stalker) +maid-useful-tasks|女仆实用任务 (Maid Useful Task) +@titlechanger-next|标题切换器 Next (TitleChanger Next) +embers-underground-rooms@ + +dontstarve4@|不要饿死 4 (Don't Starve 4) +spark-core@|星火核心* +nether-core-useful-nether-rock|下界核心 (Nether Core) +slashblade-js|拔刀剑 JS (SlashBlade JS) +caerula-arbor@|方块与深蓝之树* +alices-doll|元歌 (Alice's Doll) +bedrock-redux@|基岩再现* +item-entity-control|掉落物清理* +wishing-fountain|许愿泉* +@unbelievable-enchantment|令人不可置信的附魔 (Unbelievable) +@hgws-spyglass-a|Hgw的望远镜 (Hgw's Spyglasses) +we-do-copyright@ +useful-clipboard +seeking-immortals-virus@seeking-immortal-virus|月之石:基因计划/求仙者:基因计划 (Moonstone :Virus/Seeking Immortals :Virus) +gambler-illager-irons-spells-and-spellbooks-addon +chimericlib +pokecube-alternative +@intuitive-netherite +create-propulsion@|机械动力:推进工程 (Create: Propulsion) + + +event-wrapper@|事件包装器* + +@modwhitelist|模组白名单 (ModWhiteList) +@instant-build|瞬时建造 (Instant Build) +beacon-conduit-tweaks|信标与潮涌核心调整 (Beacon & Conduit Tweaks) +tfc-tools-trim@|群峦传说:工具纹饰 (TFC Tools Trim) +@kill-youkai-with-knives +mo-bees@|更多蜜蜂 (Mo' Bees) + +faux-custom-entity-data@ + +poopsky@|空中厕所 (PoopSky) +@solarus-classic + +create-unlimited@ +skeleton-ai-fix@|骷髅 AI 修复 (Skeleton AI Fix) +climate-rivers@ +dungeonsdelight@dungeons_delight|地牢乐事 (Dungeons Delight) +cleanroom-relauncher-unofficial@|Cleanroom 模组式启动器非官方版* +silents-power-scale@ +trident-return-fabric +resource-world@|资源世界* +ijm-tweaks@ +no-mans-delight@ + +applemilktea2-tweaked +@carpet-blue-addition +@yaca|毯上添花 (Yet Another Carpet Addition) +@steel_myfirstmod|钢铁 +movie-discs|Minecraft 大电影插曲唱片 (A Minecraft Movie Discs) + + +materials-integration|资源统合* + + + +modular-machinery-reborn-create +sheep-variety@ + + +@tetraclip|易验锻造 (TetraClip) +@rozhud +the-cosmic-spokespersons@|宇宙代言者* +mc-mods-in-zero@all-in-zero|一切于零 (All In Zero) +yunzhu-transit-extension@|云竹交通拓展* + +goodbye-dirt-screen@|澄清素视 / 去你的泥土屏幕* +create-stock-bridge@ +create-escalated@escalated|机械动力:自动扶梯 (Create: Escalated) +create-mechanical-confection@createmechanical-confection|机械动力:蛋糕工坊 (Create: Mechanical Confection) +farmers-delight-compat@ +gtwoodprocessing@gtwp + +vintagedisplay@ +voidless-framework@ +mixin-args +melonlib@ +@no-kebab +mechanicals-lib@ +create-mechanical-cow@ +global-options@ +kubejs-projecte-fork@ +untoggle-sprint@ +vndialog@nvdialog|VN对话框引擎 (VNDialog) +@elytrabugfix +@ezbowls +soundtrack-events +commandkeys@ +iron-chests-with-netherite-chest@iron-chests-(with-netherite-chest) +emerald-on-a-stick-villager-follower@emerald-on-a-stick-(villager-follower) +fishing-indicators@ + +just-another-witchery-remake@ +@inexorable-origins +cybersus@ +@passivearmour +zettai-rpg@ +md-units@md-unit-robots +extreme-core +dreamless-spells-and-spellbooks +gregtech-meowmelmuku|格雷科技非官方版 - 喵呜酱版 (GregTech - MeowmelMuku) +@namedloot +@enchantment-decay +create-jet-boots +train-deco@|机械动力:地铁列车装饰* +packed-packs@ +dyed-flames@ +hopper-gadgetry@ + + +quickcopy@|迅摹天工 (QuickCopy) +item-informations|物品信息* +shootscreen|拍屏 (ShootScreen) +@server-expansion|扫地小狐 (Server Expansion) +@valkyrien_skies-defense|瓦尔基里:防御 (Valkyrien_Skies: defense) + +tinkerslashblade-patch|刀锻冶匠魂修复 (TinkerSlashBlade Patch) +alienevo@ + +banit|干掉它! (BanIt) +alexs-mobs-naturalist-compat@ + +tinkers-ingenuity|匠心之作 (Tinkers' Ingenuity) +curiosities@|趣味物品* + +@cs2_c4|Qis的C4 (C4) +bomb-disposal-expert@bde|拆弹专家* +sprintify|长疾速适* +shield-system +@burythelight +command-aliases@ +pigium-performance-mod +spectrumjei@|光谱世界JEI (SpectrumJEI) +@itemban +@skiesclear +vminus@ +@villagertalk1 +debug-utils-forge@debugutils¨debug-utils-fabric +slimefun-essentials-port +uma-little-maid@uma_maid|马儿小女仆* +i-like-wood-twilight-forest-plugin +i-like-wood-oh-the-biomes-youll-go-plugin +i-like-wood-immersive-engineering-plugin +click2pick@ +hudless@ +dungeons-perspective@ +miniutilities-flight-fix@ +linked-chests@new-linked-chests +create-direct-chute@direct-chute +create-packagers-psi-compat@packagerspsic +create-more-packages@ +create-extra-gauges@extra-gauges|机械动力:更多仪表 (Create: Extra Gauges) +ships-legacy +traders-backport +banner-patterns-backport@ +convenient-effects@ +baguettelib +fast-event@fastevent +@citreforged +better-meteorite|更好的陨石* +paragraphs-reforged@ + +tpsbooster +custom-portal-api-reforged@ +forgedpaginatedadvancements@|分页进度 (Neo)Forge 版 (ForgedPaginatedAdvancements) +colorfulanvils-reforged@ +keymap-maintained +create-mechanical-companion@ +crazy-ae2-addons@ +schizophrenia|精神分裂症* +@mobswithpowersaddon +wolf-sword-mod@ + +charged-mobs@ +the-mangled-hound +avp@ +@giantess-toki +enchant-limiter@ +crafter-backport +citadel-fix|Citadel优化修复* +knit +gallant-tireless-altruist@|热心市民* + +cerulean@cerulean-advancements +color-format + +swim-in-lava +orevolution@ +even-better-nether@ +plastoid-armor@ +corpse-x-curios-api-compat@ +@trinkets-canary +@a-strange-world-we-live-in +spellhud-addon@ +replication-ae2-bridge@ +@deltarune-mod +eternalpotions@ +@l-mans-cat-clocks +life-leech-enchantment@lifeleech|生命汲取附魔* +sakaz-hand|奇语之手* +clayium-unofficial@|粘土工业非官方版* +mekanism-weaponry +wardends-revenge +mob-control-rod +unlimitedperipheralworks@ + +verdant-wonders@ +underlay@ + +lazy-item-generator|咸鱼物品生成器* +crab-street-light@|螃蟹的路灯* + +undertale-delight@|决心乐事* + +@origins-algorithmic-phantom|起源:算法幻影 (Origins:Algorithmic Phantom) + +spawn-egg-information@|刷怪蛋信息显示 (Spawn Egg Infomation) +calypsos-candy-workshop@|卡里普索的糖果工坊 (Calypso's Candy Workshop) +fill-tool +growth-tonic +quivermob + + +world-drop + + +shell-armor +cart-livery +territorial-dealings +potion-packs +armor-smelter + +carpet-sls-addition@sls-addition +forge-string-unpatched-powered-permanent-string@fsu|(Neo)Forge 常亮绊线特性恢复 (Forge String Unpatched - Powered Permanent String) +quests-kill-task-tweaks +lpctools@ +immersive-messages-api@ +immersive-damage-indicators@ +easy-disenchanting@ +respect-my-trims@ + +cloudgolem-edited|湫渃云魔修改 (CloudGolem Edited) +maidaddition +webcam|网络摄像头* +projecteteams@ +battle-frenzy|越战越勇* +@plane-advancements +cosmopolitan@|四海一家* +redtassel|红缨 (redtassel) +sridr|拔刀剑锻造增伤改革 (SlashBlade Refine Increased Damage Reform) + +mianbaos-modernwarfare|面包军火库 (Mianbao's ModernWarfare) +creator-sword@|机械动力:机械师之剑 (Create: Creator Sword) +create-limited-draining@|机械动力:流体抽取限制 (Create: Limited Draining) +create-no-touching|机械动力:防御 (Create: No Touching) +create-aether-industry|机械动力:天境工业* +create-entitycontroller@create-entity-control|机械动力:实体控制 (Create: Entity Control) +better-advancements-blessed-edtion|更好的进度 - 祝福版 (Better Advancements - Blessed Edtion) +gloom-raiders@ +herobrine-prime +legend-of-the-dwerden@ +dnt-stronghold-overhaul-lite-edition +dnt-nether-fortress-overhaul +gtfocraftprotocol@gtfo-craft-protocol + +keerdm-zombie-apocalypse-essentials@keerdm-zombie-apocolypse-essentials +chovys-apocalypse@ +bexlas-enhanced-ores +starve-library@|饿死图书馆* + + +infinite-refills|无限续杯* +systrace@|一导即出* +fluxed-core@ +myluckyblock@|我的幸运方块 (MyLuckyBlock) + +backpack-plus@backpackplus|背倍加 (Backpack Plus/Backpack Plus: Sophisticated Backpacks Addon) +@hydration-mod + +defiled-lands-reborn@|污秽之地重置版* +@copper-bulb-early|铜灯补充 (Copper Bulb Early) +future-fireproof@|未来防火* +@low-durability-switcher +dimensional-potions +ghasts-drop-records|恶魂掉落唱片* +ftb-chunks-compatibility-mod@ +charm-forked@ +early-bedtime@ + +instant-picking@ +@quick-craft +kubejs-curios +copper-carrots@ +tinkers-jewelry@|工匠珠宝 (Tinkers' Jewelry) +thief@ +applied-schematicannon +more-functional-storage@|更多功能性存储* +vital-herbs|活力草药* + +hbm-ntm-structure-1-12-2 +illusioners +cataclysms@ +bas-cave-enemies +sniffer-ride +aesthetic-shelving +arboreal-nature@ + +fracture-point@fracturepoint +@ceres + +creeper-super|智能爆破专家* +expanded-experience +reworked-phantoms@ +ex-nihilo-fabricio@ +hybrid-delights@ +create-clothes@|机械动力:服装 (Create: Clothes) +create-delivery-director@delivery-director +create-cardboard-things@ + +watkinsbase + + + +toggleable-enchantments@ + + + +scape-and-run-parasites-deep-sea-danger@ + +craft-in-shadow +@jewelryz +better-armory-mod@seths-better-armory +twilight-forest-dungeons-villages@the-twilight-forest-dungeons-villages|暮色森林 - 地牢与村庄 (Twilight Forest - Dungeons & Villages) +mice@ +ancient-golems@ +model-citizens +botanical-machinery-extra@tPTR9GcJ +flowerary@ +extrabotany-reburn@extrabotany|额外植物学:重燃 (Extrabotany: Reburn) + + + +umapyoi-delight|马儿跳乐事* +lne-rogues@ +lne-archers@ +lne-wizards@ +lne-paladins@ +@protomanlys-weather +tinkers-mechworks-legacy +bbl-core@ +cooparticlesapi@|空栈粒子框架 (CooParticlesAPI) +fdlib@ +potion-icons@potionicons +catvision +spectre-things@ +chatplus@ +ritual-enchanting +peaceful-progression@ + + +usefulmagic@|实用魔法 (UsefulMagic) +keepinventorynext|死亡不掉落增强 (Keeping Inventoiry Next) + +tinkers-jewelry-ex|工匠珠宝拓展 (Tinkers' Jewelry EX) +lovely-sparkle-pieces|璀璨饰品* + +yuns-weather@ +qliphoth-awakening@|逆卡巴拉:觉醒* + + +universal-mod-localizer@universal_mod_localizer|通用模组汉化器* +smart-creeper@|智慧苦力怕* +peaceful-depletion@peaceful_depletion|和平消耗* +@everything-is-tnt +structure-pool-api@ +create-bluemap@ +tragicmc-2-continuation|悲惨世界2:延续 (TragicMC 2 Continuation) +nebula-parasites@ +bonsai-trees-unofficial-extended-life|盆栽非官方延续版* +@its-as-shrimple-as-that +worldedit-items@ +slashblade-skin@|拔刀皮肤 (SlashBlade Skin) +iron-door-key@ +just-enough-fishing-jef@just-enough-fishing-(jef) +containersearch@container-search +mousepets@ +backported-minecarts@ +simple-incubator@ +amethyst-stairs-slabs-and-walls +@vessels +ultimate-scaler@ +legendary-weapons-byititor@legendaryweapons +slender-reborn +craft-vania-lite +pollution-of-create +create-chocolate-fountain@|机械动力:巧克力喷泉 (Create: Chocolate Fountain) +create-currency-shops@|机械动力:货币商店 (Create: Currency Shops) +create-nether-industry@|机械动力:下界工业 (Create: Nether Industry) +backported-diamond-ore-gen +tfthreadsafetyaddon +serverautosaver +infinistack@|无限堆叠 (InfiniStack) +powerful-dummy|强力假人* +beyond-bosses@beyondbosses +mini-utilities-y +concoction@concoction!|田园调酿! (Concoction!) +zombietactics2@ +radiation-zone-reborn|辐射荒原:再行 (Radiation Zone: Reborn) + +@crumbling-hearts + +dye-the-world@ +modernmarkings@ +hololive-product@ +fetzis-displays@ +shadered@ +sweety-garden@ + +@twilight-forest-aurora-palace-regeared +changshengjue@|长生诀 (ChangShengJue) + +medieval-buildings-nether-edition +@ribbits-croaks +echoes-of-time@ +horror-alexbrine +zzz-craft|绝区零·星见雅 (ZZZ Miyabi) + +cozy-cabins-and-cottages@ +servereye +deepseek@deepseek-neoforge +ai-command|AI指令生成 (AI Command Generator) + +flighthud-do-a-barrel-roll-fix + +fast-container-placement@|快速容器放置* +@teleport-mod +@what-meme +crackers-wither-storm-mod-v-sides-soundtrack@ + +roberts-game-tweaks|Robert的游戏调整 (Robert's Game Tweaks) + +datapackloaderrorfix@datapack-load-error-fix|数据包错误修复:重生 (Datapack Load Error Fix Reborn) +@whats-this +@additional-jewelryz +tacz-tes-compat@ + +day-counter-mod +directionhud +raw-netherite-reforged@ +blast-travel-reborn@blasttravelreborn|旅行火炮·重生* +shanxi-skeleton@shanxiskeleton|山西骷髅* +@gunpowder-overhaul|火药改革 (Gunpowder Overhaul) +smoking-stuff-a-wizards-hobby@ +mc-modsoy-smelter@alloy-smelter +@autocrafter-early +time-in-a-bottle-charger@ +just-a-sculk-vial@ +lockylocks@ +server-i18n-api@ +fragmentum-forge@fragmentum¨fragmentum-neoforge¨fragmentum-fabric +@monument-data-fix|Monument 数据修复 (Monument Data Fix) +@better_tp +waystone-currencys@|消币则至 / 传送石碑:货币 (Waystone: Currencys) +@armor-stand|盔甲架 (ArmorStand) +threadtweak-reforged|ThreadTweak (Neo)Forge 移植版 (ThreadTweak Reforged) +@environmental-creepers-backport +com-bat +touhou-little-maid-rpg-class-task@touhou-little-maid-rpg-task +unknown5473lib@ +heat-and-climate-patch|热量与气候修复* + +@clientupdater + +modern-lucky-block@ +foxrecipemaker +@global-mob-health-multiplier|全局生物血量倍率 (Global Mob Health Multiplier) +chatbox-for-mc@chatbox|对话框 (ChatBox) +perfectly-balanced-bows +@playerex-alcohol|PlayerEx 酒精版 (PlayerEx: Alcohol) +hak-minepiece +grease@ +cleaver-compedium +phayriosis-parasite-infection +srp-calamity-catastrophe-cataclysm@|逃寄:无妄之灾 (SRP: Calamity Catastrophe Cataclysm) +moss-overgrowth +create-pillager-arise +create-qol@ +create-remote-terminal@|机械动力:远程终端 (Create: Remote Terminal) +fallen-fungus + +songs-of-war@|战争之歌 (Songs of War) +cataclysm-summons@ +cutepuppymod@ +giant-swamp-tree@|沼泽巨树* +big-oak-tree@|大橡树* +giant-tree-stump@|巨型树桩* + +polars-mad-tweaks@ +cobblemon-ranked@|方块宝可梦-排位赛* +eiramoticons +horse-breeding-fix@ +tablistextension@|TAB 列表扩展 (TabListExtension) +rally-of-the-guard-guardvillagers +bncci +@recipe-maker +portaltransform@|传送门嬗变 (PortalTransform) +@a555sd|更多的画 (More Paintings) +unusual-furniture@ +xiaoanmooncake@|小安的月饼狂热 (Xiaoan's Mooncake Fever) +foragers-insight@|巧觅巧食 (Forager's Insight) +palestinian-delight@ +mekanism-more-machine@mekanismmoremachine|通用机械:更多机器 (Mekanism: More Machine) +custom-battleroyale@|自定义大逃杀 (Custom BattleRoyale) +improved-pillager-outpost +rebalanced-enchanting@ +dark-doppelganger@ +enders-spellsandstuff +hazen-n-stuff@ +spongeforge@ + +@don%22t-die|补药趋势啊! (Don't Die!) +sdm-market@ +omnilook@ + +survivalist-essentials@ +villager-trading-plus@trading+ +mending-fix|经验修补修复* + +colorwheel@ +tlib@ +smoothscreen@ + +@fuzz +advanced-loot-info@|高级战利品信息显示* +resourcepackcached@ +aotake-sweep|竹叶清* + +effectual@ +cold-light@|冷晖之枪* + +huanles-weapons@|Huanle的武器 (Huanle's weapons) +@clay-soldiers-remake +threateningly-mobs@ +basic-spinosaurus +european-wildlife +marvelous-menagerie@ +roman-weaponary +compat-structure@ +flower-bed@ +archery-expansion-squared +create-more-linked-remote@ + + + +gambagoons-better-emeralds +ingameime-vintage@|游戏内输入法-1.12.2 (IngameIME-Vintage) +extreme-sound-muffler-legacy@ +amazing-trophies + + +global-server-configs@global-server-config|全局服务器配置* +expandedbonemeal +@aireplyassistant|AI回复助手 (AIReplyAssistant) +utiljs +moon-info-updated@ +@server-market|服务器市场 (Server Market) +nbt-tooltip@nbttooltip +delicate-dyes@ +@modernmixins +sdm-economy +sdm-ui-lib@ +mcllm@ +@inventory-pause-yipeekiyaay +chestsearch|容器检索 (ChestSearch) +clicktor|Clicktor连点器 (Clicktor - Auto Clicker) +extended-bone-meal@¨extended-bone-meal-fabric +show-me-the-enchantment|怎魔,你不附器* +better-sign-edit@ +disc-recipes@|唱片合成 (Disc Recipe) + +@backportsupplement|移植补充 (backportsupplement) +scoutreforked@|侦察兵 重构 (Scout Reforked) +immersion-in-traffic-context|沉浸交通道路 (Immersion in Traffic Context) - 旧版¨immersion-in-traffic-context-2@immersion-in-traffic-context|沉浸交通道路 (Immersion in Traffic Context) +arknightsfurniture@|明日方舟家具 (ArknightsFurniture) +gunsmith-lib +@emixx +experiencelib@ +mystical-mobs + +progressive-difficulty-chaos-integration@ +ottapomos-scps +scp-foundation-requisites@ +thermal-construct@ +war-wither@|战争凋灵* +status-effect-bars-reforged@ +dark-tower-maze + +the-occult +wolftailui@ +better-client@better-client-enc|更好的客户端* +clientharvest@ +auto-afk¨@auto-afk|Auto AFK - 全,优先在这 +particle-effects-reforged@ +hold-my-items-refoxed +dont-claim-our-structures +cosy-critters-creepy-crawlies@cosy-critters-creepy-crawlies-neo +thin-air-ad-astra-compat +yyzsbackpack@yyzs-backpack|yyz的背包 (Yyz's Backpack) + +vital-delight + +@mining-in-place +pathfinder-navigation|寻路者导航* +adorable-eggs@ +food-addition@ +everything-totem|万物皆可图腾* +thaumic-renaissance@thaumcraft-renaissance +@executive +@make-i18n-great-again +steve-goes-fishing@ +voltaic-api@voltaic +boat-delete-begone@boatdeletebegone +zs-packet +raise-them-hotbars +quick-leafdecay +footprint-particle-returns +inventory-crafter-returns +colorwheel-patcher@ + + + +@llpswsounds|llpsw的大喇叭 (llpswsounds) +difficulty-lock@¨difficulty-lock-fabric +ryymr@ +@lazybeefix + +lazy-ae2-tweaks +coordinates-hud@coordinateshud +just-enough-botania@ +fumo-fumo +touhoupixelcanteen-a-farmers-delight-plugin@touhoupixelcanteen|幻雀妖 (Gensokyo Izakaya) +perfect-parity-the-garden-awakens-edition@ +perfect-parity-spring-to-life-reforged +hypertubes@hypertube|机械动力:超级管道 (Create: Hypertubes) +perfect-parity-spring-to-life-edition@perfect-parity-1-21-5 +create-geography@|机械动力:地理学 (Create: Geography) +create-apothic-enchanting@ +demis-enigmatic-dice@ + +@mpem|月夜性能优化 (Moonlit Performance Enhancement Module) +@eventbenchmark|事件性能测试 (EventBenchmark) +no-more-garbage-in-cell +pick-up-filter-puf@pick-up-filter + +identity-fix-morph@identity-fix + +stick-it@ +aimod +epca@|终末-归寄万物 (End-Parasitize and Convert All) +legendary-relics|传说遗物* + +true-power@|真正的力量 (True POWER) +ender-villages|末地村庄* +twilight-forest-villages@|暮色森林村庄* +poland-nature +amethyst-extra +villagers-windmill +extended-wrenches@ +why-stack-only-64|为什么才64个呢? (Why Stack Only 64?) +@digcooldown|挖掘冷却控制 (DigCoolDown) + + +potentials@ +deltaboxlib@ +gobbobs-animated-blocks|Gobbob 的动画方块 (GobBob's Animated Blocks) +glowingfootsteps|发光足迹粒子 (GlowingFootsteps) +simply-swords-overhaul@ +farms-and-foods@farms-foods +@achievement-fix|成就修复 (Achievement Fix) + +lang-magic-tweaker +spawn-dimension-choice@|诞生维度自选* +reforge-stone@|重铸石* +numericalbotany +cameraoverhaul-vintage@ + + +advanced-hoppers + +ars-meteorites|新生陨星* +the-hard-herobrine-mod + +tektopia-addons +jason-voorhees +biome-improvement-mindthemoods-pile-of-rocks +mochila@|简彩跃光* +soulytra +@advanced-tfc-blueprint|高级群峦蓝图 (Advanced TFC Blueprint) +@accesswidener-loader +improperui-forged@ + +enchantment-to-attack-faster|并非环取/攻击速度附魔非官方版 (Attack Speed Enchantment Unofficial) +@stopgrowth|停止生长 (StopGrowth) +squid-no-glitch +@permanent-night-vision|无痕夜视 (Permanent Night Vision) +@rems-carpet-addition + +colorful-hex@ + +bbl-no-rain-fog@ + +@be-quiet-negotiator +link15s-no-i-frames +jei-integration-reborn@|JEI扩展:重生 (JEI Integration: Reborn) +appliedsync +jei-uu-assembler@ +ominous-overlays +create-nuclear-shell@ +world-of-wonders +horrible-meteor-shower|陨石雨* +desertification@ +cinchs-abandoned-houses@ +curse-breaker@ +hundred-years-warfare@|百年战争* +biologica@ +oritech-things@ +potato-vehicle-industries +warfare-wings@ +avaritias-delight@|无尽乐事 (Avaritia's Delight) +mamas-herbs-and-harvest@ +vs-orbit@|瓦尔基里:轨道学 (VS Orbit) +touhou-little-maid-spell@|车万女仆:万法皆通 (Touhou Little Maid: Spell) +despawn-notifier|余影待终/掉落物消失提醒* +customnpcs-unofficial-from-betazavr|自定义 NPC BetaZavr 非官方版 (CustomNPCs Unofficial from BetaZavr) + +efficient-core-automatic-mining|Efficient Core自动挖掘器* +@bento_box|便当盒 (Bento Box) +custom-100-day-boss@|自定义100天Boss (Custom 100-Day BOSS) +endinglibrary@|终焉图书馆 (EndingLibrary) +cinchs-extra-torches@ +corpse-x-cosmetic-armor-reworked-compat@ +modular-angel-ring +magic-feather-replumed@magicfeather +essentialcraft-magic-reflux +ad-astra-star +neomopeds +create-more-parallel-pipes@ +create-garnished-reworked@ +create-shimmer|机械动力:微光 (Create: Shimmer) +blue-archive-school-banners +cialloblade|重锋:cia出如llo (CialloBlade) +windows-keyboard-fixes-returns +aquatic-torches-returns +cratetech-crate-storage +bigger-and-better@ +blabber@ +reducedores@ +durabilityrarity@ +ironfist-lite +shear-chicken@shear-chickens +no-moon-jar@no_moon.jar +@deep_space +blue-grove +quarkponders@ +sussy-sniffers +firefly-bush-backport@ +agritech-trees-automated-trees@agritech-trees +agritech-evolved@ +wealizh@|工业故事* +@hydrometallurgy|湿法冶金学 (Hydrometallurgy) +mekanism-ecoenergistics-unofficial + +woodlandfoxverses@|林间狐咏 (WoodlandFoxVerses) + + +swaying-garden|摇曳花园* +time-feeds-villager@|逝者如饲:村民 (Time Feeds: Villager) +ftb-backups-3|FTB 备份 3 (FTB Backups 3) +kurolib@ +trimmed@ +free-camera-api-tripod@|自由相机API-三脚架 (Free Camera API Tripod) +abelia@ + +simple-weather +simple-copy@ +natures-aura-render-fix@ +creakingchopperenchantment@ +daily-rewards@ +initialdimensionreborn@ + +@oo-ee-a-e-a-fabric + +redstone-chans-enchantment-expansion|红石酱的附魔拓展 (Redstone-chan's Enchantment Expansion) +the-plugin-mod@ +cave-vision +@el-addon-retrieve-to-slot +aether-gloves-for-all +reducedloot@ +@irisfixes|Iris 修复 (IrisFixes) +musicjs + +suspendtheserver|自动挂起服务器 (Suspend The Server) +screenshot-layers@ +anti-spider-climbing +rechiseled-chipped@ + +weatherdisplay@ +radium-fabric@radium-mod +cinnabar + +pquality@ + +mte-patches +happy-ghast-breeding@ +happy-ghast-flight@ +the-angry-ghast@ +morfonica-dolls@morfonica-in-minecraft +for-vanilla-flowers +@skillpractise|技能练习 (SkillPractise) + + + +bedrock-hotbar-offset@bedrock-hotbar +mss-more-slot-swap¨more-slot-swap +show-all-advancements@|显示所有进度* + +mana-display@ + +curse-forge|诅咒锻造* + + +disconnect-packet-fix@ +happyghast-on-1-12-2@happyghast_on_1.12.2|1.12.2的快乐恶魂 (HappyGhast_on_1.12.2) +automationera@|自动化时代 (Automation Era) +@tears-backport +lava-chicken-disc +lava-dennis +album-go-wall +forgotten-java +johanness-renaissance-rebirth@johanness-renaissancerebirth|约翰内斯的文艺复兴:火器之重生 (Johannes's Renaissance: Musket Rebirth) +swarm-infection@ +necro-rooted +mycelial-crisis@|菌丝危机:崛起 (Mycelial Crisis: Mushroom Rising) + +lethalsteelproject|致命拔刀计划 (Lethal Steel Project) +lovecraft-girlfriends-3@ +@faithful-mace +bard-craft +@bilibilimedia|哔哩哔哩WaterMedia兼容模组 +items-timer +neo-language-reload@ +@oxidizium +ixeris@ +substrate-sodium-addon@substrate +hide-item-frame@|隐藏物品展示框* +@smoothmaps +neoessentials@ +structure-layout-optimizer@ +mutant-creatures-legacy +dynamites-overhaul@ +dynamite-addon¨dynamite-addon-fabric +maid-mana-source|女仆魔源* +maidens-merry-making@mamas-merrymaking +bbl-invisible-lights@ +superior-trees@ +underground-rivers@ +improved-village-placement@ +@photosynthesis +@mineno +slashbladetetra + +irons-spells-n-spellbooks-dynamic-skill-trees@ +spell-elemental@ +ward-ring-extension-for-irons-spells-n-spellbooks +dungeons-and-combat-x-irons-spells +smallcolonies +farmers-cutting-regions-unexplored +serene-landscapes@ +blood-arsenal-reawakened@ + + +spell-colonies +nature-reimagined +ominous-bottle-add +only-hammers@ +auto-resource|自动资源* +iu-additions@ +rubiks-cube|魔方* +clockworklib@ + +fabridge@ + +true-fullbright +quickslots +hide-hud-in-third-person-view@hide-hud-third-person +automlg@auto_mlg +elytraautopilot@elytra_autopilot +simple-conveyor-belts@ +smidgeon-o-bliss-remastered@smidgeon-o-bliss|片刻满足 重置版 (Smidgeon o' Bliss REMASTERED) +xl-food-reborn|超多食物:重生 (XL Food Mod Reborn) +create-spin-spawner +vs-rotanator +create-refilling-boxes@ +cbc-chemical-warfare|机械动力火炮:化学与生物战争 (CBC: Chemical Warfare) +cbc-warium-projectiles@|机械动力火炮:Warium炮弹 (CBC: Warium Projectiles) +create-colored +create-law-and-order|机械动力:法律与秩序 (Create: Law and Order) +blockexporter@ +fix-attack-lag@|修复攻击卡顿* +@clienthings +@misinput +lavablocker@ +gildedarmors@gilded-armor|鎏金盔甲 (Gilded Armor) +inventory-management-deluxe +runningmapmusic|跑图音乐 (RunningMapMusic) +lava-chicken-music-disc@lava-chicken-music-disk +porting-dead-libs@ +panoramica¨panoramica-fabric +create-mt-integration|资源统合-机械动力配方附加* +valkyrien-skies-war-and-peace@valkyrien-warpeace|瓦尔基里:战争与和平 (Valkyrien War and Peace) +sillys-auto-totem@ +repairables-anvil@|可修复的铁砧* +@throwable-bricks +@now-time|准点报时 (Now Time) +fluidjs@ +hybridcompat|混合兼容 (HybridCompat) +@recipecooldown|配方冷却 (RecipeCooldown) +counter-mod +lotr-renewed-class-mod|魔戒种族 (LOTR Races) + +craftable-chain-armors|锁链盔甲配方 (Chain Armor Recipe) +item-cooling-reduction@|物品冷却缩减* +yosbs@ + + +@no-bugs +dark-window-bar@ +sodium-core-shader-support@ +@anvilcraft-headtap|铁砧工艺:敲你脑袋 (AnvilCraft: HeadTap) +hearts-in-a-bottle@ +copper-tools-and-shears@|铜质工具和剪刀 (Copper Tools and Shears) +windchime-unofficial-continued@ + +potionsplus +tinkers-wood@ +illuminated@ +galosphere-argent-edge +brutality-a-terramity-addon +free-epic-games@|FE 游戏框架 (FreeEpicGames) + +fabric-database-h2@|H2数据库* +tokien-theme-bq|更好的任务-托尔金主题 (Tolkien Theme [BQ]) +tpa-utilities + +shutup-opengl +maid-command|女仆指令* +speedy-hopper-vanilla +suggestions-fix-fabric +no-ixapi@no.ixmodapi +@chinese-ancient-blade|中华古刃 (Chinese Ancient Blade) +epicfight-zylob@epicfight-sword-light-modifications|史诗战斗:刀光修改 (EpicFight Sword Light Modifications) +perfect-parity-pale-garden-awakens-neo +expressive-advanced +philia-amulet|友爱护符 (PhiLia Amulet) +stronger-fire-boss|原焰帝臻* +myec@|更多渴望:附魔与制造 (More of Yearn: Enchants & Crafts) +abandoned-urban|废弃城市 (Abandoned urban) +fungal-hazard|蕈骸迷途* +more-useful-copper-2-0@more-useful-copper|更有用的铜 (More Useful Copper) +boom-bombs@ +polars-exploration-additions@ +@happy-ghast-upgrades +ozymandias-sundries +tensura-enigmatic +createtraincontrol@|机械动力:列车控制 (CreateTrainControl) +create-collection-bundles@ +create-enhanced-mastery +create-industrial-tools@ +create-smart-bounds@ +create-fantasizing-again@|机械动力:又在幻想了 (Create: Fantasizing Again) +crafting-station-jei-edition-updated@ +uncraft-everything@ +@videoplayer +net-music-play-list@|网络音乐机:播放列表 (NetMusic: Play List) + +gregs-modern-construct + +smart-key-prompts@|灵活按键提示 (SmartKeyPrompts) +@zero-whitelist|Zero白名单 (Zero Whitelist) +milometer|计程器* +@pearlchunkloading|珍珠加载区块移植 (Pearl Chunk Loading) +clean-drops +auto-replace +@footprint + +simple-villager-follow@ +tinkers-experience +hedgehog-companion@ +i-want-to-spin@|我要开转* +kiss@kiss-fabric +@mc-bds|北斗导航 (MC BDS) +neo-the-titans@|新泰坦生物:撼世之物 (Neo Titans Mod:Earthshak Creature) + +nuggets-repair-items@|矿粒修复物品* + + +terra-atmos@terra_atmos|群峦环境音效* +tlm-true-power@true-power-of-maid|车万女仆:真正的力量 (TLM: True POWER) + + + +@splash-window +neoenchant +@showcase +enhancedtooltips@ +locate-fixer +journeymap-fixes +ancient-structure@ancient-structures + +wizard-samurai-irons-spells-addon¨@wizard-samurai-irons-spells-addon|Wizard Samurai - Iron's Spells Addon - 更新较慢 +survival-instinct +enderzoo-patched@enderzoopatched +illager-keep +codex-of-champions +ars-controle@ +medieval-craft-historical-firearms +too-many-withers +reliquified-l-ender-s-cataclysm@ + +findshit@log-creator-finder-findshit|找史大王 / 日志溯源 (find log's creator / findshit) +enchantment-lookup@|附魔查询* + + + + +@mods-checker|模组校验 (ModsChecker) +no-enchanting-xp-requirment +client-dynamic-light|客户端动态光源* + +multiyggdrasil@ +thaumcraft-4-patched +patchful +gtnh-customizer@ +view-sounds@ +ae-inventory-profiles +tooltips-reforged@|提示框:重铸* +@wyr +soaring-phantoms@ + +ritchies-projectile-library@rpl +modopedia@ +@translate-allinone|一体化翻译 (Translate All in One) +button-fix@ +@birthday-fabric|生日模组 (Birthday Fabric) +bucketstacking +creeper-no-break-blocks@ +create-cog-hud@|机械动力:齿轮 HUD (Create: Cog HUD) +@createtools-n-weapons +create-pipe-networks@ +jiagu-reappearance|岁在甲骨* +multicolored-redstone-lamps +reliquified-twilight-forest@ +witch-tower +the-nightmare-000@ +meowmere@|彩虹猫之刃* +@fallenflowers-server-economy|Fallenflower的服务器经济 (Fallenflower's Server Economy) +deadout-medical-supplies|死亡突围医疗用品 (Deadout Medical) +@thermal-shock +better-questing-npc-integration|更好的任务-NPC扩展 (Better Questing - NPC Integration) + +eu2emc|EU转EMC能量转换器 (EU2EMC) + +simplesorter@|简单整理 (SimpleSorter) +spawncursion|生成式入侵 (SpawnCursion) +grass-be-gone|不要草* +tacz-unidict|TACZ:铳械协议 (TACZ: Unidict) +gem-lichens|宝石地衣* +lethality-a-terramity-addon@ +lootr-fixes +no-name-provideds-potion-fruit@potion-fruit +fungus-stew +auto-sapling|自动树苗种植* +alans-bees +snack-sticks@ +fish-fix@ +stuttering-screen-lag-protection +tilefinder@ +immersive-furniture@|沉浸式家具* +modernnetworking +like1-8 +spoduos-future-mineration +enderio-continuous|末影接口延续版 (EnderIO Continuous) +enchantment-broker@ + +new-dawn +enhanced-glass +hospitals@ +comfy-cozy +epicnpc|史诗战斗NPC (EpicNpc) +epic-fight-script-extension|史诗战斗:脚本扩展版* +@undead-transformation + +skullskinless|头颅无皮肤/易颜得帧 (SkullSkinless) +staynight|永夜定驻 (Stay Night) +blockblocker|方块放置阻止/抑用挡置 (BlockBlocker) +shoving-shovels@ +electric-coating|不止电池 / 电力镀层 (NotOnlyBattery / Electric Coating) +araxers-bestiary@ +better-questing-immersive-engineering-multiblock +bloodyquests +croaker@ +crawl-on-demand@ +gaze-a-malum-addon +osce|矿石菌种社区版 (OreSpawn Community Edition) +explosive-arrow +more-relics@ +no-sun@no-sun-mod|暗无天日* +opposing-force@|针锋相对* + +@pingfix +@volumescroll +talk-balloons@ +health-indicator-txf@ + +snowy-weather + +dimensionlock@ +fluidium|锍* + +peritia + +inventory-sort@|背包整理* +corpse-kibou-no-hana|希望の花 (Corpse: Kibou no Hana) +redyeable +@natural-motion-blur +@modpack-checker +convenient-achievements +vintage-vibes@ + +@smelter-the-hedgehog +@hopper-the-hedgehog +custom-trades-mod +tameable-zombie-horse-and-skeleton-horse|可驯服的僵尸马和骷髅马* +mi-tweaks +qa-villager-tweaks@qa-villager-extends|Qa 村拓展 & 废物革新 (Qa Villager Extends & Waste Innovations) +multiblocked-extended-compatibility +enum-extender-js +@btc + +no-pigs +vanimals@ +wind-charged-weaponry@ +untagged-mobs +enchanted-potato +cit-for-nbt + +bonemealtweaker +hellstone-golem|狱岩魔像* +netherstar-crafting|可合成的下界之星* +tutes-cn-sweetinks-items@|塔兹与甜墨的物品 (Tutes-cn & Sweetink's Items) +i-am-steve@i..am-steve +backported-stufff + +tumbleweeds@ +mending-mirror|破镜重圆* + +natures-life +yggdrasils + + +@deepseeks-enchant|DeepSeek的附魔 (DeepSeek's Enchant) + + + +isitwaxed +simple-hp-bar@ +login-hp-fix +shape-shifter-curse@|幻形者诅咒* + + +tinkers-planner-reborn@|匠魂蓝图:重燃 (Tinker's Planner Reborn) +hunger-overflow +nocreeper +mo-creatures-extended +skippy-pearls +spelunkery-plus +forge-better-redstone +jeb-just-enough-book@justenoughbook +pal@ +data-anchor@ +elytra-hopping +oh-more-wandering-trades@|更多游商交易* +beacon-anti-phantom@|不时轻轻肘击幻翼的邻座信标同学 (Beacon Anti-Phantom) +@flexible-painting|灵活的画 (Flexible Painting) + +cooler-animations + +hardcore-architect + +carpet-neoforged@neoforge-carpet +no-campfire-smoke +tiny-tasks +fancy-outline +echo-compass-hud@ +decorative-stands +confluence-otherworld-gun-fix@ +cauldronpp@cauldron++ +sbm-cardboardboxes + + +bedrock-age@|基岩时代* + +return-scepter|回程魔杖* +@koniavacraft|娜拉工艺 (Koniavacraft) +emojicraft|Emoji工艺* +kylin-arm|麒麟臂* +server-hats@ +forgotten-ruins@ + +creeperhost-presents-steves-carts@ +perspatium@per-spatium + +offlawn-legacy +metalborn +@wizards-mod +mo-creatures-nostalgia-edition@ +mocreatures-awakened +sterling +cuisine-tfc|料理群峦 (Cuisine TFC) +@natural-temperature +silent-gear-metalworks +treetap@ +better-cave-update +@affix +starry-end +dynamic-trees-for-cobblemon +immersive-portal-gun-for-forge@ +adorable-hamster-pets@ +infinite-lava@|无限熔岩* +ethereal-shots|无限箭制 (Unlimited Arrow Works) + +epic-fight-super-golem|超级铁傀儡 (Epic Fight - Super Golem) +fallen-log-hideout +pastel@pastel-mod|彩绘世界* +mob-catcher-unofficial +retro-pet-items +confluence-dimension-patch|汇流来世维度补丁* +convenient-storage|便捷存储* +legendreliclib|传世遗产库 (LegendRelicLib) +jauml@ +nemexlib@ +cryonicconfig@ +knight-lib@ + + +@okom + +craft-slabs-back-into-blocks@ +highland-statue +restore-ore@|复原矿石* +factory-blocks@|工厂方块* +camouflaged-doors +rotten-planks-and-logs +create-extended-bogeys-borked-addon +create-unify-updated-to-create-6@ +create-arm-made-cuisine|机械动力:臂力臂力炒菜 (Create: Arm-made Cuisine) +create-cultivation-craft@|机械动力:栽培工艺 (Create: Cultivation Craft) +kaleidoscope-cookery@|森罗物语:厨房* +retroemi-forge@ +@pearlecho +@mcdaycounter +minecolonies-war-n-taxes +falling-down@ +more-red-x-cc-tweaked-compat@ + +@speed-uuuuuuup|加加加加加加加速! (Speed Uuuuuuup) + +wither-reincarnated@ +biome-snapshot@ +toros-auto-attack@ +creeperfire|自定义烧货 / 苦力怕阳光下燃烧 (CreeperFire) +fastspawner|刷怪笼渲染优化/产器速算 (FastSpawner) +sophisticated-storage-plus|存取思深/精妙存储扩容* +whaleborne@|鲸帆远航* +uniful@ +newspaper-big-book-bibliocraft-legacy-backport +bic-clipboard +templates-2@ + + + + +workstation-recipe-exporter@|可视化配方编写* +simple-auto-attack +hostile-to-neutral +tracer +fishing-tick-fix@ +fzmm@ +pasteljei@|彩绘世界JEI (PastelJEI) +e4mc-retro@ + +mantlejs@ +one-enough-hand|只手遮天* +persistent-moon-phases +sakurapack-compatability-patch +cattlestrophic@cattlestrophic! +ae-recipe-tool +minecraft-cursor@ +stalker-creepers-fabric@ +epiv-fight-l-enders-cataclysm-compatibility|史诗战斗灾变兼容 (Epic Fight & L_Enders Cataclysm compatibility) +lunar-nether-backport +lookinmyeyes +more-relics-more-rpg-content@more-relics-rpg +backstab-reforged +armamentarium + +remnant-bosses@ +choccos-mobs@ + + +uncrafting-table-xiaoyu-2009|拆解台 (Uncrafting Table) + +aewirelesschannel|AE无线频道 (AE Wireless Channel) +infinitepower|无尽能源 / 能量叠生 (Infinite Power) +hoshikima@|随意作品* +create-bugfix-clipboard-patch@|机械动力:剪贴板修复 (Create Bugfix: Clipboard Patch) +tool-disassemble|拆器碎散/匠魂工具拆解* +summer-to-life|夏意盎然 (Summer to Life) +@freedraw +geckojs@ +sanandreasps-manager-pack + +touhoulittlemaid-orihime@|车万女仆:织姬 (Touhou Little Maid: Orihime) +more-mod-tetra|更多Tetra模组锻造材料* +cataclysm-dimensions@cataclysm-dimension|灾变:维度* + +misttaczskills@|TaCZ:圣化技能扩展 (MistCloud Tacz Skills Extension) +quality-railway@|品质铁路* + +custom-mob-attributes@ +custom-durability@ +@dragons-egg(s) +zombie-variants@ +extra-carts +fairy-factions-revived +netherited@netherited-fireproof¨fabric-netherited +creeperhost-presents-soul-shards@ +myths-n-legends@myths-and-legends|神话与传说 (Myths & Legends) +@snackcraft|零食工艺 (SnackCraft) + +copper-backport@ + +@shield-indicator|盾牌指示器 (Shield Indicator) +a-bastion-remnant-treasure-reset|堡垒遗迹藏宝室重置 (Bastion Remnant Treasure Reset) +a-bastion-remnant-hoglin-stable-reforged|堡垒遗迹疣猪兽棚重铸 (Bastion Remnant Hoglin Stable Reforged) +colonial-arcana-minecolonies-addon|殖民地魔法 (Colonial Arcana) + +fires-ender-expansion +thetitansneo@|泰坦生物Neo (TheTitansNeo) +vectorientation-reneoforge +copyid@|复制ID (CopyID) +@a-lightcolor-beacon +@surveyor +@create-portable-packaging +create-more-pipe-bombs-in-packages@ +create-bugfix-schematic-patch@|机械动力:蓝图补丁 (Create Bugfix: Schematic Patch) + +create-ornithopter-glider@ +create-train-parts@ +@breakable-blocks +flux-network-x-cc-tweaked +twotility +opticubes +closets-by-smplesco@ +variety-chests-mod +light-detector +quality-hails +ancient-structures-edo-japan@ +tiger-shark@tigershark|海虎 (TigerShark) + + + +better-end-cities-better-end@better-end-cities-for-betterend|更好的末地城 (Better End Cities)¨better-end-cities-vanilla@better-end-cities-base|更好的末地城 (Better End Cities) +fallen-gems-affixes +skill-tree +blatium@ +trimica@ +fantasy-weapons-medieval-series@fantasy_weapons +@lsktp|磷光传送 (LSKTP) +ksit@ +bestia@ +@itemfinderinall-items +filterchat +kit-keep-inventory-timer-keepinventorytimer +useful-luck@ +@sneak-fertilizing +p1neros-epic-fight-leawind-compat +custom-entity-leveling@|自定义实体等级* +no-monster-rooms +@carpetrmsaddition +@fireworkindicator +squeedometer-reforged-special-port + +difficulty-patch +squake-reforged@squake-fabric-updated¨squake-fabric-1-20 +squake-reforged-special-port +brigo@ +ae2-web-integration@ +skillet-man-core +p1neros-dialogue-lib + + +create-arm-made-barbeque|机械动力:臂力臂力烧烤 (Create : Arm-made Barbeque) +indestructible-blocks + +epic-fight-super-chef +epicfight-nightfall|史诗战斗:夜幕 (EpicFight-Nightfall) +genesis-official +featurecreep + +fabric-orm-jimmer@ +aces-spell-utils@ +targeteventbackport +silk-kt@silk + + +@playercommands-(old-mc) +legends-forge-series-vikings-n-northerners +tinkers-battle-spades +@its-not-real +ly-meteors +ashvehicle +@smart-absorption +@mooshees +city-of-chambers +tower-of-chambers@towers-of-chambers-neoforge + +ancient-structures-chinese@ +eypipes +shipping-bin +hbm-nuclear-tech-mod-community-edition@ntm-ce|HBM的核科技社区版 (HBM's Nuclear Tech Mod: Community Edition) +gte2-coremod@ +japan-props@ + +one-enough-item@ +o123456789@ +friendly-chests-no-fluid +herios-floral-expansion@ +pinkcabbage-transparent-betterscreen@pinkcabbagetransparentbetterscreen|粉红大包菜的屏幕透明度优化 (PinkCabbage Transparent BetterScreen) +wastify-returns +sillys-crossbow-fix@ +thaumpotion-tweaker@ +novoatlas@ +resource-pack-tweaks +night-vision-decay-fix|夜视衰减修复* +roid-tweaker +translatorpp@ +modular-machinery-community-edition-addons +randomaddon|随意之作 (Random Addon) +myhead|持器射首 / MyGO 你个头 (BanG Dream! It's MyHead!!!) +boss-dps-tracker|查其所伤/Boss伤害追踪器 (Boss DPS Tracker) +wandering-trader-may-leave@ +mod-tabs +totem-bar@ +visualores-meowmel +savebabystriders +bygone-nether-fixes@|逝去的下界修复* +bossesrise@|首领崛起 (Bosses'Rise) + +advancementinfo-update +expanded-mace-enchanting@ +silky-spawners +starhud@ +celeritas-dynamic-lights@ +resistance-balancer@ +silkier-touch@ +wither-spawn-fix@|凋灵生成修复* +accelerated-rendering@acceleratedrendering|加速渲染* +cii@ +simpler-wooden-pipes@ +garden-cloche-backport +bh-boss-hatred@boss-hatred|首领仇恨 (Boss Hatred) + +camol +bbb-unforged@ +performance-monitoring-enhancer +create-upsizing@ +better-world-loading-forge@better-world-loading¨better-world-loading-fabric + +apocalypse-minimap-hud@apocalypseminimaphud|启示录:小地图Hud* +advancementnomore|进度移除 (AdvancementNoMore) +collisium +dypsis@ +chat-plus@ +mcreatormemfix@ +@atlas +legacy-tweaks@legacytweaks +easy-elevators@|简单电梯* + +davincing +aeronautical-radio|航空无线电* +hunter-vs-mice@|猎人鼠鼠游戏* +citymod-one-block-one-building@city_mod +gedrite-mod@ +@shorkie +enchantable-boat@ +throw-bricks +animal-pens@animalpens + + + +@glys-can|GLY的罐头 (GLYCan) +fargo-soul|Fargo魂石* +@brokenbows|破损弓 (Broken Bows) +mekanism-trimming@|通用机械纹饰* +teleportcakes@|跃迁蛋糕 (Teleport Cakes) +repair-amulet +alpine +clientchatclean|客户端消息清理 (ClientChatClean) +clickmobs +vlib@ +wabbanode-companion +@mcmti|麦克风语音识别文本输入 (Microphone Text Input) +powernexus-menu +hit-delay-fix +betterexcavate|更好的挖掘机制 (BetterExcavate) +optimization-of-campfire-smoke|营火烟雾优化 (Optimization of Campfire Smoke) +armored-combat-enhancer + +animal-hats@animal-hats-yeah +@raid-restore +asgardandelion-for-botania +trotting-wagons@ +grindstonehoning +rainbowwrenchforjei-reforge|彩虹扳手:Forge版 (RainbowWrenchForJei: ReForge) +better-locate-structure-command|更好的结构定位指令* +att-miss|闪避攻击* +energizexp@ +no-more-magic-choices|更好的铁魔法UI* +patternbetter@|更好的ME样板供应器 (Pattern Better) +legacy-skins@ +@oh-my-pc +vsprinter@ +clickvillagers +@button-packet-id-fix +accessories-compat-layer@ +world-downloader@ +tameable-guinea-pigs +familiarslib +dmr@|龙骑士重制版 (Dragon Mounts Remastered) + +avaritia-expand|无尽贪婪 : 拓展 (Avaritia : Expand) +polaristrading|北极星市场方块 (PolarisTrading) +ecliptic-seasons-multimod-patch|节气:多维修补 (Ecliptic Seasons: MultiMod Patch) +random-things-returns +infinite-storage-cell +delta-technology|八宝粥行动* +elegant-spells@|雅致咒术* +@seelescraft|希儿的工坊 (Seele's Craft) +readyhomes|随时可住 (ReadyHomes) +arknights-weapon|方舟武器* + +illager-warship@ +asian-fountains@ +illager-chef-trader +skyblock-villager +@redstoneer-villager +perrys-urban@ +neo-blahaj + +teleportation-crystal|传送水晶* +majo-spell-enchantment|魔女的魔咒 (Majo's Spell Enchantment) +oaks-capes@ + +cobblemon-ride-on@|Cobblemon:骑乘! (Cobblemon: Ride On!) +clayium-additions +farmers-tfc|农夫群峦 (Farmers TFC) +oaks-delight@ + +pathfinding-edition-for-minecolonies@|殖民地寻路大修* +clicksigns@ +@salted-fish-craft|咸鱼 (Salted Fish) +herios-helian-mod@ +decorative-food@|装饰性食物* + +anvilcraft-alloyextension@|铁砧工艺:合金扩展 (Anvilcraft: Alloy Extension) +arkifs-hoverboard-mod +glow@glows +leaf-villager-trader +guard-villager-trader +hunter-villager-trader +garbage-collector-villager +more-traders@ +ae2-better-villagers@ +harvester-trader +railman-villager@ +dimensionaltraders +taxbiometrader@tax-leons-biome-trader +quickelytraswapperplus-client@elytraswapper+ +@elytrakey +elytraswapperplus +taste-fatigue@|味觉疲劳* +realistic-nametag@ +hitboxplus@ +@hittable +hitmarker +autolandingwater@|自动落地水 (AutoLandingWater) +skygrid-reloaded@ +@stone-wood-industry|石木工艺 (Stone & Wood Industry) +roomopolis@ +bbl-placers@ + +draconic-legacy-models|龙之进化旧版模型* +furnaces +gtconstruct +rain-be-gone-ritual@ +the-vegan-option|素食者的选择* +gensokyo-delight-youkais-feasts@|幻想乡乐事 ~~ 妖怪们的飨宴 (Gensokyo Delight ~ Youkais' Feasts) + +tuttas-doors@ +@effectlivingdead|行尸走肉 (Effect Living Dead) +vs-chunkloader@|VS区块加载器 (VS ChunkLoader) +create-blocks-bogies@blocks-bogies +create-netherite-additions@ +create-sophisticated-backpacks-compat@ +create-item-pets +c-bc-nukes-6-0-port +plushieverse@ +thavma@ +arsarms@ +yorupo-mod@ +yande-mod@ +gtcefucontent +mcheli-overdrive-ext@mcheli-o-ext +iron-biplane@ +realistic-computers + +boss-mob-enhancer +flight-api|飞行 API (Flight API) +unlimited-spawners@|无限刷怪笼* + +@minecart-visualizer|敞骑速视 / 矿车信息可视化 (MinecartVisualizer) +@shadowborders +authenticate@|认证* + +unbinilium +veinbreaker@ +actions@ +i-have-no-mouth-but-i-must-chat@ihavenomouthbutimustchat +renderscale@ +proportional-destruction-particles +tacz-ammo-query +fast-happy-ghasts +@starhudforged +@slotted-armor-hud + +@say-sorry! +@playerautoma +im-fast@ +@unpath +no-more-popups@ +sussypatches@ +@simple-item-editor +baby-zombie-removal@ +immersive-sounds +boatview360@ +@my-resource-pack +oaks-bits@oaks-bits-and-bops +@starsource|星源拔刀剑 (Star Source Blade) +snow-waifu-spell|雪下的誓言* +mob-farm-trap@|香草刷怪塔陷阱强化:涌渊敌冢* +twograve +perrys-decorations@ +perry-s-decorations-2 +bookshelf-extended-enchanting-reach +enchanter-fix@ +dynamic-regen-enhancer +guinea-pig-variety@ + +@areas-hint|域名 (Areas Hint) +yammo + +fps-display-doubler@ +inventory-stages|背包阶段* +gregmek|格雷矿物通用机械支持 (GregMek) +@armor-hud +@ukus-armor-hud +mob-flow-utilities@flowtech-mob-systems + +ftb-materials +the-great-below +illagerblabber@ + +serene-season-extended-fix@serene-seasons-plus +create-enchantment-industry-plus@ +boiled-one-unleashed +creaturecraft-plus +war-elephants + +one-click-one-block-1c1b@oneclickoneblock|点到为止 (One Click One Block) +@translatabledebugoptions|可翻译调试选项屏幕 (TranslatableDebugOptions) + +suppressopengl1280@|OpenGL错误隐藏 (Suppress OpenGL Error 128(0-2)) +fexs-vehicle-mod@fvtm +otterlib +dimban|维度禁用 (DimBan) +onlyoneitem|仅存一物 (Only One Item) +bedload|自定义区块加载器 (BedLoad) +@unreachable-nether + +@detail-armor-bar-reconstructed +@auto-fishing + +indrevjei@|工业革命JEI (IndRevJEI) +fpresearchpatcher|飞向未来研究数据包兼容 (Futurepack Research Patcher) +me-infinity-cell|ME无限元件 (ME Infinity Cell) +air-jump +more-sniffer-flowers@|更多嗅探兽花卉* + +enchantability|附魔能力* +ender-lead@|末影拴绳* + + +create-growableores-compat@creategrowableores-compat + +gears-n-kinetics@ +valkyrien-sails@ + +moo-fluids-modern +yan-from-ff14@|FF14的羊 (Yan from FF14) + + +tfc-cuisine@|群峦料理 (TFC Cuisine) +tfc-no-collapse|群峦传说:塌方禁止 (TFC No Collapse) +no-sleep-chat-overlay-nsco@no-sleep-chat-overlay-(nsco) +funkys-fancy-furnaces@ +timber-enchantment +@alternative-chunkloading +@particulate +haydenapi +spore-inquisition +ice-and-fire-spartan-weaponry-extras +@vanitydungeons +@fcitx5-enhancer +kubejs-actually-additions@ +vibrative-voice@ +spawnlock +enchantment-custom-table@|自定义附魔台* + +navigator + +keeping-inventory-reborn +camel-extend|骆驼拓展* +confluence-music|汇流音乐* +cancel-attack-cooldown|取消冷却间隔* +surprising-loot|藏奇速释/惊喜战利品* +@onlykeys +flair +minecraft-comes-alive-reforged|凡家物语·重制* +cave-mita-dweller@mita-dweller +eeeabs-mobs-death-mode +revivetoken@|复活币 (ReviveToken) +real-filing-reborn-cabinet-based-item-storage@ +quivers +infused-crystals@ +mendingremover@ +auto-vanilla@autovanilla +underground-villages-stoneholm@underground-village,-stoneholm +gep@ + +more-harnesses@|更多挽具* +vanilla-aiots@ +nether-villager-merchant@ +end-villager-trader@ +deep-dark-trader@ +random-generator-block +devour +quantum-storage-reborn@ +library-section@ +move-subtitles@ +@modrenf3 +modern-inline@ +culler@ +@playernoticeboard +extendedae-plus@ +@ae2uel-extra + +gems-realm@ +arrowcollect@|箭矢回收修复 (ArrowCollect) +@primitivemobsrevival +steampunk-clocktower +piglin-outpost|猪灵前哨站* +nolando-structurez +skinlayers3d-customskinloader-bridge@ +puffish-biome-dither@biome-dither +voracious +@minecraft-dungeons-weaponry +gentech-block-generation@ +byzantine-styles-pack-for-minecolonies + +aquaculture-tinkers@ +cups +blue-archive-halo@|仿碧蓝档案光环* +minebackup|存档时光机 (MineBackup)¨@minebackup|存档时光机 (MineBackup) - 推荐的方式 +ecological-replenishment-station@|生态补给站* +@advancedhostility|进阶仇恨 (Advanced Hostility) +aggro-fix@ +chest-curio-items@|箱子里的小饰品* +galaxysimagination|Galaxy的奇思妙想 (Galaxy's Imagination) +delightful-cuisine-for-woodheads-reforged|懒人厨房·重制 (Delightful Cuisine for Woodheads Reforged) +@loans-cinema +banana-baking@ +duacan-delight|岩城乐事* +slashblade-refabricated@|拔刀剑:重织 (SlashBlade: Refabricated) +ender-dragon-fix + +detailab-compat@|细节盔甲兼容 (Detail Armor Bar Compat) +calypsos-mobs@|卡里普索的生物 (Calypso's Mobs) +dirtcraft-unoffical|泥土工艺 - 非官方版 (DirtCraft - Unofficial) +specialmaterials@|材料 (Materials) +@onlytpnext|仅传送Next (OnlyTPNext) +easy-survival-command|简单生存指令TP (EasySurvivalCommand) +@gensokyo-reverie-of-lost-dreams|梦隐的幻想乡 (Gensokyo Reverie of Lost Dream) +reliquified-ars-nouveau@ +requesting-interface@irequesting +applied-experienced@ +plain-cars-pack@plaincars +gt-craft-iv-mts@gt-craft-ivmts +ad-astra-more-structures@ +perfect-dodge|完美闪避* +simple-paraglider@|简易滑翔翼* +human-gunner +tacz-headshot-extension|TaCZ 爆头机制扩展 (TaCZ Headshot Extension) +dream-in-a-manhunt + + +@thesunrise +more-critters@|更多异兽* +oelib@ +itemblacklistfixed|物品黑名单修复版 (ItemBlackListFIXED) + +voxelmap-patch +xaero-train-map@ +traversable-leaves-neoforge¨traversable-leaves¨traversable-leaves-fabric +@etched-extension +vs-addition-continue|VS Addition Continue - 更新慢¨@vs-addition-continue|VS Addition Continue - 更新较快 + +clavis@ +luckyblock-lib + +nopackcompatcheck@|禁用资源包兼容性检查 (NoPackCompatCheck) + + +crabbers-delight-expand|蟹农乐事:渔冶锭整 (Crabber's Delight Expand) + +offlinegrowth@ + +fauna-and-orchestra@faunaandorchestra + + +contact-love-rekindled@contact-loverekindled|往来:旧情复燃 (Contact: LoveRekindled) +autosow-by-neni-o@ +piglin-join-wto|猪灵加入了WTO (Piglin Join WTO) +keyboard-detector@|键位检测器* +potion-pill|药水药丸* +inhrtburys-coin|Inhrtbury的金币 (Inhrtbury's Coin) +@firesight +epic-villages +@brainfk-in-minecraft +@aviator-dreams-reloaded +russian-dream + +cbc-ballistics +create-programmable-pals +create-ore-excavation-plus@ +@createtreadmill|机械动力:跑步机 (Create:Treadmill) +create-more-package-couriers@ +regius@ + + + +dont-make-me-see-red|别让我红温* + +peyros-scythe|佩伊洛的镰刀 (Peyro's Scythe) + +@readstar|占星术 (ReadStar) +illage-and-legend +giant-dead-oak-tree@ + +ascension-nether +ascension-end +@echovoids +soulful-nether@soulfulnether +zefs-nether +the-end-update-concept +@ending-biomes +charred-horizons@ +@nether-update-expanded +i-see-my-armored-hand@ismah +naturally-spawning-withers@|自然生成凋灵* +wither-infection@ +creeper-infection@ +long-books@ +ftb-chunks-recoloured +jei-hover-search@ +rollable@ +invisibility-aggro-fix@ +quick-skin@ +countryball@minecraft-countryball-mod +tinkers-construct-emergence +pointblank-jelly@pb-jelly +terrabnormals +extra-mining-world +herobrine011840s-nether-biomes +my-end +update-ender-a-reimagine-of-the-end +@air-puffers +companions-mod@|同伴! (Companions!) +@ai-chat|AI聊天 (AI Chat) +apothic-attributes-extension|神化属性拓展* +databank@ +randomtp@ + +instantunify-reforged +@blockfire +morphoverlay +display-prior-work-count +extended-scripts +natures-aura-simplified|自然灵气:简化 (Nature's Aura Simplified) +bed-spawn-backport@|想设就设* +visible-effect@|药水效果显示* +@config-manager|设置管理器 (Config Manager) +simple-datapacks@ +shulkerrrt@srrt +custom-icon-sets +gregic-probe-ceu +@antilootgame +graphene@|石墨烯性能优化* + +talents-fabric@talents +@combat-maids +voxelfurni +voxels +voxel-pairing +no-stuck-healing +pixelcompress +matrinoxes-village-names +redlink-wireless-redstone-control@ +@nekohashizuku-blade|雫拔刀剑 (ShizukuBlade) +xtones-reworked@ +@tinkers-enchanting +new-woods +ennuis-bigger-inventories@ennuis_bigger_inventories +@soldisco|生活调味料:探索 (Spice of Life: Discovery) +missing-cookery +@farmers-tea-resteeped +peruvians-delight@ +productivefarming +brewin-compat-delight@cocktails-delight|鸡尾酒乐事 (Cocktails Delight) +kubejs-tweaks +krypton-fnp@ +neoauth@ +crystalix +chisel-chipped-integration +refined-types@ +mystical-automation@ +utility-vest +little-big-redstone@ +@stone-is-stone +almost-unified-ie +@trident-are-weapon +collect-seeds +create-delicious-teas@ +@showtime +@windup-music-box +babylonian-empire-origins +mc-mods-the-arcanist-gear +epitaphs +biologist|生物学家* +wandering-trapper2|流浪猎人2* +skiing2|滑雪* +backported-animal-variants@ +explore-ruins-aether@ +warpdrive-extras@ +@chest-transport-reloaded +lrs-blockollection +@the-what-tools +tacz-chaoscrafts-apocalyptic-arsernal +detail-armor-bar-re-equipment@|细节盔甲条:重装 (Detail Armor Bar Re-equepment) +justenoughanvilcraft@jeac +boat-fly|船飞行* +finite-water-infinite-lava +transfer-labels@ +growth-accelerator-tiers +astages-curios +astages-pufferfishs-skills +sound-physics-perfected@ +the-sound-of-rain@ + +greekfantasy-unofficial +musketeer-illager-port +cataclysm-apotheosis-addon-neo +iron-apples-iron-series@ +@mangos-compat-delight +tinkers-oreganized@ +simple-basketballs@simple-basketball +decorative-blocks-repurposed +create-mechanical-botany@ +@insecticide + +naked-gauntlet|焰眼掉装* +only-one-item@ + +aimbow-bow-hit-indicator|弓箭瞄准 (AimBow) + +@tt20forged +@worldfarview +@fixmcstats +soul-return-scroll|还魂符* +slashblade-murasame@|拔刀剑:丛雨丸* + +dungeon-tools-2|地牢工具 2* +gregtech-beyond-coremod +create-compatible-storage@ +antique-rockets@ +meta-changer +chromatic-enchantments@ + + +tfc-detail-armor-bar@|群峦传说:细节盔甲条 (TFC Detail Armor Bar) + +tinkers-compatibility@ +fabric-trade@ +giant-nether-tree@|巨型下界树* +gamerule-doblockupdates +terralith-restoned +guitas-woodworks@ +power-grid@|机械动力:交错电网 (Create: Power Grid) + +audaki-cart-engine@ + + +humansmod@humans-mod +aquaacrobaticslegacy +@modmenu-btw +armored-arms@ +armored-golems +disable-fog@ +accrelatedrendering-refabricated@|加速渲染:重织 (AcceleratedRendering-reFabricated) +minemenureforged|我的菜单 重制 (MineMenuReforged) +function-command-deduplicator@|函数命令去重器* +@hide-armour +ftb-quests-freeze-fix@|FTB任务冻结修复 (FTB Quests Freeze Fix) +playeranimatorapi@ +strictly-origins@ +born-in-configuration@ +eyes-of-ice-and-fire@ +better-hp@betterhp +jsonate +plsgodie|残血了就给我乖乖去死啊! (PlsGoDie) +tetra-patchouli-book|Tetra帕秋莉手册* + +configurable-death@ +invenaudio@ +client-curse-of-binding-prevention +simpleclockmod + +audio-improvements@ + + + +simple-crop-harvester|简易农作物收割* +darkness-curse|暗影诅咒·重生 (Darkness Curse • Reborn) +scroll-wheel-command@scroll-whell-command|滚轮命令* +infoplus@ +@bin-slot +cobblemon-utils +flamingo-mania + +endangered-plants|濒危植物* + +better-melon@|更好的西瓜* +better-snifferty@|更好的嗅探* +@bobs-originium-dream|鲍勃之源石梦想 (BOB's Originium Dream) + +minibloom +teatime@tea_time +garden-trails@ + +gd656killicon|GD656击杀图标 (GD656Killicon) - 此的正式版页¨@gd656killicon|GD656击杀图标 (GD656Killicon) - 此的最及时的文件页 +itemcleaner@|掉落物清洁者 (ItemCleaner) +@tinkers-dolabrae +metallic-tinkering@ +kubejs-draconic-evolution +kubejs-mystical-agriculture@ +modern-beta-forge-islands +modern-beta-forge-release-plus +pomkots-world@ +black-dragon-armor|怪物猎人·世界:黑龙盔甲* +kimetsu-no-yaiba-reload|鬼灭之刃 重制* +resonantisshelomoh|同调造物·所罗门 (Fabrica Resonantis: Shelomoh) +withering-away-reborn +villager-extend-localbully|村民拓展:地头蛇 (Villager Extend - LocalBully) +dancing-villagers +natures-of-witchery +tct-flashlight@tctflashlight +mace-attack-assistance +changed-doomsday +changed-ice +tile-entity-breaker +frozen-ocean +portable-pet-sphere@ +@thaumicthermae +bbl-routers@ +bed-sapwnpoint +wans-storage-shelves@storage-shelves +winefoxs-spellbooks@winefoxs_spellbooks|酒狐的魔法书 (Winefox's Spellbooks) +better-allay@ +codechicken-lib-cre@ +solcarrot-fix|生活调味料:胡萝卜版 - 死吃修复* + +nanexs-cherry-biome +digital-botania + +crab-city-facilities@|螃蟹的城建 (Crab city facilities) +bbl-casting@casting +bbl-smart-crafting +foolproof@ +realistic-terrain-generation-community|真实地形生成:社区版* +more-outlines@ +phantomtweaks@removephantoms|移除幻翼 (RemovePhantoms) +simple-item-blacklist|简易物品黑名单* +titlescreen-cleaner + +ultimate-skeletons-and-titans|终极骷髅* +manaitaplus-legacy@|砧板传承 (ManaitaPlus Legacy) + +blockoffensive@|方块攻势 (BlockOffensive) + +hugme-forge-edition|抱抱我!Forge 版* + + + +tool-upadate@tool-update|工具附魔等级升级 (Tool Update) +@better-gregtech-and-applied-energistics|更好的格雷科技与应用能源 (Better GregTech And Applied Energistics) + +tprt-sakuratinker-expand|挚爱 — 魂樱工匠补充 (myLove(sakuratnker expand)) +better-turtle-scute@|更好的海龟壳* +@infinite-water-block-1.7.10|无限水源方块 (Infinite Water Block) +floatable-pressure-plates@|可浮空压力板* + + +more-rust@rust|锈 (Rust) +cryofloric-arts@|严寒插花术* +tacz-refabricated@|TaCZ:重织 (Timeless and Classics Zero: Refabricated) + +ashen-witch-broom@|魔女的扫帚:重制版* +maidswordsoaring|女仆御剑 (Maid Sword Soaring) +lembrary +skyboxify@ +create-furnace-lava-adapter +create-trainutilities@ +@createtrainscustomportalapi1.20.1 +create-xptool@cxptcreatexptool|机械动力:经验工具 (Create: XPTool) +graveyard-death-mode +beautiful-campfires@ +kimetsu-no-yaiba-final-hope +legend-ary@ +tfc-hourglass@|床起速时 / 梦该醒了 (TFC Hourglass) + + + + + +alans-unified-ui@alan-unified-ui +cntiertagger@ +pick-up-the-hint|物品拾取提示 (Pick Up the Hint) +jei-tetra +eyes-in-the-shadows@ +bandagez +kineticdamage@ +underwater-village@ +dimension-parasite@|维度寄生者* +@realistic-stamina +ciscos-content +pet-home@pet_home +changed-xtras@ +alexs-caves-enriched@|Alex 的洞穴:浓缩 (Alex's Caves: Enriched) +@fps-to-the-trash +@entity-desync-viewer +re-entity-outliner +@c2mef +hellspawn-starting-dimension@hellspawn +jj-weapon-config +bbl-compat@opolis-compat +tinkertime-geology +spectral-arrow-tweaks +too-many-bows@ + +@soulbinditem|灵魂绑定 (Soulbind) + + + +maid-beside|女仆伴行* +snkey|键 (Sn Key) +vzlinglib@ +@signfinder|告示牌查找器 (Signfinder) + + + +@colorful-leaves-mod +decorative-computers@|装饰性电脑 (DECORATIVE COMPUTERS) +landk-furniture@ +derfl007s-road-mod@derfl007s-road-mod-repaved +medieval-paintings@ +glymworld-deepslate + +roadarchitect@ + + +lazybank@|咸鱼银行* + + +@vanilla-enchantment-tweak|香草附魔调整 (Vanilla Enchantment Tweaker) + +@projectile-ding +client-time@clienttime +replanter-plus@ +ae2-retex-port +tinker-tantrum +amethyst-additions +@tetravsikt +@advanced-netherite-upgrade-templates|高级下界合金升级模板 (Advanced Netherite Upgrade Templates) +@falling-sand +gregified-energistics@ +scalable-storage-ceu@ +luminous-blocks@ +epic-structures-witch-huts + +void-block-fabric@void-block-fabric-1.21.1 +more-stews-mod +@ported +better-music-player +berries-and-mobs +applied-soul +packagedfluidcrafting@|封包流体合成 (Packaged Fluid Crafting) +packagingprovider@|封包供应器 (Packaging Provider) +mts-iv-recurring-air-war + + + +@explodee +swift-wheel@|迅捷轮盘* +@clienttimeandweathercontrolmod|客户端时间与天气控制 (ClientTimeAndWeatherControlMod) +better-spectral-arrows +polymorphic-tom@polymorphic-toms-simple-storag +shoulder-surfing-ultimine@ +artisan-pottery@ +epic-fight-avalon +@neospeedzero|自定义速通挑战:Zero (NeoSpeed Zero) +fluffy-dandelions@ +nether-update-concept-mod +@little-maid-mood-flutter|车万女仆:情绪萌动 (Little Maid: Mood Flutter) +mobvotes-sniffer@sniffer +ae-wireless-transceiver@|AE无线收发器 (AE Wireless Transceiver) +create-train-lights@ +kabooms +zoo-architect@ + +@noverifychat|无验证聊天 (NoVerifyChat / FixChatVerify) +giant-cherry-blossom-bonsai-tree@ +lemonskin@|柠檬皮 (LemonSkin) +water-erosion +@undertale-healthbars + +tetra-gui-compat +@shortratio-mod +quantumchunks@ + +@citrus +@accessory-api +@catalyst +@day-counter-enhanced +messenger-crow +epic-fight-super-warden|史诗战斗:超级监守者 (Epic Fight - Super Warden) +armageddon +cobblemon-mega-showdown@ +golem-dungeons@|傀儡地牢* + +explosion-overhaul-a-new-level-of-destruction +@skillz +hadean-breathe@|幽焰之息* +can-you-survive +eternal-shield-bead|永御盾珠* +slashnouveau +@aether-stapi +@notenoughminecraft +originiumarts@|源石技艺 (OriginiumArts) +simplebackhome|简单回家 (SimpleBackHome) +@qismorecommands|齐的更多命令 (Qi's More Commands) +polymorphic-travelers-backpack@ +playernbt-quests-ftb-quests +interactive-block-prompt@ibp|可交互方块提示* +@timeshifts +@weathershift +chat-binds@chatbinds +tridentperf-1-0-0 +maid-s-bakeries|女仆的烘焙坊 (Maid's Bakeries) + +elytraautocollect|鞘翅自动搜集 (ElytraAutoCollect) +@banitems|物品封禁 (Banitems) + +tt20-forged@tt20-reforged +default-server-properties@|默认服务器属性* +f3-lite@ +text-animator@ + +yet-another-furniture@ + +qarsans-insurgency +yum-delicious@yum!-delicious!|Yum!美味! (Yum! Delicious!) +lunarinispread@|丰盛晚宴 (Lunarini Spread) + +rs-backpack@ +no-template-netherite@ + +@mobcapture +koifish@ + + +@mcinspects +@csgo-inspects +armor-hud-by-mcjunky33@ +@can-i-sleep-now +@zenxarch-damage-vignette +simple-teleport-commands@teleportg +too-many-binds +too-many-binds-plus@toomanybinds +astral-dragon +middle-earth-additions-npc@|中洲拓展:NPC (Middle-Earth Additions: Npc) +middle-earth-additions-factions@|中洲拓展:派系 (Middle-Earth Additions: Factions) +middle-earth-additions-war@|中洲拓展:战争 (Middle-Earth Additions: War) +brews-and-bevs@|酿造与饮料 (Brews and Bevs) +@kimetsu-no-yaiba-x-epic-fight + +lrs-dynamic-dungeon +buff-mobs@ +banner-claim@|旗帜圈地* +@reformundyingtotem|不死图腾重制 (ReformUndyingTotem) + +more-world-crafting@|更多世界合成* +@simplelocks|简单的锁 (SimpleLocks) +luminous-helmet +steel-armor-blocks@sab|机械动力:钢铁装甲方块 (Create: Steel Armor Blocks) +create-armor-blocks@|机械动力:装甲方块 (Create: Armor Blocks) +rolled-homogenous|轧压均质装甲* +elemental-end-portal +unseens-better-stronghold +salutation +better-than-bountiful +global-customnpc-data +modern-beta-forge-rivers +zombie-improvements@zombieimprovements +rewithered@ +better-lost-candle +openblocks-reopened +@rc-toys +fancy-toasts@ + + +@trueuuid|正版离线共存 (TrueUUID) +owapote-bc-exlaser +truly-custom-horse-tack@ +tacz-applied-ammo-box@ +azurum-miner@ +thermal-recycling|热力回收* + +revoted-wildfire@ +biome-makeover-altar-fix +techgunsmixins +open-persistence@ +hungerstrike-extended-support@ +@floras-delight +fintastic@|鳍妙至极* +auto-reload-crossbow@|弩自动装填* +aimassiste|辅助瞄准 (AimAssiste) +zombie-dinosaur@a-zombie-dinosaur +monster-expansion@ +monster-girl|怪物女孩* +@offlineauth|离线认证 (OfflineAuth) +claxels-classic-paxels +meowmeldrawers +@perrys-botany +warforge-factions-remaintained@warforge-remaintaned +lunar-moon-reborn +minefactorial@ +create-universal-ores@ +create-crystallized@ +chorus-expansion +@lootshare +clojure-lib +@stripcustomdata|扔掉"custom_data"! (StripCustomData) +wheres-my-brain +champions-alter@|冠军-重塑 (champions-alter) +slashblade-hf-blade@energyblade|拔刀剑:高频刀 (SlashBlade: HF Blade) +virtual-witch-arrangement|虚拟魔女排布法* +@player-move-detector +valkyrien-space-war@|瓦尔基里太空战争* +@blazerod-model-assimp +@bindfirework-hotbar +@new-soul +beautiful-potions@beautiful-potions-mod-edition +yukamis-sophisticated-backpack-tab@ +crouch-to-block@ + +juv@juvenile-preserve|永雏 (Juvenile Preserve) +hooklib@ +oasis2@ +blue-ice|蓝冰* +json-model-legacy@ +lidar-laser-mod +sleep-tighter +butterflies-extension +back-in-slime-honey +alans-basalt-generator +demis-better-stealth + + +@coords-hud|坐标 HUD (Coords HUD) + +@eternisstarrysky|星河传承 (Eternis Starry Sky) +@safe-respawn|安全重生 (Safe(ish) Respawn) +palmon|帕鲁梦* +@spectators-generate-loot|旁观者生成战利品 (Spectators Generate Loot) +death-reduces-life@deathpenaltymod|死亡减少生命值 (Death Reduces Life Mod) +maid-chunk-loader|车万女仆:区块加载* +maidusehandcrank@|女仆摇曲柄 (MaidUseHandCrank) +hard-pity@|大保底:凋灵骷髅/下界合金/三叉戟/龙蛋* +genetics-resequenced@ +moo-fluids +create-balanced-flight-forked +mc-modsthemodium-enderio-capacitor-additions +ironsarms +burst@ +chat-calculator@ + +unbreakable-leads@ +mortality-a-terramity-addon@ + + +chatjs@ +let-me-peek@peekmod +persistent-players +torchmaster-cobblemon-compat +nemos-backpacks@ +homy-tp@ +@shellphone +faded-conquest-ii + + +chosenlib@ + +render-blender|渲染搅拌机* +ve-fluidhandling +@client-export-helper|客户端数据导出 (Client Export Helper) + + +overgeared@ +rain-after-long-drough|久旱逢甘霖 (Rain after long drough) + +@clarityhud +spawn-egg-preview@|刷怪蛋预览* +vulkanmod-extra@ +vramo +@afar + +middle-key-ping@|中键标点 (MiddleKeyPing) +scape-and-run-randomizer +amnesia-core +@minecraft-sqlite-jdbc +sqlite-jdbc +forbidden-arcanus-js + +@sha1redemption +f-k-create-world@fcw|不要创建世界 (F××k Create World) +maid-task-scrolling-helper@|女仆任务滚动助手* +rozutils@ +instantly-interact-internally@|随点随用* +@jsonem-mult|Json格式化实体模型·多加载器 (Json Entity Models Muit) +gadothaumy@ + +dimensional-teleporter|维度传送器* +avaritia-integration|无尽贪婪:集成 (Avaritia:Integration) +super-lead-rope|超级拴绳 (SuperLead) - 新项目¨super-lead|超级拴绳 (SuperLead) - 旧项目,不再更新¨@superlead|超级拴绳 (SuperLead) +solo-leveling-mod +platanitos@ +@spiceoflifelatiao|生活调味料:辣条版 (Spice Of Life: Latiao) +spicy-species@spicy_species +thaumic-isorropia-kedition +thaumic-concilium-kedition +znet + +railcraft-diesel-locomotive-addon + + + + +alchemistry-redox@ + +extra-hostile-neural-networks +extended-crafting-expanded +packagedexexcrafting@ +scp-reborn|SCP:重生 (SCP: Reborn) +spiritual-flame-firearms@|灵焰炽铳* +a-weird-bow@|奇奇怪怪的弓* + +bacchanalian-mobs +toxony@|毒术* + +ncm-for-mc@neteasecloudmusic-for-minecraft|NCM播放器 (Ncm for Mc) +lavamelon|熔岩西瓜* +@bananaskin|香蕉皮 (BananaSkin) +worn-tear@|磨痕* +cool-rain-reforged@ +twilight-forest-cave-fix@|暮色森林洞穴修复* + +create-fluid@|机械动力:流体 (Create: Fluid) +create-fly@|机械动力飞越版* +sbm-wooden-buckets|木桶 ([SBM] Wooden Buckets) +sea-of-chests +flammable-tweaker +changed-armor-and-weapons +abominationsinfection +ly-target-dummy|目标假人 (Target Dummy) +unique-accessories@ +@plants-vs-zombieminecraft-warfare-pvz + +goners-armor-trims + +muffins-slime-golem@ +dontstarve-moss-edition@|不要饿死:Moss版 (Don't Starve: Moss Edition) +jerotes-delight|Jerotes乐事* +stellar-striker|星神之怒* +ptp@ +the-mad-hatter@ +magic-bees-kedition +complicated-backpacks@complicatedbackpacks +retro-mario-worlds@ +@guard-villagers-1.21.1 +@mcmassok-guardvillagers-fork +villager-pagoda-house@ +@maid-function-extension|女仆!给我阎魔刀 (Maid Function Extension) +xfoxsword|狐狐圣剑 (XfoxSword) +soul-pact|灵魂契约* + +resolution-controll@resolution-control-plus-plus|分辨率控制++ (ResolutionControl++) +@stackable-shulkers-fix|潜影盒堆叠修复 (Stackable Shulkers Fix) +spectrum-rush@|色谱竞速* +libertys-villagers-revived +blue-skies-tweaks +drpgspawnfix +eat-yourself@ +kaiju-calamity +@hattened +ender-christmas-plus@ender-christmas+ +juniors-open-smash-bats@opensmashbats +choppers-delight@ +delighto-flight|云端之乐 (Delight o' Flight) +xbbs-roaring-knight@|XBB的呼啸骑士 (XBB's Roaring Knight) +suixingxiugai@|随性修改 (Suixing Xiugai) + + +avaritia-tweak|无尽贪婪:魔改 (Avaritia: Tweak) +gregtech-easy-core +polishedlib +minecraftapi +easy-gun-mod@easy-guns +lightroot@ +miscmfrcircuits +dartpatch +polar-bears-frozen-oceans-backport +uptodatemod +concrete-and-marble-mod-2 +kaminari-motor-works +block-highlightfx@block-hightlightfx +better-compass-hud@ +@mendmeter +smallstairs|小楼梯 (Small Stairs)¨small-stairs|小楼梯* +mana-crystals@ +abstract-rpg +more-pylons@ +thermal-parallel@|热力并行* +mcpatcher@ +spindles-tfc +tfc-more-items@ +dynamic-trees-tfc-seeds@ +farmer-enchants@ +tiny-tree + +xnet-zhcn-edition|XNet 汉化版 (XNet-zhCN edition) +mtr-yomi-utility-mod@|Yomi的MTR实用拓展 (MTR Yomi Utility Mod) + +laseas-wilderness-traders|Lasea的荒野商人 (Lasea's Wilderness Traders) + +mtr-moogs-temples-reimagined@ + +perennial-pastries@ +narrativecraft@ +mixinbooter2fermiumbooter@ +moogs-structure-lib@ +chickens-can-cast-fireball +bad-sound@ +heirlooms@ +warborn-capture-points +tacz-x-gunslightsaddon-addon@tacz-x-guns-lights-addon-addon +hunger-tweaks@ +it-takes-a-pillage-continuation@ +swansong@ +no-creativity-and-adventure-mod|无创造和冒险 (No creativity and adventure) +croparium@|矿石种植工艺* +indigestion-tablet@indigestion-tablets|健胃消食片* +me-beam-former@|ME光束 (ME Beam Former) +create-fast-schematiccannon@create-fast-schematic-cannon|机械动力:更快的蓝图加农炮 (Create: Fast Schematic Cannon) + +trail-of-light +abominations-apocalypse +@pams-harvestcraft-2-nerf +pommel-held-item-models@ +echoes-of-battle +thaumic-wonders-unofficial|神秘奇境非官方版* +mystical-expansion +refraction-continuation|折射:延续* +expanded-arcanum +@tpatools|TPA工具集合 (TPATools) +hud-manager@|界面管理器 (HUD Manager) +simple-smithing-overhaul@ +tinyfish-death-penalty@|死亡惩罚 (Death Penalty) +@dine|动态NBT编辑器 (Dynamic In-Game NBT Editor) +@wecuifix +time-control@|时间控制* +embers-text-api@ +stageenchantment|阶段附魔 (StageEnchantment) +@black-sun +the-many-faces-of-enderman + +@eternal-sky-orbs +antiqueatlas-recurrentcomplex-compatability@ +global-shaderpack-properties|全局光影包配置 (Global Shaderpacks Properties) +strawberrylib@ +@ibukigourd +onekeyminer-chainable-visuals@|一键连锁:可视化 (OneKeyMiner Chainable Visuals) +precision-mining@ +better-capes-x@ +botanic-cheater +villagerxp@ +silk-suspicious-sand +trial-liberator@ +nycto@ + + +healingbed +@cleardrops|清道夫 (ClearDrops) +@craftaudit|方块审计 (CraftAudit) +kiss-mod-unofficial@|Kiss Mod:非官方版* +rawinput@ +loot-beams-retro +am2pga +gtbcs-geomancy-plus + +@modmenu-babric + + +@hiirosakura +universalsummoning|通用召唤 (Universal Summoning) + +@gambac +cad-editor@ +@unitweaks +@nyalib + +nei-mystcraft-plugin +jei-mystcraft-plugin +bubblesex +legendary-stages +tesseract-optimizations +@uwufied-beta +@uniwrench +useful-ribbits + + +power-advantage|能量优势* + +create-transmission + + + + +applied-pneumatics@|应用气动* +@bratwurst +neoa-ban|机器码封禁Neo版 (NeoABan) +trashpandas-ascension +@food-needed-to-respawn-at-bed +block-cannon|方块投射炮* +pocket-space-teleporter@|口袋空间传送器* +re-from-the-ground-up +@stacks-are-stacks +vc-vocacraft@vocacraft|乐音奇旅 (VocaCraft) +resource-fish + + + +@immibis-peripherals +horde-beacon|尸潮信标* + +extreme-blocks|极限方块* + +talecraft +new-crimson-revelations +makeae2better@ +@elemental-arrows-stationapi +@nyabags +@past-el-palettes +@blowing-bubbles +mobs-n-growths-origins +roadarchitect-encounters + +@mystcraft-ageless +thaumcraft-return-of-the-ancients@ + + + + +neocontinuity@ +continuity-unofficial-port-1-16@continuity-unofficial-port-1.16 +@safefarmland|耕地保护 (SafeFarmland) +@bone-meal-fern +ae2-cell-upgrade-compat +iris-shader-folder@ +rpcdrive@ + +mixintrace-resmithed@mixintrace-reforged +tetra-musket|火枪锻造* +tudigong-wayfinder|土地公 (TuDiGong) +mob-statues + +charset-cre@ +legacy-farms +thaumictweaker +covers1624-lib + +one-enough-block@ +@better-chat|更好的聊天框 (Better Chat) + +@renderlimiter|渲染抑制器 (RenderLimiter) +@cornucopia-reborn|丰饶之角:重生 (Cornucopia Reborn) +longwings@ +more-ae2-additions +congrega-mystica +@no-screenshot-message|无屏幕截图消息 (No Screenshot Message) +fast-industrial-platform|快速工业平台* +@rolling-gate-rzf-addition|人哉肥的卷帘门附加包 (Rolling Gate RZF Addition) +tensura-mortal-cultivation|转生:凡人修仙 (Tensura: Mortal Cultivation) +pickup-limits + + +armorycache|军械库 (Armory Cache) +gregtech-storage-drawers@ +@chiseled-mod + +@area_lib +unordinaryextras +awakened-craziness +villager-market-nbt-fix|村民市场 - NBT 修复版 (Villager Market - NBT Fix) +illager-expansions +@tropicraft-stationapi +bbl-shops +@dronebox +@volo-volare +@customanvilrenameable|自定义铁砧改名权 (CustomAnvilRenameable) + + +anvilcraft-extra-power|铁砧工艺:额外电力 (Anvilcraft:Extra Power) +create-prismatic-shine@|机械动力:流光溢彩 (Create: Prismatic Shine) +@dream-stone|梦之石 (Dream Stone) + +enhance|增幅 (Enhance Buffs) +recipes-of-the-lost@|失落配方 (Recipes of the Lost) +@huhobot-mod + +tacz-pack-upgrader@ + + +@ping-view + + +extravagant-delight@ +dodos-mobs +pillager-caravans@ +@worlds-whisper|世界之低语 (World's Whisper) + +create-soul|机械之魂* +@netmusic-loginneed|网络音乐机:登登你的 (NetMusic: LoginNeed) + +quality-equipment-reforked +metalmith|铜铁新生* +@convenient-malum|更方便的灵灾 (Convenient Malum) +nautilus-spears-mounts-of-mayhem@|鹦鹉螺&矛 - 群骑纷争 (Nautilus & Spears - Mounts of Mayhem) +telepathic-maid@|电波女仆* +tombmanygraves-2-api +mytown + + +@linverticalslab|竖半砖 (Lin Vertical Slab) + +@pearlchunkloader|珍珠区块加载器 (PearlChunkLoader) +@lv-wings +@foxbox +@more_than_a_foxbox +@fox-plushies +ecliptic-seasons-oh-the-biomes-weve-gone +tacz-1-21-1@tacz-1.21.1 +tacz-special-forces@ +sculpture@|生物雕像* +aps-repowered +citizen-pot|市民锅* +linear-experience@lineaer-experience|线性经验* +@durability-viewer-continuation|耐久指示器:延续 (Durability Viewer Continuation) + +huaji-age-astral-regenesis@|滑稽纪元:轮回星启 (HUAJI Age: Astral Regenesis) +slashblade-fabric-addons@|拔刀剑:重织附属包 (SlashBlade Fabric Addons) + +proof-of-honor@|荣誉的证明 (Proof of Honor) +splendour-ablaze-epoch|棠煌纪元* +spellbooks-attributes-reforged|铁魔法属性:重铸 (Spellbooks Attributes:Reforged) + +snows-bosses-mechasent|Snow的Boss:机械遣使 (Snow's Bosses: Mechasent) +create-crafter-integration +create-schematicchecker@createschematicchecker|机械动力:蓝图校验 (Create: Schematic Checker) + +ae-terminal-view-cell-fix@terminal-view-cell-fix|AE2显示元件槽位修复 (AE Terminal View Cell Fix) +pearload|实体区块加载* +mbc-projectez +comfy-cozy-brickery@comfy-cozy-brickery-patch +spear-downport@|矛:向下移植版* +accurate-spears@|‌精准长矛‌* +soundreload +world-mod-cacher +orbital-railgun-by-mishkis|Orbital Railgun - 他人的非官方上传,¨@orbital-railgun + + + +file-director-incremental-mod-downloading +paytheprice@ +@the-silicon-mod|硅 (Silicon) +@nitrogen_rbn|氮 (Nitrogen) + + +extended-itemview-eiv@eiv + + +projecte-teams-sync +sequence-pathways-lotm-mod@lotmmod +yung-structures-addon-for-loot-integrations +backpacks-for-dummies@ +@egafixer|附魔金苹果修复 (Enchant Golden Apple Fixer) +@fixtconstructpickaxe|匠魂挖掘等级修复 (FixTconstructPickaxe) +co-lib +omni-cells@ae2-omni-cells|OMNI 存储元件 (OMNI Cells) + + +sdm-gamestages-helper +mangos-multiblock-library + + +@a177-added-modified-enchantments|A177增修附魔 (A177 Added Modified Enchantments) +qa-enchants@|Qa 附魔* + +create-golems-galore@ +vmh +ore-stages-reborn@ +journey-map-stages-reborn@journeymapstages-reborn +the-one-prode-stage@ +sdm-mob-stages +passive-skill-tree-stage +sdm-loot-overhaul@ +@area-tools +lightbind|亮度绑定 (LightBind) +qg-geocraft@qg_geocraft|天圆地方 (GeoCraft) +timberreplant@ +hunting-dimension-reforged +better-angel-ring +tcompat-tinkers-construct-addon@tcompat +j-a-c-m-just-another-chisel +acuisine@assorted-cuisine +juniors-troll-tnt@trolltnt +compact-mekanism-machines +compact-mekanism-machines-plus@ +woot-revived@ + +croparium-the-twilight-forest@|矿石种植工艺:暮色森林 (Croparium: the Twilight Forest) +@leafs-crucible-ice-and-fire|Leaf的炼金炉 - 冰与火 (Leafs Crucible - Ice and Fire) + +starcatcher@|捕星者* +thermaloot +rs-insert-export-upgrade@ +voidminer-forked +sanguine-neural-networks@ +chiseler@ + +@mod-menu-bta +xp-cost +shut-up-realms@ +narrator@narrator-legacy +mc-truststore@ +rlcraft-dregora-srp-arachnida-tweak +broken-heart-undershirt-statistic +stitchedsnow@ +@moderndeco + +create-henry@ +recipe-history-addon-for-jei@jei-recipe-history-addon-1.16.5 +@proto-hivemind-girl|新生心智 (Proto Hivemind Girl) +wooden-tools-are-dumb@ +laserio-uel +hamtastic-hamsters@hamtastic-hamsters! +gateways-to-eternity-more-gateways@ +cursed-earth-returns +not-enough-trials +orbital-railgun-reforged + + + +create-heat@|机械热力 (Create: Heat) +@dream-enchantment|梦之咒 (Dream Enchantment) +@eatalways|一直吃 (EatAlways) + +rehurttime@|伤害免疫机制重做 (ReHurtTime) +naraka@ + +minechem-working-with-better-builders-wands +dungeons-mobs-port +obtainable-end@ +slideshowplus@ +classic-and-simple-status-bars-rebuild|经典且简易的状态栏:重制版 (Classic and simple status bars rebuild) +@the-last-crystal-cup +createworldui@crwui|新版创建世界界面 (CreateWorldUI) +@whiteout +mining-quakes@ +tpw@wenxingtpw +inspectability-forge@hi-inspectability +@orbital-railgun-sounds +beneathmixins +cutting-delight@ +locate-command-backport +the-copperier-age@ +@veinminer-client + +@vertigo +powercrystalscore +twilightsoul|暮色之魂 (TwilightSoul) + +endfield-industry@|终末地工业* +modclassifier|模组分类器 (ModClassifier) +lightningsuperpeashooter|电能机枪豌豆 (Lightning Super Peashooter) +display-delight-fabric@ + +@life-essential-oil|生命精油 (Life Essential Oil) +st-drive@stdrive +roadweaver@|阡陌交通 (RoadWeaver) +xemos-cluckshroom +@the-past-ages +take-back-the-night@ +winds-of-requiem@ +classjs@ +c3-blocks@ +@allium +create-netherless-ported@ +mechanical-healing-machine@ +@potionenchant|药水附魔 (PotionEnchant) +tongda-way|通达路 (TongDaWay) + +enigmatic-legacy-cursed-ring +elemental-synergies +simple-netherite-horse-armor@ +project-mmo-farmers-delight-compat@project-mmo-farmers-delight +darling-decorations@darling-decorations! +cute-n-sweet@cute-n-sweet! +inspectability@ +crafttweakeradditions@ +hunting-dimension-remake +@lootify-(structures) +portable-storage@|随身仓库* +lootstories|遇言典著 (LootStories) +otherworld-core +simple-corpse +botania-mana-fluid +create-ae-generator +create-additional-logistics@|机械动力:物流附加 (Create: Additional Logistics) +issrf-range-fix-irons-spells-n-spellbooks|铁魔法溢出射程修复 (Range Fix - Iron's Spells 'n Spellbooks) +goety-delight@goetydelight|诡厄乐事* +advanced-little-garbage@advanced_little_garbage|高级小垃圾* +@tpa-tp +@miteequilibrium|MITE:宁静 (MITE: Equilibrium) +tetrawhetstone|Tetra磨刀石 (TetraWhetstone) +brain-stealer-dragon-addon|龙之生存:夺脑龙 (Brain Stealer Dragon - Addon) +official-epic-fight-x-parcool@official-epic-x-parcool +jump-efficiency|跳跳效率* +smooth-scrolling-reforged + +one-enough-fluid@ +jerksteve@ + +ydms-mobhealthbar-mod@ydms-mobhealthbar +otherworld-origins +dragon-mounts-patches@ +gregtech-modern-ore-generation-standalone@gtmogs +cape-banners +bftp@blast-from-the-past +compact-crafting-updated +appliedchisel|应用凿子 (AppliedChisel) +item-obliterator-despawn-fix +@borukva-food +dynamic-difficulty-mod +obituary-exchange +from-the-caves@from-the-caves-official +lumen-alveary-patch +configurable-tooltips +modlistmemory@|模组列表记忆 (Mod List Memory) +macu-lib@ + +better-end-crashed-ships-tweaks@betterend-crashed-ships-tweaks + +no-caves-mod@|无洞穴* +simply-desire-paths +happy-ghasts-boost@ +cbr-addon@|自定义大逃杀扩展 (CBR Addon) +compact-expansion +armor-quick-swap@|盔甲快速切换* + +mixing-and-cutting@mixing_and_cutting!|混合切制 (Mixing and Cutting!) +yumo-isk-stackstackstack|拼好组 (Yumo isk-Stackstackstack) + +flourfood|面食 (Flour Food) + +neo-ae2-toogleable-view-cell@|AE2可切换显示原件-Neo (Neo AE2 Toogleable View Cell) +mtt-more-tetra-tools|更多Tetra工具 (More Tetra Tools) + +compat-delight@ + + +thermal-processing +botanical-machinery-extra-reforked +botanical-machinery-reforked +armorplus-reforged + +@better_tooltips +@ironmanarmor +vs-genesis@ +element-endow|元素赋予* +resource-bar-api@ +goety-iron|诡厄铁魔法* +i-feel-bad@|恙 - 疫恙待诊* +@backoff + +mc-mods-creepypasta-in-one@all-creepypasta-in-one +disable-structures@|禁用结构* +windowlogging-renewed +leaderboards +@beacon-dragon-egg|信标龙蛋 (Beacon Dragon Egg) +maid-travel-camera|女仆旅行相机* +nieih@ + +origins-furs-updated@ +tinkers-gears@|匠械 (Tinkers' Gears) + +moreeverything +epic-fight-skill-tree@ +dtk-update@pale-lively-update +goety-tetra-fix|魔力剑聚晶Tetra兼容 (GoetyTetraFix) +otherworld-apotheosis +mana-attributes@ +azalea-growth-control@ +natural-waters@ +health-bars@new-health-bars +enchantment-insights@ +bloomcraft@ +bmc-pale-garden-patcher +@polluted-rain +modernfix-mvus@ +stutterfix-refursbished@stutterfix-refurbished +noisiumforked@ +golems-kill-creepers@golemskillcreepers +no-animal-tempt-delay@ + +pixelshot + +changeling +ancient-scribes +kamenriderperfectionproject@|假面骑士补完计划 (Kamen Rider Completion Plan) +goety-iron-link|法厄通* +superaim + +taczattributeadd@|Tacz 属性添加 (TaczAttributeAdd) +@itemtocoin|以物易币 (ItemToCoin) +pet-rocktm|宠物石 (Pet Rock™) +gunfire-overhaul-echoes-of-the-battlefield +stamina-attributes@ +clanging-howl +limbus-company-mod-lcm|边狱公司:麦块部门 (Limbus Company Mine Section) + +realistic-bird-behavior@|真实鸟类行为* +wing-kirin|翼麒麟* +mcheli-reforged-mch-r + + + +enigmatic-legacy-plus@enigmaticlegacy+|神秘遗物+ (Enigmatic Legacy+) + + +novacore@ +snowycrescentcore@|雪月核心 (Snowy Crescent Core) +hostile-neural-industrialization@ +clockwork@clockwork_mod +vista@vista_tv +kismet +sea-life@new-sea-life +armored-foes@ +vehicle-upgrade@ +party-creepers +mc-mods-the-heads@all-the-heads +fantastic-wings@ +village-masquerade@ +new-shroomcraft@shroomcraft +tinker-and-better-combat + +extralib@ +whats-your-build +where-did-i-die@ + +tooltips-txf@ +@allow-disconnect +target-locks|注视锁定 (Target Lock) +fleeing-animals@ +peacegiver|和平方块 (PeaceGiver) +better-books@better-enchantment-tooltips +@chest-on-a-ghast + +general-feedback@|通用意见反馈* +raid-counter@ +modern-startup-qol-reforked +loot-integrations-dungeon-crawl +vanilla-loot-addon-for-loot-integrations +loot-integrations-cataclysm +aquamirae-x-better-combat-compatibility +ice-and-fire-dragons-x-better-combat@ +eternal-currencies +comfortable-campfires@ +embers-floating-islands@ +farmers-cutting-oh-the-biomes-weve-gone +beds-dont-explode +enchantment-library-at-home +turtlearmor +wandering-collector-forge@ + +jaffactory +horses-can-swim@swimming-horses-forge +mob-population-control +blighted-beasts +@the-witchs-broom|魔女的扫帚-Fabric移植版 (Majo's Broom) + +attribute-sculptor|属性雕刻家* +notexturerotations@|无纹理旋转 (NoTextureRotations) +baked-enchants +@priority +combatproperties + +judgement-day +@origins-plus + + + +dynamic-rpg-resource-bars@dynamic-resource-bars +lwjgl3ify-colorful@lwjgl3ify-1.12 +lib-39@|叁玖库 (Lib39) + +@simple-paper-doll|简单的纸娃娃 (Simple Paper Doll) + +@destroying-minecraft + +@trophymod|奖杯模组 (Trophy Mod) +create-brassworks-missions@ +elysian-event +sticky-enchanting-lapis@ +hungry-pouches +antiquities@ + +pams-harvest-the-nether +certain-questing-additions@ +alexs-mobs-capsid-fix|Alex生物衣壳体修复 (Alex's Mobs Capsid Fix) +parcoolskill@|跑酷技能 (ParCoolSkill) +merchantjs@ +fetchjs@ +mc-mods-the-mafuyu@all-the-mafuyu|万象瑞雪 (All the Mafuyu) +goety-end-biomes +structure-spawn-area-fix@|结构生成区域修复* +aloof-new@aloof¨aloof|Aloof! - 旧版 + +armory-rpg-series@ +moving-light-source@ +ftb-mighty-ender-chicken-rehatched +cyborg-robot-chicken-returns@ +dragon-wings@dragon-wings-09|龙翅膀* + +furnitures-o-plenty@ +windswept-delights@ +beltborne-lanterns-accessories-layer@ +beltborne-lanterns@ +mesophils-cities@ +mesophils-cities-classic +villagers-reborn@ +@simple-player-logger +mint-lib@ +better-fishtanks@|更好的鱼缸* +@roman-minimap +accelerated-recoiling|加速碰撞* +thank-your-eggs|谢个蛋/鸡谢动力* +star-rail-apocalyptic-shadow|星穹铁道:末日幻影 (Star Rail: Apocalyptic Shadow) +unusual-adventures +gui-scaler@auto-gui-scaler +ae2-id-sorter +@danganronpa|魔女论破 (DespairBook) +maids-return@|女仆归心 (Maid's Return) +boosted-brightness-remastered@ +helpfulcampfires@ +geophilic-backport-vanilla-backport-compact +nexus-layer +zipline@ +fathomless-crimson +@hexconnect +phase-journey +lucky-pot +@enchantment-controller|附魔控制器 (Enchantment Controller) +auroraslanterns@ +pocket-repose@ +fishing-plus@fishing+ +chaoscrafts-devices@ +obsessed@ +arsenal-rpg-series@ +mod-change-log|模组变更记录* +@entity-glow|实体发光 (Entity Glow (Backport)) +sophisticated-sorter@|精妙整理* +abi-forge¨abi-fabric +display-edit +arthys-elemental-engine-aee-forge +bobby-legacy@ +ambience-mini +arthys-ebonite-ae-forge +enigmatic-arcana + +optifine-cit-enchantment-patch@optifine-cit-patch +controller-mod@controllermod|控制器支持 (Controller Support Mod) +new-enchantment-switch@enchantment-switch +ftgu-from-the-ground-up@from-the-ground-up +options-profiles@ +forgematicaprinter@ +better-biome-blend-continued@ +furnace-xp-storage@ +recased@ + +elemenics|元质学* +pale-bloom +zip-fetcher@ +create-kinetic-illuminator@ +@tagban + +trade-tweaks@|交易优化* + + +bryszirake +no-worldgen-5-you@ +no-worldgen-5-you-continued@ +spiral-tower-villages@ +care-to-share@ +@hamstermod|仓鼠模组 (Hamster Mod) +@statictnt|静态TNT (StaticTNT) +floating-damage-numbers +voice-messages|语音消息* + + +@garden-farming|园林耕作 (Garden Farming) +lets-do-tfc-farm-charm|群峦农艺 ([Let's Do] TFC Farm Charm) +ride-casually@|随意骑乘* + +night-repair@|夜视修复* + + + + + + +originjs|起源JS (OriginJs) + +ancient-nature-a-prehistoric-experience +mte-more-tetra-effects|更多Tetra词条 (More Tetra Effects) +@vertical-bobbing +extraquests@ +crashexploitfixer@|崩溃漏洞修复 (CrashExploitFixer) +sticky-it +you-have-treasure@|你有宝! (You Have Treasure!) +nether-portal-configurator +lavasweeper@|熔岩清道夫 (LavaSweeper) +@more-people +simply-improved-terrain|简单地形改进*¨simply-improved-terrain-fabric|简单地形改进 (Simply Improved Terrain) + +faewulfs-lib@faewulfslib +mce2-lib +bop-legacy-reborn-croparium@|超多生物群系往昔重生 & 矿石种植工艺 (Biomes O' Plenty Legacy Reborn & Croparium) +lotr-reworked-new-beginning@|魔戒:重置 (LOTR Reworked) +kelp-fertilizer@|海带肥料* +crystalwing|水晶之翼 (CrystalWing) +@label-my-items +lightoverlay@ +rcw@ + + +obituary +worn-horseshoes@wornhorseshoes +antiqueatlasautomarker +connectorlib@ +milkable-creepers +@villager-clothes +monsters-girls-witchy-stuff +grimoire-of-gaia-spells|盖亚魔法 (Grimoire of Gaia Spells) +psi-oddities|Psi-奇思妙想* +@schempaste +mining-progress-hud|挖掘进度 HUD (Mining Progress HUD) +creativetabs@creativetabsplus +create-missiles@ + + +nuclear-bomb-bay@ +lightning-rod-backport +complicated-bees@ +werdens-illagers|沃尔顿的刌民 (Werden's Illager +) +thaumic-attempts +horseshoes-forge +replication-matter-overflow-tank +spaceploitation + + +pathfinder-api@ +no-resource-pack-warnings-forge@ +dbc-expansion|DBC扩展 (DBC-Expansion) +cutt-promix@cutt_promix|砧板乐事 (Pro Assistant Cutting Board) +dirty-bowls-delight|脏碗乐事* +corpsetweaker@corpse-tweaker|遗体调整 (CorpseTweaker) +convenient-interface|便捷接口* +brimm-armors-tactical-military-armors +@the-shadow-tapes +starter-bunker +shortbow-revamped +places@ +pets-pillage +ultimine-rewind@|连锁撤回* +project-time-master + +let-me-click-and-send-for-server@ +extra-hoppers@ +quick-pack@ +armored-paws-backport@wolf-armor-backport + + +create-mining-laser +create-who-touched-my-train@|机械动力:谁动了我的列车! (Create: Who Touched My Train!) +@so-lets-set-the-ore-on-fire +tab +armor-tooltip +modefite-item-definition-backport@ +hobbit-hill-village@ +alexs-caves-better-combat@ + +mc-modstheimbaium +storage-drawers-extra-reloaded +startup-qol +modern-startup-qol +domestication-innovation-fixed|驯养革新修复版* +@clear-despawn-reworked +spartancataclysm@|斯巴达的武器:灾变 (Spartan Weaponry: Cataclysm) +@metalrender +nirvana-library@ + +animated-mojang-logo@ +hardcoreastagesitem +@morbid-reborn-reborn-reborn + +fullbright-ultimate +fast-pipes@ +immersive-enchanting@|沉浸式附魔* + +boss-checklist@ +fire-resistance-tiers +cursedinfuserbycage|诅咒之笼注入 (CursedInfuserCage) +enchantedsails@ +pale-monarch@pale-monarch-boss-mod +firmanutrition@ +calypsos-night-vision-goggles|卡里普索的夜视仪 (Calypso's Night Vision Goggles) +the-apiarists-terminal +bee-mastery@ +nonupdate-retro@|不再有更新:Retro 版 (NonUpdate-Retro) +custom-message|自定义消息* +kjsutils + +create-access-denied@ +create-better-motors@ +@create-cc-total-logistics +create-fuel-motor@ +create-extra-casing@ +@create-meta-logistics|机械动力:元物流 (Create: Meta Logistics) +bush-master-core +@tritiumconfiguration|氚配置 (TritiumConfiguration) + +@mob-effect-display-fix|状态效果显示修复 (Mob Effect Display Fix) + + +anvilcraft-pigsplus@anvilcraftpigsplus|铁砧工艺:猪+ (AnvilCraft: PigsPlus) + +@kaleidoscope-compat|森罗物语:兼容 (Kaleidoscope Compat) + +@teas-official-random-things|Eh5の茶会:随意作品 (Teas Official Random Things) + + +@chatscreen|聊天屏幕 (Chat Screen) + + +sunny-riptide-trident@ +@lastwords|鸳鸯董卓 (LastWords) + +@bubble-column-tweaks|气泡柱调整 (Bubble Column Tweaks) + +@villager-inventory-hwyla-plugin +blessfulled +irregular-implements@ +sounds-be-gone@soundsbegone +@copper-grates-bubble +@fireworkdurability +create-colored-chain-conveyor@ +create-dimension-steamworks-realm@create-dimension,-steamworks-realm +punchy@punchy-fpa +@quickswap|快速切换物品栏 (Quick Swap) +@blockdynamics_mod|繁殖抑制&实体冻结器 (Block Dynamics) +armor-durability-hud +g3-doors +arcane-convergence|奥法归一* +ae2-ftbquest-detector|AE2-FTB任务检测器 (AE2-Ftbquest-Detector) +better-library@ + +dimensions-of-alexs-caves@|Alex的洞穴:维度 (Dimensions-of-Alex's-Caves) +better-combat-particle@|更好的战斗粒子* +vsplit@|V裂 (VSplit) +taczcurios@|Tacz饰品 (TaczCurios) +jeai@ + + +unofficial-variedcommodities +literal-sky-block-neo +cnpc-cobblemon-integration +cnpc-gecko-addon@cnpc-geckolib-addon +minecards@minecards-forge|我的卡牌* + +construction-wand-kots@|建筑手杖-耕云钓月版 (Construction Wand - KOTS) +thaumcraft-nei-plugin-patched@ +replication-rs2-bridge + +player-attribute-commands@|玩家属性指令* +lumis-lots + +omnisearch@|万象搜索* +ftb-unearthed +@colored-obsidian +collectors-caravan@ + +@itemagnetic + +soul-candles@|灵魂蜡烛* +lunchbox-sustenance-project|好好吃饭* +just-some-more-crops|农务多多* +cobblemon-spawn-alerts@|方块宝可梦生成提醒* +hex-text@ +hand-snow-ball|给我一个雪球* +extended-shaders +titles-and-timing@renxi.ch|称号与计时 (Titles and Timing) +biomespy|群系间谍 (BiomeSpy) +random-dungeon-spawners|随机地牢刷怪笼* +versionerreborn@|整合包版本工具:重生 (VersionerReborn) +critical-strike@ +ghostblocks@ghostblock|幽灵方块 (GhostBlock) +@crossbow_scoping +create-threaded-trains@ +raing-row@raing_row|雨后生草 (Rain Grow Mod) + +@seafloor_gardening|海底花园 (Seafloor Gardening) +nemos-vertical-slabs@ +electric-advantage|电力优势* +froglightsreimagined@ +flower-pots-plus + +@sturdy-farmland +bettervannilafishes@|更好的原版鱼类 (Better Vannila Fishes) + +ezunclear-reactor-big-explosion-preventer|易研电炸/核抑危 (EzUnclear) + +kubejs-goety +create-stuff-and-addition-tank-fix@ +create-ratatouille-fried-delights@|机械动力:齿轮与麦穗的炸物拓展 (Create:Ratatouille Fried Delights) +spellcasters-archives|施法者档案馆 (Spellcaster's Archives) +enders-spells-and-stuff-requiem +ironrust@ +web@webs +letmecc@|让我看看 (Let Me See See) +@autoclicker.1.0|自动点击器 (Auto Clicker) + + +fancy-trail|梦幻刀光* +caster-curios-bonus|灿奇术饰* +anyblade@|万物皆为刃 (Anything SlashBlade) + + +tongda-railway|通达铁路 (TongDa Railway) +crystcursed-dragon|晶咒龙* +brutal-mobs|狂暴生物* +super-headcrab|超级猎头蟹* + +@simple-locations|简单位置 (Simple Locations) +lios-seafaring-dungeons@ + +inductive-automation +steam-advantage|蒸汽优势* +@better-block-entities + +rs-logical +industrial-revolution-by-redstone-rebooted + +omoshiroi-kamo +death-taxes@death-and-taxes +@emotional-support-creeper +ly-ender-compass +walking-crops +harken-scythe-resharpened@ + + +resonant-engine +@liquid-xp|液体经验 (Liquid XP) + +xlvs-locks|Xlv 的锁 (Xlv's Locks) +the-legend-of-2900-core + +graphene-extension +dr-stone-kingdom-of-science@dr.-stone-kingdom-of-science +kinetic-pixel-dup-bug-fix +@custom-shutdown|自选关机 (Custom Shutdown) + +formatless|格逝* +invisiblocks-1-2-1|隐形方块 (Invisiblocks) +mage +spore-addon-nightmare|孢子扩展包:噩梦 (Spore Addon: Nightmare) +the-biomass-must-grow|生物质必须生长* +create-nuka-cola@create-nuka +dyson-cube-project|戴森立方计划* + +annoying-villagers-herobrine-invasion@|烦人的村民 (Annoying Villagers: Herobrine Invasion) +@net-music-peripheral|网络音乐机:电脑外设 (Net Music: Peripheral) + +tacz-golem-compat@|傀儡装配-战术人形 (TaCZ Golem Compat) +customizable-player-health@|可自定义的玩家生命值* + +goety-twilight|诡厄暮色* +attribute-achievement-rewards@achievement-attribute-rewards|成就属性提升 (Attribute Achievement Rewards/Achievement attribute rewards) + +@easyentitylib +coolcatlib + +@chronograph|计时仪 (Chronograph) +cnpc-additions@ +complicated-bees-genetic-industry +squish@ +tameableminisheep@ +tameablemossbloom@ +wolf-armor-and-storage-legacy@ + +@mcedia + +phonk-edit@ +ae2addonlib +infinity-mending-datapack-mod +epic-knights-ores-and-alloys +epic-knights-dark-ages-addon +indestructible-server-fix|坚不可摧服务端修复* +chromosome-lib@ +turtlebois-core-library +simple-voice-chat-group-player-names@svc-group-player-names +cinematic-zoom-neoforge@cinematiczoom +busy-villagers + +ars-affinity +ars-hex-unity +pretty-in-pink@ +chatcalc-neoforge@chatcalc +dust-and-ore@dust-and-ores +matrix-minecraft-bridge + +@entity-chat +jei-copy-recipe-json|JEI随意复制 (JEI Copy Recipe Json) +configured-burn-time@|可配置的燃烧时间 (Configurable Burn Time) +time-controller@ +@improved-snow-melting +ridebattle-lib@ridebattlelib|骑士战争库 (RideBattleLib) + +gamma-tweaks@ + +wandering-trader-express|流浪速递* +stewme|铁锅炖自己 (Stew Me) +kubejs-powah-reborn +inheritable-coat-color@|可继承的绵羊毛色* +pouch-of-unknown-nirvana|未知之袋:涅槃 (Pouch of Unknown: Nirvana) +ae2-auto-pattern-upload@|AE2自动样板上传 (AE2 Auto Pattern Upload) + +classbioarsenal|职业自定义:词条与生物 (ClassBioarSenal) +petite-inventory@|真实物品栏 / 娇小物品栏* +cipher-wright +short-players@|矮玩家* +backported-spears@ +ufo-future +copper-age-backport@backport-copper-age +animal-garden-sea-otter@ +animal-garden-porcupine@ +animal-garden-red-panda@ +animal-garden-owl@ +bytebuddies +entity-enchantment|实体附魔* +smoothwater +insanity-assorted-magics +bonded@ +indexer@ +dimensional-worldborder-continuation +dimensional-worldborder +damage-tracker +the-growling-man +mapwright@ + +wandering-ribbit@ +kinetic-minecart@ + +classic-pipes@ + +dust-and-ore-raw-ore-expansion +@minecraft-sigma +@pricks-n-planks +archogenum +giant-drops +kubejs-data-component +quantum-things@ +simple-emotes@ +flux-ducts +valley@valleys + +wizard-tower +the-dyson-sphere-project@dyson-sphere-project|戴森球计划* +bronze-mod@bronze|青铜 (Bronze) +lib39@|钇* +companions-dogfolk@ +the-block-keeps-ticking@ +better-pet-teleporting@|更好的宠物传送* +beacon-aura@ +create-ender-storage +portalfarm-despawn-fix@ +@kitchen-projectiles +eternally-overburdened +robot-dinos +stellar-decay|繁星枯朽* +annihilationblade|湮灭之刃 (Annihilation Blade) +acceleratedblade@|拔刀剑:加速渲染兼容 (SlashBlade: AcceleratedRendering) +heartbladeunoffical|心之所向非官方版 (HeartBladeUnOffical) +slashblade-japanese-addon-pack-adder|拔刀剑·日系附属·扩展包 (SJAPA·The SlashBlade EXtra) +project-saligia-reborn|炼金重铸计划·七罪新约* +lostbladereborn|遗忘之刃重生 (LostBladeReborn) +slashblade-shinku-and-blood-katana|炼狱真红之刃 (SlashBlade: Shinku And Blood Katana) +foxbladeextrare|狐月刀改·重生 (FoxBladeExtraRe) +spelunkers-palette@ +@seasons-api|季节 API (Seasons API) +mavity-lib@ +void-lib@ +easy-platform|简易平台* +dont-get-hurt@|无伤大雅* + +flight-ring@|飞行戒指* + +autorepairhandler|坚不可摧 (AutoRepairHandler) +wonderous-sea-endlessocean@wonderoussea +@bettertp|更好的传送 (BetterTP) +ftb-echoes +makeup-aesthetics-decor@ +opencomputers-rescaled +entityguardian +deep-dark-dimensional-dungeons +infinite-light@|无限光源* +@list-core +thermal-tweaks-dynamic-temperature-survival +debloat@ +orthocamera-unofficial-neoforge-port@orthocamera-(unofficial-neoforge-port) +crossroads-legacy +@wilder-enderscapes +charcoalplus@ +modern-decor-outdoor@ +shadeless-blocks@ +modern-decor-wooden@ +shadeless-mobs@ +herobrine-old-edition@herobrine-mod-alpha-version +multiplayer-spawners@ +compact-crafting-fork + +custom-machinery-ars-nouveau +peaceful-hunger@ +ftb-ez-crystals + +falling-blocks-anim +immersive-overlays@ +volcano + +nbtstructurelib@ +@enderlib +coalapi@ +homo-http-router@homohttprouter|野兽先辈的HTTP路由器* +fastconfigapi@ +@awakeapi +@anti-offhand +@so-tuff + +moreeventsjs +spudiversity-more-and-more-potato|土豆盛宴-更多的土豆! (Spudiversity - More And More Potato) + +flans-mod-tyrants-and-plebians-edition +connected-caves@ +invasion-code-red-reborn@ +mecha-pillager-boss +@zg-mobs +invincibleconquest +@arknights-races|明日方舟种族 (Arknights origins races) +gulliver-lite@gulliverlite +mojo-redmetal +logistics-bridge|Logistics Bridge - 原版¨logistics-bridge-dmnedition|Logistics Bridge - 修复版 +sourceblock@|源方块 (Source Block) +aec|以太工艺 (AetherCraft) +animal-garden-sugar-glider@ +animal-garden-meerkat@ +just-sit@just-sit! +tameable-endermen +vanilla-shears@vanillashears +logibots +always-eat@ +spice-of-life-valheim-reforged@ +enchantedstorage@|附魔收纳 (EnchantedStorage) +ultimine-addition +immersive-tips@|沉浸式提示* +lightspeedre-launch-optimizations@lightspeedre +enhancedgunsounds +@mcsr-ranked +@create-cafe-unofficial|机械动力:咖啡馆 非官方分支 (Create Cafe Unofficial Version) +realm-rpg-treasure-balloons + +@alexs-caves-delight-(-farmers-delight-alexs-caves-add-on) +kitchen-tools@kitchen-tools-tc6-addon|厨师宝具* +camphor@ +jade-magnifying-glass@ +c418-music-restored@ + +crab-claws@ +draconic-evolution-render-patcher@ +touhou-little-maid-epistalove@|车万女仆:纸短情长 (Touhou Little Maid: Epistalove) +omnicore@ +@voxelbridge + +immersive-fixes@|沉浸工程修复* +schematic-energistics@ +boss-rush@boss-rush-mod|老板冲* +mekanism-bigger-teleporters@ +carpet-igny-addition@ +registry-blocker@ +more-ornamental-plants@|观赏植物* +presence-footsteps-neoforge@pf-neoforge|脚步声NeoForge版 (Presence Footsteps (NeoForge)) +@villager-translator|村民语言翻译器 (Villager translator) +ai-player@|AI玩家 (AI Player) +aaron@ +@hextech-lib|海克斯 (Hextech Lib) + +missing-trees@ +pk-craft@p.e.k.k.a-craft +easy-craft-tweaker@easy-crafttweaker +wenxins-warp-pipes@ +forgelin-legacy@ +anothertips@ + +copper-drops +cooks-collection@ + +no-end|我的末地呢?!* +ome-tweaks@ +clutter-no-more@ +decocraft-nature@deconature +frex@ +open-terrain-generator-continued@ +duplicationless|复演结/コピーの終結* + +custom-mob-targets + +bopintegration-catized@bopic|超多生物群系集成:非官方版 (BOPIntegration - Catifized) +@rawmouseinput + +buildnotes@|建筑笔记 (BuildNotes) + + +hbms-nuclear-tech-modernized@|HBM的核科技现代化 (HBM's Nuclear Tech Modernized) +mtr-france-addon@ +minions-remastered +applied-enough-items@|应用定整* +milkspray|牛奶喷雾 (Milk Spray) +@road-to-evolution|进化之路 (Road to Evolution) +@totem-of-homing|归家图腾 (Totem of Homing) +better-foliage-legacy-edition@ + + +@adventure-platform-mod +pedestal-crafting +pedestal-crafting-patched@ +putbuildings@|建筑放置 (PutBuildings) +@no-air-mining-penalty|去除浮空挖掘惩罚 (No Air Mining Penalty) + + +reader + +improved-cleanroom-relauncher@ +qbithop +catalogue-vintage +wilder-flowers@ +render-held-item-while-a-wolf-witchery-addon +economicalmilktea +unnamed-monster@ +half-bite +merry-snow@|瑞雪物语* + +hdd-continuation@ +headdowndisplay@hdd +refined-equivalence + +amtweaker + + +fluidityfoodstuffs +chisel-modern +rmscore@ +magic-coins-tweak +irons-apothic-invaders@ +mekagenjei-mekanism-generator-addon +boatfly|船只飞行 (BoatFly) +ibicf +kube-utils@ +laputan@ +lecovian@ +pops@ +bad-ores +reactor-plus + + + +petrock-mod +bettertalk +autocrafter2000 + +baby-mobs-rebrushed@ +animal-garden-mouse@ +better-sleeping|更好的睡眠* +amtgenerators +blooming-biosphere +extrabees-community|更多蜜蜂:社区版 (ExtraBees: Community Edition) +programmable-magic@|可编程魔法* +better-farming@better-farming-plus +evil-seagull@|邪恶海鸥* +hbm-galacticraft-companion +gamingbarns-guns +jas-compatability-addon + +ad-astra-auto-lander +@createfkcrafter|机械动力:解放合成器 (Create: FuckCrafter) +create-cobblemon-balls-overhaul +create-air-ducts@ +grimoire-of-gaia-redux + +create-wrapped +create-cogs-invaders +notenoughscaffold +ore-trees-reboot +re-barked +composing +antique-armory|匠魂盔甲怀古* +cataclysm-ignis-soulfires +just-dyna-things +metal-detector +replication-addon-tiered + + +savethehorse|哦齁齁齁斯 (SaveTheHorse) +hamsters-delight@|仓鼠乐事 (Hamster's Delight) +the-ultimate-ore-mod +animal-garden-fennec-fox@ +animal-garden-common-raven@ +nether-master-remastered@nether-portal-remastered +redstone-recharged@recharged +toil-and-trouble@ +basicweapons@|基础武器 (Basic Weapons) + +youkaishomecomingcurios|妖怪们的归家:饰品兼容 (Youkais Home Coming Curios) +drop-force@|掉落力* +sacrifice|祭品/掉落不死亡* + +getoutofmyway|别挡我的路! (GetOutOfMyWay) +stronger-snowballs@ + + +simply-swords-epicfied|简易刀剑 - 史诗战斗 (Epic Fight - Simply Swords EpicFied 2) +cotton-resources + +talents +rain-rot@ +lothryas-spell-additiions +shershavy@ +craycrafting +@rain-world-weaponry +customtitlescreen +unusual-prehistory-2@|不寻常的史前史2* +shield-api@ +brick-lib-api@ +whatversioning|申必版本号 (WhatVersioning) +yourender|完了 (YourEnder) +@mana-jade|以玉定植 (Mana Jade) +villagerapi@ +peeping-angels@ +simple-teleporters-reforged@ +structures-tweaker@ +tooltip-overhaul@ + +pre-menu-screen +titlescreennotice +spellboundskiescustom +kind-of-nice-weapon +copperized + +comes-alive-reworked@|凡家物语:重制* +better-animal-feeding@ +tiny-dragons@ +@eternal_winter_mirage|永冬幻境 (Eternal Winter Mirage) +tightfire@ +wax-item-frames@ +obese-crops@ +@frame-changer + + + +tfcgurman@tfc_gurman +fungi-delight@ +leaves-youll-go@ +yagens-attributes@|Yagen的属性 (Yagen's Attributes) +terrarium-world@terrarium-earth +daylightchangerstruggle@ + +@eclipses-tweakeroo-additions +utamis-futon@ +@not-enough-furniture +ceruleans-mystical-smithery +mutated-mobs-mod +ftbxaerocompat +aesthetic-windows +bagels-palette-blocks@ +astrochem@ +dynamic-portals +heralds-ii@ +industrialized-architecture +better-starting-armors@ +@slashblade-frostbite-snowbloom|拔刀剑:雪蚀绽霜 (SlashBlade: Frostbite Snowbloom) +raspberry-core@ +advancedcamera-by-lostmortal +classic-peripherals@classicperipherals +sbm-punt-animal +sbm-baggable-mobs +sbm-helm-bucket +animal-garden-spotted-hyena@ +animal-garden-western-gorilla@ +more-concrete@ +lukis-strongholds +lukis-woodland-mansions +thaumic-model +gtse +ancore@ +xdonplugins@ + + +expanded-storage-kots|扩展存储 - 耕云钓月版 (Expanded Storage - KOTS) +ragdolls@ +mar-mars-enhanced-ore-variety@ +superflat-progression@ +@tinkers-origin|始源匠心 (Tinker's Origin) +renxin-music-player@|荏心音乐机* +slotify +textile@textile-lib +clash +morebatsvariants +hxcperipherals +yori3os-grappling-hooks@ +seasonal-decorations@|🎄 季节性装饰 (🎄 Seasonal Decorations) +neon-sentry-keeper + +maid-please-help-me-forge|女仆,请帮我打铁* + + +chemcraft-more-backpacks|更多林业背包 (More Backpacks) +e-flux +thaumcraft-extras|神秘扩展* + +peacefulpack +sulfur-and-nitre +combat-evolution +shaderfixerragecraftver|光影修复:Ragecraft 版 (ShaderFixerRagecraftVer) +brokenentity-0 +the-cardboard-box-extension +kubejs-cc@kubejs+cc-tweaked +sbm-elevators +sbm-cacti-bucket +sbm-grappling-hook +sbm-hand-held-piston +petting@ +datapatched@ +no-villages +hbms-nuclear-tech-leafias-cursed-edition +cell-chemistry +ae2-all-encompassing@|AE2:包罗万象 (AE2: All Encompassing) +tiptool +burrowers@ +skyislands +fastflyblockbreaking-reworked +aether-ruined-portals +fca-flame-chase-artifacts|星穹饰品 (Flame Chase Artifacts) +@more-backpack-upgrades|更多背包升级 (More Backpack Upgrades) +@daedalus-enchantments|代达罗斯附魔 (DaedalusEnchantments) + +better-lock-on@|史诗战斗 - 更好的锁定 (Epic Fight - Better Lock On) +nightfall-invade|史诗战斗:夜幕入侵 (NightFall : Invade) + +copper-friend-backport|铜器时代的小家伙* +slab-topographic|自然台阶 (slab topographic) +tag-editor|贴标签* + +omnitool@omnitools|全能工具 (OmniTools) + + +@syncmatica-revolution|共享原理图增强 (Syncmatica Revolution) +quantumhue-visualizer|量子色域 视界 (QuantumHue Visualizer) + +sbw-drr|[SBW]龙之崛起:重铸 (DragonRise: Reforge) +nine-nether-regions@|九幽引 (Nine-nether Regions) +handheld-moon@|掌中明月* +carpenters-blocks-ce|木匠方块-社区版 (Carpenter's Blocks-CE) + +@yos-coins +ae-infinity-disk@|AE无限磁盘 (AE Infinity Disk) +survivalplus-primer¨survivalplus-primer-fabric +northstar-redux@|机械动力:北极星 - 重制版 (Create: Northstar - Redux) +create-igneodynamics@ +create-numismatics-utils@ +create-vintage-unofficial-port@create-vintage-(unofficial-port) +create-bits-n-bobs@ +ccb-tweaks@ccbt +gregtechceu-modern-extra-unofficial@gtceu_extra +geotetraarmor +more-more-tooltips +more-tooltips +elemental-creepers-redux +mc-modsthecreepers +wikiful@ +atlatls@ +@itemaccessrestrictor|物品存取限制器 (Item Access Restrictor) +kaguyafd|辉夜姬的五难题:重置 (KaguyaFD) + +ahh-pvp@ +toggle-sneak-sprint@togglesneaksprint +monstie-hunter-baby-monster-collector@monstie-hunter-baby-monster-collector! +enchants +hubris +custom-nether-portals@custom-nether-portal +damagenumberlegacy +helios-divinity +item-marks|物品标记* +mossylib@ + + +better-trading-menu@|更好的交易菜单* +easy-npc-config-ui@ +evolved-mekanism-extras|通用机械:进化扩展* +@music-hud +backups +inventory-particles@|物品栏粒子* +backport-recipes@ +primal-survival@ +electrical-age-eln@electrical-age-jrddunbr-edition +@showfps|显示FPS (ShowFPS) +magia-daemonica +death-n-taxes +f5-camera-control-f5@summer_xtjl_f5_camera_control|F5视角控制器 (F5 Camera control) +super-factory-manager-unofficial-backport-sfm-ub +cart-complete +veilings + +narutoloading +visual-keymap@|可视化键位图* + + +grindstoneplus|更好的砂轮 (GrindstonePlus) +anvilcraft-transducers|铁砧工艺:并入电网 (AnvilCraft Transducers) +confluence-weapon-modification@confluence_weaponmodification|汇流来世:武器修改 (Confluence: Weapon Modification) +some-useless-things@a-useless-mod|无用之物* +hmag-spells|藏妻术式 (HMaG Spells) +tsb-tetra-spell-book|Tetra法术书 (Tetra Spell Book) +lucky-fishing-rod@|幸运钓竿* +gilded-krmor + +traces-of-the-fallen +lycanite-mobs-additions +revmobs +kaleidoscope-cookery-refabricated@|森罗物语:厨房——重织* +timelesslib@ +norfrieds-eldritch-takeover +minecolonies-modernitzation-update|殖民地现代化更新 (Minecolonies Modernization Update) +setcraftjs|套装效果 (SetCraftJS) +xymultichat@|聊天分栏 (XYMultiChat) +mc-mods-of-slashblades + +texture-locale-redirector@ +eidolon-edoni@|幻梦:欢宴 (Eidolon : Edoni) +mekanism-morecapacity@mekanismmorecapacity +modular-machinery-cryogenic-simulation-edition +sbm-wooden-rails +project-fruit|水果地形* +@mcef2 +tlm-native-power|车万女仆:原生的力量 (TLM: Native POWER) +hogcraft +awesome-sheep-swell@|丰毛肥羊* +@casks|桶 (Casks) +luxurious-misfortunes +transparent-entities@ +paintings-n-discs-backport +fallen-elves +@pv-addon-flashback + +ae2fluidcraft-rework-unofficial|AE2流体合成套件重置非官方版 (AE2 Fluid Craft Rework Unofficial) +annihilation-recreated +simple-kelpies@ +tacz-turrets@ + + +health-scoring +supearlposition +daisy@ +no-fall-mod +@farmers-assortment +foggy-world + +thieves +witt +techrot@ +create-easyfilling@ +mortar-and-pastels@mortar +@delicate_little_garbage|精致小垃圾 (Delicate Little Garbage) +elementalcraft-reactions@|属性锻造:元素反应 (ElementalCraft: Reactions) + +kubejs-recipes-create|KubeJS配方生成 (KubeJS Recipes Create) +hamstercore@|仓鼠核心 (HamsterCore) +showercore|洗浴核心 (Shower Core) +playsound-pro@playsound_pro|音频播放专业版* +omnisprint@|四向疾跑 (OmniSprint) +@totem-of-luck|幸运图腾 (Totem of Luck) +infinite-provider@|无限供应器* +annuus@ +myosotis@ + + + + + + + +magistics|魔法物流* +littlefix +@legacyvoicechat +fast-recipe-search|快速配方查找* + +speech-recognition +faster-block-placement@|更快的方块放置* +instantsleep +chunk-save-fix@|区块保存修复* +peacefulsurface¨peacefulsurface-fabric +mazons-quarks +lucisrenderlib@|光 渲染库 (LucisRenderLib) +no-ai-guess@|禁止 AI 胡扯 (No AI Guess) +itemnamecopier|复制物品名称 (ItemNameCopier) +ping-like-r2 +super-bosses@ +slashblade-patchouli@ +ender-dragon-suit +ecliptic-seasons-lets-do +lets-do-hearth-timber@|木工营造 ([Let's Do] Hearth & Timber) +immersive-vehicles-vdeco@vdeco +netherized-kedition +wizardry-and-fire +pepsied-item-name-recolorer +pepsied-auto-droppers +pepsied-copper-item-pipes +pepsied-exp-vacuum +pepsied-pocket-dimension +pepsied-mining-quarries +sbm-red-cow +fangs-textiles-and-trinkets + + + +saurialib@ +riftlibrary@ +clean-portals-randomportals-cleanroom-edition +spinning-items-displayer-mod@ +attack-range-attribute@ +kryptonfnp-patcher@ +riautomobility@ +cyberware-reforged@ +project-plastic +blocky-file@|方块文件* + +kaleidoscope-nether@|森罗物语:下界* +me-placement-tool@|ME放置工具 (ME Placement Tool) +pepsied-slow-hopper +nocubes-food-desire +@dense-flowers +prehistoric-rift@ + + +more-slashblade-ex-enchantment-effects|超多附魔增效 (More SlashBlade Ex Enchantment Effects) +tinkers-emc|匠魂EMC (Tinker's EMC) +@tacz-advanced-deathinfo|TACZ 高级死亡信息 (TACZ Advanced DeathInfo (Kill Banners)) +summon-totem|召唤图腾* +traditionalcraft@|古法工艺 (Traditional Craft) + +christmas-music-discs@|圣诞音乐唱片* +friends-for-life@ + +wool-pressure-plates@|羊毛压力板* +protect-mobs-from-daylight@ +pepsied-more-professions +pepsied-chaos-core +pepsied-auto-bridger +custom-sapling@|自定义树苗* +chestlie|箱子是个谎言 (ChestLie) +patternprovidersave@|样板供应器保存 (PatternProviderSave) +create-lazytick@createlazytick|机械动力:懒惰刻 (Create: LazyTick) +create-sentry-mechanical-arm|机械动力:哨戒动力臂 (Create: Sentry Mechanical Arm) +just-enough-fuels|JEI匠魂燃料* +trade-refresh-legacy@trade_refresh_legacy|交易刷新:旧版* + +aquatic-breeding@|水产养殖* +pack-up@ppack-up|场取速拾* +fox-white-technologies +the-watching-deer + +sketches-blueprints +whitefoxlib + +compost@ +@copper-coins +bons-odds-n-ends@odds-n-ends +i-f-amphithere-mod + +unu-civilian-pack-for-mts@unu-civilian-pack +rlcraft-manhunt +ancient-forgemastery@ +relentless-undead +@classic-farlands|经典边境之地 (Classic Farlands) + +the-morbid-unreborn +@crop-critters + +clash-of-cards +re-animal@ +tfc-ruins@ +@airraid +@easytp|便捷传送 (EasyTp) + +stardew-hud@|星露谷物语HUD (Stardew HUD) +enhance-bionics|增强仿生* + +profile-cached@ +goety-awaken@|诡厄巫法:觉醒 (Goety: Awaken) +iss-food-spelling@|食施法 (ISS: Food Spelling) +one-enough-enchantment@ +one-enough-value@ +@coordinate-manager|坐标管理器 (Coordinate Manager) + + +@gravestones-fix|墓碑修复 (Gravestones Fix) +whimsy-deco@ +incendium-translation-fix@ +@sinfo +tarkovcraft-core@ +saro-s-road-blocks-mod@saros-road-blocks +saro-s-road-signs-mod@saros-road-signs + +more-mc-music-discs@more-music-discs|更多音乐唱片 (More Music Discs) + +astikorcarts-deluxe +village-spirits +immersive-engineering-js +bygone-fortress + + +extra-shiny +pack-cen-header-fix@ +tmagriculture + +zombie-rush-1-12-2@zombie-rush+ +foxae2upgrade +wasteland-expanded@ +wakes-reforged@ +dank-null-legacy +subtle-fix +hyxcate|宙蚀之刻 (Hyxcate (Night/Day Events and Meteors)) + + +bucket-hat +christmas-sweaters +christmas-delight@christmas-delight-(farmers-delight-addon) +autumnal-winterly@ +zombie-virus-antidote@(hordes)-zombie-virus-antidote +@letmespeak +otyacraft-engine-renewed@ + +openinventory@ +zombies-break-glass@|僵尸破坏玻璃* +@vintagetag +floodlights +ic2c-additions +ic2additions@ +uranium-big-reactor +custommachinery-fork +player-animation-library@ +cnpc-epicfight-integration@ + +@pextras + +create-hamsterwheel@ +guerreros-del-mundo-2 +tacz-additions +potion-replacer +home-dust|回城之尘* +@hagds_tpa +oeuvre + +@kaleidoscope-addons|森罗物语:玩偶拓展 (Kaleidoscope Addons) +@bte|藍月光的交通扩展 (BML's Transit Expansion) +tongdarailway-for-forge|通达铁路-for-Forge (TongDaRailway for Forge) +counter-strike-grenades@counterstrikegrenade|反恐精英:投掷物* + +sync-forge +@sync-fabric-reported +player-shells@|玩家躯壳* +cataclysm-ametyst-crab-temple@ +@entity-0-elytra-fix +goety-mastery-of-magic-addon@|巫法精通 (Goety: Mastery of Magic Addon) +malisis-doors-revived +akuto-engine + +@omnicrossbow +knightperipherals + +@things-made-easy +tool-trims-mod@ +@classic-caves|经典洞穴 (Classic Caves) +just-parry@ +colored-light-core + +the-zenith-sword@|天顶剑* +better-f3-reborn +blockcraftery-refurbished +wonderland-jar@ +block-duplicator-tree@ +the-enderwoman-mod@ + +@no-hurt-flash +no-hurt-flash-reforged +@darks-found-footage-addon +@arknights-origins-originium-arts|起源:明日方舟源石技艺 +quincys-plate|Quincy的盘子 (Quincy's Plate) +visiontoggle@visiontoggle+ +regions-unexplored-expansion@ +cyberbop +adorable-dolls@|可爱多* +@tpnoop|随意传送 (No permission tp) +qliphoth-armaments + +dragon-rings|龙之赛环* +viscriptshop@ + + +@create-ergonomic|Create:实用功能 (Create: Ergonomic) +mending-gems +energy-meters + + + + +maid-attributes@|女仆属性* +@storage-and-one-click-synthesis|存储和一键合成 (Storage and One-Click Synthesis) +rcg-lib|王城剑兰 Lib* +@hide-crosshair|隐藏准星 (Crosshair Hider) +fast-fps-display|快速帧率显示 (Fast FPS Display)¨@fast-fps-display|快速帧率显示 (Fast FPS Display) - 源代码/正式版/测试版 +catzilla +wy-s-item|小狼夜瑛的物品 (Wolf_Yeying_s_Item) +thebladeofchaos49|混乱处刑 (Blade of Chaos) +maophone-trial-version@|MaoPhone体验版 (MaoPhone - Trial Version) + + +mrmc|世界之心 (Aether Cores) + +@arcane-vortex|秘法涡流 (Arcane Vortex) + +contactquests@|往来任务 (ContactQuests) + +custom-potion-color|自定义药水颜色* +modular-forcefields@modular-force-field-systems +shinyfood + +integrated-lucky-blocks +doublingtable +immersive-ores@ +spartan-compatibility +looters-compass@ + + +the-creep +bettermineteam@ +stopwatch +as-you-wish@ + + +clifftree-mod +marvelous-menagerie-paradoxical@|绝妙的生物群:悖论 (Marvelous Menagerie: Paradoxical) +callable-horse-compatible|长骑速驰 · 召之马来兼容版 (Callable Horse compatible) +spiritborne-ascendants +rgb-chat-vintage + +bloody-bits-fix +descendants-weaponry@ +chemicalscience@ +hud-control@|HUD 控制 (HUD Control) + +mchce|MC 直升机:社区版 (McHeli: Community Edition) + +easier-proud-soul-acquisition|更容易的耀魂碎片获取 (easier proud soul acquisition) +@slashblade-re-refabricated|拔刀剑:再重织 (SlashBlade: RE-Refabricated) +mystical-agriculture-community-edition@|神秘农业社区版* +lazydfu-reloaded@ + +tacz-slings@ +easydoll@|简易玩偶 (EasyDoll) + +gaiatweaks@ + +luckier-clover@|更幸运的四叶草* + + +universal-trinkets@ +roguelike-tower|肉鸽塔 (Roguelike tower) + +stranger-things-the-upside-down@ + +prims-stranger-things-mod + +super-backpack@|超级背包* + + +radiance¨@radiance-mod-windows¨@radiance-mod-linux +xaerolib@ + +umt-universal-metal-tools|通用金属工具 (Universal Metal Tools) +steel-spin-balls +bosses-delight|BOMD乐事* +emptiableboxes|清空编辑框 (Emptiable Boxes) +gadgets-n-goodies-mod +lag-spike-profiler +jabelars-moving-light-sources +just-enough-torches +quantum-lights +curios-slot-for-ammo-boxes +lumenized-continued@|流光溢彩延续版* +thirdpersoncrosshair +hiresshot@|高清摄影 (HiResShot) +@swappingaffinity +damage-correction@|伤害补正* +no-fly-zone@ + +twod-projectiles@twod_projectiles|2D 投掷物 ➵ (2D Projectiles ➵) +morethermalevaporation +autofish-for-tic@|自动钓鱼Forge版-匠魂兼容 (AutoFish for Tic) +wtc-wizardterracurios|泰拉饰品拓展 (Wizard Terra Curios) +invitemmark@|物品标记 (InvItemMark) +book-of-dragons@ + +nexuslib@ +formless|无相* +storagebox-adapter@ +nondirectionaldamagetiltfix@ +mekanism-atmospheric-stabilizer +mekajadeupgrades +re-avaritia-io-neo@re-avaritia-io +more-capacitor + +@lexforgefix +@aa-mbvd|泥砖菜盘(逆转裁判) (AA-MBVD) + + +the-wax-gourd@|东垂瓜* + +@eternal-firework-rocket|永恒烟花火箭 (Eternal Firework Rocket) +arse-ars-extensions|魔艺拓展 (Ars Extensions) +@gemattribute|宝石属性 (GemAttribute) +enhancedquarries@|增强采石场 (Enhanced Quarries) + + +extraloader@ +skyrims-skeletons-meme + +@3k08 +spacecube@|空间立方体 (Space Cube) +cinematic-cataclysm +call-you-by-your-name@|呼朋引伴/你的名字* +@techutils +storagebox-mod +storagebox-fabric@ +extended-tools@ +dynamic-electricity@ +maptip@ +astikorcarts-tfc +@nvidium-neoforge +item-flicker@itemflicker +vamppatch +speedy-path@ +@core-lib-api +@text-placeholder-api-expr +iridium-story|铱物语* +jei-enhancements@ + +dlc-manager|DLC管理器 (DLC Manager) - 主要通道¨@dlc-manager|DLC管理器 (DLC Manager) + +@map.png +bluelib@¨bluelib-common@|BlueLib - Common 版 +bluedude-dragons@ +@native-nicknames + +@kaishanstick|开山棒 (KaiShanStick) +hell-yeah-grass +small-stairs119@ +nuclear-boiler@ + +kaleidoscope-doll-workshop@|森罗物语:玩偶工坊* +skybeam-block-revival@ +mechanix + +fruitydelight@|水果乐事 (FruityDelight) +the-architects-bypass +terran-expansion +anvilcraft-kubejs@anvilcraf-kubejs|铁砧工艺:KubeJS (AnvilCraft: KubeJS) +steam-n-rails-neoforge@create-steam-n-rails-1.21.1 +foxified-dense-flowers@ +chickens-2@ +ender-io-conduit-replacer +valkyrien-logistics@|瓦尔基里:逻辑仪表 (Create: Valkyrien Logistics) +anvilcraft-better-beacons-compatible@|铁砧工艺:更好的信标兼容 (AnvilCraft: BetterBeaconsCompatible) +anvilcraft-curios@|铁砧工艺:饰品 (AnvilCraft: Curios) +anvilcraft-patchouli@|铁砧工艺:帕秋莉手册 (AnvilCraft: Patchouli) +@illusion|幻形 (Illusion) +tnt-duper|TNT复制器 (TNT Duper) +create-storage-neo-forge@ +create-springs@ +@create-more-parallel-pipes-fabric +baby-animals +@infernum-effugium + +world-reloader|息壤* +ascension-mastery@|飞升:精通* + +@skip-server-resource-packs +alexs-mobs-1-21-1-port@alexs-mobs(1.21.1) +alexs-caves-unofficial-port@alexs-caves-(unofficial-port) +betterend-neoforge@ +betternether-neoforge@ +@create-wells +wunderlib@ +wunderlib-neoforge@ +citadel-1-21-1-port@citadel-(1.21.1-port) +bclib-neoforge@ +worldweaver-neoforge@ +mod-menu-neoforge-edition@mod-menu-(neoforge-edition)|模组菜单(NeoForge 版) (Mod Menu (NeoForge Edition)) +bugfixerupper@ +@create-storage-refabricated + +critters-delight@ + +stars-good-life|星光的养成模组* +@beacon-enhancement|[黎氏科技] 指向靶点 (XCZ Target Directed) +@diexvcreeper|Diexv苦力怕 (DiexvCreeper) +kaleidoscope-cookery-automation@kaleidoscopecookery-automation|森罗厨房:自动化 (Kaleidoscope Cookery: Automation) +bastion-remnant-renovation-project|堡垒遗迹翻新工程* + + + +compostbin@|堆肥箱* +anvilcraft-ponder@|铁砧工艺:思索 (AnvilCraft: Ponder) +anvilcraft-guideme@|铁砧工艺:GuideME (AnvilCraft: GuideME) +anvilcraft-delta@|铁砧工艺:三角化 (AnvilCraft: Delta) +anvilcraft-lite@|铁砧工艺:青春版 (AnvilCraft: Lite) + +me-proxy@ +kubejs-oritech-kjs@kubejs-oritech + +@oredetector1|矿石探测器 (Ore Detector) +enchanted-wands-tomes@ +@create-cafe-fabric|机械动力:咖啡馆 (Fabric) (Create Cafe Fabric) +createjeicompat +jeiores +enhanced-mob-variants +squickens +additional-small-stairs@ +@golem-dandori +@private-horses +@dropbar +@vanilla-outsider-better-dogs +@oceans-delight-polymer-port +@storage-delight-polymer +@crate-delight-polymer +@more-delight-polymer +@spanish-delight-polymer +@choppers-delight-port +@frights-delight-polymer +@ubes-delight-polymer +@farmers-delight-polymer +repair-box + +@out-of-sight-out-of-mind +@channelchat|聊天频道 (ChannelChat) +omocha-no-shugosha|Omocha no Shugosha / おもちゃの守護者 +spice-of-life-maid@|生活调味料:酒狐萝贝 (Spice of Life: Maid) +bbsdbz-mobs +onlylooking-updated +velocity-blur +@kmmms +rpg-style-more-bosses-early@rpg-style-more-bosses + +ancient-city-renovation-project|远古城市翻新工程* +warship-arise|战舰崛起之时* +@valkrien-skies-tfc-compat-fix|瓦尔基里X群峦传说兼容 (Valkrien Skies TFC Compat Fix) +prometheus@prometheus-api|普罗米修斯* +dynamic-registrar|动态注册* +blue-oceans@|蔚蓝之海 (BlueOceans) +one-click-one-block-legacy@|点到为止:遗产* +@alwaysallowtp|始终允许传送 (AlwaysAllowTP) +@touhou-little-maid-beacon|车万女仆:移动信标 (Touhou Little Maid: Beacon) +luyubaubles|语录签名 (LuyuBaubles) +anvilcraft-kaleidoscope@|铁砧工艺:森罗物语 (AnvilCraft: Kaleidoscope) +modular-bees|模块化蜜蜂* + +forever-babies@|稚子长留* +maingraph@maingraph-for-mc|麦块主图 (Maingraph for MC) +command-block-ui-overhaul@|命令方块界面重构 (CommandBlockUIOverhaul) +@chaintogether|链在一起 (ChainTogether) +@glowmyblocks|光耀千万块 (GowingBlockOutlines) +@zip-to-it + +fork-twilightforest-thread-safety-addon-for-forge|暮色森林线程修复(Forge) (Twilight Forest Thread Safety Addon Fork for Forge) +@homura_lightning_enchantment|Homura的闪电附魔 (Homura Lightning Enchantment) +@homura-life-steal-enchantment|Homura的吸血附魔 (Homura Life Steal Enchantment) +easy-auto-cycler@ + +f34@ +biome-hud +one-stack +animights +230215-library +ctnh-core +debugify-reforged + +@lotr-legacy-kings-addon + +ae2-tangible-bookmarks@ +deadbyskillcheck@ +stormies-spiders@ +saints-dragons@ + + +buildtech|建筑科技 (BuildTech) +forge-multipart-integration-fmpi +chemlab +@grand-indestructible-kingdom +@hidden-world-border|隐藏的世界边界 (Hidden World Border) +craftingtable-iv|智能工作台4 (CraftingTable IV) +tokusatsu-hero-instrumentality-project-evolution@thip-evo|特摄英雄补完计划-进化 (Tokusatsu Hero Instrumentality Project-Evolution) +buddy-drones@ +@tlskin +shels-minechat +legacy-gamemode-switcher +@borukva-food-exotic +betterblockz@ +packagedtacz|封包TaCZ (PackagedTacz) +lotas-light@ + +better-keepinventory@keepinventory +mob-locator@ + +zoesteria + +@random-optimization|随意优化 (Random Optimization) +embergetic-expansion-embers-rekindled +irons-spell-books-arcane-essence-blocks@irons-spellbooks-arcane-essence-blocks +vampirism-irons-spells-compatibility@ +unofficial-irons-spells-n-spellbooks-skill-tree + + + +item-rarity|万象棱镜* +forgesoul|魂锻 (ForgeSoul) +zhipeiweidu|我的支配维度* +tfc-sophisticated-backpacks-upgrade|群峦精妙背包升级 (TFC Sophisticated Backpacks Upgrade) +explosives-plus-plus +shape-shifter-curse-addon@|幻形者诅咒扩展包* +mine-trigger +power-converters3|能源转换3* +@stickerbomb +@unlockedcamera +stygian-end-recontinuation +undead-variants@ +clone-items|克隆物品 (CloneItems) +more-compostables +legacy-duplicator-mod +ftbquest-slot-rewards + + +@be-a-doll + + +guardian-chests|守护者之箱* +industrial-wires-classic|工业线缆经典版* +industrial-wires-reengineered + +@everything-invisible|万物隐藏 + +@hidehitbox +ae2-crystal-science@|应用能源:水晶科技 (AE2 Crystal Science) +pc-compat@ + +taov-core|瓦基大冒险核心 (TAOV Core) +natural-philosophy@ +monster-spellbooks +advanced-arsenal@ +first-person-view@ + +eat-whenever-you-want@ + + +visiting-villagers@ +loot-beams-refork@|战利品光束:Refork (Loot Beams: Refork) + + +too-many-tinkers|TmT 匠魂材质映射* +rosettaenchanttable +@huh-what-is-this|这是什么东西? (Huh?What Is This) +akatzumapick@|汤姆的简易存储附属 (AkatZumaPick) + +immersive-optimization-edition +shoulder-surfing-irons-spells-integration@shoulder-surfing-iron-spells-integration +tf-storage@|TF存储 (TF Storage) +playeraffixes|玩家天赋 (PlayerAffixes) +wild-mobs-mod|野生生物 (Wild Mobs) +chest-cavity-beyond +loading-protection|加载中保护* + + +lets-do-lilis-pottery@ +hotbarlock-reborn +carry-me@ +ae-tetra +improved-botania-pools +improved-botania-sparks +improved-botania-spreaders +ftb-quests-lang-splitter +circumnavigate@ +sculkandjaw@|幽匿与钳合 (Sculk And Jaw) +raxiores-of-raxiore + +fsang18s-heropack +ponder-for-kaleidoscope-cookery|森罗厨房:思索 (Ponder For KaleidoscopeCookery) +@sanity-neo +somnia-ce@|梦醒时分:社区版 (Somnia: Community Edition) +vs-hose-connectors@ +beautifultnts@ +create-rubberworks@ +create-utilities-j|机械动力:实用物品 J版* +create-item-drawers@|机械动力:物品抽屉 (Create: Item Drawers) +glass-remastered@ +the-rpg-inventory-and-classarmor-mod +dragonforged + +nebulalib@ +wunderlib-forge@ +bclib-forge@ +undertale-death-screen@ +skibidi-toilet-skibidi-doom-craft +roberts-tooltips|Robert的物品提示 (Robert's Tooltips) +@chunk-debug|区块调试 (ChunkDebug) +betternether-forge@ +betterend-forge@ +spitfire-throwable-fire-charges +lava-chicken-boss@ +better-water-breathing +brick-break-pickaxe-cracking +crawling-chaos@ +searchcarefully@|仔细搜刮 (SearchCarefully) +scape-and-run-parasites-halloween@ + + + + + + + + + + + + +ct + + +@rarityglow + +rezero-return-by-death@aland-return-by-death +ic2xuumatter@|UU物质查看器 (IC2X UU-Matter) +beta-plus +@gl_ass +@huazhou-chinese-armor|华胄 (HuaZhou : Chinese Armor) +@betterarrow|更好的箭矢 (BetterArrow) +illusionist-grimoire +mygo-mine-fargo|我的魂石 (Mine Fargo) + +ore-spawn-confusion|矿异位* + +lognore +create-harmonics@|机械动力:和声学 (Create: Harmonics) +@unfriendly-creature|不友好的生物 (Unfriendly Creature) +@gd656peek|GD656战术侧头 (GD656Peek) + +neo-bee-fix@ +itemlod +onysd-guns +tinkers-arsenal-reloaded +fluxzoom@ +zoomx@ +grim-kingdoms-lost-structures-ruins +vanillaconfig@ +@spatialaudio +awaken-gateway-entity|轻轻敲响沉睡的心灵* + + + +@qiuymmod +@orelocator_compass|矿石定位器 (OreLocator Compass) +@log-filter1|日志过滤器 (Log Filter) +icustommenu + + + + + + + + + + +@configurationsbackport + +day-counter-plus@ +spore-underground-bunker-spawner-compat@sporeunderground-bunker-spawner-compat +@bta +sneak-push@ +balanced-unbreakable +super-mob-tracker|超级生物追踪器* +everything-nunchaku +cell-terminal|元件终端* +ic2-reinforced-stone|工业防爆石 (IC2 Reinforced Stone) +milkcarton|牛奶盒* + +ic2cuumatter@|UU物质查找器 (IC2C UU-Matter) +limitless-vehicle|永无止境: 载具* +beautify-refoxed@|美化!(NeoForge) (Beautify: ReFoxed) +aecapfix@ +lcompat@ +raritycore@|稀有度核心 (RarityCore) +simply-cozy@ +souls-like-universe-weapons-armors@slu +do-me-a-favor@dmaf +cave-dweller-evolved@¨@cave-dweller-evolved-(fabric) +obfuscated-kamussy@obfuscated +poison-madness + +combatlog@ +marvelous-species +@blink-eye +sporeadds@ +lord-of-the-mysteries-craft@lotmc + +weather2-remaster-addon-weather-computers-and@weather2-remaster-addon-weather,-computers-and-broadcast +@particleculling-1.8.9-port +@renderlib-1.8.9-port +@nothirium-1.8.9-port +@entityculling-1.8.9-port + +oxygen-mod +@dispenspear|矛发射器 (Dispenspear) +qianmospeedmod@|阡陌疾旅 (Qianmo Speed) +funky-fluids@ + +brainier-bees@ +rrv@ +hopper-golden-edition +ae2-powertools +simple-sleep-vote@ +scape-and-run-parasites-aether +santa-logistics@ + + +easy-survival-plus@easy-survival-mod + + +@kaleidoscope-texture-expansion|森罗厨房:乐此不疲 (Kaleidoscope Texture Expansion) +legendary-additions +tacz-arcana-timeless-and-classics-guns + +mebahels-creatures-draugr@|Mebahel 的生物 - 尸鬼 (Mebahel's Creatures - Draugr Invasion) + + +dgmodules|DG 模块 (DG Modules) +@cvn|虚拟矿脉 (Custom Virtual Vein) +curvebuilding +minemenu-no-shift-conflict-patch@|我的菜单 - 非官方按键冲突优化补丁 (MineMenu: No-Shift-Conflict Patch) + +@chestlooteditor|自定义箱子战利品 (ChestLootEditor) + +tinkers-ancient-tools-rebuilding|工匠:古物重建 (Tinkers: Ancient Tools Rebuilding) +mace-enchantments +masterful-machinery-fork +enchantment-limiter-fork +cobblemonraiddens@ + +heartmod@binding-of-isaac-heart-mod +pokecube-legacy@ +seasons-mc +immersive-cinematics +akashic-goggles@ + + + +@creeperneutral|苦力怕中立 (Creeper Neutral) +chainsaw-man-devilcraft@ +@blockgiveeffects|方块附加药水效果 (BlockGiveEffects) +@illage-art|灾厄艺术 (Illage Art) +crd-broadcasts@ + +@create-blockchain +miscellaneous-metals@marbleds-core +owen233666s-windows@ +infinity-pattern-provider@|无限样板供应器* +@carpet-sdk-additon +@gbattlepass +floralis@ +spartan-weaponry-unofficial@|斯巴达的武器:非官方版* +iron-furnaces-enhanced +spectral-utilities +pvp-flagging@ + + +@fractal-lightning|分形闪电 (Fractal Lightning) +electroblobs-wizardry-redux@ +epic-fight-super-golem-x-modular-golems|傀儡装配X超级铁傀儡 (Epic Fight - Super Golem x Modular Golems) + +@f3-screenshot +ssc-xu-addon@ +unitytranslate@ +celeritasleafculling@celeritas-leaf-culling + +redstone-chemical-elements@redstone-chan-chemical-elements|红石酱的化学元素 (Redstone-chan Chemical Elements) +tbc +ocean-lily-pad-village@ +@player-doll +@crazy-hunters-manhunt-ai +@dont-hit-the-bees +skeleton-uses-custom-bow@ +@zerocontact +jubitus-birds +structureoverlapless|结构不重叠 (StructureOverlapless) + +chat-calculator-boost@|聊天计算器增强* +@no_mobs_destroy_block|禁止生物破坏方块 (No Mobs Destroy Block) +instantworldmirror|瞬时世界之镜 (Instant World Mirror) +@floating-excavation|浮空挖掘 (FloatingExcavation) +hostile-mobs-and-girls-recall|敌对生物与魔物娘:追忆 (Hostile Mobs and Girls: Recall) +@holoinventory-reloaded|物品显示/物品清单:重载版 (HoloInventory-Reloaded) +@everlaartifacts|七叶镜绫的随想/言引定制 (EverlaArtifacts) +@bright-sunflower|曜日金葵 (Bright Sunflower) +atm-azure-tetra-materials|蓝钢锻艺 (Azure Tetra Materials) + +revelation-goety-fix@|诡启兼容 (RevelationGoetyFix) +resource-farm|资源农场* + + + + +create-infinite-water@createinfinite-water|机械动力:无限水 (Create: Infinite Water) +@create-optical-fabric|机械动力:光学 (Fabric) (Create Optical Fabric) + + +@honormod +botany-pot-configuration-card +hellish-trials@ + +@voxy-worldgen +fullbright-optimized@optimized-fullbright +merlins-epic-boss-cataclysm +enter-sandworm@ +playerengine@ +terralith-no-structures +pistonproplus@|活塞ProPlus (PistonProPlus) +biology-dictionary@|生物辞典* + +more-tier-upgrade|更多精妙堆叠* +more-functional-storage-upgrade@|更多功能性存储升级* + +carpet-lms-addition@ +maid-restaurant@|女仆餐厅* +seven-elements@ +neo-eco-ae-extension@neoecoae +golem-snowball-damage +in-the-corners@ +waystones-x@ +waypoint-bridge +olderpingdisplay@ +expanded-unuverse-pack@expanded-unuverse-pack-mts +unu-military-pack-for-mts@unu-military-pack +raisy@ + +kaleidoscope-chinese-food@kaleidoscopechinesefood|森罗厨房:国味* +mythicalaccessories|神话饰品 (Mythical Accessories) + +combat-circle@ +player2npc@ + +tacz-fire-control-extension +celeritas-extra@ +caves-revamp@ +pneumatic-popcorn +rubber-tree-for-dynamic-trees@ +bladecraft|更多剑 (BladeCraft) +terrafirmagreg-core@ +@etched-fabric +epicfight-physic-rag-doll@ +spice-of-life-valheim-updated@sol-valheim-updated +ae2-improved-search +ae2-fluid-terminals-rework +shoulderturrets + +spartan-shields-unofficial@|斯巴达之盾:非官方版* +@fake-ping +christmascolonies|圣诞殖民地 (ChristmasColonies) +mnaoverpowered@ +stack-manager@ +ae2-mod-id-view-cell +@curios-media-holder|我抄饰你的媒 (Curios Media Holder / Trinkets Media Holder) +custommeteorjs@ +kaleidoscope-end@|森罗物语:末地* +macaws-regions-unexplored@ + +bc-extra-pipes +@debugsurvivability +ae2-toggleable-view-cells +better-ic2-seed-bags +energized-power-farmers-delight@energized-power-fd +energized-power-the-aether@energized-power-ta +energized-power-biomes-o-plenty@energized-power-bop +weapon-class@ +boss-spawner-block|自定义生物刷怪笼 +goety-integration@|巫法集成* +blockz@|方块末日 (BlockZ) + + +simplycataclysm@ +attributefix-sync@ +sophisticated-item-actions@|精妙物品操作* +only-hammers-and-excavators@ +foolish@ + +entitychinesename@|实体中文名 (Entity Chinese Name) +firma-aircraft@|群峦航线* +exura@|更多实用设备:再重生 (Extra Utilities Reborn Again) + +shaolib@ +manage-your-ship@ +peak-craft@ +pink-precious-flowers|闪耀的长庭 (Shimmering Golden Flowers) +ae2-sampleintegration@ae2uel-smart-pattern-system|AE2 智能样板系统 (Smart Pattern System) +@new-big-trees +bananaplant@ + +caps-connected-area-prompt-shear@caps +@strinova-strings-and-floating|仿卡拉彼丘机制 (Imitating the Strinova Mechanism) +explainium +sourceflow-infinite@|源流无尽* +hbms-ntm-ce-space@ntm-ce-space + +ultimatespawn@ +simple2048|简单的2048 (Simple 2048) +@net-music-advanced-player|网络音乐机:高级唱片机 (Net Music: Advanced Player) +@extendednoteblock|扩展音符盒 (Extended Note Block) +realistic-explosives-ic2-exp-addon +nomoref3-f4@nomoref3+f4|旁观时间管理大师 (NoMoreF3+F4) +@ccccc_ + + +@force-beacon-load-for-forge|信标强制加载Forge版 (ForceBeaconLoadForForge) +folks-favors@folksfavors +easy-adventure@|便携基地* +star-optimized +networkblocker@|网络拦截器 (Network Blocker) +simple-world-downloader@ +class-armor-beast-master +class-armor-necromancer-and-paladin +class-armor-berserker-mage-and-archer +industrial-platform|工业平台* + +sunlight-zombie-mod@sunlight-zombie +lycheejs +colorwand@|调色棒* +@item-router +@commandbot +@village-diplomacy +@i-wanna-show +musket-mod-reloaded@ +@chainveinfabric +vcfix@ +@mixin-blacklist|Mixin 黑名单 (Mixin Blacklist) +chisel-3-the-cricket-strikes-back@chisel-3|凿子3 (Chisel 3) +mankini|曼基尼* +teamprojecte-reborn@|等价团队:重生 (Team ProjectE Reborn) +@mcapibridge +behemoths@ +@bar|备份永远是对的 (Backup Always Right) +@speed-slider|速度调整器 (Speed Slider) +questtapestry +occultism-ritual-satchel@|神秘学 仪式挎包* +mineclawd@ +@core-plants|矿石种子 (Core Plants) +enderio-evolution@enderio_evolution|末影接口:进化 (Ender IO: Evolution) +pocket-legion@|口袋军团* +@randomblocks_emerald_rabbit|随机方块空岛生存 +tennory@|战甲军械* +ankinbt@|安之编辑 (AnkiNBT) +ingame-info-xml-canoeedition|游戏信息显示 独木舟版 (InGame Info XML CanoeEdition) +lunatriuscorecanoeedition + + +thaumic-integration +@bedrockultimatetool|基岩究极工具 (BedrockUltimateTool) +@windowplayerhead +morecars|更多车 (morecars) + +telepad|传送台* +primitive-mobs-wondersapped +@farmerscreate +maestro@maestro-music +accents@ +fancy-entity-renderer@ +pantheonapi +eye-of-dreams-reforged + +mobs-equipment +civillis@|文礼* +desert-villager-trader@ +@mmdskin +@netmusiccanneedqq|网络音乐机:看你的QQ (NetMusicCanNeedQQ) +panoramic-screenshot@|万能截图 (Power Screenshot) + +custom-totem-particles|自定义图腾粒子* - 缺失 2.91 最新¨@custom-totem-particles|自定义图腾粒子 (Custom Totem Particles) +@GuxlRbJ2|Yomi的常磐装饰 (Yomi's Joban Client Mod) +@U75MCH6y +irons-spells-n-spellbooks-restrictions@irons-spells-n-spellbooks-restricitons +@IepjOJdK +@state-machine|状态机模组 (State Machine) +empty-shulker-nesting@ +pakcagedfaa@packaged_faa|封包禁忌与奥秘 (PackagedFAA) +ad-inferos + +cc-directgpu@ccdirectgpu-mod +easy-exchange@|简单替换* +@simple-image-renderer +ait-extras@ +rats-ratn-edition +@eye_of_dreams +foolish-unofficial-patch + +@damage-engine|伤害引擎 (Damage Engine) +travelers-lib@ + + + +station-builder@|车站建设器* +heavy-duty-plate-blocks|重装防护板块 (Heavy-Duty Plate Blocks) +@brxs-customizable-nextbot|Brx的自定义Nextbot (Brx's Customizable Nextbot) +sakura-reforged|樱·重制* +@worst-luck-possible +ihfr-fo + +item-despawn-to-what@|掉落物转化* +jurassic-saga@ +ae2-tech-add-on|AE2 科技扩展 (AE2 Tech Add-On) +@create-nerfad +questextra +flans-mod-npc-vehicles +@easyloginmod|简易登录 (EasyLogin) +inventory-sort-nf|背包整理(NeoForge 版) (Inventory Sort (NeoForge Edition)) +someordinarytweaks-forge@ordinarytweaks + +qliphoth-awakening-dimensions@ +@mca-expanded +ex-meteor-shower|流星雨 (Meteor Shower) +chaos-persists +adventurers-amulets|冒险家的护身符 (Adventurer's Amulets) + +@mortem +create-frequency-filter +@accurate-skies + + +@xytpa|Xy的TPA模组 + +steves-factory-manager-reborn|史蒂夫工厂-重置 (Steve's Factory Manager Reborn) +steves-addons|史蒂夫工厂管理附加 (Steve's Addons) +ffs-fancy-fluid-storage@|液体存储 (Fancy Fluid Storage) +reverie-foundry|遐想旅途 (Journey of Reverie) +flowercraft|花朵世界* +@rrtt217-s-hdr-mod +lycheejs-neoforge + +epic-fight-the-arachne +insane-tnt@ +extra-tnt +mob-loot-bags@ + +steve-chair@ +stoic-dummy@ +wildex-bestiary@ +fubricapi@fubric-api + + + +adaptability|适应性* +redstone-chans-void-dimension@|虚空维度 (Void Dimension) + +@tchy_difficultyadjustment|太初寰宇难度调整 (TCHY Difficulty Adjustment) + + + +noisiumed@ +tradable-wind-burst@|可交易风爆* +@enchant-tweaker +mbd2thread@|MBD2 线程拓展 (Mbd2Thread) +@ignatiushcsmoreore|IgnatiusHC 的更多矿石 (IgnatiusHC's More Ore) +ultimate-village|终极村庄* +@fangsu-mtr-addon|方速MTR扩展 (FangSu MTR Addon) +@mitoftk|我的世界:王国之泪 (Minecraft: Tears of the Kingdom) +more-candles@|更多蜡烛* + +tacz-automatic-first-person +@kgt6neiaddon +abyssalcraft-remnant-tweaker +herobrine-companion@herobrine_companion|Herobrine 的陪伴* +industrial-forestry +avaritia-lite-extended +goety-hostility@ +fish-traps-remastered@|鱼栅非官方重制版* +the-ponderer@|思索者 (Ponderer) +fallen-lib +lazyyyyy@ + +zunpet-vintage +fluxed-crystals-2|变换水晶2 (Fluxed-Crystals 2) +gregtech-ceu-gaseous-blast-handler +gtmoretools@ + + +violas-wardrobe@|Viola 的衣柜 (Viola's Wardrobe) +@simple-chat-disabler +@cbc-phantom-shells|机械动力火炮:幻影炮弹 (CBC Phantom Shells) + +@create-jade-quartz +create-idlx@ +@physics-drop +sketchrender@ +brainrot-protocol +my-shadow@ +pipecraft@ +better-forests@|更好的森林* +overworld-ancient-debris@ +simply-potion-rings@ +bettervanilla|更好的原版 (Better Vanilla) +more-respawn-anchors-remastered@|更多重生锚重制版* +goety-ladder@goetyladder|诡厄巫法:阶梯 (Goety: Ladder) +outer-rim@the-outer-rim|Sown 的星球大战 (Sown's Star Wars Mod) +evoc|优化效能 (Extreme Vanilla Optimizations Collection) +mobiuscore + +wormhole-potion@|虫洞药水* +finndusfillies +moogs-glow-up@ +starlight-with-create-fix +@zombies-everywhere +undyings-bosses +nice-to-have@ +@fmod +more-enchantment-info@|更多附魔信息* +@profitabletrade + + +harvestcraft-waila-fixes +ore-stages-restaged +the-mini-bosses +nether-descent@ +wtp-whats-this-pack +im-looking-at-blood + +iriss-plushie-mod@ +screencopy@ +legendgear-returns +legend-gear +ae2helpers@ +ae2-pattern-workstation|AE2样板工作站 (AE2 Pattern Workstation) +chiseltones +chisel-facades|錾面* +tinkers-extra-integrations +talismans-2|符咒2* +dalek-mod-all-dimensions-plus@ +pepoyo@pepoyo-mod +ctnh-changelog|CTNH更新日志 (CTNH-Changelog) +@i-want-cute-plushies-! +tinkers-ponder@|工匠思索 (Tinkers' Ponder) +@nekostulaicompanion +@chatpurity|聊天过滤 (ChatPurity) + +qwertech +silent-gear-jei@silentgearjei|寂静装备JEI (Silent Gear JEI) +cobbledex-rei-emi-jei@ + +tcondiadema-plus@|匠魂领域附加 (TconDiadema Plus) +@new-year-red|新年红 (New Year Red) +@fix-mc-249973-in-1.19 +i-wanna-music@|给我音乐!* +@1.8-style-inventory +@numeric-id + +morechisels|更多凿子 (More Chisels) + + + + +naturot@ +@infinity-stack +@zstdmc +vulkanbobby@ +applied-replicatics@|应用复制学* +@undead-fire-weakness|亡灵弱火 (Undead Fire Weakness) +ruthless +betterlooting@better-looting|更好的拾取 +@arknights-furs|明日方舟种族外观 (Arknights Origin Furs) + + + +@i-should-eat-more|吃不能停 (I Should Eat More) +mekanism-ponders@ +@cbc-compact-mount|机械动力火炮:紧凑式炮座 (CBC: Compact Mount) +create-auto-track@|机械动力:径工地点 (Create: Auto Track) +pulsetech@ + + +@night-lights-polymer +snowscaress@ + +fancy-outlines +ae2-pattern-encoding-access-terminal@ +efficient-entities@ +distant-banners@ +chroma-carvings +coffeechat|无忧聊 (CoffeeChat) +chest-tracker-port@|箱子追踪非官方移植版 (Chest Tracker (Unofficial port)) +better-crash-reports@better-crash-report|更好的崩溃日志* +trinkets-updated@ +not-enough-glyphs +@not-enough-vulkan +goslingcord +emojicord +@logarithmic-volume-control +scarcity@ +mo-bends-unofficial-modern-port@|更多弯曲 [现代化移植] (Mo' Bends [MODERN PORT]) +@supersteve|超级史蒂夫 (Super Steve) + +longroad|前路已明 (Road Is Ahead) +rough-render-excessive-eating@|粗渲滥食* + +simple-minesweeper|简单的扫雷* +mets-blade@mets_blade|拔刀剑:更多电力工具 (MoreElectricTools Blade) +slashblade-ununextremeaddon|拔刀剑重锋—一点也不极端的拓展 (SlashBladeUnUnExtremeAddon) +dragit|图片拖拽 (DragIt) +ixapi + + +anything-but-fish@|就是不钓鱼* +order-to-cook@|下单了* +butchery-lite@ +applied-construction-sticks@|应用建筑棒* +farscape-addon-for-gc3 + +serene-seasons-better-winter@ +@mc122477fix-re-updated + +refined-construction-sticks@ +yeti-jar-dweller +create-automotives@ +exposure-expanded@ +smart-spawn@ +random-mob-textures@ +uifadefx@ +daily-boss@ +it-seems-loosely-connected-to-the-ceiling@|与洞顶的连接似乎并不牢固 (It seems loosely connected to the ceiling) +agricraft-refitted@ + + + + +@unmannedonlinetickstasis|服务器无人时间静止 (Server Tick Stasis) +turbulence-loading-animation|乱流加载动画* +slashblade-model-warmup|拔刀剑:模型预热 (SlashBlade Model WarmUp) +raids-enhanced@raidsenhanced + +caged-mobs-kots|笼中生物 - 耕云钓月版 (Caged Mobs - KOTS) + +@basic-server-commands|常用服务器命令 (Basic Server Commands) +raritycore-for-fabric@raritycore_fabric|稀有度核心Fabric版 (RarityCore For Fabric) + +toms-storage-star-optimized|汤姆存储 - 星的奇妙优化* +sbw-wrecked@sbw-wrecked!|[SBW]残骸系统 ([SBW] Wrecked!) +shipping-box|售货箱* +@coin-to-shop|消费了! (Coin To Shop) +@liteloaderloader +i-need-dragon-egg@|我需要龙蛋* +nickname|昵称* +redstone-chan-cobblestone-generator@cobblestone-generator|圆石生成器 (Cobblestone Generator) +elytra-contrails@elytra-contrails-mod|鞘翅尾迹 (Elytra Contrails Mod) +guard-horn@|警卫号角* +jei-trim-hider@|JEI 纹饰模板隐藏 (JEI Trim Hider) +@sekirodiedscreen|只狼死亡界面:重生 (SekiroDiedScreen) +endfieldpanorama@|终末地游戏加载页面 (EndfieldPanorama) - 本体¨endfieldearlywindowmodule@|终末地游戏加载页面 (EndfieldPanorama) - 本体所需的加载模块 +bmts-imagination|让我改改 (Let Me Tweak It) + + + +puyu@|璞玉* +neo-titans-variant@|新泰坦生物-变种 (NeoTitansVariantMod) +assembly-line|装配线* + +@better-coordinate-records|更好的坐标记录 / 更好的座標紀錄 (Better coordinate records) +efn-enhance|夜幕强化 (EFN Enhance) +pets-locator@ +guide-book|合成指南书* +elders-wild +voidaic-arcania +@more-swords+ +scp-662-butlers-hand-bell +@perihelion +auroras-arsenal +infernal-expansion-redux@ +hbms-nuclear-tech-mod-waldemar-edition +@cloud-boots-legacy +@htcpwebserver +@noserversideclientmods +@minecraftpatcher +@staticenchanteditemrenderer +@timeup +@paragraphsreborn + +ae2-overclocked@|AE2超频 (AE2 Overclocked) +@bred-is-cool +integrated-mekanism@ +rainjava + + +me-soul-card + +mcqoy@ +qomc@ +explosive-enhancement-legacy@explosive-enhancement-1.12.2 +@sharedinv|共享物品栏 (Shared Inventory) + +landing-mud|落地泥!* + +@mtr-tat|列车与物品 (MTR Trains and Textures) +friendtp@|朋友TP (FrinedTP) + +display-tool|生物显血·极轻量版* +@digging-leaderboard|Minecraft 挖掘榜 (Minecraft Digging Leaderboard) +@first-person-immersive-audio|第一人称沉浸式音频 (First-person immersive audio) +technological-assistance|科技辅助* +not-enough-bandwidth@|网络包优化* +apprentices-codex@|学徒法典 (Apprentice's Codex) +asterism-arcanum-addon-for-irons-spells-and +wizards-help-irons-spells-n-spellbooks-addon +ftw-addon +new-years-delight-a-farmers-delight-add-on@new-years-delight-(a-farmers-delight-add-on) +@more-tools-1.21.1+ +@toms_simple_storage_in_tfc + +@oled-saver + +existencealone@existence|存在 (Existence) + +@the-nuke-mod +armor-3d@ +hot-iron +dangerous@ +balaclava-mod@ +@goodblock +tacz-sound-attracts-zombies@|枪鸣尸至 (TaCZ: Sound Attracts Zombies) +ntrials@ +alexs-mobs-fabric|Alex 的生物(Fabric) (Alex's Mobs (Fabric)) +citadel-fabric +bibliocraft-legacy-fabric +untamed-wilds-unofficial-port@untamed-wilds-(unofficial-port) +cit-recrafted@ +greek-fantasy-unofficial-port@greek-fantasy-(unofficial-port) +universutil +indev-hell-mod +apocalypse-dimension@ +dranergize-dragon-origin@ + +damage-indicators-classic +deadly-weather-storms +vapourware@ +inlinelatex@ +fear-of-sound@ +horror-pacman +@lock-doors-from-villagers +depths-update@ +furnace-mk2@furnacemk2 +auto-clicker-fabric@auto-clicker +@no-moon-network-fix +multi-key-bindings@ +dog-dog@dogdog + +deus-ex-machina-reborn +nanbin-create-mod@|南滨创意* +@multi-racing-utilities|竞速实用工具 +simple-absorption@ +cobblemon-trials-edition@ +potion-core-remastered@potioncoreremastered|药水核心重制版* +fantasy-iron-fix|铁梦兼容* +goety-awaken-fix|厄醒修复* +goety-twilight-fix|诡暮兼容* + +@emeraldcraft|绿宝石工艺 (EmeraldCraft) +you-are-the-zombie-2-0|我是僵尸 (As The Zombie) +mobcivics@ + +tarotcards-remastered@|塔罗牌:重制 (TarotCards: Remastered) +@copyblock|复制方块 (Copy Block) +@apocalypse_end|天启终焉 (Apocalypse End) + +@bypass-fabric-check + +tensionadd|剑拔弩张之时附加 (TensionAdd) +@trim-upgrade-core|纹饰增强 : 核心 (Trim Upgrade : Core) +openlink-chmlfrp-extension@|开放式联机:Chmlfrp扩展 (OpenLink Chmlfrp Extension) + + +enchantato-enchantment-table + +red-envelope-reforge|红包 (Red Envelope) +advanced-backups-patch@|高级备份补丁* +@network-proxy +@asmcraft + +apotheosis-things|神化小玩意* +weaken-satiated-shield|更平衡的饱腹代偿* +kaleidoscope-tavern@kaleidoscopetavern|森罗物语:酒馆* +the-farlands-are-back-tfab +beta-graphics@ +world-corruption-fixer +@echoes-of-utopia +structural-tools@|结构工具* +@originclasses +slime-chunk-finder@ + +optinotfine@ +enderdragon-loot +@carpet_cuo_addition + +@iceandfire-atm-compatibility +@modern-glass-doors(forge)|时尚玻璃门 (Neo)Forge 版 (Modern Glass Doors(Forge)) +ae2-better-magnet-card +rangedjs-kubejs-addon@rangedjs + +kaleidoscope-tfc-cookery|森罗物语:群峦厨房 (Kaleidoscope TFC Cookery) +reliable-recipes@ +inline-tooltips@ +mtr-east-japan-railway-addon +raidspawn +gtoex@ +@zzaiclear +@veil +gregtech-molecule-drawings +the-broken-script-patches-herdyn-edition¨@the-broken-script-patches|The Broken Script Patches - 原 +wifi-mod +more-tide-fish@ +ez-actions@ +create-train-tracker + + +create-backtank-is-jetpack +create-real-stack-size@ +create-fluidlogistic|机械动力:流体包裹 (Create: Fluid Logistic) +@fluid-shell-extensions|流体炮弹扩展 (Fluid Shell Extensions) +kubejs-create-automation +nether-star-items-forge@nether-star-items¨nether-star-items-fabric +piglin-hunt-fix +ok-core +@ccexpand-peripherals|CC拓展外设 (CCExpand Peripherals) + +colored-end-crystals +wenzhou-specialties|温州美食* +peyros-scythe-fix|铁镰兼容 (Peyro's Scythe Fix) +snowify-eternal-snow@ +@modernui-mc-mvus +horror-messages-kamussy@horror-messages +velthoric@ + +re-constructed-wands@reconstructed-wands +enchantment-library@|附魔图书馆* +load-stone@ +creatures-of-sonaria-in-minecraft@creatures-of-sonariacraft + +command-keybindings +@rdpfix +true-end-cf@true_end +barnyard-buddies@ +black-souls-options|黑色之魂:选项 (Black Souls: Options) +@crosstie +jcplugin +pursuit-of-immortality|无光仙途 (Nonsun's Pursuit of Immortality) +craftingnetherstar +emeddium-au-naturel-edit +viewmodel-tuner@ +aethersteel@ +custom-better-beacons@ +immersive-cookfarm@immersive-cooking-adoon +goety-heart-of-creation + +dragns-livestock-overhaul-pets-addon@dragns-livestock-overhaul-pets-addon! +unnatural-absorption +ripples-of-the-past-recording@ +serene-seasons-api-stub-ecliptic-seasons-bridge|静谧四季兼容桥 (Serene Seasons API Stub / Ecliptic Seasons Bridge) +ecliptic-seasons-bundles|节气:捆绑包 (Ecliptic Seasons : Bundles) +@maceeffect|重锤效果 (MaceEffect) +spiders-shoot-webs@ +@attribute-pvp-helper + +enigmatic-addons-legacy|神秘遗物拓展经典版* +beak-pouchs-plight@|喙囊悲事 (Beak&Pouch's Plight) +hammers-galore@|锤子多多* +language-amend@|译言订正* + +mechanical-millstone +zoology-of-the-world-of-withernauts +stackable-flowers@ +dragns-deadly-dinos-reconstructed@ +teleporttagjs@ +teleport-tag@teleporttag|传送标签* +insconfigjs@ +insconfig@|即时重配 (InsConfig) +entityreplacer@|生物替换 (EntityReplacer) +nohurtred|没有受击变红 (NoHurtRed) +bilibili-media-kots|哔哩哔哩WaterMedia兼容模组 - 耕云钓月版 (Bilibili Media - KOTS) +satiated-shield-fix|饱腹代偿修复* +tacz-armor-scaling@|TaCZ护甲缩放 (TaCZ Armor Scaling) +crazy-chocobos@crazy-chocobos! +burnt-basic@ +@regsyncfix +giddy-guinea-pigs@giddy-guinea-pigs! +dragns-crop-overhaul@dragns-crop-overhaul! +dragns-livestock-overhaul-permafrost@ +radical-rats +little-tractor@ +fancy-ferrets@fancy-ferrets! +@dune-striders +rummage|翻箱倒柜* +tacz-creative-supplement@ +@iems|综合能源管理系统 (Integrated Energy Management System) +anvilcraft-qualia-addon@aqa|铁砧工艺:Qualia (AnvilCraft: Qualia Addon) + +create-more-machines|机械动力:更多机械* +turret-mod-rebirth +kind-seagull|善良海鸥* +paper-kite-manor@paper_kite_manor|纸鸢庄园* +epicfight-clash-blade@|史诗战斗:冲击之刃 (EpicFight : Clash Blade) +attribute-keeper +@collide|冲撞 (Collide) + +frostfire-dragon|冰焰龙* +advancements-rewards@advancements_rewards|成就&奖励 (Advancements&Rewards) +@kaleidoscope-cookertransmutation-callback|森罗厨房:嬗变饭袋回调 (Kaleidoscope Cooker: Transmutation Callback) +constructionwandlegacy|建筑手杖怀古 (Construction Wand Legacy) + +@minewatch +@weight-system|重量系统 (Weight System) +interlace-spellweaves-irons-spells-and-spellbooks|交错织法 (Interlace SpellWeaves) +mobs-use-shield +skilltreemkp@ +cells +wanderer-pets@ +medieval-embroidery@ +dragns-wagons +dragns-deadly-dinos@dragns-deadly-dinos! +dragns-bettas-aquatics@ +reliable-remover@ +reliable-replacer@ +mob-dismemberment-unofficial-modern-port@|怪物肢解 [非官方现代化移植] (Mob Dismemberment [UNOFFICIAL MODERN PORT]) +guard-villagers-automatic-guard-conversion@ +repair-station@ + +gtm-advanced-hatch@ +kubejs-jei +traveler-tool-belt@ +floor-beds@ +shadow-actionbar +baby-steps + +vintage-damage-indicators@|复古伤害显示* + + +apricityui@|晴雪UI (ApricityUI) + +functionalstoragelegacy|怀旧功能性存储 (FunctionalStorageLegacy) + +echo-chest-experience-obliterator@ + +custom-stars-forge + +mobs-use-shields +fairy-factions +navs-pipes +big-lost-city@ +@taczaddonsfix +rollthesky +@tamablefairy|车万女仆:收容异变 (Tamable Fairy) +maidsconstruct@|女仆匠魂 (Maid's Construct) +bugrock +enchantato-loot +just-enough-crafting-tree-ject + +advanced-hud@advancedhud +ycqin +deep-blue-a-bettas-aquatics-addon@deep-blue-a-bettas-aquatics-addon! +applied-create@|应用机动* +tradeworks@ +@create-origins +torque-link-create-to-tfc|旋力转接:机械动力×群峦 (Torque Link Create To TFC) + +i-hate-ghost-blocks +custom-chest-name|自定义箱子名称* +modern-chickens@ + +rpg-backpacks@|RPG背包 (RPG Backpacks) +resource-replicator@|资源复制机* +@the-fossils-mod +little-johns-galvanized-square-steel@little-johns +navaroneecorelib +@yosbr-neo +@osten_botanics|东洋花卉 (Osten Botanics) +tree-vein-miner +ziplines-rezipped@ +reconnectible-chains@ +foxeternity +serverofflineauth@|服务器离线认证 (ServerOfflineAuth) +legendary-spellbooks +lootselect@ +sorcery-age@|咒术时代* +nosmithing-template@no-smithing-template|无锻造模板 (No Smithing Template) +mm-modern-mayhem@ +epicfight-extra@ +the-space@space +roguelike-world|地牢世界* +music-trigger@ + +cheating-free-locate-teleporting|无作弊Locate传送* +wallpapers@ +@creepebucketlib +missing-mods-checker@ +undead-nights@ +@abm991s-zombie-infection|abm991的僵尸感染 (abm991's Zombie Infection) +simplesorterr@|简单R键整理 (SimpleSorterR) +@tacticalwheel|战术轮盘 (Tactical Wheel) +dbcachievement|DBC成就 (DBCAchievement) +jei-research|深度求索 (Research) +aperture-innovations@ +townsfolk-tenants +custom-light@custom_light|自定义亮度* +the-cave-crawler +particle-rain-backport@particle-rain-(backport) +@inventory-disabled|物品栏禁用 (Inventory disabled) +navs-motors-inc + +theoria +ad-skies +attribute-unification|亿衍定真* +team-healthbar@|是敌是友一看便知* +touhou-maid-affection@|车万女仆附属:爱恋 (Touhou Maid: Affection) + +stoprendering +@ancient-planks|远古木板 (Ancient Planks) + +more-notches +newflatworld@|新开山棒 (NewFlatWorld) +oreganized-carcinogenius@ +better-trim-tooltips-forge@|更好的盔甲纹饰提示 (Better Trim Tooltips) +shutter-up@ +@pridespecial +worldgenfeaturefix@ +bloodmoon-update +immersive-gateways@ +slabbed@ +@item-replicator|物品复制器 (ItemReplicator) +hantoke1s-more-golden-apples@hantoke1s-more-golden-apple|更多金苹果/满目金果 (HanToKe1's More Golden Apples) +mc-music-player@custom-music-player|网易云音乐播放器 (Minecraft Music Player) +wallpaper +field-guide@ +calamity-curios|灾厄饰品* + +carvable-pumpkins-mod + +way-where-are-you@ +teamtasks-todolist@todolist|待办列表 (TeamTasks: TodoList) +@create-diesel-generators-fabric-restitched +create-enhanced-schematicannon@ +@luncheon +pollys-pets +yuutolib +randommixins +no-ai-spawn-eggs@ +p2pdetails|P2P详细信息 (P2PDetails) +afterimages@ +smooth-movement +creosote-oil-fuel-power|更有用的杂酚油 (Creosote Oil Fuel & Power) +rideable-blazes@ +alexs-caves-cacophony +alexs-mobs-delight|Alex 的生物乐事 (Alex's Mobs Delight) +tinkers-idea +ae2-me-interface-through +mekanism-sun|通用机械:人造太阳* + +anvil-lib@ +vkbc|葡园酒香森罗酒馆酒瓶兼容 (Vinery & Kaleidoscope Tavern Bottle Compatibility) +kaleidoscope-world-liquor@|森罗酒馆:世界名酒* +@burning +@burning-energy +realisticsunburn +novums-altitude +mystcraft-reborn@|神秘岛:重生* +@cod-pattern +tacz-lesraisins-tactical-equipements@lr-tactical|TaCZ:绿葡萄战术装备 (TACZ: LesRaisins Tactical Equipements) +rotten-ruins|腐朽之疫* +strawgolem-extended-life@straw-golem-unofficial-extended-life|稻草傀儡非官方延续版 (Straw Golem Unofficial Extended Life) +caves-not-cliffs-backport@caves-not-cliffs-backported +irons-spells-n-spellbooks-scroll-description +epic-fight-skillbook-description +cnpcextended +yifeis-game-adjustments|Yifei的游戏调整 +forcegl3-1 +baublevault + +embellish-chat@ + + + + +dolt-mod-how@ +irons-spells-spoken-sorcery@|铁魔法:言出法随 (Iron's Spells: Spoken Sorcery) + + +@tickrate +nitshas-fastbind@ + + + +nether-alloy-totem@|下界合金图腾* +inhabitants@ + +zoomax@ + +tfc-super-hammer|群峦超级锤 (TFC Super Hammer) +evolution-of-entities +@cobblemon-lucky-block|宝可梦幸运方块 (Cobblemon Lucky Block) +nekojs +mememobs@|迷因生物 (MemeMobs) +tinkers-centrifuge|匠魂:分离 (Tinkers' Centrifuge) +questlog@ +@perftriage +create-ender-gateway@ +applied-extended-crafting@|应用合成拓展* +mech-trowel@ +gui-tween@|GUI 动画 (GUI Tween) +hexalia@ +ars-unification@ +ars-elemancy +ars-polymorphia@ +debug-block-overlay-reloaded@debug-block-collision-reloaded +@progressive-tiers|阶梯强化 (Progressive Tiers) +apothic-enchanting-addition|通量神化附属* +puddles-floods@ +star-dragon-dragon-survival-addon|星辰龙 (Star Dragon) +casual-swing + +@carvedmelon + + + + +john-mod-resurrected +ohaydens-mob-control@mob-control +@wikirenderer +create-energy-cannons@|机械动力:能量加农炮 (Create: Energy Cannons) +pipe-climber|管道攀爬者* + + +demogorgons +toows@ +@noopentolan +@marlow-crystal-optimizer +mc-mods-the-mons-coremod +epic-fight-the-leonidas +epic-fight-wraithon +epic-fight-the-mimic +gearreborn|装备重生 (Gear Reborn) +@panorama_screen +make-panorama@makepanorama +@dbtools + +neko-ui@nekoui +ae2-inf-pattern-addon +@mod-menu-1.1x +fluffy-title@|蓬松标题* +human-emperor-banner|人皇幡* + +eeeabs-mobs-custom-bossbars@ + +kryxiom@ +legendary-mage@|传奇法师* +thaumcraft-recipe-aspect-patcher|亿源定值 (Thaumcraft Aspect Recipe Patcher) +itisme|强调 (It Is Me) + + +epic-fight-better-skill-menu +epic-fight-skill-irons-spells-n-spellbooks +epic-fight-skill-tacz +tijons-epic-crayfish +tijons-epic-arsenal-tacz@tijons-epic-arsenal +mobsfriendly@ +syscmd|系统命令 (SysCmd) - 只包含最新¨@syscmd|系统命令 (SysCmd) +mob-controller-mob-pet@mob_controller|驭役斗战·万物皆驯! (Mob Controller) + + +crazyvillagers-forge@crazyvillagers|疯狂的村民 (Crazy Villagers) + +gregtech-modern-quality-of-life@gtmqol|格雷科技现代版生活品质升级 (GregTech Modern Quality of Life) +custom-lan@ +ae2-pattern-archive@|AE2样板档案馆 (AE2 Pattern Archive) +preloading-tricks@ +ares-hud +tarotcardsplus@|塔罗牌Plus (TarotCardsPlus) +no-portals@ +p1neros-epic-x-cataclysm +epic-fight-dodge-parry-reward + +tfc-tri-hydrate|群峦:三水合物 (TFC: TriHydrate) +neogrid@neo-grid|自动电网 (NeoGrid) +enhanced-inventories|储物增强* +tfcmaid@|群峦女仆 (TfcMaid) +ae2-cell-render +aerobind@ +@galmc-api +tvcraft-the-legend-of-tenna@tvcraft-legend-of-tenna|TV世界:天纳传说 (TVCraft: The Legend of Tenna) +srp-info@ +@flywheel-of-terror +refinedrains-spells +inventory-tools +valkyrien-warium@ +voicetrigger@|声随形动 (VoiceTrigger) +neobiosphere@ +@homemade-stand|自制替身 (Homemade Stand) +unlimitedchat-for-1-7-10|无限制聊天 (UnlimitedChat) +ae2-odds-ends +registry-dumper-3000@ +oriental-armoury +autoreconnect-cn|自动重连 (AutoReconnect) +@mmdskinsync +beyond-storage-addon@beyond_storage_addon +decapitation +@narrow-zone +@aekey-legacy +okbackpack +thirst-was-tweaked@ +@loots + + +sophisticated-jei-index|精妙背包:JEI 索引升级 (Sophisticated JEI Index) +tropicraft-legacy +tcrmodsfilter +no-worldgen-warning +p1neros-epic-bow +p1neros-primal-arena-dimension +bountiful-villager +tcrmeshes +tcr-core +settings-profiles@ + +beyond-deepest-dark-sculk-dimension +anvilcraft-create@|铁砧工艺:机动附加 (AnvilCraft: Create Addition) +@fractalterrain +tlmo-additions@|车万女仆:织姬拓展 (TLMO Additions) +pull-me-up@ +integrations-o-plenty@ +grothic-mobs +eclipse-of-divinity +witching-gadgets-patched +mystical-extended-tier +ntm-fluid-converters@ +forkedendertweaker@ + +caves-delight@caves_delight +minimum-for-maximum@ +@gently-holds +anisum@|八角* +thezenith@thezenithsword|天顶剑 (TheZenithSword) +sbw-ping-from-drone +gravisuit-classic +tiny-storage +keymacro@|按键宏 (KeyMacro) +industrial-foregoing-simulation|工业先锋:模拟 (Industrial Foregoing: Simulation) +sbw-drill-baby-drill@sbw-drill,-baby,-drill! +ash-of-sin-no-more-invalid-statistic|罪业余烬:别再无效统计 (Ash Of Sin: No More Invalid Statistic) +immersive-flight-simulator-ifs-immersive-vehicles +imageframeclient@ +emi-patternizer@|EMI快速编码 (EMI Patternizer) +pattern-uploader@|样板自动上传* + +slashblade-mobs@|拔刀生物 (SlashBlade Mobs) +powercraft-gates|能量工厂:门 (PowerCraft Gates) +superwindmills-ic2-classic-addon +thecasketofrrveriesbosses +@sbw-combined-perk +reliquified-irons-spells-n-spellbooks@ +kilt-forgeconfigapiport-fix@ +entity-respawner +kill-cam +thaumic-all-aspect@|神秘全要素* +withers-wrath +defiled-lands-reforged|污秽之地重铸版* +sandwichable-unofficial-port@ +@lanbeacon|局域网信标 (LANBeacon) +harvesting-crops-for-xp +wizarding-world-mod +dont-touch-my-datapack|别碰我的数据包 (Don't Touch My Datapack) +brighter-full-bright@brighter +tlm-attributedisplay|车万女仆:属性显示 (Touhou Little Maid: Attribute Display) +jadeownerfix@|一眼认主 (JadeOwnerFix) +logistics-network@logisticsnetwork +@the-tnt-mod + +@elytra-chestplate-swap +@noloadingterrain|无加载地形中 (No Loading Terrain) + +ground-loot|露天战利品* + +corrupted-worlds-jar-horror@corrupted_worlds +minecraft-flight-simulator@immersive-vehicles-official-content-pack +frontline-comabat-pack@frontline-combat-pack +three-in-one-uncrafting-table@|三合一拆解台* +more-flux-storage|更多通量存储* +trowel@|抹泥铲* +trowel-future@ +lockdown-reneoforged|地图生成锁定 (Lock Down Reneoforged) +ardas-uncrafting-table@ +mana-and-artifice-attributes +tinkerswizardry|巫师匠艺 (Tinker's Wizardry) +@entity_recycle_bin|实体回收站 (Entity Recycle Bin) +whistling-petals@|飞矢摇芳* +create-track-map-unofficial-fork@create-track-map-(unofficial-fork) +sulphur-backport + +@private-vault +sophisticated-inventory-interactions@ +@quickorganizer|快捷背包整理 (QuickOrganizer) +even-better-burning +create-paper@|机械动力:纸张* +@a-villagers-dream +colds-wandering-trader +majobroom-kots|魔女的扫帚 - 耕云钓月版 (Majo's Broom KOTS) +@simupack|模拟大都市:筑艺坊 (Simupack) +waterwheel-immortal|水车仙人* +tf-remastered|暮色创世 (TF Remastered) + +configurable-sunburn +villager-inflation-fix-vif + +stalkerentity +openitempuller@ +scape-and-run-parasites-twilight@ +tool-switcher@|自动切换工具* +casual-tinkering@ +hyperlink@ +mooncake-delight@|月饼乐事* +more-vanilla-armor-fabric@|更多原版盔甲 Fabric* +no-smithing-template-refabriced@|无锻造模板(非官方Fabric移植) (No Smithing Template ReFabriced) +schematicannon-processing-pattern@|蓝图加农炮处理样板* +deadeye-mod@ +sbw-halovehicles + + +miningspeedtweak|挖掘速度调整 (MiningSpeedTweak) + + + + +fluid-couriers +@absolutely-a-zoom-mod +warium-n-spell-book + +@animatium + +ore-zombies|矿石僵尸* + +vaders-ore-spiders-mod|矿石蜘蛛 (Ore Spiders) + +crafting-slots@ +ddlc-chibis +create-additional-lights@ + +autoroadbuild|自动筑路 (AutoRoadBuild) +@net-music-better-login|网络音乐机:更好的登录 (Net Music: Better Login) +life-bet|我有一局,和你赌命* +create-butter-cat@createbutter-cat|机械动力:黄油猫 (Create: Butter Cat) +map-distance-fix@ +hexautomata@|咒法自动机 (HexAutomata) +fictional@|虚饰修复 (Fictional Mod) +sixalphasix-jar +mycelium-mire +ore-spiders-revived +@playerdieautomessage +vintagecraft +scary-player@scaryplayer +sulkan@ +@armorstatus +thalassophobia +silly-umas +better-survival-reforged|更好的生存重铸版* +dualhotbar-reworked@ +concurrent-chunk-management-engine-for-forge-the +fungal-infection-spore-unhinged|真菌侵染:孢子・疯狂版 (Fungal Infection: Spore; Unhinged) +spore-mooshroom-boogaloo|孢子:哞菇狂欢 (Spore: Mooshroom Boogaloo) +spore-infestation-expansion|孢子:侵染扩展 (Spore: Infestation Expansion) +entomophobia|昆虫恐惧症* +apotheosis-spore-apoth-boss-compat|神化:孢子 Boss 适配扩展 (Apotheosis Spore (Apoth Boss Compat)) +spore-dimension|孢子维度* +spore-additions|孢子添加* + +zoologicalparkcollection +@fabric-key-binding-api-v1-for-1.14.2 +chisel-unofficial-novus +botania-editor@botaniaeditor +sapling@ +@anvil-musbox|艺演叮砧/铁砧音符盒 (Anvil MusBox) + +@nocc|无指令确认屏幕 (No Command Confirm) +mrt-sign-addon@mtr-sign-addon +chocolate-croissant-beyond-the-horizon-paucbh + +superior-ambience +bamboodecor +angels-of-lovecraft +superior-combat-sounds +when-dungeons-arise-lost-architects +death-generator +kaleidoscope-cookery-satiated-shield-tuner@|饱腹代偿调整器 (Kaleidoscope Cookery: Satiated Shield Tuner) +shirium +simple-sculk-blocks@ +eternal-starlight-delight@ +gardons-tnt-pack +mega-tnt-mod +not-enough-tnt + +quantified-api@quantifiedapi +mekanism-empowered|通用机械:增强 (Mekanism: Empowered) +mekanism-empowered-core|通用机械:增强核心 (Mekanism: Empowered Core) +astral-mekanism|星界机械&能源 (Astral Mekanism & Energistics) +subtitle-highlight-unofficial-reset@|字幕高亮非官方重置版* +wheres-that-structure +tacz-soul|枪械工坊之魂 (TaCZ Soul) +mutant-addition@mutant-addition-mod + +rhenium|铼* +fwa@ +superior-trees-tht-performance-addon + +piggyback@ +@pandacommandwhitelist +melius-commands@|更好的自定义命令 (MeliusCommands) +@serverauth-mod|服务器登陆模组 (ServerAuth Mod) +mini-mob|迷你生物* +@beryl +scavenger-mobs@ +overgeared-spartan-shields + +fermiummixins@ +panorama-mod-recreated@ +ender-storage-energy +ophidiophobia +spice-wood-content@ +ender-io-custom-capacitors@ +@the-right-path +extra-chisels +tabular +baby-dont-herd-me@babydontherdme +railway-depot-worker + +discsbackport +dragon-mounts-legacy-tweaked +history-items|魔戒历史物品 (LOTR History Items) +lotr-race-abilities|魔戒种族能力 (LOTR Race Abilities) +valentias-entropy@ + + +create-food-filling@|机械动力:食物注药 (Create: Food Filling) +@kaleidoscope-painting-extension|森罗酒馆:画拓展 (Kaleidoscope Painting Extension) +aether-addon-beyond-parity@aether-beyond-parity + +lagless +@ryansrenderingkit|渲染 • 龙 (Ryan's Rendering Lib) +holographic-ui-lib +holographic-keybinds +lightspeed-kryo + +@clearitems + +memorycatcher +gtceu-terminals@ +superior-spellcasting +irons-patreon-library@irons-lib +yttrjei@ +strange-trinkets@|奇怪饰品* +adaptive-optimization +@echo-clones +modfixer +elemental-wolf + +draconic-codex-expansion-of-the-ancient-tome-from-quark +interbridge +uprising-project-shinobi +human-encounters +the-witch-hut@ +dragon-survival-iaf-integration@|龙之生存:冰火兼容 (Dragon Survival: IAF Integration) +@linuxssh +better-combat-heavier-weapons + +ageratum@|藿香* +fakedate@ +@aether-bedrock-mobs +@him-forge-1201 +channel@|沉浸语音* +not-enough-bandwidth-legacy@not-enough-bandwidth-legacy(nebl)|网络包优化重制版* +epic-rpg-attribute-core@xp-attribute-core +phantoms|幻翼* +@village_revolution|村庄革新 (Village Revolution) +better-combat-toggle-on-off +parkour-and-more +ash-of-sin-no-more-too-many-structures|罪业余烬:不再过多结构 (Ash Of Sin: No More Too Many Structures) +the-between@ +evolutionary-defense-tower@|进化防御塔* +the-zoomify-mod@zoomify! +origins-neoforge@|起源 (NeoForge) (Origins (NeoForge)) +lovecraft-boyfriends-3 +saddlebag-wolf-bag-pet-backpack-companion-utility@saddlebag +rpg-attribute-system@ +rpg-mob-leveling-system@ +robotica@ +nuvem-voadora-flying-cloud|筋斗云 (Nuvem Voadora (Flying Cloud)) +better-with-gold@ +@mphone +mineconf@|我的配置 (MineConf) +@blazesdl +epic-armor-visibility@ +colortooltips@|灵动提示框 (ColorTooltips) +neoi@ +kaleidoscope-contraption@|森罗物语:动态结构* +musical-foxes@ +dojutsu-slot-ahznbs-naruto-shinobicraft-addon|瞳术槽位 (Dojutsu Slot) +better-arachnophobia +orespawn-boss +immersive-horse-riding@ +camcord-reforged +the-gingerbread-house@ +the-fisherman-house@ +carry-on-back +clone-minerador-clone-miner +zombies-eat-animals@ +the-lost-city@the-lost-city-by-berezka +much-more-dungeons +patchouli-library@ +weather-refined@weatherrefind +@death-rewind|死亡回溯 (Death Rewind) +death-keeper@ +quickshot@ +powerborne-heroes@ +magic-reborn +excessive-utilities@ +kimetsucraft-kc +curiosities-syndicate@ +neurolib@ +mlp-boss +neoorigins@neo-origins +berezka-library@berezkas-library +epic-structures-dungeons@ +@morphica +particull@ +ticktact@ +optileaves@¨@optileaves(fabric) +lost-trinkets-renewed +@quitornot-revived|退出前确认:复生 (QuitOrNot Revived) +@beyondcmd-extension|超越维度:命令扩展 (Beyond:Cmd Extension) +@guioptimizer|UI缓存覆载 (GUI Cache Reuse) +@cnpc-dangerous-script-extension|CNPC:脚本系统扩展 (CNPC: Dangerous Script Extension) +buildcraft-unofficial@|建筑非官方版 (BuildCraft UNOFFICIAL) +carpet-lir-addition|地毯-LIR拓展 (Carpet LIR Addition) +slave-mark|抗争证明 (Mark of Revolution) +@elder-tales|幻境神话 (Elder Tales) +headpats|摸摸头* +golem-magicka@|傀儡装配-奥法魔像* +sword-parry-enchant@parry-enchant +golemera +the-imitator +cyberware-visible-modifications@ +structure-crafter@|构印师匠* +pop-up-emotes@ + +ice-and-fire-dragonsteel +overgeared-ice-and-fire-edition +overgeared-spartan + +loot-sentinel@ +legendary-titles@ +weapon-rarity\@epic-rpg-weapon-rarity +party-hud@ +rpg-class-artifacts@ +average-dps@ +xp-dungeon-blocks@unique-dungeon-blocks +asynclogger|异步日志 (Async Logger) +legacy-image-maps +first-person-body +realistic-rowing@ +@endermannospawniron|末地铁块不生成末影人 (EndermanNoSpawnIron) +star-technology-core +siegeweapons@ +jerotes-villages-pillage@|Jerotes村庄的掠夺 (Jerotes Village's Pillage) +@minegenshin|像素原神 (Minegenshin) +leveling-rank@epic-rpg-leveling-rank +@endless_backrooms|无尽的后室 (Endless Backrooms) +sbw-electronic-countermeasure-force +functional-storage-unofficial-extended-life|功能性存储非官方延续版* +spell-wheel-pages +create-utilities-unofficial-port +froggyincntrlcont@ +where-are-my-translations@ +wear-anything +transformacoes-sun-wukong +atmosfera-neo + +litewers-ai-girlfriend-gf@litewers-ai-girlfriend-(gf) +trackwork-refabricated@|驱动工艺:重织* +@victus-neoforge-unofficial|Victus非官方1.21.1Neoforge版本 +the-last-sword-you-will-ever-need-remastered@|最终之剑:重制版 (The Last Sword You Will Ever Need: Remastered) +advanced-combat-re@|高级战斗:重制 (Advanced Combat: Re) +realisticdining@|更真实的用餐 (Realistic Dining) +a-better-foods@|更多的食物* +ban-hunger-value@|禁用饥饿值* +delta-delight@|三角洲乐事 (Delta's Delight) +more-rarities@|更多稀有度* +time-in-a-bottle-fix-tiab-fix@ + +item-glint@|手持物品描边* +@mc-273265_fix +sbw-colorized@sbw-colorized! +fading-time +@customnpcs-sortplus +@customnpcs-crafting-view +survival-monitor@ + +wmd +@more-xp-more-hp +the-age-of-engender +yumemigusa@ +mineberkcraft +armor-poser@ +treeliable@ + + +better-caravans@ +dragonminez@ + +avaritia-armor-upgrade|无尽防御升级* +no-lapis-lazuli@|无青金石* +stronger-structures +warning@ +create-bbq-belt|机械动力:传送带烧烤 (Create: BBQ Belt) +shogi +mna-arcane-adornment|奥术饰品 (MnA: Arcane Adornment) +@in-game-log-display|游戏内日志显示 (In-game Log Display) +kindred-legacy¨pokemonmd-disciples-of-corruption +@elytra-jump|鞘翅跳 (ElytraJump) +dynamic-trees-universal-compat +@tellus +malice-and-mischief +insight-ui@ +project-mmo-xp-bottles@ +swing-through-grass@ +apothic-extensions +simply-tents@ +floral-tonics-tinctures@floral-tonics-and-tinctures +epca-ride-addon@|终末-归寄万物骑乘附加 (E-PCA Ride Addon) +mekanism-pipez-fix@ +@burvys-zombies +goety-fabric@|诡厄巫法Fabric版 (Goety-Fabric) +jvs-pillage@|J村的掠夺 (JV's Pillage) + +xp-farming@ +simply-bows@ +synesthesia +create-solar-powered@ + +dc-render-api@|龙咒异闻录渲染API (DC Render API) +dragon-curse-chronicles@|龙咒异闻录* +koifees-mobs +@vanilla-constructs +ice-and-fire-curios-and-trinkets@ + +jei-swift-copy|JEI迅速复制 (JEI Swift Copy) +create-rns@ +create-shape-craft@|机械动力:图形工艺 (Create: Shape Craft) +@notenoughbandwidthfabric|网络包优化Fabric版 (Not Enough Bandwidth Fabric) +@glass-armor|玻璃盔甲 (Glass Armor) +dmzkiattacks@ +sorttochests +petrescue +simply-tents-blacklist@|简易帐篷:黑名单* +leashall@ +auto-swap@autoswap +@reset-villager-trades +cbc-enchanced-shells-create-big-cannons|机械动力火炮:增强型弹药 (CBC Enchanced Shells) +xnet-additions + +zcraft-stalker-pda +shellbound-for-airship@ +integrated-seven-seas@ +integrated-dungeons-arise +damagesource-is-not-null@ +caps-awim-tactical-gear +caps-awim-s-tactical-equipment@caps_awim%60s-tactical-equipment-1.20.1-1.16.5 +drone-fpv@fpv-drone|FPV无人机 (Drone FPV) +gabous-libs@ + +sitoneverything@ +epic-tnt-mod@ +the-body-boosts@ +f-tech-equipment#project-logo@f-tech-equipment|未来科技:装备 (F-Tech: Equipment) +jujutsu-kaisen-ultimate-zenith + +terramity-paisleys-summoning@paisleys-summoning +kaleidoscope-dimensions-wine@kaleidoscopedimensions-wine|森罗物语:次元酒窖* +betterlan@ +flys-config-lib@ +better-than-wolves-modern-port|比狼好 [现代化移植] (Better Than Wolves [MODERN PORT]) +microdurability-maintained@ +windy-forge-port +recycling-arrows +back-tools-modern +dark-fantasy-nordic-tombs@ +bee-gui@ +envelope@ +@windy +iron-furnaces-fabric-neoforge|更多熔炉(Fabric & NeoForge) (Iron Furnaces (Fabric & NeoForge)) +iron-shulkers|更多潜影盒(Fabric & NeoForge) (Iron Shulkers (Fabric & NeoForge)) +iron-chests-fabric-edition|更多箱子(Fabric 版) (Iron Chests (Fabric Edition)) +@piggy-lib +dungeons-and-villages-deeper-and-darker@ +spring-to-life-backport@ +tricky-trials-backport@ +dark-fantasy-church-of-sin-vanilla@ +ipv2 +tidal-observation-card@|潮汐观测卡* +watermelon-power@watermelon_power|西瓜发电* +@pumpkineve|南瓜前夜 (Pumpkin Eve) + + + +bblib@bluebirdlib +drop-container-contents|一键搬空* +@exploitpreventer +hats-classic +sal-fishs-enchantments|sal_fish的附魔 (sal_fish's enchantments) +sal-fishs-hud|sal_fish的hud (sal_fish's hud) +broadcast-radio@|电波通讯* + + +roaring@ +symformers@ + +mrfegs-image-frame@ +tsuki|月* +@bookfiller +@files-njs +malstone@|灵灾附属:异域* +jei-want-that +dragonmine-z-super@ + +unified-combat +artificers-armory@ +sweets-delight +tweaks-delight@ + +simple-snowy-fix-forge-fabric@simple-snowy-fix-(forge-fabric) + +enchanting-plus-classic +universal-portals +oculus-for-simpleclouds + +@yunbeiuc|云北城建 (Yunbei Urban Construction) +log-deduplicator + +project-atmosphere@ +@happy-ghast-shoot +naming-unconvention +apotheosis-localized|神化本地化* +kotlinlangforge@kotlin-lang-forge + +ntm-space-plus +enchantment-library-compat|以音定著* +tacz-magazines +the-beyond +glowtools@ +enchantment-level-cap-indicator@ +morematerials-reborn@|更多材料:重生 (MoreMaterials Reborn) +ranking-list +earth-and-water@ +botany-pots-fps-fix +nikos-backported-lush-cave +mob-dismemberment-fabric-neoforge|怪物肢解(Fabric & NeoForge) (Mob Dismemberment (Fabric & NeoForge)) +@the-morbid-reengaged +item-scrapper +random-tnt-adds-4-useless-tnt-blocks + +au-naturel-da-fishing-mod +crafter-hologram +village-utilities +some-illager-servants +cataclysm-fallingtree-compat + +fip-vips-aimoptimizer +minepersist@ +indestructible-enchantment|附魔:无法破坏* + +ponder-legacy@ponderlegacy|思索:遗产* +@cursor-backport|光标样式回植 (Cursor Backport) +recurrent-complex-volts +beyond-oxygen@ + +tinkers-reposession +infinite-storage-bundle +jei-worldgen +@auto-attack-port|自动攻击移植版 (Auto Attack Port) + +better-mob-combat-fix@ +spelled@|语言魔法* +krypton-hybrid + + +@misias-manametalmod-extension|米西娅的魔法金属扩展 (Misia's ManaMetalMod Extension) +hunger-begone@|饱腹远行* +the-boreal@ +kerria +cc-complementary-core@ +cs-towers +vista-all-the-cassettes@ +the-silver-age@ +industrial-foregoing-more-upgrade-plugins@industrial-foregoingmore-upgrade-plugins|工业先锋:更多升级插件 (Industrial Foregoing: More Upgrade Plugins) +biome-golems@ +kittycat@ +@forcegl4.0 +kpk +createmek-steam|通用机动:蒸汽机 (CreateMek Steam) +tacz-magic-bullet +immersivethunder-legacy +megablocked-unofficial-remake@ +ouro-tweaker@ +no-fishing-delays|没有钓鱼等待* +item-scrapper-pack-tacz +@real-nicknames +@raccoons-rabies +infernaddon +@airstrikepointers|空袭指示器 (AirstrikePointers) +gatewaysjs +witheria +simply-airdrops +malum-arma +@the-error-(horror) +item-scrapper-pack-armor-tools +@carpetgui|地毯GUI (CarpetGUI) + +@collections-field + + +end-remastered-promax@|末地创世增强 (End Remastered ProMax) +@vs-safe-and-sound +jerotes-village-golems@|Jerotes村庄-傀儡装配* + +item-scrapper-pack-vpb + +@splashcycle + +citadel-neoforge +alexs-mobs-neoforge|Alex 的生物(NeoForge) (Alex's Mobs (NeoForge)) +immersive-aircraft-x-immersive-engineering|沉浸式飞机x沉浸工程 (Immersive Aircraft x Immersive Engineering) + + + +yaml-config@ +bosscraft-respawn-unofficial-port@bosscraft-unofficial-port +infinitylib-lighting-patch +auratip@|浮冰UI (Aura Tip) +chunk-animator-fabric-neoforge|区块加载动画(Fabric & NeoForge) (Chunk Animator (Fabric & NeoForge)) + + +shincolle-reforge + + +@italians-delight-remade +modern-industrialization-parallel-hatch|现代工业化并行仓扩展* +modernindustrialization-multi-slot-fluid-hatch@mimsf|现代工业化多槽流体仓 (Modern Industrialization Multi-Slot Fluid Hatch) +infinite-items-ie +yet-another-bingo-team-chest@yab-teamchest|Yet Another Bingo 队伍箱 (Yet Another Bingo - Team Chest) + +lava-vision-enchantment|附魔:熔岩明视* +modern-mob-spawn +irons-spellbooks-ambidexterity|允用对杖 (Ambidexterity) +tough-as-nails-legacy|意志坚定:传承 (Tough As Nails: Legacy) + + +magic-of-color@ +tunes-n-tomes-a-bards-journey +originium-materials|源石:材料* +researchd@ +tacz-leaning +tacz-dolphin-dive +create-repair@ +create-just-enough-time|机械动力:预见时间 (Create: Just Enough Time) +@appliedcannon|应用加农炮 (AppliedCannon) + +nvl-storage-blocks +nvl-blocks +the-sun-town +moremousetweaks@ +flys-adrenaline@ +enchanting-infuser-backport +totem-morph +elemental-witches-unofficial-remake@elemental-witches-reborn +item-scrapper-pack-marbleds-arsenal +medical-remedies +alien-cat + +item-scrapper-pack-tacz-zc +modernindustrialization-parallel-control-hatch@mi-parallel-hatch|现代工业化并行控制仓 (Modern Industrialization Parallel Control Hatch) +simple-build-colony +@bundled_ +mekanism-config-card-upgrades|通用机械配置卡增强* +stealth-and-alert@|潜行与警戒 (Stealth and Alert) +iv-mts-q-m-p-qawsed-military-pack@ivmts-q.m.p-qawsed-military-pack|喀斯德军事附属包 (Qawsed Military Pack) +@enchant-enhancemen|附魔增强 (Enchant Enhancemen) +@cookie-keybind-helper + +@obfuscate-lib-compatible-fix|Obfuscate 兼容修复 (Obfuscate Lib Compatible Fix) +visual-villager-trade-addition|可视化村民交易添加* + +@create-drill-backport +rss-automessage@|RS的自动发送信息 (RS's AutoMessage) +unbreakables@ +enhanced-explosives@ +epic-fight-limbus-company-moveset + +@arsenal + +aaas-strongermobs|更强的怪物 (AAA's StrongerMobs) +@legacy-of-utopia +packcompanion +portalmod@ +theworldbelow@alpha-below + + +mc-matrix-bridge@ +@world-importer +weaponsexpanded@ + +item-icon-exporter@|物品图标导出器* +@right-click-chest-boat +rechests@ +@ratatouille +ttle-iron-sword|小铁剑* +combatflex|战斗韧性 (CombatFlex) +experience-remover@ +dream-relics@|旧梦遗物* + + +thermodynamica@ +sable@ +fox-trot-brew@|狐步酿香* +farmers-delight-legacy|农家乐 (Farmer's Delight Legacy) +@syals-delight|事乐乐事 (Syal's delight) +create-unclamped@ +cta@|机械动力:坦克扩展 (Create: Tank Additions) +create-aeronautics@|机械动力:航空学 (Create: Aeronautics) +tips-enhancement +siege-of-settlements@ +ninshu-origins@ninshu-origins-naruto-mod +dayspot +aerlune-adventures +ancient-elements-better-combat-fix +artifex +epic-structures-igloo@ +grim-kingdoms-lost-structures-ruins-vanilla|Grim Kingdoms: Vanilla Edition - 仅¨@grim-kingdoms-lost-structures-ruins-vanilla-edition|Grim Kingdoms: Vanilla Edition - 数据包 +end-villager-outpost@|末地村民前哨站* +japanese-residence +jungle-treehouse-village@|丛林树屋村庄* +illager-arena@ +beginner-survival-house@ +skeleton-ghost-ship@ +animal-barn +hobbit-house +desert-survival-house@ +villager-saloon +giant-lily-pads@|巨型睡莲* +villager-clock-tower@ +old-fisherman-swamp-house@ +giant-snowy-tree@ +giant-red-mushroom@|巨型红色蘑菇* +giant-palm-tree@|巨型棕榈树* +giant-cactus@|巨型仙人掌* +giant-brown-mushroom@|巨型棕色蘑菇* +big-birch-tree@|大型白桦树* +giant-pine-tree@|巨型松树* +giant-natural-additions@ +giant-yellow-tree@ +giant-jungle-tree@|巨型丛林树* +forest-survival-treehouse@|森林生存树屋* +giant-oak-tree@|巨型橡树* +villager-gold-washing-facility@ +bamboo-jungle-survival-house@ +villager-frog-house@ +cherry-grove-starter-house@ + +big-gift-snowglobe@swamp-boat +snowman-house@ +giant-christmas-tree@|巨型圣诞树* +orc-hut@ +villager-mushroom-house@ +greek-villager-house|希腊村民房屋* +turtle-house|海龟房屋* +gingerbread-house|姜饼屋* +villager-observatory@ +desert-village-temple|沙漠村庄神殿* +arcane-armaments +villager-train-station@|村民火车站* +villager-country-house@ +desert-watchtower|沙漠瞭望塔* +villager-brewery@|村民酿造厂* +illager-viking-longship +georges-flying-island@ +villager-tannery-house@ +ancient-enchantment-temple@ +small-mob-arena +villager-warship@ +villager-flower-house@ +villager-fish-shop@ +giant-torii@|巨型鸟居* +small-viking-villager-house@|小型维京村民房屋* +villager-forge@ +llama-stable@ +villager-butcher-house@ +villager-fishermans-hut@ +villager-cleric-house@ +villager-fletcher-house@ +villager-cartographer-house@ +villager-farmer-house@ +villager-circus-tent@|村民马戏团帐篷* +big-horse-stable@|大型马厩* +small-biome-towers@ +taiga-survival-house@ +desert-pillager-wall@ +modern-villager-house@|现代村民房屋* +mushroom-survival-house@ +small-wagons|小型马车* +piglin-quartz-tower@|猪灵石英塔* +fine-art-paintings@ +new-ambient-music@ +rojiura-backport-decoration +qpack +edenring-forge +loot-bag-mod-renewed +stackupup|叠叠乐 (StackUpUp) +drop-down-keybindings@|下拉式按键绑定 (Drop-Down Keybindings) +ecliptic-seasons-fabricated|节气:重织 (Ecliptic Seasons : Fabricated) +from-the-caves-april-1st-incident +dojutsu-addon-ahznbs-naruto-shinobicraft-addon|瞳术拓展 (Dojutsu Addon) +nomorebook|帕秋莉:不要这么多书 (NoMoreBook) +sieging-of-the-illagers + +@scalable-tooltips +future-villager-trades-visible +autodisconnect|自动断连 (AutoDisconnect) +dyson-cube-project-refitted@ +blocklings-nostalgia-edition|方块酱:怀旧版 (Blocklings: Nostalgia Edition) + +slashblade-amazingshining|荧光惊异 (SlashBlade:AmazingShining) +the-god-fox|御神狐之刃 (The God Fox Reborn) +godbirdreborn|毕方重生 (GodBirdReborn) +balmungreborn|巴鲁蒙格重生 (BalmungReborn) +pseudo-edge-dawnbreaker|伪格雷普终境之刃·终境破晓 (Pseudo-Edge: Dawnbreaker) +slashblade-thebladechronicles|刀绘卷 (SlashBlade: Egotachi) +slashblade-colseweaponinsystem|近距长兵·重解 (SlashBlade: ColseWeaponInSystem) +sumer-mega-renderer +class-selection-mod + + +better-combat-nbt-fix@ +@magitech_mod +gadomancy-unofficial|魔像秘经非官方版* +@bosscraft-respawn-overlord + +mekanism-card|通用机械:实用卡* +create-aeronauticstoolgun|机械动力航空学:工具枪 (Create Aeronautics: Toolgun)¨@create-aeronautics-toolgun|机械动力航空学:工具枪 (Create Aeronautics: Toolgun) - 正在审核 +clutterbestiary@ + +custom-murder-mystery@|自定义谁是杀手* +autotranslator-cn@autotranslator|自动翻译 (autotranslator) +what-i-wanna-show-u@ +madness-mod@madness_entities +not-so-shrimple-remolted +@peony-from-field-to-table + +capsule-modify +candle-blaze +aquarius-libs@ +xbrgb-dyecraft@f6YrFYJU|全彩工艺 (XBRGB-DyeCraft) +@ia_engines +tinkers-gadgets@ +create-twistermill@ +elytra-drag-new +deepslate-dubble@deepslatedubble +tinkers-tactical-toughness|工匠御械/御严抵阵* +datafly-lib@ +kaleidoscope-twilight@|森罗物语:暮色* +oculus-unofficial +matter-overdrive-refitted +nutrition-unofficial-extended-life-continued +drop-multiplier|多倍掉落* +additional-enchantments@ +wits-backport +fights-frights +brazilian-expansion@ +similar-prehistory@ +animal-garden-snow-leopard@ +always-shield@ +simply-tooltips@ +@from-the-woods +functional-storage-downgrade-fix@ +transform-or-morph-into-any-mobs +@litematica-container-filler|投影容器填充机 (Litematica Container Filler) +bibliocraft-reshelved +macaws-functional-furniture +lotr-bane-viewer|魔戒克星信息查看器 (LOTR Bane Viewer) +imaginary-branch|虚数分支[二游ACT] (Imaginary Branch[Character Transformation]) +fpe-companions + +picture-mode@ + +visual-health@visualhealth +@first-step-mod|初见 (First Steps) +@betterponder|更好的Ponder (BetterPonder) +foodtastic-crops-and-trees +circulation-flow-networks|环流网络* +castle-shift@ + +vertical-slab-block|竖半砖 (Vertical Slab) + +modernindustrialization-item-fluid-combined-hatch@mi-item-fluid-combined-hatch|现代工业化物品流体总成仓 (Modern Industrialization Item-Fluid Combined Hatch) +quickstack-backpacks-compat + +ansible-crafting@ +anti-oneshot +@c4-pro +ender-modpack-tweaks@ +eternal-core-starter@eternal_core_starter|永恒核心:启程 (Eternal Core: Starter) +functionality-forge@functionality +lily-pads-expansion +zcoper-karts +@taccorps-trinkets +soulbound-sigils|灵魂印记* +doomsday-functionality +tiny-mob-farm-boss-addon@ +simple-structure-mushroom-fields@simplestructure-mushroom-fields +cursed-fate@ +kashimo-mythical-beast-amber-cursed-fate-addon@kashimo-(mythical-beast-amber)-cursed-fate-addon +cursed-fate-projection-sorcery@ +cursed-speech-cursed-fate-addon@cursed-speech-cursed-fate-addon. +cursed-fate-multiverse@ +cf-ratio-technique@ + +box-of-structures-goety +blades-dungeons@ + +gaucho +waystones-sable@ +xiaoxiang-cultivation-world@|小翔的修仙世界 (Xiaoxiang Cultivatio) + + +iss-affiliated-distant-shock-barrier@iss-affiliateddistant-shock-barrier|远距冲击屏障 (Distant Shock Barrier) +goetyfocus@gyfc|诡厄巫法:聚晶核心 (GoetyFocus) + +swem-lite +swdm +rumors +animation-api-reborn +attributification@ +swgc@ +chunk-animator-embeddium-compat +tag-fixes@ + +suns-son-mod +disable-villages-generation|禁用村庄生成* +locks-reforged@ +tidyinv +tetra-data-kubejs +@letemburn|让它们燃烧! (Create: LET!EM!BURN!) +kaleidoscope-tavern-refabricated@|森罗物语酒馆:重织* +kaleidoscope-bloodwine@kaleidoscope_bloodwine|森罗酒馆:血酒 (kaleidoscope:bloodwine) + +iss-tms-this-is-a-magic-staff@this-is-a-magic-staff|万法皆杖 (This is a Magic Staff) +ai-myhs-plants-vs-zombies@ai_myhs-plants-vs.-zombies|Ai_myh的植物大战僵尸 (Ai_myh's Plants Vs. Zombies Mod) +cursedfate-npcs +moderngamingworlds-nether-portal-restrictor@nether-portal-restrictor|下界传送门限制器 (Nether Portal Restrictor) +kubejs-kaleidoscope@ +happyghast-extend|乐魂拓展 (HappyGhast Extend) +planar-artifice-forked-continuation +@tacz-presence +@diexvapocalypse + + + +mousetweaks-x-accessories-fix@ +malice-and-light-cursed-fate-addon-dabura +cursed-fate-divine-general-mahoraga +create-crafts-additions-and-aeronautics-compat@ +cave-dweller-fabric-port +@152mmboom +wild-caves-4|洞穴装饰 4* +derpy-squid-mod +universal-smithing-template|通用升级模版* +concatenated-compat +@xaeros-playerposition|Xaero玩家位置显示 (Xaero's Player Position) +feywild-library +grand-depths@grand_depths + +@next-boundary-cornerstone|下一个边境-基石 (NextBoundary-Cornerstone) +the-trial-monolith +blades-libraries@ +carved-wood@ + +cawezs-mantle-to-stratus@ +attacker +super-source-block|超级源方块* +eternitys@ +more-fun-tnts@ + + +pipez-lag-fix +butchery-alexs-mobs@butchery-alexs-mobs-addon +bllues-weapons +giant-ice-spike@|巨型冰刺* +giant-bamboo@|巨型竹子* +quick-boot +zfastnoise@ +collision-damage-port +disaster-plants-cursed-fate-addon@disaster-plants-cursed-fate-addon. +mrcrayfishs-furniture-mod-tools-refurbished@ +hats-x-mo-bends-compat +@dimensional-inventories +curios-eggs@ +taczeo@ +blades-temples@ +middle-age-castles +lost-cities-modern-tweaks@ +expanded-ecosphere@ +thunderbolt-lib|闪枢库 (Thunderbolt_lib) +crucifix-unbanished +country-road-creature +ftb-quests-entity-visualization +uncapped-spectator-speed +creatures-and-beasts-the-unofficial-port +antlers-of-hunger@ +neofavoriteitems@|Neo物品收藏 (Neo Favorite Items) +quickalias@|快捷别名 (QuickAlias) +botania-dimension-blacklist@ +kaleidoscope-fruit-brew|森罗物语:果酒 +tinkers-unexplored@ +aesthetic-frames@ +aesthetic-edges@ +aesthetic-ladders@ +aesthetic-seating@ +invincible-craft +aesthetic-tables@ +aesthetic-storage@ +aesthetic-surfaces@ +aesthetic-stairs@ +the-lost-records +cherry-tree-pond +jaki-versatile-structures@ +recipeexport@ +@natural-sponge|天然海绵 (Natural Sponge) +mob-amputation-unofficial-modern-port|怪物截肢 [非官方现代化移植] (Mob Amputation [UNOFFICIAL MODERN PORT]) +boomspeakers + +ars-magica-2-rekindled|魔法艺术2:复刻版 (Ars Magica 2: Rekindled) +winds-spellbooks-irons-spells-n-spellbooks-addon@winds-spellbooks +hexxyskies@ +manaita-plus-general|更好的砧板经典版* +structure-generation-improver-sgi-foundations@structure-generation-improver-(sgi-foundations!) +primal-frontier@ + + +create-tweaked-controller-for-fabric +mod-primal@ +batch-edit-and-save-and-upload-ae2-pattern-content@batch-edit-and-save-and-upload-ae2-pattern-content-with-local...|批量编辑,保存到本地,模拟玩家编写AE2样板 (batch edit and save and upload AE2 pattern content with local files) + +stack-calculator@ +nbtech2fix@|超级牛逼的科技整合包2 一些修复 (nbtech2fix) +better-safe-bed-backport +@sterile-egg|无菌蛋 (Sterile Egg) + +okprogressions +ae2enhanced +townstead +mebahels-api@ +moreupgradetemplate-abovethesky@mut-ats|更多锻造模板:凌空之上 (MoreUpgradeTemplate-AboveTheSky) + + +ae2-lightning-tech@|AE2 闪电科技 (AE2 Lightning Tech) +@epicfight_touhoulittlemaid|史诗战斗:车万女仆 (EpicFight:TouhouLittleMaid) +put-a-plug-in-it@put-a-plug-in-it! +elemental-witches-legacy +starfield-pastoral|星野牧歌 (StarfieldPastoral) + +create-radars-unofficial-port@|机械动力:雷达重制版 (Create: Radars Unofficial Port) +create-propulsion-simulated@|机械动力:推进工程 - 模拟物理 (Create Propulsion: Simulated) + +create-additions-sable-compat@ +create-stressbound@|机械动力:应力链界 (Create: Stressbound) +create-tracks +create-propulsion-sable@ +create-towed@ +create-dreams-n-desires-updated-to-create-6 +create-more-catalysts@createmore-catalysts|机械动力:更多触媒 (Create:More Catalysts) +create-more-alloys +create-pipesn-physics@create-pipes-n-phisycs +dabr-dragonsurvivalcompat + +block-display@ +modern-damage-control@|现代伤害控制* +mutehotkey-fabric|静音快捷键 (MuteHotkey) +@easymute|简易静音 (EasyMute) +ramization +antique-beasts@mebahels-antique-beasts +mebahels-zombie-horde@ +mekanism-advanced-configuration-card|通用机械高级配置卡* +@my-battle-mod +botania-flower-adjust|植物魔法花生成调整* +placeable-gunpowder-1-12 +anvilcore@anvilcore- +formicapi@ +jcs-dungeons-musics +dragon-radars +fast-recipes +no-auto-jump|禁止自动跳跃* +satstack +@custom-end-portals +hlelevators@ +@moremobility +berk-furniture@ +woodyoudeco +touhou-little-maid-vampirism|车万女仆:血族 (touhou_little_maid_vampirism) +hats-renewed +shared-pets@ +err422@ +kubejsable@ +geckolibbetterfps +svdialog@ +botania-seeds@ +shadow-config@ +@nuke-block|核弹 (Nuke block) +projecte-infinite|等价交换无限 (ProjectE Infinite) +modernindustrialization-structure-exporter@mi-structure-exporter|现代工业化结构导出工具 +chrono-dawn@ +too-much-entities|太多的实体* +zero-ordinary-vehicles +false-swipe + +ds-caperspectivefix +create-aeronautics-compatability@ +create-aeroworks@ +@flyhigher|直上九霄 (FlyHigher) +drive-by-wire-with-sable@drive-by-wire-sable +create-nomad@ +medieval-healing|中世纪治疗* +quark-backpack-plus@|夸克背包增强* +farmers-delight-compatibility-fix|农夫乐事兼容修复 (Farmer's Delight Compatibility Fix) + +webdisplay-fork-for-shimer +thaumic-duality-interface@|ME源质二合一接口* +visual-loot-edit|可视化战利品池编辑器* + +mixin-extras-neoforge-on-forge-fix +fancy-frames@ + +@any-random-drops|随机掉落 (Any Random-drop) + +warp-o-mania +shrunkgateway|微缩天辉星门* +chocolate-quest-golden-apple-edition +better-snowball@ +society-trading@ +wiki-zoomer-unofficial +dream-cocoon@|睡梦包裹* +powercraft-new-live + + +kira-death-note@ +@planket +moregolems@ +maples-chicken-collection@ +maples-creeper-collection@ +maples-bee-collection@ +splendid-slimes@ + + + + + + + + +plain-grinder@ +maples-rabbit-collection@ +maples-frog-collection@ + + +deuf-neoforge@ +dynamic-lightings@dynamic-lighting +ancient-villages@ +twilight-forest-final-boss-remake +cosmetics-equipment@ +ore-vein-miner +illager-structures + + + + +prehistoric-seacreatures@ + + + +touhou-little-maid-growableores-compat@touhou-little-maidgrowableores-compat|车万女仆:GrowableOres 兼容 (Touhou Little Maid: GrowableOres Compat) +natura-call-of-nature +animalsplusplus +better-indicators|更好的指示器* +@rail-lubricant +@mushroom-madness +@undo|撤回 (Undo mod) + +gonebutnotforgotten-jar@gonebutnotforgotten +abyssal-corrupter|深渊侵蚀者* +project-poppa +visual-mobs-edit|可视化生物编辑器* +@sabelfanconfig|航空学-额外配置 (SableFanConfig) +jackie-chan-adventures-talisman-legend|符咒传说 (Jackie Chan Adventures: Talisman Legend) + + +@sleepy-disconnect +attribute-setter@attributesetter +@netmusiccd-preview|网络音乐机:唱片预览 (NetMusic: CD Preview) +redstonelink-makomi@|红石远联 (RedstoneLink-makomi) + + +terrano +visualcontrol +mebahels-creatures-dwarven-automatons@ +lootbags-plus@ +skniros-furniture@ +abandoned-watchtowers@ +a-squidly-minecraft-movie-mod +galosphere-trimming@ +abandoned-urban-remaster@ +hollowmarch@ +rock-candy +refined-storage-mixin@ +tensura-compat-ice-fire@ +@random-world-names|随机世界名称 (Random World Names) + + +alexs-caves-spellbooks +deeper-and-darker-spellbooks@ +long-horse +olvens-deep-end +@sculktech +patchouli-cryogenic-simulation-edition + +ender-core-ceu +enderio-ceu +beyond-bosses-2 +tpa-qmz@tpa_qmz +boss-checklist-addon +paintable@ +diversity-of-life +smooth-menus|平滑菜单* +iron-jetpacks-updated-fabric +harsh-encounters@ +tws-ore-dredging@ore-dredging|TW的矿石淘采 (TW`s Ore Dredging) +@elixir_dan|丹 (Elixir) +per-world-game-rules@|游戏规则分身 (Per-Dimension Game Rules) +structures-better-structures-exploration +structures-modd +sturdy-farmland-growth-edition@ +smart-particles@ + +@wills-farming-tweaks + +charged-creeper-render-fix|闪电苦力怕渲染修复* +nohurtflash@ +advanced-wall-climber-api@ +modern-blocks-port +particle-tweaks@ +artifacts-merging@ +echoes-of-the-end-structures@echoes-of-the-end-(-structures) +delight-lib@ +thaumicapi + +@big-cry|哇哇大哭 (Big Cry) +clab +shincolle-shin +azumanga-mod@ +decofood +dragons-reborn +the-great-outdoors +riichi-mahjong-forge +particle-interactions-reforged +inmis-forge-port +luminous-monsters@ +luminous-tag@ +even-more-magic@ +piglet-structures@ +undertale-world@|传说之下 世界* +kubejs-mekanism-extends@ +unconfusion@|解惑* + + + +mapleful +universal-cutting-recipe@|通用切制配方* + +jeasync +mi-item-hatch-stack-upgrade@|现代工业化物品堆叠升级 (Modern Industrialization Item Hatch Stack Upgrade) +sandrone-toy-mod@ +cute-ships|萌系船只* + + +dannys-aot +simpletppro@|简单的传送 (SimpletpPro) +invincible-wobble-edit-mod +@ygogacha|游戏王抽卡 (YGOGacha) + +servantry|仆从学* +recursivecraft|递归合成 (RecursiveCraft) + +aeronautic-additions-and-chunkloader +transducers|能源转换器* + + +ftbuxaerocompat +odd-accessories@|古怪饰品* +diet-appleseed-edition@|饮食均衡-苹果籽版 (Diet - AppleSeed Edition) + +no-enderman-grief-mod +anatidaephobia +hazentouvelib +flux-overdrive|通量超驱* +capns-chisel-search + +an-extra-touch@ +slashblade-resharped-yamazakura|拔刀剑重锋 · 山樱之刃 (SlashBlade Resharped: Yamazakura) +thirstwastaken-unofficialfabric@|口渴-非官方 Fabric 版 (ThirstWasTaken-UnofficialFabric) +touhou-little-maid-for-ae2|车万女仆:AE附属 (Touhou Little Maid for AE2) +command-block-golem-recast +brntalk@ + +retro-draconic +nuts-and-fruit +@polymer-patch-for-gensokyo-reverie-of-lost-dreams|梦隐的幻想乡:Polymer 兼容性补丁 (Polymer Patch For Gensokyo: Reverie of Lost Dreams) +nature-horizons@|自然地平线* +@openboatutils +minecraft-story-mode-mod|故事模式模组* +mod-required@|模组依赖导出* + +photon-and-epicfight-mod + +no-see-no-tick@ +gregtechmodern-food-option +tag-stacker@ +recursive-ae2-pattern-provider@recursiveae2patternprovider +potato-bread|马铃薯面包* + +create-skies-on-fire@|机械动力:燃烧的天空 (Create: Skies on Fire) +create-right-hand@ +@create-configured +unified-api@ +isometric-renders-forked@ +@lotrinfo|魔戒信息显示 (LOTR Info) +compactmachinespor@|压缩空间:产量推演 重制版 (CompactMachinesPOR) +enhanced-celestials-tweaks +@golemscript +grindstone-sharpener@|磨刀石* +dynamiducts +more-creeps-and-weirdos-revival@more-creeps-revival +rolling-giant-oldest-view +nvl-simple-blocks + + +beyond-the-skybox@beyond_the_skybox +frostbytes-maximum-mobility@ +armor-stand-arms-mod +less-simple-void-world +metallum-metal-backend@metallum-mc +just-hammers-backport@ +additional-hammers +nvls-teleport-blocks +touhou-little-maid-vanilla-companion@|车万女仆:香草伙伴 (Touhou Little Maid - Vanilla Companion) +immersive-favella +@sable-destructive + +epca-drive|寄械传动 (E-PCA Drive Addon) +future-small-decorations|未来小装饰* +the-wings-of-fire@wings-of-fire! + +goetic-legacy|诡厄遗物* + +an-adaptive-nemesis@anadaptive-nemesis|自适应宿敌 (Adaptive Nemesis) +gourmet-boost@|食补* +gastro-crisis + +auto-sable-physics¨@auto-sable-physics|Auto Sable Physics - 正在审核 +nsprefab|建造蓝图 (NSPrefab) +@celestial-vela +rupters-random-mobs +aerodynamics4mc@ +elysium-jar +walkie-talkie-plus +luos-structures-of-goety +atoms-blueprint-lib +large-spruce-starter-house +the-titans-old-dream-unofficial|泰坦旧梦 (The Titans: Old Dream (Unofficial)) + +@join-autosprint-mod +etbw2-shadow-fog-effect +|23517|22955|23445|23483|23404|||23463||23058|21626|21915|21471|21414|||20600|23301|23327|22998|21872|23314|22095||23246|23391||||23097|1||18541|21067||||||23308||||23364|23382|21808|23081||22391|||||20729||||||23514||22319|22721|22606|18916|||||22592||23322||18589|22487||||22035|||||23270||23070|||||21276|22832|23447|16695||21998||20427|23295|||18397||20991|22678||23477|||21168|21330|23121|23072|21454||23419|17687|||18100||17867|21924|||||18323|||22444|15374|15100|18550|13979|15310|22065||21952|15799|14643|22824||22887|||22984|21862|21940||||19002|16942||||22273|||||22651||22663|22718|16611||22912|22656|||23040|||17538|15149|17340|17998|23497||7895||22696|17137|23513|||21209|21383|22286||23462||||23430||11271|22662|22420|23217||18698|22804|19515||23432|21190|23459|23399||||18736|21109|23482||15074||23349|||||20143|21614|21360|||22963|23268|20680|22302|21537|22066|22776|||22666|||||23296|20722|22147||23360|22375|19132|20946|22607|23052|22630|22919||20236|23506|19908|22803|23433|21020|||22308||16686|23332||21550|19898|18543||16282||22584|||23384|18805||22623||19705||15779||22211||23381||23383|23146|22852|22185|23141|19906|22559|||14541||||||20296|||21890|14936||18271||22359|19895|17527|||5||21657|23348|22976|23504||23198|20102|22888|23516|20537|22680|||||20800|22616||21077|15392|||21916|23227|20908||22839|23180|23287|23510|21933||||||20647|23215|22649|23140|22270|22619||21260|||18727|19327|16213|19424||18352||19478|22062|20723|23113|22366||||22970||23408|23446|23147|16299||22124|18048|19516|18226|18151|23284|14014||18341||23302||22350||||23310|22155|||23213||20460|21807|23205|23054|22043|21699|21354|21051||23496|23172|23428|||20763|22703|23292|19764|22809|20544|22917|22504|22222|15049||21345|22841|20213|21908|23243|19951|22135|21182|22981|22395|23024|20390|20835||23036|||21810|19480|22044|23489|20976|23148|23324|23500|23123|22104|16114|22474|23238||23181|22938|6|23265|21841|23225|22855||22358|21708|7|18908|23187|20287||21959|23203|20848|22238|22594|21833|21099|||22479||20997|23495|17534|23479|22072|||20010|20557|23493||21373|23478|23130|22426|23102|23275|23507|23218|20489|21005|22879|22086|20691|22096|23151|22144|21960|23424|23254|22987|23488||23453|23167|23281|21319|23105|21790|22440|20715|23417|22793|22837|22292|21344|20429|19032|21508|23166||23392||22380|23427|23357|22639||18036|9|17059|23086|23451|21265|23311|21827|23183|22438|10|19624|22012|21568|20635|22240|20595|22702||||||||||||23328||21756|14744|23389|18614|23437||19546||23422|23407|23473|22219|20765|22198|21760|23042|21125|19554|21509|22815|22109|20089|20811|21282|23282|||21758|22461||19026|11|20799|23233|23263|19460|22497||20539|22255|20658||21942|23481|18137|22006|22315|22501||12|22700|20725|18959|21381|23494|19934|13|15910||19173|22339|15555|23067||21301|19141|20935|11648|22597|21697|21623|19689|17751|22790|22192||21768|19882||19020|20263|22732|19396|23252|23251||19503||20721|20504|22552|20399||21340|20949|20833|22362|23448||20787|21470|21948|15777|22245|21558|23395|23426|21230||||22425||22664|23125|21870|17582|21733||15731||22539|17234|21961|22593|20671|21389|22772||22652|22624|22658||22337|||18507|23388||22071||19245||21480|20168||||19759|18372||18809|14520|21082|11958|19262|14661|22625|20950|23330|15829|21799|18338|17493|17983|19639|16429|19909|17175|23214|20548|22224||17408|17352|12625|21391|||21235|20944|20353|19982|23073|21028|23511||21779|17515|22498|22697|19058||21076|22872|19120|15550|22929||21679|20538|19202|22372|20225|18070|16924|21532|21466|21832|20051|18843||18981|14942|22665|16821|19704|23012|23015|17245|21641|23004|20385|21279|16702|21989|21983|21659|16975|23136|19526|20175|23226|21859|23002|18481|23346|||||12570|||19010||19331|21170|20665|23465||17258|22914|18312|22544|23285||22524|21452|23264|23199|19251|23033|20631|22684|18166|22030|19620||22117|23132|19650|21887|21705|20311|22612|20178|22277|12321|18962|11904|15966|21515|13626|13416|15376|12630|17641|21885|21621|22750|21686|22883|22935|22551|23039|11581||23306|22568|22845||19735|21119|17041|13632|22505|22749|17809|22057|||16617|22961||23100|||18367|16313|20274|21034||19489|23449|17053|22566|18586|18795|20943|22769|22567|21712|21711|20066|19736|23139|22285|18856|21451||13948|15218|15240|23457|23458|21135|23021|21823|21228|20939|20855|20419|23106||23342||22905|23401|22254|||14953|15342|22312|21950|20550|19151|20545|16047|23200|14|22182|20237|21898|22899|20015|22139|19658|11339|10325|23456|18769|20127|15110|17147|20063|20982||20208|21791|17903|22272|22878|23455|22215|23165|||23380|19397|17391|21080|21474|22208|14446||22274|17095|13879|22464|21736|20146|19486|20205|23304|18170|21721|21687|19289|21990|23386|18902|21256|19932|19452|20812|22482|21300|22509|23080|21104|17616|19124|22033|23350|19662|17823|22784|22645||23434|19117|23191|22598|21633||15287|||19844|21549|14755|17180|17350|15558|||20652|14504|19578||21120|18272|15517|17318|18233|20639||22084||22902||22303||22040|20327|18493|20042|17191|15335|14719|18773|21648|17939|19970|22918|15717|14096|18090|20977|17724||21739||22617|23186|17881|23061|22885|22997|22370||20805|18065|15776|18393|21401|20609|12389|15664|16334|17587|15985|21377||22529|23260|16608|22495|||23111|||22234|23518|22373|19891|21392||20266|21263|22041|20938|17329|23010|22655|21764||21041|22402|23209|22523|21038|20354|17754|23223|21352|23472|21393|22156|23358|21964|22920|21813||15447|20426|17486|22876|23390|18632|22374||21353|21358|22933|22720|18886|22206|20836|21861|23194||15957|17731|23336|20803|23240|20405||22101|20359|20513||23501|21462|22447|19666|16238|16475|||20655|22087|19142|22260|17507|19334|14304|23000|21843|23452|22154|23512|22969|||20751|21804|21312|22064|20983|17532|21163|23064|17942|22805|20466|17131|21548|21445|21223|19070||23112|20941|21824|21376|23329|22618|22836|20495|21574|20254|20619|22779|22422|21151|20995|18814|20686|||20533|19182|21846|19729|17841|17839||21855|20667|15767|23051|22471||14659|21498|11567|11717||22550||22132|19728|20134|17347|23098|22877|20786|22184|18515|16309|20598||20915|17237|19928||20039|20394|14808|16|20796||12758|19993|22840|14113|20586|22220|23229|14806|21287|22306||22847|20271||18402|19680|22446|21635|21980|23259|18563||20730|23197||||18458|19518|||20966|17440|19968|23315|21719|22543||22650|22177|15619||23276|17160|20932|22167|23352||21207|17135|21457|22894|18463|21030|14478|17082|11129|22067|20096|||18941|||22331||15890|23320|19017|20842|||22791|22672|22906|19036|20439|12163|22602|17176|19861|22054|21081|22759|20826|16271|21868|11844|22417||23402|21049|19825|14447|19604|18840|22168|17500|19492|17483|22080|23313|13909|21446|19399|19184|20409|23150|18068|23376|22416|20358|23013|20204|21856|22299|23338|21742|19527|18975|21583|23371|21785|16989|19344|21666||19581|22910|21403||19940|21460|||18738|20048|21891|||17462|16763|||22424|17314|21378|21907|21117|20895|21520|23175|21255|20337|20868|22163|23196||21878|19994|23278|13961|21308|22200||22496|18972|17873|20793|19475|21962|20346|21420|20904|22077|20281|20463||22399|19248|20644|22106|23423|22434|17562|17026|22741||20698|20322|17064|19558|18653|21551|22671|22972|18544|18815||17682|16147|21188|21866|19742|21251|20257|21503|21783|22886|23344||23387|22079|22515|22635|17737|19702|13049|21588|23074|20501|18787||20057|21427|21450|19490|23190|21917|22995|14950|20190|22327|18395|16881|17749|21447|22691|20145|13474|21944|21552|15830|22686|20228|19828|22570|17753|19590|16981|14788|14278|20314|20435|19305|17772|23221|22418|22982|22088|22336|14024|21008|22011|18883|21811|21753|22414|19313||22862||21800|21126|15198|23333||19219|19780|20933|23241|22432||17284|19663|21573|22727|23107|18582|16183|14155|23431|23044|16292|19654|19511|17677|20408|22753|21642|14705|17223|17977|14456|18882|17564|9657|23230|21483||22442|17028|20239|22241|20074|14939|18932|22435|16322|16807||||22078|23046||20720||22405|22300|23053|22253||22410|17960|12503|22757|19786|16248|16813|22325|20035|21227|22506|22846|21048|23421|19871||14923|20576|21254|13190|21294|15729|21731|20543|22882|17826|23090||23273|23474|20283|23484|21963|20920|22353|21722|19047|18520|16492|19284|12938|13937|18132|21925|10998|11313|13178|15440|18808|14471|17961|21735||||19614|19000|21071|22706|21491|21315|20541|20788|20978||20374|20834|||23189|23184|18477|19247|20119|20971|23108|22587|22861|15780||18350|14515|15906||21362|16574|19163|15168|21233|19348|16418|22966||23091|16406|19711|23442|20882|22709|21493||20396|21536|23476|19339|20347|18835|21685|22002|22992|22875|22928|17091||16789|21213|23096|23356|20757||22556|20867|22157|20838|13461|||23412|21320|18912|22201||14171|21359|15298|18858|23377|20519|16770|17762|18989|19507||22492||22622|16588|17357|16027|20222|16203||22858|20574||21418|21210|20380||19923|15066|22951|17193|20142|22160|22297|21335|22595|20076|21922|18706|19066|20197|22016|20969|17247|15771||17965|20850|22121|18537||21097|16351|23068|16979|19250|22364||16635|23461||12953|22962|19996|14067|19878|19461|19727|16487|18249|21441|20894|21608|14170||16727|||22874|21767|20922||20260|18803|18396|13468|22223|20152|14819|20719|19992|18593|18301|16117|9064|21658|22332|16988|19991|22828|21208|20514|22269|22023|23454|14121|19543|22794||21433|22648|22572|9889|13630||12056|18370|||||22660|21267|22256|22309|16956|16517||22596||22564||22411|14754|22731|18834|15902|22977|18205|21896|15114|19645|20898|20791|14470|19183|12927|14934|21782|16200|17728|20095|20735|18435|14612|17309|22536|15888|18430|10852|21700|21737|22262|13306|18467|18921|18188|22213|18649|20594|17936|20783|21900|21172|18109|10430|17757|22081|18670|18045|13905|21098|16302|15723|19514|19912|18030|16346||21586|18909|23008|18553|17838|||21411|20202|17282|20028|17140|21314|12631|20008|16630|21431|||23290|18029|16230|21469|16364|19941|22895|17955||16848|23396|15012|10465|18007|17605|16033||14279|17673|20774||||22585||20099|21910|22236|19443|21653|21664|22683|15928|16204|22867|10416|22166|21720|20044|20416|23232|||21607|22113|20906|17919|21947|14673|19379|19520|17752|14533|23347||21366|16062||20448|13241||15930|16624|20012||22517|18683|21656|16957|20831|22726|20443|21130|23414|22889|21740|23509|22282||20122|22462|22347|21229||23375|21957|20768|17896|22688|18418|21407|17591||22956|23037|22470||20618|22162|22502|16682|9297|14863|19691|22485|||||22692|21303|13728|22457|22249|18405|23088|14505|17597|18969|21156|21928|21031|22014||22787|20928|19973|18910|22921|18722|18661|23117|22999|18893|19760|20536|21881||21689|18256|19886|22216|12906|21178|21258|19504|20914|21338|14996|20101|21026|19091|18457|17167|22141|18945|15140|19525|12875|17|21343|22247|22960|21101|18389|11072|21778|||22025|22110|18681|22235|22034|23235|23154|20203|20018|22531|||22873|21616|19616||22808|20201|10238|23245|22212|22924|17010|17317|22452|22891|18006|18146|19263|21723|13706|20772|16550|11292|22816|18997|17626|19398|22993|16190||20014|21365|23255|22268||21398|21214|15821|19449|19441|21763|22275|16765|18210|14963||16172|18807|19221|14606|14288|17874|21439|14127|14263|21786|19459|15639|13202|17740|18484|22352|10252|18425|19038|17005|20054|22180|18383|18120|16539|22186|21542|21422||21751|23373|15663|15185|20128|12364|20060|14119|13204|13375|12979|11597|10858|12859|14901|13432|11625|23351|18172|19678|18313|16094|14631|19343|16296|13492|23354|18426|22901|17197|23321|16129|23083|12615|||21968|22540||23485|22947||20328|20226|22532|19673|18282|21192||19393|22636|21247|18674|21650|20755|13254||||20622|22681|23317|19306|21836|23142|18067|15472|23267||13338|||||22647|20198|14379|16764|16331|15162|22659|23505|23353||19542|22953|18252||20612|||16388|23169|22575|17649|13737|18764|23366|23079|13936|20670|20224||22869|18793|21672|||21661|21324|22820|23133|11275||14723||11819||21311|15403|22849||15702||20875||22189||17818|15842|20436|||16428|20032|23099|19933|19910|22633|18609|18206|17680||22957|21293|23256|23298|17378|19164|21042|17323|18564|20759|22542|21718|18638|21455||22481||15270|23280|21665|22412|22396|23057|22694|16519|21043|17885|13931|16158||18667|19761|22131|15986|18012|22601|19360||16543|20854|23025|13977|22657|15524||20124|20802|23234|20246|22115|16562|21037|21880|19708|22654|22761|18232|18626|20264|10006|14557|18333|21604|17933|20112||16072|22738|17489|22637|13473|17595|22638|21975|23206|21600|21006|15575|23158|||14780||19929|19657|17995|17877|21680|18852|11662|17502|22070|20959|19700|22148|18290|21965|17806|22361|18404|21321||20462|18755|16815|17710|10615|22980|14335|10026|9834|23071|17790|18922||22450|7916|7031|10768|11737|11714|7127|9280|8303||7484||22810|19750|16260|23161|16825|16932|16725|||18844|9727|22516|19506|23247|16990||22158|11929|20077|23093|16345|18573|16915|21384|19212|20858||22693||17331|14092|22870|23269|16064||21045|12544|19274|16558|13281|8909|18003|15266|14543|12769|16181|10844|11723|21797|20892|15242|22958|22250|17668|23491|23177|13958|18640|16160|22930|19374|21589|11459|18049|22534|19152||23406|20705|20596|18||18496|19563|21495|11847|18281|23294|19|20059||20234|20252|19383|17656|22248|12357|19307|23131||14829|22739|14667|18801|20961|21526|21291|9306|13832|15484|15877|13986|20962|22913|21860|22227|16426|19359|14307|19922|8988|15935|18465|15970|22443|12749|18719|17161|20801|20161|20465|21775|17060||17169|20499|19771|19938|22226||8607|15635|21812|21545|15714|21557||21167|17351||16097|21677||23116|22904|||21837|18944|18646|8839|16856|17648|13605|19116|16068|19330|||17774|22384|14826|13588|21307||19683|14070|17481|21931||23345|18744|17385|14296|22390|23202|22061|16607|17827|22164|20646|16708|22949|22988|17938|14874|14761|22577|21745|18424|19837|13742|21421||21249||19701|15365|15364|8314|20386|13550|15355|15443|11645|14743|14008|9716|14188|20551|22408|22942|20457|19984|21159|19958|22907|16661||15734|8595|13496|19033|12086|20485|22063|13913|16379|19710|17783|18099|18848||15801|20909|21792|14261|18569|19468|21729|19128|17692|18207|18952|22231|18699|21280|18522|15108|18817||19955|14940|17411|16381|15026||19031|15210|14372||21070|15983|16845|20211|20||16760|14765|23283|16344|21663|15230|20696|14601|17647|20636|22893|20511|20298|16684|22010|22890|16520|23436||22751|10888|16014|22398||20900|21755|21840|15979|18280|18204|20710|21404|||20270|21565|23363|||14833|14524|15038|20531|20630|22094|12880|17644|19778|23415||22673|22714|19102|22582|23138||17900|20206|20086|23114|21004|20648|20078|20471|22404|12921|21197||22085|19279|21627|22217|22120|22562|23385|19098|16352|21390|11193||19799|17588|20132|23487|23369||18707||20505|21015|10584|12134|14487|||19921|20273||18631|20025|12581|14172|14703|22176|14349|20451|21|17475|18652|17773|21674|21220|18265|17465|20075|19648|18034|20809|21732||22|23||24|25|21923||16091|20336|22547|19768|19997|21481|23288|16403||15867|18819|26|18534|9958|22294|17658|18721|22940|23193|21176|18453|14102|22923||23032|10225|23014|16793|20480|11067|22191|22766|17972|12053|20888|19295|27|12952|16227|11912|12241|15719|20330|19519|20484|28|23066||15181|21002|20606|20233|23095|17777|20568|18551||16928|16353|17729|22468|19444|15483||16377||29||30|15673|23059|16082|22181|12547|11533|16463|8810|17101|12033|20651|21007|||22599|22971|19168|21858|19290|16521|12830|22868|22171||20345||||18408||18176|21560|11505|16293|18248|19231|16872|16363||17037|22823|21937|20778||21243|22530|20829|14902|12556|19896|13786||||16849|17428|21468||19632|12589|16099|18452||12066|13642|12197|17739|19380|22626|21683|21204|23444|13471|15755|22554|21226|13586||||||15705||22932|||||||||16733|23127||18289|22646|17659||21388|21978|21717|20430|23367|18195|17453|14255|14585||15222|14957||18842|19964|20685|21955|8844|12804||18992|22927|19085|21268|13650|22153|15956||21696||20080|20013|21497|16019|20248|13307|19636|20981|18348|20470|18689|22871|20886|31|19215|16596|18657|23272|22197|21059|16891|22003|22218|22059|15279|20109|17461|13797|11619||17765||15835|18841|11740|12297|8730|19879|20288|12395|7594|20563|21749|14690|20679|13687|16645||22926|9193|15486|||21770|21036|22128|19256|20559|17185|21351|20896|23323|18227|21253|8154|18243|16688|16300|22604|13290|14621|21849|19622|22228|20924|19101|15418|13032|21889|15390|||||19897|19045|18854|14922||17472|20592|10516|19463|9020|18125|20887||21449|19737|20553|23425|19975|14678|19508|12718|19606|18853|13305|19233|13135|21780|18907|18756|18786|16423|21124|22716|15533|14892|14961|17735|23077|23104|19477|17448|19346|19714|19278|20007|17027||19877|21725|19129|16189||14693|20819|22807|22488|14525|22244|20952|18791|20029|23005|15684||19113|22896|17232|20326|18126|19237|20250|20191|19509|18827||21438|21678||18943|12011|15264|16017||19479|20209|23305|22126|17779|16547|21609|19550|14129|17847|18211|17764|20613|18035||13058|17875|20569|17528|33|8210|9652|20794|19733|9293|19789|20040|||14570||||||23410||19009|19429|17966|22283|14097|11061|21613|14161|19111|20282|13599|16340|16032|||22581|18680||18081|||22419|13245|20184|13331|17124|17706|15931|15652|12844|20280|19239|15102|16279|19059|13221|23049|18529|22563|20195|21624|16167|15103|15007|17117|9513|18235|19416|12413|16771||23499|21772|12381|8630|21591||18011|21631||20923|17464|19530|20420|17050|17796|13497|20366|22357|18552|19560|16073|15084|20860|14491|15195||16803|22503|17864||19149||21357|13152||17722|18329|21456||20433|22797|15135|15940||22441|20140|18164|14649|20295|12499|22298|23249||22349|22266|16536|22111|19963|15104|20434|20945|15131||12831|14011|||20091|20810|21575|18105|18864|18456||11948|19651||23289||11805|17253|22288|18740|18557|20156|20312|20094|19355|22050|22707||11734|20067|12427|19513|22922|||22151|21183|16263|19675|16477|12654|22711||22333|22243|20115||20395|19744||21078||22827|23309|||23182|12594|18401||19187|20974|21555||15069|21638|19242|21309|16462|22448|20221|22778|22682|21333|21646|12609|21277||18645|23084|19794|22271|7515|13702|20645|22591|18470|23475|22983|21771|22814|23118|17080|15477|16627|20193|18965||21918|19186|22745|23361|19455|19532|21762|23185||||18377|20351|22013|22001|23043|23038|23035|18924|17984|22621|20930||19972|19438|22455|21759|20217|21054|22989|18760|19227|22668|14005|21459|18585|18572|17280|16235|19079|15925|17192||20626|22903|17810|22600||23087|19361|18309||20781|22640|18196||18478|11047|20227|16859|16476|16974|18802|8708|20446||23155|12899||20417|17490|8884|21464||18636|17654|23379|14710||16012|19298|11931||16676|16264|22020|||18616|19097|18488|15937|16755|19609||16970||14344|13469|18002|14180|16677|18374|11697|22387|22321|21707|22829||10889|22478|13046|23050||21266||21102||21584|12198|22022|18462|20857|20540|21145|20522|20673|15189|23394|21283|17662|19270|20182|17325|20718|16837|13160|15568|17402|17285|22916||||20546|18497|23460|19493|20912|18165|23210||20085|22257|21023|23028|17375|18757||||20779|||21593|23162|22944|21984|14237|20375|19387|15740|22843||22105|15370|19123|19722|20285|19065|13585|18911|17912|13429|18199|21533|18356|21798|13771|18647|19288|21636||20709|19977|8991|20407|21289|17688|15634|10940|8979|13634|18672||11741||17259|16992|10494|21196|17057|12665|21482|22493|13794|22439||23334|20369|17940||22939|21953|17450||17927|13545||14825|19115||13495|22098|17036|18635|16037||15886|21828|15954|20918|19382|16312|14774|17128|35|21484|13169|17173|19505|17372||13845||15993||19353|9347|16389|23450|17275|13192|20310|22032|12355||16829|14254||19229|18149||14227|21750|17394|21932|15768|13651|15409|17467|20714|13145|17287|13707|21654|17516|21703|10373|19849|16507|||17570|17471||||22985|13300|23156|18642|21615|21884|14356|20565|18525|22175|22039|16206|12770|10355|12668|15699|20958|20068||||19415|18547|12048|5769|21088|14508|13052|21055|17581|14183|18979|23159|12679|18654|11383|20780|13657||23034|12877|12523|8804|16499|21329|21511|20332|37|16797|21972|17442|22558|12257|22555|18923|17991|21215|22613|21423||19371|23173|15596|15143|21702|18494||20398|19410||14867|21706|21147|19435|19376|14784|20317|20171|16153|15180|20605|22466||11345|17696|17145|17106|21118|18193|17617||21187|14189|12221|13070|23176|16868|18123|21000||20144|17918|18051|21222|17281|19682|21203|23124|13243|19362|19430|23145|15436|19140|21166|17087|18037||12814|17755|15811|16931|22326||||18611|15675|17801|||12260|8805|18239|22069|20611|21465|17153|||12188|15959|19551|15213|19791|15759|22723||21448||19189||21165||21709||15138|14112|13890|13261|8158|15868|16537|12920|16314|13017|12998|21602|18119|17249|15491|21634|12394|12055|18130|18710|21546|15395|21416|20294|15305|19064|22388|20951|22838|16054||20103|18693|18062||10229|13255|22695|21958||13644|12079|6881|16658|19081|20724|21436||10717|14301|13061|19902|22525|23228|16042|14075|21816|||15600|13753|6391|18789|20853|22801|17104|22371|13106|19495|9152|18956||21592||||20806|22143||8177|12728|21838|20807|12896|21538|12030|7524|10460||18501|13294||16245|17619|18687|16443|15167|22278|12796|21473|15009|17072|16373|12656|13752|16497|19014|18311|17030|12153||18245|10368|16319|14904||12415|22511|17039||22429|20687|14159|||12797|19169|13176|14932||18400|22465|12083|17049|14639|12335|18236|15525|15199|17517|22811|13560|12885|12788|19440|15040|22472||17816|19373||14542||15793|20183|38|19469|12370||39|16842|18900||19781||12001|||15357|20440|19618|23429|14971|21510|21062|20105|20769|19615|21727||17019|17141|18335|22092|13080|18998|20121|17976|12591|9756|13332|18153|16286|16448|19692|14713||18737|18260|22973||14036|21463|||20286|20111|16482||13024|11013||17336|9728|13941|11136|15853|10960|18038|12914|12774|23069|19672||21540|17694|22614|20335|14284|13128|23303|18364|19749|21402||16801|18113|23438|18784|||20916|17627|19447|15452|22931||18342||19512|20808|19600|19990|15650|21826|23023|21985|18605||19257|13646|18833|19052|20530||13435||10401|17381|17674|22561|23242|13871|14626|13999|22915|17901|14240|15872|15640|21342|20597|16317|10923|15215|16976||11064|21224|19207|20488|14083|23143|22188|21500|19954|15236||16197|7946|17557|20389|19784|18723|14876|20279|21261|19805|21618||22377|17379|16198||19573|20578|17601|||17217|14315||19332|21326|18928|18917|16967|10304|18304|16247||21195|17535|21603|21116||13196||12088|18258|22565|17430|15874|22049|21695||14611|20521|21556|18054|20816|16649|18759|18220|19547|22389|14567|19375|19957||21606|16382|14458|18229|21143|17540|21122|14496|13762|19762|14422|19192|17098|17078|18118|20384|16879|15656|16504|40|21726|17222|19528|21710|16940|21802|11517|21093|18985|21682|19268|16863|18935|16265|20251|11101|19214|21930|20581|20899|21003|||22149||17770|17609|14328||18346|19706|11807||22685||18179|16830||8298|16040|20348|17062|21444|20910|14045|14665||12292||14499|21850|21386|18599|12101||||16513||22964||20728||21951|13362|23094|15686||22318|20955|22627|19883|20437|22758|20754|20748||17295|23029|17111|18931|18770|23031|18821|21784|18499|16358|16376|||20870||21643|21926|20992|13328||16790||19294|17209|21867|16502|18838|||19798||21290|20219|20580|8504||12259|19642|14482|22356||10681|20319|17276|19644|22747|22382|||||||||18019|||||||||||16698||15150|||||9965|21692||20162|12675|19937|17819|12076|21994|19292||19199|42|8719|16595|11448|17433|9737|13765|20030|21085|21296|22629|17999|23017||16442|16587|18378|7298|20996|21264|16228|17851|20814|23157|13440||||19565|19488||15927|17456|19907||15527|18575|16118|20194|22752|22351|18251|18159|22768|10289|21675|10381|17714|21835|17868|22859|20980|16935|21217|15769|19271|21570|14714|12968|14886|22783|15817|12203|||14603|16387|17002|8625||19517|22174|||20666|16945|20902|21072|9767|21505|16997||23122|14637|19813|18942|21506||22991|20734|20963||11348|21879|14846|||21946|19531|22608|20412|19121|13659|21212|20403|22781|20333|16366|18703|14959|21845|15079|18046|21408|8383|22454|18837|23293|16214|19801|21876|18505|14309|7200|21974|20037|13434|20265||23236|16746|14413||19367|15134|15091||12607|20925|22202|20372|23222|21339|22990|13412|12994|20584|14989|16225|15815|18380|15846|18075|10903|10804|19767|14593|12192|15547||17975|17096|20199|18322|19924|15749|18053|13428||15683|16571|11715|23163|22304|21579|15738|21902|21534|19566|18659|21306|23188|21595|21364|22884|23355|22136|19434|13942|19763|14875|20527|16425|20073|17650|15691|22774|21136|19866|22519|20844|17344|17200|10966|9180||13277|20936|22545|12317|13101|12545|19679||23027|21796|20376|18064||18660|21847|17575||21625|14406||19088|16058||14594|21129|12154|20334|22007|12809|17709|19100|23134|20601|21346|5456|16819|11712|14965|11496|15567|19541|18872|20098|17813|7032|23207||14633|20841|19588|16030|22058|18560|20825|18503|18718|7045|12750|17182|20859|12323|19299|20486|16631|16606|22557|14995|21645|19354|20506|16548|20817|22129|11162|19718|19668|12164|21903|15696|7291|11891|7961|12919|10659|12251|12672|17362|21527|9742|12067|15562|20509|13780|17214|12895|19962|11368|17613|19324|17920|11319|21262|18513|19880||15309|9892|22945||10503|16022|18183|21805|17149|21380||18273||17766|15460|21322|21773|20872|8004|10904|8651||11134|19612|13854|14047|17301|14656|21242|19918|23325|20069|16361|21496|21601|||14387|8150|17705|16156|17778|16112|15728|7374|12732|21379|22825||21777|17476|13561|15239||21822||||15583|16076|15173|21927||||15751|19408|20474|12505|15458|20490|21237|18276|16840|21681|22083|16786|21001|22183|20381||14355|20688|23416|19608|22284||||15670|18363|||20623|18087|17785|20088|18021|18517|15856||21148|14619||19013||19083|19240|20313|13726||19389|22258|19913|19904|18448||21286|21996|22267|22937|17911|14948|17218|16031|12412|12887|17897|18528|16614|20567||17929|12288|22427|18676|21954||||14485||18558|22296|15659|15774||7780||22381|20424|21232|16693|21009|10464|16604|18160|16710|22507|7846||11754||7906|10626|21865|21270|17397|18283|18925|13283|19582|21806|16601|15016|18386||15294|22195|16416|21724||8287|15073|17700||6877|21272|11288|13858|20852|21292|22323|17290|18532|17196|16715|16832|8355|19619|10151|18162|23258|20790|20599|20368|18816|15593|17069|8048|19342|13866|19323|19432|12975|19167||22632|18315|21567|18117|7971|15588|23216|19450|23341|11188|19818|16294|18890|14696|16899|12923|17189||10991|14928|17786|11641|11062|22735||18648|10579|19104|21612|45|13603|21304||22615|14566|19911|17846|20839|||21127|14888|17926|14062|21673|15692|18486|17780|15461|22499|21146|17438|17501||19204|18326|19147|21310||20300|21874|19273|18668|20338|19310||13361|21155|15313|46|21531|22123|||21535|||19315|20158|18709||21518|20516|20905||||8205||19943|||13514|||19423|23244|21690|16583|22549|17730|21252|22742|18157|14786|21921|19961|21443|17311|15341|18279|18398|18197|19236|16365|21628|19613|17079|8558|22473|13124|20242|13895|21105|20614|17917|21410|8403|8951|||21669|20561||17828|16330|13717|16809|17886|22029|18010|17206|19293|21349|13658||5674|11303||14445||13284|15662|13923|21057|15566|16199|18061|18079|21744||21271|11042|14019|18518|10732|21193|10363|18074|14746|15334|16275|12536|19287|10106|10457|18618|16670|18953|15952|18022|16773|22406|14722|19574|22892|22514|9215|11889|21577|17034|22193|15411|21559|20998||18014|19283|9432|23153||18368|21022|19792||13438||15605|15404|18266|20397|23503|18542|22108||15226|20661|21406|18514|15018|16509|21936||21044|21571|21010|19075|||9610|20792|22161|14583|19630|17952|23119|19096|10399|5351|22210|20308|21115|21820|19999|19185|10222|21216|9778|13383|14015|20893|12218|16827|16303|12189|19024|12883|10472|21123|14580|19016|12638|21920||8584|20176|11024|22796|16392|18391|17255|11331|12597|22480|21905|16002||20269|13316|17521|12694|19827|16772|14332|17304|19748|15300||21079|20668|21206||20139|22314|23149|20002|17360|20449|20752|22728|19637|10511|22569||22330|||11759|21091|22521|20862|21830|20090|17733|18978|21516|15617|16224|12962|13810|16468|14295|14106|12170|22310|17803|19677|18004|17577|11893|15420|17126|20438|12626|22130|17775|20340|20083|13823|9423|23279|14049|20082|20694|16893|18307|13344|22897|19255|16888||22771||10969|17294|17670|20798|20324|21370|18148|18023|12115|20927|13388|15063|15791|17261|14152|19721|12100|22203|16993|17745|12752|13171|10028|14509|14431|14365|7092|13139|19522|14624|18584|16866|19681|18904|11839|19862|21375|14500|||22644|14579||18222||21576|18895|16433|14871|||13025|14685|17594|12504|9874|14655|13112|21332|19703|13203||13349|13109|20967|20740|15857||8871|17707||22826|13159|12584|9350||16011|13520|20517|22477|14752|16834|18749||18103|20507||16193|18753|15579|15383|14262|6643|15377|20675|13583|21259|14099|10548|19621|11603|10864|23239|22017|21547|21596|13200|21218|21524|15679|12959|6716|13838|13819|10753||18767||19471|14479|18431|17293||15296|6058|||21494||18362|17174|16465|15820|22764|16329|16243||18958|23018||9006||19655|18601|19795|47|19869|18758|||20813|5695||15014|22789|12377|9708|6012|12666|14133|8193|17370|12158|21895||23261|14916||19254||48|16439|20276|||11096|21529|19177|21752|5720|9799|17207|14807|19138|13147|16445|20344|14194|13812|18619|11742|17526||21164|12516|10599|12043|14732||21748|19335|18523|20629|18202|11204|17736|9975|18629|10949|22221|21774|19807|18691|19303|18354||12825|||18308|13420|21058|12059|18697|22018|15521||22305|18859|13906||20731|16370|21893|19291|15445|17513||18887|17795|16508|11673|11265|14868||13787|14587|21853||18218|22674|20856|23164|22679||21476|17932|12719||9712|23398|21161|8720||||||||15075|22421|22093|12705|18829|13031|12836|14908|17986||20323|22611|19851|19726|22005|9964|19043|11091|17985|21787|22344|||18225|17947|||17165|20173||18548|19454|6770||||21453|20454|21035||15090|15245|7483|12892|17511|18776|16056|19919|17031|14325|14623|14218|22178|20603|22880|15837|17833|18741||14670|14777|16873|15496|16446|||12664|20056|22817|17132|22068|9526|6090|12479|17081|19536|14530||18344|15528|16589|7836|17271|20677|16937|20948|18745||20291|15101|11352||18571|12137|19412|14327|20304|20315|9195|23170|14634|22830|17602|15117|8970|18679||15875|9247|20883|18050|20510|18780|19481|9263|23171|12042|21899|9114|15884|18967||19870|9477|14233|11237|19125||||||20272|||15989|17162|20240|12549|11460|6558|16599|10349|11616|13392|21981|12090|21789|15325|8147|15028|21111|17367|14397|8680|||22076|18730|13654|11124||16360|10132|10204|16394|20789||15372||20452|13003||11068|17396|21348|12018|14219||10585|14418|11147|7743||9029|6630||||17246|14824|||20036|21024|15963|13234|16955|16026|18800|16405|22733|17637|19538|18595|16217|21175|18877|21598||20556|22046|18320||14193|20464|5465|13526|18028|||10175|20739|16864||18228|16270|15059|21852|17229|10533|20588|||17274||22287|8173|10962|11508|20707|14142|19426|7640|12384||9658|||10744|7107|||18017|12741|21519|6109|11825|7044|5168|9257|12180||10139||11875|11748|||14941|13260|12886|11694|11223|17210|18394|14292|15798|15089|15667||22748||17988|12639|21110|21605|10116|16740|19144|7888|21236|20891|20141|13399||18024|18739||13708|15044||10374|20956|17529|9807|||17840|7797|12856|18437|21894|20973||19442|13036|6257|9319|10581|16100|18535|15122|11497|19646|11127|8369|18231|12176||12429|7207|22527|10084|15153|12023||||6938|5996|5686|7142||10292|10013|12266|12647|16105||17923|10081|15703|21651|20890|14512|14817|14234|18300|20837|15330|14168|14150|15939|15087|15071|14726|15839|11402|8604|8053|16464|14201|14323|18889|15536|22631|11750|15998|21815|14385|18328||18986|17571|20220||13725|21061|19661|22363|5147|18101|19889|16948|16749|13215|15495|10981|11164|8440|8958|11053||11266|20458|11756|16119|20065|21313||10894|16836|17417|9248|15261|11349|17409|13579|17358|10364|17655|18459|18915|15646|12580|16938|9575|20804|21617|11476|22091|19819|13012|15469|13955|6568|16909|14448|20180|9967|10242|11178|20106||22491||17460||18018|16434||15152|16719|17621||18901|12145|15237|12567|11312|21911|13503|21554|21299|21011||||14967|18203|12222|22187|10600|6209|20053|13681||19062|18031|10642|20585|16341|18134|19533|22348|11661|19731||15802||7468|13874|13570|9898|19810|19448|14380|16681|14330|10450|18976|19041|18174|16409|10425|14061|12799|7231|17882|19007|15327|14836|17726|6365|17665|22548|20331|20566|14647|11914||11461|16180|19549|12107|8033|15288|16762||14920||19103|16968|12637|16005|20524|19241|19145|15541|15467|19739|18930||21356|16141|20400|8910|16559|23318|21334|20365|20785|12624|22451|16861|11435|17946|19510|14066|15630|18539||13125|16080|20038|17987|14123|19394|18623|19174|21273|22677|15307|14783|13360|14999|15398|15616|13425|15051|15352|22574|19633|14396|18340|15964|16729|22770|17835|16305|8168|8132|18345|22320|13295|18417|16911|12617|13934|21060|12881|13914||17008|20041|22379|13498||20363|15371|16102|12663|22642|21347|20268|17941|17663|20638|16575|49|22854||15498|12298|16201|15262||9580||16222|20455||17871||10420|11568|20632|20277|20361|17278|13035|16295|19483|17302|19154|22518|14899|14724|21522||19707|19980|18429|15256|16796|17908||18598|11452|18828|12098|15790|8906|21132|15644|14976||12526|10403|20764|19754|23019|16605|11230|14239|14644|20911|14224|21219|5639|7955|17789|21075|20062||14104|17715|15408|13800||22965|19874|9396||20542|22676|19665|22469|16411|19012|19779|10318|15368|16744|16592|20043|15613|||16683|21478||15214|7977|12109|15716|22295|14839|18460|15713|11922|13827|19351|21929|19787|14785|||17233|21426|11306|15286|||18284|21103|17849|9865|13317|17699||14679|17306|18913|20926|17040|8286|19482|22494|17335|18960|20554|19180|16226|18388|12092|19881||5876|19979|13143|19457||14745|11944|17198|18696|16290|13692|11138|8186|11150|6195|15282||14548|12999|17156|22311|11610|11289|17788|18254|23286|16494|18044|17236|6687|7375|9517||16529|20828|18806|21671|22853|15581|11379|18726|12037|15151|7779|7155|8856|14139|12763||15263|15730|13478||22610|23120|17445|17043|22112|17435|20189|14559|23065|15620|10391|18735|19011||11947|13833|6675|21327|16962|12474|14857|20986|20702|17094|18000|10205|10293||21525|11016|15207|16900||13179|14947|20230|19521|14088|13697|19194||22857|14517|15687|20964||18785|19220|20467|16880|21566|20832||19197|15432|12868|9792||||18115|21160|13700|13047||21068|11539|18163|10908|14991|18974|13691|18015|7392||17561||21652|9999|11290|20186|18747|14595|12356|14553|11532|15897|14038|15746|13862|19804|16456|12929|15838|23110||14635|18299|17732||17485|9510|19099|22127|20968|15393|11733|6543|22475|21698|20181|7653|11802|19403|||20185|16977|20573|13285||21578|13711|12546|14358|19580|7764|21572|||21385|22835|15991|14469||15421|20885|18533|16641|12716||16593||17254|17399|11045||12866|12065|6545||18409|6810|17025|12293|22538|7919|14709|20110|||9845|6433|5124|11638|8299|17551|20934|8371|11491|6872|19840|16609|12685|18794|21397|19160|13223|18559|17201|20684|14666|10351|22074|10811||21191|21660|21934|14832|14452|22756|22526|11157|13551|15187||17033|6625|7335|9993|18742||12054||11923|6453|13809|10871|18664|9184|14354|14191|16572|18556|16983|12147||12311|10878||15724|10539|12199||11033|17102||17993|14182||8857|21597|10822|15999|13899|17103|6384|16525|13547|15641|10007|11845|8495|20737|18955|14303|15112|17606|17667|21485|10842|||19649|14720|20654|13423|22911|19688|7855|17727|15358|20508|11030|16654|9174|15643|16920||18669|15625|12559|22967|14285|12767|18620|11115|16250|||22580|22334|16774|5893|13022|16824|17109|15275|14030|13656|21873||14021|15319|14318|18242|12712|7323|22925|18088|9917|13641|12937|19752|18590|20360||12313|6316|17015|19981|||15196|22705|5193|19815|21064|9938|10469|18076|11411|20135|12162||12366|18621|7406||17954|14169|||16479||||20136||7986|6300|10241|13506|16261|6874|7994|||16905||13983|13075||21991|22394|16402|14145|10843|16730|9559|7783|19548|15439|4878|11678|12314||19603|14241|12955|7414|9750|19107|||10513|20342|11022|22008|19942||15926||21502|20756|14564|15479||16194|6777|22736|12699|18751|13014|9311|14925|12132|15293|18954|9456|14361|22724|17505|21202|14851|14622|6410|14166|14143|6952|13329||12263|21831|10726|15882|7962|16980|16806|16205||11957|15863|8627|15960|13590|13232|16278|20620|8603|9585|11489|10919|5975|8342|13877|9192|18136|20649|14314|18993|12827|16369|11985|14086|19046|14467|50|18332|16929|14423|5780|14363|14821|6347|15814|20414||13289|16461|18526|8103|6003|12704|16357|6167||15854|17800|8106|6955|8276|4609|16137|15689|12156|19564||15246|21730|7991|8964|17509|13443|14052|6251|7695|15107|18561|19384|7016|16952|9721|16816|7477|18361|15252|21490|||21564|17861|9519|19363|22620|14428|13535|18531|21157|9738|13239|8086|18951|10426|12264|11515|11479|19873|17890|15405|21371|12047||17748|9351||22152|18673|||8952|14204||18994||||11337|9135|9501|17159|18849|18295|||16130|16724|13227||20245||15661|8022||20318||22237||7591|17684|17742|22689|18042|22263|12901|19652|18847|15775|10851|9066|20114|19285|10366|12632|20699|15819|22239|22978|6982||9687|17074|16336|9349|11362|19300|17296|7707|16799|8211|19106|||22140|20388|21142|9030|14290||16857|11556|22743|20669|13817|17474|14243|19074|13386||||18472|12976|20589|8921||18771|13276||13888|13969||15658|8753|18428|20027|21200|12141|10015|16769|16397|15032|7776|16413|8914|3176|21803|15250|11657|13543|12748|9961|19161|21795||8443|13292|11131|18455|20761|||||12533|13665|14381|20726|16061|12061|19035||14962||12160|13395|8772||20523||11321|23056|11315||18253|6956|12031|15015|21640||15591|13649|21150|16833|12411|15391||16493|13567|22754|22036|7968|15141||9249|6146|9334|20784|19769|18570||13631|12015|8933|14983|8366|15943|9880|12781||8329||||13048|22114|11874|12900|22821|||18583|6987|6671|10256|18600|17620||14952|19276|17701|17721|20847|19723|19216|15034|12271|||22934|16590|22500|11880|13390|11514|12211|16580||13722|16776||13792|18175|21971|18447|21245|12612|17238|19137||20244||22099|||10985|19318|17695||||10927|11815|18903|7532|18343|17957|11038||||18811|19743|16712|12738|17546||16906||17895|21241||19894|||9223|19635|10992|11340|5845|20706|15188|22252|||14671||13493|14414|8498|19365|17265|16168|21688|15903|||13253|16745|18294|10171|8356|13115|20602|21090|15056|19277||9582|17862|16236|13528|||13122|17569|12815|15627|7432|9115|8214|12253|14226|11578|22578|19843||21017|12491||||19427|19172|7186|15388|6846||16077|20160|6470|22974|15159|19686|4449|12673|22196|20745|3349|9718|6921||16718|14573|17484|16242|||14804|21854|12464|22082|10065|11554|15489|13741|20093||20795|20988|20845|||14652|6269|11130|13951||10412|22125|15694|16737|12903|12470|17492|22150|13319||8092|15481|22103|11711|9632|11107|11725|17678|12743|10950|9096|13509|7782|22133|11474|20491|17548|13552|10836|16272|19584|13452|23231||12935||13455|15732|8806|6406|9125|19093|17368|20006|14843|10375|||6508|7981|||11781||10891|14313|6677|10269|23160|14459|19684|15905|11783|10038|18655|19080|17327|16045|18325|18358|18578|19226|7982|12468|20642|13401|17768|13210|21794|11075|8118|5397|9429|10034|19130|9560|13666|21914|||16089||10577|18013|18555|20447|20017|18420|15412||19358|11427|15080|15297|9118|8454|12051|12235|7717|12561|12008|8533|9698||21056||21281|20577|9107|17542|8559|16057||20716|18177|17073|12956|22365|10217|18138|8665|8908|7217||10694|15336|10827|12234|6599|7786|14281|16350|9772|||17842|7595|11854|11177||22986|12562|15381||19004||18219|21728|19576|10459|9213|9375|14538|14798|10598|14900|21032|15969|13915|10137|13217|10794|10029|14760|20481|5286|11973|7664|8384|4724|18415|17003|12764|13802|19146|21781|18375|21180|12320|11293|8666||18139|||9286|13224||13805|17188|20023|20479|13004|20431|11879||13830|15203|17449|16696|16095|11187|12822|11146||6804|16961|13850|17076|18480|10997|15221|18733|18032|11784||16734|15569|15223|17565|20456|12463|8391|13100|4916|13715|21776||11632|10508|14465|13472|5656||12740|16088|4075|16922|13908||15423|15806|20664|12585||20953|18576|14077|8537|22172|13177|21582|7881|17750|20045|20869|11699|9506|13875|6143||15707|12343|9463|19693|19308|20849|21363|16297|17393|7724|||||21425||19395|15861|12436|17138|4423|21746||18446|18056|22725|20571|23502|15269||17922|6182|13872|20258|5980||14518|6431|17058|20736||||5693|17544|15977|20846||13517|13612|18360|12621|19885|16612|15589|9315|10146|13925|14216|13466|15178|12737|17552|21133|10818|15017|14787|15912|10316|17194|18476||10040|6824||9034|||17824|11926|16495|18089|16838|10000|15272|12563|14000|8653|15205|7148|16090|15219|16971|18106|16321|20192|||13667|13343|12467|18752|15043|21419|16663|22775|8017|13363|7857|21966|13589|11433|11369|11389|21499|10682|21819|17017|15784|14109|7158|16010|13673|19988|13141|8773|19660|14268|23195|22760||19976|10582|18434|11139|13628|5997|11393|8412|15971|10073|14616|16533|9919|6303|18278|5379|11745|17001||13026|15816|11614|14847|21997|16000|4338|9426|18433|7620|6927|9828|7310|9532|18319||19591||7357|16704|6457|9341|6861|13099|16471|6171||6104|18152|17434|7933|12706|||11841|5762|8238|10956|9893|9219|8100|18421|18371|21501|18792|52|16735|7398|19190|10382|16805|16567|14202|17834|14081|8707|19971|18184|18403|12331|19086|18357|17898|11253|15660|5855|20159|5850|20055|9812|6163|19715|7245|13273|8124|9218|8422|16578|15000|7964|17348|6589|20497|16699|12840|13928|15557||12379|8803|13820|13451|23370|10988|15813|14604|9342|9989|9123||19594|18474|10857|9222|19890||18419|16457|19019|7399|11282|11318|14466|21569|18441|13357|19018|20356|9584|13606|10933|7159|9809|14058|6053|22097|16050|20393|21248|9578|9199|7818|15437|9626|22819|18860|15563||9502|17407|9786|14766|16187|10550|16371|18743|21014|16662||20341|17321|11108|16478|17632|15682|14082|17324|12808|18297|8985|7830||20289|18824|8181|21863|20177|17213||18353|18412|6418|17767||8254|17423|13680|9497|15361|16671|10552|14870||17672|20746|8324|20690|21704|12157|17307|22522|14990|17361|17924|22100|8615||18473|17996|13699|14437|||17108|15860|11541|18832|16328|14316|14103|16896||18147|20255|20662||13703|15133|8930|7567|14935|18302|20871|9345|7023|8390|7665|6287|19575|10924|20064|8131|18475|10243||18546|12819|7996|16913|18587|21073|21587|11428||19534|10467|15946|22795|23365|22089|17070|19611|10545|15513|||7145||19847|9963|20120|20879|17607|10483|13008|17794|15431|12640|18080|15492||16016|20562|||||16750|18521|16304|12151|8733|8409|7889|9002|18422|17129|18939|16185|12287|||7625|16680||12871|18337|12939|8461|10578|11079|10869|18167|10169|17092|10723|17084|9949|14588|21486|12848|8894|||20441|16854|17270|11046|11631||19234|17422||16831||10452|21033|19867|8721|19028|11215|||11850|12302|53|18483|18846|16555|16766|12843|14275|6733|||16015|8931|19617|18191|10096|16946|16335|9062|11087|16538|10491||14522|9406||14351|17860|20418|5265|3592|16084|18592|18055|8279|7621||8235||11419|12244|21201|||7553|8685|13186|17814|13424|12369|18500|17585|18078|16954|8104|19466|13322|16165||18263|16822|15170|21274|20004|13873|15690|18317|17717||17029|10657|14196|19627|18142|20830|10164|17479|20674||17038|6033|5878|10780|10288|15548|20650|19089|14056|9826|23220|13596|18850|14408||8725|13394|9641|14270|20411|9153|8400|13882|22489|14390|9787|22301|13919|12598|13275|15818||6809|22881|10897|22027|10928|11189||9579||12161||9069|14662|22436|7111|17959|7666|19834|12202|16657|20472|7376|6244||19556|19986|10528|22863|13902|19195|22207|7927|19690|7372||10929||19068|20681|17315|20972|19392|17497|12442|6829|22445|9592|12136||6186|21715|8570|11451|10143|9092|9083|17583|5466|15033|11621|19816|17831|19005|19301|19337|20423|17805|19499|14376|14331|19987|18701|13074|9143|18790|15789|11004|5673||17316|15873|9163|14100|9332|20535|21701|20024|11575|22403|12272|||9972|6504|18717|9060|17429|19989|10167|14018|16512||15834|11021|7489|6397|5320|23006|15399|7462|4815|14864|13637|17152|19944|12627|10713||14157|18530|11785|11092|7292|11216|16826|12472||17241|10546|7669|18704|14228|12391||7599|19022|19859|16145|6847|20302|15499|11827|14596|20989|17869|14514|8858|11418|5821|11254|14632|17979|20672|16385|18866|11629|17181|7312|21250|16436|13698|13963|15603|13694|8388|11549|15375|7108||14555|16269|16132|10558|17971|6112|6688|8992|11300|14610|20072|11836|13069||20703|15505|13970|16367|19205|16431|9564|13287|11822|13237|13695|||14812|20711|14369|7246|5709|5418|20079||19259|12805||15435|12925|11668|14455|14027||15115|16378||11257|18288||21430|9013|9722|13896|14013|12971|7544|17099||17447||19974|21475|13521|20637|10362|13098|7622|17633|17615|19401|13369|14695|22242|13750|8381|17300|14320|10413|18135|20125|14012|18634|23011|11099||17130|14841||17624|18666|10014|18182|11294|19056|16510|11860|11991|19336||18788|18891|16960|21084||16610|20753||5462|13940|21765|20502|20743|18114||19568|18964||17556|17804|22042|7263|10679|19947|16637|8485|15120|8049|9337|11883|20960||4302|16728|13749|16306||17931|14057|14153|14789|16890|20157|11820||10376|16898|14043|14312|17151||19425|12739|20579||23075|9779||23418|16177|4965||16794|9404|10066|19077||11962|18810|9285|7552||19641|11327|22865|14516|16584|17113|14563||20343|11801||11070|14435|13671|17994|19281||6910|19808|12744||12077|19422||15208|14618||18223|13013|17510|13594|18250|17883|21581||||12419|14797|21541||16241|14453|10875|11268||22799|15800|17660|14837|12286|14248|17424|18610|8057||14135|16581|17204|9014|12488|13964|7545|19369|21647|16259|21029|8313|15142|10828|13788|6041|23400|19746|18156|11882|5449||9210|55|18663|11334|12905|15001|14163|6242|7821|7448|10008|56|6697||15253|18186|4692|13938|9167|19724|17945|21417|19640|||||9329|9109|9838||21517|19243|5537|15766|18110|15126|17052|13824|5460|19487|4601|13853||9794|16862|11020|12421|17884|9888|7402|8436|12878|10847|14339|8263|10082|9050||||10377|13593|13643|14401|17227|18468|14429|16526|11782||9270|16347|15487|11135|6911|22508|11059|11140|19983|20461|19863|4990|10436|15615|10489|8567|57|12623|9388|15961|19776|23030|14586|20459|18938|22634||16721|9986|16622|7871|15231|6730|5798||9955|9583|11690|10589|12096|13926|14903|17211|12034|12554|12130|16460|8244|14677||16281||11595|13119|10157|12124||9765|13016|20362|21144|58|||9046|11350|6525|16779||10496|18643|14521|19628|18639|6632|11749|14398|20881||14809|12524|11534|13116|||8305|18823|13220|6943|8863|11025|10067|5264|16355|10250|17642|8942|20196|16085|11065|13943|10110|11112|11412|23211|14002|5083|4912|7746|21943|7341|12462|13704|12931|18194|21829|15010|8215|18093||8499|11361||14537|14561|11486|6605|14134|8002|16858|21297|12340||12052||16273|7853|7163|12933|14697||13684|||18627|19034|8007|16908|19027|13892|17383|11700|17286|21021|15629|16660||10789|9007|19042||16467|15430||10569|19777||9856|7950|10313|14545|12283|7120|6961||15234|10336||6148|6980|||6594|16541|6690|13364|13512||19340|9857|7711|16218|8949|12318|17792|19206||11055|11630|18545|22052|11596|9243|15174|20453|6612|15060|16527||20339|17953|20071|10695|19008|6122|19122||13974|21912|16451|16984|8577|18127|13187|13374|14484|21221|21113|11876|10218|20034|22145|11409|10573|19057|12236||7421|21590||8783|20608|14852|7197|18927|21676|3994|18765|14060|10996|13129|6903|17855||||||||||||||||||6155|14009|8684|9863|18410|15459||||5952||15209|9847|7083|6474|21442|22251|3462|14574|13645|9369|8748|14179|10798||||||||||||6654|12560|17921|16650||12995|9487|16301|6766|19899|4141|13213|7403|8731|9320|6178|18314|14337|6039|5701|10147|7592|8947|14023|19829|9421|5706|16855|21302|7792|14031|13917|15898|13037|18461|18057|10043||19914|9258|11636|10829|9023|22232|12200|14016|14391|15427|17876|10561|18567|7303|13629||9859|16886||8148|13092|13056|10690|12790||13467|15578|10524|10470||19803|11965|6597|11060||19876|11550|8740|4923|7446|6085|6900|11624|16523|19264||8841|14148|||10454|14258|20450|17494|17388||10815|7239|19875||5651|16978|||14472|7901|9567|17371||18607|19765|18862||7266||19725|14441|10234|17405|10607||18187|22510||6388||20492|11848|17878|11843|8814||11897|12851|14733|13995||||||10953|8189|11667||16395||18286|12230|16126|17719|12487|15259|15840|14672|22431|17566|20382|5297|14627|17536|20929|21662|12837|11050|15105||7514|10746||6816|12616|14059|5733|12768|13093|13326||12779|13402|11633|7593|10629|7039|19179|7730|21472||19260||||15988|3127|19418|10251|15832|8768|20218|12268|6042||14265|6618|19730||4415|10048|6699|19155|16751|8723|12771|20256||11221|11125|14400|5812|10185|7037|19023|9383||9991|13303|12352|16229|16666|17603|13736|||18511|15509||9272|20020||16563||13491|19485|9325|15190|11484|11179|16484|13230|||15130|14589|18898||22317|22291|5482||||11014||18098|19950|22229|8716|13082||13379|15648|16078|18878|4663|13407|10781||20878|4299|11470|3497||10340|14063||11718|17769|9138|8510|5339|16738|17000|10140||9759|12846||16894|8692||12166|10306|14003|20137|23413|12605||9661|9921|19670|||10973||13089|||23464|||15426|17747|12512||21405|20468|13153|19712|16173|10734|8529|9885|13582|17703|20058|3479||17491||10601|16251||15373|14492|14173|7979|19050|6902|8141||19210|12187|17537|13768|14978|9527|13756|18440|11142|10724|9148|7047|15400|12888|10885|19524|20350|14571|15419|9233|8959|3798|6460|14175||12893|13504|5357|5169|8732|11766|22898|4185||11417|18796|19598|10210|21489|8142||21523|14463|5224|5429|11018|9853|3997|6784|13615|19109||16398|11252|14793|6566|7956|14076|8072|16466||17386|19209|9529|12756|8255|17291|14642|13595|4242||11353|14613|6245|14297|4740|17067|8781|13236|15111|3076|5420|8578|6497|13348|4996||||11269|9671|20940||14577|9629|13529|21240|10835|11113|7731|19577|10215|10211|11483|10703|11183|9833||17829|8980|9326|19900|6683|10793|15574|11171|11970|10918|16277|17148|10612||12618|7634|15654||12346|5391|16093|4153|12670||11719|14986|12802|6948|15465|4880|10144|8835|9093|11263|7029|7939|17312|20771|13939|8586|9774|4258|3393|19021|9908|18875|4967|22856|13271|13796|17712|8843|12078|5324|13136|8011|6154|6636||9231|7404|9822|14116||5591||6340||15607|7354||12552||8628|17702|19865|15165|11691|6539|12492|14341|8137|14699||10670|4424||19119|21239|8127|20708|13366|11927|12531|14368|7306|9424|10616|15850|10173||14210|8746|11218|17418||5626|7858||||5937|9842||8880|10874|10963|13151|11530|6860|12448|17716|16846|8028|11732|9505|7519|8662|6620|8967|12239|10156|8639|21095|21667|10592|10068|13557|9108|8782|9469|5842|9343|10560|7033|8361|17836|9647|8462|12977|18224|10060|11674|12592|14383|17446||11507|17406|7989|10196|12772|||16875||7969|23089|11430||5900||14394|7254|4648|10259|20678|4526|13846|18588||13408|14993|14669|19597|14443|13391|||14894|15609|14858|20692|16210||9680||14575|20352|17522|15182|15500|13640|21318|14395|17420|13967|9623||4818|8367|19067|10791|10651|19474||11576|12803|11881|15155|16276|14844|21372|11392|15561|13355|12812||14032|11637|20851|||12703|9194||15212|17279|19087|18581|12475|||13299|19316|17899|14321|8352|13841|15553|7296|15414||13718|8611|19945|17341|10752|13021|21544|11137|5770|5380|11675|8125|18622|22190|17248|14131|4207|10111|16455|12361|6428|6939|6129|9254|22512|19484|21177|11390|7539||12729|10602|10135|14628|14225|10079|13233|17431|17012|14684|13222|16907|10138|11371|5112||7721|14440|19567|16280|18407|19118|17916|18257||9781|6227|13505|8579|6097|8360|5837|5194|9627|16530|5734|9700|13225|11148|12489|19936|8088|13268|5234|11144|5613|15922|8673|8018|7891|12326||8754|5700|15608|5492|8245|5897|7803|8463||19157||20329|10165|12518|17384|19357|11343|8176|9832|16934|11599|20070|19939|7491|9089|7930|13117|9095|7516|7966|9204|15191|15823|16004|11787|11945||8070|8003|16528|12205|22019|16135|6172|17639|13591|8846||14727|12303||11464|19309||12853|9530|9944|13609|9881|18161||15564|||21553|8473|16532|13901|10429|17579|18221|7473|12416|21504|21741|17555|15700|8039|7676|14483|9157|5723|10438|10125|22401||17909|5744|10661|10480|5364|11872||15271|18471|5994|7610|8093|9702|8338|8259|15941|15827|20325|3623||13208|20118|18491|9145||17817|12064|11768|16638|59|12461|7486|22146|20373|22393|6471|18296||20001|||11194|18708|8612|7149|8620|15914|8564|15025|16674|4598|15990|7069|7349|11057|18287|17264|13635||20031|11863|21194|8693|16986|13670|||8122|||14473||7712|5991|5274|14800||11626|13959|||18255|14592|16008|12178||8079|||6061|13672||20130|20392|13920|10347|19858|15255|10832|19571||12206|8932|||19998|9586||19286|19570|8944|11239|15086|11794|11141|17992|7091|21065|13501|16540|9392|11790|11685|13063|9563||15551|12385|15610|13837||16059|16883|9942|9088|19431|16798|16128|12400||12021|10406|16025|21987||7301|21458|18933|22413||21412|||17738||10588|20241||20624|16308|22056|10792|6086|18566|10009||3805|7882|6862|17334|13975|15559|14531|13544||8769|20653|20640||11423|14154|8515||9124|15116||10625|12150||11526|21369|19806|18549|6326||5703|16959|9214|11930|21394|10343|17968|15422|19631||20243|22138||10705|22669||5197|15273|14299|15510|13197|13731|18772|15085|17215|16399|6581|13732|10074|14930|12601|||||15369|16421||16368|15955||5214||||15621||14716|15323|20022|22281|10045|17071|6759|19143|14055|11954|16726|19664|11888|17376||10819|6678|7243|17852|21848|10630|9636|11195|7000|12440|22341|6753|11244|22367|22134|17653||3716|15248|14160|9059|7364|9479||6183|16930|12057|17365|18579|10978|18920|20750|6110|13272|8717|8395|4455|16324|20113|14384||12319|14654|23498|6928|9097|11990|5857|4685|10064|10330|10944|9420|9494|10711|4653|4968|4871|4658|5241|9922|5471|3571|11826||9782||8997|14305|12566|12013|11527|14371||7008|9624|18608|9605|10970|12289|9461|12628|10667|10566|15987|8486|11502|11233||8311|10618|13030|6074|5526|10309|13571|13485|9630|7533|9273|10854|7837|7954|12476|12460||13311|13668|7904||13480|9911|||5925|6595|7143|9841|6119|15631|4418||11562|4969|18261||13490|14770|6870|19402|21050|17266||17574|13980|12029|16551|19218|12431|13489|13015|12530|14854|9086|20253|7020|7153||4534|7015|21128|14740|16705|20153|7987|16289|12224|14238|12721|19139|11834|16811|11522|14776|5592|21945|9973|4129|21714||8866|5277|||20979|21437|14781|16354|3594|14701|8523|5838|16568|18971|19378|14108|14217|12957|18469|6913||6615|12551|17689|12879|15455|15520|10224|6064|17179|19596|14927||11278|6981|12942||4807|15614||11285|16063|8458|8346|11083|14584|10113|13218|3799|10039|11499|14298|13231|8542||14402|||22137|17808||16921||11652|11966||10022|10119|14926||14277|15624|22822|20560|17720|16125|14811|6726|12334|5179|4559|12159|12696|15518|4218|11385|12915|7973|18762|11207|11646|11503|15934|7173|14259|11165|4584|7843|8688|20564||6622|10537|12403|9155|11341|6554|5165|5334|10887|13987|8474|9250||13965||18492|11902|10639|17114|11512||11665|17718|12595|17235|5880|23082|13457|14386|13997|14029|10478|17580|15171|12973|10738|7864|10194|8045|11692|16420|11821|21400|11852|12281||10733|9983|13201|7232|16055|16060|10715|15402|11971|16311|5553|14805|18826||8755||5795|14749|7429|10621|17948|11477|11132|16936|19304|16024|15176|15715|17781|16453|5255|17470|16941|8907|7597|9511|7322|15864|6790|9368|8943||15645|10504|6586|7587|11424|7626|6965|16919|19201||9179|22051|9278|10365|15099|9572|6208||6644|19188|10479|10664|9562|8715|10866|7026|60|7183|13367|4617|6304|7813|5508|16310|18813|||16777|7931|11354|15339|17646|13916|12362|18277||||10520|18240|13777|17089|12688|15642|8281|20767|15831|18871|7661|12511|12891|19888|15626|15359|11681|12255|||12367|17844|10492|17116|10282|7048|18262|14974|17389|7499|7176|14271||19629|12733||21691||20210|4621||12365|4271|9453|11397|14199|14842||9015|10547|9534|13855|11089|4654|7736||15786|5350|11054|19166|17366|4910|21716|17256|9554|6936|6016||14513|21025|16108|22589|16814|12450|10967||17146|13001|14322|21382|15128|16927|10699||7139|4647|8807|8252|7481|8554|7036|15502|11344||6432|13345|12519|3917|3152|8203|22279|8192|17704|13891||12945|14718|13148|10484|12325|23101|10782|9480|9576|8965||10080|12828|6957|7655|11708|9806|8568||9854|12284|10090||4719|12620|12332|12645|12371|16028|||12762|10345|6246|15470|8726|13852|19320|13487|20843|7302|4788|19835|4361|22533|6990|9979|7826|3222|14212|16123|7294|7377|10688|7093|9307|11729|10187|13530|8323|11786|13978|14937||12414|8763|15571||14215|13760||11735|||19821|6031|20777|19265|12941|11123|19060|15406|10352|22744|19364||13310|8811|19552|12496|6335|10935|13929|10153||5918|22053|16524|4720|16110|11246|4554|6481|16148|6960|19561|17277|16958||4381|12579|19437||8571|9031|3024||7242|11915|2576|21995|22073||5438||19249|15618|12697|||17292|12112||19368|7218|11357|17458||14071|||14507|9861|14968|8449|8321|14251|17539|11457|10432|8285|11298|10549|16808|7851|9598||10473|13549|9870|14342|7434|9691|10975|13803|7280|13396|16700|17184|11974|4146|11406|20903|4156|8840|6454|7271|17452|15161|17892|13449|16748|13009|3852|10505|18999|19037|16356|17506|17956||21713|13422|5026|10696|9425|14896|||10240|6958|18489|6736|12071|14873|8892|21108|13751|4436|9259|13766|14848|16239|8847|16874|21817|22214|19930|9773||11553|16648|15244||6062|6830|13864|22708|14992||17468|||11472||19595|9464||16561|4092|||9101|18047|15315|7802|20717|11753|13538|15745|19903|13568|17970|18857||15303|14758|9663|11654|5843|7602|10716|22798|13709|3772|10872|6273|15302|15708|13746|5126|10320|14972|13113|6802|16784|19094|7944||10777|16692|17195|12390|15516|6463|5740|12890|13038|15163|11892|7614|6923||19133|16531|6635|12520|12125|15754|14393|13154||21440|15638|17047|6091|21766||13990|12152|15515|8171|15544|15243|14126|16124|20046|22653|8509|||11764|18637|12960|9681|11094|||10155|||19854|||8670|6590|16694|3394||13738|18980|12375|4641|10495|15848|17685|13548|||10926|8431|5765||16867||18091|9120|||4493|6283|11172|13118|4817|19757|10050|12397|||11569|13191|6682|6585|10754||13095|||||||||||13785|2788|||19674|12659|8800||12393|15048|5585|9666|13173|12345|19404||6374|10451|||9154|5340|20021|7132|6400|11467|7510|13924|8520|15037|15797|11488|19995|18116|18108|17743|11109|8569|15560|14664|19175|5382|11950|6711|9830|8696|16120|19599|3081|14044|10423||16143|11251|16633|16759|10273|12407|13893|13541|16149|5890|17127|13804|7503|6705|14080|11763|3787|10845|9620|22460|21632|19960|10011|11076|6364|16053|6309|16396|16625|||8920|19272|5766|7704||9520|5428|19419|5383|12167|||15647|10105||9380|14375|6642|17798|18966|10433|6929|13515|10332|7420|3064|9920|19252|9175|5993|6706|9448|10543|14650|9241|12002|19785|15062|19607|12254|9228|4416|8015|11395|12308|11199|13870|15147|||4303|7507|17982|3611|4190|10200|5447||13484||12602|17123|11536||20016|||18208|18881|16133|||6966|||16348|6848|10176|8080|||20607|8790|13188|18291|9987|10993|14597|16258|6318|21492|15067||15474||14688|12593|23277|12329||5995|2274|6836|15054|61|14107|19319|18716|14006|8512|10868|8476|11097|||13286||6495|17863|6931|9462|20776|10859|||62|11910|16665|5504|19044||5783|12821|9422|14711|7639|15301|||11398|8640|7772|15438|||13993|15407|11955|11011|9308|10207|7734|18180|3810|17962|18783|11858|9518|5694|20773|15497|10059|3821|21295|20656|16678|10945|11436|9146|14141|7860|8954|18454|3928|11523||15757|12838|10745|10468|10027|19282|21317|7604|20290|22483|3510|12986|21052|18830|11693|20483|13235|14814|10982|10342|14001|14728|14578|13034||17299||6333||18948|6069|18077|12182|15807|5439|9498|9784|15753|8339|||4803|16315|20534|16570|18230|10995|8036|16342|16767||22755|||13410||15077|11186|6105|14779||12449|14407|8315||4811|15295|||20421|19015||7476|8012|7116|5621|10764|16046|16998|8336||19839|9760|16207|22340|10389|15899|12839|12537||8590|16320|7009|16987|11149|16985|15473|9581|15554|17887|12333|7685|18144||21114|6811|10016|13393|15121|14838|11226|16107|11283|9495||14436|22376|15417|11227|11399|11793|11590||7936|11519|20876|22261|14994|18443|16564|16518||8163||4506|14093|16634|9667|8739|5629|6563|16802||||18008|18094|9976|18268|15003|13414|11832|6745|12108|14915|12683|8026|7433|12274|13325|10586|12324|14392|8496|17812|19150||9851|12742|14409|6901|12650|8969|18651||21693|3576|4330|19280|14252|8658|11056||4221|19266|9302|9206|13994|15344|8221|19602|11721|13566|13189|4860||17093|7121|11071|14110|10939||9602|6993||18777||4289|9493|13045||17439||10534|11767|17904||7098|11579|5384|9238|12220||17107|10730|13130|17741||8502|19084|10296|11903|13462|9951|||8340|11738|5313|15782|13111|8729|14966||8227|23041|8257|13040|14907|19114|9370|8087||||11485|9704|22463|5120|22289||13840|7205|12451|15871|17592|19790|19267|10012|16483|15763|19420|17815|21355|5045|10519|15972|7063|18761|20957||16211|15742|5754|5532||16603|||20747|10876|9362|12513||||11301|13165|15299|12757|12907|7670|5833||3871|14449||16615|7040|18798|9574|17600|6075|12902||14037|11073|20149|13458|17353|21153|17676|18662|9035|12967||20164|19476|19766|18217|11867|11152|10663|13264|14810|3735|18869|5399|22792|12835|12225|13674|13685|6600|7827|11909|19196||12353|13382|7527|17776|17560|3371|19927||||19797|17891|11758|19887|13956|7088||9684|13132|8073||16506|12099|21432|12243|7754|9685|9283|8025|13831|18150|12857|12495|11600|15123|22936|12548|9444|10707|11241|12003|9322|5933|13358|7070|12680|15475|14317|16994|19860|6837|21479|14291|13127|9303|13262|7992|9454|18892|12991|5219|8929|8671|17143|9239|8308||5510|9654|9290|20309|13911|||||64|14236|12990|4475||7790|8185|16048||12987|7585|14707|||19838|10265|17498||17821|5915|13138|12785|11117|||15710|16178|13330|11627||10208|17974|17250|5775|17734|9090|16741|19855||11563|12135|4085|2894|18445|11761|8038||19948|15316|12596|10093|10042|16083|6985|12682|8543|7249|7975|14300|12876|13229|15809|15752|6616|11682||13747|6491|10314|11998|11828|13453|6078|16115|12466||3878|14568|13757|4104|15878|5398|14230|9271|11894|12542||7103|15913|6067||8637|10131|10108|20278|15035|5371|13321|14498|7710|7948|14147||||19071|6424|10934|9729|11911||20442|9909|11606|8556||10431|9849|9082|9488|||11258|3637|5295|10771|19095|8377|7970|15866|8597|11823|13278|13333|17436|12517|9868|20775|8711|16318|12599|6472|17401|8456|7921|10411||14282||12249|21336|17589|11727|8107|10557|3536|10099|10485|10652|13900|15183|18495|14120||13114|13613||19200|18961||7550|5170|8868|9540|9555|16953|17354|16785||10805||11814|20151|8795|10141|8444|8047|16023|10880|||3112|12734|9084|12232|7945|10529|10925||11238|5757|9818|10701|14565|8128|22670|7453|15995||||11921||8108|11663|9200|5898|5166|||10049|2686|13511|15865|14334|10018|13163|19557||12456|20628|9393|5539|11314|18766|9412|13377|15772|18929|15546|11007|12829|8060|16252|12776||9795|20133|12746|13226|12854|13446|9808|14554|9508|6270|19061|18043|9600|12227|10666|8923|9176|11429|10760|10183|19811|10383|11987|17850|16171|15146|11009|4005|7761|7680|9903|6000|6813|18039|14704|15504|9814|14004|9550|10972|5540|7071|8160|19822|12662|5640|7611|12418|15949|23128|18617|16545|6885|4212||17822|6723|9763|4655|8872|8695|13537|16435|15506|19920|18874|11676|10091|11311|23129|9170|20261|12350|18247|8971|18562||21512|||14410|17625|22205|6021|10987|8599|14438|11323|13953|9552|13705|15156|8475|10149|9645|12730|21809|20284|20634|15124|17120|19967|11299|12250|10799||7274|3437||7384||15106|14034|7097|10471|14136|4403||6120|16375|9631||12565|6967|12120|6686|21284|13992|5590||9899|10297|16620|12148|12660|11066|17105|21184|7612|9027|14641|9785||18129|13193|13821|12726|14988|||9910|13450|||21938|3898|16709|4758|10544|7454|13372|19208|20425|11155|17024|16414|8481|6930|17363|13085|11386|6626||15338|8563|4458|17345|13791|10083|9298|17545|11281|18140|9521|18085|14581|18083|11653|5144||10178|11890|11224|11593|9265|14033|9482|16162|8659|18190|15292|22397|19400|13500|12687|18812|3582|||15794|11561|8335|11540|9928|15843|16917|21563||19409|19165|12309|16800||||||12267|8058|9683|18604|12027|10482|7210|12127|7140|10047||20147|12104|14211||11566|10917|14149|4274|11925|17697|10333|17935|9673|18212||13947|21622|5950||11666|14477||14646|9537||10393||16926|8972|13265|6193|13445|9185|20487|||||7427|6863|18863|8465|3793||4223|19198|4382|12025|11773|11877|5057|17937|11986|9660|8784|14729|11373|18246|11669|12816|15736|6328|10262|8968|11528|8392|4622|10294|11544|11504|16691|||21185||5953|11601|9357||6747|||7211|17380||11607|10737|10152|4296|4991|12992|11267|8531|15144|14094|8758|16753|13313|8873|12315|4917|10245|12177|21278|||15078||4849|8319|9895|||18804|20965||4044||9483|6151|12070|11346|17308|18982|8678|8833|9481|18020|15761|14068|17419|10448|3811|7304||14906|19587|13957|10434|19850|7046|13488|7878|13482|8689|6947|10356|14712|15735|4130|8445|8562|7224|9288|5368|11552||4948|6336||15488||||10148|18527|7297|3854|9147|11960|6317|9435|9992|8829|3937|7749|20633|9208|5133|5597|7673|11967|16933|20840|14769|7762|14598||21477|20231|7075|10841||8143|6087|8849|6841||8660|8282|7487|18373|14050|13180|16122|14879|7260|10893|6546|6672|4176|10826|10442|17251|12951|5476|12969|10718|13710|4816|6291||||10796||15127|15247|16632|4987|3938|13597|||10461||3822|6024||7235|4471|||11015||11384|11774|7892|6746|5432|7687|||10455|10443|10341||15274|18641|14174|13930|9439|14889|8705|8555|12063|21244|18724||7806|7804|18884|10617|17332||8815|10414|11644|16393|18950||6034|14306|22773||17269||16810|16086|14546|13842|13447|8808|13790|||||10525||7226|19831|15911|13144|6492|19719|15743|15022||13989|14569|10673|19112|15129|15858|||4265|14617|8487||6934|5868|6458|5387|7584|4076|2707|15433|11837|9279|11051|17640|21644|10507|20660|6441|8271|17950|18334||19222|14490|12678|6693|17584|9945|8922|9021|8917|14245|10321|6271|6854|6713|14599||9914|20321|17856|3657||9546|10521|5699|||9783|19952|11592|13465||6752||||8903|8228|10921|13071|12568||7928||8113||9977|18485|||||6134|13784|13054|23490|7400|7395|21234|||17414|9900||9677|7522|19385|13166|17820|20907|9566|23103|5038|6767|10127|4374|||6750|7572|6582||7910|10727||||18677|21875|9149|5027||18169|8277|9141||16566|10691|18025|19225|16246|13370|7174|15651|5406|8887|66||18104|14702|14887|14461|13314|19884|12228|8407|8157|12453|14717|10257|15804|6578|17610|16852|6288|16626|7463|20727|9105|12229|5298|8224|15833|14865|9478||21637|67|12186|6416|7831|7658||17268|10044|13652||6464||13954|7854|||10233|16254|11956|18684|10421|13950|12572|18836|13475|20701|19261|19406|20061|8505|16619|11032|18516|9044|7252|6890|13602|8881|8712|9616|5069||13134|22430|10556|15385|8608|14958|7861|5318|21513|6547|3289|5108|5785|10124|16904||11205|16629|7258|21047|7191|4200|5098|10346|4725||16380|9408|6658||9588|6648||20975||9866|13918|2092|9503||15192||8497|4825|19078|9823|8273|6808|17533|19159|5172|4957||18896|15211|15094|15384|5095||15565||||15744|8945|12633|18899|7894|8309|9764|10947|9191|4489|4745|8899||68|19405|13981|16237|12958|7373|20092|10899|21100|6099|16757|22383|12984|6348|5822|5912|9028|17713|12300|7526|3843||19329|||11649||13682|15810|14608|21986|13327|11995|10307|9860|10221|18778|3482|18066|7598|20401|5489|16223|10331|10290|8694|23271||8638|8823|8009|10388|15451|10853|13729||10270|17934|23409|14691|10834||9565||12014|19048|17698|10036|6673||9952|12443|11372||15726|5844|||11391|12950|21387|7175||13878|10968|9291|6179|18577|10786|10542|19915||12677||8194|21368|18293|7917|7911||18731||4386|9933|12465|10877|16999|16349|20100||11918|17263|11235|22000|8249|8893|6025|9324|8098|3208|14683|6322||4688|7667|2173|||23001||9061||6222|7508|19333|6272|21231|12985|18538|20476|16877|23178|4111|10678|13669||21684|16220|6571|11687|6035|14065|17478|9606|12195|9650|9651|14827|19917|14338||||13247|5003|11710||5478|10910|11751||6147|8105|6187|9455|4588|10900||18508|5050|7038|5846|5966|22573|5314|13199|16623|10198|13921||19411|9768|13486|12438|20547|11983|16723|11325|7099||9309|5772|11031|18073|7160|3927|15685|4312|18705|4208|20766|12406|5607|8566|9719|6603||6664|20874||16139|10684|12174|21171|6573||19148|15494|6724|7361|8610|14132|5568|20275|14532|12527|12190|10203|10097|15611|15501|3806|5778|15184|8999|13341|7839|15216|14640|15397|12983|16001|14454||5016|10604|13507|6217|16775||8518|5445|6455|15052|12586||12755||13018|7627|11465|9276||11855|16138|4764||13575|16925||22954||14764|15172|16221|15606|5631|16174|10506|5817||16897|9969|15570|10551|19302||13743|16972|8472|20477|14087|10339|16659|12867||15434|21882|18058|22458|5511|12000|7765|22169|3429|16689|17288||18774|8702|18946|6284||6092|14944|8642|17177|18168|14831||7126|8068|6812|19796|8362|11609|9081||20528|21639|13610|18650|16038|15340|13984|11584|15975|19676|17543|8973|5828|11988|12388|15008|6526|14918|19391|2139|13867||||20320|||9037|13149|6592|17723|11008|17858|16569|10693|13072|10415|16070|7368|9000|19053|||11671|7449|14287|11531|17395|15919|15693|17390|15046|19732|10002|9281|23372|14464|18330|5907||20262|13352||17202|15901|13005|11612|6505|10676|20575|9024||69|21169|11720|15529|19853|12658|8609|10230|22553|9821|4233|3552|15671|12711|6667|4635|21323|10656|11604|14185|16951|18906|15503|8938|18781||8876|5784|10653|9642|17006|10298|6775|3585|21747|15278|13161|14799|10608|4850|13073|7564|17208|12110|11799|8643|||6461||19110|17519|3879|10254|9295||18988|16697|19832|||8752|7220|15602|7725||9485|3717|17262||9751||20349|16159|9594|8575|9694|15737|15362||14242|7588|19436|12690|||8975|1968|13775|18498|6918|7768|7110|4959|15852|15002||8359|13027|5571|8029|17859|7299|11111|10089|16323|19529||11449|3733|4116|10809||10098|5519|5960|9607||15803|3198|9533|20616|8534|11830|8535|7842|15879|8300|11800|12669|21106|22698|9003|18438|9331|14167|4618|5477|9547|7862|||20406|13781|9621|10154|11776|10122|14933|9397|9300|7054|10964|12277|20316|7315|15229||19782||11920|16711|14778|9544|13086|10439|9659|9837|15653|||||18936|11084|9085|9960|12982|4224|10892|7413|4540|18728|14878|16256|4304|8393|11709|7438|5278|12970|11317|14181|22259|9655|4563|12932|15828|16104|13448|16136|8706|4924|7766|4494|5562|5315|10231|13822|5758|16871||8115|13972|20478||21374|13887|19572|6215|7064|9186|9323|6564|4134|9104|9978|9577|8430||18298|15225|8082|6479|7389|9418|5021|17342||6624|8601||8709|7884|4698|10741|9077|15476|13569||16752|20712||22342|3614|7286|15232|6362|14898|9025|10646|9045|9459|7907|9744|8343|6350|2429|20733|3846|16480|14523|11726|7327|16511|16184|8855|16240|19559|11516||5205|23063|17061|13301|4175|19610|11219|14433|||11996|19753||14486|4898|13814|8432|20901||11730|15081|10400|7485|8648|18158|19502|14450|18746|||||17686|8344|16947|17690|8646|19092|7256|11351|8859|3050|8386|11853|14795|16049|14880|11163|20931|11462|15227||16234|17925|2899||2691|21149|14987|19238|15923|16191|12344|2821||6389|8418|22021|2320||4297|4693|12988||9058|17495|16642|22276|12855|12773|8382|12786|14310|6285|5541|4417|11420|18060|15706|20200|15711|6976|13481||19069|21361|13861|15770|16449||||14919||14884|7784|11862|10706|3215||12538|7601|13499|11210||4117|5088|14223|19228|17973||12910||18799|14186|9802|12484|18820|6468||16202|11509|7517|7561|11493|7411|3192|10671|7277|10428|4741|5479|8433|7990|20643|18072|7500|20861||16043|15962|6329|16736|16231|13829|6520|20445||7041|7565|||15206|15893|18779|5858|15224||1766||6404|14125|4015|9797|12943|9267|10275|14164|3958|16514|10922|4888|16079|17403|13246|4177|3543|4354|9235|15109|6821|5671|5075|6264|6261|6093|9352|15320|5189|4465|6469|8879|6628|15257|6853|19350|4586|11779|9178|14501|12966|15164|12787|9234|13198|15186|20970|8724|6268|10983|8636||8877|18694|22204|4854||22369|10941|11333|13280|4034|10030||7497|6236|15896|13944|6277|11019|16549|6248|11688|18339||17437|5412|5622||11090|7738||21275|19946|7609||14791|11937|17016|17242|16515|15415|4480|5232|17837|10813|6604|8265||9401|5739|19321|17576|11151|14689|7811|13378|19553||5450|14205|10961||8294|19390|7834|7958|11686||18442|6392|8459|6308|5217|5079|15095|5964|9158|6449||6378|8750|20003||16982|5602|10126|7405|14200|4331|8283|2603|5331||17298|9078|7796|22740||8389||10041|10838|12717|8821|11364|13339|21063||11035|19108|17514|10943|16950|5066|11190|9745|20503|||||8236|18351||15267|14682|16384||16003|15425|12062|15698|9705|12336||15290|22415||16452||21189|5839|11856|3691|17949|4759|12972|2264||17889||10901|5630|9209||8962|21328|5549|8312|4531||21883|5249||8262|11905|19755|14357|6574|11529|18264|18509|17065|18026|8374|7686|6794||||3514|16731|15792|16152|14645||21821|19465|16706||15909|14246|5586||9220|13982|14955|2556|6381|19713||5792|14853|12039|12217|10232|13554|9905|13120|8514|13868|15291|11286|9923|5493|12007|16440||9769|5220|11935|12294|6040|7650|14700|12439|16490||13356|20019||||15604|9047|9635|21620|||11231|14276|6379|10766|7347|7953|16232|8770|6403|9509|5065|6159|6522|5484|5322|7010||4348|16339|14763|16714|||21040|15916|17199|70|9869||17784|17902|6517|18216|3154|22199|16163|13624|19414|5768|||||||12122|3486|13020||13897|10312|10729|20555|11703|7615|4068|11403|12327|15306|5729|20695|18355|20033|3134|7636|12782|4173|11272|12842||13903|16175|9775|18416|11798|8152||11762||||14151|15169|11559|5528|5611|5173|7947||12928|13214|7325|11034|9875|12481|16716|13962|10329||5921|9734||19969|9224|11835|5771|8140|11857||16916|8467|6465|11868|15537|18750|12894|7202|19171|19388|21949|||9344|9675|10632|22802|17636|18919|2478|7502|5899|6572|7759|11026|11446|8427|7998|20700|2251|2933|3800|8153|8862|23250|13336|7896|18406|13436||15677|||8201|18732|13527|19772|5802|19001|17872|10896|11118|14460|14750|20188||5225|17553|18237||11866|5533|10424|13090||9289|13801|8525|19916||7065|17568||8517|13123|9943|14803||13522||16481|9042|9038|18612|10303|16244|3262|4699|20223|17848|7381||4714||10338|4404|16812|15508|10559|9701|10606||3343|15764|18274|5588||5735|12614||8736||||22848|13146||||10023|11804|12700|12543|15088|5110|9831|15526|10072|14220||14250|17746|12273|6662|12258|10337|3451|5483|9637||14921|||14737|21913|6933||14353|14495|14503|10593|10774|7284|4930|3728|13398|11453|15157|15006||5881|9413||11049|12724|||4280|9166||12540|15005||3087|7234|4213|6301|11941|22909|18414|||7562|8998|8860|6296|7195|10463|12916|9136|12727|6111||13856|4552|12701|11208|10446||10830|15542|8912|11198|5662|6231|4833|20172|9312|10499|10284||5174|5247|6852|11475|7980|7747|21211|19592||11145|7425|8183|8050|8699|15139|4344|19445|12068||16417|3480|5407|7960|5467|14208|18449|||5279||9531|4326|10475|16327|9628|11173||14231|9187|||4633|3704|6523|17906||10031|18143|11078|16640||15992|6356|5791|6436||19156||8904|6791|12214||5141|4742|12486|9688|5643|14249|15485|16469|13795|8206|6972|4659||4268|9142|4528|9971|14527|12434|15996|17155|||16116|5554|15083|5067|2537|4846|5883|12095|11938|2800|10942|13763|17756|||3680|15628|9040|4358|3872|4669|5542|4159|5052|13228|10814||8759|7691|16576|9056||10025|14813|7072|11487|4982|17879|12478|13041||11182|15238|11870|16131|13304||20689|||6969|13297|14213|6004|16444|10279|10227|9855|16427|12823|12290|15632|9790|14419||11940|14176||10763|3897|10685|11651|20212|||4945|10613|11444|10334|10731|7551|3619|19193|21738||6131|10938|4966|10277|12525|14540|12410|12575|5093|7726|17666|10568|7816|10477||8508|14035|19905|8852|14117||8830|19039||7440|8605|5503|11865|15480|16390|||5212|2305|3785|5593|17425|15258|6442|13334|4459|15318|16176|17612|11494|9843|13745|10986||||5687||15530|6036|5667|6223|7647|5512|17243|17427|10954|7537|7671|5325|8380|10631|14860||4660|6281|10386|8925|13863|18347|21434|8824|10239|8701||4542|12376||6228|18855|13985|6779|12557|10253|16860|11174||8703|6722|5087||7616|12849||12806|9016|10839|13655|10644|9953|15929|9646|11500|10271|5513||10980|11211|12629|9348||10687|11558|3929|4597|2824|12649||8089||11360|12918|17044|5346|5175|6897|15328|5578|3731|7382|4881|10063|8155|3930||11780|8983|9703|7988|4275|5608|5176|9798|4834|6591|5773||15741||17963|6565|9974|4359||18845|14416|13346|6778|8738|10554|18524|8791|20148|11574||17416|20525||18624|14759|10497|12652|10740|3856|13088|11510|15539|5506|||17503|19857|13172||||14535|18097||7586|15747|7319|15097|||7934||11833|9947|15997|||12834||11133||||||71||12908|2023|||14462|11001|13249|13662|8365|10590|12996|2694|18365|11949|8896|20357|16285|14519|9316|12430|17328|9730|14840||8574|20444|18995|15030|18112|5682|14264|9548|18868|8831||16262|7428|17168|19211|16437|13835|14272|13238|17045|6674|11849|8961|5664|22860|8587|14855|9121||6535|6137|7324|6754|8188|7504|16127|12760|7523|18996||5145|8074||8450|13843|8522|16788|3189|4634|5498|13250|15519|||10785||16447|7326|5908|4580|15787|17441|10280|18464|5926|20549|20166|7715|10902|6037|15072|16651|3965|4610|9906|5136|14046||16374|12191|14528|6292|11564|3628|5061|4328|5341|13581|5354|8816|10674|7206|16597||11591|5779|10709||4921||6764|9690|10299|7396|9472|9695|3913|8633|4879|3246|13158|5717|3171|5213|21086|18432|20187||9442|5990||8326|3544|22328|17943|13266|22675|15958|4053|3588|16407|8034|11454|2659|17967|3817|4154|8874||9528|14802|14039|13323||11482|7073|17004|12847|15283|5524|72|14562|10512|6331|16338|8787|4726|14845|12060|8926|6556|12765||9449|12457|12944|12810|13417|13411|16841|8222|10390|9260|10714|7999|3593|16343|14294|9363|5916|5001|14706|19090|6740|14340|12936|10636|13793||10037|4071|20207|9091|13282|10510||12455|6351|||13373|11919||16579|12882|15217|12172|11463|5869|13167|5885|11913|||16781|6480|11367|||5080|12817|10379|8778|8580|14686|23179|17910|9747|14924|14439|8302|17122||13427|19135|11394|7822|3388|||4048|18502|22400|6079|7773|21521|||9720||4548|11677|12279|5922|11121|8138|7104|12149|16839||12382|4090|17343|14040|12713|8332|10324|2965|||13019|19544|16964|6466|18914|15760|8583||||17444|7422|6323|11041|6878||9982|5872|||11620||10957|||13857|19562|10575|8700|6411|7814|5181|5372|4360|2306|8655|23435||16113|21839||17797|16850|18894|18084|17499|19433||19472|3494|7534|17651|10168|10790|17225|15424|20047|6669|4666|6941|2822|7838|19497|4776|12383|11431|13880|14415|||4187|10174|7571|13949|18606|13168|21999|14877|18658||9226|18466|8511|3658|16656|8331|6509|3590|11831|10053|14098|15674|15938|11670|18209|16155|14675||18270|7430|7443|10755|10380|2653|17634|16044|14734|17989|20473|2442|16018|6068|17604|19072|19634|15312|18171||9470|||8455|5463|4901|8737|6224|13195|15851|17090|23274||10447|15201|10920|||18692||18602|4457|17652|15859|4253|9266|14668|7201|15756||||7540|15019||11380|6761|11405|16912|6072|7898|18336||19802|9761|20387|16889|7465|19956|16485|||2284|11387|7408|9752|5677|11471|14660|14767|17744|17573|11374|15924|6694|2655|73|2156|20355|12119|13444|14359|13518|18124|9188|15697|2186|8135|19451|5712||||17857|15876||6265|11077|19473|15836|7043|5827||8483||13971|10417||13945|14346|11513|12404|6515|18181|16287|17230|15918|3160|14834|74|11803|2901|3242|4611||13608|13182|11291|8764|2638|5644|3354||11154|5132|20942|3459|5424|6338|8442|1921|2163|2424|2717||||16756|13353|9931|10913|17178|3129|2875|2944|3579|7355|7859|||||3062|3411||3612||14405|18285|13502|8801|2366|1655|6194|||11158|9732|8492|10086||9491|15594|9017|7253|4636|7055|6189||19352|21788|6765|6506|12884|14343|19181|13087|4391|9057|3369|8174|3116|75||2664|3970|2913||10142|15869|10775|2341||8420|15442|13648|9361|4689|15125|8549||5328|18625|9399|12143|10404|15932|15070||17549|11684|4246||||8099|19770|10055|21134|9240|12794|10118|4440|8913||7293||11492|16266||||13380|8766|15649|7886||8208|15241|2375|8940|5243||4667|8306|4754|8679|4847|6803|3959|9041|2317|5183|15360|15951||6800|6544|7285|16209|9190|9904|6005|5904|9709|5499|5984|8550|8410|14680|12426|4796|20084|15665|5485|8042|10197|11381|4743|9613|7657|16644|18690|15064|7824|17629||6174|18071||||9777|13464|14951|16516||4906|4000|11280|16498|18768|17326|6375|10647|5517|7074|5774|14377|||12789|||1797|5312|17691|19720|20000||18128|5736|9201|6886|11906|8528|14822|13312|22026|2954||5022|13337|18720|15908|5865|5013|6806|3341|16887|17239|15311|5905|9073|||17541|15636|13678||12016|16621|9473|18096|12587|19569|10285|14905|7081|7330|17635|12954|13720|15507|6220|7677|7255|6276||12069||15676|15429|14489|19717|10236||||8788|13564|16679|13308|4500|4986|6401|6259|9004|9402|22812||15329|21842|10603|10761|16432|7307|8317|15202|4628|||8957|3504||16166|6560|6427|15322|16195|20587|11250|3047|5299|13174|5402|14911|9672|17825|9625|8197|12506|6879|13397|19458|15235|17693|20758|23219|9164|8927|4876|7352|8539|3372|16500|9376||4835|6608|13973|8697|3212|12500|10514|7668|9990|12667|10158|21973|17333|7873|8675|11704|15534|17373|7937||16470|13044|21027|14085|13050|13347|11543|7193|12328||14820|11478||8044|16486|9137|8375||11003|6548|19601|5111||10801||7755|5579|3624|4613|16939|16098|15280|7578|10867|6532|14653|14319|3721|9593|11895|13479|6606|7769|2729|5441|17083|18439|15228|16560|5343|10101|15783|13324|7952|12337|19745||4169|13910|8056|14881|7378|6924|19372|17711|7737|10024|20131|11817|5743|11546|6645|9887|11640|5910|6018|3776|5030|5781|13740|10931|13140|5063|15795|11560|3234|7295|18714|||17496||76|6368|7338|12841|8246|6925||4038|17477|11169|15915|8019|13368|8994||7501||7739|8327|7135|6125|6306|5716|4105|7805|6849|8307|3161|10662||7727|5763|6831|12661|9225|8401|17170|7100|8631||9168|7679|11017|5490|10115|3235|22528|6840|16096|7353|4941|10710|9589|7941|8404|8623|7817|14859|12139|||||4933|||20615|12444|9327|9725|9317|8207|9516|9032|4399|20428|8953|17172|22230|13563|10669|8536|9416|10515|6414|2529|3498|4135|19269|8986|17480|5280|5015|21977|3921|6756|2922|3300|15416||||||||6676|11355|10192|10136|12534|10266|10824|10409|12501|13209|14007|16196|13825|2472|4329|17771|5373|17035|11795|10344|16553|15378|14128|2801|15332|9934|9864|8291|15881|11202||8223|13773|3239|10907|9075|14909|8796|||10658|11659|18259|12278|14378|11410|9070||16653|14938||10523|18797||||8516|15265|15260|13851|12261|16283|19653||6206|13206|14140|7547|14084|9633|8825|16386|10076|8347|16144|17679||13194|4419|13519|22116|17944|21769|15047|||8145|5400|9941|1749|18870|11458|9514|13912|13714|16843|8834|9985|4133|13755|19758||20558|||8838|11196|8241|19809|4978|4428||3986|15976|4675|3172|6891|13342|13269|9717|13400|9358||||||16401|11052|12089|6946|10319|22346|11605|21139|13807|22392|18568|18825|9614|18685|8572|||19317|||12242|77|||7618|19407|5618||7563|15304|5819|4885|6868|15825|7237|16534|8165|||9545|12240|4339|4049|14605|17469|20582|11421|||||10767|8691||17473|18991|6393|22785|10396|6385||13403||14293|14883|16910|4831|6932|9395||12238||6737||6655|19756|2430||2321|9653|10680|7229|6850|11829|13433|16505|6994|8491|14366|11869|23291|14432||4290|17964|18702|17567|9803|7387|5149|2764|3487|6490|8175|8269|18141|5721|8848|2507||7267||5090||10179|19500|1834|3899||13532|8565|8052|9850||19232|23045|10466|12073|6785|16865|8734|2829|7024|7798||15448|5457|15514|4444|5965|17905|16885|7388|7698|4318|20167|9122|9211|21074|8396|8084|2832|6482|6065|6394|12142|6009|21429|9882|4639|10112|12398|7189|4262|7699|7525|||11884|||14849|16170|11213|3877|13633||7819|17843|7753|3507|8368|20663|12494|3599|7558|21901||6367|7872|12644|12865|7401|9766|13350|14302|9318|5056|14502|12553|9507|5919|9676|3146|5335|11220|2645||6701|4473||10408||11468|7419|17338|17550|5753|16577|5813||14388|5414|11961|13620|13185|10258||10244|15883||8161|4535|15796|6914|16216||3247|11413|10490|16667|||||22583||11184|11082|10728|11622|9968|4300|4545|5906|9437|12869|2384||5148|10453|16372||10104|13102|8681||13298|15637|7198|8101|3931|||10159|8869|||17990||17914||7623|5028|7874|19413|7718|10188|6649|14549|8328|3206||17220|8408|10865|12165||||15953|13076|15281||8501|14424|6567|5646|6038|5425|7358|12226|18506|8209||8469|4602|4178|1849|2436|19417|11365|10078|8503|2403|9001||3379|6708|3276|4671|7607||7329|21988|5072|5882|8289||16146|7632|9409|12368|6477|6076|10263|6175|14856|21630|21897|21668|14893|5969|7972|3669|12493|10665|10435|17958|9033|11120||6995|4899|15612|4573|10056|14475||17158|22588||9541|6169|3334|10020|2982|6486|17915|5790|2539|12322|4707|11356|15585|4186||8054|11401|5509|15522|17980|17112|8202|6260|20005|4407|7012|9150|8581|11824||18865|6977|3745|9726|||9788|18822|15511||||15947|16255||7758|11598|8519|8090|19029|19892|13105|13340|18983||6396|5806||14360|18379|5987|13081|15762|11247|14526|15678|15982|11885|16075|4708|11302||12860|23378||||8268|7554|2681|3373||6768|4927|3784||12193|3263|15020|16066|6988|5430|8398|6695|3750|3873|12424||13002|78|12131|12604|7630|5985|||17142|11307|19158|14187|12588|5123|2992|10001|||||6744|12459||19623|6580|8585|6066|13108|3097|13754||7136||10759|6864|16895|7079|5306|3909|9353|3463|8477|9359|9871|11816|10683|10955|11214|10328||14997|13242|16488|14073|8950|20306|3460|4490|4476|15781|13859|2303|||12359|6443|14020|12508|15592|13534|4760|11279|||||8978|17056|4596|13839|6663|5577|9171|4080|6498|14427|9076|2376|9414|15739|10837|3595|15233|10628|6048|7393|5603|||10776|12035|||17297|13996|9217|||||5725|7289|9813|7227|6970|4808|||||18376||2815|17614||11375|11276||10595|16853|8617|17791|12422|8890|14274|21818|10422|13600|9207|9878|11095|11842|11180|6983|20738|20621||21018||16474|9019|11572|17212|11680|11969|13584|||10974|16459|7651|4781|18369|11976|11229|12833|7645|11425|||18775|5055|8895|9894|5782|14638|11336|4421|2210||11192||5874|6534|6168|15904|13091|8385|9932||12374|6339|11535|12012||5374||3853|||10087|15725|5018|4155|2736|13270|7450|14235|9710|6613||10930||16780|9714|15709|11335|8083|8647|9330|14090|4127|16963|18839|15512|13066|10770||5861|79|9339|13476|10522|8031|15464|16182|20232|4857|13477|16995|15193|12342|10109|7879|8889|19773|||7538||8111|5547|16636||12777|9484|9980|12872||10778|14025|13933|4770|14266|18937|9111|12075|10255|7223|18392|20377|15200|9251|12747|17088|14190|12209|7339|5070||8437||15096|11297|10640|21629|17134|18763|6623||7469|12454|4263|4679|12262|14362||4587|9762|12252|6123|16404|8641|15973|9438|9427|19716|23405|16109|11102|17504|8573|7435|5832|13083|19322|13686||18479|10620|14547|21367|7365|4790|9102|15449|14494||18178|9829|16013|14629||8593|19836|3700|6415|3692|5909||13927|17183|4309|11128|6221|10912|4556|9824|9609|22324|||13782|21152|9835|23022||9212||7940|||9411|14742||16071|10310|6610|17611|19131|12312|10765|7983|17590|4247|20215|4777|6203|9678||||12396|4589|3107|14954|15576|7464|7021|12723||8865|13142||8076|18145|16818|10123|8526||15055|8146|9099|14347|10102|12564||11308|11404|4703|13774|3440|7812|13359|12965|13849||22015|12636|13764|19925||10932||17382|12304|9918||19030|5362|10627|7027|13592|8727|4430|18782|13816|5689|3689||6721|8438|10735|16882|6583|4704||16291|10392|8178|9467|9649|11080|11501|11886|14946|19694|16914||8318|13365|16326|16274|5731|3209|9011|6529|3940|8151|6512|10441|10216|10958|11185|11951|15347|6293|19926|3561||15446|13713|15580||12363|16720|19296||11262|13441|16965|9927|15098|13799||9639|||6617|13133||15681|12105|4826|11284|15493|19496|12138|15870|17115|18349|16778|19428|10500|9706|12521|7899|18715|15045|5793|7459|3630|14101|11701|8000|20379|7369||17525|12608|12689|9542|10182|14434|6162|21285|10772|||14818|11104|7793|5745|6252|5258|8602|7383|||13677|7273||3894|5515|14630|11359|13776|15968||7178|10133|8657|10831|3751|4100|11924|3182|6207|2456|9758|18267|16923|6814|12106|15984|10219|12184|15900|||||11968|7060|10359|9524|4069|14895|5543|8316|18630|8540|13844|6550|19126|14866||||||11366|11594|14054|18712|9065|15441|15194|4323|11274||5894|7569|5741|6113|15333|2852|12010|12889|16669|19312|9172|18968|6070|8063|16732||7530|4805|12117|7248|9907|15948|17681|15145|7828|21507|12022|5755|7028|9268|5451|8613|11440|16673|21112|21121|7129|8471|10812|18990|12458|7470|10535|15179|6475|2672|3051|7984|2711|8120||7580|12471|6742|13689|6975|4571|11728|7635|5609|10353|8085|12731|9890|18234|5961|||||5573|5968|10180|9538|16535|8743|11110|7603|16792|15623|1452|6818|15065|3863|10743|13813|20165|7506|8845|5375|13406|9590|9313|17163|11437||2554|5886|12477|9801|7985|3108|3586|12577|17119|2802|8413|11277|13836|6974|12981||16791|17426|11587|6696|||20762|11320|10911|16021|7320|6510|14122|14956|15136|12913|15601|15980||10795|15482|9221|8233|1632|13419|||11309|11791|19311|11324|6792|7493|16179|5472|4793|13121|15894|||9236||10725||9131|10449|14694|8649|||13516|10645|12223||||9800|11939|15004|80|17421|19134|19539|15586|||10317|6559||||7261|5256||3336|14493||20307|||9465|6940|15950||7165|13869|5823|13828|10384|4474|9883|5976|11695|9515||3638|9815|14687|13415|8095||5480|12710|7649|8898|13084|12861|18189|12420|12583|12080|6319|22307|18700|14214|4277||7849|12818|21877|6996|17811|12801|11639|13162|16140|2547|12245|||19049|13039|9819|9913|12714|6002|16782|9071|14882|6815|10531|11316|3982|2427|3077|3128|3580|2834|4019|3193|7568|9692|20050|4375|20267||10223|13617|10821|9713|||8372|8668||5007|||15118|7154|7208|5675|7287|10609|12351|6718|16586|13256||8464||7264|11932|5599|4747|4762|4412|8935|4022|6459|18102|8399|11747|8600|8353|11722||12185|10261|||9255|8664|13818|13531|13898|11093|21754|13463|6456|6412|7196|16944|15478|10810|15177|16150|9018|3439|7089|5632|4072|6919||5109|9724|13335||5776|10747|16870|5036|20116|10094|3518|9604|15050|9400|6527|5195|9160|8946|13387|6679||11434|8378|10946|17139|17482|6501|7825|13578|||11851|5128|19788|9525|7003|16154|14681|5655|10437|15849|||15277|8837|5574|8891|9051|6484|6834|21089|||21619||2925|6342||5518|8624|3925|7230|5034|11328|15061|6883|17013|8240|13536|||11618|3868|20520|13055|3966|3471||6805|13059|8792|4027|16067|19326|2670|15847|11422|14730|12087|3088||3683|11796|10032|6865|6882|14079|13558|6650|||5333|4902|11044|7275|5289|17007|14676||14801|6054|14426|2920|6866||7439|10509|4820||7915|9048|7777|5653|11808|11438|||21888|11511|6857|6500|2352|2037|19824|4891|3200|4737|11240|11731|11455|4637|15276|8348|7644|5951||9336|4942|14969|3406||11933||9935|13181||||16035|17457|18970||9557||7951|6787|7678|8553|11426||16036|15463||7774|10638|3834|5487|4564|16690|||||3666|4761|10624|5240|||||6562|11760|7600|11959|10069|4196|4922|18603|15812||13279|12183|16943|12569|15119|8669|3943|13988|5777|5572|6022|4705||7057|2085|12898|6584|6819|8216|3319|10739|6135|15363|8493|7688|14267|12606|7164|3827|15598|13184|18949|14815|11589|13723||14280|18310||3794|2612|6007|3322|7146|4575||4823|11248|6557||6887|4234|10410|5002|14984|13696||12175|11585||8059|16795|14558|9686||2816|3831||22338|5610|9261|17273|7791|19535|3849|5127|12301||||15166||||||||4557|3444|4226|6712||8116|10054|9569|13815|9415|9611|4789|3995|14648|17364||9457|10278|2905|4031|8123|19793|12219|14657|10398|13212|12874||10833|6698|15599|5514|4028|4096|6561|9466|7213|10884|12113|9053||20174||10807|8826||5619|13057|12405|9643|5799|7179|6935||8672|2740|14095|4973|4892|16267|12387|6321|12006|4886|12653|4928|5159|8234|11775|10249|17643|18897|21181|5494|9116|13421|8544|5679|19841|8996|4721||10748|7498|12964|17068|7905||15974|6266|3832|3722|4070|4283|4656|12946|6894|7018|4840|17121|5658|15597|13258||17593|4383|11706|15386|2233|11977|15456|8434|5746|3858|8916|4235|9043|11570|16034|10762|19501|17675|3914|7452|12378|6213|7829|4101|6668|12507|13216|10051|10046|10751||7362|8677|5529|6684|16157|||||9612|17085||17638|13580|15468|20741|9169|8179||12795|5355|13302|12648|6026|6798|13267|7542|10071|7528|5261||10936|7426|13991|18695|12233|7543||5071|8182|3933|7061|13523|14308|3768||8832|7654|19893|8167|6795|10749|||18885|4131|5967|13663|9430|5696|10571|10914||3045|4804|8198|5262|||7922|2240|3968|7278||5222|||||6190|9282|2165|8918|5866|13614|6382|16602|15092|13384|||6440|12399||18366||7890|3663|7965|10538|5808|5376|||11058|10145|12619|12094|12622|7748|15841|10773|5164|6030|17415|10444|19494|4799|8818|6188|11813|3311|16713|5308|10501||||13733||14324|4170||7943|14850|13293|8619|||15011||15337|||17845||3971|8744|2981|3505|20154|12146|14198|10675|17051|||||3011|19223|13647|12204|4215|12904|8096|14782|13137|12845|14756|10004||||16552||18633|12349|7308|9954|4483|18275|6949|3801|18214|14790|||4498|6132|14977|12681|21094|4086|7316|||5311|11063|11672|10445|8802|8428||11329|9390|||15577||8632|12761|5560|7062|7240||||||11658||2395|7681|9229||6487||7441|8272|18200|2569|5569|4468|5208||||12791|15021||||11812|13513|15895|14336||3016|15027|21179|||2415||9378|11159|8775|13318|3676||12265|8102|8513|11201|3150|11861|1791|2921|11746||7017|4644|17586|10360||14497|3302|2643|19935|2767|7750|9441|9929|6951||11797|8506|3396|18918|10898|6869|9410|6689|81||9820|||17951|12445||4643|6298|15031|5344|2112|15907||16573|||12446|10120|13770|8014|||||9294|18957|12555|6614|12707|7166|5361|10797|9543|5152|3416|5388|4727|6962|10402|7840|11615|2466|5113|3756|2147||10058|8760|3286|2015||4103|3864|6043|17524|7385|5796|12529|14773|2565|14862|6807|8494||||||10121|||14072|2440|4191|2408|9451|9599|2688|2626|7608|16142|12997||18005|3380|8654|17009||11304|16618||15584|13767|13683|13604|18198|12084|21409|9049||6363|2751|3615|3686|7109|6173|3464|10162|21906||17628||4259|7290|5954|5767|8248|6707|7276|19347||17157|||12103||17997|12532|12215|9284|13006||10758|9338|2651|4673|9816||||3625|2407|3828|||5764|13454|10697|18331|||4248|5051|11225|9622|14794|2968|11664|10502|3469|7807|11683|15382|9036||8166||4147|4550|3738|2416|10518|1681|4931|4697|8218|14998|10576|13483|3236|4324|4007|2835|||16628|4322|5931|13110|17558|11840|12386|2276|9385|7648|3046|12582|2570||6871|7887|11707|5956|13623||15945|7247|3307|7456|2045|7447|9872||12780|9827||14738||16918|12409|13240|14420|2140|1802|1785|2277|2129|4614|4160|1658||6117|3009|4997|14912|14367|23137||19456|3032|4460|4785||13404|2540|12433|7007|3195|16284|8310|6395|5408|8956|13043||9110|20107|9522||2705|3255|12024|2215|9891||4642|3606|3168|11810|12216|11206|||14273|13244|1803|3777|4984|5879|3473|3312|13559|15356|2876||3880|3948|8297|14269|13011|3082|3989|2170|4087|82|2986|12497|9770|2771|2107|2557|8984|18399|5830|12613|11571|9644|7742|10286|7238||5329||10948||4467|2765|13094|18565|3888|16161|3690|1575|21154|4192|13060|9679||14114||1195|||9419|9619|||2718|20987|5581||7348|||||7619|10326|11396||7168|2299|10756|13155|8468|14156|13077||5365|11580|2730|2486|1511|7850||2431|2997|6262|2827|11088|3441||16973|16009|2987|3796|10702|20493|9862|3042|2665||7101|2348||||5889|11655|15538|11811|6681|4970|10633|6771|11400|14286|9551||5708|10677||19659|2207|1782|1244|3991|1682|6373|3237|||2897|2451|2487|5244|1579||2669|2154|3308|3539|17708|17020|5104|13437|5836|10855|8589||3701|12291|12044|7094|11069||5648|7993|1747|8924|4683|7370|6493|3365|10061||9940|8560|7262||11027||3113|13251|17530|||8722|14177|14551||6359||2748|1762|2572|6576||16438||7250|2073|14417|2432||2193|3910|3537|5423|2360|8071|3072||4819|5301||10788|7466|||3633|9447||3251|4694|7581|9356|14053|9202||13164|15343|2035||9936|2698|2105|8771|3039|6015|2888|2517|5981|3301|4787|10905|3432|13252|7049|3955|8301|2353|2696|8293|11416|9067|19699|4425|10440||14137|8144||11952|9825||4590|6772|4895|19421|9901|6180|5309|3226|16491|12807|12576||17186|3883|3381|10605|11573|10308|6709|13385|14345|16672|16424|7013|1846|83||||4260|2910||||5665|1661|5196||5305|11788|10994||8333|1683|4081|1832|7431||2174|1583|7219|10881|15622|14481|3030|16288|2863|9054|5684||8735|7482||12081|14539|3789||2783|7785|12989|13865|10517|11608||11305|20627|6232|10555|17657|3654||14658|||||10474|12201|6295|8576|2489|6503|5081|3667|19470|3724|9662|7590|2294|5307|6799|19830|16869|1419||12535|18086|||8915|13068|16422||12702|9055||12642|16092||3328|11310||23201|||1669|7924|19669||16450|21096|15321|14411||19297|2702|1659|4384|10803|7268|17981|11043|9603|5955|3596|16685|13103|13007|13381|12194|8064|10209|20749|7161|8023||12863|2726|10916|7570|2843|84|11480||15668||3203|6312||16006|9072|2695|13834|6198|21137|11006|10166|21969|12974|18244|13205|10092|16169||||13826|11963||7050|20087|7157|10458|7356|15981||13688|6780|11980|7096|8267|4595|7682||1477|1969|10984|6444|11270|2022|2588|2598|20049|19170|||6769|||||||16307|9656|12019|7697|13442|7123|5551|15595|9844|||5167||5507|8041|3335|13309|7424|15254|17454|12437|5091|19349|6286|6239|3780|2828|3649|13636|16876|7471|5153|6160|10989|7735|17190|17432|4932|15822|14981|2936|1464|3438|1843|5137|2075|14897|8480||14674||||9360|4054||16501|6826|14064|5500|9151|11611|14026|4157|5595|17463|7221|11623|16069|5887||12041|3825|6640|8614|8756||21107|11209|16408||4011|7566||6725|5303|3976|9489|6101|4687|17216|18947|6445|12926|22719||4565|13028|2110|10637||10021|13508|10999|8260||11450|17623||15523|14283|17523|6181|19814|6577|13150|9601|10915|6164|5326|1656|3790|5023||18215|4836|6922|5347|5190|2496|8008|8109||21793|12058|13860|15704|14736|7708|5641|||13409|6253|12093|7112|6703|9886|5803|8466|14753|15805||3934|2388|2490|5409|8875|15249|5191|6170|5520|1991|2975|7760|1571|3240|6579|5704|11936||1638|1783|14138|6446|9810|12684|4125|4238|4889|||20299|7613|15175|||17928|7652||3386|18095|3629|16332|1580|1992|3249||4057|6489|7815|6240|5970|5521|8212|3179|2457|9301|||3752|4974|13724|6907|9068|12541|11002|4753|19959|12708|17758|5705||7416|3829|12330|6651|11577|7556|7259|2340|12275|||8133|7716|14124|12691||8239|5888|2400|2646||5971|7444|8686|7272|6157|8521|5809|12441||7478|3952|1739|14708|6601|4214|5155||12045||7518|8779||7167|4256|14731|17322|3293|5154||4288|16419|6631|11203|3791|5856|12655|1706|8936||3345|8032|3006|10635|8557|7030|8081|||5945|8960|22024|6360||4615|5442|13096|15053|9595|7445|22170|16851|8742|8270|10784|15721|17257|||15068|1176|7051|7199|7557|4269|2993|12246|7114|3808||6138|4118|4389|17154|12766|8416|5185|2731|17164|12978|10394|12097|6149|2994|||4231|7866|7417|3180|12778|3272||4864|17392||10311||16103||6352|8698|3183|5824|4837|3120|5927|4911|7124|9389|14444||5917|11245||10570|12646|6978|10481|7637||11181|2656||3788|6128|18052|1354|1337|3915|3546|||14891|18082|4342|4501|11992|11116|11656|9262|16489|13721||||13170|1201|6425|8687|3346|4017|4668|4661|5481|8020|12009||||19345|13946|10861|15552|9452|11871|3499|4821|17888|||9535|10163|8441|7883|15317|||4120|1677|1497|2790|9119|9277|7897|16600|13601|5266|6140|12026|3960|4451|2378|6827|||16544||5750|7942|3895|8376|3725|5134|8548|18423|13288|15933||17683|17018||7488||12269|17369|4855|9740|7713||3485|2508|2076|1630|2246|2620|2580|||10357|4715|9079|11792|4530|6963|6843|8217|15308|12993||11809|18381|11376|6607|14816|5546|12469|1098|7371|1257|6077|20590|3110|6588|14625||17219|12270|5702|9500|7505|12676|12603|9696|||11736||6873|11332|3522|6575|8021||6426|9156|11565|4201|16253||16065|17404||16556|17355|17894|8337|4434|7084|3281|2723|7605|12858|7336|2727|20108|4678|4581|3671||4950|4291|8885|15917|10906|3583|8870|10130|3718|8747|7799|3620|15154|4063|7978|11447|12425|7119||10385||9377|14022|18940|4768|4314|13078|8001|11228||8478|9314||17240|5962|3847|7535|12870|10062|7745|4362|4336|11170|||8030|9959|5652|5106|5221|4093|9008|14144||8482|12800||14609|3746|5053|||9305|5416|10879|4848|8851||1738|10070|5468|9126|6383|5860|12129|7460||7058||11036|7684|8065|3918|8397|7875|4918|10295|19656||6817|5366|11086|17224|4684|8451|5464|20500|8470|4413|||12610|10327|11679|5089|6904|3892|6518|3067|2249|1910|19845|10689|19051|20494|16233|7646|6593|16458|10378|11908||11689|11347|5229|14229|13263||1924|||6844|16591|9103|3549|||5037|8149|3347|6773||3889|1349|15396|18413|17554|7641|4499|17622||19275|10361|9840|2749|5604|9242|3647|5645|11887|15543|7066|7925||7722|6513|9372|13062|5901|16613|8993|18713|7281|14869|2806|4512|5825|||4197|||12168|2931|10672||8439|10264|6905|13542||7744|8934|9674|11551|11859|4058|2144|18867|16325|3351|3101|4121||4198|12032|14721|11028|11769|7903|2807|12483|14146|5742|13546||12671|5814|5567||8817|6536|10619|10206|7317|8798||7184|4890|13727|9227|6434||3512|7181|6114|11713|8322||8275|10493|7115|13211|8663|14370|3323|8861|6027|3363||||15366|11588|11634|15076|12128|4958|4992|17413||13065|18063|7701|10952|9596|18504||||9475|6633||14600|20391|6717|12140||85|8741|2549|16949|22788|8243|7763|15532|12452|7957|9127|5732|6407|17320|15824|3547|4722|8013|18384|||12571||7800|12911|6757|6234|6419|7703||7340||17014|4484||14260|12850|14203|23009|10107|8320|2773|14913|8682|9757||6665|6355|11777|13439|8225|||12792||||3279|9183|||14979|1520|13555|10856|13621||11978|13876|16646|13051|12432|3352||5020|3398|5281|2759|3243|10235|10719|2631|13157|1917|13107|6405|1611|4520|11260|9117|3865|3196||8538|2976|6954|5302|5336|6991|9417|13811|12358|5200|9216|12036|12126|6979|10553|13884|||11647|7509|8966|11660|9746||7436|14975||8809|13023||19823|15680||8051|9796|9715|3626|4010|3643|8582|5417|4939|10246|10213|4706|4779|5282|17913|5024|1960|6659|9848|5606|9597|8078|11100|12248|12498|10418|15466|4701|7926|6313|12401|9113|14872|5377|6908|5852||5615|5992|7321|2938|9140|14232|17487|15572|15722|7333||11846|7380|8820|17283|7696|9133|13219|1847|14970||12643|2283||4513|7474|13675|5078|14725|12745|9328|4310|9256|8888|7959|8363|11259|11191|6254|13716|10623|5794|8219||3283|8905||9962|9237||16652||7479||8423|19040|3520|2202|1725|||2889|||3818|2155|3027|2535|2315||8530|11156|14510|10722|8853|11542|10769|2939||11907|19153|5064|9791|4812|2934|21092|16020|16996||15379|14511|14111|9669|11964|16249|9252|18536|8479|8928|6828|8650|4988||14476|11232|8827|86|||10100|5488|2300|16582||17763|2825||9733|4210|4943|4316|3407|6646|5789|4576|6507||4695|4138|13042|3309|15285|11175|14945|10567|18987||7794|3553|14206|5283|2884|3881|4519||14373|11628||14607|7128|5160|4469|6152|12316|12692|10456||2088||||6661||||12339||4278|2190|8370|19127|2810|10397|2182|13886|5327|21138||||10700|5600|4944|4267|5505|11122|3696|5659|6214|8524|6229|5342|3529|6657|3357|8402|||14430|10596||13156|18185||10736|19341|||18519|9670|11197|2558|6010|5201|4600|8010|4012|4319|11264|16415|5257|9873|2668|6937|2734|3476|2230|5972|8634|7801|6820|5443|11103|10849|13618|15889|3252|9333|4680|16257|16884|11445|7269|16337|9052|20364||2448||5612|7004|6212|9173|9458|8357||14663|19377||11724|6898|6294|6139|17412||8129|5101|5209|7913||4225||3823|5840|3105|10846||11242||14556|3548|3781|16121||3228|3855|6357|13719|13524|9373|6502|12480|6343|5561|3770|3268|9858|11443|7795|2367|7019|11439|11236|3018|1642|16969|12793|2132||5637||11635|2077|14178|12121|3364|3519|12049|9098|6080|18851|18092|8683|14550|12753|11999|2217||12820|9981|3901|7077|7751|9924||10228|13320|3199|3273|7366|4751|1624|3280|11200|3597|10367|2776|17063|9925|20415|15669|12736|6855|18213|15268|18591|4139||7576|8621|8718||7437|17032|5367||18656|3201|3431||10088|17563|7131|17289||9499|6429||17793|5623|15444|7582|2895|10237|5902|10779|3640|5620|10010||||4865|15058|6115|5681|||9407|5977|7225|7909|3399|10698|7778|8334|2589|8886|7908|5589|2265|6647|9490|8645|11518|4993|3001||7203|8500|14748|13079|17893|10783|3111|2288||10820|4485|13806|11521|14762|8180|2497||11322|2566|13126|5636|4108|8184|13679|3949|6052|7756|15994||10976||5726|8204|9100|2735|8117|5913|10128|8037|4219|8710|5210|9374|2409|2298|3427|4209|15093||||6297|10370|3094|1941||4629|3010|12171|8591|17572|4791|6165|17930|7141|15844|11255|13976||19230|5011|4367|2003||14364||4619|8405|19638|9731||19328|12862|14582|3526|5226|8867|13904|9648|4728|||4183|4953|3214|5787|11934|4032|3207||2647|5117|5356|6197|4252|||3584||13693|6126||5138|8061|6788|11771|3677|3573|2445|4060||11105|7236|3433|12447|9181||1709||2534||5788|3693|13960|4514|4792|3500|11993|8349|7579|7105|7233|7885|19244|7863|14165|7529|15727|18596|5369|17221|22173|4013|13619||5291|5759|12417|16647|1228|8882|4507|4369|3734|12348|9748|11520|11772|14399|7694|19217|3574|2803|4800|5107|5530|5102|7412|6386|3069|15453|11217|7423|8448|5187|4094|4532|7577|16087|7674|7076||13259|||13894|7531|12686|6238|4934|3739|4772||10816|5938|6942|4109|6161|2006||4574||10610|2428|7536|9995|6073|4378|12210|3617||5177|2935|2389|6047||4442|7935|6912||6102||3747|2577|4166|5394|6420|5182|3229||||4400|4294|3258||5614||8850|||10260|12909|8295|3065|4858|2187|2628|10191|17313|8745|15284|17443||15428|9876|4261|3748|10335|7880|5875|6226|17166|9009|8411|3508|5616|16768|10189|4040|3496|16473|7967|2689|3972|7938|14184|5998|2784|16192||16594|13907|13848|15148|7282|5330|4801|4686|||3465|4132|4266|5786|14960|4379|6402|5118||7117||6832|1608|4143|1850|5410|9486|11296|9608|4716|11081|7379|13627|12515|7169|6200|2716|11972|5115|2254|1366|7914|8121|7397|4144|1671|6205|11160|15573|5114|5161|2188|4591|5668|3836|8446|7185|3919||2632|5440|3294|||2329|4470|9793|9946|3031|4649|5978||2038|10486|4874|4373|14457|11743||3742|1625|4298||1648|17252|3900|2285|15891|12004|13676|4784|11975|15885|9884|14256|11873|16820|14244|9496|11838|4073|8626|8024|12832|10267|8415|6108|12473|17832|5853|16643|3906|17598||12179||14389|4355|3697|5275|6127|4211|6094||6758|11370|4914|8330|12085|6514|22142||7130|||4998|21199||||3845|10823|8266|11029|4940|7162|13000||6749|13622|1856|8172|15353|6660|4437|7559|14326||9836|5548|||||2947|4445|4856||8364|3802|3740|4553|4670|3434|10634|6499|4907||13783|2871|6700|8156|4014|2443|8656|3902|9134|8112|17042|1734|11378|5892|8989|10848|3765|13351|10476|4765||5635||12490|7080|12824|19055|7342|17272|8546|2513|2760|3448|3204|2675|2697|3173|3230|16761|4748|2969|5448|8097|3816||4179|2483|7351|6358|10035|7976|1031||13625|5555|6098|2902|4954|8545|2509|2914|7359|9159|7740|12118|5851|12402|17171|10150||3564|1927|6760|11899||6762||4676|13778||1732||16496|7407|1088|5642|3145|1756|6984||6399|4082|8055|7492|5570|12930|1147|2567|3457||1613|7360|5459|10937|6237|2574||1713|11586|5738|87|7171|3012||3284|6738||2243|13735|||13296||||1417|4343|2036|20917|||14602|10990|2590|8027|4802|5413|2830|8793|4232|11765|1076|2988|13371|4284||5497||2658||15462|4045|2171|6587|4102|4376|9879|4955|8911|||4949||9476|11928|5251|10641|2594|10562||14735|14931||14739|16787|13789|17086|11234|17578|6973|7279|4024|6496|4405|4766|1633|2385|9386|18628|9634|7659||14069|2890|11256|10909|2446|12038|13430|15967|7809|3013|4977|10654|||1297||6176|3587|3033|11650|2016|1409|12296|6906|13376|14792|22952|6909|1425|3530|5727|5143|4712||5973||14329|2676|7455|10427|9296|13525|13405|8661|2194|2134|5895|||||12028|4946|2719|2191|2891|4691|3702|9615||3413|9915|1928|3662|5009|3449|10371|2336|15024|2844|10527|6858|5099|16639||8974|9450|||18154||12798|13456|10315|8406|12435|5473|1360|5158|2198||19985|20150|18734||13998|16188||6314|1383|4472|9132|1475|3095|6782|6201|15978|2818||5202||1769|10977|7963|10287||15113|20657|4749|7787|4786|4900|7808|7832|11273||10720|10597|3621|4851|9867|3366|1444|2203|2708|3466|9299|16212||||13661|15718|11547|3277|2267|14757|7188|4841|3912|1653|1993|2545|7490|4001|6046|4794|1227|5293|1851|1970||2368|5941|3445|6652|8296|4730|5389|||9735|5811||5259|20009|4008|3838||2484|9571|1173|15540|||13539|13010|9269|5129|4184|17455|5269|4244|3395|2853||10281|1874|7511|17054|2255|8652||18686|4410|3861|8190|2660|1994|3367|3130|5453|2157|3089|4332|8358|6166|6670|8794|8785|7035|4164|3762|1962|1350|2720|19734||6081|4149|1487|9591|9354|6345|6569|6822|20297|2840|2122|4122|9996||5722|3389|3430|8424|9446||9912|3631|9789|6755|8460|9664|2236|1270|9640||1719|5035|7192|3121|4270|2027|1524|1017|13758||||5058|17547|1589|5039|3450|8067|3890|2768|6859|7575|3313|4592|2613|3378|6049|13889|2793||5370|2419|9553|11705|7893|5188|5076|4441|2458|8786|14412|3729|7714|1820|7059|1479|10882|4220|2392|4755|10214||19833|13966|12852|6786|9997|12295|12114|13460|11916|9196||12550|5491|5982|3329|2860|5756|1786||6516|18725|3151||11979|3303|10757|8955||14089|6789|7311|4919|12285||7949|4734|3400|5042|4429|2930|1761|3713|12282|2510|1525|4827|9244|5654|3535|1678|3907|2797|1590|1869|5348|7194|4883|1465|2020|5223||8622|2420|4401|4710|2158|21350||4757|4887|8864|15082|11982|15450|8195|8900|3859|3254|15965|4994|7078|7122|7386|12091|3866||5121|6344|8797||1925|4387|5801||6719|7662|8489|4672|17021|1804|13104|1899|5008|3164||1518|3812|8854|1207|1995|2779|6639|1458|4731|7222|1770|1566|17144|17559|4650|2342|3860|4756|8354|12173|2244|3167||5974|3792||2393|5841|8901|6895|9460|3741||9998|9512|7902||7209|7187|11900|5559|7974||9939|2089||2872|4363|1863|4091|6330|6279|1069||12372|8292||2546|2097|11039|2654|16722||9022|5949|||3467||9957|10692||5957|7475|||3036|4456|1169|985|8119|3839|3641|4975|15778|13540|10077|6691|7467|6521|8229|17488||4767||5891|3070|8196|11382|7844|2302|3054|14105|7409|8110|4305|3184|2501|3324|3681|1956|11506|2000||4509|2661|3953|5678|4145|4709|3644|2136|2550|4824|2211|7270|4662|1990|19846|9723||3950|3190|4206|4462|4604|7729|11338|10193|4638|7706|4607|12611||4495|1139|15892|14772|20104|11287|10129|15921|15454|6720|3483|3157|7672|17596|3778||10247|12720|7318|4202|4989|8199|12590|9264|4869|7494|5272|14614|9232|18754|2777|5392|7845|6191|||3326|20169|12509|3275||1218|10649|5715|6218|12635||6533|3174||9379|||15666||1591||5358|||13576|4870|7835|4136|6398|5563|2671|12528|2018|10354|3668||9754|8452|10712|15413|12897|5094||||3678||18040||8527|4543|4487||4050|4813|4893|9063|3122|5663|4632|5669|4626|4979|6387|7512|3758|2046|10075|7719|8091|4486|8159|2864|10498|10268|3786|6103|2220|3769|3317|1914|18711|6124|10574|2502|6462||8842|1998|3264|2417|3421|4006|11456|3216|1324|5934|2007|1433|1469|1692|19545||3837|7560|2090|1619|1844|1598|1460|1142|2318|16151|3566|10862|2861|4925|5676|4239|3162|9771|6685|11582|7014|16655|3337|6136|5461|9010|7011|3743|2595|2396|4446|2485|1710|5040|2241|2616|3098|6307|4608|5352|6199|3339|3071|9161|1242|3709|4431|1229|13952|8629|4964|3684|1363|4349|11524|2915|2608|9287|6421||4539|3265|8345|3987|3650|4222|3754|2268|8588|11466||5245|8762||4061||6875|8561|1750|7867|20305||2772|2794|10650|2108|2386|5421|||4217||11377|2271|6133|2091|6202|5864|18905||5130|||3705|5942|3757|6153|4466|6735|12082|3797|6763|8251|10594|5178|5522|10462|10883|12020|3830|11981|10387||5728|4254|2903|2133||7457||||3185|21198|3550|2237|1996|4229|2728||5267||19325|6369|13883||2080|2515|9776||19626|7642|8425|9274|5292|4681|1418|1949|10160|5415|12040|15855|9387|11994|2050|1567|5633|8488|6280|2949|1963|1825|6302|3055|3884|2785|5381|18671|3370|4009|12912||4340|7125||10870|5332|2721|5419|7170|2955|4783|2950|1848||21415|19203||9570||12698||||10563|13701||13935|7461|5084|3607|||5426|16164|20301||8247|15549|942|11702|7133|7631|5988|8674|11752|7345|10808|10787|3759||||||10742|4406|5935|9984|2292|3969|1410|9573|11555|2978|6184|15023|4364|12963|5434|2280|7394|16430|1521|2374|2421|2313|1302|13257||6680||||17374|3941|8213|6088||||1100|4999|6100|2877|5624|2724||14028|||8776|||3418||1836|1606|2684|3656|10177|9749|4735|5815|3939|2169|1957|3944|10526||1501|673|2159|2808|3241|10212|3153|4567|4630||||4447|5804|2845|1259|2972|9471|4752|12102|4020|2086|3648|19076|2555|17531|5867|5634|5989||4867|7086|8902|5986|4245||5073|2141|9365||4620|3274|3706|4861|3401|10655|10181|18613|18321||10170|3922|18873|6274|5657|11161|2357|5820|16616|4546|15197|6211|5752|8435|4976|4718|4003|8169|16739||7929|11898||9504|10863|2599|7877||7002||5923|9371|16208||3698|3525||4555|3951|||2581|5502|5227|757|1695|946|2028|6258|7856|5260|4763|6621|5747|6751||10103|7643|4936|5557||9817|5235|2798|7752|5685|4276|9026|2596|1873|1792|1902|1542|7520|4295|4002|4161|1748|13413|||14195|2518|4026|10301|5019|5198||8414|1493|4616|1696|1204|6430|12306|4414|7068|8136|16703|13885|10959|4142|5884|5068|3501|8598|4059|4510|5359|1811|2622|1552|2495|8237|8280|15057|10860|2503|16743|1875|2068|5004|8191|12423|4016||10302|2804|6055|14796|3707|2418|2813|6530|3114|3299|6225|||2940||14980|2212|10117|3419|3492|14929|18305|12428|3123|4491|3295|3454|16362|4729|1961||1187|7868|||3809|6467|3137|4782|6082|3857|3325|10895|||892||8551|1576|3672|||11789|2687||3659|5031|10195|7692|7683||7728|7848|1181|4582|3147|4452||2272|8532|13556|2795|10614|2256|15758||2504|17066|6439|9682|5737|12674|7770|3559|6346|2924||1805|||||2208||12754|6609|2324|11770|4502|2391||2617|6541||7583|2522|3973|5748|5566|5932||16383|20238|2143|4083|4292|3447|13431|7244|10202|5044||4533||6549|6611|13798|12213|7346|6008|5582|4920|5647|2245|2841|3942|16758|15720|11388||4088|5928|2865|6050|2333|4568|4913|14480|3422|3227|3194|5142|21331|11739|13426|||14544|3956|762|1976|2175|3117|781|752|1778|1248|1455|9736|1439|1351|1837|2579|2662|10201|4983|16333|5516|2551|3673|3408|3310|3061||6289|8606||4960||11942||2137|3978|8350|13562|10873|11106|7628|9558|14041|9366|13067|9937|8789|16687|7415|11953|15331||1867|4560|6106|3961|5710|8264|5105|4251|5253|11010|9956|6353|9203|10248|3645|9253|3109|5271|2024|2666||1779|2087|8114|1284|4171|16472|6704|5690|6095|7042|5395|4797|9741|||4842|12641|8066|6006|4035|3314|1654|19054||2441|||3527|10005||1845|12155|2354|849||1688|1165|6997|1395|3220|788|925|4064|||1953||8981|||||15471|2511|4333|3954|1380|3424|8878|1616|6141|2943|2887||||1182|10565||1498||1764|6542|4496|1954|1964|2138|3974|2866|7833||4021|4937|||||14158|5826|10276|797|1926|12873|1592||4356|8453|12305|3523||3545|1414|4150|870||8919|9128||7025|7521|8995|9005|5849|1262|8780|4605|13616|1672|||5958|1330|1932||2878|9403|6255|4822|6634|3305|4657|4368|5025|1948|||4536|14247|12299||11363|6741|5525||14382|||6249|||6210|11602|13638|4651||7920|17466||7265|7767|7151|13847|17125|915|1647|||6825||2961|8134|1660|3099|1156|4980|17661|11896|5043|3477|4537|6915|9689||14768|13033||4578|19467|14197||10583|3285|13611||5538|6971|6629|4432|12380|11074|2012|2789|14222||||1411|1503|1929|1230|||4422|||7495|15920|6702|2862|12940|9436|5204|17799|||1287|1662|||17349|14488||3037|3565|2307|1431|1271|2908|4516|1420|1894|1320|14890|3197|3603|4282|8982|3078|3374|2356|8897|10540|9340||7451|4162||10750|2858|5276|7391|6011|3875||1838|1454|1930|3287|2663|7549|1495|2692|8990||6059|2563|15389|6219|7606|5495|6602|5242|9755|10190||||7869|9144|4711||5150|9391||3217|9950|2805|2677|9304|3819|4962|4325|6327|3779|4627|5454|2926|7332|2447|4077|14775||8325|855|9549||18269|7852|7053|6354||3554|9384|19523|2314|4272|6377|9839|4353|2648|2855|4327|4961|12247|11490||14130|7152|5474|7190|6743|6256|5230|3155|3814|5627|12980|7137|4036|5594|5527|5103|14943|6998|21288|6017|5605|14828|8976|8164|6267|6142|4110||6845|4585||5959|4193|5041|2709|2176|10134|1450|6107|1689|3992|5005|3025|17100|1331|2142|6774|1488||4051||11643|3026|5946|3560|4402|8836||2713|8883||2559||3278|11415||11143|||2995|7283|8035|5151||3355|5444|5097|6278|955|18385|10057|2989||6324|2167|1547|5246|4527|13922|2678||1265|16565||1009|8728|2043|10532|8040|4903|6044|7995|11617|9398|7771|4750|4443|12917|2394|12338|3515|3327||6889||1871|5446|10220|16585|6247||17118|4074|5353|5688|4394|14078|7932||1502|13565|12116||||21238|||3993|7350|3368|11119|11153|7709|9139|7212|8373|6896|6032|9230|7313|8256|10003||2682|3290|6537||4541|3052|6598|1900|4317|1905|2259||5146|1401|1196|2633|4065|7034|1720|9182|3766|4769|7172|3412|1559|4478|1407|2127||2404|1473|3988|6233|5469||6531|1723|1449|1939|3002||5085|1393||||2983|7156|3876||2113||7546||3218|5847|7056|9811|2605|4320||3348|8429|8977|8187|6417|4882|6370|10965|6944|4396||8242|6121|3503|4947|9106||5248|5252|4872|10358|4388|2514|11696|943|1180|7705|1355|15348|11330|12485|4908|2161|1554|14620|17346|2856|1821|5896|4119|4397|12017|1771|3826|4522|5337|3589|12005|5854|6483|13577|9162|3869|2541|17356|1536|3664|4696|4525|6641|9896|6118||4523|4646|9805|3528|3417|12373|5385|2817|5059||13572|7732|2183|3425|2523||8484|||4929|1315|1309|10825|2413|5436|928|1888|2970|||12111|5564|3330||5131|||||||6376||11997|6060|2124|4566|10407|2714|2757|1376|2618|2102|6797||2184|2957|11989|11778|4230|2746|2335|3186|4453|||2743|2780|3484|900|1978|1108|4255|14404|2349|1245|1402|2867|8253|||4503|2377|5807|7775|4549|6435|4631|5236|||1125|2242|1986|14118|2880|2542|2725|7923|6063|3511|3472|6528|3435|14192|5730||3604|4723|12354|2990|||5979|6485|1872|8618|2623|4623|5544|3736||9440|1183|823|1062|9087|1581|11126|4897|4167||2498|2536|4838||2079|2180|11946||8417|1852|11012|3282|4862|2053|12783|1490|3945|2130|1860|2573||4128|6945|5360|4645|4203|7788|948|8447||5870|||5300||18861||5691|||5296|||1887|14949||1118||1814|3414|6013|3896|1077|710|4337|5054|16828|4843|6884|5871|4427|11176|5304|3269||14982|12539|5638|18444|2928|||3773|2879|5719|7390|6478||13734|1549|2459||2979|1087||5617|5316|1084|6028||3516||3870|8757|7690|8819|4463|1253|2649|8704|14474|4204|4682|6019|3318|3181|12574|2831||1385|1353|1357|1162|1089||1370|12922||14552||9012|5046|10643|3059|10186|2065|5718|7660|8005|||10172|16742|12196|||12276|10017|12392|2474||959|4174||2074|1310|10199||3563|3014||8592|7870|2310|2571|3342|5797|||1199|1697||1133|5670||1531|5496|3066|3426||3983|2397|3867|13744|11537|4039|13881||19462|5914||14529|2195||18963|10806||625|1241||1278|4504|2179|1610|1249|1246|1247||7182||8290|5697|5238|3223|3760|4780|2673|953|1989|2481|4285||4438|3835|3833|3005|5550|1219||1334|5596|2160|3115|1057|3882||4732||8774|10971|1807|1981|2437|9568||9468|12775|932|4433|12715|7900|8541|2683|1965|2758|5628|5575|2199|1073|1126|6263|1702|1516|916|2062|7147|3053||3591|1159||9355||613|1048|1665|10161|1054|3699|3782|3028|1224|8987||3850|11168|7841|1085|3891|3043|3175|3458|2600|1903|4365|3248|6325|11864|12280|11917|9743|14017|12181|9431|9994|12133|3844|1269|2781|813|8304|17339||9364||3908|7087|3726|2218|2543|1704|1881|2308|4829|4844|3391|1459|791|1839|1026|1128|1373|1209|2482|1059|2564|3730|2008||2362|2885|3131||2316|7513|4488||1004|366|426|1673|1127|602|612|5552||6552|7617||1877|2117|4956|5033|8139|10283|10648|2379|954|1267|10419|1272|2530|3461|1855|1250|662|1434|8767|3090|7138|12725|7472|12237|1735|6241|3813|5711||7300|3975|4479|7723|4236||5920|4066|18482|4033|4963||8077|6989|11000|5082|7847|4216|10487|8937|4971|10951|1798|7573||3569|6739|4205|3350|2172|1858||2953|5092||9129|2627|6083|7823|1754|1895|9428||2309||3409|2382||4227|||14917|3385|2493|9930|1122|9205|1478|1876|||3340|1703|1601|7638|2227|||4746||5192|1560|6130|7733|2063|2216|6570|1829|9443||703|697|13029||774|||1052|4345|1090|664|3244|3015|3714|1707|2125|1235|1091|2231|893|1210||||1481|1153|1038||1374|2192|2345|962|8596|1494|8130|4492|12347|3428|10979|902||3083|6071|4237|4137|3148||4089|4351|903|2128|1789|610|7548|9367|7331|5338|1426|||11557|12046|3998|4717|5649|7757|2774|2552|12759||11469|2962|5317||15826|1285|||6551|501||4257|4884|3481|4078|1699|2221|1364|15582|1298|2103|6084|6727|9966|5427|2791|2881|4981|9080||584|493|982|5862|1001||10536|1979|4518|3040|1311|672|1667|2273||||3618|7085|1002|12735|4569|1010||5829|1236|1711|1922|1936|8751|3533|1046|1102|2228|4306|5323|1480|14973|1985|647|2189|1840|2123|2401|3521|3848|2624|7789|10274|2715|5122|3581|2205|||8351|4612|5047|3135|3568|5523|2786|3296|3985|5584|1528|5983|5431|5698||14209|||907|1526|2410||1033|2811|8963|2745|3073|3387|2118|1972|2657|3096|4311|10622|2644|3084|6916|2911|9753|1853|3694|2951|1517|5760|19687|12811|14403||6953|10591||3920|3410|9665||7629|||4321|4859||16701|13553|13932|2017||1377|6856|744|17267|1889|2346|2948|10564|6959|2358|8421|963|597|1339|683|1060|2838|1639|11358||3044|2347|6390|5660|1532|4690|2260|4390|2488|5239|||6638|6014|9539|2634|3840|12123|2477|4380|4055|6408|2907|2873|4640|5287|2363|3452||4249|6793|||10184|5321|5707|13573|13712|9617|3132|2639||2609|2460|9405|15041|1911|1987|4366|8799|1109|5290||6892|7118|3598|1288|876|1562|2343|16546|3710|3540|1078|1214|1421|1857|1435|3453||8507|9292|5156|14010|||5401|4845|2060|1378|3541|2532||1461|1282|2586|4583|1901|6332|10323||6619|4866|10800|4029|4830|3297|6447|3979|965||||||||2337|681|1055|10850||894|1966|2185|1322|4482|5724|2058|10291|1258|1280|7288|8616|2874|4894|6637|1594|3916|7458|2679|3158|3719|4385|5911|5751|3753|7022||||2449|1886|2126|3202|2181|5010|8220|11613|2916|4677||19593|12522|3383|5531|6656|5437|||10660|8813|9165|7675|14692||952|4733||3138|4558|5250|10541|4315|8490|6196|4775|13183|16215|7214|2833||5029|6371|3298|5032||1980|1070||4370|2081|5816|3652||4832|3187|8162|4126|2882||3578|4047||2917|6715|4084|5545|2614||8635|3737||7363|21834|5580|5963|4538|1071|||1708|6243|9916|1483|1896|3727|4547||3655||1289|3003|1715|802|||1307|1507|1367||1645|1958|1568|4056|992|2700|7082|||674|868|3021|2942|1555|1556|1388||819|1040|1841|1584|972|3392|559|1394|6409|4736||1808||4515|7480|8552|2369|2061|2505|2640||9130|1585|9638|6380||3259|1234|8261|6235|863|12573|2531|998||1595|704||1306|5929|957|2119|798||14042|2753|1408|13739|1878|6893||2512|3149|5218|7367|10817|3600|6361|4738|7314|1185|5186||4439|9197|||6538|2257|2461|||||14350|5100|993|1056|3359|5199|944|9275|1700|||2868||16598||6349||721|3375|1428||4112|1649|2641|840|4664|||3256|9189|853|2524|||8457|7106|1967|4570|3946||6230|5534|5288|3253||9321||10395|6731|2553|11744||5125|5936||1406||7810|||2814|8777||4713||3999||7781|||12949|12212||5231|4123|17630|1447|2029|1800|5263|1912|2204|6144|4301|1757|5749|2281|7442|3695||7689|5048|7144|14576|7228|13639||1335|6413|1260|2383|1341|3260|3007|1286||1375|2952|||5215||1923|10085|2846|2278|||2960|6299||3555|5096|8939|6020|6056|1174|2752|2782|2812|2069|2166|8226|3188|3079|3231|614|975|4199|5270||11167||1620|829|4873|2433||6250|1942|1835|2494||11538|1212|1184||7496|8828|561|1596|10322|1379|2001|995|2289|1523|4181|2355|5650|1529|7997|1726|922|2904|1822||8379|12307||1744|10840|11295|9948|7343|4408|1463|4508|5403|4450|4561|8765|3068|3390||6372||11005|1442|2886|13748|4852||||3763|2331|1879|2769|1396||2213|1799||5848|7344|1880|3091|5139|2606|1134|2047|1440|958|1276|1745|2040|659|758|747|573|956|765|1029|1812|2148||3136|3996|3720|15733|10686|3962|4286|3820|11473||6666|7596|2044|4904|994|6096|2041|4674|13769|4165|8594|11757||7693|9536|3360|5863|3219|3687||7633|2224|1870|4097||4435|686|3488|3665|541|5924|947||1154||3361|977|2055|15531|||1018|754|735|1281|1772|2402|13598|3321|2918|3086|3935|2473|1787|2690|1215||919|1092||799||8426|1163|4398|3029|2450||||10530|3490|5228|5939|692|11984|1114|1263|675|1988|3774|4544|5435|2538|2854|6448|||3851|||1931|2200|2462||2390||1864|14534|1006||8046|1631|9039|1558|2066||909|||4240|6732|||7820|4067|4702|8274||3291|2525|10372|6823|1217|5877|2149|||4511|1686|8126|7257|3139|3250|3270|2248|2591|5458|11114||6842|13533|4896|5268|6422|2819|5393|5135|6899|949|2114|3513||639|2998|4098|3862|4551|3556|2252|7700|9926|3331|2325|3420|3605|2999|14115|3140|||||||||||||1384|||1135||2398|1674|1676|1593|12514|1290|4798|16074||2322||632|5761|1727|7702||4250|3557|5396|5077|3478|5390|11642|980|2958|5943||||1826|2820|3468|1489|||||||||||388||2520|8250|2583|1254|978|1299|1597|1801|1164|882||1101|15137|4593|1255|843|14348|3841|7624|3783|4774|3824|2463||3764|3923|3178|11212|5810||766|622|433|877|1079||4307|1626|4228|3124||4411|4606|3125|4079|3126|6305|5944|||1338|||14741|2287|13808||9246|||5818|3660|888|1806||2732||9177|651|1327|1793|6729||1157|844|2839|1827|1422||||1389|1643|1007|4828|88||1666|1399|2370|7204|3803|2650|3990|8043|5014|2560|4182|||2980|12510|5598||3156|3947|3056|5294||5873|3080|8016|4579|4025|2754|5074|11432|4371|9707||1170|3442|5680|1573|6023|1763|6888|3102|4448||11495|2712|||||3577|3551|||871|1997|3685||12934|4099|8069|4744|3245|1166|1386|7918||8676|2601||1705|17319|5535|16668|2071|10052|3534|1831|2145|2984|3653|2072||15944|9381||4052|11048||7052|7215|4243|851|1950|1940|3517|1774|6880|2722|3266|3288|3634||3885|1893|4652|3402|2963|3474|3210|3531|16298|3338||1432|1430|2582|2030|2344|1973|2364|6451|6089|15808|8200|||6920|1904|6519|4454|7876||1141|2115|10300||1403|1044|1504|3038|7865|4124|1152||2009|4995|904|10802|5452||1453|2422|5683|1344|556|1938|4357|||1740|1392|8713|6653|5233|988|736|650|607|10704||1600|1303|748|1467|648|1397|1106|3267|3063|933|1138|896|5558|6555|1663|3163|3646|2099|1233|1943|2319|6315|7328|2826|9697|2234|7741|1121|784|||1140|3491|477|4341||1123|1041|3075|3022|3008|1186|511|1623||1512|13459|1371|16823|9394|3332||1729|2837|6801|6045|3271|1974|1514|7134|2491||7309|1809|2414|720|2787|1080|1758||5692|745||||1865|513|2526|6986|864|1868||2253|7334|1119|1751|1064|1690|2311|3509|633||6057|5661|9492|4935|3100||2434|2229|2235|||4037||89|620|1491|4853|772|4168|989||5422|1543|562|3761||1316|1499|2135|1781||||2923|5475||1854||||5203|1237|929|2332|2755|2225|5486|3542|1095||9434|804|1132|6275|1190|3446|9382|2051|11545|1541|6450||1698|911|789|693|||5800|487|2423||2761|4313|2799|3911|3771|3232|2380|1110|1752|2275|1906|508|16051|2561|773|522||1332|434|1679|7555|1197|5162|335|2637|8394|746|||2387|2869|3679|5556|2674|2592||3601|1884|1111|90|2996|4264|539|523|1470|1042|830|2067|3936|2747|6476|2250|2912||2371|3233|4420||5411|2762|1474|3570|1533|2048||1983|||||858|1436|4665|4106|2025|1049|2479|9310|3133||||3567|2177|5672|4464|1063|||698|2196||845|2991|2032|934|1534|2146|3688|3502|6999|5000|6423|1955|2293|3558|4281|10488|4951||4409|5062||1387|8094|8341|2959|1014|||6692|10708|4287|3489|1609||2039|3106||3703|4188|9523|7150|3874|3023|3775|7574|1466|5310|||||6964|7418|10405|11414||5583||1239|594||9618|7067|4814|4163|1050|2295|1032|2929|2258|3886|2611|950|3456|6334||||13274|10886|755||488|8232|1158|712|1200|983|2506|1765|917|1456|2326|1563|1813|478|1815|3575|2052|1577|2262||8714|2629|3142|3903|||3639||2701|1742|2266|2635||814||1274|2290||3384|1225|3984|2956|9556|11037|4624|7337|2054|5948|898|1067||422||6192||820|3292|1136|4477|841|2372|6366|5006|6282|1220|1336|1202|1115|930|486|657|883|2412||4172|2312|1823|1767|1824|1650|1564|5216|3470|2014|2896|2809|6876||3980|4347|2083|2282|4392|878|2737|1784|2584||2153|3238|833||13607|3732|6992||695||1545|1264|1226|||981||2381|865|970|504||3755|5601|17830|1144|852|1513|3034|999|549|1328||3443|8547|1605||1794|4577|2327|2909||7410|2847|4023|731|2630|4562|3141|6851|2738|4114|2836|4521|4809|787|||1312|1582|8062|1211|1216|1635|1317|866|4700||1743|8419|3304|1586|91|1627|2350||6216|2527|782|2021||846|887|4875|3616|3715|807|1788|1773|1096|6728|4426|1352|778|2084|2467||5211|3382|3963|7005|6714|4350|3397|3932||9699|9668|4377|2100||5345|889|684|4603|628|711|466|821|1268|940|7113|3019|2770|1030|3362|1404|1951|2470|2405|1959|1952|1897|1587|12360|11222|4062|1129||6150|1694|3635|9902|5386|937|727||3344|2093|4372|5273||1130|1273|11326|1171|3506|3211|1984|3060|2214|2098|2607|2883|2685|2941|3977|718||3744|1365|4335|706|749|4148||1508|||6926||2985||283||468||3103|1721|1915|6341|2946|2796|12502|11698|2464|1143|1859||1540|5576|2019|10668|2974|1053|1206||1313|2399|2078||5536|6029|3403|1427|518|1484|2206|3670|3524|3674|1500|1861|9335|2625|13574|9852|4905|6867|9094|5254|2621||5206|4140|259|971|3795|1510|12864|1423|558|3057|1283|623|528|1231|1448|548|1082||449|4180|2544|6734|15220||1599|1522||621|4517|1333|1021|1457|3627|1000|2857|4810|536|4461|2733|1675|775|6511|2703||1919||2238|4041|2438|3224|2359|3143|351|2468|2056|3169|3048|4046|3315|2439|3423|17337|1537|1602|8812||3017|7720|12924|2351|1833|3191|722|1161|1223|10272|9074|503|1390|1191|1622|776|3257|609|1345||3815|||||1275|6833|||713|2101||||3562|2562||524||1755|1907|2619|4524|1716|5666|920|327|5319|4346|2095|9245|5565|4194|4863|4393|3074|12826|6540|4599|1898|1736||427|||||3000|2453|927|5999|534|||2291|763|415|2120|4868|2693|2744|4273|1604|1670|1780|2642||3020|1810|417|1011|9346||2279||793|9112|1221|3221|||1882|5625|8667|2892|8761|1177|816|2471|||1714||2226|769|3842|1358|1538|10348|631|1775|1321||2604|2406|923|8288|2492|1918|3316|2906|1342|5455|6320|1188|1724|2297|2247|897|574|1093|649|1292|1372|2452|6177|588|1746|652|2026|1561|1028|||7090|1022|750|732|2636|1485|1612|542|4877|537||10019|2964|2301|5834|1515|1301|4739|4115|2919|4042|3092|1890||5501|6145|3205|4985|4095|1318|792|2010|1687|4972|7656|3320|7095|2096|5363|3661||5835|317|1777|2932|6917|6310|2475|2521|3904|3964|5805|2519|986|1557|825|913|1947|505|8006|2197|6473|554||626|384||2973||2476|92|7251|1933|5207|1476|1437|1753|2741|2042|3632|7541|2109|1741|2121||1530|5470|1816|2966|5157|2082|1691|2823|3926|9433|8278||874|951||5404|405|1398|1664|3608|5049|10721|1509|3170|3213|1574|6710|||1415|||||973|342|4030||1603||1934||1553||3610|2667|4926||2775|7102|2454|6290|1550|1314|2652|3118|714|687|1391|1441|1323|3651|1381|3306|3924|3609|2150|2848|1445|740|733|1045|884|836|634||800|227|531|340|964|598||599|469|880||1034|1617|6051|2131|4241|2116|3804|3767|1628|3613|360|483|353||529|5587|990|3708|1086|1012|2898|1883||11040|1908|1160||1462|462|1020|794|1074|5116|589|869||918|400|572|1116|3225|1103|603|367|636|520|737||514|1570|543|1636|2033|||2365|4952|2742||4151|1546|960|1684|2261||1240||1066|1343|2842|9988|2710|6494|4529|3261|4625|2977||3622|5140|890|2361|2162|2328|1730|2516||4594|3004|3893|5378|6950|7241|715|2013|5012|3905|563|1519|1346|1203|611|2756|810|879|1891|1578|1548|723|1051|646|2269|1208|867|5284|691|6524|389|1261|1361|2286|1819|582|805|1892|1737|831|1293|5237|2704|872|3165|3493|1817|1935|2967|2222|2548|2870|2766|519|2469|3682|2444|4915|1607|2455|2587|3377|5405|753|2338|627|666|2849|550|1003|3572|2465|5859|509|1015|1937|873|4806|976||3404|1112|859||779|901|899|854|1019|1614|644|4795|555|660|441|423|689|764|2680|5349|1013|2568|585|637|3415|1913|1722|2927|1733|1795|1862||4152|931|1496|4043|1167|5903|838|629|8284|796|780||2602|438|716|2575|428|638|354||1866|624|1099|6488|1717|1148|2296|||1731|2893||926|1329|1131|1256|1657|839|2339|443|1506|435|3675|5930|4018|5060|3749|3807|4352|7305|4938|2610|1637|1348|3093|4308||2070|3602|1830|2971||1424|9587|2004|941|3035||767|4189|1446|1527|463|640|450|575|935|1094|1193|608|5180|790||1412|3144|938|2104|777|967|1117|1027|969||1192|532|1304|1621|1982||1916|9739|699|1451|3104|1544|2011|1818|2031|4839|1646|3436|1072|2106|997|1438|349|1668|1083|1178|1213|1097|4195|1920|1058||||470|756|759|2002|5433|1238|1145|||1471|1068||770|6776|280|1629|7001|1718|2763||2425|3538|3711|4771||2792||7912|2706|3119||6627|2094||2049|1588|1416|1944|1651||2330|2859|3712|3177|442|1149|1198|521|1640|806|564|3957|676|1120|164||724|274|312|4909|1113||291|419|9804||2201|491|834|615||734|1569|905|690||479|912|2900|||2615|2178|885|3636|2064|2699|2528|2168|2585|1400|1680|1486|1701|1652|3166|1300|1644|1468|3085|1405|1151|1368|2151|751|2499|4334|2219|2304|3405|1693|3058||1790|||6337|1172|3356||655||656||515|2945|3049||||641|1945|547|2426|760|||2597|||1443|1492|2059|1179|386||2334|741|2323|811|||1615|2435|700|358|2263|586|661|1946|669||785|895|2232|2005|2057|1975|1168|1565|1279|2411|2739||996|1551|494|368|808|707|1104|742|253||359|2937||677|595|1008|318|860||540||2500|795|512|987|1291|||527|489|1039||875|217|306|369|1776|817|410|6156|||4158|13587|8948|6783|8170|6185|6158|20482|282|653|914|619|1971|719|945|1065|2851|1828|238|165|545|145|275|268|158|140|185|616|116|151|136|139|120|181|112|143|114|439|109|546|246|194|128|117|111|118||93|107|169|115|121|142|129|132|152|244|241|371|157|138|581|168|174|130|153|192|133|127|119|372|134|144|125|201|206|137|146|131|203|195|288|154|187|294|459|159|304|361|296|397|850|336|835|329|906|600|94|1618|320|2111|570||265|567|379|1043|861||1251|1482|1016|842|1356|1295|1362|284|467|||430|583|343|936||694|8231|525||393|1047|1296|1359|1641|1061||552|346|286|516|576|484|591|254|1036|1189|172|7180|1539|1308|1194|1340|1277|1252|2270|2152|2034|1712|670|1024|1472|260|592|399|517|322|186|6116|538||1107||726|5086|605|362|3642|984||344||678|1005||1175|569|1413|630|696|643|223|665|396|1035|544|565|847|2778|363|321|247|341|301||490|266||370|824|3723|||1768|4572||406|452|812|148|530|453|461|587||364|502|411|454|464|3041|1146|1325||1842|1885|436|337|832|708|429|2223|2373||||437|457|330|499|496|228|381|235|1023|323|783|444|725||156|738|103|604||460|412|682|269|229|||458|448|352|272|309|418|3532|310|407|578|331|216|768|1319|218|455|1232|95|728|239|471|332|248|1572|939|803|618|219|2533|500|252|160|176|178|1369|226|255|273|481|141|432|473|390|221|495|256||771|1429|385|2480|506|979|||161|1977|635||270|826|230|124||261|862|827|257|857|||5285|6311|991|654|5947||2750|2593||701|2239|3159|1222|801|413|1759|398|1205|345||420|3333|106|126|3475|663|1305|593|401|245|566|365|233|472|729|1243|276|347|155|212|596|324|264|3981|382|1294|402|224|1150|207|287|231|786|848|311|642|485|277|350||447|974|1025|685|809|577|456|533|910||289|315|1155||373|394||177||424|355|730|293|183|553|886|391|||208|179|510|307|313|377|249|||||||||196|197|232|||198|328|535|568|375|308|1105|||||170||||1037|250|204|162|122|166|213||298|4279|338|1760|380|968|||171|182|184|242|||445|325|837|387|395|480|300|243|356|1999|590|431|408|135|||688|1081|416|717|188|209||193|392|1909|297|409|326|446|211|234|421|667|966|492|668|761|557|2164||319||220|374|451|348|302|921|1124|316|299||1685|961|705|497|475|709|1326|357|189|314|908|236|465|498|571|262|680||||658|258||606|507|474|1075|||414|251|739|1382||1137|551||271|199|||383|822|617||278|580|279|702|190||263|601|295|881|645|440||579|173|147|333|110|290|214||476||281|240|526|222|191||856|376|339|113|167|104|292|175|108|210|482|303|237|163|||200|123|202|149|150|205|215|180|671|378|285||334|305|425||1347||818|560|225||404|891|679|924|267|102|98|101|96|100|105||97|99 \ No newline at end of file diff --git a/Plain Craft Launcher 2/Resources/moddata.zip b/Plain Craft Launcher 2/Resources/moddata.zip deleted file mode 100644 index 851cdd0078b0815d89e3d8e07861ac9fb6b38685..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 394453 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�T^nO+L8Khi0{c?{DWF~ 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ΞeJOQ>UC|ApYZjEfK%K#xN-l+b`(z~Cs+zsm;E8! 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

PG?3CN#Dr;dyPKrV;w&lL!M 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 }JC{~?eH6IJO6-c~vDLnCP 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

    f9u}jX|VXFzL$CrBL(+?qbE@$iRjT(J_k>SrMgS zy-!+ciVkR)r5ycB|3e`XdV6rp0SbySkET`>Mt7)Y*60knOU6o96rQwKpZGI3+9%F! zi)7KFkUvLHH@g>UI+fS?5QlP zss-tc2AxpZjII5Ro)W3ylr7X6O$;;smmg74Rk0^wZ_~c_NMr<%nhYsefD&B95P#uB z@6<&tnw?-eHHK&t79P}naku@`bA2B4TD+XXmkY|Mv-(jPHM5lt%;R~lBH1P=G=o&Q z$x^PCCUC@~L&&PY0XY7a<`s%bAhT_$X$18oG#2u}9+9LiFZaXQTcuMOd@v48gx z^E=N9ik{h6BN)09L!lm_$I|CXaF$pX%NkEQ23lBSCv6WnNZ^;}`mgR`TJ350Q~&%6 zXc|J*YJ0E~fPKacL3@!+YSr@{Wh)b`j!923plLbr{MierN~}Hg*Y1e5RM7g7LEDRn z$^h!*luQxvl@vTDWuhQrd~O6%@W{!OhXEv5MJy2dDo)+1v2tFaT&;{Y>U}mgY=zsG zK2WI8J$gx4UOQ!shUV<2W51$f4Yj>*+RcLKSjZ$yrRiy)F)WJf3?%Ez%;%Zt;R@K+ zQ-m_+gosqvHZ+`>mBw#A+xekDO*g`=ig0lRn!$8ifN6I{!JQ@oP&uGbvvjVr@RVQS z7-*ji#;JkuVRH~GlxWVC-o5VLg{)}r;mhvHcc?xe{Rrj<2!(^1Z&yp#VEZG?=chYPi@6{$=ms}hbuprWUnhv4 z^uiU&j%b9_Y+1Ki`8-gnp~XmmE=s0G<|Lp8SQZt_2`?HDQG#(!#YXL(g_}ohL6}6K zje$~5&1sIZYz4jNDKREi>k>L&5uTn!>fvyqL& z0MGyJ2@Ow3-1*7z9wzJ^yvI1idqho-H3a>I+qn3!7Z|lA6iR2ZT9u?|NlySoYkJU* z1Z-?d7jt85IkV#{k=E zQOHfYH*b#uoqP6V_kO7BDfnFNqRld0X>BkXuHp;*D4B?9Pzu*b* z{;A;-_X3zww@dW2uo@P}LUc`?F{KO#EM2ZpkVXMAJiA`T^6Pp#cS>UiP3Pwy=)3G> z;mM+Lpg#!3JLo$&ta!lYF&dGFMm%L=R*m((S%%fDaQxF=e(L{ztMg$&T43>nw00qk zYc-|3g5LoW)9-uB1{R?@-l8cemC}J`)pA`1`Dm@!4clp^&%!9ON!x8`iy*@kO%a*< zv;%979d8D=MUwH@2I)igGRt{_Qu1$nSbz73=WB{B*}p;riF0T{czqR3j*)99(g8&g z)N68|8lhGwXcB2}K8jX#unJ_LmunQE08AGr<UT^h6clH%jy`CLoBly|g-FGZ=QW!&q2Jx)@G8UvZR#tRe zdWx+G1b@FT)GIAoAYjVl)mxOt*lbE_R{_~)KQL~NpPXG^z0Sb%ujx!J;Ny$~G8}N* zz5U^AO&Iu?$#adzI+CHag91nTJ}3aRq6`9|^beCwB$0%Fj5Q&Bn`WzqRSCo?Q=P!F zDm-;+rr4lwJ;09Xu*xLO!N}rsgPXXIM2k+1zPk=~Ma`1FGT%>L%i_an&df?R@Ogk! zLl&gH6{B44lojOv&!9iRC=to4_U7p)2nYpI9=(mwkJG}%bu0l=i)A`iVhBpMgFQ;K zZqvis%12R9goakXd&vx34>+Zz$Nr5Q{HTV;qvf#`XhyjYD)A<4?wJ zb)sP34n7e;9`q46|CtseslD!*W9_9&m^bH7byhFXyh-u@##4Q6?2zHGt_A)FBBmn3 z>2YiNf!5vJM>|AvljVgWWy7X_Xy-W1C*6^$iBU!SjlB-41A(cj7>q`8yu!qp$ym?G9b^ta^1girhV+y`pO)udXN3n0Sut$ z|3F1(%IIlnjgXRwiPWQS`FAL-2z;r)R~Auc6z*KQ*W6)8J*|D_LFdw|&e~H-$E3n0<{1=NnbI~# zzh87QDH|v_dB@ES{`!YVif%=|)nN1!uzisI{z-UchY~P0cU?!_ByiD@6 z9Jnn^x>W`Y<24EU1pm;YD{iVO-u%JbXchby-alv(thOn*42pLF#Ev6g#mjX!#hZ-y zk&Pf!raaN|Qi>9JyU{F1pfm`BNKC(_R;5DI(uwZui}u^!d&>{m<1XvfP3Y5(*~|g1 z(M9A9hq2)>Z}2)R%f01${>lme#xvj};~_aSB#32&O=7Owi>vS(xpI}2g(c#z3eD3)oS334sQWPSn153sn~Wo%K?OJ$^1YXOv8n zhAnkYEcHHI-v&ifT{~c5K zlIF3FZnf3a+LDzDt7&W$+57b>%{0A-&mh2X<5qX+_(s7!KH2AJ8}(0T>{O>i$%LB- z^e9X)-#DHIh1L=cQqe%dOnLg8hCqC0i2$kAI|7)8p-Gq$r5iF~v2NbRR!XQ<;;pYd z=v}(rSv}o;eHnAGIv!H~mCAQ~JSLd92mrKPOHE~zm&QD{`h>JnbqsU^RA@xiEJN`m zf^GCAIpV?I7s-5}V~;->=oXJhvw2>5zGV|r-`FF}z6K)!Hwl}m8obDaNf1QMJ? zwhzkWRZrtEA&z$D$+ifHI?MoKA`E;%`_jQ&qI5B_cyz0OpuZ%=YE=btP>iE2bdFX` zIO8rnWDUpuGWvh6N=XjR);QdddbLOlk2t8xq0oV{8(ussS^_sxyCbLIdm|5)Jb{eq z+Ti=(pPy%lS2_({U7jA4?Hqa&F=!CL|1WSN&Upt9d?9K9#uoaq?=rkKl19#_)tfbm z0ag>D;Vcaa$T(+E_vS(}bQJ{ZMYC5@hfCi(PWmD= zFTg-{9<6p(K6al!=)O40`790GF9WyJK#KY)TkbomgzauKS$3jzS@xfn z0q{3nXtu$5gr>vpDmd~)$s>ra9;u15w3Toq$gfR!@ z>K&NEubp8}GfQ%^NE)pK3O6|Xb94V6P)h*<6aW+e000O8$|QeW>me7TT?7UIND>SH z3jhEB000000000000000003=oWMpAudbWlqL1^@s6009620672v0EPqx0000d CJ;yu%