Skip to content

Commit

Permalink
Upgrade codebase to Python 3
Browse files Browse the repository at this point in the history
  • Loading branch information
Hopper262 committed Aug 11, 2021
1 parent 761f633 commit 3ec0a26
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 102 deletions.
3 changes: 2 additions & 1 deletion GameTester.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,8 @@ def pingTimeout(self):
def connectionRefused(self):
self.tester.gameConnectFailed(self)

def datagramReceived(self, data, (host, port)):
def datagramReceived(self, data, addr_tuple):
(host, port) = addr_tuple
_fmt = struct.Struct('>2sH')
_magic, _crc, = _fmt.unpack_from(data)
_dataOffset = _fmt.size
Expand Down
69 changes: 34 additions & 35 deletions MetaPackets.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
#
# Metaserver is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with Metaserver. If not, see <http://www.gnu.org/licenses/>.

Expand All @@ -23,13 +23,13 @@
def unpack_strings(data, num_strings=1, offset=0):
maxp = len(data)
p = offset
cur_string = ''
cur_string = b''
all_strings = []

for i in range(num_strings):
foundstring = ''
foundstring = b''
if p < maxp:
nextnull = data.find('\x00', p)
nextnull = data.find(b'\x00', p)
if nextnull < 0:
p = maxp
else:
Expand Down Expand Up @@ -75,25 +75,25 @@ class MessagePacket:
NOT_SUPPORTED = 15

_messages = [
"Syntax error (unrecognized command).",
"Login failed (Games not allowed at this time)." ,
"Login failed (Invalid Game Version number)." ,
"Login failed (Bad user or Password)." ,
"User not logged in." ,
"Bad metaserver version." ,
"User already logged in!",
"Unknown game type!",
"User logged in.",
"User logged out.",
"Player not in a room!",
"You already created a game!",
"This account is already logged in!",
"The desired room is full!",
"Your account has been locked",
"The game server for your product has been shutdown" ]
"Syntax error (unrecognized command).".encode('mac_roman'),
"Login failed (Games not allowed at this time).".encode('mac_roman'),
"Login failed (Invalid Game Version number).".encode('mac_roman'),
"Login failed (Bad user or Password).".encode('mac_roman'),
"User not logged in.".encode('mac_roman'),
"Bad metaserver version.".encode('mac_roman'),
"User already logged in!".encode('mac_roman'),
"Unknown game type!".encode('mac_roman'),
"User logged in.".encode('mac_roman'),
"User logged out.".encode('mac_roman'),
"Player not in a room!".encode('mac_roman'),
"You already created a game!".encode('mac_roman'),
"This account is already logged in!".encode('mac_roman'),
"The desired room is full!".encode('mac_roman'),
"Your account has been locked".encode('mac_roman'),
"The game server for your product has been shutdown".encode('mac_roman') ]

def __init__(self, which):
self.data = self._fmt.pack(which) + self._messages[which] + '\x00'
self.data = self._fmt.pack(which) + self._messages[which] + b'\x00'


class LoginPacket:
Expand All @@ -103,10 +103,10 @@ class LoginPacket:
def __init__(self, data):
self.platform_type, self.metaserver_version, self.flags, self.user_id, self.max_authentication, player_data_size, self.service_name, self.build_date, self.build_time, self.username = self._fmt.unpack_from(data)

self.service_name = self.service_name.rstrip('\x00')
self.build_date = self.build_date.rstrip('\x00')
self.build_time = self.build_time.rstrip('\x00')
self.username = self.username.rstrip('\x00')
self.service_name = self.service_name.rstrip(b'\x00')
self.build_date = self.build_date.rstrip(b'\x00')
self.build_time = self.build_time.rstrip(b'\x00')
self.username = self.username.rstrip(b'\x00')

PlayerDataChunk.unpack_into(self, data, self._fmt.size)

Expand All @@ -118,9 +118,9 @@ class PasswordResponsePacket:
def __init__(self, data):
self.password_data, = self._fmt.unpack_from(data)

def decode_password(self, auth_type=0, salt=''):
def decode_password(self, auth_type=0, salt=b''):
if auth_type == 0: # plaintext
self.password = self.password_data.rstrip('\x00')
self.password = self.password_data.rstrip(b'\x00')
elif auth_type == 4: # HTTPS
self.password = self.password_data
else: # unrecognized
Expand All @@ -144,7 +144,7 @@ class RoomLoginPacket:

def __init__(self, data):
self.token, = self._fmt.unpack_from(data)
self.token = self.token.rstrip('\x00')
self.token = self.token.rstrip(b'\x00')
self.username, stringlen = unpack_strings(data, 1, self._fmt.size)

class PlayerDataPacket:
Expand Down Expand Up @@ -246,21 +246,21 @@ class RoomMessagePacket:
code = 10

def __init__(self, message):
self.data = message + '\x00'
self.data = message + b'\x00'

class PlayerListPacket:
code = 1

def __init__(self, player_list, verb):
self.data = ''
self.data = b''
for user_info in player_list:
self.data += user_info.roomPlayerDataChunk(verb)

class GameListPacket:
code = 2

def __init__(self, game_list, verb):
self.data = ''
self.data = b''
for game_info in game_list:
self.data += game_info.dataChunk(verb)

Expand All @@ -271,7 +271,7 @@ class OutgoingChatPacket:
def __init__(self, user_info, message):
chatname = user_info.chatname
color = user_info.player_info.player_color
self.data = self._fmt.pack(0, 26 + len(chatname) + len(message), color[0], color[1], color[2], 0, user_info.user_id, 0) + chatname + '\x00' + message + '\x00'
self.data = self._fmt.pack(0, 26 + len(chatname) + len(message), color[0], color[1], color[2], 0, user_info.user_id, 0) + chatname + b'\x00' + message + b'\x00'

class OutgoingPrivateMessagePacket:
code = 201
Expand All @@ -280,5 +280,4 @@ class OutgoingPrivateMessagePacket:
def __init__(self, user_info, target_id, message):
chatname = user_info.chatname
color = user_info.player_info.player_color
self.data = self._fmt.pack(target_id, 1, 0, 26 + len(chatname) + len(message), color[0], color[1], color[2], 1, user_info.user_id, target_id) + chatname + '\x00' + message + '\x00'

self.data = self._fmt.pack(target_id, 1, 0, 26 + len(chatname) + len(message), color[0], color[1], color[2], 1, user_info.user_id, target_id) + chatname + b'\x00' + message + b'\x00'
9 changes: 4 additions & 5 deletions MetaProtocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
#
# Metaserver is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# You should have received a copy of the GNU General Public License
# along with Metaserver. If not, see <http://www.gnu.org/licenses/>.

Expand All @@ -32,7 +32,7 @@ class MetaProtocol(Protocol, TimeoutMixin):

def __init__(self):
# Protocol.__init__(self)
self._unprocessed = ''
self._unprocessed = b''
self._awaitingPing = False

def connectionMade(self):
Expand Down Expand Up @@ -75,7 +75,7 @@ def packMessage(self, code, data):
def sendPacket(self, packet):
extradata = packet.data
if extradata == None:
extradata = ''
extradata = b''
if not isinstance(packet, OutgoingKeepAlivePacket):
log.msg("sending %s (%d bytes)" % (packet.__class__.__name__.rsplit('.', 1).pop(), len(extradata)))
data = self._fmt.pack(self.SIGNATURE, packet.code, self._fmt.size + len(extradata)) + extradata
Expand Down Expand Up @@ -117,4 +117,3 @@ def dataReceived(self, data):
currentOffset = bodyEnd

self._unprocessed = alldata[currentOffset:]

14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,17 @@ This is a partial implementation of [Bungie](http://www.bungie.net/)'s Myth meta

### Limitations

The implementation is designed for use with [Aleph One](http://source.bungie.org/), and only supports the subset of features actually used by Aleph One. It also trades scalability for simplicity: only one room is available, handled by the same server process as the initial user connections.
The implementation is designed for use with [Aleph One](http://alephone.lhowon.org/), and only supports the subset of features actually used by Aleph One. It also trades scalability for simplicity: only one room is available, handled by the same server process as the initial user connections.

### Requirements

* [Python](http://www.python.org/) 2.x (tested with 2.6.9)
* [Twisted](http://www.twistedmatrix.com/) (tested with 8.2.0)
* [MySQL](http://www.mysql.com/) (tested with 5.5.34)
* [MySQL-Python](http://mysql-python.sourceforge.net) (tested with 1.2.3)
* [bcrypt](https://github.com/pyca/bcrypt/) (tested with 3.1.7)
* Python 3 (tested with 3.7.10)
* MySQL or compatible database (tested with MariaDB 10.5.10)
* Python modules:
* Twisted (tested with 21.7.0)
* PyMySQL (tested with 1.0.2)
* bcrypt (tested with 3.2.0)
* crcmod (tested with 1.7)

### Acknowledgements

Expand Down
4 changes: 2 additions & 2 deletions ReconnectingConnectionPool.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from twisted.enterprise import adbapi
from twisted.python import log
import MySQLdb
import pymysql

class ReconnectingConnectionPool(adbapi.ConnectionPool):
"""Reconnecting adbapi connection pool for MySQL.
Expand All @@ -22,7 +22,7 @@ class ReconnectingConnectionPool(adbapi.ConnectionPool):
def _runInteraction(self, interaction, *args, **kw):
try:
return adbapi.ConnectionPool._runInteraction(self, interaction, *args, **kw)
except MySQLdb.OperationalError, e:
except pymysql.OperationalError as e:
if e[0] not in (2006, 2013):
raise
log.msg("RCP: got error %s, retrying operation" %(e))
Expand Down
43 changes: 22 additions & 21 deletions Roomd.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ def handleRoomLoginPacket(self, packet):
self.user_info = self.globals['users'][self.user_id]
uname = self.user_info.username
if uname is None:
uname = 'guest'
if packet.username == '':
packet.username = 'guest'
uname = b'guest'
if packet.username == b'':
packet.username = b'guest'
if uname != packet.username:
self.sendMessage(MessagePacket.BAD_USER)
return False
Expand Down Expand Up @@ -153,7 +153,7 @@ def handleCreateGamePacket(self, packet):
self.sendMessage(MessagePacket.NOT_LOGGED_IN)
return False

self.logEvent('create game', packet.game_data.encode('hex'))
self.logEvent('create game', packet.game_data.hex())
verb = self.VERB_CHANGE
if self.game_info is None:
gid = self.userd.buildGameID(self.user_id)
Expand Down Expand Up @@ -263,11 +263,11 @@ def connectionLost(self, reason):
self.checkRainbow()

def sendRoomMessage(self, message):
self.sendPacket(RoomMessagePacket(message))
self.sendPacket(RoomMessagePacket(message.encode('mac_roman')))

def broadcastRoomMessage(self, message):
self.logBroadcast(message)
self.sendPacketToRoom(RoomMessagePacket(message))
self.sendPacketToRoom(RoomMessagePacket(message.encode('mac_roman')))

def sendPlayerList(self, send, recip, verb):
send_list = self.buildSendList('users', send)
Expand All @@ -285,7 +285,7 @@ def buildSendList(self, which, send):
if send in self.globals[which] and self.globals[which][send].visible:
send_list.append(self.globals[which][send])
else:
for id, info in self.globals[which].iteritems():
for id, info in self.globals[which].items():
if info.visible and not id == (0 - send):
send_list.append(info)
return send_list
Expand All @@ -299,7 +299,7 @@ def sendPacketToRoom(self, packet, recip=0):
if conn is not None and not conn.deaf:
conn.sendPacket(packet)
else:
for user_id, info in self.globals['users'].iteritems():
for user_id, info in self.globals['users'].items():
if not user_id == (0 - recip):
conn = info.roomd_connection
if conn is not None and not conn.deaf:
Expand Down Expand Up @@ -391,7 +391,7 @@ def logLogin(self):
self.user_info.player_info.team_color[0],
self.user_info.player_info.team_color[1],
self.user_info.player_info.team_color[2],
self.user_info.player_info.build_date + " " + self.user_info.player_info.build_time,
self.user_info.player_info.build_date + b' ' + self.user_info.player_info.build_time,
self.user_info.player_info.platform_type))
deferred.addErrback(self.reportDbError)

Expand All @@ -404,15 +404,16 @@ def userActive(self):
self.sendPlayerList(self.user_id, 0, self.VERB_CHANGE)
self.checkRainbow()

def handleChatCommand(self, message, target=None):
if not message.startswith("."):
def handleChatCommand(self, messagebytes, target=None):
if not messagebytes.startswith('.'.encode('mac_roman')):
return False
message = messagebytes.decode('mac_roman')
words = message.split()
if words[0] == ".afk":
away_msg = "afk"
if len(words) > 1:
away_msg = ' '.join(words[1:])
self.user_info.afk = away_msg
self.user_info.afk = away_msg.encode('mac_roman')
self.sendPlayerList(self.user_id, 0, self.VERB_CHANGE)
self.checkRainbow()
elif words[0] == ".back":
Expand All @@ -422,11 +423,11 @@ def handleChatCommand(self, message, target=None):
self.sendRoomMessage("No user selected")
else:
if target.username is None:
self.sendRoomMessage(target.chatname + " is a guest")
self.sendRoomMessage(target.chatname.decode('mac_roman') + " is a guest")
elif target.moderator:
self.sendRoomMessage(target.chatname + " is the moderator \"" + target.username + "\"")
self.sendRoomMessage(target.chatname.decode('mac_roman') + " is the moderator \"" + target.username.decode('mac_roman') + "\"")
else:
self.sendRoomMessage(target.chatname + " is registered as \"" + target.username + "\"")
self.sendRoomMessage(target.chatname.decode('mac_roman') + " is registered as \"" + target.username.decode('mac_roman') + "\"")
elif words[0] == ".help":
self.sendCommandHelp()
elif words[0] == ".action" or words[0] == ".me":
Expand All @@ -438,7 +439,7 @@ def handleChatCommand(self, message, target=None):
self.sendRoomMessage("Please wait 15 seconds between " + words[0] + " commands")
else:
self.user_info.action_timer = cur_time + 15
self.broadcastRoomMessage(self.user_info.chatname + ' ' + ' '.join(words[1:]))
self.broadcastRoomMessage(self.user_info.chatname.decode('mac_roman') + ' ' + ' '.join(words[1:]))
elif words[0] == ".credits" or words[0] == ".about":
self.sendRoomMessage("Aleph One Metaserver - http://metaserver.lhowon.org/")
elif words[0] == ".kick" and self.user_info.moderator:
Expand All @@ -447,10 +448,10 @@ def handleChatCommand(self, message, target=None):
elif target.roomd_connection:
extra = ''
if target.username:
extra = ' [' + target.username + ']'
self.logEvent('kick', target.chatname + extra)
extra = ' [' + target.username.decode('mac_roman') + ']'
self.logEvent('kick', target.chatname.decode('mac_roman') + extra)
target.roomd_connection.transport.loseConnection()
self.broadcastRoomMessage('Moderator ' + self.user_info.chatname + ' kicked ' + target.chatname)
self.broadcastRoomMessage('Moderator ' + self.user_info.chatname.decode('mac_roman') + ' kicked ' + target.chatname.decode('mac_roman'))
elif words[0] == ".rainbow" and self.user_info.moderator:
if self.globals['rainbow'] is None:
self.globals['rainbow'] = 'rainbow'
Expand Down Expand Up @@ -510,7 +511,7 @@ def checkRainbow(self):
# check if any moderators are still in the room; count visible users
cancel = True
num_users = 0
for user_info in self.globals['users'].values():
for user_info in list(self.globals['users'].values()):
if user_info.moderator:
cancel = False
if user_info.visible:
Expand Down Expand Up @@ -539,7 +540,7 @@ def checkRainbow(self):

def resetColors(self):
changed = False
for user_info in self.globals['users'].values():
for user_info in list(self.globals['users'].values()):
if user_info.player_info.player_color != user_info.original_player_color:
user_info.player_info.player_color = user_info.original_player_color
changed = True
Expand Down
Loading

0 comments on commit 3ec0a26

Please sign in to comment.