1
0
forked from Clones/Controlify

✏️ Abstract GUID and controller name into drivers

This commit is contained in:
isXander
2023-06-04 12:28:44 +01:00
parent b68f718901
commit e9e83a8b5e
8 changed files with 2051 additions and 12 deletions

View File

@ -32,13 +32,13 @@ public class GamepadController extends AbstractController<GamepadState, GamepadC
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.drivers.printDrivers();
if (!this.name.startsWith(type().friendlyName()))
setName(this.drivers.nameProviderDriver().getName());
this.rumbleManager = new RumbleManager(this);
this.defaultConfig = new GamepadConfig();

View File

@ -4,13 +4,15 @@ import dev.isxander.controlify.controller.gamepad.GamepadState;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWGamepadState;
public class GLFWGamepadDriver implements BasicGamepadInputDriver {
public class GLFWGamepadDriver implements BasicGamepadInputDriver, NameProviderDriver, GUIDProvider {
private final int jid;
private final String guid;
private BasicGamepadState state = new BasicGamepadState(GamepadState.AxesState.EMPTY, GamepadState.ButtonState.EMPTY);
public GLFWGamepadDriver(int jid) {
this.jid = jid;
this.guid = GLFW.glfwGetJoystickGUID(jid);
}
@Override
@ -56,4 +58,24 @@ public class GLFWGamepadDriver implements BasicGamepadInputDriver {
public String getBasicGamepadDetails() {
return "GLFW Gamepad";
}
@Override
public String getName() {
return GLFW.glfwGetGamepadName(jid);
}
@Override
public String getNameProviderDetails() {
return "GLFW Gamepad";
}
@Override
public String getGUID() {
return guid;
}
@Override
public String getGUIDProviderDetails() {
return "GLFW Gamepad";
}
}

View File

@ -0,0 +1,7 @@
package dev.isxander.controlify.driver;
public interface GUIDProvider extends Driver {
String getGUID();
String getGUIDProviderDetails();
}

View File

@ -0,0 +1,61 @@
package dev.isxander.controlify.driver;
import dev.isxander.controlify.Controlify;
import net.minecraft.client.Minecraft;
import net.minecraft.server.packs.resources.Resource;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Map;
import java.util.stream.Collectors;
public class GameControllerDBDriver implements NameProviderDriver {
private static final Map<String, String> GUID_TO_NAME = generateNameMap();
private final String name;
public GameControllerDBDriver(String guid) {
this.name = GUID_TO_NAME.getOrDefault(guid, "Unknown Controller");
}
@Override
public void update() {
}
@Override
public String getName() {
return this.name;
}
@Override
public String getNameProviderDetails() {
return "gamecontrollerdb.txt";
}
public static boolean isSupported(String guid) {
return GUID_TO_NAME.containsKey(guid);
}
private static Map<String, String> generateNameMap() {
Resource resource = Minecraft.getInstance().getResourceManager()
.getResource(Controlify.id("controllers/gamecontrollerdb.txt"))
.orElseThrow();
try (BufferedReader reader = resource.openAsReader()) {
return reader
.lines()//.parallel() for some reason this causes deadlock https://stackoverflow.com/questions/34820066/why-does-parallel-stream-with-lambda-in-static-initializer-cause-a-deadlock
.filter(line -> !line.startsWith("#") && !line.isBlank())
.map(line -> line.split(","))
.filter(entry -> entry.length >= 2)
.collect(Collectors.toUnmodifiableMap(
entry -> entry[0], // guid
entry -> entry[1], // name,
(a, b) -> a // if there are duplicates, just use the first one
));
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}

View File

@ -8,7 +8,7 @@ import org.hid4java.HidDevice;
import java.util.*;
public record GamepadDrivers(BasicGamepadInputDriver basicGamepadInputDriver, GyroDriver gyroDriver, RumbleDriver rumbleDriver, BatteryDriver batteryDriver) {
public record GamepadDrivers(BasicGamepadInputDriver basicGamepadInputDriver, GyroDriver gyroDriver, RumbleDriver rumbleDriver, BatteryDriver batteryDriver, GUIDProvider guidProviderDriver, NameProviderDriver nameProviderDriver) {
public Set<Driver> getUniqueDrivers() {
Set<Driver> drivers = Sets.newIdentityHashSet();
drivers.addAll(List.of(basicGamepadInputDriver, gyroDriver, rumbleDriver, batteryDriver));
@ -17,17 +17,24 @@ public record GamepadDrivers(BasicGamepadInputDriver basicGamepadInputDriver, Gy
public void printDrivers() {
if (DebugProperties.PRINT_DRIVER) {
Controlify.LOGGER.info("Drivers in use: Basic Input = '{}', Gyro = '{}', Rumble = '{}', Battery = '{}'",
Controlify.LOGGER.info("Drivers in use: Basic Input = '{}', Gyro = '{}', Rumble = '{}', Battery = '{}', Name = '{}', GUID = '{}'",
basicGamepadInputDriver.getBasicGamepadDetails(),
gyroDriver.getGyroDetails(),
rumbleDriver.getRumbleDetails(),
batteryDriver.getBatteryDriverDetails()
batteryDriver.getBatteryDriverDetails(),
nameProviderDriver.getNameProviderDetails(),
guidProviderDriver.getGUIDProviderDetails()
);
}
}
public static GamepadDrivers forController(int jid, Optional<HidDevice> hid) {
BasicGamepadInputDriver basicGamepadInputDriver = new GLFWGamepadDriver(jid);
GLFWGamepadDriver glfwDriver = new GLFWGamepadDriver(jid);
BasicGamepadInputDriver basicGamepadInputDriver = glfwDriver;
NameProviderDriver nameProviderDriver = glfwDriver;
GUIDProvider guidProviderDriver = glfwDriver;
GyroDriver gyroDriver = GyroDriver.UNSUPPORTED;
RumbleDriver rumbleDriver = RumbleDriver.UNSUPPORTED;
BatteryDriver batteryDriver = BatteryDriver.UNSUPPORTED;
@ -37,13 +44,20 @@ public record GamepadDrivers(BasicGamepadInputDriver basicGamepadInputDriver, Gy
gyroDriver = sdl2Driver;
rumbleDriver = sdl2Driver;
batteryDriver = sdl2Driver;
// SDL2 bypasses XInput abstraction
guidProviderDriver = sdl2Driver;
}
// broken
// TODO: Fix Steam Deck driver
if (hid.isPresent() && SteamDeckDriver.isSteamDeck(hid.get()) && false) {
gyroDriver = new SteamDeckDriver(hid.get());
}
return new GamepadDrivers(basicGamepadInputDriver, gyroDriver, rumbleDriver, batteryDriver);
if (GameControllerDBDriver.isSupported(guidProviderDriver.getGUID())) {
nameProviderDriver = new GameControllerDBDriver(guidProviderDriver.getGUID());
}
return new GamepadDrivers(basicGamepadInputDriver, gyroDriver, rumbleDriver, batteryDriver, guidProviderDriver, nameProviderDriver);
}
}

View File

@ -0,0 +1,7 @@
package dev.isxander.controlify.driver;
public interface NameProviderDriver extends Driver {
String getName();
String getNameProviderDetails();
}

View File

@ -6,13 +6,15 @@ import dev.isxander.controlify.controller.gamepad.GamepadState;
import dev.isxander.controlify.debug.DebugProperties;
import org.libsdl.SDL;
public class SDL2GamepadDriver implements GyroDriver, RumbleDriver, BatteryDriver {
public class SDL2GamepadDriver implements GyroDriver, RumbleDriver, BatteryDriver, GUIDProvider {
private final long ptrGamepad;
private GamepadState.GyroState gyroDelta;
private GamepadState.GyroState gyroDelta = new GamepadState.GyroState(0, 0, 0);
private final boolean isGyroSupported, isRumbleSupported;
private final String guid;
public SDL2GamepadDriver(int jid) {
this.ptrGamepad = SDL.SDL_GameControllerOpen(jid);
this.guid = SDL.SDL_JoystickGUIDString(SDL.SDL_GameControllerGetJoystick(ptrGamepad));
this.isGyroSupported = SDL.SDL_GameControllerHasSensor(ptrGamepad, SDL.SDL_SENSOR_GYRO);
this.isRumbleSupported = SDL.SDL_GameControllerHasRumble(ptrGamepad);
@ -75,6 +77,11 @@ public class SDL2GamepadDriver implements GyroDriver, RumbleDriver, BatteryDrive
return isRumbleSupported;
}
@Override
public String getGUID() {
return guid;
}
@Override
public void close() {
SDL.SDL_GameControllerClose(ptrGamepad);
@ -94,4 +101,9 @@ public class SDL2GamepadDriver implements GyroDriver, RumbleDriver, BatteryDrive
public String getBatteryDriverDetails() {
return "SDL2gp";
}
@Override
public String getGUIDProviderDetails() {
return "SDL2gp";
}
}