Add a generic fallback tracker for all games

This commit is contained in:
Fabian Dill 2021-05-19 21:55:18 +02:00
parent e1b4975a11
commit 31a3c1cf33
4 changed files with 118 additions and 48 deletions

View File

@ -414,7 +414,7 @@ def main(args, seed=None):
return player, team, bytes(rom.name) return player, team, bytes(rom.name)
pool = concurrent.futures.ThreadPoolExecutor() pool = concurrent.futures.ThreadPoolExecutor()
multidata_task = None
check_accessibility_task = pool.submit(world.fulfills_accessibility) check_accessibility_task = pool.submit(world.fulfills_accessibility)
rom_futures = [] rom_futures = []

View File

@ -0,0 +1,63 @@
{% extends 'tablepage.html' %}
{% block head %}
{{ super() }}
<title>{{ player_name }}&apos;s Tracker</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename="styles/tracker.css") }}"/>
<script type="application/ecmascript" src="{{ url_for('static', filename="assets/jquery.scrollsync.js") }}"></script>
<script type="application/ecmascript" src="{{ url_for('static', filename="assets/tracker.js") }}"></script>
{% endblock %}
{% block body %}
{% include 'header/dirtHeader.html' %}
<div id="tracker-wrapper" data-tracker="{{ room.tracker|suuid }}/{{ team }}/{{ player }}">
<div id="tracker-header-bar">
<input placeholder="Search" id="search"/>
<span class="info">This tracker will automatically update itself periodically.</span>
</div>
<div class="table-wrapper">
<table class="table non-unique-item-table">
<thead>
<tr>
<th>Item</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
{% for name, count in acquired_items.items() %}
<tr>
<td>{{ name }}</td>
<td>{{ count }}</td>
</tr>
{%- endfor -%}
</tbody>
</table>
</div>
<div class="table-wrapper">
<table class="table non-unique-item-table">
<thead>
<tr>
<th>Location</th>
<th>Checked</th>
</tr>
</thead>
<tbody>
{% for name in checked_locations %}
<tr>
<td>{{ name | location_name}}</td>
<td></td>
</tr>
{%- endfor -%}
{% for name in not_checked_locations %}
<tr>
<td>{{ name | location_name}}</td>
<td></td>
</tr>
{%- endfor -%}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}

View File

@ -5,7 +5,7 @@ from werkzeug.exceptions import abort
import datetime import datetime
from uuid import UUID from uuid import UUID
from worlds.alttp import Items, Regions from worlds.alttp import Items
from WebHostLib import app, cache, Room from WebHostLib import app, cache, Room
from Utils import restricted_loads from Utils import restricted_loads
from worlds import lookup_any_item_id_to_name, lookup_any_location_id_to_name from worlds import lookup_any_item_id_to_name, lookup_any_location_id_to_name
@ -327,7 +327,8 @@ def get_static_room_data(room: Room):
player_small_key_locations[item_player].add(ids_small_key[item_id]) player_small_key_locations[item_player].add(ids_small_key[item_id])
result = locations, names, use_door_tracker, player_checks_in_area, player_location_to_area, \ result = locations, names, use_door_tracker, player_checks_in_area, player_location_to_area, \
player_big_key_locations, player_small_key_locations, multidata["precollected_items"] player_big_key_locations, player_small_key_locations, multidata["precollected_items"], \
multidata["games"]
_multidata_cache[room.seed.id] = result _multidata_cache[room.seed.id] = result
return result return result
@ -344,9 +345,9 @@ def getPlayerTracker(tracker: UUID, tracked_team: int, tracked_player: int):
abort(404) abort(404)
# Collect seed information and pare it down to a single player # Collect seed information and pare it down to a single player
locations, names, use_door_tracker, seed_checks_in_area, player_location_to_area, player_big_key_locations, player_small_key_locations, precollected_items = get_static_room_data(room) locations, names, use_door_tracker, seed_checks_in_area, player_location_to_area, \
player_big_key_locations, player_small_key_locations, precollected_items, games = get_static_room_data(room)
player_name = names[tracked_team][tracked_player - 1] player_name = names[tracked_team][tracked_player - 1]
seed_checks_in_area = seed_checks_in_area[tracked_player]
location_to_area = player_location_to_area[tracked_player] location_to_area = player_location_to_area[tracked_player]
inventory = collections.Counter() inventory = collections.Counter()
checks_done = {loc_name: 0 for loc_name in default_locations} checks_done = {loc_name: 0 for loc_name in default_locations}
@ -361,6 +362,7 @@ def getPlayerTracker(tracker: UUID, tracked_team: int, tracked_player: int):
multisave = restricted_loads(room.multisave) multisave = restricted_loads(room.multisave)
else: else:
multisave = {} multisave = {}
checked_locations = set()
# Add items to player inventory # Add items to player inventory
for (ms_team, ms_player), locations_checked in multisave.get("location_checks", {}).items(): for (ms_team, ms_player), locations_checked in multisave.get("location_checks", {}).items():
@ -368,6 +370,7 @@ def getPlayerTracker(tracker: UUID, tracked_team: int, tracked_player: int):
# Skip teams and players not matching the request # Skip teams and players not matching the request
player_locations = locations[ms_player] player_locations = locations[ms_player]
if ms_team == tracked_team: if ms_team == tracked_team:
checked_locations = locations_checked
# If the player does not have the item, do nothing # If the player does not have the item, do nothing
for location in locations_checked: for location in locations_checked:
if location in player_locations: if location in player_locations:
@ -377,52 +380,57 @@ def getPlayerTracker(tracker: UUID, tracked_team: int, tracked_player: int):
if ms_player == tracked_player: # a check done by the tracked player if ms_player == tracked_player: # a check done by the tracked player
checks_done[location_to_area[location]] += 1 checks_done[location_to_area[location]] += 1
checks_done["Total"] += 1 checks_done["Total"] += 1
if games[tracked_player] == "A Link to the Past":
# Note the presence of the triforce item
game_state = multisave.get("client_game_state", {}).get((tracked_team, tracked_player), 0)
if game_state == 30:
inventory[106] = 1 # Triforce
# Note the presence of the triforce item # Progressive items need special handling for icons and class
game_state = multisave.get("client_game_state", {}).get((tracked_team, tracked_player), 0) progressive_items = {
if game_state == 30: "Progressive Sword": 94,
inventory[106] = 1 # Triforce "Progressive Glove": 97,
"Progressive Bow": 100,
"Progressive Mail": 96,
"Progressive Shield": 95,
}
progressive_names = {
"Progressive Sword": [None, 'Fighter Sword', 'Master Sword', 'Tempered Sword', 'Golden Sword'],
"Progressive Glove": [None, 'Power Glove', 'Titan Mitts'],
"Progressive Bow": [None, "Bow", "Silver Bow"],
"Progressive Mail": ["Green Mail", "Blue Mail", "Red Mail"],
"Progressive Shield": [None, "Blue Shield", "Red Shield", "Mirror Shield"]
}
# Progressive items need special handling for icons and class # Determine which icon to use
progressive_items = { display_data = {}
"Progressive Sword": 94, for item_name, item_id in progressive_items.items():
"Progressive Glove": 97, level = min(inventory[item_id], len(progressive_names[item_name]))
"Progressive Bow": 100, display_name = progressive_names[item_name][level]
"Progressive Mail": 96, acquired = True
"Progressive Shield": 95, if not display_name:
} acquired = False
progressive_names = { display_name = progressive_names[item_name][level+1]
"Progressive Sword": [None, 'Fighter Sword', 'Master Sword', 'Tempered Sword', 'Golden Sword'], base_name = item_name.split(maxsplit=1)[1].lower()
"Progressive Glove": [None, 'Power Glove', 'Titan Mitts'], display_data[base_name+"_acquired"] = acquired
"Progressive Bow": [None, "Bow", "Silver Bow"], display_data[base_name+"_url"] = icons[display_name]
"Progressive Mail": ["Green Mail", "Blue Mail", "Red Mail"],
"Progressive Shield": [None, "Blue Shield", "Red Shield", "Mirror Shield"]
}
# Determine which icon to use
display_data = {}
for item_name, item_id in progressive_items.items():
level = min(inventory[item_id], len(progressive_names[item_name]))
display_name = progressive_names[item_name][level]
acquired = True
if not display_name:
acquired = False
display_name = progressive_names[item_name][level+1]
base_name = item_name.split(maxsplit=1)[1].lower()
display_data[base_name+"_acquired"] = acquired
display_data[base_name+"_url"] = icons[display_name]
# The single player tracker doesn't care about overworld, underworld, and total checks. Maybe it should? # The single player tracker doesn't care about overworld, underworld, and total checks. Maybe it should?
sp_areas = ordered_areas[2:15] sp_areas = ordered_areas[2:15]
return render_template("playerTracker.html", inventory=inventory, get_item_name_from_id=get_item_name_from_id, return render_template("lttpTracker.html", inventory=inventory,
player_name=player_name, room=room, icons=icons, checks_done=checks_done, player_name=player_name, room=room, icons=icons, checks_done=checks_done,
checks_in_area=seed_checks_in_area, acquired_items={lookup_any_item_id_to_name[id] for id in inventory}, checks_in_area=seed_checks_in_area[tracked_player], acquired_items={lookup_any_item_id_to_name[id] for id in inventory},
small_key_ids=small_key_ids, big_key_ids=big_key_ids, sp_areas=sp_areas, small_key_ids=small_key_ids, big_key_ids=big_key_ids, sp_areas=sp_areas,
key_locations=player_small_key_locations[tracked_player], key_locations=player_small_key_locations[tracked_player],
big_key_locations=player_big_key_locations[tracked_player], big_key_locations=player_big_key_locations[tracked_player],
**display_data) **display_data)
else:
return render_template("genericTracker.html",
acquired_items={lookup_any_item_id_to_name[id]: count for id, count in inventory.items()},
player=tracked_player, team=tracked_team, room=room, player_name=player_name,
checked_locations= checked_locations, not_checked_locations = set(locations[tracked_player])-checked_locations)
@app.route('/tracker/<suuid:tracker>') @app.route('/tracker/<suuid:tracker>')
@ -432,7 +440,7 @@ def getTracker(tracker: UUID):
if not room: if not room:
abort(404) abort(404)
locations, names, use_door_tracker, seed_checks_in_area, player_location_to_area, player_big_key_locations, \ locations, names, use_door_tracker, seed_checks_in_area, player_location_to_area, player_big_key_locations, \
player_small_key_locations, precollected_items = get_static_room_data(room) player_small_key_locations, precollected_items, games = get_static_room_data(room)
inventory = {teamnumber: {playernumber: collections.Counter() for playernumber in range(1, len(team) + 1)} inventory = {teamnumber: {playernumber: collections.Counter() for playernumber in range(1, len(team) + 1)}
for teamnumber, team in enumerate(names)} for teamnumber, team in enumerate(names)}
@ -447,7 +455,6 @@ def getTracker(tracker: UUID):
else: else:
multisave = {} multisave = {}
if "hints" in multisave: if "hints" in multisave:
for (team, slot), slot_hints in multisave["hints"].items(): for (team, slot), slot_hints in multisave["hints"].items():
hints[team] |= set(slot_hints) hints[team] |= set(slot_hints)