Roblox macros that play from outside the game: Anime Vanguards, and a falling-notes piano event.
70 lines
2.0 KiB
Python
70 lines
2.0 KiB
Python
"""Config and recorded routines on disk."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
CONFIG_DIR = ROOT / "config"
|
|
ROUTINE_DIR = CONFIG_DIR / "routines"
|
|
|
|
|
|
def _merge(defaults, saved):
|
|
"""Saved values win; keys only in defaults are filled in."""
|
|
if not isinstance(defaults, dict) or not isinstance(saved, dict):
|
|
return saved if saved is not None else defaults
|
|
out = dict(defaults)
|
|
for key, value in saved.items():
|
|
out[key] = _merge(defaults.get(key), value) if key in defaults else value
|
|
return out
|
|
|
|
|
|
def config_path(macro: str) -> Path:
|
|
return CONFIG_DIR / f"{macro}.json"
|
|
|
|
|
|
def load(macro: str, defaults: dict) -> dict:
|
|
path = config_path(macro)
|
|
if not path.exists():
|
|
return json.loads(json.dumps(defaults))
|
|
with path.open(encoding="utf-8") as handle:
|
|
return _merge(defaults, json.load(handle))
|
|
|
|
|
|
def save(macro: str, data: dict) -> Path:
|
|
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
path = config_path(macro)
|
|
with path.open("w", encoding="utf-8") as handle:
|
|
json.dump(data, handle, indent=2)
|
|
handle.write("\n")
|
|
return path
|
|
|
|
|
|
def routine_path(name: str) -> Path:
|
|
return ROUTINE_DIR / f"{name}.json"
|
|
|
|
|
|
def load_routine(name: str) -> list[dict]:
|
|
path = routine_path(name)
|
|
if not path.exists():
|
|
raise FileNotFoundError(f"no routine called {name!r} — record one first")
|
|
with path.open(encoding="utf-8") as handle:
|
|
data = json.load(handle)
|
|
return data.get("steps", []) if isinstance(data, dict) else data
|
|
|
|
|
|
def save_routine(name: str, steps: list[dict], note: str = "") -> Path:
|
|
ROUTINE_DIR.mkdir(parents=True, exist_ok=True)
|
|
path = routine_path(name)
|
|
with path.open("w", encoding="utf-8") as handle:
|
|
json.dump({"note": note, "steps": steps}, handle, indent=2)
|
|
handle.write("\n")
|
|
return path
|
|
|
|
|
|
def list_routines() -> list[str]:
|
|
if not ROUTINE_DIR.exists():
|
|
return []
|
|
return sorted(path.stem for path in ROUTINE_DIR.glob("*.json"))
|