Online Emotes
With MCE Online, the emotion balloons a player shows are seen by the other players too: press F3 and a heart pops over your avatar on every screen that has you in range.
Emotes ride on the same realtime match as the position updates (see World Sync). They need no extra service, no RPC and no database: an emote is a tiny message that is relayed and forgotten.
Available in Pro and Source tiers.
The Flow
sender Nakama world match receiver
────── ────────────────── ────────
F3 pressed
PlayerEmotes.Played("heart")
OnlineEmoteRelay ──opcode 3──▶ relays it as it comes ──opcode 3──▶ WorldSyncService.HandleEmote
{"e":"heart"} (no inspection) OnlineEmotes.TryRead (checks the name)
OnPlayerEmote(userId, "heart")
PlayerSpawnManager.ApplyEmote
OnlineEmotes.ShowOver(avatar, "heart", gameSet)
- Sender. The local player's hotkey raises
PlayerEmotes.Played(the same event local code listens to).OnlineEmoteRelayis attached to that event while the world sync service runs, and sends the balloon's name to the world match only while the service is running and connected with a world match joined. Attaching twice does not send twice. - Server. The world match forwards opcode
3to the other players as it comes, like the map-change (2) and follower (4) events. It does not interpret the body. - Receiver.
WorldSyncServicereads the message strictly, raisesOnPlayerEmote(userId, balloonName), andPlayerSpawnManagerdraws the balloon over that player's avatar -- if the avatar is spawned, which means only players inside your area of interest see it.
The Message
| Opcode | 3 (WorldSyncService.OP_EMOTE) |
| Body | {"e":"heart"} -- a JSON object with the balloon's name in e |
| Build it with | OnlineEmotes.Payload(name) |
Safety: a Peer Cannot Make You Draw Anything
What a peer sends is text from outside, so it is never trusted:
- The name is checked by
OnlineEmotes.IsValidNamebefore anything uses it: lower case letters, digits and underscores, at mostOnlineEmotes.MaxNameLength(32) characters.OnlineEmotes.TryRead(json, out name)returnsfalsefor anything else -- malformed JSON, an empty name, a long one -- andWorldSyncServicelogsBad emote from <user>: not a balloon name.and drops it. - What is drawn is always the balloon of that name that your game or the engine already owns (
EmotionBalloonSet.Resolve). The message carries a name, never a sprite. A name nobody has draws nothing.
This is also why the balloons need no content synchronization: if your game replaces heart with its own drawing, every player of your game sees your heart.
Observing Emotes
| Member | When |
|---|---|
WorldSyncService.OnPlayerEmote | A valid emote arrived: (userId, balloonName) |
OnlineEmotes.Shown | A balloon was drawn over a remote avatar, already in place: (balloonName, avatarTransform). A listener that throws is logged and does not stop the balloon. |
using OpenMon.MCE.Online.World;
OnlineEmotes.Shown += (name, avatar) =>
Debug.Log($"{avatar.name} shows '{name}'.");
Reference
| Type | Namespace | Role |
|---|---|---|
OnlineEmotes | OpenMon.MCE.Online.World | Message format, name validation, ShowOver(Transform avatar, string name, EmotionBalloonSet game), the Shown event |
OnlineEmoteRelay | OpenMon.MCE.Online.World | Carries PlayerEmotes.Played to the socket |
WorldSyncService | OpenMon.MCE.Online.World | OP_EMOTE, OnPlayerEmote |
PlayerSpawnManager | OpenMon.MCE.Online.World | Draws the balloon over the remote avatar |