2017-10-15 21:30:31 +00:00
|
|
|
#! /usr/bin/python3
|
|
|
|
|
2017-10-20 14:59:15 +00:00
|
|
|
import os
|
2017-10-15 21:30:31 +00:00
|
|
|
import sys
|
|
|
|
|
|
|
|
import curses
|
|
|
|
import threading
|
|
|
|
import json
|
|
|
|
import getpass
|
|
|
|
import argparse
|
2017-10-26 08:30:51 +00:00
|
|
|
from .display.screen import Screen
|
2017-10-19 10:23:26 +00:00
|
|
|
import string
|
2017-12-28 21:47:36 +00:00
|
|
|
from .display.display import Display
|
2017-10-15 21:30:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Client:
|
|
|
|
|
2017-10-29 14:11:47 +00:00
|
|
|
def __init__(self, stdscr, display, name, connection, keybindings, logFile=None):
|
2017-10-15 21:30:31 +00:00
|
|
|
self.stdscr = stdscr
|
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
|
2017-10-17 09:08:34 +00:00
|
|
|
self.connection = connection
|
2017-10-29 14:11:47 +00:00
|
|
|
self.logFile = logFile
|
2017-10-15 21:30:31 +00:00
|
|
|
|
2017-10-27 14:43:15 +00:00
|
|
|
self.commands = {}
|
2017-12-28 21:47:36 +00:00
|
|
|
if "input" in keybindings:
|
|
|
|
for key, commands in keybindings["input"].items():
|
|
|
|
if isinstance(commands[0], str):
|
|
|
|
commands = [commands]
|
|
|
|
self.commands[key] = [("send", ["input", command]) for command in commands]
|
|
|
|
if "control" in keybindings:
|
|
|
|
for key, commands in keybindings["control"].items():
|
|
|
|
if isinstance(commands[0], str):
|
|
|
|
commands = [commands]
|
|
|
|
self.commands[key] = commands
|
2017-10-19 10:23:26 +00:00
|
|
|
|
2017-12-28 21:47:36 +00:00
|
|
|
self.controlsString = """\
|
|
|
|
Default Controls:
|
|
|
|
wasd or arrows:
|
|
|
|
Move around
|
|
|
|
e: Grab
|
|
|
|
q: Drop
|
|
|
|
E: Use
|
|
|
|
r: Interact
|
|
|
|
f: Attack
|
|
|
|
t: Chat"""
|
2017-10-23 20:38:40 +00:00
|
|
|
|
2017-10-26 16:47:26 +00:00
|
|
|
self.display.showInfo(self.controlsString)
|
|
|
|
|
2017-12-28 21:47:36 +00:00
|
|
|
self.actions = {
|
|
|
|
"send": (lambda data: self.connection.send(json.dumps(data))),
|
|
|
|
"text": (lambda: self.readString())
|
|
|
|
}
|
2017-10-25 07:48:41 +00:00
|
|
|
|
2017-10-26 10:24:58 +00:00
|
|
|
|
2017-12-28 21:47:36 +00:00
|
|
|
def readString(self):
|
|
|
|
text = self.display.getString()
|
|
|
|
string = str(text, "utf-8")
|
|
|
|
if string:
|
|
|
|
self.connection.send(json.dumps(["input", ["say", string]]))
|
|
|
|
|
2017-10-26 10:24:58 +00:00
|
|
|
def start(self):
|
2017-10-15 21:30:31 +00:00
|
|
|
threading.Thread(target=self.listen, daemon=True).start()
|
2017-10-26 10:24:58 +00:00
|
|
|
self.connection.send(json.dumps(["name", self.name]))
|
2017-10-15 21:30:31 +00:00
|
|
|
self.command_loop()
|
2017-10-23 20:38:40 +00:00
|
|
|
|
2017-10-15 21:30:31 +00:00
|
|
|
|
|
|
|
def listen(self):
|
|
|
|
self.connection.listen(self.update, self.close)
|
|
|
|
|
|
|
|
def close(self, err=None):
|
|
|
|
self.keepalive = False
|
|
|
|
sys.exit()
|
|
|
|
|
|
|
|
|
|
|
|
def update(self, databytes):
|
|
|
|
if not self.keepalive:
|
|
|
|
sys.exit()
|
|
|
|
datastr = databytes.decode('utf-8')
|
|
|
|
data = json.loads(datastr)
|
2017-10-25 09:08:16 +00:00
|
|
|
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":
|
|
|
|
print("error: name is already taken", file=sys.stderr)
|
|
|
|
self.close()
|
|
|
|
if msgType == 'field':
|
|
|
|
field = msg[1]
|
2017-10-26 09:03:59 +00:00
|
|
|
fieldWidth = field['width']
|
|
|
|
fieldHeight = field['height']
|
2017-10-27 10:38:23 +00:00
|
|
|
self.display.resizeField((fieldWidth, fieldHeight))
|
2017-10-25 09:08:16 +00:00
|
|
|
fieldCells = field['field']
|
|
|
|
mapping = field['mapping']
|
2017-10-26 09:03:59 +00:00
|
|
|
self.display.drawFieldCells(
|
|
|
|
(tuple(reversed(divmod(i, fieldWidth))),
|
|
|
|
mapping[spr])
|
|
|
|
for i, spr in enumerate(fieldCells))
|
2017-10-25 09:08:16 +00:00
|
|
|
|
|
|
|
if msgType == 'changecells'and len(msg[1]):
|
2017-10-26 09:03:59 +00:00
|
|
|
self.display.drawFieldCells(msg[1])
|
2017-10-25 09:08:16 +00:00
|
|
|
|
2017-10-26 09:37:57 +00:00
|
|
|
if msgType == "playerpos":
|
|
|
|
self.display.setFieldCenter(msg[1])
|
|
|
|
|
2017-10-25 09:08:16 +00:00
|
|
|
if msgType == "health":
|
2017-10-27 09:39:41 +00:00
|
|
|
health = msg[1]
|
|
|
|
if health:
|
|
|
|
self.display.setHealth(*health)
|
2017-10-29 22:26:12 +00:00
|
|
|
else:
|
|
|
|
self.log("You have died. Restart the client to respawn")
|
2017-10-25 09:08:16 +00:00
|
|
|
if msgType == "inventory":
|
2017-10-26 16:47:26 +00:00
|
|
|
self.display.setInventory(msg[1])
|
2017-10-25 09:08:16 +00:00
|
|
|
if msgType == "ground":
|
2017-10-26 16:47:26 +00:00
|
|
|
self.display.setGround(msg[1])
|
2017-10-29 14:01:47 +00:00
|
|
|
if msgType == "message":
|
2017-10-29 22:26:12 +00:00
|
|
|
self.log(msg[1])
|
2017-10-19 10:23:26 +00:00
|
|
|
|
2017-10-26 09:03:59 +00:00
|
|
|
|
|
|
|
self.display.update()
|
2017-10-25 13:50:24 +00:00
|
|
|
|
2017-10-29 22:26:12 +00:00
|
|
|
def log(self, text):
|
|
|
|
self.display.addMessage(text)
|
|
|
|
if self.logFile:
|
|
|
|
with(open(self.logFile, 'a')) as f:
|
|
|
|
f.write(text+'\n')
|
|
|
|
|
2017-10-15 21:30:31 +00:00
|
|
|
def command_loop(self):
|
|
|
|
while self.keepalive:
|
|
|
|
key = self.stdscr.getch()
|
|
|
|
if key == 27:
|
|
|
|
self.keepalive = False
|
2017-11-13 10:57:00 +00:00
|
|
|
return
|
2017-11-13 13:15:04 +00:00
|
|
|
try:
|
|
|
|
keyname = str(curses.keyname(key), "utf-8")
|
|
|
|
except ValueError:
|
|
|
|
continue
|
2017-11-13 10:57:00 +00:00
|
|
|
if keyname in self.commands:
|
2017-12-28 21:47:36 +00:00
|
|
|
for command, *data in self.commands[keyname]:
|
|
|
|
self.actions[command](*data)
|
2017-10-19 10:23:26 +00:00
|
|
|
|
2017-10-15 21:30:31 +00:00
|
|
|
|
2017-10-20 15:02:05 +00:00
|
|
|
|
2017-10-15 21:30:31 +00:00
|
|
|
|