1
0
mirror of https://github.com/moparisthebest/xeps synced 2024-11-25 10:42:19 -05:00
xeps/inbox/multi-user_gaming.xml
2017-08-23 14:45:07 +02:00

3030 lines
102 KiB
XML

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE xep SYSTEM 'xep.dtd' [
<!ENTITY % ents SYSTEM 'xep.ent'>
<!ENTITY INVITE "&lt;invite/&gt;">
<!ENTITY JOIN "&lt;join/&gt;">
<!ENTITY ERROR "&lt;error/&gt;">
<!ENTITY TEXT "&lt;text/&gt;">
<!ENTITY GAME "&lt;game/&gt;">
<!ENTITY TURN "&lt;turn/&gt;">
<!ENTITY SAVE "&lt;save/&gt;">
<!ENTITY SAVED "&lt;saved/&gt;">
<!ENTITY ITEM "&lt;item/&gt;">
<!ENTITY X "&lt;x/&gt;">
<!ENTITY FEATURE "&lt;item/&gt;">
<!ENTITY NAME "&lt;name/&gt;">
<!ENTITY ROOM "&lt;room@service&gt;">
<!ENTITY ROOMJID "&lt;room@service/nick&gt;">
<!ENTITY USERJID "&lt;user@domain&gt;">
%ents;
]>
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
<xep>
<header>
<title>Multi-User Gaming</title>
<abstract>This document defines an XMPP protocol extension for multi-user gaming.</abstract>
&LEGALNOTICE;
<number>xxxx</number>
<status>ProtoXEP</status>
<type>Standards Track</type>
<sig>Standards</sig>
<approver>Council</approver>
<dependencies>
<spec>XMPP Core</spec>
<spec>XMPP IM</spec>
<spec>XEP-0004</spec>
<spec>XEP-0030</spec>
<spec>XEP-0055</spec>
</dependencies>
<supersedes/>
<supersededby/>
<shortname>mug</shortname>
<author>
<firstname>Torsten</firstname>
<surname>Grote</surname>
<email>Torsten.Grote(&#228;t)fsfe.org</email>
<jid>Torsten.Grote(&#228;t)jabber.fsfe.org</jid>
</author>
<author>
<firstname>Arne</firstname>
<surname>König</surname>
<email>arne.ko(&#228;t)23inch.de</email>
<jid>arne++(&#228;t)jabber.ccc.de</jid>
</author>
<author>
<firstname>G&#252;nther</firstname>
<surname>Nie&#223;</surname>
<email>guenther.niess(&#228;t)web.de</email>
<jid>niess(&#228;t)jabber.ccc.de</jid>
</author>
<revision>
<version>0.0.3</version>
<date>2009-04-20</date>
<initials>gn</initials>
<remark><p>Added sections about entering non-anonymous, semi-anonymous and fully-anonymous rooms.</p></remark>
</revision>
<revision>
<version>0.0.2</version>
<date>2009-03-14</date>
<initials>ak, gn</initials>
<remark><p>Second draft.</p></remark>
</revision>
<revision>
<version>0.0.1</version>
<date>2008-07-17</date>
<initials>tg</initials>
<remark><p>First draft.</p></remark>
</revision>
</header>
<section1 topic='Introduction' anchor='intro'>
<p>
Many modern instant messenger networks support playing games.
Still, XMPP mostly lacks this kind of support.
Therefore, this document (Multi-User Gaming or MUG) describes a base protocol for game playing over XMPP.
</p>
<p>
This protocol is not by itself sufficient to play games.
It just describes a basic protocol framework which game-specific protocols can use.
</p>
</section1>
<section1 topic='Requirements' anchor='reqs'>
<p>
This document addresses the functionality which is needed to play multi-user games over XMPP.
In particular this functionality consists of:
</p>
<ol start='1'>
<li>discovering support for games and of particular games</li>
<li>inviting users to game rooms</li>
<li>discovering and joining existing game rooms</li>
<li>exchanging game information (moves, states, etc.)</li>
<li>saving and loading of matches</li>
<li>terminating games</li>
<li>allow spectators to watch the match</li>
<li>validate game moves</li>
</ol>
<p>
In addition, this document provides protocol elements for supporting the following room types:
</p>
<ol>
<li>moderated or unmoderated</li>
<li>public or hidden</li>
<li>members-only or open</li>
<li>password-protected or unsecured</li>
</ol>
<p>
The following requirements are explicitly not adressed, but might be realized by seperate XEPs.
</p>
<ol>
<li>support for near-realtime games or for games which require low latency</li>
<li>defined timers for each turn</li>
<li>scores and highscores</li>
<li>tournaments</li>
</ol>
<p>
The extensions needed to implement these requirements are qualified by the 'http://jabber.org/protocol/mug' namespace
(and the #owner, and #user fragments on the main namespace URI).
</p>
</section1>
<section1 topic='Terminology' anchor='terms'>
<section2 topic='General Terms' anchor='terms-general'>
<p>Game -- a XEP which defines the rules of a match</p>
<p>Initiator -- the entity that started a game.</p>
<p>Match -- represents a specific instance of a game played in a room.</p>
<p>Member -- a user with an affiliation of type "member" in the context of member-only games.</p>
<p>Owner -- a priviledged entity that owns a game.</p>
<p>Player -- a user in a match who has a defined game role</p>
<p>Role -- role in the game (e.g. 'black' and 'white' in chess)</p>
<p>Room -- a game room in which matches are played</p>
<p>Room JID --
the &ROOMJID; by which an occupant is identified within the context of a match;
contrast with Bare JID and Full JID.</p>
<p>Spectator -- an entity who does not actually plays the game but watches it.</p>
<p>Occupant -- a player or spectator who is currently in the match.</p>
</section2>
<section2 topic='Room Types' anchor='terms-room'>
<p>Unmoderated Room --
The owner has limited rights. The match cannot be saved; antonym: Moderated Room.</p>
<p>Moderated Room --
The owner is allowed to kick users, revoke roles and save the match; antonym: Unmoderated Room.</p>
<p>Hidden Room --
a room that cannot be found by any user through normal means such as searching and service discovery;
antonym: Public Room.</p>
<p>Public Room --
a room that can be found by any user through normal means such as searching and service discovery;
antonym: Hidden Room.</p>
<p>Members-Only Room --
a room that a user cannot enter without being on the member list;
antonym: Open Room.</p>
<p>Open Room --
a room that anyone may enter without being on the member list;
antonym: Members-Only Room.</p>
<p>Password-Protected Room --
a room that a user cannot enter without first providing the correct password;
antonym: Unsecured Room.</p>
<p>Unsecured Room --
a room that anyone is allowed to enter without first providing the correct password;
antonym: Password-Protected Room.</p>
<p>Fully-Anonymous Room --
a room in which the full JIDs or bare JIDs of occupants cannot be discovered by anyone,
including the room owner; contrast with Non-Anonymous Room and Semi-Anonymous Room.</p>
<p>Semi-Anonymous Room --
a room in which an occupant's full JID can be discovered by the room owner only;
contrast with Fully-Anonymous Room and Non-Anonymous Room.</p>
<p>Non-Anonymous Room --
a room in which an occupant's full JID is exposed to all other occupants;
contrast with Semi-Anonymous Room and Fully-Anonymous Room.</p>
</section2>
<section2 topic='Room Status' anchor='terms-room_status'>
<p>active -- room that is currently in use</p>
<p>adjourned -- 'saved' room</p>
</section2>
<section2 topic='Match Status'>
<p>
There are three different match status:
</p>
<p>created -- before the initial room configuration is done</p>
<p>inactive -- before and after a match, turns are not possible, options can be changed</p>
<p>active -- within a match, turns are possible, options cannot be changed</p>
<p>paused -- halted within a match, turns are not possible, options cannot be changed</p>
</section2>
<section2 topic='Dramatis Personae' anchor='terms-personae'>
<p>Most of the examples in this document use the scenario of Miranda and Ferdinand playing chess in Act V, Scene I of Shakespeare's The Tempest,
represented here as the "island-chess@games.shakespeare.lit" room. The characters are as follows:</p>
<table caption='Dramatis Personae'>
<tr>
<th>Room Nickname</th><th>Full JID</th><th>Affiliation</th><th>Game Role</th>
</tr><tr>
<td>damsel</td><td>miranda@shakespeare.lit/desktop</td><td>Owner</td><td>White</td>
</tr><tr>
<td>lad</td><td>ferdinand@shakespeare.lit/laptop</td><td>None</td><td>Black</td>
</tr><tr>
<td>KingOfNaples</td><td>alonso@shakespeare.lit/pda</td><td>None</td><td>None</td>
</tr><tr>
<td>prospero</td><td>prospero@shakespeare.lit/cell</td><td>None</td><td>None</td>
</tr>
</table>
</section2>
</section1>
<section1 topic='Affiliations' anchor='affiliations'>
<p>The following affiliations are defined:</p>
<ol>
<li>Member</li>
<li>Owner</li>
<li>None (the absence of an affiliation)</li>
</ol>
<p>
Support for the all affiliations is REQUIRED.
(The "None" affiliation is the absence of an affiliation.)
</p>
<p>
If a user without a defined affiliation enters a match, the user's affiliation is defined as "None".
</p>
<p>
The member affiliation provides a way for room owners to specify a "whitelist" of users
who are allowed to enter a members-only match.
When a member enters a members-only match, his or her affiliation does not change.
</p>
<p>
Information about affiliations MUST be sent in all presence stanzas generated or reflected by the match and sent to occupants.
</p>
<section2 topic='Privileges' anchor='privileges'>
<p>Owners are allowed to do what they like (saving/loading, change match options, etc.)
except in unmoderated matches. This match type restricts the use of owner privileges to specific room statuses.
Users with no affiliation SHALL NOT enter members-only matches.
Besides that, these users have the same privileges as members.</p>
<table caption='Owner Privileges Overview'>
<tr>
<th>Room Type</th>
<th>Configure</th>
<th>Save/Load</th>
<th>Grant Member</th>
<th>Revoke Member</th>
<th>Assign Role</th>
<th>Revoke Role</th>
</tr>
<tr>
<td>moderated match</td>
<td>inactive</td>
<td>all status</td>
<td>all status</td>
<td>all status</td>
<td>all status</td>
<td>all status</td>
</tr>
<tr>
<td>unmoderated match</td>
<td>inactive</td>
<td>inactive</td>
<td>all status</td>
<td>inactive</td>
<td>inactive and paused</td>
<td>inactive and paused</td>
</tr>
</table>
</section2>
<section2 topic='Changing Affiliations' anchor='changing-affi'>
<p>The ways in which a user's affiliation changes are well-defined.
Sometimes the change results from the user's own action (e.g., registering as a member of the match),
whereas sometimes the change results from an action taken by an owner.
If a user's affiliation changes, a MUG service implementation MUST change the user's affiliation to reflect the change
and communicate that to all occupants.</p>
</section2>
</section1>
<section1 topic="Entity Use Cases" anchor='entityusecases'>
<p>
A MUG implementation MUST support &xep0030;, &xep0128; and &xep0055;.
</p>
<section2 topic='Discovering MUG Component Support' anchor='disco-component'>
<p>
A Jabber entity may wish to discover if a service implements the
Multi-User Game protocol; in order to do so, it sends a service
discovery information ("disco#info") query to the service's JID:
</p>
<example caption="Client Queries Gaming Service for MUG Support via Disco"><![CDATA[
<iq from='alonso@shakespeare.lit/pda'
id='disco1'
to='games.shakespeare.lit'
type='get'>
<query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>
]]></example>
<p>
The service MUST return its identity and the features it supports:
</p>
<example caption="Service Returns Disco Info Results"><![CDATA[
<iq from='games.shakespeare.lit'
id='disco1'
to='alonso@shakespeare.lit/pda'
type='result'>
<query xmlns='http://jabber.org/protocol/disco#info'>
<identity
category='game'
name='Shakespeare Gaming Service'
type='multi-user'/>
<feature var='jabber:iq:search'/>
<feature var='http://jabber.org/protocol/mug'/>
<feature var='http://jabber.org/protocol/mug/chess'/>
<feature var='http://jabber.org/protocol/mug/poker'/>
<feature var='http://jabber.org/protocol/mug/maumau'/>
</query>
</iq>
]]></example>
</section2>
<section2 topic='Discovering Active Rooms' anchor='disco-matches'>
<p>
The service discovery items ("disco#items") protocol enables a user to query a
service for a list of associated items, which in the case of a game service would
consist of the active game rooms hosted by the service.
</p>
<example caption="User Queries for Active Rooms"><![CDATA[
<iq from='alonso@shakespeare.lit/pda'
id='disco2'
to='games.shakespeare.lit'
type='get'>
<query xmlns='http://jabber.org/protocol/disco#items'/>
</iq>
]]></example>
<p>
The service SHOULD return a full list of the active and public rooms it hosts.
</p>
<example caption="Service Returns Disco Item Results"><![CDATA[
<iq from='games.shakespeare.lit'
id='disco2'
to='alonso@shakespeare.lit/pda'
type='result'>
<query xmlns='http://jabber.org/protocol/disco#items'>
<item jid='chess@games.shakespeare.lit'
name='The Game of Kings'/>
<item jid='island-chess@games.shakespeare.lit'
name='A lovers match'/>
<item jid='maumau@games.shakespeare.lit'
name='Public Mau Mau Match'/>
<item jid='poker@games.shakespeare.lit'
name='Poker'/>
</query>
</iq>
]]></example>
<p>
If the full list of rooms is large (see &xep0030; for details),
the service MAY return only a partial list of rooms.
If it does so, it SHOULD include a &lt;set/&gt; element (as defined in &xep0059;)
to indicate that the list is not the full result set.
</p>
</section2>
<section2 topic='Search for Rooms' anchor='search-room'>
<p>
It is RECOMMENDED that a user uses &xep0055; to search for active or adjourned rooms.
At first the user needs to discover what search fields are supported by the service:
</p>
<example caption="Client Requests Search Fields from Service"><![CDATA[
<iq type='get'
from='prospero@shakespeare.lit/cell'
to='games.shakespeare.lit'
id='search1'
xml:lang='en'>
<query xmlns='jabber:iq:search'/>
</iq>
]]></example>
<p>
The service MUST then return the possible search fields to the user, and MAY include instructions:
</p>
<example caption="Service Returns Search Form to Client"><![CDATA[
<iq type='result'
from='games.shakespeare.lit'
to='prospero@shakespeare.lit/cell'
id='search1'
xml:lang='en'>
<query xmlns='jabber:iq:search'>
<instructions>
Use the enclosed form to search. If your Jabber client does not
support Data Forms, visit http://web.games.shakespeare.lit/
</instructions>
<x xmlns='jabber:x:data' type='form'>
<title>Room Search</title>
<instructions>
Please provide the following information
to search for active or adjourned matches.
</instructions>
<field type='hidden'
var='FORM_TYPE'>
<value>jabber:iq:search</value>
</field>
<field type='text-single'
label='Room Name'
var='mug#roomsearch_name'/>
<field type='boolean'
label='Saved Rooms'
var='mug#roomsearch_saved'/>
<field type='list-single'
label='Free Game Roles'
var='mug#roomsearch_roles'>
<option label='1'><value>1</value></option>
<option label='2'><value>2</value></option>
<option label='3'><value>3</value></option>
<option label='4'><value>4</value></option>
<option label='5'><value>5</value></option>
</field>
<field type='list-single'
label='Maximum Number of Occupants'
var='mug#roomsearch_max_occupants'>
<option label='1'><value>2</value></option>
<option label='2'><value>3</value></option>
<option label='3'><value>4</value></option>
<option label='4'><value>5</value></option>
<option label='5'><value>10</value></option>
<option label='5'><value>20</value></option>
</field>
<field type='list-single'
label='Game Category'
var='mug#roomsearch_category'>
<option label='Board Games'><value>board</value></option>
<option label='Card Games'><value>cards</value></option>
</field>
<field type='list-multi'
label='Games'
var='mug#roomsearch_game'>
<option label='Chess'><value>http://jabber.org/protocol/mug#chess</value></option>
<option label='Tic-Tac-Toe'><value>http://jabber.org/protocol/mug#tictactoe</value></option>
</field>
</x>
</query>
</iq>
]]></example>
<p>
The Saved Room option allows to search for active or adjourned rooms (see <link url='#terms-room_status'>Room Status</link>).
The Game Category field is to classify the game and to be able to only search for certain types of games.
Every game protocol MUST define its category in the corresponding game XEP.
</p>
<p>
After having received the possible search fields,
the user MAY then submit a search request, specifying values for any desired fields:
</p>
<example caption="User Submits Search Form"><![CDATA[
<iq type='set'
from='prospero@shakespeare.lit/cell'
to='games.shakespeare.lit'
id='search2'
xml:lang='en'>
<query xmlns='jabber:iq:search'>
<x xmlns='jabber:x:data' type='submit'>
<field type='hidden' var='FORM_TYPE'>
<value>jabber:iq:search</value>
</field>
<field var='status'>
<value>active</value>
</field>
<field var='game'>
<value>http://jabber.org/protocol/mug/chess</value>
</field>
</x>
</query>
</iq>
]]></example>
<p>
The submitting entity MAY submit the 'category' or 'game' field but MUST NOT submit both.
Sending an empty form adds up to searching for all games.
</p>
<p>
The service SHOULD then return a list of search results that match the values provided:
</p>
<example caption="Service Returns Search Results"><![CDATA[
<iq type='result'
from='games.shakespeare.lit'
to='prospero@shakespeare.lit/cell'
id='search2'
xml:lang='en'>
<query xmlns='jabber:iq:search'>
<x xmlns='jabber:x:data' type='result'>
<field type='hidden' var='FORM_TYPE'>
<value>jabber:iq:search</value>
</field>
<reported>
<field var='status' label='Match Status' type='list-single'/>
<field var='category' label='Game Category' type='list-single'/>
<field var='game' label='Game NS' type='text-single'/>
<field var='jid' label='Jabber ID' type='jid-single'/>
</reported>
<item>
<field var='status'><value>active</value></field>
<field var='category'><value>board</value></field>
<field var='game'><value>http://jabber.org/protocol/mug/chess</value></field>
<field var='jid'><value>island-chess@games.shakespeare.lit</value></field>
</item>
...
</x>
</query>
</iq>
]]></example>
<p>
If the full list of rooms is large,
the service MAY return only a partial list of rooms.
If it does so, it SHOULD include a &lt;set/&gt; element (as defined in &xep0059;)
to indicate that the list is not the full result set.
</p>
</section2>
<section2 topic='Querying for Room Information' anchor='disco-matchinfo'>
<p>
Using the disco#info protocol, a user may also query a specific room for
more detailed information about the room. A user MAY do so before entering a
room in order to discover the room configuration.
</p>
<example caption="Discovering Game Options of an Active Room"><![CDATA[
<iq from='alonso@shakespeare.lit/pda'
id='disco3'
to='island-chess@games.shakespeare.lit'>
type='get'>
<query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>
]]></example>
<p>
The room then MUST return its identity and the features it supports.
</p>
<example caption="Room Returns Extended Disco Info Results"><![CDATA[
<iq from='island-chess@games.shakespeare.lit'
id='disco3'
to='alonso@shakespeare.lit/pda'
type='get'>
<query xmlns='http://jabber.org/protocol/disco#info'>
<feature var='http://jabber.org/protocol/mug'/>
<feature var='http://jabber.org/protocol/mug/chess'/>
<feature var='mug_passwordprotected'/>
<feature var='mug_open'/>
<feature var='mug_moderated'/>
<feature var='mug_public'/>
<feature var='mug_semianonymous'/>
<x xmlns='jabber:x:data' type='result'>
<field var='FORM_TYPE' type='hidden'>
<value>http://jabber.org/protocol/mug#matchinfo</value>
</field>
<field var='mug#game' type='hidden'>
<value>http://jabber.org/protocol/mug/chess</value>
</field>
<field var='mug#match_description' label='Description'>
<value>A lovers match</value>
</field>
<field var='mug#match_occupants' label='Number of Occupants'>
<value>2</value>
</field>
<field var='mug#match_players' label='Number of Players'>
<value>2</value>
</field>
<field var='mug#match_maxoccupants' label='Maximum Number of Occupants'>
<value>5</value>
</field>
<field var='mug#match_chat' label='Communication Ressource'>
<value>xmpp:island-chess@conference.shakespeare.lit?join</value>
</field>
</x>
</query>
</iq>
]]></example>
<p>
A room MUST also return more detailed information in its disco#info response
using &xep0128;, identified by inclusion of a hidden FORM_TYPE field whose
value is "http://jabber.org/protocol/mug#matchinfo".
It MUST include a 'mug#game' field specifiying the namespace of the
game.
Optional information MAY include a more verbose description of the room
and the current number of occupants and players in the match or
'mug#match_chat' field specifiying a URI for the chat.
This is usually a &xep0045;.
</p>
<p>
See <link url='#terms-room'>Room Types</link> for details.
</p>
</section2>
<section2 topic='Querying for Room Items' anchor='disco-roomitems'>
<p>
A user MAY also query a specific match for its associated items (occupants):
</p>
<example caption='User Queries for Items Associated with a Specific Room'><![CDATA[
<iq from='alonso@shakespeare.lit/pda'
id='disco4'
to='island-chess@games.shakespeare.lit'
type='get'>
<query xmlns='http://jabber.org/protocol/disco#items'/>
</iq>
]]></example>
<p>
An implementation MAY return a list of existing occupants if that
information is publicly available, or return no list at all if this
information is kept private.
</p>
<example caption='Room Returns Disco Item Results (Items are Public)'><![CDATA[
<iq from='island-chess@games.shakespeare.lit'
id='disco4'
to='alonso@shakespeare.lit/pda'
type='result'>
<query xmlns='http://jabber.org/protocol/disco#items'>
<item jid='island-chess@games.shakespeare.lit/lad'/>
<item jid='island-chess@games.shakespeare.lit/damsel'/>
</query>
</iq>
]]></example>
<p>
Note: These &lt;item/&gt; elements are qualified by the disco#items namespace,
not the mug namespace; this means that they cannot possess 'role' attributes,
for example.
</p>
<example caption='Room Returns Empty Disco Item Results (Items are Private)'><![CDATA[
<iq from='island-chess@games.shakespeare.lit'
id='disco4'
to='alonso@shakespeare.lit/pda'
type='result'>
<query xmlns='http://jabber.org/protocol/disco#items'/>
</iq>
]]></example>
</section2>
<section2 topic='Querying a Room Occupant' anchor='disco-occupant'>
<p>
If a non-occupant attempts to send a disco request to an address of the form
&ROOMJID;, a MUG service SHOULD return the request to the entity and specify a
&badrequest; error condition. If an occupant sends such a request, the service
MAY pass it through the intended recipient.
</p>
</section2>
<section2 topic='Discovering Client Support for MUG' anchor='disco-client'>
<p>
A Jabber user may want to discover if one of the user's contacts supports the
Multi-User Game protocol. This is done using Service Discovery.
</p>
<example caption='User Queries Contact Regarding MUG Support'><![CDATA[
<iq from='alonso@shakespeare.lit/pda'
id='disco5'
to='ferdinand@shakespeare.lit/laptop'
type='get'>
<query xmlns='http://jabber.org/protocol/disco#info'/>
</iq>
]]></example>
<p>
The client SHOULD return its identity and the features it supports:
</p>
<example caption='Contact Returns Disco Info Results'><![CDATA[
<iq from='ferdinand@shakespeare.lit/laptop'
id='disco5'
to='alonso@shakespeare.lit/pda'
type='result'>
<query xmlns='http://jabber.org/protocol/disco#info'>
<identity
category='client'
type='pc'/>
...
<feature var='http://jabber.org/protocol/mug'/>
<feature var='http://jabber.org/protocol/mug/chess'/>
...
</query>
</iq>
]]></example>
<p>
A user may also query a contact regarding which room the contact is in.
This is done by querying the contact's full JID (&lt;user@host/resource&gt;)
while specifying the Service Discovery node
'http://jabber.org/protocol/mug#matches':
</p>
<example caption='User Queries Contact for Current Rooms'><![CDATA[
<iq from='alonso@shakespeare.lit/pda'
id='matches1'
to='ferdinand@shakespeare.lit/laptop'
type='get'>
<query xmlns='http://jabber.org/protocol/disco#items'
node='http://jabber.org/protocol/mug#matches'/>
</iq>
]]></example>
<p>
The requested client MAY list the active rooms as response;
see the <link url='#impl'>Implementation Guidelines</link> section of this document for details.
</p>
<example caption='Contact Returns Room Query Results'><![CDATA[
<iq from='ferdinand@shakespeare.lit/laptop'
id='matches1'
to='alonso@shakespeare.lit/pda'
type='result'>
<query xmlns='http://jabber.org/protocol/disco#items'
node='http://jabber.org/protocol/mug#matches'>
<item jid='island-chess@games.shakespeare.lit'/>
</query>
</iq>
]]></example>
<p>
Optionally, the contact MAY include its room nick as the value of the 'name' attribute:
</p>
<code><![CDATA[
...
<item jid='island-chess@games.shakespeare.lit'
name='lad'/>
...
]]></code>
</section2>
<section2 topic='Announcing a Running Game' anchor='user-gaming'>
<p>
The client MAY implement &xep0196; to announce running games.
To publish a running game the user sends:
</p>
<example caption='User Publishes Gaming Information'><![CDATA[
<iq type='set' from='ferdinand@shakespeare.lit/laptop' id='publish1'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='urn:xmpp:gaming:0'>
<item id='1feea9cceec2537e1b561e66d45bc566e276f22f'>
<game xmlns='urn:xmpp:gaming:0'>
<name>A lovers match</name>
<char_name>lad</char_name>
<server_name>Shakespeare Gaming Service</server_name>
<server_address>games.shakespeare.lit</server_address>
<uri>xmpp:island-chess@games.shakespeare.lit?play;game=http://jabber.org/protocol/mug/chess</uri>
</game>
</item>
</publish>
</pubsub>
</iq>
]]></example>
<p>
When the user stops playing the game (i.e. leaves the game room),
the user's client SHOULD send an empty &GAME; element with the same ItemID:
</p>
<example caption='User Publishes Gaming Information'><![CDATA[
<iq type='set' from='ferdinand@shakespeare.lit/laptop' id='publish2'>
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
<publish node='urn:xmpp:gaming:0'>
<item id='1feea9cceec2537e1b561e66d45bc566e276f22f'>
<game xmlns='urn:xmpp:gaming:0'/>
</item>
</publish>
</pubsub>
</iq>
]]></example>
</section2>
</section1>
<section1 topic="Occupant Use Cases" anchor='occupantusecases'>
<section2 topic='Invitation' anchor='mug-invite'>
<p>It can be useful to invite other users to a room in which one is an occupant.
To do this, a MUG client sends XML of the following form to the &ROOM; itself
adding an &INVITE; element for every invitee.
(the reason is OPTIONAL and the message MUST be explicitly or implicitly of type "normal"):</p>
<example caption="Occupant Sends an Invitation by Way of Room"><![CDATA[
<message
from='ferdinand@shakespeare.lit/desktop'
to='island-chess@games.shakespeare.lit'>
<game xmlns='http://jabber.org/protocol/mug#user'>
<invite to='alonso@shakespeare.lit'>
<reason>
Hey Alonso, this is the game of your son!
</reason>
</invite>
</game>
</message>
]]></example>
<p>
The &ROOM; itself MUST then add a 'from' address to the &INVITE; element whose value is the room JID of the invitor
and send the invitation to the invitee specified in the 'to' address.
The room SHOULD add the password if the room is password-protected:
</p>
<example caption="Room Sends Invitation to Invitee on Behalf of Invitor"><![CDATA[
<message
from='island-chess@games.shakespeare.lit'
to='alonso@shakespeare.lit/pda'>
<game xmlns='http://jabber.org/protocol/mug#user'>
<invited
from='ferdinand@shakespeare.lit/desktop'
var='http://jabber.org/protocol/mug/chess'>
<reason>
Hey Alonso, this is the game of your son!
</reason>
</invited>
<password>cauldronburn</password>
</game>
</message>
]]></example>
<p>
If the room is members-only, the service MAY also add the invitee to the member list.
If the invitor supplies a non-existent JID, the room SHOULD return an &notfound; error to the invitor.
The invitee MAY choose to formally decline (as opposed to ignore) the invitation;
and this is something that the sender may want to be informed about.
In order to decline the invitation,
the invitee MUST send a message of the following form to the &ROOM; itself:
</p>
<example caption="Invitee Declines Invitation"><![CDATA[
<message
from='alonso@shakespeare.lit/pda'
to='island-chess@games.shakespeare.lit'>
<game xmlns='http://jabber.org/protocol/mug#user'>
<decline to='ferdinand@shakespeare.lit'>
<reason>
Sorry, I'm too busy right now.
</reason>
</decline>
</game>
</message>
]]></example>
<example caption="Room Informs Invitor that Invitation Was Declined"><![CDATA[
<message
from='island-chess@games.shakespeare.lit'
to='ferdinand@shakespeare.lit/Desktop'>
<game xmlns='http://jabber.org/protocol/mug#user'>
<declined from='alonso@shakespeare.lit'>
<reason>
Sorry, I'm too busy right now.
</reason>
</declined>
</game>
</message>
]]></example>
<p>
Invitations MAY be based on room JIDs rather than bare JIDs
(so that, for example, an occupant could invite someone from one match to
another without knowing that person's bare JID).
Thus the service MUST handle both the invites and declines.
</p>
</section2>
<section2 topic='Joining a Room' anchor='mug-join'>
<section3 topic='Entering a Room' anchor='mug-join-game'>
<p>
A User enters a room as follows:
</p>
<example caption="Jabber User Seeks to Enter a Room"><![CDATA[
<presence
from='alonso@shakespeare.lit/pda'
to='island-chess@games.shakespeare.lit/KingOfNaples'>
<game
xmlns='http://jabber.org/protocol/mug'
var='http://jabber.org/protocol/mug/chess'/>
</presence>
]]></example>
<p>
The service MAY assign a free role to the user.
</p>
</section3>
<section3 topic="Presence Broadcast" anchor='mug-join-broadcast'>
<p>
If the service is able to add the user to the room,
it MUST send presence from all the existing occupants' room JIDs to the new occupant's full JID,
including extended presence information about roles in a &GAME; element
qualified by the 'http://jabber.org/protocol/mug' namespace
and containing an &ITEM; child with the 'affiliation' attribute
set to a value of "owner", "member", or "none" as appropriate:
</p>
<example caption="Service Sends Match State and Presence from Existing Occupants to New Occupant"><![CDATA[
<presence
from='island-chess@games.shakespeare.lit'
to='alonso@shakespeare.lit/pda'>
<game xmlns='http://jabber.org/protocol/mug'>
<status>active</status>
<state xmlns='http://jabber.org/protocol/mug/chess'>
<x xmlns='jabber:x:data' type='submit'>
...
</x>
</state>
</game>
</presence>
<presence
from='island-chess@games.shakespeare.lit/damsel'
to='alonso@shakespeare.lit/pda'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='owner' role='White'/>
</game>
</presence>
<presence
from='island-chess@games.shakespeare.lit/lad'
to='alonso@shakespeare.lit/pda'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='none' role='Black'/>
</game>
</presence>
]]></example>
<p>
The service MUST also send the new occupant's presence to all occupants including the new occupant.
If a role was assigned to the new occupant, it MUST be included in the presence
in order to notify the new and all other occupants about the new occupant's role.
</p>
<example caption="Service Sends New Occupant's Presence to All Occupants"><![CDATA[
<presence
from='island-chess@games.shakespeare.lit/KingOfNaples'
to='miranda@shakespeare.lit/desktop'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='none'/>
</game>
</presence>
<presence
from='island-chess@games.shakespeare.lit/KingOfNaples'
to='ferdinand@shakespeare.lit/laptop'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='none'/>
</game>
</presence>
]]></example>
<example caption="Service Sends New Occupants Presence to New Occupant"><![CDATA[
<presence
from='island-chess@games.shakespeare.lit/KingOfNaples'
to='alonso@shakespeare.lit/pda'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='none'/>
</game>
</presence>
]]></example>
<p>
Note: The order of the presence stanzas sent to the new occupant is important.
The service MUST first send the complete list of the existing occupants to the
new occupant and only then send the new occupant's own presence to the new
occupant. This helps the client know when it has received the complete
"room roster".
</p>
</section3>
<section3 topic="Non-Anonymous Rooms" anchor='enter-nonanon'>
<p>
If the room is non-anonymous, the service MUST send the new occupant's full JID
to all occupants using extended presence information in an &GAME; element qualified
by the 'http://jabber.org/protocol/mug' namespace and containing an &ITEM; child
with a 'jid' attribute specifying the occupant's full JID:
</p>
<example caption="Service Sends Full JID to all Occupants"><![CDATA[
<presence
from='island-chess@games.shakespeare.lit/KingOfNaples'
to='miranda@shakespeare.lit/desktop'
<game xmlns='http://jabber.org/protocol/mug'>
<item jid='alonso@shakespeare.lit/pda' affiliation='none'/>
</game>
</presence>
[...]
]]></example>
</section3>
<section3 topic="Semi-Anonymous Rooms" anchor='enter-semianon'>
<p>
If the room is semi-anonymous, the service MUST send presence from the new occupant
to all occupants as specified above, but MUST include the new occupant's full JID
only in the presence notifications it sends to the room owner and not to any other
occupant.
</p>
</section3>
<section3 topic="Fully-Anonymous Rooms" anchor='enter-fullyanon'>
<p>
If the room is fully-anonymous, the service MUST send presence from the new occupant
to all occupants as specified above, but MUST NOT include the new occupant's full JID
to any other occupant.
</p>
</section3>
<section3 topic='Password-Protected Rooms' anchor='enter-pw'>
<p>
If the room requires a password and the user did not supply one (or the password
provided is incorrect), the service MUST deny access to the room and inform the
user that they are unauthorized; this is done by returning a presence stanza of
type "error" specifying a &notauthorized; error:
</p>
<example caption='Service Denies Access Because No Password Provided'><![CDATA[
<presence
from='island-chess@games.shakespeare.lit'
to='alonso@shakespeare.lit/pda'
type='error'>
<game xmlns='http://jabber.org/protocol/mug'/>
<error type='auth'>
<not-authorized xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</presence>
]]></example>
<p>
Passwords SHOULD be supplied with the presence stanza sent when entering the room,
contained within an &lt;game/&gt; element qualified by the
'http://jabber.org/protocol/mug' namespace and containing a &lt;password/&gt; child.
Passwords are to be sent as cleartext; no other authentication methods are supported
at this time, and any such authentication or authorization methods shall be defined
in a separate specification (see the <link url='#security'>Security Considerations</link>
section of this document).
</p>
<example caption='User Provides Password On Entering a Room'><![CDATA[
<presence
from='alonso@shakespeare.lit/pda'
to='island-chess@games.shakespeare.lit/KingOfNaples'>
<game
xmlns='http://jabber.org/protocol/mug'
var='http://jabber.org/protocol/mug/chess'>
<password>brave new world</password>
</game>
</presence>
]]></example>
</section3>
<section3 topic='Members-Only Rooms' anchor='enter-members'>
<p>
If the room is members-only but the user is not on the member list, the service MUST
deny access to the room and inform the user that they are not allowed to enter the
room; this is done by returning a presence stanza of type "error" specifying a
&registration; error condition:
</p>
<example caption='Service Denies Access Because User Is Not on Member List'><![CDATA[
<presence
from='island-chess@games.shakespeare.lit'
to='alonso@shakespeare.lit/pda'
type='error'>
<game xmlns='http://jabber.org/protocol/mug'/>
<error type='auth'>
<registration-required xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</presence>
]]></example>
</section3>
<section3 topic='Nickname Conflict' anchor='enter-conflict'>
<p>
If the room already contains another user with the nickname desired by the user
seeking to enter the room (or if the nickname is reserved by another user on the
member list), the service MUST deny access to the room and inform the user of the
conflict; this is done by returning a presence stanza of type "error" specifying a
&conflict; error condition:
</p>
<example caption='Service Denies Access Because of Nick Conflict'><![CDATA[
<presence
from='island-chess@games.shakespeare.lit'
to='alonso@shakespeare.lit/pda'
type='error'>
<game xmlns='http://jabber.org/protocol/mug'/>
<error type='cancel'>
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</presence>
]]></example>
<p>
However, if the bare JID &USERJID; of the present occupant matches the bare JID
of the user seeking to enter the room, then the service SHOULD allow entry to the user,
so that the user has two (or more) in-room "sessions" with the same roomnick, one for each resource.
If a service allows more than one occupant with the same bare JID and the same room nickname,
it SHOULD route in-room messages and presence to all of the user's resources
and allow all of the user's resources to send messages to the room;
it is up to the implementation to determine how to route
private messages to all or only one resource
(based on presence priority or some other algorithm).
</p>
</section3>
<section3 topic='Max Users' anchor='enter-maxusers'>
<p>
If the room has reached its maximum number of occupants, the service SHOULD
deny access to the room and inform the user of the restriction; this is done
by returning a presence stanza of type "error" specifying a &unavailable;
error condition:
</p>
<example caption='Service Informs User that Room Occupant Limit Has Been Reached'><![CDATA[
<presence
from='island-chess@games.shakespeare.lit'
to='alonso@shakespeare.lit/pda'
type='error'>
<game xmlns='http://jabber.org/protocol/mug'/>
<error type='wait'>
<service-unavailable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</presence>
]]></example>
<p>
Alternatively, the room could kick an "idle user" in order to free up space.
</p>
</section3>
<section3 topic='Locked Room' anchor='enter-locked'>
<p>
If a user attempts to enter a room while it is "locked" (i.e., before the room creator
provides an initial configuration and therefore before the room officially exists), the
service MUST refuse entry and return an &notfound; error to the user:
</p>
<example caption='Service Denies Access Because Room Does Not Exist'><![CDATA[
<presence
from='island-chess@games.shakespeare.lit'
to='alonso@shakespeare.lit/pda'
type='error'>
<game xmlns='http://jabber.org/protocol/mug'/>
<error type='cancel'>
<item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</presence>
]]></example>
</section3>
<section3 topic='Nonexistent Room' anchor='enter-nonexistent'>
<p>
If the room does not already exist when the user seeks to enter it, the service SHOULD
create it; however, this is not required, since an implementation or deployment MAY
choose to restrict the privilege of creating rooms. For details, see the
<link url='#creatematch'>Creating a Room</link> section of this document.
</p>
</section3>
</section2>
<section2 topic='Taking a Role' anchor='take-role'>
<p>
When a user wants to take a free role,
he sends the following presence to &ROOM;.
</p>
<example caption="User Wants To Take a Role"><![CDATA[
<presence
from='ferdinand@shakespeare.lit/laptop'
to='island-chess@games.shakespeare.lit'>
<game xmlns='http://jabber.org/protocol/mug'>
<item role='Black'/>
</game>
</presence>
]]></example>
<p>
After the role has been successfully assigned to the requesting occupant,
the service MUST send the new presence to all occupants.
</p>
<example caption="Service Sends Changed Occupant's Presence to All Occupant"><![CDATA[
<presence
from='island-chess@games.shakespeare.lit/lad'
to='miranda@shakespeare.lit/desktop'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='none' role='Black'/>
</game>
</presence>
<presence
from='island-chess@games.shakespeare.lit/lad'
to='ferdinand@shakespeare.lit/laptop'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='none' role='Black'/>
</game>
</presence>
]]></example>
<example caption="Service Sends Changed Occupants Presence Back To Occupant"><![CDATA[
<presence
from='island-chess@games.shakespeare.lit/lad'
to='alonso@shakespeare.lit/pda'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='none' role='Black'/>
</game>
</presence>
]]></example>
<p>If the role is already taken, the service must return the following error.</p>
<example caption="Service Informs User About Role Conflict"><![CDATA[
<presence
from='island-chess@games.shakespeare.lit'
to='alonso@shakespeare.lit/pda'
type='error'>
<game xmlns='http://jabber.org/protocol/mug'/>
<error type='cancel'>
<conflict xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</presence>
]]></example>
<p>
If the requested role doesn't exist in the match, the service MUST return a not-acceptable error.
</p>
</section2>
<section2 topic='Game Start' anchor='mug-start'>
<p>
After the match is ready to be started (as to be defined by the game protocol),
all players MUST send start messages in order to start the game.
</p>
<example caption='Player Send a Start Message'><![CDATA[
<message
from='miranda@shakespeare.lit/desktop'
to='island-chess@games.shakespeare.lit'>
<start xmlns='http://jabber.org/protocol/mug#user'/>
</message>
]]></example>
<p>
In order to see what players are ready to start, the service MUST reflect
the start message from each player to all players.
</p>
<example caption='The Service reflects the Start Message'><![CDATA[
<message
from='island-chess@games.shakespeare.lit/damsel'
to='miranda@shakespeare.lit/desktop'>
<start xmlns='http://jabber.org/protocol/mug#user'/>
</message>
<message
from='island-chess@games.shakespeare.lit/damsel'
to='ferdinand@shakespeare.lit/desktop'>
<start xmlns='http://jabber.org/protocol/mug#user'/>
</message>
]]></example>
<p>
If the match is not ready, the service MUST send the following error.
</p>
<example caption='Service Informs Player that the Match is Not Ready'><![CDATA[
<message
from='island-chess@games.shakespeare.lit'
to='miranda@shakespeare.lit/desktop'
type='error'>
<start xmlns='http://jabber.org/protocol/mug#user'/>
<error type='cancel'>
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</message>
]]></example>
<p>
After the service received messages from all players,
it MUST update the match status from inactive to active by a
presence broadcast to all occupants.
If the owner changes the configuration or roles change after a player sent his message
and before the service sends presence broadcast indicating the game status active,
the player MUST send the message again.
</p>
<example caption='Service Broadcasts the Start Message to All'><![CDATA[
<presence
from='island-chess@games.shakespeare.lit'
to='alonso@shakespeare.lit/pda'>
<game xmlns='http://jabber.org/protocol/mug'>
<status>active</status>
<state xmlns='http://jabber.org/protocol/mug/chess'>
<x xmlns='jabber:x:data' type='submit'>
...
</x>
</state>
</game>
</presence>
<presence
from='island-chess@games.shakespeare.lit'
to='ferdinand@shakespeare.lit/laptop'>
<game xmlns='http://jabber.org/protocol/mug'>
<status>active</status>
<state xmlns='http://jabber.org/protocol/mug/chess'>
<x xmlns='jabber:x:data' type='submit'>
...
</x>
</state>
</game>
</presence>
<presence
from='island-chess@games.shakespeare.lit'
to='miranda@shakespeare.lit/desktop'>
<game xmlns='http://jabber.org/protocol/mug'>
<status>active</status>
<state xmlns='http://jabber.org/protocol/mug/chess'>
<x xmlns='jabber:x:data' type='submit'>
...
</x>
</state>
</game>
</presence>
]]></example>
<p>
Note that the spectator alonso recieves the start presence, too.
</p>
</section2>
<section2 topic='Game Play' anchor='mug-play'>
<p>
In order to make a move in a match, a &MESSAGE; stanza MUST be send to &ROOMJID;
containing a &TURN; element qualified by 'http://jabber.org/protocol/mug#user' namespace.
Game protocols SHOULD place own elements defining the turn inside the &TURN; element.
</p>
<example caption='Occupant Sends a Game Turn'><![CDATA[
<message
from='miranda@shakespeare.lit/desktop'
to='island-chess@games.shakespeare.lit'
type='chat'>
<turn xmlns='http://jabber.org/protocol/mug#user'>
<play xmlns='http://jabber.org/protocol/mug/chess'
suit='queen'
col='d'
row='2'/>
</turn>
</message>
]]></example>
<p>
A service MUST validate the player's move before passing it to the occupants.
If the turn is invalid, as defined by the game protocol,
the service MUST return an error and kick the player
unless the player is the owner of the room, in which case he SHOULD lose his game role.
</p>
<example caption='Service Informs Player About an Invalid Turn'><![CDATA[
<message
from='island-chess@games.shakespeare.lit'
to='miranda@shakespeare.lit/desktop'
type='error'>
<turn xmlns='http://jabber.org/protocol/mug#user'>
<play xmlns='http://jabber.org/protocol/mug/chess'
suit='queen'
col='d'
row='2'/>
</turn>
<error type='cancel'>
<undefined-condition xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
<invalid-turn xmlns='http://jabber.org/protocol/mug'/>
</error>
</message>
<presence
from='island-chess@games.shakespeare.lit/damsel'
to='miranda@shakespeare.lit/desktop'
type='unavailable'>
<invalid-turn xmlns='http://jabber.org/protocol/mug#user'/>
</presence>
]]></example>
<p>
If a spectator sends a turn the service MUST return the following error.
</p>
<example caption='Service Denies Turn'><![CDATA[
<message
from='island-chess@games.shakespeare.lit/KingOfNaples'
to='alonso@shakespeare.lit/pda'
type='error'>
<turn xmlns='http://jabber.org/protocol/mug#user'>
<play xmlns='http://jabber.org/protocol/mug/chess'
suit='queen'
col='d'
row='2'/>
</turn>
<error type='auth'>
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</message>
]]></example>
<p>
If a player sends a turn while the match status is 'inactive' or 'paused'
the service MUST send this error:
</p>
<example caption='Service Denies Turn Because of Match Status'><![CDATA[
<message
from='miranda@shakespeare.lit/desktop'
to='island-chess@games.shakespeare.lit'
type='error'>
<turn xmlns='http://jabber.org/protocol/mug#user'>
<play xmlns='http://jabber.org/protocol/mug/chess'
suit='queen'
col='d'
row='2'/>
</turn>
<error type='cancel'>
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</message>
]]></example>
<p>
If the move is valid, the service MUST distribute the turn.
The occupants, who receive the turn are defined by the game protocol.
However, the turn MUST be reflected to the sender.
</p>
<example caption='Service Reflects Turn to All Occupants'><![CDATA[
<message
from='island-chess@games.shakespeare.lit/damsel'
to='ferdinand@shakespeare.lit/laptop'
type='chat'>
<turn xmlns='http://jabber.org/protocol/mug#user'>
<play xmlns='http://jabber.org/protocol/mug/chess'
suit='queen'
col='d'
row='2'/>
</turn>
</message>
<message
from='island-chess@games.shakespeare.lit/damsel'
to='alonso@shakespeare.lit/pda'
type='chat'>
<turn xmlns='http://jabber.org/protocol/mug#user'>
<play xmlns='http://jabber.org/protocol/mug/chess'
suit='queen'
col='d'
row='2'/>
</turn>
</message>
<message
from='island-chess@games.shakespeare.lit/damsel'
to='miranda@shakespeare.lit/desktop'
type='chat'>
<turn xmlns='http://jabber.org/protocol/mug#user'>
<play xmlns='http://jabber.org/protocol/mug/chess'
suit='queen'
col='d'
row='2'/>
</turn>
</message>
]]></example>
</section2>
<section2 topic='Resignation' anchor='mug-resign'>
<p>
If a client wants to resign, he sends the following.
</p>
<example caption='User resigns'><![CDATA[
<presence
from='miranda@shakespeare.lit/desktop'
to='island-chess@games.shakespeare.lit'>
<game
xmlns='http://jabber.org/protocol/mug'>
<item role='none'/>
</game>
</presence>
]]></example>
<p>
Afterwards, the service decides whether to cancel or pause the match
based on the game specification.
</p>
</section2>
<section2 topic='Termination' anchor='mug-term'>
<p>
The game protocol respectively the game protocol implementation decides when a match is over.
In the case of game termination,
the service MUST notify every player through updated presence including the resulting final state.
</p>
<example caption='Service Sends Termination Broadcast to all Players'><![CDATA[
<presence
from='island-chess@games.shakespeare.lit'
to='ferdinand@shakespeare.lit/laptop'>
<game xmlns='http://jabber.org/protocol/mug'>
<status>inactive</status>
<state xmlns='http://jabber.org/protocol/mug/chess'>
<won>Black</won>
</state>
</game>
</presence>
<presence
from='island-chess@games.shakespeare.lit'
to='alonso@shakespeare.lit/pda'>
<game xmlns='http://jabber.org/protocol/mug'>
<status>inactive</status>
<state xmlns='http://jabber.org/protocol/mug/chess'>
<won>Black</won>
</state>
</game>
</presence>
<presence
from='island-chess@games.shakespeare.lit'
to='miranda@shakespeare.lit/desktop'>
<game xmlns='http://jabber.org/protocol/mug'>
<status>inactive</status>
<state xmlns='http://jabber.org/protocol/mug/chess'>
<won>Black</won>
</state>
</game>
</presence>
]]></example>
</section2>
<section2 topic="Changing Nickname">
<p>To change his nickname, an occupant sends the following presence.</p>
<example caption='Occupant Changes Nickname'><![CDATA[
<presence
from='miranda@shakespeare.lit/desktop'
to='island-chess@games.shakespeare.lit/miranda'>
<game xmlns='http://jabber.org/protocol/mug'/>
</presence>
]]></example>
<p>The service must send the updated presence to all occupants.</p>
<example caption='Service Updates Nick'><![CDATA[
<presence
from='island-chess@games.shakespeare.lit/damsel'
to='miranda@shakespeare.lit/desktop'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='owner'
nick='miranda'
role='White'/>
</game>
</presence>
<presence
from='island-chess@games.shakespeare.lit/damsel'
to='ferdinand@shakespeare.lit/laptop'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='owner'
nick='miranda'
role='White'/>
</game>
</presence>
<presence
from='island-chess@games.shakespeare.lit/damsel'
to='alonso@shakespeare.lit/pda'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='owner'
nick='miranda'
role='White'/>
</game>
</presence>
]]></example>
<p>
If the room already contains another user with the nickname the same rules apply
as on <link url='#enter-conflict'>entering a room</link>.
</p>
</section2>
<section2 topic='Sending a Private Message' anchor='privatemessage'>
<p>
Since each occupant has a unique room JID, an occupant MAY send a "private message" to a
selected occupant via the service by sending a message to the occupant's match JID. The message
type SHOULD be "chat", or MAY be left unspecified (i.e., a normal message). This privilege
SHOULD be allowed to any occupant (even a spectator in a moderated room).
</p>
<example caption='Occupant Sends Private Message'><![CDATA[
<message
from='miranda@shakespeare.lit/desktop'
to='island-chess@games.shakespeare.lit/lad'
type='chat'>
<body>Sweet lord, you play me false.</body>
</message>
]]></example>
<p>
The service is responsible for changing the 'from' address to the sender's match JID and
delivering the message to the intended recipient's full JID.
</p>
<example caption='Recipient Receives the Private Message'><![CDATA[
<message
from='island-chess@games.shakespeare.lit/damsel'
to='ferdinand@shakespeare.lit/laptop'
type='chat'>
<body>Sweet lord, you play me false.</body>
</message>
]]></example>
<p>
If the sender attempts to send a private message to a room JID that does not exist,
the service MUST return an &notfound; error to the sender.
</p>
<p>
If the sender is not an occupant of the room in which the intended recipient is visiting,
the service MUST return a &notacceptable; error to the sender.
</p>
</section2>
<section2 topic='Getting Member List' anchor='getmemberlist'>
<p>
If allowed in accordance with room configuration, an occupant MAY be allowed to
retrieve the list of room members. For details, see the
<link url='#modifymember'>Modifying the Member List</link> section of this document.
</p>
</section2>
<section2 topic='Exiting A Room'>
<p>
In order to exit a multi-user game room, an occupant sends a presence stanza
of type "unavailable" to the &ROOMJID; it is currently using in the room.
</p>
<example caption='Occupant Exits a Room'><![CDATA[
<presence
from='ferdinand@shakespeare.lit'
to='island-chess@games.shakespeare.lit/lad'
type='unavailable'/>
]]></example>
<example caption='Service Sends Presence Related to Departure of Occupant'><![CDATA[
<presence
from='island-chess@games.shakespeare.lit/lad'
to='miranda@shakespeare.lit'
type='unavailable'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='member' role='none' />
</game>
</presence>
<presence
from='island-chess@games.shakespeare.lit/lad'
to='alonso@shakespeare.lit'
type='unavailable'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='member' role='none' />
</game>
</presence>
<presence
from='island-chess@games.shakespeare.lit/lad'
to='ferdinand@shakespeare.lit'
type='unavailable'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='member' role='none' />
</game>
</presence>
]]></example>
<p>
If the leaving occupant had a role that was indispensable, the service MUST pause or cancel the game.
</p>
<example caption='Service Broadcasts the Pause Message to All'><![CDATA[
<presence>
from='island-chess@games.shakespeare.lit'
to='ferdinand@shakespeare.lit/laptop'>
<pause xmlns='http://jabber.org/protocol/mug'/>
</presence>
<presence>
from='island-chess@games.shakespeare.lit'
to='miranda@shakespeare.lit/desktop'>
<pause xmlns='http://jabber.org/protocol/mug'/>
</presence>
]]></example>
<p>
To resume the game, all players have to send &lt;start/&gt; messages again.
</p>
<example caption='Service Broadcasts the Cancel Message to All'><![CDATA[
<presence
from='island-chess@games.shakespeare.lit'
to='ferdinand@shakespeare.lit/laptop'>
<game xmlns='http://jabber.org/protocol/mug'>
<status>inactive</status>
<state xmlns='http://jabber.org/protocol/mug/chess'>
<match-canceled />
</state>
</game>
</presence>
<presence
from='island-chess@games.shakespeare.lit'
to='miranda@shakespeare.lit/desktop'>
<game xmlns='http://jabber.org/protocol/mug'>
<status>inactive</status>
<state xmlns='http://jabber.org/protocol/mug/chess'>
<match-canceled />
</state>
</game>
</presence>
]]></example>
</section2>
</section1>
<section1 topic='Owner Use Cases'>
<section2 topic='Creating a Room' anchor='creatematch'>
<p>To create a room a user sends the following presence to the room.</p>
<example caption='User Creates a Room and Signals Game Support'><![CDATA[
<presence
from='miranda@shakespeare.lit/desktop'>
to='island-chess@games.shakespeare.lit/damsel'>
<game xmlns='http://jabber.org/protocol/mug'
var='http://jabber.org/protocol/mug/chess'/>
</presence>
]]></example>
<p>
If the priviledge to create a room is restricted to certain users
and the room cannot be created,
the service MUST reply with the following error.
</p>
<example caption='Service Informs User of Inability to Create a Room'><![CDATA[
<presence
from='island-chess@games.shakespeare.lit/damsel'
to='miranda@shakespeare.lit/desktop'
type='error'>
<game xmlns='http://jabber.org/protocol/mug'
var='http://jabber.org/protocol/mug/chess'/>
<error type='cancel'>
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</presence>
]]></example>
<p>
If a game element or the var attribute with the game namespace is
missing then the service MUST deny creating a room and send a
presence with a bad request error back to the user.
</p>
<p>
If this user is allowed to create a room and the room does not yet exist,
the service MUST create the room according to some default configuration,
assign the requesting user as the initial room owner,
and add the owner to the room but not allow anyone else to enter the room
(effectively "locking" the room).
The initial presence stanza received by the owner from the room MUST include
extended presence information indicating the user's status as an owner
and acknowledging that the room is awaiting configuration and that the initial
match status is 'created'.
</p>
<example caption='Service Acknowledges Room Creation'><![CDATA[
<presence
from='island-chess@games.shakespeare.lit'
to='alonso@shakespeare.lit/pda'>
<game xmlns='http://jabber.org/protocol/mug'>
<status>created</status>
</game>
</presence>
<presence
from='island-chess@games.shakespeare.lit/damsel'>
to='miranda@shakespeare.lit/desktop'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='owner' role='White'/>
</game>
</presence>
]]></example>
<p>
The role attribute is only necessary if the service assignes roles automatically.
</p>
<section3 topic='Creating an Instant Room'>
<p>
To request a room with the default configuration the owner sends the following query.
</p>
<example caption='Initiator Requests Instant Room'><![CDATA[
<iq from='miranda@shakespeare.lit/desktop'
id='create1'
to='island-chess@games.shakespeare.lit'
type='set'>
<query xmlns='http://jabber.org/protocol/mug#owner'>
<options>
<x xmlns='jabber:x:data' type='submit'/>
</options>
</query>
</iq>
]]></example>
</section3>
<section3 topic='Configuring the Room'>
<p>
If the user wants to configure the room, he MAY first request the configuration form.
</p>
<example caption='Initiator Requests Configuration Form'><![CDATA[
<iq from='miranda@shakespeare.lit/desktop'
id='create1'
to='island-chess@games.shakespeare.lit'
type='get'>
<query xmlns='http://jabber.org/protocol/mug#owner'>
<options/>
</query>
</iq>
]]></example>
<p>
If no configuration is possible, the service MUST return the following error.
</p>
<example caption='Service Informs Owner that No Configuration is Possible'><![CDATA[
<iq from='island-chess@games.shakespeare.lit'
id='create1'
to='miranda@shakespeare.lit/desktop'
type='result'>
<query xmlns='http://jabber.org/protocol/mug#owner'>
<options/>
</query>
</iq>
]]></example>
<p>
The service then sends the initial configuration form to the user.
</p>
<example caption='Service Sends Configuration Form'><![CDATA[
<iq from='island-chess@games.shakespeare.lit'
id='create1'
to='miranda@shakespeare.lit/desktop'
type='result'>
<query xmlns='http://jabber.org/protocol/mug#owner'>
<options>
<x xmlns='jabber:x:data' type='form'>
<title>Configuration for "Island Chess" Room</title>
<instructions>
Your room island-chess@games.shakespeare.lit has been created!
The default configuration is as follows:
- Moderated and public room
- Up to 20 occupants
- No password required
- No invitation required
To accept the default configuration, click OK. To
select a different configuration, please complete
this form.
</instructions>
<field
type='hidden'
var='FORM_TYPE'>
<value>http://jabber.org/protocol/mug#matchconfig</value>
</field>
<field
label='Natural-Language Room Name'
type='text-single'
var='mug#roomconfig_roomname'/>
<field
label='Short Description of the Room'
type='text-single'
var='mug#roomconfig_matchdesc'/>
<field
label='Type of the Room Policy'
type='list-single'
var='mug#roomconfig_roompolicy'>
<value>moderated</value>
<option label='Moderated Room'><value>moderated</value></option>
<option label='Unmoderated Room'><value>unmoderated</value></option>
</field>
<field
label='Allow Occupants to Invite Others?'
type='boolean'
var='mug#roomconfig_allowinvites'>
<value>0</value>
</field>
<field
label='Maximum Number of Occupants'
type='list-single'
var='mug#roomconfig_maxusers'>
<value>20</value>
<option label='2'><value>2</value></option>
<option label='5'><value>5</value></option>
<option label='10'><value>10</value></option>
<option label='20'><value>20</value></option>
<option label='30'><value>30</value></option>
<option label='50'><value>50</value></option>
<option label='None'><value>none</value></option>
</field>
<field
label='Make Room Publicly Searchable?'
type='boolean'
var='mug#roomconfig_publicroom'>
<value>1</value>
</field>
<field
label='Make Room Members-Only?'
type='boolean'
var='mug#roomconfig_membersonly'>
<value>0</value>
</field>
<field
label='Type of the Anonymity'
type='list-single'
var='mug#roomconfig_anonymity'>
<value>semi-anonymous</value>
<option label='Fully-Anonymous Room'><value>fully-anonymous</value></option>
<option label='Semi-Anonymous Room'><value>semi-anonymous</value></option>
<option label='Non-Anonymous Room'><value>non-anonymous</value></option>
</field>
<field
label='Password Required to Enter?'
type='boolean'
var='mug#roomconfig_passwordprotectedroom'>
<value>0</value>
</field>
<field type='fixed'>
<value>
If a password is required to enter this room,
you must specify the password below.
</value>
</field>
<field
label='Password'
type='text-private'
var='mug#roomconfig_roomsecret'/>
<field type='fixed'>
<value>
You may specify a URL for a communication resources such as a MUC chat,
a video chat or an IRC chat, leave it empty for no chat
or leave it up to the server to create one.
</value>
</field>
<field
label='Communication Ressource'
type='text-multi'
var='mug#roomconfig_chat'/>
</x>
<options xmlns='http://jabber.org/protocol/mug/chess'>
<x xmlns='jabber:x:data' type='form'>
<title>Configuration for Chess Game</title>
<instructions>
The default configuration is as follows:
- Classic Chess
To accept the default configuration, click OK. To
select a different configuration, please complete
this form.
</instructions>
<field var='FORM_TYPE'>
type='hidden'
<value>http://jabber.org/protocol/mug/chess#chessconfig</value>
</field>
<field
label='Game Variant'
type='list-single'
var='mug/chess#config_variant'>
<value>classic</value>
<option label='The standard classical chess'><value>classic</value></option>
<option label='Four Player Bosworth'><value>bosworth</value></option>
<option label='Four Player Tandem Chess'><value>tandem</value></option>
<option label='Three Handed Chess'><value>threehanded</value></option>
</field>
...
</x>
</options>
</options>
</query>
</iq>
]]></example>
<p>
To finish the configuration, the user MUST submits the completed form to the service.
</p>
<example caption='Owner Submits Configuration Form'><![CDATA[
<iq from='miranda@shakespeare.lit/desktop'
id='create2'
to='island-chess@games.shakespeare.lit'
type='result'>
<query xmlns='http://jabber.org/protocol/mug#owner'>
<options>
<x xmlns='jabber:x:data' type='submit'>
<field var='FORM_TYPE'>
<value>http://jabber.org/protocol/mug#roomconfig</value>
</field>
<field var='mug#roomconfig_roomname'>
<value>A lovers room</value>
</field>
<field var='mug#roomconfig_roomdesc'/>
<value>The Chess Match at Act V, Scene IV of Shakespeare's The Tempest</value>
</field>
<field var='mug#roomconfig_roompolicy'>
<value>moderated</value>
</field>
<field var='mug#roomconfig_allowinvites'>
<value>0</value>
</field>
<field var='mug#roomconfig_maxusers'>
<value>5</value>
</field>
<field var='mug#roomconfig_publicroom'>
<value>1</value>
</field>
<field var='mug#roomconfig_membersonly'>
<value>0</value>
</field>
<field var='mug#roomconfig_anonymity'>
<value>semi-anonymous</value>
</field>
<field var='mug#roomconfig_passwordprotectedroom'>
<value>1</value>
</field>
<field var='mug#roomconfig_roomsecret'>
<value>bravenewworld</value>
</field>
<field var='mug#roomconfig_chat'/>
</x>
<options xmlns='http://jabber.org/protocol/mug/chess'>
<x xmlns='jabber:x:data' type='submit'>
<field var='FORM_TYPE'>
<value>http://jabber.org/protocol/mug/chess#chessconfig</value>
</field>
<field var='mug/chess#config_variant'>
<value>classic</value>
</field>
...
</x>
</options>
</options>
</query>
</iq>
]]></example>
<p>
In addition to the room configuration, the user MAY also supply a custom initial state for the match.
</p>
<example caption="Owner Submits Configuration Form Including a Constructed Match"><![CDATA[
<iq from='miranda@shakespeare.lit/desktop'
id='create2'
to='island-chess@games.shakespeare.lit'
type='result'>
<query xmlns='http://jabber.org/protocol/mug#owner'>
<options>
<x xmlns='jabber:x:data' type='submit'>
...
</x>
<options xmlns='http://jabber.org/protocol/mug/chess'>
<x xmlns='jabber:x:data' type='submit'>
...
</x>
</options>
</options>
<state xmlns='http://jabber.org/protocol/mug/chess'>
<x xmlns='jabber:x:data' type='submit'>
...
</x>
</state>
</query>
</iq>
]]></example>
<p>
Valid states are defined by the game protocol
and may consist of the explicit current state in form of a data form
or the series of turns that led to the state.
</p>
<p>
If the room creation fails because the specified room configuration options violate
one or more service policies (e.g., because the password for a password-protected room is blank),
the service MUST return a &lt;not-acceptable/&gt; error.
</p>
<example caption='Service Informs Owner that Requested Configuration Options Are Unacceptable'><![CDATA[
<iq from='island-chess@games.shakespeare.lit'
id='create2'
to='miranda@shakespeare.lit/desktop'
type='error'>
<error type='modify'>
<not-acceptable xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</iq>
]]></example>
<p>Alternatively, the room owner MAY cancel the configuration process:</p>
<example caption='Owner Cancels Initial Configuration'><![CDATA[
<iq from='miranda@shakespeare.lit/desktop'
id='create2'
to='island-chess@games.shakespeare.lit'
type='set'>
<query xmlns='http://jabber.org/protocol/mug#owner'>
<x xmlns='jabber:x:data' type='cancel'/>
</query>
</iq>
]]></example>
<p>
If the room owner cancels the initial configuration, the service SHOULD destroy the room, making sure to send unavailable presence to the room owner (see the "Destroying a Room" use case for protocol details).
</p>
</section3>
</section2>
<section2 topic='Subsequent Room Configuration'>
<p>
The owner may change the configuration whenever the match status is 'inactive'.
</p>
<example caption='Owner Requests Configuration Form'><![CDATA[
<iq from='miranda@shakespeare.lit/desktop'
id='create1'
to='island-chess@games.shakespeare.lit'
type='get'>
<query xmlns='http://jabber.org/protocol/mug#owner'/>
</iq>
]]></example>
<example caption='Service Sends Configuration Form'><![CDATA[
<iq from='island-chess@games.shakespeare.lit'
id='create1'
to='miranda@shakespeare.lit/desktop'
type='result'>
<query xmlns='http://jabber.org/protocol/mug#owner'>
<options>
<x xmlns='jabber:x:data' type='form'>
<title>Configuration for "Island Chess" Room</title>
<instructions>
To select a different configuration, please complete
this form.
</instructions>
<field
type='hidden'
var='FORM_TYPE'>
<value>http://jabber.org/protocol/mug#roomconfig</value>
</field>
<field
label='Natural-Language Room Name'
type='text-single'
var='mug#roomconfig_roomname'>
<value>A lovers match</value>
</field>
<field
label='Short Description of the Room'
type='text-single'
var='mug#roomconfig_roomdesc'>
<value>The Chess Match at Act V, Scene IV of Shakespeare's The Tempest</value>
</field>
<field
label='Type of the Room Policy'
type='list-single'
var='mug#roomconfig_roompolicy'>
<value>moderated</value>
<option label='Moderated Room'><value>moderated</value></option>
<option label='Unmoderated Room'><value>unmoderated</value></option>
</field>
<field
label='Allow Occupants to Invite Others?'
type='boolean'
var='mug#roomconfig_allowinvites'>
<value>0</value>
</field>
<field
label='Maximum Number of Occupants'
type='list-single'
var='mug#roomconfig_maxusers'>
<value>5</value>
<option label='2'><value>2</value></option>
<option label='5'><value>5</value></option>
<option label='10'><value>10</value></option>
<option label='20'><value>20</value></option>
<option label='30'><value>30</value></option>
<option label='50'><value>50</value></option>
<option label='None'><value>none</value></option>
</field>
<field
label='Make Room Publicly Searchable?'
type='boolean'
var='mug#roomconfig_publicroom'>
<value>1</value>
</field>
<field
label='Make Room Members-Only?'
type='boolean'
var='mug#roomconfig_membersonly'>
<value>0</value>
</field>
<field
label='Type of the Anonymity'
type='list-single'
var='mug#roomconfig_anonymity'>
<value>semi-anonymous</value>
<option label='Fully-Anonymous Room'><value>fully-anonymous</value></option>
<option label='Semi-Anonymous Room'><value>semi-anonymous</value></option>
<option label='Non-Anonymous Room'><value>non-anonymous</value></option>
</field>
<field
label='Password Required to Enter?'
type='boolean'
var='mug#roomconfig_passwordprotectedroom'>
<value>1</value>
</field>
<field type='fixed'>
<value>
If a password is required to enter this room,
you must specify the password below.
</value>
</field>
<field
label='Password'
type='text-private'
var='mug#roomconfig_roomsecret'>
<value>bravenewworld</value>
</field>
</x>
<options xmlns='http://jabber.org/protocol/mug/chess'>
<x xmlns='jabber:x:data' type='form'>
<title>Configuration for Chess Game</title>
<instructions>
The default configuration is as follows:
- Classic Chess
To accept the default configuration, click OK. To
select a different configuration, please complete
this form.
</instructions>
<field var='FORM_TYPE'>
type='hidden'
<value>http://jabber.org/protocol/mug/chess#chessconfig</value>
</field>
<field
label='Game Variant'
type='list-single'
var='mug/chess#config_variant'>
<value>classic</value>
<option label='The standard classical chess'><value>classic</value></option>
<option label='Four Player Bosworth'><value>bosworth</value></option>
<option label='Four Player Tandem Chess'><value>tandem</value></option>
<option label='Three Handed Chess'><value>threehanded</value></option>
</field>
...
</x>
</options>
</options>
</query>
</iq>
]]></example>
<p>
If there are no configuration options available,
the service MUST return an empty query element to the owner as shown in the previous use case.
</p>
<p>
The owner SHOULD then submit the form with updated configuration information.
</p>
<section3 topic='Notification of Configuration Changes'>
<p>
If as a result of a change in the room configuration the room type is changed to members-only,
any occupants MUST become members and the service MUST reflect the updated presence to all.
</p>
<p>
A room MUST send notification to all occupants when the room configuration changes.
If the game configuration changed, the game MUST also specify an adequate match state.
</p>
<example><![CDATA[
<presence
from='island-chess@games.shakespeare.lit'
to='alonso@shakespeare.lit/pda'>
<game xmlns='http://jabber.org/protocol/mug'>
<configuration-changed/>
<status>inactive</status>
<state xmlns='http://jabber.org/protocol/mug/chess'>
...
</state>
</game>
</presence>
]]></example>
</section3>
</section2>
<section2 topic='Room Saving' anchor='mug-save'>
<p>
The owner may save the room whenever the match status is 'inactive' and
save the room including the match state in a moderated room.
</p>
<example caption='Owner Saves the Room'><![CDATA[
<iq from='miranda@shakespeare.lit/desktop'
id='save'
to='island-chess@games.shakespeare.lit'>
type='result'>
<save xmlns='http://jabber.org/protocol/mug#owner'/>
</iq>
]]></example>
<p>
If saving is allowed, the service MUST inform all occupants and remove them from the room.
</p>
<example caption='Service Broadcasts Presence to all Occupants'><![CDATA[
<presence
from='island-chess@games.shakespeare.lit/damsel'
to='miranda@shakespeare.lit/desktop'
type='unavaiable'>
<saved xmlns='http://jabber.org/protocol/mug'/>
</presence>
<presence
from='island-chess@games.shakespeare.lit/lad'
to='ferdinand@shakespeare.lit/laptop'
type='unavaiable'>
<saved xmlns='http://jabber.org/protocol/mug'/>
</presence>
]]></example>
<example caption='Service Informs Owner of Successful Save Request'><![CDATA[
<iq from='island-chess@games.shakespeare.lit'
id='save'
to='miranda@shakespeare.lit/desktop'
type='result'/>
]]></example>
<p>
After saving the room, nobody can join it until it is loaded by the owner.
</p>
</section2>
<section2 topic='Room Loading' anchor='mug-load'>
<p>
For Discovering of Saved Rooms see <link url="#search-room">search for rooms</link>.
Send an iq stanza to request loading a the room as follows:
</p>
<example caption='Owner Requests Loading an Adjourned Room'><![CDATA[
<iq from='miranda@shakespeare.lit/desktop'
id='load1'
to='island-chess@games.shakespeare.lit'
type='get'>
<load xmlns='http://jabber.org/protocol/mug#owner'/>
</iq>
]]></example>
<p>
After loading, the match status is 'paused' if the match was 'active' before saving.
Alternatively, the match status is set to 'inactive' if the match was inactive.
The service SHOULD send an invitation to all occupants that were present in the game when saved.
</p>
<p>
Players entering the room SHOULD be assigned the role they had when the room was saved.
</p>
</section2>
<section2 topic='Modifying the Member List' anchor='modifymember'>
<p>
In the context of a members-only match, the member list is essentially a
"whitelist" of people who are allowed to enter the match. Anyone who is not
a member is effectively banned from entering the match.
</p>
<p>
In the context of an open match, the member list is simply a list of users
(bare JID and reserved nick) who are registered with the match. Such users
may appear in a match roster, have their match nickname reserved, be
returned in search results, and the like.
</p>
<p>
It is RECOMMENDED that only the room owner
has the privilege to modify the member list in members-only rooms.
To do so, the owner first requests the member list by querying the room
for all users with an affiliation of "member":
</p>
<example caption='Owner Requests Member List'><![CDATA[
<iq from='miranda@shakespeare.lit/desktop'
id='member3'
to='island-chess@games.shakespeare.lit'
type='get'>
<query xmlns='http://jabber.org/protocol/mug#owner'>
<item affiliation='member'/>
</query>
</iq>
]]></example>
<p>
Note: A service SHOULD also return the member list to any occupant in a
members-only room; i.e., it SHOULD NOT generate a &forbidden; error when
a member in the room requests the member list.
This functionality may assist clients in showing all the existing members
even if some of them are not in the room, e.g. to help a member determine
if another user should be invited.
A service SHOULD also allow any member to retrieve the member list even
if not yet an occupant.
</p>
<p>
The service MUST then return the full member list to the owner qualified
by the 'http://jabber.org/protocol/mug#owner' namespace; each item MUST
include the 'affiliation' and 'jid' attributes and MAY include the 'nick' and
'role' attributes for each members that is currently an occupant.
</p>
<example caption='Service Sends Member List to Owner'><![CDATA[
<iq from='island-chess@games.shakespeare.lit'
id='member3'
to='miranda@shakespeare.lit/desktop'
type='result'>
<query xmlns='http://jabber.org/protocol/mug#owner'>
<item affiliation='member'
jid='alonso@shakespeare.lit'
nick='KingOfNaples'/>
</query>
</iq>
]]></example>
<p>
The owner MAY then modify the member list. In order to do so, the owner MUST
send the changed items (i.e., only the "delta") to the service; each item MUST
include the 'affiliation' attribute (normally set to a value of "member" or "none")
and 'jid' attribute but SHOULD NOT include the 'nick' attribute and MUST NOT include
the 'role' attribute (which is used to manage game roles in a room):
</p>
<example caption='Owner Sends Modified Member List to Service'><![CDATA[
<iq from='miranda@shakespeare.lit/desktop'
id='member4'
to='island-chess@games.shakespeare.lit'
type='set'>
<query xmlns='http://jabber.org/protocol/mug#owner'>
<item affiliation='none'
jid='alonso@shakespeare.lit'/>
<item affiliation='member'
jid='prospero@shakespeare.lit'/>
</query>
</iq>
]]></example>
<p>
The service MUST modify the member list and then inform the owner of success:
</p>
<example caption='Service Informs Owner of Success'><![CDATA[
<iq from='island-chess@games.shakespeare.lit'
id='member4'
to='miranda@shakespeare.lit/desktop'
type='result'/>
]]></example>
<p>
The service MUST change the affiliation of any affected user.
If the user has been removed from the member list, the service MUST change the user's
affiliation from "member" to "none".
If the user has been added to the member list, the service MUST change the user's affiliation to "member".
</p>
<p>
If a removed member is currently in a members-only room, the service SHOULD kick
the occupant by changing the removed member's affiliation to "none" and send appropriate
presence to the removed member as previously described.
No matter whether the removed member was in or out of a members-only room, the service MUST
subsequently refuse entry to the user.
</p>
<p>
For all room types, the service MUST send updated presence from this individual to all occupants,
indicating the change in affiliation by including an &lt;game/&gt; element qualified by the
'http://jabber.org/protocol/mug' namespace and containing an &lt;item/&gt; child with the
'affiliation' attribute set to a value of "none".
</p>
<example caption="Service Sends Notice of Loss of Membership to All Occupants"><![CDATA[
<presence
from='island-chess@games.shakespeare.lit/KingOfNaples'
to='miranda@shakespeare.lit/desktop'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='none'/>
</game>
</presence>
...
]]></example>
<p>
In addition, the service SHOULD send an invitation to any user who has been added to the
member list of a members-only room if the user is not currently affiliated with the
room, for example as an owner (such a user would by definition not be
in the match; note also that this example includes a password but not a reason --
both child elements are OPTIONAL):
</p>
<example caption='Room Sends Invitation to New Member'><![CDATA[
<message
from='island-chess@games.shakespeare.lit'
to='prospero@shakespeare.lit'>
<invited xmlns='http://jabber.org/protocol/mug#user'
from='miranda@shakespeare.lit'
var='http://jabber.org/protocol/mug/chess'>
<password>cauldronburn</password>
</invited>
</message>
]]></example>
<p>
While only the owner SHOULD be allowed to modify the member list,
an implementation MAY provide a configuration option that opens invitation privileges
to any member of a members-only match. In such a situation, any invitation sent SHOULD
automatically trigger the addition of the invitee to the member list.
However, if invitation privileges are restricted to the owner and a mere member attempts
to a send an invitation, the service MUST deny the invitation request and return a
&forbidden; error to the sender:
</p>
<example caption='Service Returns Error on Attempt by Mere Member to Invite Others to a Members-Only Match'><![CDATA[
<message
from='island-chess@games.shakespeare.lit'
to='alonso@shakespeare.lit/pda'
type='error'>
<invite xmlns='http://jabber.org/protocol/mug#user'
to='prospero@shakespeare.lit'>
<reason>
Hey Prospero, join the game!
</reason>
</invite>
<error type='auth'>
<forbidden xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
</error>
</message>
]]></example>
<p>
Invitations sent through an open room MUST NOT trigger the addition of the invitee
to the member list.
</p>
<p>
If a user is added to the member list of an open room and the user is in the room,
the service MUST send updated presence from this individual to all occupants,
indicating the change in affiliation by including an &lt;game/&gt; element qualified by
the 'http://jabber.org/protocol/mug' namespace and containing an &lt;item/&gt;
child with the 'affiliation' attribute set to a value of "member".
</p>
<example caption="Service Sends Notice of Membership to All Occupants"><![CDATA[
<presence
from='island-chess@games.shakespeare.lit/prospero'
to='miranda@shakespeare.lit/desktop'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='member'/>
</game>
</presence>
...
]]></example>
</section2>
<section2 topic='Revoke and Assign Roles' anchor='modifyroles'>
<p>
The room owner may decide to modify the assigned game roles in a room.
To do so, the owner first requests a list of the occupants
and assigned roles by querying the room:
</p>
<example caption='Owner Requests List of All Occupants and Assigned Roles'><![CDATA[
<iq from='miranda@shakespeare.lit/desktop'
id='roles1'
to='island-chess@games.shakespeare.lit'
type='get'>
<query xmlns='http://jabber.org/protocol/mug#owner'>
<item role='all'/>
</query>
</iq>
]]></example>
<p>
Note: The role 'all' is a reserved name for querying the list of
active players and MUST NOT be redefined by games for other purposes.
</p>
<p>
The service SHOULD then return the full list of all occupants qualified by
the 'http://jabber.org/protocol/mug#owner' namespace; each item MUST include the
'role' and 'nick' attributes and MAY include the 'jid' and 'affiliation' attributes for each
occupant in the room.
</p>
<example caption='Service Sends List of Occupants and Assigned Roles to Owner'><![CDATA[
<iq from='island-chess@games.shakespeare.lit'
id='roles1'
to='miranda@shakespeare.lit/desktop'
type='result'>
<query xmlns='http://jabber.org/protocol/mug#owner'>
<item role='White'
nick='damsel'/>
<item role='Black'
nick='lad'/>
<item role='none'
nick='KingOfNaples'/>
</query>
</iq>
]]></example>
<p>
The service MUST send a &forbidden; error if the owner has not the
required <link url="#privileges">Privileges</link>.
</p>
<p>
The owner MAY then modify the roles assigned by occupants.
In order to do so, the owner MUST send the changed items (i.e., only the "delta") to the service;
each item MUST include the 'roles' attribute
and 'nick' attribute but SHOULD NOT include the 'jid' attribute and MUST NOT include
the 'affiliation' attribute:
</p>
<example caption='Owner Sends Modified List of Assigned Roles to Service'><![CDATA[
<iq from='miranda@shakespeare.lit/desktop'
id='roles2'
to='island-chess@games.shakespeare.lit'
type='set'>
<query xmlns='http://jabber.org/protocol/mug#owner'>
<item role='none'
nick='lad'/>
<item role='Black'
nick='KingOfNaples'/>
</query>
</iq>
]]></example>
<p>
The service MUST modify the roles of the occupants and then inform the owner of success:
</p>
<example caption='Service Informs Owner of Success'><![CDATA[
<iq from='island-chess@games.shakespeare.lit'
id='roles2'
to='miranda@shakespeare.lit/desktop'
type='result'/>
]]></example>
<p>
The service MUST change the roles of any affected user and
MUST send updated presence to all occupants,
indicating the changed role by including an &lt;game/&gt; element qualified by the
'http://jabber.org/protocol/mug' namespace and containing an &lt;item/&gt; child with the
'role' attribute.
</p>
<example caption="Service Sends Notice of Changed Roles to All Occupants"><![CDATA[
<presence
from='island-chess@games.shakespeare.lit/KingOfNaples'
to='miranda@shakespeare.lit/desktop'>
<game xmlns='http://jabber.org/protocol/mug'>
<item role='Black'/>
</game>
</presence>
...
]]></example>
</section2>
<section2 topic='Transfer Ownership' anchor='transferowner'>
<p>
The room owner may decide to transfer the ownership to another occupant.
</p>
<example caption="Owner Transfers the Ownership to Another Occupants"><![CDATA[
<iq from='miranda@shakespeare.lit/desktop'
id='owner1'
to='island-chess@games.shakespeare.lit'
type='set'>
<query xmlns='http://jabber.org/protocol/mug#owner'>
<item affiliation='owner'
jid='ferdinand@shakespeare.lit'/>
</query>
</iq>
]]></example>
<example caption='Service Informs Owner of Success'><![CDATA[
<iq from='island-chess@games.shakespeare.lit'
id='owner1'
to='miranda@shakespeare.lit/desktop'
type='result'/>
]]></example>
<example caption="Service Informs Occupants About the Affiliation Changes"><![CDATA[
<presence
from='island-chess@games.shakespeare.lit/lad'
to='miranda@shakespeare.lit/desktop'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='owner'/>
</game>
</presence>
<presence
from='island-chess@games.shakespeare.lit/damsel'
to='miranda@shakespeare.lit/desktop'>
<game xmlns='http://jabber.org/protocol/mug'>
<item affiliation='none'/>
</game>
</presence>
...
]]></example>
</section2>
</section1>
<section1 topic='Business Rules' anchor='rules'>
<p>OPTIONAL.</p>
</section1>
<section1 topic='Implementation Notes' anchor='impl'>
<p>The following guidelines may assist client and component developers in creating MUG implementations.</p>
<section2 topic='Services' anchor='impl-services'>
<ol start='1'>
<li>
<p>
In order to allow supporting multiple games on the service the component
may offer a game plugin interface.
</p>
</li>
<li>
<p>
To manage team games, the service should offer game plugins an
API and leave game turn message routing to the game plugins.
</p>
</li>
<li>
<p>
In case of loading a room the service SHOULD remember each player's role,
so it can assign the roles properly when the room is loaded.
</p>
</li>
<li>
<p>
The game service MAY offer a managed multi-user chatroom.
This can be done by creating a new chat room and keep membership
synchronized with the game room.
</p>
</li>
</ol>
</section2>
<section2 topic='Clients' anchor='impl-clients'>
<ol start='1'>
<li>
<p>
In order to respect the users privacy the jabber client SHOULD
hide active matches for discovering as default behavior.
However jabber clients MAY offer a setting to enable the active match discovery.
</p>
</li>
<li>
<p>
MUG clients MAY highlight users that participate in a room chat somehow.
The highlighting could be done with a small speech balloon icon behind the players name.
</p>
</li>
</ol>
</section2>
</section1>
<section1 topic='Internationalization Considerations' anchor='i18n'>
<p>OPTIONAL.</p>
</section1>
<section1 topic='Security Considerations' anchor='security'>
<p>REQUIRED.</p>
</section1>
<section1 topic='IANA Considerations' anchor='iana'>
<p>REQUIRED.</p>
</section1>
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
<p>
If this protocol will be accepted by the XMPP Standards Foundation, the &REGISTRAR;
should includes the following information in its registries.
</p>
<!-- <p>
TODO: Complete this paragraph with disco nodes, fields used within Data Forms, etc.
</p>
--> <section2 topic='Protocol Namespaces' anchor='registrar-protocol'>
<p>
The XMPP Registrar includes the following MUG-related namespaces in its registry of protocol namespaces:
</p>
<ul>
<li>http://jabber.org/protocol/mug</li>
<li>http://jabber.org/protocol/mug#user</li>
<li>http://jabber.org/protocol/mug#owner</li>
</ul>
</section2>
<section2 topic='Service Discovery Category/Type' anchor='registrar-discocat'>
<p>
A Multi-User Game service or match is identified by the "game" category
and the "multi-user" type within Service Discovery.
</p>
</section2>
<section2 topic='Service Discovery Features' anchor='registrar-features'>
<p>
There are many features related to a MUG service or match that can be
discovered by means of Service Discovery. The most fundamental of these
is the 'http://jabber.org/protocol/mug' namespace. In addition, a MUG match
SHOULD provide information about the specific match features it implements,
such as password protection and match moderation.
</p>
<!-- <p>
TODO: list the required disco features
</p>
--> </section2>
<section2 topic='URI Query Types' anchor='registrar-querytypes'>
<section3 topic='play' anchor='registrar-querytypes-play'>
<p>
The "play" querytype is registered as a MUG-related action, with keys of "game" and "password".
</p>
<example caption="Play Action: IRI/URI"><![CDATA[
xmpp:island-chess@games.shakespeare.lit?play
]]></example>
<p>
The application MUST either present an interface enabling the user to provide a room nickname
or populate the room nickname based on configured preferences or nickname discovery.
</p>
<p>
If the application doesn't know the game namespace of the room it MUST
<link url='#disco-matchinfo'>query for room information</link> to receive the game namespace.
</p>
<example caption="Play Action: Resulting Stanza"><![CDATA[
<presence to='island-chess@games.shakespeare.lit/KingOfNaples'>
<game
xmlns='http://jabber.org/protocol/mug'
var='http://jabber.org/protocol/mug/chess'/>
</presence>
]]></example>
<p>
In order to avoid sending the service discovery query,
the play action SHOULD include the game namespace for the room.
</p>
<example caption="Play Action with Game: IRI/URI"><![CDATA[
xmpp:island-chess@games.shakespeare.lit?play;game=http://jabber.org/protocol/mug/chess
]]></example>
<p>
The play action MAY include a password for the room.
Naturally, access to a URI that includes a room password MUST be appropriately controlled.
</p>
<example caption="Play Action: IRI/URI"><![CDATA[
xmpp:island-chess@games.shakespeare.lit?play;password=brave%20new%20world
]]></example>
<example caption="Play Action with Password: Resulting Stanza"><![CDATA[
<presence to='island-chess@games.shakespeare.lit/KingOfNaples'>
<game
xmlns='http://jabber.org/protocol/mug'
var='http://jabber.org/protocol/mug/chess'>
<password>brave new world</password>
</game>
</presence>
]]></example>
<p>
The following submission registers the "play" querytype.
</p>
<code><![CDATA[
<querytype>
<name>play</name>
<proto>http://jabber.org/protocol/mug</proto>
<desc>enables joining a multi-user game room</desc>
<doc>XEP-XXXX</doc>
<keys>
<key>
<name>game</name>
<desc>the game namespace required to enter a multi-user game room</desc>
</key>
<key>
<name>password</name>
<desc>the password required to enter a multi-user game room</desc>
</key>
</keys>
</querytype>
]]></code>
</section3>
</section2>
</section1>
<section1 topic='XML Schemas' anchor='schema'>
<section2 topic='http://jabber.org/protocol/mug' anchor='schemas-mug'>
<code><![CDATA[
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema
xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace='http://jabber.org/protocol/mug'
xmlns='http://jabber.org/protocol/mug'
elementFormDefault='qualified'>
<xs:element name='game'>
<xs:complexType>
<xs:sequence>
<xs:element ref='configuration-changed' minOccurs='0'/>
<xs:element ref='status' minOccurs='0'/>
<xs:any processContents='skip' minOccurs='0'/>
<xs:element ref='item' minOccurs='0'/>
<xs:element name='password' type='xs:string' minOccurs='0'/>
</xs:sequence>
<xs:attribute name='var' type='xs:string' use='optional'/>
</xs:complexType>
</xs:element>
<xs:element name='configuration-changed'>
<xs:complexType/>
</xs:element>
<xs:element name='status'>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="created"/>
<xs:enumeration value="active"/>
<xs:enumeration value="inactive"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name='item'>
<xs:complexType>
<xs:attribute name='affiliation' use='optional'>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="owner"/>
<xs:enumeration value="member"/>
<xs:enumeration value="none"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name='jid' type='xs:string' use='optional'/>
<xs:attribute name='role' type='xs:string' use='optional'/>
<xs:attribute name='nick' type='xs:string' use='optional'/>
</xs:complexType>
</xs:element>
<xs:element name='pause'>
<xs:complexType/>
</xs:element>
<xs:element name='saved'>
<xs:complexType/>
</xs:element>
</xs:schema>
]]></code>
</section2>
<section2 topic='http://jabber.org/protocol/mug#user' anchor='schemas-muguser'>
<code><![CDATA[
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema
xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace='http://jabber.org/protocol/mug#user'
xmlns='http://jabber.org/protocol/mug#user'
elementFormDefault='qualified'>
<xs:element name='game'>
<xs:complexType>
<xs:sequence>
<xs:choice>
<xs:element ref='invite' maxOccurs='unbounded'/>
<xs:element ref='invited'/>
<xs:element ref='decline'/>
<xs:element ref='declined'/>
</xs:choice>
<xs:element name='password' type='xs:string' minOccurs='0'/>
</xs:sequence>
<xs:attribute name='var' type='xs:string' use='optional'/>
</xs:complexType>
</xs:element>
<xs:element name='invite'>
<xs:complexType>
<xs:sequence>
<xs:element ref='reason' minOccurs='0'/>
</xs:sequence>
<xs:attribute name='to' type='xs:string' use='required'/>
</xs:complexType>
</xs:element>
<xs:element name='invited'>
<xs:complexType>
<xs:sequence>
<xs:element ref='reason' minOccurs='0'/>
</xs:sequence>
<xs:attribute name='from' type='xs:string' use='required'/>
<xs:attribute name='var' type='xs:string' use='required'/>
</xs:complexType>
</xs:element>
<xs:element name='decline'>
<xs:complexType>
<xs:sequence>
<xs:element ref='reason' minOccurs='0'/>
</xs:sequence>
<xs:attribute name='to' type='xs:string' use='required'/>
</xs:complexType>
</xs:element>
<xs:element name='declined'>
<xs:complexType>
<xs:sequence>
<xs:element ref='reason' minOccurs='0'/>
</xs:sequence>
<xs:attribute name='from' type='xs:string' use='required'/>
</xs:complexType>
</xs:element>
<xs:element name='reason' type='xs:string'/>
<xs:element name='turn'>
<xs:complexType>
<xs:sequence>
<xs:any processContents='skip'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='invalid-turn'>
<xs:complexType/>
</xs:element>
<xs:element name='start'>
<xs:complexType/>
</xs:element>
</xs:schema>
]]></code>
</section2>
<section2 topic='http://jabber.org/protocol/mug#owner' anchor='schemas-mugowner'>
<code><![CDATA[
<?xml version='1.0' encoding='UTF-8'?>
<xs:schema
xmlns:xs='http://www.w3.org/2001/XMLSchema'
targetNamespace='http://jabber.org/protocol/mug#owner'
xmlns='http://jabber.org/protocol/mug#owner'
elementFormDefault='qualified'>
<xs:element name='query'>
<xs:complexType>
<xs:sequence>
<xs:element ref='options' minOccurs='0'/>
<xs:any processContents='skip' minOccurs='0'/>
<xs:element ref='item' minOccurs='0' maxOccurs='unbounded'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='options'>
<xs:complexType>
<xs:sequence>
<xs:any processContents='skip' minOccurs='0' maxOccurs='2'/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name='item'>
<xs:complexType>
<xs:attribute name='affiliation' use='optional'>
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="owner"/>
<xs:enumeration value="member"/>
<xs:enumeration value="none"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name='role' type='xs:string' use='optional'/>
<xs:attribute name='nick' type='xs:string' use='optional'/>
<xs:attribute name='jid' type='xs:string' use='optional'/>
</xs:complexType>
</xs:element>
<xs:element name='save'>
<xs:complexType/>
</xs:element>
<xs:element name='load'>
<xs:complexType/>
</xs:element>
</xs:schema>
]]></code>
</section2>
</section1>
</xep>