forked from Clones/Controlify
✏️ New ControllerManager class to store controllers
This commit is contained in:
@ -20,7 +20,7 @@ quilt_json5 = "1.0.3"
|
|||||||
sodium = "mc1.19.4-0.4.10"
|
sodium = "mc1.19.4-0.4.10"
|
||||||
iris = "1.5.2+1.19.4"
|
iris = "1.5.2+1.19.4"
|
||||||
immediately_fast = "1.1.10+1.19.4"
|
immediately_fast = "1.1.10+1.19.4"
|
||||||
sdl2_jni = "2.26.4-4"
|
sdl2_jni = "2.26.5-18"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" }
|
minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" }
|
||||||
|
@ -7,11 +7,10 @@ import dev.isxander.controlify.api.entrypoint.ControlifyEntrypoint;
|
|||||||
import dev.isxander.controlify.config.gui.ControllerBindHandler;
|
import dev.isxander.controlify.config.gui.ControllerBindHandler;
|
||||||
import dev.isxander.controlify.controller.Controller;
|
import dev.isxander.controlify.controller.Controller;
|
||||||
import dev.isxander.controlify.controller.ControllerState;
|
import dev.isxander.controlify.controller.ControllerState;
|
||||||
import dev.isxander.controlify.controller.joystick.CompoundJoystickController;
|
|
||||||
import dev.isxander.controlify.controller.sdl2.SDL2NativesManager;
|
import dev.isxander.controlify.controller.sdl2.SDL2NativesManager;
|
||||||
import dev.isxander.controlify.debug.DebugProperties;
|
import dev.isxander.controlify.debug.DebugProperties;
|
||||||
import dev.isxander.controlify.gui.screen.ControllerDeadzoneCalibrationScreen;
|
import dev.isxander.controlify.gui.screen.ControllerDeadzoneCalibrationScreen;
|
||||||
import dev.isxander.controlify.gui.screen.VibrationOnboardingScreen;
|
import dev.isxander.controlify.gui.screen.SDLOnboardingScreen;
|
||||||
import dev.isxander.controlify.screenop.ScreenProcessorProvider;
|
import dev.isxander.controlify.screenop.ScreenProcessorProvider;
|
||||||
import dev.isxander.controlify.config.ControlifyConfig;
|
import dev.isxander.controlify.config.ControlifyConfig;
|
||||||
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
||||||
@ -127,7 +126,7 @@ public class Controlify implements ControlifyApi {
|
|||||||
// find already connected controllers
|
// find already connected controllers
|
||||||
for (int jid = 0; jid <= GLFW.GLFW_JOYSTICK_LAST; jid++) {
|
for (int jid = 0; jid <= GLFW.GLFW_JOYSTICK_LAST; jid++) {
|
||||||
if (GLFW.glfwJoystickPresent(jid)) {
|
if (GLFW.glfwJoystickPresent(jid)) {
|
||||||
var controllerOpt = Controller.createOrGet(jid, controllerHIDService.fetchType());
|
var controllerOpt = ControllerManager.createOrGet(jid, controllerHIDService.fetchType(jid));
|
||||||
if (controllerOpt.isEmpty()) continue;
|
if (controllerOpt.isEmpty()) continue;
|
||||||
var controller = controllerOpt.get();
|
var controller = controllerOpt.get();
|
||||||
|
|
||||||
@ -145,14 +144,12 @@ public class Controlify implements ControlifyApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkCompoundJoysticks();
|
if (ControllerManager.getConnectedControllers().isEmpty()) {
|
||||||
|
|
||||||
if (Controller.CONTROLLERS.isEmpty()) {
|
|
||||||
LOGGER.info("No controllers found.");
|
LOGGER.info("No controllers found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getCurrentController().isEmpty() && config().isFirstLaunch()) {
|
if (getCurrentController().isEmpty() && config().isFirstLaunch()) {
|
||||||
this.setCurrentController(Controller.CONTROLLERS.values().stream().findFirst().orElse(null));
|
this.setCurrentController(ControllerManager.getConnectedControllers().stream().findFirst().orElse(null));
|
||||||
} else {
|
} else {
|
||||||
// setCurrentController saves config
|
// setCurrentController saves config
|
||||||
config().saveIfDirty();
|
config().saveIfDirty();
|
||||||
@ -213,7 +210,7 @@ public class Controlify implements ControlifyApi {
|
|||||||
|
|
||||||
boolean outOfFocus = !config().globalSettings().outOfFocusInput && !client.isWindowActive();
|
boolean outOfFocus = !config().globalSettings().outOfFocusInput && !client.isWindowActive();
|
||||||
|
|
||||||
for (var controller : Controller.CONTROLLERS.values()) {
|
for (var controller : ControllerManager.getConnectedControllers()) {
|
||||||
if (!outOfFocus)
|
if (!outOfFocus)
|
||||||
wrapControllerError(controller::updateState, "Updating controller state", controller);
|
wrapControllerError(controller::updateState, "Updating controller state", controller);
|
||||||
else
|
else
|
||||||
@ -295,7 +292,7 @@ public class Controlify implements ControlifyApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onControllerHotplugged(int jid) {
|
private void onControllerHotplugged(int jid) {
|
||||||
var controllerOpt = Controller.createOrGet(jid, controllerHIDService.fetchType());
|
var controllerOpt = ControllerManager.createOrGet(jid, controllerHIDService.fetchType(jid));
|
||||||
if (controllerOpt.isEmpty()) return;
|
if (controllerOpt.isEmpty()) return;
|
||||||
var controller = controllerOpt.get();
|
var controller = controllerOpt.get();
|
||||||
|
|
||||||
@ -308,9 +305,7 @@ public class Controlify implements ControlifyApi {
|
|||||||
config().setDirty();
|
config().setDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
checkCompoundJoysticks();
|
if (ControllerManager.getConnectedControllers().size() == 1) {
|
||||||
|
|
||||||
if (Controller.CONTROLLERS.size() == 1) {
|
|
||||||
this.setCurrentController(controller);
|
this.setCurrentController(controller);
|
||||||
|
|
||||||
ToastUtils.sendToast(
|
ToastUtils.sendToast(
|
||||||
@ -325,12 +320,12 @@ public class Controlify implements ControlifyApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onControllerDisconnect(int jid) {
|
private void onControllerDisconnect(int jid) {
|
||||||
Controller.CONTROLLERS.values().stream().filter(controller -> controller.joystickId() == jid).findAny().ifPresent(controller -> {
|
ControllerManager.getConnectedControllers().stream().filter(controller -> controller.joystickId() == jid).findAny().ifPresent(controller -> {
|
||||||
Controller.remove(controller);
|
ControllerManager.disconnect(controller);
|
||||||
|
|
||||||
controller.hidInfo().ifPresent(controllerHIDService::unconsumeController);
|
controller.hidInfo().ifPresent(controllerHIDService::unconsumeController);
|
||||||
|
|
||||||
setCurrentController(Controller.CONTROLLERS.values().stream().findFirst().orElse(null));
|
setCurrentController(ControllerManager.getConnectedControllers().stream().findFirst().orElse(null));
|
||||||
LOGGER.info("Controller disconnected: " + controller.name());
|
LOGGER.info("Controller disconnected: " + controller.name());
|
||||||
this.setInputMode(currentController == null ? InputMode.KEYBOARD_MOUSE : InputMode.CONTROLLER);
|
this.setInputMode(currentController == null ? InputMode.KEYBOARD_MOUSE : InputMode.CONTROLLER);
|
||||||
|
|
||||||
@ -340,28 +335,6 @@ public class Controlify implements ControlifyApi {
|
|||||||
false
|
false
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
checkCompoundJoysticks();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkCompoundJoysticks() {
|
|
||||||
config().getCompoundJoysticks().values().forEach(info -> {
|
|
||||||
try {
|
|
||||||
if (info.isLoaded() && !info.canBeUsed()) {
|
|
||||||
LOGGER.warn("Unloading compound joystick " + info.friendlyName() + " due to missing controllers.");
|
|
||||||
Controller.CONTROLLERS.remove(info.type().mappingId());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!info.isLoaded() && info.canBeUsed()) {
|
|
||||||
LOGGER.info("Loading compound joystick " + info.type().mappingId() + ".");
|
|
||||||
CompoundJoystickController controller = info.attemptCreate().orElseThrow();
|
|
||||||
Controller.CONTROLLERS.put(info.type().mappingId(), controller);
|
|
||||||
config().loadOrCreateControllerData(controller);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void askToSwitchController(Controller<?, ?> controller) {
|
private void askToSwitchController(Controller<?, ?> controller) {
|
||||||
|
107
src/main/java/dev/isxander/controlify/ControllerManager.java
Normal file
107
src/main/java/dev/isxander/controlify/ControllerManager.java
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
package dev.isxander.controlify;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import dev.isxander.controlify.controller.Controller;
|
||||||
|
import dev.isxander.controlify.controller.gamepad.GamepadController;
|
||||||
|
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
||||||
|
import dev.isxander.controlify.controller.joystick.CompoundJoystickController;
|
||||||
|
import dev.isxander.controlify.controller.joystick.SingleJoystickController;
|
||||||
|
import dev.isxander.controlify.debug.DebugProperties;
|
||||||
|
import dev.isxander.controlify.utils.DebugLog;
|
||||||
|
import net.minecraft.CrashReport;
|
||||||
|
import net.minecraft.CrashReportCategory;
|
||||||
|
import net.minecraft.ReportedException;
|
||||||
|
import org.hid4java.HidDevice;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public final class ControllerManager {
|
||||||
|
private ControllerManager() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static Map<String, Controller<?, ?>> CONTROLLERS = new HashMap<>();
|
||||||
|
|
||||||
|
public static Optional<Controller<?, ?>> createOrGet(int joystickId, ControllerHIDService.ControllerHIDInfo hidInfo) {
|
||||||
|
try {
|
||||||
|
Optional<String> uid = hidInfo.createControllerUID();
|
||||||
|
if (uid.isPresent() && CONTROLLERS.containsKey(uid.get())) {
|
||||||
|
return Optional.of(CONTROLLERS.get(uid.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hidInfo.type().dontLoad()) {
|
||||||
|
DebugLog.log("Preventing load of controller #" + joystickId + " because its type prevents loading.");
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GLFW.glfwJoystickIsGamepad(joystickId) && !DebugProperties.FORCE_JOYSTICK && !hidInfo.type().forceJoystick()) {
|
||||||
|
GamepadController controller = new GamepadController(joystickId, hidInfo);
|
||||||
|
CONTROLLERS.put(controller.uid(), controller);
|
||||||
|
checkCompoundJoysticks();
|
||||||
|
return Optional.of(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
SingleJoystickController controller = new SingleJoystickController(joystickId, hidInfo);
|
||||||
|
CONTROLLERS.put(controller.uid(), controller);
|
||||||
|
checkCompoundJoysticks();
|
||||||
|
return Optional.of(controller);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
CrashReport crashReport = CrashReport.forThrowable(e, "Creating controller #" + joystickId);
|
||||||
|
CrashReportCategory category = crashReport.addCategory("Controller Info");
|
||||||
|
category.setDetail("Joystick ID", joystickId);
|
||||||
|
category.setDetail("Controller identification", hidInfo.type());
|
||||||
|
category.setDetail("HID path", hidInfo.hidDevice().map(HidDevice::getPath).orElse("N/A"));
|
||||||
|
category.setDetail("HID service status", Controlify.instance().controllerHIDService().isDisabled() ? "Disabled" : "Enabled");
|
||||||
|
category.setDetail("GLFW name", Optional.ofNullable(GLFW.glfwGetJoystickName(joystickId)).orElse("N/A"));
|
||||||
|
throw new ReportedException(crashReport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void disconnect(Controller<?, ?> controller) {
|
||||||
|
controller.close();
|
||||||
|
CONTROLLERS.remove(controller.uid(), controller);
|
||||||
|
|
||||||
|
checkCompoundJoysticks();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void disconnect(String uid) {
|
||||||
|
Controller<?, ?> prev = CONTROLLERS.remove(uid);
|
||||||
|
if (prev != null) {
|
||||||
|
prev.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
checkCompoundJoysticks();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Controller<?, ?>> getConnectedControllers() {
|
||||||
|
return ImmutableList.copyOf(CONTROLLERS.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isControllerConnected(String uid) {
|
||||||
|
return CONTROLLERS.containsKey(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void checkCompoundJoysticks() {
|
||||||
|
Controlify.instance().config().getCompoundJoysticks().values().forEach(info -> {
|
||||||
|
try {
|
||||||
|
if (info.isLoaded() && !info.canBeUsed()) {
|
||||||
|
Controlify.LOGGER.warn("Unloading compound joystick " + info.friendlyName() + " due to missing controllers.");
|
||||||
|
disconnect(info.type().mappingId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info.isLoaded() && info.canBeUsed()) {
|
||||||
|
Controlify.LOGGER.info("Loading compound joystick " + info.type().mappingId() + ".");
|
||||||
|
CompoundJoystickController controller = info.attemptCreate().orElseThrow();
|
||||||
|
CONTROLLERS.put(info.type().mappingId(), controller);
|
||||||
|
Controlify.instance().config().loadOrCreateControllerData(controller);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@ package dev.isxander.controlify.config;
|
|||||||
|
|
||||||
import com.google.gson.*;
|
import com.google.gson.*;
|
||||||
import dev.isxander.controlify.Controlify;
|
import dev.isxander.controlify.Controlify;
|
||||||
|
import dev.isxander.controlify.ControllerManager;
|
||||||
import dev.isxander.controlify.controller.Controller;
|
import dev.isxander.controlify.controller.Controller;
|
||||||
import dev.isxander.controlify.controller.joystick.CompoundJoystickInfo;
|
import dev.isxander.controlify.controller.joystick.CompoundJoystickInfo;
|
||||||
import dev.isxander.controlify.utils.DebugLog;
|
import dev.isxander.controlify.utils.DebugLog;
|
||||||
@ -78,7 +79,7 @@ public class ControlifyConfig {
|
|||||||
|
|
||||||
JsonObject newControllerData = controllerData.deepCopy(); // we use the old config, so we don't lose disconnected controller data
|
JsonObject newControllerData = controllerData.deepCopy(); // we use the old config, so we don't lose disconnected controller data
|
||||||
|
|
||||||
for (var controller : Controller.CONTROLLERS.values()) {
|
for (var controller : ControllerManager.getConnectedControllers()) {
|
||||||
// `add` replaces if already existing
|
// `add` replaces if already existing
|
||||||
newControllerData.add(controller.uid(), generateControllerConfig(controller));
|
newControllerData.add(controller.uid(), generateControllerConfig(controller));
|
||||||
}
|
}
|
||||||
@ -111,7 +112,7 @@ public class ControlifyConfig {
|
|||||||
JsonObject controllers = object.getAsJsonObject("controllers");
|
JsonObject controllers = object.getAsJsonObject("controllers");
|
||||||
if (controllers != null) {
|
if (controllers != null) {
|
||||||
this.controllerData = controllers;
|
this.controllerData = controllers;
|
||||||
for (var controller : Controller.CONTROLLERS.values()) {
|
for (var controller : ControllerManager.getConnectedControllers()) {
|
||||||
loadOrCreateControllerData(controller);
|
loadOrCreateControllerData(controller);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -2,9 +2,11 @@ package dev.isxander.controlify.config.gui;
|
|||||||
|
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import dev.isxander.controlify.Controlify;
|
import dev.isxander.controlify.Controlify;
|
||||||
|
import dev.isxander.controlify.ControllerManager;
|
||||||
import dev.isxander.controlify.api.bind.ControllerBinding;
|
import dev.isxander.controlify.api.bind.ControllerBinding;
|
||||||
import dev.isxander.controlify.bindings.BindContext;
|
import dev.isxander.controlify.bindings.BindContext;
|
||||||
import dev.isxander.controlify.config.GlobalSettings;
|
import dev.isxander.controlify.config.GlobalSettings;
|
||||||
|
import dev.isxander.controlify.controller.BatteryLevel;
|
||||||
import dev.isxander.controlify.controller.Controller;
|
import dev.isxander.controlify.controller.Controller;
|
||||||
import dev.isxander.controlify.controller.ControllerConfig;
|
import dev.isxander.controlify.controller.ControllerConfig;
|
||||||
import dev.isxander.controlify.controller.ControllerState;
|
import dev.isxander.controlify.controller.ControllerState;
|
||||||
@ -12,7 +14,9 @@ import dev.isxander.controlify.controller.gamepad.GamepadController;
|
|||||||
import dev.isxander.controlify.controller.gamepad.BuiltinGamepadTheme;
|
import dev.isxander.controlify.controller.gamepad.BuiltinGamepadTheme;
|
||||||
import dev.isxander.controlify.controller.joystick.SingleJoystickController;
|
import dev.isxander.controlify.controller.joystick.SingleJoystickController;
|
||||||
import dev.isxander.controlify.controller.joystick.mapping.JoystickMapping;
|
import dev.isxander.controlify.controller.joystick.mapping.JoystickMapping;
|
||||||
|
import dev.isxander.controlify.controller.sdl2.SDL2NativesManager;
|
||||||
import dev.isxander.controlify.gui.screen.ControllerDeadzoneCalibrationScreen;
|
import dev.isxander.controlify.gui.screen.ControllerDeadzoneCalibrationScreen;
|
||||||
|
import dev.isxander.controlify.gui.screen.SDLOnboardingScreen;
|
||||||
import dev.isxander.controlify.reacharound.ReachAroundMode;
|
import dev.isxander.controlify.reacharound.ReachAroundMode;
|
||||||
import dev.isxander.controlify.rumble.BasicRumbleEffect;
|
import dev.isxander.controlify.rumble.BasicRumbleEffect;
|
||||||
import dev.isxander.controlify.rumble.RumbleSource;
|
import dev.isxander.controlify.rumble.RumbleSource;
|
||||||
@ -58,7 +62,7 @@ public class YACLHelper {
|
|||||||
.name(Component.translatable("controlify.gui.current_controller"))
|
.name(Component.translatable("controlify.gui.current_controller"))
|
||||||
.tooltip(Component.translatable("controlify.gui.current_controller.tooltip"))
|
.tooltip(Component.translatable("controlify.gui.current_controller.tooltip"))
|
||||||
.binding(Controlify.instance().getCurrentController().orElse(Controller.DUMMY), () -> Controlify.instance().getCurrentController().orElse(Controller.DUMMY), v -> Controlify.instance().setCurrentController(v))
|
.binding(Controlify.instance().getCurrentController().orElse(Controller.DUMMY), () -> Controlify.instance().getCurrentController().orElse(Controller.DUMMY), v -> Controlify.instance().setCurrentController(v))
|
||||||
.controller(opt -> new CyclingListController<>(opt, Iterables.concat(List.of(Controller.DUMMY), Controller.CONTROLLERS.values().stream().filter(Controller::canBeUsed).toList()), c -> Component.literal(c == Controller.DUMMY ? "Disabled" : c.name())))
|
.controller(opt -> new CyclingListController<>(opt, Iterables.concat(List.of(Controller.DUMMY), ControllerManager.getConnectedControllers().stream().filter(Controller::canBeUsed).toList()), c -> Component.literal(c == Controller.DUMMY ? "Disabled" : c.name())))
|
||||||
.build())
|
.build())
|
||||||
.option(globalVibrationOption = Option.createBuilder(boolean.class)
|
.option(globalVibrationOption = Option.createBuilder(boolean.class)
|
||||||
.name(Component.translatable("controlify.gui.load_vibration_natives"))
|
.name(Component.translatable("controlify.gui.load_vibration_natives"))
|
||||||
@ -102,7 +106,7 @@ public class YACLHelper {
|
|||||||
|
|
||||||
yacl.category(globalCategory.build());
|
yacl.category(globalCategory.build());
|
||||||
|
|
||||||
for (var controller : Controller.CONTROLLERS.values()) {
|
for (var controller : ControllerManager.getConnectedControllers()) {
|
||||||
yacl.category(createControllerCategory(controller, globalVibrationOption));
|
yacl.category(createControllerCategory(controller, globalVibrationOption));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,15 +4,10 @@ import com.google.common.reflect.TypeToken;
|
|||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import dev.isxander.controlify.Controlify;
|
import dev.isxander.controlify.Controlify;
|
||||||
import dev.isxander.controlify.InputMode;
|
import dev.isxander.controlify.ControllerManager;
|
||||||
import dev.isxander.controlify.api.ControlifyApi;
|
|
||||||
import dev.isxander.controlify.bindings.ControllerBindings;
|
import dev.isxander.controlify.bindings.ControllerBindings;
|
||||||
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
import dev.isxander.controlify.controller.hid.ControllerHIDService;
|
||||||
import dev.isxander.controlify.controller.sdl2.SDL2NativesManager;
|
|
||||||
import dev.isxander.controlify.rumble.RumbleCapable;
|
import dev.isxander.controlify.rumble.RumbleCapable;
|
||||||
import dev.isxander.controlify.rumble.RumbleManager;
|
|
||||||
import dev.isxander.controlify.rumble.RumbleSource;
|
|
||||||
import org.libsdl.SDL;
|
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@ -63,7 +58,7 @@ public abstract class AbstractController<S extends ControllerState, C extends Co
|
|||||||
protected void setName(String name) {
|
protected void setName(String name) {
|
||||||
String uniqueName = name;
|
String uniqueName = name;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (CONTROLLERS.values().stream().map(Controller::name).anyMatch(uniqueName::equalsIgnoreCase)) {
|
while (ControllerManager.getConnectedControllers().stream().map(Controller::name).anyMatch(uniqueName::equalsIgnoreCase)) {
|
||||||
uniqueName = name + " (" + i++ + ")";
|
uniqueName = name + " (" + i++ + ")";
|
||||||
if (i > 1000) throw new IllegalStateException("Could not find a unique name for controller " + name + " (" + uid() + ")! (tried " + i + " times)");
|
if (i > 1000) throw new IllegalStateException("Could not find a unique name for controller " + name + " (" + uid() + ")! (tried " + i + " times)");
|
||||||
}
|
}
|
||||||
|
@ -54,46 +54,6 @@ public interface Controller<S extends ControllerState, C extends ControllerConfi
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Controller<?, ?>> CONTROLLERS = new HashMap<>();
|
|
||||||
|
|
||||||
static Optional<Controller<?, ?>> createOrGet(int joystickId, ControllerHIDService.ControllerHIDInfo hidInfo) {
|
|
||||||
try {
|
|
||||||
Optional<String> uid = hidInfo.createControllerUID();
|
|
||||||
if (uid.isPresent() && CONTROLLERS.containsKey(uid.get())) {
|
|
||||||
return Optional.of(CONTROLLERS.get(uid.get()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hidInfo.type().dontLoad()) {
|
|
||||||
DebugLog.log("Preventing load of controller #" + joystickId + " because its type prevents loading.");
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GLFW.glfwJoystickIsGamepad(joystickId) && !DebugProperties.FORCE_JOYSTICK && !hidInfo.type().forceJoystick()) {
|
|
||||||
GamepadController controller = new GamepadController(joystickId, hidInfo);
|
|
||||||
CONTROLLERS.put(controller.uid(), controller);
|
|
||||||
return Optional.of(controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
SingleJoystickController controller = new SingleJoystickController(joystickId, hidInfo);
|
|
||||||
CONTROLLERS.put(controller.uid(), controller);
|
|
||||||
return Optional.of(controller);
|
|
||||||
} catch (Throwable e) {
|
|
||||||
CrashReport crashReport = CrashReport.forThrowable(e, "Creating controller #" + joystickId);
|
|
||||||
CrashReportCategory category = crashReport.addCategory("Controller Info");
|
|
||||||
category.setDetail("Joystick ID", joystickId);
|
|
||||||
category.setDetail("Controller identification", hidInfo.type());
|
|
||||||
category.setDetail("HID path", hidInfo.hidDevice().map(HidDevice::getPath).orElse("N/A"));
|
|
||||||
category.setDetail("HID service status", Controlify.instance().controllerHIDService().isDisabled() ? "Disabled" : "Enabled");
|
|
||||||
category.setDetail("GLFW name", Optional.ofNullable(GLFW.glfwGetJoystickName(joystickId)).orElse("N/A"));
|
|
||||||
throw new ReportedException(crashReport);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void remove(Controller<?, ?> controller) {
|
|
||||||
controller.close();
|
|
||||||
CONTROLLERS.remove(controller.uid(), controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
Controller<?, ?> DUMMY = new Controller<>() {
|
Controller<?, ?> DUMMY = new Controller<>() {
|
||||||
private final ControllerBindings<ControllerState> bindings = new ControllerBindings<>(this);
|
private final ControllerBindings<ControllerState> bindings = new ControllerBindings<>(this);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package dev.isxander.controlify.controller.joystick;
|
package dev.isxander.controlify.controller.joystick;
|
||||||
|
|
||||||
|
import dev.isxander.controlify.ControllerManager;
|
||||||
import dev.isxander.controlify.controller.Controller;
|
import dev.isxander.controlify.controller.Controller;
|
||||||
import dev.isxander.controlify.controller.ControllerType;
|
import dev.isxander.controlify.controller.ControllerType;
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ public record CompoundJoystickInfo(Collection<String> joystickUids, String frien
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean canBeUsed() {
|
public boolean canBeUsed() {
|
||||||
List<Controller<?, ?>> joysticks = Controller.CONTROLLERS.values().stream().filter(c -> joystickUids.contains(c.uid())).toList();
|
List<Controller<?, ?>> joysticks = ControllerManager.getConnectedControllers().stream().filter(c -> joystickUids.contains(c.uid())).toList();
|
||||||
if (joysticks.size() != joystickUids().size()) {
|
if (joysticks.size() != joystickUids().size()) {
|
||||||
return false; // not all controllers are connected
|
return false; // not all controllers are connected
|
||||||
}
|
}
|
||||||
@ -25,13 +26,13 @@ public record CompoundJoystickInfo(Collection<String> joystickUids, String frien
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isLoaded() {
|
public boolean isLoaded() {
|
||||||
return Controller.CONTROLLERS.containsKey(createUID(joystickUids));
|
return ControllerManager.isControllerConnected(createUID(joystickUids));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<CompoundJoystickController> attemptCreate() {
|
public Optional<CompoundJoystickController> attemptCreate() {
|
||||||
if (!canBeUsed()) return Optional.empty();
|
if (!canBeUsed()) return Optional.empty();
|
||||||
|
|
||||||
List<Integer> joystickIDs = Controller.CONTROLLERS.values().stream()
|
List<Integer> joystickIDs = ControllerManager.getConnectedControllers().stream()
|
||||||
.filter(c -> joystickUids.contains(c.uid()))
|
.filter(c -> joystickUids.contains(c.uid()))
|
||||||
.map(Controller::joystickId)
|
.map(Controller::joystickId)
|
||||||
.toList();
|
.toList();
|
||||||
|
@ -2,14 +2,13 @@ package dev.isxander.controlify.mixins.core;
|
|||||||
|
|
||||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||||
import dev.isxander.controlify.Controlify;
|
import dev.isxander.controlify.Controlify;
|
||||||
|
import dev.isxander.controlify.ControllerManager;
|
||||||
import dev.isxander.controlify.controller.Controller;
|
import dev.isxander.controlify.controller.Controller;
|
||||||
import dev.isxander.controlify.gui.screen.BetaNoticeScreen;
|
import dev.isxander.controlify.gui.screen.BetaNoticeScreen;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.components.toasts.SystemToast;
|
|
||||||
import net.minecraft.client.gui.components.toasts.ToastComponent;
|
import net.minecraft.client.gui.components.toasts.ToastComponent;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import net.minecraft.client.main.GameConfig;
|
import net.minecraft.client.main.GameConfig;
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.server.packs.resources.ReloadInstance;
|
import net.minecraft.server.packs.resources.ReloadInstance;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
@ -54,18 +53,8 @@ public abstract class MinecraftMixin {
|
|||||||
setScreen(new BetaNoticeScreen());
|
setScreen(new BetaNoticeScreen());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ModifyExpressionValue(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/packs/resources/ReloadableResourceManager;createReload(Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;Ljava/util/concurrent/CompletableFuture;Ljava/util/List;)Lnet/minecraft/server/packs/resources/ReloadInstance;"))
|
|
||||||
private ReloadInstance onReloadResources(ReloadInstance resourceReload) {
|
|
||||||
resourceReload.done().thenRun(() -> {
|
|
||||||
if (Controlify.instance().controllerHIDService().isDisabled()) {
|
|
||||||
getToasts().addToast(SystemToast.multiline((Minecraft) (Object) this, SystemToast.SystemToastIds.UNSECURE_SERVER_WARNING, Component.translatable("controlify.error.hid"), Component.translatable("controlify.error.hid.desc")));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return resourceReload;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject(method = "close", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/telemetry/ClientTelemetryManager;close()V"))
|
@Inject(method = "close", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/telemetry/ClientTelemetryManager;close()V"))
|
||||||
private void onMinecraftClose(CallbackInfo ci) {
|
private void onMinecraftClose(CallbackInfo ci) {
|
||||||
Controller.CONTROLLERS.values().forEach(Controller::close);
|
ControllerManager.getConnectedControllers().forEach(Controller::close);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user