Skip to content

3.4.0

Choose a tag to compare

@github-actions github-actions released this 05 Jul 02:29
· 146 commits to main since this release
e6143da

See the roadmap for details

Added

  • AssetDatabaseBatchHelper.EnsureAssetFolder / EnsureAssetParentFolder: batch-safe helpers that register every missing folder segment with the AssetDatabase (never via raw disk, which can leave the database out of sync and spawn numbered duplicate folders) and pause any open StartAssetEditing batch first, so a subsequent AssetDatabase.CreateAsset cannot fail with "Parent directory must exist".

Changed

  • [WValueDropDown] provider-misconfiguration is now logged as a Warning, not an Error: a null/empty/missing/throwing or wrong-return-type dropdown value provider is a handled condition — the dropdown falls back to an empty option list — so WValueDropDownAttribute / DropDownValueProvider now log these diagnostics at Warning severity instead of Error. The message text is unchanged. This better reflects that the feature degrades gracefully, and (as a side effect) stops these editor-tooling diagnostics from failing PlayMode tests that incidentally exercise the dropdown path.
  • DirectoryHelper.EnsureDirectoryExists no longer logs an error before throwing: passing a path outside Assets/ in the editor previously emitted a Debug.LogError and threw an ArgumentException (a redundant double signal that polluted the console and could fail unrelated tests that did not expect the log). It now throws the ArgumentException only, and the exception message names the offending path (for example, Cannot create directory 'SomeFolder/SubFolder' outside the Assets folder: AssetDatabase only manages paths under 'Assets/'.). Callers that already catch the exception are unaffected; callers that relied on the console log should read the thrown exception instead.

Fixed

  • Unity 6000.3 compatibility for runtime helpers: Object.GetUnityObjectId, UnityObjectExtensions.FindObjectsOfTypeShim, SceneHelper.EnsureOneComponent, and the Rigidbody2D velocity helpers now gate Unity 6 APIs by the specific version that introduced them instead of treating every Unity 6000.x editor as equivalent. Unity 6000.3 and earlier supported matrix versions compile through the older overloads while Unity 6000.4+ continues to use the newer no-sort object lookup and EntityId.ToULong paths.
  • EffectHandler periodic catch-up after a long frame: missed periodic ticks now advance on their scheduled interval instead of sliding from the current frame, and unlimited periodic effects are capped per update so a large frame hitch cannot monopolize the player loop. Remaining due ticks continue catching up on subsequent updates.
  • Protobuf abstract-root deserialization reporting corrupt data instead of a registration error: abstract [ProtoContract] roots without [ProtoInclude] metadata now require an explicit RegisterProtobufRoot mapping before deserialize, so ambiguous abstract roots fail with the documented type-resolution exception instead of falling through to protobuf-net's version-specific corrupt-data / constructor errors. Explicit registrations also take precedence over abstract root heuristics.
  • Background logging using a stale Unity main-thread capture: WallstopStudiosLogger now shares UnityMainThreadGuard's captured main-thread state, preventing background log calls from being misclassified after test/player lifecycle resets.
  • Protobuf serialization of an EMPTY SerializableHashSet / SerializableSortedSet / SerializableDictionary / SerializableSortedDictionary throwing SerializationInputException ("data is empty") on deserialize: an empty collection serializes to a zero-byte payload (the wrapper carries only repeated fields), but ProtoDeserialize ran its generic empty-payload guard before the collection-wrapper interception, so a valid empty collection could not round-trip. The collection interception now runs first, so an empty collection round-trips to an empty collection; the empty-payload guard still rejects empty input for ordinary (non-collection) message types. Wire format for non-empty payloads is unchanged.
  • Serialization crashing or silently corrupting data on IL2CPP/AOT standalone players: Serializer now serializes the affected types through AOT-safe paths instead of protobuf-net's reflection / Reflection.Emit model, which under IL2CPP hit the unsupported GetTypeModifiers icall or bound immutable structs to empty values. Deque<T>, CyclicBuffer<T>, and SparseSet route through plain array/scalar protobuf wrappers (also fixing a spurious [ProtoAfterDeserialization] ArgumentOutOfRangeException); FastVector2Int, FastVector3Int, ImmutableBitSet, and Parabola route through mutable protobuf surrogates. Serializer.JsonStringify / JsonSerialize of anonymous types (and other types lacking a public parameterless constructor) now use a reflection-light writer instead of System.Text.Json's parameterized-constructor converter, which has no AOT code under IL2CPP. A package link.xml preserves the serialization assemblies. JSON output and protobuf round-trip values are unchanged on mono / editor. The package pre-registers the common element specializations (int, long, float, double, bool, string, Vector2, Vector3, Vector2Int, Vector3Int, FastVector2Int, FastVector3Int); consumers that store a custom value-type element in a Deque<T> or CyclicBuffer<T> must register that T for AOT themselves (reference-type elements share a single generic specialization and need no registration).
  • Relational component attributes ([SiblingComponent] / [ChildComponent] / [ParentComponent]) crashing or resolving the wrong components on IL2CPP/AOT players: the collection fast-path built a runtime generic accessor via Expression.Compile(), which IL2CPP cannot service (it threw at runtime). It now uses the AOT-safe non-generic GetComponents / GetComponentsInChildren / GetComponentsInParent(Type, …) overloads. Include-inactive filtering also wrongly treated every component as enabled on IL2CPP (a reflection delegate path that silently failed), so disabled components were not filtered out; the enabled state is now read AOT-safely. Behavior on mono / editor is unchanged.
  • [WNotNull] validation (this.CheckForNulls()) silently doing nothing in player builds: the null check was compiled only into the editor, so it never threw ArgumentNullException for a null [WNotNull] field in a built player. It now runs in every build (AOT-safe) exactly as the API documents, so missing required references fail fast at runtime instead of being silently ignored.
  • [ValidateAssignment] validation (this.ValidateAssignments()) silently doing nothing in player builds: like CheckForNulls, the warning pass was compiled only into the editor (while the sibling AreAnyAssignmentsInvalid already ran everywhere), so unassigned fields were never reported in a built player. It now runs in every build (AOT-safe), consistent with AreAnyAssignmentsInvalid.
  • ScriptableObjectSingleton assets not regenerating on Unity 6 after the asset file was deleted: when a singleton's .asset was removed but its .meta remained, Unity 6000.3+ retains the path-to-GUID mapping, which ScriptableObjectSingletonCreator treated as "path already occupied" and skipped recreation. Creation decisions now key on the asset body file, so the singleton is recreated on every Unity version.
  • AssetDatabase.CreateAsset failing with "Parent directory must exist" / "Creating asset at path … failed": editor utilities that create assets — ScriptableObjectSingletonCreator, ScriptableObjectSingletonMetadataUtility, AttributeMetadataCacheGenerator, PersistentDirectorySettings, and the sprite/atlas/animation creator windows — now ensure the parent folder is registered with the AssetDatabase before creating the asset, including while an AssetDatabase batch is open (common under -batchmode). Previously, creating an asset in a not-yet-registered folder could fail or be skipped.
  • Unity 6 deprecation warnings from Object.FindObjectsOfType / FindObjectOfType: runtime DI-integration code (Reflex / VContainer / Zenject) now routes object lookups through a version-gated shim that uses FindObjectsByType / FindFirstObjectByType on Unity 2022.2+ (including Unity 6) and the legacy API below it, eliminating the deprecation warnings while preserving behavior.
  • MonoBehaviour.ExecuteFunctionAfterFrame callback never firing in headless/batch mode: the helper yielded WaitForEndOfFrame, which never resumes under -batchmode -nographics (no end-of-frame render signal), so the queued callback was silently dropped on headless players, dedicated servers, and CI. It now advances a single frame in batch mode (the headless-safe equivalent) and continues to use WaitForEndOfFrame in interactive/graphical sessions, so the callback runs in every environment.

Install

  • Import the attached .unitypackage into a Unity project, or
  • install com.wallstop-studios.unity-helpers@3.4.0 from npm / OpenUPM through Unity Package Manager.

The release includes the npm tarball and the .unitypackage, each with a .sha256 checksum.