GFramework/docs/zh-CN/source-generators/godot-project-generator.md
GeWuYou 833a295b84 feat(godot): 添加 Godot 集成功能和测试基础设施
- 新增 AdditionalTextGeneratorTestDriver 用于源生成器测试
- 添加 AutoLoadAttribute 特性支持 AutoLoad 类型映射
- 扩展项目构建目标,支持自定义 project.godot 路径验证
- 创建完整 Godot 集成教程文档,涵盖节点生命周期、信号系统等功能
- 添加源代码生成器测试项目配置和相关依赖包引用
2026-04-14 09:05:33 +08:00

4.3 KiB
Raw Blame History

Godot 项目元数据生成器

project.godot 生成 AutoLoad 与 Input Action 的强类型访问入口。

概述

GFramework.Godot.SourceGenerators 会读取 Godot 项目根目录下的 project.godot,并把其中最常用的项目级元数据暴露为稳定的编译期 API。

当前覆盖:

  • [autoload] 段:生成 GFramework.Godot.Generated.AutoLoads
  • [input] 段:生成 GFramework.Godot.Generated.InputActions

这项能力的目标不是替代场景级生成器,而是把 Godot 工程配置和 C# 代码之间的字符串约定收敛到编译期。

接入方式

NuGet 引用

当项目通过 NuGet 引用 GeWuYou.GFramework.Godot.SourceGenerators 时,生成器会默认把项目根目录下的 project.godot 加入 AdditionalFiles

如需覆盖默认路径,可以设置:

  • 可以改成项目根目录下的其他相对路径
  • 文件名必须仍然是 project.godot,否则生成器会给出警告并忽略该文件
<PropertyGroup>
  <GFrameworkGodotProjectFile>Config/project.godot</GFrameworkGodotProjectFile>
</PropertyGroup>

仓库内直接引用生成器

如果你通过 ProjectReference(OutputItemType=Analyzer) 直接引用生成器项目,则需要手动加入:

<ItemGroup>
  <AdditionalFiles Include="project.godot" />
</ItemGroup>

AutoLoad 访问层

基础行为

假设 project.godot 中声明了:

[autoload]
GameServices="*res://autoload/game_services.tscn"
AudioBus="*res://autoload/audio_bus.gd"

生成器会产出:

using GFramework.Godot.Generated;

var gameServices = AutoLoads.GameServices;

if (AutoLoads.TryGetAudioBus(out var audioBus))
{
}
  • 对于能唯一映射到 C# 节点类型的条目,属性会是强类型的
  • 对于无法映射或对应非 C# 脚本的条目,属性会退化为 Godot.Node
  • 生成器通过 Godot.Engine.GetMainLoop() 与当前 SceneTree.Root 解析 /root/<AutoLoadName> 节点

显式映射

当 AutoLoad 名称无法仅靠类名唯一推断时,可以使用 [AutoLoad] 明确指定:

using GFramework.Godot.SourceGenerators.Abstractions;
using Godot;

[AutoLoad("GameServices")]
public partial class GameServices : Node
{
}

规则如下:

  • 显式 [AutoLoad] 映射优先于隐式类名推断
  • 标记了 [AutoLoad] 的类型必须继承 Godot.Node
  • 若多个类型映射到同一个 AutoLoad生成器会报告诊断并退化为 Godot.Node 访问器,直到映射唯一

Input Action 常量

基础行为

假设 project.godot 中有:

[input]
move_up={
}
ui_cancel={
}

生成器会产出:

using GFramework.Godot.Generated;

if (Input.IsActionJustPressed(InputActions.MoveUp))
{
}

转换规则:

  • move_up -> MoveUp
  • ui_cancel -> UiCancel
  • 非法字符会被清理后再转换为 PascalCase
  • 如果多个动作名落到同一个标识符,生成器会追加稳定数字后缀,例如 MoveUp_2

与现有 Godot 生成器的关系

这项能力和现有的场景级生成器是互补的:

  • AutoLoads / InputActions 解决的是项目级元数据访问
  • [GetNode] 解决的是场景节点引用注入
  • [BindNodeSignal] 解决的是节点事件订阅样板

推荐组合方式:

using GFramework.Godot.Generated;
using GFramework.Godot.SourceGenerators.Abstractions;
using Godot;

public partial class MainHud : Control
{
    [GetNode]
    private Button _startButton = null!;

    public override void _Ready()
    {
        __InjectGetNodes_Generated();

        if (Input.IsActionPressed(InputActions.UiCancel))
        {
        }

        var services = AutoLoads.GameServices;
    }
}

诊断与约束

当前会重点报告以下问题:

  • [AutoLoad] 标记在非 Godot.Node 类型上
  • 多个类型映射到同一个 AutoLoad 名称
  • 不同 AutoLoad 名称或 Input Action 名称在清洗后发生标识符冲突
  • project.godot 内部重复声明同名 AutoLoad 或 Input Action

这些诊断的目的不是阻断所有生成,而是在可能的情况下保留稳定输出,同时把不确定性显式暴露出来。

相关文档