Skip to content

Commit 2aeaf6f

Browse files
committed
reduce allocations in input API's GetPressedButtons() logic
1 parent dece408 commit 2aeaf6f

5 files changed

Lines changed: 43 additions & 38 deletions

File tree

src/SMAPI/Framework/Input/GamePadStateBuilder.cs

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -145,54 +145,52 @@ public GamePadStateBuilder OverrideButtons(IDictionary<SButton, SButtonState> ov
145145
}
146146

147147
/// <inheritdoc />
148-
public IEnumerable<SButton> GetPressedButtons()
148+
public void FillPressedButtons(HashSet<SButton> set)
149149
{
150150
// buttons
151151
foreach (Buttons button in this.GetPressedGamePadButtons())
152-
yield return button.ToSButton();
152+
set.Add(button.ToSButton());
153153

154154
// triggers
155155
if (this.LeftTrigger > 0.2f)
156-
yield return SButton.LeftTrigger;
156+
set.Add(SButton.LeftTrigger);
157157
if (this.RightTrigger > 0.2f)
158-
yield return SButton.RightTrigger;
158+
set.Add(SButton.RightTrigger);
159159

160160
// left thumbstick direction
161161
if (this.LeftStickPos.Y > GamePadStateBuilder.LeftThumbstickDeadZone)
162-
yield return SButton.LeftThumbstickUp;
162+
set.Add(SButton.LeftThumbstickUp);
163163
if (this.LeftStickPos.Y < -GamePadStateBuilder.LeftThumbstickDeadZone)
164-
yield return SButton.LeftThumbstickDown;
164+
set.Add(SButton.LeftThumbstickDown);
165165
if (this.LeftStickPos.X > GamePadStateBuilder.LeftThumbstickDeadZone)
166-
yield return SButton.LeftThumbstickRight;
166+
set.Add(SButton.LeftThumbstickRight);
167167
if (this.LeftStickPos.X < -GamePadStateBuilder.LeftThumbstickDeadZone)
168-
yield return SButton.LeftThumbstickLeft;
168+
set.Add(SButton.LeftThumbstickLeft);
169169

170170
// right thumbstick direction
171171
if (this.RightStickPos.Length() > GamePadStateBuilder.RightThumbstickDeadZone)
172172
{
173173
if (this.RightStickPos.Y > 0)
174-
yield return SButton.RightThumbstickUp;
174+
set.Add(SButton.RightThumbstickUp);
175175
if (this.RightStickPos.Y < 0)
176-
yield return SButton.RightThumbstickDown;
176+
set.Add(SButton.RightThumbstickDown);
177177
if (this.RightStickPos.X > 0)
178-
yield return SButton.RightThumbstickRight;
178+
set.Add(SButton.RightThumbstickRight);
179179
if (this.RightStickPos.X < 0)
180-
yield return SButton.RightThumbstickLeft;
180+
set.Add(SButton.RightThumbstickLeft);
181181
}
182182
}
183183

184184
/// <inheritdoc />
185185
public GamePadState GetState()
186186
{
187-
this.State ??= new GamePadState(
187+
return this.State ??= new GamePadState(
188188
leftThumbStick: this.LeftStickPos,
189189
rightThumbStick: this.RightStickPos,
190190
leftTrigger: this.LeftTrigger,
191191
rightTrigger: this.RightTrigger,
192192
buttons: this.GetPressedGamePadButtons().ToArray()
193193
);
194-
195-
return this.State.Value;
196194
}
197195

198196

src/SMAPI/Framework/Input/IInputStateBuilder.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ internal interface IInputStateBuilder<out THandler, TState>
2020
/// <param name="overrides">The button state overrides.</param>
2121
THandler OverrideButtons(IDictionary<SButton, SButtonState> overrides);
2222

23-
/// <summary>Get the currently pressed buttons.</summary>
24-
IEnumerable<SButton> GetPressedButtons();
23+
/// <summary>Fill a set with the currently pressed buttons.</summary>
24+
/// <param name="set">The set to populate with the pressed buttons.</param>
25+
void FillPressedButtons(HashSet<SButton> set);
2526

2627
/// <summary>Get the equivalent state.</summary>
2728
TState GetState();

src/SMAPI/Framework/Input/KeyboardStateBuilder.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,17 +50,15 @@ public KeyboardStateBuilder OverrideButtons(IDictionary<SButton, SButtonState> o
5050
}
5151

5252
/// <inheritdoc />
53-
public IEnumerable<SButton> GetPressedButtons()
53+
public void FillPressedButtons(HashSet<SButton> set)
5454
{
5555
foreach (Keys key in this.PressedButtons)
56-
yield return key.ToSButton();
56+
set.Add(key.ToSButton());
5757
}
5858

5959
/// <inheritdoc />
6060
public KeyboardState GetState()
6161
{
62-
return
63-
this.State
64-
?? (this.State = new KeyboardState(this.PressedButtons.ToArray())).Value;
62+
return this.State ??= new KeyboardState(this.PressedButtons.ToArray());
6563
}
6664
}

src/SMAPI/Framework/Input/MouseStateBuilder.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,19 @@ public MouseStateBuilder OverrideButtons(IDictionary<SButton, SButtonState> over
6666
}
6767

6868
/// <inheritdoc />
69-
public IEnumerable<SButton> GetPressedButtons()
69+
public void FillPressedButtons(HashSet<SButton> set)
7070
{
7171
foreach (var pair in this.ButtonStates)
7272
{
7373
if (pair.Value == ButtonState.Pressed)
74-
yield return pair.Key;
74+
set.Add(pair.Key);
7575
}
7676
}
7777

7878
/// <inheritdoc />
7979
public MouseState GetState()
8080
{
81-
this.State ??= new MouseState(
81+
return this.State ??= new MouseState(
8282
x: this.X,
8383
y: this.Y,
8484
scrollWheel: this.ScrollWheelValue,
@@ -88,7 +88,5 @@ public MouseState GetState()
8888
xButton1: this.ButtonStates[SButton.MouseX1],
8989
xButton2: this.ButtonStates[SButton.MouseX2]
9090
);
91-
92-
return this.State.Value;
9391
}
9492
}

src/SMAPI/Framework/Input/SInputState.cs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ internal sealed class SInputState : InputState
3838
/// <summary>The builder which reads the mouse state and applies overrides.</summary>
3939
private readonly MouseStateBuilder MouseStateBuilder = new();
4040

41+
/// <summary>The pooled cache set for <see cref="FillPressedButtons"/> in <see cref="TrueUpdate"/>.</summary>
42+
private readonly HashSet<SButton> PooledPressedButtons = [];
43+
4144

4245
/*********
4346
** Accessors
@@ -82,21 +85,26 @@ public void TrueUpdate()
8285
KeyboardStateBuilder keyboard = this.KeyboardStateBuilder;
8386
MouseStateBuilder mouse = this.MouseStateBuilder;
8487

88+
// get pooled button set
89+
HashSet<SButton> pressedButtons = this.PooledPressedButtons;
90+
8591
// get real values
8692
controller.Reset(base.GetGamePadState());
8793
keyboard.Reset(base.GetKeyboardState());
8894
mouse.Reset(base.GetMouseState());
8995
Vector2 cursorAbsolutePos = new((mouse.X * zoomMultiplier) + Game1.viewport.X, (mouse.Y * zoomMultiplier) + Game1.viewport.Y);
9096
Vector2? playerTilePos = Context.IsPlayerFree ? Game1.player.Tile : null;
91-
HashSet<SButton> reallyDown = new(this.GetPressedButtons(keyboard, mouse, controller));
97+
98+
pressedButtons.Clear();
99+
this.FillPressedButtons(pressedButtons, keyboard, mouse, controller);
92100

93101
// apply overrides
94102
bool hasOverrides = false;
95103
if (this.CustomPressedKeys.Count > 0 || this.CustomReleasedKeys.Count > 0)
96104
{
97105
// reset overrides that no longer apply
98-
this.CustomPressedKeys.ExceptWith(reallyDown);
99-
this.CustomReleasedKeys.IntersectWith(reallyDown);
106+
this.CustomPressedKeys.ExceptWith(pressedButtons);
107+
this.CustomReleasedKeys.IntersectWith(pressedButtons);
100108

101109
// apply overrides
102110
if (this.ApplyOverrides(this.CustomPressedKeys, this.CustomReleasedKeys, controller, keyboard, mouse))
@@ -107,9 +115,11 @@ public void TrueUpdate()
107115
}
108116

109117
// get button states
110-
var pressedButtons = hasOverrides
111-
? new(this.GetPressedButtons(keyboard, mouse, controller))
112-
: reallyDown;
118+
if (hasOverrides)
119+
{
120+
pressedButtons.Clear();
121+
this.FillPressedButtons(pressedButtons, keyboard, mouse, controller);
122+
}
113123
var activeButtons = this.DeriveStates(this.ButtonStates, pressedButtons);
114124

115125
// update
@@ -315,15 +325,15 @@ private SButtonState GetState(IDictionary<SButton, SButtonState> activeButtons,
315325
}
316326

317327
/// <summary>Get the buttons pressed in the given stats.</summary>
328+
/// <param name="set">The set to populate with pressed buttons.</param>
318329
/// <param name="keyboard">The keyboard state.</param>
319330
/// <param name="mouse">The mouse state.</param>
320331
/// <param name="controller">The controller state.</param>
321332
/// <remarks>Thumbstick direction logic derived from <see cref="ButtonCollection"/>.</remarks>
322-
private IEnumerable<SButton> GetPressedButtons(KeyboardStateBuilder keyboard, MouseStateBuilder mouse, GamePadStateBuilder controller)
333+
private void FillPressedButtons(HashSet<SButton> set, KeyboardStateBuilder keyboard, MouseStateBuilder mouse, GamePadStateBuilder controller)
323334
{
324-
return keyboard
325-
.GetPressedButtons()
326-
.Concat(mouse.GetPressedButtons())
327-
.Concat(controller.GetPressedButtons());
335+
keyboard.FillPressedButtons(set);
336+
mouse.FillPressedButtons(set);
337+
controller.FillPressedButtons(set);
328338
}
329339
}

0 commit comments

Comments
 (0)