allow basic WebHost functionality to work

This commit is contained in:
Fabian Dill 2021-04-04 03:18:19 +02:00
parent d451145d53
commit 20b72369d8
5 changed files with 57 additions and 40 deletions

View File

@ -119,7 +119,8 @@ class Context(Node):
self._load(self._decompress(data), use_embedded_server_options)
self.data_filename = multidatapath
def _decompress(self, data: bytes) -> dict:
@staticmethod
def _decompress(data: bytes) -> dict:
format_version = data[0]
if format_version != 1:
raise Exception("Incompatible multidata.")

View File

@ -84,9 +84,13 @@ def local_path(*path):
# cx_Freeze
local_path.cached_path = os.path.dirname(os.path.abspath(sys.argv[0]))
else:
# we are running in a normal Python environment
import __main__
local_path.cached_path = os.path.dirname(os.path.abspath(__main__.__file__))
if hasattr(__main__, "__file__"):
# we are running in a normal Python environment
local_path.cached_path = os.path.dirname(os.path.abspath(__main__.__file__))
else:
# pray
local_path.cached_path = os.path.abspath(".")
return os.path.join(local_path.cached_path, *path)

View File

@ -9,13 +9,13 @@ import socket
import threading
import time
import random
import zlib
import pickle
from .models import *
from MultiServer import Context, server, auto_shutdown, ServerCommandProcessor, ClientMessageProcessor
from Utils import get_public_ipv4, get_public_ipv6, parse_yaml
from Utils import get_public_ipv4, get_public_ipv6, restricted_loads
class CustomClientMessageProcessor(ClientMessageProcessor):
@ -81,7 +81,7 @@ class WebHostContext(Context):
def init_save(self, enabled: bool = True):
self.saving = enabled
if self.saving:
existing_savegame = Room.get(id=self.room_id).multisave
existing_savegame = restricted_loads(Room.get(id=self.room_id).multisave)
if existing_savegame:
self.set_save(existing_savegame)
self._start_async_saving()
@ -90,7 +90,7 @@ class WebHostContext(Context):
@db_session
def _save(self, exit_save:bool = False) -> bool:
room = Room.get(id=self.room_id)
room.multisave = self.get_save()
room.multisave = pickle.dumps(self.get_save())
# saving only occurs on activity, so we can "abuse" this information to mark this as last_activity
if not exit_save: # we don't want to count a shutdown as activity, which would restart the server again
room.last_activity = datetime.utcnow()

View File

@ -8,6 +8,7 @@ from uuid import UUID
from worlds.alttp import Items, Regions
from WebHostLib import app, cache, Room
from NetUtils import Hint
from Utils import restricted_loads
def get_id(item_name):
@ -253,7 +254,7 @@ for item_name, data in Items.item_table.items():
big_key_ids[area] = data[2]
ids_big_key[data[2]] = area
from MultiServer import get_item_name_from_id
from MultiServer import get_item_name_from_id, Context
def attribute_item(inventory, team, recipient, item):
@ -295,9 +296,9 @@ def get_static_room_data(room: Room):
result = _multidata_cache.get(room.seed.id, None)
if result:
return result
multidata = room.seed.multidata
multidata = Context._decompress(room.seed.multidata)
# 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']}
locations = multidata['locations']
names = multidata["names"]
seed_checks_in_area = checks_in_area.copy()
@ -308,30 +309,24 @@ def get_static_room_data(room: Room):
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)}
player_checks_in_area = {playernumber: {areaname: len(multidata["checks_in_area"][playernumber][areaname])
if areaname != "Total" else multidata["checks_in_area"][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"][playernumber])
for playernumber in range(1, len(names[0]) + 1)}
player_big_key_locations = {playernumber: set() for playernumber in range(1, len(names[0]) + 1)}
player_small_key_locations = {playernumber: set() for playernumber in range(1, len(names[0]) + 1)}
for _, (item_id, item_player) in multidata["locations"]:
for _, (item_id, item_player) in locations.items():
if item_id in ids_big_key:
player_big_key_locations[item_player].add(ids_big_key[item_id])
if item_id in ids_small_key:
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, player_big_key_locations, player_small_key_locations
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"]
_multidata_cache[room.seed.id] = result
return result
@ -348,7 +343,7 @@ def getPlayerTracker(tracker: UUID, tracked_team: int, tracked_player: int):
abort(404)
# 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 = 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 = get_static_room_data(room)
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]
@ -356,13 +351,18 @@ def getPlayerTracker(tracker: UUID, tracked_team: int, tracked_player: int):
checks_done = {loc_name: 0 for loc_name in default_locations}
# Add starting items to inventory
starting_items = room.seed.multidata.get("precollected_items", None)[tracked_player - 1]
starting_items = precollected_items[tracked_player - 1]
if starting_items:
for item_id in starting_items:
attribute_item_solo(inventory, item_id)
if room.multisave:
multisave = restricted_loads(room.multisave)
else:
multisave = {}
# Add items to player inventory
for (ms_team, ms_player), locations_checked in room.multisave.get("location_checks", {}):
for (ms_team, ms_player), locations_checked in multisave.get("location_checks", {}):
# logging.info(f"{ms_team}, {ms_player}, {locations_checked}")
# Skip teams and players not matching the request
@ -380,7 +380,7 @@ def getPlayerTracker(tracker: UUID, tracked_team: int, tracked_player: int):
checks_done["Total"] += 1
# Note the presence of the triforce item
for (ms_team, ms_player), game_state in room.multisave.get("client_game_state", []):
for (ms_team, ms_player), game_state in multisave.get("client_game_state", []):
# Skip teams and players not matching the request
if ms_team != tracked_team or ms_player != tracked_player:
continue
@ -484,7 +484,8 @@ def getTracker(tracker: UUID):
room = Room.get(tracker=tracker)
if not room:
abort(404)
locations, names, use_door_tracker, seed_checks_in_area, player_location_to_area, player_big_key_locations, player_small_key_locations = 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 = get_static_room_data(room)
inventory = {teamnumber: {playernumber: collections.Counter() for playernumber in range(1, len(team) + 1)}
for teamnumber, team in enumerate(names)}
@ -492,14 +493,18 @@ def getTracker(tracker: UUID):
checks_done = {teamnumber: {playernumber: {loc_name: 0 for loc_name in default_locations}
for playernumber in range(1, len(team) + 1)}
for teamnumber, team in enumerate(names)}
precollected_items = room.seed.multidata.get("precollected_items", None)
hints = {team: set() for team in range(len(names))}
if "hints" in room.multisave:
for key, hintdata in room.multisave["hints"]:
if room.multisave:
multisave = restricted_loads(room.multisave)
else:
multisave = {}
if "hints" in multisave:
for key, hintdata in multisave["hints"]:
for hint in hintdata:
hints[key[0]].add(Hint(*hint))
for (team, player), locations_checked in room.multisave.get("location_checks", {}):
for (team, player), locations_checked in multisave.get("location_checks", {}):
if precollected_items:
precollected = precollected_items[player - 1]
for item_id in precollected:
@ -513,7 +518,7 @@ def getTracker(tracker: UUID):
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", []):
for (team, player), game_state in multisave.get("client_game_state", []):
if game_state:
inventory[team][player][106] = 1 # Triforce
@ -525,7 +530,7 @@ def getTracker(tracker: UUID):
activity_timers = {}
now = datetime.datetime.utcnow()
for (team, player), timestamp in room.multisave.get("client_activity_timers", []):
for (team, player), timestamp in multisave.get("client_activity_timers", []):
activity_timers[team, player] = now - datetime.datetime.utcfromtimestamp(timestamp)
player_names = {}
@ -533,12 +538,12 @@ def getTracker(tracker: UUID):
for player, name in enumerate(names, 1):
player_names[(team, player)] = name
long_player_names = player_names.copy()
for (team, player), alias in room.multisave.get("name_aliases", []):
for (team, player), alias in multisave.get("name_aliases", []):
player_names[(team, player)] = alias
long_player_names[(team, player)] = f"{alias} ({long_player_names[(team, player)]})"
video = {}
for (team, player), data in room.multisave.get("video", []):
for (team, player), data in multisave.get("video", []):
video[(team, player)] = data
return render_template("tracker.html", inventory=inventory, get_item_name_from_id=get_item_name_from_id,

View File

@ -2,6 +2,7 @@ import json
import zlib
import zipfile
import logging
import MultiServer
from flask import request, flash, redirect, url_for, session, render_template
from pony.orm import commit, select
@ -46,9 +47,12 @@ def uploads():
spoiler = zfile.open(file, "r").read().decode("utf-8-sig")
elif file.filename.endswith(".archipelago"):
try:
multidata = json.loads(zlib.decompress(zfile.open(file).read()).decode("utf-8-sig"))
multidata = zfile.open(file).read()
MultiServer.Context._decompress(multidata)
except:
flash("Could not load multidata. File may be corrupted or incompatible.")
else:
multidata = zfile.open(file).read()
if multidata:
commit() # commit patches
seed = Seed(multidata=multidata, spoiler=spoiler, patches=patches, owner=session["_id"])
@ -61,10 +65,13 @@ def uploads():
flash("No multidata was found in the zip file, which is required.")
else:
try:
multidata = json.loads(zlib.decompress(file.read()).decode("utf-8-sig"))
multidata = file.read()
MultiServer.Context._decompress(multidata)
except:
flash("Could not load multidata. File may be corrupted or incompatible.")
raise
else:
logging.info(multidata)
seed = Seed(multidata=multidata, owner=session["_id"])
commit() # place into DB and generate ids
return redirect(url_for("viewSeed", seed=seed.id))