Releases: Wintersta7e/mz-plugin-studio
Releases · Wintersta7e/mz-plugin-studio
MZ Plugin Studio v1.6.0
Added
- Plugin Browser panel — new 288px side panel for projects with many plugins (50+). Toggled via a
Listicon in the sidebar or Ctrl+Shift+E. Replaces the cramped bottom icon list that became unusable past ~10 plugins. Features: filename search, filter (All / Open / Dirty / Errors), sort (file order or A–Z), per-row status glyphs (error / warning / dirty dot), hover-to-close for open plugins, active-plugin highlight, and a footer summary (N total · X dirty · Y errors). @type locationsupport — official MZ map+coordinate picker. Added to parameter-type dropdown under "Game Data", parsed from imported plugins, and emitted with a JSON default ({"mapId":"0","x":"0","y":"0"}) in the IIFE body.@requiredAssetsannotation — plugin-level meta field for assets preserved during MZ's "Exclude unused files" deployment. New MetaEditor textarea (one asset path per line); generator emits one@requiredAssetsline per entry; parser extracts them on import.tests/templates-output.test.ts— 10 regression tests covering the six template bug fixes (save-load, input-handler, method-alias, battle-system, message-system, plugin-commands).- 24 new generator/validation/shortcut tests covering struct-array deep-parse, number[]/boolean[]/ID[] element coercion, nullish boolean defaults, reserved-word camelCase sanitization, identifier collision detection,
@requiredAssetsround-trip,@type locationround-trip, comment-aware command dedup, and the Ctrl+Shift+E plugin-browser shortcut.
Fixed
- Struct-array parser now deep-parses correctly — MZ double-encodes
struct<X>[]as a JSON array of JSON strings. The generator previously emittedJSON.parse(accessor || '[]'), leaving each element as a string (soarr[0].xsilently returnedundefined). Now emits.map(s => JSON.parse(s))for struct arrays. - Number/ID arrays now coerce their elements —
number[],actor[],variable[], etc. now emit.map(Number)so arithmetic works;boolean[]emits.map(v => v === 'true'). - Boolean
@default trueno longer silently becomesfalse— the previousaccessor === 'true'returnedfalsewhen the param key was absent fromparams(edge case: plugin added but never opened in Plugin Manager). Now nullish-coalesces to the declared default. camelCase()no longer emits invalid JS identifiers — a parameter namedclass,default,return,123abc, etc. previously producedconst class = ...(strict-mode SyntaxError on plugin load). Sanitizer now suffixes_on reserved words and prefixes_on digit-start names.validatePlugindetects post-transform identifier collisions — two differently-named parameters that camelCase to the same identifier (e.g.,foo-barandfoo_bar) now surface as a hard error rather than silently producing duplicateconstdeclarations.- Command dedup no longer false-matches commented-out examples — doc comments referencing
registerCommand(...)previously suppressed generation of the real command body. A newstripCommentsOnly()helper masks comments while preserving string literals before the substring check. - save-load template warns about non-persistent storage —
Game_ActorsandGame_Mapare no longer silently offered as "just another option": dropdown labels mark them as non-persistent, and generated code includes a prominent WARNING comment explaining that properties set ininitialize()will be lost on save reload / map change. - input-handler template no longer collides across plugins — the global-key handler method is now key-scoped (
updateGlobalKeyInput_Q,updateGlobalKeyInput_Tab, etc.) so two plugins each hooking a different key don't clobber each other'sScene_Base.prototype.updateGlobalKeyInput. - method-alias replace-without-call emits a prominent WARNING — for predicates like
Game_Battler.canMove,Game_Action.canUse, etc., silently returningundefinedbreaks MZ logic. The placeholder now includes a multiline warning + a TODO naming the specific method. - battle-system damage multiply is sign-preserving — the old
Math.floor(value * m)over-healed by 1 point for healing skills (wherevalueis negative). Now emitsvalue >= 0 ? Math.floor(value * m) : Math.ceil(value * m). - message-system custom escape code regex has a word boundary — the no-parameter
replacepath previously emitted/\\X/gi, which would match\XY,\XX, etc. Now adds(?![A-Za-z])so only single-character escape codes match. - plugin-commands async callback uses per-interpreter state — the previous module-scope
let _XPending = falsecollided when two parallel events fired the same async command concurrently. Now stores the pending flag on the invokingGame_Interpreterinstance.
Changed
@require 1emission dropped — Kadokawa's MZ annotation reference marks@requireas discontinued (MV-era). The UI checkbox is kept (faded) for round-tripping legacy imports, but the generator no longer emits@require 1on file/animation parameters or command args.@noteRequire 1emission dropped — not part of the official Kadokawa note-asset spec (only@noteParam,@noteType,@noteDir,@noteDataare documented). Parser still reads the legacy tag for back-compat.@type textmarked as MV-legacy in the parameter-type dropdown — the canonical MZ multi-line type ismultiline_string(mapped tonoteinternally).textstill parses and emits for compatibility.- Generated command stubs drop the
console.log(...)line — every generatedPluginManager.registerCommandcallback previously shipped aconsole.log('X called with:', { args })stub that survived to production. Replaced with an inline comment naming the parsed args. - Sidebar plugin list moved to the new panel — the cramped icon-rail
.jsfile list was removed (replaced by the Plugin Browser). The sidebar rail is now just: Open Project / New Plugin / [open-plugin tabs] / Plugin Browser / Project Data Browser / Settings / Shortcuts. lucide-react1.7.0 → 1.8.0 (safe minor; icon additions, no breaking changes).- Release-workflow retention policy: keep latest 2 releases (was 3).
- Parameter-type count: 28 → 29 (added
location). - Test count: 572 → 606 (+34 tests across generator, validation, mz-annotations, templates-output, and shortcuts).
Removed
uuidand@types/uuidas direct dependencies — never imported in source, tests, or tools. The project usescrypto.randomUUID()exclusively. Eliminates dead-dep attack surface and avoids a forced Node-20+ upgrade on uuid's v14 bump (which introduced breaking changes we would have had to work around for no benefit).
MZ Plugin Studio v1.5.0
Added
- Grouped Parameter Type Dropdown — 6 logical groups (Basic, Text, Lists, Game Data, Files, Structure) with inline descriptions
- Progressive Disclosure — advanced parameter fields collapsed by default, auto-expand when populated
- Inline Parameter Name Validation — real-time error feedback for empty, invalid, and duplicate names
- Drag-and-Drop Target Indicators — visual border + background highlight on drop target during parameter reorder
- Actionable Welcome Screen — "New Plugin" card on the landing page for immediate onboarding
- Copy ID Button — one-click ID copy on project browser items (actors, items, switches, etc.)
- Template Category Persistence — last-selected template category remembered across opens
- Save All (Ctrl+Shift+S) — save all dirty open plugins in parallel with toast summary
- Toggle Preview (Ctrl+B) — collapse/expand the code preview panel
- Command Name Collision Warning — warns when command names shadow MZ built-in commands (28 names)
- Settings Reset to Defaults — one-click button to restore all settings
- Export Format Descriptions — explanatory text for each export option
- Accessibility — aria-labels on sidebar, status bar, and toast notifications; aria-live regions for dynamic content
- Per-plugin dirty/saved/rawMode state tracking — switching tabs preserves unsaved indicators and raw mode toggles
generatePluginOutput()facade for unified raw/generated code switchingMemoizedParamRowwrapper for stable ParameterCard callback bindingseslint-plugin-react-hookswithrules-of-hooks(error) andexhaustive-deps(warn)consistent-type-importsESLint rule (error) — enforcesimport typesyntax- 14 new tests: plugin-store (6), ui-store (3), plugin-output (3), toast-store (2) — 411 total
Fixed
- Security:
assertSafeProjectPath()added to all 16 project IPC handlers (was missing) - Security:
assertSafeFilename()now enforces.jsextension for plugin directory writes - Security: Dev CSP
ws:restricted tows://localhost:*(was open to any host) - Security:
shell.openExternaluses normalizedparsed.hrefinstead of raw URL - Raw mode new-parameter detection now checks both
params['name']andparams["name"](fixes duplicate declarations) - Raw mode new-command detection now checks all 4 quote combinations including
PLUGIN_NAME+ double-quote (fixes duplicate registrations) - History fingerprint now content-aware (parameter renames, type changes, and edits are properly captured in undo history)
closePluginhistory cleanup race condition — cleanup now fires before state switchhistoryStore.clear()now resetsactivePluginIdto nullOptionsEditorlocal state now syncs on external option changes (undo, preset apply)findBlockEndescaped backslash handling (\\before quote no longer incorrectly treated as escape)scanDependenciesnow called explicitly aftersetAllGameData(removed fragilesetTimeout(0)ordering)setDebugLoggingguarded withwindow.apicheck for test environments.mdand.d.tsadded toALLOWED_EXTENSIONS(README and TypeScript declaration exports were broken)- Toast eviction timer cleanup prevents stale timer fires
- SettingsDialog ref capture in useEffect cleanup
- 6 npm audit vulnerabilities resolved (flatted, minimatch, picomatch)
Changed
- TypeScript:
noImplicitAny: trueenabled in both web and node tsconfigs - ESLint:
no-unused-varsupgraded from warn to error,no-non-null-assertionadded as warn,no-consoleadded as warn - Status bar abbreviations expanded and font size bumped for readability
- Raw mode toggle relabeled with clearer on/off states
- Sidebar divider widened to 6px for easier grab targeting
- Shared types moved to
src/shared/types/as canonical location (renderer re-exports, main/preload import directly) env.d.tsimportsAPItype from preload instead of redeclaring all interfacesgenerateParamParser/generateArgParserunified into sharedgenerateAccessorParserparseProjectreadsSystem.jsononce (was 3 times per call)- Monaco
optionsmemoized in CodeEditor, CodePreview, and DiffView - Store selectors narrowed: CodeEditor subscribes to
customCodeonly, MetaEditor tometa, StatusBar tometa.name - ProjectBrowser filter calls wrapped in
useMemo - ParameterCard wrapped in
React.memowith stable callback bindings rawSourcestripped from history entries to reduce memory retention