diff --git a/build.gradle b/build.gradle index 62adb97..856f2ed 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '1.1-SNAPSHOT' + id 'fabric-loom' version '1.6-SNAPSHOT' id 'java-library' id 'maven-publish' id 'com.github.johnrengelman.shadow' version '7.0.0' @@ -13,7 +13,7 @@ group = project.maven_group version = "${project.mod_version}+${getMCVersionString()}" // This field defines the Java version your mod target. -def targetJavaVersion = 17 +def targetJavaVersion = 21 boolean isMCVersionNonRelease() { return project.minecraft_version.matches('^\\d\\dw\\d\\d[a-z]$') diff --git a/gradle.properties b/gradle.properties index 58b556e..1104bfa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,9 +3,9 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties # check these on https://fabricmc.net/use -minecraft_version=1.20.4 -yarn_mappings=1.20.4+build.3 -loader_version=0.15.3 +minecraft_version=1.20.5 +yarn_mappings=1.20.5+build.1 +loader_version=0.15.10 # Mod Properties mod_version = 1.9.4 @@ -17,11 +17,11 @@ changelog = See changes at: https://github.com/TeamMidnightDust/MidnightControls # Dependencies # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api -fabric_version=0.91.3+1.20.4 +fabric_version=0.97.7+1.20.5 sodium_version=mc1.19.2-0.4.4 spruceui_version=5.0.3+1.20.4 -midnightlib_version=1.5.3-fabric -modmenu_version=7.0.0 +midnightlib_version=1.5.4-fabric +modmenu_version=10.0.0-beta.1 emotecraft_version=2.1.3-SNAPSHOT-build.29-MC1.19-fabric bendylib_version=2.0.+ emi_version=1.1.1+1.20.4+fabric diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1af9e09..b82aa23 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/eu/midnightdust/midnightcontrols/MidnightControls.java b/src/main/java/eu/midnightdust/midnightcontrols/MidnightControls.java index 312fae5..2c76298 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/MidnightControls.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/MidnightControls.java @@ -9,15 +9,18 @@ package eu.midnightdust.midnightcontrols; -import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig; import eu.midnightdust.midnightcontrols.event.PlayerChangeControlsModeCallback; +import eu.midnightdust.midnightcontrols.packet.ControlsModePacket; +import eu.midnightdust.midnightcontrols.packet.FeaturePacket; +import eu.midnightdust.midnightcontrols.packet.HelloPacket; import io.netty.buffer.Unpooled; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; import net.minecraft.network.PacketByteBuf; -import net.minecraft.util.Identifier; +import net.minecraft.network.packet.CustomPayload; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; @@ -34,9 +37,9 @@ import java.util.Optional; */ public class MidnightControls implements ModInitializer { private static MidnightControls INSTANCE; - public static final Identifier CONTROLS_MODE_CHANNEL = new Identifier(MidnightControlsConstants.CONTROLS_MODE_CHANNEL.toString()); - public static final Identifier FEATURE_CHANNEL = new Identifier(MidnightControlsConstants.FEATURE_CHANNEL.toString()); - public static final Identifier HELLO_CHANNEL = new Identifier(MidnightControlsConstants.HELLO_CHANNEL.toString()); + public static final CustomPayload.Id CONTROLS_MODE_CHANNEL = CustomPayload.id(MidnightControlsConstants.CONTROLS_MODE_CHANNEL.toString()); + public static final CustomPayload.Id FEATURE_CHANNEL = CustomPayload.id(MidnightControlsConstants.FEATURE_CHANNEL.toString()); + public static final CustomPayload.Id HELLO_CHANNEL = CustomPayload.id(MidnightControlsConstants.HELLO_CHANNEL.toString()); public static boolean isExtrasLoaded; public final Logger logger = LogManager.getLogger("MidnightControls"); @@ -47,19 +50,19 @@ public class MidnightControls implements ModInitializer { isExtrasLoaded = FabricLoader.getInstance().isModLoaded("midnightcontrols-extra"); this.log("Initializing MidnightControls..."); - ServerPlayNetworking.registerGlobalReceiver(HELLO_CHANNEL, (server, player, handler, buf, responseSender) -> { - String version = buf.readString(32); - ControlsMode.byId(buf.readString(32)) - .ifPresent(controlsMode -> server - .execute(() -> PlayerChangeControlsModeCallback.EVENT.invoker().apply(player, controlsMode))); - server.execute(() -> { - ServerPlayNetworking.send(player, FEATURE_CHANNEL, this.makeFeatureBuffer(MidnightControlsFeature.HORIZONTAL_REACHAROUND)); - }); + PayloadTypeRegistry.playC2S().register(HelloPacket.PACKET_ID, HelloPacket.codec); + PayloadTypeRegistry.playC2S().register(ControlsModePacket.PACKET_ID, ControlsModePacket.codec); + PayloadTypeRegistry.playS2C().register(ControlsModePacket.PACKET_ID, ControlsModePacket.codec); + PayloadTypeRegistry.playS2C().register(FeaturePacket.PACKET_ID, FeaturePacket.codec); + + ServerPlayNetworking.registerGlobalReceiver(HelloPacket.PACKET_ID, (payload, context) -> { + ControlsMode.byId(payload.controlsMode()) + .ifPresent(controlsMode -> PlayerChangeControlsModeCallback.EVENT.invoker().apply(context.player(), controlsMode)); + context.responseSender().sendPacket(new FeaturePacket(MidnightControlsFeature.HORIZONTAL_REACHAROUND)); }); - ServerPlayNetworking.registerGlobalReceiver(CONTROLS_MODE_CHANNEL, - (server, player, handler, buf, responseSender) -> ControlsMode.byId(buf.readString(32)) - .ifPresent(controlsMode -> server - .execute(() -> PlayerChangeControlsModeCallback.EVENT.invoker().apply(player, controlsMode)))); + ServerPlayNetworking.registerGlobalReceiver(ControlsModePacket.PACKET_ID, + (payload, context) -> ControlsMode.byId(payload.controlsMode()) + .ifPresent(controlsMode -> PlayerChangeControlsModeCallback.EVENT.invoker().apply(context.player(), controlsMode))); } /** @@ -80,44 +83,6 @@ public class MidnightControls implements ModInitializer { this.logger.info("[MidnightControls] " + warning); } - /** - * Returns a packet byte buffer made for the midnightcontrols:controls_mode plugin message. - * - * @param controlsMode the controls mode to send - * @return the packet byte buffer - */ - public PacketByteBuf makeControlsModeBuffer(@NotNull ControlsMode controlsMode) { - Objects.requireNonNull(controlsMode, "Controls mode cannot be null."); - return new PacketByteBuf(Unpooled.buffer()).writeString(controlsMode.getName(), 32); - } - - /** - * Returns a packet byte buffer made for the midnightcontrols:feature plugin message. - * - * @param features the features data to send - * @return the packet byte buffer - */ - public PacketByteBuf makeFeatureBuffer(MidnightControlsFeature... features) { - if (features.length == 0) - throw new IllegalArgumentException("At least one feature must be provided."); - var buffer = new PacketByteBuf(Unpooled.buffer()); - buffer.writeVarInt(features.length); - for (var feature : features) { - buffer.writeString(feature.getName(), 64); - buffer.writeBoolean(feature.isAllowed()); - } - return buffer; - } - - public PacketByteBuf makeHello(@NotNull ControlsMode controlsMode) { - var version = ""; - Optional container; - if ((container = FabricLoader.getInstance().getModContainer(MidnightControlsConstants.NAMESPACE)).isPresent()) { - version = container.get().getMetadata().getVersion().getFriendlyString(); - } - return new PacketByteBuf(Unpooled.buffer()).writeString(version, 32).writeString(controlsMode.getName(), 32); - } - /** * Gets the MidnightControls instance. * diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsClient.java b/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsClient.java index 1b318fd..0849d62 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsClient.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsClient.java @@ -29,6 +29,9 @@ import eu.midnightdust.midnightcontrols.client.ring.MidnightRing; import dev.lambdaurora.spruceui.hud.HudManager; import eu.midnightdust.midnightcontrols.client.touch.TouchInput; import eu.midnightdust.midnightcontrols.client.util.RainbowColor; +import eu.midnightdust.midnightcontrols.packet.ControlsModePacket; +import eu.midnightdust.midnightcontrols.packet.FeaturePacket; +import eu.midnightdust.midnightcontrols.packet.HelloPacket; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; @@ -37,6 +40,7 @@ import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.resource.ResourceManagerHelper; import net.fabricmc.fabric.api.resource.ResourcePackActivationType; import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.option.KeyBinding; @@ -48,9 +52,7 @@ import org.jetbrains.annotations.NotNull; import org.lwjgl.glfw.GLFW; import java.io.File; -import java.util.Objects; -import java.util.Timer; -import java.util.TimerTask; +import java.util.*; /** * Represents the midnightcontrols client mod. @@ -94,19 +96,19 @@ public class MidnightControlsClient extends MidnightControls implements ClientMo this.ring.registerAction("buttonbinding", ButtonBindingRingAction.FACTORY); - ClientPlayNetworking.registerGlobalReceiver(CONTROLS_MODE_CHANNEL, (client, handler, buf, responseSender) -> - responseSender.sendPacket(CONTROLS_MODE_CHANNEL, this.makeControlsModeBuffer(MidnightControlsConfig.controlsMode))); - ClientPlayNetworking.registerGlobalReceiver(FEATURE_CHANNEL, (client, handler, buf, responseSender) -> { - int features = buf.readVarInt(); - for (int i = 0; i < features; i++) { - var name = buf.readString(64); - boolean allowed = buf.readBoolean(); - MidnightControlsFeature.fromName(name).ifPresent(feature -> client.execute(() -> feature.setAllowed(allowed))); - } - }); + ClientPlayNetworking.registerGlobalReceiver(CONTROLS_MODE_CHANNEL, (payload, context) -> + context.responseSender().sendPacket(new ControlsModePacket(MidnightControlsConfig.controlsMode.getName()))); + ClientPlayNetworking.registerGlobalReceiver(FeaturePacket.PACKET_ID, ((payload, context) -> {})); + ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> { - sender.sendPacket(HELLO_CHANNEL, this.makeHello(MidnightControlsConfig.controlsMode)); - sender.sendPacket(CONTROLS_MODE_CHANNEL, this.makeControlsModeBuffer(MidnightControlsConfig.controlsMode)); + var version = ""; + Optional container; + if ((container = FabricLoader.getInstance().getModContainer(MidnightControlsConstants.NAMESPACE)).isPresent()) { + version = container.get().getMetadata().getVersion().getFriendlyString(); + } + var controlsMode = MidnightControlsConfig.controlsMode.getName(); + sender.sendPacket(new HelloPacket(version, controlsMode)); + sender.sendPacket(new ControlsModePacket(controlsMode)); }); ClientPlayConnectionEvents.DISCONNECT.register(this::onLeave); @@ -255,6 +257,7 @@ public class MidnightControlsClient extends MidnightControls implements ClientMo MidnightControlsConfig.controlsMode = this.previousControlsMode; } + ClientPlayNetworking.getSender().sendPacket(new ControlsModePacket(MidnightControlsConfig.controlsMode.getName())); } } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightInput.java b/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightInput.java index e4a7671..84fe7a5 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightInput.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightInput.java @@ -489,7 +489,7 @@ public class MidnightInput { state = 1; asButtonState = 1; } - if (MidnightControlsConfig.debug) System.out.println(axis + " "+ value + " " + absValue + " " + state); + //if (MidnightControlsConfig.debug) System.out.println(axis + " "+ value + " " + absValue + " " + state); } } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightReacharound.java b/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightReacharound.java index ca9554d..4178179 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightReacharound.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightReacharound.java @@ -15,6 +15,7 @@ import net.minecraft.block.BlockState; import net.minecraft.block.FluidBlock; import net.minecraft.block.SlabBlock; import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; import net.minecraft.util.hit.BlockHitResult; @@ -74,7 +75,7 @@ public class MidnightReacharound { } public static float getPlayerRange(@NotNull MinecraftClient client) { - return client.interactionManager != null ? client.interactionManager.getReachDistance() : 0.f; + return client.player != null ? Double.valueOf(client.player.getAttributeValue(EntityAttributes.PLAYER_BLOCK_INTERACTION_RANGE)).floatValue() : 0.f; } /** diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/controller/Controller.java b/src/main/java/eu/midnightdust/midnightcontrols/client/controller/Controller.java index 282d89d..1af322f 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/controller/Controller.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/controller/Controller.java @@ -151,25 +151,17 @@ public record Controller(int id) implements Nameable { private static boolean updateMappingsSync() { try { MidnightControlsClient.get().log("Updating controller mappings..."); - File databaseFile = new File("config/gamecontrollerdatabase.txt"); - try { - BufferedInputStream in = new BufferedInputStream(new URL("https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt").openStream()); - BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(databaseFile)); - byte[] dataBuffer = new byte[1024]; - int bytesRead; - while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) { - out.write(dataBuffer, 0, bytesRead); - } - out.close(); - } catch (Exception ignored) {/* Just continue when internet connection is not available */} - var database = ioResourceToBuffer(databaseFile.getPath(), 1024); - if (database != null) GLFW.glfwUpdateGamepadMappings(database); + Optional databaseFile = getDatabaseFile(); + if (databaseFile.isPresent()) { + var database = ioResourceToBuffer(databaseFile.get().getPath(), 1024); + if (database != null) GLFW.glfwUpdateGamepadMappings(database); + } if (!MidnightControlsClient.MAPPINGS_FILE.exists()) return false; var buffer = ioResourceToBuffer(MidnightControlsClient.MAPPINGS_FILE.getPath(), 1024); if (buffer != null) GLFW.glfwUpdateGamepadMappings(buffer); } catch (IOException e) { - e.printStackTrace(); + e.fillInStackTrace(); } try (var memoryStack = MemoryStack.stackPush()) { @@ -182,8 +174,8 @@ public record Controller(int id) implements Nameable { if (client != null) { client.getToastManager().add(SystemToast.create(client, SystemToast.Type.PERIODIC_NOTIFICATION, Text.translatable("midnightcontrols.controller.mappings.error"), Text.literal(string))); - MidnightControls.get().log(I18n.translate("midnightcontrols.controller.mappings.error")+string); } + MidnightControls.get().log(I18n.translate("midnightcontrols.controller.mappings.error")+string); } } catch (Throwable e) { /* Ignored :concern: */ @@ -205,4 +197,19 @@ public record Controller(int id) implements Nameable { } return true; } + + private static Optional getDatabaseFile() { + File databaseFile = new File("config/gamecontrollerdatabase.txt"); + try { + BufferedInputStream in = new BufferedInputStream(new URL("https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt").openStream()); + BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(databaseFile)); + byte[] dataBuffer = new byte[1024]; + int bytesRead; + while ((bytesRead = in.read(dataBuffer, 0, 1024)) != -1) { + out.write(dataBuffer, 0, bytesRead); + } + out.close(); + } catch (Exception e) {return Optional.empty();} + return Optional.of(databaseFile); + } } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsSettingsScreen.java b/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsSettingsScreen.java index ad38808..5c576cb 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsSettingsScreen.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsSettingsScreen.java @@ -27,6 +27,7 @@ import dev.lambdaurora.spruceui.widget.SpruceLabelWidget; import dev.lambdaurora.spruceui.widget.container.SpruceContainerWidget; import dev.lambdaurora.spruceui.widget.container.SpruceOptionListWidget; import dev.lambdaurora.spruceui.widget.container.tabbed.SpruceTabbedWidget; +import eu.midnightdust.midnightcontrols.packet.ControlsModePacket; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; @@ -92,6 +93,7 @@ public class MidnightControlsSettingsScreen extends SpruceScreen { id = GLFW.GLFW_JOYSTICK_1; id = searchNextAvailableController(id, false); MidnightControlsConfig.setController(Controller.byId(id)); + if (MidnightControlsConfig.debug) System.out.println(Controller.byId(id).getName() + "'s Controller GUID: " + Controller.byId(id).getGuid()); }, option -> { var controller = MidnightControlsConfig.getController(); @@ -182,7 +184,7 @@ public class MidnightControlsSettingsScreen extends SpruceScreen { MidnightControlsConfig.save(); if (this.client != null && this.client.player != null) { - ClientPlayNetworking.getSender().sendPacket(MidnightControls.CONTROLS_MODE_CHANNEL, this.mod.makeControlsModeBuffer(next)); + ClientPlayNetworking.getSender().sendPacket(new ControlsModePacket(next.getName())); } }, option -> option.getDisplayText(Text.translatable(MidnightControlsConfig.controlsMode.getTranslationKey())), Text.translatable("midnightcontrols.menu.controls_mode.tooltip")); diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/TouchscreenOverlay.java b/src/main/java/eu/midnightdust/midnightcontrols/client/gui/TouchscreenOverlay.java index bf2de6f..83b30a2 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/gui/TouchscreenOverlay.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/gui/TouchscreenOverlay.java @@ -86,6 +86,9 @@ public class TouchscreenOverlay extends Screen { @Override public void renderInGameBackground(DrawContext context) {} + @Override + protected void applyBlur(float delta) {} + private void pauseGame() { assert this.client != null; this.client.setScreen(new GameMenuScreen(true)); diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/ControlsOptionsScreenMixin.java b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/ControlsOptionsScreenMixin.java index e1fc3c4..e61814c 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/ControlsOptionsScreenMixin.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/ControlsOptionsScreenMixin.java @@ -10,14 +10,19 @@ package eu.midnightdust.midnightcontrols.client.mixin; import eu.midnightdust.midnightcontrols.client.gui.MidnightControlsSettingsScreen; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.option.ControlsOptionsScreen; import net.minecraft.client.gui.screen.option.GameOptionsScreen; +import net.minecraft.client.gui.widget.OptionListWidget; import net.minecraft.client.gui.widget.TextIconButtonWidget; import net.minecraft.client.option.GameOptions; import net.minecraft.text.Text; import net.minecraft.util.Identifier; +import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -27,14 +32,29 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; */ @Mixin(ControlsOptionsScreen.class) public abstract class ControlsOptionsScreenMixin extends GameOptionsScreen { - public ControlsOptionsScreenMixin(Screen parent, GameOptions gameOptions, Text text) { - super(parent, gameOptions, text); + + @Shadow @Nullable private OptionListWidget optionListWidget; + + public ControlsOptionsScreenMixin(Screen parent, GameOptions gameOptions, Text title) { + super(parent, gameOptions, title); } - @Inject(method = "init", at = @At(value = "INVOKE", ordinal = 1, shift = At.Shift.AFTER, target = "Lnet/minecraft/client/gui/screen/option/ControlsOptionsScreen;addDrawableChild(Lnet/minecraft/client/gui/Element;)Lnet/minecraft/client/gui/Element;")) - private void addControllerButton(CallbackInfo ci) { - TextIconButtonWidget iconWidget = TextIconButtonWidget.builder(Text.translatable("midnightcontrols.menu.title.controller"), (button -> this.client.setScreen(new MidnightControlsSettingsScreen(this, false))), true) - .dimension(20,20).texture(new Identifier("midnightcontrols", "icon/controller"), 20, 20).build(); - iconWidget.setPosition(this.width / 2 + 158, this.height / 6 - 12); - this.addDrawableChild(iconWidget); + @Unique TextIconButtonWidget button = TextIconButtonWidget.builder(Text.translatable("midnightcontrols.menu.title.controller"), (button -> this.client.setScreen(new MidnightControlsSettingsScreen(this, false))), true) + .dimension(20,20).texture(new Identifier("midnightcontrols", "icon/controller"), 20, 20).build(); + + @Inject(at = @At("TAIL"), method = "init") + public void midnightcontrols$onInit(CallbackInfo ci) { + this.midnightcontrols$setupButton(); + this.addDrawableChild(button); + } + + @Override + public void resize(MinecraftClient client, int width, int height) { + super.resize(client, width, height); + this.midnightcontrols$setupButton(); + } + @Unique + public void midnightcontrols$setupButton() { + assert optionListWidget != null; + button.setPosition(optionListWidget.getWidth() / 2 + 158, optionListWidget.getY() + 4); } } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameRendererMixin.java b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameRendererMixin.java index 082da55..50aafe5 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameRendererMixin.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameRendererMixin.java @@ -9,6 +9,7 @@ package eu.midnightdust.midnightcontrols.client.mixin; +import com.llamalad7.mixinextras.sugar.Local; import com.mojang.blaze3d.systems.RenderSystem; import eu.midnightdust.midnightcontrols.ControlsMode; import eu.midnightdust.midnightcontrols.client.MidnightControlsClient; @@ -18,14 +19,13 @@ import eu.midnightdust.midnightcontrols.client.touch.TouchUtils; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.render.GameRenderer; -import net.minecraft.client.util.math.MatrixStack; +import org.joml.Matrix4f; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(GameRenderer.class) public abstract class GameRendererMixin { @@ -38,15 +38,16 @@ public abstract class GameRendererMixin { if (this.client.currentScreen != null && MidnightControlsConfig.controlsMode == ControlsMode.CONTROLLER) MidnightControlsClient.get().input.onPreRenderScreen(this.client, this.client.currentScreen); } - @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;draw()V", shift = At.Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILSOFT) - private void renderVirtualCursor(float tickDelta, long startTime, boolean tick, CallbackInfo ci, boolean bl, MatrixStack matrixStack, DrawContext drawContext) { + @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;draw()V", shift = At.Shift.BEFORE)) + private void renderVirtualCursor(float tickDelta, long startTime, boolean tick, CallbackInfo ci, @Local DrawContext drawContext) { MidnightControlsRenderer.renderVirtualCursor(drawContext, client); drawContext.draw(); } - @Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/GameRenderer;renderHand:Z", ordinal = 0), method = "renderWorld") - private void postWorldRender(float tickDelta, long limitTime, MatrixStack matrix, CallbackInfo ci) { + @Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/GameRenderer;renderHand:Z"), method = "renderWorld") + private void captureProjAndModMatrix(float tickDelta, long limitTime, CallbackInfo ci, @Local(ordinal = 1) Matrix4f matrices) { TouchUtils.lastProjMat.set(RenderSystem.getProjectionMatrix()); TouchUtils.lastModMat.set(RenderSystem.getModelViewMatrix()); - TouchUtils.lastWorldSpaceMatrix.set(matrix.peek().getPositionMatrix()); + TouchUtils.lastWorldSpaceMatrix.set(matrices); } + } diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/MouseMixin.java b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/MouseMixin.java index c7fe2b4..8c23182 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/MouseMixin.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/MouseMixin.java @@ -51,7 +51,7 @@ public abstract class MouseMixin implements MouseAccessor { @Shadow private boolean hasResolutionChanged; - @Shadow private double lastMouseUpdateTime; + @Shadow private double glfwTime; @Shadow @Final private SmoothUtil cursorXSmoother; @@ -116,8 +116,8 @@ public abstract class MouseMixin implements MouseAccessor { cursorYSmoother.clear(); } EyeTrackerHandler.updateMouseWithEyeTracking(x + cursorDeltaX, y + cursorDeltaY, client, - lastMouseUpdateTime, leftButtonClicked, cursorXSmoother, cursorYSmoother); - lastMouseUpdateTime = GlfwUtil.getTime(); + glfwTime, leftButtonClicked, cursorXSmoother, cursorYSmoother); + glfwTime = GlfwUtil.getTime(); cursorDeltaX = 0.0; cursorDeltaY = 0.0; ci.cancel(); diff --git a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/WorldRendererMixin.java b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/WorldRendererMixin.java index 44f760a..ca74665 100644 --- a/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/WorldRendererMixin.java +++ b/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/WorldRendererMixin.java @@ -9,6 +9,7 @@ package eu.midnightdust.midnightcontrols.client.mixin; +import com.llamalad7.mixinextras.sugar.Local; import eu.midnightdust.lib.util.MidnightColorUtil; import eu.midnightdust.midnightcontrols.ControlsMode; import eu.midnightdust.midnightcontrols.client.MidnightControlsClient; @@ -61,6 +62,7 @@ public abstract class WorldRendererMixin { @Shadow private static void drawCuboidShapeOutline(MatrixStack matrices, VertexConsumer vertexConsumer, VoxelShape shape, double offsetX, double offsetY, double offsetZ, float red, float green, float blue, float alpha) { } + @Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/hit/HitResult;getType()Lnet/minecraft/util/hit/HitResult$Type;")) private HitResult.Type dontRenderOutline(HitResult instance) { if (MidnightControlsConfig.controlsMode == ControlsMode.TOUCHSCREEN && MidnightControlsConfig.touchMode == TouchMode.FINGER_POS) { @@ -78,8 +80,7 @@ public abstract class WorldRendererMixin { shift = At.Shift.AFTER ) ) - private void onOutlineRender(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, - LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) { + private void onOutlineRender(float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, Matrix4f matrix4f2, CallbackInfo ci, @Local MatrixStack matrices) { if (((MidnightControlsConfig.controlsMode == ControlsMode.CONTROLLER && MidnightControlsConfig.touchInControllerMode) || MidnightControlsConfig.controlsMode == ControlsMode.TOUCHSCREEN) && MidnightControlsConfig.touchMode == TouchMode.FINGER_POS) { this.renderFingerOutline(matrices, camera); diff --git a/src/main/java/eu/midnightdust/midnightcontrols/packet/ControlsModePacket.java b/src/main/java/eu/midnightdust/midnightcontrols/packet/ControlsModePacket.java new file mode 100644 index 0000000..efa2ea2 --- /dev/null +++ b/src/main/java/eu/midnightdust/midnightcontrols/packet/ControlsModePacket.java @@ -0,0 +1,33 @@ +package eu.midnightdust.midnightcontrols.packet; + +import eu.midnightdust.midnightcontrols.MidnightControlsConstants; +import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig; +import io.netty.buffer.Unpooled; +import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; + +import java.util.Objects; +import java.util.Optional; + +public record ControlsModePacket(String controlsMode) implements CustomPayload { + public static final Id PACKET_ID = new Id<>(MidnightControlsConstants.CONTROLS_MODE_CHANNEL); + public static final PacketCodec codec = PacketCodec.of(ControlsModePacket::write, ControlsModePacket::read); + + public static ControlsModePacket read(RegistryByteBuf buf) { + return new ControlsModePacket(buf.readString(32)); + } + + public void write(RegistryByteBuf buf) { + Objects.requireNonNull(controlsMode, "Controls mode cannot be null."); + buf.writeString(controlsMode, 32); + } + + @Override + public Id getId() { + return PACKET_ID; + } +} \ No newline at end of file diff --git a/src/main/java/eu/midnightdust/midnightcontrols/packet/FeaturePacket.java b/src/main/java/eu/midnightdust/midnightcontrols/packet/FeaturePacket.java new file mode 100644 index 0000000..6ebe41e --- /dev/null +++ b/src/main/java/eu/midnightdust/midnightcontrols/packet/FeaturePacket.java @@ -0,0 +1,43 @@ +package eu.midnightdust.midnightcontrols.packet; + +import eu.midnightdust.midnightcontrols.MidnightControlsConstants; +import eu.midnightdust.midnightcontrols.MidnightControlsFeature; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; + +public record FeaturePacket(MidnightControlsFeature... features) implements CustomPayload { + public static final Id PACKET_ID = new Id<>(MidnightControlsConstants.FEATURE_CHANNEL); + public static final PacketCodec codec = PacketCodec.of(FeaturePacket::write, FeaturePacket::read); + + public static FeaturePacket read(RegistryByteBuf buf) { + int featureLength = buf.readVarInt(); + MidnightControlsFeature[] receivedFeatures = new MidnightControlsFeature[featureLength]; + for (int i = 0; i < featureLength; i++) { + var name = buf.readString(64); + boolean allowed = buf.readBoolean(); + var feature = MidnightControlsFeature.fromName(name); + if (feature.isPresent()) { + feature.get().setAllowed(allowed); + receivedFeatures[i] = feature.get(); + } + } + return new FeaturePacket(receivedFeatures); + } + + public void write(RegistryByteBuf buf) { + if (features.length == 0) + throw new IllegalArgumentException("At least one feature must be provided."); + + buf.writeVarInt(features.length); + for (var feature : features) { + buf.writeString(feature.getName(), 64); + buf.writeBoolean(feature.isAllowed()); + } + } + + @Override + public Id getId() { + return PACKET_ID; + } +} \ No newline at end of file diff --git a/src/main/java/eu/midnightdust/midnightcontrols/packet/HelloPacket.java b/src/main/java/eu/midnightdust/midnightcontrols/packet/HelloPacket.java new file mode 100644 index 0000000..130b4ea --- /dev/null +++ b/src/main/java/eu/midnightdust/midnightcontrols/packet/HelloPacket.java @@ -0,0 +1,24 @@ +package eu.midnightdust.midnightcontrols.packet; + +import eu.midnightdust.midnightcontrols.MidnightControlsConstants; +import net.minecraft.network.RegistryByteBuf; +import net.minecraft.network.codec.PacketCodec; +import net.minecraft.network.packet.CustomPayload; + +public record HelloPacket(String version, String controlsMode) implements CustomPayload { + public static final CustomPayload.Id PACKET_ID = new CustomPayload.Id<>(MidnightControlsConstants.HELLO_CHANNEL); + public static final PacketCodec codec = PacketCodec.of(HelloPacket::write, HelloPacket::read); + + public static HelloPacket read(RegistryByteBuf buf) { + return new HelloPacket(buf.readString(32), buf.readString(32)); + } + + public void write(RegistryByteBuf buf) { + buf.writeString(version, 32).writeString(controlsMode, 32); + } + + @Override + public Id getId() { + return PACKET_ID; + } +} \ No newline at end of file