Add [TypeSelector] dropdown for [SerializeReference] and type repair#49
Open
VPDPersonal wants to merge 82 commits into
Open
Add [TypeSelector] dropdown for [SerializeReference] and type repair#49VPDPersonal wants to merge 82 commits into
VPDPersonal wants to merge 82 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
- Paint the accent gradient as one continuous mesh with shared boundary vertices instead of many separately-filled painter2D strips. - Adjacent strips each anti-aliased their own edges to transparent, so the dark background bled through at every seam as faint vertical lines. - A single mesh is only smoothed on its outer silhouette, removing the seams while keeping the quadratic alpha falloff.
- Replace the standalone Welcome window with a square "home" tab; the Welcome UI moves into a reusable WelcomeView and first-run auto-show now opens this window on the home tab. - Add a rightmost square "settings" tab (placeholder SettingsView) sharing the --square / __tab-icon styling with the home tab. - Generate outline home and gear icons under Resources/Icons, tinted per tab state: grey idle, brighter on hover, green when active. - Rename the window title to "Aspid FastTools" and restore the multi-tone "traffic light" canvas gradient on the home tab.
- Add AspidThemeSettings, AspidThemeSettingsProvider and AspidThemeStyleSheetExtensions so editor components can layer a user theme override over the default dark palette - Route internal editor elements through AddAspidThemeStyleSheets() instead of hard-wiring AspidStyles.DefaultStyleSheet (Id/Type fields, drawers, registry, selectors and the serialize-reference windows)
…scan - Rebuild the Inspect Asset graph view as collapsible gradient-header cards with two-line nodes and an amber accent for broken refs, matching the Project Audit design - Flatten the Project Audit Rescan button to a header-style action: drop its left padding and pill background so it lines up with the panel title and reads like the group "Fix all" headers - Extend AspidGradientButton with trailing label and trailing-content support consumed by the redesigned cards
…ypes - Add IMelee/IRanged interfaces and a Sword melee type so the TypeSelector demo shows constrained managed-reference picking - Add a TypeSelectorTutorial scene and script, and update Pistol/Railgun/Shotgun to fit the expanded sample
- Add TUTORIAL.md / TUTORIAL_RU.md walkthrough (Lessons 1–8) keyed to the TypeSelectorTutorial scene and script - Link the tutorial from the sample README/README_RU and update the package manifest sample description
- Render each sample's package.json description as a wrapped line under a full-width divider in the samples list - Lay out the sample name and its Import/Reimport action on a single header row - Replace the imported-state "Select" (ping folder) with "Reimport", which re-imports over the existing copy after a confirm dialog - Mirror the gradient button's hover recolor for the relocated name/action labels
- Introduce AspidWindowFooter: a transparent bottom bar pairing the package version (linking to its GitHub release tag) with a GitHub link, above a faded divider - Pin it to the bottom of the Managed References window so it persists across every tab/mode instead of living inside the Welcome tab - Drop the now-redundant inline footer from the Welcome UXML
- Wrap long Project Audit entry paths onto multiple lines (min-width:0) so the rid stays pinned right instead of overflowing into a horizontal scroll - Stack one summary help-box per bulk Fix all and keep the results region when the last group clears, so prior receipts survive until an explicit Rescan instead of being overwritten or dropped - Skip Unity scenes in the object-loading scanners via a shared IsScene helper (LoadAllAssetsAtPath cannot read .unity files); fall back to the YAML pass - Defer the ListView add-button install one tick to avoid mutating the subtree mid-attach - Restyle the Inspect Asset reference graph (GraphView + ReferenceGraph.uss)
- Each fix receipt carries a right-pinned Undo button that re-points its entries back to the original missing type, restoring the broken state (only the YAML type line moves, data blocks stay on disk, so the revert is faithful) - Undo drops only its own receipt and re-renders the group list, leaving receipts and Undo buttons for other still-applied fixes standing - Extract the scene/Prefab-Mode skip filter and the batched per-file rewrite into shared helpers used by both the fix and the undo
- EditorWindow.minSize only bounds the floating window; a docked column ignores it and squeezes the content into character-wrapped, vertical text. - Give the mode container a min-width so the content slides off-screen (clipped) instead of collapsing; toolbar/footer stay flexible.
- Position the per-receipt Undo chip absolute in the help box's top-right corner instead of in the row's flex flow, so the title and message stretch edge to edge instead of being cut short at the chip.
- Picking <None> in the Project Audit Fix all picker now nulls the group's broken references instead of being a no-op. - On disk: rewrite each field/array pointer to the null id (-2) and add Unity's RefIds null sentinel, dropping the broken payload (TryNullReference) — matches what Unity writes for a null reference. - Open in Prefab Mode / a loaded scene: null the reference on the live object in memory (TryClearMissingReferenceInMemory), saved with the asset, since a file rewrite there would be clobbered on save. - Stop rendering the -2 null sentinel as a graph node so cleared fields no longer surface as "rid -2" shared cards.
- Render unassigned [SerializeReference] fields (null sentinel rid -2) as dim <None> leaves so a cleared or never-set slot stays visible in the graph instead of dropping out. - Carry the full field path of each nested reference (e.g. _primaryWeapon._chargeEffect) via a new ReferenceGraphEdge. - Add scanner structural tests and an empty-fields YAML fixture; show the empty slots in the Loadout sample prefab. Refresh READMEs and CHANGELOG.
- The tab labels "Inspect Asset" / "Project Audit" read as generic tools; rename to "Asset References" / "Project References" so they reflect the managed-reference scope the window already declares. - Sync the labels across code comments, CHANGELOG and the sample docs.
- Keep a document whose RefIds block resolves to zero real nodes but still holds a field pointer, so an asset whose every [SerializeReference] field is unassigned renders its slots as <None> instead of dropping out with a "No managed references" empty state. - Only return null now when there is neither a node nor a field pointer (every managed-ref field is an empty list — nothing to graph). - Add an all-unassigned fixture and a regression test.
- Picking <None> in a missing card's Fix picker now nulls the reference instead of doing nothing — an empty type name fell through the null-type guard and silently no-op'd. - Add a Clear action on every assigned reference card that resets it to <None>, so a reference can be cleared from the graph everywhere, not just re-pointed when missing. - Both route through a shared ClearReference (YAML null-sentinel rewrite); confirmed and not undoable, with a neutral-tinted __clear-reference button. - Document the new clear behavior in the EN/RU READMEs.
- Every reference card in the Managed References graph is now an inline type dropdown: picking a type assigns or re-points the reference and <None> clears it. Drops the dedicated Clear button on assigned cards — resetting is done through the picker, not a separate action. - Healthy and empty (unassigned) slots edit through the live SerializedObject API keyed by field path, so Unity creates or removes the RefIds entry as the Inspector would; missing references keep the YAML rewrite (Unity cannot reassign a missing type through the API). - Persist live edits via SavePrefabAsset for prefab assets and SaveAssetIfDirty for ScriptableObjects, then rescan from disk. - Neutral-tint the dropdown band; the amber accent moves to a --missing modifier so only a broken card reads as a call to action.
- Healthy and empty graph cards now label their dropdown band ("Change ▼" /
"Assign ▼") instead of showing a lone chevron, matching the missing
card's "Fix Missing ▼".
- The empty (<None>) card drops its dimmer fill/border override so it reads
at the same weight as the live cards — it is now an editable dropdown, so
only its dim italic <None> placeholder sets it apart.
Nesting is read from each card's field path (e.g. _primaryWeapon._chargeEffect), so the per-depth left margin was redundant. Render every card flush in a flat column; remove the depth parameter threaded through AppendNode / BuildNodeCard / BuildEmptySlotCard / BuildBackEdgeCard and the IndentStep constant.
- The Asset References "Rescan" row sized to its field (height:auto, ~24px) while the Project References "Scan Project" button kept the gradient button's 30px default, so the two tabs' top panels differed in height. Pin the Rescan row to 30px so both action rows — and the panels — match. - Fix two invalid unitless USS lengths in the same file: padding-left: 4 and margin-bottom: 2 (now 4px / 2px).
NestedLoadout.prefab is a three-level hierarchy (NestedLoadout → WeaponSlot → BackupSlot) with a Loadout on every object, each carrying a missing [SerializeReference] type (GhostPistol / GhostBlade / GhostAura) the Inspector can't reach outside Prefab Mode — plus a nested reference, an empty <None> slot and healthy refs. Exercises the graph's per-component multi-document view, missing types on child objects, and the inline assign / re-point / clear dropdowns. Documented in the sample README EN/RU.
The per-document header bands floated transparent over the dotted canvas, their fill showing only on hover. Give them the same resting card surface as the node cards below (translucent dark fill + hairline border) so each header reads at the same weight as its group; the amber issue hover glow is kept.
- Bind Alt+1/2/3/0 to Home/Asset/Project/Settings via ShortcutManager with the window as context, so the keys work whenever the window is focused (a panel KeyDownEvent only fired while an inner element held focus) - Show the live binding as a keyboard-cap badge on the two mode tabs and as a tooltip on every tab, reading it back from ShortcutManager so it tracks user rebinds in Edit > Shortcuts
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
Extends
[TypeSelector]to[SerializeReference]and adds a full authoring + integrity toolkit for managed references. Every row works in both IMGUI and UIToolkit.[SerializeReference]List<T>fields. Pick → instantiate,<None>→ clear, the instance's nested props draw inline. Candidates default to the declared type, narrowed by[TypeSelector(typeof(IMelee))].Modifier<T>; arguments are inferred from a closed-generic field or picked in a follow-up window honouring constraints.[TypeSelectorItem](display name /Category/Name/ tooltip / order / icon); per-project Favorites ★ + Recent; collapsible groups with in-header search.Tools → Aspid 🐍 → Managed References FastTools, four tabs: Home (overview + installable samples), Inspect Asset (whole graph from YAML —MISSING/SHAREDbadges, orphans, inline Fix, Open Source Prefab), Project Audit (project sweep grouped by broken type,Fix allwith YAML diff preview, per-fix receipts with Undo, deep-links to Inspect) and Settings.AspidThemeSettings+ Project Settings page) that re-skins every Aspid FastTools editor view; a reusableAspidWindowFooter(version + GitHub link) is pinned to the bottom of the window.sr:Quick Search; delete-script guard; proactive breakage notification; build/CI gate (SerializeReferenceCiGate.RunCheck);[SerializeReferenceRequired]; Project Settings page.+; Create New Script.SerializeReferencessample (weapons/effects, melee/ranged types, genericModifier<T>, broken/shared demo prefabs) with a step-by-step tutorial (TypeSelectorTutorialscene +TUTORIAL.mdEN/RU); README EN/RU + Documentation + CHANGELOG; first EditMode test assembly (Aspid.FastTools.Unity.Editor.Tests).Notes for review
Unity/Editor/Scripts/SerializeReferences/. The selector was extracted into a reusable view;TypeSelectorWindowis now a thin dropdown host (publicShowAPI unchanged, gained optionalfilter/additionalTypes).SerializeReferenceYamlEditor), at-any-depth repair through nested refs and[Serializable]containers, and the bulk rewrite (edits asset files directly — irreversible, hence the diff preview + confirmation).AspidThemeSettings/AspidThemeSettingsProvider, applied across ~11 editor views) and a reusableAspidWindowFootercomponent pinned to the window bottom.aspid-fasttools-type-selector); stylesheet renamed toAspid-FastTools-TypeSelector.uss(meta GUID preserved).[TypeSelector]unification (Unify SerializeReference selector into [TypeSelector] with usage analyzer #50) and theAspid.FastTools.Analyzerssubmodule —AFT0001fix (Unity declaresSerializeReferencewithout theAttributesuffix), a widenedAFT0003, plus newAFT0004/AFT0005diagnostics. The submodule pointer tracks the analyzer'sfeat/aft-usage-rulesbranch (to be merged into itsmainseparately).Linked issues
Closes #10