diff --git a/README.md b/README.md
index 845c392..d3e6bc6 100644
--- a/README.md
+++ b/README.md
@@ -52,6 +52,10 @@ You need to fill in the Export Presets > Resources > Filter to export non-resour
data/*
```
+#### Custom feature
+
+- **disableVersionIsolation** Disable version isolation.
+
## Configuring Openobserve
> This is optional, and the game will work even if you do not configure Openobserve.
diff --git a/README_JA.md b/README_JA.md
index 0608bf5..02a9d86 100644
--- a/README_JA.md
+++ b/README_JA.md
@@ -50,6 +50,10 @@ git clone https://github.com/Cold-Mint/Traveller.git
data/*
```
+#### 風習特徴
+
+- **disableVersionIsolation** 版孤立を無効化する。
+
## はいちOpenobserve
> これはオプションなので、Openobserveを設定しなくてもゲームは正常に動作します。
diff --git a/README_ZH.md b/README_ZH.md
index 5cef5e2..a61c06b 100644
--- a/README_ZH.md
+++ b/README_ZH.md
@@ -52,6 +52,10 @@ git clone https://github.com/Cold-Mint/Traveller.git
data/*
```
+#### 自定义特性
+
+- **disableVersionIsolation** 禁用版本隔离。
+
## 配置Openobserve
> 这是可选的操作,即使您不配置Openobserve,游戏也能正常运行。
diff --git a/locals/Log.csv b/locals/Log.csv
index 1d1a5f9..3b809ad 100644
--- a/locals/Log.csv
+++ b/locals/Log.csv
@@ -97,4 +97,8 @@ log_load_dll_argument_null_exception,{0}参数为空。,The {0} parameter is emp
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ファイルを正常にロードしました。
-log_mod_folder_does_not_exist,位于{0}的模组文件夹不存在。,The module folder at {0} does not exist.,{0}に位置するモジュールフォルダは存在しません。
\ No newline at end of file
+log_mod_folder_does_not_exist,位于{0}的模组文件夹不存在。,The module folder at {0} does not exist.,{0}に位置するモジュールフォルダは存在しません。
+log_mod_not_contain_dll,模组{0}不包含DLL文件。,The module {0} does not contain a DLL file.,モジュール{0}にDLLファイルが含まれていません。
+log_mod_not_contain_pck,模组{0}不包含PCK文件。,The module {0} does not contain a PCK file.,モジュール{0}にPCKファイルが含まれていません。
+log_load_pck_success,成功加载位于{0}的PCK文件。,Successfully loaded the PCK file located at {0}.,{0}にあるPCKファイルを正常にロードしました。
+log_load_pck_failed,加载PCK文件{0}失败。,Failed to load the PCK file {0}.,PCKファイル{0}のロードに失敗しました。
\ No newline at end of file
diff --git a/scripts/Config.cs b/scripts/Config.cs
index 4c9668b..716823d 100644
--- a/scripts/Config.cs
+++ b/scripts/Config.cs
@@ -95,7 +95,7 @@ public static class Config
/// 公司/创作者名字
///
public const string CompanyName = "ColdMint";
-
+
///
/// Solution Name
/// 解决方案名称
@@ -119,7 +119,12 @@ public static class Config
/// Whether version isolation is enabled
/// 是否启用版本隔离
///
- public const bool EnableVersionIsolation = true;
+ public static bool EnableVersionIsolation()
+ {
+ //By default, we enable version isolation, but special feature identifiers can be set to disable version isolation.
+ //默认情况,我们启用版本隔离,但是可以设置特殊的功能标识来禁用版本隔离。
+ return !OS.HasFeature("disableVersionIsolation");
+ }
///
/// Default version name
@@ -210,10 +215,14 @@ public static class Config
/// Get what platform is currently running on
/// 获取当前在什么平台上运行
///
+ ///
+ ///Whether to include an editor environment
+ ///是否包含编辑器环境
+ ///
///
- public static OsEnum GetOs()
+ public static OsEnum GetOs(bool containEditor = false)
{
- if (OS.HasFeature("editor"))
+ if (containEditor && OS.HasFeature("editor"))
{
return OsEnum.Editor;
}
@@ -271,7 +280,7 @@ public static class Config
///
public static string GetGameDataDirectory()
{
- if (EnableVersionIsolation)
+ if (EnableVersionIsolation())
{
return Path.Join(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), CompanyName,
ProjectSettings.GetSetting("application/config/name").AsString(), UserId,
@@ -285,6 +294,15 @@ public static class Config
}
}
+ ///
+ /// GetModDataDirectory
+ /// 获取模组文件夹
+ ///
+ ///
+ public static string GetModDataDirectory()
+ {
+ return Path.Join(GetGameDataDirectory(), "Mods");
+ }
///
/// Get the export directory for the level graph
diff --git a/scripts/inventory/ItemTypeRegister.cs b/scripts/inventory/ItemTypeRegister.cs
index 7ab2fed..1a2b071 100644
--- a/scripts/inventory/ItemTypeRegister.cs
+++ b/scripts/inventory/ItemTypeRegister.cs
@@ -69,7 +69,7 @@ public static class ItemTypeRegister
///
///
///
- private static IList ParseFile(string filePath)
+ private static IList? ParseFile(string filePath)
{
var yamlFile = FileAccess.Open(filePath, FileAccess.ModeFlags.Read);
diff --git a/scripts/loader/uiLoader/SplashScreenLoader.cs b/scripts/loader/uiLoader/SplashScreenLoader.cs
index a47c30a..464eb90 100644
--- a/scripts/loader/uiLoader/SplashScreenLoader.cs
+++ b/scripts/loader/uiLoader/SplashScreenLoader.cs
@@ -82,7 +82,6 @@ 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());
@@ -97,6 +96,14 @@ public partial class SplashScreenLoader : UiLoaderTemplate
Directory.CreateDirectory(dataPath);
}
+ ModLoader.Init();
+ var modPath = Config.GetModDataDirectory();
+ if (!Directory.Exists(modPath))
+ {
+ Directory.CreateDirectory(modPath);
+ }
+
+ ModLoader.LoadAllMods(modPath);
//Registered camp
//注册阵营
var defaultCamp = new Camp(Config.CampId.Default)
diff --git a/scripts/mod/ModLoader.cs b/scripts/mod/ModLoader.cs
index 380b7bb..173005f 100644
--- a/scripts/mod/ModLoader.cs
+++ b/scripts/mod/ModLoader.cs
@@ -1,8 +1,10 @@
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;
@@ -18,8 +20,16 @@ public class ModLoader
///
private static AssemblyLoadContext? _assemblyLoadContext;
- private static string[] _requiredDllList = new[] { Config.SolutionName };
+ 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.
@@ -39,7 +49,7 @@ public class ModLoader
return;
}
- foreach (var requiredDll in _requiredDllList)
+ foreach (var requiredDll in RequiredDllList)
{
var dllPath = Path.Join(dllFolder, requiredDll + ".dll");
//Load the necessary dll files.
@@ -49,85 +59,214 @@ public class ModLoader
//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);
+ throw new FileNotFoundException("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);
+ LoadDllFile(dllPath);
}
}
///
- /// Load a module for a directory
- /// 加载某个目录的模组
+ /// 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
///模组路径
///
- public static void LoadMod(string modFolderPath)
+ ///
+ /// 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.
//模组文件夹不存在。
- LogCat.LogErrorWithFormat("mod_folder_does_not_exist", LogCat.LogLabel.ModLoader, true, modFolderPath);
- return;
+ throw new DirectoryNotFoundException("Mod folder does not exist:" + modFolderPath);
}
- try
+ var modManifestPath = Path.Join(modFolderPath, Config.ModManifestFileName);
+ var modManifest =
+ ModManifest.CreateModManifestFromPath(modManifestPath);
+ if (modManifest == null)
{
- var modManifest =
- ModManifest.CreateModManifestFromPath(Path.Join(modFolderPath, Config.ModManifestFileName));
+ throw new NullReferenceException("mod manifest is null:" + modManifestPath);
}
- catch (FileNotFoundException fileNotFoundException)
+
+ var dllList = modManifest.DllList;
+ if (dllList == null || dllList.Length == 0)
{
- //Do not continue to load the file when it does not exist.
- //当文件不存在时就不要继续加载了。
- LogCat.WhenCaughtException(fileNotFoundException, LogCat.LogLabel.ModLoader);
- return;
+ //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);
}
}
}
\ No newline at end of file
diff --git a/scripts/mod/ModManifest.cs b/scripts/mod/ModManifest.cs
index 4892f9d..2b26c2c 100644
--- a/scripts/mod/ModManifest.cs
+++ b/scripts/mod/ModManifest.cs
@@ -25,12 +25,20 @@ public class ModManifest
/// Dll path list of the mod
/// 模组的Dll路径列表
///
+ ///
+ ///Allow relative paths, such as:... / Points to the parent directory.
+ ///允许使用相对路径,例如: ../指向上级目录。
+ ///
public string[]? DllList { get; set; }
///
/// Pck path list of mod
/// 模组的Pck路径列表
///
+ ///
+ ///Allow relative paths, such as:... / Points to the parent directory.
+ ///允许使用相对路径,例如: ../指向上级目录。
+ ///
public string[]? PckList { get; set; }
///
@@ -50,7 +58,7 @@ public class ModManifest
///当给定的路径不存在时,抛出此异常。
///
///
- public static ModManifest CreateModManifestFromPath(string filePath)
+ public static ModManifest? CreateModManifestFromPath(string filePath)
{
if (!filePath.EndsWith(Config.ModManifestFileName))
{
diff --git a/scripts/serialization/YamlSerialization.cs b/scripts/serialization/YamlSerialization.cs
index ff05b83..a08fb58 100644
--- a/scripts/serialization/YamlSerialization.cs
+++ b/scripts/serialization/YamlSerialization.cs
@@ -51,8 +51,10 @@ public static class YamlSerialization
///
///
///
- public static T Deserialize(string yaml)
+ // ReSharper disable ReturnTypeCanBeNotNullable
+ public static T? Deserialize(string yaml)
{
return YamlDeserializer.Deserialize(yaml);
}
+ // ReSharper restore ReturnTypeCanBeNotNullable
}
\ No newline at end of file
diff --git a/scripts/utils/ExplorerUtils.cs b/scripts/utils/ExplorerUtils.cs
index 473da55..ec3aafa 100644
--- a/scripts/utils/ExplorerUtils.cs
+++ b/scripts/utils/ExplorerUtils.cs
@@ -58,6 +58,7 @@ public static class ExplorerUtils
case Config.OsEnum.Macos:
case Config.OsEnum.Ios:
case Config.OsEnum.Web:
+ case Config.OsEnum.Editor:
default:
throw new ArgumentOutOfRangeException();
}
diff --git a/scripts/utils/ResUtils.cs b/scripts/utils/ResUtils.cs
index 423b514..728873d 100644
--- a/scripts/utils/ResUtils.cs
+++ b/scripts/utils/ResUtils.cs
@@ -23,20 +23,22 @@ public static class ResUtils
public static string? GetSelfDllFolder()
{
var currentDirectory = Environment.CurrentDirectory;
- if (Config.GetOs() == Config.OsEnum.Editor)
+ var osEnum = Config.GetOs(true);
+ if (osEnum == Config.OsEnum.Editor)
{
return Path.Join(currentDirectory, ".godot", "mono", "temp", "bin", "Debug");
}
- if (Config.GetOs() == Config.OsEnum.Windows)
+ if (osEnum == Config.OsEnum.Windows)
{
return Path.Join(currentDirectory, "data_" + Config.SolutionName + "_windows_x86_64");
}
- if (Config.GetOs() == Config.OsEnum.Linux)
+ if (osEnum == Config.OsEnum.Linux)
{
return Path.Join(currentDirectory, "data_" + Config.SolutionName + "_linuxbsd_x86_64");
}
+
return null;
}