From 45149af8590eadee3bec57c8cd3ef676d587ccc7 Mon Sep 17 00:00:00 2001 From: Martin Prokoph Date: Wed, 17 Jul 2024 23:23:05 +0200 Subject: [PATCH] Improved Cursors - Cursor position is now float instead of integer, making movement way smoother - Added a fallback cursor to use in Wayland sessions --- .../midnightcontrols/MidnightControls.java | 4 + .../client/MidnightControlsClient.java | 22 +++--- .../client/enums/VirtualMouseSkin.java | 8 ++ .../client/gui/MidnightControlsRenderer.java | 72 +++++++++++------- .../client/mixin/GameRendererMixin.java | 1 + .../midnightcontrols/textures/gui/cursor.png | Bin 327 -> 0 bytes .../gui/sprites/cursor/dark/default.png | Bin 0 -> 4297 bytes .../gui/sprites/cursor/dark/default_slot.png | Bin 0 -> 4311 bytes .../gui/sprites/cursor/dark/mouse_pointer.png | Bin 0 -> 4346 bytes .../gui/sprites/cursor/dark/secondary.png | Bin 0 -> 4321 bytes .../sprites/cursor/dark/secondary_slot.png | Bin 0 -> 4320 bytes .../gui/sprites/cursor/light/default.png | Bin 0 -> 4297 bytes .../gui/sprites/cursor/light/default_slot.png | Bin 0 -> 4311 bytes .../sprites/cursor/light/mouse_pointer.png | Bin 0 -> 4647 bytes .../gui/sprites/cursor/light/secondary.png | Bin 0 -> 4321 bytes .../sprites/cursor/light/secondary_slot.png | Bin 0 -> 4320 bytes 16 files changed, 69 insertions(+), 38 deletions(-) delete mode 100644 common/src/main/resources/assets/midnightcontrols/textures/gui/cursor.png create mode 100644 common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/dark/default.png create mode 100644 common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/dark/default_slot.png create mode 100644 common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/dark/mouse_pointer.png create mode 100644 common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/dark/secondary.png create mode 100644 common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/dark/secondary_slot.png create mode 100644 common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/light/default.png create mode 100644 common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/light/default_slot.png create mode 100644 common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/light/mouse_pointer.png create mode 100644 common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/light/secondary.png create mode 100644 common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/light/secondary_slot.png diff --git a/common/src/main/java/eu/midnightdust/midnightcontrols/MidnightControls.java b/common/src/main/java/eu/midnightdust/midnightcontrols/MidnightControls.java index b86a890..55793ce 100644 --- a/common/src/main/java/eu/midnightdust/midnightcontrols/MidnightControls.java +++ b/common/src/main/java/eu/midnightdust/midnightcontrols/MidnightControls.java @@ -10,6 +10,7 @@ package eu.midnightdust.midnightcontrols; import eu.midnightdust.lib.util.PlatformFunctions; +import net.minecraft.util.Identifier; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -29,6 +30,9 @@ public class MidnightControls { isExtrasLoaded = PlatformFunctions.isModLoaded("midnightcontrols-extra"); log("Initializing MidnightControls..."); } + public static Identifier id(String path) { + return Identifier.of(MidnightControlsConstants.NAMESPACE, path); + } /** * Prints a message to the terminal. diff --git a/common/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsClient.java b/common/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsClient.java index e93736c..19e57bc 100644 --- a/common/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsClient.java +++ b/common/src/main/java/eu/midnightdust/midnightcontrols/client/MidnightControlsClient.java @@ -12,7 +12,6 @@ package eu.midnightdust.midnightcontrols.client; import eu.midnightdust.lib.util.PlatformFunctions; import eu.midnightdust.midnightcontrols.ControlsMode; import eu.midnightdust.midnightcontrols.MidnightControls; -import eu.midnightdust.midnightcontrols.MidnightControlsConstants; import eu.midnightdust.midnightcontrols.MidnightControlsFeature; import eu.midnightdust.midnightcontrols.client.compat.MidnightControlsCompat; import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding; @@ -51,25 +50,27 @@ import java.util.concurrent.atomic.AtomicReference; */ public class MidnightControlsClient extends MidnightControls { public static boolean lateInitDone = false; - public static final KeyBinding BINDING_LOOK_UP = InputManager.makeKeyBinding(Identifier.of(MidnightControlsConstants.NAMESPACE, "look_up"), + public static final KeyBinding BINDING_LOOK_UP = InputManager.makeKeyBinding(id("look_up"), InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_8, "key.categories.movement"); - public static final KeyBinding BINDING_LOOK_RIGHT = InputManager.makeKeyBinding(Identifier.of(MidnightControlsConstants.NAMESPACE, "look_right"), + public static final KeyBinding BINDING_LOOK_RIGHT = InputManager.makeKeyBinding(id("look_right"), InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_6, "key.categories.movement"); - public static final KeyBinding BINDING_LOOK_DOWN = InputManager.makeKeyBinding(Identifier.of(MidnightControlsConstants.NAMESPACE, "look_down"), + public static final KeyBinding BINDING_LOOK_DOWN = InputManager.makeKeyBinding(id("look_down"), InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_2, "key.categories.movement"); - public static final KeyBinding BINDING_LOOK_LEFT = InputManager.makeKeyBinding(Identifier.of(MidnightControlsConstants.NAMESPACE, "look_left"), + public static final KeyBinding BINDING_LOOK_LEFT = InputManager.makeKeyBinding(id("look_left"), InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_KP_4, "key.categories.movement"); - public static final KeyBinding BINDING_RING = InputManager.makeKeyBinding(Identifier.of(MidnightControlsConstants.NAMESPACE, "ring"), + public static final KeyBinding BINDING_RING = InputManager.makeKeyBinding(id("ring"), InputUtil.Type.KEYSYM, InputUtil.UNKNOWN_KEY.getCode(), "key.categories.misc"); - public static final Identifier CONTROLLER_BUTTONS = Identifier.of(MidnightControlsConstants.NAMESPACE, "textures/gui/controller_buttons.png"); - public static final Identifier CONTROLLER_EXPANDED = Identifier.of(MidnightControlsConstants.NAMESPACE, "textures/gui/controller_expanded.png"); - public static final Identifier CONTROLLER_AXIS = Identifier.of(MidnightControlsConstants.NAMESPACE, "textures/gui/controller_axis.png"); - public static final Identifier CURSOR_TEXTURE = Identifier.of(MidnightControlsConstants.NAMESPACE, "textures/gui/cursor.png"); + public static final Identifier CONTROLLER_BUTTONS = id("textures/gui/controller_buttons.png"); + public static final Identifier CONTROLLER_EXPANDED = id("textures/gui/controller_expanded.png"); + public static final Identifier CONTROLLER_AXIS = id("textures/gui/controller_axis.png"); + public static final Identifier WAYLAND_CURSOR_TEXTURE_LIGHT = id("cursor/light/mouse_pointer"); + public static final Identifier WAYLAND_CURSOR_TEXTURE_DARK = id("cursor/dark/mouse_pointer"); public static final File MAPPINGS_FILE = new File("config/gamecontrollercustommappings.txt"); public static final MinecraftClient client = MinecraftClient.getInstance(); public static final MidnightInput input = new MidnightInput(); public static final MidnightRing ring = new MidnightRing(); public static final MidnightReacharound reacharound = new MidnightReacharound(); + public static boolean isWayland; private static MidnightControlsHud hud; private static ControlsMode previousControlsMode; @@ -87,6 +88,7 @@ public class MidnightControlsClient extends MidnightControls { }, delay, period); HudManager.register(hud = new MidnightControlsHud()); + isWayland = GLFW.glfwGetVersionString().contains("Wayland"); } /** diff --git a/common/src/main/java/eu/midnightdust/midnightcontrols/client/enums/VirtualMouseSkin.java b/common/src/main/java/eu/midnightdust/midnightcontrols/client/enums/VirtualMouseSkin.java index d5a4311..3069d0d 100644 --- a/common/src/main/java/eu/midnightdust/midnightcontrols/client/enums/VirtualMouseSkin.java +++ b/common/src/main/java/eu/midnightdust/midnightcontrols/client/enums/VirtualMouseSkin.java @@ -81,4 +81,12 @@ public enum VirtualMouseSkin implements Nameable { public static @NotNull Optional byId(@NotNull String id) { return Arrays.stream(values()).filter(mode -> mode.getName().equalsIgnoreCase(id)).findFirst(); } + public String getSpritePath() { + return switch (this) { + case DEFAULT_LIGHT -> "cursor/light/default"; + case DEFAULT_DARK -> "cursor/dark/default"; + case SECOND_LIGHT -> "cursor/light/secondary"; + case SECOND_DARK -> "cursor/dark/secondary"; + }; + } } diff --git a/common/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsRenderer.java b/common/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsRenderer.java index 90b97ab..2886a12 100644 --- a/common/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsRenderer.java +++ b/common/src/main/java/eu/midnightdust/midnightcontrols/client/gui/MidnightControlsRenderer.java @@ -10,21 +10,34 @@ package eu.midnightdust.midnightcontrols.client.gui; import com.mojang.blaze3d.systems.RenderSystem; +import eu.midnightdust.midnightcontrols.ControlsMode; import eu.midnightdust.midnightcontrols.client.enums.ControllerType; import eu.midnightdust.midnightcontrols.client.MidnightControlsClient; import eu.midnightdust.midnightcontrols.client.MidnightControlsConfig; import eu.midnightdust.midnightcontrols.client.MidnightInput; import eu.midnightdust.midnightcontrols.client.compat.MidnightControlsCompat; import eu.midnightdust.midnightcontrols.client.controller.ButtonBinding; +import eu.midnightdust.midnightcontrols.client.enums.VirtualMouseSkin; import eu.midnightdust.midnightcontrols.client.util.HandledScreenAccessor; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.BufferRenderer; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.VertexFormat; +import net.minecraft.client.render.VertexFormats; import net.minecraft.client.resource.language.I18n; +import net.minecraft.client.texture.Sprite; import net.minecraft.screen.slot.Slot; +import net.minecraft.util.Identifier; import org.jetbrains.annotations.NotNull; +import org.joml.Matrix4f; import org.lwjgl.glfw.GLFW; +import static eu.midnightdust.midnightcontrols.MidnightControls.id; + /** * Represents the midnightcontrols renderer. * @@ -192,14 +205,28 @@ public class MidnightControlsRenderer { private static int getButtonTipWidth(@NotNull String action, @NotNull TextRenderer textRenderer) { return 15 + 5 + textRenderer.getWidth(action); } + public static void renderWaylandCursor(@NotNull DrawContext context, @NotNull MinecraftClient client) { + if (MidnightControlsConfig.virtualMouse || client.currentScreen == null || MidnightControlsConfig.controlsMode != ControlsMode.CONTROLLER) return; + + float mouseX = (float) client.mouse.getX() * client.getWindow().getScaledWidth() / client.getWindow().getWidth(); + float mouseY = (float) client.mouse.getY() * client.getWindow().getScaledHeight() / client.getWindow().getHeight(); + + try { + Identifier spritePath = MidnightControlsClient.WAYLAND_CURSOR_TEXTURE_LIGHT; + if (MidnightControlsConfig.virtualMouseSkin == VirtualMouseSkin.DEFAULT_DARK || MidnightControlsConfig.virtualMouseSkin == VirtualMouseSkin.SECOND_DARK) + spritePath = MidnightControlsClient.WAYLAND_CURSOR_TEXTURE_DARK; + Sprite sprite = client.getGuiAtlasManager().getSprite(spritePath); + drawUnalignedTexturedQuad(sprite.getAtlasId(), context, mouseX, mouseX + 8, mouseY, mouseY + 8, 999, sprite.getMinU(), sprite.getMaxU(), sprite.getMinV(), sprite.getMaxV()); + } catch (IllegalStateException ignored) {} + } public static void renderVirtualCursor(@NotNull DrawContext context, @NotNull MinecraftClient client) { if (!MidnightControlsConfig.virtualMouse || (client.currentScreen == null || MidnightInput.isScreenInteractive(client.currentScreen))) return; - int mouseX = (int) (client.mouse.getX() * (double) client.getWindow().getScaledWidth() / (double) client.getWindow().getWidth()); - int mouseY = (int) (client.mouse.getY() * (double) client.getWindow().getScaledHeight() / (double) client.getWindow().getHeight()); + float mouseX = (float) client.mouse.getX() * client.getWindow().getScaledWidth() / client.getWindow().getWidth(); + float mouseY = (float) client.mouse.getY() * client.getWindow().getScaledHeight() / client.getWindow().getHeight(); boolean hoverSlot = false; @@ -217,7 +244,7 @@ public class MidnightControlsRenderer { } if (!hoverSlot && client.currentScreen != null) { - var slot = MidnightControlsCompat.getSlotAt(client.currentScreen, mouseX, mouseY); + var slot = MidnightControlsCompat.getSlotAt(client.currentScreen, (int) mouseX, (int) mouseY); if (slot != null) { mouseX = slot.x(); @@ -231,32 +258,21 @@ public class MidnightControlsRenderer { mouseY -= 8; } - //context.getMatrices().push(); - context.getMatrices().translate(0f, 0f, 999f); - drawCursor(context, mouseX, mouseY, hoverSlot, client); - //context.getMatrices().pop(); + try { + Sprite sprite = client.getGuiAtlasManager().getSprite(id(MidnightControlsConfig.virtualMouseSkin.getSpritePath() + (hoverSlot ? "_slot" : ""))); + drawUnalignedTexturedQuad(sprite.getAtlasId(), context, mouseX, mouseX + 16, mouseY, mouseY + 16, 999, sprite.getMinU(), sprite.getMaxU(), sprite.getMinV(), sprite.getMaxV()); + } catch (IllegalStateException ignored) {} } - - /** - * Draws the virtual cursor. - * - * @param context the context - * @param x x coordinate - * @param y y coordinate - * @param hoverSlot true if hovering a slot, else false - * @param client the client instance - */ - public static void drawCursor(@NotNull DrawContext context, int x, int y, boolean hoverSlot, @NotNull MinecraftClient client) { - //RenderSystem.disableDepthTest(); - //RenderSystem.setShaderColor(1.f, 1.f, 1.f, 1.f); - //RenderSystem.disableBlend(); - //RenderSystem.setShaderTexture(0, MidnightControlsClient.CURSOR_TEXTURE); - context.drawTexture(MidnightControlsClient.CURSOR_TEXTURE, x, y, - hoverSlot ? 16.f : 0.f, MidnightControlsConfig.virtualMouseSkin.ordinal() * 16.f, - 16, 16, 32, 64); - context.fill(1, 1, x, y, 0xFFFFFF); - context.draw(); - //RenderSystem.enableDepthTest(); + private static void drawUnalignedTexturedQuad(Identifier texture, DrawContext context, float x1, float x2, float y1, float y2, float z, float u1, float u2, float v1, float v2) { + RenderSystem.setShaderTexture(0, texture); + RenderSystem.setShader(GameRenderer::getPositionTexProgram); + Matrix4f matrix4f = context.getMatrices().peek().getPositionMatrix(); + BufferBuilder bufferBuilder = Tessellator.getInstance().begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_TEXTURE); + bufferBuilder.vertex(matrix4f, x1, y1, z).texture(u1, v1); + bufferBuilder.vertex(matrix4f, x1, y2, z).texture(u1, v2); + bufferBuilder.vertex(matrix4f, x2, y2, z).texture(u2, v2); + bufferBuilder.vertex(matrix4f, x2, y1, z).texture(u2, v1); + BufferRenderer.drawWithGlobalProgram(bufferBuilder.end()); } public record ButtonSize(int length, int height) { diff --git a/common/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameRendererMixin.java b/common/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameRendererMixin.java index 94f1402..e7dcf78 100644 --- a/common/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameRendererMixin.java +++ b/common/src/main/java/eu/midnightdust/midnightcontrols/client/mixin/GameRendererMixin.java @@ -42,6 +42,7 @@ public abstract class GameRendererMixin { @Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;draw()V", shift = At.Shift.BEFORE)) private void renderVirtualCursor(RenderTickCounter tickCounter, boolean tick, CallbackInfo ci, @Local DrawContext drawContext) { MidnightControlsRenderer.renderVirtualCursor(drawContext, client); + if (MidnightControlsClient.isWayland) MidnightControlsRenderer.renderWaylandCursor(drawContext, client); drawContext.draw(); } @Inject(at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/GameRenderer;renderHand:Z"), method = "renderWorld") diff --git a/common/src/main/resources/assets/midnightcontrols/textures/gui/cursor.png b/common/src/main/resources/assets/midnightcontrols/textures/gui/cursor.png deleted file mode 100644 index 78fabc49ee8166aa3e9a1b7ce5e92016427b2f43..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 327 zcmV-N0l5B&P)GCb&#bTql9gjiUEk{bx7?%>|ZqBe_#xLSYNa6N?=m#sYW(ih8yy==-#EZo?al0LZ zE^Z@#k5s^zbs~VNz)nboBG`?i)B(f`u})MXeqG8Bq61}LPj3@dOEt71TP@aGU8z;} zEnQHMd*y=}76M!f?1WS(g0I(7Y7zZ~7#1p#^S2>C^cL0Mpr^Nqs-+s*kgXQ$t*+EA Z_WySTG|^zkN0$Hq002ovPDHLkV1fn3h=l+E diff --git a/common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/dark/default.png b/common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/dark/default.png new file mode 100644 index 0000000000000000000000000000000000000000..1fe04edcf066656343c76e9caa4ee9cb17ad35a5 GIT binary patch literal 4297 zcmeHKdu$X%7~gBD#R^EFv7)W63#L5W+uQB#?cJuwqjv{g?3JcHO7Q{R+nu|v+}$2~ z+upTELV5Uzh?=MgNCY%Sf&|nkL=8v*<0G1={DCMCQ{n?3(P$K6wDp_4>q|*Y6Zx-u zH#gtReBW=r`OP=q?L6Gruw-({O(g_DOqS~cO;At8Wnv-x&Ze(#hU#O~Do15`E-?`r zpy`-EIIs>B#|XK=QAl8`2cS#?8SCJ3lcUJ4w}O0gUVakf*?FA;kXc6oF&XNeP&kmw zpxy^Xe=s-KQIPR7(f-tdgpmj9C32{dpR4a`FTK#acER~` z>&_l2+`M>;-m!$A6 z{Qx)j<gh5QCk1xYcS6)k~_8a4MP+LC$OKbH`5fsytKI*5p-lj-h^HD2= zkSmn(qjtTn+eFRX4Pmu=jq25?1@lX4vJwC!kfo5>L_C?6vOdbjl|aVb3`N>1)*2tx z3UTB&Ohocd-sz%)S-q2^=9iE)rWTc&0*mty(DG63mX(qiCX>lHGu2MRj4`a&>t$RV z!*Mid(CMzErDW-3dM1X*VFXZGHT9IG8%YvlDiNc@@=+9wlY{;xQlZcgd@`M90r+6D zN{V5fE+&y+Mp~q;U?+g&9lD}LI^2~)OcP2Q9j1zcohWI|90{SRL-wf-Gj1M@rfIBax!fxNfluz z0C(zu!wbBiAR$7F)yPHj?rN2eL`6hbbDE&?)yR#a>IjHsrVdf5#7BCCp)`PE71qVM zRTmu*1vkw{!I6m9E6_ZEL^K|JWknlGQ>Dd*nNVOm^@I{bOez_(2QcB%qDI+ARXbh7 zJ&ke2ih_ZUs@Ibp+2Mh(o9>J z$rysfk&o2De*Fqjz$qTY32u(|@Ip1si(Uw%sK(Qx%CV{_vK}NvN28~WsFhJnv?vA? z=4cxHb0TNk+camiL8cwyJpj&Vmq@eXKRILaYi4l97+iD>^DkOzY=sdi2JCWukh&lf zGDE2_Pa94;SMkYj$5osGpvNZ}6Tjnhjng$I2F9d39$n*fjfsIVDUV0j|3+8I@MQ`m z;YBC|SEXOy>?7ftHLbBe9E5sFs{YWSLjwZ?9LLGBe0aeLd?9yOO%2V&!mmGz;zs1o zB?020qDp)bzcy93GEETIO~=JS?AUoDbQW83C|LY$acS9<;>@=AEa;kH1zRn@k-%^6 zg#AK^G%}-G?IeDoT+uV79F!{Mz@qStr_{D%j@Fg!Bg(Mg+65K0O0 TdgQnFF&ZHU8v+Mv+cy3UDu|!H literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/dark/default_slot.png b/common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/dark/default_slot.png new file mode 100644 index 0000000000000000000000000000000000000000..b44486161ceb797eca56e511ab1ed7547cee42a9 GIT binary patch literal 4311 zcmeHKdu$X%7~g9ttyLa{hKjbjESgeqZy$Gid$;L<^zNXGz0$O$v_7DFyK~o-yW3-L z+q+gtsNyRkLV_l0qoOeyB|eBki~%WvCPot;e;_J|B|h*GjV96zuq337p>kib^=LzxFM*1_c(N0D7`2l?8(yc^^td7T1~IY$983+e$VJjmrx zzYIlxAUD?`knyL){?>zpkw@#*a=3})oj#wF^MO6fyCqhXIFaOei4!D&18v8%;~rt8 z_iJV^29#}jAkZWS0%XcGqIw(=M0Q}yE`R-dH&-6p*zy8JQ$LbJJNHOuLLuvwbxZ2* zYg+c^cb(?N3b$V0e0ycl>3icnm;z)+EsR8aPx|D zXYcy_VBxk^_vvkGE00^BHB`@!cn&O`xuNVZd89;Xi$2a(%Qe{@uiZ5~+*fg-ow zD;Eg{cer}q2Tv%U9=-PHsi*c2_CDi1vS#0!yBlkhCyO4s{_R)a9DXEy0`P|eUwFJIivXt(V(&kgNecjw+MYcC(^+_16ZYw6>%8{T;E#`?K? zp1q%6`g+;(>#C2{J^9=G>nCpZ?zdeZW&lkEc|Y1cVT5^fg1X7!=-FyW5yVHTEBFu@WAKh zk-_rpR}h0edTYDY9&V6SBjHpuBZ8dSL<(;hQM)3WQq)bzA|oiKC;ik<@4QQqy5^_W z3t={#3ZO2%zRyH0eT}VZ-zL?kQ7e|0)@CIDNFYlgvx#^zEoJ?bjVpnSyBUhKRjf^Z zsvY7eV3>$>JKau}4rTQoo?2c?)|y&WY7VZ-LqN+&g_vfPHo8p}g?doZT09X#Q^)L6-Dccgj;1mw zjuN1nhFQ5uQ{odhW`QY)>4}tW1!PaswDjmWS(ALjBldD8Is)cnxRbO;*KR9=RyZsL z4YeD)CkOo$o?p@oRoA4PsJI26Ah>CdN7ZPzC@OS>M;tABT$;ckVTsl*5}h$k@jhPgm!b9n~o?*qdlD9Lmsc_atWRZ5Nk~xqEd-Z^a?|10L2Pk z1@T@UY!RZ}$m5~C(TGSRjpa2})ZB{4XG3YKw8}6O3T&sIP-2KlC1dsgCR|$CB>O3s zlO6AAiYrzW4E$7sp6t$!547qD)M6=^O-|%F-YvQWo)tWTkekTHYeQxlBGFIfbEj>N zw?%@*0I>>=Qvk60VJ%X?M2cmYt%eczQy5}wBn&4>Q!FK@SP1aOQgG{N3SP$Y5}WfJ zBZUo3kM{nXHa<6GE$G8;*XwDRy4UW?9i|qvIoHZHqL(Bx48?M?O+V`}Kc_0QI9An93OQ@#9S1Np{I?g zl~GKzG6odpXd3-R1xZd%G9`Ye>6)f%N(@X%c{;kL>6#J)Q&OIe zuK$d#((%U>O2S1b15c%rj+4dk%$nEK&>Dhzb*f?i{{15(BRtQ`vV360d-y@_u$miN zh?~FuB#Il6TUG~&2aBrkL;Q+VeMg!guAGmHgLrb_YUnJs>=)St% qrqI!n$f3dG~cmeU$fMe0Ik)Z}KBjiwH@YTA`d;S8%n59bq literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/dark/mouse_pointer.png b/common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/dark/mouse_pointer.png new file mode 100644 index 0000000000000000000000000000000000000000..dd957f0f06dc1b475fe8d6564ccb75043d455227 GIT binary patch literal 4346 zcmeHKe{dAl9p6g`iBXUUHKIvfR@*@6-u}3~AG?zaBzG5bmXS9&F70G!*TjTwjO5##f1bH-d$kN1jWj%~~MP5)K5&w4uke1R{v+z=j?E##a|tyw&&-0+~*zO3T7^?p;;?5O8p_4GAmN64WPxjps^t}47B``B~$UAfX% zety;2kB2MfxpnSH)eUd#l;1mg%h8ihyfE0i+c&iI4@>WFu1URBwDs1Po;`5oQS$`q zk2f4^>U+{x|DzjU?zj+b=iTQPoZI*Gg~u87?)}EubNg4^yMM#7;i0u_I#>No`b*jE zzkm1#jkESVwS}*KzU)^ks$Q$#^{?6AAC^xsJMNgba_+W@YxmVZ@aew?uYQ<0*e)A; ze?F&)IK({mPp))YPk-#p`olk|{7rAcmEHXd51oI`vvKFLxBgy9_f5MlQCNPeGIF}m znc29fD&RpY|8a6oY0-yYZ9BZ6c(dL={Kt0v(uRRrV(!K2?!tQUs(Cet`!M9rdXT2|H}i;SYUmhw}d zz5EJAYO0@F>5j0GbO3c}jeQ1M-q+lw^sQ4wm0DC=T9cK4Ac-uQ%q9~lQ_A`&n^yuG zyBUhKA=WxS)dBM;pc{x3oPv|3Ls_kdr)o>d8bggqt-*#o1-$vGF3U zH{uK@iXy}E4A0Ympv~TtC1>fBc^jt4aRia67+TuW^c0CX<*43m`6&wO$&vVy=}2Uh zK4s=r06mzjoMt#D%OsP`_!g!W>H(5`KwsO!Z0k)UrWKibx1pd=4@z0Lji*qR(e~+X zBVi9mRTz{&Nr0NrD>tD_yy8Y%UkD~>*$kIM9=c5&m+oSk+kE#gb zII3{UwB(e6FcpwHHQ@0gUi2y)OCvAqp#=eWL>KR(IgcWGxu~j&yfBVpnW4d~loR8l z!c;0y@rsBzQC8`wE2_|f*C*3a86nyyL{-5h3T({B*;J|`HRwiChIDF4IgXfgDsER` z!KJ#Eu%B`{*)dN`LbhViz)v-4sqXApMVppH%PkqJ$$5E>7u-C{`8+N!>m38NBg2H5 z=%?~~r(J{7BEeulSQ*b#Ah7)~7AasL+0ui;mC_}r;s`d5{7fD3YhN=95XUJopXjDlK^15r=2mD?hD<`*_?Rc=7QAY1 zRHN*s9Db2c@9pIOtRcPt4KwfHW1y$gG;NjI)C3F6w>xHyPi z12=)Q*a}BN#h(|C?+x^Q>w|AiK%LAW(@0};&2mVT=J3H2G rm~m#4>-elM7BAU&v)7fo+hcFr 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 literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/light/default_slot.png b/common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/light/default_slot.png new file mode 100644 index 0000000000000000000000000000000000000000..636545fb506634c66f9302c300759694073e34a6 GIT binary patch literal 4311 zcmeHKdu$s;8ehjv69R>%jR=JVmIW?p%X%O7#`Y37G`8DpiPMmzNy?+`cz4#>tL=5y zo7f3dYM{JCc}WGSB`WkzCn~5YhqzVq7$kUxL45? zWf@ft4bXJWqg+G>iffu&;&M~O>Om-rKqfk*TK!0oQ-i~<2$Hz(i@O13yAckzE8#Gmu}s}aVv5R-Y<()!^46_2Z*T1U3&S#B(`TRDE1!-= z?U&ZoH$Tw6{I#z(S?8;LMoY(CHKnKSyZ^dJ*OgT#?ykM7bmh11aK#XxaP?l}G7g<)~YKMyOMk<{v+B&)C>d z^||$DzPMO(y<`eU>lXce7kdBrHOEgrdvJ8{xxleCudcbbtug&x=_A*@{_<;Mk7eJ* z!--Yzv<~eFG~ayX8@=b_-J*1M>DhfRp5Mu7ckZ{&oZY|fkNdZ-y?AWXhK=h#m;YIL z<6j@Xsb%5b=N}Z8y;Aw-b#-qy@BV)AwHMJT?y1|Z?^&{==F)x5_y6aAqvN0C4s|2z zPfu61Qir+6zY{9v4GilaZ8`Ep?F)k?W6upQKYZ>$!?s;(-}`qhJ2daIq`Uf5ZS1t$ zliRkpF5G~7{(G{jqV$s=b{tt+w%r`Q__uEJ>#ZXzs3l)5>vz}Gl&H~vY`BomZOobD zdyESg+=o82j*V93KZ6(?FuHo}-dL-wnkf&`%sBSsQyH>hRAW;XWQrJdxK9x*o<$Q>7aAlB5 zH^j>xJa1hhg-pKWJkj?3k8o}AZX zS_w`F27??ga-ztB2AdsB+bGYbvo{ck0!9R9Rm;fOhMA@bCW@Q=c8FnMoSyJ6m5IeB z;nUe73&01LM;T7=@LVdzO}EI}(E$J{I`oSc*{;D1<~nfJ?6*`L9l&Y(hUpNRI%%Kj zx023sG?l|ioC4J>%qq;7lAO3n3qnD{NM#%=AbW+%=Jc zm-C{`7d$6OF;g@2!C%uR=Z0O{Zs3sDfzqbCb-9-#NPG=$aJ+vr?Xmt~t79#lWnT z=c4O3qpM=-F@@7`5z4_+=|I!%_rf!4QG07w6zbKP)`JHRj*pLvqNpg!p{BRUgWP3z zv~^Oqe*Q0=G~&0dj!+Mm){=+#C7G7>S&F)JF)1!;_sCVyS!OG-XxW!#l~vwb#7lZ> zp=*g9?X|;Zirm~O=R%1!I%n8@G`Udr3}0RiO3RhV%C4(Us+;D!=JVV5UAwkX%+Yze s7#?ho9xp#p_T;C${)eiMMKpFL)iXlv9j$l23TBiNZHv6zyy?Cl0g_gwJOBUy literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/light/mouse_pointer.png b/common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/light/mouse_pointer.png new file mode 100644 index 0000000000000000000000000000000000000000..c12dff58a517ce2d00933295ab2d30d42994447d GIT binary patch literal 4647 zcmeHLeQ*@z8Q)6?i3f2Eq>V^Y*QIUv=-z&0?_;+)Ah|opVGc6k2*D!cz1?>&D|ffY z?k0DMGBrT7R8*k0qn1&qfVTPtN+1|%tJr`A@X9fpdGg{cLUX~%X7bz1DRdzY`l znNDWpzwFL?`|k5T@9%w{-}AiB-tLaJmCGyLx48*|sEoFR+u>Smw~FcT`|yssN`i1z zfAKsEye(+F2l&o!=J;wmLdLB0pt&8`w+7F-{PHVfpozTIwfl{wcJp+C3S ze+ByUi#qmv4(7tL#4n-o(6{aRH8kzP!n$XmZyy!T88R@kutMfEtD9UNjkOW}l7bH- zS6fK(9#QmgA|SH7AhCXl^OHO;aUArC65@e9<-{Do{1lpN-2xGw{dmp%=E1f_uU_gh zF4hQIOZ)oTvQt~P-Tu&;@|xt`b?eKT{$6_g^icHO$cq1LysNwF{LtnlXWzf~%#qUV z%LcWMRkiO}@3q#?PWTQjoW7yz7&%;lI@BL<_0a|SM_#`7>ec?5^Xtz3^;+#6UY$Eu zKkLmW(4UUaJ$~|sKOgFQIxxKAl@<4`Y|NY}+j09ZUV8QF!{)nqAi3n9UirIbV9c$<8tex?E^R|ya9s2Bp+@TI+{OJ4Dt;7-Lk$-UR zX}tsL`f z=l=q^w_b~PTAi_0N!HUIr05Ck$)~eU7#o-5vq;{AEi!?VS|&*S?eJ?9sVPBftvANT zvLW29we%Z!b^pq^+`mZ{6>7<1cVk`xfHbxcnNO!Orj!p-4z2`!Tg*_Tqhf6eQk{@( zA>F{F;1N759m#9GJhj+OHX4d5wTG7#A>b}Zbz4?eVwhYm=gBpAbR)@dq9`&f&+t4A z8noG$u~44QnDcCi0!A2{vY}-yP0x@vCQ9f%R*<4#oE)()osGpt;WK8D1>l3pqb$RD zSSFoj#?LUVNH2gC4f@;}X1p(pnRaaIJ%)@Uy*Ojd8xNt#qw}*pM#^zVkr|xAX;3v` zRc^wP_P!jQVN;OQ(phH~kUc@u($q1sCfH_=IPQ!$1g4MTPS76l-BAXuSWF7*a*u6Z zG#sSt^(94@HAQl|4Prw8vk8v&D*=ucydp~n{9J&ReO{j&;C+fLh~uE58Ph@;8QV|* z?$H3J0ds5u0|fSQ3N0Xn>4dB(fGG2#j1n@-qHz$b3=OgprN&!jLn#2o%Od7Pq|k|m zgiH(m0HPBJV>%!t6rn*BST(>oP>L)q(~UHOaB69k#7s7mbOvm~rKYxMkZSO-W0JNM zvQ(H5q*}F1PkwA5uBGv63)yUPexBn6KkEyyEYExWV@e&^Fd-9zRI$Q3BX(FMa0ZA) zcAf%&BL`n3r;O@GT-Q@U$~I|qBnCT4K^6)_K?l6iLLDC|)QebNVhfhrNHJZ})V}|x zZSNbh5%eM2Et+ZRMxP@pY^K$CbK$OVo6?+JM3T;akdR!k-bB4vaqI-F!jRmJGD!@D zqnN29a_w`n0CSwI21GBd2#P=ps#m5(1d)WW@v2Yt3Vx;F)hN2Dt5yyfxG4z~7HArI zgpu=|FfEv9POcly7>0=dA-3o3^iCK~+(cv*Oa2PS&i$k=spB(#mpb-^zvj4PzTPC*6*8tOeWTJVdsL11p= zQB1lUxdcg0Eix&7r|6oZYf=nMN_i@~rs$d!1Cvso%C0YrF8A0gBhJ9zy&Sv{-Zl8U zKf>$e^u(RZ!^C3ytazjQ1(4j7ZCPi+H>bMpPvi7ZCW*(U3VXMo%mkc zcMslUeEjXo`*tl|+TP;c`3bSBee0Jlx%M4YAKX)2wR`W+9&7*SN4a-q9@+Nw3$x?T z%xfDwI`HO&nT^e_9ZOqfXZn86&VA!n7jdxTQ2%gOS!Gk@AIvN7b?;kp*b{B9{pN?a StkA&(A{tp4eyO=@>;C}ew+@*A literal 0 HcmV?d00001 diff --git a/common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/light/secondary.png b/common/src/main/resources/assets/midnightcontrols/textures/gui/sprites/cursor/light/secondary.png new file mode 100644 index 0000000000000000000000000000000000000000..e62b6cd15edeff443db6d5a098a898aaae7fffe3 GIT binary patch literal 4321 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 E0M*i`!T