콘텐츠로 이동

Godot SDK

Framedash Godot SDK(C# 애드온)를 사용하여 퍼포먼스 텔레메트리를 자동으로 수집하는 방법을 설명합니다.

  • Godot 4.3 이상 .NET(C#) 빌드. 표준 GDScript 전용 빌드는 C# 애드온을 컴파일할 수 없습니다.
  • .NET 8 SDK 이상(net8.0을 타깃팅할 수 있는 SDK면 됩니다. 애드온은 net8.0을 타깃으로 하는 게임 어셈블리로 빌드됩니다)
  • Web(HTML5) export는 Godot 4에서 .NET web export를 지원하지 않으므로 지원되지 않습니다.

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을 생략하면 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개나 100KB에 도달하는 시점 중 먼저 오는 쪽에 자동으로 플러시됩니다. 오래 실행되는 게임은 손으로 플러시할 필요가 없습니다.

짧게 실행되거나 헤드리스로 실행되면 다음 자동 플러시 전에 종료될 수 있습니다. 이때는 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_start, perf_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); // 로드 시간(밀리초)

ReportMapLoadloadTimeMs가 NaN, 무한대, 음수일 때 해당 샘플을 통째로 버립니다(클램프하지 않습니다).

두 경로 모두 metrics["load_time_ms"]attributes["map_name"]를 담은 map_load 이벤트를 발생시킵니다. 이 이벤트는 의도적으로 map_id를 비워 두므로 공간 히트맵과 활성화 게이트의 대상에서 제외됩니다. 이 호출들은 어느 스레드에서든 안전하게 호출할 수 있고, 예외를 던지지 않으며, Initialize 전에는 아무 동작도 하지 않습니다.

Godot SDK 0.1.4 이상에서 사용할 수 있습니다. SDK는 디스크 읽기 카운터를 io.read_bytes, io.read_time_ms, io.read_ops 메트릭 키로 perf_heartbeat 이벤트에 첨부할 수 있습니다. 각 값은 이전 heartbeat 이후의 델타이며, 실제 샘플이 들어온 뒤에야 키가 붙습니다(0으로 채우지 않습니다). 다른 성능 메트릭과 마찬가지로 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 주기로 메모리 카테고리별 사용량을 샘플링해 perf_heartbeat 이벤트에 mem.* 메트릭으로 자동 첨부합니다. 값은 Godot의 Performance 모니터에서 가져오며, 옵트인이 필요 없습니다.

  • 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(...)를 호출해 구성하세요.

직접 관리하는 scene node(예: 자체 autoload scene)에 TelemetrySDK 스크립트를 추가한 경우에만 Inspector에서 API key, endpoint, sampling rate, camera rotation 등의 [Export] 필드를 편집할 수 있습니다.

첫 통합 시에는 상세 로깅을 켜서 전송을 확인하세요.

TelemetrySDK.Instance.VerboseLogging = true;

전송 실패 시 재시도 사다리를 기록합니다. 예: [Framedash] Retry 1/3 in 1.0s (HTTP 0). HTTP 0은 API 거부가 아니라 전송 계층 실패(DNS, TLS, 타임아웃)를 뜻합니다. 이벤트가 도달하지 않으면 문제 해결을 참고하세요.

Godot 에디터의 Build는 C# 프로젝트의 .csproj / .sln을 생성합니다. godot --headless --build-solutions --quit기존 솔루션을 빌드할 뿐, 한 번도 빌드한 적 없는 프로젝트에서는 초기 .csproj / .sln을 생성하지 못합니다. 새 CI 전용 프로젝트에서는 종료 코드 0으로 오류 없이 끝나면서도 프로젝트 파일을 전혀 쓰지 않을 수 있습니다(4.6.3 mono에서 확인). 따라서 첫 빌드는 헤드리스로 할 수 없습니다.

에디터에서 한 번도 연 적 없는 CI 전용 프로젝트에서는 먼저 프로젝트 파일을 직접 만드세요. 프로젝트 루트에 <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를 등록할 뿐이므로, 헤드리스 실행에서는 에디터 UI로 플러그인을 활성화할 필요가 없습니다.

이벤트가 도달하지 않으면 문제 해결을 참고하세요.

자동화 테스트나 프로파일링 실행에서는 세션 전체에 태그를 달아 모든 이벤트가 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 프로파일링을 참고하세요.