.. _MetaProtocol: ******** Protocol ******** General Workflow ================ .. _metaworkflow-authentication: Authentication -------------- To authenticate, a client sends an :ref:`reference-ml-message-com.daysofwonder.metalobby.AsyncAuthRequest` to the server. The server can answer with: * :ref:`reference-ml-message-com.daysofwonder.metalobby.AsyncConnectedRequest` if the authentication is successful * :ref:`reference-ml-message-com.daysofwonder.metalobby.AsyncConnectionErrorRequest` if the authentication is not successful .. seqdiag:: seqdiag { default_fontsize = 11; activation = none; edge_length = 400; // default is 192 "Client"; "Server"; // normal edge and doted edge Client -> Server [label = "AsyncAuthRequest"]; === error === Server --> Client [label = "AsyncConnectionErrorRequest"]; === connected === Server --> Client [label = "AsyncConnectedRequest"]; Server [color = yellow] } When successful, the client will receive the full :ref:`reference-ml-message-com.daysofwonder.Player` and a :ref:`ml-concept-session`. The client authenticates the end-user to the server with an |dow| API OAuth2 access token. Presence -------- To monitor presence of other users, the client needs to send their |dow| player id with a :ref:`req-ml-RegisterPresenceRequest` and subscribe to the presence stream with a :ref:`req-ml-SubscribePresenceServiceRequest`. Once subscribed, anytime the presence of one of the monitored participants changes, an :ref:`req-ml-AsyncBuddyPresencePartialUpdateRequest` is sent with the state change. Note that presence events are batched, so an :ref:`req-ml-AsyncBuddyPresencePartialUpdateRequest` can contain more than one participant presence information. Logging out ----------- For the user to log out of the server, the client should send an :ref:`reference-ml-message-com.daysofwonder.metalobby.AsyncDisconnectRequest`. After this, all requests coming from the client will be rejected until the next :ref:`reference-ml-message-com.daysofwonder.metalobby.AsyncAuthRequest`. Heartbeat --------- The client must send regularly :ref:`req-ml-PingRequest` to signal the server it is still connected. The server will respond with the exact same :ref:`req-ml-PingRequest`. This allows the client to notice that the connection with the |ml| has been dropped (a TCP timeout can take a long time). The :ref:`req-ml-PingRequest` contains a ``timestamp`` field where you can write the local timestamp. Since the server sends back the same request, in return you'll get the same timestamp you sent, this allows to compute the time distance between the client and the server. Metalobby ========= .. _metaworkflow-roomlist: Getting Chat room list information ---------------------------------- It is possible at any time to get access to the list of |rooms| the |participant| is chatting in. It is also possible to get information about only one room at a time. To do so the client needs to send a :ref:`reference-ml-message-com.daysofwonder.metalobby.WhatsNewRoomcatRequest`, to which the server will respond with a :ref:`reference-ml-message-com.daysofwonder.metalobby.RoomListRequest`. The returned status is a list (possibly of zero or one element) of :ref:`reference-ml-message-com.daysofwonder.metalobby.RoomDetails`. These RoomDetails contains all information about a given |room|, including (but not limited to): * Participant list * Room name * Room topic * ... .. _metaworkflow-create-room: Creating Chat Room ------------------ To create a new |room|, the client sends a :ref:`req-ml-CreateRoomRequest`, with the correct :ref:`reference-ml-field-com.daysofwonder.metalobby.RoomConfiguration` and possibly initial participants. The server can answer with an :ref:`req-ml-ErrorRequest` (``TOO_MANY_OFFERS``) if the creator has too many rooms in progress, or with a :ref:`req-ml-RoomCreatedRequest` if it succeeded. .. seqdiag:: seqdiag { default_fontsize = 11; activation = none; edge_length = 400; // default is 192 "Client"; "Server"; // normal edge and doted edge Client -> Server [label = "CreateRoomRequest"]; === error === Server --> Client [label = "ErrorRequest"]; === success === Server --> Client [label = "RoomCreatedRequest"]; Server [color = yellow] } .. _metaworkflow-room-join: Entering room ------------- Once the |room| is created, a :ref:`req-ml-RoomCreatedRequest` is sent to all initial participants of the room, which are automatically added to the room list. .. seqdiag:: seqdiag { default_fontsize = 11; activation = none; edge_length = 400; // default is 192 "Creator"; "Server"; "Participants" // normal edge and doted edge Creator -> Server [label = "CreateRoomRequest"]; === Room initialization success === Server --> Creator [label = "RoomCreatedRequest"]; Participants -> Creator [label = "RoomCreatedRequest"]; Server [color = yellow] } .. note:: As soon as a participant enters the room, she can start chatting in it. There is no need to wait for all invitees to join the room. .. _metaworkflow-room-leave: Leaving room ------------ Until the room is :ref:`destroyed `, it is possible for a |participant| to leave a |room| by sending a LeaveRoomRequest. After she left, the participant cannot chat in the room anymore, unless she is invited back in. .. seqdiag:: seqdiag { default_fontsize = 11; activation = none; edge_length = 400; // default is 192 "Client"; "Server"; // normal edge and doted edge Client -> Server [label = "LeaveRoomRequest"]; Server --> Client [label = "RoomLeftRequest"]; Server [color = yellow] } .. note:: When the creator leaves the room, the room is destroyed In Room ======= .. _metaworkflow-chat: Chat in room ------------ Participants can send chat messages from a |room| with a :ref:`req-ml-RoomChatRequest` specifying the ``roomId`` (available in :ref:`req-ml-RoomDetails` after room creation). If the user is not in the specified room, or if it does not exist, it will receive a :ref:`req-ml-ErrorRequest` (``UNKNOWN_ROOM``). .. seqdiag:: seqdiag { default_fontsize = 11; activation = none; edge_length = 300; "Client"; "Server"; "Others" Client -> Server [label = "RoomChatRequest\n(text='test')"]; Server --> Client [label = "ClientChatRequest\n(text='test',sender=A)"]; Server -> Others [label = "ClientChatRequest\n(text='test',sender=A)"]; Others [width=200, label="Other Clients in lobby"] Server [color = yellow] } If the chat message text triggers the anti-profanity filter several times in a row, the sender will be muted for a certain time, and the workflow becomes: .. seqdiag:: seqdiag { default_fontsize = 11; activation = none; edge_length = 300; "Participant A"; Server; "Participant B" "Participant A" -> Server [label = "RoomChatRequest\n(room_id=12,text='profanity')"]; Server --> "Participant A" [label = "ClientChatBlockedRequest\n(room_id=12,text='',sender=A,muted=true)"]; Server -> "Participant B" [label = "ClientChatBlockedRequest\n(room_id=12,text='',sender=A,muted=true)"]; "Participant A" -> Server [label = "RoomChatRequest\n(room_id=12,text='message')\n\n", color=red, failed]; Server [color = yellow] } and no chat message is sent to the other participants. When sending chat requests you can also specify some participants in the field ``recipient_ids``. This is useful if you want to filter who receives the message (for instance, to implement private messaging). In a room, ``recipient_ids`` must contain `local ids`. * If ``recipient_ids`` is empty, the message will be sent to `all participants` of the room * If ``recipient_ids`` is filled, only these participants ids will receive the message (and the sender will always receive it back). .. seqdiag:: seqdiag { default_fontsize = 11; activation = none; edge_length = 200; "Participant A"; Server; "Participant B"; "Participant C" "Participant A" -> Server [label = "RoomChatRequest\n(room_id=12,\ntext='test',\nrecipients_ids=[idB])"]; Server --> "Participant A" [label = "ClientChatRequest\n(room_id=12,\ntext='test',\nrecipients_ids=[idB],\nsender=A)"]; Server -> "Participant B" [label = "ClientChatRequest\n(room_id=12,\ntext='test',\nrecipients_ids=[idB],\nsender=A)"]; Server -> "Participant C" [label = "ClientChatRequest\n(room_id=12,\ntext='test',\nrecipients_ids=[idB],\nsender=A)", color=red, failed]; Server [color = yellow] } .. _metaworkflow-chatcode: Chat codes ---------- The server supports message ``codes``, useful for implementing custom messages like pre-made quickchat messages, commands, emojis, special animation in the lobby... Just fill the ``code`` integer parameter and it will be relayed. Please be aware that chat codes between 0 and 255 are reserved by the server and are not free to use. Provide a higher value. The code 0 is the "dummy code" and will behave the same way as if no code was provided. You also have to provide a non-empty ``text`` (matching the message in default app locale) for older clients to display the message correctly, and for debugging purpose. The text will still pass through the profanity filter as usual. Currently implemented chat codes in the |ml|: +------------+-----------------------------------------------------------+ | Chat code | Description | +============+===========================================================+ | 1 | Welcome message (in room) | +------------+-----------------------------------------------------------+ | 2 | Inappropriate message from a participant | +------------+-----------------------------------------------------------+ | 3 | Advertising /report command feature | +------------+-----------------------------------------------------------+ | 4 | "Thanks for your report" | +------------+-----------------------------------------------------------+ | 5 | Report cooldown (users cannot spam report) | +------------+-----------------------------------------------------------+ | 6 | Help (list of commands) | +------------+-----------------------------------------------------------+ | 7 | Meta-Lobby statistics (command /statistics) | +------------+-----------------------------------------------------------+ | 8 | In-room statistics (command /statistics) | +------------+-----------------------------------------------------------+ | 9 | Welcome message (in meta-lobby) | +------------+-----------------------------------------------------------+ | 10 ~ 255 | Reserved for future use | +------------+-----------------------------------------------------------+ .. _metaworkflow-chat-commands: Chat commands ------------- The |ml| offers a few commands, to be issued from the chat like a regular message. Currently, there are: * ``/help``: displays the list of all supported commands * ``/report toto``: to report the user `toto` (please note that no check is done server-side regarding the username) * ``/statistics``: displays statistics on the meta-lobby (number of participants, number of rooms) or the current room (number of active participants, of forfeiters...) .. _metaworkflow-chat-history: Get Chat history ---------------- It is possible to get the history of the previous chat messages by sending a :ref:`req-ml-GetChatRoomHistoryRequest` (by specifying a ``room_id``). The server will send back a :ref:`req-ml-ClientChatRoomHistoryRequest` with the latest previously exchanged messages. Note that the chat history will never display private messages. .. seqdiag:: seqdiag { default_fontsize = 11; activation = none; edge_length = 200; "Participant"; Server; "Participant" -> Server [label = "GetChatRoomHistoryRequest\n(room_id=12)"]; Server --> "Participant" [label = "ClientChatRoomHistoryRequest\n(room_id=12)"]; Server [color = yellow] } Invitation ========== .. _metaworkflow-room-invite: Invite new participants ----------------------- It is possible to invite more buddies to the room after creation with an :ref:`req-ml-InviteFriendsToRoomRequest` (by specifying a ``room_id``). The ``details`` give information about the room, such as its name or topic. .. seqdiag:: seqdiag { default_fontsize = 11; activation = none; edge_length = 200; "Inviter"; Server; "Invitee B"; "Invitee C"; "Inviter" -> Server [label = "InviteFriendsToRoomRequest\n(room_id=12, friends=[B, C])"]; Server --> "Invitee B" [label = "InvitedRoomRequest\n(room_id=12, invitation_by=A, details)"]; Server --> "Invitee C" [label = "InvitedRoomRequest\n(room_id=12, invitation_by=A, details)"]; Server [color = yellow] } .. _metaworkflow-invitation-answer: Answer to invitation -------------------- Upon reception of an invitation, you can choose to accept or to decline it. To do so, send an :ref:`req-ml-AnswerInvitationRoomRequest` filling the ``invitation_answer`` field. Accept invitation: the invitee will automatically join the room. Client should then perform a :ref:`req-ml-GetChatRoomHistoryRequest` to get the list of past messages. .. seqdiag:: seqdiag { default_fontsize = 11; activation = none; edge_length = 200; "Invitee"; Server; "Participants in room"; Server -> "Invitee" [label = "InvitedRoomRequest\n(room_id=12, invitation_by=A, details)"]; "Invitee" -> Server [label = "AnswerInvitationRoomRequest\n(room_id=12, \ninvitation_answer=true)"]; "Invitee" <-- Server [label = "RoomJoined\n(room_id=12, participant)"]; "Participants in room" <-- Server [label = "RoomJoined\n(room_id=12, participant)"]; Server [color = yellow] } In order to decline an invitation, simply put ``false`` as value for ``answer``. The room admin will receive a corresponding :ref:`req-ml-RoomInvitationDeclinedRequest`. .. seqdiag:: seqdiag { default_fontsize = 11; activation = none; edge_length = 200; "Invitee"; Server; "Room admin"; Server -> "Invitee" [label = "InvitedRoomRequest\n(room_id=12, invitation_by=A, details)"]; "Invitee" -> Server [label = "AnswerInvitationRoomRequest\n(room_id=12, \ninvitation_answer=false)"]; "Room admin" <- Server [label = "RoomInvitationDeclinedRequest\n(room_id=12, participant)"]; Server [color = yellow] } Community ========= .. _metaworkflow-buddy-list: Buddy list management --------------------- It is possible for a participant to get the content of her :ref:`Buddy List`, by sending an :ref:`req-ml-AsyncBuddyListRequest`. In return the server will send back an :ref:`req-ml-AsyncBuddyListContentRequest` containing the list of :ref:`buddies `. To add a buddy, send an :ref:`req-ml-AsyncBuddyManagementRequest` with the :ref:`operation ` ``ADD``, and the |dow| participant id to add. On return the server will send back an :ref:`req-ml-AsyncBuddyAddedRequest`. To remove a buddy, follow the same workflow with the :ref:`operation ` ``REMOVE``. The server will send back an :ref:`req-ml-AsyncBuddyRemovedRequest` to confirm the operation. .. _metaworkflow-ignored-list: Ignored list management ----------------------- As with the :ref:`Buddy List`, the client can manage the |participant| :ref:`Ignored list `. To get access to the list, send an :ref:`req-ml-AsyncIgnoreListRequest`, the server will return an :ref:`req-ml-AsyncIgnoreListContentRequest`. To manage the ignore list, send an :ref:`req-ml-AsyncIgnoreManagementRequest` with the proper ``ADD`` or ``REMOVE`` :ref:`operation `, and the server will respond with either an :ref:`req-ml-AsyncIgnoreAddedRequest` or an :ref:`req-ml-AsyncIgnoreRemovedRequest`.