Skip to content

Commit 0ad1e84

Browse files
author
StArray
committed
refactor(core): 重构 Il2CppDomain 并改进运行时程序集加载机制
- 删除 Il2Cpp.Core、Coroutine 等废弃代码,简化 Il2CppDomain 实现 - Il2CppDomain 实现 IAppDomain 接口,支持事件触发 AssemblyLoad - 优化 OpenAssembly 改为直接传字符串,使用事件通知程序集加载 - 新增 WaitForAssembly 方法支持带超时的程序集等待加载 - 调整 Il2CppAssembly 获取方式,改用 Il2CppDomain.Current 统一调用 - Il2CppClass 修正 GetClass 适配符替换 '+' 为 '/' 支持泛型嵌套类 - Il2CppClass New 方法改用底层函数 New - Il2CppMethod.FunctionPtr 访问时解引用指针获取函数地址 - 移除 Il2Cpp.Core.cs 中 Vector3 等结构体定义 - 移除 Coroutine.cs 中 Unity MonoBehaviour 协程相关代码 - RuntimeAbstractions 中增加 UnmanagedObject 抽象基类及相关接口扩展 - RuntimeHookAttributes 由 Il2CppHookAttribute 改名为 UnmanagedHookAttribute 并合并 MonoHook 用法 - SourceGenerator HookGenerator 支持 UnmanagedHook 并优化包含 UnmanagedCallersOnly 特性方法处理 - 修改 MinHook 包装,增加钩子状态管理及日志输出,避免重复钩子创建 - Dx11hook 修正部分代码风格及空指针检查,确保 RenderTargetView 重建逻辑健壮 - GraphicsDevice 通过反射调用 UnityEngine.SystemInfo.get_graphicsDeviceType 获取设备类型 - GET_STARTED.md 文档完善 Mod 开发指导、引用说明和示例代码 - 修复 ModLoader 日志打印显示异常,改为输出完整异常信息 - ModManagerUI 添加对并发集合的引用,准备支持多线程场景
1 parent a18d693 commit 0ad1e84

36 files changed

Lines changed: 1628 additions & 881 deletions

‎.gitignore‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,8 @@ tests
6767
!*.slnx.backup/
6868
Android/library/src/main/cpp/CMakeFiles/
6969

70-
*.i
70+
*.i
71+
cmake-build-*/
72+
LevelDebugger
73+
.run
74+
.vscode

‎Corehold/log.txt‎

Lines changed: 0 additions & 7 deletions
This file was deleted.

‎GET_STARTED.md‎

Lines changed: 104 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,38 @@ Final layout / 最终目录:
120120

121121
## 3. Write a Mod / 写 Mod (跨平台)
122122

123-
Reference `StArray.ModManager.dll` → implement `IModPlugin` → build DLL → drop into `mods/{ModName}/`.
124-
引用 `StArray.ModManager.dll` → 实现 `IModPlugin` → 编译 DLL → 放入 `mods/{ModName}/`。
123+
### 引用 DLL / Reference DLLs
124+
125+
| DLL | 用途 | 必需 |
126+
|---|---|---|
127+
| `StArray.ModManager.dll` | ModManager 核心 API(`IModPlugin`, `IModSettings`, 运行时抽象, ImGui 等) | ✅ |
128+
| `StArray.ModManager.Windows.dll` | Windows 平台原生依赖(仅部署时,不引用) | ❌ |
129+
| `ImGui.NET.dll` | ImGui 绑定(`ImGuiNET` 命名空间) | 如需 UI |
130+
131+
### .csproj 模板
132+
133+
```xml
134+
<Project Sdk="Microsoft.NET.Sdk">
135+
136+
<PropertyGroup>
137+
<TargetFramework>net10.0</TargetFramework>
138+
<ImplicitUsings>enable</ImplicitUsings>
139+
<Nullable>enable</Nullable>
140+
</PropertyGroup>
141+
142+
<ItemGroup>
143+
<Reference Include="StArray.ModManager">
144+
<HintPath>path\to\StArray.ModManager.dll</HintPath>
145+
</Reference>
146+
<Reference Include="ImGui.NET">
147+
<HintPath>path\to\ImGui.NET.dll</HintPath>
148+
</Reference>
149+
</ItemGroup>
150+
151+
</Project>
152+
```
153+
154+
### 最简单的 Mod
125155

126156
```csharp
127157
using StArray.ModManager.Runtime;
@@ -148,6 +178,78 @@ public class HelloMod : IModPlugin
148178
}
149179
```
150180

181+
### 可设置项的 Mod
182+
183+
实现 `IModSettings` 添加设置页:
184+
185+
```csharp
186+
public class ConfigurableMod : IModPlugin, IModSettings
187+
{
188+
public string Id => "com.example.configurable";
189+
190+
// ── 声明设置字段,自动显示在 ModManager 检查器 ──
191+
[ModSettingLabel("Show HUD")]
192+
[ModSettingLabelSide(ModInspector.LabelSide.Right)] // 勾选框,标签在右侧
193+
public bool ShowHud = true;
194+
195+
[ModSettingLabel("Scale")]
196+
[ModSettingRange(0.5f, 3f)]
197+
public float Scale = 1f;
198+
199+
public void OnGui() => ModInspector.Draw(this);
200+
}
201+
```
202+
203+
### 使用 UnmanagedHook / UnmanagedStub
204+
205+
参考 [LevelDebugger](LevelDebugger/),分三步:
206+
207+
1. **定义 Stub** — 用 `UnmanagedObject` 封装游戏类的字段/属性/方法调用
208+
2. **声明 Hook** — 用 `[UnmanagedHook(程序集, 类, 方法)]` 标记替换方法
209+
3. **注册设置** — 用 `[ModSettingLabel]` 特性声明可开关项
210+
211+
```csharp
212+
// Stub — 封装游戏类字段/方法
213+
public sealed class ScrControllerStub(nint ptr) : UnmanagedObject(ptr)
214+
{
215+
public int CurrentSeqID => Obj.GetField<int>("currentSeqID");
216+
public nint PlayerOne => Obj.GetField<nint>("playerOne");
217+
}
218+
219+
// Hook
220+
public class MyMod : IModPlugin
221+
{
222+
[UnmanagedHook("Assembly-CSharp.dll", "scrController", "TogglePauseGame")]
223+
static bool TogglePauseGame(nint thiz)
224+
{
225+
var ret = TogglePauseGameOriginal(thiz);
226+
Logger.Warn("MyMod", "Game paused");
227+
return ret;
228+
}
229+
}
230+
```
231+
### Stub / Hook 详细文档
232+
233+
参见:
234+
- [LevelDebugger 完整示例](LevelDebugger/) — 含 Stub 定义、Hook 声明、HUD 渲染、设置面板
235+
- [RuntimeObject API](StArray.ModManager/RuntimeAbstractions/RuntimeObject.cs) — 字段读写、方法调用、数组访问
236+
- [RuntimeArray API](StArray.ModManager/RuntimeAbstractions/RuntimeArray.cs) — 强类型数组元素读写
237+
- [ModInspector](StArray.ModManager/Inspector/) — 自动绘制设置面板
238+
- [UnmanagedObject](StArray.ModManager/RuntimeAbstractions/IUnmanagedObject.cs) — Stub 基类,提供 `Wrap<T>()` 安全包装
239+
240+
### package / 发布
241+
242+
Mod 部署到 `mods/{ModId}/` 目录,ModManager 自动识别:
243+
244+
```
245+
GameFolder/
246+
└── Corehold/
247+
└── mods/
248+
└── {YourModId}/
249+
├── {YourModId}.dll
250+
└── 依赖.dll # 如有额外依赖
251+
```
252+
151253
### Optional interfaces / 可选接口
152254

153255
```csharp

‎StArray.ModManager.SourceGenerator/HookGenerator.cs‎

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@ namespace StArray.ModManager.SourceGenerator;
99

1010
/// <summary>
1111
/// 增量 Source Generator —— 为 <see cref="NativeHookAttribute"/> 和
12-
/// <see cref="Il2CppHookAttribute"/> 自动生成 Hook 安装/卸载/原函数调用基础设施。
12+
/// <see cref="UnmanagedHookAttribute"/> 自动生成 Hook 安装/卸载/原函数调用基础设施。
1313
/// </summary>
1414
[Generator]
1515
public class HookGenerator : IIncrementalGenerator
1616
{
1717
private const string NativeHookAttrName = "StArray.ModManager.Hooks.NativeHookAttribute";
18-
private const string Il2CppHookAttrName = "StArray.ModManager.Hooks.Il2CppHookAttribute";
19-
private const string MonoHookAttrName = "StArray.ModManager.Hooks.MonoHookAttribute";
18+
private const string UnmanagedHookAttrName = "StArray.ModManager.Hooks.UnmanagedHookAttribute";
2019

2120
public void Initialize(IncrementalGeneratorInitializationContext context)
2221
{
@@ -43,6 +42,7 @@ private sealed class HookInfo
4342
public ImmutableArray<(string Type, string Name)> Parameters { get; set; }
4443
public ImmutableArray<string> CtorArgs { get; set; }
4544
public ImmutableArray<(string Key, string Value)> NamedArgs { get; set; }
45+
public bool HasUnmanagedCallersOnly { get; set; }
4646
}
4747

4848
private static HookInfo? GetHookInfo(GeneratorSyntaxContext ctx)
@@ -58,8 +58,7 @@ private sealed class HookInfo
5858
string? attrType = attrName switch
5959
{
6060
NativeHookAttrName => "NativeHook",
61-
Il2CppHookAttrName => "Il2CppHook",
62-
MonoHookAttrName => "MonoHook",
61+
UnmanagedHookAttrName => "UnmanagedHook",
6362
_ => null,
6463
};
6564
if (attrType == null) continue;
@@ -75,6 +74,9 @@ private sealed class HookInfo
7574
var na = ImmutableArray.CreateBuilder<(string, string)>();
7675
foreach (var n in attr.NamedArguments) na.Add((n.Key, FormatConstant(n.Value)));
7776

77+
var uco = sym.GetAttributes().Any(a =>
78+
a.AttributeClass?.ToDisplayString() == "System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute");
79+
7880
return new HookInfo
7981
{
8082
AttrType = attrType,
@@ -84,6 +86,7 @@ private sealed class HookInfo
8486
Parameters = pl.ToImmutable(),
8587
CtorArgs = ca.ToImmutable(),
8688
NamedArgs = na.ToImmutable(),
89+
HasUnmanagedCallersOnly = uco,
8790
};
8891
}
8992
return null;
@@ -141,8 +144,9 @@ private static void GenerateCode(SourceProductionContext ctx, Compilation compil
141144
sb.AppendLine($" private static nint _{sf}_origPtr;");
142145
sb.AppendLine($" private static _{sf}Delegate? _{sf}_orig;");
143146

144-
// ── 持久引用(防止 delegate 被 GC) ──
145-
sb.AppendLine($" private static _{sf}Delegate? _{sf}_wrap;");
147+
// ── 持久引用(防止 delegate 被 GC;[UnmanagedCallersOnly] 不需要) ──
148+
if (!h.HasUnmanagedCallersOnly)
149+
sb.AppendLine($" private static _{sf}Delegate? _{sf}_wrap;");
146150

147151
// ── Install ──
148152
sb.AppendLine();
@@ -161,59 +165,50 @@ private static void GenerateCode(SourceProductionContext ctx, Compilation compil
161165
}
162166
sb.AppendLine($" if (t == nint.Zero) return false;");
163167
sb.AppendLine($" _{sf}_origPtr = t;");
164-
sb.AppendLine($" _{sf}_wrap = {h.MethodName};");
165-
sb.AppendLine($" var d = global::System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(_{sf}_wrap);");
166-
sb.AppendLine($" var o = global::StArray.ModManager.Runtime.HookHelper.Hook(t, d);");
167-
sb.AppendLine($" if (o == nint.Zero) return false;");
168-
sb.AppendLine($" _{sf}_orig = global::System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer<_{sf}Delegate>(o);");
169-
sb.AppendLine(" return true;");
170-
}
171-
else if (h.AttrType == "Il2CppHook")
172-
{
173-
var a = h.CtorArgs.Length > 0 ? h.CtorArgs[0] : "\"\"";
174-
var c = h.CtorArgs.Length > 1 ? h.CtorArgs[1] : "\"\"";
175-
var m = h.CtorArgs.Length > 2 ? h.CtorArgs[2] : "\"\"";
176-
string? ptn = null;
177-
foreach (var n in h.NamedArgs)
178-
if (n.Key is "ParameterTypeNames" or "parameterTypeNames") ptn = n.Value;
179-
string pc = "-1";
180-
foreach (var n in h.NamedArgs)
181-
if (n.Key is "ParameterCount" or "parameterCount") pc = n.Value;
182-
183-
sb.AppendLine($" var asm = global::StArray.ModManager.Il2Cpp.Il2CppAssembly.Get({a});");
184-
sb.AppendLine($" if (asm == null) return false;");
185-
sb.AppendLine($" var cls = asm.GetClass(\"\", {c});");
186-
sb.AppendLine($" if (cls == null) return false;");
187-
if (ptn != null)
188-
sb.AppendLine($" var method = cls.GetMethod({m}, {ptn});");
168+
if (h.HasUnmanagedCallersOnly)
169+
sb.AppendLine($" var d = typeof({h.ContainingType}).GetMethod(\"{h.MethodName}\", global::System.Reflection.BindingFlags.Static | global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic)!.MethodHandle.GetFunctionPointer();");
189170
else
190-
sb.AppendLine($" var method = cls.GetMethod({m}, {pc});");
191-
sb.AppendLine($" if (method == null) return false;");
192-
sb.AppendLine($" var t = method.FunctionPtr;");
193-
sb.AppendLine($" _{sf}_origPtr = t;");
194-
sb.AppendLine($" _{sf}_wrap = {h.MethodName};");
195-
sb.AppendLine($" var d = global::System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(_{sf}_wrap);");
171+
{
172+
sb.AppendLine($" _{sf}_wrap = {h.MethodName};");
173+
sb.AppendLine($" var d = global::System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(_{sf}_wrap);");
174+
}
196175
sb.AppendLine($" var o = global::StArray.ModManager.Runtime.HookHelper.Hook(t, d);");
197176
sb.AppendLine($" if (o == nint.Zero) return false;");
198177
sb.AppendLine($" _{sf}_orig = global::System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer<_{sf}Delegate>(o);");
199178
sb.AppendLine(" return true;");
200179
}
201-
else // MonoHook
180+
else // UnmanagedHook
202181
{
203182
var a = h.CtorArgs.Length > 0 ? h.CtorArgs[0] : "\"\"";
204-
var nsArg = h.CtorArgs.Length > 1 ? h.CtorArgs[1] : "\"\"";
205-
var c = h.CtorArgs.Length > 2 ? h.CtorArgs[2] : "\"\"";
206-
var m = h.CtorArgs.Length > 3 ? h.CtorArgs[3] : "\"\"";
183+
string clsNs;
184+
string c;
185+
string m;
186+
if (h.CtorArgs.Length == 4)
187+
{
188+
clsNs = h.CtorArgs[1];
189+
c = h.CtorArgs[2];
190+
m = h.CtorArgs[3];
191+
}
192+
else
193+
{
194+
clsNs = "\"\"";
195+
c = h.CtorArgs.Length > 1 ? h.CtorArgs[1] : "\"\"";
196+
m = h.CtorArgs.Length > 2 ? h.CtorArgs[2] : "\"\"";
197+
}
198+
foreach (var n in h.NamedArgs)
199+
if (n.Key is "Namespace" or "namespace") clsNs = n.Value;
207200
string? ptn = null;
208201
foreach (var n in h.NamedArgs)
209202
if (n.Key is "ParameterTypeNames" or "parameterTypeNames") ptn = n.Value;
210203
string pc = "-1";
211204
foreach (var n in h.NamedArgs)
212205
if (n.Key is "ParameterCount" or "parameterCount") pc = n.Value;
213206

214-
sb.AppendLine($" var asm = global::StArray.ModManager.Mono.MonoAssembly.Get({a});");
207+
sb.AppendLine($" var domain = global::StArray.ModManager.RuntimeAbstractions.RuntimeManager.GetDomain();");
208+
sb.AppendLine($" if (domain == null) return false;");
209+
sb.AppendLine($" var asm = domain.OpenAssembly({a});");
215210
sb.AppendLine($" if (asm == null) return false;");
216-
sb.AppendLine($" var cls = asm.GetClass({nsArg}, {c});");
211+
sb.AppendLine($" var cls = asm.GetClass({clsNs}, {c});");
217212
sb.AppendLine($" if (cls == null) return false;");
218213
if (ptn != null)
219214
sb.AppendLine($" var method = cls.GetMethod({m}, {ptn});");
@@ -222,8 +217,13 @@ private static void GenerateCode(SourceProductionContext ctx, Compilation compil
222217
sb.AppendLine($" if (method == null) return false;");
223218
sb.AppendLine($" var t = method.FunctionPtr;");
224219
sb.AppendLine($" _{sf}_origPtr = t;");
225-
sb.AppendLine($" _{sf}_wrap = {h.MethodName};");
226-
sb.AppendLine($" var d = global::System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(_{sf}_wrap);");
220+
if (h.HasUnmanagedCallersOnly)
221+
sb.AppendLine($" var d = typeof({h.ContainingType}).GetMethod(\"{h.MethodName}\", global::System.Reflection.BindingFlags.Static | global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic)!.MethodHandle.GetFunctionPointer();");
222+
else
223+
{
224+
sb.AppendLine($" _{sf}_wrap = {h.MethodName};");
225+
sb.AppendLine($" var d = global::System.Runtime.InteropServices.Marshal.GetFunctionPointerForDelegate(_{sf}_wrap);");
226+
}
227227
sb.AppendLine($" var o = global::StArray.ModManager.Runtime.HookHelper.Hook(t, d);");
228228
sb.AppendLine($" if (o == nint.Zero) return false;");
229229
sb.AppendLine($" _{sf}_orig = global::System.Runtime.InteropServices.Marshal.GetDelegateForFunctionPointer<_{sf}Delegate>(o);");
@@ -261,7 +261,8 @@ private static void GenerateCode(SourceProductionContext ctx, Compilation compil
261261
sb.AppendLine($" global::StArray.ModManager.Runtime.HookHelper.Unhook(_{sf}_origPtr);");
262262
sb.AppendLine($" _{sf}_origPtr = nint.Zero;");
263263
sb.AppendLine($" _{sf}_orig = null;");
264-
sb.AppendLine($" _{sf}_wrap = null;");
264+
if (!h.HasUnmanagedCallersOnly)
265+
sb.AppendLine($" _{sf}_wrap = null;");
265266
sb.AppendLine($" }}");
266267
}
267268
sb.AppendLine(" }");

0 commit comments

Comments
 (0)