Replication
client.udp is the Replication API over native UDP.
await game.udp.connect(minted)
game.udp.subscribe({"actor_update": lambda n: print(n.uuid, n.chunk, n.payload)})
await game.udp.send_actor_update((0, 0, 0), my_uuid, pose_bytes)
echo = await game.udp.send_actor_update_and_wait((0, 0, 0), my_uuid, pose_bytes)
Connecting mints nothing new. It calls serverWithLeastClients with your
app token, waits for the session to be ready, then signs every datagram with
that token. The handler names subscribe accepts are actor_update,
voxel_update, audio, video, actor_left, text, client_event,
server_event, generic_spatial, single_actor_message, channel_message,
generic_error, status and any.
Sends on client.udp cover actor updates, voxel updates, audio and video
packets (send_video_frame fragments a whole frame), text, client events,
single-actor messages and channel publishes. Generic spatial messages and idle
heartbeats are on client.udp.connection. Each send returns its sequence
number, and each *_and_wait variant resolves with the server's echo or raises
on timeout. Sends are bundled into
MESSAGE_BUNDLE datagrams; flush_sends() sends the pending bundle now.
A game loop
On a hot path, use the connection underneath. It sends a frame's entities in one call and reads whole batches of notifications:
conn = game.udp.connection
conn.send_actor_updates(chunks, uuids, poses, stride=88) # numpy: (n, 3) int64, n x 32 octets
async for batch in conn.batches():
actors = batch.types == crowdypy.wire.MessageType.ACTOR_UPDATE_NOTIFICATION
positions = batch.chunks[actors] # a view, not a copy
Each batch is a set of columns: types, app_ids, chunks (n × 3),
uuids (n × 32), epoch_ms, sequences, the type-specific extras, and the
payloads as offsets into one buffer. They are numpy views of native memory,
and nothing is copied until you copy it.
crowdypy.replication.ReplicationConnection is the same connection for code
without an event loop: wait(), then poll() from your own loop.
Video and audio
crowdypy.media fragments video frames onto the wire and reassembles them
(fragment_frame, VideoFrameAssembler), using the header format the other
SDKs use. send_video_frame and send_audio_packet send them.