# G-Less Telemetry for Unreal Engine 5

Fail-safe, opt-out telemetry for PC games and Steam demos. The runtime plugin records pseudonymous sessions, runs, progression and handled errors without putting network or file I/O on the gameplay thread.

## Runtime safety contract

- UE HTTP is asynchronous, capped at a 10-second request timeout, and cancelled best-effort on opt-out; gameplay never waits for a response.
- Durable queue reads and writes run on the thread pool, not the game thread.
- The queue is capped at 500 events and uploads at most 25 at a time. Under pressure, heartbeats and progress samples are discarded before run boundaries and errors.
- Failed uploads use exponential backoff with jitter (5 seconds up to 5 minutes). There is no tight retry loop.
- Events are stored under `Saved/GlessTelemetry` while offline and replayed on a later launch. Event IDs make retries safe to deduplicate server-side.
- `SetTelemetryEnabled(false)` immediately makes all public calls no-ops and asynchronously removes unsent local telemetry.
- The SDK does not install signal handlers, exception hooks or a crash reporter. An unclean session is inferred server-side from a missing `session_end` after the last heartbeat, so telemetry code does not run inside a crash path.

No software can promise survival against every engine, OS or hardware failure. This design keeps telemetry off critical gameplay paths, bounds its memory/disk workload, validates inputs, and uses weak UObject references in async callbacks so telemetry failure cannot intentionally fail game logic.

## Install

1. Copy `GlessTelemetry` to `<YourProject>/Plugins/GlessTelemetry`.
2. Regenerate project files and enable **G-Less Telemetry** in Unreal's Plugins window.
3. Add this to `Config/DefaultGame.ini`:

```ini
[GlessTelemetry]
EnabledByDefault=true
Endpoint=https://YOUR_HOST/api/telemetry/ingest
ProjectId=YOUR_PROJECT_UUID
WriteKey=gls_pk_YOUR_ONE_TIME_KEY
Channel=demo
BuildId=0.2.0-demo
HeartbeatSeconds=30
FlushSeconds=5
```

Use `Channel=demo`, `playtest`, `retail`, or `development`. Never reuse a build ID for materially different binaries. If any required endpoint/key value is absent, the subsystem stays inactive.

## Player privacy setting

Expose one localized checkbox, enabled by default, and apply it immediately:

```cpp
UGlessTelemetrySubsystem* Telemetry =
    GetGameInstance()->GetSubsystem<UGlessTelemetrySubsystem>();

Telemetry->SetTelemetryEnabled(bShareAnonymousTelemetry);
```

Suggested Simplified Chinese copy: **上报匿名的错误数据和云统计信息**. Store the same value in the game's normal user settings so it appears consistently in the UI; the SDK also persists a generic privacy value in `GameUserSettings.ini`.

## Gameplay instrumentation

The subsystem automatically emits `session_start`, `heartbeat`, and `session_end`. One process session can contain multiple gameplay runs.

```cpp
Telemetry->StartRun(TEXT("standard"));
Telemetry->SetProgress(CurrentDepthMeters, CurrentBiome);
Telemetry->EndRun(TEXT("completed"), FinalScore);
Telemetry->ReportError(TEXT("save_recovered"), TEXT("checkpoint_load"));
```

For multiplayer games, the generic SDK also supports a matchmaking funnel and
run population changes without knowing anything about a specific title:

```cpp
Telemetry->TrackMatchmakingAttempt(TEXT("four_v_four"), PartySize);
Telemetry->TrackMatchmakingResult(TEXT("four_v_four"), true, TEXT("matched"), PartySize, Teammates, WaitSeconds);
Telemetry->StartRunWithContext(TEXT("four_v_four"), Players, Teammates, true, true);
Telemetry->UpdateRunPopulation(Players, Teammates);
```

All public functions are Blueprint-callable. Only report handled errors using stable codes; do not send exception text, paths, Steam names, emails, chat or other direct identifiers.

## Event conventions

- Event names: stable `snake_case`, up to 80 characters.
- Player ID: random installation UUID; never replace it with a Steam ID or display name.
- Run outcomes: use a small stable vocabulary such as `completed`, `won`, `lost`, `draw`, `quit_to_lobby`, and `abandoned`.
- Matchmaking results: use stable values such as `matched`, `cancelled`, `network_failure`, `travel_failure`, and `oss_unavailable`.
- The write key grants append-only ingest access to its project. It cannot read analytics or manage the project.
