diff --git a/src/client/java/ru/nevetime/clientirc/ClientIrcMod.java b/src/client/java/ru/nevetime/clientirc/ClientIrcMod.java index ad5a60c..a41d45b 100644 --- a/src/client/java/ru/nevetime/clientirc/ClientIrcMod.java +++ b/src/client/java/ru/nevetime/clientirc/ClientIrcMod.java @@ -40,6 +40,7 @@ public final class ClientIrcMod implements ClientModInitializer { service = new IrcService(config, LOGGER); OverlayHud.init(); + WorldOverlayRenderer.init(); MiddleClickHandler.init(() -> service, () -> resolvePlayerName(Minecraft.getInstance())); ClientLifecycleEvents.CLIENT_STARTED.register(client -> { diff --git a/src/client/java/ru/nevetime/clientirc/WorldOverlayRenderer.java b/src/client/java/ru/nevetime/clientirc/WorldOverlayRenderer.java new file mode 100644 index 0000000..58359c0 --- /dev/null +++ b/src/client/java/ru/nevetime/clientirc/WorldOverlayRenderer.java @@ -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.RenderType; +import net.minecraft.client.renderer.SubmitNodeCollector; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.joml.Vector3fc; + +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(); + Vector3fc 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, RenderType.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(), RenderType.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, RenderType.lines(), MARKER_COLOR, OUTLINE_WIDTH, false); + pose.popPose(); + } + } +}