From a8a55995727df8ed73804d7d21e3160c12fe0cdd Mon Sep 17 00:00:00 2001 From: Anthony Yakovlev Date: Mon, 15 Jun 2026 20:53:32 +0300 Subject: [PATCH] make a fix for the problem where devices will get lost during a package upgrade --- Packages/com.unity.inputsystem/CHANGELOG.md | 1 + .../Editor/InputSystemEditorInitializer.cs | 30 ++++++++++++++++ .../InputSystem/Editor/InputSystemObject.cs | 35 +++++++++++++++++++ .../Editor/InputSystemObject.cs.meta | 11 ++++++ 4 files changed, 77 insertions(+) create mode 100644 Packages/com.unity.inputsystem/InputSystem/Editor/InputSystemObject.cs create mode 100644 Packages/com.unity.inputsystem/InputSystem/Editor/InputSystemObject.cs.meta diff --git a/Packages/com.unity.inputsystem/CHANGELOG.md b/Packages/com.unity.inputsystem/CHANGELOG.md index 3453304eb6..73b3864462 100644 --- a/Packages/com.unity.inputsystem/CHANGELOG.md +++ b/Packages/com.unity.inputsystem/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed +- Fixed input devices being lost (no keyboard, mouse, gamepad, etc.) after upgrading the package while the Editor is open (related to the recent fast enter playmode change). [ISX-2569] - Fixed `InputSystemProvider` disabling project-wide actions on shutdown when UI Toolkit destroys its objects mid-play. The provider now scopes its lifecycle to the UI action map only and does not disable project-wide actions [UUM-134130](https://issuetracker.unity3d.com/product/unity/issues/guid/UUM-134130) - Fixed `InputActionRebindingExtensions.GetBindingDisplayString(InputAction, InputBinding, ...)` returning an empty string for composite bindings when the binding mask filters by group [UUM-141423](https://issuetracker.unity3d.com/product/unity/issues/guid/UUM-141423) - Fixed `InputEventPtr.handled` not preventing actions from triggering when switching devices. The default event handled policy has been changed from `SuppressStateUpdates` (now deprecated) to `SuppressActionEventNotifications`, which keeps device state synchronized while suppressing action callbacks for handled events. [ISXB-1097](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1097) diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/InputSystemEditorInitializer.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/InputSystemEditorInitializer.cs index cb444898b7..4500497457 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/InputSystemEditorInitializer.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/InputSystemEditorInitializer.cs @@ -162,6 +162,36 @@ internal static void InitializeInEditor(bool calledFromCtor, IInputRuntime runti } var existingStateManagers = Resources.FindObjectsOfTypeAll(); + + // Upgrade migration: package versions up to and including 1.18 stored this state in a + // ScriptableObject named InputSystemObject. That instance survives the domain reload + // triggered by a package upgrade, but the renamed InputSystemStateManager type won't match + // it. Adopt the surviving legacy instance's state into a new state manager so connected + // devices (and other state) are preserved across the upgrade instead of being lost - native + // only re-reports devices once per editor process, so there is no in-process recovery + // otherwise. See ISX-2569. + if (globalReset && (existingStateManagers == null || existingStateManagers.Length == 0)) + { + var legacyObjects = Resources.FindObjectsOfTypeAll(); + if (legacyObjects != null && legacyObjects.Length > 0) + { + var legacy = legacyObjects[0]; + var migrated = ScriptableObject.CreateInstance(); + migrated.hideFlags = HideFlags.HideAndDontSave; + migrated.systemState = legacy.systemState; + migrated.newInputBackendsCheckedAsEnabled = legacy.newInputBackendsCheckedAsEnabled; + migrated.settings = legacy.settings; + migrated.exitEditModeTime = legacy.exitEditModeTime; + migrated.enterPlayModeTime = legacy.enterPlayModeTime; + + // The legacy instances are no longer needed; get rid of them so we don't migrate twice. + for (var i = 0; i < legacyObjects.Length; ++i) + Object.DestroyImmediate(legacyObjects[i]); + + existingStateManagers = new[] { migrated }; + } + } + if (existingStateManagers != null && existingStateManagers.Length > 0) { if (globalReset) diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/InputSystemObject.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/InputSystemObject.cs new file mode 100644 index 0000000000..8b82ff84da --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/InputSystemObject.cs @@ -0,0 +1,35 @@ +#if UNITY_EDITOR +using UnityEngine; + +namespace UnityEngine.InputSystem +{ + /// + /// Legacy compatibility type. Package versions up to and including 1.18 stored the domain-reload + /// survival state in a hidden, ScriptableObject of this + /// exact type and name (this type was renamed to in 1.20). + /// + /// + /// When a project upgrades from such a version, that instance survives the domain reload triggered + /// by the upgrade - but only if its serialized script reference still resolves. That reference is + /// { fileID: 11500000, guid: <this file's guid> }, so this file MUST keep the original + /// InputSystemObject.cs GUID (5cdce2bffd1e49bda08b3db54a031207) and this MUST be the + /// primary class of the file (matching the file name). If the reference fails to resolve, Unity + /// drops the object during the reload and the input state - including the list of connected devices + /// - is lost on upgrade, with no in-process recovery (native only re-reports devices once per editor + /// process). See ISX-2569. + /// + /// The fields below must keep the same names and serialized layout as 1.18's InputSystemObject so the + /// surviving data deserializes into them. InputSystemEditorInitializer.InitializeInEditor + /// detects a surviving instance of this type, migrates its state into a + /// , and then destroys it. + /// + internal class InputSystemObject : ScriptableObject + { + [SerializeField] public InputSystemState systemState; + [SerializeField] public bool newInputBackendsCheckedAsEnabled; + [SerializeField] public string settings; + [SerializeField] public double exitEditModeTime; + [SerializeField] public double enterPlayModeTime; + } +} +#endif // UNITY_EDITOR diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/InputSystemObject.cs.meta b/Packages/com.unity.inputsystem/InputSystem/Editor/InputSystemObject.cs.meta new file mode 100644 index 0000000000..a52187a7d9 --- /dev/null +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/InputSystemObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5cdce2bffd1e49bda08b3db54a031207 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: