Introduction
Mario Kart Wii's ghost system has been broken for some time; you can download ghosts via "Ghost Race" randomly, but you can't download the "best player", or any rival ghosts.
This is quite some issue as it basically renders the entire section irrelevant. It seems communication with @Wiimm and @Leseratte has been contacted, but no response.
I don't want to cause a riot or start any issues. I just want the leaderboards to be fixed if Wiimmfi is trying to go for "full support".
Explanation of the Ghost System
The ghost system on Mario Kart Wii uses SAKE/RACE; SAKE (pronounced like the Japanese alcohol, sa-keh) is a server designed by GameSpy for UGC (User-Generated Content) to be stored on.
Its purpose is to hold files, such as ghosts, or user-submitted tracks (in other games). It works by using custom SOAP - SOAP is an extension to XML with custom fields.
The game uses RACE, which is Nintendo's own server, for leaderboards (specifically, the Top 10). This goes against GAMESPY design, but it's Nintendo so they got away with it
The game uses SAKE, to upload the ghost to, as well as to download ghosts from.
Top 10
The game sends to RACE the following data:
Quellcode
- POST /RaceService/NintendoRacingService.asmx HTTP/1.1
- Host: mariokartwii.race.gs.wiimmfi.de
- User-Agent: GameSpyHTTP/1.0
- Connection: close
- Content-Length: 505
- Content-Type: text/xml
- SOAPAction: "http://gamespy.net/RaceService/GetTopTenRankings"
- <?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://gamespy.net/RaceService/"><SOAP-ENV:Body><ns1:GetTopTenRankings><ns1:gameid>1687</ns1:gameid><ns1:regionid>REGION</ns1:regionid><ns1:courseid>COURSE</ns1:courseid></ns1:GetTopTenRankings></SOAP-ENV:Body></SOAP-ENV:Envelope>
The course ID is sent, along with region (which is set to 0 for worldwide), and the action to "Get Top 10 Rankings". The server complies, and sends back 10 rankings - each one has their rank, the "userdata" (their mii and country code), and their time.
Ghost Races
For Ghost Races, the game uses SakeFileServer, which is a simple way to upload and download files with simple filters. An example HTTP request for MKW:
This asks the server for ghosts for MKW (1687), without caring about region (0), with the user's PID so the server doesn't send the user's own ghosts back (p0), what i'm assuming is the course (c0), and the time that the ghost should be better than (t0)
The server responds with a header that seems to just be for server interaction, and then an RKG appended to this header. Then, the game just checks if the header is correct and then reads the RKG.
This currently works fine on Wiimmfi!
Rival Ghosts and World Champion Ghosts
The World Champion and Rival Ghosts work differently. The game first asks the server for the best time via SAKE storage server (which is communicated with via XML) for the game - I have an example communication from a beta server here:
Quellcode
- POST /SakeStorageServer/StorageServer.asmx HTTP/1.1
- Host: mariokartwii.sake.gs.wiimmfi.de
- User-Agent: GameSpyHTTP/1.0
- Connection: close
- Content-Length: 912
- Content-Type: text/xml
- SOAPAction: "http://gamespy.net/sake/SearchForRecords"
- <?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://gamespy.net/sake"><SOAP-ENV:Body><ns1:SearchForRecords><ns1:gameid>1687</ns1:gameid><ns1:secretKey>9r3Rmy</ns1:secretKey><ns1:loginTicket>23c35e51_JKLMNOPQRSTUV__</ns1:loginTicket><ns1:tableid>StoredGhostData</ns1:tableid><ns1:filter>course = 5 and gameid = 1687</ns1:filter><ns1:sort>time</ns1:sort><ns1:offset>0</ns1:offset><ns1:max>1</ns1:max><ns1:surrounding>0</ns1:surrounding><ns1:ownerids></ns1:ownerids><ns1:cacheFlag>0</ns1:cacheFlag><ns1:fields><ns1:string>profile</ns1:string><ns1:string>fileid</ns1:string></ns1:fields></ns1:SearchForRecords></SOAP-ENV:Body></SOAP-ENV:Envelope>
The server then sends back a response:
Quellcode
- HTTP/1.0 200 OK
- Server: BaseHTTP/0.3 Python/2.7.3
- Date: Mon, 13 Jul 2015 04:34:23 GMT
- Content-Type: text/xml; charset=utf-8
- <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><SearchForRecordsResponse xmlns="http://gamespy.net/sake"><SearchForRecordsResult>Success</SearchForRecordsResult><values><ArrayOfRecordValue><RecordValue><intValue><value>600006225</value></intValue></RecordValue><RecordValue><intValue><value>1</value></intValue></RecordValue></ArrayOfRecordValue></values></SearchForRecordsResponse></soap:Body></soap:Envelope>
Then, the game downloads the file from SAKE File Server -
And the server sends the RKG file with a header that the game requires.
The Current Problem
The current problem is that Wiimmfi does not send any data on the search for rival or world champion via SAKE; my game asks:
Quellcode
- POST /SakeStorageServer/StorageServer.asmx HTTP/1.1
- Host: mariokartwii.sake.gs.wiimmfi.de
- User-Agent: GameSpyHTTP/1.0
- Connection: close
- Content-Length: 924
- Content-Type: text/xml
- SOAPAction: "http://gamespy.net/sake/SearchForRecords"
- <?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://gamespy.net/sake"><SOAP-ENV:Body><ns1:SearchForRecords><ns1:gameid>1687</ns1:gameid><ns1:secretKey>9r3Rmy</ns1:secretKey><ns1:loginTicket>23c35e512ed91d82GQbDRaYQ</ns1:loginTicket><ns1:tableid>GhostData</ns1:tableid><ns1:filter>course = 8 and gameid = 1687 and time < 81502</ns1:filter><ns1:sort>time desc</ns1:sort><ns1:offset>0</ns1:offset><ns1:max>1</ns1:max><ns1:surrounding>0</ns1:surrounding><ns1:ownerids></ns1:ownerids><ns1:cacheFlag>0</ns1:cacheFlag><ns1:fields><ns1:string>fileid</ns1:string></ns1:fields></ns1:SearchForRecords></SOAP-ENV:Body></SOAP-ENV:Envelope>
And the server replies with:
Quellcode
- Date: Sun, 19 Aug 2018 19:29:32 GMT
- Server: Apache/2.4.6 (Linux/SUSE)
- X-Powered-By: PHP/5.4.20
- Content-Length: 396
- Connection: close
- Content-Type: text/xml; charset=utf-8
- <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><SearchForRecordsResponse xmlns="http://gamespy.net/sake"><SearchForRecordsResult>Success</SearchForRecordsResult><values/></SearchForRecordsResponse></soap:Body></soap:Envelope>
There is no MKW ghost there. It doesn't tell the game a file ID, so the game errors because it doesn't know what to do!
This is fundamentally a problem that is server-side, and thus the error falls on the head of the server maintainers.
Oh, and Another Thing...
Someone was banned for apparently uploading hacked times a long time ago (like a year or so), and nothing has happened about it.
Multiple times they have stated they haven't uploaded a hacked time, and yet the server administrators haven't done anything.
While the argument of "we dont have the ghost" can be valid IF the game didnt send the ghost (for competitions it'll either send the ghost file, OR just upload the ranking to RACE and nothing else), but even still, that proves the idiocy.
If someone sent a hacked time once, why are they being permanently banned when people have been just leaderboard-banned for doing it once? It seems unjust and unfair from any angle, and it's upsetting to see someone be banned over a time to a leaderboard server that's unmoderated, and doesn't even work.
The person should be unbanned, and while this may mean my entire thread will be ignored by @Wiimm, I felt it was important to reference.