C API
Overview
The C API is a flat C ABI wrapped around RealtimeClient.
It exists so that the same client core can be used from a C translation unit and from any language that can call a C function and read a packed struct: C#, Rust, Python, Swift, Go etc.
Every entry point is a free function prefixed realtime_, takes an opaque handle as its first parameter and exchanges only ABI-stable types: int32_t, uint8_t, const char* for UTF-8 text, const uint8_t* plus a length for binary payloads, and packed structs.
Nothing crosses the boundary that a foreign language cannot describe: no C++ types, no exceptions, no coroutines and no function-pointer callbacks.
Three C++ mechanisms are therefore replaced by ABI-safe equivalents.
| C++ mechanism | C API equivalent |
|---|---|
Task<Result<T>> returned by an async operation |
The call returns void and the outcome arrives later as a matching *Result event on the event queue. |
Broadcaster subscriptions such as OnPlayerJoined |
Every broadcaster is pre-subscribed at creation time and forwarded onto the same event queue. |
Rich types such as RealtimeMap, PlayerView or RoomListing |
A documented byte layout, the blob format described further down this page. |
The rest of the Realtime Core documentation describes the behavior, this page describes how to reach it from C. Each manual page carries a C tab beside its C++ sample showing the same operation over this ABI.
Library and Header
The C API is a separate library target from Common and Matchmaking.
It builds as a shared library on platforms that support dynamic linking and otherwise as a static library.
| Path | Description |
|---|---|
RealtimeCore/CAPI/RealtimeCAPI.h |
The declarations of the whole ABI, plus the packed structs and the enums. |
RealtimeCore/lib/<platform>/<arch>/c_api_* |
The C API library for your platform and architecture. |
Library filenames follow the same scheme as the rest of the SDK, c_api_<platform>_<arch>[_<toolset>]_<config>_<runtime>.
A release build for Windows x64 against the static runtime produces c_api_windows_x86_64_release_mt.dll.
Additionally on platforms that support import libraries it ships with one.
Handles
Two opaque handles carry all state.
Both are void* and are only ever passed back into realtime_* functions.
| Handle | Created by | Destroyed by | Purpose |
|---|---|---|---|
RealtimeEventQueueHandle |
realtime_event_queue_create() |
realtime_event_queue_destroy() |
Receives async results and broadcaster events. |
RealtimeHandle |
realtime_create() |
realtime_destroy() |
One client, the equivalent of one RealtimeClient instance. |
The queue is created first and passed into realtime_create, which subscribes to every broadcaster on the new client before returning.
Destroy in the reverse order: the client first, then the queue.
realtime_create returns NULL when appId, appVersion or the queue handle is NULL.
Every other entry point tolerates a NULL handle by doing nothing and returning its documented zero value.
C
typedef void* RealtimeHandle;
typedef void* RealtimeEventQueueHandle;
RealtimeEventQueueHandle queue = realtime_event_queue_create();
RealtimeHandle client = realtime_create("your-app-id", "1.0", queue);
/* ... run the session ... */
realtime_destroy(client);
realtime_event_queue_destroy(queue);
The Event Queue
The queue replaces both Task<Result<T>> and the broadcasters.
Each entry is a fixed-size 28-byte RealtimeEvent; anything variable-length lives in a separate byte buffer, the blob, that the event addresses by offset and length.
C
#pragma pack(push, 4)
typedef struct
{
int32_t type; /* offset 0 - the event type */
uint32_t origin; /* offset 4 - per-event integer, often a sender */
uint32_t counter; /* offset 8 - per-event integer */
int32_t mode; /* offset 12 - error code on a *Result event */
int32_t blobOffset; /* offset 16 - byte offset into the blob buffer */
int32_t blobLength; /* offset 20 - byte length in the blob buffer */
int32_t _reserved; /* offset 24 - padding, reserved for future use */
} RealtimeEvent;
#pragma pack(pop)
Four functions drive it.
| Function | Description |
|---|---|
int32_t realtime_event_queue_poll(queue, RealtimeEvent* out, int32_t maxEvents) |
Copies up to maxEvents events into out, removes them from the queue and returns how many were copied. |
const uint8_t* realtime_event_queue_blob(queue, int32_t* outLength) |
Returns the blob buffer and writes its size to outLength. The offsets of a polled batch address into this buffer. |
void realtime_event_queue_flush(queue) |
Clears both the events and the blob buffer. |
void realtime_event_queue_destroy(queue) |
Frees the queue. |
Polling removes the events but retains the blob, so the offsets of a batch stay valid until you flush. The natural rhythm is therefore one poll and one flush per frame, after the pump.
C
static void PumpEvents(RealtimeHandle client, RealtimeEventQueueHandle queue)
{
RealtimeEvent events[64];
int32_t count;
realtime_service(client);
while ((count = realtime_event_queue_poll(queue, events, 64)) > 0)
{
int32_t blobLength = 0;
const uint8_t* blob = realtime_event_queue_blob(queue, &blobLength);
for (int32_t i = 0; i < count; ++i)
{
const RealtimeEvent* e = &events[i];
const uint8_t* payload = (e->blobOffset >= 0) ? blob + e->blobOffset : NULL;
HandleEvent(e, payload, e->blobLength);
}
}
realtime_event_queue_flush(queue);
}
An event whose payload that would push the buffer past its size limit is dropped with blobOffset = -1 and blobLength = 0, so always test blobOffset >= 0 before reading.
Event Types
Async results occupy 0 to 15 and broadcaster events 100 to 120.
Async Results
One of these arrives for every fire-and-forget call, in place of the C++ Task.
origin and counter are always 0.
mode carries the ErrorCode: 0 means success, anything else is a failure, and the blob then holds the error message as UTF-8 text with no length prefix and no terminator.
| Value | Event | Raised by | Blob on success |
|---|---|---|---|
| 0 | ConnectResult |
realtime_connect |
empty |
| 1 | DisconnectResult |
realtime_disconnect |
empty |
| 2 | CreateRoomResult |
realtime_create_room |
empty |
| 3 | JoinRoomResult |
realtime_join_room |
empty |
| 4 | JoinOrCreateRoomResult |
realtime_join_or_create_room |
empty |
| 5 | LeaveRoomResult |
realtime_leave_room |
empty |
| 6 | ReconnectResult |
realtime_reconnect |
empty |
| 7 | AvailableRegionsResult |
realtime_available_regions |
region array |
| 8 | SelectRegionResult |
realtime_select_region |
empty |
| 9 | JoinLobbyResult |
realtime_join_lobby |
empty |
| 10 | LeaveLobbyResult |
realtime_leave_lobby |
empty |
| 11 | GetLobbyStatsResult |
realtime_get_lobby_stats |
lobby-stats array |
| 12 | GetRoomListResult |
realtime_get_room_list |
room-listing array |
| 13 | JoinRandomRoomResult |
realtime_join_random_room |
empty |
| 14 | JoinRandomOrCreateRoomResult |
realtime_join_random_or_create_room |
empty |
| 15 | FindFriendsResult |
realtime_find_friends |
friend array |
The room operations report success with an empty blob rather than with a serialized room.
Read the joined room through the realtime_room_* queries once the result arrives.
Broadcaster Events
These mirror the callbacks documented in the client callbacks reference.
mode is always 0; the meaning of origin, counter and the blob differs per event.
| Value | Event | origin |
counter |
Blob |
|---|---|---|---|---|
| 100 | Disconnected |
DisconnectCause |
0 | empty |
| 101 | Error |
ErrorCode |
0 | message text |
| 102 | RoomPropertiesChanged |
0 | 0 | map |
| 103 | RoomListUpdated |
0 | 0 | room-listing array |
| 104 | MasterClientChanged |
new master player number | previous player number | empty |
| 105 | PlayerJoined |
player number | 0 | player |
| 106 | PlayerLeft |
player number | 1 when the player stays reserved | empty |
| 107 | PlayerPropertiesChanged |
player number | 0 | map |
| 108 | Event |
sender player number | event code | the raw event payload |
| 109 | DirectMessage |
sender player number | 1 when relayed by the server | the raw message payload |
| 110 | LobbyStats |
0 | 0 | lobby-stats array |
| 111 | CustomAuthStep |
0 | 0 | string map |
| 112 | AppStatsUpdated |
0 | 0 | empty |
| 113 | Warning |
warning code | 0 | empty |
| 114 | PropertiesChangeFailed |
0 | 0 | empty |
| 115 | CacheSliceChanged |
new cache slice index | 0 | empty |
| 116 | DirectConnectionEstablished |
remote player number | 0 | empty |
| 117 | DirectConnectionFailed |
remote player number | 0 | empty |
| 118 | CustomOperationResponse |
operation code | error code | error string, then a map |
| 119 | RoomJoined |
0 | 0 | empty |
| 120 | RoomLeft |
0 | 0 | empty |
Event (108) covers the whole 0 to 255 event-code range, the ABI's replacement for SubscribeEvent.
It forwards the raw wire payload, so a C client receives exactly the bytes the sender passed to realtime_send_event.
The Blob Format
All structured data crossing the ABI, properties, player lists and room listings alike, uses one small binary format.
It is native-endian and unaligned: every field follows the previous one with no padding, so read it with memcpy rather than by casting a struct pointer over it.
Three primitives make up everything else.
| Primitive | Layout |
|---|---|
| Integer | int32_t, int16_t, int64_t, uint8_t, float or double, in native byte order. |
| String | [int32 byteLength][UTF-8 bytes]. Not null-terminated. A length of 0 is the empty string. |
| Count-prefixed list | [int32 count][element]... |
Map
A map is the wire form of RealtimeMap and is what every property function consumes and produces.
[int32 entryCount]
per entry:
[int32 keyLength] [key UTF-8]
[uint8 typeTag] [payload]
Keys are always strings.
A RealtimeMap entry whose key is not a string, or whose value has no tag in the table below, is dropped from the blob rather than written with a mismatched tag.
entryCount is therefore the number of entries actually present, which can be lower than the map the sender started with.
| Tag | Type | Payload |
|---|---|---|
| 0 | bool |
uint8, 0 or 1 |
| 1 | byte | uint8 |
| 2 | int16 | int16 |
| 3 | int32 | int32 |
| 4 | int64 | int64 |
| 5 | float | float |
| 6 | double | double |
| 7 | string | string |
| 8 | byte array | [int32 count][bytes] |
| 9 | int32 array | [int32 count][int32]... |
| 10 | float array | [int32 count][float]... |
| 11 | string array | [int32 count][string]... |
Nested maps have no tag: a property value cannot itself be a map over this ABI.
String Array
[int32 count][string]...
Used for property-key lists (realtime_remove_player_properties, realtime_room_remove_properties), for the lobby-property key list, and for realtime_room_expected_users and realtime_room_plugins.
String Map
[int32 count] followed by a [string key][string value] pair per entry.
Only CustomAuthStep (111) uses it.
Player
The wire form of PlayerView, produced by realtime_local_player, realtime_room_players and the PlayerJoined event.
[int32 number]
[string name]
[string userId]
[map customProperties]
[uint8 isInactive]
[uint8 isMasterClient]
A player array is [int32 count] followed by that record per player.
Room Listing
The wire form of RoomListing, produced by realtime_get_cached_room_list, GetRoomListResult (12) and RoomListUpdated (103).
[string name]
[int32 playerCount]
[uint8 maxPlayers]
[uint8 isOpen]
[int32 directMessaging]
[map customProperties]
A room-listing array is [int32 count] followed by that record per room.
Region
Produced by AvailableRegionsResult (7) as [int32 count] followed by, per region:
[string code]
[string server]
[int32 pingMs]
Lobby Stats
Produced by GetLobbyStatsResult (11) and LobbyStats (110) as [int32 count] followed by, per lobby:
[string name]
[int32 type]
[int32 peerCount]
[int32 roomCount]
Friend
Produced by FindFriendsResult (15) and realtime_get_friend_list as [int32 count] followed by, per friend:
[string userId]
[uint8 isOnline]
[string roomName]
[uint8 isInRoom]
Blob Helpers
The C tabs throughout this manual build and read blobs with the small helper set below. It is not part of the SDK, so copy it into your project or replace it with whatever serialization layer your language already provides.
C
/* photon_blob.h - minimal blob writer and reader for the Realtime Core C API.
The blob format is native-endian and unaligned; every access goes through
memcpy so the code stays valid on strict-alignment targets too. */
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
/* --------------------------------- writer --------------------------------- */
typedef struct
{
uint8_t* data;
int32_t len;
int32_t cap;
int32_t countAt; /* offset of the count slot opened by rt_begin */
int32_t count; /* entries written since rt_begin */
} rt_blob;
static void rt_raw(rt_blob* b, const void* src, int32_t n)
{
if (b->len + n > b->cap)
{
b->cap = b->cap ? b->cap : 256;
while (b->cap < b->len + n) { b->cap *= 2; }
b->data = (uint8_t*)realloc(b->data, (size_t)b->cap);
}
memcpy(b->data + b->len, src, (size_t)n);
b->len += n;
}
static void rt_i32(rt_blob* b, int32_t v) { rt_raw(b, &v, 4); }
static void rt_u8(rt_blob* b, uint8_t v) { rt_raw(b, &v, 1); }
static void rt_str(rt_blob* b, const char* s)
{
int32_t n = s ? (int32_t)strlen(s) : 0;
rt_i32(b, n);
if (n > 0) { rt_raw(b, s, n); }
}
/* Maps and string arrays share the same [int32 count][entries...] framing. */
static void rt_begin(rt_blob* b) { b->countAt = b->len; b->count = 0; rt_i32(b, 0); }
static void rt_end(rt_blob* b) { memcpy(b->data + b->countAt, &b->count, 4); }
static void rt_free(rt_blob* b) { free(b->data); b->data = NULL; b->len = b->cap = 0; }
/* Map entries: [int32 keyLen][key][uint8 tag][payload]. */
static void rt_put_bool(rt_blob* b, const char* k, int32_t v) { rt_str(b, k); rt_u8(b, 0); rt_u8(b, v ? 1 : 0); ++b->count; }
static void rt_put_u8(rt_blob* b, const char* k, uint8_t v) { rt_str(b, k); rt_u8(b, 1); rt_u8(b, v); ++b->count; }
static void rt_put_i16(rt_blob* b, const char* k, int16_t v) { rt_str(b, k); rt_u8(b, 2); rt_raw(b, &v, 2); ++b->count; }
static void rt_put_i32(rt_blob* b, const char* k, int32_t v) { rt_str(b, k); rt_u8(b, 3); rt_i32(b, v); ++b->count; }
static void rt_put_i64(rt_blob* b, const char* k, int64_t v) { rt_str(b, k); rt_u8(b, 4); rt_raw(b, &v, 8); ++b->count; }
static void rt_put_f32(rt_blob* b, const char* k, float v) { rt_str(b, k); rt_u8(b, 5); rt_raw(b, &v, 4); ++b->count; }
static void rt_put_f64(rt_blob* b, const char* k, double v) { rt_str(b, k); rt_u8(b, 6); rt_raw(b, &v, 8); ++b->count; }
static void rt_put_str(rt_blob* b, const char* k, const char* v) { rt_str(b, k); rt_u8(b, 7); rt_str(b, v); ++b->count; }
/* String-array entries: [int32 len][utf8]. */
static void rt_add_str(rt_blob* b, const char* v) { rt_str(b, v); ++b->count; }
/* --------------------------------- reader --------------------------------- */
typedef struct { const uint8_t* p; int32_t len; int32_t pos; } rt_reader;
static rt_reader rt_read(const uint8_t* data, int32_t len)
{
rt_reader r;
r.p = data;
r.len = (data != NULL) ? len : 0;
r.pos = 0;
return r;
}
static int32_t rt_get_i32(rt_reader* r)
{
int32_t v = 0;
if (r->pos + 4 <= r->len) { memcpy(&v, r->p + r->pos, 4); r->pos += 4; }
else { r->pos = r->len; }
return v;
}
static float rt_get_f32(rt_reader* r)
{
float v = 0.0F;
if (r->pos + 4 <= r->len) { memcpy(&v, r->p + r->pos, 4); r->pos += 4; }
else { r->pos = r->len; }
return v;
}
static uint8_t rt_get_u8(rt_reader* r)
{
return (r->pos < r->len) ? r->p[r->pos++] : (uint8_t)0;
}
/* Returns a pointer into the blob and the byte length. UTF-8, NOT terminated. */
static const char* rt_get_str(rt_reader* r, int32_t* outLen)
{
int32_t n = rt_get_i32(r);
if (n < 0 || r->pos + n > r->len) { *outLen = 0; return ""; }
const char* s = (const char*)(r->p + r->pos);
r->pos += n;
*outLen = n;
return s;
}
/* Skip one map value whose tag byte has already been read. */
static void rt_skip_value(rt_reader* r, uint8_t tag)
{
int32_t n;
switch (tag)
{
case 0: case 1: r->pos += 1; break; /* bool, byte */
case 2: r->pos += 2; break; /* int16 */
case 3: case 5: r->pos += 4; break; /* int32, float */
case 4: case 6: r->pos += 8; break; /* int64, double */
case 7: case 8: n = rt_get_i32(r); r->pos += n; break; /* string, byte[] */
case 9: case 10: n = rt_get_i32(r); r->pos += n * 4; break; /* int32[], float[] */
case 11:
n = rt_get_i32(r);
for (int32_t i = 0; i < n; ++i) { r->pos += rt_get_i32(r); }
break;
default: r->pos = r->len; break; /* unknown tag */
}
if (r->pos > r->len) { r->pos = r->len; }
}
/* Skip a whole map, for stepping over the customProperties of a player or a
room listing on the way to the fields behind it. */
static void rt_skip_map(rt_reader* r)
{
int32_t n = rt_get_i32(r);
for (int32_t i = 0; i < n; ++i)
{
int32_t keyLen = 0;
(void)rt_get_str(r, &keyLen);
rt_skip_value(r, rt_get_u8(r));
}
}
Return-Pointer Lifetime
Every function that returns a const uint8_t* blob writes into the same internal scratch buffer on the client handle:
realtime_local_playerrealtime_get_friend_listrealtime_get_cached_room_listrealtime_room_custom_propertiesrealtime_room_playersrealtime_room_expected_usersrealtime_room_lobby_propertiesrealtime_room_plugins
Each of these calls invalidates the pointer the previous one returned, and realtime_service can clobber the buffer while it drains completed operations.
Read a returned blob, or copy its bytes into your own storage, before calling anything else on the handle.
The event-queue blob returned by realtime_event_queue_blob is a separate buffer with the different lifetime described above: it stays valid until realtime_event_queue_flush.
Functions that write text into a caller-supplied buffer, realtime_get_best_region, realtime_room_name, realtime_user_id and realtime_get_master_server_address, return the number of bytes written excluding the terminator, or the size the buffer needs when it was too small.
All four also return 0 for an invalid handle and for a genuinely empty string, so they cannot report "not set" on their own.
Pair realtime_room_name with realtime_has_current_room, and treat a 0 from realtime_get_best_region as "no region measured yet" only if you tracked an AvailableRegionsResult yourself.
Threading and Re-entrancy
All realtime_* calls on one handle must happen on the same thread, neither the pending-operation lists nor the event queue is guarded against concurrent access.
While iterating a polled batch you hold a pointer into the blob buffer.
A handler must therefore not call realtime_service, realtime_service_basic or realtime_dispatch_incoming_commands, because an inner pump can grow that buffer and invalidate the pointer for the rest of the batch.
Record what the handler wants to do and act on it after the loop.
ABI Reference
Parameters passed as int32_t where the C++ API takes an enum use the numeric values from the enums reference.
Out-of-range values are clamped to the documented default rather than forwarded: an unknown matchmakingMode or receiverGroup becomes FillRoom or Others, an unknown lobbyType becomes Default, and an unknown caching becomes DoNotCache.
Booleans are int32_t, where 0 is false and anything else is true.
Lifecycle and Pump
| Function | Description |
|---|---|
RealtimeHandle realtime_create(const char* appId, const char* appVersion, RealtimeEventQueueHandle) |
Creates a client and subscribes it to the queue. NULL on invalid arguments. |
void realtime_destroy(RealtimeHandle) |
Destroys the client and discards its pending operations. |
void realtime_service(RealtimeHandle) |
The full pump: network I/O, dispatch, send, and draining of completed operations into the queue. |
void realtime_service_basic(RealtimeHandle) |
Exchanges data with the socket layer only. |
int32_t realtime_send_outgoing_commands(RealtimeHandle) |
Sends queued outgoing commands; non-zero while more remain. |
int32_t realtime_send_acks_only(RealtimeHandle) |
Sends acknowledgements, or a ping on TCP and WebSocket. |
int32_t realtime_dispatch_incoming_commands(RealtimeHandle) |
Dispatches one queued incoming command; non-zero if one was dispatched. |
Connection
| Function | Description |
|---|---|
void realtime_connect(h, const char* userId, const char* username, int32_t authType, const char* authParameters, const char* serverAddress) |
Connects. Every parameter after the handle accepts NULL for the default. authType is a CustomAuthenticationType, where 255 is None. Raises ConnectResult. |
void realtime_disconnect(h) |
Raises DisconnectResult. |
void realtime_reconnect(h) |
Reconnects and rejoins the last room. Raises ReconnectResult. |
int32_t realtime_is_connected(h) |
1 or 0. |
int32_t realtime_is_in_room(h) |
1 or 0. |
int32_t realtime_is_in_lobby(h) |
1 or 0. |
int32_t realtime_state(h) |
A ConnectionState. |
int32_t realtime_disconnect_cause(h) |
A DisconnectCause. |
Connect, disconnect and reconnect are fire-and-forget.
Issuing a second one before the first completes is legal and both run, but the order their results arrive in is decided by the SDK, not by call order.
Chain off the *Result event instead of firing operations back to back.
Regions
| Function | Description |
|---|---|
void realtime_available_regions(h) |
Raises AvailableRegionsResult with a region array. |
void realtime_select_region(h, const char* region) |
Raises SelectRegionResult. |
int32_t realtime_get_best_region(h, char* out, int32_t size) |
Writes the best region from the last ping as UTF-8. |
Rooms
| Function | Description |
|---|---|
void realtime_create_room(h, const char* roomName, uint8_t maxPlayers, int32_t isVisible, int32_t isOpen, int32_t playerTtlMs, int32_t emptyRoomTtlMs, const char* plugins, const uint8_t* props, int32_t propsLength) |
A NULL roomName lets the server generate one, maxPlayers 0 means unlimited and plugins is a semicolon-separated list. props is a map blob of initial custom properties. Raises CreateRoomResult. |
void realtime_join_room(h, const char* roomName, int32_t rejoin) |
Raises JoinRoomResult. |
void realtime_join_or_create_room(h, ...) |
The same parameters as realtime_create_room; the properties apply only when the room is created. Raises JoinOrCreateRoomResult. |
void realtime_join_random_room(h, uint8_t maxPlayers, int32_t matchmakingMode, const char* lobbyName, int32_t lobbyType, const char* sqlFilter) |
Raises JoinRandomRoomResult. |
void realtime_join_random_or_create_room(h, uint8_t maxPlayers, int32_t isVisible, int32_t isOpen, int32_t playerTtlMs, int32_t emptyRoomTtlMs, const char* plugins, const uint8_t* props, int32_t propsLength) |
The server names the room it creates, so there is no roomName. Raises JoinRandomOrCreateRoomResult. |
void realtime_leave_room(h, int32_t willComeBack) |
willComeBack keeps the actor reservation alive for a rejoin within PlayerTtl. Raises LeaveRoomResult. |
Room Queries and Mutations
| Function | Description |
|---|---|
int32_t realtime_has_current_room(h) |
1 or 0. |
int32_t realtime_room_name(h, char* out, int32_t size) |
Writes the room name as UTF-8. |
int32_t realtime_room_player_count(h) |
The number of players in the room. |
uint8_t realtime_room_max_players(h) |
0 means unlimited. |
int32_t realtime_room_is_open(h), realtime_room_is_visible(h) |
1 or 0. |
int32_t realtime_room_master_client_id(h), realtime_room_is_master_client(h) |
The master client's player number, and whether it is the local player. |
int32_t realtime_room_player_ttl_ms(h), realtime_room_empty_room_ttl_ms(h) |
The room's TTL settings. |
int32_t realtime_room_publish_user_id(h) |
1 or 0. |
int32_t realtime_room_direct_mode(h) |
A DirectMode. |
int32_t realtime_room_suppress_room_events(h) |
1 or 0. |
const uint8_t* realtime_room_custom_properties(h, int32_t* outLength) |
Map blob. |
const uint8_t* realtime_room_players(h, int32_t* outLength) |
Player array blob. |
const uint8_t* realtime_room_expected_users(h, int32_t* outLength) |
String array blob. |
const uint8_t* realtime_room_lobby_properties(h, int32_t* outLength) |
String array blob of the keys published to the lobby. |
const uint8_t* realtime_room_plugins(h, int32_t* outLength) |
String array blob. |
int32_t realtime_room_set_open(h, int32_t), realtime_room_set_visible(h, int32_t) |
Non-zero when the change was sent. |
int32_t realtime_room_set_max_players(h, uint8_t) |
Non-zero when the change was sent. |
int32_t realtime_room_set_properties(h, const uint8_t* props, int32_t propsLength) |
Map blob. |
int32_t realtime_room_set_properties_expected(h, const uint8_t* props, int32_t propsLength, const uint8_t* expected, int32_t expectedLength) |
Compare-and-set; both are map blobs. |
int32_t realtime_room_remove_properties(h, const uint8_t* keys, int32_t keysLength) |
String array blob of keys. |
int32_t realtime_room_set_lobby_properties(h, const uint8_t* props, int32_t propsLength) |
String array blob of keys. |
int32_t realtime_room_set_expected_users(h, const uint8_t* users, int32_t usersLength) |
String array blob of user ids. |
int32_t realtime_room_set_master_client(h, int32_t playerNumber) |
Non-zero when the change was sent. |
Players
| Function | Description |
|---|---|
void realtime_set_player_name(h, const char* name) |
Sets the local player's name. |
void realtime_set_player_properties(h, const uint8_t* props, int32_t propsLength) |
Map blob. |
void realtime_remove_player_properties(h, const uint8_t* keys, int32_t keysLength) |
String array blob of keys. |
const uint8_t* realtime_local_player(h, int32_t* outLength) |
Player blob. |
int32_t realtime_local_player_number(h) |
-1 when not in a room. |
Lobbies and Matchmaking
| Function | Description |
|---|---|
void realtime_join_lobby(h, const char* lobbyName, int32_t lobbyType) |
Raises JoinLobbyResult. |
void realtime_leave_lobby(h) |
Raises LeaveLobbyResult. |
void realtime_get_lobby_stats(h) |
Raises GetLobbyStatsResult with a lobby-stats array. |
void realtime_get_room_list(h, const char* lobbyName, const char* sqlFilter) |
Raises GetRoomListResult with a room-listing array. |
const uint8_t* realtime_get_cached_room_list(h, int32_t* outLength) |
The last received room list, without a round trip. |
void realtime_set_auto_join_lobby(h, int32_t autoJoin) |
Whether a successful connect also joins the default lobby. |
Friends
| Function | Description |
|---|---|
void realtime_find_friends(h, const char** userIds, int32_t count) |
Raises FindFriendsResult with a friend array. |
const uint8_t* realtime_get_friend_list(h, int32_t* outLength) |
The last received friend array. |
int32_t realtime_get_friend_list_age(h) |
The age of that snapshot in milliseconds. |
Messaging
| Function | Description |
|---|---|
int32_t realtime_send_event(h, uint8_t eventCode, const uint8_t* data, int32_t dataLength, int32_t reliable, uint8_t channel, int32_t receiverGroup, const int32_t* targetPlayers, int32_t targetCount, uint8_t interestGroup, int32_t caching, int32_t encrypt, int32_t cacheSliceIndex) |
Sends a raw payload. targetPlayers may be NULL with targetCount 0, and takes precedence over receiverGroup when set. Non-zero on success. |
int32_t realtime_send_direct(h, const uint8_t* data, int32_t dataLength, const int32_t* targetPlayers, int32_t targetCount, int32_t receiverGroup, int32_t fallbackRelay) |
Peer-to-peer send with an optional server relay fallback. |
int32_t realtime_change_groups(h, const uint8_t* removeGroups, int32_t removeCount, const uint8_t* addGroups, int32_t addCount) |
Interest group subscriptions, as plain uint8_t arrays. |
int32_t realtime_send_custom_operation(h, uint8_t opCode, const uint8_t* params, int32_t paramsLength, int32_t reliable, uint8_t channelId, int32_t encrypt) |
params is a map blob. The response arrives as CustomOperationResponse (118). |
targetCount is capped at 65536 entries.
Authentication
| Function | Description |
|---|---|
void realtime_send_custom_auth_data(h, const uint8_t* data, int32_t dataLength) |
Answers a CustomAuthStep (111) with binary data. |
void realtime_send_custom_auth_string(h, const char* str) |
Answers with a UTF-8 string. |
void realtime_send_custom_auth_properties(h, const uint8_t* props, int32_t propsLength) |
Answers with a map blob. |
State and Statistics
| Function | Description |
|---|---|
int32_t realtime_server_time(h) |
The server timestamp in milliseconds. |
void realtime_fetch_server_timestamp(h) |
Requests a fresh server timestamp. |
int32_t realtime_user_id(h, char* out, int32_t size) |
Writes the user id as UTF-8. |
int32_t realtime_get_master_server_address(h, char* out, int32_t size) |
Writes the address as UTF-8. |
int32_t realtime_get_network_stats(h, RealtimeNetworkStats* out) |
Non-zero on success. |
int32_t realtime_get_traffic_stats_incoming(h, RealtimeTrafficStats* out) |
Non-zero on success. |
int32_t realtime_get_traffic_stats_outgoing(h, RealtimeTrafficStats* out) |
Non-zero on success. |
int32_t realtime_get_traffic_stats_game_level(h, RealtimeTrafficStatsGameLevel* out) |
Non-zero on success. |
int32_t realtime_get_traffic_stats_elapsed_ms(h) |
The length of the current measurement window. |
void realtime_set_traffic_stats_enabled(h, int32_t), int32_t realtime_get_traffic_stats_enabled(h) |
Traffic accounting is opt-in. The getter mirrors the last value set. |
void realtime_reset_traffic_stats(h) |
Clears the counters for a fresh window. |
int32_t realtime_get_count_players_online(h), realtime_get_count_players_ingame(h), realtime_get_count_games_running(h) |
The application stats from the last AppStatsUpdated (112). |
The three statistics structs are packed to 4 bytes, like RealtimeEvent.
C
#pragma pack(push, 4)
typedef struct
{
int32_t roundTripTime;
int32_t roundTripTimeVariance;
int32_t bytesIn;
int32_t bytesOut;
int32_t packetLossByCrc;
int32_t resentReliableCommands;
} RealtimeNetworkStats; /* 24 bytes */
typedef struct
{
int32_t packageHeaderSize;
int32_t reliableCommandCount;
int32_t unreliableCommandCount;
int32_t fragmentCommandCount;
int32_t controlCommandCount;
int32_t totalPacketCount;
int32_t totalCommandsInPackets;
int32_t reliableCommandBytes;
int32_t unreliableCommandBytes;
int32_t fragmentCommandBytes;
int32_t controlCommandBytes;
int32_t totalCommandBytes;
} RealtimeTrafficStats; /* 48 bytes */
typedef struct
{
int32_t operationByteCount;
int32_t operationCount;
int32_t resultByteCount;
int32_t resultCount;
int32_t eventByteCount;
int32_t eventCount;
int32_t longestOpResponseCallback;
int32_t longestEventCallback;
int32_t longestDeltaBetweenDispatching;
int32_t longestDeltaBetweenSending;
int32_t dispatchIncomingCommandsCalls;
int32_t sendOutgoingCommandsCalls;
} RealtimeTrafficStatsGameLevel; /* 48 bytes */
#pragma pack(pop)
Network Configuration
Each of these pairs a getter with a setter. See Configuration for which of them may change while connected.
| Getter | Setter |
|---|---|
int32_t realtime_get_disconnect_timeout(h) |
void realtime_set_disconnect_timeout(h, int32_t) |
int32_t realtime_get_ping_interval(h) |
void realtime_set_ping_interval(h, int32_t) |
uint8_t realtime_get_quick_resend_attempts(h) |
void realtime_set_quick_resend_attempts(h, uint8_t) |
int32_t realtime_get_crc_enabled(h) |
void realtime_set_crc_enabled(h, int32_t) |
int32_t realtime_get_limit_of_unreliable_commands(h) |
void realtime_set_limit_of_unreliable_commands(h, int32_t) |
Full Example
A complete C program, with the entry-point declarations it needs, is the C tab of the Quick Start Guide. It creates the queue and the client, connects, joins or creates a room, pings once a second until a ping arrives back, then disconnects.
Next Steps
Work through the manual with the C tab selected on each sample. Client and Service Loop and Asynchronous Operations cover the pump and the result model the queue replaces, and Callbacks and Subscriptions explains the events the queue delivers.
Back to top- Overview
- Library and Header
- Handles
- The Event Queue
- Event Types
- The Blob Format
- Blob Helpers
- Return-Pointer Lifetime
- Threading and Re-entrancy
- ABI Reference
- Lifecycle and Pump
- Connection
- Regions
- Rooms
- Room Queries and Mutations
- Players
- Lobbies and Matchmaking
- Friends
- Messaging
- Authentication
- State and Statistics
- Network Configuration
- Full Example
- Next Steps