heavy rework of our input system

- implement the InputController abstract class, an adapter class for any HID interface to use common controller methods relevant to Heaven Studio
- implement InputKeyboard and InputJoyshock classes, for keyboard input and controllers driven by JoyShockLibrary respectively
- add Linux compile of JoyShockLibrary
This commit is contained in:
minenice55 2022-07-23 20:36:10 -04:00
parent 6699e7d98b
commit ecbe84074f
19 changed files with 1009 additions and 337 deletions

View file

@ -43,11 +43,13 @@ public static class JSL
public const int SplitFull = 3;
// PS5 Player maps for the DS Player Lightbar
public const int DS5P1 = 4;
public const int DS5P2 = 10;
public const int DS5P3 = 21;
public const int DS5P4 = 27;
public const int DS5P5 = 31;
public static readonly int[] DualSensePlayerMask = {
4,
10,
21,
27,
31
};
[StructLayout(LayoutKind.Sequential)]
public struct JOY_SHOCK_STATE
@ -100,6 +102,8 @@ public static class JSL
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);
[DllImport("JoyShockLibrary")]
public static extern int JslConnectDevices();
@ -147,7 +151,7 @@ public static class JSL
[DllImport("JoyShockLibrary")]
public static extern void JslSetCallback(EventCallback callback);
[DllImport("JoyShockLibrary")]
public static extern void JslSetTouchCallback(EventCallback callback);
public static extern void JslSetTouchCallback(TouchCallback callback);
[DllImport("JoyShockLibrary")]
public static extern int JslGetControllerType(int deviceId);

Binary file not shown.

View file

@ -0,0 +1,27 @@
fileFormatVersion: 2
guid: c785dbfac2c67974fa1cce056df6404d
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
userData:
assetBundleName:
assetBundleVariant:

View file

@ -198,7 +198,7 @@ namespace HeavenStudio
// LateUpdate works a bit better(?) but causes some bugs (like issues with bop animations).
private void Update()
{
PlayerInput.UpdateJoyShocks();
PlayerInput.UpdateInputControllers();
if (BeatmapEntities() < 1) //bruh really you forgot to ckeck tempo changes
return;
@ -528,12 +528,5 @@ namespace HeavenStudio
{
HeavenStudio.GameCamera.ResetAdditionalTransforms();
}
void OnApplicationQuit()
{
Debug.Log("Disconnecting JoyShocks...");
JSL.JslSetCallback(null);
JSL.JslDisconnectAndDisposeAll();
}
}
}

View file

@ -59,6 +59,7 @@ namespace HeavenStudio
DontDestroyOnLoad(this.gameObject);
instance = this;
Starpelly.OS.ChangeWindowTitle("Heaven Studio DEMO");
PlayerInput.InitInputControllers();
}
public static GameObject CreateFade()
@ -141,5 +142,11 @@ namespace HeavenStudio
MasterVolume = value;
AudioListener.volume = MasterVolume;
}
void OnApplicationQuit()
{
Debug.Log("Disconnecting JoyShocks...");
PlayerInput.DisconnectJoyshocks();
}
}
}

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f0c2ca50a4b8a1b499a3efd717f1daaa
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dc30ca18de2bbc24d984b036097fe60d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,258 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.Util;
using static JSL;
namespace HeavenStudio.InputSystem
{
public class InputJoyshock : InputController
{
static string[] joyShockNames =
{
"Unknown",
"Joy-Con (L)",
"Joy-Con (R)",
"Pro Controller",
"DualShock 4",
"DualSense"
};
int[] mappings = new int[]
{
ButtonMaskUp,
ButtonMaskDown,
ButtonMaskLeft,
ButtonMaskRight,
ButtonMaskS,
ButtonMaskE,
ButtonMaskW,
ButtonMaskN,
ButtonMaskL,
ButtonMaskR,
ButtonMaskPlus,
};
int joyshockHandle;
int type;
int splitType;
string joyshockName;
InputDirection hatDirectionCurrent;
InputDirection hatDirectionLast;
//buttons, sticks, triggers
JOY_SHOCK_STATE joyBtStateCurrent, joyBtStateLast;
//gyro and accelerometer
IMU_STATE joyImuStateCurrent, joyImuStateLast;
//touchpad
TOUCH_STATE joyTouchStateCurrent, joyTouchStateLast;
InputJoyshock otherHalf;
public InputJoyshock(int handle)
{
joyshockHandle = handle;
}
public override void InitializeController()
{
joyBtStateCurrent = new JOY_SHOCK_STATE();
joyBtStateLast = new JOY_SHOCK_STATE();
joyImuStateCurrent = new IMU_STATE();
joyImuStateLast = new IMU_STATE();
joyTouchStateCurrent = new TOUCH_STATE();
joyTouchStateLast = new TOUCH_STATE();
//FUTURE: remappable controls
type = JslGetControllerType(joyshockHandle);
joyshockName = joyShockNames[type];
splitType = JslGetControllerSplitType(joyshockHandle);
}
public override void UpdateState()
{
joyBtStateLast = joyBtStateCurrent;
joyBtStateCurrent = JslGetSimpleState(joyshockHandle);
}
public override string GetDeviceName()
{
if (otherHalf != null)
return "Joy-Con Pair";
return joyshockName;
}
public override InputFeatures GetFeatures()
{
InputFeatures features = InputFeatures.Style_Pad | InputFeatures.Style_Baton;
switch (type)
{
case TypeJoyConLeft:
features |= InputFeatures.Readable_ShellColour | InputFeatures.Readable_ButtonColour | InputFeatures.Writable_PlayerLED | InputFeatures.Extra_SplitControllerLeft | InputFeatures.Extra_HDRumble;
break;
case TypeJoyConRight:
features |= InputFeatures.Readable_ShellColour | InputFeatures.Readable_ButtonColour | InputFeatures.Writable_PlayerLED | InputFeatures.Extra_SplitControllerRight | InputFeatures.Extra_HDRumble;
break;
case TypeProController:
features |= InputFeatures.Readable_ShellColour | InputFeatures.Readable_ButtonColour | InputFeatures.Readable_LeftGripColour | InputFeatures.Readable_RightGripColour | InputFeatures.Writable_PlayerLED | InputFeatures.Extra_HDRumble;
break;
case TypeDualShock4:
features |= InputFeatures.Readable_AnalogueTriggers | InputFeatures.Readable_Pointer | InputFeatures.Writable_LightBar;
break;
case TypeDualSense:
features |= InputFeatures.Readable_AnalogueTriggers | InputFeatures.Readable_Pointer | InputFeatures.Writable_PlayerLED | InputFeatures.Writable_LightBar;
break;
}
features |= InputFeatures.Readable_MotionSensor | InputFeatures.Extra_Rumble | InputFeatures.Style_Pad | InputFeatures.Style_Baton | InputFeatures.Style_Touch;
return features;
}
public override int GetLastButtonDown()
{
return BitwiseUtils.FirstSetBit(joyBtStateCurrent.buttons & joyBtStateLast.buttons);
}
public override KeyCode GetLastKeyDown()
{
return KeyCode.None;
}
public override bool GetButton(int button)
{
return BitwiseUtils.WantCurrent(joyBtStateCurrent.buttons, mappings[button]);
}
public override bool GetButtonDown(int button)
{
return BitwiseUtils.WantCurrentAndNotLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, mappings[button]);
}
public override bool GetButtonUp(int button)
{
return BitwiseUtils.WantNotCurrentAndLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, mappings[button]);
}
public override float GetAxis(InputAxis axis)
{
switch (axis)
{
case InputAxis.AxisLTrigger:
return joyBtStateCurrent.lTrigger;
case InputAxis.AxisRTrigger:
return joyBtStateCurrent.rTrigger;
case InputAxis.AxisLStickX:
return joyBtStateCurrent.stickLX;
case InputAxis.AxisLStickY:
return joyBtStateCurrent.stickLY;
case InputAxis.AxisRStickX:
return joyBtStateCurrent.stickRX;
case InputAxis.AxisRStickY:
return joyBtStateCurrent.stickRY;
case InputAxis.TouchpadX: //isn't updated for now, so always returns 0f
//return joyTouchStateCurrent.t0X;
case InputAxis.TouchpadY:
//return joyTouchStateCurrent.t0Y;
default:
return 0f;
}
}
public override bool GetHatDirection(InputDirection direction)
{
//todo: check analogue stick hat direction too
switch (direction)
{
case InputDirection.Up:
return BitwiseUtils.WantCurrent(joyBtStateCurrent.buttons, ButtonMaskUp);
case InputDirection.Down:
return BitwiseUtils.WantCurrent(joyBtStateCurrent.buttons, ButtonMaskDown);
case InputDirection.Left:
return BitwiseUtils.WantCurrent(joyBtStateCurrent.buttons, ButtonMaskLeft);
case InputDirection.Right:
return BitwiseUtils.WantCurrent(joyBtStateCurrent.buttons, ButtonMaskRight);
default:
return false;
}
}
public override bool GetHatDirectionDown(InputDirection direction)
{
//todo: check analogue stick hat direction too
switch (direction)
{
case InputDirection.Up:
return BitwiseUtils.WantCurrentAndNotLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, ButtonMaskUp);
case InputDirection.Down:
return BitwiseUtils.WantCurrentAndNotLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, ButtonMaskDown);
case InputDirection.Left:
return BitwiseUtils.WantCurrentAndNotLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, ButtonMaskLeft);
case InputDirection.Right:
return BitwiseUtils.WantCurrentAndNotLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, ButtonMaskRight);
default:
return false;
}
}
public override bool GetHatDirectionUp(InputDirection direction)
{
//todo: check analogue stick hat direction too
switch (direction)
{
case InputDirection.Up:
return BitwiseUtils.WantNotCurrentAndLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, ButtonMaskUp);
case InputDirection.Down:
return BitwiseUtils.WantNotCurrentAndLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, ButtonMaskDown);
case InputDirection.Left:
return BitwiseUtils.WantNotCurrentAndLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, ButtonMaskLeft);
case InputDirection.Right:
return BitwiseUtils.WantNotCurrentAndLast(joyBtStateCurrent.buttons, joyBtStateLast.buttons, ButtonMaskRight);
default:
return false;
}
}
public override void SetPlayer(int playerNum)
{
if (playerNum == -1)
{
this.playerNum = null;
JslSetPlayerNumber(joyshockHandle, 0);
return;
}
if (type == TypeDualSense)
{
if (playerNum <= 4)
{
playerNum = DualSensePlayerMask[playerNum];
}
}
JslSetPlayerNumber(joyshockHandle, playerNum);
this.playerNum = playerNum;
}
public override int? GetPlayer()
{
return this.playerNum;
}
public int GetHandle()
{
return joyshockHandle;
}
public void DisconnectJoyshock()
{
if (otherHalf != null)
{
otherHalf = null;
}
JslSetRumble(joyshockHandle, 0, 0);
JslSetLightColour(joyshockHandle, 0);
JslSetPlayerNumber(joyshockHandle, 0);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: abe9a6a60f8629440a3cae605aca60a3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,154 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static JSL;
namespace HeavenStudio.InputSystem
{
public class InputKeyboard : InputController
{
static KeyCode[] keyCodes = (KeyCode[]) System.Enum.GetValues(typeof(UnityEngine.KeyCode));
//FUTURE: remappable controls
//KeyCode[] mappings = new KeyCode[Enum.GetNames(typeof(ButtonsPad)).Length];
KeyCode[] mappings = new KeyCode[]
{
KeyCode.UpArrow,
KeyCode.DownArrow,
KeyCode.LeftArrow,
KeyCode.RightArrow,
KeyCode.X,
KeyCode.Z,
KeyCode.C,
KeyCode.V,
KeyCode.S,
KeyCode.D,
KeyCode.Return,
};
InputDirection hatDirectionCurrent;
InputDirection hatDirectionLast;
public override void InitializeController()
{
//FUTURE: remappable controls
}
public override void UpdateState()
{
// Update the state of the controller
}
public override string GetDeviceName()
{
return "Keyboard";
}
public override InputFeatures GetFeatures()
{
return InputFeatures.Readable_StringInput | InputFeatures.Style_Pad | InputFeatures.Style_Baton;
}
public override int GetLastButtonDown()
{
return 0;
}
public override KeyCode GetLastKeyDown()
{
for(KeyCode i = keyCodes[1]; i <= KeyCode.Menu; i++) {
if (Input.GetKeyDown(i))
return i;
}
return KeyCode.None;
}
public override bool GetButton(int button)
{
return Input.GetKey(mappings[button]);
}
public override bool GetButtonDown(int button)
{
return Input.GetKeyDown(mappings[button]);
}
public override bool GetButtonUp(int button)
{
return Input.GetKeyUp(mappings[button]);
}
public override float GetAxis(InputAxis axis)
{
return 0;
}
//todo: directionals
public override bool GetHatDirection(InputDirection direction)
{
switch (direction)
{
case InputDirection.Up:
return Input.GetKey(KeyCode.UpArrow);
case InputDirection.Down:
return Input.GetKey(KeyCode.DownArrow);
case InputDirection.Left:
return Input.GetKey(KeyCode.LeftArrow);
case InputDirection.Right:
return Input.GetKey(KeyCode.RightArrow);
default:
return false;
}
}
public override bool GetHatDirectionDown(InputDirection direction)
{
switch (direction)
{
case InputDirection.Up:
return Input.GetKeyDown(KeyCode.UpArrow);
case InputDirection.Down:
return Input.GetKeyDown(KeyCode.DownArrow);
case InputDirection.Left:
return Input.GetKeyDown(KeyCode.LeftArrow);
case InputDirection.Right:
return Input.GetKeyDown(KeyCode.RightArrow);
default:
return false;
}
}
public override bool GetHatDirectionUp(InputDirection direction)
{
switch (direction)
{
case InputDirection.Up:
return Input.GetKeyUp(KeyCode.UpArrow);
case InputDirection.Down:
return Input.GetKeyUp(KeyCode.DownArrow);
case InputDirection.Left:
return Input.GetKeyUp(KeyCode.LeftArrow);
case InputDirection.Right:
return Input.GetKeyUp(KeyCode.RightArrow);
default:
return false;
}
}
public override void SetPlayer(int playerNum)
{
if (playerNum == -1)
{
this.playerNum = null;
return;
}
this.playerNum = playerNum;
}
public override int? GetPlayer()
{
return playerNum;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 19bccc8eebf390943a5c6d8bc59f4c7f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,168 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace HeavenStudio.InputSystem
{
/// <summary>
/// Generic class to allow adapting any type and combination of HIDs to a universal controller format.
/// Specifically designed for Heaven Studio, but can be adapted to any use.
/// </summary>
public abstract class InputController
{
//Buttons and Axis used by most controllers
public enum InputButtons : int
{
ButtonPadUp = 0,
ButtonPadDown = 1,
ButtonPadLeft = 2,
ButtonPadRight = 3,
ButtonPlus = 4,
ButtonOptions = 4,
ButtonMinus = 5,
ButtonShare = 5,
ButtonLClick = 6,
ButtonRClick = 7,
ButtonL = 8,
ButtonR = 9,
ButtonZL = 10,
ButtonZR = 11,
ButtonFaceS = 12,
ButtonFaceE = 13,
ButtonFaceW = 14,
ButtonFaceN = 15,
ButtonHome = 16,
ButtonPS = 16,
ButtonCapture = 17,
ButtonTouchpadClick = 17,
ButtonSL = 18,
ButtonSR = 19,
}
public enum InputAxis : int
{
AxisLTrigger = 4,
AxisRTrigger = 5,
AxisLStickX = 0,
AxisLStickY = 1,
AxisRStickX = 2,
AxisRStickY = 3,
TouchpadX = 6,
TouchpadY = 7
}
//D-Pad directions, usable to adapt analogue sticks to cardinal directions
public enum InputDirection : int
{
Up = 0,
Right = 1,
Down = 2,
Left = 3,
}
//Common specific controller features
[System.Flags]
public enum InputFeatures
{
//readable properties
Readable_ShellColour,
Readable_ButtonColour,
Readable_LeftGripColour,
Readable_RightGripColour,
Readable_AnalogueTriggers,
Readable_StringInput,
Readable_Pointer,
Readable_MotionSensor,
//writable properties
Writable_PlayerLED,
Writable_LightBar,
Writable_Chroma,
Writable_Speaker,
//other / "special" properties
Extra_SplitControllerLeft,
Extra_SplitControllerRight,
Extra_Rumble,
Extra_HDRumble,
//supported control styles
Style_Pad,
Style_Baton,
Style_Touch
};
//Following enums are specific to Heaven Studio, can be removed in other applications
//Control styles in Heaven Studio
public enum ControlStyles
{
Pad,
Baton,
Touch
}
//buttons used in Heaven Studio gameplay (Pad Style)
public enum ButtonsPad : int
{
PadUp = 0,
PadDown = 1,
PadLeft = 2,
PadRight = 3,
PadS = 4,
PadE = 5,
PadW = 6,
PadN = 7,
PadL = 8,
PadR = 9,
PadPause = 10,
}
//FUTURE: buttons used in Heaven Studio gameplay ("Form Baton" / WiiMote Style)
public enum ButtonsBaton : int
{
BatonS = 0, //-- all these...
BatonE = 1, // |
BatonW = 2, // |
BatonN = 3, //--
BatonA = 4, // < ...map to this, but are directional
BatonB = 5, // should never be used alone
Baton1 = 6,
Baton2 = 7,
BatonPause = 8,
}
//FUTURE: buttons used in Heaven Studio gameplay (Touch Style)
public enum ButtonsTouch : int
{
TouchL = 0,
TouchR = 1,
TouchTap = 2,
TouchFlick = 3,
TouchButtonL = 4,
TouchButtonR = 4,
}
protected int? playerNum;
public abstract void InitializeController();
public abstract void UpdateState(); // Update the state of the controller
public abstract string GetDeviceName(); // Get the name of the controller
public abstract InputFeatures GetFeatures(); // Get the features of the controller
public abstract int GetLastButtonDown(); // Get the last button down
public abstract KeyCode GetLastKeyDown(); // Get the last key down (used for keyboards and other devices that use Keycode)
public abstract bool GetButton(int button); // is button currently pressed?
public abstract bool GetButtonDown(int button); // is button just pressed?
public abstract bool GetButtonUp(int button); // is button just released?
public abstract float GetAxis(InputAxis axis); // Get the value of an axis
public abstract bool GetHatDirection(InputDirection direction); // is direction active?
public abstract bool GetHatDirectionDown(InputDirection direction); // direction just became active?
public abstract bool GetHatDirectionUp(InputDirection direction); // direction just became inactive?
public abstract void SetPlayer(int playerNum); // Set the player number (starts at 1, set to -1 or null for no player)
public abstract int? GetPlayer(); // Get the player number (null if no player)
//public abstract Sprite GetDisplayIcon(); //"big icon" for the controller in the settings menu
//public abstract Sprite GetPlaybackIcon(); //"small icon" for the controller during playback
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f940937684f598749af06c1297727c4b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,227 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using HeavenStudio.InputSystem;
using static JSL;
namespace HeavenStudio
{
public class PlayerInput
{
//Clockwise
public const int UP = 0;
public const int RIGHT = 1;
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<InputController> inputDevices;
public static int InitInputControllers()
{
inputDevices = new List<InputController>();
//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);
}
}
else
{
Debug.Log("No JoyShocks found.");
}
//end JoyShock setup
//TODO: XInput setup (boo)
//end XInput setup
return inputDevices.Count;
}
public static int GetNumControllersConnected()
{
return inputDevices.Count;
}
public static List<InputController> GetInputControllers()
{
return inputDevices;
}
public static InputController GetInputController(int player)
{
//select input controller that has player field set to player
//this will return the first controller that has that player number in the case of controller pairs (eg. Joy-Cons)
//so such controllers should have a reference to the other controller in the pair
foreach (InputController i in inputDevices)
{
if (i.GetPlayer() == player)
{
return i;
}
}
return null;
}
public static void UpdateInputControllers()
{
foreach (InputController i in inputDevices)
{
i.UpdateState();
}
}
public static void DisconnectJoyshocks()
{
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;
}
// The autoplay isn't activated AND
// The song is actually playing AND
// The GameManager allows you to Input
public static bool playerHasControl()
{
return !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput;
}
/*--------------------*/
/* MAIN INPUT METHODS */
/*--------------------*/
// BUTTONS
//TODO: refactor for controller and custom binds, currently uses temporary button checks
public static bool Pressed(bool includeDPad = false)
{
bool keyDown = GetInputController(1).GetButtonDown((int) InputController.ButtonsPad.PadE) || (includeDPad && GetAnyDirectionDown());
return keyDown && !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput ;
}
public static bool PressedUp(bool includeDPad = false)
{
bool keyUp = GetInputController(1).GetButtonUp((int) InputController.ButtonsPad.PadE) || (includeDPad && GetAnyDirectionUp());
return keyUp && !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput;
}
public static bool Pressing(bool includeDPad = false)
{
bool pressing = GetInputController(1).GetButton((int) InputController.ButtonsPad.PadE) || (includeDPad && GetAnyDirection());
return pressing && !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput;
}
public static bool AltPressed()
{
bool down = GetInputController(1).GetButtonDown((int) InputController.ButtonsPad.PadS);
return down && playerHasControl();
}
public static bool AltPressedUp()
{
bool up = GetInputController(1).GetButtonUp((int) InputController.ButtonsPad.PadS);
return up && playerHasControl();
}
public static bool AltPressing()
{
bool pressing = GetInputController(1).GetButton((int) InputController.ButtonsPad.PadS);
return pressing && playerHasControl();
}
//Directions
public static bool GetAnyDirectionDown()
{
return (GetInputController(1).GetButtonDown((int) InputController.ButtonsPad.PadUp)
|| GetInputController(1).GetButtonDown((int) InputController.ButtonsPad.PadDown)
|| GetInputController(1).GetButtonDown((int) InputController.ButtonsPad.PadLeft)
|| GetInputController(1).GetButtonDown((int) InputController.ButtonsPad.PadRight)
) && playerHasControl();
}
public static bool GetAnyDirectionUp()
{
return (GetInputController(1).GetButtonUp((int) InputController.ButtonsPad.PadUp)
|| GetInputController(1).GetButtonUp((int) InputController.ButtonsPad.PadDown)
|| GetInputController(1).GetButtonUp((int) InputController.ButtonsPad.PadLeft)
|| GetInputController(1).GetButtonUp((int) InputController.ButtonsPad.PadRight)
) && playerHasControl();
}
public static bool GetAnyDirection()
{
return (GetInputController(1).GetButton((int) InputController.ButtonsPad.PadUp)
|| GetInputController(1).GetButton((int) InputController.ButtonsPad.PadDown)
|| GetInputController(1).GetButton((int) InputController.ButtonsPad.PadLeft)
|| GetInputController(1).GetButton((int) InputController.ButtonsPad.PadRight)
) && playerHasControl();
}
public static bool GetSpecificDirection(int direction)
{
return GetInputController(1).GetHatDirection((InputController.InputDirection) direction) && playerHasControl();
}
public static bool GetSpecificDirectionDown(int direction)
{
return GetInputController(1).GetHatDirectionDown((InputController.InputDirection) direction) && playerHasControl();
}
public static bool GetSpecificDirectionUp(int direction)
{
return GetInputController(1).GetHatDirectionUp((InputController.InputDirection) direction) && playerHasControl();
}
}
}

View file

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 9503627b14bba414cae0fbc5da9e4120
guid: ff41ce113a3b89f4892e362c8ef3d773
MonoImporter:
externalObjects: {}
serializedVersion: 2

View file

@ -1,8 +1,12 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using HeavenStudio;
using HeavenStudio.InputSystem;
using static JSL;
namespace HeavenStudio.Editor
@ -11,13 +15,52 @@ namespace HeavenStudio.Editor
{
[SerializeField] private TMP_Text numConnectedLabel;
[SerializeField] private TMP_Text currentControllerLabel;
[SerializeField] private TMP_Dropdown controllersDropdown;
[SerializeField] private TMP_Dropdown splitControllersDropdown;
private void Start() {
numConnectedLabel.text = "Connected: " + PlayerInput.GetNumControllersConnected();
currentControllerLabel.text = "Current Controller: " + PlayerInput.GetInputController(1).GetDeviceName();
}
public void SearchAndConnectControllers()
{
int connected = PlayerInput.InitJoyShocks();
int connected = PlayerInput.InitInputControllers();
numConnectedLabel.text = "Connected: " + connected;
//do this better
currentControllerLabel.text = "Current Controller: " + PlayerInput.GetJoyShockName(0);
currentControllerLabel.text = "Current Controller: " + PlayerInput.GetInputController(1).GetDeviceName();
}
public void populateControllersDropdown()
{
List<TMP_Dropdown.OptionData> dropDownData = new List<TMP_Dropdown.OptionData>();
var vals = PlayerInput.GetInputControllers();
for (int i = 0; i < vals.Count; i++)
{
TMP_Dropdown.OptionData optionData = new TMP_Dropdown.OptionData();
optionData.text = vals[i].GetDeviceName();
dropDownData.Add(optionData);
}
controllersDropdown.AddOptions(dropDownData);
controllersDropdown.value = 0;
}
public void populateSplitControllersDropdown()
{
List<TMP_Dropdown.OptionData> dropDownData = new List<TMP_Dropdown.OptionData>();
var vals = PlayerInput.GetInputControllers();
InputController.InputFeatures features;
for (int i = 0; i < vals.Count; i++)
{
features = vals[i].GetFeatures();
if (features.HasFlag(InputController.InputFeatures.Extra_SplitControllerLeft) || features.HasFlag(InputController.InputFeatures.Extra_SplitControllerRight))
{
TMP_Dropdown.OptionData optionData = new TMP_Dropdown.OptionData();
optionData.text = vals[i].GetDeviceName();
dropDownData.Add(optionData);
}
}
splitControllersDropdown.AddOptions(dropDownData);
splitControllersDropdown.value = 0;
}
}
}

View file

@ -1,319 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static JSL;
namespace HeavenStudio
{
public class PlayerInput
{
///////////////////////////////
////TEMPORARY JSL FUNCTIONS////
///////////////////////////////
static string[] joyShockNames =
{
"Unknown",
"Joy-Con (L)",
"Joy-Con (R)",
"Pro Controller",
"DualShock 4",
"DualSense"
};
static int numDevicesFound = 0;
static int numDevicesConnected = 0;
static int[] deviceHandles;
static Dictionary<int, JOY_SHOCK_STATE> joyBtStateCurrent;
static Dictionary<int, JOY_SHOCK_STATE> joyBtStateLast;
static Dictionary<int, IMU_STATE> joyImuStateCurrent;
static Dictionary<int, IMU_STATE> joyImuStateLast;
public static int InitJoyShocks()
{
//flush old joyshocks
Debug.Log("Flushing possible JoyShocks...");
JslDisconnectAndDisposeAll();
numDevicesFound = 0;
numDevicesConnected = 0;
numDevicesFound = JslConnectDevices();
if (numDevicesFound > 0)
{
deviceHandles = new int[numDevicesFound];
numDevicesConnected = JslGetConnectedDeviceHandles(deviceHandles, numDevicesFound);
joyBtStateCurrent = new Dictionary<int, JOY_SHOCK_STATE>();
joyBtStateLast = new Dictionary<int, JOY_SHOCK_STATE>();
if (numDevicesConnected < numDevicesFound)
{
Debug.Log("Found " + numDevicesFound + " JoyShocks, but only " + numDevicesConnected + " are connected.");
}
else
{
Debug.Log("Found " + numDevicesFound + " JoyShocks.");
Debug.Log("Connected " + numDevicesConnected + " JoyShocks.");
}
foreach (int i in deviceHandles)
{
Debug.Log("Setting up JoyShock: " + joyShockNames[JslGetControllerType(i)] + " ( Player " + i + ", type " + JslGetControllerType(i) + " )");
}
return numDevicesConnected;
}
else
{
Debug.Log("No JoyShocks found.");
return 0;
}
}
public static string GetJoyShockName(int playerNum)
{
return joyShockNames[JslGetControllerType(deviceHandles[playerNum])];
}
public static void UpdateJoyShocks()
{
if (deviceHandles == null || numDevicesConnected == 0) return;
foreach (var id in deviceHandles)
{
if (joyBtStateCurrent.ContainsKey(id))
{
joyBtStateLast[id] = joyBtStateCurrent[id];
}
else
{
joyBtStateLast[id] = new JOY_SHOCK_STATE();
}
joyBtStateCurrent[id] = JslGetSimpleState(id);
}
}
//TODO: refactor to allow controller selection (and for split controllers, multiple controllers)
static bool GetJoyBtDown(int bt)
{
if (deviceHandles == null || numDevicesConnected <= 0) // <= player number in the future
{
return false;
}
bt = 1 << bt;
int p1Id = deviceHandles[0];
try
{
int curBt = joyBtStateCurrent[p1Id].buttons;
int oldBt = joyBtStateLast[p1Id].buttons;
return ((curBt & bt) == bt) && ((oldBt & bt) != bt);
}
catch (System.Exception)
{
return false;
}
}
static bool GetJoyBt(int bt)
{
if (deviceHandles == null || numDevicesConnected <= 0) // <= player number in the future
{
return false;
}
bt = 1 << bt;
int p1Id = deviceHandles[0];
try
{
int curBt = joyBtStateCurrent[p1Id].buttons;
return (curBt & bt) == bt;
}
catch (System.Exception)
{
return false;
}
}
static bool GetJoyBtUp(int bt)
{
if (deviceHandles == null || numDevicesConnected <= 0) // <= player number in the future
{
return false;
}
bt = 1 << bt;
int p1Id = deviceHandles[0];
try
{
int curBt = joyBtStateCurrent[p1Id].buttons;
int oldBt = joyBtStateLast[p1Id].buttons;
return ((curBt & bt) != bt) && ((oldBt & bt) == bt);
}
catch (System.Exception)
{
return false;
}
}
////END TEMPORARY JSL FUNCTIONS
///////////////////////////////
//Clockwise
public const int UP = 0;
public const int RIGHT = 1;
public const int DOWN = 2;
public const int LEFT = 3;
// The autoplay isn't activated AND
// The song is actually playing AND
// The GameManager allows you to Input
public static bool playerHasControl()
{
return !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput;
}
/*--------------------*/
/* MAIN INPUT METHODS */
/*--------------------*/
// BUTTONS
//TODO: refactor for controller and custom binds, currently uses temporary button checks
public static bool Pressed(bool includeDPad = false)
{
bool keyDown = Input.GetKeyDown(KeyCode.Z) || GetJoyBtDown(ButtonMaskE) || (includeDPad && GetAnyDirectionDown());
return keyDown && !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput ;
}
public static bool PressedUp(bool includeDPad = false)
{
bool keyUp = Input.GetKeyUp(KeyCode.Z) || GetJoyBtUp(ButtonMaskE) || (includeDPad && GetAnyDirectionUp());
return keyUp && !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput;
}
public static bool Pressing(bool includeDPad = false)
{
bool pressing = Input.GetKey(KeyCode.Z) || GetJoyBt(ButtonMaskE) || (includeDPad && GetAnyDirection());
return pressing && !GameManager.instance.autoplay && Conductor.instance.isPlaying && GameManager.instance.canInput;
}
public static bool AltPressed()
{
bool down = Input.GetKeyDown(KeyCode.X) || GetJoyBtDown(ButtonMaskS);
return down && playerHasControl();
}
public static bool AltPressedUp()
{
bool up = Input.GetKeyUp(KeyCode.X) || GetJoyBtUp(ButtonMaskS);
return up && playerHasControl();
}
public static bool AltPressing()
{
bool pressing = Input.GetKey(KeyCode.X) || GetJoyBt(ButtonMaskS);
return pressing && playerHasControl();
}
//Directions
public static bool GetAnyDirectionDown()
{
return (Input.GetKeyDown(KeyCode.UpArrow)
|| Input.GetKeyDown(KeyCode.DownArrow)
|| Input.GetKeyDown(KeyCode.LeftArrow)
|| Input.GetKeyDown(KeyCode.RightArrow)
|| GetJoyBtDown(ButtonMaskUp)
|| GetJoyBtDown(ButtonMaskDown)
|| GetJoyBtDown(ButtonMaskLeft)
|| GetJoyBtDown(ButtonMaskRight)
) && playerHasControl();
}
public static bool GetAnyDirectionUp()
{
return (Input.GetKeyUp(KeyCode.UpArrow)
|| Input.GetKeyUp(KeyCode.DownArrow)
|| Input.GetKeyUp(KeyCode.LeftArrow)
|| Input.GetKeyUp(KeyCode.RightArrow)
|| GetJoyBtUp(ButtonMaskUp)
|| GetJoyBtUp(ButtonMaskDown)
|| GetJoyBtUp(ButtonMaskLeft)
|| GetJoyBtUp(ButtonMaskRight)
) && playerHasControl();
}
public static bool GetAnyDirection()
{
return (Input.GetKey(KeyCode.UpArrow)
|| Input.GetKey(KeyCode.DownArrow)
|| Input.GetKey(KeyCode.LeftArrow)
|| Input.GetKey(KeyCode.RightArrow)
|| GetJoyBt(ButtonMaskUp)
|| GetJoyBt(ButtonMaskDown)
|| GetJoyBt(ButtonMaskLeft)
|| GetJoyBt(ButtonMaskRight)
) && playerHasControl();
}
public static bool GetSpecificDirectionDown(int direction)
{
KeyCode targetCode = getKeyCode(direction);
if (targetCode == KeyCode.None) return false;
int targetMask = getButtonMask(direction);
if (targetMask == 0) return false;
return (Input.GetKeyDown(targetCode) || GetJoyBtDown(targetMask)) && playerHasControl();
}
public static bool GetSpecificDirectionUp(int direction)
{
KeyCode targetCode = getKeyCode(direction);
if (targetCode == KeyCode.None) return false;
int targetMask = getButtonMask(direction);
if (targetMask == 0) return false;
return (Input.GetKeyUp(targetCode) || GetJoyBtUp(targetMask)) && playerHasControl();
}
private static KeyCode getKeyCode(int direction)
{
KeyCode targetKeyCode;
switch (direction)
{
case PlayerInput.UP: targetKeyCode = KeyCode.UpArrow; break;
case PlayerInput.DOWN: targetKeyCode = KeyCode.DownArrow; break;
case PlayerInput.LEFT: targetKeyCode = KeyCode.LeftArrow; break;
case PlayerInput.RIGHT: targetKeyCode = KeyCode.RightArrow; break;
default: targetKeyCode = KeyCode.None; break;
}
return targetKeyCode;
}
private static int getButtonMask(int direction)
{
int targetKeyCode;
switch (direction)
{
case PlayerInput.UP: targetKeyCode = ButtonMaskUp; break;
case PlayerInput.DOWN: targetKeyCode = ButtonMaskDown; break;
case PlayerInput.LEFT: targetKeyCode = ButtonMaskLeft; break;
case PlayerInput.RIGHT: targetKeyCode = ButtonMaskRight; break;
default: targetKeyCode = -1; break;
}
return targetKeyCode;
}
}
}

View file

@ -0,0 +1,50 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace HeavenStudio.Util
{
public static class BitwiseUtils
{
/// <summary>
/// Returns the value of the lowest set bit in the given integer.
/// </summary>
/// <param name="num">The integer to check.</param>
public static int FirstSetBit(int num)
{
return num & (-num);
}
/// <summary>
/// Returns true if the wanted bit is set in the given integer.
/// </summary>
/// <param name="num">The integer to check.</param>
/// <param name="want">The bit(s) to check for.</param>
public static bool WantCurrent(int num, int want)
{
return (num & want) == want;
}
/// <summary>
/// Returns true if the wanted bit is set in the first integer, and not in the second.
/// </summary>
/// <param name="num1">The first integer to check.</param>
/// <param name="num2">The second integer to check.</param>
/// <param name="want">The bit(s) to check for.</param>
public static bool WantCurrentAndNotLast(int num1, int num2, int want)
{
return ((num1 & want) == want) && ((num2 & want) != want);
}
/// <summary>
/// Returns true if the wanted bit is not set in the first integer, but set in the second.
/// </summary>
/// <param name="num1">The first integer to check.</param>
/// <param name="num2">The second integer to check.</param>
/// <param name="want">The bit(s) to check for.</param>
public static bool WantNotCurrentAndLast(int num1, int num2, int want)
{
return ((num1 & want) != want) && ((num2 & want) == want);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 18f088a4c3c17b143a1985f3cee5d90a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: