This commit is contained in:
Chris 2020-06-06 19:58:43 -04:00
commit 3448437815
1 changed files with 57 additions and 40 deletions

View File

@ -27,7 +27,7 @@ import Utils
from Utils import get_item_name_from_id, get_location_name_from_address, ReceivedItem
from NetUtils import Node, Endpoint
console_names = frozenset(set(Items.item_table) | set(Regions.location_table))
console_names = frozenset(set(Items.item_table) | set(Regions.location_table) | set(Items.item_name_groups))
CLIENT_PLAYING = 0
CLIENT_GOAL = 1
@ -61,7 +61,7 @@ class Context(Node):
super(Context, self).__init__()
self.data_filename = None
self.save_filename = None
self.disable_save = False
self.saving = False
self.player_names = {}
self.rom_names = {}
self.remote_items = set()
@ -82,12 +82,46 @@ class Context(Node):
self.remaining_mode: str = remaining_mode
self.item_cheat = item_cheat
self.running = True
self.client_activity_timers: typing.Dict[typing.Tuple[int, int], datetime.datetime] = {} # datatime of last new item check
self.client_connection_timers: typing.Dict[typing.Tuple[int, int], datetime.datetime] = {} # datetime of last connection
self.client_activity_timers: typing.Dict[
typing.Tuple[int, int], datetime.datetime] = {} # datatime of last new item check
self.client_connection_timers: typing.Dict[
typing.Tuple[int, int], datetime.datetime] = {} # datetime of last connection
self.client_game_state: typing.Dict[typing.Tuple[int, int], int] = collections.defaultdict(int)
self.er_hint_data: typing.Dict[int, typing.Dict[int, str]] = {}
self.commandprocessor = ServerCommandProcessor(self)
def load(self, multidatapath: str):
with open(multidatapath, 'rb') as f:
self._load(f)
self.data_filename = multidatapath
def _load(self, fileobj):
jsonobj = json.loads(zlib.decompress(fileobj.read()).decode("utf-8-sig"))
for team, names in enumerate(jsonobj['names']):
for player, name in enumerate(names, 1):
self.player_names[(team, player)] = name
self.rom_names = {tuple(rom): (team, slot) for slot, team, rom in jsonobj['roms']}
self.remote_items = set(jsonobj['remote_items'])
self.locations = {tuple(k): tuple(v) for k, v in jsonobj['locations']}
if "er_hint_data" in jsonobj:
self.er_hint_data = {int(player): {int(address): name for address, name in loc_data.items()}
for player, loc_data in jsonobj["er_hint_data"].items()}
def init_save(self, enabled: bool):
self.saving = enabled
if self.saving:
if not self.save_filename:
self.save_filename = (self.data_filename[:-9] if self.data_filename[-9:] == 'multidata' else (
self.data_filename + '_')) + 'multisave'
try:
with open(self.save_filename, 'rb') as f:
jsonobj = json.loads(zlib.decompress(f.read()).decode("utf-8"))
self.set_save(jsonobj)
except FileNotFoundError:
logging.error('No save data found, starting a new game')
except Exception as e:
logging.exception(e)
def get_save(self) -> dict:
d = {
"rom_names": list(self.rom_names.items()),
@ -361,7 +395,7 @@ def notify_team(ctx: Context, team: int, text: str):
def save(ctx: Context):
if not ctx.disable_save:
if ctx.saving:
try:
jsonstr = json.dumps(ctx.get_save())
with open(ctx.save_filename, "wb") as f:
@ -668,6 +702,10 @@ class ClientMessageProcessor(CommandProcessor):
if item_name in Items.hint_blacklist:
self.output(f"Sorry, \"{item_name}\" is marked as non-hintable.")
hints = []
elif item_name in Items.item_name_groups:
hints = []
for item in Items.item_name_groups[item_name]:
hints.extend(collect_hints(self.ctx, self.client.team, self.client.slot, item))
elif item_name in Items.item_table: # item name
hints = collect_hints(self.ctx, self.client.team, self.client.slot, item_name)
else: # location name
@ -929,12 +967,15 @@ class ServerCommandProcessor(CommandProcessor):
item = " ".join(item_or_location)
item, usable, response = get_intended_text(item)
if usable:
if item in Items.item_table: # item name
if item in Items.item_name_groups:
hints = []
for item in Items.item_name_groups[item]:
hints.extend(collect_hints(self.ctx, team, slot, item))
elif item in Items.item_table: # item name
hints = collect_hints(self.ctx, team, slot, item)
notify_hints(self.ctx, team, hints)
else: # location name
hints = collect_hints_location(self.ctx, team, slot, item)
notify_hints(self.ctx, team, hints)
notify_hints(self.ctx, team, hints)
return True
else:
self.output(response)
@ -997,51 +1038,27 @@ async def main(args: argparse.Namespace):
ctx = Context(args.host, args.port, args.password, args.location_check_points, args.hint_cost,
not args.disable_item_cheat, args.forfeit_mode, args.remaining_mode)
ctx.data_filename = args.multidata
data_filename = args.multidata
try:
if not ctx.data_filename:
if not data_filename:
import tkinter
import tkinter.filedialog
root = tkinter.Tk()
root.withdraw()
ctx.data_filename = tkinter.filedialog.askopenfilename(filetypes=(("Multiworld data","*multidata"),))
data_filename = tkinter.filedialog.askopenfilename(filetypes=(("Multiworld data", "*multidata"),))
ctx.load(data_filename)
with open(ctx.data_filename, 'rb') as f:
jsonobj = json.loads(zlib.decompress(f.read()).decode("utf-8-sig"))
for team, names in enumerate(jsonobj['names']):
for player, name in enumerate(names, 1):
ctx.player_names[(team, player)] = name
ctx.rom_names = {tuple(rom): (team, slot) for slot, team, rom in jsonobj['roms']}
ctx.remote_items = set(jsonobj['remote_items'])
ctx.locations = {tuple(k): tuple(v) for k, v in jsonobj['locations']}
if "er_hint_data" in jsonobj:
ctx.er_hint_data = {int(player): {int(address): name for address, name in loc_data.items()}
for player, loc_data in jsonobj["er_hint_data"].items()}
except Exception as e:
logging.exception('Failed to read multiworld data (%s)' % e)
return
raise
ip = args.host if args.host else Utils.get_public_ipv4()
ctx.disable_save = args.disable_save
if not ctx.disable_save:
if not ctx.save_filename:
ctx.save_filename = (ctx.data_filename[:-9] if ctx.data_filename[-9:] == 'multidata' else (
ctx.data_filename + '_')) + 'multisave'
try:
with open(ctx.save_filename, 'rb') as f:
jsonobj = json.loads(zlib.decompress(f.read()).decode("utf-8"))
ctx.set_save(jsonobj)
except FileNotFoundError:
logging.error('No save data found, starting a new game')
except Exception as e:
logging.exception(e)
ctx.init_save(not args.disable_save)
ctx.server = websockets.serve(functools.partial(server, ctx=ctx), ctx.host, ctx.port, ping_timeout=None,
ping_interval=None)
ip = args.host if args.host else Utils.get_public_ipv4()
logging.info('Hosting game at %s:%d (%s)' % (ip, ctx.port,
'No password' if not ctx.password else 'Password: %s' % ctx.password))
await ctx.server