Skip to content

Bitmask-Accelerated Queries & API Cleanup

Latest

Choose a tag to compare

@brunomikoski brunomikoski released this 16 May 12:41
b80ef5a

Added

  • New PreviewMode enum (Default/Inline/PropertyEditorWindow) on SOCItemEditorOptionsAttribute, plus a matching project-wide default in SOCSettings (Project Settings > Scriptable Object Collection > Item Inspector). When set to PropertyEditorWindow, the per-field Edit button opens Unity's floating Property Editor via EditorUtility.OpenPropertyEditor instead of the inline preview panel — fixes rendering issues with third-party inspectors (e.g. Odin) that don't draw correctly in the inline IMGUI drawer. Default on the attribute defers to the project setting; project setting defaults to Inline so existing behavior is unchanged.
  • New CollectionItemMask64 static helper plus IEnumerable<T>.ToItemMask64<T>() and List<T>.FromItemMask64<T>() extension methods. Provides a 64-bit bitmask representation of a set of collection items keyed on ScriptableObjectCollectionItem.Index, with Bit/Has/Add/Remove/Overlaps/IsSubsetOf helpers and a From<T>(items, out bool fits) builder that flags when any item's Index >= 64. Bit positions are per-collection — callers are responsible for only comparing masks built from items of the same collection.
  • CollectionItemPicker<T> now exposes a cached bitmask (CachedMask) and a CanUseBitmask gate (combines MaskFitsIn64 with every item collection's SupportsBitmaskIndexing flag), plus CountMatchesIn(ulong) and CountMatchesIn(IEnumerable<T>) overloads backed by a SWAR PopCount. The mask is rebuilt on OnAfterDeserialize, on every mutating operation (Add/Clear/Remove/Insert/RemoveAt/indexer set), and lazily in Edit Mode; reused without rebuild in Play Mode.
  • ScriptableObjectCollection virtual SupportsBitmaskIndexing (default true). Override to false on collections whose item ordering can change at runtime (e.g. CDN-delivered content) so the bitmask fast path is skipped — each item's Index is cached on first access and would otherwise go stale after a reorder.
  • CollectionItemPicker<T>.ToString() override returning [item1, item2, ...] (empty collection renders as []; null entries render as <null>). Uses StringBuilder to avoid per-call allocations on long pickers.
  • CollectionItemQuery<T>.IsEmpty() returns true when every QuerySet's picker contains zero items — useful for skipping the Matches evaluation on default-constructed queries.
  • CollectionItemPickerPropertyDrawer now writes itemLastKnownName and collectionLastKnownName when an entry is added to a picker, so newly added items have populated cache names immediately instead of empty strings.

Changed

  • Reverted CollectionItemQuery.MatchType enum values: SomeNotNotAny, NoneNotAll. The new names mirror Any/All and describe the actual semantics (target has none of the picker items / target is missing at least one of them). Integer values are preserved (2 and 3), so existing serialized QuerySet data deserializes unchanged.
  • Added XML documentation on MatchType values and the Matches method to surface the semantics in IntelliSense.
  • CollectionItemQuery<T>.Matches now selects between a bitmask fast path (MatchesViaBitmask) and the existing GUID-based path (MatchesViaGuids) at the start of each call. The bitmask path is used only when every QuerySet's picker reports CanUseBitmask == true; otherwise the call falls back to the original GUID comparison. Match results are unchanged — only the evaluation strategy.
  • CollectionItemPicker<T> events renamed: OnItemTypeAddedEventOnItemAddedEvent, OnItemTypeRemovedEventOnItemRemovedEvent. The old names are preserved as [Obsolete] shims with explicit add/remove accessors that forward subscriptions to the new events, so existing +=/-= call sites keep compiling with a deprecation warning pointing to the new name. The shims will be removed in a future major version. OnChangedEvent is unchanged.
  • CollectionItemIndirectReference.itemLastKnownName and collectionLastKnownName are now wrapped in #if UNITY_EDITOR and no longer compiled into player builds. Runtime resolution relies exclusively on GUIDs.
  • CollectionItemQuery<T>.Matches(IEnumerable<T> targetItems, out int) now tolerates a null targetItems — treated as empty, so Any/All sets fail and NotAny/NotAll sets pass.

Fixed

  • CollectionItemQueryPropertyDrawer.IsCombinationImpossible no longer reports false positives for Any + NotAny and All + NotAll rule pairs. Impossibility for these now requires the stricter subset relationship between pickers (not just any intersection), matching the real-world satisfiability. All + NotAny continues to be flagged on any intersection, which is correct.
  • CollectionItemPicker and CollectionItemIndirectReference<T> now implement ISerializationCallbackReceiver to invalidate their runtime caches on deserialization, so inspector edits to a picker during Play Mode take effect immediately instead of returning the stale cached Items/Ref.
  • CollectionItemIndirectReferencePropertyDrawer now re-syncs stale itemLastKnownName/collectionLastKnownName from the live asset and collection names on every draw (via ApplyModifiedPropertiesWithoutUndo), preventing the cached names from drifting when an asset is renamed outside the inspector.

Removed

  • Removed the runtime fallback in CollectionItemIndirectReference.TryGetCollectionItem that, when the stored GUIDs failed to resolve, attempted to look the collection and item back up by collectionLastKnownName/itemLastKnownName. With the names now editor-only, GUID is the single runtime lookup path; rename recovery is handled at edit time by the drawer instead.
  • Removed long-deprecated [Obsolete] API surface that has been carrying compile warnings across prior releases:
    • SOCSettings.SetDefaultNamespace(string) — use SetNamespacePrefix(string) instead.
    • The four ScriptableObjectCollectionUtility.CreateScriptableObjectOfType(...) overloads that took a parentFolder / parentFolderPath plus a createFolderForThisCollection bool. Use the overloads that take a complete path; build the path with Path.Combine at the call site if you previously relied on the auto-folder behavior.
    • DrawAsSOCItemAttribute — no longer needed since Unity 2022.2 supports PropertyDrawer on interfaces directly.
    • CollectionItemEditorOptions class — use SOCItemEditorOptionsAttribute instead.
    • CollectionsRegistry.GetCollectionByGUID(string) — use the LongGuid overload (regenerate your collection's static access class to pick up the new GUID type).
    • ScriptableObjectCollection.GetItemByGUID(string) — use the LongGuid overload (same: regenerate the static access class).