跳到內容

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。

SDK 已發布到 Godot Asset Library。此方式僅限 GUI。在 Godot 編輯器中:

  1. 開啟 AssetLib 分頁
  2. 搜尋 Framedash Telemetry SDK,並選擇版本 0.1.8
  3. 按一下 Download,接著按一下 Install。保持選取 addons/framedash/,讓外掛程式安裝到 res://addons/framedash/

若要固定發行版本或用於 CI,請複製 Framedash Godot SDK 儲存庫

Terminal window
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/

透過任一方式安裝後:

  1. 建置一次 C# 方案。這會產生 .csproj / .sln 並編譯外掛程式,讓其 autoload 型別可用。
  2. 在 Godot 編輯器中開啟 Project > Project Settings > Plugins
  3. 啟用 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");
}
}

endpointUrlbuildId 是選填項。省略 endpointUrl 時,SDK 會使用 https://ingest.framedash.dev/v1/events

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();

預設情況下事件會匿名傳送。玩家登入後呼叫 SetPlayerId,後續事件即可關聯到該玩家:

TelemetrySDK.Instance.SetPlayerId(playerId);

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_startperf_heartbeat)不受取樣影響。

自 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 之前為無操作。

自 Godot SDK 0.1.4 起可用。SDK 可以把磁碟讀取計數器以 io.read_bytesio.read_time_msio.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);

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_heartbeatmap_id 為空、不會進入空間熱力圖網格,SDK 會把同一取樣也放到帶位置的事件上,從而支援逐格的記憶體熱力圖。帶位置的事件攜帶的是按 heartbeat 週期更新的快取取樣。

呼叫方傳入的指標鍵一律優先,無論是鍵衝突還是容量:mem.* 只填入 50 個指標攝取上限以下剩餘的槽位,且優先填入 mem.vram

外掛程式註冊的 autoload 使用 TelemetrySDK.cs 的程式碼預設值建立,因此不能透過 Project Settings 編輯 [Export] 欄位。一般設定應呼叫 TelemetrySDK.Initialize(...)

如果你將 TelemetrySDK script 加到自己控制的 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 拒絕。若事件未到達,見疑難排解

Godot 編輯器的 Build 會為 C# 專案產生 .csproj / .slngodot --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 建置:

Terminal window
dotnet build

編譯後的組件會產生在 .godot/mono/temp/bin/Debug/。由於外掛程式只是註冊一個 Initialize 能自行建立的 autoload,無頭執行無需透過編輯器介面啟用外掛程式。

若事件未到達,見疑難排解

在自動化測試或效能剖析執行中,請為整個工作階段打標籤,使每個事件都攜帶 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_IDFRAMEDASH_GIT_BRANCHFRAMEDASH_GIT_COMMITFRAMEDASH_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_startperf_heartbeat)始終是 source=automated,而你的 Track 事件始終是 source=player,在 CI 與正常遊玩中都一樣。完整流水線見 CI 剖析