mirror of
https://github.com/Pathoschild/SMAPI.git
synced 2026-10-12 02:08:51 +00:00
reduce allocations when applying input overrides
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
@@ -21,7 +22,7 @@ internal class GamePadStateBuilder : IInputStateBuilder<GamePadStateBuilder, Gam
|
||||
private GamePadState? State;
|
||||
|
||||
/// <summary>The current button states.</summary>
|
||||
private readonly Dictionary<SButton, ButtonState> ButtonStates = [];
|
||||
private readonly Dictionary<Buttons, ButtonState> ButtonStates = [];
|
||||
|
||||
/// <summary>The left trigger value.</summary>
|
||||
private float LeftTrigger;
|
||||
@@ -53,21 +54,21 @@ internal class GamePadStateBuilder : IInputStateBuilder<GamePadStateBuilder, Gam
|
||||
|
||||
var states = this.ButtonStates;
|
||||
states.Clear();
|
||||
states[SButton.DPadUp] = pad.Up;
|
||||
states[SButton.DPadDown] = pad.Down;
|
||||
states[SButton.DPadLeft] = pad.Left;
|
||||
states[SButton.DPadRight] = pad.Right;
|
||||
states[SButton.ControllerA] = buttons.A;
|
||||
states[SButton.ControllerB] = buttons.B;
|
||||
states[SButton.ControllerX] = buttons.X;
|
||||
states[SButton.ControllerY] = buttons.Y;
|
||||
states[SButton.LeftStick] = buttons.LeftStick;
|
||||
states[SButton.RightStick] = buttons.RightStick;
|
||||
states[SButton.LeftShoulder] = buttons.LeftShoulder;
|
||||
states[SButton.RightShoulder] = buttons.RightShoulder;
|
||||
states[SButton.ControllerBack] = buttons.Back;
|
||||
states[SButton.ControllerStart] = buttons.Start;
|
||||
states[SButton.BigButton] = buttons.BigButton;
|
||||
states[Buttons.DPadUp] = pad.Up;
|
||||
states[Buttons.DPadDown] = pad.Down;
|
||||
states[Buttons.DPadLeft] = pad.Left;
|
||||
states[Buttons.DPadRight] = pad.Right;
|
||||
states[Buttons.A] = buttons.A;
|
||||
states[Buttons.B] = buttons.B;
|
||||
states[Buttons.X] = buttons.X;
|
||||
states[Buttons.Y] = buttons.Y;
|
||||
states[Buttons.LeftStick] = buttons.LeftStick;
|
||||
states[Buttons.RightStick] = buttons.RightStick;
|
||||
states[Buttons.LeftShoulder] = buttons.LeftShoulder;
|
||||
states[Buttons.RightShoulder] = buttons.RightShoulder;
|
||||
states[Buttons.Back] = buttons.Back;
|
||||
states[Buttons.Start] = buttons.Start;
|
||||
states[Buttons.BigButton] = buttons.BigButton;
|
||||
|
||||
this.LeftTrigger = triggers.Left;
|
||||
this.RightTrigger = triggers.Right;
|
||||
@@ -85,63 +86,81 @@ internal class GamePadStateBuilder : IInputStateBuilder<GamePadStateBuilder, Gam
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public GamePadStateBuilder OverrideButtons(IDictionary<SButton, SButtonState> overrides)
|
||||
/// <summary>Override the state for a button.</summary>
|
||||
/// <param name="button">The button to override.</param>
|
||||
/// <param name="state">The new state to set.</param>
|
||||
public void OverrideButton(Buttons button, SButtonState state)
|
||||
{
|
||||
foreach (var pair in overrides)
|
||||
bool isDown = state.IsDown();
|
||||
bool changed = false;
|
||||
|
||||
switch (button)
|
||||
{
|
||||
bool changed = true;
|
||||
// left thumbstick
|
||||
case Buttons.LeftThumbstickUp:
|
||||
changed = Set(ref this.LeftStickPos.Y, isDown ? 1 : 0);
|
||||
break;
|
||||
case Buttons.LeftThumbstickDown:
|
||||
changed = Set(ref this.LeftStickPos.Y, isDown ? -1 : 0);
|
||||
break;
|
||||
case Buttons.LeftThumbstickLeft:
|
||||
changed = Set(ref this.LeftStickPos.X, isDown ? -1 : 0);
|
||||
break;
|
||||
case Buttons.LeftThumbstickRight:
|
||||
changed = Set(ref this.LeftStickPos.X, isDown ? 1 : 0);
|
||||
break;
|
||||
|
||||
bool isDown = pair.Value.IsDown();
|
||||
switch (pair.Key)
|
||||
{
|
||||
// left thumbstick
|
||||
case SButton.LeftThumbstickUp:
|
||||
this.LeftStickPos.Y = isDown ? 1 : 0;
|
||||
break;
|
||||
case SButton.LeftThumbstickDown:
|
||||
this.LeftStickPos.Y = isDown ? -1 : 0;
|
||||
break;
|
||||
case SButton.LeftThumbstickLeft:
|
||||
this.LeftStickPos.X = isDown ? -1 : 0;
|
||||
break;
|
||||
case SButton.LeftThumbstickRight:
|
||||
this.LeftStickPos.X = isDown ? 1 : 0;
|
||||
break;
|
||||
// right thumbstick
|
||||
case Buttons.RightThumbstickUp:
|
||||
changed = Set(ref this.RightStickPos.Y, isDown ? 1 : 0);
|
||||
break;
|
||||
case Buttons.RightThumbstickDown:
|
||||
changed = Set(ref this.RightStickPos.Y, isDown ? -1 : 0);
|
||||
break;
|
||||
case Buttons.RightThumbstickLeft:
|
||||
changed = Set(ref this.RightStickPos.X, isDown ? -1 : 0);
|
||||
break;
|
||||
case Buttons.RightThumbstickRight:
|
||||
changed = Set(ref this.RightStickPos.X, isDown ? 1 : 0);
|
||||
break;
|
||||
|
||||
// right thumbstick
|
||||
case SButton.RightThumbstickUp:
|
||||
this.RightStickPos.Y = isDown ? 1 : 0;
|
||||
break;
|
||||
case SButton.RightThumbstickDown:
|
||||
this.RightStickPos.Y = isDown ? -1 : 0;
|
||||
break;
|
||||
case SButton.RightThumbstickLeft:
|
||||
this.RightStickPos.X = isDown ? -1 : 0;
|
||||
break;
|
||||
case SButton.RightThumbstickRight:
|
||||
this.RightStickPos.X = isDown ? 1 : 0;
|
||||
break;
|
||||
// triggers
|
||||
case Buttons.LeftTrigger:
|
||||
changed = Set(ref this.LeftTrigger, isDown ? 1 : 0);
|
||||
break;
|
||||
case Buttons.RightTrigger:
|
||||
changed = Set(ref this.RightTrigger, isDown ? 1 : 0);
|
||||
break;
|
||||
|
||||
// triggers
|
||||
case SButton.LeftTrigger:
|
||||
this.LeftTrigger = isDown ? 1 : 0;
|
||||
break;
|
||||
case SButton.RightTrigger:
|
||||
this.RightTrigger = isDown ? 1 : 0;
|
||||
break;
|
||||
// buttons
|
||||
default:
|
||||
{
|
||||
ButtonState newState = isDown ? ButtonState.Pressed : ButtonState.Released;
|
||||
|
||||
// buttons
|
||||
default:
|
||||
this.ButtonStates[pair.Key] = isDown ? ButtonState.Pressed : ButtonState.Released;
|
||||
break;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
this.State = null;
|
||||
if (!this.ButtonStates.TryGetValue(button, out ButtonState oldState) || newState != oldState)
|
||||
{
|
||||
this.ButtonStates[button] = newState;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return this;
|
||||
if (changed)
|
||||
this.State = null;
|
||||
return;
|
||||
|
||||
[SuppressMessage("ReSharper", "CompareOfFloatsByEqualityOperator", Justification = "Floating points not an issue for the specific values we're checking.")]
|
||||
static bool Set(ref float field, int newValue)
|
||||
{
|
||||
if (field != newValue)
|
||||
{
|
||||
field = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -200,9 +219,9 @@ internal class GamePadStateBuilder : IInputStateBuilder<GamePadStateBuilder, Gam
|
||||
/// <summary>Get the pressed gamepad buttons.</summary>
|
||||
private IEnumerable<Buttons> GetPressedGamePadButtons()
|
||||
{
|
||||
foreach (var pair in this.ButtonStates)
|
||||
foreach ((Buttons button, ButtonState state) in this.ButtonStates)
|
||||
{
|
||||
if (pair.Value == ButtonState.Pressed && pair.Key.TryGetController(out Buttons button))
|
||||
if (state == ButtonState.Pressed)
|
||||
yield return button;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,6 @@ internal interface IInputStateBuilder<out THandler, TState>
|
||||
/// <param name="state">The initial state before any overrides are applied.</param>
|
||||
void Reset(TState state);
|
||||
|
||||
/// <summary>Override the states for a set of buttons.</summary>
|
||||
/// <param name="overrides">The button state overrides.</param>
|
||||
THandler OverrideButtons(IDictionary<SButton, SButtonState> overrides);
|
||||
|
||||
/// <summary>Fill a set with the currently pressed buttons.</summary>
|
||||
/// <param name="set">The set to populate with the pressed buttons.</param>
|
||||
void FillPressedButtons(HashSet<SButton> set);
|
||||
|
||||
@@ -30,23 +30,17 @@ internal class KeyboardStateBuilder : IInputStateBuilder<KeyboardStateBuilder, K
|
||||
this.PressedButtons.Add(button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public KeyboardStateBuilder OverrideButtons(IDictionary<SButton, SButtonState> overrides)
|
||||
/// <summary>Override the state for a key.</summary>
|
||||
/// <param name="key">The key to override.</param>
|
||||
/// <param name="state">The new state to set.</param>
|
||||
public void OverrideButton(Keys key, SButtonState state)
|
||||
{
|
||||
foreach (var pair in overrides)
|
||||
{
|
||||
if (pair.Key.TryGetKeyboard(out Keys key))
|
||||
{
|
||||
this.State = null;
|
||||
bool changed = state.IsDown()
|
||||
? this.PressedButtons.Add(key)
|
||||
: this.PressedButtons.Remove(key);
|
||||
|
||||
if (pair.Value.IsDown())
|
||||
this.PressedButtons.Add(key);
|
||||
else
|
||||
this.PressedButtons.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
if (changed)
|
||||
this.State = null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -50,19 +50,20 @@ internal class MouseStateBuilder : IInputStateBuilder<MouseStateBuilder, MouseSt
|
||||
this.ScrollWheelValue = state.ScrollWheelValue;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public MouseStateBuilder OverrideButtons(IDictionary<SButton, SButtonState> overrides)
|
||||
/// <summary>Override the state for a button.</summary>
|
||||
/// <param name="button">The button to override.</param>
|
||||
/// <param name="state">The new state to set.</param>
|
||||
public void OverrideButton(SButton button, SButtonState state)
|
||||
{
|
||||
foreach (var pair in overrides)
|
||||
{
|
||||
if (this.ButtonStates.ContainsKey(pair.Key))
|
||||
{
|
||||
this.State = null;
|
||||
this.ButtonStates[pair.Key] = pair.Value.IsDown() ? ButtonState.Pressed : ButtonState.Released;
|
||||
}
|
||||
}
|
||||
ButtonState newState = state.IsDown()
|
||||
? ButtonState.Pressed
|
||||
: ButtonState.Released;
|
||||
|
||||
return this;
|
||||
if (this.ButtonStates.TryGetValue(button, out ButtonState oldState) && oldState != newState)
|
||||
{
|
||||
this.State = null;
|
||||
this.ButtonStates[button] = newState;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -251,34 +251,24 @@ internal sealed class SInputState : InputState
|
||||
if (pressed.Count == 0 && released.Count == 0)
|
||||
return false;
|
||||
|
||||
// group keys by type
|
||||
IDictionary<SButton, SButtonState> keyboardOverrides = new Dictionary<SButton, SButtonState>();
|
||||
IDictionary<SButton, SButtonState> controllerOverrides = new Dictionary<SButton, SButtonState>();
|
||||
IDictionary<SButton, SButtonState> mouseOverrides = new Dictionary<SButton, SButtonState>();
|
||||
foreach (SButton button in pressed.Concat(released))
|
||||
{
|
||||
SButtonState newState = SInputState.DeriveState(
|
||||
oldState: this.GetState(button),
|
||||
isDown: pressed.Contains(button)
|
||||
);
|
||||
|
||||
if (button is SButton.MouseLeft or SButton.MouseMiddle or SButton.MouseRight or SButton.MouseX1 or SButton.MouseX2)
|
||||
mouseOverrides[button] = newState;
|
||||
else if (button.TryGetKeyboard(out Keys _))
|
||||
keyboardOverrides[button] = newState;
|
||||
else if (button.TryGetController(out Buttons _))
|
||||
controllerOverrides[button] = newState;
|
||||
}
|
||||
|
||||
// override states
|
||||
if (keyboardOverrides.Count > 0)
|
||||
keyboard.OverrideButtons(keyboardOverrides);
|
||||
if (controllerOverrides.Count > 0)
|
||||
controller.OverrideButtons(controllerOverrides);
|
||||
if (mouseOverrides.Count > 0)
|
||||
mouse.OverrideButtons(mouseOverrides);
|
||||
foreach (SButton button in pressed)
|
||||
Apply(button, this.GetState(button), isDown: true, controller, keyboard, mouse);
|
||||
foreach (SButton button in released)
|
||||
Apply(button, this.GetState(button), isDown: pressed.Contains(button), controller, keyboard, mouse);
|
||||
|
||||
return true;
|
||||
|
||||
static void Apply(SButton button, SButtonState oldState, bool isDown, GamePadStateBuilder controller, KeyboardStateBuilder keyboard, MouseStateBuilder mouse)
|
||||
{
|
||||
SButtonState newState = SInputState.DeriveState(oldState, isDown);
|
||||
|
||||
if (button is SButton.MouseLeft or SButton.MouseMiddle or SButton.MouseRight or SButton.MouseX1 or SButton.MouseX2)
|
||||
mouse.OverrideButton(button, newState);
|
||||
else if (button.TryGetKeyboard(out Keys key))
|
||||
keyboard.OverrideButton(key, newState);
|
||||
else if (button.TryGetController(out Buttons controllerButton))
|
||||
controller.OverrideButton(controllerButton, newState);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Update active button states based on the currently pressed buttons.</summary>
|
||||
|
||||
Reference in New Issue
Block a user