mirror of
https://github.com/barronwaffles/dwc_network_server_emulator.git
synced 2026-08-27 21:34:08 -05:00
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:
36
README.md
36
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.
|
||||
|
||||
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
|
||||
@@ -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()
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user