diff options
| author | troido <troido@protonmail.com> | 2019-09-26 20:19:26 +0200 |
|---|---|---|
| committer | troido <troido@protonmail.com> | 2019-09-26 20:19:26 +0200 |
| commit | 548aa5ef6a128ff561c09849e07047a978fc1c5b (patch) | |
| tree | fe119adfbaa58861e7ba8e74492bef91f0883989 /asciifarm | |
| parent | 41ccee19d4522ae8f5eb0abdb4b9a67f0f415d69 (diff) | |
made server -> client messages into objects; clear field when entering different room
Diffstat (limited to 'asciifarm')
| -rw-r--r-- | asciifarm/client/connection.py | 2 | ||||
| -rw-r--r-- | asciifarm/client/display.py | 1 | ||||
| -rw-r--r-- | asciifarm/client/gameclient.py | 118 | ||||
| -rw-r--r-- | asciifarm/client/layout.xml | 5 | ||||
| -rw-r--r-- | asciifarm/common/messages.py | 68 |
5 files changed, 128 insertions, 66 deletions
diff --git a/asciifarm/client/connection.py b/asciifarm/client/connection.py index 20f4964..0a188c3 100644 --- a/asciifarm/client/connection.py +++ b/asciifarm/client/connection.py @@ -27,4 +27,4 @@ class Connection: callback(data) def send(self, message): - send(self.sock, bytes(message, 'utf-8')) + send(self.sock, message) diff --git a/asciifarm/client/display.py b/asciifarm/client/display.py index fbcd34a..edd5acb 100644 --- a/asciifarm/client/display.py +++ b/asciifarm/client/display.py @@ -79,6 +79,7 @@ class Display: def resizeField(self, size): self.getWidget("field").set_size(*size) + self.getWidget("fieldbackground").change() def drawFieldCells(self, cells): field = self.getWidget("field") diff --git a/asciifarm/client/gameclient.py b/asciifarm/client/gameclient.py index 57503db..facb54e 100644 --- a/asciifarm/client/gameclient.py +++ b/asciifarm/client/gameclient.py @@ -35,7 +35,7 @@ class Client: def sendMessage(self, message): - self.connection.send(json.dumps(message.to_json())) + self.connection.send(message.to_json_bytes()) def sendInput(self, inp): message = messages.InputMessage(inp) @@ -78,64 +78,64 @@ class Client: self.close("Connection closed by server") return datastr = databytes.decode('utf-8') - data = json.loads(datastr) - if len(data) and isinstance(data[0], str): - data = [data] - for msg in data: - msgType = msg[0] - if msgType == 'error': - error = msg[1] - if error == "nametaken": - self.close("error: name is already taken") - return - if error == "invalidname": - self.close("Invalid name error: "+ str(msg[2:])) - return - self.log(" ".join(msg[1:])) - if msgType == "message": - self.log(*msg[1:]) - if msgType == "world": - for msg in msg[1]: - msgType = msg[0] - if msgType == 'field': - field = msg[1] - fieldWidth = field['width'] - fieldHeight = field['height'] - self.display.resizeField((fieldWidth, fieldHeight)) - fieldCells = field['field'] - mapping = field['mapping'] - self.display.drawFieldCells( - ( - tuple(reversed(divmod(i, fieldWidth))), - mapping[spr] - ) - for i, spr in enumerate(fieldCells)) - - if msgType == 'changecells' and len(msg[1]): - self.display.drawFieldCells(msg[1]) - - if msgType == "playerpos": - self.display.setFieldCenter(msg[1]) - - if msgType == "health": - health, maxHealth = msg[1] - self.display.setHealth(health, maxHealth) - if maxHealth is None: - self.log("You have died. Restart the client to respawn") - if msgType == "inventory": - self.display.setInventory(msg[1]) - if msgType == "equipment": - self.display.setEquipment(msg[1]) - if msgType == "ground": - self.display.setGround(msg[1]) - if msgType == "message": - self.log(*msg[1:]) - if msgType == "options": - if msg[1] != None: - description, options = msg[1] - self.log(description) - for option in options: - self.log(option) + msg = json.loads(datastr) + message = messages.messages[msg[0]].from_json(msg) + if isinstance(message, messages.ErrorMessage): + error = message.errType + if error == "nametaken": + self.close("error: name is already taken") + return + if error == "invalidname": + self.close("Invalid name error: "+ str(message.description)) + return + self.log(message.errtype + ": " + message.description) + elif isinstance(message, messages.MessageMessage): + self.log(message.text, message.type) + elif isinstance(message, messages.WorldMessage): + for msg in message.updates: + self.handleWorldUpdate(msg) + + def handleWorldUpdate(self, msg): + msgType = msg[0] + if msgType == 'field': + field = msg[1] + fieldWidth = field['width'] + fieldHeight = field['height'] + self.display.resizeField((fieldWidth, fieldHeight)) + fieldCells = field['field'] + mapping = field['mapping'] + self.display.drawFieldCells( + ( + tuple(reversed(divmod(i, fieldWidth))), + mapping[spr] + ) + for i, spr in enumerate(fieldCells)) + + if msgType == 'changecells' and len(msg[1]): + self.display.drawFieldCells(msg[1]) + + if msgType == "playerpos": + self.display.setFieldCenter(msg[1]) + + if msgType == "health": + health, maxHealth = msg[1] + self.display.setHealth(health, maxHealth) + if maxHealth is None: + self.log("You have died. Restart the client to respawn") + if msgType == "inventory": + self.display.setInventory(msg[1]) + if msgType == "equipment": + self.display.setEquipment(msg[1]) + if msgType == "ground": + self.display.setGround(msg[1]) + if msgType == "message": + self.log(*msg[1:]) + if msgType == "options": + if msg[1] != None: + description, options = msg[1] + self.log(description) + for option in options: + self.log(option) def log(self, text, type=None): diff --git a/asciifarm/client/layout.xml b/asciifarm/client/layout.xml index f945382..d50ecba 100644 --- a/asciifarm/client/layout.xml +++ b/asciifarm/client/layout.xml @@ -36,6 +36,9 @@ <log id="msg" align="bottom" height="20%%"> Welcome to asciifarm </log> - <field id="field" char-size="1"></field> + <overlay> + <fill id="fieldbackground" char=" "></fill> + <field id="field"></field> + </overlay> </vbox> </hbox> diff --git a/asciifarm/common/messages.py b/asciifarm/common/messages.py index 059094e..855fe1d 100644 --- a/asciifarm/common/messages.py +++ b/asciifarm/common/messages.py @@ -1,6 +1,7 @@ import re import unicodedata +import json class InvalidMessageError(Exception): errType = "invalidmessage" @@ -10,6 +11,9 @@ class InvalidMessageError(Exception): self.description = description if errType is not None: self.errType = errType + + def toMessage(self): + return ErrorMessage(self.errType, self.desctiption) class InvalidNameError(InvalidMessageError): errType = "invalidname" @@ -23,6 +27,9 @@ class Message: def to_json(self): raise NotImplementedError + def to_json_bytes(self): + return bytes(json.dumps(self.to_json()), "utf-8") + @classmethod def from_json(cls, jsonobj): raise NotImplementedError @@ -46,7 +53,6 @@ class ClientToServerMessage(Message): class NameMessage(ClientToServerMessage): typename = "name" - nameRegex = re.compile("(~|\w)\w*") categories = {"Lu", "Ll", "Lt", "Lm", "Lo", "Nd", "Nl", "No", "Pc"} @@ -57,9 +63,6 @@ class NameMessage(ClientToServerMessage): for char in name if name[0] != "~" else name[1:]: category = unicodedata.category(char) assert category in self.categories, InvalidNameError("all name caracters must be in these unicode categories: " + "|".join(self.categories) + " (except the tilde in a tildename)") - - #assert (name.rfind("~") < 1), InvalidNameError("tilde character may only occur at start of name") - #assert (self.nameRegex.match(name) is not None), InvalidNameError("name must match the following regex: {}".format(self.nameRegex.pattern)) self.name = name def body(self): @@ -90,9 +93,64 @@ class ChatMessage(ClientToServerMessage): +class ServerToClientMessage(Message): + msglen = 0 + + + @classmethod + def from_json(cls, jsonlist): + assert len(jsonlist) == cls.msglen, InvalidMessageError + assert jsonlist[0] == cls.msgType(), InvalidMessageError + return cls(*jsonlist[1:]) + + +class MessageMessage(ServerToClientMessage): # this name feels stupid + """ A message to inform the client. This is meant to be read by the user""" + + typename = "message" + msglen = 3 + + def __init__(self, text, type=""): + self.text = text + self.type = type + + def to_json(self): + return [self.typename, self.text, self.type] + + +class WorldMessage(ServerToClientMessage): + """ A message about the world state """ + + typename = "world" + msglen = 2 + + def __init__(self, updates): + assert isinstance(updates, list), InvalidMessageError + self.updates = updates + + def to_json(self): + return [self.typename, self.updates] + +class ErrorMessage(ServerToClientMessage): + + typename = "error" + msglen = 3 + + def __init__(self, errType, description=""): + self.errType = errType + self.description = description + + def to_json(self): + return [self.typename, self.errType, self.description] + + + messages = {message.msgType(): message for message in [ NameMessage, InputMessage, - ChatMessage + ChatMessage, + WorldMessage, + ErrorMessage, + MessageMessage ]} |
