diff --git a/gui/wolf_workflow_tab.py b/gui/wolf_workflow_tab.py
index 2be7abd..9b8d369 100644
--- a/gui/wolf_workflow_tab.py
+++ b/gui/wolf_workflow_tab.py
@@ -4397,8 +4397,6 @@ class WolfWorkflowTab(QWidget):
f" Added {result.files_added} file(s), omitted "
f"{result.excluded_entries} tool/private item(s)."
)
- if result.sanitized_plugin_lists:
- log(" Removed playtest plugins from the archived plugins.js.")
return True, (
f"Created {result.output_path.name} ({size_mb:.1f} MB) at "
f"{result.output_path}."
diff --git a/gui/workflow_tab.py b/gui/workflow_tab.py
index f2b4ea7..ed6d042 100644
--- a/gui/workflow_tab.py
+++ b/gui/workflow_tab.py
@@ -526,7 +526,7 @@ _STEP_HELP: dict[int, str] = {
"• Export ALL - everything under translated/
"
"Create Public Release ZIP packages the complete game beside its folder while "
"omitting translator workspaces, VCS metadata, documentation, backups, saves, and "
- "playtest plugins. GameUpdate files are kept."
+ "other tool artifacts. GameUpdate files and all installed plugins are kept."
),
6: (
"Step 6 - Images (MV/MZ)
"
@@ -2228,7 +2228,7 @@ class WorkflowTab(QWidget):
self._release_zip_btn = _make_btn("📦 Create Public Release ZIP", "#007acc")
self._release_zip_btn.setToolTip(
"Archive the detected game folder for players. Excludes DazedTL workspaces, "
- "version-control files, documentation, backups, saves, and playtest plugins; "
+ "version-control files, documentation, backups, and saves; "
"keeps GameUpdate files. The source game folder is not changed."
)
self._release_zip_btn.clicked.connect(self._create_public_release)
@@ -4211,8 +4211,6 @@ class WorkflowTab(QWidget):
f"{result.files_added} file(s); omitted {result.excluded_entries} "
"tool/private item(s)."
)
- if result.sanitized_plugin_lists:
- message += " Removed playtest plugins from the archived plugins.js."
self._log(f"✅ {message}")
QMessageBox.information(
self,
diff --git a/tests/test_release_package.py b/tests/test_release_package.py
index b76ce11..f0dace3 100644
--- a/tests/test_release_package.py
+++ b/tests/test_release_package.py
@@ -79,7 +79,8 @@ class ReleasePackageTests(unittest.TestCase):
prefix = "Translated Game/"
with zipfile.ZipFile(output) as archive:
names = set(archive.namelist())
- archived_plugins = archive.read(prefix + "js/plugins.js").decode("utf-8")
+ archived_plugin_bytes = archive.read(prefix + "js/plugins.js")
+ archived_plugins = archived_plugin_bytes.decode("utf-8")
for relative in (
"Game.exe",
@@ -92,6 +93,8 @@ class ReleasePackageTests(unittest.TestCase):
"gameupdate/patch.ps1",
"gameupdate/patch-config.txt",
"js/plugins/CorePlugin.js",
+ "js/plugins/TLInspector.js",
+ "js/plugins/Forge_MZ.js",
):
self.assertIn(prefix + relative, names)
@@ -111,17 +114,15 @@ class ReleasePackageTests(unittest.TestCase):
".gitignore",
".env",
"gameupdate/previous_patch_sha.txt",
- "js/plugins/TLInspector.js",
- "js/plugins/Forge_MZ.js",
):
self.assertNotIn(prefix + relative, names)
self.assertIn('"name":"CorePlugin"', archived_plugins)
- self.assertNotIn("TLInspector", archived_plugins)
- self.assertNotIn("Forge_MZ", archived_plugins)
+ self.assertIn("TLInspector", archived_plugins)
+ self.assertIn("Forge_MZ", archived_plugins)
+ self.assertEqual(archived_plugin_bytes, plugins_js)
self.assertEqual(source_plugins.read_bytes(), plugins_js)
self.assertEqual(result.output_path, output.resolve())
- self.assertEqual(result.sanitized_plugin_lists, 1)
self.assertEqual(progress[-1][:2], (result.files_added, result.files_added))
def test_release_path_must_be_outside_game_folder(self):
diff --git a/util/release_package.py b/util/release_package.py
index 3c2af03..8701b16 100644
--- a/util/release_package.py
+++ b/util/release_package.py
@@ -2,9 +2,7 @@
from __future__ import annotations
-import codecs
import os
-import re
import tempfile
import zipfile
from dataclasses import dataclass
@@ -25,7 +23,6 @@ class ReleasePackageResult:
files_added: int
bytes_added: int
excluded_entries: int
- sanitized_plugin_lists: int
# These are never game payloads and should be ignored wherever they occur.
@@ -91,16 +88,10 @@ _EXCLUDED_FILE_NAMES = frozenset(
".gitattributes",
".gitignore",
"desktop.ini",
- "forge_mv.bat",
- "forge_mv.js",
- "forge_mz.bat",
- "forge_mz.js",
"patch2.ps1",
"patch2.sh",
"previous_patch_sha.txt",
"thumbs.db",
- "tlinspector.bat",
- "tlinspector.js",
}
)
@@ -115,8 +106,6 @@ _UPDATER_ROOT_FILE_NAMES = frozenset(
_ROOT_DOCUMENT_SUFFIXES = frozenset({".doc", ".docx", ".markdown", ".md", ".pdf", ".rst"})
_BACKUP_SUFFIXES = (".bak", ".backup", ".orig", ".tmp")
-_PLUGIN_LIST_PATHS = frozenset({"js/plugins.js", "www/js/plugins.js"})
-_PLAYTEST_PLUGIN_NAMES = ("TLInspector", "Forge_MV", "Forge_MZ")
def default_release_zip_path(game_root: str | Path) -> Path:
@@ -205,67 +194,6 @@ def _iter_release_files(root: Path) -> tuple[list[tuple[Path, Path]], int]:
return files, excluded
-def _remove_plugin_object(content: str, plugin_name: str) -> str:
- """Remove one object from RPG Maker's JavaScript plugin-array syntax."""
- marker = re.search(rf'"name"\s*:\s*"{re.escape(plugin_name)}"', content)
- while marker:
- start = content.rfind("{", 0, marker.start())
- if start < 0:
- raise ReleasePackageError(f"Could not remove {plugin_name} from plugins.js")
- depth = 0
- end = None
- in_string = False
- escaped = False
- for index in range(start, len(content)):
- char = content[index]
- if in_string:
- if escaped:
- escaped = False
- elif char == "\\":
- escaped = True
- elif char == '"':
- in_string = False
- continue
- if char == '"':
- in_string = True
- elif char == "{":
- depth += 1
- elif char == "}":
- depth -= 1
- if depth == 0:
- end = index + 1
- break
- if end is None:
- raise ReleasePackageError(f"Could not parse {plugin_name} in plugins.js")
-
- before = content[:start].rstrip()
- after = content[end:].lstrip()
- if after.startswith(","):
- after = after[1:].lstrip()
- elif before.endswith(","):
- before = before[:-1].rstrip()
- separator = "\n" if before and after and not before.endswith("\n") else ""
- content = before + separator + after
- marker = re.search(rf'"name"\s*:\s*"{re.escape(plugin_name)}"', content)
- return re.sub(r",(\s*)\];", r"\1];", content)
-
-
-def sanitize_plugins_js(raw: bytes) -> tuple[bytes, bool]:
- """Remove DazedTL playtest entries while preserving the source file's BOM."""
- had_bom = raw.startswith(codecs.BOM_UTF8)
- try:
- content = raw.decode("utf-8-sig")
- except UnicodeDecodeError as exc:
- raise ReleasePackageError(f"plugins.js is not valid UTF-8: {exc}") from exc
- original = content
- for plugin_name in _PLAYTEST_PLUGIN_NAMES:
- content = _remove_plugin_object(content, plugin_name)
- if content == original:
- return raw, False
- encoded = content.encode("utf-8")
- return (codecs.BOM_UTF8 + encoded if had_bom else encoded), True
-
-
def _archive_name(root: Path, relative: Path) -> str:
return (Path(root.name or "game") / relative).as_posix()
@@ -306,7 +234,6 @@ def create_release_zip(
temporary = Path(temporary_name)
files_added = 0
bytes_added = 0
- sanitized = 0
try:
with zipfile.ZipFile(
temporary,
@@ -319,16 +246,8 @@ def create_release_zip(
if progress:
progress(index, total, relative.as_posix())
arcname = _archive_name(root, relative)
- if relative.as_posix().casefold() in _PLUGIN_LIST_PATHS:
- raw = source.read_bytes()
- payload, changed = sanitize_plugins_js(raw)
- info = zipfile.ZipInfo.from_file(source, arcname=arcname)
- archive.writestr(info, payload, compress_type=zipfile.ZIP_DEFLATED)
- sanitized += int(changed)
- bytes_added += len(payload)
- else:
- archive.write(source, arcname=arcname)
- bytes_added += source.stat().st_size
+ archive.write(source, arcname=arcname)
+ bytes_added += source.stat().st_size
files_added += 1
os.replace(temporary, output)
except Exception:
@@ -340,5 +259,4 @@ def create_release_zip(
files_added=files_added,
bytes_added=bytes_added,
excluded_entries=excluded,
- sanitized_plugin_lists=sanitized,
)