Asciifarm/asciifarm/client/gameclient.py

158 lines
4.8 KiB
Python
Raw Normal View History

2019-09-17 22:32:35 +00:00
2017-10-15 21:30:31 +00:00
import os
2017-10-15 21:30:31 +00:00
import sys
import threading
import json
import getpass
import argparse
2017-10-19 10:23:26 +00:00
import string
from queue import Queue
2019-09-17 22:32:35 +00:00
import ratuil.inputs
2017-10-15 21:30:31 +00:00
from .inputhandler import InputHandler
2017-10-15 21:30:31 +00:00
class Client:
2019-09-17 22:32:35 +00:00
def __init__(self, display, name, connection, keybindings, logFile=None):
2019-09-18 10:07:58 +00:00
2017-10-26 10:43:46 +00:00
self.display = display
2017-10-15 21:30:31 +00:00
self.name = name
self.keepalive = True
self.connection = connection
2017-10-29 14:11:47 +00:00
self.logFile = logFile
self.closeMessage = None
2017-10-15 21:30:31 +00:00
self.inputHandler = InputHandler(self, keybindings["actions"])
self.controlsString = keybindings.get("help", "")
2017-10-23 20:38:40 +00:00
self.display.showInfo(self.controlsString)
self.queue = Queue()
def send(self, data):
text = json.dumps(data)
self.connection.send(text)
def start(self):
2017-10-15 21:30:31 +00:00
threading.Thread(target=self.listen, daemon=True).start()
threading.Thread(target=self.getInput, daemon=True).start()
self.connection.send(json.dumps(["name", self.name]))
2017-10-15 21:30:31 +00:00
self.command_loop()
def listen(self):
self.connection.listen(self.pushMessage, self.onConnectionError)
def pushMessage(self, databytes):
self.queue.put(("message", databytes))
def onConnectionError(self, error):
self.queue.put(("error", error))
2017-10-15 21:30:31 +00:00
def getInput(self):
while True:
2019-09-17 22:32:35 +00:00
key = ratuil.inputs.get_key()
self.queue.put(("input", key))
def close(self, msg=None):
2017-10-15 21:30:31 +00:00
self.keepalive = False
self.closeMessage = msg
2017-10-15 21:30:31 +00:00
def update(self, databytes):
if len(databytes) == 0:
self.close("Connection closed by server")
return
2017-10-15 21:30:31 +00:00
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
2018-01-10 16:18:29 +00:00
if error == "invalidname":
self.close("error: "+ msg[2])
2018-01-10 16:18:29 +00:00
return
self.log(error)
if msgType == 'field':
field = msg[1]
2017-10-26 09:03:59 +00:00
fieldWidth = field['width']
fieldHeight = field['height']
self.display.resizeField((fieldWidth, fieldHeight))
fieldCells = field['field']
mapping = field['mapping']
2017-10-26 09:03:59 +00:00
self.display.drawFieldCells(
2019-09-16 19:38:57 +00:00
(
tuple(reversed(divmod(i, fieldWidth))),
mapping[spr]
)
2017-10-26 09:03:59 +00:00
for i, spr in enumerate(fieldCells))
if msgType == 'changecells' and len(msg[1]):
2017-10-26 09:03:59 +00:00
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])
2017-12-30 11:49:28 +00:00
if msgType == "equipment":
self.display.setEquipment(msg[1])
if msgType == "ground":
self.display.setGround(msg[1])
2017-10-29 14:01:47 +00:00
if msgType == "message":
self.log(*msg[1:])
2018-07-28 14:22:02 +00:00
if msgType == "options":
if msg[1] != None:
description, options = msg[1]
self.log(description)
for option in options:
self.log(option)
2017-10-19 10:23:26 +00:00
2019-01-20 00:19:24 +00:00
def log(self, text, type=None):
if not isinstance(text, str):
text = str(text)
2019-01-20 00:19:24 +00:00
self.display.addMessage(text, type)
if self.logFile:
with(open(self.logFile, 'a')) as f:
2019-01-20 00:19:24 +00:00
f.write("[{}] {}\n".format(type or "", text))
2017-10-15 21:30:31 +00:00
def command_loop(self):
while self.keepalive:
self.display.update()
action = self.queue.get()
if action[0] == "message":
self.update(action[1])
elif action[0] == "input":
2019-09-17 22:32:35 +00:00
if action[1] == "^C":
raise KeyboardInterrupt
self.inputHandler.onInput(action[1])
elif action[0] == "error":
raise action[1]
2019-09-17 22:32:35 +00:00
elif action[0] == "sigwinch":
self.display.update_size()
else:
raise Exception("invalid action in queue")
2017-10-19 10:23:26 +00:00
2019-09-17 22:32:35 +00:00
def onSigwinch(self, signum, frame):
self.queue.put(("sigwinch", (signum, frame)))
2017-10-15 21:30:31 +00:00
2017-10-15 21:30:31 +00:00