Created
November 24, 2021 22:25
-
-
Save Pinacolada64/b3c747d456c4ebfa4278f400d3f28941 to your computer and use it in GitHub Desktop.
Trying to update `net_server.py` to read json files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/env python3 | |
import socketserver | |
import json | |
from dataclasses import dataclass, field | |
import enum | |
import net_common as nc | |
class Map(object): | |
# added this from read_map_2.py | |
def __init__(self): | |
"""dict Room{name: str, alignment: str, items: list, desc: str}""" | |
self.rooms = {} | |
def read_map(self, filename: str): | |
""" | |
Data format on C64: | |
* Room number (rm) | |
* Location name (lo$) | |
* items: monster, item, weapon, food | |
* exits: north, east, south, west, | |
RC (room command: 1=move up, | |
2=move down), | |
RT (Room exit transports you to: | |
room #, or 0=Shoppe) | |
https://github.com/Pinacolada64/TADA-old/blob/master/text/s_t_level-1-data.txt | |
""" | |
with open(filename) as jsonF: | |
map_data = json.load(jsonF) | |
for room_data in map_data['rooms']: | |
room = Room(**room_data) | |
self.rooms[room.number] = room | |
K = nc.K # net_common.K? | |
Mode = nc.Mode | |
""" | |
# fake data | |
# TODO: switch over to reading "map_1.json" | |
roomsData = { | |
'ul': {K.name: 'Upper Left', K.exits: {'s': 'll', 'e': 'ur'}}, | |
'ur': {K.name: 'Upper Right', K.exits: {'s': 'lr', 'w': 'ul'}}, | |
'll': {K.name: 'Lower Left', K.exits: {'n': 'ul', 'e': 'lr'}}, | |
'lr': {K.name: 'Lower Right', K.exits: {'n': 'ur', 'w': 'll'}}, | |
} | |
""" | |
usersData = { | |
'ryan': {K.password: 'swordfish', K.money: 1000, K.room: 'ul', | |
K.health: 100, K.xp: 0}, | |
'core': {K.password: 'joshua', K.money: 10, K.room: 'ul', | |
K.health: 99, K.xp: 0}, | |
} | |
compass_txts = {'n': 'North', 'e': 'East', 's': 'South', 'w': 'West'} | |
@dataclass | |
class Room(object): | |
name: str | |
exits: dict | |
def exitsTxt(self): | |
exit_txts = [] | |
for k in self.exits.keys(): | |
if k in compass_txts: exit_txts.append(compass_txts[k]) | |
return ", ".join(exit_txts) | |
@dataclass | |
class User(object): | |
name: str | |
password: str | |
money: int | |
room: str | |
health: int | |
xp: int | |
@dataclass | |
class Message(object): | |
lines: list | |
mode: Mode = Mode.cmd | |
changes: dict = field(default_factory=lambda: {}) | |
error: int = 0 | |
error_line: str = '' | |
rooms = {} | |
for id, info in game_map.rooms.items(): | |
room = Room(name=info[K.name], exits=info[K.exits]) | |
rooms[id] = room | |
users = {} | |
for name, info in usersData.items(): | |
user = User(name=name, password=info[K.password], money=info[K.money], | |
room=info[K.room], health=info[K.health], xp=info[K.xp]) | |
users[name] = user | |
class PlayerServer(socketserver.BaseRequestHandler): | |
def handle(self): | |
self.sender = f"{self.client_address[0]}:{self.client_address[1]}" | |
self.ready = None | |
self.user = None | |
print(f"connect (addr={self.sender})") | |
running = True | |
while running: | |
try: | |
request = nc.fromJSONB(self.request.recv(1024)) | |
if request is None: | |
running = False | |
break | |
try: | |
response = self.processMessage(request) | |
except Exception as e: | |
print(e) | |
self.sendData(Message(lines=["server side error"], error=1)) | |
if response is None: | |
running = False | |
else: | |
self.sendData(response) | |
except: | |
logging.warning("ignore malformed JSON") | |
self.sendData(Message(lines=["malformed JSON"], error=1)) | |
logging.info(f"disconnect {self.user.name} (addr={self.sender})") | |
def sendData(self, data): | |
self.request.sendall(nc.toJSONB(data)) | |
def roomMsg(self, lines=[], changes={}): | |
room = rooms[self.user.room] | |
room_name = room.name | |
exitsTxt = room.exitsTxt() | |
lines2 = list(lines) | |
lines2.append(f"You are in {room_name} with exits to {exitsTxt}") | |
return Message(lines=lines2, changes=changes) | |
def processMessage(self, data): | |
if self.ready is None: # assume init message | |
app = data.get('app') | |
if app == nc.app: | |
key = data.get('key') | |
if key == nc.key: | |
# TODO: handle protocol difference | |
self.ready = True | |
return Message(lines=['Welcome to TADA!', 'Please log in.'], mode=Mode.login) | |
else: | |
return None # poser, ignore them | |
else: | |
return None # poser, ignore them | |
if self.user is None: | |
user_id, password = data['login'] | |
if user_id not in users: | |
# TODO: check password | |
# when failing don't tell that have wrong user id | |
return Message(error_line='Login failed.', error=1, | |
lines=['Please try again.'], mode=Mode.login) | |
else: | |
self.user = users[user_id] | |
print(f"login {self.user.name} (addr={self.sender})") | |
money = self.user.money | |
lines = [f"Welcome {self.user.name}.", f"You have {money} gold."] | |
changes = {K.room_name: rooms[self.user.room].name, | |
K.money: money, K.health: self.user.health, | |
K.xp: self.user.xp} | |
return self.roomMsg(lines, changes) | |
if 'cmd' in data: | |
cmd = data['cmd'].split(' ') | |
# TODO: handle all commands (would be more sophisticated, e.g. proper parser) | |
if cmd[0] in compass_txts: cmd.insert(0, 'go') | |
print(f"{cmd}") | |
if cmd[0] in ['g', 'go']: | |
direction = cmd[1] | |
room = rooms[self.user.room] | |
if direction in room.exits: | |
self.user.room = room.exits[direction] | |
room_name = rooms[self.user.room].name | |
return self.roomMsg(changes={'room_name': room_name}) | |
else: | |
return Message(lines=["You cannot go that direction."]) | |
if cmd[0] in ['look']: | |
return self.roomMsg() | |
if cmd[0] in ['bye', 'logout']: | |
return Message(lines=["Bye for now."], mode=Mode.bye) | |
if cmd[0] in ['help', 'cheatcode']: | |
return Message(lines=["Wouldn't that be nice."]) | |
else: | |
return Message(lines=["I didn't understand that. Try something else."]) | |
def startServer(host, port): | |
with socketserver.TCPServer((host, port), PlayerServer) as server: | |
print(f"server running ({host=}, {port=})") | |
server.serve_forever() | |
if __name__ == "__main__": | |
# FIXME: code never seems to reach here? I don't see a log message... | |
import textwrap | |
import logging | |
logging.basicConfig(level=logging.DEBUG, format='[%(levelname)s] | %(message)s') | |
# load map | |
logging.info(f'Loading map "level_1.json"') | |
game_map = Map() | |
game_map.read_map("level_1.json") | |
# print rooms | |
wrapper = textwrap.TextWrapper(width=80) | |
for number, room in game_map.rooms.items(): | |
logging.info(f"#{number} - {room.name}\n") | |
logging.info(f'{monster=} {item=} {weapon=} {food=}') | |
logging.info(wrapper.fill(text=room.desc)) | |
exits_txt = room.exitsTxt() | |
if exits_txt is not None: | |
print(f"exits: {exits_txt}") | |
# except IOError as e: | |
# logging.info(f'{e}') | |
host = "localhost" | |
startServer(host, nc.serverPort) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment