diff --git a/src/client/java/ru/nevetime/clientirc/ClientIrcMod.java b/src/client/java/ru/nevetime/clientirc/ClientIrcMod.java index 2ce2e2a..ad5a60c 100644 --- a/src/client/java/ru/nevetime/clientirc/ClientIrcMod.java +++ b/src/client/java/ru/nevetime/clientirc/ClientIrcMod.java @@ -39,6 +39,7 @@ public final class ClientIrcMod implements ClientModInitializer { FriendsManager.init(configDir); service = new IrcService(config, LOGGER); + OverlayHud.init(); MiddleClickHandler.init(() -> service, () -> resolvePlayerName(Minecraft.getInstance())); ClientLifecycleEvents.CLIENT_STARTED.register(client -> { diff --git a/src/client/java/ru/nevetime/clientirc/OverlayHud.java b/src/client/java/ru/nevetime/clientirc/OverlayHud.java new file mode 100644 index 0000000..ea98bae --- /dev/null +++ b/src/client/java/ru/nevetime/clientirc/OverlayHud.java @@ -0,0 +1,103 @@ +package ru.nevetime.clientirc; + +import com.mojang.authlib.GameProfile; +import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElement; +import net.fabricmc.fabric.api.client.rendering.v1.hud.HudElementRegistry; +import net.fabricmc.fabric.api.client.rendering.v1.hud.VanillaHudElements; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.multiplayer.PlayerInfo; +import net.minecraft.resources.Identifier; + +public final class OverlayHud { + private static final Identifier COMPASS_LAYER = Identifier.fromNamespaceAndPath("clientirc", "compass"); + private static final Identifier WATERMARK_LAYER = Identifier.fromNamespaceAndPath("clientirc", "watermark"); + + private static final int COMPASS_WIDTH = 180; + private static final int COMPASS_HEIGHT = 14; + private static final int COMPASS_Y = 2; + + private OverlayHud() {} + + public static void init() { + HudElementRegistry.attachElementAfter( + VanillaHudElements.MISC_OVERLAYS, COMPASS_LAYER, (HudElement) OverlayHud::renderCompass); + HudElementRegistry.attachElementAfter( + VanillaHudElements.MISC_OVERLAYS, WATERMARK_LAYER, (HudElement) OverlayHud::renderWatermark); + } + + private static void renderCompass(GuiGraphicsExtractor graphics, DeltaTracker deltaTracker) { + Minecraft mc = Minecraft.getInstance(); + if (mc.level == null) return; + Font font = mc.font; + + int x = (graphics.guiWidth() - COMPASS_WIDTH) / 2; + int y = COMPASS_Y; + + graphics.fill(x, y, x + COMPASS_WIDTH, y + COMPASS_HEIGHT, 0x80000000); + + float yaw = mc.gameRenderer.mainCamera().yRot(); + + int[] cardYaws = {180, -90, 0, 90}; + String[] cardLabels = {"N", "E", "S", "W"}; + + for (int i = 0; i < cardYaws.length; i++) { + float delta = wrapDegrees(cardYaws[i] - yaw); + if (Math.abs(delta) > 90.0f) continue; + int px = x + 90 + (int) delta; + int color = Math.abs(delta) <= 5.0f ? 0xFFFFFF55 : 0xFFFFFFFF; + int labelWidth = font.width(cardLabels[i]); + graphics.text(font, cardLabels[i], px - labelWidth / 2, y + 3, color, true); + } + + graphics.fill(x + 89, y + 11, x + 92, y + 14, 0xFFFFFFFF); + } + + private static void renderWatermark(GuiGraphicsExtractor graphics, DeltaTracker deltaTracker) { + Minecraft mc = Minecraft.getInstance(); + if (mc.level == null) return; + Font font = mc.font; + int x = 4; + int y = 4; + int lineHeight = font.lineHeight + 2; + + String nick = resolveNick(mc); + int fps = mc.getFps(); + int ping = resolvePing(mc); + + graphics.text(font, nick, x, y, 0xFFFFFFFF, true); + graphics.text(font, "FPS: " + fps, x, y + lineHeight, 0xFFFFFFFF, true); + graphics.text(font, "Ping: " + ping + " ms", x, y + 2 * lineHeight, 0xFFFFFFFF, true); + } + + private static String resolveNick(Minecraft mc) { + if (mc.player != null) { + GameProfile profile = mc.player.getGameProfile(); + if (profile != null && profile.name() != null && !profile.name().isBlank()) { + return profile.name(); + } + } + if (mc.getUser() != null) { + String name = mc.getUser().getName(); + if (name != null && !name.isBlank()) { + return name; + } + } + return "—"; + } + + private static int resolvePing(Minecraft mc) { + if (mc.getConnection() == null || mc.getUser() == null) return 0; + PlayerInfo info = mc.getConnection().getPlayerInfo(mc.getUser().getProfileId()); + return info == null ? 0 : info.getLatency(); + } + + private static float wrapDegrees(float v) { + v = v % 360.0f; + if (v >= 180.0f) v -= 360.0f; + if (v < -180.0f) v += 360.0f; + return v; + } +}