From 6fe5ab19636742a6841609fbc07dfa797fe3fae1 Mon Sep 17 00:00:00 2001 From: DazedAnon Date: Sun, 5 Jul 2026 10:52:56 -0500 Subject: [PATCH] Bootstrap UI Scaler and Hotkey for Forge --- util/forge/config.py | 17 ++++-- util/forge/installer.py | 5 +- util/forge/modern_patches.py | 107 +++++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 7 deletions(-) create mode 100644 util/forge/modern_patches.py diff --git a/util/forge/config.py b/util/forge/config.py index 97534f7..1e0908c 100644 --- a/util/forge/config.py +++ b/util/forge/config.py @@ -12,6 +12,7 @@ from pathlib import Path from util.playtest.config import load_config from util.forge.scale_patches import apply_ui_scale_patches +from util.forge.modern_patches import apply_modern_forge_patches _PKG_ROOT = Path(__file__).resolve().parent @@ -38,10 +39,16 @@ def _js_literal(value) -> str: return json.dumps(str(value)) -def plugin_entry(engine: str, hotkey: str, ui_scale: str = "auto") -> str: +def plugin_entry(engine: str, hotkey: str, ui_scale: str = "auto", *, modern: bool = False) -> str: + name = PLUGIN_BY_ENGINE[engine] + if modern: + return ( + f' {{ "name": "{name}", "status": true, ' + f'"description": "Forge — in-game cheat & editor overlay", ' + f'"parameters": {{}} }}' + ) hk = _js_literal(hotkey.strip() or "F10") scale = _js_literal(ui_scale.strip() or "auto") - name = PLUGIN_BY_ENGINE[engine] if engine == "MZ": return ( f' {{ "name": "{name}", "status": true, ' @@ -149,13 +156,13 @@ def prepare_forge_js(engine: str, source: Path | None = None, cfg: dict | None = """Build the Forge plugin written into a game folder (vanilla source + Dazed patches).""" src = source or bundled_plugin_path(engine) text = src.read_text(encoding="utf-8") - if not is_legacy_forge_plugin(text): - return text - effective = {**load_config(), **(cfg or {})} hotkey = effective.get("forgeHotkey", "F10") ui_scale = effective.get("uiScale", "auto") + if not is_legacy_forge_plugin(text): + return apply_modern_forge_patches(text, hotkey, str(ui_scale)) + text = apply_ui_scale_patches(text, engine) text = _patch_forge_hotkey(text, hotkey, engine) text = _patch_forge_ui_scale_default(text, str(ui_scale), engine) diff --git a/util/forge/installer.py b/util/forge/installer.py index beea151..8f09db4 100644 --- a/util/forge/installer.py +++ b/util/forge/installer.py @@ -8,7 +8,7 @@ from __future__ import annotations import re from pathlib import Path -from util.forge.config import PLUGIN_BY_ENGINE, plugin_entry, prepare_forge_js +from util.forge.config import PLUGIN_BY_ENGINE, is_legacy_forge_plugin, plugin_entry, prepare_forge_js _PKG_ROOT = Path(__file__).resolve().parent @@ -187,7 +187,8 @@ def install(game_root: Path, source_js: Path | None = None, cfg: dict | None = N hotkey = (cfg or {}).get("forgeHotkey", "F10") ui_scale = (cfg or {}).get("uiScale", "auto") - entry = plugin_entry(engine, hotkey, ui_scale) + modern = not is_legacy_forge_plugin((source_js or default_src).read_text(encoding="utf-8")) + entry = plugin_entry(engine, hotkey, ui_scale, modern=modern) try: content = _upsert_plugin_entry(content, plugin_name, entry, nl) plugins_js.write_text(content, encoding="utf-8", newline="") diff --git a/util/forge/modern_patches.py b/util/forge/modern_patches.py new file mode 100644 index 0000000..4b129ef --- /dev/null +++ b/util/forge/modern_patches.py @@ -0,0 +1,107 @@ +"""Install-time patches for the rewritten Forge plugin (unified forge.js).""" + +from __future__ import annotations + +import json +import re + +_BOOTSTRAP_START = "/**/" +_BOOTSTRAP_END = "/**/" + +_MODIFIER_ALIASES = { + "control": "ctrl", + "ctrl": "ctrl", + "alt": "alt", + "shift": "shift", + "meta": "meta", + "cmd": "meta", + "command": "meta", + "win": "meta", +} + + +def forge_key_str(hotkey: str) -> str: + """Convert a Dazed forgeHotkey value to Forge shortcut keyStr format.""" + raw = (hotkey or "F10").strip() + if not raw: + return "f10" + parts = re.split(r"\s*\+\s*|\s+", raw) + out: list[str] = [] + for part in parts: + token = part.strip().lower() + if not token: + continue + mapped = _MODIFIER_ALIASES.get(token) + if mapped: + if mapped not in out: + out.append(mapped) + else: + out.append(token) + return " ".join(out) or "f10" + + +def _bootstrap_js(hotkey: str, ui_scale: str) -> str: + key_str = json.dumps(forge_key_str(hotkey)) + scale = json.dumps(str(ui_scale or "auto").strip() or "auto") + return f"""{_BOOTSTRAP_START} +(function () {{ + var toggleKey = {key_str}; + var uiScale = {scale}; + try {{ + var saved = JSON.parse(localStorage.getItem("forge:shortcuts") || "{{}}"); + saved.toggle_ui = Object.assign({{}}, saved.toggle_ui, {{ keyStr: toggleKey, enabled: true }}); + localStorage.setItem("forge:shortcuts", JSON.stringify(saved)); + }} catch (e) {{}} + function resolveUiScale(v) {{ + if (v !== "auto" && v != null && String(v).trim() !== "") {{ + var n = parseFloat(v); + if (!isNaN(n) && n > 0) return Math.max(0.75, Math.min(3, n)); + }} + var base = 816; + var gameW = (typeof Graphics !== "undefined" && Graphics.width) ? Graphics.width : 0; + var viewW = window.innerWidth || document.documentElement.clientWidth || base; + var w = Math.max(gameW || base, viewW); + var scale = w / base; + var dpr = window.devicePixelRatio || 1; + if (dpr > 1.15) scale *= Math.min(2, 0.75 + dpr * 0.35); + return Math.max(1, Math.min(2.75, scale)); + }} + function applyUiScale() {{ + var host = document.getElementById("forge-mvmz-host"); + if (!host) return; + var fx = resolveUiScale(uiScale); + host.style.zoom = String(fx); + }} + if (!window.__dazedForgeUiScaleHook) {{ + window.__dazedForgeUiScaleHook = true; + var observer = new MutationObserver(applyUiScale); + observer.observe(document.documentElement, {{ childList: true, subtree: true }}); + window.addEventListener("resize", applyUiScale); + setInterval(applyUiScale, 500); + }} + applyUiScale(); +}})(); +{_BOOTSTRAP_END}""" + + +def _strip_existing_bootstrap(text: str) -> str: + while True: + start = text.find(_BOOTSTRAP_START) + if start < 0: + return text + end = text.find(_BOOTSTRAP_END, start) + if end < 0: + return text + text = text[:start] + text[end + len(_BOOTSTRAP_END) :] + return text + + +def apply_modern_forge_patches(text: str, hotkey: str, ui_scale: str) -> str: + """Inject Dazed hotkey / UI-scale bootstrap before the Forge bundle runs.""" + text = _strip_existing_bootstrap(text) + bootstrap = _bootstrap_js(hotkey, ui_scale) + match = re.search(r"\*/\s*\n", text) + if not match: + return bootstrap + "\n" + text + pos = match.end() + return text[:pos] + bootstrap + "\n" + text[pos:]