package dev.isxander.controlify.controller.gamepad; import dev.isxander.controlify.InputMode; import dev.isxander.controlify.api.ControlifyApi; import dev.isxander.controlify.bindings.ControllerBindings; import dev.isxander.controlify.controller.AbstractController; import dev.isxander.controlify.controller.hid.ControllerHIDService; import dev.isxander.controlify.driver.*; import dev.isxander.controlify.rumble.RumbleManager; import dev.isxander.controlify.rumble.RumbleSource; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWGamepadState; import java.util.Set; public class GamepadController extends AbstractController { private GamepadState state = GamepadState.EMPTY; private GamepadState prevState = GamepadState.EMPTY; private final RumbleManager rumbleManager; private GamepadState.GyroState absoluteGyro = GamepadState.GyroState.ORIGIN; private final GamepadDrivers drivers; private final Set uniqueDrivers; public GamepadController(int joystickId, ControllerHIDService.ControllerHIDInfo hidInfo) { super(joystickId, hidInfo); if (!GLFW.glfwJoystickIsGamepad(joystickId)) throw new IllegalArgumentException("Joystick " + joystickId + " is not a gamepad!"); if (!this.name.startsWith(type().friendlyName())) setName(GLFW.glfwGetGamepadName(joystickId)); this.drivers = GamepadDrivers.forController(joystickId, hidInfo.hidDevice()); this.uniqueDrivers = drivers.getUniqueDrivers(); this.rumbleManager = new RumbleManager(this); this.defaultConfig = new GamepadConfig(); this.config = new GamepadConfig(); this.bindings = new ControllerBindings<>(this); } @Override public GamepadState state() { return state; } @Override public GamepadState prevState() { return prevState; } @Override public void updateState() { prevState = state; uniqueDrivers.forEach(Driver::update); BasicGamepadInputDriver.BasicGamepadState basicState = drivers.basicGamepadInputDriver().getBasicGamepadState(); GamepadState.AxesState deadzoneAxesState = basicState.axes() .leftJoystickDeadZone(config().leftStickDeadzoneX, config().leftStickDeadzoneY) .rightJoystickDeadZone(config().rightStickDeadzoneX, config().rightStickDeadzoneY); GamepadState.GyroState gyroState = drivers.gyroDriver().getGyroState(); state = new GamepadState(deadzoneAxesState, basicState.axes(), basicState.buttons(), gyroState, absoluteGyro); } public GamepadState.GyroState absoluteGyroState() { return absoluteGyro; } public boolean hasGyro() { return drivers.gyroDriver().isGyroSupported(); } @Override public void clearState() { state = GamepadState.EMPTY; } public void consumeButtonState() { this.state = new GamepadState(state().gamepadAxes(), state().rawGamepadAxes(), GamepadState.ButtonState.EMPTY, state().gyroDelta(), state().absoluteGyroPos()); } GLFWGamepadState getGamepadState() { GLFWGamepadState state = GLFWGamepadState.create(); GLFW.glfwGetGamepadState(joystickId, state); return state; } @Override public boolean setRumble(float strongMagnitude, float weakMagnitude, RumbleSource source) { if (!canRumble()) return false; var strengthMod = config().getRumbleStrength(source); if (source != RumbleSource.MASTER) strengthMod *= config().getRumbleStrength(RumbleSource.MASTER); strongMagnitude *= strengthMod; weakMagnitude *= strengthMod; return drivers.rumbleDriver().rumble(strongMagnitude, weakMagnitude); } @Override public boolean canRumble() { return drivers.rumbleDriver().isRumbleSupported() && config().allowVibrations && ControlifyApi.get().currentInputMode() == InputMode.CONTROLLER; } @Override public RumbleManager rumbleManager() { return this.rumbleManager; } @Override public void close() { uniqueDrivers.forEach(Driver::close); } }