Skip to content

Commit 3bb18fc

Browse files
committed
reduce allocations in input handling
This reuses the input builders instead of creating new ones each time we build input.
1 parent 81d6214 commit 3bb18fc

File tree

6 files changed

+75
-48
lines changed

6 files changed

+75
-48
lines changed

docs/release-notes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
# Release notes
44
## Upcoming release
55
* For players:
6+
* Minor performance optimizations.
67
* Fixed the Linux/macOS installer not saving the color scheme correctly in 4.5.0+.
78
* Fixed typo in config UI text (thanks to QuentiumYT!).
89
* Improved translations. Thanks to dewanggatrustha (updated Indonesian), QuentiumYT (updated French), and Timur13240

src/SMAPI/Framework/Input/GamePadStateBuilder.cs

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ internal class GamePadStateBuilder : IInputStateBuilder<GamePadStateBuilder, Gam
2121
private GamePadState? State;
2222

2323
/// <summary>The current button states.</summary>
24-
private readonly Dictionary<SButton, ButtonState> ButtonStates;
24+
private readonly Dictionary<SButton, ButtonState> ButtonStates = [];
2525

2626
/// <summary>The left trigger value.</summary>
2727
private float LeftTrigger;
@@ -39,9 +39,8 @@ internal class GamePadStateBuilder : IInputStateBuilder<GamePadStateBuilder, Gam
3939
/*********
4040
** Public methods
4141
*********/
42-
/// <summary>Construct an instance.</summary>
43-
/// <param name="state">The initial state.</param>
44-
public GamePadStateBuilder(GamePadState state)
42+
/// <inheritdoc />
43+
public void Reset(GamePadState state)
4544
{
4645
this.State = state;
4746

@@ -51,32 +50,39 @@ public GamePadStateBuilder(GamePadState state)
5150
GamePadButtons buttons = state.Buttons;
5251
GamePadTriggers triggers = state.Triggers;
5352
GamePadThumbSticks sticks = state.ThumbSticks;
54-
this.ButtonStates = new Dictionary<SButton, ButtonState>
55-
{
56-
[SButton.DPadUp] = pad.Up,
57-
[SButton.DPadDown] = pad.Down,
58-
[SButton.DPadLeft] = pad.Left,
59-
[SButton.DPadRight] = pad.Right,
60-
61-
[SButton.ControllerA] = buttons.A,
62-
[SButton.ControllerB] = buttons.B,
63-
[SButton.ControllerX] = buttons.X,
64-
[SButton.ControllerY] = buttons.Y,
65-
[SButton.LeftStick] = buttons.LeftStick,
66-
[SButton.RightStick] = buttons.RightStick,
67-
[SButton.LeftShoulder] = buttons.LeftShoulder,
68-
[SButton.RightShoulder] = buttons.RightShoulder,
69-
[SButton.ControllerBack] = buttons.Back,
70-
[SButton.ControllerStart] = buttons.Start,
71-
[SButton.BigButton] = buttons.BigButton
72-
};
53+
54+
var states = this.ButtonStates;
55+
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;
71+
7372
this.LeftTrigger = triggers.Left;
7473
this.RightTrigger = triggers.Right;
7574
this.LeftStickPos = sticks.Left;
7675
this.RightStickPos = sticks.Right;
7776
}
7877
else
79-
this.ButtonStates = [];
78+
{
79+
this.ButtonStates.Clear();
80+
81+
this.LeftTrigger = 0;
82+
this.RightTrigger = 0;
83+
this.LeftStickPos = Vector2.Zero;
84+
this.RightStickPos = Vector2.Zero;
85+
}
8086
}
8187

8288
/// <inheritdoc />

src/SMAPI/Framework/Input/IInputStateBuilder.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ internal interface IInputStateBuilder<out THandler, TState>
1212
/*********
1313
** Methods
1414
*********/
15+
/// <summary>Reset the state.</summary>
16+
/// <param name="state">The initial state before any overrides are applied.</param>
17+
void Reset(TState state);
18+
1519
/// <summary>Override the states for a set of buttons.</summary>
1620
/// <param name="overrides">The button state overrides.</param>
1721
THandler OverrideButtons(IDictionary<SButton, SButtonState> overrides);

src/SMAPI/Framework/Input/KeyboardStateBuilder.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ internal class KeyboardStateBuilder : IInputStateBuilder<KeyboardStateBuilder, K
2020
/*********
2121
** Public methods
2222
*********/
23-
/// <summary>Construct an instance.</summary>
24-
/// <param name="state">The initial state.</param>
25-
public KeyboardStateBuilder(KeyboardState state)
23+
/// <inheritdoc />
24+
public void Reset(KeyboardState state)
2625
{
2726
this.State = state;
2827

src/SMAPI/Framework/Input/MouseStateBuilder.cs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,39 +13,38 @@ internal class MouseStateBuilder : IInputStateBuilder<MouseStateBuilder, MouseSt
1313
private MouseState? State;
1414

1515
/// <summary>The current button states.</summary>
16-
private readonly IDictionary<SButton, ButtonState> ButtonStates;
16+
private readonly Dictionary<SButton, ButtonState> ButtonStates = [];
1717

1818
/// <summary>The mouse wheel scroll value.</summary>
19-
private readonly int ScrollWheelValue;
19+
private int ScrollWheelValue;
2020

2121

2222
/*********
2323
** Accessors
2424
*********/
2525
/// <summary>The X cursor position.</summary>
26-
public int X { get; }
26+
public int X { get; private set; }
2727

2828
/// <summary>The Y cursor position.</summary>
29-
public int Y { get; }
29+
public int Y { get; private set; }
3030

3131

3232
/*********
3333
** Public methods
3434
*********/
35-
/// <summary>Construct an instance.</summary>
36-
/// <param name="state">The initial state.</param>
37-
public MouseStateBuilder(MouseState state)
35+
/// <inheritdoc />
36+
public void Reset(MouseState state)
3837
{
3938
this.State = state;
4039

41-
this.ButtonStates = new Dictionary<SButton, ButtonState>
42-
{
43-
[SButton.MouseLeft] = state.LeftButton,
44-
[SButton.MouseMiddle] = state.MiddleButton,
45-
[SButton.MouseRight] = state.RightButton,
46-
[SButton.MouseX1] = state.XButton1,
47-
[SButton.MouseX2] = state.XButton2
48-
};
40+
var states = this.ButtonStates;
41+
states.Clear();
42+
states[SButton.MouseLeft] = state.LeftButton;
43+
states[SButton.MouseMiddle] = state.MiddleButton;
44+
states[SButton.MouseRight] = state.RightButton;
45+
states[SButton.MouseX1] = state.XButton1;
46+
states[SButton.MouseX2] = state.XButton2;
47+
4948
this.X = state.X;
5049
this.Y = state.Y;
5150
this.ScrollWheelValue = state.ScrollWheelValue;

src/SMAPI/Framework/Input/SInputState.cs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@ internal sealed class SInputState : InputState
2929
/// <summary>Whether there are new overrides in <see cref="CustomPressedKeys"/> or <see cref="CustomReleasedKeys"/> that haven't been applied to the previous state.</summary>
3030
private bool HasNewOverrides;
3131

32+
/// <summary>The builder which reads the game pad state and applies overrides.</summary>
33+
private readonly GamePadStateBuilder ControllerStateBuilder = new();
34+
35+
/// <summary>The builder which reads the keyboard state and applies overrides.</summary>
36+
private readonly KeyboardStateBuilder KeyboardStateBuilder = new();
37+
38+
/// <summary>The builder which reads the mouse state and applies overrides.</summary>
39+
private readonly MouseStateBuilder MouseStateBuilder = new();
40+
3241

3342
/*********
3443
** Accessors
@@ -68,10 +77,15 @@ public void TrueUpdate()
6877
{
6978
float zoomMultiplier = (1f / Game1.options.zoomLevel);
7079

80+
// get builders
81+
GamePadStateBuilder controller = this.ControllerStateBuilder;
82+
KeyboardStateBuilder keyboard = this.KeyboardStateBuilder;
83+
MouseStateBuilder mouse = this.MouseStateBuilder;
84+
7185
// get real values
72-
var controller = new GamePadStateBuilder(base.GetGamePadState());
73-
var keyboard = new KeyboardStateBuilder(base.GetKeyboardState());
74-
var mouse = new MouseStateBuilder(base.GetMouseState());
86+
controller.Reset(base.GetGamePadState());
87+
keyboard.Reset(base.GetKeyboardState());
88+
mouse.Reset(base.GetMouseState());
7589
Vector2 cursorAbsolutePos = new((mouse.X * zoomMultiplier) + Game1.viewport.X, (mouse.Y * zoomMultiplier) + Game1.viewport.Y);
7690
Vector2? playerTilePos = Context.IsPlayerFree ? Game1.player.Tile : null;
7791
HashSet<SButton> reallyDown = new(this.GetPressedButtons(keyboard, mouse, controller));
@@ -159,9 +173,13 @@ public void ApplyOverrides()
159173
{
160174
if (this.HasNewOverrides)
161175
{
162-
var controller = new GamePadStateBuilder(this.ControllerState);
163-
var keyboard = new KeyboardStateBuilder(this.KeyboardState);
164-
var mouse = new MouseStateBuilder(this.MouseState);
176+
GamePadStateBuilder controller = this.ControllerStateBuilder;
177+
KeyboardStateBuilder keyboard = this.KeyboardStateBuilder;
178+
MouseStateBuilder mouse = this.MouseStateBuilder;
179+
180+
controller.Reset(this.ControllerState);
181+
keyboard.Reset(this.KeyboardState);
182+
mouse.Reset(this.MouseState);
165183

166184
if (this.ApplyOverrides(pressed: this.CustomPressedKeys, released: this.CustomReleasedKeys, controller, keyboard, mouse))
167185
{

0 commit comments

Comments
 (0)