-
Notifications
You must be signed in to change notification settings - Fork 842
Hd/fix input registering domain reload #3373
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
Changes from all commits
44c264e
a2b602f
04a29ae
5cf0df1
87bd5a7
db232f3
0b2d0ac
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 |
---|---|---|
|
@@ -11,45 +11,36 @@ public enum Kind { KeyOrButton, Mouse, Axis } | |
public enum Axis { X, Y, Third, Fourth, Fifth, Sixth, Seventh, Eigth } | ||
public enum Joy { All, First, Second } | ||
|
||
public string name = ""; | ||
public string desc = ""; | ||
public string btnNegative = ""; | ||
public string btnPositive = ""; | ||
public string altBtnNegative = ""; | ||
public string altBtnPositive = ""; | ||
public float gravity = 0.0f; | ||
public float deadZone = 0.0f; | ||
public float sensitivity = 0.0f; | ||
public bool snap = false; | ||
public bool invert = false; | ||
public Kind kind = Kind.Axis; | ||
public Axis axis = Axis.X; | ||
public Joy joystick = Joy.All; | ||
public string name = ""; | ||
public string desc = ""; | ||
public string btnNegative = ""; | ||
public string btnPositive = ""; | ||
public string altBtnNegative = ""; | ||
public string altBtnPositive = ""; | ||
public float gravity = 0.0f; | ||
public float deadZone = 0.0f; | ||
public float sensitivity = 0.0f; | ||
public bool snap = false; | ||
public bool invert = false; | ||
public Kind kind = Kind.Axis; | ||
public Axis axis = Axis.X; | ||
public Joy joystick = Joy.All; | ||
|
||
internal bool IsEqual((string name, InputManagerEntry.Kind kind) partialEntry) | ||
=> this.name == partialEntry.name && this.kind == partialEntry.kind; | ||
|
||
internal bool IsEqual(InputManagerEntry other) | ||
=> this.name == other.name && this.kind == other.kind; | ||
} | ||
|
||
public class InputRegistering | ||
public static class InputRegistering | ||
{ | ||
static bool InputAlreadyRegistered(string name, InputManagerEntry.Kind kind, SerializedProperty spAxes) | ||
{ | ||
for (var i = 0; i < spAxes.arraySize; ++i) | ||
{ | ||
var spAxis = spAxes.GetArrayElementAtIndex(i); | ||
var axisName = spAxis.FindPropertyRelative("m_Name").stringValue; | ||
var kindValue = spAxis.FindPropertyRelative("type").intValue; | ||
if (axisName == name && (int)kind == kindValue) | ||
return true; | ||
} | ||
static List<InputManagerEntry> s_PendingInputsToRegister = new List<InputManagerEntry>(); | ||
|
||
return false; | ||
} | ||
static bool havePendingOperation => s_PendingInputsToRegister.Count > 0; | ||
|
||
static void WriteEntry(SerializedProperty spAxes, InputManagerEntry entry) | ||
static void CopyEntry(SerializedProperty spAxis, InputManagerEntry entry) | ||
{ | ||
if (InputAlreadyRegistered(entry.name, entry.kind, spAxes)) | ||
return; | ||
|
||
spAxes.InsertArrayElementAtIndex(spAxes.arraySize); | ||
var spAxis = spAxes.GetArrayElementAtIndex(spAxes.arraySize - 1); | ||
spAxis.FindPropertyRelative("m_Name").stringValue = entry.name; | ||
spAxis.FindPropertyRelative("descriptiveName").stringValue = entry.desc; | ||
spAxis.FindPropertyRelative("negativeButton").stringValue = entry.btnNegative; | ||
|
@@ -66,8 +57,75 @@ static void WriteEntry(SerializedProperty spAxes, InputManagerEntry entry) | |
spAxis.FindPropertyRelative("joyNum").intValue = (int)entry.joystick; | ||
} | ||
|
||
public static void RegisterInputs(List<InputManagerEntry> entries) | ||
static void AddEntriesWithoutCheck(SerializedProperty spAxes, List<InputManagerEntry> newEntries) | ||
{ | ||
int endOfCurrentInputList = spAxes.arraySize; | ||
spAxes.arraySize = endOfCurrentInputList + newEntries.Count; | ||
|
||
SerializedProperty spAxis = spAxes.GetArrayElementAtIndex(endOfCurrentInputList); | ||
for (int i = 0; i < newEntries.Count; ++i, spAxis.Next(false)) | ||
CopyEntry(spAxis, newEntries[i]); | ||
} | ||
|
||
// Get a representation of the already registered inputs | ||
static List<(string name, InputManagerEntry.Kind kind)> GetCachedInputs(SerializedProperty spAxes) | ||
{ | ||
int size = spAxes.arraySize; | ||
List<(string name, InputManagerEntry.Kind kind)> result = new List<(string name, InputManagerEntry.Kind kind)>(size); | ||
|
||
SerializedProperty spAxis = spAxes.GetArrayElementAtIndex(0); | ||
for (int i = 0; i < size; ++i, spAxis.Next(false)) | ||
result.Add((spAxis.FindPropertyRelative("m_Name").stringValue, (InputManagerEntry.Kind)spAxis.FindPropertyRelative("type").intValue)); | ||
return result; | ||
} | ||
|
||
static void MakeUniquePendingInputsToRegister() | ||
{ | ||
for (int pendingIndex = s_PendingInputsToRegister.Count - 1; pendingIndex > 0; --pendingIndex) | ||
{ | ||
InputManagerEntry pendingEntry = s_PendingInputsToRegister[pendingIndex]; | ||
int checkedIndex = pendingIndex - 1; | ||
for (; checkedIndex > -1 && !pendingEntry.IsEqual(s_PendingInputsToRegister[checkedIndex]); --checkedIndex) ; | ||
|
||
if (checkedIndex == -1) | ||
continue; | ||
|
||
// There is a duplicate entry in PendingInputesToRegister. | ||
// Debug.LogWarning($"Two entries with same name and kind are tryed to be added at same time. Only first occurence is kept. Name:{pendingEntry.name} Kind:{pendingEntry.kind}"); | ||
|
||
// Keep only first. | ||
// Counting decreasingly will have no impact on index before pendingIndex. So we can safely remove it. | ||
s_PendingInputsToRegister.RemoveAt(pendingIndex); | ||
} | ||
} | ||
|
||
static void RemovePendingInputsToAddThatAreAlreadyRegistered(List<(string name, InputManagerEntry.Kind kind)> cachedEntries, List<InputManagerEntry> newEntries) | ||
{ | ||
for (int newIndex = newEntries.Count - 1; newIndex >= 0; --newIndex) | ||
{ | ||
var newEntry = newEntries[newIndex]; | ||
int checkedIndex = cachedEntries.Count - 1; | ||
for (; checkedIndex > -1 && !newEntry.IsEqual(cachedEntries[checkedIndex]); --checkedIndex) ; | ||
|
||
if (checkedIndex == -1) | ||
continue; | ||
|
||
// There is a already a cached entry that correspond. | ||
// Debug.LogWarning($"Another entry with same name and kind already exist. Skiping this one. Name:{newEntry.name} Kind:{newEntry.kind}"); | ||
|
||
// Keep only first. | ||
// Counting decreasingly will have no impact on index before pendingIndex. So we can safely remove it. | ||
s_PendingInputsToRegister.RemoveAt(newIndex); | ||
} | ||
} | ||
|
||
static void DelayedRegisterInput() | ||
{ | ||
// Exit quickly if nothing more to register | ||
// (case when several different class try to register, only first call will do all) | ||
if (!havePendingOperation) | ||
return; | ||
|
||
// Grab reference to input manager | ||
var assets = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/InputManager.asset"); | ||
// Temporary fix. This happens some time with HDRP init when it's called before asset database is initialized (probably related to package load order). | ||
|
@@ -76,18 +134,39 @@ public static void RegisterInputs(List<InputManagerEntry> entries) | |
|
||
var inputManager = assets[0]; | ||
|
||
// Wrap in serialized object | ||
// Wrap in serialized object to access c++ fields | ||
var soInputManager = new SerializedObject(inputManager); | ||
var spAxes = soInputManager.FindProperty("m_Axes"); | ||
|
||
foreach (InputManagerEntry entry in entries) | ||
{ | ||
WriteEntry(spAxes, entry); | ||
} | ||
// At this point, we assume that entries in spAxes are already unique. | ||
|
||
// Ensure no double entry are tried to be registered (trim early) | ||
MakeUniquePendingInputsToRegister(); | ||
|
||
// Cache already existing entries to minimaly use serialization | ||
var cachedEntries = GetCachedInputs(spAxes); | ||
// And trim pending entries regarding already cached ones. | ||
RemovePendingInputsToAddThatAreAlreadyRegistered(cachedEntries, s_PendingInputsToRegister); | ||
|
||
// Add now unique entries | ||
AddEntriesWithoutCheck(spAxes, s_PendingInputsToRegister); | ||
|
||
// Commit | ||
soInputManager.ApplyModifiedProperties(); | ||
} | ||
|
||
public static void RegisterInputs(List<InputManagerEntry> entries) | ||
{ | ||
#if ENABLE_INPUT_SYSTEM && ENABLE_INPUT_SYSTEM_PACKAGE | ||
Debug.LogWarning("Trying to add entry in the legacy InputManager but using InputSystem package. Skiping."); | ||
return; | ||
#else | ||
s_PendingInputsToRegister.AddRange(entries); | ||
|
||
//delay the call in order to do only one pass event if several different class register inputs | ||
EditorApplication.delayCall += DelayedRegisterInput; | ||
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. does this mean we could end up calling this function multiple times in the same frame? 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. No it means you can call it multiple time in a frame, it will all be batched in delayed call.
Delayed calls:
So we inspected the already registered inputs only once instead of two time when done at same frame. And for unregistering, the mechanism where not here prior and was never requested. I assume it is not needed in this case. But it can be implemented in a similar way. I assume this was done to add inputs in the InputManager.asset only and not remove them. |
||
#endif | ||
} | ||
} | ||
#endif | ||
} |
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 line is replaced by
DelayedRegisterInput();
in the test to compare algorithm in same conditions.