WebHost: On-Server rolling
This commit is contained in:
parent
cfb8e2ce71
commit
22abd09087
8
Main.py
8
Main.py
|
@ -216,11 +216,9 @@ def main(args, seed=None):
|
||||||
'S' if world.keyshuffle[player] else '', 'B' if world.bigkeyshuffle[player] else '')
|
'S' if world.keyshuffle[player] else '', 'B' if world.bigkeyshuffle[player] else '')
|
||||||
|
|
||||||
outfilepname = f'_T{team + 1}' if world.teams > 1 else ''
|
outfilepname = f'_T{team + 1}' if world.teams > 1 else ''
|
||||||
if world.players > 1:
|
outfilepname += f'_P{player}'
|
||||||
outfilepname += f'_P{player}'
|
outfilepname += f"_{world.player_names[player][team].replace(' ', '_')}" if world.player_names[player][
|
||||||
if world.players > 1 or world.teams > 1:
|
team] != 'Player%d' % player else ''
|
||||||
outfilepname += f"_{world.player_names[player][team].replace(' ', '_')}" if world.player_names[player][
|
|
||||||
team] != 'Player%d' % player else ''
|
|
||||||
outfilesuffix = ('_%s_%s-%s-%s-%s%s_%s-%s%s%s%s%s' % (world.logic[player], world.difficulty[player],
|
outfilesuffix = ('_%s_%s-%s-%s-%s%s_%s-%s%s%s%s%s' % (world.logic[player], world.difficulty[player],
|
||||||
world.difficulty_adjustments[player],
|
world.difficulty_adjustments[player],
|
||||||
world.mode[player], world.goal[player],
|
world.mode[player], world.goal[player],
|
||||||
|
|
38
Mystery.py
38
Mystery.py
|
@ -103,27 +103,27 @@ def main(args=None, callback = ERmain):
|
||||||
# set up logger
|
# set up logger
|
||||||
if args.loglevel:
|
if args.loglevel:
|
||||||
erargs.loglevel = args.loglevel
|
erargs.loglevel = args.loglevel
|
||||||
loglevel = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}[erargs.loglevel]
|
loglevel = {'error': logging.ERROR, 'info': logging.INFO, 'warning': logging.WARNING, 'debug': logging.DEBUG}[
|
||||||
|
erargs.loglevel]
|
||||||
import sys
|
|
||||||
class LoggerWriter(object):
|
|
||||||
def __init__(self, writer):
|
|
||||||
self._writer = writer
|
|
||||||
self._msg = ''
|
|
||||||
|
|
||||||
def write(self, message):
|
|
||||||
self._msg = self._msg + message
|
|
||||||
while '\n' in self._msg:
|
|
||||||
pos = self._msg.find('\n')
|
|
||||||
self._writer(self._msg[:pos])
|
|
||||||
self._msg = self._msg[pos + 1:]
|
|
||||||
|
|
||||||
def flush(self):
|
|
||||||
if self._msg != '':
|
|
||||||
self._writer(self._msg)
|
|
||||||
self._msg = ''
|
|
||||||
|
|
||||||
if args.log_output_path:
|
if args.log_output_path:
|
||||||
|
import sys
|
||||||
|
class LoggerWriter(object):
|
||||||
|
def __init__(self, writer):
|
||||||
|
self._writer = writer
|
||||||
|
self._msg = ''
|
||||||
|
|
||||||
|
def write(self, message):
|
||||||
|
self._msg = self._msg + message
|
||||||
|
while '\n' in self._msg:
|
||||||
|
pos = self._msg.find('\n')
|
||||||
|
self._writer(self._msg[:pos])
|
||||||
|
self._msg = self._msg[pos + 1:]
|
||||||
|
|
||||||
|
def flush(self):
|
||||||
|
if self._msg != '':
|
||||||
|
self._writer(self._msg)
|
||||||
|
self._msg = ''
|
||||||
log = logging.getLogger("stderr")
|
log = logging.getLogger("stderr")
|
||||||
log.addHandler(logging.StreamHandler())
|
log.addHandler(logging.StreamHandler())
|
||||||
sys.stderr = LoggerWriter(log.error)
|
sys.stderr = LoggerWriter(log.error)
|
||||||
|
|
|
@ -42,6 +42,7 @@ app.config["PONY"] = {
|
||||||
'filename': os.path.abspath('db.db3'),
|
'filename': os.path.abspath('db.db3'),
|
||||||
'create_db': True
|
'create_db': True
|
||||||
}
|
}
|
||||||
|
app.config["MAX_ROLL"] = 20
|
||||||
app.config["CACHE_TYPE"] = "simple"
|
app.config["CACHE_TYPE"] = "simple"
|
||||||
app.autoversion = True
|
app.autoversion = True
|
||||||
av = Autoversion(app)
|
av = Autoversion(app)
|
||||||
|
@ -133,5 +134,6 @@ def favicon():
|
||||||
return send_from_directory(os.path.join(app.root_path, 'static'),
|
return send_from_directory(os.path.join(app.root_path, 'static'),
|
||||||
'favicon.ico', mimetype='image/vnd.microsoft.icon')
|
'favicon.ico', mimetype='image/vnd.microsoft.icon')
|
||||||
|
|
||||||
|
|
||||||
from WebHostLib.customserver import run_server_process
|
from WebHostLib.customserver import run_server_process
|
||||||
from . import tracker, upload, landing, check # to trigger app routing picking up on it
|
from . import tracker, upload, landing, check, generate # to trigger app routing picking up on it
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import zipfile
|
import zipfile
|
||||||
|
from typing import *
|
||||||
|
|
||||||
from flask import request, flash, redirect, url_for, session, render_template
|
from flask import request, flash, redirect, url_for, session, render_template
|
||||||
|
|
||||||
|
@ -11,9 +11,11 @@ banned_zip_contents = (".sfc",)
|
||||||
def allowed_file(filename):
|
def allowed_file(filename):
|
||||||
return filename.endswith(('.txt', ".yaml", ".zip"))
|
return filename.endswith(('.txt', ".yaml", ".zip"))
|
||||||
|
|
||||||
|
|
||||||
from Mystery import roll_settings
|
from Mystery import roll_settings
|
||||||
from Utils import parse_yaml
|
from Utils import parse_yaml
|
||||||
|
|
||||||
|
|
||||||
@app.route('/mysterycheck', methods=['GET', 'POST'])
|
@app.route('/mysterycheck', methods=['GET', 'POST'])
|
||||||
def mysterycheck():
|
def mysterycheck():
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
@ -21,46 +23,56 @@ def mysterycheck():
|
||||||
if 'file' not in request.files:
|
if 'file' not in request.files:
|
||||||
flash('No file part')
|
flash('No file part')
|
||||||
else:
|
else:
|
||||||
options = {}
|
|
||||||
file = request.files['file']
|
file = request.files['file']
|
||||||
# if user does not select file, browser also
|
options = get_yaml_data(file)
|
||||||
# submit an empty part without filename
|
if type(options) == str:
|
||||||
if file.filename == '':
|
flash(options)
|
||||||
flash('No selected file')
|
|
||||||
elif file and allowed_file(file.filename):
|
|
||||||
if file.filename.endswith(".zip"):
|
|
||||||
|
|
||||||
with zipfile.ZipFile(file, 'r') as zfile:
|
|
||||||
infolist = zfile.infolist()
|
|
||||||
|
|
||||||
for file in infolist:
|
|
||||||
if file.filename.endswith(banned_zip_contents):
|
|
||||||
return "Uploaded data contained a rom file, which is likely to contain copyrighted material. Your file was deleted."
|
|
||||||
elif file.filename.endswith(".yaml"):
|
|
||||||
options[file.filename] = zfile.open(file, "r").read()
|
|
||||||
elif file.filename.endswith(".txt"):
|
|
||||||
options[file.filename] = zfile.open(file, "r").read()
|
|
||||||
else:
|
|
||||||
options = {file.filename: file.read()}
|
|
||||||
if not options:
|
|
||||||
flash("Did not find a .yaml file to process.")
|
|
||||||
else:
|
|
||||||
results = {}
|
|
||||||
for filename, text in options.items():
|
|
||||||
try:
|
|
||||||
yaml_data = parse_yaml(text)
|
|
||||||
except Exception as e:
|
|
||||||
results[filename] = f"Failed to parse YAML data in {filename}: {e}"
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
roll_settings(yaml_data)
|
|
||||||
except Exception as e:
|
|
||||||
results[filename] = f"Failed to generate mystery in {filename}: {e}"
|
|
||||||
else:
|
|
||||||
results[filename] = "Looks fine"
|
|
||||||
return render_template("checkresult.html", results=results)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
flash("Not recognized file format. Awaiting a .yaml file.")
|
results, _ = roll_yamls(options)
|
||||||
|
return render_template("checkresult.html", results=results)
|
||||||
|
|
||||||
return render_template("check.html")
|
return render_template("check.html")
|
||||||
|
|
||||||
|
|
||||||
|
def get_yaml_data(file) -> Union[Dict[str, str], str]:
|
||||||
|
options = {}
|
||||||
|
# if user does not select file, browser also
|
||||||
|
# submit an empty part without filename
|
||||||
|
if file.filename == '':
|
||||||
|
return 'No selected file'
|
||||||
|
elif file and allowed_file(file.filename):
|
||||||
|
if file.filename.endswith(".zip"):
|
||||||
|
|
||||||
|
with zipfile.ZipFile(file, 'r') as zfile:
|
||||||
|
infolist = zfile.infolist()
|
||||||
|
|
||||||
|
for file in infolist:
|
||||||
|
if file.filename.endswith(banned_zip_contents):
|
||||||
|
return "Uploaded data contained a rom file, which is likely to contain copyrighted material. Your file was deleted."
|
||||||
|
elif file.filename.endswith(".yaml"):
|
||||||
|
options[file.filename] = zfile.open(file, "r").read()
|
||||||
|
elif file.filename.endswith(".txt"):
|
||||||
|
options[file.filename] = zfile.open(file, "r").read()
|
||||||
|
else:
|
||||||
|
options = {file.filename: file.read()}
|
||||||
|
if not options:
|
||||||
|
return "Did not find a .yaml file to process."
|
||||||
|
return options
|
||||||
|
|
||||||
|
|
||||||
|
def roll_yamls(options: Dict[str, Union[str, 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)
|
||||||
|
except Exception as e:
|
||||||
|
results[filename] = f"Failed to parse YAML data in {filename}: {e}"
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
rolled_results[filename] = roll_settings(yaml_data)
|
||||||
|
except Exception as e:
|
||||||
|
results[filename] = f"Failed to generate mystery in {filename}: {e}"
|
||||||
|
else:
|
||||||
|
results[filename] = True
|
||||||
|
return results, rolled_results
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
import random
|
||||||
|
import zlib
|
||||||
|
import json
|
||||||
|
|
||||||
|
from flask import request, flash, redirect, url_for, session, render_template, send_file, Response
|
||||||
|
|
||||||
|
from EntranceRandomizer import parse_arguments
|
||||||
|
from Main import main as ERmain
|
||||||
|
from Main import get_seed, seeddigits
|
||||||
|
from Patch import update_patch_data
|
||||||
|
|
||||||
|
from .models import *
|
||||||
|
from WebHostLib import app
|
||||||
|
from .check import get_yaml_data, roll_yamls
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/generate', methods=['GET', 'POST'])
|
||||||
|
@app.route('/generate/<race>', methods=['GET', 'POST'])
|
||||||
|
def generate(race=False):
|
||||||
|
if request.method == 'POST':
|
||||||
|
# check if the post request has the file part
|
||||||
|
if 'file' not in request.files:
|
||||||
|
flash('No file part')
|
||||||
|
else:
|
||||||
|
file = request.files['file']
|
||||||
|
options = get_yaml_data(file)
|
||||||
|
if type(options) == str:
|
||||||
|
flash(options)
|
||||||
|
else:
|
||||||
|
results, gen_options = roll_yamls(options)
|
||||||
|
if any(result == str for result in results.values()):
|
||||||
|
return render_template("checkresult.html", results=results)
|
||||||
|
elif len(gen_options) > app.config["MAX_ROLL"]:
|
||||||
|
flash(f"Sorry, generating of multiworld is limited to {app.config['MAX_ROLL']} players for now. "
|
||||||
|
f"If you have a larger group, please generate it yourself and upload it.")
|
||||||
|
else:
|
||||||
|
seed_id = gen(gen_options, race=race)
|
||||||
|
return redirect(url_for("view_seed", seed=seed_id))
|
||||||
|
return render_template("generate.html", race=race)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/dl_patch/<int:patch_id>/<suuid:room_id>")
|
||||||
|
def download_patch(patch_id, room_id):
|
||||||
|
patch = Patch.get(id=patch_id)
|
||||||
|
if not patch:
|
||||||
|
return "Patch not found"
|
||||||
|
else:
|
||||||
|
import io
|
||||||
|
|
||||||
|
room = Room.get(id=room_id)
|
||||||
|
last_port = room.last_port
|
||||||
|
pname = room.seed.multidata["names"][0][patch.player - 1]
|
||||||
|
|
||||||
|
patch_data = update_patch_data(patch.data, server="berserkermulti.world:" + str(last_port))
|
||||||
|
patch_data = io.BytesIO(patch_data)
|
||||||
|
|
||||||
|
fname = f"P{patch.player}_{pname}_{app.jinja_env.filters['suuid'](room_id)}.bmbp"
|
||||||
|
return send_file(patch_data, as_attachment=True, attachment_filename=fname)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/dl_spoiler/<suuid:seed_id>")
|
||||||
|
def download_spoiler(seed_id):
|
||||||
|
return Response(Seed.get(id=seed_id).spoiler[3:], mimetype="text/plain")
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/dl_raw_patch/<suuid:seed_id>/<int:player_id>")
|
||||||
|
def download_raw_patch(seed_id, player_id):
|
||||||
|
patch = select(patch for patch in Patch if patch.player == player_id and patch.seed.id == seed_id).first()
|
||||||
|
|
||||||
|
if not patch:
|
||||||
|
return "Patch not found"
|
||||||
|
else:
|
||||||
|
import io
|
||||||
|
|
||||||
|
pname = patch.seed.multidata["names"][0][patch.player - 1]
|
||||||
|
|
||||||
|
patch_data = update_patch_data(patch.data, server="")
|
||||||
|
patch_data = io.BytesIO(patch_data)
|
||||||
|
|
||||||
|
fname = f"P{patch.player}_{pname}_{app.jinja_env.filters['suuid'](seed_id)}.bmbp"
|
||||||
|
return send_file(patch_data, as_attachment=True, attachment_filename=fname)
|
||||||
|
|
||||||
|
|
||||||
|
def gen(gen_options, race=False):
|
||||||
|
target = tempfile.TemporaryDirectory()
|
||||||
|
with target:
|
||||||
|
playercount = len(gen_options)
|
||||||
|
seed = get_seed()
|
||||||
|
random.seed(seed)
|
||||||
|
|
||||||
|
if race:
|
||||||
|
random.seed() # reset to time-based random source
|
||||||
|
|
||||||
|
seedname = "M" + (f"{random.randint(0, pow(10, seeddigits) - 1)}".zfill(seeddigits))
|
||||||
|
|
||||||
|
erargs = parse_arguments(['--multi', str(playercount)])
|
||||||
|
erargs.seed = seed
|
||||||
|
erargs.name = {x: "" for x in range(1, playercount + 1)} # only so it can be overwrittin in mystery
|
||||||
|
erargs.create_spoiler = not race
|
||||||
|
erargs.race = race
|
||||||
|
erargs.skip_playthrough = race
|
||||||
|
erargs.outputname = seedname
|
||||||
|
erargs.outputpath = target.name
|
||||||
|
erargs.teams = 1
|
||||||
|
erargs.progression_balancing = {}
|
||||||
|
erargs.create_diff = True
|
||||||
|
|
||||||
|
for player, (playerfile, settings) in enumerate(gen_options.items(), 1):
|
||||||
|
for k, v in vars(settings).items():
|
||||||
|
if v is not None:
|
||||||
|
getattr(erargs, k)[player] = v
|
||||||
|
|
||||||
|
if not erargs.name[player]:
|
||||||
|
erargs.name[player] = os.path.split(playerfile)[-1].split(".")[0]
|
||||||
|
|
||||||
|
erargs.names = ",".join(erargs.name[i] for i in range(1, playercount + 1))
|
||||||
|
del (erargs.name)
|
||||||
|
|
||||||
|
erargs.skip_progression_balancing = {player: not balanced for player, balanced in
|
||||||
|
erargs.progression_balancing.items()}
|
||||||
|
del (erargs.progression_balancing)
|
||||||
|
ERmain(erargs, seed)
|
||||||
|
return upload_to_db(target.name)
|
||||||
|
|
||||||
|
|
||||||
|
def upload_to_db(folder):
|
||||||
|
patches = set()
|
||||||
|
spoiler = ""
|
||||||
|
multidata = None
|
||||||
|
for file in os.listdir(folder):
|
||||||
|
file = os.path.join(folder, file)
|
||||||
|
if file.endswith(".bmbp"):
|
||||||
|
player = int(file.split("P")[-1].split(".")[0].split("_")[0])
|
||||||
|
patches.add(Patch(data=open(file, "rb").read(), player=player))
|
||||||
|
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:
|
||||||
|
commit() # commit patches
|
||||||
|
seed = Seed(multidata=multidata, spoiler=spoiler, patches=patches, owner=session["_id"])
|
||||||
|
commit() # create seed
|
||||||
|
for patch in patches:
|
||||||
|
patch.seed = seed
|
||||||
|
return seed.id
|
|
@ -4,3 +4,4 @@ waitress>=1.4.4
|
||||||
flask-caching>=1.9.0
|
flask-caching>=1.9.0
|
||||||
Flask-Autoversion>=0.2.0
|
Flask-Autoversion>=0.2.0
|
||||||
Flask-Compress>=1.5.0
|
Flask-Compress>=1.5.0
|
||||||
|
Flask-Limiter>=1.3.1
|
|
@ -0,0 +1,9 @@
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
document.getElementById('upload-button').addEventListener('click', () => {
|
||||||
|
document.getElementById('file-input').click();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('file-input').addEventListener('change', () => {
|
||||||
|
document.getElementById('upload-form').submit();
|
||||||
|
});
|
||||||
|
});
|
|
@ -6,7 +6,7 @@
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
{% for filename, resulttext in results.items() %}
|
{% for filename, resulttext in results.items() %}
|
||||||
<span>{{ filename }}: {{ resulttext }}</span><br>
|
<span>{{ filename }}: {{ "Looks ok" if resulttext == True else resulttext }}</span><br>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% block head %}
|
||||||
|
{{ super() }}
|
||||||
|
<title>Generate Game</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ static_autoversion("uploads.css") }}"/>
|
||||||
|
<script type="application/ecmascript" src="{{ static_autoversion("generate.js") }}"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div id="uploads-wrapper">
|
||||||
|
<div id="uploads" class="main-content">
|
||||||
|
<h3>Upload YAML(s){% if race %} (Race Mode){% endif %}</h3>
|
||||||
|
<p>
|
||||||
|
This page accepts a yaml file containing generator options.
|
||||||
|
You can find a documented example at <a
|
||||||
|
href="https://raw.githubusercontent.com/Berserker66/MultiWorld-Utilities/master/easy.yaml">easy.yaml</a>.
|
||||||
|
This file can be saved as .yaml, edited to your liking and then supplied to the generator.
|
||||||
|
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.
|
||||||
|
{%- else -%}
|
||||||
|
You can go to <a href="{{ url_for("generate", race=True) }}">Race Mode</a> to create a game without
|
||||||
|
spoiler log.
|
||||||
|
{%- endif -%}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
After generation is complete, you will have the option to download a patch file.
|
||||||
|
This patch file can be opened with the <a
|
||||||
|
href="https://github.com/Berserker66/MultiWorld-Utilities/releases">Client</a> to create a rom file.
|
||||||
|
In-Browser patching will come.
|
||||||
|
</p>
|
||||||
|
<div id="uploads-form-wrapper">
|
||||||
|
<form id="upload-form" method="post" enctype="multipart/form-data">
|
||||||
|
<input id="file-input" type="file" name="file">
|
||||||
|
</form>
|
||||||
|
<button id="upload-button">Upload</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -1,5 +1,5 @@
|
||||||
{% extends 'layout.html' %}
|
{% extends 'layout.html' %}
|
||||||
|
{% import "macros.html" as macros %}
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<title>Multiworld {{ room.id|suuid }}</title>
|
<title>Multiworld {{ room.id|suuid }}</title>
|
||||||
<link rel="stylesheet" type="text/css" href="{{ static_autoversion("host_room.css") }}"/>
|
<link rel="stylesheet" type="text/css" href="{{ static_autoversion("host_room.css") }}"/>
|
||||||
|
@ -18,6 +18,10 @@
|
||||||
This room will be closed after {{ room.timeout//60//60 }} hours of inactivity. Should you wish to continue
|
This room will be closed after {{ room.timeout//60//60 }} hours of inactivity. Should you wish to continue
|
||||||
later,
|
later,
|
||||||
you can simply refresh this page and the server will be started again.<br>
|
you can simply refresh this page and the server will be started again.<br>
|
||||||
|
{% if room.last_port %}
|
||||||
|
You can connect to this room by using '/connect berserkermulti.world:{{ room.last_port }}'
|
||||||
|
in the <a href="https://github.com/Berserker66/MultiWorld-Utilities/releases">client</a>.<br>{% endif %}
|
||||||
|
{{ macros.list_patches_room(room.seed.patches, room) }}
|
||||||
{% if room.owner == session["_id"] %}
|
{% if room.owner == session["_id"] %}
|
||||||
<form method=post>
|
<form method=post>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -26,15 +30,15 @@
|
||||||
placeholder="Server Command. /help to list them, list gets appended to log.">
|
placeholder="Server Command. /help to list them, list gets appended to log.">
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
{% endif %}
|
|
||||||
Log:
|
Log:
|
||||||
<div id="logger"></div>
|
<div id="logger"></div>
|
||||||
<script>
|
<script>
|
||||||
let xmlhttp = new XMLHttpRequest();
|
let xmlhttp = new XMLHttpRequest();
|
||||||
let url = '{{ url_for('display_log', room = room.id) }}';
|
let url = '{{ url_for('display_log', room = room.id) }}';
|
||||||
|
|
||||||
xmlhttp.onreadystatechange = function () {
|
xmlhttp.onreadystatechange = function () {
|
||||||
if (this.readyState == 4 && this.status == 200) {
|
if (this.readyState === 4 && this.status === 200) {
|
||||||
document.getElementById("logger").innerText = this.responseText;
|
document.getElementById("logger").innerText = this.responseText;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -47,5 +51,6 @@
|
||||||
window.setTimeout(request_new, 1000);
|
window.setTimeout(request_new, 1000);
|
||||||
window.setInterval(request_new, 10000);
|
window.setInterval(request_new, 10000);
|
||||||
</script>
|
</script>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -19,9 +19,15 @@
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div id="landing-buttons">
|
<div id="landing-buttons">
|
||||||
<a href="uploads">
|
<a href="{{ url_for("generate") }}">
|
||||||
<button>Start Playing</button>
|
<button>Start Playing</button>
|
||||||
</a>
|
</a>
|
||||||
|
<a href="{{ url_for("uploads") }}">
|
||||||
|
<button>Upload Multiworld</button>
|
||||||
|
</a>
|
||||||
|
<a href="{{ url_for("mysterycheck") }}">
|
||||||
|
<button>Test YAML Config</button>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div id="landing-body">
|
<div id="landing-body">
|
||||||
<p>This is a <span data-tooltip="Allegedly.">randomizer</span> for The Legend of Zelda: A
|
<p>This is a <span data-tooltip="Allegedly.">randomizer</span> for The Legend of Zelda: A
|
||||||
|
|
|
@ -6,3 +6,13 @@
|
||||||
{{ caller() }}
|
{{ caller() }}
|
||||||
</ul>
|
</ul>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
{% macro list_patches_room(patches, room) %}
|
||||||
|
{% if patches %}
|
||||||
|
<ul>
|
||||||
|
{% for patch in patches %}
|
||||||
|
<li><a href="{{ url_for("download_patch", patch_id=patch.id, room_id=room.id) }}">
|
||||||
|
Patch for player {{ patch.player }} - {{ room.seed.multidata["names"][0][patch.player-1] }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{%- endmacro -%}
|
|
@ -21,25 +21,33 @@
|
||||||
<td>Created: </td>
|
<td>Created: </td>
|
||||||
<td id="creation-time" data-creation-time="{{ seed.creation_time }}"></td>
|
<td id="creation-time" data-creation-time="{{ seed.creation_time }}"></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% if seed.spoiler %}
|
||||||
|
<tr>
|
||||||
|
<td>Spoiler: </td>
|
||||||
|
<td><a href="{{ url_for("download_spoiler", seed_id=seed.id) }}">Download</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>Players: </td>
|
<td>Players: </td>
|
||||||
<td>
|
<td>
|
||||||
<ul>
|
<ul>
|
||||||
{% for team in seed.multidata["names"] %}
|
{% for team in seed.multidata["names"] %}
|
||||||
<li>Team #{{ loop.index }} - {{ team | length }}
|
<li>Team #{{ loop.index }} - {{ team | length }}
|
||||||
<ul>
|
<ul>
|
||||||
{% for player in team %}
|
{% for player in team %}
|
||||||
<li>{{ player }}</li>
|
<li>
|
||||||
{% endfor %}
|
<a href="{{ url_for("download_raw_patch", seed_id=seed.id, player_id=loop.index) }}">{{ player }}</a>
|
||||||
</ul>
|
</li>
|
||||||
</li>
|
{% endfor %}
|
||||||
{% endfor %}
|
</ul>
|
||||||
</ul>
|
</li>
|
||||||
</td>
|
{% endfor %}
|
||||||
</tr>
|
</ul>
|
||||||
<tr>
|
</td>
|
||||||
<td>Rooms: </td>
|
</tr>
|
||||||
<td>
|
<tr>
|
||||||
|
<td>Rooms: </td>
|
||||||
|
<td>
|
||||||
{% call macros.list_rooms(rooms) %}
|
{% call macros.list_rooms(rooms) %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ url_for("new_room", seed=seed.id) }}">Create New Room</a>
|
<a href="{{ url_for("new_room", seed=seed.id) }}">Create New Room</a>
|
||||||
|
|
Loading…
Reference in New Issue