From a1ee9aaee2407ea71622f6ec33f72b78ba4f6263 Mon Sep 17 00:00:00 2001 From: noramibuu <50046813+noramibu@users.noreply.github.com> Date: Thu, 11 Dec 2025 01:48:30 +0300 Subject: [PATCH 1/4] implement better locator --- .../meteorclient/mixin/LocatorBarMixin.java | 229 ++++++++++++++++++ .../meteorclient/systems/modules/Modules.java | 1 + .../systems/modules/render/BetterLocator.java | 78 ++++++ src/main/resources/meteor-client.mixins.json | 1 + 4 files changed, 309 insertions(+) create mode 100644 src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java create mode 100644 src/main/java/meteordevelopment/meteorclient/systems/modules/render/BetterLocator.java diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java new file mode 100644 index 0000000000..925e25dab9 --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java @@ -0,0 +1,229 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ +package meteordevelopment.meteorclient.mixin; +import java.util.UUID; +import meteordevelopment.meteorclient.systems.modules.Modules; +import meteordevelopment.meteorclient.systems.modules.render.BetterLocator; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.hud.bar.LocatorBar; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.network.PlayerListEntry; +import net.minecraft.client.render.RenderTickCounter; +import net.minecraft.client.gl.RenderPipelines; +import net.minecraft.client.resource.waypoint.WaypointStyleAsset; +import net.minecraft.entity.Entity; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.ColorHelper; +import net.minecraft.client.util.Window; +import net.minecraft.text.Text; +import net.minecraft.util.math.MathHelper; +import net.minecraft.world.World; +import net.minecraft.world.tick.TickManager; +import net.minecraft.world.waypoint.EntityTickProgress; +import net.minecraft.world.waypoint.TrackedWaypoint; +import net.minecraft.world.waypoint.Waypoint; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(LocatorBar.class) +public abstract class LocatorBarMixin { + + @Shadow @Final private MinecraftClient client; + @Shadow @Final private static Identifier ARROW_UP; + @Shadow @Final private static Identifier ARROW_DOWN; + @Shadow @Final private static Identifier BACKGROUND; + private static final Identifier XP_BACKGROUND = Identifier.ofVanilla("hud/experience_bar_background"); + private static final Identifier XP_PROGRESS = Identifier.ofVanilla("hud/experience_bar_progress"); + + private int getCenterX(Window window) { + return (window.getScaledWidth() - 182) / 2; + } + + private int getCenterY(Window window) { + return window.getScaledHeight() - 24 - 5; + } + + @Overwrite + public void renderBar(DrawContext context, RenderTickCounter tickCounter) { + BetterLocator locatorHud = Modules.get().get(BetterLocator.class); + boolean showXP = locatorHud != null && locatorHud.isActive() && locatorHud.alwaysShowExperience.get(); + int i = this.getCenterX(this.client.getWindow()); + int j = this.getCenterY(this.client.getWindow()); + + if (showXP) { + ClientPlayerEntity clientPlayerEntity = this.client.player; + int k = clientPlayerEntity.getNextLevelExperience(); + if (k > 0) { + int l = (int)(clientPlayerEntity.experienceProgress * 183.0F); + context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, XP_BACKGROUND, i, j, 182, 5); + if (l > 0) { + context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, XP_PROGRESS, 182, 5, 0, 0, i, j, l, 5); + } + } else { + context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, BACKGROUND, i, j, 182, 5); + } + } else { + context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, BACKGROUND, i, j, 182, 5); + } + + if (locatorHud != null && locatorHud.isActive() && locatorHud.showDirections.get()) { + float yaw = MathHelper.wrapDegrees(this.client.gameRenderer.getCamera().getYaw()); + int centerX = i + 182 / 2; + int centerY = j; + + drawDirection(context, "S", 0, yaw, centerX, centerY); + drawDirection(context, "W", 90, yaw, centerX, centerY); + drawDirection(context, "N", 180, yaw, centerX, centerY); + drawDirection(context, "E", -90, yaw, centerX, centerY); + } + } + + private void drawDirection(DrawContext context, String text, float dirYaw, float playerYaw, int centerX, int y) { + float relative = MathHelper.wrapDegrees(dirYaw - playerYaw); + if (relative >= -60 && relative <= 60) { + int x = centerX + MathHelper.floor(relative * 173.0 / 2.0 / 60.0); + + context.getMatrices().pushMatrix(); + context.getMatrices().translate((float)x, (float)y); + context.getMatrices().scale(0.65f, 0.65f); + + int width = this.client.textRenderer.getWidth(text); + context.drawText(this.client.textRenderer, text, -width / 2, 0, 0xFFFFFFFF, true); + + context.getMatrices().popMatrix(); + } + } + + @Overwrite + public void renderAddons(DrawContext context, RenderTickCounter tickCounter) { + int i = this.getCenterY(this.client.getWindow()); + Entity entity = this.client.getCameraEntity(); + if (entity != null) { + World world = entity.getEntityWorld(); + TickManager tickManager = world.getTickManager(); + EntityTickProgress entityTickProgress = entityx -> tickCounter.getTickProgress(!tickManager.shouldSkipTick(entityx)); + + BetterLocator locatorHud = Modules.get().get(BetterLocator.class); + boolean showHeads = locatorHud != null && locatorHud.isActive() && locatorHud.displayHeads.get(); + boolean showData = locatorHud != null && locatorHud.isActive() && locatorHud.displayData.get(); + boolean onlyTab = showData && locatorHud.displayOnlyOnTab.get(); + boolean showName = showData && locatorHud.displayName.get(); + boolean showCoords = showData && locatorHud.displayCoords.get(); + + boolean shouldShowData = showData && (!onlyTab || this.client.options.playerListKey.isPressed()); + + this.client.player.networkHandler.getWaypointHandler().forEachWaypoint( + entity, + waypoint -> { + if (!(Boolean)waypoint.getSource().left().map(uuid -> uuid.equals(entity.getUuid())).orElse(false)) { + double d = waypoint.getRelativeYaw(world, this.client.gameRenderer.getCamera(), entityTickProgress); + if (!(d <= -60.0) && !(d > 60.0)) { + int j = MathHelper.ceil((context.getScaledWindowWidth() - 9) / 2.0F); + int l = MathHelper.floor(d * 173.0 / 2.0 / 60.0); + + float dist = MathHelper.sqrt((float)waypoint.squaredDistanceTo(entity)); + Waypoint.Config config = waypoint.getConfig(); + WaypointStyleAsset style = this.client.getWaypointStyleAssetManager().get(config.style); + + float near = style.nearDistance(); + float far = style.farDistance(); + float progress = 1.0f - MathHelper.clamp((dist - near) / (far - near), 0.0f, 1.0f); + + float distanceScale = MathHelper.lerp(progress, 0.5f, 1.0f); + + float w = 9 * distanceScale; + float h = 9 * distanceScale; + float x = j + l - (w - 9) / 2; + float y = i - 2 - (h - 9) / 2; + + boolean renderedHead = false; + if (showHeads && waypoint.getSource().left().isPresent()) { + UUID uuid = waypoint.getSource().left().get(); + PlayerListEntry entry = this.client.getNetworkHandler().getPlayerListEntry(uuid); + if (entry != null) { + Identifier skin = entry.getSkinTextures().body().texturePath(); + + context.drawTexture(RenderPipelines.GUI_TEXTURED, skin, (int)x, (int)y, 8.0f, 8.0f, (int)w, (int)h, 8, 8, 64, 64); + context.drawTexture(RenderPipelines.GUI_TEXTURED, skin, (int)x, (int)y, 40.0f, 8.0f, (int)w, (int)h, 8, 8, 64, 64); + renderedHead = true; + + if (shouldShowData) { + context.getMatrices().pushMatrix(); + context.getMatrices().translate(x + w / 2, y - 5); + context.getMatrices().scale(0.5f, 0.5f); + + int textColor = -1; + if (locatorHud.respectColor.get()) { + textColor = (Integer)config.color + .orElseGet( + () -> waypoint.getSource() + .map( + u -> ColorHelper.withBrightness(ColorHelper.withAlpha(255, u.hashCode()), 0.9F), + n -> ColorHelper.withBrightness(ColorHelper.withAlpha(255, n.hashCode()), 0.9F) + ) + ); + } + + if (showName) { + Text name = entry.getDisplayName(); + if (name == null) name = Text.of(entry.getProfile().name()); + + String text = name.getString(); + if (showCoords) { + text += " (" + (int)dist + "m)"; + } + + int width = this.client.textRenderer.getWidth(text); + context.drawTextWithBackground(this.client.textRenderer, Text.of(text), -width / 2, 0, width, textColor); + } else if (showCoords) { + String text = (int)dist + "m"; + int width = this.client.textRenderer.getWidth(text); + context.drawTextWithBackground(this.client.textRenderer, Text.of(text), -width / 2, 0, width, textColor); + } + + context.getMatrices().popMatrix(); + } + } + } + + if (!renderedHead) { + Identifier identifier = style.getSpriteForDistance(dist); + int k = (Integer)config.color + .orElseGet( + () -> waypoint.getSource() + .map( + uuid -> ColorHelper.withBrightness(ColorHelper.withAlpha(255, uuid.hashCode()), 0.9F), + name -> ColorHelper.withBrightness(ColorHelper.withAlpha(255, name.hashCode()), 0.9F) + ) + ); + context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, identifier, (int)x, (int)y, (int)w, (int)h, k); + } + + TrackedWaypoint.Pitch pitch = waypoint.getPitch(world, this.client.gameRenderer, entityTickProgress); + if (pitch != TrackedWaypoint.Pitch.NONE) { + int m; + Identifier identifier2; + if (pitch == TrackedWaypoint.Pitch.DOWN) { + m = 6; + identifier2 = ARROW_DOWN; + } else { + m = -6; + identifier2 = ARROW_UP; + } + + context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, identifier2, j + l + 1, i + m, 7, 5); + } + } + } + } + ); + } + } +} \ No newline at end of file diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/Modules.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/Modules.java index 43a1bb1136..0ccbabc173 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/Modules.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/Modules.java @@ -484,6 +484,7 @@ private void initMovement() { } private void initRender() { + add(new BetterLocator()); add(new BetterTab()); add(new BetterTooltips()); add(new BlockESP()); diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/BetterLocator.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/BetterLocator.java new file mode 100644 index 0000000000..fcc8def8c1 --- /dev/null +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/BetterLocator.java @@ -0,0 +1,78 @@ +package meteordevelopment.meteorclient.systems.modules.render; + +import meteordevelopment.meteorclient.settings.BoolSetting; +import meteordevelopment.meteorclient.settings.Setting; +import meteordevelopment.meteorclient.settings.SettingGroup; +import meteordevelopment.meteorclient.systems.modules.Categories; +import meteordevelopment.meteorclient.systems.modules.Module; + +public class BetterLocator extends Module { + private final SettingGroup sgGeneral = settings.getDefaultGroup(); + private final SettingGroup sgData = settings.createGroup("Display Data"); + + public final Setting displayHeads = sgGeneral.add(new BoolSetting.Builder() + .name("display-heads") + .description("Displays player heads instead of dots on the locator bar.") + .defaultValue(true) + .build() + ); + + public final Setting alwaysShowExperience = sgGeneral.add(new BoolSetting.Builder() + .name("always-show-experience") + .description("Always shows the experience bar.") + .defaultValue(false) + .build() + ); + + public final Setting showDirections = sgGeneral.add(new BoolSetting.Builder() + .name("show-directions") + .description("Shows cardinal directions (N, S, E, W) on the locator bar.") + .defaultValue(true) + .build() + ); + + + public final Setting displayData = sgData.add(new BoolSetting.Builder() + .name("display-player-data") + .description("Displays information about the player.") + .defaultValue(true) + .build() + ); + + public final Setting displayName = sgData.add(new BoolSetting.Builder() + .name("display-name") + .description("Displays the player's name.") + .defaultValue(true) + .visible(displayData::get) + .build() + ); + + public final Setting displayCoords = sgData.add(new BoolSetting.Builder() + .name("display-distance") + .description("Displays the player's distance.") + .defaultValue(true) + .visible(displayData::get) + .build() + ); + + + + public final Setting respectColor = sgData.add(new BoolSetting.Builder() + .name("respect-color") + .description("Respects the player's color.") + .defaultValue(false) + .visible(displayData::get) + .build() + ); + + public final Setting displayOnlyOnTab = sgData.add(new BoolSetting.Builder() + .name("display-only-on-tab") + .description("Only displays data when holding the player list key (Tab).") + .defaultValue(true) + .visible(displayData::get) + .build() + ); + public BetterLocator() { + super(Categories.Render, "better-locator", "Modifies the Locator HUD."); + } +} diff --git a/src/main/resources/meteor-client.mixins.json b/src/main/resources/meteor-client.mixins.json index 039572d42c..828b2274b7 100644 --- a/src/main/resources/meteor-client.mixins.json +++ b/src/main/resources/meteor-client.mixins.json @@ -124,6 +124,7 @@ "LivingEntityAccessor", "LivingEntityMixin", "LivingEntityRendererMixin", + "LocatorBarMixin", "MapRendererMixin", "MapTextureManagerAccessor", "MessageHandlerMixin", From 718089b9485648a005b05c52d5c26e5907c22a21 Mon Sep 17 00:00:00 2001 From: noramibuu <50046813+noramibu@users.noreply.github.com> Date: Thu, 11 Dec 2025 02:11:40 +0300 Subject: [PATCH 2/4] copyright header --- .../meteorclient/mixin/LocatorBarMixin.java | 30 ++++++++++--------- .../systems/modules/render/BetterLocator.java | 5 ++++ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java index 925e25dab9..0310687e39 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java @@ -2,7 +2,9 @@ * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). * Copyright (c) Meteor Development. */ + package meteordevelopment.meteorclient.mixin; + import java.util.UUID; import meteordevelopment.meteorclient.systems.modules.Modules; import meteordevelopment.meteorclient.systems.modules.render.BetterLocator; @@ -72,7 +74,7 @@ public void renderBar(DrawContext context, RenderTickCounter tickCounter) { } else { context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, BACKGROUND, i, j, 182, 5); } - + if (locatorHud != null && locatorHud.isActive() && locatorHud.showDirections.get()) { float yaw = MathHelper.wrapDegrees(this.client.gameRenderer.getCamera().getYaw()); int centerX = i + 182 / 2; @@ -89,14 +91,14 @@ private void drawDirection(DrawContext context, String text, float dirYaw, float float relative = MathHelper.wrapDegrees(dirYaw - playerYaw); if (relative >= -60 && relative <= 60) { int x = centerX + MathHelper.floor(relative * 173.0 / 2.0 / 60.0); - + context.getMatrices().pushMatrix(); context.getMatrices().translate((float)x, (float)y); context.getMatrices().scale(0.65f, 0.65f); - + int width = this.client.textRenderer.getWidth(text); context.drawText(this.client.textRenderer, text, -width / 2, 0, 0xFFFFFFFF, true); - + context.getMatrices().popMatrix(); } } @@ -109,14 +111,14 @@ public void renderAddons(DrawContext context, RenderTickCounter tickCounter) { World world = entity.getEntityWorld(); TickManager tickManager = world.getTickManager(); EntityTickProgress entityTickProgress = entityx -> tickCounter.getTickProgress(!tickManager.shouldSkipTick(entityx)); - + BetterLocator locatorHud = Modules.get().get(BetterLocator.class); boolean showHeads = locatorHud != null && locatorHud.isActive() && locatorHud.displayHeads.get(); boolean showData = locatorHud != null && locatorHud.isActive() && locatorHud.displayData.get(); boolean onlyTab = showData && locatorHud.displayOnlyOnTab.get(); boolean showName = showData && locatorHud.displayName.get(); boolean showCoords = showData && locatorHud.displayCoords.get(); - + boolean shouldShowData = showData && (!onlyTab || this.client.options.playerListKey.isPressed()); this.client.player.networkHandler.getWaypointHandler().forEachWaypoint( @@ -131,11 +133,11 @@ public void renderAddons(DrawContext context, RenderTickCounter tickCounter) { float dist = MathHelper.sqrt((float)waypoint.squaredDistanceTo(entity)); Waypoint.Config config = waypoint.getConfig(); WaypointStyleAsset style = this.client.getWaypointStyleAssetManager().get(config.style); - + float near = style.nearDistance(); float far = style.farDistance(); float progress = 1.0f - MathHelper.clamp((dist - near) / (far - near), 0.0f, 1.0f); - + float distanceScale = MathHelper.lerp(progress, 0.5f, 1.0f); float w = 9 * distanceScale; @@ -149,7 +151,7 @@ public void renderAddons(DrawContext context, RenderTickCounter tickCounter) { PlayerListEntry entry = this.client.getNetworkHandler().getPlayerListEntry(uuid); if (entry != null) { Identifier skin = entry.getSkinTextures().body().texturePath(); - + context.drawTexture(RenderPipelines.GUI_TEXTURED, skin, (int)x, (int)y, 8.0f, 8.0f, (int)w, (int)h, 8, 8, 64, 64); context.drawTexture(RenderPipelines.GUI_TEXTURED, skin, (int)x, (int)y, 40.0f, 8.0f, (int)w, (int)h, 8, 8, 64, 64); renderedHead = true; @@ -158,7 +160,7 @@ public void renderAddons(DrawContext context, RenderTickCounter tickCounter) { context.getMatrices().pushMatrix(); context.getMatrices().translate(x + w / 2, y - 5); context.getMatrices().scale(0.5f, 0.5f); - + int textColor = -1; if (locatorHud.respectColor.get()) { textColor = (Integer)config.color @@ -174,12 +176,12 @@ public void renderAddons(DrawContext context, RenderTickCounter tickCounter) { if (showName) { Text name = entry.getDisplayName(); if (name == null) name = Text.of(entry.getProfile().name()); - + String text = name.getString(); if (showCoords) { text += " (" + (int)dist + "m)"; } - + int width = this.client.textRenderer.getWidth(text); context.drawTextWithBackground(this.client.textRenderer, Text.of(text), -width / 2, 0, width, textColor); } else if (showCoords) { @@ -187,7 +189,7 @@ public void renderAddons(DrawContext context, RenderTickCounter tickCounter) { int width = this.client.textRenderer.getWidth(text); context.drawTextWithBackground(this.client.textRenderer, Text.of(text), -width / 2, 0, width, textColor); } - + context.getMatrices().popMatrix(); } } @@ -226,4 +228,4 @@ public void renderAddons(DrawContext context, RenderTickCounter tickCounter) { ); } } -} \ No newline at end of file +} diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/BetterLocator.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/BetterLocator.java index fcc8def8c1..a425e276df 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/BetterLocator.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/BetterLocator.java @@ -1,3 +1,8 @@ +/* + * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). + * Copyright (c) Meteor Development. + */ + package meteordevelopment.meteorclient.systems.modules.render; import meteordevelopment.meteorclient.settings.BoolSetting; From 4f293bbde970aa7111e1d2d82b394090680f1456 Mon Sep 17 00:00:00 2001 From: noramibuu <50046813+noramibu@users.noreply.github.com> Date: Tue, 16 Dec 2025 14:00:18 +0300 Subject: [PATCH 3/4] refactor better locator added meteor waypoints refactored mixin for compatibility --- .../meteorclient/mixin/LocatorBarMixin.java | 352 +++++++++--------- .../systems/modules/render/BetterLocator.java | 69 +++- 2 files changed, 218 insertions(+), 203 deletions(-) diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java index 0310687e39..062fc520a5 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java @@ -5,227 +5,211 @@ package meteordevelopment.meteorclient.mixin; -import java.util.UUID; +import com.llamalad7.mixinextras.sugar.Local; +import com.mojang.blaze3d.pipeline.RenderPipeline; import meteordevelopment.meteorclient.systems.modules.Modules; import meteordevelopment.meteorclient.systems.modules.render.BetterLocator; - +import meteordevelopment.meteorclient.systems.waypoints.Waypoints; +import meteordevelopment.meteorclient.systems.waypoints.Waypoint; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.hud.bar.LocatorBar; -import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.gl.RenderPipelines; import net.minecraft.client.network.PlayerListEntry; import net.minecraft.client.render.RenderTickCounter; -import net.minecraft.client.gl.RenderPipelines; import net.minecraft.client.resource.waypoint.WaypointStyleAsset; -import net.minecraft.entity.Entity; +import net.minecraft.text.Text; import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ColorHelper; -import net.minecraft.client.util.Window; -import net.minecraft.text.Text; import net.minecraft.util.math.MathHelper; -import net.minecraft.world.World; -import net.minecraft.world.tick.TickManager; -import net.minecraft.world.waypoint.EntityTickProgress; +import net.minecraft.util.math.Vec3d; import net.minecraft.world.waypoint.TrackedWaypoint; -import net.minecraft.world.waypoint.Waypoint; - import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; 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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(LocatorBar.class) public abstract class LocatorBarMixin { - @Shadow @Final private MinecraftClient client; - @Shadow @Final private static Identifier ARROW_UP; - @Shadow @Final private static Identifier ARROW_DOWN; - @Shadow @Final private static Identifier BACKGROUND; - private static final Identifier XP_BACKGROUND = Identifier.ofVanilla("hud/experience_bar_background"); - private static final Identifier XP_PROGRESS = Identifier.ofVanilla("hud/experience_bar_progress"); - - private int getCenterX(Window window) { - return (window.getScaledWidth() - 182) / 2; - } - - private int getCenterY(Window window) { - return window.getScaledHeight() - 24 - 5; - } - @Overwrite - public void renderBar(DrawContext context, RenderTickCounter tickCounter) { - BetterLocator locatorHud = Modules.get().get(BetterLocator.class); - boolean showXP = locatorHud != null && locatorHud.isActive() && locatorHud.alwaysShowExperience.get(); - int i = this.getCenterX(this.client.getWindow()); - int j = this.getCenterY(this.client.getWindow()); - - if (showXP) { - ClientPlayerEntity clientPlayerEntity = this.client.player; - int k = clientPlayerEntity.getNextLevelExperience(); - if (k > 0) { - int l = (int)(clientPlayerEntity.experienceProgress * 183.0F); - context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, XP_BACKGROUND, i, j, 182, 5); - if (l > 0) { - context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, XP_PROGRESS, 182, 5, 0, 0, i, j, l, 5); + @Unique private static final Identifier XP_BACKGROUND = Identifier.ofVanilla("hud/experience_bar_background"); + @Unique private static final Identifier XP_PROGRESS = Identifier.ofVanilla("hud/experience_bar_progress"); + + @Unique private BetterLocator module; + + @Inject(method = "renderBar", at = @At("HEAD"), cancellable = true) + private void renderBarHead(DrawContext context, RenderTickCounter tickCounter, CallbackInfo ci) { + module = Modules.get().get(BetterLocator.class); + if (module == null || !module.isActive()) return; + + if (module.alwaysShowExperience.get()) { + int maxExp = client.player.getNextLevelExperience(); + if (maxExp > 0) { + int cx = getCenterX(); + int cy = getCenterY(); + int progress = (int) (client.player.experienceProgress * 183.0F); + + context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, XP_BACKGROUND, cx, cy, 182, 5); + if (progress > 0) { + context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, XP_PROGRESS, 182, 5, 0, 0, cx, cy, progress, 5); } - } else { - context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, BACKGROUND, i, j, 182, 5); + + renderOverlays(context, cx, cy); + ci.cancel(); } - } else { - context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, BACKGROUND, i, j, 182, 5); } + } - if (locatorHud != null && locatorHud.isActive() && locatorHud.showDirections.get()) { - float yaw = MathHelper.wrapDegrees(this.client.gameRenderer.getCamera().getYaw()); - int centerX = i + 182 / 2; - int centerY = j; + @Inject(method = "renderBar", at = @At("RETURN")) + private void renderBarReturn(DrawContext context, RenderTickCounter tickCounter, CallbackInfo ci) { + if (module != null && module.isActive()) { + renderOverlays(context, getCenterX(), getCenterY()); + } + } - drawDirection(context, "S", 0, yaw, centerX, centerY); - drawDirection(context, "W", 90, yaw, centerX, centerY); - drawDirection(context, "N", 180, yaw, centerX, centerY); - drawDirection(context, "E", -90, yaw, centerX, centerY); + @Unique + private void renderOverlays(DrawContext context, int cx, int cy) { + if (module.showDirections.get()) { + float yaw = MathHelper.wrapDegrees(client.gameRenderer.getCamera().getYaw()); + int centerX = cx + 91; + drawDirection(context, "S", 0, yaw, centerX, cy); + drawDirection(context, "W", 90, yaw, centerX, cy); + drawDirection(context, "N", 180, yaw, centerX, cy); + drawDirection(context, "E", -90, yaw, centerX, cy); } + renderMeteorWaypoints(context, cx + 91, cy); + } + + @Unique + private int getCenterX() { + return (client.getWindow().getScaledWidth() - 182) / 2; + } + + @Unique + private int getCenterY() { + return client.getWindow().getScaledHeight() - 29; } + @Unique private void drawDirection(DrawContext context, String text, float dirYaw, float playerYaw, int centerX, int y) { float relative = MathHelper.wrapDegrees(dirYaw - playerYaw); if (relative >= -60 && relative <= 60) { - int x = centerX + MathHelper.floor(relative * 173.0 / 2.0 / 60.0); + renderText(context, text, centerX + MathHelper.floor(relative * 1.4416667), y, 0xFFFFFFFF); + } + } + + @Unique + private void renderMeteorWaypoints(DrawContext context, int centerX, int centerY) { + if (!module.displayWaypoints.get()) return; + + Vec3d cameraPos = client.gameRenderer.getCamera().getPos(); + float playerYaw = MathHelper.wrapDegrees(client.gameRenderer.getCamera().getYaw()); + boolean showData = (module.displayWaypointName.get() || module.displayWaypointDistance.get()) && (!module.displayWaypointOnlyOnTab.get() || client.options.playerListKey.isPressed()); + + for (Waypoint waypoint : Waypoints.get()) { + if (!waypoint.visible.get() || !Waypoints.checkDimension(waypoint)) continue; + + BlockPos pos = waypoint.getPos(); + double dx = pos.getX() - cameraPos.x; + double dz = pos.getZ() - cameraPos.z; + + double angle = Math.toDegrees(Math.atan2(dz, dx)) - 90; + float relative = MathHelper.wrapDegrees((float) angle - playerYaw); + + if (relative >= -60 && relative <= 60) { + double dist = Math.sqrt(dx * dx + dz * dz); + int x = centerX + MathHelper.floor(relative * 1.4416667); + int color = waypoint.color.get().getPacked(); + + float progress = getProgress((float) dist, WaypointStyleAsset.DEFAULT_NEAR_DISTANCE, WaypointStyleAsset.DEFAULT_FAR_DISTANCE); + float size = MathHelper.lerp(progress, 3.0f, 6.0f); + int offset = (int) size / 2; + int yOffset = centerY + 1 + (3 - (int)size) / 2; + + context.fill(x - offset, yOffset, x + offset + 1, yOffset + (int)size, color); + + if (showData) { + String text = module.displayWaypointName.get() ? waypoint.name.get() : ""; + if (module.displayWaypointDistance.get()) text += (text.isEmpty() ? "" : " ") + "(" + (int) dist + "m)"; + renderText(context, text, x + 0.5f, centerY - 5.0f, color); + } + } + } + } + + @Redirect(method = "*", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawGuiTexture(Lcom/mojang/blaze3d/pipeline/RenderPipeline;Lnet/minecraft/util/Identifier;IIIII)V")) + private void onDrawWaypointIcon(DrawContext context, RenderPipeline pipeline, Identifier id, int x, int y, int w, int h, int color, @Local(argsOnly = true) TrackedWaypoint waypoint) { + if (w != 9 || h != 9 || module == null || !module.isActive() || client.getCameraEntity() == null || waypoint == null) { + context.drawGuiTexture(pipeline, id, x, y, w, h, color); + return; + } - context.getMatrices().pushMatrix(); - context.getMatrices().translate((float)x, (float)y); - context.getMatrices().scale(0.65f, 0.65f); + PlayerListEntry entry = waypoint.getSource().left().map(uuid -> client.getNetworkHandler().getPlayerListEntry(uuid)).orElse(null); + boolean showHeads = entry != null && module.displayHeads.get(); + + float dist = MathHelper.sqrt((float) waypoint.squaredDistanceTo(client.getCameraEntity())); + WaypointStyleAsset style = client.getWaypointStyleAssetManager().get(waypoint.getConfig().style); + float scale = MathHelper.lerp(getProgress(dist, style.nearDistance(), style.farDistance()), 0.5f, 1.0f); + float size = 9 * scale; + float drawY = y - (size - 9) / 2; + + if (showHeads) { + float drawX = x - (size - 9) / 2; + Identifier skin = entry.getSkinTextures().body().texturePath(); + context.drawTexture(RenderPipelines.GUI_TEXTURED, skin, (int) drawX, (int) drawY, 8.0f, 8.0f, (int) size, (int) size, 8, 8, 64, 64); + context.drawTexture(RenderPipelines.GUI_TEXTURED, skin, (int) drawX, (int) drawY, 40.0f, 8.0f, (int) size, (int) size, 8, 8, 64, 64); + } else { + context.drawGuiTexture(pipeline, id, x, y, w, h, color); + } - int width = this.client.textRenderer.getWidth(text); - context.drawText(this.client.textRenderer, text, -width / 2, 0, 0xFFFFFFFF, true); + if (entry != null && module.displayPlayerData.get() && (!module.displayPlayerOnlyOnTab.get() || client.options.playerListKey.isPressed())) { + int textColor = -1; + if (module.respectPlayerColor.get()) { + textColor = (Integer) waypoint.getConfig().color.orElseGet(() -> + waypoint.getSource().map( + u -> ColorHelper.withBrightness(ColorHelper.withAlpha(255, u.hashCode()), 0.9F), + n -> ColorHelper.withBrightness(ColorHelper.withAlpha(255, n.hashCode()), 0.9F) + ) + ); + } - context.getMatrices().popMatrix(); + String text = ""; + if (module.displayPlayerName.get()) { + Text name = entry.getDisplayName(); + text = (name != null ? name : Text.of(entry.getProfile().name())).getString(); + if (module.displayPlayerDistance.get()) text += " (" + (int) dist + "m)"; + } else { + text = (int) dist + "m"; + } + renderText(context, text, x + 4.5f, drawY - 5, textColor); } } - @Overwrite - public void renderAddons(DrawContext context, RenderTickCounter tickCounter) { - int i = this.getCenterY(this.client.getWindow()); - Entity entity = this.client.getCameraEntity(); - if (entity != null) { - World world = entity.getEntityWorld(); - TickManager tickManager = world.getTickManager(); - EntityTickProgress entityTickProgress = entityx -> tickCounter.getTickProgress(!tickManager.shouldSkipTick(entityx)); - - BetterLocator locatorHud = Modules.get().get(BetterLocator.class); - boolean showHeads = locatorHud != null && locatorHud.isActive() && locatorHud.displayHeads.get(); - boolean showData = locatorHud != null && locatorHud.isActive() && locatorHud.displayData.get(); - boolean onlyTab = showData && locatorHud.displayOnlyOnTab.get(); - boolean showName = showData && locatorHud.displayName.get(); - boolean showCoords = showData && locatorHud.displayCoords.get(); - - boolean shouldShowData = showData && (!onlyTab || this.client.options.playerListKey.isPressed()); - - this.client.player.networkHandler.getWaypointHandler().forEachWaypoint( - entity, - waypoint -> { - if (!(Boolean)waypoint.getSource().left().map(uuid -> uuid.equals(entity.getUuid())).orElse(false)) { - double d = waypoint.getRelativeYaw(world, this.client.gameRenderer.getCamera(), entityTickProgress); - if (!(d <= -60.0) && !(d > 60.0)) { - int j = MathHelper.ceil((context.getScaledWindowWidth() - 9) / 2.0F); - int l = MathHelper.floor(d * 173.0 / 2.0 / 60.0); - - float dist = MathHelper.sqrt((float)waypoint.squaredDistanceTo(entity)); - Waypoint.Config config = waypoint.getConfig(); - WaypointStyleAsset style = this.client.getWaypointStyleAssetManager().get(config.style); - - float near = style.nearDistance(); - float far = style.farDistance(); - float progress = 1.0f - MathHelper.clamp((dist - near) / (far - near), 0.0f, 1.0f); - - float distanceScale = MathHelper.lerp(progress, 0.5f, 1.0f); - - float w = 9 * distanceScale; - float h = 9 * distanceScale; - float x = j + l - (w - 9) / 2; - float y = i - 2 - (h - 9) / 2; - - boolean renderedHead = false; - if (showHeads && waypoint.getSource().left().isPresent()) { - UUID uuid = waypoint.getSource().left().get(); - PlayerListEntry entry = this.client.getNetworkHandler().getPlayerListEntry(uuid); - if (entry != null) { - Identifier skin = entry.getSkinTextures().body().texturePath(); - - context.drawTexture(RenderPipelines.GUI_TEXTURED, skin, (int)x, (int)y, 8.0f, 8.0f, (int)w, (int)h, 8, 8, 64, 64); - context.drawTexture(RenderPipelines.GUI_TEXTURED, skin, (int)x, (int)y, 40.0f, 8.0f, (int)w, (int)h, 8, 8, 64, 64); - renderedHead = true; - - if (shouldShowData) { - context.getMatrices().pushMatrix(); - context.getMatrices().translate(x + w / 2, y - 5); - context.getMatrices().scale(0.5f, 0.5f); - - int textColor = -1; - if (locatorHud.respectColor.get()) { - textColor = (Integer)config.color - .orElseGet( - () -> waypoint.getSource() - .map( - u -> ColorHelper.withBrightness(ColorHelper.withAlpha(255, u.hashCode()), 0.9F), - n -> ColorHelper.withBrightness(ColorHelper.withAlpha(255, n.hashCode()), 0.9F) - ) - ); - } - - if (showName) { - Text name = entry.getDisplayName(); - if (name == null) name = Text.of(entry.getProfile().name()); - - String text = name.getString(); - if (showCoords) { - text += " (" + (int)dist + "m)"; - } - - int width = this.client.textRenderer.getWidth(text); - context.drawTextWithBackground(this.client.textRenderer, Text.of(text), -width / 2, 0, width, textColor); - } else if (showCoords) { - String text = (int)dist + "m"; - int width = this.client.textRenderer.getWidth(text); - context.drawTextWithBackground(this.client.textRenderer, Text.of(text), -width / 2, 0, width, textColor); - } - - context.getMatrices().popMatrix(); - } - } - } - - if (!renderedHead) { - Identifier identifier = style.getSpriteForDistance(dist); - int k = (Integer)config.color - .orElseGet( - () -> waypoint.getSource() - .map( - uuid -> ColorHelper.withBrightness(ColorHelper.withAlpha(255, uuid.hashCode()), 0.9F), - name -> ColorHelper.withBrightness(ColorHelper.withAlpha(255, name.hashCode()), 0.9F) - ) - ); - context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, identifier, (int)x, (int)y, (int)w, (int)h, k); - } - - TrackedWaypoint.Pitch pitch = waypoint.getPitch(world, this.client.gameRenderer, entityTickProgress); - if (pitch != TrackedWaypoint.Pitch.NONE) { - int m; - Identifier identifier2; - if (pitch == TrackedWaypoint.Pitch.DOWN) { - m = 6; - identifier2 = ARROW_DOWN; - } else { - m = -6; - identifier2 = ARROW_UP; - } - - context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, identifier2, j + l + 1, i + m, 7, 5); - } - } - } - } - ); + @Unique + private float getProgress(float dist, float near, float far) { + return 1.0f - MathHelper.clamp((dist - near) / (far - near), 0.0f, 1.0f); + } + + @Unique + private void renderText(DrawContext context, String text, float x, float y, int color) { + if (text.isEmpty()) return; + context.getMatrices().pushMatrix(); + context.getMatrices().translate(x, y); + context.getMatrices().scale(0.5f, 0.5f); + int width = client.textRenderer.getWidth(text); + + if (color == 0xFFFFFFFF) { + context.drawText(client.textRenderer, text, -width / 2, 0, color, true); + } else { + context.drawTextWithBackground(client.textRenderer, Text.of(text), -width / 2, 0, width, color); } + + context.getMatrices().popMatrix(); } } diff --git a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/BetterLocator.java b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/BetterLocator.java index a425e276df..de3df586e7 100644 --- a/src/main/java/meteordevelopment/meteorclient/systems/modules/render/BetterLocator.java +++ b/src/main/java/meteordevelopment/meteorclient/systems/modules/render/BetterLocator.java @@ -13,14 +13,8 @@ public class BetterLocator extends Module { private final SettingGroup sgGeneral = settings.getDefaultGroup(); - private final SettingGroup sgData = settings.createGroup("Display Data"); - - public final Setting displayHeads = sgGeneral.add(new BoolSetting.Builder() - .name("display-heads") - .description("Displays player heads instead of dots on the locator bar.") - .defaultValue(true) - .build() - ); + private final SettingGroup sgPlayers = settings.createGroup("Players"); + private final SettingGroup sgMeteorWaypoints = settings.createGroup("Meteor Waypoints"); public final Setting alwaysShowExperience = sgGeneral.add(new BoolSetting.Builder() .name("always-show-experience") @@ -37,46 +31,83 @@ public class BetterLocator extends Module { ); - public final Setting displayData = sgData.add(new BoolSetting.Builder() + public final Setting displayHeads = sgPlayers.add(new BoolSetting.Builder() + .name("display-heads") + .description("Displays player heads instead of dots on the locator bar.") + .defaultValue(true) + .build() + ); + + public final Setting displayPlayerData = sgPlayers.add(new BoolSetting.Builder() .name("display-player-data") .description("Displays information about the player.") .defaultValue(true) .build() ); - public final Setting displayName = sgData.add(new BoolSetting.Builder() + public final Setting displayPlayerName = sgPlayers.add(new BoolSetting.Builder() .name("display-name") .description("Displays the player's name.") .defaultValue(true) - .visible(displayData::get) + .visible(displayPlayerData::get) .build() ); - public final Setting displayCoords = sgData.add(new BoolSetting.Builder() + public final Setting displayPlayerDistance = sgPlayers.add(new BoolSetting.Builder() .name("display-distance") .description("Displays the player's distance.") .defaultValue(true) - .visible(displayData::get) + .visible(displayPlayerData::get) .build() ); - - - public final Setting respectColor = sgData.add(new BoolSetting.Builder() + public final Setting respectPlayerColor = sgPlayers.add(new BoolSetting.Builder() .name("respect-color") .description("Respects the player's color.") .defaultValue(false) - .visible(displayData::get) + .visible(displayPlayerData::get) .build() ); - public final Setting displayOnlyOnTab = sgData.add(new BoolSetting.Builder() + public final Setting displayPlayerOnlyOnTab = sgPlayers.add(new BoolSetting.Builder() .name("display-only-on-tab") .description("Only displays data when holding the player list key (Tab).") .defaultValue(true) - .visible(displayData::get) + .visible(displayPlayerData::get) + .build() + ); + + public final Setting displayWaypoints = sgMeteorWaypoints.add(new BoolSetting.Builder() + .name("display-waypoints") + .description("Displays Meteor Client waypoints on the locator bar.") + .defaultValue(true) .build() ); + + public final Setting displayWaypointName = sgMeteorWaypoints.add(new BoolSetting.Builder() + .name("display-name") + .description("Displays the waypoint's name.") + .defaultValue(true) + .visible(displayWaypoints::get) + .build() + ); + + public final Setting displayWaypointDistance = sgMeteorWaypoints.add(new BoolSetting.Builder() + .name("display-distance") + .description("Displays the waypoint's distance.") + .defaultValue(true) + .visible(displayWaypoints::get) + .build() + ); + + public final Setting displayWaypointOnlyOnTab = sgMeteorWaypoints.add(new BoolSetting.Builder() + .name("display-only-on-tab") + .description("Only displays data when holding the player list key (Tab).") + .defaultValue(false) + .visible(displayWaypoints::get) + .build() + ); + public BetterLocator() { super(Categories.Render, "better-locator", "Modifies the Locator HUD."); } From 92988ece8c3be5af357f38ec5656670eaa93198e Mon Sep 17 00:00:00 2001 From: noramibuu <50046813+noramibu@users.noreply.github.com> Date: Tue, 16 Dec 2025 14:12:42 +0300 Subject: [PATCH 4/4] 1.21.11 --- .../meteordevelopment/meteorclient/mixin/LocatorBarMixin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java b/src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java index 062fc520a5..80d2de7394 100644 --- a/src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java +++ b/src/main/java/meteordevelopment/meteorclient/mixin/LocatorBarMixin.java @@ -108,7 +108,7 @@ private void drawDirection(DrawContext context, String text, float dirYaw, float private void renderMeteorWaypoints(DrawContext context, int centerX, int centerY) { if (!module.displayWaypoints.get()) return; - Vec3d cameraPos = client.gameRenderer.getCamera().getPos(); + Vec3d cameraPos = client.gameRenderer.getCamera().getCameraPos(); float playerYaw = MathHelper.wrapDegrees(client.gameRenderer.getCamera().getYaw()); boolean showData = (module.displayWaypointName.get() || module.displayWaypointDistance.get()) && (!module.displayWaypointOnlyOnTab.get() || client.options.playerListKey.isPressed());