diff --git a/Gaming/Game.cs b/Gaming/Game.cs index 12331ff..b9c6f0f 100644 --- a/Gaming/Game.cs +++ b/Gaming/Game.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; - using System.Runtime.CompilerServices; using System.Runtime.InteropServices; public abstract class Game(bool verbose = false) : Device, IDisposable @@ -19,7 +18,6 @@ private ulong _frameStartTime; private ulong _frameEndTime; private readonly SortedDictionary _gameControllers = []; - private readonly Dictionary _mappedControllers = []; private bool _disposed; protected ScopedHandle Window { get; } = new(SDL.DestroyWindow); @@ -68,8 +66,8 @@ this._vsync = this.UseVSYNC; if (this._vsync) { - float framesPerSecond = this.FramesPerSecond; - float? refreshRate = currentDisplayMode?.RefreshRate; + var framesPerSecond = this.FramesPerSecond; + var refreshRate = currentDisplayMode?.RefreshRate; Debug.Assert(refreshRate.HasValue, "refresh rate is unavailable"); this._vsync = Math.Abs(framesPerSecond - refreshRate.Value) < 0.001; if (this._vsync) @@ -160,11 +158,11 @@ case SDL.EventType.GamepadButtonUp: _ = this.HandleGamepadButtonUp(e.GButton); break; - case SDL.EventType.JoystickAdded: - this.AddJoystick(e); + case SDL.EventType.GamepadAdded: + this.AddGampad(e); break; - case SDL.EventType.JoystickRemoved: - this.RemoveJoystick(e); + case SDL.EventType.GamepadRemoved: + this.RemoveGamepad(e); break; } } @@ -208,26 +206,23 @@ SDL.LogWarn(SDL.LogCategory.Render, "Running slowly"); } - protected virtual void RemoveJoystick(SDL.Event e) + protected virtual void RemoveGamepad(SDL.Event e) { var which = e.JDevice.Which; var found = this._gameControllers.TryGetValue(which, out var gameController); Debug.Assert(found); Debug.Assert(gameController != null, "controller is not null"); - _ = this._mappedControllers.Remove(gameController.GetJoystickId()); _ = this._gameControllers.Remove(which); SDL.LogInfo(SDL.LogCategory.Input, $"Joystick device {which} removed ({this._gameControllers.Count} controllers available)"); } - protected virtual void AddJoystick(SDL.Event e) + protected virtual void AddGampad(SDL.Event e) { var which = e.JDevice.Which; var found = this._gameControllers.ContainsKey(which); Debug.Assert(!found); GameController gameController = new(which); - uint joystickId = gameController.GetJoystickId(); this._gameControllers[which] = gameController; - this._mappedControllers[joystickId] = which; SDL.LogInfo(SDL.LogCategory.Input, $"Joystick device {which} address ({this._gameControllers.Count} controllers available)"); } @@ -239,13 +234,6 @@ return gameController; } - public uint MappedController(uint which) - { - var success = this._mappedControllers.TryGetValue(which, out var id); - Wrapper.MaybeThrowException(success, "Unknown joystick"); - return id; - } - public uint ChooseControllerIndex(int who) { int count = this._gameControllers.Count; diff --git a/Gaming/GameController.cs b/Gaming/GameController.cs index b79cdab..bb46d58 100644 --- a/Gaming/GameController.cs +++ b/Gaming/GameController.cs @@ -8,8 +8,6 @@ { private readonly uint _index; private readonly ScopedHandle _gamepad = new(SDL.CloseGamepad); - private readonly ScopedHandle _haptic = new(SDL.CloseHaptic); - private bool _hapticRumbleSupported; private bool _disposed; public GameController(uint index) @@ -20,66 +18,20 @@ private void Open() { - var joysticks = SDL.GetJoysticks(out var count); - Wrapper.MaybeThrowException(joysticks != null, "Unable to obtain joystick information"); - Debug.Assert(count > 0, "count > 0"); - Debug.Assert(this._index < count, "this._index < count"); - if (SDL.IsGamepad(this._index)) - { - this._gamepad.Handle = SDL.OpenGamepad(this._index); - Wrapper.MaybeThrowException(this._gamepad, "Unable to open gamepad"); - this.OpenHaptic(); - var gamepadName = SDL.GetGamepadName(this._gamepad); - Wrapper.MaybeThrowException(gamepadName != null, "Unable to obtain gamepad name"); - SDL.LogInfo(SDL.LogCategory.Input, "Game controller name: " + gamepadName); - } - else - { - SDL.LogWarn(SDL.LogCategory.Input, "Joystick is not a game controller"); - } - } - - private void Close() - { - this._gamepad.Dispose(); - this.CloseHaptic(); - } - - private void OpenHaptic() - { - this._haptic.Handle = SDL.OpenHaptic((int)this._index); // XXXX Possible SDL3-cs int cast bug - Wrapper.MaybeThrowException(this._haptic, "Unable to open haptic gamepad"); - Wrapper.MaybeThrowException(SDL.InitHapticRumble(this._haptic), "Unable to initialise haptic gamepad"); - this._hapticRumbleSupported = SDL.HapticRumbleSupported(this._haptic); - } - - private void CloseHaptic() - { - this._haptic.Dispose(); - this._hapticRumbleSupported = false; + Debug.Assert(SDL.IsGamepad(this._index)); + this._gamepad.Handle = SDL.OpenGamepad(this._index); + Wrapper.MaybeThrowException(this._gamepad, "Unable to open gamepad"); + var gamepadName = SDL.GetGamepadName(this._gamepad); + Wrapper.MaybeThrowException(gamepadName != null, "Unable to obtain gamepad name"); + SDL.LogInfo(SDL.LogCategory.Input, "Game controller name: " + gamepadName); } public void StartRumble() { - if (this._hapticRumbleSupported && !SDL.PlayHapticRumble(this._haptic, 1f, 1000U)) - SDL.LogWarn(SDL.LogCategory.Input, "Unable to start haptic rumble: " + SDL.GetError()); + var success = SDL.RumbleGamepad(this._gamepad, 0xFFFF, 0x0000, 1000); + Wrapper.MaybeThrowException(success, "Unable to start haptic rumble"); } - public void StopRumble() - { - if (this._hapticRumbleSupported && !SDL.StopHapticRumble(this._haptic)) - SDL.LogWarn(SDL.LogCategory.Input, "Unable to stop haptic rumble: " + SDL.GetError()); - } - - public static uint BuildJoystickId(IntPtr gamepad) - { - var gamepadJoystick = SDL.GetGamepadJoystick(gamepad); - Wrapper.MaybeThrowException(gamepadJoystick, "Unable to obtain joystick from gamepad"); - return SDL.GetJoystickID(gamepadJoystick); - } - - public uint GetJoystickId() => GameController.BuildJoystickId((IntPtr) this._gamepad); - public void Dispose() { this.Dispose(true); @@ -92,7 +44,7 @@ { if (disposing) { - this.Close(); + this._gamepad.Dispose(); } this._disposed = true; } diff --git a/Gaming/Gaming.csproj b/Gaming/Gaming.csproj index dc8d520..d82a378 100644 --- a/Gaming/Gaming.csproj +++ b/Gaming/Gaming.csproj @@ -5,6 +5,7 @@ enable enable latest-all + True diff --git a/Gaming/ScopedHandle.cs b/Gaming/ScopedHandle.cs index 35dbbe9..846dc58 100644 --- a/Gaming/ScopedHandle.cs +++ b/Gaming/ScopedHandle.cs @@ -9,6 +9,7 @@ private readonly Action _deleter = deleter ?? throw new ArgumentNullException(nameof(deleter)); public override bool IsInvalid => this.handle == IntPtr.Zero; + public bool IsValid => !this.IsInvalid; public IntPtr Handle { @@ -18,13 +19,14 @@ protected override bool ReleaseHandle() { - if (!this.IsInvalid) + if (this.IsValid) this._deleter(this.handle); return true; } public static nint FromScopedHandle(ScopedHandle h) { + // But it can still be invalid (i.e. h.IsInvalid == true) Debug.Assert(h is not null); return h.DangerousGetHandle(); }