summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortroido <troido@protonmail.com>2019-09-26 20:19:26 +0200
committertroido <troido@protonmail.com>2019-09-26 20:19:26 +0200
commit548aa5ef6a128ff561c09849e07047a978fc1c5b (patch)
treefe119adfbaa58861e7ba8e74492bef91f0883989
parent41ccee19d4522ae8f5eb0abdb4b9a67f0f415d69 (diff)
made server -> client messages into objects; clear field when entering different room
-rw-r--r--asciifarm/client/connection.py2
-rw-r--r--asciifarm/client/display.py1
-rw-r--r--asciifarm/client/gameclient.py118
-rw-r--r--asciifarm/client/layout.xml5
-rw-r--r--asciifarm/common/messages.py68
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
]}