Difference between revisions of "MultiplayerServerWML"

From The Battle for Wesnoth Wiki
m (Updating the lobby state)
(The login procedure: Add [options] subtag originally from https://github.com/wesnoth/wesnoth/commit/bcaa7f4f2c7b0e4f15eb231d75db010c5d5f6577)
 
(97 intermediate revisions by 17 users not shown)
Line 1: Line 1:
= Multiplayer Server WML =
+
This page describes the [[WML]] used to communicate with the multiplayer server for Wesnoth, [[wesnothd]].
This page describes the WML used to communicate with the multiplayer server (wesnothd).
+
 
 +
== The handshake ==
 +
 
 +
The client sends four bytes, then the server replies with four bytes. To get a new connection number, the client will send these four bytes: 0x00 0x00 0x00 0x00. The server then sends back the connection number (wesnothd calls this number the "socket number"). Since 1.13+ the server no longer is using socket numbers to keep track of clients and always sends the same number to them all. Since 1.15+ client can also send 0x00 0x00 0x00 0x01 instead to request entire connection to be [https://github.com/wesnoth/wesnoth/blob/2f8136951cd77526188cf8d0fb2cf21eaa2ebe63/src/server/common/server_base.hpp#L60-L76 encapsulated in TLS] immediately '''after'''. If the handshake is successful, the server will be the first to send a data package. All packages are in [http://en.wikipedia.org/wiki/Gzip gzip] format and are preceded by four bytes that specify the size of the package to come in '''big-endian''' (network byte order). Below you'll find information about what data the (unzipped) packages contain. Unpacked WML uses utf-8 charset.
  
 
== The login procedure ==
 
== The login procedure ==
Line 9: Line 12:
 
* client response
 
* client response
 
** '''[version]'''
 
** '''[version]'''
*** ''version'' The client's version string.
+
*** '''version''': The client's version string.
 +
*** '''client_source''': The client's distribution info. (Steam, SourceForge, App Store, etc.)
 +
 
 +
* server response (if the server does not accept this version)
 +
** '''[redirect]'''
 +
*** '''host''': The host you should connect to.
 +
*** '''port''': The port you should connect to.
 +
*** '''version''': A comma-separated list of globs that this server should accept (e.g. "1.0*,1.2*,1.4*,1.7*,1.8*")
 +
** or '''[reject]''' (if the version is unknown)
 +
*** '''accepted_versions''': A comma-separated list of globs that this server does accept
  
 
* server request
 
* server request
Line 16: Line 28:
 
* client response
 
* client response
 
** '''[login]'''
 
** '''[login]'''
*** ''username'' The username the client would like to have.
+
*** '''username''': The username the client would like to have.
 +
*** '''password''': The hashed password, created from the password and salt received from the server. More information about how this password is being generated, including a real world example, can be found in the file [http://forum.wesnoth.org/download/file.php?id=41145 HashedPasswords.pdf] (885 KiB). Since version 1.15+ if TLS was successfully established before then password will be passed as is, without hashing, relying on TLS for secrecy. Passing password hashes is no longer supported to free the client from responsibility to support all hash schemes the forum can potentially use. Client will emit error instead of trying to send password if TLS wasn't established.
  
 
* server response
 
* server response
 
** '''[join_lobby]'''
 
** '''[join_lobby]'''
 +
*** '''is_moderator''': "yes" if the user is a moderator, "no" otherwise.
 +
*** '''profile_url_prefix''': The external URL prefix for player profiles (empty if the server doesn't have an attached database)
 +
** or '''[error]'''
 +
*** '''message''': The error message.
 +
*** '''password_request''': If not empty the server asks the client to provide a password for its desired username.
 +
*** '''phpbb_encryption''': If "yes" the client will encrypt the password using phpbb's algorithm.
 +
*** '''random_salt''': Random salt sent to the client for mixing with the password hash.
 +
*** '''hash_seed''': Salt generated from the original hash that is required to recreate it.
 +
*** '''salt''': Salt generated from the original hash that is required to recreate it.
 +
*** '''force_confirmation''': Display an ok/cancel dialog with the content of the 'message' key.
  
 
* server response
 
* server response
 
** '''[gamelist]'''
 
** '''[gamelist]'''
*** '''[game]'''
+
*** '''[game]''' (repeated)
**** ''mp_use_map_settings'' Does the game use the map settings specified in the scenario.
+
**** '''id''': A unique id of the game.
**** ''mp_fog'' Does the game use fog.
+
**** '''name''': The title of the game.
**** ''mp_shroud'' Does the game use shroud.
+
**** '''mp_scenario''': The id of the scenario.
**** ''mp_countdown'' Does the game use a timer.
+
**** '''mp_era''': The id of the used era.
**** ''observer'' Are observers allowed or not.
+
**** '''mp_use_map_settings''': Does the game use the map settings specified in the scenario.
**** ''map_data'' The map data.
+
**** '''mp_fog''': Does the game use fog.
**** ''experience_modifier'' The experience setting.
+
**** '''mp_shroud''': Does the game use shroud.
**** ''turn'' The current turn/max turn.
+
**** '''mp_village_gold''': The number of gold per village.
**** ''id'' The id of the game.
+
**** '''experience_modifier''': The experience setting.
**** ''mp_countdown_reservoir_time''
+
**** '''mp_countdown''': Does the game use a timer.
**** ''mp_village_gold'' The number of gold per village.
+
**** '''mp_countdown_reservoir_time''': Upper limit of the possibly available time.
**** ''mp_countdown_init_time''
+
**** '''mp_countdown_init_time''': Initial time.
**** ''mp_era'' The id of the used era.
+
**** '''mp_countdown_action_bonus''': Time bonus per action.
**** ''mp_countdown_action_bonus''
+
**** '''mp_countdown_turn_bonus''': Time bonus per turn.
**** ''mp_countdown_turn_bonus''  
+
**** '''map_data''': The map data. ''Notice: not sent to lobby if the game uses shroud''
**** ''name'' The title of the game.
+
**** '''hash''': The hash value of the map_data.
**** ''human_sides'' The number of sides played by humans.
+
**** '''observer''': Are observers allowed or not.
**** ''hash'' The hash value of the map_data.
+
**** '''human_sides''': The number of sides played by humans.
**** ''mp_scenario'' The id of the scenario.
+
**** '''slots''': The number of vacant/max slots.
**** ''slots'' The number of vacant/max slots.
+
**** '''[slot_data]''' replaces '''slots''' since {{DevFeature1.13|12}}
** '''[user]'''
+
***** '''max''': The number of total slots.
*** ''name'' The username of the player.
+
***** '''vacant''': The number of vacant slots.
*** ''location'' The name of the game the player is in.
+
**** '''turn''': The current turn/max turn.
*** ''available'' "yes" if the player is in the lobby; "no" if in a game.
+
**** '''[turn_data]''' replaces '''turn''' since {{DevFeature1.13|12}}
Many of these keys are described more indepth on the [[ScenarioWML]] page.
+
***** '''current''': The current turn number.
 +
***** '''max''': The total number of turns.
 +
**** '''[modification]''' Modifications used in this game. See [[ModificationWML]].
 +
***** '''id''': ID of the modification.
 +
***** '''name''': Name of the modification.
 +
***** '''addon_id''': ID of the addon the modification is from.
 +
***** '''require_modification''': A boolean value; if set to yes, all players have to have this modification installed to join the game.
 +
**** '''[options]''' Options selected for this game. See [[OptionWML]].
 +
***** '''[campaign|era|modification|multiplayer]'''
 +
****** '''id''': ID of the addon the campaign|era|modification|multiplayer (scenario) is from.
 +
****** '''[option]'''
 +
******* '''id''': ID of the option.
 +
******* '''value''': Value of the option.
 +
** '''[user]''' (repeated)
 +
*** '''name''': The username of the player.
 +
*** '''game_id''': The ID of the game the player is in.
 +
*** '''location''': The name of the game the player is in.
 +
*** '''available''': "yes" if the player is in the lobby; "no" if in a game.
 +
Many of the keys under [game] are described more indepth on the [[ScenarioWML]] page.
 +
 
 +
== Error messages ==
 +
 
 +
* '''[error]'''
 +
** '''message''': The error message.
 +
 
 +
== Chat (lobby and in-game) ==
 +
 
 +
* '''[message]'''
 +
** '''sender''': (optional - filled by the server) The sender of the message.
 +
** '''message''': The message itself.
 +
** '''room''': The room the message is from/to
 +
* '''[whisper]'''
 +
** '''receiver''': The receiver of the whisper
 +
** '''sender''': (optional - filled by the server) The sender of the whisper.
 +
** '''message''': The message itself.
 +
 
 +
== Nickname registration related commands (lobby and in-game) ==
 +
 
 +
* '''[nickserv]'''
 +
** '''[info]''': Request info about another username.
 +
*** '''name''': The username.
  
 
== Updating the lobby state ==
 
== Updating the lobby state ==
  
* server message - basically a diff from two [gamelist]s
+
* '''[gamelist_diff]''': server message - basically a [[DiffWML|diff]] from two gamelists, which also includes the user list.
** '''[gamelist_diff]'''
 
*** '''[insert_child]''' or '''[delete_child]'''
 
**** ''index'' Index of the child (game or user).
 
**** '''[gamelist]''' or '''[user]''' (repeated) Same tags/keys as above in [gamelist] and [user] possible
 
*** '''[change_child]''' Same tags as above in [gamelist] possible
 
**** ''index'' Index of the child (game or user).
 
***** '''[insert]''' or '''[delete]''' Same keys as above in [game] possible
 
**** '''[gamelist]''' or '''[user]''' (repeated)
 
***** '''[change_child]''' Same tags as above in [gamelist] possible
 
****** '''[insert]''' or '''[delete]''' Same keys as above in [game] possible
 
***** '''[insert_child]''' Same tags as above in [gamelist] possible
 
  
* server message - players joining([observer_quit])/quitting([observer] a game
+
* '''[observer]''' or '''[observer_quit]''': server message - players joining([observer_quit] - quitting the lobby "game")/quitting([observer] - joining the lobby "game") a game
** '''[observer]''' or '''[observer_quit]'''
+
** '''name''': Username of the player/observer.
*** ''name'' Username of the player/observer.
+
* '''[refresh_lobby]''': Request the full gamelist.
  
== Game creation ==
+
== Game setup (the phase from creation to start) ==
 
To create a game the client sends:
 
To create a game the client sends:
 
* '''[create_game]'''
 
* '''[create_game]'''
** ''name'' The title of the game.
+
** '''name''': The title of the game.
** ''human_sides'' The number of sides played by humans.
+
** '''password''': The password to use to join the game.
 +
** '''ignored''': The list of ignored players from the host.
 +
** '''auto_hosted''': True if this request is from a bot, false otherwise.
  
 
followed by a message with the scenario options as under [game] (see above) plus the scenario data ([time], [era], [side], etc. see [[ScenarioWML]])
 
followed by a message with the scenario options as under [game] (see above) plus the scenario data ([time], [era], [side], etc. see [[ScenarioWML]])
  
 
* '''[join]'''
 
* '''[join]'''
** ''id'' The id of the game.
+
** '''id''': The id of the game.
** ''observe'' Join the game as an observer.
+
** '''observe''': Join the game as an observer.
 +
 
 +
* '''[scenario_diff]''': [[DiffWML|diff]] of the [[ScenarioWML]] (side changes, etc.)
 +
 
 +
* '''[start_game]''': sent by the host to start a game
 +
* '''[leave_game]''': sent by the client when it leaves a game; sent by the server to make a client leave a game
 +
** '''reason''': optional reason if sent by the server and was initiated by moderator action
 +
 
 +
== In-game communication ==
 +
 
 +
* '''[store_next_scenario]''': sent by the host - the scenario data (see [[ScenarioWML]]) to advance to the next scenario
 +
* '''[notify_next_scenario]''': sent by the server to tell players that the data for the next scenario is available
 +
* '''[load_next_scenario]''': sent by the client to request the data for the next scenario
 +
* '''[next_scenario]''': data for the next scenario (see [[ScenarioWML]]), sent by the server on request
 +
 
 +
* '''[info]''': sent by the host on game end - info about the game state
 +
** '''type''': "termination"
 +
** '''condition''': the termination reason
  
* '''[leave_game]'''
+
* '''[change_controller]''': a player (un)droids one of his sides or assigns control to someone else (The host can assign control for any side.)
 +
** '''side''': the side to change controller
 +
** '''player''': the nickname of the player to take control
 +
** '''controller''': the new controller: "human" or "human_ai"
 +
** '''own_side''': "yes"
  
== Error messages ==
+
If a player leaves this is sent to the host for all sides he owned.
 +
* '''side_drop''': The number of a side that dropped because a player left.
 +
* '''controller''': The controller of that side. ("ai", "network")
 +
 
 +
* '''[muteall]''': the host mutes/unmutes all observers - toggles
 +
* '''[mute]''': the host mutes an observer - toggles
 +
** '''username''': the username of the observer - if not specified the servers returns a list of muted usernames
 +
* '''[kick]''' or '''[ban]''': the host kicks/bans a player/observer
 +
** '''username''': the username of the player/observer
  
* '''[error]'''
+
* '''[turn]'''
** ''message'' The error message.
+
** '''[command]''': (repeated) can contain all the tags you can find in a [[ReplayWML|replay]]: [recruit], [move], [end_turn], etc.
 +
*** '''[speak]'''
 +
**** '''message''': text of the message
 +
**** '''id''': the sender
 +
**** '''team_name''': the name of the team the message is for - empty if it's a public message
  
== Lobby chat ==
+
== Game history ==
* server message
+
This is a request to query a set of 11 rows of game history data based on the provided search criteria. The official client calls this from the Match History button in the  multiplayer lobby to display 10 rows of data. The 11th row is used as a flag to indicate whether there is more data to be queried or not via the right/left arrows on the dialog.
** '''[message]'''
 
*** ''sender'' The sender of the message.
 
*** ''message'' The message itself.
 
** '''[whisper]'''
 
*** ''receiver'' The receiver of the whisper
 
*** ''sender'' The sender of the whisper.
 
*** ''message'' The message itself.
 
  
* client message
+
* '''[game_history_request]'''
** '''[message]'''
+
** '''offset''': where in the result set to start returning data from. If there are 50 results and offset 10 is given, then rows 10-21 will be returned.
*** ''sender'' (optional) The sender of the message.
+
** '''search_player''': the forum username of the player to search for.
*** ''message'' The message itself.
+
** '''search_game_name''': the name of the game to filter results by. Can use the * (matches any character before or after it's used) and _ (matches any single character) wildcards.
** '''[whisper]'''
+
** '''search_content_type''': the type of content to filter by. Must be one of:
*** ''receiver'' The receiver of the whisper
+
*** '''0''': scenario
*** ''sender'' (optional) The sender of the whisper.
+
*** '''1''': era
*** ''message'' The message itself.
+
*** '''2''':modification
 +
** '''search_content''': The content to filter by. This is the ID of the content, not the name displayed on the UI, due to the translated name getting stored in the database.
  
 
== Administrative commands ==
 
== Administrative commands ==
 
* '''[query]'''
 
* '''[query]'''
** ''type'' The type of query. See [[ServerAdministration]] for details.
+
** '''type''': The type of query. See [[ServerAdministration]] for details.
 +
 
 +
== See also ==
 +
[https://github.com/renom/fastbot fastbot] -  the bot for tournaments which implements the protocol, can log in into the lobby and host games. Written in Go.
 +
[[Category:WML Reference]]
 +
[[Category:Server Documentation]]

Latest revision as of 16:53, 3 July 2024

This page describes the WML used to communicate with the multiplayer server for Wesnoth, wesnothd.

The handshake

The client sends four bytes, then the server replies with four bytes. To get a new connection number, the client will send these four bytes: 0x00 0x00 0x00 0x00. The server then sends back the connection number (wesnothd calls this number the "socket number"). Since 1.13+ the server no longer is using socket numbers to keep track of clients and always sends the same number to them all. Since 1.15+ client can also send 0x00 0x00 0x00 0x01 instead to request entire connection to be encapsulated in TLS immediately after. If the handshake is successful, the server will be the first to send a data package. All packages are in gzip format and are preceded by four bytes that specify the size of the package to come in big-endian (network byte order). Below you'll find information about what data the (unzipped) packages contain. Unpacked WML uses utf-8 charset.

The login procedure

  • server request (optional)
    • [version]
  • client response
    • [version]
      • version: The client's version string.
      • client_source: The client's distribution info. (Steam, SourceForge, App Store, etc.)
  • server response (if the server does not accept this version)
    • [redirect]
      • host: The host you should connect to.
      • port: The port you should connect to.
      • version: A comma-separated list of globs that this server should accept (e.g. "1.0*,1.2*,1.4*,1.7*,1.8*")
    • or [reject] (if the version is unknown)
      • accepted_versions: A comma-separated list of globs that this server does accept
  • server request
    • [mustlogin]
  • client response
    • [login]
      • username: The username the client would like to have.
      • password: The hashed password, created from the password and salt received from the server. More information about how this password is being generated, including a real world example, can be found in the file HashedPasswords.pdf (885 KiB). Since version 1.15+ if TLS was successfully established before then password will be passed as is, without hashing, relying on TLS for secrecy. Passing password hashes is no longer supported to free the client from responsibility to support all hash schemes the forum can potentially use. Client will emit error instead of trying to send password if TLS wasn't established.
  • server response
    • [join_lobby]
      • is_moderator: "yes" if the user is a moderator, "no" otherwise.
      • profile_url_prefix: The external URL prefix for player profiles (empty if the server doesn't have an attached database)
    • or [error]
      • message: The error message.
      • password_request: If not empty the server asks the client to provide a password for its desired username.
      • phpbb_encryption: If "yes" the client will encrypt the password using phpbb's algorithm.
      • random_salt: Random salt sent to the client for mixing with the password hash.
      • hash_seed: Salt generated from the original hash that is required to recreate it.
      • salt: Salt generated from the original hash that is required to recreate it.
      • force_confirmation: Display an ok/cancel dialog with the content of the 'message' key.
  • server response
    • [gamelist]
      • [game] (repeated)
        • id: A unique id of the game.
        • name: The title of the game.
        • mp_scenario: The id of the scenario.
        • mp_era: The id of the used era.
        • mp_use_map_settings: Does the game use the map settings specified in the scenario.
        • mp_fog: Does the game use fog.
        • mp_shroud: Does the game use shroud.
        • mp_village_gold: The number of gold per village.
        • experience_modifier: The experience setting.
        • mp_countdown: Does the game use a timer.
        • mp_countdown_reservoir_time: Upper limit of the possibly available time.
        • mp_countdown_init_time: Initial time.
        • mp_countdown_action_bonus: Time bonus per action.
        • mp_countdown_turn_bonus: Time bonus per turn.
        • map_data: The map data. Notice: not sent to lobby if the game uses shroud
        • hash: The hash value of the map_data.
        • observer: Are observers allowed or not.
        • human_sides: The number of sides played by humans.
        • slots: The number of vacant/max slots.
        • [slot_data] replaces slots since (Version 1.13.12 and later only)
          • max: The number of total slots.
          • vacant: The number of vacant slots.
        • turn: The current turn/max turn.
        • [turn_data] replaces turn since (Version 1.13.12 and later only)
          • current: The current turn number.
          • max: The total number of turns.
        • [modification] Modifications used in this game. See ModificationWML.
          • id: ID of the modification.
          • name: Name of the modification.
          • addon_id: ID of the addon the modification is from.
          • require_modification: A boolean value; if set to yes, all players have to have this modification installed to join the game.
        • [options] Options selected for this game. See OptionWML.
          • [campaign|era|modification|multiplayer]
            • id: ID of the addon the campaign|era|modification|multiplayer (scenario) is from.
            • [option]
              • id: ID of the option.
              • value: Value of the option.
    • [user] (repeated)
      • name: The username of the player.
      • game_id: The ID of the game the player is in.
      • location: The name of the game the player is in.
      • available: "yes" if the player is in the lobby; "no" if in a game.

Many of the keys under [game] are described more indepth on the ScenarioWML page.

Error messages

  • [error]
    • message: The error message.

Chat (lobby and in-game)

  • [message]
    • sender: (optional - filled by the server) The sender of the message.
    • message: The message itself.
    • room: The room the message is from/to
  • [whisper]
    • receiver: The receiver of the whisper
    • sender: (optional - filled by the server) The sender of the whisper.
    • message: The message itself.

Nickname registration related commands (lobby and in-game)

  • [nickserv]
    • [info]: Request info about another username.
      • name: The username.

Updating the lobby state

  • [gamelist_diff]: server message - basically a diff from two gamelists, which also includes the user list.
  • [observer] or [observer_quit]: server message - players joining([observer_quit] - quitting the lobby "game")/quitting([observer] - joining the lobby "game") a game
    • name: Username of the player/observer.
  • [refresh_lobby]: Request the full gamelist.

Game setup (the phase from creation to start)

To create a game the client sends:

  • [create_game]
    • name: The title of the game.
    • password: The password to use to join the game.
    • ignored: The list of ignored players from the host.
    • auto_hosted: True if this request is from a bot, false otherwise.

followed by a message with the scenario options as under [game] (see above) plus the scenario data ([time], [era], [side], etc. see ScenarioWML)

  • [join]
    • id: The id of the game.
    • observe: Join the game as an observer.
  • [start_game]: sent by the host to start a game
  • [leave_game]: sent by the client when it leaves a game; sent by the server to make a client leave a game
    • reason: optional reason if sent by the server and was initiated by moderator action

In-game communication

  • [store_next_scenario]: sent by the host - the scenario data (see ScenarioWML) to advance to the next scenario
  • [notify_next_scenario]: sent by the server to tell players that the data for the next scenario is available
  • [load_next_scenario]: sent by the client to request the data for the next scenario
  • [next_scenario]: data for the next scenario (see ScenarioWML), sent by the server on request
  • [info]: sent by the host on game end - info about the game state
    • type: "termination"
    • condition: the termination reason
  • [change_controller]: a player (un)droids one of his sides or assigns control to someone else (The host can assign control for any side.)
    • side: the side to change controller
    • player: the nickname of the player to take control
    • controller: the new controller: "human" or "human_ai"
    • own_side: "yes"

If a player leaves this is sent to the host for all sides he owned.

  • side_drop: The number of a side that dropped because a player left.
  • controller: The controller of that side. ("ai", "network")
  • [muteall]: the host mutes/unmutes all observers - toggles
  • [mute]: the host mutes an observer - toggles
    • username: the username of the observer - if not specified the servers returns a list of muted usernames
  • [kick] or [ban]: the host kicks/bans a player/observer
    • username: the username of the player/observer
  • [turn]
    • [command]: (repeated) can contain all the tags you can find in a replay: [recruit], [move], [end_turn], etc.
      • [speak]
        • message: text of the message
        • id: the sender
        • team_name: the name of the team the message is for - empty if it's a public message

Game history

This is a request to query a set of 11 rows of game history data based on the provided search criteria. The official client calls this from the Match History button in the multiplayer lobby to display 10 rows of data. The 11th row is used as a flag to indicate whether there is more data to be queried or not via the right/left arrows on the dialog.

  • [game_history_request]
    • offset: where in the result set to start returning data from. If there are 50 results and offset 10 is given, then rows 10-21 will be returned.
    • search_player: the forum username of the player to search for.
    • search_game_name: the name of the game to filter results by. Can use the * (matches any character before or after it's used) and _ (matches any single character) wildcards.
    • search_content_type: the type of content to filter by. Must be one of:
      • 0: scenario
      • 1: era
      • 2:modification
    • search_content: The content to filter by. This is the ID of the content, not the name displayed on the UI, due to the translated name getting stored in the database.

Administrative commands

See also

fastbot - the bot for tournaments which implements the protocol, can log in into the lobby and host games. Written in Go.

This page was last edited on 3 July 2024, at 16:53.