equipment messages are now list of pairs, not dict; server gets address on creation

This commit is contained in:
troido 2019-09-25 08:10:46 +02:00
parent 84d899aa45
commit 7c33c47f9b
6 changed files with 62 additions and 69 deletions

View File

@ -134,12 +134,10 @@ class Display:
def setEquipment(self, slots):
self.equipment.setItems(
sorted([
slot + ": " + (item if item else "")
for slot, item in slots.items()
])
)
self.equipment.setItems([
slot + ": " + (item if item else "")
for slot, item in slots
])
def setGround(self, items):
self.ground.setItems(items)

View File

@ -15,9 +15,9 @@ saveExt = ".save.json"
class Game:
def __init__(self, socketType, worldFile=None, saveDir=None, saveInterval=1):
def __init__(self, socketType, address, worldFile=None, saveDir=None, saveInterval=1):
self.server = gameserver.GameServer(socketType)
self.server = gameserver.GameServer(socketType, address)
worldLoader = worldloader.WorldLoader(saveDir)
roomLoader = roomloader.RoomLoader(worldFile, os.path.join(saveDir, "rooms"))
@ -31,9 +31,9 @@ class Game:
self.counter = 0
def start(self, address):
def start(self):
self.server.start(address)
self.server.start()
try:
self.game_loop()

View File

@ -18,20 +18,17 @@ nameRegex = re.compile("(~|\w)\w*")
class GameServer:
def __init__(self, socketType):
def __init__(self, socketType, address):
self.serv = server.Server(socketType, self.newConnection, self.receive, self.close)
self.serv = server.Server(socketType, address, self.newConnection, self.receive, self.close)
self.connections = {}
self.players = {}
self.messages = queue.Queue()
def start(self, address):
def start(self):
self.listener = threading.Thread(target=self.serv.listen, daemon=True, args=(address,))
self.listener = threading.Thread(target=self.serv.listen, daemon=True)
self.listener.start()
def sendState(self, view):
@ -69,7 +66,7 @@ class GameServer:
self.error(n, "invalidname", "name may not be longer than 256 utf8 bytes")
return
if nameRegex.match(name) is None:
self.error(n, "invalidname", "Name must match the regex: {}".format(nameRegex.pattern))
self.error(n, "invalidname", "Name must match the following regex: {}".format(nameRegex.pattern))
return
if name[0] == "~" and name[1:] != self.serv.getUsername(n):
self.error(n, "invalidname", "tildenames are only available on unix sockets and when the rest of the name equals the username")

View File

@ -39,4 +39,4 @@ def main(argv=None):
hostname, sep, port = address.partition(':')
address = (hostname, int(port))
game.Game(args.socket, args.world, args.savedir, 300).start(address)
game.Game(args.socket, address, args.world, args.savedir, 300).start()

View File

@ -40,7 +40,7 @@ class _BytesBuffer:
class Server:
def __init__(self, socketType, onConnection=(lambda *_:None), onMessage=(lambda *_:None), onConnectionClose=(lambda *_:None)):
def __init__(self, socketType, address, onConnection=(lambda *_:None), onMessage=(lambda *_:None), onConnectionClose=(lambda *_:None)):
if socketType == "abstract" or socketType == "unix":
self.sockType = socket.AF_UNIX
@ -53,13 +53,14 @@ class Server:
self.onConnection = onConnection
self.onMessage = onMessage
self.onConnectionClose = onConnectionClose
self.sel = selectors.DefaultSelector()
self.address = address
self.selector = None
def listen(self, address):
print("starting {} socket server on address {}".format(self.socketType, address))
def listen(self, selector=None):
print("starting {} socket server on address {}".format(self.socketType, self.address))
try:
self.sock.bind(address)
self.sock.bind(self.address)
except PermissionError:
print("You don't have permission to use this socket file.\nRun the server with the '-s' option to specify another socket file path.\nWARNING: if an existing file is given, it will be overwritten.")
sys.exit(-1)
@ -71,51 +72,49 @@ class Server:
self.sock.setblocking(False)
self.sel.register(self.sock, selectors.EVENT_READ, "ACCEPT")
if selector is None:
selector = selectors.DefaultSelector()
self.selector = selector
selector.register(self.sock, selectors.EVENT_READ, self._accept)
self.connections = {}
print("listening")
while True:
events = self.sel.select()
events = selector.select()
for key, mask in events:
if key.data == "ACCEPT":
sock = key.fileobj
connection, client_address = sock.accept()
connection.setblocking(False)
self.sel.register(connection, selectors.EVENT_READ, "RECEIVE")
self.connections[connection] = _BytesBuffer()
self.onConnection(connection)
elif key.data == "RECEIVE":
connection = key.fileobj
data = connection.recv(4096)
if data:
buff = self.connections[connection]
buff.addBytes(data)
for message in buff.readMessages():
self.onMessage(connection, message)
else:
del self.connections[connection]
self.onConnectionClose(connection)
#listener = threading.Thread(target=self._listenCon, args=(connection,), daemon=True)
#listener.start()
sock = key.fileobj
callback = key.data
callback(sock)
#def _listenCon(self, connection):
#self.connections.add(connection)
#self.onConnection(connection)
#data = receive(connection)
#while data:
#self.onMessage(connection, data)
#try:
#data = receive(connection)
#except socket.error:
#break
#if not len(data):
#break
#self.connections.discard(connection)
#self.onConnectionClose(connection)
def _accept(self, sock):
connection, client_address = sock.accept()
connection.setblocking(False)
self.selector.register(connection, selectors.EVENT_READ, self._receive)
self.connections[connection] = _BytesBuffer()
self.onConnection(connection)
def _receive(self, connection):
try:
data = connection.recv(4096)
except ConnectionResetError:
data = None
if data:
buff = self.connections[connection]
buff.addBytes(data)
for message in buff.readMessages():
self.onMessage(connection, message)
else:
self.closeConnection(connection)
def closeConnection(self, connection):
try:
del self.connections[connection]
except KeyError:
return
connection.close()
self.selector.unregister(connection)
self.onConnectionClose(connection)
def getUsername(self, connection):
@ -129,14 +128,13 @@ class Server:
def send(self, connection, msg):
try:
if connection in self.connections:
length = len(msg)
header = length.to_bytes(4, byteorder="big")
connection.sendall(header + msg)
except Exception:
del self.connections[connection]
self.onConnectionClose(connection)
print("failed to send to client")
try:
connection.sendall(header + msg)
except BrokenPipeError:
self.closeConnection(connection)
def broadcast(self, msg):
for connection in frozenset(self.connections):

View File

@ -16,7 +16,7 @@ def onSelectionChange(p):
changeActions = {
"health": lambda p: ["health", p.getHealthPair()],
"inventory": lambda p: ["inventory", [obj.getName() for obj in p.getInventory()]],
"equipment": lambda p: ["equipment", {slot: (item.getName() if item else None) for slot, item in p.getEquipment().items()}],
"equipment": lambda p: ["equipment", sorted([(slot, (item.getName() if item else None)) for slot, item in p.getEquipment().items()])],
"ground": lambda p: ["ground", [obj.getName() for obj in p.getGroundObjs() if obj.getName()]],
"pos": lambda p: ["playerpos", p.getPos()],
"selection": onSelectionChange