Skip to content

Commit

Permalink
Change 'priority' to 'status', add 'Unspecified' and 'Avoid' statuses…
Browse files Browse the repository at this point in the history
…, update colors
  • Loading branch information
EmilyV99 committed Jun 14, 2024
1 parent 66b5a18 commit 2f5540e
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 51 deletions.
6 changes: 3 additions & 3 deletions CommonClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -528,10 +528,10 @@ async def shutdown(self):
self.input_task.cancel()

# Hints
def update_hint(self, location: int, finding_player: int, priority: typing.Optional[bool]) -> None:
def update_hint(self, location: int, finding_player: int, status: typing.Optional[NetUtils.HintStatus]) -> None:
msg = {"cmd": "UpdateHint", "location": location, "player": finding_player}
if priority is not None:
msg["priority"] = priority
if status is not None:
msg["status"] = status
async_start(self.send_msgs([msg]), name="update_hint")

# DataPackage
Expand Down
71 changes: 47 additions & 24 deletions MultiServer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1065,7 +1065,8 @@ def register_location_checks(ctx: Context, team: int, slot: int, locations: typi
ctx.save()


def collect_hints(ctx: Context, team: int, slot: int, item: typing.Union[int, str], priority: bool) -> typing.List[NetUtils.Hint]:
def collect_hints(ctx: Context, team: int, slot: int, item: typing.Union[int, str], status: NetUtils.HintStatus) \
-> typing.List[NetUtils.Hint]:
hints = []
slots: typing.Set[int] = {slot}
for group_id, group in ctx.groups.items():
Expand All @@ -1078,26 +1079,29 @@ def collect_hints(ctx: Context, team: int, slot: int, item: typing.Union[int, st
found = location_id in ctx.location_checks[team, finding_player]
entrance = ctx.er_hint_data.get(finding_player, {}).get(location_id, "")
hints.append(NetUtils.Hint(receiving_player, finding_player, location_id, item_id, found, entrance,
item_flags, priority))
item_flags, status))

return hints


def collect_hint_location_name(ctx: Context, team: int, slot: int, location: str, priority: bool) -> typing.List[NetUtils.Hint]:
def collect_hint_location_name(ctx: Context, team: int, slot: int, location: str, status: NetUtils.HintStatus) \
-> typing.List[NetUtils.Hint]:
seeked_location: int = ctx.location_names_for_game(ctx.games[slot])[location]
return collect_hint_location_id(ctx, team, slot, seeked_location, priority)
return collect_hint_location_id(ctx, team, slot, seeked_location, status)


def collect_hint_location_id(ctx: Context, team: int, slot: int, seeked_location: int, priority: bool) -> typing.List[NetUtils.Hint]:
def collect_hint_location_id(ctx: Context, team: int, slot: int, seeked_location: int, status: NetUtils.HintStatus) \
-> typing.List[NetUtils.Hint]:
result = ctx.locations[slot].get(seeked_location, (None, None, None))
if any(result):
item_id, receiving_player, item_flags = result

found = seeked_location in ctx.location_checks[team, slot]
entrance = ctx.er_hint_data.get(slot, {}).get(seeked_location, "")
return [NetUtils.Hint(receiving_player, slot, seeked_location, item_id, found, entrance, item_flags, priority)]
return [NetUtils.Hint(receiving_player, slot, seeked_location, item_id, found, entrance, item_flags, status)]
return []


def format_hint(ctx: Context, team: int, hint: NetUtils.Hint) -> str:
text = f"[Hint]: {ctx.player_names[team, hint.receiving_player]}'s " \
f"{ctx.item_names[ctx.slot_info[hint.receiving_player].game][hint.item]} is " \
Expand All @@ -1106,7 +1110,15 @@ def format_hint(ctx: Context, team: int, hint: NetUtils.Hint) -> str:

if hint.entrance:
text += f" at {hint.entrance}"
return text + (". (found)" if hint.found else ("." if hint.priority else ". (non-priority)"))

status_names: typing.Dict[NetUtils.HintStatus, str] = {
NetUtils.HintStatus.HINT_FOUND: "(found)",
NetUtils.HintStatus.HINT_UNSPECIFIED: "(unspecified)",
NetUtils.HintStatus.HINT_NO_PRIORITY: "(no priority)",
NetUtils.HintStatus.HINT_AVOID: "(avoid)",
NetUtils.HintStatus.HINT_PRIORITY: "(priority)",
}
return text + ". " + status_names.get(hint.status, "(unknown)")


def json_format_send_event(net_item: NetworkItem, receiving_player: int):
Expand Down Expand Up @@ -1503,7 +1515,7 @@ def _cmd_getitem(self, item_name: str) -> bool:
def get_hints(self, input_text: str, for_location: bool = False) -> bool:
points_available = get_client_points(self.ctx, self.client)
cost = self.ctx.get_hint_cost(self.client.slot)

status = NetUtils.HintStatus.HINT_UNSPECIFIED if for_location else NetUtils.HintStatus.HINT_PRIORITY
if not input_text:
hints = {hint.re_check(self.ctx, self.client.team) for hint in
self.ctx.hints[self.client.team, self.client.slot]}
Expand All @@ -1529,9 +1541,9 @@ def get_hints(self, input_text: str, for_location: bool = False) -> bool:
self.output(f"Sorry, \"{hint_name}\" is marked as non-hintable.")
hints = []
elif not for_location:
hints = collect_hints(self.ctx, self.client.team, self.client.slot, hint_id, True)
hints = collect_hints(self.ctx, self.client.team, self.client.slot, hint_id, status)
else:
hints = collect_hint_location_id(self.ctx, self.client.team, self.client.slot, hint_id, True)
hints = collect_hint_location_id(self.ctx, self.client.team, self.client.slot, hint_id, status)

else:
game = self.ctx.games[self.client.slot]
Expand All @@ -1551,16 +1563,16 @@ def get_hints(self, input_text: str, for_location: bool = False) -> bool:
hints = []
for item_name in self.ctx.item_name_groups[game][hint_name]:
if item_name in self.ctx.item_names_for_game(game): # ensure item has an ID
hints.extend(collect_hints(self.ctx, self.client.team, self.client.slot, item_name, True))
hints.extend(collect_hints(self.ctx, self.client.team, self.client.slot, item_name, status))
elif not for_location and hint_name in self.ctx.item_names_for_game(game): # item name
hints = collect_hints(self.ctx, self.client.team, self.client.slot, hint_name, True)
hints = collect_hints(self.ctx, self.client.team, self.client.slot, hint_name, status)
elif hint_name in self.ctx.location_name_groups[game]: # location group name
hints = []
for loc_name in self.ctx.location_name_groups[game][hint_name]:
if loc_name in self.ctx.location_names_for_game(game):
hints.extend(collect_hint_location_name(self.ctx, self.client.team, self.client.slot, loc_name, False))
hints.extend(collect_hint_location_name(self.ctx, self.client.team, self.client.slot, loc_name, status))
else: # location name
hints = collect_hint_location_name(self.ctx, self.client.team, self.client.slot, hint_name, False)
hints = collect_hint_location_name(self.ctx, self.client.team, self.client.slot, hint_name, status)

else:
self.output(response)
Expand Down Expand Up @@ -1832,7 +1844,8 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict):

target_item, target_player, flags = ctx.locations[client.slot][location]
if create_as_hint:
hints.extend(collect_hint_location_id(ctx, client.team, client.slot, location, False))
hints.extend(collect_hint_location_id(ctx, client.team, client.slot, location,
NetUtils.HintStatus.HINT_UNSPECIFIED))
locs.append(NetworkItem(target_item, location, target_player, flags))
ctx.notify_hints(client.team, hints, only_new=create_as_hint == 2)
if locs and create_as_hint:
Expand All @@ -1842,9 +1855,9 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict):
elif cmd == 'UpdateHint':
location = args["location"]
player = args["player"]
priority = args["priority"]
status = args["status"]
if not isinstance(player, int) or not isinstance(location, int) \
or (priority is not None and not isinstance(priority, bool)):
or (status is not None and not isinstance(status, int)):
await ctx.send_msgs(client,
[{'cmd': 'InvalidPacket', "type": "arguments", "text": 'UpdateHint',
"original_cmd": cmd}])
Expand All @@ -1858,9 +1871,16 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict):
"original_cmd": cmd}])
return
new_hint = hint
if priority is None:
if status is None:
return
try:
status = NetUtils.HintStatus(status)
except ValueError:
await ctx.send_msgs(client,
[{'cmd': 'InvalidPacket', "type": "arguments",
"text": 'UpdateHint: Invalid Status', "original_cmd": cmd}])
return
new_hint = new_hint.re_prioritize(ctx, priority)
new_hint = new_hint.re_prioritize(ctx, status)
if hint == new_hint:
return
ctx.replace_hint(client.team, hint.finding_player, hint, new_hint)
Expand Down Expand Up @@ -2169,9 +2189,9 @@ def _cmd_hint(self, player_name: str, *item_name: str) -> bool:
hints = []
for item_name_from_group in self.ctx.item_name_groups[game][item]:
if item_name_from_group in self.ctx.item_names_for_game(game): # ensure item has an ID
hints.extend(collect_hints(self.ctx, team, slot, item_name_from_group, True))
hints.extend(collect_hints(self.ctx, team, slot, item_name_from_group, NetUtils.HintStatus.HINT_PRIORITY))
else: # item name or id
hints = collect_hints(self.ctx, team, slot, item, True)
hints = collect_hints(self.ctx, team, slot, item, NetUtils.HintStatus.HINT_PRIORITY)

if hints:
self.ctx.notify_hints(team, hints)
Expand Down Expand Up @@ -2205,14 +2225,17 @@ def _cmd_hint_location(self, player_name: str, *location_name: str) -> bool:

if usable:
if isinstance(location, int):
hints = collect_hint_location_id(self.ctx, team, slot, location, False)
hints = collect_hint_location_id(self.ctx, team, slot, location,
NetUtils.HintStatus.HINT_UNSPECIFIED)
elif game in self.ctx.location_name_groups and location in self.ctx.location_name_groups[game]:
hints = []
for loc_name_from_group in self.ctx.location_name_groups[game][location]:
if loc_name_from_group in self.ctx.location_names_for_game(game):
hints.extend(collect_hint_location_name(self.ctx, team, slot, loc_name_from_group, False))
hints.extend(collect_hint_location_name(self.ctx, team, slot, loc_name_from_group,
NetUtils.HintStatus.HINT_UNSPECIFIED))
else:
hints = collect_hint_location_name(self.ctx, team, slot, location, False)
hints = collect_hint_location_name(self.ctx, team, slot, location,
NetUtils.HintStatus.HINT_UNSPECIFIED)
if hints:
self.ctx.notify_hints(team, hints)
else:
Expand Down
41 changes: 29 additions & 12 deletions NetUtils.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ class ClientStatus(ByValue, enum.IntEnum):
CLIENT_GOAL = 30


class HintStatus(enum.IntEnum):
HINT_FOUND = 0
HINT_UNSPECIFIED = 1
HINT_NO_PRIORITY = 10
HINT_AVOID = 20
HINT_PRIORITY = 30


class SlotType(ByValue, enum.IntFlag):
spectator = 0b00
player = 0b01
Expand Down Expand Up @@ -200,7 +208,6 @@ class JSONtoTextParser(metaclass=HandlerMeta):
"salmon": "FA8072",
"white": "FFFFFF",
"orange": "FF7700",
"gold": "EDED2D",
}

def __init__(self, ctx):
Expand Down Expand Up @@ -304,19 +311,19 @@ class Hint(typing.NamedTuple):
found: bool
entrance: str = ""
item_flags: int = 0
priority: bool = True
status: HintStatus = HintStatus.HINT_UNSPECIFIED

def re_check(self, ctx, team) -> Hint:
if self.found:
return self
found = self.location in ctx.location_checks[team, self.finding_player]
if found:
return self._replace(found=found)
return self._replace(found=found, status=HintStatus.HINT_FOUND)
return self

def re_prioritize(self, ctx, priority: bool) -> Hint:
if priority != self.priority:
return self._replace(priority=priority)
def re_prioritize(self, ctx, status: HintStatus) -> Hint:
if status != self.status:
return self._replace(status=status)
return self

def __hash__(self):
Expand All @@ -338,12 +345,22 @@ def as_network_message(self) -> dict:
else:
add_json_text(parts, "'s World")
add_json_text(parts, ". ")
if self.found:
add_json_text(parts, "(found)", type="color", color="green")
elif self.priority:
add_json_text(parts, "(priority)", type="color", color="red")
else:
add_json_text(parts, "(non-priority)", type="color", color="gold")
status_names: typing.Dict[HintStatus, str] = {
HintStatus.HINT_FOUND: "(found)",
HintStatus.HINT_UNSPECIFIED: "(unspecified)",
HintStatus.HINT_NO_PRIORITY: "(no priority)",
HintStatus.HINT_AVOID: "(avoid)",
HintStatus.HINT_PRIORITY: "(priority)",
}
status_colors: typing.Dict[HintStatus, str] = {
HintStatus.HINT_FOUND: "green",
HintStatus.HINT_UNSPECIFIED: "white",
HintStatus.HINT_NO_PRIORITY: "slateblue",
HintStatus.HINT_AVOID: "salmon",
HintStatus.HINT_PRIORITY: "plum",
}
add_json_text(parts, status_names.get(self.status, "(unknown)"), type="color",
color=status_colors.get(self.status, "red"))

return {"cmd": "PrintJSON", "data": parts, "type": "Hint",
"receiving": self.receiving_player,
Expand Down
3 changes: 2 additions & 1 deletion Utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,8 @@ def find_class(self, module: str, name: str) -> type:
if module == "builtins" and name in safe_builtins:
return getattr(builtins, name)
# used by MultiServer -> savegame/multidata
if module == "NetUtils" and name in {"NetworkItem", "ClientStatus", "Hint", "SlotType", "NetworkSlot"}:
if module == "NetUtils" and name in {"NetworkItem", "ClientStatus", "Hint",
"SlotType", "NetworkSlot", "HintStatus"}:
return getattr(self.net_utils_module, name)
# Options and Plando are unpickled by WebHost -> Generate
if module == "worlds.generic" and name in {"PlandoItem", "PlandoConnection"}:
Expand Down
15 changes: 14 additions & 1 deletion docs/network protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,20 @@ Sent to the server to update the status of a Hint. The client must be the 'recei
| ---- | ---- | ----- |
| player | int | The ID of the player whose location is being hinted for. |
| location | int | The ID of the location to update the hint for. If no hint exists for this location, the packet is ignored. |
| priority | bool | Optional. If included, sets the priority of the hint to this status. |
| status | HintStatus | Optional. If included, sets the priority of the hint to this status. |

#### HintStatus
An enumeration containing the possible hint states.

```python
import enum
class HintStatus(enum.IntEnum):
HINT_FOUND = 0
HINT_UNSPECIFIED = 1
HINT_NO_PRIORITY = 10
HINT_AVOID = 20
HINT_PRIORITY = 30
```

### StatusUpdate
Sent to the server to update on the sender's status. Examples include readiness or goal completion. (Example: defeated Ganon in A Link to the Past)
Expand Down
Loading

0 comments on commit 2f5540e

Please sign in to comment.