- Implement tests for PropFile, including preset conversion, file dictionary conversion, round-trip serialization, version rejection, default values for missing keys, flattening, sanitization, and save/load functionality. - Create tests for PropEditor, covering window title formatting, mode button text, safe saving, and recent file list management. - Add tests for PropTheme, validating fallback behavior, invalid input handling, and default values for primitives and UI tokens. - Introduce tests for ThumbnailCache, ensuring proper key formatting, PNG handling, and behavior with missing files.
2.7 KiB
Phase 9 Prop Editor — Round 5 (File → Recent + save-serialization fix)
Status: implemented (2026-09-19; direct bugfix + feature round).
Source: two user feedback points against the shipped Round 4 Prop Editor.
Feedback summary
- File → Recent: show the last 5 opened props (sandbox-stage pattern).
- Loading
props/eye.propdraws nothing (the prop name shows, geometry is blank).
Diagnosis (point 2 — root cause)
PropFile._serialize_shape() declared
var points: PackedVector2Array = shape.get("points", PackedVector2Array())
but the editor always serializes export-format shapes whose points is an Array of
{x, y} dictionaries. The implicit Array → PackedVector2Array conversion cannot construct
Vector2 from a dictionary and silently yields Vector2.ZERO per element, preserving the
count but zeroing every coordinate. Every save therefore wrote all points as (0, 0) —
verified in props/eye.prop and props/box.prop (all x: 0.0, y: 0.0), which load as a
degenerate, invisible shape. The round-1 tests only asserted point counts and dict shape,
so the corruption slipped through.
Fix: _serialize_shape() now uses the existing _coerce_points() helper (which handles
both PackedVector2Array and Array-of-{x,y} inputs). Regression assertions were added so
point values are verified through to_file_dict and the full round-trip.
The two already-saved user files (props/eye.prop, props/box.prop) are unrecoverable
(every coordinate was zeroed at save time) and must be re-authored.
Changes
| Target | Change |
|---|---|
scripts/prop_file.gd |
_serialize_shape uses _coerce_points (bug fix). |
scripts/prop_editor.gd |
SETTINGS_PATH := "user://prop_editor_settings.json", RECENT_MAX := 5, _recent_props; update_recent_list(list, path, max) static (dedupe + front-insert + trim); 🕑 Recent submenu in the File menu (RecentProps child popup, updated on about_to_popup, missing files pruned, "(No recent props)" placeholder); _load_settings/_save_settings; _push_recent(path) on every successful load; missing recent → error dialog + removal. |
tests/test_prop_editor_file.gd |
New value-preservation assertions (serialized x == 64, round-trip (64,0)/(64,64)). |
tests/test_prop_editor_round3.gd |
New _test_recent_list (dedupe, front-insert, trim). |
Verification
--check-onlyclean; all five suites green: file 66, theme 53, canvas 87, thumb 10, round3 21.- Manual F6: save a prop with shapes at distinct coordinates, reload — geometry must match; File → 🕑 Recent lists the last 5 opens and opens them; missing recent file shows the error and prunes itself.