MOD 文件路径怎么组织才不会和原游戏冲突
MOD 文件必须和原游戏资源分离,否则更新游戏会清空 MOD。最稳妥的方式是让 MOD 放在独立目录(比如
Mods/MyMod1/),加载时用前缀或命名空间隔离资源 ID。别把 MOD 文件直接扔进
Data/或
Assets/里——那是自找麻烦。
常见错误:用
Directory.GetFiles("Assets/", "*.asset") 一把梭扫全目录,结果 MOD 和原版同名文件互相覆盖,加载顺序一变就崩溃。
所有 MOD 目录加唯一标识前缀,例如 mod_MyMod1_,避免资源 ID 冲突 用
AssemblyLoadContext隔离 MOD 的 DLL(如果含脚本),防止类型重复注册 禁止 MOD 覆盖核心配置文件(如
GameConfig.json),改用叠加式 patch 机制
如何安全地重载已加载的 MOD 资源
C# 没有真正的“卸载程序集”能力,
AssemblyLoadContext.Unload()在 .NET Core 3.0+ 才可用,且要求所有类型完全脱离引用,否则抛
InvalidOperationException: Cannot unload an assembly loaded into the default context。
所以别指望热重载 C# 脚本类;对资源(贴图、配置、音频)可以安全替换,但对行为逻辑,得设计成“可插拔组件”,运行时切换实例,而非替换类型本身。
用WeakReference管理资源实例,方便 GC 回收旧对象 配置类统一走
JsonSerializer.Deserialize<t>()</t>,不缓存静态实例 若 MOD 含
ScriptableObject(Unity 场景),必须调用
Resources.UnloadUnusedAssets()+ 手动
DestroyImmediate()
MOD 配置文件解析时怎么处理版本兼容与字段缺失
用户会随便改 JSON,字段少一个、拼错一个、类型写成字符串却该是整数——这些都会让
JsonSerializer.Deserialize<t>()</t>直接抛
JsonException,整个 MOD 加载失败。
不能靠 try-catch 整个反序列化过程来兜底,得让解析本身具备容错性。.NET 6+ 的
JsonSerializerOptions.PropertyNameCaseInsensitive = true是基础,但远远不够。 所有配置类字段加
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)],允许空值 关键字段用可空类型(
int?、
string),配合
??提供默认值 用
JsonDocument.Parse()先粗筛结构,校验必要字段是否存在、类型是否合法,再进强类型反序列化
Unity 项目中如何避免 MOD 脚本干扰主线程调度
MOD 作者可能随手写个
while(true) { Thread.Sleep(1); },或者在 Update()里做 heavy IO,直接拖垮帧率。你不能信任任何外部代码的写法。
Unity 的
Coroutine和
JobSystem都无法跨 Assembly 安全调度,所以 MOD 行为必须被“沙箱化”:不是限制语法,而是限制执行上下文。 禁止 MOD 直接访问
UnityEngine.Time.deltaTime或
Input,统一走你暴露的只读接口(如
IModContext.TickTime) 所有 MOD 的
Update()-类回调,必须注册到你自己的调度器(
ModUpdateScheduler.Run()),并设硬性超时(如 2ms/frame) DLL 加载后检查 IL 中是否有
Thread.Start、
Task.Factory.StartNew等高危调用(可用
System.Reflection.Metadata静态扫描)
真正难的不是加载 MOD,而是当它出错时,你能准确定位是哪个 MOD 的哪行逻辑卡住了主线程——日志得带上下文堆栈、加载时间戳、Assembly 签名哈希,缺一不可。
