mirror of
https://github.com/moparisthebest/xeps
synced 2024-11-25 02:32:18 -05:00
3030 lines
102 KiB
XML
Executable File
3030 lines
102 KiB
XML
Executable File
<?xml version='1.0' encoding='UTF-8'?>
|
|
<!DOCTYPE xep SYSTEM 'xep.dtd' [
|
|
<!ENTITY % ents SYSTEM 'xep.ent'>
|
|
<!ENTITY INVITE "<invite/>">
|
|
<!ENTITY JOIN "<join/>">
|
|
<!ENTITY ERROR "<error/>">
|
|
<!ENTITY TEXT "<text/>">
|
|
<!ENTITY GAME "<game/>">
|
|
<!ENTITY TURN "<turn/>">
|
|
<!ENTITY SAVE "<save/>">
|
|
<!ENTITY SAVED "<saved/>">
|
|
<!ENTITY ITEM "<item/>">
|
|
<!ENTITY X "<x/>">
|
|
<!ENTITY FEATURE "<item/>">
|
|
<!ENTITY NAME "<name/>">
|
|
<!ENTITY ROOM "<room@service>">
|
|
<!ENTITY ROOMJID "<room@service/nick>">
|
|
<!ENTITY USERJID "<user@domain>">
|
|
%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>
|
|
<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(ät)fsfe.org</email>
|
|
<jid>Torsten.Grote(ät)jabber.fsfe.org</jid>
|
|
</author>
|
|
<author>
|
|
<firstname>Arne</firstname>
|
|
<surname>König</surname>
|
|
<email>arne.ko(ät)23inch.de</email>
|
|
<jid>arne++(ät)jabber.ccc.de</jid>
|
|
</author>
|
|
<author>
|
|
<firstname>Günther</firstname>
|
|
<surname>Nieß</surname>
|
|
<email>guenther.niess(ät)web.de</email>
|
|
<jid>niess(ä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>
|
|
&LEGALNOTICE;
|
|
</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'>
|
|
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:
|
|
<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'>
|
|
The following affiliations are defined:
|
|
<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'>
|
|
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.
|
|
<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'>
|
|
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.
|
|
</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 <set/> 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 <set/> 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 <item/> 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 (<user@host/resource>)
|
|
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'>
|
|
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"):
|
|
<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 ¬found; 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 ¬authorized; 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 <game/> element qualified by the
|
|
'http://jabber.org/protocol/mug' namespace and containing a <password/> 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
|
|
®istration; 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 ¬found; 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 ¬found; 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 ¬acceptable; 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 <start/> 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 <not-acceptable/> 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 <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 "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 <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 "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 <game/> element qualified by the
|
|
'http://jabber.org/protocol/mug' namespace and containing an <item/> 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 ®ISTRAR;
|
|
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>
|