1212using UnityEngine . InputSystem . Users ;
1313using UnityEngine . InputSystem . Processors ;
1414using UnityEngine . InputSystem . XInput ;
15+ using UnityEngine . Profiling ;
16+ using UnityEngine . TestTools . Constraints ;
1517using Object = UnityEngine . Object ;
1618using Gyroscope = UnityEngine . InputSystem . Gyroscope ;
19+ using Is = UnityEngine . TestTools . Constraints . Is ;
1720
1821/// <summary>
1922/// Tests for <see cref="PlayerInput"/> and <see cref="PlayerInputManager"/>.
@@ -826,6 +829,25 @@ public void PlayerInput_ByDefaultChoosesMostSpecificControlSchemeAvailable()
826829 Assert . That ( playerInput . currentControlScheme , Is . EqualTo ( "PS4Gamepad" ) ) ;
827830 }
828831
832+ // https://fogbugz.unity3d.com/f/cases/1214519/
833+ [ Test ]
834+ [ Category ( "PlayerInput" ) ]
835+ public void PlayerInput_CanHaveSpacesAndSpecialCharactersInActionNames ( )
836+ {
837+ InputSystem . AddDevice < Gamepad > ( ) ;
838+
839+ var go = new GameObject ( ) ;
840+ var playerInput = go . AddComponent < PlayerInput > ( ) ;
841+ playerInput . defaultActionMap = "gameplay" ;
842+ playerInput . notificationBehavior = PlayerNotifications . SendMessages ;
843+ playerInput . actions = InputActionAsset . FromJson ( kActions ) ;
844+ var listener = go . AddComponent < MessageListener > ( ) ;
845+
846+ Press ( ( ButtonControl ) playerInput . actions [ "Action With Spaces!!" ] . controls [ 0 ] ) ;
847+
848+ Assert . That ( listener . messages , Has . Exactly ( 1 ) . With . Property ( "name" ) . EqualTo ( "OnActionWithSpaces" ) ) ;
849+ }
850+
829851 // Test setup where two players both use the keyboard but with two different control
830852 // schemes.
831853 [ Test ]
@@ -1133,6 +1155,42 @@ public void PlayerInput_CanReceiveMessageWhenValueActionIsCanceled()
11331155 } ) ) ;
11341156 }
11351157
1158+ [ Test ]
1159+ [ Category ( "PlayerInput" ) ]
1160+ [ TestCase ( PlayerNotifications . SendMessages , typeof ( MessageListener ) ) ]
1161+ [ TestCase ( PlayerNotifications . BroadcastMessages , typeof ( MessageListener ) ) ]
1162+ [ TestCase ( PlayerNotifications . InvokeUnityEvents , typeof ( PlayerInputEventListener ) ) ]
1163+ [ TestCase ( PlayerNotifications . InvokeCSharpEvents , typeof ( PlayerInputCSharpEventListener ) ) ]
1164+ [ Retry ( 2 ) ] // Warm up JIT.
1165+ public void PlayerInput_TriggeringAction_DoesNotAllocateGCMemory ( PlayerNotifications notificationBehavior , Type listenerType )
1166+ {
1167+ var gamepad = InputSystem . AddDevice < Gamepad > ( ) ;
1168+
1169+ var go = new GameObject ( ) ;
1170+ var playerInput = go . AddComponent < PlayerInput > ( ) ;
1171+ playerInput . notificationBehavior = notificationBehavior ;
1172+ playerInput . defaultActionMap = "gameplay" ;
1173+ playerInput . actions = InputActionAsset . FromJson ( kActions ) ;
1174+
1175+ var listener = ( IListener ) go . AddComponent ( listenerType ) ;
1176+ // We don't want the listener to actually record messages. They have an object field which will
1177+ // box values and thus allocate GC garbage. We *do* want the listener to actually read values
1178+ // to make sure that doesn't allocate anything.
1179+ listener . messages = null ;
1180+
1181+ // First message is allowed to perform initialization work and thus allocate.
1182+ PressAndRelease ( gamepad . buttonSouth ) ;
1183+
1184+ var kProfilerRegion = "PlayerInput_TriggeringAction_DoesNotAllocateGCMemory" ;
1185+
1186+ Assert . That ( ( ) =>
1187+ {
1188+ Profiler . BeginSample ( kProfilerRegion ) ;
1189+ PressAndRelease ( gamepad . buttonSouth ) ;
1190+ Profiler . EndSample ( ) ;
1191+ } , Is . Not . AllocatingGCMemory ( ) ) ;
1192+ }
1193+
11361194 [ Test ]
11371195 [ Category ( "PlayerInput" ) ]
11381196 [ TestCase ( PlayerNotifications . SendMessages , typeof ( MessageListener ) ) ]
@@ -1791,14 +1849,6 @@ public void TODO_PlayerInput_CanSetUpSplitScreen_AndManuallyAllocatePlayersToScr
17911849 Assert . Fail ( ) ;
17921850 }
17931851
1794- [ Test ]
1795- [ Category ( "PlayerInput" ) ]
1796- [ Ignore ( "TODO" ) ]
1797- public void TODO_PlayerInput_TriggeringAction_DoesNotAllocate ( )
1798- {
1799- Assert . Fail ( ) ;
1800- }
1801-
18021852 // An action is either
18031853 // (a) button-like, or
18041854 // (b) axis-like, or
@@ -1823,7 +1873,8 @@ public void TODO_PlayerInput_TriggeringAction_DoesNotAllocate()
18231873 ""actions"" : [
18241874 { ""name"" : ""Fire"", ""type"" : ""button"" },
18251875 { ""name"" : ""Look"", ""type"" : ""value"" },
1826- { ""name"" : ""Move"", ""type"" : ""value"" }
1876+ { ""name"" : ""Move"", ""type"" : ""value"" },
1877+ { ""name"" : ""Action With Spaces!!"", ""type"" : ""value"" }
18271878 ],
18281879 ""bindings"" : [
18291880 { ""path"" : ""<Gamepad>/buttonSouth"", ""action"" : ""fire"", ""groups"" : ""Gamepad"" },
@@ -1836,7 +1887,8 @@ public void TODO_PlayerInput_TriggeringAction_DoesNotAllocate()
18361887 { ""path"" : ""<Keyboard>/w"", ""name"" : ""up"", ""action"" : ""move"", ""groups"" : ""Keyboard&Mouse"", ""isPartOfComposite"" : true },
18371888 { ""path"" : ""<Keyboard>/s"", ""name"" : ""down"", ""action"" : ""move"", ""groups"" : ""Keyboard&Mouse"", ""isPartOfComposite"" : true },
18381889 { ""path"" : ""<Mouse>/delta"", ""action"" : ""look"", ""groups"" : ""Keyboard&Mouse"" },
1839- { ""path"" : ""<Mouse>/leftButton"", ""action"" : ""fire"", ""groups"" : ""Keyboard&Mouse"" }
1890+ { ""path"" : ""<Mouse>/leftButton"", ""action"" : ""fire"", ""groups"" : ""Keyboard&Mouse"" },
1891+ { ""path"" : ""<Gamepad>/buttonNorth"", ""action"" : ""Action With Spaces!!"", ""groups"" : ""Gamepad"" }
18401892 ]
18411893 },
18421894 {
@@ -1884,8 +1936,8 @@ public void TODO_PlayerInput_TriggeringAction_DoesNotAllocate()
18841936
18851937 private struct Message : IEquatable < Message >
18861938 {
1887- public string name ;
1888- public object value ;
1939+ public string name { get ; set ; }
1940+ public object value { get ; set ; }
18891941
18901942 public Message ( string name , object value = null )
18911943 {
@@ -1923,65 +1975,71 @@ public override int GetHashCode()
19231975
19241976 private interface IListener
19251977 {
1926- List < Message > messages { get ; }
1978+ List < Message > messages { get ; set ; }
19271979 }
19281980
19291981 private class MessageListener : MonoBehaviour , IListener
19301982 {
1931- public List < Message > messages { get ; } = new List < Message > ( ) ;
1983+ public List < Message > messages { get ; set ; } = new List < Message > ( ) ;
19321984
19331985 // ReSharper disable once UnusedMember.Local
19341986 public void OnFire ( InputValue value )
19351987 {
1936- messages . Add ( new Message { name = "OnFire" , value = value . Get < float > ( ) } ) ;
1988+ messages ? . Add ( new Message { name = "OnFire" , value = value . Get < float > ( ) } ) ;
19371989 }
19381990
19391991 // ReSharper disable once UnusedMember.Local
19401992 public void OnLook ( InputValue value )
19411993 {
1942- messages . Add ( new Message { name = "OnLook" , value = value . Get < Vector2 > ( ) } ) ;
1994+ messages ? . Add ( new Message { name = "OnLook" , value = value . Get < Vector2 > ( ) } ) ;
19431995 }
19441996
19451997 // ReSharper disable once UnusedMember.Local
19461998 public void OnMove ( InputValue value )
19471999 {
1948- messages . Add ( new Message { name = "OnMove" , value = value . Get < Vector2 > ( ) } ) ;
2000+ messages ? . Add ( new Message { name = "OnMove" , value = value . Get < Vector2 > ( ) } ) ;
19492001 }
19502002
19512003 // ReSharper disable once UnusedMember.Local
19522004 public void OnOtherAction ( InputValue value )
19532005 {
1954- messages . Add ( new Message { name = "OnOtherAction" , value = value . Get < float > ( ) } ) ;
2006+ messages ? . Add ( new Message { name = "OnOtherAction" , value = value . Get < float > ( ) } ) ;
2007+ }
2008+
2009+ // ReSharper disable once UnusedMember.Local
2010+ public void OnActionWithSpaces ( InputValue value )
2011+ {
2012+ messages ? . Add ( new Message { name = "OnActionWithSpaces" , value = value . Get < float > ( ) } ) ;
19552013 }
19562014
19572015 // ReSharper disable once UnusedMember.Local
19582016 public void OnDeviceLost ( PlayerInput player )
19592017 {
1960- messages . Add ( new Message { name = "OnDeviceLost" , value = player } ) ;
2018+ messages ? . Add ( new Message { name = "OnDeviceLost" , value = player } ) ;
19612019 }
19622020
19632021 // ReSharper disable once UnusedMember.Local
19642022 public void OnDeviceRegained ( PlayerInput player )
19652023 {
1966- messages . Add ( new Message { name = "OnDeviceRegained" , value = player } ) ;
2024+ messages ? . Add ( new Message { name = "OnDeviceRegained" , value = player } ) ;
19672025 }
19682026
19692027 // ReSharper disable once UnusedMember.Local
19702028 public void OnControlsChanged ( PlayerInput player )
19712029 {
1972- messages . Add ( new Message { name = "OnControlsChanged" , value = player } ) ;
2030+ messages ? . Add ( new Message { name = "OnControlsChanged" , value = player } ) ;
19732031 }
19742032
19752033 // ReSharper disable once UnusedMember.Local
19762034 public void OnPlayerJoined ( PlayerInput player )
19772035 {
1978- messages . Add ( new Message { name = "OnPlayerJoined" , value = player } ) ;
2036+ messages ? . Add ( new Message { name = "OnPlayerJoined" , value = player } ) ;
19792037 }
19802038
19812039 // ReSharper disable once UnusedMember.Local
19822040 public void OnPlayerLeft ( PlayerInput player )
19832041 {
1984- messages . Add ( new Message { name = "OnPlayerLeft" , value = player } ) ;
2042+ messages ? . Add ( new Message { name = "OnPlayerLeft" , value = player } ) ;
19852043 }
19862044 }
19872045
@@ -1990,7 +2048,7 @@ public void OnPlayerLeft(PlayerInput player)
19902048 [ Preserve ]
19912049 private class PlayerInputEventListener : MonoBehaviour , IListener
19922050 {
1993- public List < Message > messages { get ; } = new List < Message > ( ) ;
2051+ public List < Message > messages { get ; set ; } = new List < Message > ( ) ;
19942052
19952053 public void OnEnable ( )
19962054 {
@@ -2031,40 +2089,40 @@ private void SetUpActionEvents(PlayerInput player)
20312089
20322090 private void OnFireEvent ( InputAction . CallbackContext context )
20332091 {
2034- messages . Add ( new Message ( $ "Fire { context . phase } ", context . ReadValueAsObject ( ) ) ) ;
2092+ messages ? . Add ( new Message ( $ "Fire { context . phase } ", context . ReadValueAsObject ( ) ) ) ;
20352093 }
20362094
20372095 private void OnLookEvent ( InputAction . CallbackContext context )
20382096 {
2039- messages . Add ( new Message ( $ "Look { context . phase } ", context . ReadValueAsObject ( ) ) ) ;
2097+ messages ? . Add ( new Message ( $ "Look { context . phase } ", context . ReadValueAsObject ( ) ) ) ;
20402098 }
20412099
20422100 private void OnMoveEvent ( InputAction . CallbackContext context )
20432101 {
2044- messages . Add ( new Message ( $ "Move { context . phase } ", context . ReadValueAsObject ( ) ) ) ;
2102+ messages ? . Add ( new Message ( $ "Move { context . phase } ", context . ReadValueAsObject ( ) ) ) ;
20452103 }
20462104
20472105 private void OnDeviceLost ( PlayerInput player )
20482106 {
2049- messages . Add ( new Message ( "OnDeviceLost" , player ) ) ;
2107+ messages ? . Add ( new Message ( "OnDeviceLost" , player ) ) ;
20502108 }
20512109
20522110 private void OnDeviceRegained ( PlayerInput player )
20532111 {
2054- messages . Add ( new Message ( "OnDeviceRegained" , player ) ) ;
2112+ messages ? . Add ( new Message ( "OnDeviceRegained" , player ) ) ;
20552113 }
20562114
20572115 private void OnControlsChanged ( PlayerInput player )
20582116 {
2059- messages . Add ( new Message ( "OnControlsChanged" , player ) ) ;
2117+ messages ? . Add ( new Message ( "OnControlsChanged" , player ) ) ;
20602118 }
20612119 }
20622120
20632121 // il2cpp internally crashes if this gets stripped. Need to investigate, but for now we preserve it.
20642122 [ Preserve ]
20652123 private class PlayerInputCSharpEventListener : MonoBehaviour , IListener
20662124 {
2067- public List < Message > messages { get ; } = new List < Message > ( ) ;
2125+ public List < Message > messages { get ; set ; } = new List < Message > ( ) ;
20682126
20692127 public void OnEnable ( )
20702128 {
@@ -2079,30 +2137,30 @@ public void OnEnable()
20792137
20802138 private void OnAction ( InputAction . CallbackContext context )
20812139 {
2082- messages . Add ( new Message ( $ "{ context . action . name } { context . phase } ", context . ReadValueAsObject ( ) ) ) ;
2140+ messages ? . Add ( new Message ( $ "{ context . action . name } { context . phase } ", context . ReadValueAsObject ( ) ) ) ;
20832141 }
20842142
20852143 private void OnDeviceLost ( PlayerInput player )
20862144 {
2087- messages . Add ( new Message ( "OnDeviceLost" , player ) ) ;
2145+ messages ? . Add ( new Message ( "OnDeviceLost" , player ) ) ;
20882146 }
20892147
20902148 private void OnDeviceRegained ( PlayerInput player )
20912149 {
2092- messages . Add ( new Message ( "OnDeviceRegained" , player ) ) ;
2150+ messages ? . Add ( new Message ( "OnDeviceRegained" , player ) ) ;
20932151 }
20942152
20952153 private void OnControlsChanged ( PlayerInput player )
20962154 {
2097- messages . Add ( new Message ( "OnControlsChanged" , player ) ) ;
2155+ messages ? . Add ( new Message ( "OnControlsChanged" , player ) ) ;
20982156 }
20992157 }
21002158
21012159 // il2cpp internally crashes if this gets stripped. Need to investigate, but for now we preserve it.
21022160 [ Preserve ]
21032161 private class PlayerManagerEventListener : MonoBehaviour , IListener
21042162 {
2105- public List < Message > messages { get ; } = new List < Message > ( ) ;
2163+ public List < Message > messages { get ; set ; } = new List < Message > ( ) ;
21062164
21072165 public void OnEnable ( )
21082166 {
@@ -2128,7 +2186,7 @@ private void OnPlayerLeft(PlayerInput player)
21282186 [ Preserve ]
21292187 private class PlayerManagerCSharpEventListener : MonoBehaviour , IListener
21302188 {
2131- public List < Message > messages { get ; } = new List < Message > ( ) ;
2189+ public List < Message > messages { get ; set ; } = new List < Message > ( ) ;
21322190
21332191 public void OnEnable ( )
21342192 {
@@ -2141,12 +2199,12 @@ public void OnEnable()
21412199
21422200 private void OnPlayerJoined ( PlayerInput player )
21432201 {
2144- messages . Add ( new Message ( "OnPlayerJoined" , player ) ) ;
2202+ messages ? . Add ( new Message ( "OnPlayerJoined" , player ) ) ;
21452203 }
21462204
21472205 private void OnPlayerLeft ( PlayerInput player )
21482206 {
2149- messages . Add ( new Message ( "OnPlayerLeft" , player ) ) ;
2207+ messages ? . Add ( new Message ( "OnPlayerLeft" , player ) ) ;
21502208 }
21512209 }
21522210}
0 commit comments