Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a260324
Update the parser for migration
AswinRajGopal Sep 25, 2025
00b37a5
Added a test to cover the package migration.
AswinRajGopal Oct 2, 2025
d637adf
Revert "Added a test to cover the package migration."
AswinRajGopal Oct 3, 2025
4e76813
Revert "Update the parser for migration"
AswinRajGopal Oct 3, 2025
a8ba533
The the processors are split by , instead of ; it was typo
AswinRajGopal Oct 3, 2025
ff05b1d
Robust handling of migration logic
AswinRajGopal Oct 6, 2025
829c4aa
Added test to cover the migration
AswinRajGopal Oct 6, 2025
9467adf
Update test
AswinRajGopal Oct 7, 2025
3e490f1
Address PR feeback.
AswinRajGopal Oct 7, 2025
a31d971
Address PR comments.
AswinRajGopal Oct 7, 2025
817ff0e
Update the test to include more than one processors in actionmap.
AswinRajGopal Oct 7, 2025
2914bf7
Removed redundant call
AswinRajGopal Oct 7, 2025
6daabc9
Revert changes and moved the function changes to NameAndParameters as…
AswinRajGopal Oct 8, 2025
6aca9db
Bring back the test which verifies the migration along with processed…
AswinRajGopal Oct 10, 2025
f3f7ea5
Update the test as per review comments.
AswinRajGopal Oct 16, 2025
f5b06da
Simply the code removing redundancy - as these checks are handled in …
AswinRajGopal Oct 16, 2025
6b4c75a
Add check incase if raw string is null.
AswinRajGopal Oct 16, 2025
64076cb
Reformatting files.
AswinRajGopal Oct 16, 2025
f042f1e
Merge branch 'develop' into isxb-1678/fix-customprocessor-serialise-r…
ekcoh Oct 21, 2025
14dfb97
Merge branch 'develop' into isxb-1678/fix-customprocessor-serialise-r…
LeoUnity Oct 24, 2025
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
26 changes: 26 additions & 0 deletions Assets/Tests/InputSystem.Editor/CustomProcessorEnumTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,5 +108,31 @@

yield return null;
}

[UnityTest]
public IEnumerator Migration_FromLegacyJson_ShouldConvertOrdinal_KeepInvertVector2_AndSeparators()
{
var legacyJson = m_Asset.ToJson().Replace("\"version\": 1", "\"version\": 0").Replace("Custom(SomeEnum=10)", "Custom(SomeEnum=1)");

// Add a trailing processor to verify the semicolon separator is preserved.
if (!legacyJson.Contains(";InvertVector2(invertX=true)"))
legacyJson = legacyJson.Replace("Custom(SomeEnum=1)\"", "Custom(SomeEnum=1);InvertVector2(invertX=true)\"");

var migratedAsset = InputActionAsset.FromJson(legacyJson);
Assume.That(migratedAsset, Is.Not.Null, "Failed to load legacy JSON into an InputActionAsset.");

var migratedJson = migratedAsset.ToJson();
Assume.That(migratedJson, Is.Not.Null.And.Not.Empty, "Migrated JSON was empty.");

Assert.Less(migratedJson.IndexOf("InvertVector2(invertX=true)", StringComparison.Ordinal), migratedJson.IndexOf(",Custom(SomeEnum=20)", StringComparison.Ordinal),
"Expected a comma between the first and second processors, with InvertVector2 first."
);

Assert.Greater(migratedJson.IndexOf(";InvertVector2(invertX=true)", StringComparison.Ordinal), migratedJson.IndexOf("Custom(SomeEnum=20)", StringComparison.Ordinal),

Check warning on line 131 in Assets/Tests/InputSystem.Editor/CustomProcessorEnumTest.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

Assets/Tests/InputSystem.Editor/CustomProcessorEnumTest.cs#L131

Added line #L131 was not covered by tests
"Expected a semicolon between the second and third processors, with the trailing InvertVector2 last."
);

yield return null;
}

Check warning on line 136 in Assets/Tests/InputSystem.Editor/CustomProcessorEnumTest.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

Assets/Tests/InputSystem.Editor/CustomProcessorEnumTest.cs#L135-L136

Added lines #L135 - L136 were not covered by tests
}
#endif
129 changes: 97 additions & 32 deletions Packages/com.unity.inputsystem/InputSystem/Actions/InputActionAsset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine.InputSystem.Editor;
using System.Globalization;
using UnityEngine.InputSystem.Utilities;

////TODO: make the FindAction logic available on any IEnumerable<InputAction> and IInputActionCollection via extension methods
Expand Down Expand Up @@ -1014,60 +1014,125 @@
{
if (parsedJson.version >= JsonVersion.Version1)
return;
if ((parsedJson.maps?.Length ?? 0) > 0 && (parsedJson.version) < JsonVersion.Version1)

if (parsedJson.maps == null || parsedJson.maps.Length == 0)
{
parsedJson.version = JsonVersion.Version1;
return;
}

for (var mi = 0; mi < parsedJson.maps.Length; ++mi)
{
for (var mi = 0; mi < parsedJson.maps.Length; ++mi)
var mapJson = parsedJson.maps[mi];
if (mapJson.actions == null || mapJson.actions.Length == 0)
continue;

Check warning on line 1028 in Packages/com.unity.inputsystem/InputSystem/Actions/InputActionAsset.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

Packages/com.unity.inputsystem/InputSystem/Actions/InputActionAsset.cs#L1028

Added line #L1028 was not covered by tests

for (var ai = 0; ai < mapJson.actions.Length; ++ai)
{
var mapJson = parsedJson.maps[mi];
for (var ai = 0; ai < mapJson.actions.Length; ++ai)
var actionJson = mapJson.actions[ai];
var raw = actionJson.processors;
if (string.IsNullOrEmpty(raw))
continue;

var parts = System.Text.RegularExpressions.Regex.Split(raw, @"\s*([,;])\s*");
if (parts.Length == 0)
continue;

Check warning on line 1039 in Packages/com.unity.inputsystem/InputSystem/Actions/InputActionAsset.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

Packages/com.unity.inputsystem/InputSystem/Actions/InputActionAsset.cs#L1039

Added line #L1039 was not covered by tests

var tokens = new List<string>();
for (int i = 0; i < parts.Length; i += 2)
if (!string.IsNullOrEmpty(parts[i]))
tokens.Add(parts[i]);

if (tokens.Count == 0)
continue;

Check warning on line 1047 in Packages/com.unity.inputsystem/InputSystem/Actions/InputActionAsset.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

Packages/com.unity.inputsystem/InputSystem/Actions/InputActionAsset.cs#L1047

Added line #L1047 was not covered by tests

var parsed = new List<NameAndParameters>(tokens.Count);
foreach (var t in tokens)
parsed.Add(NameAndParameters.Parse(t));

var rebuiltTokens = new List<string>(tokens.Count);
var anyProcessorChanged = false;

for (int pi = 0; pi < parsed.Count; pi++)
{
var actionJson = mapJson.actions[ai];
var raw = actionJson.processors;
if (string.IsNullOrEmpty(raw))
var nap = parsed[pi];

var procType = InputSystem.TryGetProcessor(nap.name);
if (procType == null || nap.parameters.Count == 0)
{
rebuiltTokens.Add(tokens[pi]);

Check warning on line 1063 in Packages/com.unity.inputsystem/InputSystem/Actions/InputActionAsset.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

Packages/com.unity.inputsystem/InputSystem/Actions/InputActionAsset.cs#L1062-L1063

Added lines #L1062 - L1063 were not covered by tests
continue;
}

var dict = new Dictionary<string, string>(nap.parameters.Count, System.StringComparer.OrdinalIgnoreCase);
foreach (var p in nap.parameters)
dict[p.name] = p.value.ToString();

var changedThisProcessor = false;

var list = NameAndParameters.ParseMultiple(raw).ToList();
var rebuilt = new List<string>(list.Count);
foreach (var nap in list)
foreach (var field in procType.GetFields(BindingFlags.Public | BindingFlags.Instance))
{
var procType = InputSystem.TryGetProcessor(nap.name);
if (nap.parameters.Count == 0 || procType == null)
{
rebuilt.Add(nap.ToString());
if (!field.FieldType.IsEnum)
continue;

if (!dict.TryGetValue(field.Name, out var rawVal))
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))
if (int.TryParse(rawVal, NumberStyles.Integer, CultureInfo.InvariantCulture, out var n))
{
if (dict.TryGetValue(field.Name, out var ordS) && int.TryParse(ordS, out var ord))
var values = System.Enum.GetValues(field.FieldType);
var looksLikeOrdinal = n >= 0 && n < values.Length && !System.Enum.IsDefined(field.FieldType, n);
if (looksLikeOrdinal)
{
var values = Enum.GetValues(field.FieldType).Cast<object>().ToArray();
if (ord >= 0 && ord < values.Length)
var underlying = Convert.ToInt32(values.GetValue(n));
if (underlying != n)
{
dict[field.Name] = Convert.ToInt32(values[ord]).ToString();
anyChanged = true;
dict[field.Name] = underlying.ToString(CultureInfo.InvariantCulture);
changedThisProcessor = true;
}
}
}
}

if (!changedThisProcessor)
{
rebuiltTokens.Add(tokens[pi]);
}
else
{
var ordered = nap.parameters.Select(p =>
{
var v = dict.TryGetValue(p.name, out var nv) ? nv : p.value.ToString();
return $"{p.name}={v}";
});

var migrated = $"{nap.name}({string.Join(",", ordered)})";
rebuiltTokens.Add(migrated);
anyProcessorChanged = true;
}
}

if (!anyChanged)
if (anyProcessorChanged)
{
var sb = new System.Text.StringBuilder(raw.Length + 16);
int tokenIndex = 0;
for (int partIndex = 0; partIndex < parts.Length; ++partIndex)
{
if ((partIndex % 2) == 0)
{
rebuilt.Add(nap.ToString());
if (tokenIndex < rebuiltTokens.Count)
sb.Append(rebuiltTokens[tokenIndex++]);
}
else
{
var paramText = string.Join(",", dict.Select(kv => $"{kv.Key}={kv.Value}"));
rebuilt.Add($"{nap.name}({paramText})");
sb.Append(parts[partIndex]);
}
}

actionJson.processors = string.Join(";", rebuilt);
mapJson.actions[ai] = actionJson;
actionJson.processors = sb.ToString();
}
parsedJson.maps[mi] = mapJson;
mapJson.actions[ai] = actionJson;
}
parsedJson.maps[mi] = mapJson;
}
// Bump the version so we never re-migrate
parsedJson.version = JsonVersion.Version1;
Expand Down