Skip to main content

The data transfer chain

DataTransferer, the type you use, is the last link in an inheritance chain built on Process: Process → PlayerTracker → ReadyCheckProcess → DataChunker → ChunkedTransferSession → DataSender → DataChunkReceiver → DataSenderReceiver → DataTransferer. Each layer adds one concern on top of the one below it, so this section documents them bottom-up in that same order. Reading the DataTransferer page without the ones before it skips the reasoning behind most of what it does.

The problem being solved​

VRChat caps the total parameter size of a single network event at 16 KB and the overall outgoing Udon bandwidth to about 11 KB/s, so sending an arbitrary string to a set of players means splitting it into chunks, sending them one at a time, and confirming each one arrived before sending the next, all while players can join, leave, get suspended, or have ownership of the sending object change mid-transfer. Each layer in the chain exists to handle one slice of that: chunking the data, sequencing the chunks through a ready check, broadcasting lifecycle events, validating and reassembling what arrives, and exposing a clean public API on top.

Reading order​

Read these in order; each page assumes the ones before it:

  1. DataChunker: splits and validates the raw string, no networking or process state of its own.
  2. ChunkedTransferSession: runs the ready check of each chunk in turn.
  3. DataSender: broadcasts the sequencing transitions as networked lifecycle events.
  4. DataChunkReceiver: validates, stores, and acknowledges each incoming chunk.
  5. DataSenderReceiver: turns the raw hooks of the receiver into Last* properties and events.
  6. DataTransferer: the type you use, adding only transfer-focused event names on top.

What you use​

Unless you're extending the chain, you only use DataTransferer: call TransferData(data, playerIds), subscribe to its events, read LastData when a transfer completes. The intermediate pages explain why DataTransferer behaves the way it does under failure conditions (a player leaving mid-transfer, an ownership handover between chunks, a malicious direct call to one of the network-callable methods), not to hand you a separate API surface at each layer.