1
0
forked from Clones/Controlify

✏️ Real-world gyro sensitivity

This commit is contained in:
isXander
2023-06-15 18:34:28 +01:00
parent f7cf37f201
commit dc78eb61a2
10 changed files with 110 additions and 61 deletions

View File

@ -17,7 +17,7 @@ public class GamepadConfig extends ControllerConfig {
public boolean flickStick = false;
public boolean invertGyroX = false;
public boolean invertGyroY = false;
public GamepadState.GyroState gyroCalibration = GamepadState.GyroState.ORIGIN;
public GamepadState.GyroState gyroCalibration = new GamepadState.GyroState();
public BuiltinGamepadTheme theme = BuiltinGamepadTheme.DEFAULT;

View File

@ -20,7 +20,7 @@ public class GamepadController extends AbstractController<GamepadState, GamepadC
private GamepadState prevState = GamepadState.EMPTY;
private final RumbleManager rumbleManager;
private GamepadState.GyroState absoluteGyro = GamepadState.GyroState.ORIGIN;
private GamepadState.GyroState absoluteGyro = new GamepadState.GyroState();
public final GamepadDrivers drivers;
private final Set<Driver> uniqueDrivers;
@ -86,8 +86,8 @@ public class GamepadController extends AbstractController<GamepadState, GamepadC
}
// TODO: Add some sort of gyro filtering
GamepadState.GyroState gyroState = drivers.gyroDriver().getGyroState().subtracted(config().gyroCalibration);
this.absoluteGyro = this.absoluteGyro.added(gyroState);
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);
}

View File

@ -3,12 +3,14 @@ package dev.isxander.controlify.controller.gamepad;
import dev.isxander.controlify.controller.ControllerState;
import dev.isxander.controlify.utils.ControllerUtils;
import org.jetbrains.annotations.Nullable;
import org.joml.Vector3f;
import org.joml.Vector3fc;
import java.util.List;
import java.util.Objects;
public final class GamepadState implements ControllerState {
public static final GamepadState EMPTY = new GamepadState(AxesState.EMPTY, AxesState.EMPTY, ButtonState.EMPTY, GyroState.ORIGIN, GyroState.ORIGIN);
public static final GamepadState EMPTY = new GamepadState(AxesState.EMPTY, AxesState.EMPTY, ButtonState.EMPTY, new GyroState(), new GyroState());
private final AxesState gamepadAxes;
private final AxesState rawGamepadAxes;
private final ButtonState gamepadButtons;
@ -24,7 +26,7 @@ public final class GamepadState implements ControllerState {
AxesState gamepadAxes,
AxesState rawGamepadAxes,
ButtonState gamepadButtons,
@Nullable GamepadState.GyroState gyroDelta,
@Nullable GyroState gyroDelta,
GyroState absoluteGyroPos
) {
this.gamepadAxes = gamepadAxes;
@ -102,7 +104,7 @@ public final class GamepadState implements ControllerState {
}
public GyroState gyroDelta() {
if (gyroDelta == null) return GyroState.ORIGIN;
if (gyroDelta == null) return new GyroState();
return gyroDelta;
}
@ -202,31 +204,75 @@ public final class GamepadState implements ControllerState {
);
}
public record GyroState(float pitch, float yaw, float roll) {
public static GyroState ORIGIN = new GyroState(0, 0, 0);
public interface GyroStateC extends Vector3fc {
float pitch();
public GyroState added(GyroState other) {
return new GyroState(pitch + other.pitch, yaw + other.yaw, roll + other.roll);
float yaw();
float roll();
}
public static class GyroState extends Vector3f implements GyroStateC {
public GyroState(float pitch, float yaw, float roll) {
super(pitch, yaw, roll);
}
public GyroState subtracted(GyroState other) {
return new GyroState(pitch - other.pitch, yaw - other.yaw, roll - other.roll);
public GyroState(GyroStateC vec) {
super(vec);
}
public GyroState multiplied(float scalar) {
return new GyroState(pitch * scalar, yaw * scalar, roll * scalar);
public GyroState() {
}
public GyroState divided(float scalar) {
return new GyroState(pitch / scalar, yaw / scalar, roll / scalar);
@Override
public float pitch() {
return x;
}
public GyroState deadzone(float deadzone) {
return new GyroState(
Math.max(pitch - deadzone, 0) + Math.min(pitch + deadzone, 0),
Math.max(yaw - deadzone, 0) + Math.min(yaw + deadzone, 0),
Math.max(roll - deadzone, 0) + Math.min(roll + deadzone, 0)
);
@Override
public float yaw() {
return y;
}
@Override
public float roll() {
return z;
}
@Override
public GyroState mul(Vector3fc v) {
super.mul(v);
return this;
}
@Override
public GyroState mul(float scalar) {
super.mul(scalar);
return this;
}
@Override
public GyroState div(Vector3fc v) {
super.div(v);
return this;
}
@Override
public GyroState div(float scalar) {
super.div(scalar);
return this;
}
@Override
public GyroState sub(Vector3fc v) {
super.sub(v);
return this;
}
@Override
public GyroState sub(float x, float y, float z) {
super.sub(x, y, z);
return this;
}
}
}

View File

@ -3,20 +3,22 @@ package dev.isxander.controlify.driver;
import dev.isxander.controlify.controller.gamepad.GamepadState;
public interface GyroDriver extends Driver {
GamepadState.GyroState getGyroState();
GamepadState.GyroStateC getGyroState();
boolean isGyroSupported();
String getGyroDetails();
GyroDriver UNSUPPORTED = new GyroDriver() {
private final GamepadState.GyroStateC zero = new GamepadState.GyroState();
@Override
public void update() {
}
@Override
public GamepadState.GyroState getGyroState() {
return GamepadState.GyroState.ORIGIN;
public GamepadState.GyroStateC getGyroState() {
return zero;
}
@Override

View File

@ -49,7 +49,7 @@ public class SDL2GamepadDriver implements GyroDriver, RumbleDriver, BatteryDrive
}
@Override
public GamepadState.GyroState getGyroState() {
public GamepadState.GyroStateC getGyroState() {
return gyroDelta;
}

View File

@ -14,7 +14,7 @@ public class SteamDeckDriver implements GyroDriver, BasicGamepadInputDriver {
private final HidDevice hidDevice;
private int interval = 0;
private GamepadState.GyroState gyroDelta = GamepadState.GyroState.ORIGIN;
private GamepadState.GyroState gyroDelta = new GamepadState.GyroState();
private BasicGamepadState basicGamepadState = new BasicGamepadState(GamepadState.AxesState.EMPTY, GamepadState.ButtonState.EMPTY);
public SteamDeckDriver(HidDevice hidDevice) {
@ -114,7 +114,7 @@ public class SteamDeckDriver implements GyroDriver, BasicGamepadInputDriver {
}
@Override
public GamepadState.GyroState getGyroState() {
public GamepadState.GyroStateC getGyroState() {
return gyroDelta;
}

View File

@ -33,7 +33,7 @@ public class ControllerCalibrationScreen extends Screen {
protected int calibrationTicks = 0;
private final Map<Integer, double[]> deadzoneCalibration = new HashMap<>();
private GamepadState.GyroState accumulatedGyroVelocity = GamepadState.GyroState.ORIGIN;
private GamepadState.GyroState accumulatedGyroVelocity = new GamepadState.GyroState();
public ControllerCalibrationScreen(Controller<?, ?> controller, Screen parent) {
this(controller, () -> parent);
@ -121,7 +121,7 @@ public class ControllerCalibrationScreen extends Screen {
if (stateChanged()) {
calibrationTicks = 0;
deadzoneCalibration.clear();
accumulatedGyroVelocity = GamepadState.GyroState.ORIGIN;
accumulatedGyroVelocity = new GamepadState.GyroState();
}
if (calibrationTicks < CALIBRATION_TIME) {
@ -154,7 +154,7 @@ public class ControllerCalibrationScreen extends Screen {
private void processGyroData() {
if (controller instanceof GamepadController gamepad && gamepad.hasGyro()) {
accumulatedGyroVelocity = accumulatedGyroVelocity.added(gamepad.drivers.gyroDriver().getGyroState());
accumulatedGyroVelocity.add(gamepad.drivers.gyroDriver().getGyroState());
}
}
@ -167,7 +167,7 @@ public class ControllerCalibrationScreen extends Screen {
private void generateGyroCalibration() {
if (controller instanceof GamepadController gamepad && gamepad.hasGyro()) {
gamepad.config().gyroCalibration = accumulatedGyroVelocity.divided(CALIBRATION_TIME);
gamepad.config().gyroCalibration = accumulatedGyroVelocity.div(CALIBRATION_TIME);
}
}

View File

@ -424,8 +424,8 @@ public class ControllerConfigScreenFactory {
.build())
.binding(gpCfgDef.gyroLookSensitivity, () -> gpCfg.gyroLookSensitivity, v -> gpCfg.gyroLookSensitivity = v)
.controller(opt -> FloatSliderControllerBuilder.create(opt)
.range(0f, 1f)
.step(0.05f)
.range(0f, 3f)
.step(0.1f)
.valueFormatter(percentOrOffFormatter))
.listener((opt, sensitivity) -> gyroOptions.forEach(o -> {
o.setAvailable(sensitivity > 0);

View File

@ -17,8 +17,10 @@ import net.minecraft.client.player.KeyboardInput;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import org.joml.Vector3f;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiFunction;
@ -27,12 +29,12 @@ public class InGameInputHandler {
private final Controller<?, ?> controller;
private final Minecraft minecraft;
private double lookInputX, lookInputY;
private boolean shouldShowPlayerList;
private GamepadState.GyroState gyroInput = GamepadState.GyroState.ORIGIN;
private double lookInputX, lookInputY; // in degrees per tick
private final GamepadState.GyroState gyroInput = new GamepadState.GyroState();
private boolean wasAiming;
private boolean shouldShowPlayerList;
private final NavigationHelper dropRepeatHelper;
public InGameInputHandler(Controller<?, ?> controller) {
@ -106,15 +108,6 @@ public class InGameInputHandler {
minecraft.levelRenderer.needsUpdate();
}
if (controller.bindings().INVENTORY.justPressed()) {
if (minecraft.gameMode.isServerControlledInventory()) {
minecraft.player.sendOpenInventory();
} else {
minecraft.getTutorial().onOpenInventory();
minecraft.setScreen(new InventoryScreen(minecraft.player));
}
}
}
if (controller.bindings().TOGGLE_HUD_VISIBILITY.justPressed()) {
minecraft.options.hideGui = !minecraft.options.hideGui;
@ -157,10 +150,12 @@ public class InGameInputHandler {
// normal look input
impulseY = controller.bindings().LOOK_DOWN.state() - controller.bindings().LOOK_UP.state();
impulseX = controller.bindings().LOOK_RIGHT.state() - controller.bindings().LOOK_LEFT.state();
impulseX *= Math.abs(impulseX);
impulseY *= Math.abs(impulseY);
impulseX *= Math.abs(impulseX) * 10f; // 10 degrees per second
impulseY *= Math.abs(impulseY) * 10f;
impulseX *= controller.config().horizontalLookSensitivity;
impulseY *= controller.config().verticalLookSensitivity;
if (controller.config().reduceAimingSensitivity && player != null && player.isUsingItem()) {
if (controller.config().reduceAimingSensitivity && player.isUsingItem()) {
float aimMultiplier = switch (player.getUseItem().getUseAnimation()) {
case BOW, CROSSBOW, SPEAR -> 0.6f;
case SPYGLASS -> 0.2f;
@ -177,23 +172,29 @@ public class InGameInputHandler {
if (gamepad.config().gyroRequiresButton) {
if (gamepad.bindings().GAMEPAD_GYRO_BUTTON.justPressed() || (isAiming && !wasAiming))
gyroInput = GamepadState.GyroState.ORIGIN;
gyroInput.set(0);
if (gamepad.bindings().GAMEPAD_GYRO_BUTTON.held() || isAiming) {
if (gamepad.config().relativeGyroMode)
gyroInput = gyroInput.added(gamepad.state().gyroDelta().multiplied(0.1f));
gyroInput.add(new Vector3f(gamepad.state().gyroDelta()).mul(0.1f));
else
gyroInput = gamepad.state().gyroDelta();
gyroInput.set(gamepad.state().gyroDelta());
useGyro = true;
}
} else {
gyroInput = gamepad.state().gyroDelta();
gyroInput.set(gamepad.state().gyroDelta());
useGyro = true;
}
if (useGyro) {
impulseY += -gyroInput.pitch() * gamepad.config().gyroLookSensitivity * (gamepad.config().invertGyroY ? -1 : 1);
impulseX += (-gyroInput.roll() + -gyroInput.yaw()) * gamepad.config().gyroLookSensitivity * (gamepad.config().invertGyroX ? -1 : 1);
// convert radians per second into degrees per tick
GamepadState.GyroState thisInput = new GamepadState.GyroState(gyroInput)
.mul(Mth.RAD_TO_DEG)
.div(20)
.mul(gamepad.config().gyroLookSensitivity);
impulseY += -thisInput.pitch() * (gamepad.config().invertGyroY ? -1 : 1);
impulseX += (-thisInput.roll() + -thisInput.yaw()) * (gamepad.config().invertGyroX ? -1 : 1);
}
}
@ -201,15 +202,15 @@ public class InGameInputHandler {
impulseX = lookInputModifier.modifyX(impulseX, controller);
impulseY = lookInputModifier.modifyY(impulseY, controller);
lookInputX = impulseX * controller.config().horizontalLookSensitivity * 65f;
lookInputY = impulseY * controller.config().verticalLookSensitivity * 65f;
lookInputX = impulseX;
lookInputY = impulseY;
wasAiming = isAiming;
}
public void processPlayerLook(float deltaTime) {
if (minecraft.player != null) {
minecraft.player.turn(lookInputX * deltaTime, lookInputY * deltaTime);
minecraft.player.turn(lookInputX / 0.15f * deltaTime, lookInputY / 0.15f * deltaTime);
}
}