diff --git a/locals/Log.csv b/locals/Log.csv
index d6d8e73..f09a131 100644
--- a/locals/Log.csv
+++ b/locals/Log.csv
@@ -86,4 +86,14 @@ log_weapon_not_in_pickup_range,武器不在拾取范围内。,The weapon is not
log_weapon_picked_up,武器被拾取。,Weapon picked up.,武器が拾い取られました。
log_weapon_pickup_failed,武器拾取失败。,Weapon pickup failed.,武器の拾い取りに失敗しました。
log_enter_the_picking_range_body,进入拾取范围。,Enter the picking range.,拾い取り範囲に入ります。
-log_search_for_weapon_timeout,搜索武器超时。,Search for weapon timeout.,武器の検索がタイムアウトしました。
\ No newline at end of file
+log_search_for_weapon_timeout,搜索武器超时。,Search for weapon timeout.,武器の検索がタイムアウトしました。
+log_initialize_the_context,初始化上下文环境。,Initialize the context environment.,コンテキスト環境を初期化します。
+log_initialize_the_context_failed,初始化上下文环境失败。,Initialize the context environment failed.,コンテキスト環境の初期化に失敗しました。
+log_get_dll_folder_failed,获取DLL文件夹失败。,Failed to get the DLL folder.,DLLフォルダの取得に失敗しました。
+log_dll_not_exist,位于{0}的Dll文件不存在。,The Dll file located at {0} does not exist.,{0}にあるDLLファイルが存在しません。
+log_load_dll,开始加载位于{0}的DLL文件。,Start loading the DLL file located at {0}.,{0}にあるDLLファイルのロードを開始します。
+log_load_dll_argument_exception,{0}不是绝对路径。,{0} is not an absolute path.,{0}は絶対パスではありません。
+log_load_dll_argument_null_exception,{0}参数为空。,The {0} parameter is empty.,{0}パラメータが空です。
+log_load_dll_file_load_exception,加载DLL文件{0}失败。,Failed to load the DLL file {0}.,DLLファイル{0}のロードに失敗しました。
+log_load_dll_bad_image_format_exception,{0}不是有效的程序集。,{0} is not a valid assembly.,{0}は有効なアセンブリではありません。
+log_load_dll_success,成功加载位于{0}的dll文件。,Successfully loaded the dll file located at {0}.,{0}にあるDLLファイルを正常にロードしました。
\ No newline at end of file
diff --git a/scripts/Config.cs b/scripts/Config.cs
index 1278cff..7cf9ba5 100644
--- a/scripts/Config.cs
+++ b/scripts/Config.cs
@@ -52,7 +52,7 @@ public static class Config
/// App配置文件路径
///
public const string AppConfigPath = "res://AppConfig.yaml";
-
+
///
/// The percentage of speed reduced after a thrown item hits an enemy
/// 抛出的物品击中敌人后减少的速度百分比
@@ -89,6 +89,12 @@ public static class Config
/// 公司/创作者名字
///
public const string CompanyName = "ColdMint";
+
+ ///
+ /// Solution Name
+ /// 解决方案名称
+ ///
+ public static string SolutionName = "ColdMint.Traveler";
///
/// How many item slots are there on the shortcut bar
@@ -187,7 +193,11 @@ public static class Config
//The host operating system is a web browser
//宿主操作系统是网页浏览器
- Web
+ Web,
+
+ //Running on editor
+ //在编辑器内运行
+ Editor
}
///
@@ -197,6 +207,11 @@ public static class Config
///
public static OsEnum GetOs()
{
+ if (OS.HasFeature("editor"))
+ {
+ return OsEnum.Editor;
+ }
+
if (OS.HasFeature("windows"))
{
return OsEnum.Windows;
diff --git a/scripts/debug/LogCat.cs b/scripts/debug/LogCat.cs
index 9c0789c..91324b7 100644
--- a/scripts/debug/LogCat.cs
+++ b/scripts/debug/LogCat.cs
@@ -64,6 +64,11 @@ public static class LogCat
/// 日志收集器
///
public const string LogCollector = "LogCollector";
+ ///
+ /// Mod Loader
+ /// 模组加载器
+ ///
+ public const string ModLoader = "ModLoader";
}
@@ -192,7 +197,7 @@ public static class LogCat
break;
}
- StringBuilder.Append(DateTime.Now.ToString(" yyyy-M-d HH:mm:ss "));
+ StringBuilder.Append(DateTime.Now.ToString(" (K)yyyy-MM-d hh:mm:ss.fff "));
StringBuilder.Append(label);
StringBuilder.Append(" :");
var key = $"log_{message}";
diff --git a/scripts/loader/uiLoader/SplashScreenLoader.cs b/scripts/loader/uiLoader/SplashScreenLoader.cs
index b80687a..a47c30a 100644
--- a/scripts/loader/uiLoader/SplashScreenLoader.cs
+++ b/scripts/loader/uiLoader/SplashScreenLoader.cs
@@ -10,6 +10,7 @@ using ColdMint.scripts.inventory;
using ColdMint.scripts.loot;
using ColdMint.scripts.map;
using ColdMint.scripts.map.roomInjectionProcessor;
+using ColdMint.scripts.mod;
using Godot;
namespace ColdMint.scripts.loader.uiLoader;
@@ -81,6 +82,7 @@ public partial class SplashScreenLoader : UiLoaderTemplate
//Disable all logs in the release version.
//在发行版禁用所有日志。
LogCat.MinLogLevel = Config.IsDebug() ? LogCat.InfoLogLevel : LogCat.DisableAllLogLevel;
+ ModLoader.Init();
ContributorDataManager.RegisterAllContributorData();
DeathInfoGenerator.RegisterDeathInfoHandler(new SelfDeathInfoHandler());
MapGenerator.RegisterRoomInjectionProcessor(new ChanceRoomInjectionProcessor());
diff --git a/scripts/mod/ModLoader.cs b/scripts/mod/ModLoader.cs
new file mode 100644
index 0000000..2a4b41e
--- /dev/null
+++ b/scripts/mod/ModLoader.cs
@@ -0,0 +1,105 @@
+using System;
+using System.IO;
+using System.Runtime.Loader;
+using ColdMint.scripts.debug;
+using ColdMint.scripts.utils;
+
+namespace ColdMint.scripts.mod;
+
+///
+/// Mod Loader
+/// 模组加载器
+///
+public class ModLoader
+{
+ ///
+ /// AssemblyLoadContext
+ /// 装配加载上下文
+ ///
+ private static AssemblyLoadContext? _assemblyLoadContext;
+
+ private static string[] _requiredDllList = new[] { Config.SolutionName };
+
+ 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 NullReferenceException("dll not exist:" + dllPath);
+ }
+
+ //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);
+ }
+ }
+
+ public static void LoadMod()
+ {
+ }
+}
\ No newline at end of file
diff --git a/scripts/utils/ResUtils.cs b/scripts/utils/ResUtils.cs
index e142f61..423b514 100644
--- a/scripts/utils/ResUtils.cs
+++ b/scripts/utils/ResUtils.cs
@@ -1,4 +1,5 @@
using System;
+using System.IO;
namespace ColdMint.scripts.utils;
@@ -14,6 +15,31 @@ public static class ResUtils
///
private const string Suffix = ".remap";
+ ///
+ /// Gets the location of its own dll
+ /// 获取自身dll的存放位置
+ ///
+ ///
+ public static string? GetSelfDllFolder()
+ {
+ var currentDirectory = Environment.CurrentDirectory;
+ if (Config.GetOs() == Config.OsEnum.Editor)
+ {
+ return Path.Join(currentDirectory, ".godot", "mono", "temp", "bin", "Debug");
+ }
+
+ if (Config.GetOs() == Config.OsEnum.Windows)
+ {
+ return Path.Join(currentDirectory, "data_" + Config.SolutionName + "_windows_x86_64");
+ }
+
+ if (Config.GetOs() == Config.OsEnum.Linux)
+ {
+ return Path.Join(currentDirectory, "data_" + Config.SolutionName + "_linuxbsd_x86_64");
+ }
+ return null;
+ }
+
///
/// The game returns the res directory with a.remap suffix at runtime, causing an error while loading the resource
/// 游戏在运行时返回res目录后带有.remap后缀,导致加载资源时出错