Add friends, markers, HUD overlays, tab complete
- FriendsManager persists a per-user friend list at config/clientirc-friends.json. - MarkerManager holds one ephemeral marker per owner (5 min expiry). - IRC protocol extended with marker_set / marker_remove; server relays them. - IrcService DisplayLine replaced with sealed IrcEvent (Chat / System / MarkerSet / MarkerRemove); chat formatting moved into the client. - ClientIrcMod handles .friends add/remove/list, .marker remove, .help; chat lines from friends are prefixed with a green dot; marker events from non-friends are ignored. - OverlayHud draws a top-center compass strip and a top-left watermark (nick / FPS / ping) via HudLayerRegistrationCallback. - WorldOverlayRenderer draws green crosses above friends and magenta beams + base cubes at active markers via WorldRenderEvents.AFTER_ENTITIES. - MiddleClickHandler binds MMB via KeyMapping, raycasts a block or 20-block look ray, stores locally and sends marker_set on a daemon executor. - ChatScreenMixin completes . prefix commands on Tab; first mixin in the project, plumbed through clientirc.client.mixins.json and fabric.mod.json.
This commit is contained in:
126
src/client/java/ru/nevetime/clientirc/OverlayHud.java
Normal file
126
src/client/java/ru/nevetime/clientirc/OverlayHud.java
Normal file
@@ -0,0 +1,126 @@
|
||||
package ru.nevetime.clientirc;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.HudLayerRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.IdentifiedLayer;
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.LayeredDraw;
|
||||
import net.minecraft.client.multiplayer.PlayerInfo;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public final class OverlayHud {
|
||||
private static final ResourceLocation COMPASS_LAYER = ResourceLocation.fromNamespaceAndPath("clientirc", "compass");
|
||||
private static final ResourceLocation WATERMARK_LAYER = ResourceLocation.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() {
|
||||
HudLayerRegistrationCallback.EVENT.register(layered -> {
|
||||
layered.attachLayerAfter(IdentifiedLayer.MISC_OVERLAYS, COMPASS_LAYER, (LayeredDraw.Layer) OverlayHud::renderCompass);
|
||||
layered.attachLayerAfter(IdentifiedLayer.MISC_OVERLAYS, WATERMARK_LAYER, (LayeredDraw.Layer) OverlayHud::renderWatermark);
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean skip(Minecraft mc) {
|
||||
if (mc == null) {
|
||||
return true;
|
||||
}
|
||||
if (mc.options != null && mc.options.hideGui) {
|
||||
return true;
|
||||
}
|
||||
return mc.level == null;
|
||||
}
|
||||
|
||||
private static void renderCompass(GuiGraphics graphics, DeltaTracker deltaTracker) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (skip(mc)) {
|
||||
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.getMainCamera().getYRot();
|
||||
|
||||
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.drawString(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(GuiGraphics graphics, DeltaTracker deltaTracker) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (skip(mc)) {
|
||||
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.drawString(font, nick, x, y, 0xFFFFFFFF, true);
|
||||
graphics.drawString(font, "FPS: " + fps, x, y + lineHeight, 0xFFFFFFFF, true);
|
||||
graphics.drawString(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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user