Skip to content

08 — Server / Client API Reference (lattice.h)

Status: Reference (authoritative for the implemented public C ABI). Source of truth: reference/include/lattice/lattice.h — the real, compilable C ABI exported by liblattice.so. Every signature below is copied verbatim from that header. Read alongside: README · 02 Netcode LLD (wire/semantics) · 05 Engine Integration (ergonomic per-engine API) · 07 Reference Implementation & Conformance (what the skeleton implements + the test harness).


0. How to read this document

This is the function-level reference for everything an engine binding (lattice-unity, lattice-unreal, lattice-godot, lattice-web) or a native integrator compiles against. It is organized by role and topic:

  1. Runner lifecycle & the tick pump
  2. Server / host functions
  3. Client functions
  4. Serialization API — BitWriter / BitReader
  5. Callback / event model, threading & enums
  6. C ABI → engine high-level mapping

For each public function you get: the real signature, parameters, return value + error codes, the role (server / client / both) it is valid on, and a short usage snippet.

0.1 Scope: public ABI vs. test-only hooks

Two families of symbols live in lattice.h:

Family Prefix Status
Public ABI lattice_* (everything in §§1–4 here) The supported engine-binding surface. Stable; this is what bindings call.
Test-only hooks lattice_test_* NOT part of the public API. Conformance/unit-test scaffolding only.

The lattice_test_* symbols are TEST-ONLY hooks and are deliberately excluded from this reference. They exist solely so the conformance harness can drive the internal deterministic network-condition simulator (NetSim), the loopback "wire", the reliability layer, and the ACK-bitfield logic without reaching into an internal header — see 07 Reference Implementation & Conformance. They are namespaced lattice_test_* precisely so they are obviously distinct from production calls, and a shipping build may strip them entirely. Do not bind against them, do not document them to game developers, and do not rely on them at runtime. (For the curious, they cover: lattice_test_netsim_*, lattice_test_wire_*, lattice_test_reliable_*, and lattice_test_ack_bitfield — all test scaffolding for 02 §5 reliability and 02 §3.4 ACK-bitfield conformance.)

0.2 Provenance & currency note

This reference documents the implemented reference ABI as it exists now (lattice.h + liblattice.so). The reference core is a faithful, compilable model of the documented wire encodings, plus an in-memory loopback transport, simple delta replication, and reliable RPC; it deliberately omits crypto, NAT/relay, prediction/rollback, and interest management (those are documented as design in 02 and called out as extension points in 07). This document is current as of the present core and is kept updated as later features add calls — when the production core lands prediction, AoI, authority transfer, etc., their ABI entry points are added here in the same per-function format.

Note on naming: 05 §2.2 shows a representative ABI sketch using lt_* names and lt_prefab_id/lt_field_id handles. That sketch is illustrative of the binding strategy; the implemented ABI uses the lattice_* names and the handle/typedef set documented here. Where they differ, this document and lattice.h are authoritative.

0.3 Universal ABI rules (02 §19, lattice.h header comment)

These hold for every function below:

  • Opaque handles. lattice_runner*, lattice_bitwriter*, lattice_bitreader* are forward-declared incomplete types. Never dereference them.
  • POD only across the line. No C++ types, STL containers, or exceptions ever cross the boundary. Structs are fixed-layout POD, passed by value or pointer.
  • Caller-owned buffers. All buffers you pass in are caller-owned; the core copies anything it retains (type descriptors, field arrays, key strings, initial state, RPC payloads).
  • Little-endian wire. Byte-aligned scalars are little-endian; bit-packed fields are MSB-first within each byte, consistently on both ends (02 §20.3).
  • Synchronous callbacks. All callbacks fire synchronously inside lattice_runner_tick() on the calling thread. Do no blocking work in them, and never let an exception propagate out of one into the core.
  • Status codes, not exceptions. Functions that can fail return lattice_result; outputs are written through pointers. Use lattice_result_str to render a code.

1. Runner lifecycle & the tick pump

A runner (lattice_runner) is one networked simulation instance — the implemented analogue of 05's NetworkRunner / ULatticeRunnerSubsystem / LatticeRunner node. The lifecycle is the same for every role; the role is chosen by lattice_runner_start.

1.1 The standard sequence

create → set_callbacks → start(MODE) → listen(port)  [SERVER/HOST]
                                      \ connect(addr,port,token) [CLIENT]
→ register_type (×N, identically on every peer)
→ loop: tick(dt)            // recv → tick → send; callbacks fire here
→ destroy

1.2 lattice_runner_create

LATTICE_API lattice_runner* lattice_runner_create(const lattice_runner_config* cfg);

Create a runner. Role: both.

Param Meaning
cfg Optional lattice_runner_config. May be NULL for all defaults. Deep-copied; need not outlive the call.

Returns: an owning lattice_runner*, or NULL on allocation failure. Destroy with lattice_runner_destroy.

1.2.1 lattice_runner_config

typedef struct {
    uint32_t tick_rate_hz; /* fixed simulation rate; default 60 if 0 */
    uint32_t max_objects;  /* soft hint; 0 => unbounded in this skeleton */
    uint32_t reserved;
} lattice_runner_config;

tick_rate_hz sets the fixed simulation rate (default 60 Hz, 02 §10.1); max_objects is a soft capacity hint (0 ⇒ unbounded in the reference). Leave reserved zeroed.

lattice_runner_config cfg = { .tick_rate_hz = 60, .max_objects = 4096, .reserved = 0 };
lattice_runner* r = lattice_runner_create(&cfg);
if (!r) { /* OOM */ }

1.3 lattice_runner_set_callbacks

LATTICE_API lattice_result lattice_runner_set_callbacks(lattice_runner* r, const lattice_callbacks* cb);

Install the event callback table. Role: both. Set this before start/listen/connect so no event is missed. The lattice_callbacks struct (including its user_data) is copied; the function pointers must remain valid for the runner's lifetime.

Returns: LATTICE_OK, or LATTICE_ERR_INVALID_ARG if r is NULL.

lattice_callbacks cb = {0};
cb.user_data       = my_ctx;
cb.on_spawned      = on_spawned;
cb.on_state_updated= on_state_updated;
cb.on_despawned    = on_despawned;
cb.on_rpc          = on_rpc;
lattice_runner_set_callbacks(r, &cb);

1.4 lattice_runner_start

LATTICE_API lattice_result lattice_runner_start(lattice_runner* r, lattice_game_mode mode);

Put the runner into a role. Role: both (the mode decides which). Call once, after create/set_callbacks and before listen/connect.

mode (lattice_game_mode) Role Authority Local participant
LATTICE_MODE_SERVER Dedicated server yes no (headless)
LATTICE_MODE_HOST Listen-server / P2P host yes yes
LATTICE_MODE_CLIENT Client no yes
LATTICE_MODE_SHARED_HOST Shared/distributed authority yes (per-object owners) yes — behaves like HOST in the reference

Returns: LATTICE_OK, or LATTICE_ERR_INVALID_ARG.

lattice_runner_start(r, LATTICE_MODE_HOST);   // listen-server that is also a player

1.5 lattice_runner_listen

LATTICE_API lattice_result lattice_runner_listen(lattice_runner* r, uint16_t port);

Begin accepting connections on port. Role: server / host only (valid after start with SERVER, HOST, or SHARED_HOST). In the reference's loopback transport port is a logical rendezvous id rather than a real socket bind.

Returns: LATTICE_OK; LATTICE_ERR_INVALID_ARG (bad r); LATTICE_ERR_NO_SESSION if start has not been called or the mode is CLIENT.

lattice_runner_listen(r, 7777);

1.6 lattice_runner_connect

LATTICE_API lattice_result lattice_runner_connect(lattice_runner* r, const char* addr, uint16_t port,
                                                  const uint8_t* token, uint32_t token_len);

Initiate a client connection. Role: client only (valid after start with CLIENT). See 3.1.

1.7 lattice_runner_tick — the recv → tick → send pump

/* Pump one or more fixed steps. Order per step is recv -> tick -> send; callbacks
 * fire synchronously on the calling thread (docs/02 §19 ABI rules). */
LATTICE_API lattice_result lattice_runner_tick(lattice_runner* r, double dt);

Advance the runner. Role: both. This is the single pump the host loop drives every frame, and it is the only place callbacks fire.

Per fixed step the runner performs, in order:

  1. recv — drain inbound datagrams; decode snapshots/RPCs/connect events into an internal queue.
  2. tick — advance the simulation one fixed step; apply replicated deltas; drain the event queue, firing callbacks synchronously on this thread (on_spawned, on_state_updated, on_rpc, etc.).
  3. send — build and pace outbound snapshots and ACKs (server/host), or input/RPC traffic (client).

dt is real wall-clock seconds since the last call; the runner internally accumulates and may run zero or more fixed steps of 1 / tick_rate_hz to consume it (02 §10.1 accumulator loop). Drive it from the engine's fixed step (Unity FixedUpdate, Unreal game thread tick, Godot _physics_process) on the main/game thread, because callbacks land on the calling thread (§5.5).

Returns: LATTICE_OK; LATTICE_ERR_INVALID_ARG (bad r); LATTICE_ERR_NOT_CONNECTED / LATTICE_ERR_NO_SESSION if pumped before a session exists.

double last = now_seconds();
for (;;) {
    double t = now_seconds(), dt = t - last; last = t;
    lattice_runner_tick(r, dt);   // recv -> tick -> send; callbacks fire inside here
}

1.8 lattice_runner_state

LATTICE_API lattice_connection_state lattice_runner_state(lattice_runner* r);

Current connection state. Role: both. Returns a lattice_connection_state (DISCONNECTED / CONNECTING / CONNECTED / DISCONNECTING); a NULL runner reports LATTICE_CONN_DISCONNECTED. Clients poll this after connect to know when the handshake completed (the on_connected callback is the event-driven equivalent).

if (lattice_runner_state(r) == LATTICE_CONN_CONNECTED) { /* ready */ }

1.9 lattice_runner_destroy

LATTICE_API void lattice_runner_destroy(lattice_runner* r);

Tear down the runner and free all core-owned storage (objects, snapshot buffers, type registry, connection state). Role: both. Idempotent-safe on NULL. After this the handle is invalid; do not call any other function with it. The core never frees buffers you own.


2. Server / host functions

The functions in this section require authority — i.e. the runner was started with LATTICE_MODE_SERVER, LATTICE_MODE_HOST, or LATTICE_MODE_SHARED_HOST. Spawning/despawning and authoritative state writes from a plain CLIENT are rejected (see each function's error codes). Type registration and the serialization helpers are role-agnostic and must run identically on every peer so schemas match.

2.1 lattice_register_type

LATTICE_API lattice_type_id lattice_register_type(lattice_runner* r, const lattice_type_desc* desc); /* 0 on error */

Register a replicable type (a NetworkObject/struct schema). Role: both — and it must be called in the same order with the same descriptors on the server and every client, so the derived type_ids and the content hash agree (05 §7, 02 §20.2). The core deep-copies the field array and key string, so your buffers need not outlive the call.

Param Meaning
r The runner.
desc A lattice_type_desc describing the type's state block + serialization.

Returns: a non-zero lattice_type_id on success; 0 on error (NULL args, zero state_size, malformed field array, or a key collision).

2.1.1 lattice_type_desc

typedef struct {
    const char*               key;          /* stable type key; hashed + matched across peers */
    uint32_t                  state_size;   /* bytes of the local state block for one object   */
    const lattice_field_desc* fields;       /* may be NULL when the manual path is used         */
    uint32_t                  field_count;
    lattice_serialize_fn      serialize;    /* optional manual path; NULL => declarative        */
    lattice_deserialize_fn    deserialize;  /* optional manual path                             */
    void*                     user;         /* passed back to manual fns                        */
} lattice_type_desc;

Two registration paths, chosen by whether serialize/deserialize are set:

  • Declarative path (serialize == NULL): the core walks the fields array (one lattice_field_desc per replicated leaf field) and packs/unpacks each field from the state block automatically. This is the analogue of the codegen output in 02 §20 — the [Networked]/UPROPERTY declarative path of 05 §12.2.
  • Manual path (serialize/deserialize non-NULL): the whole state block is one unit; your function drives a BitWriter/BitReader. This is the INetworkSerializable path of 05 §12.3 / 02 §21. user is handed back to both functions.
typedef void (*lattice_serialize_fn)(lattice_bitwriter* w, const void* state, void* user);
typedef void (*lattice_deserialize_fn)(lattice_bitreader* r, void* state, void* user);

The key is hashed into the schema/version negotiation; mismatched catalogs are rejected at connect (see lattice_type_content_hash).

2.1.2 lattice_field_desc

typedef struct {
    const char*         name;        /* field name (part of the content hash) */
    lattice_field_kind  kind;
    uint32_t            offset;      /* byte offset of this field in the state block */
    lattice_float_quant quant;       /* for COMPRESSED_FLOAT / VECTOR*            */
    int32_t             ranged_min;  /* for RANGED_INT                            */
    int32_t             ranged_max;  /* for RANGED_INT                            */
    uint32_t            quat_bits;   /* for QUATERNION smallest-three (default 10)*/
    uint32_t            byte_capacity;/* for STRING/BYTES: fixed capacity in block*/
    lattice_type_id     struct_type; /* for STRUCT: a nested registered type      */
} lattice_field_desc;

One entry per replicated leaf field in the declarative path. kind is a lattice_field_kind; offset is the field's byte offset within the state block; the remaining fields are encoding hints used only by the relevant kind (quantization for COMPRESSED_FLOAT/VECTOR*, ranged_min/max for RANGED_INT, quat_bits for QUATERNION, byte_capacity for STRING/BYTES, struct_type for a nested STRUCT). name participates in the content hash. See 02 §14.6 for the wire encodings.

Declarative registration example:

typedef struct { float health; lattice_vec3 pos; int32_t score; } PlayerBlock;

lattice_field_desc fields[] = {
  { .name="health", .kind=LATTICE_FIELD_COMPRESSED_FLOAT, .offset=offsetof(PlayerBlock,health),
    .quant={ .min=0.f, .max=100.f, .precision=0.1f } },
  { .name="pos",    .kind=LATTICE_FIELD_VECTOR3, .offset=offsetof(PlayerBlock,pos),
    .quant={ .min=-4096.f, .max=4096.f, .precision=0.001f } },        /* 1 mm */
  { .name="score",  .kind=LATTICE_FIELD_RANGED_INT, .offset=offsetof(PlayerBlock,score),
    .ranged_min=0, .ranged_max=1000000 },
};
lattice_type_desc desc = {
  .key="Player", .state_size=sizeof(PlayerBlock),
  .fields=fields, .field_count=3,
};
lattice_type_id PLAYER = lattice_register_type(r, &desc);   // 0 == failure

Manual registration example:

static void player_ser(lattice_bitwriter* w, const void* s, void* u) {
    const PlayerBlock* p = s;
    lattice_bw_write_compressed_float(w, p->health, (lattice_float_quant){0,100,0.1f});
    lattice_bw_write_vector3(w, p->pos, (lattice_float_quant){-4096,4096,0.001f});
    lattice_bw_write_ranged_int(w, p->score, 0, 1000000);
}
static void player_deser(lattice_bitreader* r, void* s, void* u) {
    PlayerBlock* p = s;
    p->health = lattice_br_read_compressed_float(r, (lattice_float_quant){0,100,0.1f});
    p->pos    = lattice_br_read_vector3(r, (lattice_float_quant){-4096,4096,0.001f});
    p->score  = lattice_br_read_ranged_int(r, 0, 1000000);
}
lattice_type_desc desc = { .key="Player", .state_size=sizeof(PlayerBlock),
                           .serialize=player_ser, .deserialize=player_deser };
lattice_type_id PLAYER = lattice_register_type(r, &desc);

2.2 lattice_spawn

LATTICE_API lattice_netid lattice_spawn(lattice_runner* r, lattice_type_id type,
                                        const void* initial_state, uint64_t owner); /* authority only; 0 on error */

Create a replicated object. Role: authority only (server / host / shared-host). The core allocates a stable lattice_netid, copies initial_state (a state_size-byte block of type) into its arena, and queues a spawn to peers — firing on_spawned on the authority and on every receiving client during their next tick.

Param Meaning
type A lattice_type_id from lattice_register_type.
initial_state Pointer to the initial state block (copied). May be NULL ⇒ zero-initialized.
owner The owning peer id (0 for none / server-owned). Used by RPC OWNER targeting and authority semantics.

Returns: a non-zero lattice_netid; 0 on errortype unknown, runner not authority (client called it), or no session.

PlayerBlock init = { .health = 100.f, .score = 0 };
lattice_netid id = lattice_spawn(r, PLAYER, &init, owner_peer);   // 0 == failed

2.3 lattice_despawn

LATTICE_API lattice_result lattice_despawn(lattice_runner* r, lattice_netid id);

Destroy a replicated object. Role: authority only. Queues a despawn to peers and fires on_despawned on every peer (and locally) on the next tick; the core frees the object's state block.

Returns: LATTICE_OK; LATTICE_ERR_UNKNOWN_OBJECT (no such id); LATTICE_ERR_NOT_AUTHORITY (caller is a client); LATTICE_ERR_INVALID_ARG.

lattice_despawn(r, id);

2.4 lattice_object_state

LATTICE_API void* lattice_object_state(lattice_runner* r, lattice_netid id); /* mutable; NULL if unknown */

Get a pointer to the object's mutable host-memory state block. Role: both — but the meaning differs:

  • On the authority this is the writable source of truth. Mutate fields in place, then call lattice_object_mark_dirty so the change is included in the next snapshot.
  • On a client this is the locally-replicated copy maintained by the core. Treat it as read-only: read it (typically inside on_state_updated) to drive your view. Authoritative writes from a client are not replicated.

Returns: a pointer to the state_size-byte block, or NULL if id is unknown. The pointer is valid until the object is despawned or the runner is destroyed; do not free it.

PlayerBlock* p = lattice_object_state(r, id);   // NULL if unknown
if (p) { p->health -= 10.f; lattice_object_mark_dirty(r, id, /*field*/0); }

2.5 lattice_object_mark_dirty

LATTICE_API lattice_result lattice_object_mark_dirty(lattice_runner* r, lattice_netid id, uint32_t field_index);

Mark a field of an object dirty so it is delta-encoded into the next snapshot. Role: authority (writes are authority-gated). field_index is the index into the type's fields array (declarative path); for the manual path, marking any field re-serializes the whole block. The dirty bit drives delta compression (02 §14.2–14.3).

Returns: LATTICE_OK; LATTICE_ERR_UNKNOWN_OBJECT; LATTICE_ERR_NOT_AUTHORITY (client caller); LATTICE_ERR_INVALID_ARG (e.g. field_index out of range).

PlayerBlock* p = lattice_object_state(r, id);
p->score += 50;
lattice_object_mark_dirty(r, id, 2);   // field index 2 == "score"

2.6 lattice_object_count / lattice_object_at

LATTICE_API uint32_t      lattice_object_count(lattice_runner* r);
LATTICE_API lattice_netid lattice_object_at(lattice_runner* r, uint32_t index);

Enumerate the runner's known objects. Role: both. lattice_object_count returns how many objects the runner currently tracks (those it has authority over, or those replicated to it as a client). lattice_object_at maps a dense index in [0, count) to its lattice_netid, or returns 0 if out of range. Iteration order is deterministic (ascending network_id, 02 §18.2); a despawn invalidates indices, so re-read count per pass.

for (uint32_t i = 0, n = lattice_object_count(r); i < n; ++i) {
    lattice_netid id = lattice_object_at(r, i);
    /* ... */
}

2.7 Authority & ownership

Authority is set at runner level by the lattice_game_mode (SERVER/HOST/SHARED_HOST = authority; CLIENT = not) and at object level by the owner argument to lattice_spawn. The reference enforces this through the LATTICE_ERR_NOT_AUTHORITY gate on spawn/despawn/mark_dirty and through RPC target routing (§2.8). Per-object authority transfer for shared/distributed mode (the RequestAuthority/GrantAuthority protocol and on_authority_changed callback of 02 §17.2 / 05 §2.2) is a design feature not yet exposed in the reference ABI; its entry points will be added here when the production core lands them.

2.8 RPC (server / host side targets)

LATTICE_API lattice_result lattice_rpc(lattice_runner* r, lattice_netid id, uint16_t rpc_id,
                                       lattice_rpc_target target, const uint8_t* payload,
                                       uint32_t len, int reliable);

Send an event RPC associated with object id. Role: both (see targeting rules). The same function is used by server and client; the lattice_rpc_target selects recipients and the reliable flag selects the channel.

Param Meaning
id The object the RPC is scoped to (for routing — e.g. OWNER/ALL_BUT_OWNER resolve against this object's owner).
rpc_id Caller-defined 16-bit method id; surfaced verbatim to on_rpc.
target lattice_rpc_targetSERVER / OWNER / ALL / ALL_BUT_OWNER.
payload / len Opaque argument bytes (copied). Typically built with a BitWriter; read back with a BitReader. May be NULL/0.
reliable Non-zero ⇒ a reliable channel (Reliable-Ordered/Unordered, 02 §5); zero ⇒ unreliable.

Server-side targets. When the authority invokes lattice_rpc:

target Delivered to
LATTICE_RPC_SERVER The authority itself (local dispatch).
LATTICE_RPC_OWNER The peer that owns id (owner from spawn).
LATTICE_RPC_ALL Every peer that has the object (and the authority).
LATTICE_RPC_ALL_BUT_OWNER Every peer except the owner.

Which callback fires: every recipient's on_rpc(user_data, id, rpc_id, payload, len) fires inside their next tick.

Returns: LATTICE_OK; LATTICE_ERR_UNKNOWN_OBJECT; LATTICE_ERR_NOT_CONNECTED / LATTICE_ERR_NO_SESSION; LATTICE_ERR_INVALID_ARG.

/* Authority broadcasts "door opened" reliably to everyone: */
lattice_bitwriter* w = lattice_bw_create();
lattice_bw_write_ranged_int(w, door_index, 0, 255);
lattice_rpc(r, door_id, RPC_DOOR_OPENED, LATTICE_RPC_ALL,
            lattice_bw_data(w), lattice_bw_byte_count(w), /*reliable=*/1);
lattice_bw_destroy(w);

2.9 Which callbacks fire on the server/host

Callback Fires on server/host when
on_connected A client completes its handshake (per-runner connect signal).
on_disconnected A peer drops / times out (reason code).
on_spawned Locally, when this authority spawns an object (mirrors what clients receive).
on_despawned Locally, on despawn.
on_state_updated Rare on a pure authority — it owns the truth; mainly relevant for SHARED_HOST accepting a remote owner's state.
on_rpc A client sent a LATTICE_RPC_SERVER RPC, or a local SERVER-targeted RPC dispatched.
on_log Any time the core emits a diagnostic.

3. Client functions

A client runner (LATTICE_MODE_CLIENT) connects to an authority, reads replicated state, and sends client→server RPCs. It cannot spawn/despawn or write authoritative state (those return LATTICE_ERR_NOT_AUTHORITY / 0).

3.1 lattice_runner_connect (client)

LATTICE_API lattice_result lattice_runner_connect(lattice_runner* r, const char* addr, uint16_t port,
                                                  const uint8_t* token, uint32_t token_len);

Connect to a server/host. Role: client only (after start(LATTICE_MODE_CLIENT)).

Param Meaning
addr Server address (UTF-8 const char*). In the reference loopback transport, a logical rendezvous id.
port Server port (logical id in the reference).
token / token_len Optional connect token bytes (copied). In production this is the Ed25519-signed connect token from 03 Auth Service, validated during the handshake (02 §4.2); the reference accepts but does not cryptographically verify it. May be NULL/0.

Returns: LATTICE_OK (connect initiated — the runner moves to LATTICE_CONN_CONNECTING); LATTICE_ERR_NO_SESSION (not started, or started as a server); LATTICE_ERR_INVALID_ARG. Connection completion is observed via on_connected or by polling lattice_runner_state for LATTICE_CONN_CONNECTED.

lattice_runner_start(r, LATTICE_MODE_CLIENT);
lattice_runner_connect(r, "host.example", 7777, token, token_len);
while (lattice_runner_state(r) != LATTICE_CONN_CONNECTED)
    lattice_runner_tick(r, dt);   // pump until connected (on_connected also fires here)

3.2 Reading replicated state

A client never writes authoritative state; it observes it through three callbacks plus the read-only state pointer:

  1. on_spawned(user, id, type, owner) — a new object entered the client's world. Look up type, instantiate your view, and map id ↔ your object.
  2. on_state_updated(user, id)id's replicated state changed; read it with lattice_object_state and apply to your view.
  3. on_despawned(user, id)id left; destroy your view and unmap.
static void on_spawned(void* u, lattice_netid id, lattice_type_id type, uint64_t owner) {
    spawn_view(u, id, type, owner);
}
static void on_state_updated(void* u, lattice_netid id) {
    const PlayerBlock* p = lattice_object_state(((App*)u)->runner, id);  /* read-only on client */
    if (p) update_view(u, id, p);
}
static void on_despawned(void* u, lattice_netid id) { destroy_view(u, id); }

You can also poll the world with lattice_object_count/lattice_object_at (e.g. a late initialization sweep), reading each via lattice_object_state.

3.3 Client → server RPC

A client uses the same lattice_rpc function, but clients may only originate LATTICE_RPC_SERVER RPCs — a request to the authority, which validates and may re-broadcast (02 §16.2, 05 §4.3 RpcTargets.StateAuthority). Attempting ALL/OWNER/ALL_BUT_OWNER from a client is rejected (it cannot forge a broadcast).

target from a client Result
LATTICE_RPC_SERVER Sent to the authority; its on_rpc fires. The supported client→server path.
LATTICE_RPC_OWNER / ALL / ALL_BUT_OWNER Rejected — authority-only targets (LATTICE_ERR_NOT_AUTHORITY).
/* Client asks the server to fire a weapon: */
lattice_bitwriter* w = lattice_bw_create();
lattice_bw_write_vector3(w, aim_dir, (lattice_float_quant){-1.f, 1.f, 0.001f});
lattice_rpc(r, my_pawn_id, RPC_FIRE, LATTICE_RPC_SERVER,
            lattice_bw_data(w), lattice_bw_byte_count(w), /*reliable=*/1);
lattice_bw_destroy(w);

3.4 Which callbacks fire on the client

Callback Fires on the client when
on_connected The handshake to the server/host completes.
on_disconnected The connection drops / times out (reason).
on_spawned An object enters the client's world (full baseline).
on_state_updated A replicated object's state delta is applied.
on_despawned An object leaves / is destroyed.
on_rpc The server sent this client an RPC (OWNER/ALL/ALL_BUT_OWNER that includes it).
on_log The core emits a diagnostic.

4. Serialization API — BitWriter / BitReader

These are the typed bit-packing primitives ("functions for custom variables"). They back the manual serialization path (lattice_type_desc.serialize/deserialize) — i.e. the C-ABI realization of the INetworkSerializable / BitBuffer interface in 05 §12.3 and 02 §21. The same handles are passed into your serialize/deserialize callbacks, and the create/destroy forms are available standalone (RPC payload construction, round-trip testing).

The Write* / Read* methods are 1:1 mirrors: read in the exact order, with the exact descriptors, you wrote. All packing is little-endian, MSB-first within each byte (02 §20.3).

4.1 lattice_float_quant — the quantization descriptor

typedef struct {
    float min;
    float max;
    float precision;
} lattice_float_quant;

Passed to every compressed-float / compressed-vector method; defines the quantization range and step (02 §14.6 / §21.4). It is the C-ABI form of 05's FloatQuant { min, max, precision } / [Quantize(min,max,precision)].

4.2 BitWriter lifecycle & buffer access

LATTICE_API lattice_bitwriter* lattice_bw_create(void);
LATTICE_API void               lattice_bw_destroy(lattice_bitwriter* w);
LATTICE_API void               lattice_bw_reset(lattice_bitwriter* w);
LATTICE_API uint32_t           lattice_bw_bit_count(const lattice_bitwriter* w);
LATTICE_API uint32_t           lattice_bw_byte_count(const lattice_bitwriter* w);
LATTICE_API const uint8_t*     lattice_bw_data(const lattice_bitwriter* w); /* flushed byte buffer */
Function Role Notes
lattice_bw_create both Allocate a standalone writer. (Inside a serialize callback the core hands you the writer — do not create/destroy that one.)
lattice_bw_destroy both Free a writer you created.
lattice_bw_reset both Clear contents for reuse without reallocating.
lattice_bw_bit_count both Number of bits written so far.
lattice_bw_byte_count both Byte length of the flushed buffer (ceil(bits/8)); the len to pass to lattice_rpc.
lattice_bw_data both Pointer to the flushed byte buffer (valid until the next write/reset/destroy).

4.3 BitWriter typed Write* methods

LATTICE_API void lattice_bw_write_bool(lattice_bitwriter* w, int v);
LATTICE_API void lattice_bw_write_enum(lattice_bitwriter* w, uint32_t value, uint32_t count);
LATTICE_API void lattice_bw_write_byte(lattice_bitwriter* w, uint8_t v);
LATTICE_API void lattice_bw_write_int(lattice_bitwriter* w, int32_t v);
LATTICE_API void lattice_bw_write_ranged_int(lattice_bitwriter* w, int32_t value, int32_t min, int32_t max);
LATTICE_API void lattice_bw_write_long(lattice_bitwriter* w, int64_t v);
LATTICE_API void lattice_bw_write_ranged_long(lattice_bitwriter* w, int64_t value, int64_t min, int64_t max);
LATTICE_API void lattice_bw_write_float(lattice_bitwriter* w, float v);
LATTICE_API void lattice_bw_write_compressed_float(lattice_bitwriter* w, float value, lattice_float_quant q);
LATTICE_API void lattice_bw_write_double(lattice_bitwriter* w, double v);
LATTICE_API void lattice_bw_write_vector2(lattice_bitwriter* w, lattice_vec2 v, lattice_float_quant q);
LATTICE_API void lattice_bw_write_vector3(lattice_bitwriter* w, lattice_vec3 v, lattice_float_quant q);
LATTICE_API void lattice_bw_write_vector4(lattice_bitwriter* w, lattice_vec4 v, lattice_float_quant q);
LATTICE_API void lattice_bw_write_quaternion(lattice_bitwriter* w, lattice_quat v, uint32_t bits_per_comp);
LATTICE_API void lattice_bw_write_string(lattice_bitwriter* w, const char* s);
LATTICE_API void lattice_bw_write_bytes(lattice_bitwriter* w, const uint8_t* p, uint32_t n);
LATTICE_API void lattice_bw_write_bits(lattice_bitwriter* w, uint32_t value, uint32_t bitcount);
Method Encoding Maps to 05 §12
write_bool(w, v) 1 bit (v non-zero ⇒ 1) WriteBool
write_enum(w, value, count) ceil(log2(count)) bits — a ranged int over [0,count) WriteEnum
write_byte(w, v) 8 bits WriteByte
write_int(w, v) 32 bits WriteInt
write_ranged_int(w, value, min, max) ceil(log2(max-min+1)) bits WriteRangedInt
write_long(w, v) 64 bits WriteLong
write_ranged_long(w, value, min, max) bounded 64-bit WriteRangedLong
write_float(w, v) 32 bits (IEEE-754) WriteFloat
write_compressed_float(w, value, q) quantized per q WriteCompressedFloat
write_double(w, v) 64 bits WriteDouble
write_vector2/3/4(w, v, q) 2/3/4 components, each compressed per q WriteVector2/3/4
write_quaternion(w, v, bits_per_comp) smallest-three (2-bit index + 3×bits_per_comp; default 10 ⇒ ~32 bits) WriteQuaternion
write_string(w, s) length-prefixed UTF-8 WriteString
write_bytes(w, p, n) length-prefixed blob WriteBytes
write_bits(w, value, bitcount) raw bitcount low bits of value (escape hatch) WriteBits

4.4 BitReader lifecycle & typed Read* methods

LATTICE_API lattice_bitreader* lattice_br_create(const uint8_t* data, uint32_t byte_len);
LATTICE_API void               lattice_br_destroy(lattice_bitreader* r);

LATTICE_API int          lattice_br_read_bool(lattice_bitreader* r);
LATTICE_API uint32_t     lattice_br_read_enum(lattice_bitreader* r, uint32_t count);
LATTICE_API uint8_t      lattice_br_read_byte(lattice_bitreader* r);
LATTICE_API int32_t      lattice_br_read_int(lattice_bitreader* r);
LATTICE_API int32_t      lattice_br_read_ranged_int(lattice_bitreader* r, int32_t min, int32_t max);
LATTICE_API int64_t      lattice_br_read_long(lattice_bitreader* r);
LATTICE_API int64_t      lattice_br_read_ranged_long(lattice_bitreader* r, int64_t min, int64_t max);
LATTICE_API float        lattice_br_read_float(lattice_bitreader* r);
LATTICE_API float        lattice_br_read_compressed_float(lattice_bitreader* r, lattice_float_quant q);
LATTICE_API double       lattice_br_read_double(lattice_bitreader* r);
LATTICE_API lattice_vec2 lattice_br_read_vector2(lattice_bitreader* r, lattice_float_quant q);
LATTICE_API lattice_vec3 lattice_br_read_vector3(lattice_bitreader* r, lattice_float_quant q);
LATTICE_API lattice_vec4 lattice_br_read_vector4(lattice_bitreader* r, lattice_float_quant q);
LATTICE_API lattice_quat lattice_br_read_quaternion(lattice_bitreader* r, uint32_t bits_per_comp);
LATTICE_API uint32_t     lattice_br_read_string(lattice_bitreader* r, char* out, uint32_t cap);  /* returns length, NUL-terminates */
LATTICE_API uint32_t     lattice_br_read_bytes(lattice_bitreader* r, uint8_t* out, uint32_t cap);/* returns length */
LATTICE_API uint32_t     lattice_br_read_bits(lattice_bitreader* r, uint32_t bitcount);
  • lattice_br_create(data, byte_len) — wrap a caller-owned byte buffer (e.g. an RPC payload). Role: both. Destroy with lattice_br_destroy. (Inside a deserialize callback the core hands you the reader.)
  • Each read_* is the inverse of the matching write_* and must be called in the same order with the same descriptors. read_bool returns 0/1; the vector/quaternion readers return the POD value types (§5.7).
  • read_string/read_bytes write into your caller-owned out buffer of capacity cap and return the actual length; read_string NUL-terminates. If cap is too small the value is truncated to cap (the documented full-error path in production maps to LATTICE_ERR_BUFFER_TOO_SMALL); size out from the field's byte_capacity.

4.5 Round-trip example

/* WRITE */
lattice_bitwriter* w = lattice_bw_create();
lattice_bw_write_bool(w, alive);
lattice_bw_write_ranged_int(w, score, 0, 1000000);
lattice_bw_write_compressed_float(w, stamina, (lattice_float_quant){0,100,0.1f});
lattice_bw_write_vector3(w, pos, (lattice_float_quant){-4096,4096,0.001f});
lattice_bw_write_quaternion(w, rot, 10);
uint32_t n = lattice_bw_byte_count(w);
const uint8_t* bytes = lattice_bw_data(w);

/* READ (same order, same descriptors) */
lattice_bitreader* rd = lattice_br_create(bytes, n);
int          alive2   = lattice_br_read_bool(rd);
int32_t      score2   = lattice_br_read_ranged_int(rd, 0, 1000000);
float        stamina2 = lattice_br_read_compressed_float(rd, (lattice_float_quant){0,100,0.1f});
lattice_vec3 pos2     = lattice_br_read_vector3(rd, (lattice_float_quant){-4096,4096,0.001f});
lattice_quat rot2     = lattice_br_read_quaternion(rd, 10);

lattice_br_destroy(rd);
lattice_bw_destroy(w);

5. Callback / event model, threading & enums

5.1 lattice_callbacks

typedef struct {
    void* user_data;
    void (*on_connected)    (void* user_data);
    void (*on_disconnected) (void* user_data, int reason);
    void (*on_spawned)      (void* user_data, lattice_netid id, lattice_type_id type, uint64_t owner);
    void (*on_despawned)    (void* user_data, lattice_netid id);
    void (*on_state_updated)(void* user_data, lattice_netid id);
    void (*on_rpc)          (void* user_data, lattice_netid id, uint16_t rpc_id,
                             const uint8_t* payload, uint32_t len);
    void (*on_log)          (void* user_data, lattice_log_level level, const char* msg);
} lattice_callbacks;

Installed via lattice_runner_set_callbacks. user_data is passed back to every callback (your wrapper/runner context). Any pointer may be NULL to ignore that event.

Callback Args Meaning
on_connected Session established (client: handshake done; server: a peer connected).
on_disconnected reason Session/peer lost; reason is an implementation code (e.g. timeout vs. explicit).
on_spawned id, type, owner A replicated object appeared. Use type to instantiate; record owner.
on_despawned id A replicated object was removed.
on_state_updated id id's replicated state changed; read via lattice_object_state.
on_rpc id, rpc_id, payload, len An RPC arrived; payload/len are the (copied) args — wrap in a BitReader. The buffer is valid for the duration of the callback only.
on_log level, msg Diagnostic at lattice_log_level; msg is valid for the callback only.

The implemented callback set is leaner than the design sketch in 05 §2.2 (which also lists on_input_poll, on_sim_tick, on_authority_changed). Those belong to the prediction/input and authority-transfer features not yet in the reference; they will be added to this table when those ABI entry points land. Today, snapshot application surfaces as on_state_updated, and the simulation step is driven directly by lattice_runner_tick.

5.2 lattice_game_mode

typedef enum {
    LATTICE_MODE_SERVER      = 0,
    LATTICE_MODE_HOST        = 1, /* server that is also a local participant */
    LATTICE_MODE_CLIENT      = 2,
    LATTICE_MODE_SHARED_HOST = 3  /* shared/distributed authority (skeleton: like HOST) */
} lattice_game_mode;

5.3 lattice_connection_state

typedef enum {
    LATTICE_CONN_DISCONNECTED  = 0,
    LATTICE_CONN_CONNECTING,
    LATTICE_CONN_CONNECTED,
    LATTICE_CONN_DISCONNECTING
} lattice_connection_state;

Returned by lattice_runner_state; mirrors the connection FSM of 02 §4.1.

5.4 lattice_result (error codes)

typedef enum {
    LATTICE_OK = 0,
    LATTICE_ERR_INVALID_ARG,
    LATTICE_ERR_NOT_AUTHORITY,
    LATTICE_ERR_NO_SESSION,
    LATTICE_ERR_UNKNOWN_TYPE,
    LATTICE_ERR_UNKNOWN_OBJECT,
    LATTICE_ERR_SCHEMA_MISMATCH,
    LATTICE_ERR_BUFFER_TOO_SMALL,
    LATTICE_ERR_NOT_CONNECTED,
    LATTICE_ERR_INTERNAL
} lattice_result;
Code Meaning / typical cause
LATTICE_OK Success.
LATTICE_ERR_INVALID_ARG NULL/invalid handle, out-of-range index, malformed descriptor, stale netid.
LATTICE_ERR_NOT_AUTHORITY An authority-only call (spawn/despawn/mark_dirty, or a non-SERVER RPC target) made by a client.
LATTICE_ERR_NO_SESSION Called before start, or in the wrong role (e.g. connect on a server).
LATTICE_ERR_UNKNOWN_TYPE type_id not registered.
LATTICE_ERR_UNKNOWN_OBJECT No object with that netid.
LATTICE_ERR_SCHEMA_MISMATCH Peer catalogs/content hashes disagree (02 §20.2).
LATTICE_ERR_BUFFER_TOO_SMALL A read/get target buffer was too small for the value.
LATTICE_ERR_NOT_CONNECTED Operation needs an established session.
LATTICE_ERR_INTERNAL Unexpected internal failure.

Render any code with lattice_result_str. Note the non-lattice_result failure conventions: lattice_register_type and lattice_spawn signal failure by returning 0 (an invalid id), and lattice_object_state by returning NULL.

5.5 lattice_rpc_target

typedef enum {
    LATTICE_RPC_SERVER = 0,
    LATTICE_RPC_OWNER,
    LATTICE_RPC_ALL,
    LATTICE_RPC_ALL_BUT_OWNER
} lattice_rpc_target;

See §2.8 (authority targeting) and §3.3 (clients may originate only LATTICE_RPC_SERVER). Maps to 02 §16.2's ToServerOrHost/ToOwner/ToAll and 05 §4.3's RpcTargets.

5.6 lattice_field_kind

typedef enum {
    LATTICE_FIELD_BOOL = 0,
    LATTICE_FIELD_INT32,
    LATTICE_FIELD_INT64,
    LATTICE_FIELD_FLOAT,
    LATTICE_FIELD_DOUBLE,
    LATTICE_FIELD_RANGED_INT,
    LATTICE_FIELD_COMPRESSED_FLOAT,
    LATTICE_FIELD_VECTOR2,
    LATTICE_FIELD_VECTOR3,
    LATTICE_FIELD_VECTOR4,
    LATTICE_FIELD_QUATERNION,
    LATTICE_FIELD_STRING,
    LATTICE_FIELD_BYTES,
    LATTICE_FIELD_STRUCT
} lattice_field_kind;

The kind in a declarative lattice_field_desc; each maps to the matching BitWriter/BitReader encoding and to the per-engine primitive table in 05 §12.1.

5.7 POD value types

typedef struct { float x, y; }       lattice_vec2;
typedef struct { float x, y, z; }    lattice_vec3;
typedef struct { float x, y, z, w; } lattice_vec4;
typedef struct { float x, y, z, w; } lattice_quat;

Fixed-layout POD; mirror with [StructLayout(LayoutKind.Sequential)] (C#), a matching struct (Unreal/Godot), or a typed-array view (WASM) (05 §2.3 / §12.6).

5.8 lattice_log_level

typedef enum {
    LATTICE_LOG_TRACE = 0,
    LATTICE_LOG_DEBUG,
    LATTICE_LOG_INFO,
    LATTICE_LOG_WARN,
    LATTICE_LOG_ERROR
} lattice_log_level;

Severity passed to the on_log callback.

Handles & scalar typedefs

typedef struct lattice_runner_t    lattice_runner;     /* opaque: one networked simulation */
typedef struct lattice_bitwriter_t lattice_bitwriter;  /* opaque: typed bit-packer         */
typedef struct lattice_bitreader_t lattice_bitreader;  /* opaque: typed bit-unpacker       */
typedef uint64_t lattice_netid;    /* NetworkObject id; 0 == invalid     */
typedef uint32_t lattice_type_id;  /* registered type id; 0 == invalid   */

lattice_netid (uint64_t) and lattice_type_id (uint32_t) are values, not pointers; 0 means invalid in both. Peer ids (the owner argument / field) are uint64_t.

5.5b Threading rules

  • The core's internal I/O may run on a worker thread, but all callbacks are deferred and fire synchronously inside lattice_runner_tick on the thread that called it (02 §19; lattice.h header comment).
  • Therefore call tick on your engine's main/game thread (Unity FixedUpdate, Unreal game thread, Godot _physics_process) so callbacks land where it is safe to touch engine objects (05 §10).
  • Do no blocking work in a callback, and never let an exception/longjmp propagate out of one into the core.
  • Treat a runner handle as single-threaded: do not call its functions concurrently from multiple threads.

6. C ABI → engine high-level mapping

How each implemented lattice_* call surfaces in the idiomatic per-engine wrappers of 05 Engine Integration. (Unity uses a Roslyn source generator over [Networked]/[Rpc]; Unreal uses LATTICE_* macros; Godot uses the LatticeRunner/LatticeSync GDExtension nodes.)

6.1 Lifecycle & pump

C ABI Unity (lattice-unity) Unreal (lattice-unreal) Godot (lattice-godot)
lattice_runner_create + lattice_runner_start NetworkRunner.StartGame(GameMode, session) ULatticeRunnerSubsystem::StartGame(ELatticeMode, Session) LatticeRunner.start_game(mode, session)
lattice_runner_set_callbacks internal (wrapper installs its dispatch table) internal (subsystem) internal (node emits signals)
lattice_runner_listen host/server path of StartGame(Host/Server) StartGame(Host/Server) start_game(MODE_HOST/SERVER)
lattice_runner_connect StartGame(Client, …) (token from 03) StartGame(Client, …) start_game(MODE_CLIENT, …)
lattice_runner_tick driven from FixedUpdate (accumulator → 60 Hz) game-thread tick (subsystem) _physics_process
lattice_runner_state NetworkRunner.State / IsConnected GetConnectionState() runner.connection_state()
lattice_runner_destroy SafeHandle finalize / Shutdown() subsystem Deinitialize node _exit_tree

6.2 Types, objects & state

C ABI Unity Unreal Godot
lattice_register_type source-gen lt_object_schema baked into the prefab catalog (§7) LATTICE_NETWORKED* macros → LATTICE_NETSTRUCT registration LatticeSync.replicate(...) / define_struct(...)
lattice_spawn Runner.Spawn(prefab, owner) Runner->Spawn(Class, xform, owner) runner.spawn(scene, owner)
lattice_despawn Runner.Despawn(Object) Runner->Despawn(Actor) runner.despawn(node)
lattice_object_state + lattice_object_mark_dirty [Networked] property setter (source-gen marks dirty) LATTICE_NETWORKED property setter exported property write via LatticeSync
read of lattice_object_state (client) [Networked] getter / [OnChanged] property getter / OnRep property getter / *_changed signal
lattice_object_count / lattice_object_at Runner object enumeration runner object iteration runner object iteration

6.3 RPC & serialization

C ABI Unity Unreal Godot
lattice_rpc (target SERVER) [Rpc(RpcSources.InputAuthority, RpcTargets.StateAuthority)] LATTICE_RPC(InputAuthority, StateAuthority) @lattice_rpc(INPUT_AUTHORITY, STATE_AUTHORITY)
lattice_rpc (target ALL/OWNER/ALL_BUT_OWNER) [Rpc(StateAuthority, All/…)] LATTICE_RPC(StateAuthority, All/…) @lattice_rpc(STATE_AUTHORITY, …)
on_rpc callback generated [Rpc] dispatch stub *_Implementation annotated method body
lattice_bw_write_* / lattice_br_read_* BitBuffer / INetworkSerializable.Serialize lattice::BitWriter/BitReader Write*/Read* BitWriter/BitReader write_*/read_*
lattice_float_quant FloatQuant / [Quantize(min,max,prec)] LATTICE_RANGE/LATTICE_BOUNDS {"range"/"bounds", "precision"} dict

6.4 Callbacks

C ABI callback Unity Unreal Godot
on_connected / on_disconnected OnConnectedToServer / OnDisconnected subsystem delegates connected / disconnected signals
on_spawned / on_despawned OnSpawned (instantiate from catalog) / OnDespawned spawn/despawn delegates spawned / despawned signals
on_state_updated [OnChanged(nameof(X))] OnRep_* *_changed signal
on_rpc generated [Rpc] handler *_Implementation annotated method
on_log Unity log bridge UE_LOG bridge Godot logger

6.5 Enums

C ABI enum Unity Unreal Godot
lattice_game_mode GameMode.{Server,Host,Client,SharedHost} ELatticeMode::{...} LatticeRunner.MODE_{...}
lattice_rpc_target RpcTargets.{StateAuthority,…,All} ELatticeRpcTarget LatticeSync.{SERVER,OWNER,ALL,…}
lattice_field_kind [Networked] primitive type table (05 §12.1) LATTICE_NETWORKED member type LatticeSync.T_*
lattice_result translated to exception/warning translated to log/error translated to error

6.6 Not yet in the reference ABI (design-only today)

These appear in 02/05 but have no implemented lattice_* entry point yet; the wrappers stub or defer them, and they will be added to this reference when the production core exposes them:

Feature Where designed Future surface
Input poll / prediction tick 02 §10–11, 05 §4.3 on_input_poll / on_sim_tick callbacks + input window APIs
Authority request/transfer 02 §17.2 lattice_request_authority + on_authority_changed
Interest management (AoI) 02 §15 per-object relevancy / spatial config
NAT/relay, crypto handshake 02 §8–9 transport-config entry points

6.7 Misc helpers

LATTICE_API const char* lattice_result_str(lattice_result r);
LATTICE_API uint32_t    lattice_type_content_hash(lattice_runner* r, lattice_type_id type);
  • lattice_result_str(r)Role: both. Returns a static, human-readable string for a lattice_result (for logging). Never returns NULL.
  • lattice_type_content_hash(r, type)Role: both. Returns the content hash the core derived for a registered type (the per-type contribution to the catalog/version gate of 02 §20.2 / 05 §7); 0 if type is unknown. Compare across peers / log it to diagnose LATTICE_ERR_SCHEMA_MISMATCH.
lattice_result rc = lattice_despawn(r, id);
if (rc != LATTICE_OK) log("despawn failed: %s", lattice_result_str(rc));

7. Cross-document references

  • Wire format, reliability channels, delta/quantization, prediction, lag comp, authority models02 Netcode LLD. Every encoding hint here (compressed_float, smallest-three quaternion, ranged int, delta dirty bits) is specified there.
  • Ergonomic per-engine API the bindings present over this ABI ([Networked], [Rpc], NetworkRunner/LatticeRunner/ULatticeRunnerSubsystem, custom types, prefab catalog) — 05 Engine Integration.
  • Reference implementation scope + the lattice_test_* conformance harness (NetSim, loopback wire, reliability layer, ACK-bitfield checks — excluded from this reference by §0.1) — 07 Reference Implementation & Conformance.
  • Connect tokens consumed by lattice_runner_connect03 Auth Service.

The reference ABI (lattice.h) is authoritative wherever it differs from the illustrative lt_* sketches in earlier design docs. Product/component names are working codenames and may be renamed before release without changing any signature here.