Godot SDK
本文介绍如何使用 Framedash Godot SDK(C# 插件)自动收集性能遥测数据。
- Godot 4.3 或更高版本的 .NET(C#)版本。标准的 GDScript-only 版本无法编译 C# 插件。
- .NET 8 SDK 或更高版本(任何能以
net8.0为目标的 SDK 均可;该插件会构建进你以net8.0为目标的游戏程序集) - 不支持 Web(HTML5)导出,因为 Godot 4 暂不支持 .NET 项目的 Web 导出。
SDK 既可从 Godot Asset Library(编辑器 GUI)安装,也可从 GitHub 手动安装(适合脚本 / CI)。对于 CI 或脚本化的设置,请使用下面的手动安装,因为 Asset Library 流程需要编辑器 GUI。
Godot Asset Library(编辑器 GUI)
Section titled “Godot Asset Library(编辑器 GUI)”SDK 已发布到 Godot Asset Library。此方式仅限 GUI。在 Godot 编辑器中:
- 打开 AssetLib 标签页
- 搜索 Framedash Telemetry SDK,并选择版本
0.1.8 - 点击 Download,然后点击 Install。保持选中
addons/framedash/,以便将插件安装到res://addons/framedash/
从 GitHub 手动安装
Section titled “从 GitHub 手动安装”如需固定发布版本或用于 CI,请克隆 Framedash Godot SDK 仓库:
git clone --branch v0.1.8 --depth 1 https://github.com/crane-valley/framedash-godot-sdk.git为了让检出可复现,请固定到发布标签(v0.1.8),而不要跟踪默认分支。克隆后,如果项目中没有 addons/ 目录,请先创建该目录,然后将仓库的 addons/framedash/ 文件夹复制到 res://addons/。
通过任一方式安装后:
- 构建一次 C# 解决方案。这会生成
.csproj/.sln并编译插件,使其 autoload 类型可用。 - 在 Godot 编辑器中打开 Project > Project Settings > Plugins
- 启用 Framedash Telemetry SDK
启用插件后会注册 Framedash autoload singleton。在启动附近的 _Ready() 中初始化 SDK 一次:
using Framedash;using Godot;
public partial class GameBootstrap : Node{ public override void _Ready() { TelemetrySDK.Initialize( apiKey: "your-api-key", buildId: "1.0.0"); }}endpointUrl 和 buildId 是可选项。省略 endpointUrl 时,SDK 使用 https://ingest.framedash.dev/v1/events。
自动收集的数据
Section titled “自动收集的数据”SDK 会自动收集:
- FPS / 帧时间:根据真实帧间隔计算
- 内存:Godot static memory
- GPU / 渲染 CPU 时间:
RenderingServer报告的最近一帧计时 - 游戏线程时间:
_process花费的时间
session_start 在初始化时发送,perf_heartbeat 每 10 秒发送一次。
TelemetrySDK.Instance.Track( eventName: "player_death", mapId: "map_01", position: playerNode.GlobalPosition);如果需要附加分类属性或数值指标:
using System.Collections.Generic;
TelemetrySDK.Instance.Track( eventName: "player_death", mapId: "map_01", position: playerNode.GlobalPosition, attributes: new Dictionary<string, string> { { "cause", "fall_damage" } }, metrics: new Dictionary<string, float> { { "health", 0f } });已跟踪的事件会缓冲在内存中,并按 30 秒的间隔,或当一个批次达到 100 个事件或 100 KB(以先到者为准)自动刷新。长时间运行的游戏无需手动刷新。
短暂运行或无头运行可能在下一次自动刷新之前退出。此时请显式调用 Flush(),并让进程保持存活直到确认送达(详细日志会打印 HTTP 结果)。Flush() 只是异步启动一次发送,最后的排空会随进程退出一并完成,因此请调用 Flush() 后稍等片刻再退出,而不要在同一行紧接着退出。Godot SDK 0.1.5 及更高版本会在正常关闭时同步排空缓冲(上限 2.5 秒)。仍然没有离线队列,因此在该预算内发送失败的事件,或进程被强制终止时残留的事件,仍会丢失。见故障排查。
TelemetrySDK.Instance.Flush();识别玩家(可选)
Section titled “识别玩家(可选)”默认情况下事件以匿名方式发送。玩家登录后调用 SetPlayerId,后续事件即可关联到该玩家:
TelemetrySDK.Instance.SetPlayerId(playerId);运行时采样覆盖
Section titled “运行时采样覆盖”SDK 会应用一个全局采样率(默认 1.0 = 全部保留)。高频事件可以在运行时选用按事件名的采样率,覆盖全局采样率:
Framedash.TelemetrySDK.Instance.SetEventSamplingRate("ai_pathfind_step", 0.05f); // 约 5%Framedash.TelemetrySDK.Instance.RemoveEventSamplingRate("ai_pathfind_step"); // 回到全局采样率SetEventSamplingRate(string eventName, float rate) 设置采样率并钳制到 [0, 1],RemoveEventSamplingRate(string eventName) 移除该覆盖。自动收集的事件(session_start、perf_heartbeat)不受采样影响。
地图加载耗时采集
Section titled “地图加载耗时采集”自 Godot SDK 0.1.4 起可用。SDK 可以测量场景或关卡加载所需的时间,并将其作为 map_load 事件上报,进入构建比对(perf-diff)回归门禁以及仪表盘的加载耗时图表。
用 BeginMapLoad / EndMapLoad 包裹一次你自行控制的加载:
TelemetrySDK.Instance.BeginMapLoad("Level_01");// ... 加载场景 ...TelemetrySDK.Instance.EndMapLoad();BeginMapLoad 会在不受暂停和时间缩放影响的单调时钟上启动计时,EndMapLoad 则停止计时并发出事件。在 EndMapLoad 之前再次调用 BeginMapLoad,会替换掉当前挂起的测量。
如果自定义加载器或流式加载器已经自行测量了耗时,可以直接上报:
TelemetrySDK.Instance.ReportMapLoad("Level_01", 1234f); // 加载耗时(毫秒)当 loadTimeMs 为 NaN、无穷大或负值时,ReportMapLoad 会整个丢弃该样本(不会钳制)。
两条路径都会发出携带 metrics["load_time_ms"] 与 attributes["map_name"] 的 map_load 事件。该事件有意将 map_id 留空,因此不会进入空间热力图和激活门禁。这些调用可以从任意线程安全地进行,不会抛出异常,并且在 Initialize 之前为空操作。
磁盘 I/O 指标
Section titled “磁盘 I/O 指标”自 Godot SDK 0.1.4 起可用。SDK 可以把磁盘读取计数器以 io.read_bytes、io.read_time_ms、io.read_ops 这几个指标键附加到 perf_heartbeat 事件上。每个值都是相对上一次 heartbeat 的增量,并且只有在真正采集到样本之后这些键才会出现(不会填零)。与其他性能指标一样,io.* 会进入 perf-diff / builds-compare 回归门禁以及仪表盘图表。io.* 没有阈值告警。
Godot 没有自动的磁盘 I/O 来源,因此需要用 ReportIoSample 自行供给样本:
TelemetrySDK.Instance.ReportIoSample(bytes: 1048576, readTimeMs: 3.2f, ops: 12);内存分类指标
Section titled “内存分类指标”Godot SDK 0.1.5 及更高版本可用。SDK 会按 heartbeat 周期采样各内存分类的用量,并作为 mem.* 指标自动附加到 perf_heartbeat 事件上。这些值来自 Godot 的 Performance 监视器,无需任何 opt-in。
mem.vram:使用中的显存(字节)。mem.textures:纹理占用的显存(字节)。mem.buffers:缓冲区占用的显存(字节)。
读数为 0 或更低的采样会被省略:键缺失表示该值未收集,SDK 绝不会发送捏造的 0。
除 perf_heartbeat 外,这些键还会附加到带位置(map_id 非空)的事件上。由于 perf_heartbeat 的 map_id 为空、不会进入空间热力图网格,SDK 会把同一采样也放到带位置的事件上,从而支持逐单元格的内存热力图。带位置的事件携带的是按 heartbeat 周期刷新的缓存采样。
调用方传入的指标键始终优先,无论是键冲突还是容量:mem.* 只填充 50 个指标摄取上限以下剩余的槽位,且优先填入 mem.vram。
插件注册的 autoload 使用 TelemetrySDK.cs 的代码默认值创建,因此不能通过 Project Settings 编辑 [Export] 字段。常规设置应调用 TelemetrySDK.Initialize(...)。
如果你将 TelemetrySDK 脚本添加到自己控制的 scene node(例如自己的 autoload scene),则可以在 Inspector 中编辑 API key、endpoint、sampling rate 和 camera rotation 等 [Export] 字段。
首次集成时,请启用详细日志以确认发送:
TelemetrySDK.Instance.VerboseLogging = true;传输失败会记录重试阶梯,例如 [Framedash] Retry 1/3 in 1.0s (HTTP 0)。HTTP 0 表示传输层失败(DNS、TLS 或超时),而非 API 拒绝。若事件未到达,见故障排查。
无头 / CI
Section titled “无头 / CI”Godot 编辑器的 Build 会为 C# 项目生成 .csproj / .sln。godot --headless --build-solutions --quit 只会构建已存在的解决方案,无法在从未构建过的项目上生成初始的 .csproj / .sln:在全新的 CI-only 项目上,它可能以退出码 0 且无错误的方式结束,却仍未写出任何项目文件(在 4.6.3 mono 上观察到)。因此首次构建不能是无头构建。
对于从未在编辑器中打开过的 CI-only 项目,请先自行创建项目文件。在项目根目录手动编写 <project>.csproj,指定 Sdk="Godot.NET.Sdk/<engine version>" 并以 net8.0 为目标,同时让 Godot.NET.Sdk 版本与你构建所用的 Godot 版本一致:
<Project Sdk="Godot.NET.Sdk/4.6.3"> <PropertyGroup> <TargetFramework>net8.0</TargetFramework> <EnableDynamicLoading>true</EnableDynamicLoading> </PropertyGroup></Project>如果你至少能在编辑器中打开项目一次,另一种做法是在那里点击一次 Build,并提交生成的 .csproj / .sln。
项目文件就位后,用 .NET SDK 构建:
dotnet build编译后的程序集会生成在 .godot/mono/temp/bin/Debug/。由于插件只是注册一个 Initialize 能自行创建的 autoload,无头运行无需通过编辑器界面启用插件。
若事件未到达,见故障排查。
CI / 自动会话
Section titled “CI / 自动会话”在自动化测试或性能剖析运行中,请为整个会话打标签,使每个事件都携带 CI 构建及其 branch/commit/scenario。在测试入口处调用一次自动会话 API:
using Framedash;
// 所有参数均为可选。TelemetrySDK.Instance.BeginAutomatedSession( buildId: "build-123", branch: "main", commit: "abc1234", scenario: "nightly");// ... 运行自动化场景 ...TelemetrySDK.Instance.EndAutomatedSession();完整签名为 void BeginAutomatedSession(string buildId = null, string branch = null, string commit = null, string scenario = null)。在 CI 中,推荐使用 BeginAutomatedSessionFromEnvironment(),它会读取 FRAMEDASH_BUILD_ID、FRAMEDASH_GIT_BRANCH、FRAMEDASH_GIT_COMMIT 和 FRAMEDASH_TEST_SCENARIO(这些正是 framedash run-profile-test 导出的变量):
TelemetrySDK.Instance.BeginAutomatedSessionFromEnvironment();// ... 运行自动化场景 ...TelemetrySDK.Instance.EndAutomatedSession();自动会话会为会话内的每个事件打上 build_id 覆盖和 ci.branch / ci.commit / ci.scenario 属性,这正是进入构建比对(perf-diff)CI 门禁的依据。它不会改变任何事件的 source:SDK 自身的自动事件(session_start、perf_heartbeat)始终是 source=automated,而你的 Track 事件始终是 source=player,在 CI 与正常游玩中都一样。完整流水线见 CI 剖析。