Add [TypeSelector] dropdown for [SerializeReference] and type repair#49
Draft
VPDPersonal wants to merge 33 commits into
Draft
Add [TypeSelector] dropdown for [SerializeReference] and type repair#49VPDPersonal wants to merge 33 commits into
VPDPersonal wants to merge 33 commits into
Conversation
… 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
…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.
- 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.
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
[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) viaGenericTypeResolver.[Serializable]containers). Aliased references get a matching Make unique action.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.SerializeReferencessample (weapons/effects, a genericModifier<T>hierarchy, broken/shared-reference demo prefabs) and document the feature in the READMEs (EN/RU, root + Documentation) and the CHANGELOG.Notes for review
Unity/Editor/Scripts/SerializeReferences/(drawers,SerializeReferenceField,SerializeReferenceYamlEditor, the repair window) andTypes/Selectors/— the selector now lives in a reusableTypeSelectorView, withTypeSelectorWindowreduced to a thin dropdown host (publicShowAPI unchanged).TypeSelectorView+GenericTypeResolver), YAML-based missing-type detection/rewrite (SerializeReferenceYamlEditor), and the repair window's declared-field constraint map.aspid-fasttools-type-selectorblock) and the stylesheet renamed toAspid-FastTools-TypeSelector.uss(meta GUID preserved).[TypeSelector]unification (Unify SerializeReference selector into [TypeSelector] with usage analyzer #50) and theAspid.FastTools.Analyzerssubmodule with theAFT*compile-time rules, including a fix for AFT0001 misfiring on every[SerializeReference]field (Unity declaresSerializeReferencewithout theAttributesuffix).