From 89a370cfd9c3fb6486fcb6c5545f805dc8388aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Malrat?= Date: Wed, 23 Oct 2024 16:05:45 -0400 Subject: [PATCH 1/2] Revert "CHANGE: Performance improvement - removed project-wide asset migration code (#2025)" This reverts commit ba9677b6fb48a3a111ffb4400dfd3f4c5cd99c81. --- .../ProjectWideActionsAsset.cs | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/ProjectWideActions/ProjectWideActionsAsset.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/ProjectWideActions/ProjectWideActionsAsset.cs index 027faf6e5f..784b52506d 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/ProjectWideActions/ProjectWideActionsAsset.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/ProjectWideActions/ProjectWideActionsAsset.cs @@ -17,14 +17,25 @@ internal static class ProjectWideActionsAsset internal static class ProjectSettingsProjectWideActionsAssetConverter { + private const string kAssetPathInputManager = "ProjectSettings/InputManager.asset"; + private const string kAssetNameProjectWideInputActions = "ProjectWideInputActions"; + class ProjectSettingsPostprocessor : AssetPostprocessor { + private static bool migratedInputActionAssets = false; + #if UNITY_2021_2_OR_NEWER private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths, bool didDomainReload) #else private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) #endif { + if (!migratedInputActionAssets) + { + MoveInputManagerAssetActionsToProjectWideInputActionAsset(); + migratedInputActionAssets = true; + } + if (!Application.isPlaying) { // If the Library folder is deleted, InputSystem will fail to retrieve the assigned Project-wide Asset because this look-up occurs @@ -35,6 +46,69 @@ private static void OnPostprocessAllAssets(string[] importedAssets, string[] del } } } + + private static void MoveInputManagerAssetActionsToProjectWideInputActionAsset() + { + var objects = AssetDatabase.LoadAllAssetsAtPath(EditorHelpers.GetPhysicalPath(kAssetPathInputManager)); + if (objects == null) + return; + + var inputActionsAsset = objects.FirstOrDefault(o => o != null && o.name == kAssetNameProjectWideInputActions) as InputActionAsset; + if (inputActionsAsset != default) + { + // Found some actions in the InputManager.asset file + // + string path = ProjectWideActionsAsset.kDefaultAssetPath; + + if (File.Exists(EditorHelpers.GetPhysicalPath(path))) + { + // We already have a path containing inputactions, find a new unique filename + // + // eg Assets/InputSystem_Actions.inputactions -> + // Assets/InputSystem_Actions (1).inputactions -> + // Assets/InputSystem_Actions (2).inputactions ... + // + string[] files = Directory.GetFiles("Assets", "*.inputactions"); + List names = new List(); + for (int i = 0; i < files.Length; i++) + { + names.Add(System.IO.Path.GetFileNameWithoutExtension(files[i])); + } + string unique = ObjectNames.GetUniqueName(names.ToArray(), kDefaultAssetName); + path = "Assets/" + unique + ".inputactions"; + } + + var json = inputActionsAsset.ToJson(); + InputActionAssetManager.SaveAsset(EditorHelpers.GetPhysicalPath(path), json); + + Debug.Log($"Migrated Project-wide Input Actions from '{kAssetPathInputManager}' to '{path}' asset"); + + // Update current project-wide settings if needed (don't replace if already set to something else) + // + if (InputSystem.actions == null || InputSystem.actions.name == kAssetNameProjectWideInputActions) + { + InputSystem.actions = (InputActionAsset)AssetDatabase.LoadAssetAtPath(path, typeof(InputActionAsset)); + Debug.Log($"Loaded Project-wide Input Actions from '{path}' asset"); + } + } + + // Handle deleting all InputActionAssets as older 1.8.0 pre release could create more than one project wide input asset in the file + foreach (var obj in objects) + { + if (obj is InputActionReference) + { + var actionReference = obj as InputActionReference; + AssetDatabase.RemoveObjectFromAsset(obj); + Object.DestroyImmediate(actionReference); + } + else if (obj is InputActionAsset) + { + AssetDatabase.RemoveObjectFromAsset(obj); + } + } + + AssetDatabase.SaveAssets(); + } } // Returns the default asset path for where to create project-wide actions asset. From 60569721c21f1cdf1d667c2182bf143aaab6f290 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Malrat?= Date: Wed, 23 Oct 2024 16:07:51 -0400 Subject: [PATCH 2/2] Fixed ArgumentNullException during the migration of Project-wide Input Actions --- Packages/com.unity.inputsystem/CHANGELOG.md | 4 + .../ProjectWideActionsAsset.cs | 96 +++++++++++++------ 2 files changed, 69 insertions(+), 31 deletions(-) diff --git a/Packages/com.unity.inputsystem/CHANGELOG.md b/Packages/com.unity.inputsystem/CHANGELOG.md index 79e1ff562f..668a72a398 100644 --- a/Packages/com.unity.inputsystem/CHANGELOG.md +++ b/Packages/com.unity.inputsystem/CHANGELOG.md @@ -10,7 +10,11 @@ however, it has to be formatted properly to pass verification tests. ## [Unreleased] - yyyy-mm-dd +### Fixed +- Fixed `ArgumentNullException: Value cannot be null.` during the migration of Project-wide Input Actions from `InputManager.asset` to `InputSystem_Actions.inputactions` asset which lead do the lost of the configuration [ISXB-1105](https://issuetracker.unity3d.com/product/unity/issues/guid/ISXB-1105) +### Changed +- Added back the InputManager to InputSystem project-wide asset migration code with performance improvement (ISX-2086) ## [1.11.2] - 2024-10-16 diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/ProjectWideActions/ProjectWideActionsAsset.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/ProjectWideActions/ProjectWideActionsAsset.cs index 784b52506d..848af6320a 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/ProjectWideActions/ProjectWideActionsAsset.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/ProjectWideActions/ProjectWideActionsAsset.cs @@ -30,7 +30,7 @@ private static void OnPostprocessAllAssets(string[] importedAssets, string[] del private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) #endif { - if (!migratedInputActionAssets) + if (!migratedInputActionAssets && importedAssets.Contains(kAssetPathInputManager)) { MoveInputManagerAssetActionsToProjectWideInputActionAsset(); migratedInputActionAssets = true; @@ -47,51 +47,80 @@ private static void OnPostprocessAllAssets(string[] importedAssets, string[] del } } - private static void MoveInputManagerAssetActionsToProjectWideInputActionAsset() + private static void MoveInputManagerAssetActionsToProjectWideInputActionAsset(bool allowRetry = true) { var objects = AssetDatabase.LoadAllAssetsAtPath(EditorHelpers.GetPhysicalPath(kAssetPathInputManager)); if (objects == null) return; - var inputActionsAsset = objects.FirstOrDefault(o => o != null && o.name == kAssetNameProjectWideInputActions) as InputActionAsset; - if (inputActionsAsset != default) - { - // Found some actions in the InputManager.asset file - // - string path = ProjectWideActionsAsset.kDefaultAssetPath; + var inputActionsAssets = objects.Where(o => o != null && o.name == kAssetNameProjectWideInputActions && o is InputActionAsset); + + if (!inputActionsAssets.Any()) return; + + Debug.Log("Migrating Project-wide Input Actions from InputManager.asset to InputSystem_Actions.inputactions asset"); - if (File.Exists(EditorHelpers.GetPhysicalPath(path))) + // workarround for serialization bug with ScriptableObject in ProjectSettings during reimporting all asset, it should not be null + if (allowRetry) + { + foreach (InputActionAsset inputActionsAsset in inputActionsAssets) { - // We already have a path containing inputactions, find a new unique filename - // - // eg Assets/InputSystem_Actions.inputactions -> - // Assets/InputSystem_Actions (1).inputactions -> - // Assets/InputSystem_Actions (2).inputactions ... - // - string[] files = Directory.GetFiles("Assets", "*.inputactions"); - List names = new List(); - for (int i = 0; i < files.Length; i++) + if (inputActionsAsset.m_ActionMaps == null) { - names.Add(System.IO.Path.GetFileNameWithoutExtension(files[i])); + // unload asset to avoid serialization bug and will try again later + Resources.UnloadAsset(inputActionsAsset); + Debug.Log($"Unexpected null action map encounted during the migration, will try again once later"); + EditorApplication.delayCall += () => { MoveInputManagerAssetActionsToProjectWideInputActionAsset(allowRetry: false); }; + return; } - string unique = ObjectNames.GetUniqueName(names.ToArray(), kDefaultAssetName); - path = "Assets/" + unique + ".inputactions"; } + } + + foreach (InputActionAsset inputActionsAsset in inputActionsAssets) + { + if (inputActionsAsset != default) + { + // sanity check to avoid saving a badly serialized asset or empty asset + if (inputActionsAsset.m_ActionMaps.LengthSafe() == 0) + { + continue; + } + string path = ProjectWideActionsAsset.kDefaultAssetPath; + + if (File.Exists(EditorHelpers.GetPhysicalPath(path))) + { + // We already have a path containing inputactions, find a new unique filename + // + // eg Assets/InputSystem_Actions.inputactions -> + // Assets/InputSystem_Actions (1).inputactions -> + // Assets/InputSystem_Actions (2).inputactions ... + // + string[] files = Directory.GetFiles("Assets", "*.inputactions"); + List names = new List(); + for (int i = 0; i < files.Length; i++) + { + names.Add(System.IO.Path.GetFileNameWithoutExtension(files[i])); + } + string unique = ObjectNames.GetUniqueName(names.ToArray(), kDefaultAssetName); + path = "Assets/" + unique + ".inputactions"; + } - var json = inputActionsAsset.ToJson(); - InputActionAssetManager.SaveAsset(EditorHelpers.GetPhysicalPath(path), json); + var json = inputActionsAsset.ToJson(); + InputActionAssetManager.SaveAsset(EditorHelpers.GetPhysicalPath(path), json); - Debug.Log($"Migrated Project-wide Input Actions from '{kAssetPathInputManager}' to '{path}' asset"); + Debug.Log($"Migrated Project-wide Input Actions from '{kAssetPathInputManager}' to '{path}' asset"); - // Update current project-wide settings if needed (don't replace if already set to something else) - // - if (InputSystem.actions == null || InputSystem.actions.name == kAssetNameProjectWideInputActions) - { - InputSystem.actions = (InputActionAsset)AssetDatabase.LoadAssetAtPath(path, typeof(InputActionAsset)); - Debug.Log($"Loaded Project-wide Input Actions from '{path}' asset"); + // Update current project-wide settings if needed (don't replace if already set to something else) + // + if (InputSystem.actions == null || InputSystem.actions.name == kAssetNameProjectWideInputActions) + { + InputSystem.actions = (InputActionAsset)AssetDatabase.LoadAssetAtPath(path, typeof(InputActionAsset)); + Debug.Log($"Loaded Project-wide Input Actions from '{path}' asset"); + } } } + + bool hasChanged = false; // Handle deleting all InputActionAssets as older 1.8.0 pre release could create more than one project wide input asset in the file foreach (var obj in objects) { @@ -100,14 +129,19 @@ private static void MoveInputManagerAssetActionsToProjectWideInputActionAsset() var actionReference = obj as InputActionReference; AssetDatabase.RemoveObjectFromAsset(obj); Object.DestroyImmediate(actionReference); + hasChanged = true; } else if (obj is InputActionAsset) { AssetDatabase.RemoveObjectFromAsset(obj); + hasChanged = true; } } - AssetDatabase.SaveAssets(); + if (hasChanged == true) + { + AssetDatabase.SaveAssets(); + } } }