关于 scenario-godot-pipeline-automation
面向 Godot 工具与构建工程师的自动化流水线技能,覆盖资源导入、测试、CI 和导出。它通过可重复的命令与门禁检查,把资源变更连接到经过验证的构建产物。
主要功能
- 01GLB 探测与资源导入
- 02导入设置与纹理处理
- 03资源审计和 gdUnit4 测试
- 04缩略图检查与导出验证
- 05CI 工作流生成与检查
- 06编辑器工具和 MCP 通道
适用场景
- 01批量接收并检查 GLB 资源
- 02验证资源尺寸、碰撞与纹理
- 03在 CI 中运行测试并导出项目
- 04通过编辑器脚本修改场景
MCP 相关
技能说明可在项目工具目录构建 MCP 服务,并通过 gp.mcp_stdio 调用;共享机器上只使用无头工具。MCP 用于场景检查与编辑,不作为错误诊断依据。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ scenario-labs/ skills --skill scenario-godot-pipeline-automation安装后在 Claude Code 中输入/scenario-godot-pipeline-automation确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/critique.mdexpert-notes.mdgui-paths.mdprocedures.mdsources.mdscripts/gd_pipeline.pyscripts/agentkit/pipeline/glb_probe.gdprop_audit.gdprop_ingest.gdprop_rules.gdprop_textures.gdprop_thumbs.gdscripts/agentkit/prop_pipeline_addon/plugin.cfgplugin.gdprop_post_import.gdscripts/ci/godot_ci.shgodot-ci.ymlscripts/examples/gdext_c/pipeline_ext.cpipeline_ext.gdextensionscripts/examples/level_importer/lvl_import.gdplugin.cfgplugin.gdscripts/examples/tools/add_spawns.gdspawn_point.gdscripts/gdunit/door.gdtest_glb_probe.gdtest_imported_props.gdtest_prop_rules.gdtest_scene_runner.gd详细介绍
Godot 流水线自动化(工具与构建工程师)
目标:Godot 4.7.2.stable、macOS Apple Silicon、gdUnit4 6.2.1。
这里的专家级要求是:人类会点击执行的每个步骤都必须能作为命令由 CI 运行两次并得到相同结果;每个结果都必须由一个曾经失败过的测试检查。工具工程师负责从美术资源投放或一次提交到经过测试的导出产物这一整条路径:接入、导入、编辑器工具、测试、CI、本机扩展和 Agent 通道。如果你可用的技能中缺少这里提到的某个同级技能,请让用户安装该技能(npx skills add scenario-labs/skills --skill <name>);若在无人值守模式下运行,则根据工具架构继续操作并标记此缺口。
必备背景: scenario-godot-expert(通道、gd_run 和 gd_env、审查循环、4.7 陷阱)。本技能新增 scripts/gd_pipeline.py 和 AgentKit 模块 scripts/agentkit/pipeline/;它本身不会启动 Godot,所有运行都通过 gd_run 执行。
状态(2026-10-02): 在包含 12 个真实图像转 3D 文件的 200 个 GLB 美术资源投放中,43 项实时检查(分布在 9 个测试文件中)、第 2 轮检查(流程 15)和 8 项离线测试均已通过(references/procedures.md)。尚未运行:GitHub Runner 上的工作流、godot-cpp 和 Rust 构建(此处没有 scons 或 cargo)。
立场(专家增量)
- 首次导入前先写好导入设置。 仅包含
[remap] importer="scene"和[params]的.glb.import伴随文件会被无头--import识别,Godot 还会添加 uid [新增,已在 M2 验证]。因此,导入阶段应按文件确定缩放、枢轴、碰撞和纹理模式,然后只导入一次。事后重写.import文件会让导入时间翻倍,还会弄脏仓库。 - 向导入器传递数据,而非代码路径。
EditorScenePostImportPlugin声明按文件配置的选项(pipeline/fit_height、pipeline/unit_scale、pipeline/fix_pivot、pipeline/collision),这些选项保存在每个伴随文件中,会显示在 Import 面板里,并且只要在project.godot中列出该插件,就会在无头--import期间运行 [新增,已在 M6、M10 验证]。整个项目只需一个插件;没有pipeline/prop_id的文件不会被处理。 - AI 图像转 3D 文件不是 DCC 文件。 这里的 12 个真实文件都自称是“Khronos glTF Blender I/O”,因此生成器检查无法识别它们,只有清单可以。它们的初始缩放各不相同(一个玩具机器人高 1.96 m),材质数量从 2 到 35 不等;12 个文件中有 8 个使用了 clearcoat、transmission、ior 或 specular,而 4.7.2 会在不发出警告的情况下丢弃这些属性 [新增,已在 M8 验证]。应按清单中的高度调整它们;DCC 道具则在修正单位后保持创作时的尺寸。
- 解析字节,而非路径。 Dinoleaf 对导入代码的要求是:使用
parse(bytes: PackedByteArray),并注入源数据,这样同一个解析器就能处理res://、user://、zip 和包含字面字节的测试(sSurjCgebjw [00:04:46])。这里的 GLB 探测器采用了这种方式,其测试会在内存中构建 GLB。 - 只有亲眼看到测试失败,它才算数。 GUT 作者 Butch Wesley 的建议是:先看红灯,再看绿灯;改坏函数体来补上测试(ImqhHLlPfZg [00:13:40])。这里的每个测试套件都埋有一个故障,必须以 100 退出。
- 评判导出时看产物,而不是退出代码。 gdUnit4 被打包时,无头
--export-pack在 5 次运行中有 4 次于 "[ DONE ] savezip" 后以信号 11 在关闭时崩溃,但生成的包是完整的 [新增,实测]。检查文件、文件大小及内容;所有预设都应排除开发文件夹。 - 对 Agent 来说,无头输出才是真相(Fennara,2vSYP7GyA5U [00:02:51])。输出面板抓取器会报告磁盘上已不存在的行的错误,而且面板不会列出项目的所有错误 [00:06:20]:在相信任何一方之前,都要重新运行无头检查。MCP 服务可以编辑场景和截图,但绝不能作为错误判断依据;在共享机器上只调用它们的无头工具 [新增]。
- 通过信号测试行为,并设置有界等待。 Godotneers 和 gdUnit4 作者 Mike Schulze 会对信号和公开结果进行断言,而不会检查私有状态;要在执行操作前调用
monitor_signals(),因为更早发出的信号会被漏掉(CreugthdgJ0 [00:36:34]);每次等待都必须设置超时。无头环境没有输入设备,因此 CI 会跳过 GUI 输入测试(Butch Wesley [00:48:33];gdUnit4 6.2.1 也会打印相同的警告)。
首先确定
| 输入 | 变更 | 默认 |
|---|---|---|
美术资源包:数量、格式、清单(file,category,name,height_m,source) | 导入规则、AI 适配 | 仅 GLB,AI 文件必须提供清单 |
| 类别预算(三角形、材质、纹理边长) | 警告并拒绝不符合规则的条目 | prop_rules.gd 默认值,根据 scenario-godot-performance-export 的帧预算设置 |
| 纹理路径:提取后进行 VRAM 检查,或嵌入 Basis Universal | 导入时间、磁盘空间、Import 停靠栏控制 | 提取 |
| 目标平台 | VRAM 格式(移动端和 macOS 通用版使用 import_etc2_astc)、预设 | Linux 和 macOS 桌面端 |
| 测试框架 | 运行器、CI 命令 | 用于生成 JUnit 报告的 gdUnit4;如果项目已有 GUT,则使用 GUT;不要同时使用两者 |
| CI 主机 | 工作流文件、缓存 | GitHub Actions,通过 SHA-512 校验官方二进制文件 |
工作流
1. 探测并做出决策(不导入)。 prop_ingest.gd:ingest 将每个文件读取为字节,进行探测
(glb_probe.gd:文件头、数据块、三角形、材质、
带 glTF 角色的图像、扩展、世界边界),应用 prop_rules.gd 规则,将通过的文件复制到
res://props/<category>/<id>/<id>.glb 并附带 sidecar,然后写入 props_manifest.json。
只有内容发生变化时才会写入。将空的 .gdignore 文件放在项目内的原始资源包目录中,
否则编辑器也会导入其中的文件(已验证,流程 15)。碰撞命名使用 Godot 的节点后缀,
导入时会移除后缀(已验证,流程 15):-col 保留网格并添加带三角网格形状的 StaticBody3D,-convcol 添加凸形形状,-colonly 仅保留物理体,-noimp 移除节点。
关卡门槛:数量相符(通过 + 警告 + 拒绝 + 重复 = 文件总数),每个拒绝项都有原因,
引擎错误为零。
2. 导入。 gd_run.import_project(P)。关卡门槛:没有 ERROR: 行,但工作完成后 4.7.2 打印的退出噪声除外(ERROR: N resources still in use at exit、
WARNING: N ObjectDB instances were leaked at exit、WARNING: N RIDs of type ... were leaked;
过滤这三种信息,流程 15);每个通过的资源都有一个 .scn 文件位于 .godot/imported 中。
3. 纹理处理(提取模式)。 prop_textures.gd:fix 会在每个提取纹理的 .import 中设置 VRAM 压缩、mipmap、按 glTF 角色设置法线贴图标记,以及按类别设置尺寸限制,然后再次导入。无头模式不会绘制帧,因此 detect_3d 永远不会切换,提取的纹理会保持无损,除非执行此处理步骤[已添加,并在 M7 验证]。GATE:每个提取纹理都生成为 .s3tc.ctex(若目标平台包含移动设备,还要生成 ETC2/ASTC)。
4. 审核与测试。 prop_audit.gd:audit 会加载每个道具,并检查元数据版本、根节点名称、枢轴、适配后的高度、高度范围、三角形数量是否超过预算的三倍、Collision 物理体、是否没有 AnimationPlayer,以及 VRAM 纹理。同一个 check_prop() 会在一个 gdUnit4 测试用例中对所有道具运行。GATE:0 个失败项,JUnit 解析成功,植入的失败会以 100 退出。
5. 外观检查。 prop_thumbs.gd:thumbs(窗口模式,主窗口为 160x90,由 SubViewport 渲染)会以四分之三视角呈现每个道具,并在旁边放置一根红色的 1 m 标杆;gd_review.contact_sheet 会生成每张包含 100 个道具、宽 1500 px 的联系表。打开这些联系表。GATE:没有黑屏或缺失的道具;与标杆相比,尺寸合理;没有悬空或陷入地面的道具。
6. 重新运行并修改一个文件。 再次运行导入和导入操作:0 次复制、0 个附属文件,没有任何内容重新导入。修改一个源文件:只有对应道具及其纹理会重新导入。GATE:两项均通过。
7. 导出。 模板:.tpz 包含 templates/ 下的全部内容(35 个文件),以及内容为 4.7.2.stable 的 version.txt;4.7.2.stable 即文件夹名称。将内容移至数据目录下的 export_templates/4.7.2.stable/(Linux 上为 ~/.local/share/godot;Voylin AbMESM0UEHk [00:11:34])。C# 项目先运行 --build-solutions(列在 4.7.2 的 --help 中,该选项隐含 --editor)。然后运行 gd_run.ensure_preset、gp.exclude_from_export(P, preset)(测试框架、测试、Agent 工具、仅编辑器插件)和 gd_run.export。GATE:构建产物存在且非空,打包清单中没有开发文件,verify_pack 能加载一个道具。
8. CI。 gp.write_workflow(root, "game", presets=(...)) 会写入 .github/workflows/godot-ci.yml 和 tools/ci/godot_ci.sh。先在本地运行脚本,植入一个失败的测试,再使用 gp.lint_workflow 检查,并使用 gp.check_urls 检查 URL 是否可访问。GATE:本地运行以 0 退出,植入的失败以 11 退出,actionlint 检查通过,URL 返回 200。
9. 编辑器工具。 EditorScript 的 _run() 是一个普通方法:gd_run.run_script(..., editor=True) 任务会打开场景(EditorInterface.open_scene_from_path),等待几帧,调用 _run(),并使用 EditorInterface.save_scene() 保存。通过 EditorInterface.get_editor_undo_redo() 执行更改,以便之后能使用 Ctrl+Z 撤销(Queble,nW7YtSSJzbQ [00:04:41]);为新节点设置 owner,否则保存时它们会消失(文档)。直接调用 @export_tool_button Callable 和 _get_configuration_warnings()。GATE:撤销和重做可恢复子节点数量,保存的 .tscn 包含新节点,警告与正确和错误输入相符。
GridMap。 GridMap 关卡需要一个 MeshLibrary:对每个导入的网格调用 create_item(id)、set_item_mesh(id, mi.mesh),并保存为 .res(已验证,流程 15)。
10. 自定义格式。 由已启用插件注册的 EditorImportPlugin 会在无头 --import 模式下运行;解析错误会返回 ERR_PARSE_ERROR,在附属文件中保留 valid=false,并记录错误所在行。GATE:正确的文件以其资源类型加载;错误的文件会失败并显示清晰的消息;格式版本提升后,通过 reimport_files() 重新导入。
11. 原生代码。 仅用于经性能分析确认的热点或原生库(Snopek,4R0uoBJ5XSk [00:03:16])。对整条流程进行冒烟测试:导出 gdextension_interface.h,构建,编写 .gdextension,运行 --import,然后调用 ClassDB.class_exists 和一个绑定方法。生产环境使用 godot-cpp,并重命名 entry_symbol(Snopek [00:13:22]);尚未运行(此处没有 scons)。GATE:类已注册,方法能返回结果,没有加载错误。
12. Agent 通道。 如需实时检查场景,请在项目的工具文件夹中克隆并构建一个 MCP 服务,仅在其环境中传入 GODOT_PATH,并通过
gp.mcp_stdio(..., hold_project=P) 调用(共享 GD_MAX 锁)。在共享机器上,切勿调用会启动编辑器或游戏的工具。GATE:列出工具,验证一次无头编辑的结果可通过 gd_run 加载。
数字
此处测得(Godot 4.7.2,2026-10-02),200 个文件,进行两次全新运行:相对于该批文件。 缩略图、资源包、CI 和时间系数的数据见 procedures.md。
| 指标 | 数值 |
|---|---|
| 完整流水线,200 个文件(导入 190 个) | 21.8 至 24.2 s:接收 0.6 至 1.4,导入 17.4 至 19.7,纹理处理 0.4 至 0.5,再次导入 1.9 至 2.7,审计 0.6 至 0.7 |
| 再次运行,未作任何更改 | 接收 0.6 至 0.7 s,导入 1.4 s,重新导入 0 个文件 |
| 更改 1 个文件 | 导入 1.4 至 1.6 s,触及 4 个已导入文件(场景 + 纹理) |
| 改为嵌入 Basis Universal | 总计 13.8 至 14.4 s;.godot/imported 为 80.6 MB,而原为 154.5 MB |
| 拒绝阈值 | 超过类别三角形预算的 3 倍(12 个 AI 文件中有 3 个,三角形数为 69k 至 181k) |
| gdUnit4 6.2.1 退出码 | 0 表示通过,100 表示存在失败或错误,101 表示仅有孤儿项,103 表示无头模式被拒绝,104 表示 Godot 版本不受支持,105 表示脚本错误(GdUnitTestSessionRunner.gd) |
godot_ci.sh 退出码 [新增] | 10 表示导入失败,11 表示测试失败,12 表示导出未生成文件 |
质量门槛
- 可量化:计数一致;每个阶段的引擎错误数为 0;审计失败数为 0;gdUnit4 退出码为 0,植入的测试退出码为 100;再次运行重新导入 0 个文件;资源包列表中没有
addons/gdUnit4、test/、addons/agentkit、addons/prop_pipeline;检查project.godot中的physics/3d/physics_engine="Jolt Physics"、渲染器和插件行;actionlint 检查通过。 - 视觉:打开并检查接触表,查看道具是否为黑色或未贴纹理、相对于 1 m 立柱的比例、枢轴以及缺失部件。
常见错误
| 错误 | 表现形式 | 修复 |
|---|---|---|
通过 asset.generator 标记 AI 资源 | AI 文件被当作 DCC 资源,且保留任意比例(玩具机器人高 1.96 m) | 使用清单中的 source 列 |
| 将每个道具都缩放到清单中的高度 | 原有尺寸差异丢失(每盏灯都变成 2.2 m) | 为 DCC 修正单位,仅对 AI 资源进行适配 |
| 认为无头模式会压缩提取出的纹理 | 无损 .ctex 文件导致资源包很大 | 运行纹理处理,或使用 [importer_defaults] texture(作用于整个项目,也会影响 UI) |
gdUnit4 使用 -rd /abs/path | 报告被写入 <project>/Users/...,CI 找不到 JUnit | 使用 -rd res://... |
用 ResourceLoader.exists() 检查是否已导入 | 导入失败的资源也会显示为“存在” | 检查 .import 中的 valid=false |
更新 _get_format_version() 并运行 --import | 没有任何资源重新导入 | 使用 -e 作业:调用 scan(),等待,然后调用 reimport_files() |
| 使用默认导出筛选器发布 | gdUnit4、测试和 Agent 工具都被打包 | 使用 exclude_from_export |
对 Linux 二进制文件使用 upload-artifact | 可执行权限位丢失 | 先打包为 tar(Voylin、AbMESM0UEHk [00:20:10]) |
| 使用宽松的校验和 grep | 也会匹配 mono 构建行 | 使用精确名称,并预期有 2 行 |
在 --script -e 作业中切换插件 | is_plugin_enabled 状态矛盾,且引擎报错 | 修改 project.godot 中的 [editor_plugins] |
在 GUT 测试中留下 pause_before_teardown() | 窗口模式运行会卡住(25 s 后被终止);无头模式下的 GUT 9.7.1 不会暂停 | 使用 -gignore_pause(Butch Wesley [00:32:08],procedures 15) |
| 在 CI 中运行 GUI 输入测试 | 失败:无头模式没有输入设备 | should_skip_script() 返回原因;GUT 将其计为 Risky,退出码为 0(Butch Wesley [00:48:33],procedures 15) |
| 忽略 GUT 的孤儿节点数量 | 泄漏被打包发布(3 个泄漏节点会打印“3 orphans”) | 数量从 1 跳到 80 就是真实泄漏(Butch Wesley [00:57:00]) |
信任已合并的 .tscn | 冲突标记会破坏场景;ResourceLoader.exists() 仍会返回 true | 合并后加载每个 .tscn(返回 null 并出现 Parse Error,procedures 15;Lilith Duncan CAJ_iIedx_I [00:01:36]) |
添加 GDExtension 后信任第一次 --import | 关机时崩溃(3 个新项目中有 2 个),退出码异常 | 检查 extension_list.cfg,运行冒烟测试作业 |
交接
- 接收带清单的 GLB、纹理和音频(scenario-blender-export、
scenario-*)、预算 (scenario-godot-performance-export)、场景约定(scenario-godot-architecture、 scenario-godot-3d-world;由后者负责道具的外观和玩法)。 - 向 scenario-godot-3d-world 交付经过审计的道具、展厅和联系表;向所有人交付测试套件和 CI;向 scenario-godot-performance-export 交付预设(签名、商店)。将简化处理交给 scenario-blender-expert,将材质修复交给 scenario-godot-rendering-lighting。
Godot 4.7 注意事项
- 在
EditorScenePostImportPlugin中,_pre_process会看到ImporterMeshInstance3D节点,_post_process会看到MeshInstance3D(已验证,流程 15);碰撞后缀在两者中都已应用。 EditorScript.get_scene()已弃用:请使用EditorInterface.get_edited_scene_root()(已验证: 作业日志会记录弃用提示)。EditorPlugin.add_dock(EditorDock)取代了add_control_to_dock(4.6 中仍存在)。- 4.7.2(M8)支持的 glTF 扩展:basisu、webp、texture_transform、emissive_strength、 unlit、pbrSpecularGlossiness、lights_punctual、node_visibility、animation_pointer、OMI physics。不支持 Draco、meshopt、网格量化、clearcoat、transmission、ior、specular。
- GDExtension:
classdb_register_extension_class4和classdb_construct_object2在 4.7.2 中仍可加载,但已弃用;godot-cpp 是生产环境的实现路径。项目只有在--import写入.godot/extension_list.cfg后才会加载扩展。 - 4.4+ 的
.uid伴随文件会与其脚本一起移动;4.6 的.tscn文件带有unique_id。
参考资料
references/procedures.md(每个流程均附代码、实时测试和 结果;第 2 轮在第 15 节)、expert-notes.md(基于 源码的判断、时间戳)、critique.md(评审标准)、gui-paths.md(编辑器 GUI)、sources.md。- 代码:
scripts/agentkit/prop_pipeline_addon/(addons/prop_pipeline插件)、scripts/ci/(工作流和 CI 脚本)、scripts/gdunit/(gdUnit4 测试)、scripts/examples/(EditorScript 工具、关卡导入器、C GDExtension)。