From 7bc0fdba85d29ded27cfc2e0a2edffc50e102c1c Mon Sep 17 00:00:00 2001 From: JoyelTheDev <222600183+JoyelTheDev@users.noreply.github.com> Date: Sun, 28 Jun 2026 07:05:44 +0530 Subject: [PATCH 1/3] added coordinates and fps in hud --- .../java/me/madeq/client/hud/HudManager.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/client/java/me/madeq/client/hud/HudManager.java b/src/client/java/me/madeq/client/hud/HudManager.java index 04365d0..eb07082 100644 --- a/src/client/java/me/madeq/client/hud/HudManager.java +++ b/src/client/java/me/madeq/client/hud/HudManager.java @@ -11,6 +11,7 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.multiplayer.ClientPacketListener; import net.minecraft.client.multiplayer.ServerData; +import net.minecraft.world.entity.player.Player; public class HudManager { private static final int X = 8; @@ -37,7 +38,9 @@ public void render(GuiGraphics graphics) { List lines = List.of( new HudLine("IP", getServerIp(minecraft)), new HudLine("Engine", getEngine(minecraft)), - new HudLine("Last Packet", getLastPacketText()) + new HudLine("Last Packet", getLastPacketText()), + new HudLine("XYZ", getCoordinates(minecraft)), + new HudLine("FPS", getFps(minecraft)) ); int width = getPanelWidth(font, lines); int height = HEADER_HEIGHT + PADDING + lines.size() * ROW_HEIGHT + PADDING; @@ -123,6 +126,19 @@ private double getPacketAgeSeconds() { return (System.currentTimeMillis() - lastPacketTimeMillis) / 1000.0D; } + private String getCoordinates(Minecraft minecraft) { + Player player = minecraft.player; + if (player == null) { + return "N/A"; + } + return String.format(Locale.ROOT, "%.1f / %.1f / %.1f", + player.getX(), player.getY(), player.getZ()); + } + + private String getFps(Minecraft minecraft) { + return minecraft.getFps() + " fps"; + } + private record HudLine(String label, String value) { } -} +} \ No newline at end of file From e516075ffc45829b50e3965e6847e32c5769f7f1 Mon Sep 17 00:00:00 2001 From: JoyelTheDev <222600183+JoyelTheDev@users.noreply.github.com> Date: Sun, 28 Jun 2026 14:18:45 +0530 Subject: [PATCH 2/3] added command suggestion --- .../command/suggestion/CommandSuggestion.java | 3 + .../suggestion/CommandSuggestionManager.java | 261 ++++++++++++++++++ .../madeq/client/mixin/ChatScreenMixin.java | 49 ++++ .../resources/liteclient.client.mixins.json | 1 + 4 files changed, 314 insertions(+) create mode 100644 src/client/java/me/madeq/client/command/suggestion/CommandSuggestion.java create mode 100644 src/client/java/me/madeq/client/command/suggestion/CommandSuggestionManager.java create mode 100644 src/client/java/me/madeq/client/mixin/ChatScreenMixin.java diff --git a/src/client/java/me/madeq/client/command/suggestion/CommandSuggestion.java b/src/client/java/me/madeq/client/command/suggestion/CommandSuggestion.java new file mode 100644 index 0000000..2e95ec3 --- /dev/null +++ b/src/client/java/me/madeq/client/command/suggestion/CommandSuggestion.java @@ -0,0 +1,3 @@ +package me.madeq.client.command.suggestion; + +public record CommandSuggestion(String completion, String label, String description) {} diff --git a/src/client/java/me/madeq/client/command/suggestion/CommandSuggestionManager.java b/src/client/java/me/madeq/client/command/suggestion/CommandSuggestionManager.java new file mode 100644 index 0000000..af283ca --- /dev/null +++ b/src/client/java/me/madeq/client/command/suggestion/CommandSuggestionManager.java @@ -0,0 +1,261 @@ +package me.madeq.client.command.suggestion; + +import me.madeq.client.LiteClient; +import me.madeq.client.command.Command; +import me.madeq.client.command.CommandArgument; +import me.madeq.client.command.CommandManager; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.EditBox; +import org.lwjgl.glfw.GLFW; + +import java.util.ArrayList; +import java.util.List; + +public class CommandSuggestionManager { + + private static final int ROW_HEIGHT = 12; + private static final int PADDING_X = 4; + private static final int PADDING_Y = 3; + private static final int MAX_VISIBLE = 8; + + private static final int COLOR_BG = 0xCC101010; + private static final int COLOR_HIGHLIGHT = 0xCC1A4A7A; + private static final int COLOR_BORDER = 0xFF2A6AB0; + private static final int COLOR_LABEL = 0xFFFFFFFF; + private static final int COLOR_DESCRIPTION = 0xFFAAAAAA; + private static final int COLOR_ARG_HINT = 0xFF55AAFF; + private static final int COLOR_SEPARATOR = 0xFF333333; + + private final List suggestions = new ArrayList<>(); + private int selectedIndex = 0; + private String lastInput = ""; + + public void updateIfChanged(String currentInput) { + if (!currentInput.equals(lastInput)) { + lastInput = currentInput; + recompute(currentInput); + } + } + + public void render(GuiGraphics graphics, EditBox input, int screenWidth, int screenHeight) { + if (suggestions.isEmpty()) return; + + Minecraft mc = Minecraft.getInstance(); + int fontHeight = mc.font.lineHeight; + + int visibleCount = Math.min(suggestions.size(), MAX_VISIBLE); + int scrollOffset = computeScrollOffset(visibleCount); + int popupWidth = computePopupWidth(mc, visibleCount, scrollOffset); + int popupHeight = visibleCount * ROW_HEIGHT + PADDING_Y * 2; + int inputY = input.getY(); + int popupX = input.getX(); + int popupY = inputY - popupHeight - 2; + + if (popupY < 2) popupY = inputY + input.getHeight() + 2; + + graphics.fill(popupX - 1, popupY - 1, popupX + popupWidth + 1, popupY + popupHeight + 1, COLOR_BORDER); + graphics.fill(popupX, popupY, popupX + popupWidth, popupY + popupHeight, COLOR_BG); + + for (int i = 0; i < visibleCount; i++) { + int globalIdx = scrollOffset + i; + CommandSuggestion suggestion = suggestions.get(globalIdx); + + int rowY = popupY + PADDING_Y + i * ROW_HEIGHT; + + if (globalIdx == selectedIndex) { + graphics.fill(popupX, rowY - 1, popupX + popupWidth, rowY + ROW_HEIGHT - 1, COLOR_HIGHLIGHT); + } + + if (i < visibleCount - 1) { + graphics.fill(popupX + 2, rowY + ROW_HEIGHT - 2, popupX + popupWidth - 2, rowY + ROW_HEIGHT - 1, COLOR_SEPARATOR); + } + + int textY = rowY + (ROW_HEIGHT - fontHeight) / 2; + int cursorX = popupX + PADDING_X; + + graphics.drawString(mc.font, suggestion.label(), cursorX, textY, COLOR_LABEL, false); + cursorX += mc.font.width(suggestion.label()) + 4; + + if (!suggestion.description().isEmpty()) { + String desc = "- " + suggestion.description(); + graphics.drawString(mc.font, desc, cursorX, textY, COLOR_DESCRIPTION, false); + cursorX += mc.font.width(desc) + 6; + } + + if (globalIdx == selectedIndex) { + String argHint = buildArgHint(suggestion.completion()); + if (!argHint.isEmpty()) { + graphics.drawString(mc.font, argHint, cursorX, textY, COLOR_ARG_HINT, false); + } + } + } + + if (suggestions.size() > MAX_VISIBLE) { + String indicator = (scrollOffset + 1) + "-" + (scrollOffset + visibleCount) + "/" + suggestions.size(); + int indX = popupX + popupWidth - mc.font.width(indicator) - PADDING_X; + int indY = popupY + popupHeight - ROW_HEIGHT / 2 - mc.font.lineHeight / 2; + graphics.drawString(mc.font, indicator, indX, indY, COLOR_DESCRIPTION, false); + } + } + + public boolean handleKeyPress(int keyCode, EditBox input) { + if (suggestions.isEmpty()) return false; + + return switch (keyCode) { + case GLFW.GLFW_KEY_UP -> { + selectedIndex = (selectedIndex - 1 + suggestions.size()) % suggestions.size(); + yield true; + } + case GLFW.GLFW_KEY_DOWN -> { + selectedIndex = (selectedIndex + 1) % suggestions.size(); + yield true; + } + case GLFW.GLFW_KEY_TAB -> { + applySuggestion(input, suggestions.get(selectedIndex)); + yield true; + } + case GLFW.GLFW_KEY_ESCAPE -> { + suggestions.clear(); + yield true; + } + default -> false; + }; + } + + public boolean handleMouseClick(double mouseX, double mouseY, EditBox input, int screenWidth, int screenHeight) { + if (suggestions.isEmpty()) return false; + + Minecraft mc = Minecraft.getInstance(); + int visibleCount = Math.min(suggestions.size(), MAX_VISIBLE); + int scrollOffset = computeScrollOffset(visibleCount); + int popupWidth = computePopupWidth(mc, visibleCount, scrollOffset); + int popupHeight = visibleCount * ROW_HEIGHT + PADDING_Y * 2; + int popupX = input.getX(); + int inputY = input.getY(); + int popupY = inputY - popupHeight - 2; + + if (popupY < 2) popupY = inputY + input.getHeight() + 2; + + if (mouseX < popupX || mouseX > popupX + popupWidth) return false; + if (mouseY < popupY || mouseY > popupY + popupHeight) return false; + + int relY = (int) mouseY - popupY - PADDING_Y; + int clickedRow = relY / ROW_HEIGHT; + int globalIdx = scrollOffset + clickedRow; + + if (globalIdx >= 0 && globalIdx < suggestions.size()) { + selectedIndex = globalIdx; + applySuggestion(input, suggestions.get(globalIdx)); + return true; + } + return false; + } + + private void recompute(String input) { + suggestions.clear(); + selectedIndex = 0; + + CommandManager cm = LiteClient.getCommandManager(); + String prefix = cm.getPrefix(); + + if (!input.startsWith(prefix)) return; + + String afterPrefix = input.substring(prefix.length()); + String[] parts = afterPrefix.split(" ", -1); + + if (parts.length == 0) return; + + String typedCommandName = parts[0].toLowerCase(); + + if (parts.length == 1) { + for (Command cmd : cm.getCommands()) { + if (!cmd.isVisibleInHelp()) continue; + if (cmd.getName().toLowerCase().startsWith(typedCommandName)) { + suggestions.add(new CommandSuggestion( + prefix + cmd.getName(), + prefix + cmd.getName(), + cmd.getDescription() + )); + } + } + } else { + Command cmd = findCommand(cm, typedCommandName); + if (cmd == null) return; + + int argIndex = parts.length - 2; + if (argIndex < 0 || argIndex >= cmd.getArguments().size()) return; + + CommandArgument arg = cmd.getArguments().get(argIndex); + if (!arg.hasOptions()) return; + + String typedArg = parts[parts.length - 1].toLowerCase(); + String baseCompletion = prefix + typedCommandName + " " + + String.join(" ", java.util.Arrays.copyOfRange(parts, 1, parts.length - 1)); + if (parts.length > 2) baseCompletion += " "; + + for (String option : arg.options()) { + if (option.toLowerCase().startsWith(typedArg)) { + suggestions.add(new CommandSuggestion( + baseCompletion + option, + option, + arg.name() + " option" + )); + } + } + } + } + + private void applySuggestion(EditBox input, CommandSuggestion suggestion) { + input.setValue(suggestion.completion() + " "); + input.moveCursorToEnd(false); + recompute(input.getValue()); + lastInput = input.getValue(); + } + + private Command findCommand(CommandManager cm, String name) { + return cm.getCommands().stream() + .filter(c -> c.getName().equalsIgnoreCase(name)) + .findFirst() + .orElse(null); + } + + private String buildArgHint(String completion) { + CommandManager cm = LiteClient.getCommandManager(); + String prefix = cm.getPrefix(); + + String afterPrefix = completion.startsWith(prefix) + ? completion.substring(prefix.length()).trim() + : completion.trim(); + String commandName = afterPrefix.split(" ")[0]; + + Command cmd = findCommand(cm, commandName); + if (cmd == null || cmd.getArguments().isEmpty()) return ""; + + StringBuilder hint = new StringBuilder(" "); + for (CommandArgument arg : cmd.getArguments()) { + hint.append("<").append(arg.name()).append(":").append(arg.type().getDisplayName()).append("> "); + } + return hint.toString().stripTrailing(); + } + + private int computeScrollOffset(int visibleCount) { + int offset = 0; + if (selectedIndex >= visibleCount) { + offset = selectedIndex - visibleCount + 1; + } + return offset; + } + + private int computePopupWidth(Minecraft mc, int visibleCount, int scrollOffset) { + int maxWidth = 120; + for (int i = 0; i < visibleCount; i++) { + CommandSuggestion s = suggestions.get(scrollOffset + i); + int w = PADDING_X * 2 + + mc.font.width(s.label()) + + (s.description().isEmpty() ? 0 : 4 + mc.font.width("- " + s.description())); + if (w > maxWidth) maxWidth = w; + } + return maxWidth; + } +} diff --git a/src/client/java/me/madeq/client/mixin/ChatScreenMixin.java b/src/client/java/me/madeq/client/mixin/ChatScreenMixin.java new file mode 100644 index 0000000..f82b217 --- /dev/null +++ b/src/client/java/me/madeq/client/mixin/ChatScreenMixin.java @@ -0,0 +1,49 @@ +package me.madeq.client.mixin; + +import me.madeq.client.command.suggestion.CommandSuggestionManager; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.screens.ChatScreen; +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; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ChatScreen.class) +public class ChatScreenMixin { + + @Shadow + protected EditBox input; + + @Unique + private final CommandSuggestionManager liteclient$suggestionManager = new CommandSuggestionManager(); + + @Inject(method = "render", at = @At("HEAD")) + private void liteclient$updateSuggestions(GuiGraphics graphics, int mouseX, int mouseY, float delta, CallbackInfo ci) { + liteclient$suggestionManager.updateIfChanged(input.getValue()); + } + + @Inject(method = "render", at = @At("TAIL")) + private void liteclient$renderSuggestions(GuiGraphics graphics, int mouseX, int mouseY, float delta, CallbackInfo ci) { + ChatScreen self = (ChatScreen)(Object)this; + liteclient$suggestionManager.render(graphics, input, self.width, self.height); + } + + @Inject(method = "keyPressed", at = @At("HEAD"), cancellable = true) + private void liteclient$onKeyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable cir) { + if (liteclient$suggestionManager.handleKeyPress(keyCode, input)) { + cir.setReturnValue(true); + } + } + + @Inject(method = "mouseClicked", at = @At("HEAD"), cancellable = true) + private void liteclient$onMouseClicked(double mouseX, double mouseY, int button, CallbackInfoReturnable cir) { + ChatScreen self = (ChatScreen)(Object)this; + if (liteclient$suggestionManager.handleMouseClick(mouseX, mouseY, input, self.width, self.height)) { + cir.setReturnValue(true); + } + } +} diff --git a/src/client/resources/liteclient.client.mixins.json b/src/client/resources/liteclient.client.mixins.json index 7c6c06d..76df13b 100644 --- a/src/client/resources/liteclient.client.mixins.json +++ b/src/client/resources/liteclient.client.mixins.json @@ -5,6 +5,7 @@ "client": [ "AbstractWidgetMixin", "ChatComponentMixin", + "ChatScreenMixin", "ClientHandshakePacketListenerImplMixin", "ClientPacketListenerMixin", "ConnectScreenMixin", From dff60a17359b94dcb2bce330164ff2bf24e892a0 Mon Sep 17 00:00:00 2001 From: JoyelTheDev <222600183+JoyelTheDev@users.noreply.github.com> Date: Sun, 28 Jun 2026 14:23:22 +0530 Subject: [PATCH 3/3] updated discord rpc --- build.gradle | 2 +- gradle.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 0631dd4..0d1da6f 100644 --- a/build.gradle +++ b/build.gradle @@ -64,7 +64,7 @@ dependencies { modCompileOnly "com.viaversion:viafabricplus-api:${project.viafabricplus_version}" - include implementation("com.github.Vatuu:discord-rpc:${project.discordrpc_version}") + include implementation("com.github.JoyelTheDev:discord-rpc:${project.discordrpc_version}") } diff --git a/gradle.properties b/gradle.properties index 065a157..a93453f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,6 +22,6 @@ adventure_version=4.17.0 viafabricplus_version=4.4.8 minecraftauth_version=4.1.1 -discordrpc_version=1.6.2 +discordrpc_version=v1 examination_version=1.3.0 \ No newline at end of file