WebHost: Fix 500 Server errors relating to player/multi trackers. (#2664)
* WebHost: Fix player tracker issue with items missing from data package. Reported in https://discord.com/channels/731205301247803413/1192202112172576819 * WebHost: Fix multi-tracker error when item links are present. Reported in https://discord.com/channels/731205301247803413/1192104719959724062 * Use Utils.KeyedDefaultDict instead of checking for key * formatted revert * import tweak
This commit is contained in:
parent
7406a1e512
commit
c593a960f6
|
@ -1,4 +1,5 @@
|
|||
import datetime
|
||||
import collections
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, Callable, Dict, List, Optional, Set, Tuple
|
||||
from uuid import UUID
|
||||
|
@ -8,7 +9,7 @@ from werkzeug.exceptions import abort
|
|||
|
||||
from MultiServer import Context, get_saving_second
|
||||
from NetUtils import ClientStatus, Hint, NetworkItem, NetworkSlot, SlotType
|
||||
from Utils import restricted_loads
|
||||
from Utils import restricted_loads, KeyedDefaultDict
|
||||
from . import app, cache
|
||||
from .models import GameDataPackage, Room
|
||||
|
||||
|
@ -62,12 +63,18 @@ class TrackerData:
|
|||
self.location_name_to_id: Dict[str, Dict[str, int]] = {}
|
||||
|
||||
# Generate inverse lookup tables from data package, useful for trackers.
|
||||
self.item_id_to_name: Dict[str, Dict[int, str]] = {}
|
||||
self.location_id_to_name: Dict[str, Dict[int, str]] = {}
|
||||
self.item_id_to_name: Dict[str, Dict[int, str]] = KeyedDefaultDict(lambda game_name: {
|
||||
game_name: KeyedDefaultDict(lambda code: f"Unknown Game {game_name} - Item (ID: {code})")
|
||||
})
|
||||
self.location_id_to_name: Dict[str, Dict[int, str]] = KeyedDefaultDict(lambda game_name: {
|
||||
game_name: KeyedDefaultDict(lambda code: f"Unknown Game {game_name} - Location (ID: {code})")
|
||||
})
|
||||
for game, game_package in self._multidata["datapackage"].items():
|
||||
game_package = restricted_loads(GameDataPackage.get(checksum=game_package["checksum"]).data)
|
||||
self.item_id_to_name[game] = {id: name for name, id in game_package["item_name_to_id"].items()}
|
||||
self.location_id_to_name[game] = {id: name for name, id in game_package["location_name_to_id"].items()}
|
||||
self.item_id_to_name[game] = KeyedDefaultDict(lambda code: f"Unknown Item (ID: {code})", {
|
||||
id: name for name, id in game_package["item_name_to_id"].items()})
|
||||
self.location_id_to_name[game] = KeyedDefaultDict(lambda code: f"Unknown Location (ID: {code})", {
|
||||
id: name for name, id in game_package["location_name_to_id"].items()})
|
||||
|
||||
# Normal lookup tables as well.
|
||||
self.item_name_to_id[game] = game_package["item_name_to_id"]
|
||||
|
@ -115,10 +122,10 @@ class TrackerData:
|
|||
return self._multisave.get("received_items", {}).get((team, player, True), [])
|
||||
|
||||
@_cache_results
|
||||
def get_player_inventory_counts(self, team: int, player: int) -> Dict[int, int]:
|
||||
def get_player_inventory_counts(self, team: int, player: int) -> collections.Counter:
|
||||
"""Retrieves a dictionary of all items received by their id and their received count."""
|
||||
items = self.get_player_received_items(team, player)
|
||||
inventory = {item: 0 for item in self.item_id_to_name[self.get_player_game(team, player)]}
|
||||
inventory = collections.Counter()
|
||||
for item in items:
|
||||
inventory[item.item] += 1
|
||||
|
||||
|
@ -149,16 +156,15 @@ class TrackerData:
|
|||
"""Retrieves a dictionary of number of completed worlds per team."""
|
||||
return {
|
||||
team: sum(
|
||||
self.get_player_client_status(team, player) == ClientStatus.CLIENT_GOAL
|
||||
for player in players if self.get_slot_info(team, player).type == SlotType.player
|
||||
) for team, players in self.get_team_players().items()
|
||||
self.get_player_client_status(team, player) == ClientStatus.CLIENT_GOAL for player in players
|
||||
) for team, players in self.get_all_players().items()
|
||||
}
|
||||
|
||||
@_cache_results
|
||||
def get_team_hints(self) -> Dict[int, Set[Hint]]:
|
||||
"""Retrieves a dictionary of all hints per team."""
|
||||
hints = {}
|
||||
for team, players in self.get_team_players().items():
|
||||
for team, players in self.get_all_slots().items():
|
||||
hints[team] = set()
|
||||
for player in players:
|
||||
hints[team] |= self.get_player_hints(team, player)
|
||||
|
@ -170,7 +176,7 @@ class TrackerData:
|
|||
"""Retrieves a dictionary of total player locations each team has."""
|
||||
return {
|
||||
team: sum(len(self.get_player_locations(team, player)) for player in players)
|
||||
for team, players in self.get_team_players().items()
|
||||
for team, players in self.get_all_players().items()
|
||||
}
|
||||
|
||||
@_cache_results
|
||||
|
@ -178,16 +184,30 @@ class TrackerData:
|
|||
"""Retrieves a dictionary of checked player locations each team has."""
|
||||
return {
|
||||
team: sum(len(self.get_player_checked_locations(team, player)) for player in players)
|
||||
for team, players in self.get_team_players().items()
|
||||
for team, players in self.get_all_players().items()
|
||||
}
|
||||
|
||||
# TODO: Change this method to properly build for each team once teams are properly implemented, as they don't
|
||||
# currently exist in multidata to easily look up, so these are all assuming only 1 team: Team #0
|
||||
@_cache_results
|
||||
def get_team_players(self) -> Dict[int, List[int]]:
|
||||
def get_all_slots(self) -> Dict[int, List[int]]:
|
||||
"""Retrieves a dictionary of all players ids on each team."""
|
||||
return {
|
||||
0: [player for player, slot_info in self._multidata["slot_info"].items()]
|
||||
0: [
|
||||
player for player, slot_info in self._multidata["slot_info"].items()
|
||||
]
|
||||
}
|
||||
|
||||
# TODO: Change this method to properly build for each team once teams are properly implemented, as they don't
|
||||
# currently exist in multidata to easily look up, so these are all assuming only 1 team: Team #0
|
||||
@_cache_results
|
||||
def get_all_players(self) -> Dict[int, List[int]]:
|
||||
"""Retrieves a dictionary of all player slot-type players ids on each team."""
|
||||
return {
|
||||
0: [
|
||||
player for player, slot_info in self._multidata["slot_info"].items()
|
||||
if self.get_slot_info(0, player).type == SlotType.player
|
||||
]
|
||||
}
|
||||
|
||||
@_cache_results
|
||||
|
@ -203,7 +223,7 @@ class TrackerData:
|
|||
"""Retrieves a dictionary of all locations and their associated item metadata per player."""
|
||||
return {
|
||||
(team, player): self.get_player_locations(team, player)
|
||||
for team, players in self.get_team_players().items() for player in players
|
||||
for team, players in self.get_all_players().items() for player in players
|
||||
}
|
||||
|
||||
@_cache_results
|
||||
|
@ -211,7 +231,7 @@ class TrackerData:
|
|||
"""Retrieves a dictionary of games for each player."""
|
||||
return {
|
||||
(team, player): self.get_player_game(team, player)
|
||||
for team, players in self.get_team_players().items() for player in players
|
||||
for team, players in self.get_all_slots().items() for player in players
|
||||
}
|
||||
|
||||
@_cache_results
|
||||
|
@ -219,7 +239,7 @@ class TrackerData:
|
|||
"""Retrieves a dictionary of all locations complete per player."""
|
||||
return {
|
||||
(team, player): len(self.get_player_checked_locations(team, player))
|
||||
for team, players in self.get_team_players().items() for player in players
|
||||
for team, players in self.get_all_players().items() for player in players
|
||||
}
|
||||
|
||||
@_cache_results
|
||||
|
@ -227,14 +247,14 @@ class TrackerData:
|
|||
"""Retrieves a dictionary of all ClientStatus values per player."""
|
||||
return {
|
||||
(team, player): self.get_player_client_status(team, player)
|
||||
for team, players in self.get_team_players().items() for player in players
|
||||
for team, players in self.get_all_players().items() for player in players
|
||||
}
|
||||
|
||||
@_cache_results
|
||||
def get_room_long_player_names(self) -> Dict[TeamPlayer, str]:
|
||||
"""Retrieves a dictionary of names with aliases for each player."""
|
||||
long_player_names = {}
|
||||
for team, players in self.get_team_players().items():
|
||||
for team, players in self.get_all_slots().items():
|
||||
for player in players:
|
||||
alias = self.get_player_alias(team, player)
|
||||
if alias:
|
||||
|
@ -370,7 +390,8 @@ def render_generic_multiworld_tracker(tracker_data: TrackerData, enabled_tracker
|
|||
enabled_trackers=enabled_trackers,
|
||||
current_tracker="Generic",
|
||||
room=tracker_data.room,
|
||||
room_players=tracker_data.get_team_players(),
|
||||
all_slots=tracker_data.get_all_slots(),
|
||||
room_players=tracker_data.get_all_players(),
|
||||
locations=tracker_data.get_room_locations(),
|
||||
locations_complete=tracker_data.get_room_locations_complete(),
|
||||
total_team_locations=tracker_data.get_team_locations_total_count(),
|
||||
|
@ -389,7 +410,6 @@ def render_generic_multiworld_tracker(tracker_data: TrackerData, enabled_tracker
|
|||
|
||||
# TODO: This is a temporary solution until a proper Tracker API can be implemented for tracker templates and data to
|
||||
# live in their respective world folders.
|
||||
import collections
|
||||
|
||||
from worlds import network_data_package
|
||||
|
||||
|
@ -400,7 +420,7 @@ if "Factorio" in network_data_package["games"]:
|
|||
(team, player): {
|
||||
tracker_data.item_id_to_name["Factorio"][item_id]: count
|
||||
for item_id, count in tracker_data.get_player_inventory_counts(team, player).items()
|
||||
} for team, players in tracker_data.get_team_players().items() for player in players
|
||||
} for team, players in tracker_data.get_all_slots().items() for player in players
|
||||
if tracker_data.get_player_game(team, player) == "Factorio"
|
||||
}
|
||||
|
||||
|
@ -409,7 +429,8 @@ if "Factorio" in network_data_package["games"]:
|
|||
enabled_trackers=enabled_trackers,
|
||||
current_tracker="Factorio",
|
||||
room=tracker_data.room,
|
||||
room_players=tracker_data.get_team_players(),
|
||||
all_slots=tracker_data.get_all_slots(),
|
||||
room_players=tracker_data.get_all_players(),
|
||||
locations=tracker_data.get_room_locations(),
|
||||
locations_complete=tracker_data.get_room_locations_complete(),
|
||||
total_team_locations=tracker_data.get_team_locations_total_count(),
|
||||
|
@ -547,7 +568,7 @@ if "A Link to the Past" in network_data_package["games"]:
|
|||
if area_name != "Total" else tracker_data._multidata["checks_in_area"][player]["Total"]
|
||||
for area_name in ordered_areas
|
||||
}
|
||||
for team, players in tracker_data.get_team_players().items()
|
||||
for team, players in tracker_data.get_all_slots().items()
|
||||
for player in players
|
||||
if tracker_data.get_slot_info(team, player).type != SlotType.group and
|
||||
tracker_data.get_slot_info(team, player).game == "A Link to the Past"
|
||||
|
@ -585,7 +606,7 @@ if "A Link to the Past" in network_data_package["games"]:
|
|||
|
||||
player_location_to_area = {
|
||||
(team, player): _get_location_table(tracker_data._multidata["checks_in_area"][player])
|
||||
for team, players in tracker_data.get_team_players().items()
|
||||
for team, players in tracker_data.get_all_slots().items()
|
||||
for player in players
|
||||
if tracker_data.get_slot_info(team, player).type != SlotType.group and
|
||||
tracker_data.get_slot_info(team, player).game == "A Link to the Past"
|
||||
|
@ -593,15 +614,15 @@ if "A Link to the Past" in network_data_package["games"]:
|
|||
|
||||
checks_done: Dict[TeamPlayer, Dict[str: int]] = {
|
||||
(team, player): {location_name: 0 for location_name in default_locations}
|
||||
for team, players in tracker_data.get_team_players().items()
|
||||
for team, players in tracker_data.get_all_slots().items()
|
||||
for player in players
|
||||
if tracker_data.get_slot_info(team, player).type != SlotType.group and
|
||||
tracker_data.get_slot_info(team, player).game == "A Link to the Past"
|
||||
}
|
||||
|
||||
inventories: Dict[TeamPlayer, Dict[int, int]] = {}
|
||||
player_big_key_locations = {(player): set() for player in tracker_data.get_team_players()[0]}
|
||||
player_small_key_locations = {player: set() for player in tracker_data.get_team_players()[0]}
|
||||
player_big_key_locations = {(player): set() for player in tracker_data.get_all_slots()[0]}
|
||||
player_small_key_locations = {player: set() for player in tracker_data.get_all_slots()[0]}
|
||||
group_big_key_locations = set()
|
||||
group_key_locations = set()
|
||||
|
||||
|
@ -639,7 +660,8 @@ if "A Link to the Past" in network_data_package["games"]:
|
|||
enabled_trackers=enabled_trackers,
|
||||
current_tracker="A Link to the Past",
|
||||
room=tracker_data.room,
|
||||
room_players=tracker_data.get_team_players(),
|
||||
all_slots=tracker_data.get_all_slots(),
|
||||
room_players=tracker_data.get_all_players(),
|
||||
locations=tracker_data.get_room_locations(),
|
||||
locations_complete=tracker_data.get_room_locations_complete(),
|
||||
total_team_locations=tracker_data.get_team_locations_total_count(),
|
||||
|
|
Loading…
Reference in New Issue