WebHost: add hint cost and forfeit mode to webgen page

This commit is contained in:
Fabian Dill 2021-10-11 00:46:18 +02:00
parent f7bd637073
commit a8b105267c
6 changed files with 55 additions and 35 deletions

30
Main.py
View File

@ -7,7 +7,7 @@ import concurrent.futures
import pickle
import tempfile
import zipfile
from typing import Dict, Tuple
from typing import Dict, Tuple, Optional
from BaseClasses import MultiWorld, CollectionState, Region, RegionType
from worlds.alttp.Items import item_name_groups
@ -19,7 +19,16 @@ from worlds.generic.Rules import locality_rules, exclusion_rules
from worlds import AutoWorld
def main(args, seed=None):
ordered_areas = (
'Light World', 'Dark World', 'Hyrule Castle', 'Agahnims Tower', 'Eastern Palace', 'Desert Palace',
'Tower of Hera', 'Palace of Darkness', 'Swamp Palace', 'Skull Woods', 'Thieves Town', 'Ice Palace',
'Misery Mire', 'Turtle Rock', 'Ganons Tower', "Total"
)
def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = None):
if not baked_server_options:
baked_server_options = get_options()["server_options"]
if args.outputpath:
os.makedirs(args.outputpath, exist_ok=True)
output_path.cached_path = args.outputpath
@ -159,15 +168,15 @@ def main(args, seed=None):
output = tempfile.TemporaryDirectory()
with output as temp_dir:
with concurrent.futures.ThreadPoolExecutor(world.players+2) as pool:
with concurrent.futures.ThreadPoolExecutor(world.players + 2) as pool:
check_accessibility_task = pool.submit(world.fulfills_accessibility)
output_file_futures = [pool.submit(AutoWorld.call_stage, world, "generate_output", temp_dir)]
for player in world.player_ids:
# skip starting a thread for methods that say "pass".
if AutoWorld.World.generate_output.__code__ is not world.worlds[player].generate_output.__code__:
output_file_futures.append(pool.submit(AutoWorld.call_single, world, "generate_output", player, temp_dir))
output_file_futures.append(
pool.submit(AutoWorld.call_single, world, "generate_output", player, temp_dir))
def get_entrance_to_region(region: Region):
for entrance in region.entrances:
@ -188,9 +197,7 @@ def main(args, seed=None):
if lookup_vanilla_location_to_entrance[location.address] != main_entrance.name:
er_hint_data[region.player][location.address] = main_entrance.name
ordered_areas = ('Light World', 'Dark World', 'Hyrule Castle', 'Agahnims Tower', 'Eastern Palace', 'Desert Palace',
'Tower of Hera', 'Palace of Darkness', 'Swamp Palace', 'Skull Woods', 'Thieves Town', 'Ice Palace',
'Misery Mire', 'Turtle Rock', 'Ganons Tower', "Total")
checks_in_area = {player: {area: list() for area in ordered_areas}
for player in range(1, world.players + 1)}
@ -219,8 +226,9 @@ def main(args, seed=None):
for index, take_any in enumerate(takeanyregions):
for region in [world.get_region(take_any, player) for player in
world.get_game_players("A Link to the Past") if world.retro[player]]:
item = world.create_item(region.shop.inventory[(0 if take_any == "Old Man Sword Cave" else 1)]['item'],
region.player)
item = world.create_item(
region.shop.inventory[(0 if take_any == "Old Man Sword Cave" else 1)]['item'],
region.player)
player = region.player
location_id = SHOP_ID_START + total_shop_slots + index
@ -286,7 +294,7 @@ def main(args, seed=None):
world.worlds[player].remote_start_inventory},
"locations": locations_data,
"checks_in_area": checks_in_area,
"server_options": get_options()["server_options"],
"server_options": baked_server_options,
"er_hint_data": er_hint_data,
"precollected_items": precollected_items,
"precollected_hints": precollected_hints,

View File

@ -89,7 +89,7 @@ def launch_generator(pool: multiprocessing.pool.Pool, generation: Generation):
options = restricted_loads(generation.options)
logging.info(f"Generating {generation.id} for {len(options)} players")
pool.apply_async(gen_game, (options,),
{"race": meta["race"],
{"meta": meta,
"sid": generation.id,
"owner": generation.owner},
handle_generation_success, handle_generation_failure)

View File

@ -4,6 +4,7 @@ import random
import json
import zipfile
from collections import Counter
from typing import Dict, Optional as TypeOptional
from flask import request, flash, redirect, url_for, session, render_template
@ -33,6 +34,14 @@ def generate(race=False):
flash(options)
else:
results, gen_options = roll_options(options)
# get form data -> server settings
hint_cost = int(request.form.get("hint_cost", 10))
forfeit_mode = request.form.get("forfeit_mode", "goal")
meta = {"race": race, "hint_cost": hint_cost, "forfeit_mode": forfeit_mode}
if race:
meta["item_cheat"] = False
meta["remaining"] = False
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"]:
@ -42,7 +51,8 @@ def generate(race=False):
gen = Generation(
options=pickle.dumps({name: vars(options) for name, options in gen_options.items()}),
# convert to json compatible
meta=json.dumps({"race": race}), state=STATE_QUEUED,
meta=json.dumps(meta),
state=STATE_QUEUED,
owner=session["_id"])
commit()
@ -50,18 +60,24 @@ def generate(race=False):
else:
try:
seed_id = gen_game({name: vars(options) for name, options in gen_options.items()},
race=race, owner=session["_id"].int)
meta=meta, owner=session["_id"].int)
except BaseException as e:
from .autolauncher import handle_generation_failure
handle_generation_failure(e)
return render_template("seedError.html", seed_error=(e.__class__.__name__ + ": "+ str(e)))
return render_template("seedError.html", seed_error=(e.__class__.__name__ + ": " + str(e)))
return redirect(url_for("viewSeed", seed=seed_id))
return render_template("generate.html", race=race)
def gen_game(gen_options, race=False, owner=None, sid=None):
def gen_game(gen_options, meta: TypeOptional[Dict[str, object]] = None, owner=None, sid=None):
if not meta:
meta: Dict[str, object] = {}
meta.setdefault("hint_cost", 10)
race = meta.get("race", False)
del (meta["race"])
try:
target = tempfile.TemporaryDirectory()
playercount = len(gen_options)
@ -95,7 +111,7 @@ def gen_game(gen_options, race=False, owner=None, sid=None):
erargs.name[player] = os.path.splitext(os.path.split(playerfile)[-1])[0]
erargs.name[player] = handle_name(erargs.name[player], player, name_counter)
ERmain(erargs, seed)
ERmain(erargs, seed, baked_server_options=meta)
return upload_to_db(target.name, sid, owner, race)
except BaseException as e:
@ -105,7 +121,7 @@ def gen_game(gen_options, race=False, owner=None, sid=None):
if gen is not None:
gen.state = STATE_ERROR
meta = json.loads(gen.meta)
meta["error"] = (e.__class__.__name__ + ": "+ str(e))
meta["error"] = (e.__class__.__name__ + ": " + str(e))
gen.meta = json.dumps(meta)
commit()

View File

@ -25,6 +25,6 @@
margin-bottom: 1rem;
}
#generate-game-form{
#file-input{
display: none;
}

View File

@ -37,6 +37,18 @@
<div id="generate-game-form-wrapper">
<form id="generate-game-form" method="post" enctype="multipart/form-data">
<input id="file-input" type="file" name="file">
<label data-tooltip="After gathering this many checks, players can !hint <itemname> to get the location of that item." for="hint_cost">Hint Cost:</label><select name="hint_cost" id="hint_cost">
{% for n in range(0, 110, 5) %}
<option {% if n == 10 %}selected="selected" {% endif %} value="{{ n }}">{% if n > 100 %}Off{% else %}{{ n }}%{% endif %}</option>
{% endfor %}
</select>
<label for="forfeit_mode">Forfeit Permission:</label><select name="forfeit_mode" id="forfeit_mode">
<option value="auto">Automatic on goal completion</option>
<option value="goal">Allow !forfeit after goal completion</option>
<option value="auto-enabled">Automatic on goal completion and manual !forfeit</option>
<option value="enabled">Manual !forfeit</option>
<option value="disabled">Disabled</option>
</select>
</form>
<button id="generate-game-button">Upload</button>
</div>

View File

@ -12,10 +12,6 @@
<div id="view-seed-wrapper">
<div id="view-seed" class="grass-island">
<h1>Seed Info</h1>
{% if not seed.multidata and not seed.spoiler %}
<p>Single Player Race Rom: No spoiler or multidata exists, parts of the rom are encrypted and rooms
cannot be created.</p>
{% endif %}
<table>
<tbody>
<tr>
@ -33,18 +29,6 @@
</tr>
{% endif %}
{% if seed.multidata %}
<tr>
<td>Players:&nbsp;</td>
<td>
<ul>
{% for patch in seed.slots|sort(attribute='player_id') %}
<li>
<a href="{{ url_for("download_raw_patch", seed_id=seed.id, player_id=patch.player_id) }}">{{ patch.player_name }}</a>
</li>
{% endfor %}
</ul>
</td>
</tr>
<tr>
<td>Rooms:&nbsp;</td>
<td>