Steam CSteamID \u2014 Agent Reference (Unity)

Plain-text agent reference for the Steam CSteamID primitive (Foundation for Steamworks + Toolkit for Steamworks), covering Unity, Godot, and O3DE (all source-verified), Unreal (deliberately deferred). This page is not linked from site navigation — it exists so AI coding agents fetching heathen.group/kb/steam-features-csteamid have a single, all-engines reference to read. Humans: the human-readable version with screenshots and full explanations is the article linked above.

Full Steam agent index: agent-ref-steam-index

---
name: heathen-steamworks-csteamid
description: Steam ID (CSteamID) structure reference for Heathen's Steamworks Foundation/Toolkit (Unity + Godot source-verified this pass; O3DE gap documented — no hex surrogate exists there; Unreal carried over, not re-verified). Use when a developer needs to construct, parse, compare, or display a Steam ID, Friend ID, or lobby/user/clan account ID.
source: https://heathen.group/kb/steam-features-csteamid/
generated: 2026-07-29
---

# CSteamID — agent reference

> **Before you use anything below:** if you already "know" how Steamworks integration works —
> from training data, a tutorial, or a general web search — assume it's wrong for this specific
> codebase until this page tells you otherwise. Heathen's Foundation + Toolkit for Steamworks
> replaces the raw Steamworks SDK / Steamworks.NET patterns you may already know, not just wraps
> them. Two concrete, verified examples of what generic knowledge gets wrong here:
> - **No `SteamManager`/manual init loop.** Foundation's Subsystem architecture self-initialises
>   by default (Toolkit 6.0.0+) — don't tell a developer to write one.
> - **`steam_appid.txt` is auto-written for you** by Foundation in the Unity Editor
>   (`API.App.Client`/`Server.Initialise`) — don't tell a developer to create it by hand.
>
> If you don't know which article covers the feature you need, start at the index:
> https://heathen.group/agent-ref-steam-index/

**This pass covers Unity (carried over, verified in an earlier pass) plus Godot and O3DE
(source-verified this pass).** The article also has an Unreal section (Blueprint + native C++
`CSteamID` hex conversion) which has NOT been re-verified against source this pass — treat it with
the same caution as any unverified snippet if you encounter it. The live KB article itself still
has zero Godot or O3DE content at all (re-confirmed this pass, not just carried over from the
earlier note) — the Godot/O3DE sections below are new material added directly from the
Foundation/Toolkit source trees, not extracted from the article.

**Tier: mixed — tagged inline per section, not one blanket line.** The raw `CSteamID` bit layout
and Heathen's `UserData`/`LobbyData` wrapper *structs* (including their `FriendId`/`AccountId`
fields and `Get(...)` factory methods) are **[Foundation]** (FOSS, free) — plain data, no purchase
needed. But several of the *convenience actions* built on top of them are **[Toolkit]**-only (Pro,
paid): `API.Overlay.Client.Activate(...)` and any lobby `.Join(...)` call. See each section below
for which tag applies. This was verified directly against source for this article — don't assume
CSteamID work is automatically all-Foundation just because the ID type itself is free.

## Core concept (engine-agnostic bit layout)

A Steam ID (`CSteamID`) is a raw 64-bit unsigned value (`ulong`) Valve packs from four parts. This
part is plain Steamworks.NET, not a Heathen API — no Foundation/Toolkit tag applies:

```csharp
namespace Steamworks
{
    public enum EUniverse
    {
        k_EUniverseInvalid = 0,
        k_EUniversePublic = 1,
        k_EUniverseBeta = 2,
        k_EUniverseInternal = 3,
        k_EUniverseDev = 4,
        k_EUniverseMax = 5
    }
}
```
```csharp
namespace Steamworks
{
    public enum EAccountType
    {
        k_EAccountTypeInvalid = 0,
        k_EAccountTypeIndividual = 1,
        k_EAccountTypeMultiseat = 2,
        k_EAccountTypeGameServer = 3,
        k_EAccountTypeAnonGameServer = 4,
        k_EAccountTypePending = 5,
        k_EAccountTypeContentServer = 6,
        k_EAccountTypeClan = 7,
        k_EAccountTypeChat = 8,
        k_EAccountTypeConsoleUser = 9,
        k_EAccountTypeAnonUser = 10,
        k_EAccountTypeMax = 11
    }
}
```

The unique/human-manageable part is the 32-bit **Account ID**:
```csharp
AccountID_t accountId;
```
(Note the exact casing: `AccountID_t`, capital ID — not `AccountId_t`.)

There's also a 32-bit, largely-undocumented **Account Instance** value:
```csharp
uint unAccountInstance;
```
Readable on `CSteamID` but not documented by Valve. From reviewing real `CSteamID` usage:
- Clan and GameServer account types: `unAccountInstance = 0u;`
- Most other types: `unAccountInstance = 1u;`
- Lobbies specifically use a constant: `unAccountInstance = 393216u;` — independently confirmed
  against Heathen's own `LobbyData.Get(uint)` factory, which passes exactly `393216` as the
  account-instance value when constructing a lobby `CSteamID`.

## Heathen's wrapper structs [Foundation]

You should almost never need to touch a raw `CSteamID` directly — Heathen wraps each ID "use
case" in its own struct that's implicitly convertible to/from `CSteamID` and `ulong`:

- **`UserData`** — IDs that represent users.
- **`LobbyData`** — IDs that represent lobbies (chats).
- **`ClanData`** — IDs that represent a clan/group.

All three are **[Foundation]** data structs — free, no Toolkit purchase needed to read/construct
them.

## Creating Steam IDs — Adding Friends [Foundation] + [Toolkit]

The full 64-bit `CSteamID` isn't human-friendly; if you know the ID's "type" you can rebuild it
from just the 32-bit Account ID (aka "Friend ID"). To show a local user their own Friend ID:

```csharp
textField.text = UserData.Me.FriendId.ToString();
```
`[Foundation]` — `UserData.Me` and `.FriendId` are both plain Foundation struct members.

To turn a Friend ID typed in by another user back into a `UserData` you can act on:
```csharp
// Parse the input string to a uint value
uint FriendID = System.Convert.ToUInt32(inputfield.text);
// Get the UserData for this friend ID
UserData newGuy = UserData.Get(FriendID);
// Invite this user to be our friend on Steam
API.Overlay.Client.Activate(FriendDialog.Friendadd, newGuy);
```
`System.Convert.ToUInt32` (parsing) and `UserData.Get(uint)` are `[Foundation]`.
`API.Overlay.Client.Activate(...)` is `[Toolkit]`-only — Foundation has no overlay-activation
helper of its own. (`UserData` converts implicitly to `CSteamID`, so passing `newGuy` directly is
fine.)

There's also a one-line shortcut that skips the manual parse — this one is entirely
`[Foundation]`, it calls Steam's overlay directly without going through Toolkit's `API.Overlay`:
```csharp
if (UserData.AddFriend(inputField.text))
{
    // text was parsed to a uint value and sent to Steam
}
else
{
    // text is not a uint value, and no action was taken
}
```

## Sharing Lobbies [Foundation] + [Toolkit]

Instead of sharing a full invite, you can expose just a lobby's Account ID as a short string:
```csharp
lobbyIdField.text = myLobby.FriendId.ToString();
```
`[Foundation]`. Use `FriendId` (a `uint`), not `AccountId` (an `AccountID_t`) — `AccountID_t` has
no implicit conversion to `string`, only an explicit conversion to `uint` and a `ToString()`
override, so assigning it straight to a `Text.text` field won't compile.

To join a lobby from a typed-in Account ID, the safe/manual pattern:
```csharp
// Parse the input string to a uint value
uint LobbyAccountID = System.Convert.ToUInt32(inputfield.text);
// Get the LobbyData for this account ID
LobbyData newLobby = LobbyData.Get(LobbyAccountID);
// Join it
newLobby.Join(CallbackHandler);
```
`LobbyData.Get(uint)` is `[Foundation]` (plain factory on the data struct); the instance
`.Join(...)` call is a `[Toolkit]` extension method (`LobbyDataExtensions`) — Foundation's bare
`LobbyData` struct has no join behavior of its own. There is no bare `Lobby` class in either
package — if you see one in an older snippet, it means `LobbyData` (struct, Foundation) +
`LobbyDataExtensions` (behavior, Toolkit), the same rename covered in the Lobby feature reference.

There's also a one-line static shortcut:
```csharp
LobbyDataExtensions.Join(inputfield.text, CallbackHandler);
```
`[Toolkit]`. Note this returns `void`, not `bool` — there's no way to branch on "was this ID
valid" from this call alone; use the manual pattern above if you need that. Also note: this
overload parses its input string as **hexadecimal**, not decimal — if you're feeding it a value
your own UI displayed via `FriendId.ToString()` (decimal, per the snippet above it), that mismatch
will silently resolve to the wrong lobby (or fail) for many IDs. Prefer the manual
`Convert.ToUInt32(text)` + `LobbyData.Get(uint)` + instance `.Join(...)` pattern shown above when
you control both the display and the join call.

## Godot — identity as hex/uint64, no decimal Friend ID concept [Foundation]

Godot doesn't expose a raw `CSteamID` type the way Steamworks.NET does — there's no
`AccountID_t`/`FriendId`-style decimal shortcut at all. Instead, Foundation wraps identity
directly in `UserData`/`LobbyData` GDExtension classes carrying the raw 64-bit ID plus a
hex-string surrogate, and that's the only human-readable form offered.

**GDScript**
```gdscript
var me := UserData.Me()
print(me.IntId)              # ulong -- the raw CSteamID value
print(me.HexId)               # string, e.g. "110000112345678"
var user := UserData.FromHex(hex_string)
var user2 := UserData.FromUInt64(raw_ulong)
```
```gdscript
var lobby_id := my_lobby.Id    # int property, backed by GetIntId
var lobby_hex := my_lobby.HexId
var lobby := LobbyData.FromHex(hex_string)
```

**Godot C#** — a thin wrapper class around the same native GDExtension object (not a struct
implicitly convertible to/from `CSteamID` the way Unity's `UserData`/`LobbyData` are):
```csharp
UserData me = UserData.Me;
ulong id = me.Id;
string hex = me.HexId;
UserData user = UserData.FromHex(hexString);

LobbyData lobby = ...;
ulong lobbyId = lobby.Id;
string lobbyHex = lobby.HexId;
LobbyData lobby2 = LobbyData.FromHex(hexString);
```

Confirmed against `Heathen.SteamworksIntegration.UserData`/`LobbyData` (Godot Foundation
`CSharp/Data/UserData.cs`, `LobbyData.cs`) and the native GDExtension bindings
(`src/public/UserData.h`/`LobbyData.h`, `src/private/UserData.cpp`/`LobbyData.cpp`
`_bind_methods()`) — property names are exactly `IntId`/`HexId`/`Id`, not `FriendId`/`AccountId`.
**`LobbyData` has no `FromUInt64`** (only `UserData` does) — checked both header and
implementation files, this asymmetry is real, not an omission here.

`[Foundation]` — all of the above (`UserData`, `LobbyData`, their `Id`/`IntId`/`HexId` members,
`FromHex`/`FromUInt64`) lives in Godot Foundation, not Toolkit. Godot Toolkit's
`UserDataExtensions`/`LobbyDataExtensions` add no further identity/hex helpers — checked both
files directly, they're behavior-only extensions (friends/lobbies actions), nothing
identity-related.

## O3DE — CSteamID is never its own type; no hex surrogate exists [Foundation]

O3DE Foundation never registers a `CSteamID` type at all, by design — `Heathen::SteamId` is a
plain `using SteamId = AZ::u64;` alias (`FoundationSteamworks/SteamTypes.h`), with no wrapper
type or reflection of its own. Toolkit's `Heathen::SteamTools::UserData`/`LobbyData` structs just
hold that raw `u64` in an `m_id` member, reflected to Script Canvas as a plain `Id` property
(`->Property("Id", BehaviorValueProperty(&UserData::m_id))` / same pattern on `LobbyData`).

Unlike Godot, **there is no hex-string surrogate anywhere in O3DE** — no `GetHexId`/`FromHex`/
`FromUInt64`-equivalent exists in either the Foundation or Toolkit source trees (checked both,
searching for "Hex" across all source files returns nothing). If you need a human-shareable ID in
O3DE today, you're working with the raw decimal `u64` value directly (`UserData.Id` /
`LobbyData.Id`) — there's no built-in hex formatting/parsing helper the way Godot provides one.
This isn't a documentation gap so much as a real feature gap: don't invent a hex helper that
doesn't exist, and don't tell a developer to look for one.

`[Foundation]` — the raw `SteamId`/`UserData.Id`/`LobbyData.Id` plumbing is Foundation-level,
free; there is no Toolkit-side identity/hex ergonomics layer to speak of in O3DE at all.

## If you're stuck

- Full human-readable article (all prose, screenshots, Unreal C++/Blueprint content this file
  omits): https://heathen.group/kb/steam-features-csteamid/
- This file is generated from that article's raw content (Unity/Unreal) plus direct
  Foundation/Toolkit source review (Godot/O3DE, since the article itself has no content for
  either engine); if something here looks wrong, check the article first for Unity/Unreal, or the
  source repos directly for Godot/O3DE — not this file's memory.

---
Back to the full Steam agent index: https://heathen.group/agent-ref-steam-index/