原文地址:https://shrinken.pw/crash-2025-05-12_107-fml.html
笔者转Godot想到它支持完整的C#特性便突发奇想整个Roslyn驱动的mod加载器。
然后笔者我就反射什么乱七八糟的一把梭,就不出意外地炸了。

一直报错获取不到我写的SDK的代码,提示获取不到动态链接库。那我怎么办呢,我就搜了一下别人的写法,就比如GDWave,发现他这直接去加载编译后的模组DLL,那么我也放弃使用Roslyn同GDWave一道去了。
但是我写着写着还是一样的问题,
我就纳了闷了,我寻思我继承了啊,怎么控制台项目Get到了说继承了但Godot项目Get不到说没继承。
后来急眼了我就翻Github搜GetType,经过多个issue跳转最后找到了原因。
最后小抄一下通过AssemblyLoadContext
成功获取了我想要的东西。
完整代码如下,草草能用
ModLoader.cs
游戏项目
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<IMod> 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;
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项目
namespace CommonSDK;
public interface IMod
{
public void Init();
public void Start();
public void Loop();
}
ModBase.cs
SDK项目
using Godot;
namespace CommonSDK;
public abstract partial class ModBase<T> : Node where T : Node, new()
{
public string Name;
public string Description;
public string Author;
public static T Instance { get; } = new();
}
Test.cs
SDK项目
using Godot;
namespace CommonSDK;
public class Test
{
public void Pop()
{
GD.Print("Pop");
}
}
MyModInit.cs
模组项目
using CommonSDK;
using Godot;
namespace MyMod;
public partial class MyModInit : ModBase<MyModInit>, 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。
