A game about forced loneliness, made by TACStudios
1using System.Collections.Generic;
2using System.Linq;
3
4namespace UnityEngine
5{
6#if UNITY_EDITOR
7 using UnityEditor;
8
9 public class InputManagerEntry
10 {
11 public enum Kind
12 {
13 KeyOrButton,
14 Mouse,
15 Axis
16 }
17
18 public enum Axis
19 {
20 X,
21 Y,
22 Third,
23 Fourth,
24 Fifth,
25 Sixth,
26 Seventh,
27 Eigth
28 }
29
30 public enum Joy
31 {
32 All,
33 First,
34 Second
35 }
36
37 public string name = "";
38 public string desc = "";
39 public string btnNegative = "";
40 public string btnPositive = "";
41 public string altBtnNegative = "";
42 public string altBtnPositive = "";
43 public float gravity = 0.0f;
44 public float deadZone = 0.0f;
45 public float sensitivity = 0.0f;
46 public bool snap = false;
47 public bool invert = false;
48 public Kind kind = Kind.Axis;
49 public Axis axis = Axis.X;
50 public Joy joystick = Joy.All;
51 }
52
53 public static class InputRegistering
54 {
55 static void CopyEntry(SerializedProperty spAxis, InputManagerEntry entry)
56 {
57 spAxis.FindPropertyRelative("m_Name").stringValue = entry.name;
58 spAxis.FindPropertyRelative("descriptiveName").stringValue = entry.desc;
59 spAxis.FindPropertyRelative("negativeButton").stringValue = entry.btnNegative;
60 spAxis.FindPropertyRelative("altNegativeButton").stringValue = entry.altBtnNegative;
61 spAxis.FindPropertyRelative("positiveButton").stringValue = entry.btnPositive;
62 spAxis.FindPropertyRelative("altPositiveButton").stringValue = entry.altBtnPositive;
63 spAxis.FindPropertyRelative("gravity").floatValue = entry.gravity;
64 spAxis.FindPropertyRelative("dead").floatValue = entry.deadZone;
65 spAxis.FindPropertyRelative("sensitivity").floatValue = entry.sensitivity;
66 spAxis.FindPropertyRelative("snap").boolValue = entry.snap;
67 spAxis.FindPropertyRelative("invert").boolValue = entry.invert;
68 spAxis.FindPropertyRelative("type").intValue = (int)entry.kind;
69 spAxis.FindPropertyRelative("axis").intValue = (int)entry.axis;
70 spAxis.FindPropertyRelative("joyNum").intValue = (int)entry.joystick;
71 }
72
73 static void AddEntriesWithoutCheck(SerializedProperty spAxes, List<InputManagerEntry> newEntries)
74 {
75 if (newEntries.Count == 0)
76 return;
77
78 int endOfCurrentInputList = spAxes.arraySize;
79 spAxes.arraySize = endOfCurrentInputList + newEntries.Count;
80 // Assignment to spAxes.arraySize resizes the spAxes array to at least 1 larger than it used to be, and
81 // therefore it is OK to use endOfCurrentInputList ("one-past-end of previous size") to get the array iterator.
82 SerializedProperty spAxis = spAxes.GetArrayElementAtIndex(endOfCurrentInputList);
83 for (int i = 0; i < newEntries.Count; ++i, spAxis.Next(false))
84 CopyEntry(spAxis, newEntries[i]);
85 }
86
87 // Get a representation of the already registered inputs
88 static List<(string name, InputManagerEntry.Kind kind)> GetCachedInputs(SerializedProperty spAxes)
89 {
90 int size = spAxes.arraySize;
91 List<(string name, InputManagerEntry.Kind kind)> result = new List<(string name, InputManagerEntry.Kind kind)>(size);
92
93 if (size == 0)
94 return result;
95
96 SerializedProperty spAxis = spAxes.GetArrayElementAtIndex(0);
97 for (int i = 0; i < size; ++i, spAxis.Next(false))
98 result.Add((spAxis.FindPropertyRelative("m_Name").stringValue, (InputManagerEntry.Kind)spAxis.FindPropertyRelative("type").intValue));
99 return result;
100 }
101
102 internal static List<InputManagerEntry> GetEntriesWithoutDuplicates(List<InputManagerEntry> entries)
103 {
104 return entries
105 .GroupBy(x => new { x.name, x.kind }) // Create groups { name, kind }
106 .Select(y => y.First()) // Select first entry from each group, ignoring duplicates
107 .ToList();
108 }
109
110 internal static List<InputManagerEntry> GetEntriesWithoutAlreadyRegistered(List<InputManagerEntry> entries, List<(string name, InputManagerEntry.Kind kind)> cachedEntries)
111 {
112 return entries
113 .Where(entry => !cachedEntries.Any(cachedEntry => cachedEntry.name == entry.name && cachedEntry.kind == entry.kind))
114 .ToList();
115 }
116
117 static SerializedObject GetInputManagerSO()
118 {
119 var assets = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/InputManager.asset");
120
121 // Potentially there are multiple objects inside the Asset, we need to make sure we only grab the correct one.
122 foreach (var obj in assets)
123 {
124 // Check the asset name is correct
125 if (obj != null && obj.name == "InputManager")
126 {
127 // There is an issue where multiple objects can be named InputManager for a
128 // period when they are added to the file, even if they are given unique names.
129 // In the editor we also check the type is InputManager to work around this, however
130 // that type is not available here. So instead we inspect the contents to confirm it's
131 // the object we expect.
132 var soInputManager = new SerializedObject(obj);
133 var spAxes = soInputManager.FindProperty("m_Axes");
134 if (spAxes != null)
135 return soInputManager;
136 }
137 }
138 return null;
139 }
140
141 public static void RegisterInputs(List<InputManagerEntry> entries)
142 {
143#if ENABLE_INPUT_SYSTEM && ENABLE_INPUT_SYSTEM_PACKAGE
144 Debug.LogWarning("Trying to add entry in the legacy InputManager but using InputSystem package. Skipping.");
145 return;
146#else
147 // Grab reference to input manager
148 var soInputManager = GetInputManagerSO();
149
150 // Temporary fix. This happens some time with HDRP init when it's called before asset database is initialized (probably related to package load order).
151 if (soInputManager == null)
152 return;
153
154 var spAxes = soInputManager.FindProperty("m_Axes");
155
156 // At this point, we assume that entries in spAxes are already unique.
157
158 // Ensure no double entry are tried to be registered (trim early)
159 var uniqueEntries = GetEntriesWithoutDuplicates(entries);
160
161 // Cache already existing entries to minimally use serialization
162 var cachedEntries = GetCachedInputs(spAxes);
163
164 // And trim pending entries regarding already cached ones.
165 var uniqueNewEntries = GetEntriesWithoutAlreadyRegistered(uniqueEntries, cachedEntries);
166
167 // Add now unique entries
168 AddEntriesWithoutCheck(spAxes, uniqueNewEntries);
169
170 // Commit
171 soInputManager.ApplyModifiedProperties();
172#endif
173 }
174 }
175#endif
176}