1
0
forked from Clones/Controlify

Unknown controller submission screen.

This commit is contained in:
isXander
2023-08-02 23:16:51 +01:00
parent 90710d1510
commit 19cdf59666
9 changed files with 257 additions and 16 deletions

View File

@ -11,6 +11,7 @@ import dev.isxander.controlify.controller.sdl2.SDL2NativesManager;
import dev.isxander.controlify.debug.DebugProperties;
import dev.isxander.controlify.gui.screen.ControllerCalibrationScreen;
import dev.isxander.controlify.gui.screen.SDLOnboardingScreen;
import dev.isxander.controlify.gui.screen.SubmitUnknownControllerScreen;
import dev.isxander.controlify.ingame.ControllerPlayerMovement;
import dev.isxander.controlify.reacharound.ReachAroundHandler;
import dev.isxander.controlify.reacharound.ReachAroundMode;
@ -43,6 +44,7 @@ import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.libsdl.SDL;
import org.lwjgl.glfw.GLFW;
import java.util.ArrayDeque;
@ -168,6 +170,10 @@ public class Controlify implements ControlifyApi {
config().loadOrCreateControllerData(controller);
if (SubmitUnknownControllerScreen.canSubmit(controller)) {
minecraft.setScreen(new SubmitUnknownControllerScreen(controller, minecraft.screen));
}
if (controller.uid().equals(config().currentControllerUid()))
setCurrentController(controller);
@ -379,6 +385,10 @@ public class Controlify implements ControlifyApi {
config().loadOrCreateControllerData(controller);
if (SubmitUnknownControllerScreen.canSubmit(controller)) {
minecraft.setScreen(new SubmitUnknownControllerScreen(controller, minecraft.screen));
}
canDiscoverControllers = false;
if (config().globalSettings().delegateSetup) {
config().globalSettings().delegateSetup = false;

View File

@ -36,6 +36,8 @@ public abstract class ControllerConfig implements Serializable {
public boolean mixedInput = false;
public boolean dontShowControllerSubmission = false;
public abstract void setDeadzone(int axis, float deadzone);
public abstract float getDeadzone(int axis);

View File

@ -18,7 +18,12 @@ public record ControllerType(String friendlyName, String mappingId, String theme
private static final ResourceLocation hidDbLocation = new ResourceLocation("controlify", "controllers/controller_identification.json5");
public static ControllerType getTypeForHID(HIDIdentifier hid) {
return getTypeMap().getOrDefault(hid, ControllerType.UNKNOWN);
if (getTypeMap().containsKey(hid)) {
return getTypeMap().get(hid);
} else {
Log.LOGGER.warn("Controller found via USB hardware scan, but it was not found in the controller identification database! (HID: {})", hid);
return ControllerType.UNKNOWN;
}
}
public static void ensureTypeMapFilled() {

View File

@ -0,0 +1,7 @@
package dev.isxander.controlify.gui.screen;
public interface CustomWarningTitlePadding {
default int getMessageY() {
return 70;
}
}

View File

@ -0,0 +1,195 @@
package dev.isxander.controlify.gui.screen;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import dev.isxander.controlify.Controlify;
import dev.isxander.controlify.controller.Controller;
import dev.isxander.controlify.controller.ControllerType;
import dev.isxander.controlify.hid.HIDDevice;
import dev.isxander.controlify.utils.Log;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.multiplayer.WarningScreen;
import net.minecraft.network.chat.CommonComponents;
import net.minecraft.network.chat.Component;
import org.lwjgl.glfw.GLFW;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.regex.Pattern;
public class SubmitUnknownControllerScreen extends WarningScreen implements CustomWarningTitlePadding {
public static final String SUBMISSION_URL = "https://api-controlify.isxander.dev/api/v1/submit";
public static final Pattern NAME_PATTERN = Pattern.compile("^[\\w\\- ]{3,32}$");
private final Controller<?, ?> controller;
private final Screen lastScreen;
private int invalidNameTicks;
private Button submitButton;
private EditBox nameField;
public SubmitUnknownControllerScreen(Controller<?, ?> controller, Screen lastScreen) {
super(
Component.translatable("controlify.controller_submission.title").withStyle(ChatFormatting.BOLD),
Component.translatable("controlify.controller_submission.message"),
Component.translatable("controlify.controller_submission.dont_show_again"),
Component.translatable("controlify.controller_submission.title")
);
if (!canSubmit(controller))
throw new IllegalArgumentException("Controller ineligible for submission!");
this.controller = controller;
this.lastScreen = lastScreen;
}
@Override
protected void initButtons(int textHeight) {
this.submitButton = this.addRenderableWidget(
Button.builder(Component.translatable("controlify.controller_submission.submit"), this::onSubmitButton)
.pos(this.width / 2 - 155, textHeight + 80)
.width(150)
.build()
);
this.addRenderableWidget(
Button.builder(CommonComponents.GUI_CANCEL, btn -> onClose())
.pos(this.width / 2 + 5, textHeight + 80)
.width(150)
.build()
);
this.nameField = this.addRenderableWidget(
new EditBox(
font,
this.width / 2 - 155,
textHeight + 105,
310, 20,
Component.translatable("controlify.controller_submission.name_narration")
)
);
this.nameField.setHint(Component.translatable("controlify.controller_submission.name_hint"));
this.nameField.setValue(controller.name());
}
@Override
public void render(GuiGraphics graphics, int mouseX, int mouseY, float delta) {
renderBackground(graphics);
super.render(graphics, mouseX, mouseY, delta);
if (invalidNameTicks > 0) {
graphics.drawCenteredString(font, Component.translatable("controlify.controller_submission.invalid_name").withStyle(ChatFormatting.RED), this.width / 2, nameField.getRectangle().bottom() + 4, -1);
}
}
@Override
public void tick() {
if (invalidNameTicks > 0) {
invalidNameTicks--;
submitButton.active = invalidNameTicks < 50;
}
}
protected void onSubmitButton(Button button) {
invalidNameTicks = 0;
if (!checkValidName()) {
invalidNameTicks = 100;
return;
}
if (submit()) {
dontShowAgain();
onClose();
} else {
// TODO: Show error message
onClose();
}
}
protected boolean submit() {
try {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI(SUBMISSION_URL))
.POST(HttpRequest.BodyPublishers.ofString(this.generateRequestBody()))
.header("Content-Type", "application/json")
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() / 100 != 2) {
Log.LOGGER.error("Received non-2xx status code from '{}', got {} with body '{}'", SUBMISSION_URL, response.statusCode(), response.body());
return false;
}
Log.LOGGER.info("Successfully sent controller information to '{}'", SUBMISSION_URL);
return true;
} catch (Exception e) {
Log.LOGGER.error("Failed to submit controller to '%s'".formatted(SUBMISSION_URL), e);
return false;
}
}
private String generateRequestBody() {
HIDDevice hid = controller.hidInfo().orElseThrow().hidDevice().orElseThrow();
JsonObject object = new JsonObject();
object.addProperty("vendorID", hid.vendorID());
object.addProperty("productID", hid.productID());
object.addProperty("GUID", GLFW.glfwGetJoystickGUID(controller.joystickId()));
object.addProperty("reportedName", nameField.getValue());
object.addProperty("controlifyVersion", FabricLoader.getInstance().getModContainer("controlify").orElseThrow().getMetadata().getVersion().getFriendlyString());
Gson gson = new Gson();
return gson.toJson(object);
}
private boolean checkValidName() {
String name = nameField.getValue().trim();
return NAME_PATTERN.matcher(name).matches();
}
private void dontShowAgain() {
controller.config().dontShowControllerSubmission = true;
Controlify.instance().config().setDirty();
}
@Override
public void onClose() {
if (stopShowing.selected()) {
dontShowAgain();
}
Controlify.instance().config().saveIfDirty();
minecraft.setScreen(lastScreen);
}
@Override
public boolean shouldCloseOnEsc() {
return false;
}
@Override
protected int getLineHeight() {
return 9;
}
@Override
public int getMessageY() {
return 50;
}
public static boolean canSubmit(Controller<?, ?> controller) {
return controller.type() == ControllerType.UNKNOWN
&& !controller.config().dontShowControllerSubmission
&& controller.hidInfo()
.map(info -> info.hidDevice().isPresent())
.orElse(false);
}
}

View File

@ -76,8 +76,6 @@ public class ControllerHIDService {
}
ControllerType type = ControllerType.getTypeForHID(hid.getSecond());
if (type == ControllerType.UNKNOWN)
Log.LOGGER.warn("Controller found via USB hardware scan, but it was not found in the controller identification database! (HID: {})", hid.getSecond());
unconsumedControllerHIDs.removeIf(h -> hid.getFirst().getPath().equals(h.getFirst().getPath()));

View File

@ -0,0 +1,20 @@
package dev.isxander.controlify.mixins.feature.gui;
import dev.isxander.controlify.gui.screen.CustomWarningTitlePadding;
import net.minecraft.client.gui.screens.multiplayer.WarningScreen;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
@Mixin(WarningScreen.class)
public class WarningScreenMixin implements CustomWarningTitlePadding {
@ModifyConstant(method = "render", constant = @Constant(intValue = 70))
private int modifyMessageY(int original) {
return this.getMessageY();
}
@ModifyConstant(method = "init", constant = @Constant(intValue = 76))
private int modifyCheckboxY(int original) {
return this.getMessageY() + 6;
}
}

View File

@ -279,10 +279,13 @@
"controlify.calibration.later": "Maybe Later",
"controlify.calibration.later.tooltip": "You must calibrate to use the controller. Pressing this will deactivate the controller and you will have to use it again to calibrate.",
"controlify.beta.title": "Controlify Beta Notice",
"controlify.beta.message": "You are currently using Controlify Beta.\n\nThis mod is a work in progress and will contain many bugs. Please, if you spot a bug in this mod or have a suggestion to make it even better, please create an issue on the %s!\n\nYou can always find the link to the issue tracker in Controlify's settings menu.",
"controlify.beta.message.link": "issue tracker",
"controlify.beta.button": "Open Issue Tracker...",
"controlify.controller_submission.title": "Unknown Controller Submission",
"controlify.controller_submission.message": "Please submit some of your controller info to Controlify's database to get it added in a future update.\n\nControlify sends the following information:\n- Your controller's vendor & product IDs\n- Your controller's GUID\n- The name of your controller (in the box below)\n- The version of Controlify you are currently on\n\nThis is completely anonymous and does store any of your personal or account information.",
"controlify.controller_submission.dont_show_again": "Do not show for this controller again",
"controlify.controller_submission.submit": "Submit Data",
"controlify.controller_submission.name_hint": "Controller name",
"controlify.controller_submission.name_narration": "Controller name input field",
"controlify.controller_submission.invalid_name": "Invalid controller name. Use only letters, numbers and spaces.",
"controlify.error.hid": "Controller Detection Disabled",
"controlify.error.hid.desc": "Controller identification failed, so any controller config changes will not persist. Check logs for more info.",

View File

@ -7,26 +7,20 @@
},
"compatibilityLevel": "JAVA_17",
"client": [
"compat.fapi.KeyBindingRegistryImplAccessor",
"compat.iris.BaseOptionElementWidgetMixin",
"compat.sodium.CycleControlElementMixin",
"compat.sodium.SliderControlElementMixin",
"compat.sodium.TickBoxControlElementMixin",
"core.GLXMixin",
"feature.fixes.boatfix.BoatMixin",
"feature.rumble.explosion.LightningBoltMixin",
"feature.rumble.fishing.FishingHookMixin",
"feature.rumble.itembreak.LivingEntityMixin",
"feature.rumble.levelevents.LevelRendererMixin",
"feature.rumble.useitem.LivingEntityMixin",
"compat.fapi.KeyBindingRegistryImplAccessor",
"compat.sodium.SodiumOptionsGUIAccessor",
"compat.sodium.SodiumOptionsGUIMixin",
"compat.sodium.TickBoxControlElementMixin",
"compat.yacl.CyclingControllerElementMixin",
"compat.yacl.SliderControllerElementMixin",
"compat.yacl.YACLScreenCategoryTabAccessor",
"compat.yacl.YACLScreenCategoryTabMixin",
"compat.yacl.YACLScreenMixin",
"core.ClientPacketListenerMixin",
"core.GLXMixin",
"core.GuiMixin",
"core.KeyboardHandlerMixin",
"core.MinecraftMixin",
@ -38,7 +32,9 @@
"feature.bind.ToggleKeyMappingAccessor",
"feature.chatkbheight.ChatComponentMixin",
"feature.chatkbheight.ChatScreenMixin",
"feature.fixes.boatfix.BoatMixin",
"feature.fixes.boatfix.LocalPlayerMixin",
"feature.gui.WarningScreenMixin",
"feature.guide.ingame.ClientPacketListenerMixin",
"feature.guide.ingame.GuiMixin",
"feature.guide.screen.AbstractButtonMixin",
@ -50,7 +46,12 @@
"feature.rumble.blockbreak.MultiPlayerGameModeMixin",
"feature.rumble.damage.LocalPlayerMixin",
"feature.rumble.explosion.ClientPacketListenerMixin",
"feature.rumble.explosion.LightningBoltMixin",
"feature.rumble.fishing.FishingHookMixin",
"feature.rumble.itembreak.LivingEntityMixin",
"feature.rumble.itembreak.LocalPlayerMixin",
"feature.rumble.levelevents.LevelRendererMixin",
"feature.rumble.useitem.LivingEntityMixin",
"feature.rumble.useitem.LocalPlayerMixin",
"feature.screenop.GameRendererMixin",
"feature.screenop.MinecraftMixin",