-
Notifications
You must be signed in to change notification settings - Fork 329
FIX: ISXB-1674 - Input actions asset not converted correctly when upgrading from 1.14.1 (Regression) #2244
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
FIX: ISXB-1674 - Input actions asset not converted correctly when upgrading from 1.14.1 (Regression) #2244
Changes from all commits
a260324
00b37a5
d637adf
4e76813
a8ba533
ff05b1d
829c4aa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still do not see why this isn't moved to outer scope and reused over iterations instead of being allocated on every iteration? Am I missing something? |
||
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; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,24 @@ | |
return $"{name}({parameterString})"; | ||
} | ||
|
||
internal static string SerializeMultiple(IEnumerable<NameAndParameters> list) | ||
{ | ||
if(list == null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this null check needed? It looks like this is never called with null? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure, it was copied from the file above
It was moved here just to make sure we can reuse the logic on those 2 places. But I have no idea if it can ever be null on the original place or not. |
||
return string.Empty; | ||
|
||
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; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is not verifying that the processor string can be parsed properly, which is what we want... we could still have a ";" separating them and those asserts would most likely pass.
@ekcoh do you know how we could get access to the parsed list of processors so we could assert on that instead? I could only find InputControl.processors or InputActionState.processors, but I don't know how to go from an InputActionAsset to InputControl or InputActionState
It seems InputAction.ResolveBindings end up calling InputBindingResolver.AddActionMap which then calls InstantiateWithParameters and that leads to the parsing and creation of processors, but I am not sure how we could call that from a test and then retrieve the list of processors to assert on that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, since the API design of Input Actions is based on string you can put whatever into Processors. So this test needs to complemented with code resolving the actions and the only way to actually prove the processors is correctly parsed and applied I believe would be to enable the actions and do ReadValue on the action after being resolved. To drive that action you also likely need a fake device to drive it with e.g. 1.0 and then see that e.g. scale processor multiples by 10 or similar.
In CoreTests_Actions.cs there are various examples on how to achieve this, e.g. search for tests containing ReadValue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would have been trivial if the string based API design was not a thing and instead actions had a list of actual processors on them.