Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions Assets/Tests/InputSystem.Editor/CustomProcessorEnumTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -1027,43 +1027,37 @@ internal void MigrateJson(ref ReadFileJson parsedJson)
continue;

var list = NameAndParameters.ParseMultiple(raw).ToList();
var rebuilt = new List<string>(list.Count);
var converted = new List<NameAndParameters>(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<NamedValue>(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<object>().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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,7 @@ private void OnParametersChanged(ParameterListView listView, int index)

private static string ToSerializableString(IEnumerable<NameAndParameters> 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@
return $"{name}({parameterString})";
}

internal static string SerializeMultiple(IEnumerable<NameAndParameters> list)
{
if(list == null)
return string.Empty;

Check warning on line 33 in Packages/com.unity.inputsystem/InputSystem/Utilities/NameAndParameters.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

Packages/com.unity.inputsystem/InputSystem/Utilities/NameAndParameters.cs#L33

Added line #L33 was not covered by tests

return string.Join(NamedValue.Separator, list.Select(x => x.ToString()).ToArray());
}

internal static NameAndParameters Create(string name, IList<NamedValue> parameters)
{
var result = new NameAndParameters
{
name = name,
parameters = new ReadOnlyArray<NamedValue>(parameters.ToArray())
};
return result;
}

public static IEnumerable<NameAndParameters> ParseMultiple(string text)
{
List<NameAndParameters> list = null;
Expand Down