Skip to content

Add [TypeSelector] dropdown for [SerializeReference] and type repair#49

Draft
VPDPersonal wants to merge 48 commits into
mainfrom
feature/serialize-reference-dropdown
Draft

Add [TypeSelector] dropdown for [SerializeReference] and type repair#49
VPDPersonal wants to merge 48 commits into
mainfrom
feature/serialize-reference-dropdown

Conversation

@VPDPersonal

@VPDPersonal VPDPersonal commented Jun 7, 2026

Copy link
Copy Markdown
Owner

Summary

  • Extend [TypeSelector] to [SerializeReference] fields — IMGUI and UIToolkit drawers render a hierarchical type-picker dropdown that instantiates the chosen type, with inline resolution of open generic arguments (including nested generics) via GenericTypeResolver.
  • Detect missing managed-reference types straight from the asset YAML and repair them in place: a compact warning notice with an inline Fix picker re-points the stored type while keeping its data — for saved assets and Prefab Mode, at any nesting depth (nested references and [Serializable] containers). Aliased references get a matching Make unique action.
  • Add a Repair Missing References window (Tools → Aspid 🐍) in the Welcome design (dots canvas, asset card, hero states, amber result rows) that scans the whole asset file and fixes every orphaned reference — at any depth, on any child object — through an embedded accordion type picker.
  • Ship a SerializeReferences sample (weapons/effects, a generic Modifier<T> hierarchy, broken/shared-reference demo prefabs) and document the feature in the READMEs (EN/RU, root + Documentation) and the CHANGELOG.

Notes for review

  • New editor code lives under Unity/Editor/Scripts/SerializeReferences/ (drawers, SerializeReferenceField, SerializeReferenceYamlEditor, the repair window) and Types/Selectors/ — the selector now lives in a reusable TypeSelectorView, with TypeSelectorWindow reduced to a thin dropdown host (public Show API unchanged).
  • Trickiest spots: generic-argument resolution (TypeSelectorView + GenericTypeResolver), YAML-based missing-type detection/rewrite (SerializeReferenceYamlEditor), and the repair window's declared-field constraint map.
  • Selector USS was migrated to BEM (aspid-fasttools-type-selector block) and the stylesheet renamed to Aspid-FastTools-TypeSelector.uss (meta GUID preserved).
  • The branch also carries the [TypeSelector] unification (Unify SerializeReference selector into [TypeSelector] with usage analyzer #50) and the Aspid.FastTools.Analyzers submodule with the AFT* compile-time rules, including a fix for AFT0001 misfiring on every [SerializeReference] field (Unity declares SerializeReference without the Attribute suffix).

… drawer

Add a hierarchical type-selector dropdown for [SerializeReference] fields
(single, array and List<T>), reusing TypeSelectorWindow. Picking a concrete
type instantiates it, <None> clears the reference, the assigned instance's
nested properties are drawn inline under a foldout, and an unresolved stored
type is surfaced as a missing-type warning. Implemented for both IMGUI and
UIToolkit inspectors.

TypeSelectorWindow.Show gains an optional candidate-type filter (backward
compatible) used to exclude UnityEngine.Object, open generics, strings and
delegates.
Add a loadout-system sample exercising [SerializeReferenceSelector]: single
IWeapon field, List<IWeapon>, abstract StatusEffect base, and a nested
[SerializeReference] inside Railgun. Includes an IMGUILoadout + forcing editor
to demonstrate the IMGUI path, EN/RU README, and a package.json sample entry.
Add Loadout.prefab (UIToolkit) and IMGUILoadout.prefab (IMGUI) with pre-filled
managed references — single (Railgun + nested BurnEffect), List<IWeapon>
([Pistol, Shotgun]) and abstract-base (FreezeEffect / BurnEffect) — so the
sample can be inspected without building it by hand. Update the EN/RU sample
README "How to run" to drive the prefabs.
- Offer open generic definitions (e.g. Modifier<T>) as candidates: infer
  arguments from a closed-generic field, or resolve them in a new
  recursive, constraint-aware GenericArgumentSelectorWindow, validating
  the closed type against the field before assignment. Works in IMGUI and UIToolkit.
- Add an optional additionalTypes pass-through to TypeSelectorWindow /
  HierarchyBuilder / TypeInfo, and render generic names as Modifier<T>.
- Add a non-abstract Modifier<T> hierarchy (IModifier) with closed-generic
  subclasses, plus IModifier / Modifier<float> / List<IModifier> fields on
  Loadout and IMGUILoadout to exercise open-generic selection and the T picker.
- Document the generic flow in the sample README (EN/RU).
- Note open-generic support and the new additionalTypes parameter in the
  CHANGELOG, and add a generic bullet to the feature section of all four READMEs.
…he dropdown

- Resolve open generics inside TypeSelectorWindow as in-window argument pages (hierarchy, search, breadcrumb, live preview), removing the separate GenericArgumentSelectorWindow and its focus issues
- Extract generic resolution into GenericTypeResolver and add an argumentFilter parameter to TypeSelectorWindow.Show; the flow stays dormant unless open generics are present
- Format generic type names recursively so nested closed generics render fully (Modifier<Modifier<Int32>>)
- Resolve the generic type definition when locating a script so Open Script works for closed generics
@VPDPersonal VPDPersonal added type: feature New feature or capability status: work-in-progress Draft / not ready for review area: runtime Runtime / player code area: editor Editor-only code area: samples Sample projects labels Jun 7, 2026
VPDPersonal and others added 10 commits June 7, 2026 21:07
…eric argument selector

Open generic definitions reach the selector through the additionalTypes
path, which bypasses the name and CompilerGeneratedAttribute checks
applied to ordinary candidates. As a result anonymous types and closure
display classes (e.g. <>c__11<T>, <>f__AnonymousType0<...>) showed up as
argument candidates and bloated the unconstrained (object) list.

Exclude compiler-generated types in IsAssignableGenericDefinition so the
single gate for generic definitions filters them out.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Carry the foldout caption on the toggle's aligned BaseField label so the
  type dropdown starts at the inspector value column, matching SerializableType
- Centre the header row so the open-script button lines up with the dropdown
- Split the dropdown into field/input nodes and cancel the EnumField caption's
  -2px left margin so the text indents like SerializableType
…/paste

- CreateInstancePreservingData carries matching [SerializeField] data across a
  type switch via JsonUtility ToJson/FromJsonOverwrite, instead of resetting
- SerializeReferenceClipboard backs a header right-click Copy/Paste menu scoped
  to the field (IMGUI ContextClick + UIToolkit ContextualMenuManipulator); paste
  builds an independent instance and is disabled when the type is not assignable
… references

- Add an Edit Type action to the missing-type warning: it opens an
  Assembly/Namespace/Class editor and rewrites the stored managed-reference
  type straight into the asset YAML (parser-free, no external deps), since
  Unity cannot reassign a missing reference through the serialization API.
  Applies to ScriptableObjects — the only assets where Unity preserves missing
  references (UUM-129100).
- Detect an aliased managed reference (two fields sharing one instance) and
  offer a Make Unique Reference action that clones it into an independent copy.
- Sample: add a WeaponPreset ScriptableObject with a pre-broken asset, plus
  shared-reference and missing-type demo prefabs, and document how to test both.
…YAML

- Replace the manual Edit-Type window with a Fix button that opens the existing
  hierarchical type picker; the chosen type is rewritten into the asset YAML.
- Read the missing type straight from the asset file (stored id + RefIds type)
  instead of Unity's serialization API, which reports nothing per-property and
  drops the reference on prefabs/GameObjects (UUM-129100). Repair now works on
  prefab assets too, not just ScriptableObjects.
- Detect strictly per-field by resolving the recorded type, removing the
  single-missing fallback that falsely flagged legitimately-empty fields.
- Scan a prefab/ScriptableObject's YAML for every orphaned managed reference —
  at any nesting depth and on any child object — by walking each document's flat
  RefIds block and flagging entries whose stored type no longer resolves.
- List each with its own Fix picker that rewrites the type in the file and
  reimports, reaching references the per-field drawer cannot (nested values,
  child-object components, anything Unity dropped to <None>) without Prefab Mode.
- Open via Tools → Aspid FastTools → Repair Missing References (auto-targets the
  current selection).
… Mode repair

Replace the bulky missing-type and shared-reference help boxes with a
compact yellow inline notice: a small warning icon, terse text and an
underlined, clickable action word (Fix / Make unique) with the full
detail on hover. Covers both the IMGUI and UIToolkit drawers.

Extend missing-type repair to objects open in Prefab Mode: detection
resolves the backing document through the prefab stage (matching the
asset's file id), and the fix is applied in memory — reassigning the
reference and recovering the orphaned field data — because rewriting the
open stage's file would be discarded on save. Saved assets keep the
YAML-rewrite path.

Reselect the inspected objects after a repair so Unity's cached
object-level missing-types banner clears, and guard the UIToolkit field
against the live SerializedObject being invalidated by a reimport.
…n containers

Generalise the YAML reference resolver behind the inline missing-type Fix to
walk a property path of any shape: through managed-reference chains and through
plain [Serializable] containers (struct/class fields and List<T> of them), so a
missing type buried in a slot or list element is detected and repaired inline
like a top-level field.

When an in-memory (Prefab Mode) repair replaces a missing reference that itself
carried missing nested references, clear those now-orphaned entries too so the
object's missing-types banner clears.

Add the SlottedLoadout sample demonstrating [SerializeReferenceSelector]
references inside a container field and a List<T> of containers.
- Redesign the Repair References window in the Welcome style: boxed
  asset card with an Aspid header, centred info/success hero states,
  warning-accented results header and amber gradient rows.
- Extract the hierarchical type selector from TypeSelectorWindow into a
  reusable TypeSelectorView; the window stays a thin dropdown host with
  an unchanged public Show API.
- Expand the selector inline as an accordion under the clicked Fix row
  (dark Aspid panel, one at a time, Escape collapses) instead of the
  floating grey dropdown.
- Migrate selector USS classes to BEM under the
  aspid-fasttools-type-selector block and rename the stylesheet to
  Aspid-FastTools-TypeSelector.uss; sync the asset field when Open()
  retargets an already-open window.
- The repair window moved to Tools → Aspid 🐍 → Repair Missing
  References FastTools; mirror the new path in the CHANGELOG, both
  root/Documentation README pairs and the sample READMEs.
@VPDPersonal VPDPersonal changed the title Add [SerializeReferenceSelector] dropdown for SerializeReference fields Add [SerializeReferenceSelector] dropdown and missing-type repair Jun 10, 2026
- Remove `[SerializeReferenceSelector]`; `[TypeSelector]` now also drives `[SerializeReference]` managed-reference fields, dispatching by property type in `TypeSelectorPropertyDrawer`.
- The attribute's base types narrow the candidate list below the declared field type — applied to both concrete types and open generic definitions, in the dropdown and the missing-type Fix picker.
- Update samples, CHANGELOG and READMEs (EN/RU) to the merged attribute.
- Add the `Aspid.FastTools.Analyzers` git submodule (VPDPersonal/Aspid.FastTools.Analyzers) carrying the `AFT*` [TypeSelector] usage rules.
- Ship the prebuilt `Aspid.FastTools.Analyzers.dll` with a `RoslynAnalyzer`-labelled meta (all platforms excluded), mirroring the generator DLL.
- Document the submodule and its manual rebuild/deploy in CLAUDE.md.
- Bump the analyzer submodule: AFT0003 now also flags a sealed class paired with an interface it does not implement; redeploy the prebuilt DLL.
- Switch the submodule URL from SSH to HTTPS so public clones resolve it without keys.
- Add the rebuild-analyzers-on-change PostToolUse hook script and the build-analyzer skill mirroring the generator pipeline; document both in CLAUDE.md.
…attribute

Unify SerializeReference selector into [TypeSelector] with usage analyzer
The analyzer matched UnityEngine.SerializeReferenceAttribute, but Unity
declares the class without the Attribute suffix, so AFT0001 flagged every
valid [SerializeReference] [TypeSelector] field as an error. Bump the
analyzers submodule and redeploy the DLL.
The SerializeReferences sample description in package.json still named
the removed [SerializeReferenceSelector] attribute.
@VPDPersonal VPDPersonal changed the title Add [SerializeReferenceSelector] dropdown and missing-type repair Add [TypeSelector] dropdown for [SerializeReference] and type repair Jun 11, 2026
AFT0004 (error): [TypeSelector] managed reference whose element type
derives from UnityEngine.Object, which Unity does not serialize as a
managed reference. AFT0005 (warning): no concrete Unity-serializable
candidate visible to the compilation satisfies both the typeof() base
and the field's element type, so the picker would be empty. Bump the
analyzers submodule and redeploy the DLL.
Add a [TypeSelectorItem] runtime attribute that supplies a display
path/name, tooltip, order and icon for types shown in the picker.
TypeInfo reads it, HierarchyBuilder re-homes types under category
nodes (or renames the leaf in place) and sorts each level by Order then
alphabetically; TypeSelectorView renders an icon and tooltip, and search
still matches the real type name through TreeNode.SearchName.

Add Favorites and Recent sections to the picker's root page: a
hover-revealed star toggle per type row, recents recorded at the
view's single Emit choke point (so constructed generics record the
closed type's AQN), capped at 8 in MRU order. Both are persisted per
project via EditorPrefs JSON and pruned of unresolved types on load.
Sections surface only types in the current candidate set, only on the
base page (generic-argument pages opt out via composeSections), and are
hidden while searching; keyboard navigation skips section titles.
…ixes

Add a Smart Fix suggestion to the missing-type notice on [TypeSelector]
[SerializeReference] fields. When a stored type no longer resolves, a new
ranking engine scores existing candidate types and surfaces the best one as a
second clickable segment after Fix ("· → Pistol?"); the suggestion is never
auto-applied — the user always clicks.

- SerializeReferenceRepairSuggestions: scores candidates by [MovedFrom] rename
  (reflective, defensive), exact / case-insensitive name match, bounded
  Levenshtein, and a serialized-field-shape overlap bonus. The pool is the same
  set the picker offers (concrete managed references assignable to the field
  constraint), and the ranking is cached per (asset, document, rid) so IMGUI
  repaints never re-scan the TypeCache.
- SerializeReferenceHelpers: TryGetRepairSuggestion resolves the field names
  (YAML data block for saved assets, in-memory payload in Prefab Mode), ranks,
  and post-filters through the exact picker predicate; shared label/detail
  formatters keep the two notices in sync; the cache is cleared on repair.
- SerializeReferenceYamlEditor: additive GetReferenceFieldNames /
  ParseTopLevelFieldNames helpers for field-shape extraction.
- Wire the suggestion into both the UIToolkit notice (SerializeReferenceNotice /
  SerializeReferenceField) and the IMGUI DrawNotice, with a matching BEM USS
  class for the trailing segment.
Visualise the [SerializeReference] managed-reference graph of an asset:
a document-per-component tree of field-pointer roots, nested children,
shared (aliased) references and orphaned payloads, read straight from
the YAML so it surfaces references at any depth and the orphans the
Inspector cannot navigate to.

- SerializeReferenceGraphScanner builds the per-document graph (nodes,
  edges, roots, shared and orphan sets) with local YAML parsing.
- SerializeReferenceGraphWindow (Tools/Aspid/Managed References, priority
  21) renders indented AspidBox cards with MISSING / SHARED badges, a
  deterministic per-rid colour chip, cycle-safe back-edge leaves and an
  inline type picker to re-point a missing reference via TryRewriteType.
- New Aspid-FastTools-ReferenceGraph.uss under the reference-graph BEM
  block.
…tor drawers

Make the [TypeSelector] managed-reference drawers (IMGUI and UIToolkit)
correct under a multi-object selection.

- Detect mixed managed-reference types across targets (hasMultipleDifferentValues
  or differing managedReferenceFullTypename) and show a mixed-value dropdown
  ("—") plus a dim "different types" info notice instead of merging incompatible
  child fields.
- Apply a type pick / paste / clear to every target independently via
  ApplyManagedReferencePerTarget: each object gets its own instance (no aliasing
  across objects), created from that target's previous value for Keep-Data, all
  collapsed into a single Undo step.
- Suppress the per-asset missing/shared notices and the Make-unique action under
  multi-edit (they operate on a single backing asset); Copy reads the first
  target, Paste applies an independent instance per target.
- Add an info variant to SerializeReferenceNotice and its USS, and a dim info
  line to the IMGUI drawer, for the mixed-types hint.
…air window

Add a second mode to the Repair Missing References window: a Scan Project
button sweeps every text asset under Assets/ (.prefab/.asset/.unity) behind a
cancelable progress bar, groups the broken references by their stored
(unloadable) type, and offers a single bulk Fix all per group. One type pick
plus a mandatory confirmation rewrites every entry across every affected file,
batched per file with one ImportAsset each, then reports a success summary.

The group picker is constrained by intersecting the declared field types of the
group's entries (per-file constraint maps cached), falling back to object when
they disagree. A Smart Fix quick-apply surfaces the top-ranked suggestion in the
group header. The single-asset flow is unchanged; assigning the asset field
returns to it.

Extract BuildConstraintMap into SerializeReferenceHelpers as a shared public
helper and reuse it to constrain the Managed References graph window's Fix
picker, which was previously unconstrained.
When a [SerializeReference] list element is duplicated (Duplicate, Ctrl+D)
or appended via the list + button, Unity copies the source element's
managed-reference rid, so two elements share one instance and editing one
silently edits the other.

Add SerializeReferenceDuplicateGuard: it keeps a per (target, array path)
index -> rid snapshot of the live SerializedObject and, when a new same-array
alias appears between observations, queues a deferred swap of the later element
for an independent clone (CreateInstancePreservingData), registered as a single
Undo step. Pre-existing aliases (first observation, domain reload) and
cross-field sharing are left to the existing shared-reference notice; multi-object
edits are skipped. Snapshots resync on Undo/Redo so a reverted alias is not
re-fixed. The fix runs on EditorApplication.delayCall to avoid mutating the
SerializedObject mid-draw.

Hook the guard from SerializeReferenceField.Refresh (UIToolkit) and
SerializeReferenceIMGUIPropertyDrawer.Draw (IMGUI), gated by a size + rolling-hash
fast path so the no-change repaint cost stays minimal.
… references

Extract the golden-ratio rid→Color algorithm from SerializeReferenceGraphWindow
into a shared SerializeReferenceRidColor.ForRid helper so the inspector and the
Managed References window always show the same colour for the same rid.

UIToolkit: add a 3 px left stripe on the field root (aspid-fasttools-serialize-reference__rid-stripe)
and a round chip on the shared-reference notice row (aspid-fasttools-serialize-reference-notice__rid-chip)
when HasSharedReference is true and rid >= 0.

IMGUI: add a 3 px EditorGUI.DrawRect stripe at the left edge of the header line
using the same ForRid colour, drawn only when the shared-reference notice applies.

Both paths piggyback on the existing HasSharedReference result already computed
for the notice and skip multi-object selections and invalid (< 0) rids.
…r features

Add CHANGELOG entries and extend the SerializeReference / TypeSelector
README sections (EN/RU, root + Documentation) for: Smart Fix
suggestions, project-wide Repair scan with bulk Fix all, the Managed
References window, the [TypeSelectorItem] attribute, picker
favorites/recents, multi-object editing, auto-unique duplicated list
elements, shared-reference per-rid colours, and the AFT0004/AFT0005
analyzer rules.
Correctness, robustness and USS/BEM fixes across the SerializeReference
tooling raised in the code and USS reviews.

- Graph window Fix now rewrites only the owning document, threading the
  captured fileId through TogglePicker/ApplyFix/ResolveConstraint so a
  cross-document rid collision can no longer clobber a healthy reference;
  ClearCache is invoked after a successful rewrite.
- Duplicate guard only fixes an array that grew since the last snapshot
  and whose duplicated rid's count rose, so reordering or removing around
  a pre-existing alias no longer silently de-aliases it.
- Repair window guards both the bulk and single-asset file rewrites
  against an open Prefab Mode stage, batches per-file reimports inside
  StartAssetEditing/StopAssetEditing, and warns when a group's mixed
  field types force a typeof(object) downgrade.
- BuildConstraintMap tracks visited managed-reference rids so a cyclic
  graph no longer hangs the editor.
- Favorites refresh from any picker page; icon resolver tries Resources
  first for path-shaped strings to avoid IconContent console noise.
- USS: drop the dead serialize-reference--mixed modifier, move graph
  empty/scroll and notice suggestion/rid-chip visibility plus the type
  selector error label styling onto BEM modifier classes and USS rules.
Add the package's first EditMode test assembly (Aspid.FastTools.Unity.Editor.Tests) covering the SerializeReferenceYamlEditor parser, plus a path+write-time YAML probe cache so the per-property missing-type probe no longer reads the file on every IMGUI repaint.
…uard

Add a project-wide managed-reference usage index (modeled on the Id system) that powers a Find Usages context action and an sr: Quick Search provider, MonoScript delete protection, and a fast index-backed project scan.
Detect managed references that just became missing (script renamed/deleted) by diffing against a per-session baseline, and surface a non-intrusive notification that deep-links into the Repair window with pre-ranked Smart-Fix suggestions. Never auto-applies.
MonoScript drag-and-drop assignment, durable named instance templates, Link to Existing (deliberate instance sharing), a picker-backed list + button, and Create New Script (generate and assign a subclass stub across the domain reload).
Add [SerializeReferenceRequired] (runtime, editor-only) with an inline notice, a Project Settings page (rid colours, auto de-alias, excluded folders, gate severity), and a build (IPreprocessBuildWithReport) + headless CI (-executeMethod) gate over missing / unset-required references.
Integrate the index, detection, required notice, settings and authoring affordances into the existing drawers and repair/graph windows; add saved-scene + jump-to-source-prefab + orphan-clear repair paths and a bulk-fix diff preview; promote shared scan helpers; update the changelog.
Unify the Repair References and Managed References windows into a single Managed References workbench with two modes: Inspect Asset (the reference graph, which subsumes the per-asset repair list with inline Fix/Clear/Open Source Prefab) and Project Audit (the project-wide grouped bulk fix). A Project Audit result links to that asset's Inspect graph. One menu entry replaces the two.
Replace the left-to-right gradient fill (a generated texture + hover overlay) with a classic button: a solid dark pill with a green left accent bar that turns its border and text to the accent colour on hover and darkens on press. All states are USS-driven (:hover / :active) off the existing fill/accent custom properties, so context re-toning (e.g. the graph window's warning-hued Fix buttons) still works. Drops the now-unused gradient texture, hover overlay and colours-style helper.
The accent default referenced --aspid-colors-status-success, which the palette does not define (only -dark/-light/-text-* variants exist), so the left bar and hover tint resolved to transparent. Point it at --aspid-colors-status-success-text-light (#78EB91), the same brand green the success dividers use.
Cohesion pass: drop the slivery accent bar for a flat dark button (subtle border, green border+text on hover, sinks on press) that reads as part of the dark cards; tone the Info help box from saturated blue to the dark surface; and replace the mode toggle's accent-bar buttons with a real tab bar (own dark strip, hairline separator, active tab marked by a green underline).
Roll the button styling back to the merge state (f8bff68): the AspidGradientButton keeps its horizontal-gradient fill and hover overlay (ColorsStyle restored), the mode toggle uses the gradient buttons with an opacity active cue, and the help box returns to its original style. Undoes the classic accent-bar / flat / tab-bar / dark-info-box restyle.
- Add SerializeReferenceCanvasStyle helper and window stylesheet for status-toned canvas
- Restyle SerializeReference, ReferenceGraph and Scan panels with tabs and full-width header
- Rework TypeSelector picker: collapsible sections, breadcrumb navigation, glyph icons and footer hints
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: editor Editor-only code area: runtime Runtime / player code area: samples Sample projects status: work-in-progress Draft / not ready for review type: feature New feature or capability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant