Generate: convert plando settings to an IntFlag with error reporting for unknown plando names (#735)
This commit is contained in:
parent
b9fb4de878
commit
3205cbf932
64
Generate.py
64
Generate.py
|
@ -1,3 +1,5 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import random
|
import random
|
||||||
|
@ -7,6 +9,7 @@ from typing import Set, Dict, Tuple, Callable, Any, Union
|
||||||
import os
|
import os
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
import string
|
import string
|
||||||
|
import enum
|
||||||
|
|
||||||
import ModuleUpdate
|
import ModuleUpdate
|
||||||
|
|
||||||
|
@ -25,7 +28,38 @@ from worlds.alttp.Text import TextTable
|
||||||
from worlds.AutoWorld import AutoWorldRegister
|
from worlds.AutoWorld import AutoWorldRegister
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
categories = set(AutoWorldRegister.world_types)
|
|
||||||
|
class PlandoSettings(enum.IntFlag):
|
||||||
|
items = 0b0001
|
||||||
|
connections = 0b0010
|
||||||
|
texts = 0b0100
|
||||||
|
bosses = 0b1000
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_option_string(cls, option_string: str) -> PlandoSettings:
|
||||||
|
result = cls(0)
|
||||||
|
for part in option_string.split(","):
|
||||||
|
part = part.strip().lower()
|
||||||
|
if part:
|
||||||
|
result = cls._handle_part(part, result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_set(cls, option_set: Set[str]) -> PlandoSettings:
|
||||||
|
result = cls(0)
|
||||||
|
for part in option_set:
|
||||||
|
result = cls._handle_part(part, result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _handle_part(cls, part: str, base: PlandoSettings) -> PlandoSettings:
|
||||||
|
try:
|
||||||
|
part = cls[part]
|
||||||
|
except Exception as e:
|
||||||
|
raise KeyError(f"{part} is not a recognized name for a plando module. "
|
||||||
|
f"Known options: {', '.join(flag.name for flag in cls)}") from e
|
||||||
|
else:
|
||||||
|
return base | part
|
||||||
|
|
||||||
|
|
||||||
def mystery_argparse():
|
def mystery_argparse():
|
||||||
|
@ -64,7 +98,7 @@ def mystery_argparse():
|
||||||
args.weights_file_path = os.path.join(args.player_files_path, args.weights_file_path)
|
args.weights_file_path = os.path.join(args.player_files_path, args.weights_file_path)
|
||||||
if not os.path.isabs(args.meta_file_path):
|
if not os.path.isabs(args.meta_file_path):
|
||||||
args.meta_file_path = os.path.join(args.player_files_path, args.meta_file_path)
|
args.meta_file_path = os.path.join(args.player_files_path, args.meta_file_path)
|
||||||
args.plando: Set[str] = {arg.strip().lower() for arg in args.plando.split(",")}
|
args.plando: PlandoSettings = PlandoSettings.from_option_string(args.plando)
|
||||||
return args, options
|
return args, options
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,7 +161,7 @@ def main(args=None, callback=ERmain):
|
||||||
|
|
||||||
args.multi = max(player_id-1, args.multi)
|
args.multi = max(player_id-1, args.multi)
|
||||||
print(f"Generating for {args.multi} player{'s' if args.multi > 1 else ''}, {seed_name} Seed {seed} with plando: "
|
print(f"Generating for {args.multi} player{'s' if args.multi > 1 else ''}, {seed_name} Seed {seed} with plando: "
|
||||||
f"{', '.join(args.plando)}")
|
f"{args.plando}")
|
||||||
|
|
||||||
if not weights_cache:
|
if not weights_cache:
|
||||||
raise Exception(f"No weights found. Provide a general weights file ({args.weights_file_path}) or individual player files. "
|
raise Exception(f"No weights found. Provide a general weights file ({args.weights_file_path}) or individual player files. "
|
||||||
|
@ -403,7 +437,7 @@ def roll_triggers(weights: dict, triggers: list) -> dict:
|
||||||
def get_plando_bosses(boss_shuffle: str, plando_options: Set[str]) -> str:
|
def get_plando_bosses(boss_shuffle: str, plando_options: Set[str]) -> str:
|
||||||
if boss_shuffle in boss_shuffle_options:
|
if boss_shuffle in boss_shuffle_options:
|
||||||
return boss_shuffle_options[boss_shuffle]
|
return boss_shuffle_options[boss_shuffle]
|
||||||
elif "bosses" in plando_options:
|
elif PlandoSettings.bosses in plando_options:
|
||||||
options = boss_shuffle.lower().split(";")
|
options = boss_shuffle.lower().split(";")
|
||||||
remainder_shuffle = "none" # vanilla
|
remainder_shuffle = "none" # vanilla
|
||||||
bosses = []
|
bosses = []
|
||||||
|
@ -452,7 +486,7 @@ def handle_option(ret: argparse.Namespace, game_weights: dict, option_key: str,
|
||||||
setattr(ret, option_key, option(option.default))
|
setattr(ret, option_key, option(option.default))
|
||||||
|
|
||||||
|
|
||||||
def roll_settings(weights: dict, plando_options: Set[str] = frozenset(("bosses",))):
|
def roll_settings(weights: dict, plando_options: PlandoSettings = PlandoSettings.bosses):
|
||||||
if "linked_options" in weights:
|
if "linked_options" in weights:
|
||||||
weights = roll_linked_options(weights)
|
weights = roll_linked_options(weights)
|
||||||
|
|
||||||
|
@ -465,17 +499,11 @@ def roll_settings(weights: dict, plando_options: Set[str] = frozenset(("bosses",
|
||||||
if tuplize_version(version) > version_tuple:
|
if tuplize_version(version) > version_tuple:
|
||||||
raise Exception(f"Settings reports required version of generator is at least {version}, "
|
raise Exception(f"Settings reports required version of generator is at least {version}, "
|
||||||
f"however generator is of version {__version__}")
|
f"however generator is of version {__version__}")
|
||||||
required_plando_options = requirements.get("plando", "")
|
required_plando_options = PlandoSettings.from_option_string(requirements.get("plando", ""))
|
||||||
|
if required_plando_options not in plando_options:
|
||||||
if required_plando_options:
|
if required_plando_options:
|
||||||
required_plando_options = set(option.strip() for option in required_plando_options.split(","))
|
raise Exception(f"Settings reports required plando module {str(required_plando_options)}, "
|
||||||
required_plando_options -= plando_options
|
|
||||||
if required_plando_options:
|
|
||||||
if len(required_plando_options) == 1:
|
|
||||||
raise Exception(f"Settings reports required plando module {', '.join(required_plando_options)}, "
|
|
||||||
f"which is not enabled.")
|
f"which is not enabled.")
|
||||||
else:
|
|
||||||
raise Exception(f"Settings reports required plando modules {', '.join(required_plando_options)}, "
|
|
||||||
f"which are not enabled.")
|
|
||||||
|
|
||||||
ret = argparse.Namespace()
|
ret = argparse.Namespace()
|
||||||
for option_key in Options.per_game_common_options:
|
for option_key in Options.per_game_common_options:
|
||||||
|
@ -504,12 +532,12 @@ def roll_settings(weights: dict, plando_options: Set[str] = frozenset(("bosses",
|
||||||
# skip setting this option if already set from common_options, defaulting to root option
|
# skip setting this option if already set from common_options, defaulting to root option
|
||||||
if not (option_key in Options.common_options and option_key not in game_weights):
|
if not (option_key in Options.common_options and option_key not in game_weights):
|
||||||
handle_option(ret, game_weights, option_key, option)
|
handle_option(ret, game_weights, option_key, option)
|
||||||
if "items" in plando_options:
|
if PlandoSettings.items in plando_options:
|
||||||
ret.plando_items = game_weights.get("plando_items", [])
|
ret.plando_items = game_weights.get("plando_items", [])
|
||||||
if ret.game == "Minecraft" or ret.game == "Ocarina of Time":
|
if ret.game == "Minecraft" or ret.game == "Ocarina of Time":
|
||||||
# bad hardcoded behavior to make this work for now
|
# bad hardcoded behavior to make this work for now
|
||||||
ret.plando_connections = []
|
ret.plando_connections = []
|
||||||
if "connections" in plando_options:
|
if PlandoSettings.connections in plando_options:
|
||||||
options = game_weights.get("plando_connections", [])
|
options = game_weights.get("plando_connections", [])
|
||||||
for placement in options:
|
for placement in options:
|
||||||
if roll_percentage(get_choice("percentage", placement, 100)):
|
if roll_percentage(get_choice("percentage", placement, 100)):
|
||||||
|
@ -629,7 +657,7 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
|
||||||
raise Exception(f"unknown Medallion {medallion} for {'misery mire' if index == 0 else 'turtle rock'}")
|
raise Exception(f"unknown Medallion {medallion} for {'misery mire' if index == 0 else 'turtle rock'}")
|
||||||
|
|
||||||
ret.plando_texts = {}
|
ret.plando_texts = {}
|
||||||
if "texts" in plando_options:
|
if PlandoSettings.texts in plando_options:
|
||||||
tt = TextTable()
|
tt = TextTable()
|
||||||
tt.removeUnwantedText()
|
tt.removeUnwantedText()
|
||||||
options = weights.get("plando_texts", [])
|
options = weights.get("plando_texts", [])
|
||||||
|
@ -641,7 +669,7 @@ def roll_alttp_settings(ret: argparse.Namespace, weights, plando_options):
|
||||||
ret.plando_texts[at] = str(get_choice_legacy("text", placement))
|
ret.plando_texts[at] = str(get_choice_legacy("text", placement))
|
||||||
|
|
||||||
ret.plando_connections = []
|
ret.plando_connections = []
|
||||||
if "connections" in plando_options:
|
if PlandoSettings.connections in plando_options:
|
||||||
options = weights.get("plando_connections", [])
|
options = weights.get("plando_connections", [])
|
||||||
for placement in options:
|
for placement in options:
|
||||||
if roll_percentage(get_choice_legacy("percentage", placement, 100)):
|
if roll_percentage(get_choice_legacy("percentage", placement, 100)):
|
||||||
|
|
|
@ -12,7 +12,7 @@ def allowed_file(filename):
|
||||||
return filename.endswith(('.txt', ".yaml", ".zip"))
|
return filename.endswith(('.txt', ".yaml", ".zip"))
|
||||||
|
|
||||||
|
|
||||||
from Generate import roll_settings
|
from Generate import roll_settings, PlandoSettings
|
||||||
from Utils import parse_yamls
|
from Utils import parse_yamls
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ def get_yaml_data(file) -> Union[Dict[str, str], str]:
|
||||||
def roll_options(options: Dict[str, Union[dict, str]],
|
def roll_options(options: Dict[str, Union[dict, str]],
|
||||||
plando_options: Set[str] = frozenset({"bosses", "items", "connections", "texts"})) -> \
|
plando_options: Set[str] = frozenset({"bosses", "items", "connections", "texts"})) -> \
|
||||||
Tuple[Dict[str, Union[str, bool]], Dict[str, dict]]:
|
Tuple[Dict[str, Union[str, bool]], Dict[str, dict]]:
|
||||||
plando_options = set(plando_options)
|
plando_options = PlandoSettings.from_set(set(plando_options))
|
||||||
results = {}
|
results = {}
|
||||||
rolled_results = {}
|
rolled_results = {}
|
||||||
for filename, text in options.items():
|
for filename, text in options.items():
|
||||||
|
|
|
@ -12,7 +12,7 @@ from flask import request, flash, redirect, url_for, session, render_template
|
||||||
from worlds.alttp.EntranceRandomizer import parse_arguments
|
from worlds.alttp.EntranceRandomizer import parse_arguments
|
||||||
from Main import main as ERmain
|
from Main import main as ERmain
|
||||||
from BaseClasses import seeddigits, get_seed
|
from BaseClasses import seeddigits, get_seed
|
||||||
from Generate import handle_name
|
from Generate import handle_name, PlandoSettings
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
from .models import *
|
from .models import *
|
||||||
|
@ -120,7 +120,7 @@ def gen_game(gen_options, meta: TypeOptional[Dict[str, object]] = None, owner=No
|
||||||
erargs.outputname = seedname
|
erargs.outputname = seedname
|
||||||
erargs.outputpath = target.name
|
erargs.outputpath = target.name
|
||||||
erargs.teams = 1
|
erargs.teams = 1
|
||||||
erargs.plando_options = ", ".join(plando_options)
|
erargs.plando_options = PlandoSettings.from_set(plando_options)
|
||||||
|
|
||||||
name_counter = Counter()
|
name_counter = Counter()
|
||||||
for player, (playerfile, settings) in enumerate(gen_options.items(), 1):
|
for player, (playerfile, settings) in enumerate(gen_options.items(), 1):
|
||||||
|
|
Loading…
Reference in New Issue