Merge branch 'master' of https://github.com/Berserker66/MultiWorld-Utilities
This commit is contained in:
commit
3448437815
|
@ -27,7 +27,7 @@ import Utils
|
||||||
from Utils import get_item_name_from_id, get_location_name_from_address, ReceivedItem
|
from Utils import get_item_name_from_id, get_location_name_from_address, ReceivedItem
|
||||||
from NetUtils import Node, Endpoint
|
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_PLAYING = 0
|
||||||
CLIENT_GOAL = 1
|
CLIENT_GOAL = 1
|
||||||
|
@ -61,7 +61,7 @@ class Context(Node):
|
||||||
super(Context, self).__init__()
|
super(Context, self).__init__()
|
||||||
self.data_filename = None
|
self.data_filename = None
|
||||||
self.save_filename = None
|
self.save_filename = None
|
||||||
self.disable_save = False
|
self.saving = False
|
||||||
self.player_names = {}
|
self.player_names = {}
|
||||||
self.rom_names = {}
|
self.rom_names = {}
|
||||||
self.remote_items = set()
|
self.remote_items = set()
|
||||||
|
@ -82,12 +82,46 @@ class Context(Node):
|
||||||
self.remaining_mode: str = remaining_mode
|
self.remaining_mode: str = remaining_mode
|
||||||
self.item_cheat = item_cheat
|
self.item_cheat = item_cheat
|
||||||
self.running = True
|
self.running = True
|
||||||
self.client_activity_timers: typing.Dict[typing.Tuple[int, int], datetime.datetime] = {} # datatime of last new item check
|
self.client_activity_timers: typing.Dict[
|
||||||
self.client_connection_timers: typing.Dict[typing.Tuple[int, int], datetime.datetime] = {} # datetime of last connection
|
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.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.er_hint_data: typing.Dict[int, typing.Dict[int, str]] = {}
|
||||||
self.commandprocessor = ServerCommandProcessor(self)
|
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:
|
def get_save(self) -> dict:
|
||||||
d = {
|
d = {
|
||||||
"rom_names": list(self.rom_names.items()),
|
"rom_names": list(self.rom_names.items()),
|
||||||
|
@ -361,7 +395,7 @@ def notify_team(ctx: Context, team: int, text: str):
|
||||||
|
|
||||||
|
|
||||||
def save(ctx: Context):
|
def save(ctx: Context):
|
||||||
if not ctx.disable_save:
|
if ctx.saving:
|
||||||
try:
|
try:
|
||||||
jsonstr = json.dumps(ctx.get_save())
|
jsonstr = json.dumps(ctx.get_save())
|
||||||
with open(ctx.save_filename, "wb") as f:
|
with open(ctx.save_filename, "wb") as f:
|
||||||
|
@ -668,6 +702,10 @@ class ClientMessageProcessor(CommandProcessor):
|
||||||
if item_name in Items.hint_blacklist:
|
if item_name in Items.hint_blacklist:
|
||||||
self.output(f"Sorry, \"{item_name}\" is marked as non-hintable.")
|
self.output(f"Sorry, \"{item_name}\" is marked as non-hintable.")
|
||||||
hints = []
|
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
|
elif item_name in Items.item_table: # item name
|
||||||
hints = collect_hints(self.ctx, self.client.team, self.client.slot, item_name)
|
hints = collect_hints(self.ctx, self.client.team, self.client.slot, item_name)
|
||||||
else: # location name
|
else: # location name
|
||||||
|
@ -929,12 +967,15 @@ class ServerCommandProcessor(CommandProcessor):
|
||||||
item = " ".join(item_or_location)
|
item = " ".join(item_or_location)
|
||||||
item, usable, response = get_intended_text(item)
|
item, usable, response = get_intended_text(item)
|
||||||
if usable:
|
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)
|
hints = collect_hints(self.ctx, team, slot, item)
|
||||||
notify_hints(self.ctx, team, hints)
|
|
||||||
else: # location name
|
else: # location name
|
||||||
hints = collect_hints_location(self.ctx, team, slot, item)
|
hints = collect_hints_location(self.ctx, team, slot, item)
|
||||||
notify_hints(self.ctx, team, hints)
|
notify_hints(self.ctx, team, hints)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
self.output(response)
|
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,
|
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)
|
not args.disable_item_cheat, args.forfeit_mode, args.remaining_mode)
|
||||||
|
|
||||||
ctx.data_filename = args.multidata
|
data_filename = args.multidata
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not ctx.data_filename:
|
if not data_filename:
|
||||||
import tkinter
|
import tkinter
|
||||||
import tkinter.filedialog
|
import tkinter.filedialog
|
||||||
root = tkinter.Tk()
|
root = tkinter.Tk()
|
||||||
root.withdraw()
|
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:
|
except Exception as e:
|
||||||
logging.exception('Failed to read multiworld data (%s)' % e)
|
logging.exception('Failed to read multiworld data (%s)' % e)
|
||||||
return
|
raise
|
||||||
|
|
||||||
ip = args.host if args.host else Utils.get_public_ipv4()
|
ctx.init_save(not args.disable_save)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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.server = websockets.serve(functools.partial(server, ctx=ctx), ctx.host, ctx.port, ping_timeout=None,
|
ctx.server = websockets.serve(functools.partial(server, ctx=ctx), ctx.host, ctx.port, ping_timeout=None,
|
||||||
ping_interval=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,
|
logging.info('Hosting game at %s:%d (%s)' % (ip, ctx.port,
|
||||||
'No password' if not ctx.password else 'Password: %s' % ctx.password))
|
'No password' if not ctx.password else 'Password: %s' % ctx.password))
|
||||||
await ctx.server
|
await ctx.server
|
||||||
|
|
Loading…
Reference in New Issue