diff --git a/Assets/Plugins/JSL/JoyShockLibrary.cs b/Assets/Plugins/JSL/JoyShockLibrary.cs index 73acb8037..4f87bacb8 100644 --- a/Assets/Plugins/JSL/JoyShockLibrary.cs +++ b/Assets/Plugins/JSL/JoyShockLibrary.cs @@ -100,17 +100,44 @@ public static class JSL float t1Y; } + [StructLayout(LayoutKind.Sequential)] + public struct JSL_AUTO_CALIBRATION { + float confidence; + bool autoCalibrationEnabled; + bool isSteady; + } + + [StructLayout(LayoutKind.Sequential)] + public struct JSL_SETTINGS { + int gyroSpace; + int bodyColour; + int lGripColour; + int rGripColour; + int buttonColour; + int playerNumber; + int controllerType; + int splitType; + bool isCalibrating; + bool autoCalibrationEnabled; + bool isConnected; + } + public delegate void EventCallback(int handle, JOY_SHOCK_STATE state, JOY_SHOCK_STATE lastState, IMU_STATE imuState, IMU_STATE lastImuState, float deltaTime); public delegate void TouchCallback(int handle, TOUCH_STATE state, TOUCH_STATE lastState, float deltaTime); + public delegate void ConnectionCallback(int handle); + public delegate void DeconnectionCallback(int handle, bool isConnected); + [DllImport("JoyShockLibrary")] public static extern int JslConnectDevices(); [DllImport("JoyShockLibrary")] public static extern int JslGetConnectedDeviceHandles(int[] deviceHandleArray, int size); [DllImport("JoyShockLibrary")] public static extern void JslDisconnectAndDisposeAll(); + [DllImport("JoyShockLibrary")] + public static extern void JslStillConnected(int deviceId); [DllImport("JoyShockLibrary", CallingConvention = CallingConvention.Cdecl)] public static extern JOY_SHOCK_STATE JslGetSimpleState(int deviceId); @@ -121,12 +148,17 @@ public static class JSL [DllImport("JoyShockLibrary", CallingConvention = CallingConvention.Cdecl)] public static extern TOUCH_STATE JslGetTouchState(int deviceId); + [DllImport("JoyShockLibrary")] + public static extern void JslSetGyroSpace(int deviceId, int gyroSpace); + [DllImport("JoyShockLibrary")] public static extern float JslGetStickStep(int deviceId); [DllImport("JoyShockLibrary")] public static extern float JslGetTriggerStep(int deviceId); [DllImport("JoyShockLibrary")] public static extern float JslGetPollRate(int deviceId); + [DllImport("JoyShockLibrary")] + public static extern float JslGetTimeSinceLastUpdate(int deviceId); [DllImport("JoyShockLibrary")] public static extern float JslGetTouchId(int deviceId, bool secondTouch = false); @@ -147,12 +179,23 @@ public static class JSL public static extern void JslGetCalibrationOffset(int deviceId, ref float xOffset, ref float yOffset, ref float zOffset); [DllImport("JoyShockLibrary")] public static extern void JslGetCalibrationOffset(int deviceId, float xOffset, float yOffset, float zOffset); + [DllImport("JoyShockLibrary")] + public static extern JSL_AUTO_CALIBRATION JslGetAutoCalibrationStatus(int deviceId); [DllImport("JoyShockLibrary")] public static extern void JslSetCallback(EventCallback callback); [DllImport("JoyShockLibrary")] public static extern void JslSetTouchCallback(TouchCallback callback); + // this function will get called for each device when it is newly connected + [DllImport("JoyShockLibrary")] + public static extern void JslSetConnectCallback(ConnectionCallback callback); + // this function will get called for each device when it is disconnected + [DllImport("JoyShockLibrary")] + public static extern void JslSetDisconnectCallback(DeconnectionCallback callback); + // super-getter for reading a whole lot of state at once + [DllImport("JoyShockLibrary")] + public static extern JSL_SETTINGS JslGetControllerInfoAndSettings(int deviceId); [DllImport("JoyShockLibrary")] public static extern int JslGetControllerType(int deviceId); [DllImport("JoyShockLibrary")] diff --git a/Assets/Plugins/JSL/JoyShockLibrary.h b/Assets/Plugins/JSL/JoyShockLibrary.h index 93461a1f9..21b2f88cf 100644 --- a/Assets/Plugins/JSL/JoyShockLibrary.h +++ b/Assets/Plugins/JSL/JoyShockLibrary.h @@ -70,58 +70,79 @@ #define JSOFFSET_SR 19 // PS5 Player maps for the DS Player Lightbar -#define DS5_PLAYER_1 = 4 -#define DS5_PLAYER_2 = 10 -#define DS5_PLAYER_3 = 21 -#define DS5_PLAYER_4 = 27 -#define DS5_PLAYER_5 = 31 +#define DS5_PLAYER_1 4 +#define DS5_PLAYER_2 10 +#define DS5_PLAYER_3 21 +#define DS5_PLAYER_4 27 +#define DS5_PLAYER_5 31 typedef struct JOY_SHOCK_STATE { - int buttons; - float lTrigger; - float rTrigger; - float stickLX; - float stickLY; - float stickRX; - float stickRY; + int buttons = 0; + float lTrigger = 0.f; + float rTrigger = 0.f; + float stickLX = 0.f; + float stickLY = 0.f; + float stickRX = 0.f; + float stickRY = 0.f; } JOY_SHOCK_STATE; typedef struct IMU_STATE { - float accelX; - float accelY; - float accelZ; - float gyroX; - float gyroY; - float gyroZ; + float accelX = 0.f; + float accelY = 0.f; + float accelZ = 0.f; + float gyroX = 0.f; + float gyroY = 0.f; + float gyroZ = 0.f; } IMU_STATE; typedef struct MOTION_STATE { - float quatW; - float quatX; - float quatY; - float quatZ; - float accelX; - float accelY; - float accelZ; - float gravX; - float gravY; - float gravZ; + float quatW = 0.f; + float quatX = 0.f; + float quatY = 0.f; + float quatZ = 0.f; + float accelX = 0.f; + float accelY = 0.f; + float accelZ = 0.f; + float gravX = 0.f; + float gravY = 0.f; + float gravZ = 0.f; } MOTION_STATE; typedef struct TOUCH_STATE { - int t0Id; - int t1Id; - bool t0Down; - bool t1Down; - float t0X; - float t0Y; - float t1X; - float t1Y; + int t0Id = 0; + int t1Id = 0; + bool t0Down = false; + bool t1Down = false; + float t0X = 0.f; + float t0Y = 0.f; + float t1X = 0.f; + float t1Y = 0.f; } TOUCH_STATE; +typedef struct JSL_AUTO_CALIBRATION { + float confidence = 0.f; + bool autoCalibrationEnabled = false; + bool isSteady = false; +} JSL_AUTO_CALIBRATION; + +typedef struct JSL_SETTINGS { + int gyroSpace = 0; + int bodyColour = 0; + int lGripColour = 0; + int rGripColour = 0; + int buttonColour = 0; + int playerNumber = 0; + int controllerType = 0; + int splitType = 0; + bool isCalibrating = false; + bool autoCalibrationEnabled = false; + bool isConnected = false; +} JSL_SETTINGS; + extern "C" JOY_SHOCK_API int JslConnectDevices(); extern "C" JOY_SHOCK_API int JslGetConnectedDeviceHandles(int* deviceHandleArray, int size); extern "C" JOY_SHOCK_API void JslDisconnectAndDisposeAll(); +extern "C" JOY_SHOCK_API bool JslStillConnected(int deviceId); // get buttons as bits in the following order, using North South East West to name face buttons to avoid ambiguity between Xbox and Nintendo layouts: // 0x00001: up @@ -169,6 +190,15 @@ extern "C" JOY_SHOCK_API float JslGetGyroX(int deviceId); extern "C" JOY_SHOCK_API float JslGetGyroY(int deviceId); extern "C" JOY_SHOCK_API float JslGetGyroZ(int deviceId); +// get accumulated average gyro since this function was last called or last flushed values +extern "C" JOY_SHOCK_API void JslGetAndFlushAccumulatedGyro(int deviceId, float& gyroX, float& gyroY, float& gyroZ); + +// set gyro space. JslGetGyro*, JslGetAndFlushAccumulatedGyro, JslGetIMUState, and the IMU_STATEs reported in the callback functions will use one of 3 transformations: +// 0 = local space -> no transformation is done on gyro input +// 1 = world space -> gyro input is transformed based on the calculated gravity direction to account for the player's preferred controller orientation +// 2 = player space -> a simple combination of local and world space that is as adaptive as world space but is as robust as local space +extern "C" JOY_SHOCK_API void JslSetGyroSpace(int deviceId, int gyroSpace); + // get accelerometor extern "C" JOY_SHOCK_API float JslGetAccelX(int deviceId); extern "C" JOY_SHOCK_API float JslGetAccelY(int deviceId); @@ -185,6 +215,7 @@ extern "C" JOY_SHOCK_API float JslGetTouchY(int deviceId, bool secondTouch = fal extern "C" JOY_SHOCK_API float JslGetStickStep(int deviceId); extern "C" JOY_SHOCK_API float JslGetTriggerStep(int deviceId); extern "C" JOY_SHOCK_API float JslGetPollRate(int deviceId); +extern "C" JOY_SHOCK_API float JslGetTimeSinceLastUpdate(int deviceId); // calibration extern "C" JOY_SHOCK_API void JslResetContinuousCalibration(int deviceId); @@ -193,12 +224,19 @@ extern "C" JOY_SHOCK_API void JslPauseContinuousCalibration(int deviceId); extern "C" JOY_SHOCK_API void JslSetAutomaticCalibration(int deviceId, bool enabled); extern "C" JOY_SHOCK_API void JslGetCalibrationOffset(int deviceId, float& xOffset, float& yOffset, float& zOffset); extern "C" JOY_SHOCK_API void JslSetCalibrationOffset(int deviceId, float xOffset, float yOffset, float zOffset); +extern "C" JOY_SHOCK_API JSL_AUTO_CALIBRATION JslGetAutoCalibrationStatus(int deviceId); // this function will get called for each input event from each controller extern "C" JOY_SHOCK_API void JslSetCallback(void(*callback)(int, JOY_SHOCK_STATE, JOY_SHOCK_STATE, IMU_STATE, IMU_STATE, float)); // this function will get called for each input event, even if touch data didn't update extern "C" JOY_SHOCK_API void JslSetTouchCallback(void(*callback)(int, TOUCH_STATE, TOUCH_STATE, float)); +// this function will get called for each device when it is newly connected +extern "C" JOY_SHOCK_API void JslSetConnectCallback(void(*callback)(int)); +// this function will get called for each device when it is disconnected +extern "C" JOY_SHOCK_API void JslSetDisconnectCallback(void(*callback)(int, bool)); +// super-getter for reading a whole lot of state at once +extern "C" JOY_SHOCK_API JSL_SETTINGS JslGetControllerInfoAndSettings(int deviceId); // what kind of controller is this? extern "C" JOY_SHOCK_API int JslGetControllerType(int deviceId); // is this a left, right, or full controller? diff --git a/Assets/Plugins/JSL/x64/JoyShockLibrary.dll b/Assets/Plugins/JSL/x64/JoyShockLibrary.dll index 31c2d9910..fa0adc20e 100644 Binary files a/Assets/Plugins/JSL/x64/JoyShockLibrary.dll and b/Assets/Plugins/JSL/x64/JoyShockLibrary.dll differ diff --git a/Assets/Plugins/JSL/x64/libJoyShockLibrary.dylib b/Assets/Plugins/JSL/x64/libJoyShockLibrary.dylib index 1b1754375..d0b7327c9 100755 Binary files a/Assets/Plugins/JSL/x64/libJoyShockLibrary.dylib and b/Assets/Plugins/JSL/x64/libJoyShockLibrary.dylib differ diff --git a/Assets/Plugins/JSL/x64/libJoyShockLibrary.so b/Assets/Plugins/JSL/x64/libJoyShockLibrary.so index e8d0a5152..1f76c413e 100644 Binary files a/Assets/Plugins/JSL/x64/libJoyShockLibrary.so and b/Assets/Plugins/JSL/x64/libJoyShockLibrary.so differ diff --git a/Assets/Scripts/GlobalGameManager.cs b/Assets/Scripts/GlobalGameManager.cs index c39284c60..c3b95edcc 100644 --- a/Assets/Scripts/GlobalGameManager.cs +++ b/Assets/Scripts/GlobalGameManager.cs @@ -371,7 +371,7 @@ namespace HeavenStudio void OnApplicationQuit() { Debug.Log("Disconnecting JoyShocks..."); - PlayerInput.DisconnectJoyshocks(); + PlayerInput.CleanUp(); Debug.Log("Clearing RIQ Cache..."); Jukebox.RiqFileHandler.ClearCache(); } diff --git a/Assets/Scripts/InputSystem/ControllerTypes/InputJoyshock.cs b/Assets/Scripts/InputSystem/ControllerTypes/InputJoyshock.cs index 09380350d..4d29a1b09 100644 --- a/Assets/Scripts/InputSystem/ControllerTypes/InputJoyshock.cs +++ b/Assets/Scripts/InputSystem/ControllerTypes/InputJoyshock.cs @@ -8,6 +8,53 @@ using static JSL; namespace HeavenStudio.InputSystem { + public static class InputJoyshockInitializer + { + [LoadOrder(1)] + public static InputController[] Initialize() + { + PlayerInput.PlayerInputCleanUp += DisposeJoyshocks; + + InputController[] controllers; + int jslDevicesFound = 0; + int jslDevicesConnected = 0; + int[] jslDeviceHandles; + + jslDevicesFound = JslConnectDevices(); + if (jslDevicesFound > 0) + { + jslDeviceHandles = new int[jslDevicesFound]; + jslDevicesConnected = JslGetConnectedDeviceHandles(jslDeviceHandles, jslDevicesFound); + if (jslDevicesConnected < jslDevicesFound) + { + Debug.Log("Found " + jslDevicesFound + " JoyShocks, but only " + jslDevicesConnected + " are connected."); + } + else + { + Debug.Log("Found " + jslDevicesFound + " JoyShocks."); + Debug.Log("Connected " + jslDevicesConnected + " JoyShocks."); + } + + controllers = new InputController[jslDevicesConnected]; + foreach (int i in jslDeviceHandles) + { + Debug.Log("Setting up JoyShock: ( Handle " + i + ", type " + JslGetControllerType(i) + " )"); + InputJoyshock joyshock = new InputJoyshock(i); + joyshock.InitializeController(); + controllers[i] = joyshock; + } + return controllers; + } + Debug.Log("No JoyShocks found."); + return null; + } + + public static void DisposeJoyshocks() + { + JslDisconnectAndDisposeAll(); + } + } + public class InputJoyshock : InputController { static string[] joyShockNames = diff --git a/Assets/Scripts/InputSystem/ControllerTypes/InputKeyboard.cs b/Assets/Scripts/InputSystem/ControllerTypes/InputKeyboard.cs index d5762d78f..1f088b274 100644 --- a/Assets/Scripts/InputSystem/ControllerTypes/InputKeyboard.cs +++ b/Assets/Scripts/InputSystem/ControllerTypes/InputKeyboard.cs @@ -6,6 +6,18 @@ using static JSL; namespace HeavenStudio.InputSystem { + public static class InputKeyboardInitializer + { + [LoadOrder(0)] + public static InputController[] Initialize() + { + InputKeyboard keyboard = new InputKeyboard(); + keyboard.SetPlayer(1); + keyboard.InitializeController(); + return new InputController[] { keyboard }; + } + } + public class InputKeyboard : InputController { static KeyCode[] keyCodes = (KeyCode[]) System.Enum.GetValues(typeof(UnityEngine.KeyCode)); diff --git a/Assets/Scripts/InputSystem/InputController.cs b/Assets/Scripts/InputSystem/InputController.cs index 7f63ebc2f..a7fc62c0c 100644 --- a/Assets/Scripts/InputSystem/InputController.cs +++ b/Assets/Scripts/InputSystem/InputController.cs @@ -97,7 +97,8 @@ namespace HeavenStudio.InputSystem { Pad, Baton, - Touch + Touch, + Move } //buttons used in Heaven Studio gameplay (Pad Style) @@ -123,8 +124,8 @@ namespace HeavenStudio.InputSystem BatonE = 1, // | BatonW = 2, // | BatonN = 3, //-- - BatonA = 4, // < ...map to this, but are directional - BatonB = 5, // should never be used alone + BatonFace = 4, // < ...map to this, but are directional + BatonTrigger = 5, // should never be used alone Baton1 = 6, Baton2 = 7, BatonPause = 8, @@ -140,6 +141,8 @@ namespace HeavenStudio.InputSystem TouchButtonL = 4, TouchButtonR = 4, } + + // FUTURE: Move Style needs to be implemented per-game (maybe implement checks for common actions?) protected int? playerNum; protected int directionStateCurrent = 0; diff --git a/Assets/Scripts/InputSystem/PlayerInput.cs b/Assets/Scripts/InputSystem/PlayerInput.cs index 27c15a228..8a349fe3e 100644 --- a/Assets/Scripts/InputSystem/PlayerInput.cs +++ b/Assets/Scripts/InputSystem/PlayerInput.cs @@ -1,3 +1,7 @@ +using System; +using System.Linq; +using System.Reflection; +using System.IO; using System.Collections; using System.Collections.Generic; using UnityEngine; @@ -5,6 +9,16 @@ using HeavenStudio.InputSystem; using static JSL; +namespace HeavenStudio.InputSystem +{ + public class LoadOrder : Attribute { + public int Order { get; set; } + public LoadOrder(int order) { + Order = order; + } + } +} + namespace HeavenStudio { public class PlayerInput @@ -15,62 +29,40 @@ namespace HeavenStudio public const int DOWN = 2; public const int LEFT = 3; - /////////////////////////////// - ////TEMPORARY JSL FUNCTIONS//// - /////////////////////////////// - - static int jslDevicesFound = 0; - static int jslDevicesConnected = 0; - static int[] jslDeviceHandles; - static List inputDevices; - + + public delegate InputController[] InputControllerInitializer(); + + public delegate void InputControllerDispose(); + public static event InputControllerDispose PlayerInputCleanUp; + + static List loadRunners; + static void BuildLoadRunnerList() { + loadRunners = System.Reflection.Assembly.GetExecutingAssembly() + .GetTypes() + .Where(x => x.Namespace == "HeavenStudio.InputSystem.Loaders" && x.GetMethod("Initialize", BindingFlags.Public | BindingFlags.Static) != null) + .Select(t => (InputControllerInitializer) Delegate.CreateDelegate( + typeof(InputControllerInitializer), + null, + t.GetMethod("Initialize", BindingFlags.Public | BindingFlags.Static), + false + )) + .ToList(); + + loadRunners.Sort((x, y) => x.Method.GetCustomAttribute().Order.CompareTo(y.Method.GetCustomAttribute().Order)); + } + public static int InitInputControllers() { inputDevices = new List(); - //Keyboard setup - InputKeyboard keyboard = new InputKeyboard(); - keyboard.SetPlayer(1); - keyboard.InitializeController(); - inputDevices.Add(keyboard); - //end Keyboard setup - - //JoyShock setup - Debug.Log("Flushing possible JoyShocks..."); - DisconnectJoyshocks(); - - jslDevicesFound = JslConnectDevices(); - if (jslDevicesFound > 0) - { - jslDeviceHandles = new int[jslDevicesFound]; - jslDevicesConnected = JslGetConnectedDeviceHandles(jslDeviceHandles, jslDevicesFound); - if (jslDevicesConnected < jslDevicesFound) - { - Debug.Log("Found " + jslDevicesFound + " JoyShocks, but only " + jslDevicesConnected + " are connected."); - } - else - { - Debug.Log("Found " + jslDevicesFound + " JoyShocks."); - Debug.Log("Connected " + jslDevicesConnected + " JoyShocks."); - } - - foreach (int i in jslDeviceHandles) - { - Debug.Log("Setting up JoyShock: ( Handle " + i + ", type " + JslGetControllerType(i) + " )"); - InputJoyshock joyshock = new InputJoyshock(i); - joyshock.InitializeController(); - joyshock.SetPlayer(inputDevices.Count + 1); - inputDevices.Add(joyshock); + + BuildLoadRunnerList(); + foreach (InputControllerInitializer runner in loadRunners) { + InputController[] controllers = runner(); + if (controllers != null) { + inputDevices.AddRange(controllers); } } - else - { - Debug.Log("No JoyShocks found."); - } - //end JoyShock setup - - //TODO: XInput setup (boo) - //end XInput setup return inputDevices.Count; } @@ -159,28 +151,15 @@ namespace HeavenStudio } } - public static void DisconnectJoyshocks() + public static void CleanUp() { - if (jslDeviceHandles != null && jslDevicesConnected > 0 && jslDeviceHandles.Length > 0) - { - foreach (InputController i in inputDevices) - { - if (typeof(InputJoyshock) == i.GetType()) - { - InputJoyshock joy = (InputJoyshock)i; - joy.DisconnectJoyshock(); - } - } - } - JslDisconnectAndDisposeAll(); - jslDevicesFound = 0; - jslDevicesConnected = 0; + PlayerInputCleanUp?.Invoke(); } // The autoplay isn't activated AND // The song is actually playing AND // The GameManager allows you to Input - public static bool playerHasControl() + public static bool PlayerHasControl() { return !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput; } @@ -214,19 +193,19 @@ namespace HeavenStudio public static bool AltPressed() { bool down = GetInputController(1).GetButtonDown((int) InputController.ButtonsPad.PadS); - return down && playerHasControl(); + return down && PlayerHasControl(); } public static bool AltPressedUp() { bool up = GetInputController(1).GetButtonUp((int) InputController.ButtonsPad.PadS); - return up && playerHasControl(); + return up && PlayerHasControl(); } public static bool AltPressing() { bool pressing = GetInputController(1).GetButton((int) InputController.ButtonsPad.PadS); - return pressing && playerHasControl(); + return pressing && PlayerHasControl(); } //Directions @@ -238,7 +217,7 @@ namespace HeavenStudio || c.GetHatDirectionDown((InputController.InputDirection) DOWN) || c.GetHatDirectionDown((InputController.InputDirection) LEFT) || c.GetHatDirectionDown((InputController.InputDirection) RIGHT) - ) && playerHasControl(); + ) && PlayerHasControl(); } @@ -249,7 +228,7 @@ namespace HeavenStudio || c.GetHatDirectionUp((InputController.InputDirection) DOWN) || c.GetHatDirectionUp((InputController.InputDirection) LEFT) || c.GetHatDirectionUp((InputController.InputDirection) RIGHT) - ) && playerHasControl(); + ) && PlayerHasControl(); } @@ -260,23 +239,23 @@ namespace HeavenStudio || c.GetHatDirection((InputController.InputDirection) DOWN) || c.GetHatDirection((InputController.InputDirection) LEFT) || c.GetHatDirection((InputController.InputDirection) RIGHT) - ) && playerHasControl(); + ) && PlayerHasControl(); } public static bool GetSpecificDirection(int direction) { - return GetInputController(1).GetHatDirection((InputController.InputDirection) direction) && playerHasControl(); + return GetInputController(1).GetHatDirection((InputController.InputDirection) direction) && PlayerHasControl(); } public static bool GetSpecificDirectionDown(int direction) { - return GetInputController(1).GetHatDirectionDown((InputController.InputDirection) direction) && playerHasControl(); + return GetInputController(1).GetHatDirectionDown((InputController.InputDirection) direction) && PlayerHasControl(); } public static bool GetSpecificDirectionUp(int direction) { - return GetInputController(1).GetHatDirectionUp((InputController.InputDirection) direction) && playerHasControl(); + return GetInputController(1).GetHatDirectionUp((InputController.InputDirection) direction) && PlayerHasControl(); } } }