Send a string payload to other players
How to move an arbitrary string from one client to a set of others, using
DataTransferer to handle chunking, sequencing, and
reassembly for you. See the chain overview if you want to
understand what's happening underneath this API.
Steps
-
Declare a
[WirePool]field for it.DataTransfererships as one of TsVRC's own default pool entries, so there's nothing to register on the Configure window first. -
Subscribe to completion before you ever call
TransferData, so you don't miss a transfer that finishes on the same frame it starts:public class ScoreSync : TsBehaviour{[WirePool][SerializeField] private DataTransferer _transferer;protected override void TsStart(){_transferer.TsSubscribe(this, DataTransferer.OnTransferCompletedEvent, nameof(_OnScoresReceived));}public void _OnScoresReceived(){string payload = _transferer.LastData;// parse and apply payload}} -
Send it from whichever client has the data, to whichever players should receive it:
public void BroadcastScores(string serializedScores, string[] targetPlayerIds){_transferer.TransferData(serializedScores, targetPlayerIds);}
That's the whole public surface. DataTransferer is the type you interact with regardless
of how large the payload is or how many chunks it takes to arrive.
Serializing structured data
TransferData takes a string, so send structured data through TsJson
first:
public void BroadcastScores(DataDictionary scores, string[] targetPlayerIds)
{
_transferer.TransferData(TsJson.Serialize(scores), targetPlayerIds);
}
public void _OnScoresReceived()
{
DataDictionary scores = TsJson.Deserialize(_transferer.LastData);
if (scores != null)
{
// use scores
}
}
Showing transfer progress
Subscribe to OnTransferChunkEvent to drive a progress bar while a large payload arrives.
LastChunkIndex/LastTotalChunks are set before this event fires, so both are safe to
read from inside the handler:
public class ScoreSyncProgress : TsBehaviour
{
[WirePool][SerializeField] private DataTransferer _transferer;
[SerializeField] private Slider _progressBar;
protected override void TsStart()
{
_transferer.TsSubscribe(this, DataTransferer.OnTransferChunkEvent, nameof(_OnChunkReceived));
_transferer.TsSubscribe(this, DataTransferer.OnTransferCompletedEvent, nameof(_OnTransferDone));
}
public void _OnChunkReceived()
{
// LastChunkIndex is 1-based (it's "how many chunks have arrived so far").
_progressBar.value = (float)_transferer.LastChunkIndex / _transferer.LastTotalChunks;
}
public void _OnTransferDone() => _progressBar.value = 1f;
}
Handling a target player leaving mid-transfer
You don't need to: DataTransferer already handles a target player leaving, getting
suspended, or the sending object changing owners mid-transfer. See
the chain overview and the individual layer pages if you need
the exact guarantees (what "completed" means when the recipient list shrank, for instance).
Why this shape
VRChat caps individual network event payloads well below what most real payloads need, so a single call has to become a sequenced chunk transfer underneath. The chain overview explains why that's split across eight small layers instead of one large class.