Hints now contain ER info

This commit is contained in:
Fabian Dill 2020-05-18 05:40:36 +02:00
parent 11678fa20b
commit b2e20be077
5 changed files with 64 additions and 16 deletions

View File

@ -3957,3 +3957,11 @@ exit_ids = {'Links House Exit': (0x01, 0x00),
'Skull Woods First Section (Right)': 0x78, 'Skull Woods First Section (Right)': 0x78,
'Skull Woods First Section (Top)': 0x76, 'Skull Woods First Section (Top)': 0x76,
'Pyramid': 0x7B} 'Pyramid': 0x7B}
exit_id_to_name = {}
for name, addresses in exit_ids.items():
if type(addresses) == int:
exit_id_to_name[addresses] = name
else:
for address in addresses:
exit_id_to_name[address] = name

21
Main.py
View File

@ -236,6 +236,24 @@ def main(args, seed=None):
for future in futures: for future in futures:
rom_name = future.result() rom_name = future.result()
rom_names.append(rom_name) rom_names.append(rom_name)
def get_entrance_to_region(region: Region):
for entrance in region.entrances:
if entrance.parent_region.type in (RegionType.DarkWorld, RegionType.LightWorld):
return entrance
for entrance in region.entrances: # BFS might be better here, trying DFS for now.
return get_entrance_to_region(entrance.parent_region)
# collect ER hint info
er_hint_data = {player: {} for player in range(1, world.players + 1) if world.shuffle[player] != "vanilla"}
from Regions import RegionType
for region in world.regions:
if region.player in er_hint_data and region.locations:
main_entrance = get_entrance_to_region(region)
for location in region.locations:
if type(location.address) == int: # skips events and crystals
er_hint_data[region.player][location.address] = main_entrance.name
multidata = zlib.compress(json.dumps({"names": parsed_names, multidata = zlib.compress(json.dumps({"names": parsed_names,
"roms": rom_names, "roms": rom_names,
"remote_items": [player for player in range(1, world.players + 1) if "remote_items": [player for player in range(1, world.players + 1) if
@ -244,7 +262,8 @@ def main(args, seed=None):
(location.item.code, location.item.player)) (location.item.code, location.item.player))
for location in world.get_filled_locations() if for location in world.get_filled_locations() if
type(location.address) is int], type(location.address) is int],
"server_options": get_options()["server_options"] "server_options": get_options()["server_options"],
"er_hint_data": er_hint_data,
}).encode("utf-8"), 9) }).encode("utf-8"), 9)
if args.jsonout: if args.jsonout:
jsonout["multidata"] = list(multidata) jsonout["multidata"] = list(multidata)

View File

@ -764,9 +764,11 @@ async def process_server_cmd(ctx : Context, cmd, args):
'yellow' if hint.finding_player != ctx.slot else 'magenta') 'yellow' if hint.finding_player != ctx.slot else 'magenta')
player_recvd = color(ctx.player_names[hint.receiving_player], player_recvd = color(ctx.player_names[hint.receiving_player],
'yellow' if hint.receiving_player != ctx.slot else 'magenta') 'yellow' if hint.receiving_player != ctx.slot else 'magenta')
logging.info(f"[Hint]: {player_recvd}'s {item} can be found " text = f"[Hint]: {player_recvd}'s {item} can be found " \
f"at {get_location_name_from_address(hint.location)} in {player_find}'s World." + f"at {color(get_location_name_from_address(hint.location), 'blue_bg')} in {player_find}'s World"
(" (found)" if hint.found else "")) if hint.entrance:
text += " at " + color(hint.entrance, 'cyan_bg')
logging.info(text + (". (found)" if hint.found else "."))
elif cmd == "AliasUpdate": elif cmd == "AliasUpdate":
ctx.player_names = {p: n for p, n in args} ctx.player_names = {p: n for p, n in args}
elif cmd == 'Print': elif cmd == 'Print':

View File

@ -88,6 +88,7 @@ class Context:
self.running = True self.running = True
self.client_activity_timers = {} self.client_activity_timers = {}
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.commandprocessor = ServerCommandProcessor(self) self.commandprocessor = ServerCommandProcessor(self)
def get_save(self) -> dict: def get_save(self) -> dict:
@ -198,14 +199,14 @@ def notify_hints(ctx: Context, team: int, hints: typing.List[Utils.Hint]):
texts = [['Print', format_hint(ctx, team, hint)] for hint in hints] texts = [['Print', format_hint(ctx, team, hint)] for hint in hints]
for _, text in texts: for _, text in texts:
logging.info("Notice (Team #%d): %s" % (team + 1, text)) logging.info("Notice (Team #%d): %s" % (team + 1, text))
texts = json.dumps(texts)
for client in ctx.clients: for client in ctx.clients:
if client.auth and client.team == team: if client.auth and client.team == team:
if "Berserker" in client.tags: if "Berserker" in client.tags and client.version >= [2, 2, 1]:
payload = cmd payload = cmd
asyncio.create_task(send_json_msgs(client, payload))
else: else:
payload = texts payload = texts
asyncio.create_task(send_msgs(client, payload)) asyncio.create_task(send_json_msgs(client, payload))
def update_aliases(ctx: Context, team: int, client: typing.Optional[Client] = None): def update_aliases(ctx: Context, team: int, client: typing.Optional[Client] = None):
@ -383,7 +384,11 @@ def collect_hints(ctx: Context, team: int, slot: int, item: str) -> typing.List[
if receiving_player == slot and item_id == seeked_item_id: if receiving_player == slot and item_id == seeked_item_id:
location_id, finding_player = check location_id, finding_player = check
found = location_id in ctx.location_checks[team, finding_player] found = location_id in ctx.location_checks[team, finding_player]
hints.append(Utils.Hint(receiving_player, finding_player, location_id, item_id, found)) entrance = ""
if finding_player in ctx.er_hint_data:
if location_id in ctx.er_hint_data[finding_player]:
entrance = ctx.er_hint_data[finding_player][location_id]
hints.append(Utils.Hint(receiving_player, finding_player, location_id, item_id, found, entrance))
return hints return hints
@ -396,17 +401,24 @@ def collect_hints_location(ctx: Context, team: int, slot: int, location: str) ->
if finding_player == slot and location_id == seeked_location: if finding_player == slot and location_id == seeked_location:
item_id, receiving_player = result item_id, receiving_player = result
found = location_id in ctx.location_checks[team, finding_player] found = location_id in ctx.location_checks[team, finding_player]
hints.append(Utils.Hint(receiving_player, finding_player, location_id, item_id, found)) entrance = ""
break # each location has 1 item if finding_player in ctx.er_hint_data:
if location_id in ctx.er_hint_data[finding_player]:
entrance = ctx.er_hint_data[finding_player][location_id]
hints.append(Utils.Hint(receiving_player, finding_player, location_id, item_id, found, entrance))
break # each location has 1 item
return hints return hints
def format_hint(ctx: Context, team: int, hint: Utils.Hint) -> str: def format_hint(ctx: Context, team: int, hint: Utils.Hint) -> str:
return f"[Hint]: {ctx.player_names[team, hint.receiving_player]}'s " \ text = f"[Hint]: {ctx.player_names[team, hint.receiving_player]}'s " \
f"{Items.lookup_id_to_name[hint.item]} can be found " \ f"{Items.lookup_id_to_name[hint.item]} can be found " \
f"at {get_location_name_from_address(hint.location)} " \ f"at {get_location_name_from_address(hint.location)} " \
f"in {ctx.player_names[team, hint.finding_player]}'s World." \ f"in {ctx.player_names[team, hint.finding_player]}'s World"
+ (" (found)" if hint.found else "")
if hint.entrance:
text += f" at {hint.entrance}"
return text + (". (found)" if hint.found else ".")
def get_intended_text(input_text: str, possible_answers: typing.Iterable[str]= console_names) -> typing.Tuple[str, bool, str]: def get_intended_text(input_text: str, possible_answers: typing.Iterable[str]= console_names) -> typing.Tuple[str, bool, str]:
@ -1051,6 +1063,9 @@ async def main(args: argparse.Namespace):
ctx.rom_names = {tuple(rom): (team, slot) for slot, team, rom in jsonobj['roms']} ctx.rom_names = {tuple(rom): (team, slot) for slot, team, rom in jsonobj['roms']}
ctx.remote_items = set(jsonobj['remote_items']) ctx.remote_items = set(jsonobj['remote_items'])
ctx.locations = {tuple(k): tuple(v) for k, v in jsonobj['locations']} 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 return

View File

@ -1,6 +1,6 @@
from __future__ import annotations from __future__ import annotations
__version__ = "2.2.0" __version__ = "2.2.1"
_version_tuple = tuple(int(piece, 10) for piece in __version__.split(".")) _version_tuple = tuple(int(piece, 10) for piece in __version__.split("."))
import os import os
@ -159,17 +159,21 @@ class Hint(typing.NamedTuple):
location: int location: int
item: int item: int
found: bool found: bool
entrance: str = ""
def re_check(self, ctx, team) -> Hint: def re_check(self, ctx, team) -> Hint:
if self.found: if self.found:
return self return self
found = self.location in ctx.location_checks[team, self.finding_player] found = self.location in ctx.location_checks[team, self.finding_player]
if found: if found:
return Hint(self.receiving_player, self.finding_player, self.location, self.item, found) return Hint(self.receiving_player, self.finding_player, self.location, self.item, found, self.entrance)
return self return self
def as_legacy(self) -> tuple:
return self.receiving_player, self.finding_player, self.location, self.item, self.found
def __hash__(self): def __hash__(self):
return hash((self.receiving_player, self.finding_player, self.location, self.item)) return hash((self.receiving_player, self.finding_player, self.location, self.item, self.entrance))
def get_public_ipv4() -> str: def get_public_ipv4() -> str:
import socket import socket