Merge branch 'master' into website-redesign
This commit is contained in:
@@ -28,7 +28,7 @@ def mysterycheck():
|
||||
if type(options) == str:
|
||||
flash(options)
|
||||
else:
|
||||
results, _ = roll_yamls(options)
|
||||
results, _ = roll_options(options)
|
||||
return render_template("checkresult.html", results=results)
|
||||
|
||||
return render_template("check.html")
|
||||
@@ -60,12 +60,15 @@ def get_yaml_data(file) -> Union[Dict[str, str], str]:
|
||||
return options
|
||||
|
||||
|
||||
def roll_yamls(options: Dict[str, Union[str, str]]) -> Tuple[Dict[str, Union[str, bool]], Dict[str, dict]]:
|
||||
def roll_options(options: Dict[str, Union[dict, str]]) -> Tuple[Dict[str, Union[str, bool]], Dict[str, dict]]:
|
||||
results = {}
|
||||
rolled_results = {}
|
||||
for filename, text in options.items():
|
||||
try:
|
||||
yaml_data = parse_yaml(text)
|
||||
if type(text) is dict:
|
||||
yaml_data = text
|
||||
else:
|
||||
yaml_data = parse_yaml(text)
|
||||
except Exception as e:
|
||||
results[filename] = f"Failed to parse YAML data in {filename}: {e}"
|
||||
else:
|
||||
|
||||
@@ -37,9 +37,10 @@ def download_raw_patch(seed_id, player_id):
|
||||
return "Patch not found"
|
||||
else:
|
||||
import io
|
||||
|
||||
pname = patch.seed.multidata["names"][0][patch.player - 1]
|
||||
|
||||
if patch.seed.multidata:
|
||||
pname = patch.seed.multidata["names"][0][patch.player - 1]
|
||||
else:
|
||||
pname = "unknown"
|
||||
patch_data = update_patch_data(patch.data, server="")
|
||||
patch_data = io.BytesIO(patch_data)
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import pickle
|
||||
|
||||
from .models import *
|
||||
from WebHostLib import app
|
||||
from .check import get_yaml_data, roll_yamls
|
||||
from .check import get_yaml_data, roll_options
|
||||
|
||||
|
||||
@app.route('/generate', methods=['GET', 'POST'])
|
||||
@@ -29,7 +29,7 @@ def generate(race=False):
|
||||
if type(options) == str:
|
||||
flash(options)
|
||||
else:
|
||||
results, gen_options = roll_yamls(options)
|
||||
results, gen_options = roll_options(options)
|
||||
if any(type(result) == str for result in results.values()):
|
||||
return render_template("checkresult.html", results=results)
|
||||
elif len(gen_options) > app.config["MAX_ROLL"]:
|
||||
@@ -52,6 +52,55 @@ def generate(race=False):
|
||||
return render_template("generate.html", race=race)
|
||||
|
||||
|
||||
@app.route('/api/generate', methods=['POST'])
|
||||
def generate_api():
|
||||
try:
|
||||
options = {}
|
||||
race = False
|
||||
|
||||
if 'file' in request.files:
|
||||
file = request.files['file']
|
||||
options = get_yaml_data(file)
|
||||
if type(options) == str:
|
||||
return {"text": options}, 400
|
||||
if "race" in request.form:
|
||||
race = bool(0 if request.form["race"] in {"false"} else int(request.form["race"]))
|
||||
|
||||
json_data = request.get_json()
|
||||
if json_data:
|
||||
if 'weights' in json_data:
|
||||
# example: options = {"player1weights" : {<weightsdata>}}
|
||||
options = json_data["weights"]
|
||||
if "race" in json_data:
|
||||
race = bool(0 if json_data["race"] in {"false"} else int(json_data["race"]))
|
||||
if not options:
|
||||
return {"text": "No options found. Expected file attachment or json weights."
|
||||
}, 400
|
||||
|
||||
if len(options) > app.config["MAX_ROLL"]:
|
||||
return {"text": "Max size of multiworld exceeded",
|
||||
"detail": app.config["MAX_ROLL"]}, 409
|
||||
|
||||
results, gen_options = roll_options(options)
|
||||
if any(type(result) == str for result in results.values()):
|
||||
return {"text": str(results),
|
||||
"detail": results}, 400
|
||||
else:
|
||||
gen = Generation(
|
||||
options=pickle.dumps({name: vars(options) for name, options in gen_options.items()}),
|
||||
# convert to json compatible
|
||||
meta=pickle.dumps({"race": race}), state=STATE_QUEUED,
|
||||
owner=session["_id"])
|
||||
commit()
|
||||
return {"text": f"Generation of seed {gen.id} started successfully.",
|
||||
"detail": gen.id,
|
||||
"encoded": app.url_map.converters["suuid"].to_url(None, gen.id),
|
||||
"wait_api_url": url_for("wait_seed_api", seed=gen.id),
|
||||
"url": url_for("wait_seed", seed=gen.id)}, 201
|
||||
except Exception as e:
|
||||
return {"text": "Uncaught Exception:" + str(e)}, 500
|
||||
|
||||
|
||||
def gen_game(gen_options, race=False, owner=None, sid=None):
|
||||
try:
|
||||
target = tempfile.TemporaryDirectory()
|
||||
@@ -92,7 +141,7 @@ def gen_game(gen_options, race=False, owner=None, sid=None):
|
||||
del (erargs.progression_balancing)
|
||||
ERmain(erargs, seed)
|
||||
|
||||
return upload_to_db(target.name, owner, sid)
|
||||
return upload_to_db(target.name, owner, sid, race)
|
||||
except BaseException:
|
||||
if sid:
|
||||
with db_session:
|
||||
@@ -117,9 +166,25 @@ def wait_seed(seed: UUID):
|
||||
return render_template("waitSeed.html", seed_id=seed_id)
|
||||
|
||||
|
||||
def upload_to_db(folder, owner, sid):
|
||||
@app.route('/api/status/<suuid:seed>')
|
||||
def wait_seed_api(seed: UUID):
|
||||
seed_id = seed
|
||||
seed = Seed.get(id=seed_id)
|
||||
if seed:
|
||||
return {"text": "Generation done"}, 201
|
||||
generation = Generation.get(id=seed_id)
|
||||
|
||||
if not generation:
|
||||
return {"text": "Generation not found"}, 404
|
||||
elif generation.state == STATE_ERROR:
|
||||
return {"text": "Generation failed"}, 500
|
||||
return {"text": "Generation running"}, 202
|
||||
|
||||
|
||||
def upload_to_db(folder, owner, sid, race:bool):
|
||||
patches = set()
|
||||
spoiler = ""
|
||||
|
||||
multidata = None
|
||||
for file in os.listdir(folder):
|
||||
file = os.path.join(folder, file)
|
||||
@@ -129,20 +194,26 @@ def upload_to_db(folder, owner, sid):
|
||||
elif file.endswith(".txt"):
|
||||
spoiler = open(file, "rt").read()
|
||||
elif file.endswith("multidata"):
|
||||
try:
|
||||
multidata = json.loads(zlib.decompress(open(file, "rb").read()))
|
||||
except Exception as e:
|
||||
flash(e)
|
||||
if multidata:
|
||||
with db_session:
|
||||
if sid:
|
||||
seed = Seed(multidata=multidata, spoiler=spoiler, patches=patches, owner=owner, id=sid)
|
||||
else:
|
||||
seed = Seed(multidata=multidata, spoiler=spoiler, patches=patches, owner=owner)
|
||||
for patch in patches:
|
||||
patch.seed = seed
|
||||
if sid:
|
||||
gen = Generation.get(id=sid)
|
||||
if gen is not None:
|
||||
gen.delete()
|
||||
return seed.id
|
||||
multidata = file
|
||||
|
||||
if not race or len(patches) > 1:
|
||||
try:
|
||||
multidata = json.loads(zlib.decompress(open(multidata, "rb").read()))
|
||||
except Exception as e:
|
||||
flash(e)
|
||||
raise e
|
||||
else:
|
||||
multidata = {}
|
||||
|
||||
with db_session:
|
||||
if sid:
|
||||
seed = Seed(multidata=multidata, spoiler=spoiler, patches=patches, owner=owner, id=sid)
|
||||
else:
|
||||
seed = Seed(multidata=multidata, spoiler=spoiler, patches=patches, owner=owner)
|
||||
for patch in patches:
|
||||
patch.seed = seed
|
||||
if sid:
|
||||
gen = Generation.get(id=sid)
|
||||
if gen is not None:
|
||||
gen.delete()
|
||||
return seed.id
|
||||
|
||||
@@ -1206,6 +1206,110 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"countdown_start_time": {
|
||||
"keyString": "countdown_start_time",
|
||||
"friendlyName": "Countdown Starting Time",
|
||||
"description": "The amount of time, in minutes, to start with in Timed Countdown and Timed OHKO modes.",
|
||||
"inputType": "range",
|
||||
"subOptions": {
|
||||
"0": {
|
||||
"keyString": "countdown_start_time.0",
|
||||
"friendlyName": 0,
|
||||
"description": "Start with no time on the timer. In Timed OHKO mode, start in OHKO mode.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"10": {
|
||||
"keyString": "countdown_start_time.10",
|
||||
"friendlyName": 10,
|
||||
"description": "Start with 10 minutes on the timer.",
|
||||
"defaultValue": 50
|
||||
},
|
||||
"20": {
|
||||
"keyString": "countdown_start_time.20",
|
||||
"friendlyName": 20,
|
||||
"description": "Start with 20 minutes on the timer.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"30": {
|
||||
"keyString": "countdown_start_time.30",
|
||||
"friendlyName": 30,
|
||||
"description": "Start with 30 minutes on the timer.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"60": {
|
||||
"keyString": "countdown_start_time.60",
|
||||
"friendlyName": 60,
|
||||
"description": "Start with an hour on the timer.",
|
||||
"defaultValue": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"red_clock_time": {
|
||||
"keyString": "red_clock_time",
|
||||
"friendlyName": "Red Clock Time",
|
||||
"description": "The amount of time, in minutes, to add to or subtract from the timer upon picking up a red clock.",
|
||||
"inputType": "range",
|
||||
"subOptions": {
|
||||
"-2": {
|
||||
"keyString": "red_clock_time.-2",
|
||||
"friendlyName": -2,
|
||||
"description": "Subtract 2 minutes from the timer upon picking up a red clock.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"1": {
|
||||
"keyString": "red_clock_time.1",
|
||||
"friendlyName": 1,
|
||||
"description": "Add a minute to the timer upon picking up a red clock.",
|
||||
"defaultValue": 50
|
||||
}
|
||||
}
|
||||
},
|
||||
"blue_clock_time": {
|
||||
"keyString": "blue_clock_time",
|
||||
"friendlyName": "Blue Clock Time",
|
||||
"description": "The amount of time, in minutes, to add to or subtract from the timer upon picking up a blue clock.",
|
||||
"inputType": "range",
|
||||
"subOptions": {
|
||||
"1": {
|
||||
"keyString": "blue_clock_time.1",
|
||||
"friendlyName": 1,
|
||||
"description": "Add a minute to the timer upon picking up a blue clock.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"2": {
|
||||
"keyString": "blue_clock_time.2",
|
||||
"friendlyName": 2,
|
||||
"description": "Add 2 minutes to the timer upon picking up a blue clock.",
|
||||
"defaultValue": 50
|
||||
}
|
||||
}
|
||||
},
|
||||
"green_clock_time": {
|
||||
"keyString": "green_clock_time",
|
||||
"friendlyName": "Green Clock Time",
|
||||
"description": "The amount of time, in minutes, to add to or subtract from the timer upon picking up a green clock.",
|
||||
"inputType": "range",
|
||||
"subOptions": {
|
||||
"4": {
|
||||
"keyString": "green_clock_time.4",
|
||||
"friendlyName": 4,
|
||||
"description": "Add 4 minutes to the timer upon picking up a green clock.",
|
||||
"defaultValue": 50
|
||||
},
|
||||
"10": {
|
||||
"keyString": "green_clock_time.10",
|
||||
"friendlyName": 10,
|
||||
"description": "Add 10 minutes to the timer upon picking up a green clock.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"15": {
|
||||
"keyString": "green_clock_time.15",
|
||||
"friendlyName": 15,
|
||||
"description": "Add 15 minutes to the timer upon picking up a green clock.",
|
||||
"defaultValue": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"glitch_boots": {
|
||||
"keyString": "glitch_boots",
|
||||
"friendlyName": "Glitch Boots",
|
||||
@@ -1572,26 +1676,26 @@
|
||||
},
|
||||
"hud_palettes": {
|
||||
"keyString": "rom.hud_palettes",
|
||||
"friendlyName": "Underworld Palettes",
|
||||
"description": "Randomize the colors of the underworld (caves, dungeons, etc.), within reason.",
|
||||
"friendlyName": "HUD Palettes",
|
||||
"description": "Randomize the colors of the HUD (user interface), within reason.",
|
||||
"inputType": "range",
|
||||
"subOptions": {
|
||||
"default": {
|
||||
"keyString": "rom.hud_palettes.default",
|
||||
"friendlyName": "Vanilla",
|
||||
"description": "Overworld colors will remain unchanged.",
|
||||
"description": "HUD colors will remain unchanged.",
|
||||
"defaultValue": 50
|
||||
},
|
||||
"random": {
|
||||
"keyString": "rom.hud_palettes.random",
|
||||
"friendlyName": "Random",
|
||||
"description": "Shuffles the colors of the overworld palette.",
|
||||
"description": "Shuffles the colors of the HUD palette.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"blackout": {
|
||||
"keyString": "rom.hud_palettes.blackout",
|
||||
"friendlyName": "Blackout",
|
||||
"description": "Never use this. Makes all overworld palette colors black.",
|
||||
"description": "Never use this. Makes all HUD palette colors black.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"grayscale": {
|
||||
@@ -1634,26 +1738,26 @@
|
||||
},
|
||||
"shield_palettes": {
|
||||
"keyString": "rom.shield_palettes",
|
||||
"friendlyName": "Underworld Palettes",
|
||||
"description": "Randomize the colors of the underworld (caves, dungeons, etc.), within reason.",
|
||||
"friendlyName": "Shield Palettes",
|
||||
"description": "Randomize the colors of the shield, within reason.",
|
||||
"inputType": "range",
|
||||
"subOptions": {
|
||||
"default": {
|
||||
"keyString": "rom.shield_palettes.default",
|
||||
"friendlyName": "Vanilla",
|
||||
"description": "Overworld colors will remain unchanged.",
|
||||
"description": "Shield colors will remain unchanged.",
|
||||
"defaultValue": 50
|
||||
},
|
||||
"random": {
|
||||
"keyString": "rom.shield_palettes.random",
|
||||
"friendlyName": "Random",
|
||||
"description": "Shuffles the colors of the overworld palette.",
|
||||
"description": "Shuffles the colors of the shield palette.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"blackout": {
|
||||
"keyString": "rom.shield_palettes.blackout",
|
||||
"friendlyName": "Blackout",
|
||||
"description": "Never use this. Makes all overworld palette colors black.",
|
||||
"description": "Never use this. Makes all shield palette colors black.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"grayscale": {
|
||||
@@ -1696,26 +1800,26 @@
|
||||
},
|
||||
"sword_palettes": {
|
||||
"keyString": "rom.sword_palettes",
|
||||
"friendlyName": "Underworld Palettes",
|
||||
"description": "Randomize the colors of the underworld (caves, dungeons, etc.), within reason.",
|
||||
"friendlyName": "Sword Palettes",
|
||||
"description": "Randomize the colors of the sword, within reason.",
|
||||
"inputType": "range",
|
||||
"subOptions": {
|
||||
"default": {
|
||||
"keyString": "rom.sword_palettes.default",
|
||||
"friendlyName": "Vanilla",
|
||||
"description": "Overworld colors will remain unchanged.",
|
||||
"description": "Sword colors will remain unchanged.",
|
||||
"defaultValue": 50
|
||||
},
|
||||
"random": {
|
||||
"keyString": "rom.sword_palettes.random",
|
||||
"friendlyName": "Random",
|
||||
"description": "Shuffles the colors of the overworld palette.",
|
||||
"description": "Shuffles the colors of the sword palette.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"blackout": {
|
||||
"keyString": "rom.sword_palettes.blackout",
|
||||
"friendlyName": "Blackout",
|
||||
"description": "Never use this. Makes all overworld palette colors black.",
|
||||
"description": "Never use this. Makes all sword palette colors black.",
|
||||
"defaultValue": 0
|
||||
},
|
||||
"grayscale": {
|
||||
|
||||
@@ -232,6 +232,22 @@ timer:
|
||||
ohko: 0 # Timer always at zero. Permanent OHKO.
|
||||
timed_countdown: 0 # Starts the clock with forty minutes. Same clocks as timed mode, but if the clock hits zero you lose. You can still keep playing, though.
|
||||
display: 0 # Displays a timer, but otherwise does not affect gameplay or the item pool.
|
||||
countdown_start_time: # For timed_ohko and timed_countdown timer modes, the amount of time in minutes to start with
|
||||
0: 0 # For timed_ohko, starts in OHKO mode when starting the game
|
||||
10: 50
|
||||
20: 0
|
||||
30: 0
|
||||
60: 0
|
||||
red_clock_time: # For all timer modes, the amount of time in minutes to gain or lose when picking up a red clock
|
||||
-2: 50
|
||||
1: 0
|
||||
blue_clock_time: # For all timer modes, the amount of time in minutes to gain or lose when picking up a blue clock
|
||||
1: 0
|
||||
2: 50
|
||||
green_clock_time: # For all timer modes, the amount of time in minutes to gain or lose when picking up a green clock
|
||||
4: 50
|
||||
10: 0
|
||||
15: 0
|
||||
# Can be uncommented to use it
|
||||
# local_items: # Force certain items to appear in your world only, not across the multiworld. Recognizes some group names, like "Swords"
|
||||
# - "Moon Pearl"
|
||||
@@ -391,13 +407,3 @@ rom:
|
||||
dizzy: 0
|
||||
sick: 0
|
||||
puke: 0
|
||||
uw_palettes: # Change the colors of shields
|
||||
default: 50 # No changes
|
||||
random: 0 # Shuffle the colors
|
||||
blackout: 0 # Never use this
|
||||
grayscale: 0
|
||||
negative: 0
|
||||
classic: 0
|
||||
dizzy: 0
|
||||
sick: 0
|
||||
puke: 0
|
||||
@@ -19,10 +19,10 @@
|
||||
You can also upload a .zip with multiple YAMLs.
|
||||
A proper menu is in the works.
|
||||
{% if race -%}
|
||||
Race Mode means the spoiler log will be unavailable.
|
||||
Race Mode means the spoiler log will be unavailable, roms will be encrypted and single-player has no multidata.
|
||||
{%- else -%}
|
||||
You can go to <a href="{{ url_for("generate", race=True) }}">Race Mode</a> to create a game without
|
||||
spoiler log.
|
||||
spoiler log and with encryption.
|
||||
{%- endif -%}
|
||||
</p>
|
||||
<p>
|
||||
|
||||
@@ -122,7 +122,7 @@
|
||||
<td>{{ player_names[(team, loop.index)]|e }}</td>
|
||||
{%- for area in ordered_areas -%}
|
||||
{%- set checks_done = checks[area] -%}
|
||||
{%- set checks_total = checks_in_area[area] -%}
|
||||
{%- set checks_total = checks_in_area[player][area] -%}
|
||||
{%- if checks_done == checks_total -%}
|
||||
<td class="item-acquired center-column">
|
||||
{{ checks_done }}/{{ checks_total }}</td>
|
||||
|
||||
@@ -11,6 +11,11 @@
|
||||
<div id="view-seed-wrapper">
|
||||
<div class="main-content">
|
||||
<h3>Seed Info</h3>
|
||||
{% if not seed.multidata and not seed.spoiler %}
|
||||
<h4>
|
||||
Single Player Race Rom: No spoiler or multidata exists, parts of the rom are encrypted and rooms cannot be created.
|
||||
</h4>
|
||||
{% endif %}
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
@@ -27,6 +32,7 @@
|
||||
<td><a href="{{ url_for("download_spoiler", seed_id=seed.id) }}">Download</a></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if seed.multidata %}
|
||||
<tr>
|
||||
<td>Players: </td>
|
||||
<td>
|
||||
@@ -55,6 +61,23 @@
|
||||
{% endcall %}
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td>Patches: </td>
|
||||
<td>
|
||||
<ul>
|
||||
{% for patch in seed.patches %}
|
||||
|
||||
<li>
|
||||
<a href="{{ url_for("download_raw_patch", seed_id=seed.id, player_id=patch.player) }}">Player {{ patch.player }}</a>
|
||||
</li>
|
||||
|
||||
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -180,6 +180,25 @@ default_locations = {
|
||||
60121, 60124, 60127, 1573217, 60130, 60133, 60136, 60139, 60142, 60145, 60148, 60151, 60157},
|
||||
'Total': set()}
|
||||
|
||||
key_only_locations = {
|
||||
'Light World': set(),
|
||||
'Dark World': set(),
|
||||
'Desert Palace': {0x140031, 0x14002b, 0x140061, 0x140028},
|
||||
'Eastern Palace': {0x14005b, 0x140049},
|
||||
'Hyrule Castle': {0x140037, 0x140034, 0x14000d, 0x14003d},
|
||||
'Agahnims Tower': {0x140061, 0x140052},
|
||||
'Tower of Hera': set(),
|
||||
'Swamp Palace': {0x140019, 0x140016, 0x140013, 0x140010, 0x14000a},
|
||||
'Thieves Town': {0x14005e, 0x14004f},
|
||||
'Skull Woods': {0x14002e, 0x14001c},
|
||||
'Ice Palace': {0x140004, 0x140022, 0x140025, 0x140046},
|
||||
'Misery Mire': {0x140055, 0x14004c, 0x140064},
|
||||
'Turtle Rock': {0x140058, 0x140007},
|
||||
'Palace of Darkness': set(),
|
||||
'Ganons Tower': {0x140040, 0x140043, 0x14003a, 0x14001f},
|
||||
'Total': set()
|
||||
}
|
||||
|
||||
key_locations = {"Desert Palace", "Eastern Palace", "Hyrule Castle", "Agahnims Tower", "Tower of Hera", "Swamp Palace",
|
||||
"Thieves Town", "Skull Woods", "Ice Palace", "Misery Mire", "Turtle Rock", "Palace of Darkness",
|
||||
"Ganons Tower"}
|
||||
@@ -191,6 +210,10 @@ for area, locations in default_locations.items():
|
||||
for location in locations:
|
||||
location_to_area[location] = area
|
||||
|
||||
for area, locations in key_only_locations.items():
|
||||
for location in locations:
|
||||
location_to_area[location] = area
|
||||
|
||||
checks_in_area = {area: len(checks) for area, checks in default_locations.items()}
|
||||
checks_in_area["Total"] = 216
|
||||
|
||||
@@ -235,6 +258,14 @@ def render_timedelta(delta: datetime.timedelta):
|
||||
|
||||
_multidata_cache = {}
|
||||
|
||||
def get_location_table(checks_table: dict) -> dict:
|
||||
loc_to_area = {}
|
||||
for area, locations in checks_table.items():
|
||||
if area == "Total":
|
||||
continue
|
||||
for location in locations:
|
||||
loc_to_area[location] = area
|
||||
return loc_to_area
|
||||
|
||||
def get_static_room_data(room: Room):
|
||||
result = _multidata_cache.get(room.seed.id, None)
|
||||
@@ -244,11 +275,30 @@ def get_static_room_data(room: Room):
|
||||
# in > 100 players this can take a bit of time and is the main reason for the cache
|
||||
locations = {tuple(k): tuple(v) for k, v in multidata['locations']}
|
||||
names = multidata["names"]
|
||||
seed_checks_in_area = checks_in_area.copy()
|
||||
|
||||
use_door_tracker = False
|
||||
if "tags" in multidata:
|
||||
use_door_tracker = "DR" in multidata["tags"]
|
||||
result = locations, names, use_door_tracker
|
||||
if use_door_tracker:
|
||||
for area, checks in key_only_locations.items():
|
||||
seed_checks_in_area[area] += len(checks)
|
||||
seed_checks_in_area["Total"] = 249
|
||||
if "checks_in_area" not in multidata:
|
||||
player_checks_in_area = {playernumber: (seed_checks_in_area if use_door_tracker and
|
||||
(0x140031, playernumber) in locations else checks_in_area)
|
||||
for playernumber in range(1, len(names[0]) + 1)}
|
||||
player_location_to_area = {playernumber: location_to_area
|
||||
for playernumber in range(1, len(names[0]) + 1)}
|
||||
|
||||
else:
|
||||
player_checks_in_area = {playernumber: {areaname: len(multidata["checks_in_area"][f'{playernumber}'][areaname])
|
||||
if areaname != "Total" else multidata["checks_in_area"][f'{playernumber}']["Total"]
|
||||
for areaname in ordered_areas}
|
||||
for playernumber in range(1, len(names[0]) + 1)}
|
||||
player_location_to_area = {playernumber: get_location_table(multidata["checks_in_area"][f'{playernumber}'])
|
||||
for playernumber in range(1, len(names[0]) + 1)}
|
||||
result = locations, names, use_door_tracker, player_checks_in_area, player_location_to_area
|
||||
_multidata_cache[room.seed.id] = result
|
||||
return result
|
||||
|
||||
@@ -259,7 +309,7 @@ def get_tracker(tracker: UUID):
|
||||
room = Room.get(tracker=tracker)
|
||||
if not room:
|
||||
abort(404)
|
||||
locations, names, use_door_tracker = get_static_room_data(room)
|
||||
locations, names, use_door_tracker, seed_checks_in_area, player_location_to_area = get_static_room_data(room)
|
||||
|
||||
inventory = {teamnumber: {playernumber: collections.Counter() for playernumber in range(1, len(team) + 1)}
|
||||
for teamnumber, team in enumerate(names)}
|
||||
@@ -280,9 +330,12 @@ def get_tracker(tracker: UUID):
|
||||
for item_id in precollected:
|
||||
attribute_item(inventory, team, player, item_id)
|
||||
for location in locations_checked:
|
||||
if (location, player) not in locations or location not in player_location_to_area[player]:
|
||||
continue
|
||||
|
||||
item, recipient = locations[location, player]
|
||||
attribute_item(inventory, team, recipient, item)
|
||||
checks_done[team][player][location_to_area[location]] += 1
|
||||
checks_done[team][player][player_location_to_area[player][location]] += 1
|
||||
checks_done[team][player]["Total"] += 1
|
||||
|
||||
for (team, player), game_state in room.multisave.get("client_game_state", []):
|
||||
@@ -311,7 +364,7 @@ def get_tracker(tracker: UUID):
|
||||
lookup_id_to_name=Items.lookup_id_to_name, player_names=player_names,
|
||||
tracking_names=tracking_names, tracking_ids=tracking_ids, room=room, icons=icons,
|
||||
multi_items=multi_items, checks_done=checks_done, ordered_areas=ordered_areas,
|
||||
checks_in_area=checks_in_area, activity_timers=activity_timers,
|
||||
checks_in_area=seed_checks_in_area, activity_timers=activity_timers,
|
||||
key_locations=key_locations, small_key_ids=small_key_ids, big_key_ids=big_key_ids,
|
||||
video=video, big_key_locations=key_locations if use_door_tracker else big_key_locations,
|
||||
hints=hints, long_player_names = long_player_names)
|
||||
|
||||
Reference in New Issue
Block a user