From 5cb276d384fec3328b263a143858cffcd29a8287 Mon Sep 17 00:00:00 2001 From: polaris Date: Mon, 7 Apr 2014 13:53:18 -0400 Subject: [PATCH] Merged changes made by leseratte Merged the changes made by leseratte and made some of my own. This should possibly be enough to get Mario Kart Wii to login but I do not have a way to test it myself. --- README.md | 36 ++++++++++++++++++------------------ gamespy/gs_database.py | 16 ++++++++-------- gamespy_server.py | 35 ++++++++++++++++++++++------------- 3 files changed, 48 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 79c4c1a..e0f7412 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ -nintendo_dwc_emulator -===================== +nintendo_dwc_emulator +===================== + +A Nintendo DS (and possibly Wii) server emulator. -A Nintendo DS (and possibly Wii) server emulator. - - -Open source projects referenced during the creation of this project: -OpenSpy Core - https://github.com/sfcspanky/Openspy-Core/ -Luigi Auriemma's Gslist and enctypex_decoder - http://aluigi.altervista.org/papers.htm - - -Compatibility: -The following games have been tested with varying results. - -Tetris DS (U) - Friends only games are playable. Worldwide matchmaking does not work. -Jump Ultimate Stars (J) - Friends only games are playable. Worldwide matchmaking does not work. Voice untested. -Phantasy Star Zero (U) - "Play Alone" and playing with friends works. Matchmaking does not work. - -Matchmaking as a whole right now has not been implemented so it will most likely not work in any game yet. \ No newline at end of file + +Requirements: +Python 2.7 +Twisted +zope.interface (Twisted dependency) +pywin32 (Twisted dependency) + + +Open source projects referenced during the creation of this project: +OpenSpy Core - https://github.com/sfcspanky/Openspy-Core/ +Luigi Auriemma's Gslist and enctypex_decoder - http://aluigi.altervista.org/papers.htm + + +Please see the wiki for a list of games that have been tested: https://github.com/polaris-/nintendo_dwc_emulator/wiki/Compatibility \ No newline at end of file diff --git a/gamespy/gs_database.py b/gamespy/gs_database.py index e09918c..9a67bbb 100644 --- a/gamespy/gs_database.py +++ b/gamespy/gs_database.py @@ -19,7 +19,7 @@ class GamespyDatabase(object): # but I'm not good with databases and I'm not 100% positive that, for instance, that all # user id's will be ints, or all passwords will be ints, etc, despite not seeing any # evidence yet to say otherwise as far as Nintendo DS games go. - c.execute('''CREATE TABLE users (profileid INT, userid TEXT, password TEXT, email TEXT, uniquenick TEXT, pid TEXT, lon TEXT, lat TEXT, loc TEXT, lastname TEXT, stat TEXT, partnerid TEXT)''') + c.execute('''CREATE TABLE users (profileid INT, userid TEXT, password TEXT, gsbrcd TEXT, email TEXT, uniquenick TEXT, pid TEXT, lon TEXT, lat TEXT, loc TEXT, lastname TEXT, stat TEXT, partnerid TEXT)''') c.execute('''CREATE TABLE sessions (session TEXT, profileid INT)''') c.execute('''CREATE TABLE buddies (userProfileid INT, buddyProfileId INT, status INT)''') self.conn.commit() @@ -45,9 +45,9 @@ class GamespyDatabase(object): return profileid - def check_user_exists(self, userid): + def check_user_exists(self, userid, gsbrcd): c = self.conn.cursor() - c.execute("SELECT * FROM users WHERE userid = ?", [userid]) + c.execute("SELECT * FROM users WHERE userid = ? and gsbrcd = ?", [userid, gsbrcd]) r = self.get_dict(c.fetchone()) @@ -82,9 +82,9 @@ class GamespyDatabase(object): c.close() return profile - def perform_login(self, userid, password): + def perform_login(self, userid, password, gsbrcd): c = self.conn.cursor() - c.execute("SELECT * FROM users WHERE userid = ?", [userid]) + c.execute("SELECT * FROM users WHERE userid = ? and gsbrcd = ?", [userid, gsbrcd]) r = self.get_dict(c.fetchone()) @@ -99,7 +99,7 @@ class GamespyDatabase(object): c.close() return profileid - def create_user(self, userid, password, email, uniquenick): + def create_user(self, userid, password, email, uniquenick, gsbrcd): if self.check_user_exists(userid) == 0: profileid = self.get_next_free_profileid() @@ -121,8 +121,8 @@ class GamespyDatabase(object): password = md5.hexdigest() c = self.conn.cursor() - c.execute("INSERT INTO users VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", - [profileid, str(userid), password, email, uniquenick, pid, lon, lat, loc, lastname, stat, partnerid]) + c.execute("INSERT INTO users VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", + [profileid, str(userid), password, gsbrcd, email, uniquenick, pid, lon, lat, loc, lastname, stat, partnerid]) c.close() self.conn.commit() diff --git a/gamespy_server.py b/gamespy_server.py index 3761fa7..d7ea99f 100644 --- a/gamespy_server.py +++ b/gamespy_server.py @@ -82,7 +82,8 @@ class PlayerSession(LineReceiver): # get correct information userid = authtoken_parsed['userid'] password = authtoken_parsed['passwd'] - uniquenick = utils.base32_encode(int(userid)) + authtoken_parsed['gsbrcd'] + gsbrcd = authtoken_parsed['gsbrcd'] + uniquenick = utils.base32_encode(int(userid)) + gsbrcd email = uniquenick + "@nds" # Verify the client's response @@ -92,11 +93,11 @@ class PlayerSession(LineReceiver): proof = gs_utils.generate_proof(self.challenge, authtoken_parsed['challenge'], data_parsed['challenge'], data_parsed['authtoken']) - valid_user = self.db.check_user_exists(userid) + valid_user = self.db.check_user_exists(userid, gsbrcd) if valid_user == False: - profileid = self.db.create_user(userid, password, email, uniquenick) + profileid = self.db.create_user(userid, password, email, uniquenick, gsbrcd) else: - profileid = self.db.perform_login(userid, password) + profileid = self.db.perform_login(userid, password, gsbrcd) if profileid == None: # Handle case where the user is invalid @@ -120,7 +121,14 @@ class PlayerSession(LineReceiver): msg_d.append(('id', data_parsed['id'])) msg = gs_query.create_gamespy_message(msg_d) - self.gameid = authtoken_parsed['gsbrcd'][0:4] + # Take the first 4 letters of gsbrcd instead of gamecd because they should be consistent across game + # regions. For example, the US version of Metroid Prime Hunters has the gamecd "AMHE" and the first 4 letters + # of gsbrcd are "AMHE". However, the Japanese version of Metroid Prime Hunters has the gamecd "AMHJ" with + # the first 4 letters of bsbrcd as "AMHE". Tetris DS is the other way, with the first 4 letters as the + # Japanese version (ATRJ) while the gamecd is region specific (ATRE for US and ATRJ for JP). + # gameid is used to send all people on the player's friends list a status updates, so don't make it region + # specific. + self.gameid = gsbrcd[0:4] self.profileid = profileid utils.print_log("SENDING: %s" % msg) @@ -157,7 +165,7 @@ class PlayerSession(LineReceiver): utils.print_log("SENDING: %s" % msg) self.transport.write(bytes(msg)) - + def perform_updatepro(self, data_parsed): sesskey = data_parsed['sesskey'] @@ -166,6 +174,7 @@ class PlayerSession(LineReceiver): data_parsed.pop('__cmd__') data_parsed.pop('__cmd_val__') data_parsed.pop('updatepro') + data_parsed.pop('partnerid') data_parsed.pop('sesskey') # Create a list of fields to be updated. @@ -280,10 +289,10 @@ class PlayerSearch(LineReceiver): self.db = gs_database.GamespyDatabase() def connectionMade(self): - pass + pass def connectionLost(self, reason): - pass + pass def rawDataReceived(self, data): utils.print_log("SEARCH RESPONSE: %s" % data) @@ -297,11 +306,11 @@ class PlayerSearch(LineReceiver): self.perform_otherslist(data_parsed) else: utils.print_log("Found unknown search command, don't know how to handle '%s'." % data_parsed['__cmd__']) - - def perform_otherslist(self, data_parsed): - # How do you handle opids? It doesn't seem *too* important so skip over it for now. - self.transport.write(bytes("\\otherslist\\\\oldone\\\\final\\")) - + + def perform_otherslist(self, data_parsed): + # How do you handle opids? It doesn't seem *too* important so skip over it for now. + self.transport.write(bytes("\\otherslist\\\\oldone\\\\final\\")) + sessions = {} class PlayerFactory(Factory):