forked from Clones/Controlify
158 lines
5.9 KiB
Java
158 lines
5.9 KiB
Java
package dev.isxander.controlify.controller.gamepad;
|
|
|
|
import dev.isxander.controlify.Controlify;
|
|
import dev.isxander.controlify.bindings.ControllerBindings;
|
|
import dev.isxander.controlify.controller.AbstractController;
|
|
import dev.isxander.controlify.controller.BatteryLevel;
|
|
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
|
import dev.isxander.controlify.debug.DebugProperties;
|
|
import dev.isxander.controlify.driver.*;
|
|
import dev.isxander.controlify.rumble.RumbleManager;
|
|
import dev.isxander.controlify.rumble.RumbleSource;
|
|
import dev.isxander.controlify.utils.ControllerUtils;
|
|
import dev.isxander.controlify.utils.Log;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import org.lwjgl.glfw.GLFW;
|
|
|
|
import java.util.Set;
|
|
|
|
public class GamepadController extends AbstractController<GamepadState, GamepadConfig> {
|
|
private GamepadState state = GamepadState.EMPTY;
|
|
private GamepadState prevState = GamepadState.EMPTY;
|
|
|
|
private final RumbleManager rumbleManager;
|
|
private GamepadState.GyroState absoluteGyro = new GamepadState.GyroState();
|
|
|
|
public final GamepadDrivers drivers;
|
|
private final Set<Driver> uniqueDrivers;
|
|
|
|
private int antiSnapbackTicksL, antiSnapbackTicksR;
|
|
|
|
public GamepadController(int joystickId, ControllerHIDService.ControllerHIDInfo hidInfo) {
|
|
super(joystickId, hidInfo);
|
|
if (!GLFW.glfwJoystickIsGamepad(joystickId))
|
|
throw new IllegalArgumentException("Joystick " + joystickId + " is not a gamepad!");
|
|
|
|
this.drivers = GamepadDrivers.forController(joystickId, hidInfo.hidDevice());
|
|
this.uniqueDrivers = drivers.getUniqueDrivers();
|
|
this.drivers.printDrivers();
|
|
|
|
if (!this.name.startsWith(type().friendlyName()))
|
|
setName(this.drivers.nameProviderDriver().getName());
|
|
|
|
this.rumbleManager = new RumbleManager(this);
|
|
|
|
this.defaultConfig = new GamepadConfig();
|
|
this.config = new GamepadConfig();
|
|
if (hidInfo.hidDevice().map(hid -> SteamDeckDriver.isSteamDeck(hid.getVendorId(), hid.getProductId())).orElse(false)) {
|
|
this.defaultConfig.mixedInput = true;
|
|
this.config.mixedInput = true;
|
|
}
|
|
|
|
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().getLeftStickDeadzone())
|
|
.rightJoystickDeadZone(config().getRightStickDeadzone());
|
|
|
|
if (DebugProperties.USE_SNAPBACK) {
|
|
if (antiSnapbackTicksL > 0) {
|
|
deadzoneAxesState = deadzoneAxesState.neutraliseLeft();
|
|
antiSnapbackTicksL--;
|
|
} else if (ControllerUtils.shouldApplyAntiSnapBack(deadzoneAxesState.leftStickX(), deadzoneAxesState.leftStickY(), prevState.gamepadAxes().leftStickX(), prevState.gamepadAxes().leftStickY(), 0.08f)) {
|
|
antiSnapbackTicksL = 2;
|
|
deadzoneAxesState = deadzoneAxesState.neutraliseLeft();
|
|
}
|
|
if (antiSnapbackTicksR > 0) {
|
|
deadzoneAxesState = deadzoneAxesState.neutraliseRight();
|
|
antiSnapbackTicksR--;
|
|
} else if (ControllerUtils.shouldApplyAntiSnapBack(deadzoneAxesState.rightStickX(), deadzoneAxesState.rightStickY(), prevState.gamepadAxes().rightStickX(), prevState.gamepadAxes().rightStickY(), 0.08f)) {
|
|
antiSnapbackTicksR = 2;
|
|
deadzoneAxesState = deadzoneAxesState.neutraliseRight();
|
|
}
|
|
}
|
|
|
|
// TODO: Add some sort of gyro filtering
|
|
GamepadState.GyroState gyroState = new GamepadState.GyroState(drivers.gyroDriver().getGyroState()).sub(config().gyroCalibration);
|
|
this.absoluteGyro.add(gyroState);
|
|
|
|
state = new GamepadState(deadzoneAxesState, basicState.axes(), basicState.buttons(), gyroState, absoluteGyro);
|
|
|
|
if (DebugProperties.PRINT_TRIGGER_STATE) {
|
|
Log.LOGGER.info("Left Trigger: " + state.gamepadAxes().leftTrigger());
|
|
Log.LOGGER.info("Right Trigger: " + state.gamepadAxes().rightTrigger());
|
|
}
|
|
}
|
|
|
|
public GamepadState.GyroState absoluteGyroState() {
|
|
return absoluteGyro;
|
|
}
|
|
|
|
public boolean hasGyro() {
|
|
return drivers.gyroDriver().isGyroSupported();
|
|
}
|
|
|
|
@Override
|
|
public void clearState() {
|
|
state = GamepadState.EMPTY;
|
|
}
|
|
|
|
@Override
|
|
public boolean setRumble(float strongMagnitude, float weakMagnitude, RumbleSource source) {
|
|
if (!supportsRumble() || !config().allowVibrations) return false;
|
|
|
|
var strengthMod = config().getRumbleStrength(source);
|
|
if (source != RumbleSource.MASTER)
|
|
strengthMod *= config().getRumbleStrength(RumbleSource.MASTER);
|
|
|
|
strongMagnitude *= strengthMod;
|
|
weakMagnitude *= strengthMod;
|
|
|
|
return drivers.rumbleDriver().rumble(Math.min(strongMagnitude, 1), Math.min(weakMagnitude, 1));
|
|
}
|
|
|
|
@Override
|
|
public boolean supportsRumble() {
|
|
return drivers.rumbleDriver().isRumbleSupported();
|
|
}
|
|
|
|
@Override
|
|
public RumbleManager rumbleManager() {
|
|
return this.rumbleManager;
|
|
}
|
|
|
|
@Override
|
|
public BatteryLevel batteryLevel() {
|
|
return drivers.batteryDriver().getBatteryLevel();
|
|
}
|
|
|
|
@Override
|
|
public void close() {
|
|
uniqueDrivers.forEach(Driver::close);
|
|
}
|
|
|
|
@Override
|
|
public ResourceLocation icon() {
|
|
String theme = config().theme == BuiltinGamepadTheme.DEFAULT ? type().themeId() : config().theme.id();
|
|
return Controlify.id("textures/gui/gamepad/" + theme + "/icon.png");
|
|
}
|
|
}
|