Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b918b79fd5 | |||
| db20575681 | |||
| 1bbc10c9a9 | |||
| b6ce51dfb9 | |||
| 3b5e555ce4 | |||
| 74bcd64bc0 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,4 +6,5 @@ run/
|
|||||||
.idea/
|
.idea/
|
||||||
*.class
|
*.class
|
||||||
.primer_*.md
|
.primer_*.md
|
||||||
|
.claude/
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ minecraft_version=26.2
|
|||||||
loader_version=0.19.3
|
loader_version=0.19.3
|
||||||
fabric_version=0.152.2+26.2
|
fabric_version=0.152.2+26.2
|
||||||
|
|
||||||
mod_version=1.0.2
|
mod_version=1.0.3
|
||||||
maven_group=ru.nevetime
|
maven_group=ru.nevetime
|
||||||
archives_base_name=client-irc-chat
|
archives_base_name=client-irc-chat
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ public final class ClientIrcMod implements ClientModInitializer {
|
|||||||
FriendsManager.init(configDir);
|
FriendsManager.init(configDir);
|
||||||
service = new IrcService(config, LOGGER);
|
service = new IrcService(config, LOGGER);
|
||||||
|
|
||||||
|
OverlayHud.init();
|
||||||
|
WorldOverlayRenderer.init();
|
||||||
MiddleClickHandler.init(() -> service, () -> resolvePlayerName(Minecraft.getInstance()));
|
MiddleClickHandler.init(() -> service, () -> resolvePlayerName(Minecraft.getInstance()));
|
||||||
|
|
||||||
ClientLifecycleEvents.CLIENT_STARTED.register(client -> {
|
ClientLifecycleEvents.CLIENT_STARTED.register(client -> {
|
||||||
|
|||||||
103
src/client/java/ru/nevetime/clientirc/OverlayHud.java
Normal file
103
src/client/java/ru/nevetime/clientirc/OverlayHud.java
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package ru.nevetime.clientirc;
|
||||||
|
|
||||||
|
import com.mojang.authlib.GameProfile;
|
||||||
|
import com.mojang.blaze3d.vertex.PoseStack;
|
||||||
|
import net.fabricmc.fabric.api.client.rendering.v1.level.LevelRenderContext;
|
||||||
|
import net.fabricmc.fabric.api.client.rendering.v1.level.LevelRenderEvents;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.renderer.OrderedSubmitNodeCollector;
|
||||||
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||||
|
import net.minecraft.client.renderer.rendertype.RenderTypes;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraft.world.phys.shapes.Shapes;
|
||||||
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
|
|
||||||
|
public final class WorldOverlayRenderer {
|
||||||
|
private static final int FRIEND_COLOR = 0xFF33FF55;
|
||||||
|
private static final int MARKER_COLOR = 0xFFFF55FF;
|
||||||
|
private static final float OUTLINE_WIDTH = 2.0f;
|
||||||
|
private static final double BEAM_HEIGHT = 50.0;
|
||||||
|
|
||||||
|
private WorldOverlayRenderer() {}
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
LevelRenderEvents.AFTER_TRANSLUCENT_FEATURES.register(WorldOverlayRenderer::onRender);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void onRender(LevelRenderContext context) {
|
||||||
|
Minecraft mc = Minecraft.getInstance();
|
||||||
|
if (mc.level == null || mc.player == null) return;
|
||||||
|
|
||||||
|
SubmitNodeCollector base = context.submitNodeCollector();
|
||||||
|
if (!(base instanceof OrderedSubmitNodeCollector collector)) return;
|
||||||
|
|
||||||
|
PoseStack pose = context.poseStack();
|
||||||
|
Vec3 camPos = mc.gameRenderer.mainCamera().position();
|
||||||
|
double cx = camPos.x;
|
||||||
|
double cy = camPos.y;
|
||||||
|
double cz = camPos.z;
|
||||||
|
|
||||||
|
for (Player player : mc.level.players()) {
|
||||||
|
if (player == mc.player) continue;
|
||||||
|
GameProfile profile = player.getGameProfile();
|
||||||
|
if (profile == null) continue;
|
||||||
|
if (!FriendsManager.isFriend(profile.name())) continue;
|
||||||
|
|
||||||
|
double px = player.getX() - cx;
|
||||||
|
double py = player.getY() + player.getBbHeight() + 0.3 - cy;
|
||||||
|
double pz = player.getZ() - cz;
|
||||||
|
|
||||||
|
pose.pushPose();
|
||||||
|
pose.translate(px - 0.15, py - 0.15, pz - 0.15);
|
||||||
|
VoxelShape dot = Shapes.box(0.0, 0.0, 0.0, 0.3, 0.3, 0.3);
|
||||||
|
collector.submitShapeOutline(pose, dot, RenderTypes.lines(), FRIEND_COLOR, OUTLINE_WIDTH, false);
|
||||||
|
pose.popPose();
|
||||||
|
}
|
||||||
|
|
||||||
|
String currentDim = mc.level.dimension().identifier().toString();
|
||||||
|
for (MarkerManager.Marker marker : MarkerManager.active()) {
|
||||||
|
if (!currentDim.equals(marker.dimensionId())) continue;
|
||||||
|
|
||||||
|
double mx = marker.x() - cx;
|
||||||
|
double my = marker.y() - cy;
|
||||||
|
double mz = marker.z() - cz;
|
||||||
|
|
||||||
|
pose.pushPose();
|
||||||
|
pose.translate(mx - 0.5, my, mz - 0.5);
|
||||||
|
collector.submitShapeOutline(pose, Shapes.block(), RenderTypes.lines(), MARKER_COLOR, OUTLINE_WIDTH, false);
|
||||||
|
pose.popPose();
|
||||||
|
|
||||||
|
pose.pushPose();
|
||||||
|
pose.translate(mx - 0.05, my, mz - 0.05);
|
||||||
|
VoxelShape beam = Shapes.box(0.0, 0.0, 0.0, 0.1, BEAM_HEIGHT, 0.1);
|
||||||
|
collector.submitShapeOutline(pose, beam, RenderTypes.lines(), MARKER_COLOR, OUTLINE_WIDTH, false);
|
||||||
|
pose.popPose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package ru.nevetime.clientirc.mixin;
|
|||||||
|
|
||||||
import net.minecraft.client.gui.components.EditBox;
|
import net.minecraft.client.gui.components.EditBox;
|
||||||
import net.minecraft.client.gui.screens.ChatScreen;
|
import net.minecraft.client.gui.screens.ChatScreen;
|
||||||
|
import net.minecraft.client.input.KeyEvent;
|
||||||
import org.lwjgl.glfw.GLFW;
|
import org.lwjgl.glfw.GLFW;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
@@ -26,8 +27,8 @@ public abstract class ChatScreenMixin {
|
|||||||
};
|
};
|
||||||
|
|
||||||
@Inject(method = "keyPressed", at = @At("HEAD"), cancellable = true)
|
@Inject(method = "keyPressed", at = @At("HEAD"), cancellable = true)
|
||||||
private void clientirc$tabComplete(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable<Boolean> cir) {
|
private void clientirc$tabComplete(KeyEvent event, CallbackInfoReturnable<Boolean> cir) {
|
||||||
if (keyCode != GLFW.GLFW_KEY_TAB) return;
|
if (event.key() != GLFW.GLFW_KEY_TAB) return;
|
||||||
if (input == null) return;
|
if (input == null) return;
|
||||||
String value = input.getValue();
|
String value = input.getValue();
|
||||||
if (value == null || !value.startsWith(".")) return;
|
if (value == null || !value.startsWith(".")) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user