diff --git a/Launcher.py b/Launcher.py index be40987e..2dfc466a 100644 --- a/Launcher.py +++ b/Launcher.py @@ -14,10 +14,12 @@ import itertools import shlex import subprocess import sys +import webbrowser from os.path import isfile from shutil import which from typing import Sequence, Union, Optional +import Utils from worlds.LauncherComponents import Component, components, Type, SuffixIdentifier if __name__ == "__main__": @@ -38,7 +40,6 @@ def open_host_yaml(): exe = which("open") subprocess.Popen([exe, file]) else: - import webbrowser webbrowser.open(file) @@ -58,23 +59,36 @@ def open_patch(): launch([*get_exe(component), file], component.cli) +def generate_yamls(): + from Options import generate_yaml_templates + + target = Utils.user_path("Players", "Templates") + generate_yaml_templates(target, False) + open_folder(target) + + def browse_files(): - file = user_path() + open_folder(user_path()) + + +def open_folder(folder_path): if is_linux: exe = which('xdg-open') or which('gnome-open') or which('kde-open') - subprocess.Popen([exe, file]) + subprocess.Popen([exe, folder_path]) elif is_macos: exe = which("open") - subprocess.Popen([exe, file]) + subprocess.Popen([exe, folder_path]) else: - import webbrowser - webbrowser.open(file) + webbrowser.open(folder_path) components.extend([ # Functions Component('Open host.yaml', func=open_host_yaml), Component('Open Patch', func=open_patch), + Component('Generate Template Settings', func=generate_yamls), + Component('Discord Server', func=lambda: webbrowser.open("https://discord.gg/8Z65BR2")), + Component('18+ Discord Server', func=lambda: webbrowser.open("https://discord.gg/fqvNCCRsu4")), Component('Browse Files', func=browse_files), ]) diff --git a/Options.py b/Options.py index 6fe70ad9..5e638a46 100644 --- a/Options.py +++ b/Options.py @@ -13,6 +13,7 @@ from Utils import get_fuzzy_results if typing.TYPE_CHECKING: from BaseClasses import PlandoOptions from worlds.AutoWorld import World + import pathlib class AssembleOptions(abc.ABCMeta): @@ -1022,6 +1023,64 @@ per_game_common_options = { "item_links": ItemLinks } + +def generate_yaml_templates(target_folder: typing.Union[str, "pathlib.Path"], generate_hidden: bool = True): + import os + + import yaml + from jinja2 import Template + + from worlds import AutoWorldRegister + from Utils import local_path, __version__ + + full_path: str + + os.makedirs(target_folder, exist_ok=True) + + # clean out old + for file in os.listdir(target_folder): + full_path = os.path.join(target_folder, file) + if os.path.isfile(full_path) and full_path.endswith(".yaml"): + os.unlink(full_path) + + def dictify_range(option: typing.Union[Range, SpecialRange]): + data = {option.default: 50} + for sub_option in ["random", "random-low", "random-high"]: + if sub_option != option.default: + data[sub_option] = 0 + + notes = {} + for name, number in getattr(option, "special_range_names", {}).items(): + notes[name] = f"equivalent to {number}" + if number in data: + data[name] = data[number] + del data[number] + else: + data[name] = 0 + + return data, notes + + for game_name, world in AutoWorldRegister.world_types.items(): + if not world.hidden or generate_hidden: + all_options: typing.Dict[str, AssembleOptions] = { + **per_game_common_options, + **world.option_definitions + } + + with open(local_path("data", "options.yaml")) as f: + file_data = f.read() + res = Template(file_data).render( + options=all_options, + __version__=__version__, game=game_name, yaml_dump=yaml.dump, + dictify_range=dictify_range, + ) + + del file_data + + with open(os.path.join(target_folder, game_name + ".yaml"), "w", encoding="utf-8-sig") as f: + f.write(res) + + if __name__ == "__main__": from worlds.alttp.Options import Logic diff --git a/WebHostLib/options.py b/WebHostLib/options.py index 9b6fc904..bf8fa0d4 100644 --- a/WebHostLib/options.py +++ b/WebHostLib/options.py @@ -17,29 +17,8 @@ handled_in_js = {"start_inventory", "local_items", "non_local_items", "start_hin def create(): target_folder = local_path("WebHostLib", "static", "generated") yaml_folder = os.path.join(target_folder, "configs") - os.makedirs(yaml_folder, exist_ok=True) - for file in os.listdir(yaml_folder): - full_path: str = os.path.join(yaml_folder, file) - if os.path.isfile(full_path): - os.unlink(full_path) - - def dictify_range(option: typing.Union[Options.Range, Options.SpecialRange]): - data = {option.default: 50} - for sub_option in ["random", "random-low", "random-high"]: - if sub_option != option.default: - data[sub_option] = 0 - - notes = {} - for name, number in getattr(option, "special_range_names", {}).items(): - notes[name] = f"equivalent to {number}" - if number in data: - data[name] = data[number] - del data[number] - else: - data[name] = 0 - - return data, notes + Options.generate_yaml_templates(yaml_folder) def get_html_doc(option_type: type(Options.Option)) -> str: if not option_type.__doc__: @@ -61,18 +40,6 @@ def create(): **Options.per_game_common_options, **world.option_definitions } - with open(local_path("WebHostLib", "templates", "options.yaml")) as f: - file_data = f.read() - res = Template(file_data).render( - options=all_options, - __version__=__version__, game=game_name, yaml_dump=yaml.dump, - dictify_range=dictify_range, - ) - - del file_data - - with open(os.path.join(target_folder, "configs", game_name + ".yaml"), "w", encoding="utf-8") as f: - f.write(res) # Generate JSON files for player-settings pages player_settings = { diff --git a/WebHostLib/templates/options.yaml b/data/options.yaml similarity index 100% rename from WebHostLib/templates/options.yaml rename to data/options.yaml diff --git a/setup.py b/setup.py index 4b0c3954..94a242f0 100644 --- a/setup.py +++ b/setup.py @@ -309,16 +309,12 @@ class BuildExeCommand(cx_Freeze.command.build_exe.BuildEXE): dirs_exist_ok=True) os.makedirs(self.buildfolder / "Players" / "Templates", exist_ok=True) - from WebHostLib.options import create - create() + from Options import generate_yaml_templates from worlds.AutoWorld import AutoWorldRegister assert not apworlds - set(AutoWorldRegister.world_types), "Unknown world designated for .apworld" folders_to_remove: typing.List[str] = [] + generate_yaml_templates(self.buildfolder / "Players" / "Templates", False) for worldname, worldtype in AutoWorldRegister.world_types.items(): - if not worldtype.hidden: - file_name = worldname+".yaml" - shutil.copyfile(os.path.join("WebHostLib", "static", "generated", "configs", file_name), - self.buildfolder / "Players" / "Templates" / file_name) if worldname in apworlds: file_name = os.path.split(os.path.dirname(worldtype.__file__))[1] world_directory = self.libfolder / "worlds" / file_name diff --git a/test/webhost/TestFileGeneration.py b/test/webhost/TestFileGeneration.py index 2954946d..6010202c 100644 --- a/test/webhost/TestFileGeneration.py +++ b/test/webhost/TestFileGeneration.py @@ -25,7 +25,7 @@ class TestFileGeneration(unittest.TestCase): for file in os.scandir(target): if file.is_file() and file.name.endswith(".yaml"): with self.subTest(file=file.name): - with open(file) as f: + with open(file, encoding="utf-8-sig") as f: for value in roll_options({file.name: f.read()})[0].values(): self.assertTrue(value is True, f"Default Options for template {file.name} cannot be run.")