using System; using System.Data; using System.IO; using System.Runtime.Loader; using ColdMint.scripts.debug; using ColdMint.scripts.utils; using Godot; namespace ColdMint.scripts.mod; /// /// Mod Loader /// 模组加载器 /// public class ModLoader { /// /// AssemblyLoadContext /// 装配加载上下文 /// private static AssemblyLoadContext? _assemblyLoadContext; private static readonly string[] RequiredDllList = [Config.SolutionName]; /// /// Initializes the mod loader /// 初始化模组加载器 /// /// ///This exception is thrown if the built-in dll file cannot be found when it is loaded. ///如果加载内置dll文件时,找不到文件,则抛出此异常。 /// public static void Init() { //Initialize the context. //初始化上下文环境。 LogCat.Log("initialize_the_context", LogCat.LogLabel.ModLoader); _assemblyLoadContext = AssemblyLoadContext.GetLoadContext(typeof(Godot.Bridge.ScriptManagerBridge).Assembly); if (_assemblyLoadContext == null) { LogCat.LogError("initialize_the_context_failed", LogCat.LogLabel.ModLoader); return; } var dllFolder = ResUtils.GetSelfDllFolder(); if (dllFolder == null) { LogCat.LogError("get_dll_folder_failed", LogCat.LogLabel.ModLoader); return; } foreach (var requiredDll in RequiredDllList) { var dllPath = Path.Join(dllFolder, requiredDll + ".dll"); //Load the necessary dll files. //加载必须的dll文件。 if (!File.Exists(dllPath)) { //When the dll that must be loaded does not exist, an error is reported immediately. //当必须加载的dll不存在时,立即报错。 LogCat.LogErrorWithFormat("dll_not_exist", LogCat.LogLabel.ModLoader, true, dllPath); throw new FileNotFoundException("dll not exist:" + dllPath); } LoadDllFile(dllPath); } } /// /// Load Dll file /// 加载Dll文件 /// /// ///dll file path ///dll的文件路径 /// /// ///Throw this error if the assemblyLoadContext has not been initialized. ///如果assemblyLoadContext尚未初始化,那么抛出此错误。 /// private static void LoadDllFile(string dllPath) { if (_assemblyLoadContext == null) { throw new NullReferenceException("assemblyLoadContext is null."); } //Load the dll. //加载dll。 LogCat.LogWithFormat("load_dll", LogCat.LogLabel.ModLoader, true, dllPath); try { _assemblyLoadContext.LoadFromAssemblyPath(dllPath); } catch (ArgumentNullException argumentNullException) { //The assemblyPath parameter is null. //assemblyPath参数为空。 LogCat.LogErrorWithFormat("load_dll_argument_null_exception", LogCat.LogLabel.ModLoader, true, dllPath); LogCat.WhenCaughtException(argumentNullException, LogCat.LogLabel.ModLoader); return; } catch (ArgumentException argumentException) { //Not an absolute path. //不是绝对路径 LogCat.LogErrorWithFormat("load_dll_argument_exception", LogCat.LogLabel.ModLoader, true, dllPath); LogCat.WhenCaughtException(argumentException, LogCat.LogLabel.ModLoader); return; } catch (FileLoadException fileLoadException) { //A file that was found could not be loaded. //无法加载找到的文件。 LogCat.LogErrorWithFormat("load_dll_file_load_exception", LogCat.LogLabel.ModLoader, true, dllPath); LogCat.WhenCaughtException(fileLoadException, LogCat.LogLabel.ModLoader); return; } catch (BadImageFormatException badImageFormatException) { //assemblyPath is not a valid assembly. //assemblyPath不是有效的程序集。 LogCat.LogErrorWithFormat("load_dll_bad_image_format_exception", LogCat.LogLabel.ModLoader, true, dllPath); LogCat.WhenCaughtException(badImageFormatException, LogCat.LogLabel.ModLoader); return; } //Loading the dll succeeded. //加载dll成功。 LogCat.LogWithFormat("load_dll_success", LogCat.LogLabel.ModLoader, true, dllPath); } /// /// Load all mods /// 加载全部模组 /// /// ///This method scans the incoming subfolders and loads them as module folders. ///此方法会将扫描传入的子文件夹,并将其子文件夹看作模组文件夹加载。 /// /// ///Mod folder ///模组文件夹 /// /// ///If the given folder does not exist, throw this exception. ///如果给定的文件夹不存在,则抛出此异常。 /// public static void LoadAllMods(string modFolder) { if (!Directory.Exists(modFolder)) { //The mod directory does not exist. //模组目录不存在。 throw new DirectoryNotFoundException("mod folder not exist:" + modFolder); } var directoryInfo = new DirectoryInfo(modFolder); foreach (var directory in directoryInfo.GetDirectories()) { LoadSingleMod(directory.FullName); } } /// /// Load a single mod /// 加载单个模组 /// /// ///Mod path ///模组路径 /// /// /// If the given directory does not exist, throw this exception. ///如果给定的目录不存在,那么抛出此异常。 /// /// ///Throw this exception if the manifest file creation deserialization fails. ///如果清单文件创建反序列化失败,则抛出此异常。 /// private static void LoadSingleMod(string modFolderPath) { if (!Directory.Exists(modFolderPath)) { //The module folder does not exist. //模组文件夹不存在。 throw new DirectoryNotFoundException("Mod folder does not exist:" + modFolderPath); } var modManifestPath = Path.Join(modFolderPath, Config.ModManifestFileName); var modManifest = ModManifest.CreateModManifestFromPath(modManifestPath); if (modManifest == null) { throw new NullReferenceException("mod manifest is null:" + modManifestPath); } var dllList = modManifest.DllList; if (dllList == null || dllList.Length == 0) { //The module does not contain a dll file. //模组不包含dll文件。 LogCat.LogWarningWithFormat("mod_not_contain_dll", true, LogCat.LogLabel.ModLoader, modFolderPath); } else { //The module contains dll files, load the dll files. //包含dll文件,加载dll文件。 foreach (var dll in dllList) { var dllPath = Path.GetFullPath(dll, modFolderPath); LoadDllFile(dllPath); } } var pakList = modManifest.PckList; if (pakList == null || pakList.Length == 0) { //The module does not contain a pck file. //模组不包含pck文件。 LogCat.LogWarningWithFormat("mod_not_contain_pck", true, LogCat.LogLabel.ModLoader, modFolderPath); } else { //The module contains pck files, load the pck files. //包含pck文件,加载pck文件。 foreach (var pak in pakList) { var pakPath = Path.GetFullPath(pak, modFolderPath); LoadPckFile(pakPath); } } } /// /// Load the Pck file /// 加载Pck文件 /// /// ///Pck path ///Pck路径 /// /// ///If the given path does not exist, throw this exception. ///如果给定的路径不存在,那么抛出此异常。 /// /// ///Throw this exception if the pck package fails to load. ///如果pck包加载失败了,抛出此异常。 /// private static void LoadPckFile(string pckPath) { if (!File.Exists(pckPath)) { throw new FileNotFoundException("pck file not exist:" + pckPath); } var success = ProjectSettings.LoadResourcePack(pckPath); if (success) { LogCat.LogWithFormat("load_pck_success", LogCat.LogLabel.ModLoader, true, pckPath); } else { LogCat.LogErrorWithFormat("load_pck_failed", LogCat.LogLabel.ModLoader, true, pckPath); //Throw a suitable exception here for handling at the caller. //为这里抛出合适的异常,以便在调用方处理。 throw new DataException("load pck failed:" + pckPath); } } }