Line 1: |
Line 1: |
− | == Goal and how to help ==
| + | The TrackMania Forever game client uses a {{wp|XML-RPC}} based '''web API''' to communicate with the master server. This article attempts to document the API with the potential goal of eventually having a fully functional custom master server. |
− | | |
− | One day, eventually, Trackmania will reach his EoL. This is about documenting as much as possible to eventually get the point of having a fully functional custom auth server. If you want to give help, go ahead. Just grab fiddler and start tweaking around with the game.
| |
| | | |
| == Basic concepts == | | == Basic concepts == |
| | | |
− | TrackMania uses a XML-RPC-like API to authenticate players, load server lists, load rankings, etc... Here is some documentation about what has been reversed engineered. A lot is still left to be documented. | + | TrackMania uses a XML-RPC based protocol to authenticate players, load server lists, load rankings, etc. Below is some documentation about what has been reversed engineered. A lot is still left to be documented, as logged on the [[Web_API/Progress|Progress]] page. |
| | | |
− | The game sends unencrypted POST requests to | + | The client sends HTTP(S) POST requests to |
| * [http://game.trackmaniaforever.com/online_game/request.php http://game.trackmaniaforever.com/online_game/request.php] | | * [http://game.trackmaniaforever.com/online_game/request.php http://game.trackmaniaforever.com/online_game/request.php] |
| * [http://game2.trackmaniaforever.com/online_game/request.php http://game2.trackmaniaforever.com/online_game/request.php] | | * [http://game2.trackmaniaforever.com/online_game/request.php http://game2.trackmaniaforever.com/online_game/request.php] |
− | to communicate with the API. | + | * [http://nations.trackmaniaforever.com/online_game/request.php http://nations.trackmaniaforever.com/online_game/request.php] |
− | | + | to communicate with the master server, using the headers: |
− | It sets two headers: <code>User-Agent: GameBox</code> and <code>Accept: */*</code>, and uses the following format as request body :
| + | User-Agent: GameBox |
| + | Accept: */* |
| + | Content-Type: application/binary |
| + | Connection: Keep-Alive |
| + | Pragma: no-cache |
| | | |
| + | === Request body === |
| <pre> | | <pre> |
| <?xml version="1.0" encoding="UTF-8"?> | | <?xml version="1.0" encoding="UTF-8"?> |
Line 22: |
Line 25: |
| <distro>MOLUX</distro> | | <distro>MOLUX</distro> |
| <lang>fr</lang> | | <lang>fr</lang> |
| + | <sd>2011-02-21</sd> <!-- Only sent by dedicated server, see below --> |
| </game> | | </game> |
| <author> | | <author> |
− | <login/> | + | [...] |
− | <session/>
| |
| </author> | | </author> |
| <request> | | <request> |
Line 39: |
Line 42: |
| </pre> | | </pre> |
| | | |
− | Here is a description of the parameters : | + | Here is a description of the xml: |
| | | |
| * '''root''' | | * '''root''' |
| ** '''game''' | | ** '''game''' |
− | *** '''name''' the client you are using. Known values: TmForever | + | *** '''name''' The client you are using. Known values: TmForever |
− | *** '''version''' Version of the client | + | *** '''version''' Version of the client. |
− | *** '''distro''' Unknown. Set to MOLUX or TAHOR | + | *** '''distro''' Software distribution. E.g. MOLUX for TMNF or ORTIC for TMUF. |
− | *** '''lang''' lang of the client, as ISO 639-1 | + | *** '''lang''' Language of the client, as ISO 639-1. Dedicated server sets it to "xx". |
− | ** '''author''' | + | *** '''sd''' Dedicated Server release date as YYYY-MM-DD, only sent by server. |
− | *** '''login''' is not set when calling GetConnectionAndGameParams
| + | ** '''author''' ''See [[#Author]]''. |
− | *** '''session''' is not set when calling GetConnectionAndGameParams
| |
| ** '''request''' | | ** '''request''' |
− | *** '''name''' Name of the requested function. | + | *** '''name''' Name of the remote procedure. |
| *** '''param''' Parameters for the call. | | *** '''param''' Parameters for the call. |
− | ** '''auth''' ''Optional. Only seen with Disconnect'' | + | ** '''auth''' ''Optional. Only seen on Connect and Disconnect''. |
| *** '''value''' Looks like an auth ticket. | | *** '''value''' Looks like an auth ticket. |
| | | |
− | The server responds with XML, which has obfurscated names: | + | ==== Author ==== |
| + | The author tag identifies the user for whom the request is sent. In this documentation, three cases are possible for the author tag: |
| + | |
| + | <ul> |
| + | <li>The method doesn't require authentication (denoted as "No (Empty)"), the author tag is filled with following content: |
| + | <pre> |
| + | <login/> |
| + | <session/> |
| + | </pre> |
| + | </li> |
| + | <li>The method requires user name (denoted as "No (Set to 1)"), the author tag is filled with following content: |
| + | <pre> |
| + | <login>the user's login</login> |
| + | <session>1</session> |
| + | </pre> |
| + | </li> |
| + | <li>The method requires authentication (denoted as "Yes"), the author tag is filled with following content: |
| + | <pre> |
| + | <login>the user's login</login> |
| + | <session>the session's id</session> |
| + | </pre> |
| + | </li> |
| + | </ul> |
| | | |
| + | === Response body === |
| <pre> | | <pre> |
| <?xml version="1.0" encoding="UTF-8"?> | | <?xml version="1.0" encoding="UTF-8"?> |
Line 71: |
Line 96: |
| </pre> | | </pre> |
| | | |
− | Here is a description of the return: | + | Here is a description of the returned xml: |
| | | |
− | * '''r''' | + | * '''r''' The [r]oot element |
− | ** '''r''' | + | ** '''r''' The [r]esponse element |
− | *** '''n''' The name of the called function | + | *** '''n''' The [n]ame of the called procedure. |
− | *** '''c''' The return data | + | *** '''c''' The returned [c]ontent. |
− | ** '''e''' A string giving the execution time. | + | ** '''e''' A string giving the [e]xecution time. |
| | | |
| == Functions calls == | | == Functions calls == |
| | | |
| === GetConnectionAndGameParams === | | === GetConnectionAndGameParams === |
− | ''First request sent by client.'' | + | ''Gets a lot of information. First request sent by client.'' |
| {|class="wikitable" | | {|class="wikitable" |
| ! Session required? | | ! Session required? |
Line 88: |
Line 113: |
| ! Response | | ! Response |
| |- | | |- |
− | | No | + | | No (Empty) |
| | | | | |
| * '''dedicated''' Set to 0 with TMF. Purpose is unknown. Maybe for servers. | | * '''dedicated''' Set to 0 with TMF. Purpose is unknown. Maybe for servers. |
− | * '''download''' Max P2P download speed, as set in game config, in B/s | + | * '''download''' Max P2P download speed, as set in game config, in B/s. |
− | * '''upload''' Max P2P upload speed, as set in game config, in B/s | + | * '''upload''' Max P2P upload speed, as set in game config, in B/s. |
| + | | |
| + | * '''a''' Same as '''a''' from [[#RedirectOnMasterServer]]. |
| + | |} |
| + | |
| + | === AddBuddy === |
| + | ''Adds a player to the friends list.'' |
| + | {|class="wikitable" |
| + | ! Session required? |
| + | ! Parameters |
| + | ! Response |
| + | |- |
| + | | Yes |
| + | | |
| + | * '''l''' Friend's login. Present if the "Add buddy" button is used. |
| + | * '''e''' Friend's email. Present if the "share" button is used. |
| | | | | |
− | * '''a'''
| + | * '''c''' Is present but empty when ok. |
− | ** '''b''' Full game name (Set to "Trackmania United Forever" for TMNF and TMUF)
| + | * '''v''' Error code, see below. |
− | ** '''c''' Set to "game.trackmaniaforever.com" or "game2.trackmaniaforever.com". Server the client should use to continue talking with the API.
| + | |} |
− | ** '''d''' ?. Set to "online_game"
| + | |
− | ** '''e''' Set to 443. Maybe HTTPS port?
| + | List of seen error codes: |
− | ** '''f''' Set to 80. Maybe HTTP port?
| + | |
− | ** '''g''' Set to "World". Maybe base region?
| + | {|class="wikitable" |
− | ** '''h''' ?. Set to 1
| + | ! ID |
− | ** '''i''' ?. Set to 1
| + | ! Meaning |
| + | |- |
| + | | 14 |
| + | | Unknown username |
| + | |- |
| + | | 143 |
| + | | You must wait before adding back a deleted friend |
| |} | | |} |
| | | |
| === CheckLogin === | | === CheckLogin === |
− | ''Used to check if login is already used for account creation.'' | + | ''Checks if login is already used for account creation.'' |
| {|class="wikitable" | | {|class="wikitable" |
| ! Session required? | | ! Session required? |
Line 112: |
Line 158: |
| ! Response | | ! Response |
| |- | | |- |
− | | No | + | | No (Set to 1) |
| | | | | |
| * '''l''' Player login. | | * '''l''' Player login. |
Line 121: |
Line 167: |
| | | |
| === MailAccount === | | === MailAccount === |
− | ''Used to make the server send a password recovery email.'' | + | ''Requests the server to send a password recovery email.'' |
| {|class="wikitable" | | {|class="wikitable" |
| ! Session required? | | ! Session required? |
Line 127: |
Line 173: |
| ! Response | | ! Response |
| |- | | |- |
− | | No | + | | No (Empty) |
| | | | | |
− | * '''login''' Player login | + | * '''login''' Player login. |
| | | | | |
| ''Empty response'' | | ''Empty response'' |
Line 135: |
Line 181: |
| | | |
| === Disconnect === | | === Disconnect === |
− | ''Used to disconnect (Duh).'' | + | ''Closes connection.'' |
| {|class="wikitable" | | {|class="wikitable" |
| ! Session required? | | ! Session required? |
Line 147: |
Line 193: |
| ''Empty response'' | | ''Empty response'' |
| |} | | |} |
| + | |
| + | === GetBuddies === |
| + | ''Gets the friends list.'' |
| + | {|class="wikitable" |
| + | ! Session required? |
| + | ! Parameters |
| + | ! Response |
| + | |- |
| + | | Yes |
| + | | |
| + | * '''u''' Current UTC timestamp, as YYYY:MM:DD:hh:mm:ss. |
| + | | |
| + | ''Left to document'' |
| + | * '''c''' Current UTC timestamp, as YYYYMMDDhhmmss. |
| + | * '''b''' ''Represents one friend, can have multiple of them:'' |
| + | ** '''a''' Friend's login. |
| + | ** '''x''' Set to 1 when friend online, 0 when offline. |
| + | ** '''y''' Set to 1 wile waiting for confirmation, 0 when accepted. |
| + | |} |
| + | |
| + | === GetManialinkInfos === |
| + | ''Gets info about a manialink.'' |
| + | {|class="wikitable" |
| + | ! Session required? |
| + | ! Parameters |
| + | ! Response |
| + | |- |
| + | | Yes |
| + | | |
| + | * '''manialink''' Name of the manialink |
| + | | |
| + | * '''c''' Price of the manialink. |
| + | * '''l''' Player's coppers amount. |
| + | * '''a''' ? Set to 1 or 0. |
| + | * '''m''' Name of the manialink. |
| + | * '''u''' URL of the page corresponding to the manialink. |
| + | * '''t''' ? Maybe a {{wp|Time to live|TTL}}. |
| + | * '''rl''' ''Represents distribution of amount in c. Only set when c is != 0:'' |
| + | ** '''r''' ''Represents one player. At least two in rl:'' |
| + | *** '''l''' Player login (nadeo for the 5% tax). |
| + | *** '''c''' Amount of coppers going to the player. |
| + | |} |
| + | |
| + | === GetManialinkResource === |
| + | ''Gets info about a maniacode.'' |
| + | {|class="wikitable" |
| + | ! Session required? |
| + | ! Parameters |
| + | ! Response |
| + | |- |
| + | | Yes |
| + | | |
| + | * '''manialink''' Name of the maniacode. |
| + | | |
| + | * '''m''' Name of the maniacode. |
| + | * '''u''' URL of the page corresponding to the maniacode. |
| + | |} |
| + | |
| + | === GetOnlineProfile === |
| + | ''Gets info about the player.'' |
| + | {|class="wikitable" |
| + | ! Session required? |
| + | ! Parameters |
| + | ! Response |
| + | |- |
| + | | Yes |
| + | | |
| + | * '''dt''' ? |
| + | * '''cor''' ? |
| + | | |
| + | ''A lot is left to document here'' |
| + | * '''a''' ''General info about the player:'' |
| + | ** '''a''' Player's login. |
| + | ** '''b''' Player's display name. |
| + | ** '''c''' Player's region. |
| + | ** '''d''' ? Set to 0. |
| + | ** '''e''' ? Set to 0. |
| + | ** '''j''' ? |
| + | ** '''k''' ? |
| + | * '''b''' ? |
| + | * '''h''' ''Describes the splash screen to display after login:'' |
| + | ** '''a''' Unix timestamp, current date (unknown purpose). |
| + | ** '''c''' Full HTTP URL of the manialink to display. |
| + | |} |
| + | |
| + | === GetLeagues === |
| + | ''Gets the regions list.'' |
| + | {|class="wikitable" |
| + | ! Session required? |
| + | ! Parameters |
| + | ! Response |
| + | |- |
| + | | No (Set to 1) |
| + | | |
| + | ''Empty parameters'' |
| + | | |
| + | * '''l''' ''Multiple of them, one per region:'' |
| + | ** '''a''' Region name. |
| + | ** '''b''' Parent regions (separated with "|", eg. "France|Alsace"). |
| + | ** '''i''' An URL pointing to the region's flag (dds). |
| + | |} |
| + | |
| + | === OpenSession === |
| + | ''Gets a session ID.'' |
| + | {|class="wikitable" |
| + | ! Session required? |
| + | ! Parameters |
| + | ! Response |
| + | |- |
| + | | No (Set to 1) |
| + | | |
| + | * '''cr''' 8 characters random hex value. |
| + | | |
| + | * '''i''' Session ID. |
| + | * '''s''' ?. Seems Hexadecimal. |
| + | * '''k''' Base64 encoded, see below. |
| + | |} |
| + | |
| + | '''k''' is hard-coded in the game's binary. One value has been seen, both for United and Nations: |
| + | MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCpBgX3c4ezM18RiGPlQiVKINu+JicxOd6yuHl5q30 |
| + | 00CdTLu53A3ceuelum2+ui+MmASL3JjmVVOoNURvK7GCt79wLUUSbtTaZPXPr73TioZBCVkPd8chAb8 |
| + | EurZtlDp5QQvDCaoCfFJ4V8VJgM0IK0qVIHRP+D03tKgb2WOgK9QIBEQ== |
| + | |
| + | === RemoveBuddy === |
| + | ''Removes a player from the friends list.'' |
| + | {|class="wikitable" |
| + | ! Session required? |
| + | ! Parameters |
| + | ! Response |
| + | |- |
| + | | Yes |
| + | | |
| + | * '''b''' Friend's login. |
| + | | |
| + | ''Empty response'' |
| + | |} |
| + | |
| + | === ReceiveMessages === |
| + | ''Checks for messages.'' |
| + | {|class="wikitable" |
| + | ! Session required? |
| + | ! Parameters |
| + | ! Response |
| + | |- |
| + | | Yes |
| + | | |
| + | * '''f''' Current UTC timestamp, as YYYY:MM:DD:hh:mm:ss. |
| + | | |
| + | * '''r''' ''Represents a message, can have multiple of them:'' |
| + | ** '''s''' Sender's login. |
| + | ** '''d''' UTC timestamp of sending, as YYYYMMDDhhmmss. |
| + | ** '''u''' Subject. |
| + | ** '''t''' Content. |
| + | ** '''o''' Amount of coppers in the message. |
| + | * '''l''' New coppers amount. |
| + | * '''n''' Current UTC timestamp, as YYYYMMDDhhmmss. |
| + | |} |
| + | |
| + | === RequestAllowed === |
| + | ''Checks if a request is allowed.'' |
| + | {|class="wikitable" |
| + | ! Session required? |
| + | ! Parameters |
| + | ! Response |
| + | |- |
| + | | Yes |
| + | | |
| + | * '''r''' Request type. |
| + | * '''m''' Unknown. Set to 1. |
| + | | |
| + | * '''r''' Request type (same as r in parameters). |
| + | * '''c''' Cost in coppers. |
| + | * '''l''' Current coppers amount. |
| + | * '''a''' 1 if allowed, 0 if not. |
| + | |} |
| + | |
| + | === SendMessages === |
| + | ''Sends a message to a player.'' |
| + | {|class="wikitable" |
| + | ! Session required? |
| + | ! Parameters |
| + | ! Response |
| + | |- |
| + | | Yes |
| + | | |
| + | * '''r1''' Destination's login. |
| + | * '''s1''' Subject of the message. |
| + | * '''m1''' Content of the message. |
| + | * '''d1''' Amount of coppers attached to the message. |
| + | | |
| + | * '''c''' ? |
| + | |} |
| + | |
| + | === Subscribe === |
| + | ''Registers a new account. Warning: This is sent over HTTPS.'' |
| + | {|class="wikitable" |
| + | ! Session required? |
| + | ! Parameters |
| + | ! Response |
| + | |- |
| + | | No (Set to 1) |
| + | | |
| + | * '''pw''' Password for the account. |
| + | * '''ik''' ?. Seems caps hexadecimal. |
| + | * '''email''' Supplied email. |
| + | * '''cp''' ?. Empty. |
| + | * '''np''' Region. |
| + | * '''an''' If the user accepts to receive Nadeo news on his email address. |
| + | | |
| + | * '''s''' Game key associated with the account. |
| + | |} |
| + | |
| + | == RedirectOnMasterServer == |
| + | |
| + | This response happens sometimes. It tells the client to switch auth server. When received, the client sends same request it just sent, but to the other server specified. |
| + | |
| + | Here is a description of the response: |
| + | |
| + | * '''a''' |
| + | ** '''b''' Name of the game. |
| + | ** '''c''' New server address to use. |
| + | ** '''d''' Endpoint (generally online_game). |
| + | ** '''e''' HTTPS port. |
| + | ** '''f''' HTTP port. |
| + | ** '''g''' Base region (World). |
| + | ** '''h''' ?. Set to 1 |
| + | ** '''i''' ?. Set to 1 |
| + | ** '''j''' (Maybe) List of authorized/available remote methods (described below), or permissions. |
| + | *** '''k''' One remote call ''(multiple of them in the j tag)'' |
| + | **** '''l''' Method/Permission name. |
| + | **** '''q''' Might be if authorized/available or not (seems always 1). |
| + | |
| + | Here is a list of the methods that have been seen in '''k''': |
| + | |
| + | * AddCustomChallenge |
| + | * AddResults |
| + | * CheckServerPassword |
| + | * Connect |
| + | * ConvertAccount |
| + | * CreateGroup |
| + | * Disconnect |
| + | * GetChallenge |
| + | * GetChallengeFromUId |
| + | * GetManialinkResource |
| + | * GetReplay |
| + | * MoveFromLeague |
| + | * PayCoppersTransaction |
| + | * SLiveUpdate |
| + | * SendMessages |
| + | * ShareChallenge |
| + | * StartOfficialRecord |
| + | * StopOfficialRecord |
| + | * Subscribe |
| + | * SubscribeToGroup |
| + | * UnsubscribeFromGroup |
| + | * UpdateOnlineProfile |
| + | * UploadOfficialRecord |
| + | * ValidateSoloAccount |
| + | |
| + | == How to help == |
| + | Use a {{wp|packet analyzer}} to see the game's communication while experimenting with client features, and describe requests and responses in as much detail as possible. |
| + | |
| + | Note: For Maniaplanet it's required that the address of the debugging proxy is entered in the launcher (e.g. 127.0.0.1:8888 for Fiddler) and the proxy is configured to decrypt HTTPS traffic. |
| | | |
| [[Category:Specifications]] | | [[Category:Specifications]] |