GodotC#模组系统研究心得 2025-05-12 48 笔记 笔者转Godot想到它支持完整的C#特性便突发奇想整个Roslyn驱动的mod加载器。 然后笔者我就反射什么乱七八糟的一把梭,就不出意外地炸了。  一直报错获取不到我写的SDK的代码,提示获取不到动态链接库。那我怎么办呢,我就搜了一下别人的写法,就比如[GDWave](https://github.com/NotNite/GDWeave/blob/main/GDWeave/Loader/ModLoader.cs "GDWave"),发现他这直接去加载编译后的模组DLL,那么我也放弃使用Roslyn同GDWave一道去了。 但是我写着写着还是一样的问题,    我就纳了闷了,我寻思我继承了啊,怎么控制台项目Get到了说继承了但Godot项目Get不到说没继承。  后来急眼了我就翻Github搜GetType,经过多个issue跳转最后找到了[原因](https://github.com/godotengine/godot/issues/75160#issuecomment-1478573429 "原因")。 最后小抄一下通过`AssemblyLoadContext`成功获取了我想要的东西。 完整代码如下,草草能用 `ModLoader.cs` 游戏项目 ```csharp using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Runtime.Loader; using CommonSDK; using Godot; namespace modtestre; public partial class ModLoader : Node { private static readonly List ModInstances = []; public override void _Process(double delta) { base._Process(delta); foreach (var instance in ModInstances) { instance.Loop(); } } public override void _Ready() { GD.Print("正在开始加载模组"); LoadMods(); } private static void LoadMods() { var modsDir = OS.GetUserDataDir() + "/mods/"; GD.Print("模组文件夹路径: " + modsDir); if (Directory.Exists(modsDir)) { GD.Print("模组文件夹存在"); var dllFiles = Directory.GetFiles(modsDir, "*.dll"); GD.Print("找到库文件共: " + dllFiles.Length); foreach (var dllFile in dllFiles) { GD.Print("加载模组库文件: " + dllFile); var alc = AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()); if (alc == null) continue; var assembly = alc.LoadFromAssemblyPath(dllFile); foreach (var type in assembly.GetTypes()) { if (!IsModClass(type)) continue; var baseType = type.BaseType; //获取实例以绕过static限制 //https://github.com/godotengine/godot/issues/75160#issuecomment-1478573429 var instanceProp = baseType?.GetProperty( "Instance", BindingFlags.Public | BindingFlags.Static ); if (instanceProp == null) { GD.PrintErr($"找不到Instance属性: {type.FullName}"); continue; } if (instanceProp.GetValue(null) is IMod modInstance) { ModInstances.Add(modInstance); modInstance.Init(); GD.Print($"成功加载Mod: {type.FullName}"); } else { GD.PrintErr($"实例化失败: {type.FullName}"); } } } } else { GD.Print($"模组文件夹未找到: {modsDir}"); } } private static bool IsModClass(Type type) { if (type.IsAbstract || type.IsInterface) return false; return type.BaseType?.IsGenericType == true && type.BaseType.GetGenericTypeDefinition() == typeof(ModBase<>); } } ``` `IMod.cs` SDK项目 ```csharp namespace CommonSDK; public interface IMod { public void Init(); public void Start(); public void Loop(); } ``` `ModBase.cs` SDK项目 ```csharp using Godot; namespace CommonSDK; public abstract partial class ModBase : Node where T : Node, new() { public string Name; public string Description; public string Author; public static T Instance { get; } = new(); } ``` `Test.cs` SDK项目 ```csharp using Godot; namespace CommonSDK; public class Test { public void Pop() { GD.Print("Pop"); } } ``` `MyModInit.cs` 模组项目 ```csharp using CommonSDK; using Godot; namespace MyMod; public partial class MyModInit : ModBase, IMod { public int LoopTime = 5; public MyModInit() { Author = "Eicy"; } public void Init() { GD.Print("Made by " + Author); GD.Print(Instance.GetType().FullName); } public void Loop() { if (LoopTime <= 0) return; GD.Print("Loop"); LoopTime--; } public void Start() { new Test().Pop(); } } ``` 有机会的话再玩玩Roslyn。  本文链接: https://shrinken.pw/crash-2025-05-12_107-fml.html
厉害,完全摸不清写的什么,隔行隔山了
@hedp 都各有所长嘛(