202 lines
8.0 KiB
Markdown
202 lines
8.0 KiB
Markdown
# ShrinkSDK for Godot 4.7 C#
|
||
|
||
Godot 适配层使用共享 ShrinkSDK 运行时和 MSBuild/Cecil CodeGen。桌面基线为 Godot 4.7.2 Mono / .NET 8。Android 消费工程使用 .NET 9,并由工程提供对应平台的运行与导出验证;Web 和 iOS 不在本次支持范围。
|
||
|
||
## 直接运行 Workspace 示例
|
||
|
||
使用 Godot 4.7.2 Mono 打开:
|
||
|
||
```text
|
||
Godot/Samples/ShrinkSDK.Godot.Sample/project.godot
|
||
```
|
||
|
||
首次打开前可以先完成导入和编译:
|
||
|
||
```powershell
|
||
$godot = Join-Path $env:GODOT_HOME "godot_console.exe"
|
||
& $godot --headless --editor --path .\Godot\Samples\ShrinkSDK.Godot.Sample --quit
|
||
dotnet build .\Godot\Samples\ShrinkSDK.Godot.Sample\ShrinkSDK.Godot.Sample.csproj
|
||
& $godot --headless --path .\Godot\Samples\ShrinkSDK.Godot.Sample
|
||
```
|
||
|
||
`GODOT_HOME` 指向 Godot Mono 安装目录。成功运行时会输出 `SHRINK_GODOT_SMOKE_PASS`。
|
||
|
||
## 在现有 Godot C# 项目中安装
|
||
|
||
项目需要:
|
||
|
||
- Godot 4.7.2 Mono;
|
||
- .NET 8 SDK;
|
||
- `.csproj` 使用 `Godot.NET.Sdk/4.7.2`;
|
||
- 项目级 `NuGet.Config` 保留既有源并加入 ShrinkSDK feed。
|
||
|
||
`NuGet.Config` 的最小增量如下:
|
||
|
||
```xml
|
||
<configuration>
|
||
<packageSources>
|
||
<add key="ShrinkSDK" value="https://git.crash.work/api/packages/ShrinkSDK/nuget/index.json" />
|
||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||
</packageSources>
|
||
</configuration>
|
||
```
|
||
|
||
安装 Godot 宿主和所需模块:
|
||
|
||
```powershell
|
||
dotnet add package ShrinkSDK.Godot --version 0.2.1
|
||
dotnet add package ShrinkSDK.EntJoy.Godot --version 0.1.1
|
||
dotnet add package ShrinkSDK.EventBus --version 2.3.1
|
||
dotnet add package ShrinkSDK.Command --version 0.4.3
|
||
dotnet add package ShrinkSDK.Network --version 0.4.3
|
||
dotnet add package ShrinkSDK.DataSaver --version 2.5.0
|
||
dotnet restore
|
||
dotnet build
|
||
```
|
||
|
||
只有实际使用的模块需要安装。版本以 ShrinkSDK NuGet 源中的已发布版本为准,并保留命令中的固定版本号,不要改用浮动版本。
|
||
|
||
### EventBus 调试器(可选)
|
||
|
||
`ShrinkSDK.EventBus.Godot 0.1.1` 提供 Godot 编辑器中的事件订阅与分发调试窗口。安装 NuGet 包后,将包内 `contentFiles/any/any/addons/shrink_event_bus` 复制到项目的 `addons/shrink_event_bus`,再在 `Project > Project Settings > Plugins` 启用 **ShrinkEventBus**。它依赖公开的 `EventBus.ObserveDiagnostics`,订阅快照列出静态 `EventBus` 管理的 Bus,分发记录也可观察独立 Host;Release 构建不包含采集实现。
|
||
|
||
主线程 Bus 可以使用显式延后发布:
|
||
|
||
```csharp
|
||
var result = EventBus.PostDeferred(bus, new PlayerReadyEvent());
|
||
if (!result.Accepted)
|
||
GD.PushWarning($"deferred post rejected: {result.Failure}");
|
||
```
|
||
|
||
延后事件在下一次宿主主线程泵送时执行。`Inline`、`DedicatedThread`、`TaskPool` 或没有 `IShrinkDeferredMainThreadDispatcher` 的宿主会返回 `DeferredUnsupported`,不会静默改成同步分发。
|
||
|
||
### EntJoy ECS(可选)
|
||
|
||
`ShrinkSDK.EntJoy.Godot` 将 EntJoy 的 headless ECS/JobSystem 接入 Godot 节点生命周期。主场景根节点改为继承 `ShrinkEntJoyHost` 后,可从 `EntJoyWorld` 使用 `EntityManager`、`QueryBuilder` 和 EntJoy Job API;宿主会在 `_Ready` 初始化共享 JobSystem,在每帧 `_Process` 交换事件缓冲并提交待处理 Job,在 `_ExitTree` 释放 World。详见 [Godot/Packages/ShrinkSDK.EntJoy.Godot/README.md](Packages/ShrinkSDK.EntJoy.Godot/README.md)。
|
||
|
||
## Installer 插件
|
||
|
||
`ShrinkSDK.Godot.Installer` 的 nupkg 内包含完整的 `addons/shrinksdk`。取得 `0.2.0` 包后,将包内:
|
||
|
||
```text
|
||
contentFiles/any/any/addons/shrinksdk
|
||
```
|
||
|
||
复制到 Godot 项目的:
|
||
|
||
```text
|
||
addons/shrinksdk
|
||
```
|
||
|
||
然后在 Godot 中打开 `Project > Project Settings > Plugins`,启用 **ShrinkSDK Installer**。左侧 ShrinkSDK 面板可以:
|
||
|
||
- 查看项目直接安装的 ShrinkSDK NuGet 包及版本;
|
||
- 安装、升级或移除模块;
|
||
- 保留项目已有 NuGet 源和无关 `PackageReference`;
|
||
- 执行 `dotnet restore/build`;
|
||
- 查看 CodeGen 最后一次织入结果和生成的注册数量。
|
||
|
||
已安装版本高于面板目录版本时会显示 `Newer` 并禁用更新按钮,不会执行降级。
|
||
|
||
在 Workspace 中生成 Installer 包:
|
||
|
||
```powershell
|
||
dotnet build .\Assets\Modules\ShrinkInstaller\Godot~\ShrinkSDK.Godot.Installer.csproj -c Release
|
||
dotnet pack .\Assets\Modules\ShrinkInstaller\Godot~\ShrinkSDK.Godot.Installer.csproj -c Release --no-build -o .\Godot\Artifacts
|
||
```
|
||
|
||
## 宿主节点
|
||
|
||
主场景根节点继承 `ShrinkGodotHost`,并在 `_Ready` 中先调用 `base._Ready()`:
|
||
|
||
```csharp
|
||
using Cysharp.Threading.Tasks;
|
||
using ShrinkSDK.Godot;
|
||
|
||
public partial class GameRoot : ShrinkGodotHost
|
||
{
|
||
public override void _Ready()
|
||
{
|
||
base._Ready();
|
||
BootAsync().Forget();
|
||
}
|
||
|
||
private async UniTaskVoid BootAsync()
|
||
{
|
||
RequireWoven(GetType().Assembly);
|
||
await StartAppAsync();
|
||
}
|
||
}
|
||
```
|
||
|
||
宿主负责日志、主线程派发、时间、`user://` 持久化路径、截图、应用生命周期和网络 dispatch queue。`Runtime` 属性暴露可组合的 `ShrinkGodotRuntime`,供不直接继承宿主节点的入口复用。使用 `ShrinkNetworkService` 时,通过 `AddNetworkService(service)` 交给宿主逐帧泵送,释放前调用 `RemoveNetworkService(service)`。
|
||
|
||
`ShutdownAppAsync()` 只停止 App,保留运行时继续泵送派发和网络队列;`ShutdownAsync()` 会先停止 App,再关闭整个运行时。退出流程需要等待 App 的 inverse effect 完成时使用后者。
|
||
|
||
## 组合式宿主
|
||
|
||
Godot 4.7.2 项目优先让常驻入口继承 `Node`,持有一个 `ShrinkGodotRuntime`:在 `_Ready` 中 `Initialize(this)`,在 `_Process(delta)` 中 `Tick(delta)`,在 `_Notification(what)` 中 `Notify(what)`。入口设置 `ProcessMode = ProcessModeEnum.Always`,暂停时继续处理基础服务。
|
||
|
||
启动前必须初始化;退出时先保存业务状态并关闭服务组合,再等待 `ShutdownAsync()`,最后调用 `SceneTree.Quit()`。正常退出由项目显式协调,强制终止不保证清理。网络注册与逐帧驱动在所有者线程调用,后台任务可以使用 `TryPost` / `TryPostDeferred`。
|
||
|
||
受限沙箱中的设置存储可使用 `ShrinkGodotStorage.CreateRenameOnly(rootPath)`,通过 `ShrinkDataSaverAppModuleConfig.RuntimeConfig.Storage` 注入,并调用 `ShrinkBasicComposition.CreateEntries(services, network: null, dataSaver: config)`。轮转中断从备份恢复,孤立临时文件不会自动成为正式文件。
|
||
|
||
运行 `WorldDemo.tscn` 可验证两个实际世界节点的候选恢复、失败保留原世界、提交替换与订阅释放,以及暂停派发和正常退出。成功标记为 `SHRINK_GODOT_WORLD_PASS`。
|
||
|
||
## CodeGen 织入
|
||
|
||
EventBus、Command、Network 和 App 的特性注册由 `ShrinkSDK.CodeGen` 在构建时生成。项目正常引用这些模块后,`buildTransitive` 会默认设置:
|
||
|
||
```xml
|
||
<ShrinkCodeGenEnabled>true</ShrinkCodeGenEnabled>
|
||
```
|
||
|
||
执行:
|
||
|
||
```powershell
|
||
dotnet build
|
||
```
|
||
|
||
日志应出现类似:
|
||
|
||
```text
|
||
[ShrinkSDK.CodeGen] ... woven: instance=1, static=1, registry=2
|
||
```
|
||
|
||
运行时可以在启动阶段验证程序集:
|
||
|
||
```csharp
|
||
ShrinkGodotHost.RequireWoven(GetType().Assembly);
|
||
```
|
||
|
||
缺少织入时应修复 NuGet 引用或构建配置,不要增加运行时反射扫描兜底。只有明确采用手工注册的普通 .NET 宿主才设置 `<ShrinkCodeGenEnabled>false</ShrinkCodeGenEnabled>`。
|
||
|
||
## 特性声明示例
|
||
|
||
```csharp
|
||
using ShrinkCommand;
|
||
using ShrinkEventBus;
|
||
using ShrinkNetwork;
|
||
|
||
public readonly struct PlayerReadyEvent : IShrinkEvent { }
|
||
|
||
[ShrinkEventSubscriber]
|
||
public sealed class PlayerReadySubscriber
|
||
{
|
||
[ShrinkSubscribe]
|
||
private void OnPlayerReady(PlayerReadyEvent value) { }
|
||
}
|
||
|
||
[ShrinkCommandSubscriber]
|
||
public static class GameCommands
|
||
{
|
||
[ShrinkCommand("game/status")]
|
||
public static void Status() { }
|
||
}
|
||
|
||
[ShrinkNetworkMessage(41001, "game/player-ready")]
|
||
public sealed class PlayerReadyMessage : IShrinkNetworkMessage { }
|
||
```
|
||
|
||
实例订阅者使用 `EventBus.Attach(instance)` 绑定;静态订阅、Command、Network 和 App registry 由织入代码自动注册。
|