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.
This commit is contained in:
polaris
2014-04-07 13:53:18 -04:00
parent 0fc1b39c2f
commit 5cb276d384
3 changed files with 48 additions and 39 deletions

View File

@@ -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.
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

View File

@@ -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()

View File

@@ -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):