1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
#! /usr/bin/python3
import os
import sys
import curses
import threading
import json
import getpass
import argparse
from .display.screen import Screen
import string
from .display import Display
class Client:
def __init__(self, stdscr, display, name, connection, keybindings, logFile=None):
self.stdscr = stdscr
self.display = display
self.name = name
self.keepalive = True
self.connection = connection
self.logFile = logFile
self.commands = {}
for key, commands in keybindings["input"].items():
if isinstance(commands[0], str):
commands = [commands]
self.commands[key] = [["input", command] for command in commands]
self.controlsString = "Controls:\n"+'\n'.join(
key + ": " + ', '.join(' '.join(action[1]) for action in actions)
for key, actions in self.commands.items()
if key in string.printable)
self.display.showInfo(self.controlsString)
def start(self):
threading.Thread(target=self.listen, daemon=True).start()
self.connection.send(json.dumps(["name", self.name]))
self.command_loop()
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)
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]
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 = msg[1]
if health:
self.display.setHealth(*health)
else:
self.log("You have died. Restart the client to respawn")
if msgType == "inventory":
self.display.setInventory(msg[1])
if msgType == "ground":
self.display.setGround(msg[1])
if msgType == "message":
self.log(msg[1])
self.display.update()
def log(self, text):
self.display.addMessage(text)
if self.logFile:
with(open(self.logFile, 'a')) as f:
f.write(text+'\n')
def command_loop(self):
while self.keepalive:
key = self.stdscr.getch()
if key == 27:
self.keepalive = False
return
try:
keyname = str(curses.keyname(key), "utf-8")
except ValueError:
continue
if keyname in self.commands:
self.connection.send(json.dumps(self.commands[keyname]))
|