AIRI Stage Tamagotchi Godot 引擎 C# 开发方法:五层架构、类型驱动契约与性能边界规范
【免费下载链接】airi💖🧸 Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-sama's altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi
本篇技术指南以 csharp-development-method.md 为骨架,系统讲解@proj-airi/stage-tamagotchi-godot引擎内 C# 代码的结构分层与现代化语言特性使用规范。该引擎是 AIRI 项目的桌面端 Godot 舞台运行时(sidecar),负责 VRM 模型加载、相机视图状态与渲染效果;读者阅读本文后可掌握其场景脚本、运行时核心、传输契约、注册发现与工具链五层架构的划分依据,以及反射、LINQ、async 三类能力的使用边界,并理解文档规则在 StageRoot.cs 等真实源码中的落地方式。
适用范围与定位
该指南仅适用于engines/stage-tamagotchi-godot这一个引擎目录,不是仓库级的 C# 通用标准。AIRI monorepo 中其他包(如 Electron 宿主、插件 SDK、各 stage 包)有各自的约定,本指南不应被挪用为全仓规范。
指南定义的适用对象包括:
- Godot 场景脚本(Scene Scripts)
- 运行时协调器与控制器(Runtime Coordinators and Controllers)
- 宿主-舞台传输契约(Host-Stage Transport Contracts)
- 注册与发现代码(Registry and Discovery)
- 引擎内部的工具与编辑器支持代码(Tooling and Editor Support)
而格式化、命名等"次要"规则被刻意放在本地 .editorconfig 与 csharp-style.md 中,不在本文档内重复定义。也就是说,结构方法(怎么组织代码)与代码风格(怎么写每个字符)被明确拆分为两份文档,前者是本文主体,后者是配套的格式化基线。
五层架构模型:写代码前先分层
文档要求在任何实现开始之前,先把引擎内的 C# 代码拆分为五层。这是全文的核心骨架,约束着每个文件应承担的责任:
| 层级 | 职责 | 典型载体 |
|---|---|---|
| 1. Scene Script | Godot 持有的Node/Node3Dpartial 类,生命周期入口与场景绑定 | StageRoot.cs |
| 2. Runtime Core | 纯 C# 运行时逻辑:控制器、协调器、状态持有者、服务 | StageSceneController.cs、视图运行时 |
| 3. Contract and Transport | 消息类型、设置快照、ready/fatal/shutdown/状态更新载荷 | StageEnvelope.cs、StageSceneApplyPayload.cs、StageViewPayloads.cs |
| 4. Registry and Discovery | 描述符、启动期发现、目录与查找表 | 引擎内注册/发现代码 |
| 5. Tooling and Editor Support | Inspector 辅助、导入/导出辅助、调试或编辑器专用数据组装 | StageDevObservationAdapter.cs等开发辅助 |
文档给出的默认原则是:不要默认把这些职责全部塞进单个 Godot 脚本。这与 README 中"Godot-owned scene, scripts, and .NET project structure"的定位一致——引擎保持 Godot 资产与 .NET 逻辑分离。
场景脚本规则:保持轻薄的接线层
场景脚本应该保持"薄"。文档明确允许场景脚本承担四类工作:
- Godot 生命周期入口,如
_Ready; - 节点查找与场景接线(node lookup and scene wiring);
- 将控制权移交给运行时对象;
- 把 Godot 回调桥接进显式的运行时代码。
反过来,以下内容除非琐碎,否则不得直接写进场景脚本:传输协议处理、注册表构建、复杂状态迁移、业务/玩法规则、大型数据转换管道。若一个场景脚本同时开始拥有生命周期、运行时状态、协议处理与工具配置,就必须拆分。
以引擎根节点 StageRoot.cs 为实例,可以清晰看到这套规则的落地:StageRoot是Node3Dpartial 类,它只做接线——在_Ready中解析AvatarRoot与Camera3D节点、构造StageSceneController、StageViewRuntime、StageRenderEffectsRuntime、StageBridge等运行时对象并把事件接好;在_Process中仅调用_bridge.Poll()、_viewRuntime?.Process(delta)等委派;消息分发的HandleMessage也只是 switch 分发到各控制器方法。协议解析、VRM 导入、视图状态机全部在场景脚本之外,符合"handing control to runtime objects"的定位。
运行时核心规则:显式优于聪明
文档要求将可持久化的运行时逻辑优先放进纯 C# 对象,并给出四条偏好:
- 用小型协调器(small coordinators)而非无所不知的大型类;
- 用显式状态对象而非隐藏的可变标志位;
- 用构造函数或方法注入依赖;
- 用清晰的调用流而非隐式控制转移。
运行时代码应易于在调试器中追踪,显式的地图、状态与控制流优于巧妙的抽象。
源码中的 StageSceneController.cs 是典型示例:它通过构造函数注入Node3D avatarRoot与VrmAvatarLoader,用私有字段_currentAvatar持有显式状态;Apply方法先校验Format == "vrm",加载新模型成功后才CommitAvatar(新节点先入树,旧节点才QueueFree),实现"先成功再替换"的原子语义。文档中的"显式状态对象"在这段代码里体现为_currentAvatar与各 payload record 类型,而不是散落的布尔标志。此外,引擎通过 Directory.Build.props 固定了net10.0目标框架与LangVersion 14.0,确保同一运行时契约与语言版本,避免新 SDK 静默改变语言能力。
契约与传输规则:先用类型定义边界,再围绕类型实现传输
跨边界通信必须类型驱动(type-driven)。文档明确要求对以下内容使用显式类型:传输消息、载荷、设置快照、描述符、注册表条目、运行时状态快照。
同时明确禁止:
- 把
Dictionary<string, object?>当作默认契约形状; - 跨文件散落的魔法字符串协议;
- 匿名对象跨子系统边界传递;
- 用注释替代真正的类型定义。
规则一句话概括:先把边界定义为类型,再围绕这些类型实现传输。
引擎的 transport 目录(scripts/transport)是这套规则的直接产物:
- StageEnvelope.cs:
public sealed record StageEnvelope(string Type, JsonElement? Payload),即 Electron main 与 Godot sidecar 之间交换的消息信封,Type 是稳定消息类型字符串(如host.scene.apply),Payload 是可选 JSON; - StageSceneApplyPayload.cs:
StageSceneApplyPayload(ModelId, Format, Name, Path)描述 Electron 物化 VRM 文件后下发的场景输入,其中Format在 G1.1 阶段仅接受vrm; - StageViewPayloads.cs:集中定义了视图状态相关的十余个 record——相机姿态
StageCameraPoseState、视图快照StageViewState、局部补丁StageCameraPosePatch、请求/应答载荷(快照请求、PNG 捕获、渲染调试视图、边缘光开关)以及错误载荷。
正是因为契约全部是 record 类型,StageRoot.cs 才能在HandleMessage里用统一的分支按envelope.Type分发,并用共享的JsonSerializerOptions(camelCase、大小写不敏感、忽略空值)完成反序列化——消息类型的稳定性直接决定了分发代码的简洁性。
反射与 LINQ 策略:反射建目录,LINQ 塑形查询,运行时走显式结构
文档对反射和 LINQ 给出了明确的能力边界与心智模型:
反射用于发现(discovery),不用于执行(execution)。允许的用途包括:启动期模块发现、属性元数据读取、描述符生成、编辑器/工具支持。禁止用于:逐帧逻辑、运行时热路径分发、核心状态机执行、稳态运行时中的重复动态调用。
LINQ 用于冷路径查询与数据塑形。允许的用途包括:构建注册表、过滤描述符、配置投影、调试/工具视图。禁止在热路径、逐帧循环、重复执行的运行时查询中使用重 LINQ——当显式索引或字典更清晰、更便宜时,应优先使用它们。
文档给出一句话心智模型:
- 反射(reflection)构建目录(catalogue);
- LINQ 塑形与查询目录;
- 运行时通过显式结构执行。
这条策略与分层模型相辅相成:注册与发现层负责"建目录",契约层负责定义目录条目的类型,运行时核心层则直接操作显式状态与调用流。
异步边界策略:async 只进 I/O 与进程边界
文档要求 async 只用于I/O 与进程边界,允许的场景包括:socket 与传输建立、文件 I/O、宿主侧进程交互、天然异步的启动加载。
明确禁止把 async 推进:逐帧更新、核心运行时循环、需要保持显式的时序敏感行为。文档特别强调:不要用 async 来掩盖生命周期或排序问题。
这与引擎的实际架构相呼应:Godot 侧使用WebSocketPeer的同步轮询模型,StageBridge.cs 在_Process帧循环中调用Poll()拉取消息、SendText发送信封,连接与关闭事件通过Opened/MessageReceived/Closed事件暴露——帧循环本身保持同步、显式、可预测,异步只发生在进程边界(Electron 宿主通过本地 WebSocket 桥接,启动命令为godot --path ./engines/stage-tamagotchi-godot -- --airi-ws-url=<runtime-url>)。
延迟决策清单:不要猜测,显式决定
文档明确列出若干刻意推迟、不得猜测的项目,因为它们会显著影响代码形态:
- 可空引用类型(nullable reference types)的推广策略;
- 命名空间策略;
record的使用边界;required成员的使用边界;- 主构造函数(primary constructors)的使用边界;
- 辅助层与场景脚本之间的功能许可边界。
当其中某一项变得相关时,应当显式决定并写入引擎本地指南,而不是从风格工具(如.editorconfig、格式化器)的行为去反推。配套的 csharp-style.md 也把 "Nullable reference types / Namespace strategy / record、required 与主构造函数 / DTO 专属风格" 全部列为 Out of Scope,两份文档在"这些决定由谁来做"上保持了一致立场。
配套工程化设施:格式基线、编辑器配置与验证命令
虽然格式规则不在本文主体内,但落地时离不开三样配套设施,它们都在引擎目录内:
- .editorconfig:声明 4 空格缩进、LF 换行、UTF-8、100 列行长上限;Allman 大括号;
System.*using 优先排序;私有字段强制_camelCase(required_prefix = _);IDE0005(未使用 using)按 warning 处理。这与 csharp-style.md 中的规则条目一一对应。 - 风格基线:
Microsoft: Common C# code conventions、Microsoft: .NET code style rule options、Godot: C# style guide三份基线作为基础,引擎内部再叠加上述差异项。 - 验证命令:改动 C# 文件或
.editorconfig后,在引擎目录下执行dotnet format --verify-no-changes验证格式无漂移。
此外,引擎带有独立的验证宿主tests/stage-tamagotchi-godot.tests(.csproj 通过ProjectReference引用引擎主项目,禁用隐式 using),配合仓库根package.json中的pnpm -F @proj-airi/stage-tamagotchi-godot build / typecheck / test三个命令,保证运行时与验证宿主编译在同一运行时契约(net10.0)之上。格式与结构的双重校验,让上述分层与边界规则可以低成本地持续执行。
小结
这篇开发方法文档为engines/stage-tamagotchi-godot确立了一套可执行的 C# 工程纪律:五层架构先分层再编码,场景脚本保持轻薄,运行核心显式化,跨边界契约一律类型驱动,反射与 LINQ 只服务冷路径与发现,async 只停留在 I/O 边界,未决的策略显式推迟。从 StageRoot.cs 的接线方式、StageSceneController.cs 的依赖注入与原子替换,到 transport 目录下一组组 record 契约,这套规范已经深度渗透进引擎现有代码;对任何新增或重构该引擎 C# 代码的开发者而言,它既是架构地图,也是评审清单。
【免费下载链接】airi💖🧸 Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-sama's altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考