AIRI Stage Tamagotchi Godot 引擎 C 开发方法:五层架构、类型驱动契约与性能边界规范
2026/9/12 14:47:53 网站建设 项目流程

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 ScriptGodot 持有的Node/Node3Dpartial 类,生命周期入口与场景绑定StageRoot.cs
2. Runtime Core纯 C# 运行时逻辑:控制器、协调器、状态持有者、服务StageSceneController.cs、视图运行时
3. Contract and Transport消息类型、设置快照、ready/fatal/shutdown/状态更新载荷StageEnvelope.csStageSceneApplyPayload.csStageViewPayloads.cs
4. Registry and Discovery描述符、启动期发现、目录与查找表引擎内注册/发现代码
5. Tooling and Editor SupportInspector 辅助、导入/导出辅助、调试或编辑器专用数据组装StageDevObservationAdapter.cs等开发辅助

文档给出的默认原则是:不要默认把这些职责全部塞进单个 Godot 脚本。这与 README 中"Godot-owned scene, scripts, and .NET project structure"的定位一致——引擎保持 Godot 资产与 .NET 逻辑分离。

场景脚本规则:保持轻薄的接线层

场景脚本应该保持"薄"。文档明确允许场景脚本承担四类工作:

  • Godot 生命周期入口,如_Ready
  • 节点查找与场景接线(node lookup and scene wiring);
  • 将控制权移交给运行时对象;
  • 把 Godot 回调桥接进显式的运行时代码。

反过来,以下内容除非琐碎,否则不得直接写进场景脚本:传输协议处理、注册表构建、复杂状态迁移、业务/玩法规则、大型数据转换管道。若一个场景脚本同时开始拥有生命周期、运行时状态、协议处理与工具配置,就必须拆分。

以引擎根节点 StageRoot.cs 为实例,可以清晰看到这套规则的落地:StageRootNode3Dpartial 类,它只做接线——在_Ready中解析AvatarRootCamera3D节点、构造StageSceneControllerStageViewRuntimeStageRenderEffectsRuntimeStageBridge等运行时对象并把事件接好;在_Process中仅调用_bridge.Poll()_viewRuntime?.Process(delta)等委派;消息分发的HandleMessage也只是 switch 分发到各控制器方法。协议解析、VRM 导入、视图状态机全部在场景脚本之外,符合"handing control to runtime objects"的定位。

运行时核心规则:显式优于聪明

文档要求将可持久化的运行时逻辑优先放进纯 C# 对象,并给出四条偏好:

  • 用小型协调器(small coordinators)而非无所不知的大型类;
  • 用显式状态对象而非隐藏的可变标志位;
  • 用构造函数或方法注入依赖;
  • 用清晰的调用流而非隐式控制转移。

运行时代码应易于在调试器中追踪,显式的地图、状态与控制流优于巧妙的抽象

源码中的 StageSceneController.cs 是典型示例:它通过构造函数注入Node3D avatarRootVrmAvatarLoader,用私有字段_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,两份文档在"这些决定由谁来做"上保持了一致立场。

配套工程化设施:格式基线、编辑器配置与验证命令

虽然格式规则不在本文主体内,但落地时离不开三样配套设施,它们都在引擎目录内:

  1. .editorconfig:声明 4 空格缩进、LF 换行、UTF-8、100 列行长上限;Allman 大括号;System.*using 优先排序;私有字段强制_camelCaserequired_prefix = _);IDE0005(未使用 using)按 warning 处理。这与 csharp-style.md 中的规则条目一一对应。
  2. 风格基线Microsoft: Common C# code conventionsMicrosoft: .NET code style rule optionsGodot: C# style guide三份基线作为基础,引擎内部再叠加上述差异项。
  3. 验证命令:改动 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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询