Skip to content

Fix managed reference Inspector lifecycle - #116

Open
mackysoft wants to merge 6 commits into
mainfrom
fix/inspector-lifecycle
Open

mackysoft wants to merge 6 commits into
mainfrom
fix/inspector-lifecycle

Conversation

@mackysoft

@mackysoft mackysoft commented Oct 15, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Complete bounded child traversal for cyclic managed references and skip closed descendant subtrees when enumerating direct children.
  • Use Unity-owned subtype drawers with their normal field context and lifetime.
  • Preserve buffered Inspector edits and validate deferred menu targets before applying an operation. Cancel when the captured host, reference, ancestry or collection correspondence has changed.

Scope

  • Editor traversal, native drawer delegation, and popup/context-menu editing; external behavior regressions remain under Assets/Tests.
  • The public Type-only drawer lookup keeps its signature and returns fresh, unbound instances. Callers own those instances and dispose them when they implement IDisposable.
  • Keep Runtime attributes, type eligibility, generic version gates, clipboard scopes, and the existing JSON field-preservation semantics.
  • Menu capture may apply existing buffered Inspector edits to establish current state; cancellation performs no selected command. Null/inline targets use observable ancestry and collection order, since Unity supplies no persistent identity for indistinguishable swap histories.
  • Unity 2021.3.45f2 and 2023.2.22f1 themselves can share a nested child handler across different managed parent types when the child name and leaf type match. This change follows native handler ownership and does not repair that Unity field-info collision.

Verification

  • Graphics-enabled local EditMode on the final commit: Unity 2021.3.45f2 passed 141/141; Unity 2023.2.22f1 passed 147, with 2 pre-existing Explicit generic value-type variance reproductions skipped. Those known generic-policy defects remain outside this lifecycle change.
  • Independent source and test-oracle reviews completed with no unresolved findings.
  • Regression witnesses: old cyclic traversal reaches the external process deadline, old subtype rendering loses field context, and 6/8 selected old deferred-edit cases fail (the 2 Reset cases pass).
  • Linux EditMode on b6dec37 matched those totals, with all 65 new lifecycle cases passing on each version. The final Verification check succeeded.

Why
Unconditional descendant traversal can keep following cyclic references and scans
closed collections while calculating the height of a selector.

What Changed
Respect the requested child depth, retain independent property copies, and scope
owned iterators. Stop a drawing iteration after a child changes its structure.
Cover cyclic Inspector editing, child depth and copy behavior, and array resize.

Impact
Inspector work remains finite for the required children without changing type
eligibility, labels, or collection element enumeration.
Why
A type-wide drawer instance shares state across unrelated Inspector fields and
has neither the declaring-field context nor Unity's normal lifetime owner.

What Changed
Use Unity's current property-handler chain to measure and draw subtype content.
Cache only drawer-type metadata for the public type-only lookup, which now
returns an unbound caller-owned instance.

Impact
Contextual drawers receive Unity's field metadata, nesting and disposal behavior.
Public lookup signatures and type-discovery policies remain unchanged.
Why
Subtype drawers must observe the declaring field and retain state only within
Unity's normal Inspector ownership boundaries.

What Changed
Exercise registered consumer drawers through native Inspector editors across
hosts and independent fields, including edits, forwarding and owner disposal.
Check the public type-only helper's fresh unbound caller-owned results.

Impact
Detects the previous missing field context and protects native drawer behavior
on both supported Unity baselines without asserting private cache structure.
Why
Menu callbacks retain expired property iterators and can lose buffered edits or
operate on another collection element after the serialized structure changes.

What Changed
Capture one-shot host and path correspondence without retaining property
iterators, reconcile pending edits, and validate every host before a command.
Use scoped fresh properties and each host's current type and values for edits.
Keep popup selection callbacks in a short-lived dropdown session.

Impact
Valid menu actions preserve edits and Undo; stale targets safely cancel.
Cached popup metadata does not retain an operation's target snapshots.
Existing clipboard scopes and JSON field-preservation semantics remain intact.
Why
A host or inline object can implement IList for unrelated purposes. Capturing
a normal reference field must not invoke that object's collection interface.

What Changed
Capture immediate collection elements only when the serialized property path
actually traverses an array or List index.

Impact
Normal field ancestry uses identity comparison without calling unrelated user
Count or indexer code; actual collection retarget detection is preserved.
Why
Menus must preserve the caller's edits and operate on the intended serialized
reference after deferral, while retaining normal Undo and persistence behavior.

What Changed
Exercise context commands and real popup selections for buffered edits, valid
nested targets, stale references, collection correspondence and multiple hosts.
Verify Prefab overrides and source preservation for replacement and live paste,
including Undo, Redo and saved-scene readback.

Impact
Consumer tests detect lost edits and redirected callbacks without depending on
private target-token or cache structure. Test assets stay outside the package.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant