Skip to content

Custom network events new

Custom events are the object-less, typed sibling of a per-object RPC (design 02 §17). Where lattice_rpc always names a netid, an event may be global / session-scoped (pass netid 0) or optionally object-scoped (pass a live netid, used for OWNER / ALL_BUT_OWNER routing exactly like an RPC).

lattice_send_event

LATTICE_API lattice_result lattice_send_event(lattice_runner* r, uint16_t event_id,
                                              lattice_event_target target, lattice_netid netid,
                                              uint64_t peer, const uint8_t* payload,
                                              uint32_t len, int reliable);

Send a custom event. Role: both (for a client, target is implicitly the authority).

Param Meaning
event_id The typed event tag, delivered verbatim to on_event.
target A lattice_event_target. SERVER/OWNER/ALL/ALL_BUT_OWNER fan out per the same §16 policy as RPC; PEER sends to exactly one connection (the peer argument).
netid 0 for a global event, or an object's netid for an object-scoped event.
peer The destination connection id for LATTICE_EVENT_PEER (ignored otherwise).
payload / len Arbitrary serialized bytes (e.g. from a lattice_bw_* writer or an INetworkSerializable); may be NULL when len == 0. Delivered byte-exact.
reliable Non-zero ⇒ the event rides a reliable channel (exactly-once; ordered on the reliable-ordered channel). Zero ⇒ best-effort / unreliable.

Returns: LATTICE_OK on accept, or an error (e.g. LATTICE_ERR_NOT_CONNECTED for a client with no session). Like RPC, events are queued onto the transport and delivered to the remote on_event callback during its lattice_runner_tick().

lattice_event_target

typedef enum {
    LATTICE_EVENT_SERVER        = 0, /* client -> authority only (object-less: just the host) */
    LATTICE_EVENT_OWNER         = 1, /* authority -> the (optional) object's owner            */
    LATTICE_EVENT_ALL           = 2, /* authority -> every peer                               */
    LATTICE_EVENT_ALL_BUT_OWNER = 3, /* authority -> every peer except the owner              */
    LATTICE_EVENT_PEER          = 4  /* authority -> one specific connection (see peer arg)   */
} lattice_event_target;

The shared values deliberately mirror lattice_rpc_target so the routing policy is one decision, not two.

Receiving — on_event

void (*on_event)(void* user_data, uint16_t event_id, lattice_netid netid,
                 uint64_t sender, const uint8_t* payload, uint32_t len);

Fires synchronously inside lattice_runner_tick(). event_id is the typed tag; netid is 0 for a global/session-scoped event or the owning object's netid for an object-scoped event; sender is the peer id the event originated from (0 == the local authority); payload/len is the byte-exact blob the sender serialized (may be empty). The pointer is owned by the core and valid only for the duration of the call.

Example — a global "match started" broadcast

/* Authority -> every peer, reliable, object-less. */
uint8_t buf[8];
lattice_bitwriter* w = lattice_bw_create();
lattice_bw_write_int(w, match_id);
lattice_bw_write_byte(w, mode_byte);
lattice_send_event(r, /*event_id*/ EV_MATCH_STARTED, LATTICE_EVENT_ALL,
                   /*netid*/ 0, /*peer*/ 0,
                   lattice_bw_data(w), lattice_bw_byte_count(w), /*reliable*/ 1);
lattice_bw_destroy(w);

/* Receiver */
static void on_event(void* u, uint16_t event_id, lattice_netid netid,
                     uint64_t sender, const uint8_t* payload, uint32_t len) {
    if (event_id == EV_MATCH_STARTED) {
        lattice_bitreader* rd = lattice_br_create(payload, len);
        int32_t match_id = lattice_br_read_int(rd);
        uint8_t mode     = lattice_br_read_byte(rd);
        lattice_br_destroy(rd);
        /* ... */
    }
}