diff --git a/Assets/Tests/InputSystem.Editor/CustomProcessorEnumTest.cs b/Assets/Tests/InputSystem.Editor/CustomProcessorEnumTest.cs index f2e9cb174a..8693c35d67 100644 --- a/Assets/Tests/InputSystem.Editor/CustomProcessorEnumTest.cs +++ b/Assets/Tests/InputSystem.Editor/CustomProcessorEnumTest.cs @@ -108,5 +108,58 @@ public IEnumerator ProcessorEnum_ShouldSerializeByValue_WhenSerializedToAsset() yield return null; } + + [Test] + public void Migration_ShouldProduceValidActionAsset_WithEnumProcessorConverted() + { + var legacyJson = @" + { + ""name"": ""InputSystem_Actions"", + ""maps"": [ + { + ""name"": ""Player"", + ""id"": ""df70fa95-8a34-4494-b137-73ab6b9c7d37"", + ""actions"": [ + { + ""name"": ""Move"", + ""type"": ""Value"", + ""id"": ""351f2ccd-1f9f-44bf-9bec-d62ac5c5f408"", + ""expectedControlType"": ""Vector2"", + ""processors"": ""StickDeadzone,InvertVector2(invertX=false),Custom(SomeEnum=1)"", + ""interactions"": """", + ""initialStateCheck"": true + } + ] + } + ], + ""controlSchemes"": [], + ""version"": 0 + }"; + + // Parse and migrate the legacy JSON + var asset = InputActionAsset.FromJson(legacyJson); + + // Object is valid after migration + Assert.That(asset, Is.Not.Null, "Migration failed to produce a valid InputActionAsset."); + + var map = asset.FindActionMap("Player"); + Assert.That(map, Is.Not.Null, "Expected Player map to exist."); + + var action = map.FindAction("Move"); + Assert.That(action, Is.Not.Null, "Expected Move action to exist."); + + var processors = action.processors; + + // Verify processor order and that enum was converted properly + Assert.That(processors, Does.Contain("StickDeadzone"), "StickDeadzone processor missing."); + Assert.That(processors, Does.Contain("InvertVector2(invertX=false)"), "InvertVector2 missing."); + Assert.That(processors, Does.Contain("Custom(SomeEnum=20)"), "Custom(SomeEnum=1) should migrate to SomeEnum=20 (OptionB)."); + + // Verify To JSON + var toJson = asset.ToJson(); + var reloaded = InputActionAsset.FromJson(toJson); + Assert.That(reloaded, Is.Not.Null, "Reloaded asset after migration is null."); + Assert.That(reloaded.FindAction("Player/Move"), Is.Not.Null, "Reloaded asset did not contain expected Move action."); + } } #endif diff --git a/Packages/com.unity.inputsystem/InputSystem/Actions/InputActionAsset.cs b/Packages/com.unity.inputsystem/InputSystem/Actions/InputActionAsset.cs index 3b9a70fcca..3f72cab7ec 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Actions/InputActionAsset.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Actions/InputActionAsset.cs @@ -1027,43 +1027,37 @@ internal void MigrateJson(ref ReadFileJson parsedJson) continue; var list = NameAndParameters.ParseMultiple(raw).ToList(); - var rebuilt = new List(list.Count); + var converted = new List(list.Count); foreach (var nap in list) { var procType = InputSystem.TryGetProcessor(nap.name); if (nap.parameters.Count == 0 || procType == null) { - rebuilt.Add(nap.ToString()); + converted.Add(nap); continue; } - var dict = nap.parameters.ToDictionary(p => p.name, p => p.value.ToString()); - var anyChanged = false; - foreach (var field in procType.GetFields(BindingFlags.Public | BindingFlags.Instance).Where(f => f.FieldType.IsEnum)) + var updatedParameters = new List(nap.parameters.Count); + foreach (var param in nap.parameters) { - if (dict.TryGetValue(field.Name, out var ordS) && int.TryParse(ordS, out var ord)) + var updatedPar = param; + var fieldInfo = procType.GetField(param.name, BindingFlags.Public | BindingFlags.Instance); + if(fieldInfo != null && fieldInfo.FieldType.IsEnum) { - var values = Enum.GetValues(field.FieldType).Cast().ToArray(); - if (ord >= 0 && ord < values.Length) + var index = param.value.ToInt32(); + var values = Enum.GetValues(fieldInfo.FieldType); + if(index >= 0 && index < values.Length) { - dict[field.Name] = Convert.ToInt32(values[ord]).ToString(); - anyChanged = true; + var convertedValue = Convert.ToInt32(values.GetValue(index)); + updatedPar = NamedValue.From(param.name, convertedValue); } } + updatedParameters.Add(updatedPar); } - - if (!anyChanged) - { - rebuilt.Add(nap.ToString()); - } - else - { - var paramText = string.Join(",", dict.Select(kv => $"{kv.Key}={kv.Value}")); - rebuilt.Add($"{nap.name}({paramText})"); - } + converted.Add(NameAndParameters.Create(nap.name, updatedParameters)); } - actionJson.processors = string.Join(";", rebuilt); + actionJson.processors = NameAndParameters.SerializeMultiple(converted); mapJson.actions[ai] = actionJson; } parsedJson.maps[mi] = mapJson; diff --git a/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/Views/NameAndParametersListView.cs b/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/Views/NameAndParametersListView.cs index fd51f4d26e..a08feca97c 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/Views/NameAndParametersListView.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Editor/UITKAssetEditor/Views/NameAndParametersListView.cs @@ -83,11 +83,7 @@ private void OnParametersChanged(ParameterListView listView, int index) private static string ToSerializableString(IEnumerable parametersForEachListItem) { - if (parametersForEachListItem == null) - return string.Empty; - - return string.Join(NamedValue.Separator, - parametersForEachListItem.Select(x => x.ToString()).ToArray()); + return NameAndParameters.SerializeMultiple(parametersForEachListItem); } public override void RedrawUI(InputActionsEditorState state) diff --git a/Packages/com.unity.inputsystem/InputSystem/Utilities/NameAndParameters.cs b/Packages/com.unity.inputsystem/InputSystem/Utilities/NameAndParameters.cs index 15ceed089c..239bf59932 100644 --- a/Packages/com.unity.inputsystem/InputSystem/Utilities/NameAndParameters.cs +++ b/Packages/com.unity.inputsystem/InputSystem/Utilities/NameAndParameters.cs @@ -27,6 +27,24 @@ public override string ToString() return $"{name}({parameterString})"; } + internal static string SerializeMultiple(IEnumerable list) + { + if(list == null) + return string.Empty; + + return string.Join(NamedValue.Separator, list.Select(x => x.ToString()).ToArray()); + } + + internal static NameAndParameters Create(string name, IList parameters) + { + var result = new NameAndParameters + { + name = name, + parameters = new ReadOnlyArray(parameters.ToArray()) + }; + return result; + } + public static IEnumerable ParseMultiple(string text) { List list = null;