Emotes
Abstract game-defined emote/action events fanned out to observers as opaque data.
Services you call 1
Crossplay implements these. Resolve them from DI and call them from your own systems.
IEmoteService
Broadcasts abstract emote/action events from an in-world entity to whoever can see it. The piece never interprets emote ids or payloads — that is entirely the game's vocabulary.
-
void Play(ISession session, EmoteRequest request)Validates and broadcasts request as an EntityEmote to the sender's observers (and the sender itself when EchoToSelf is on). A sender that is not in the world, or an oversized payload (> MaxDataBytes), is silently dropped.
Configuration 1
Every tunable lives in an options object — there are no magic numbers to hunt for.
EmoteOptions
Configurable emote parameters (defaults here; never inlined in logic).
-
bool EchoToSelf { get; set; }When true (the default) the performer also receives its own EntityEmote — the client can treat the echo as the authoritative "it happened" confirmation (or play immediately and use the echo purely as an ordering signal; the framework doesn't care which). Turn off only if the game plays the local emote optimistically and never wants the server round-trip echoed back.
-
int MaxDataBytes { get; set; }Maximum size of the opaque Data payload, in bytes. Emote parameters are meant to be tiny (a step index, an intensity); anything larger is dropped as malformed/abusive. Default 64. Raise only if your game encodes richer emote parameters; keep it small to bound per-observer fan-out cost.
Wire messages 2
The protocol this piece speaks. Ids are allocated per piece so they can never collide.
EmoteRequest Client → server: play an emote / action / gesture. EmoteId is an abstract, game-defined id — the framework never knows what it means (a wave, a dance move, a taunt, a card flourish…); the game maps ids to its own animations/VFX/audio on the receiving side. Data is an optional opaque payload for game-specific parameters (e.g. a combo step, an intensity), capped server-side by EmoteOptions.MaxDataBytes.
EntityEmote Server → observers (and, by default, the performer): an in-world entity performed an emote. Sent reliably — an emote is a discrete event, not a stream. Clients map EmoteId onto their own presentation (animation, VFX, audio, a text line — the framework doesn't care).
Unity services you inject 1
Crossplay binds these in the client context. Inject and call them from your own MonoBehaviours and presenters.
IEmoteClient
The Emotes puzzle piece, client side. Send a game-defined emote id (plus an optional opaque payload); receive EntityEmote events for entities you can see. The piece carries no presentation: the game subscribes to EmotePerformed and maps ids onto its own animations / VFX / audio / UI. Remove this package and emotes simply stop — nothing else breaks.
-
event Action<EntityEmote> EmotePerformedAn entity in view (possibly yourself — the server echo) performed an emote.
-
void Play(ushort emoteId, byte[] data = null)Plays a game-defined emote, optionally with tiny opaque parameters.
UI views you can replace 1
Each ships a working uGUI panel you can drag into a scene. Substitute your own view to keep the logic and change the look — the presenter never knows.
ICrossplayEmotesView
Narrow contract the presenter drives. UI-only: render calls in, user intents out.