Skip to content

Commit 3474f49

Browse files
committed
reduce allocations when applying input overrides
1 parent f7bc2d9 commit 3474f49

File tree

5 files changed

+121
-121
lines changed

5 files changed

+121
-121
lines changed

src/SMAPI/Framework/Input/GamePadStateBuilder.cs

Lines changed: 87 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using System.Diagnostics.CodeAnalysis;
23
using System.Linq;
34
using Microsoft.Xna.Framework;
45
using Microsoft.Xna.Framework.Input;
@@ -21,7 +22,7 @@ internal class GamePadStateBuilder : IInputStateBuilder<GamePadStateBuilder, Gam
2122
private GamePadState? State;
2223

2324
/// <summary>The current button states.</summary>
24-
private readonly Dictionary<SButton, ButtonState> ButtonStates = [];
25+
private readonly Dictionary<Buttons, ButtonState> ButtonStates = [];
2526

2627
/// <summary>The left trigger value.</summary>
2728
private float LeftTrigger;
@@ -53,21 +54,21 @@ public void Reset(GamePadState state)
5354

5455
var states = this.ButtonStates;
5556
states.Clear();
56-
states[SButton.DPadUp] = pad.Up;
57-
states[SButton.DPadDown] = pad.Down;
58-
states[SButton.DPadLeft] = pad.Left;
59-
states[SButton.DPadRight] = pad.Right;
60-
states[SButton.ControllerA] = buttons.A;
61-
states[SButton.ControllerB] = buttons.B;
62-
states[SButton.ControllerX] = buttons.X;
63-
states[SButton.ControllerY] = buttons.Y;
64-
states[SButton.LeftStick] = buttons.LeftStick;
65-
states[SButton.RightStick] = buttons.RightStick;
66-
states[SButton.LeftShoulder] = buttons.LeftShoulder;
67-
states[SButton.RightShoulder] = buttons.RightShoulder;
68-
states[SButton.ControllerBack] = buttons.Back;
69-
states[SButton.ControllerStart] = buttons.Start;
70-
states[SButton.BigButton] = buttons.BigButton;
57+
states[Buttons.DPadUp] = pad.Up;
58+
states[Buttons.DPadDown] = pad.Down;
59+
states[Buttons.DPadLeft] = pad.Left;
60+
states[Buttons.DPadRight] = pad.Right;
61+
states[Buttons.A] = buttons.A;
62+
states[Buttons.B] = buttons.B;
63+
states[Buttons.X] = buttons.X;
64+
states[Buttons.Y] = buttons.Y;
65+
states[Buttons.LeftStick] = buttons.LeftStick;
66+
states[Buttons.RightStick] = buttons.RightStick;
67+
states[Buttons.LeftShoulder] = buttons.LeftShoulder;
68+
states[Buttons.RightShoulder] = buttons.RightShoulder;
69+
states[Buttons.Back] = buttons.Back;
70+
states[Buttons.Start] = buttons.Start;
71+
states[Buttons.BigButton] = buttons.BigButton;
7172

7273
this.LeftTrigger = triggers.Left;
7374
this.RightTrigger = triggers.Right;
@@ -85,63 +86,81 @@ public void Reset(GamePadState state)
8586
}
8687
}
8788

88-
/// <inheritdoc />
89-
public GamePadStateBuilder OverrideButtons(IDictionary<SButton, SButtonState> overrides)
89+
/// <summary>Override the state for a button.</summary>
90+
/// <param name="button">The button to override.</param>
91+
/// <param name="state">The new state to set.</param>
92+
public void OverrideButton(Buttons button, SButtonState state)
9093
{
91-
foreach (var pair in overrides)
94+
bool isDown = state.IsDown();
95+
bool changed = false;
96+
97+
switch (button)
9298
{
93-
bool changed = true;
99+
// left thumbstick
100+
case Buttons.LeftThumbstickUp:
101+
changed = Set(ref this.LeftStickPos.Y, isDown ? 1 : 0);
102+
break;
103+
case Buttons.LeftThumbstickDown:
104+
changed = Set(ref this.LeftStickPos.Y, isDown ? -1 : 0);
105+
break;
106+
case Buttons.LeftThumbstickLeft:
107+
changed = Set(ref this.LeftStickPos.X, isDown ? -1 : 0);
108+
break;
109+
case Buttons.LeftThumbstickRight:
110+
changed = Set(ref this.LeftStickPos.X, isDown ? 1 : 0);
111+
break;
112+
113+
// right thumbstick
114+
case Buttons.RightThumbstickUp:
115+
changed = Set(ref this.RightStickPos.Y, isDown ? 1 : 0);
116+
break;
117+
case Buttons.RightThumbstickDown:
118+
changed = Set(ref this.RightStickPos.Y, isDown ? -1 : 0);
119+
break;
120+
case Buttons.RightThumbstickLeft:
121+
changed = Set(ref this.RightStickPos.X, isDown ? -1 : 0);
122+
break;
123+
case Buttons.RightThumbstickRight:
124+
changed = Set(ref this.RightStickPos.X, isDown ? 1 : 0);
125+
break;
126+
127+
// triggers
128+
case Buttons.LeftTrigger:
129+
changed = Set(ref this.LeftTrigger, isDown ? 1 : 0);
130+
break;
131+
case Buttons.RightTrigger:
132+
changed = Set(ref this.RightTrigger, isDown ? 1 : 0);
133+
break;
134+
135+
// buttons
136+
default:
137+
{
138+
ButtonState newState = isDown ? ButtonState.Pressed : ButtonState.Released;
139+
140+
if (!this.ButtonStates.TryGetValue(button, out ButtonState oldState) || newState != oldState)
141+
{
142+
this.ButtonStates[button] = newState;
143+
changed = true;
144+
}
145+
}
146+
break;
147+
}
94148

95-
bool isDown = pair.Value.IsDown();
96-
switch (pair.Key)
149+
if (changed)
150+
this.State = null;
151+
return;
152+
153+
[SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator", Justification = "Floating points not an issue for the specific values we're checking.")]
154+
static bool Set(ref float field, int newValue)
155+
{
156+
if (field != newValue)
97157
{
98-
// left thumbstick
99-
case SButton.LeftThumbstickUp:
100-
this.LeftStickPos.Y = isDown ? 1 : 0;
101-
break;
102-
case SButton.LeftThumbstickDown:
103-
this.LeftStickPos.Y = isDown ? -1 : 0;
104-
break;
105-
case SButton.LeftThumbstickLeft:
106-
this.LeftStickPos.X = isDown ? -1 : 0;
107-
break;
108-
case SButton.LeftThumbstickRight:
109-
this.LeftStickPos.X = isDown ? 1 : 0;
110-
break;
111-
112-
// right thumbstick
113-
case SButton.RightThumbstickUp:
114-
this.RightStickPos.Y = isDown ? 1 : 0;
115-
break;
116-
case SButton.RightThumbstickDown:
117-
this.RightStickPos.Y = isDown ? -1 : 0;
118-
break;
119-
case SButton.RightThumbstickLeft:
120-
this.RightStickPos.X = isDown ? -1 : 0;
121-
break;
122-
case SButton.RightThumbstickRight:
123-
this.RightStickPos.X = isDown ? 1 : 0;
124-
break;
125-
126-
// triggers
127-
case SButton.LeftTrigger:
128-
this.LeftTrigger = isDown ? 1 : 0;
129-
break;
130-
case SButton.RightTrigger:
131-
this.RightTrigger = isDown ? 1 : 0;
132-
break;
133-
134-
// buttons
135-
default:
136-
this.ButtonStates[pair.Key] = isDown ? ButtonState.Pressed : ButtonState.Released;
137-
break;
158+
field = newValue;
159+
return true;
138160
}
139161

140-
if (changed)
141-
this.State = null;
162+
return false;
142163
}
143-
144-
return this;
145164
}
146165

147166
/// <inheritdoc />
@@ -200,9 +219,9 @@ public GamePadState GetState()
200219
/// <summary>Get the pressed gamepad buttons.</summary>
201220
private IEnumerable<Buttons> GetPressedGamePadButtons()
202221
{
203-
foreach (var pair in this.ButtonStates)
222+
foreach ((Buttons button, ButtonState state) in this.ButtonStates)
204223
{
205-
if (pair.Value == ButtonState.Pressed && pair.Key.TryGetController(out Buttons button))
224+
if (state == ButtonState.Pressed)
206225
yield return button;
207226
}
208227
}

src/SMAPI/Framework/Input/IInputStateBuilder.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,6 @@ internal interface IInputStateBuilder<out THandler, TState>
1616
/// <param name="state">The initial state before any overrides are applied.</param>
1717
void Reset(TState state);
1818

19-
/// <summary>Override the states for a set of buttons.</summary>
20-
/// <param name="overrides">The button state overrides.</param>
21-
THandler OverrideButtons(IDictionary<SButton, SButtonState> overrides);
22-
2319
/// <summary>Fill a set with the currently pressed buttons.</summary>
2420
/// <param name="set">The set to populate with the pressed buttons.</param>
2521
void FillPressedButtons(HashSet<SButton> set);

src/SMAPI/Framework/Input/KeyboardStateBuilder.cs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,17 @@ public void Reset(KeyboardState state)
3030
this.PressedButtons.Add(button);
3131
}
3232

33-
/// <inheritdoc />
34-
public KeyboardStateBuilder OverrideButtons(IDictionary<SButton, SButtonState> overrides)
33+
/// <summary>Override the state for a key.</summary>
34+
/// <param name="key">The key to override.</param>
35+
/// <param name="state">The new state to set.</param>
36+
public void OverrideButton(Keys key, SButtonState state)
3537
{
36-
foreach (var pair in overrides)
37-
{
38-
if (pair.Key.TryGetKeyboard(out Keys key))
39-
{
40-
this.State = null;
41-
42-
if (pair.Value.IsDown())
43-
this.PressedButtons.Add(key);
44-
else
45-
this.PressedButtons.Remove(key);
46-
}
47-
}
38+
bool changed = state.IsDown()
39+
? this.PressedButtons.Add(key)
40+
: this.PressedButtons.Remove(key);
4841

49-
return this;
42+
if (changed)
43+
this.State = null;
5044
}
5145

5246
/// <inheritdoc />

src/SMAPI/Framework/Input/MouseStateBuilder.cs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,20 @@ public void Reset(MouseState state)
5050
this.ScrollWheelValue = state.ScrollWheelValue;
5151
}
5252

53-
/// <inheritdoc />
54-
public MouseStateBuilder OverrideButtons(IDictionary<SButton, SButtonState> overrides)
53+
/// <summary>Override the state for a button.</summary>
54+
/// <param name="button">The button to override.</param>
55+
/// <param name="state">The new state to set.</param>
56+
public void OverrideButton(SButton button, SButtonState state)
5557
{
56-
foreach (var pair in overrides)
58+
ButtonState newState = state.IsDown()
59+
? ButtonState.Pressed
60+
: ButtonState.Released;
61+
62+
if (this.ButtonStates.TryGetValue(button, out ButtonState oldState) && oldState != newState)
5763
{
58-
if (this.ButtonStates.ContainsKey(pair.Key))
59-
{
60-
this.State = null;
61-
this.ButtonStates[pair.Key] = pair.Value.IsDown() ? ButtonState.Pressed : ButtonState.Released;
62-
}
64+
this.State = null;
65+
this.ButtonStates[button] = newState;
6366
}
64-
65-
return this;
6667
}
6768

6869
/// <inheritdoc />

src/SMAPI/Framework/Input/SInputState.cs

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -251,34 +251,24 @@ private bool ApplyOverrides(ISet<SButton> pressed, ISet<SButton> released, GameP
251251
if (pressed.Count == 0 && released.Count == 0)
252252
return false;
253253

254-
// group keys by type
255-
IDictionary<SButton, SButtonState> keyboardOverrides = new Dictionary<SButton, SButtonState>();
256-
IDictionary<SButton, SButtonState> controllerOverrides = new Dictionary<SButton, SButtonState>();
257-
IDictionary<SButton, SButtonState> mouseOverrides = new Dictionary<SButton, SButtonState>();
258-
foreach (SButton button in pressed.Concat(released))
254+
foreach (SButton button in pressed)
255+
Apply(button, this.GetState(button), isDown: true, controller, keyboard, mouse);
256+
foreach (SButton button in released)
257+
Apply(button, this.GetState(button), isDown: pressed.Contains(button), controller, keyboard, mouse);
258+
259+
return true;
260+
261+
static void Apply(SButton button, SButtonState oldState, bool isDown, GamePadStateBuilder controller, KeyboardStateBuilder keyboard, MouseStateBuilder mouse)
259262
{
260-
SButtonState newState = SInputState.DeriveState(
261-
oldState: this.GetState(button),
262-
isDown: pressed.Contains(button)
263-
);
263+
SButtonState newState = SInputState.DeriveState(oldState, isDown);
264264

265265
if (button is SButton.MouseLeft or SButton.MouseMiddle or SButton.MouseRight or SButton.MouseX1 or SButton.MouseX2)
266-
mouseOverrides[button] = newState;
267-
else if (button.TryGetKeyboard(out Keys _))
268-
keyboardOverrides[button] = newState;
269-
else if (button.TryGetController(out Buttons _))
270-
controllerOverrides[button] = newState;
266+
mouse.OverrideButton(button, newState);
267+
else if (button.TryGetKeyboard(out Keys key))
268+
keyboard.OverrideButton(key, newState);
269+
else if (button.TryGetController(out Buttons controllerButton))
270+
controller.OverrideButton(controllerButton, newState);
271271
}
272-
273-
// override states
274-
if (keyboardOverrides.Count > 0)
275-
keyboard.OverrideButtons(keyboardOverrides);
276-
if (controllerOverrides.Count > 0)
277-
controller.OverrideButtons(controllerOverrides);
278-
if (mouseOverrides.Count > 0)
279-
mouse.OverrideButtons(mouseOverrides);
280-
281-
return true;
282272
}
283273

284274
/// <summary>Update active button states based on the currently pressed buttons.</summary>

0 commit comments

Comments
 (0)