You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Nine follow-ups from a retroactive code review of the animation_* tool
family (#17) and the cyberpunk HUD friction fixes (#21). All 388 Python
+ 345 GDScript tests pass; smoke-tested live against the editor.
1. node_create scene_path now uses PackedScene.GEN_EDIT_STATE_INSTANCE
so the editor treats the result as a real scene instance (foldout icon,
.tscn stores a reference, not an exploded subtree). Removes the
_set_owner_recursive call that was running outside the undo action and
also broke the instance link by forcing descendant ownership.
2. Animation track undo no longer caches the baseline track_count at do
time - it resolves the index via anim.find_track(path, type) at undo
time. Robust to any history interleaving. New test stresses this path.
3. _coerce_value_for_track now errors with INVALID_PARAMS when the target
node exists but the property doesnt - previously the raw value passed
through and produced garbage keyframes at playback. Matches the
handlers own docstring.
4. add_method_track validates keyframe args is an Array and method is a
non-empty string. Previously a typed-assign crash or silent garbage.
5. animation_delete now uses _resolve_animation to locate the owning
library, matching the read-side symmetry with animation_get /
animation_play. Delete from non-default libraries works end-to-end.
6. theme_set_stylebox_flat flattened from 27 parameters to a nested-dict
API: border / corners / margins / shadow each take {all, sides} with
side-specific keys overriding all. Unknown keys fail loudly. Breaking
change - tool was only merged in #21 and has no external clients yet.
7. project_stop replaces the fixed 150ms sleep with a bounded poll on
session.readiness. Reaches truth as soon as the existing
readiness_changed event arrives (~17ms) instead of blanket-sleeping
150ms, with a 1s timeout for a hung play process.
8. ui_build_layout pseudo-property tests now read back via
get_theme_*_override (not the fallback get_theme_* getters), per the
CLAUDE.md "assert on the stored Variant" rule. Added missing
theme_override_styles/ test.
9. signal_connect distinguishes declared-but-uninstantiated autoloads
from genuinely missing nodes, with a clear error pointing users at
@onready/runtime-connect as the workaround. Previous "not found"
error masked the real reason most runtime-only autoloads cant be
connected at edit time.
Also updates CLAUDE.md with reference patterns for find_track-at-undo,
GEN_EDIT_STATE_INSTANCE, and get_theme_*_override readback tests.
Deferred to a follow-up PR: plugin dispatcher coroutine support +
readiness Option C (plugin-side await). That refactor touches the hot
path every command flows through and deserves its own bisect-friendly
landing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CLAUDE.md
+29Lines changed: 29 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -185,6 +185,35 @@ JSON dicts like `{"r":1,"g":0,"b":0,"a":1}` only become `Color` / `Vector2` / `V
185
185
186
186
GDScript tests that just assert `track_count == 1` will pass even when coercion is broken. **Always read back via `track_get_key_value(idx, k)` and assert `value is Color` / `value is Vector3` / etc.**`test_animation.gd``test_add_property_track_coerces_vector3_dict` is the reference pattern. The same rule applies to any future handler that takes JSON values intended to land as typed Variants in the scene.
187
187
188
+
Same principle for theme override pseudo-properties on Controls: use `get_theme_color_override`, `get_theme_constant_override`, `get_theme_font_size_override`, `get_theme_stylebox_override` in tests — **not** the fallback `get_theme_color` getters — so a broken override silently resolving via the theme fallback can't mask a bug. `test_ui.gd``test_build_layout_theme_override_*` are the reference pattern.
189
+
190
+
### Auto-generated indices: look up at undo time, not do time
191
+
192
+
When a write tool mutates a resource whose index is assigned by Godot (`Animation.add_track` returns an int index, same for track keys, `MultiMesh.instance_count`, etc.), do **not** capture that index at do time and reuse it in the undo callable. Any other mutation landing between the do and the undo makes the index stale — the undo will then remove the wrong element (or error).
193
+
194
+
Instead, undo via a helper that resolves the index at undo time via a stable lookup:
See `animation_handler.gd::_undo_remove_track_by_path` for the reference pattern. Cover with a test that interleaves a second mutation between the do and undo of the first (`test_animation.gd::test_add_property_track_undo_survives_interleaving`).
206
+
207
+
### Scene instancing: use GEN_EDIT_STATE_INSTANCE
208
+
209
+
When a tool instantiates a PackedScene into the edited scene, pass `PackedScene.GEN_EDIT_STATE_INSTANCE` to `instantiate()`:
This makes Godot treat the result as a real scene instance: the root shows the foldout icon, the `.tscn` stores a reference to the sub-scene rather than an exploded subtree, and the instance can be swapped or toggled editable via the usual editor UI. Don't manually set descendant owners to your scene_root — descendants of a scene instance stay owned by their sub-scene; overriding that breaks the instance link. See `node_handler.gd::create_node`.
216
+
188
217
## Test coverage
189
218
190
219
100% code coverage for core features, always. Every tool, handler, and protocol path must have both:
0 commit comments