forked from Clones/Controlify
➕ Experimental anti-snapback
This commit is contained in:
@ -5,9 +5,11 @@ import dev.isxander.controlify.bindings.ControllerBindings;
|
|||||||
import dev.isxander.controlify.controller.AbstractController;
|
import dev.isxander.controlify.controller.AbstractController;
|
||||||
import dev.isxander.controlify.controller.BatteryLevel;
|
import dev.isxander.controlify.controller.BatteryLevel;
|
||||||
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
||||||
|
import dev.isxander.controlify.debug.DebugProperties;
|
||||||
import dev.isxander.controlify.driver.*;
|
import dev.isxander.controlify.driver.*;
|
||||||
import dev.isxander.controlify.rumble.RumbleManager;
|
import dev.isxander.controlify.rumble.RumbleManager;
|
||||||
import dev.isxander.controlify.rumble.RumbleSource;
|
import dev.isxander.controlify.rumble.RumbleSource;
|
||||||
|
import dev.isxander.controlify.utils.ControllerUtils;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
@ -23,6 +25,8 @@ public class GamepadController extends AbstractController<GamepadState, GamepadC
|
|||||||
private final GamepadDrivers drivers;
|
private final GamepadDrivers drivers;
|
||||||
private final Set<Driver> uniqueDrivers;
|
private final Set<Driver> uniqueDrivers;
|
||||||
|
|
||||||
|
private int antiSnapbackTicksL, antiSnapbackTicksR;
|
||||||
|
|
||||||
public GamepadController(int joystickId, ControllerHIDService.ControllerHIDInfo hidInfo) {
|
public GamepadController(int joystickId, ControllerHIDService.ControllerHIDInfo hidInfo) {
|
||||||
super(joystickId, hidInfo);
|
super(joystickId, hidInfo);
|
||||||
if (!GLFW.glfwJoystickIsGamepad(joystickId))
|
if (!GLFW.glfwJoystickIsGamepad(joystickId))
|
||||||
@ -64,6 +68,23 @@ public class GamepadController extends AbstractController<GamepadState, GamepadC
|
|||||||
.leftJoystickDeadZone(config().leftStickDeadzoneX, config().leftStickDeadzoneY)
|
.leftJoystickDeadZone(config().leftStickDeadzoneX, config().leftStickDeadzoneY)
|
||||||
.rightJoystickDeadZone(config().rightStickDeadzoneX, config().rightStickDeadzoneY);
|
.rightJoystickDeadZone(config().rightStickDeadzoneX, config().rightStickDeadzoneY);
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GamepadState.GyroState gyroState = drivers.gyroDriver().getGyroState();
|
GamepadState.GyroState gyroState = drivers.gyroDriver().getGyroState();
|
||||||
|
|
||||||
state = new GamepadState(deadzoneAxesState, basicState.axes(), basicState.buttons(), gyroState, absoluteGyro);
|
state = new GamepadState(deadzoneAxesState, basicState.axes(), basicState.buttons(), gyroState, absoluteGyro);
|
||||||
|
@ -177,6 +177,14 @@ public final class GamepadState implements ControllerState {
|
|||||||
ControllerUtils.deadzone(rightTrigger, deadZone)
|
ControllerUtils.deadzone(rightTrigger, deadZone)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AxesState neutraliseLeft() {
|
||||||
|
return new AxesState(0, 0, rightStickX, rightStickY, leftTrigger, rightTrigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AxesState neutraliseRight() {
|
||||||
|
return new AxesState(leftStickX, leftStickY, 0, 0, leftTrigger, rightTrigger);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public record ButtonState(
|
public record ButtonState(
|
||||||
|
@ -80,6 +80,7 @@ public class SDL2NativesManager {
|
|||||||
// without calling JoystickUpdate, which we don't do.
|
// without calling JoystickUpdate, which we don't do.
|
||||||
SDL.SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0");
|
SDL.SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0");
|
||||||
// better rumble
|
// better rumble
|
||||||
|
SDL.SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI, "1");
|
||||||
SDL.SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
|
SDL.SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1");
|
||||||
SDL.SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
|
SDL.SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1");
|
||||||
SDL.SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_STEAM, "1");
|
SDL.SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_STEAM, "1");
|
||||||
|
@ -20,6 +20,8 @@ public class DebugProperties {
|
|||||||
public static final boolean PRINT_GYRO = boolProp("controlify.debug.print_gyro", false, false);
|
public static final boolean PRINT_GYRO = boolProp("controlify.debug.print_gyro", false, false);
|
||||||
/* Print what drivers are being used */
|
/* Print what drivers are being used */
|
||||||
public static final boolean PRINT_DRIVER = boolProp("controlify.debug.print_driver", true, true);
|
public static final boolean PRINT_DRIVER = boolProp("controlify.debug.print_driver", true, true);
|
||||||
|
/* Use experimental anti-snapback */
|
||||||
|
public static final boolean USE_SNAPBACK = boolProp("controlify.debug.use_snapback", false, false);
|
||||||
|
|
||||||
public static void printProperties() {
|
public static void printProperties() {
|
||||||
if (properties.stream().noneMatch(prop -> prop.enabled() != prop.def()))
|
if (properties.stream().noneMatch(prop -> prop.enabled() != prop.def()))
|
||||||
|
@ -1,7 +1,40 @@
|
|||||||
package dev.isxander.controlify.utils;
|
package dev.isxander.controlify.utils;
|
||||||
|
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
|
||||||
public class ControllerUtils {
|
public class ControllerUtils {
|
||||||
public static float deadzone(float value, float deadzone) {
|
public static float deadzone(float value, float deadzone) {
|
||||||
return (value - Math.copySign(Math.min(deadzone, Math.abs(value)), value)) / (1 - deadzone);
|
return (value - Math.copySign(Math.min(deadzone, Math.abs(value)), value)) / (1 - deadzone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static float applyCircularityX(float x, float y) {
|
||||||
|
return (float) (x * Math.sqrt(1 - (y * y) / 2));
|
||||||
|
}
|
||||||
|
public static float applyCircularityY(float x, float y) {
|
||||||
|
return (float) (y * Math.sqrt(1 - (x * x) / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shouldApplyAntiSnapBack(float x, float y, float px, float py, float threshold) {
|
||||||
|
float dx = x - px;
|
||||||
|
float dy = y - py;
|
||||||
|
float distanceSquared = dx * dx + dy * dy;
|
||||||
|
|
||||||
|
boolean isSnap = distanceSquared >= threshold * threshold;
|
||||||
|
boolean hasCrossedOrigin = Math.signum(x) != Math.signum(px) && Math.signum(y) != Math.signum(py);
|
||||||
|
|
||||||
|
if (isSnap && hasCrossedOrigin) {
|
||||||
|
// t is the distance from the origin to the middle of the line
|
||||||
|
float t = (-x * (px - x) + -y * (py - y)) / distanceSquared;
|
||||||
|
t = Mth.clamp(t, 0, 1);
|
||||||
|
|
||||||
|
// Calculate the distance from the middle of the line to the origin
|
||||||
|
double distanceToMiddle = Math.sqrt(Math.pow(-t * x + t * px, 2)
|
||||||
|
+ Math.pow(-t * y + t * py, 2));
|
||||||
|
|
||||||
|
// If the distance is less than 0.05, then the stick is close enough to the middle to be snap-backed
|
||||||
|
return distanceToMiddle <= 0.01;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user