From 1f2c1f847119c23fba4544ff86707790aa95e1a6 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Wed, 2 Apr 2025 22:50:51 -0400 Subject: [PATCH 01/14] Add spirit leap map --- .../config/configs/GeneralConfig.java | 2 +- .../skyblock/dungeon/DungeonMap.java | 20 ++-- .../skyblock/dungeon/LeapOverlay.java | 104 +++++++----------- 3 files changed, 51 insertions(+), 75 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/config/configs/GeneralConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/GeneralConfig.java index e79ea878e4..50fd182bdd 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/GeneralConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/GeneralConfig.java @@ -202,7 +202,7 @@ public static class ItemInfoDisplay { public RarityBackgroundStyle itemRarityBackgroundStyle = RarityBackgroundStyle.SQUARE; @SerialEntry - public float itemRarityBackgroundsOpacity = 1f; + public float itemRarityBackgroundsOpacity = 0.5f; } public enum RarityBackgroundStyle { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java index 471dc753c1..57fc5c01f1 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java @@ -45,24 +45,26 @@ public static void init() { ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> reset()); } - public static void render(MatrixStack matrices) { + private static void render(DrawContext context) { + if (Utils.isInDungeons() && DungeonScore.isDungeonStarted() && !DungeonManager.isInBoss() && SkyblockerConfigManager.get().dungeons.dungeonMap.enableMap) { + render(context.getMatrices(), SkyblockerConfigManager.get().dungeons.dungeonMap.mapX, SkyblockerConfigManager.get().dungeons.dungeonMap.mapY, SkyblockerConfigManager.get().dungeons.dungeonMap.mapScaling); + } + } + + public static void render(MatrixStack matrices, int x, int y, float scale) { MinecraftClient client = MinecraftClient.getInstance(); if (client.player == null || client.world == null) return; MapIdComponent mapId = getMapIdComponent(client.player.getInventory().main.get(8)); - MapState state = FilledMapItem.getMapState(mapId, client.world); if (state == null) return; - int x = SkyblockerConfigManager.get().dungeons.dungeonMap.mapX; - int y = SkyblockerConfigManager.get().dungeons.dungeonMap.mapY; - float scaling = SkyblockerConfigManager.get().dungeons.dungeonMap.mapScaling; VertexConsumerProvider.Immediate vertices = client.getBufferBuilders().getEffectVertexConsumers(); MapRenderer mapRenderer = client.getMapRenderer(); matrices.push(); matrices.translate(x, y, 0); - matrices.scale(scaling, scaling, 0f); + matrices.scale(scale, scale, 0f); mapRenderer.update(mapId, state, MAP_RENDER_STATE); mapRenderer.draw(MAP_RENDER_STATE, matrices, vertices, false, LightmapTextureManager.MAX_LIGHT_COORDINATE); vertices.draw(); @@ -77,12 +79,6 @@ public static MapIdComponent getMapIdComponent(ItemStack stack) { } else return cachedMapIdComponent != null ? cachedMapIdComponent : DEFAULT_MAP_ID_COMPONENT; } - private static void render(DrawContext context) { - if (Utils.isInDungeons() && DungeonScore.isDungeonStarted() && !DungeonManager.isInBoss() && SkyblockerConfigManager.get().dungeons.dungeonMap.enableMap) { - render(context.getMatrices()); - } - } - private static void reset() { cachedMapIdComponent = null; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java index 59f1968511..f1e8b4f9ce 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java @@ -1,13 +1,9 @@ package de.hysky.skyblocker.skyblock.dungeon; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Locale; -import java.util.Optional; -import java.util.UUID; +import java.util.*; import java.util.function.Supplier; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; @@ -19,11 +15,10 @@ import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.GridWidget; +import net.minecraft.client.gui.widget.GridWidget.Adder; import net.minecraft.client.gui.widget.SimplePositioningWidget; import net.minecraft.client.realms.util.RealmsUtil; -import net.minecraft.client.gui.widget.GridWidget.Adder; import net.minecraft.client.render.RenderLayer; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.ProfileComponent; import net.minecraft.item.ItemStack; @@ -43,16 +38,10 @@ public class LeapOverlay extends Screen implements ScreenHandlerListener { private static final Identifier BUTTON = Identifier.of(SkyblockerMod.NAMESPACE, "button/button"); private static final Identifier BUTTON_HIGHLIGHTED = Identifier.of(SkyblockerMod.NAMESPACE, "button/button_highlighted"); private static final int BUTTON_SPACING = 8; - private static final float SCALE = 1.5f; - private static final int BUTTON_WIDTH = (int) (130f * SCALE); - private static final int BUTTON_HEIGHT = (int) (50f * SCALE); - /** - * Compares first by class name then by player name. - */ - private static final Comparator COMPARATOR = Comparator.comparing(ref -> ref.dungeonClass().displayName()) - .thenComparing(PlayerReference::name); + private static final int BUTTON_WIDTH = 130; + private static final int BUTTON_HEIGHT = 50; private final GenericContainerScreenHandler handler; - private final List references = new ArrayList<>(); + private final SortedSet references = new TreeSet<>(); public LeapOverlay(GenericContainerScreenHandler handler) { super(Text.literal("Skyblocker Leap Overlay")); @@ -75,7 +64,7 @@ protected void init() { } gridWidget.refreshPositions(); - SimplePositioningWidget.setPos(gridWidget, 0, 0, this.width, this.height, 0.5f, 0.5f); + SimplePositioningWidget.setPos(gridWidget, 0, 0, this.width, this.height, 0.5f, 0.75f); gridWidget.forEachChild(this::addDrawableChild); } @@ -99,34 +88,27 @@ public void onSlotUpdate(ScreenHandler handler, int slotId, ItemStack stack) { default -> null; }; - PlayerReference reference = new PlayerReference(uuid, name, dungeonClass, status, handler.syncId, slotId); - tryInsertReference(reference); + updateReference(new PlayerReference(uuid, name, dungeonClass, status, handler.syncId, slotId)); } } @Override public void onPropertyUpdate(ScreenHandler handler, int property, int value) {} - /** - * Inserts the {@code reference} into the list if it doesn't exist or updates current value then updates the screen. - */ - private void tryInsertReference(PlayerReference reference) { - Optional existing = references.stream() - .filter(ref -> ref.uuid().equals(reference.uuid())) - .findAny(); - - if (existing.isEmpty()) { - references.add(reference); - references.sort(COMPARATOR); - - this.clearAndInit(); - } else if (!existing.get().equals(reference)) { - references.remove(existing.get()); - references.add(reference); - references.sort(COMPARATOR); - - this.clearAndInit(); - } + private void updateReference(PlayerReference reference) { + references.remove(reference); + references.add(reference); + clearAndInit(); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + super.render(context, mouseX, mouseY, delta); + + int x = (width >> 1) - 64; + int y = (height >> 2) - 64; + DungeonMap.render(context.getMatrices(), x, y, 1); + context.drawBorder(x, y, 128, 128, -1); } @Override @@ -170,40 +152,23 @@ protected void renderWidget(DrawContext context, int mouseX, int mouseY, float d int baseX = this.getX() + BORDER_THICKNESS; int centreX = this.getX() + (this.getWidth() >> 1); int centreY = this.getY() + (this.getHeight() >> 1); + int halfFontHeight = CLIENT.textRenderer.fontHeight >> 1; //Draw Player Head RealmsUtil.drawPlayerHead(context, baseX + 4, centreY - (HEAD_SIZE >> 1), HEAD_SIZE, reference.uuid()); - MatrixStack matrices = context.getMatrices(); - int halfFontHeight = (int) (CLIENT.textRenderer.fontHeight * SCALE) >> 1; - //Draw class as heading - matrices.push(); - matrices.translate(centreX, this.getY() + halfFontHeight, 0f); - matrices.scale(SCALE, SCALE, 1f); - context.drawCenteredTextWithShadow(CLIENT.textRenderer, reference.dungeonClass().displayName(), 0, 0, ColorHelper.fullAlpha(reference.dungeonClass().color())); - matrices.pop(); + context.drawCenteredTextWithShadow(CLIENT.textRenderer, reference.dungeonClass().displayName(), centreX, this.getY() + halfFontHeight, ColorHelper.fullAlpha(reference.dungeonClass().color())); //Draw name next to head - matrices.push(); - matrices.translate(baseX + HEAD_SIZE + 8, centreY - halfFontHeight, 0f); - matrices.scale(SCALE, SCALE, 1f); - context.drawTextWithShadow(CLIENT.textRenderer, Text.literal(reference.name()), 0, 0, Colors.WHITE); - matrices.pop(); + context.drawTextWithShadow(CLIENT.textRenderer, Text.literal(reference.name()), baseX + HEAD_SIZE + 8, centreY - halfFontHeight, Colors.WHITE); if (reference.status() != null) { //Text - matrices.push(); - matrices.translate(centreX, this.getY() + this.getHeight() - (halfFontHeight * 3), 0f); - matrices.scale(SCALE, SCALE, 1f); - context.drawCenteredTextWithShadow(CLIENT.textRenderer, reference.status().text.get(), 0, 0, Colors.WHITE); - matrices.pop(); + context.drawCenteredTextWithShadow(CLIENT.textRenderer, reference.status().text.get(), centreX, this.getY() + this.getHeight() - (halfFontHeight * 3), Colors.WHITE); //Overlay - matrices.push(); - matrices.scale(1f, 1f, 1f); context.fill(this.getX(), this.getY(), this.getX() + this.getWidth(), this.getY() + this.getHeight(), reference.status().overlayColor); - matrices.pop(); } } @@ -213,7 +178,22 @@ public void onClick(double mouseX, double mouseY) { } } - private record PlayerReference(UUID uuid, String name, DungeonClass dungeonClass, @Nullable PlayerStatus status, int syncId, int slotId) {} + private record PlayerReference(UUID uuid, String name, DungeonClass dungeonClass, @Nullable PlayerStatus status, int syncId, int slotId) implements Comparable { + /** + * Compares first by class name then by player name. + */ + private static final Comparator COMPARATOR = Comparator.comparing(ref -> ref.dungeonClass().displayName()).thenComparing(PlayerReference::name); + + @Override + public boolean equals(Object obj) { + return obj instanceof PlayerReference playerRef && uuid.equals(playerRef.uuid); + } + + @Override + public int compareTo(@NotNull LeapOverlay.PlayerReference o) { + return COMPARATOR.compare(this, o); + } + } private enum PlayerStatus { DEAD(() -> Text.translatable("text.skyblocker.dead").withColor(Colors.RED), ColorHelper.withAlpha(64, Colors.LIGHT_RED)), From b127dd11a006dc8791a95ebf253a56fa4bf073df Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Thu, 3 Apr 2025 00:17:53 -0400 Subject: [PATCH 02/14] Add fancy dungeon map --- .../config/categories/DungeonsCategory.java | 7 +++ .../config/configs/DungeonsConfig.java | 3 ++ .../skyblock/dungeon/DungeonMap.java | 49 +++++++++++++++---- .../skyblock/dungeon/LeapOverlay.java | 2 +- .../dungeon/secrets/DungeonManager.java | 23 ++++++++- .../dungeon/secrets/DungeonMapUtils.java | 10 ++-- .../assets/skyblocker/lang/en_us.json | 1 + 7 files changed, 81 insertions(+), 14 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java index 45356c01ce..74e5fefaf1 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java @@ -111,6 +111,13 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig newValue -> config.dungeons.dungeonMap.enableMap = newValue) .controller(ConfigUtils::createBooleanController) .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.map.fancyMap")) + .binding(defaults.dungeons.dungeonMap.fancyMap, + () -> config.dungeons.dungeonMap.fancyMap, + newValue -> config.dungeons.dungeonMap.fancyMap = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) .option(Option.createBuilder() .name(Text.translatable("skyblocker.config.dungeons.map.mapScaling")) .binding(defaults.dungeons.dungeonMap.mapScaling, diff --git a/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java index 4b2bf8c1b7..082a3e0ae0 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java @@ -76,6 +76,9 @@ public static class DungeonMap { @SerialEntry public boolean enableMap = true; + @SerialEntry + public boolean fancyMap = true; + @SerialEntry public float mapScaling = 1f; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java index 57fc5c01f1..1612b9fc74 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java @@ -3,7 +3,10 @@ import de.hysky.skyblocker.SkyblockerMod; import de.hysky.skyblocker.annotations.Init; import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.config.configs.DungeonsConfig; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; +import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonMapUtils; +import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonPlayerManager; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; @@ -13,18 +16,23 @@ import net.fabricmc.fabric.api.client.rendering.v1.IdentifiedLayer; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.realms.util.RealmsUtil; import net.minecraft.client.render.LightmapTextureManager; import net.minecraft.client.render.MapRenderState; import net.minecraft.client.render.MapRenderer; import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.util.math.MatrixStack; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.MapIdComponent; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.FilledMapItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.item.map.MapState; import net.minecraft.util.Identifier; +import net.minecraft.util.math.ColorHelper; +import net.minecraft.util.math.RotationAxis; +import org.joml.Vector2dc; public class DungeonMap { private static final Identifier DUNGEON_MAP = Identifier.of(SkyblockerMod.NAMESPACE, "dungeon_map"); @@ -46,12 +54,13 @@ public static void init() { } private static void render(DrawContext context) { - if (Utils.isInDungeons() && DungeonScore.isDungeonStarted() && !DungeonManager.isInBoss() && SkyblockerConfigManager.get().dungeons.dungeonMap.enableMap) { - render(context.getMatrices(), SkyblockerConfigManager.get().dungeons.dungeonMap.mapX, SkyblockerConfigManager.get().dungeons.dungeonMap.mapY, SkyblockerConfigManager.get().dungeons.dungeonMap.mapScaling); + DungeonsConfig.DungeonMap dungeonMap = SkyblockerConfigManager.get().dungeons.dungeonMap; + if (Utils.isInDungeons() && DungeonScore.isDungeonStarted() && !DungeonManager.isInBoss() && dungeonMap.enableMap) { + render(context, dungeonMap.mapX, dungeonMap.mapY, dungeonMap.mapScaling, dungeonMap.fancyMap); } } - public static void render(MatrixStack matrices, int x, int y, float scale) { + public static void render(DrawContext context, int x, int y, float scale, boolean fancy) { MinecraftClient client = MinecraftClient.getInstance(); if (client.player == null || client.world == null) return; @@ -62,15 +71,37 @@ public static void render(MatrixStack matrices, int x, int y, float scale) { VertexConsumerProvider.Immediate vertices = client.getBufferBuilders().getEffectVertexConsumers(); MapRenderer mapRenderer = client.getMapRenderer(); - matrices.push(); - matrices.translate(x, y, 0); - matrices.scale(scale, scale, 0f); + context.getMatrices().push(); + context.getMatrices().translate(x, y, 0); + context.getMatrices().scale(scale, scale, 0f); mapRenderer.update(mapId, state, MAP_RENDER_STATE); - mapRenderer.draw(MAP_RENDER_STATE, matrices, vertices, false, LightmapTextureManager.MAX_LIGHT_COORDINATE); + mapRenderer.draw(MAP_RENDER_STATE, context.getMatrices(), vertices, false, LightmapTextureManager.MAX_LIGHT_COORDINATE); vertices.draw(); - matrices.pop(); + + if (fancy) renderPlayerHeads(client, context); + context.getMatrices().pop(); } + private static void renderPlayerHeads(MinecraftClient client, DrawContext context) { + if (!DungeonManager.isClearingDungeon()) return; + + for (Entity entity : client.world.getEntities()) { + if (!(entity instanceof PlayerEntity player)) { + continue; + } + DungeonClass dungeonClass = DungeonPlayerManager.getClassFromPlayer(player); + if (dungeonClass == DungeonClass.UNKNOWN) continue; + + Vector2dc mapPos = DungeonMapUtils.getMapPosFromPhysical(DungeonManager.getPhysicalEntrancePos(), DungeonManager.getMapEntrancePos(), DungeonManager.getMapRoomSize(), entity.getPos()); + context.getMatrices().push(); + context.getMatrices().translate(mapPos.x(), mapPos.y(), 0); + context.getMatrices().multiply(RotationAxis.POSITIVE_Z.rotationDegrees(entity.getYaw() + 180)); + RealmsUtil.drawPlayerHead(context, -4, -4, 8, entity.getUuid()); + context.drawBorder(-5, -5, 10, 10, ColorHelper.fullAlpha(dungeonClass.color())); + context.getMatrices().pop(); + } + } + public static MapIdComponent getMapIdComponent(ItemStack stack) { if (stack.isOf(Items.FILLED_MAP) && stack.contains(DataComponentTypes.MAP_ID)) { MapIdComponent mapIdComponent = stack.get(DataComponentTypes.MAP_ID); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java index f1e8b4f9ce..46b92ba774 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java @@ -107,7 +107,7 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { int x = (width >> 1) - 64; int y = (height >> 2) - 64; - DungeonMap.render(context.getMatrices(), x, y, 1); + DungeonMap.render(context, x, y, 1, true); context.drawBorder(x, y, 128, 128, -1); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java index 63e71abee1..8803eeeee8 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java @@ -218,6 +218,20 @@ public static SecretWaypoint removeCustomWaypoint(String room, BlockPos pos) { return customWaypoints.remove(room, pos); } + @Nullable + public static Vector2ic getMapEntrancePos() { + return mapEntrancePos; + } + + public static int getMapRoomSize() { + return mapRoomSize; + } + + @Nullable + public static Vector2ic getPhysicalEntrancePos() { + return physicalEntrancePos; + } + /** * not null if {@link #isCurrentRoomMatched()} */ @@ -479,7 +493,7 @@ private static int removeCustomWaypointRelative(CommandContext matchAgainstCommand() { return argument("room", StringArgumentType.string()).suggests((context, builder) -> CommandSource.suggestMatching(ROOMS_DATA.values().stream().map(Map::values).flatMap(Collection::stream).map(Map::keySet).flatMap(Collection::stream), builder)).then(argument("direction", Room.Direction.DirectionArgumentType.direction()).executes(context -> { - if (physicalEntrancePos == null || mapEntrancePos == null || mapRoomSize == 0) { + if (!isClearingDungeon()) { context.getSource().sendError(Constants.PREFIX.get().append("§cYou are not in a dungeon.")); return Command.SINGLE_SUCCESS; } @@ -769,6 +783,13 @@ private static Room getRoomAtPhysical(Vec3i pos) { return rooms.get(DungeonMapUtils.getPhysicalRoomPos(pos)); } + /** + * @return {@code true} if the player is in the main clearing phase of a dungeon. + */ + public static boolean isClearingDungeon() { + return physicalEntrancePos != null && mapEntrancePos != null && mapRoomSize != 0; + } + /** * Calls {@link #isRoomMatched(Room)} on {@link #currentRoom}. * diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java index ca63d97198..58bd1b78f8 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonMapUtils.java @@ -8,14 +8,14 @@ import net.minecraft.item.map.MapDecorationTypes; import net.minecraft.item.map.MapState; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Position; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.joml.RoundingMode; -import org.joml.Vector2i; -import org.joml.Vector2ic; +import org.joml.*; +import java.lang.Math; import java.util.*; public class DungeonMapUtils { @@ -144,6 +144,10 @@ public static Vector2ic getMapPosFromPhysical(Vector2ic physicalEntrancePos, Vec return new Vector2i(physicalPos).sub(physicalEntrancePos).div(32).mul(mapRoomSize + 4).add(mapEntrancePos); } + public static Vector2dc getMapPosFromPhysical(Vector2ic physicalEntrancePos, Vector2ic mapEntrancePos, int mapRoomSize, Position physicalPos) { + return new Vector2d(physicalPos.getX(), physicalPos.getZ()).sub(physicalEntrancePos.x(), physicalEntrancePos.y()).div(32).mul(mapRoomSize + 4).add(mapEntrancePos.x(), mapEntrancePos.y()); + } + /** * Gets the map pos for the room that could be the furthest north-west on the map * (doesn't mean the room has to exist, it's just the furthest possible room) diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index 22b6b5b20c..c5681a5d21 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -163,6 +163,7 @@ "skyblocker.config.dungeons.map": "Map", "skyblocker.config.dungeons.map.enableMap": "Enable Map", + "skyblocker.config.dungeons.map.fancyMap": "Fancy Dungeon Map", "skyblocker.config.dungeons.map.mapScaling": "Map Scaling", "skyblocker.config.dungeons.map.mapScreen": "Dungeon Map & Score Placement Config...", From b75fd93aac706c630a657db3aade4482516e7bbb Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Thu, 3 Apr 2025 13:32:21 -0400 Subject: [PATCH 03/14] Fetch profiles on dungeon load and add dungeon loaded event --- .../skyblocker/events/DungeonEvents.java | 37 ++++++++++++------ .../dungeon/secrets/DungeonManager.java | 1 + .../dungeon/secrets/DungeonPlayerManager.java | 38 +++++++++++-------- .../dungeon/secrets/SecretsTracker.java | 4 +- .../tabhud/widget/DungeonPlayerWidget.java | 18 ++------- 5 files changed, 54 insertions(+), 44 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/events/DungeonEvents.java b/src/main/java/de/hysky/skyblocker/events/DungeonEvents.java index aa8565b3c8..b8448ac35b 100644 --- a/src/main/java/de/hysky/skyblocker/events/DungeonEvents.java +++ b/src/main/java/de/hysky/skyblocker/events/DungeonEvents.java @@ -7,6 +7,24 @@ import net.fabricmc.fabric.api.event.EventFactory; public class DungeonEvents { + /** + * Called when the player loads into a dungeon after the location is sent to the scoreboard. + */ + public static final Event DUNGEON_LOADED = EventFactory.createArrayBacked(DungeonLoaded.class, callbacks -> () -> { + for (DungeonLoaded callback : callbacks) { + callback.onDungeonLoaded(); + } + }); + + /** + * Called after the dungeons starts and after the tab has changed to include additional information about the run such as each player's class. + */ + public static final Event DUNGEON_STARTED = EventFactory.createArrayBacked(DungeonStarted.class, callbacks -> () -> { + for (DungeonStarted callback : callbacks) { + callback.onDungeonStarted(); + } + }); + public static final Event PUZZLE_MATCHED = EventFactory.createArrayBacked(RoomMatched.class, callbacks -> room -> { for (RoomMatched callback : callbacks) { callback.onRoomMatched(room); @@ -22,19 +40,10 @@ public class DungeonEvents { } }); - /** - * Note: This event fires after the tab has changed to include additional information about the run such as each player's class. - */ - public static final Event DUNGEON_STARTED = EventFactory.createArrayBacked(DungeonStarted.class, callbacks -> () -> { - for (DungeonStarted callback : callbacks) { - callback.onDungeonStarted(); - } - }); - @Environment(EnvType.CLIENT) @FunctionalInterface - public interface RoomMatched { - void onRoomMatched(Room room); + public interface DungeonLoaded { + void onDungeonLoaded(); } @Environment(EnvType.CLIENT) @@ -42,4 +51,10 @@ public interface RoomMatched { public interface DungeonStarted { void onDungeonStarted(); } + + @Environment(EnvType.CLIENT) + @FunctionalInterface + public interface RoomMatched { + void onRoomMatched(Room room); + } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java index 8803eeeee8..f893ffc481 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonManager.java @@ -590,6 +590,7 @@ private static void update() { Vec3d playerPos = client.player.getPos(); physicalEntrancePos = DungeonMapUtils.getPhysicalRoomPos(playerPos); currentRoom = newRoom(Room.Type.ENTRANCE, physicalEntrancePos); + DungeonEvents.DUNGEON_LOADED.invoker().onDungeonLoaded(); } MapState map = FilledMapItem.getMapState(DungeonMap.getMapIdComponent(client.player.getInventory().main.get(8)), client.world); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonPlayerManager.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonPlayerManager.java index b00a09de58..1c006cdab1 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonPlayerManager.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/DungeonPlayerManager.java @@ -1,33 +1,37 @@ package de.hysky.skyblocker.skyblock.dungeon.secrets; -import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.jetbrains.annotations.Range; -import com.mojang.util.UndashedUuid; - import de.hysky.skyblocker.annotations.Init; import de.hysky.skyblocker.events.DungeonEvents; import de.hysky.skyblocker.skyblock.dungeon.DungeonClass; import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListManager; -import de.hysky.skyblocker.utils.ApiUtils; +import de.hysky.skyblocker.utils.Utils; import it.unimi.dsi.fastutil.objects.Object2ReferenceMap; import it.unimi.dsi.fastutil.objects.Object2ReferenceOpenHashMap; import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; public class DungeonPlayerManager { /** - * @implNote Same as {@link de.hysky.skyblocker.skyblock.tabhud.widget.DungeonPlayerWidget#PLAYER_PATTERN} + * Match a player entry. + * Group 1: name + * Group 2: class (or literal "EMPTY" pre dungeon start) + * Group 3: level (or nothing, if pre dungeon start) + * This regex filters out the ironman icon as well as rank prefixes and emblems + * \[\d*\] (?:\[[A-Za-z]+\] )?(?[A-Za-z0-9_]*) (?:.* )?\((?\S*) ?(?[LXVI]*)\) */ - private static final Pattern PLAYER_TAB_PATTERN = Pattern.compile("\\[\\d*\\] (?:\\[[A-Za-z]+\\] )?(?[A-Za-z0-9_]*) (?:.* )?\\((?\\S*) ?(?[LXVI]*)\\)"); + public static final Pattern PLAYER_TAB_PATTERN = Pattern.compile("\\[\\d*\\] (?:\\[[A-Za-z]+\\] )?(?[A-Za-z0-9_]*) (?:.* )?\\((?\\S*) ?(?[LXVI]*)\\)"); private static final Object2ReferenceMap PLAYER_CLASSES = new Object2ReferenceOpenHashMap<>(5); @Init public static void init() { + DungeonEvents.DUNGEON_LOADED.register(DungeonPlayerManager::onDungeonLoaded); DungeonEvents.DUNGEON_STARTED.register(DungeonPlayerManager::onDungeonStart); } @@ -39,6 +43,18 @@ public static DungeonClass getClassFromPlayer(String name) { return PLAYER_CLASSES.getOrDefault(name, DungeonClass.UNKNOWN); } + /** + * Pre-fetches game profiles for rendering skins in the leap overlay and fancy dungeon map. + */ + private static void onDungeonLoaded() { + assert MinecraftClient.getInstance().world != null; + for (Entity entity : MinecraftClient.getInstance().world.getEntities()) { + if (entity instanceof PlayerEntity player && Utils.STRING_SCOREBOARD.stream().anyMatch(s -> s.contains(player.getGameProfile().getName()))) { + CompletableFuture.runAsync(() -> MinecraftClient.getInstance().getSessionService().fetchProfile(player.getUuid(), false)); + } + } + } + private static void onDungeonStart() { reset(); @@ -52,21 +68,13 @@ private static void onDungeonStart() { if (dungeonClass != DungeonClass.UNKNOWN) PLAYER_CLASSES.put(name, dungeonClass); } } - - //Pre-fetch game profiles for rendering skins in the leap overlay - for (Object2ReferenceMap.Entry entry : PLAYER_CLASSES.object2ReferenceEntrySet()) { - CompletableFuture.runAsync(() -> { - UUID uuid = UndashedUuid.fromString(ApiUtils.name2Uuid(entry.getKey())); - MinecraftClient.getInstance().getSessionService().fetchProfile(uuid, false); - }); - } } private static void reset() { PLAYER_CLASSES.clear(); } - private static Matcher getPlayerFromTab(@Range(from = 1, to = 5) int index) { + public static Matcher getPlayerFromTab(@Range(from = 1, to = 5) int index) { return PlayerListManager.regexAt(1 + (index - 1) * 4, PLAYER_TAB_PATTERN); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretsTracker.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretsTracker.java index dcc4a187f3..b3249107b8 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretsTracker.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/secrets/SecretsTracker.java @@ -5,8 +5,6 @@ import de.hysky.skyblocker.annotations.Init; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.events.DungeonEvents; -import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListManager; -import de.hysky.skyblocker.skyblock.tabhud.widget.DungeonPlayerWidget; import de.hysky.skyblocker.utils.ApiUtils; import de.hysky.skyblocker.utils.Constants; import de.hysky.skyblocker.utils.Http; @@ -131,7 +129,7 @@ private static void onMessage(Text text, boolean overlay) { } private static String getPlayerNameAt(int index) { - Matcher matcher = PlayerListManager.regexAt(1 + (index - 1) * 4, DungeonPlayerWidget.PLAYER_PATTERN); + Matcher matcher = DungeonPlayerManager.getPlayerFromTab(index); return matcher != null ? matcher.group("name") : ""; } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/DungeonPlayerWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/DungeonPlayerWidget.java index 14c06abcf5..e5742c2f1b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/DungeonPlayerWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/tabhud/widget/DungeonPlayerWidget.java @@ -1,6 +1,7 @@ package de.hysky.skyblocker.skyblock.tabhud.widget; import de.hysky.skyblocker.skyblock.dungeon.DungeonClass; +import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonPlayerManager; import de.hysky.skyblocker.skyblock.tabhud.util.Ico; import de.hysky.skyblocker.skyblock.tabhud.util.PlayerListManager; import de.hysky.skyblocker.skyblock.tabhud.widget.component.IcoTextComponent; @@ -13,24 +14,11 @@ import java.util.List; import java.util.regex.Matcher; -import java.util.regex.Pattern; // this widget shows info about a player in the current dungeon group public class DungeonPlayerWidget extends TabHudWidget { - - private static final MutableText TITLE = Text.literal("Player").formatted(Formatting.DARK_PURPLE, - Formatting.BOLD); - - // match a player entry - // group 1: name - // group 2: class (or literal "EMPTY" pre dungeon start) - // group 3: level (or nothing, if pre dungeon start) - // this regex filters out the ironman icon as well as rank prefixes and emblems - // \[\d*\] (?:\[[A-Za-z]+\] )?(?[A-Za-z0-9_]*) (?:.* )?\((?\S*) ?(?[LXVI]*)\) - public static final Pattern PLAYER_PATTERN = Pattern - .compile("\\[\\d*\\] (?:\\[[A-Za-z]+\\] )?(?[A-Za-z0-9_]*) (?:.* )?\\((?\\S*) ?(?[LXVI]*)\\)"); - + private static final MutableText TITLE = Text.literal("Player").formatted(Formatting.DARK_PURPLE, Formatting.BOLD); private static final List MSGS = List.of("???", "PRESS A TO JOIN", "Invite a friend!", "But nobody came.", "More is better!"); private final int player; @@ -52,7 +40,7 @@ public void updateContent(List ignored) { this.addComponent(noplayer); return; } - Matcher m = PlayerListManager.regexAt(start, PLAYER_PATTERN); + Matcher m = PlayerListManager.regexAt(start, DungeonPlayerManager.PLAYER_TAB_PATTERN); if (m == null) { this.addComponent(new IcoTextComponent()); this.addComponent(new IcoTextComponent()); From a9f1132e2682c9a4185eb5e22d87b14a79520162 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Thu, 3 Apr 2025 14:32:58 -0400 Subject: [PATCH 04/14] Add player arrow --- .../java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java index 1612b9fc74..70ba26c3f6 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java @@ -98,6 +98,7 @@ private static void renderPlayerHeads(MinecraftClient client, DrawContext contex context.getMatrices().multiply(RotationAxis.POSITIVE_Z.rotationDegrees(entity.getYaw() + 180)); RealmsUtil.drawPlayerHead(context, -4, -4, 8, entity.getUuid()); context.drawBorder(-5, -5, 10, 10, ColorHelper.fullAlpha(dungeonClass.color())); + context.fill(-1, -7, 1, -5, ColorHelper.fullAlpha(dungeonClass.color())); context.getMatrices().pop(); } } From ef6614f400828b9d7b9efe9322ea53f77a675638 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Fri, 4 Apr 2025 00:00:49 -0400 Subject: [PATCH 05/14] Add player marker tracking --- .../mixins/accessors/MapStateAccessor.java | 14 ++ .../skyblock/dungeon/DungeonMap.java | 150 ++++++++++++------ src/main/resources/skyblocker.mixins.json | 1 + 3 files changed, 116 insertions(+), 49 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/mixins/accessors/MapStateAccessor.java diff --git a/src/main/java/de/hysky/skyblocker/mixins/accessors/MapStateAccessor.java b/src/main/java/de/hysky/skyblocker/mixins/accessors/MapStateAccessor.java new file mode 100644 index 0000000000..cbf7764b5a --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/mixins/accessors/MapStateAccessor.java @@ -0,0 +1,14 @@ +package de.hysky.skyblocker.mixins.accessors; + +import net.minecraft.item.map.MapDecoration; +import net.minecraft.item.map.MapState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(MapState.class) +public interface MapStateAccessor { + @Accessor + Map getDecorations(); +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java index 70ba26c3f6..5b274a9ec8 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java @@ -4,11 +4,13 @@ import de.hysky.skyblocker.annotations.Init; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.config.configs.DungeonsConfig; +import de.hysky.skyblocker.mixins.accessors.MapStateAccessor; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonMapUtils; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonPlayerManager; import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.scheduler.Scheduler; +import it.unimi.dsi.fastutil.Pair; import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; @@ -28,90 +30,140 @@ import net.minecraft.item.FilledMapItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; +import net.minecraft.item.map.MapDecoration; +import net.minecraft.item.map.MapDecorationTypes; import net.minecraft.item.map.MapState; import net.minecraft.util.Identifier; import net.minecraft.util.math.ColorHelper; import net.minecraft.util.math.RotationAxis; +import org.apache.commons.lang3.mutable.MutableInt; +import org.joml.Vector2d; import org.joml.Vector2dc; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + public class DungeonMap { private static final Identifier DUNGEON_MAP = Identifier.of(SkyblockerMod.NAMESPACE, "dungeon_map"); - private static final MapIdComponent DEFAULT_MAP_ID_COMPONENT = new MapIdComponent(1024); - private static final MapRenderState MAP_RENDER_STATE = new MapRenderState(); - private static MapIdComponent cachedMapIdComponent = null; + private static final MapIdComponent DEFAULT_MAP_ID_COMPONENT = new MapIdComponent(1024); + private static final MapRenderState MAP_RENDER_STATE = new MapRenderState(); + private static MapIdComponent cachedMapIdComponent = null; + /** + * Data structure that stores how likely a map decoration (identified by the decoration's string key) is a player (identified by the uuid and name). + * This does so by counting how many times a map decoration and a player was closest to each other. + * The higher the number, the more likely that the map decoration is the player. + */ + private static final Map, MutableInt>> mapPlayers = HashMap.newHashMap(5); - @Init - public static void init() { + @Init + public static void init() { + Scheduler.INSTANCE.scheduleCyclic(DungeonMap::update, 1); HudLayerRegistrationCallback.EVENT.register(d -> d.attachLayerAfter(IdentifiedLayer.STATUS_EFFECTS, DUNGEON_MAP, (context, tickCounter) -> render(context))); - ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(ClientCommandManager.literal("skyblocker") - .then(ClientCommandManager.literal("hud") - .then(ClientCommandManager.literal("dungeon") - .executes(Scheduler.queueOpenScreenCommand(DungeonMapConfigScreen::new)) - ) - ) - )); - ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> reset()); - } + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(ClientCommandManager.literal("skyblocker") + .then(ClientCommandManager.literal("hud") + .then(ClientCommandManager.literal("dungeon") + .executes(Scheduler.queueOpenScreenCommand(DungeonMapConfigScreen::new)) + ) + ) + )); + ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> reset()); + } + + private static boolean shouldProcess() { + return Utils.isInDungeons() && DungeonScore.isDungeonStarted() && !DungeonManager.isInBoss(); + } + + /** + * Keeps track of players and map player markers to determine which marker corresponds to which player. + */ + private static void update() { + if (!shouldProcess() || !DungeonManager.isClearingDungeon()) { + return; + } + + MinecraftClient client = MinecraftClient.getInstance(); + assert client.player != null; + MapIdComponent mapId = getMapIdComponent(client.player.getInventory().main.get(8)); + MapState state = FilledMapItem.getMapState(mapId, client.world); + if (state == null) return; + + for (Entity entity : client.world.getEntities()) { + if (!(entity instanceof PlayerEntity player) || DungeonPlayerManager.getClassFromPlayer(player) == DungeonClass.UNKNOWN) continue; + Vector2dc mapPos = DungeonMapUtils.getMapPosFromPhysical(DungeonManager.getPhysicalEntrancePos(), DungeonManager.getMapEntrancePos(), DungeonManager.getMapRoomSize(), entity.getPos()); + + ((MapStateAccessor) state).getDecorations().entrySet().stream() + .filter(e -> e.getValue().type() == MapDecorationTypes.FRAME || e.getValue().type() == MapDecorationTypes.BLUE_MARKER) + .filter(e -> mapPos.distanceSquared(e.getValue().x() / 2d + 64, e.getValue().z() / 2d + 64) <= 8) + .min(Comparator.comparingDouble(e -> mapPos.distanceSquared(e.getValue().x() / 2d + 64, e.getValue().z() / 2d + 64))) + .ifPresent(e -> mapPlayers.computeIfAbsent(e.getKey(), _key -> new HashMap<>()).computeIfAbsent(Pair.of(player.getUuid(), player.getGameProfile().getName()), _key -> new MutableInt(0)).increment()); + } + } private static void render(DrawContext context) { DungeonsConfig.DungeonMap dungeonMap = SkyblockerConfigManager.get().dungeons.dungeonMap; - if (Utils.isInDungeons() && DungeonScore.isDungeonStarted() && !DungeonManager.isInBoss() && dungeonMap.enableMap) { + if (shouldProcess() && dungeonMap.enableMap) { render(context, dungeonMap.mapX, dungeonMap.mapY, dungeonMap.mapScaling, dungeonMap.fancyMap); } } - public static void render(DrawContext context, int x, int y, float scale, boolean fancy) { - MinecraftClient client = MinecraftClient.getInstance(); - if (client.player == null || client.world == null) return; + public static void render(DrawContext context, int x, int y, float scale, boolean fancy) { + MinecraftClient client = MinecraftClient.getInstance(); + if (client.player == null || client.world == null) return; - MapIdComponent mapId = getMapIdComponent(client.player.getInventory().main.get(8)); - MapState state = FilledMapItem.getMapState(mapId, client.world); - if (state == null) return; + MapIdComponent mapId = getMapIdComponent(client.player.getInventory().main.get(8)); + MapState state = FilledMapItem.getMapState(mapId, client.world); + if (state == null) return; - VertexConsumerProvider.Immediate vertices = client.getBufferBuilders().getEffectVertexConsumers(); - MapRenderer mapRenderer = client.getMapRenderer(); + VertexConsumerProvider.Immediate vertices = client.getBufferBuilders().getEffectVertexConsumers(); + MapRenderer mapRenderer = client.getMapRenderer(); context.getMatrices().push(); context.getMatrices().translate(x, y, 0); context.getMatrices().scale(scale, scale, 0f); - mapRenderer.update(mapId, state, MAP_RENDER_STATE); - mapRenderer.draw(MAP_RENDER_STATE, context.getMatrices(), vertices, false, LightmapTextureManager.MAX_LIGHT_COORDINATE); - vertices.draw(); + mapRenderer.update(mapId, state, MAP_RENDER_STATE); + mapRenderer.draw(MAP_RENDER_STATE, context.getMatrices(), vertices, false, LightmapTextureManager.MAX_LIGHT_COORDINATE); + vertices.draw(); - if (fancy) renderPlayerHeads(client, context); + if (fancy) renderPlayerHeads(client, context, state); context.getMatrices().pop(); - } + } - private static void renderPlayerHeads(MinecraftClient client, DrawContext context) { + public static MapIdComponent getMapIdComponent(ItemStack stack) { + if (stack.isOf(Items.FILLED_MAP) && stack.contains(DataComponentTypes.MAP_ID)) { + MapIdComponent mapIdComponent = stack.get(DataComponentTypes.MAP_ID); + cachedMapIdComponent = mapIdComponent; + return mapIdComponent; + } else return cachedMapIdComponent != null ? cachedMapIdComponent : DEFAULT_MAP_ID_COMPONENT; + } + + private static void renderPlayerHeads(MinecraftClient client, DrawContext context, MapState state) { if (!DungeonManager.isClearingDungeon()) return; - for (Entity entity : client.world.getEntities()) { - if (!(entity instanceof PlayerEntity player)) { - continue; - } - DungeonClass dungeonClass = DungeonPlayerManager.getClassFromPlayer(player); - if (dungeonClass == DungeonClass.UNKNOWN) continue; + for (Map.Entry mapPlayerDecoration : ((MapStateAccessor) state).getDecorations().entrySet()) { + if (!mapPlayers.containsKey(mapPlayerDecoration.getKey())) continue; + // Get the player uuid and name pair with the highest count (therefore most likely to be the correct player) + Pair mapPlayer = mapPlayers.get(mapPlayerDecoration.getKey()).entrySet().stream() + .max(Map.Entry.comparingByValue()).orElseThrow().getKey(); + // Use the player entity if it exists, since it gives the most accurate position and rotation + PlayerEntity player = client.world.getPlayerByUuid(mapPlayer.left()); + Vector2dc mapPos = player != null ? DungeonMapUtils.getMapPosFromPhysical(DungeonManager.getPhysicalEntrancePos(), DungeonManager.getMapEntrancePos(), DungeonManager.getMapRoomSize(), player.getPos()) : new Vector2d(mapPlayerDecoration.getValue().x() / 2d + 64, mapPlayerDecoration.getValue().z() / 2d + 64); + float deg = player != null ? player.getYaw() : mapPlayerDecoration.getValue().rotation() * 360 / 16.0F; + DungeonClass dungeonClass = DungeonPlayerManager.getClassFromPlayer(mapPlayer.right()); - Vector2dc mapPos = DungeonMapUtils.getMapPosFromPhysical(DungeonManager.getPhysicalEntrancePos(), DungeonManager.getMapEntrancePos(), DungeonManager.getMapRoomSize(), entity.getPos()); context.getMatrices().push(); context.getMatrices().translate(mapPos.x(), mapPos.y(), 0); - context.getMatrices().multiply(RotationAxis.POSITIVE_Z.rotationDegrees(entity.getYaw() + 180)); - RealmsUtil.drawPlayerHead(context, -4, -4, 8, entity.getUuid()); + context.getMatrices().multiply(RotationAxis.POSITIVE_Z.rotationDegrees(deg + 180)); + RealmsUtil.drawPlayerHead(context, -4, -4, 8, mapPlayer.left()); context.drawBorder(-5, -5, 10, 10, ColorHelper.fullAlpha(dungeonClass.color())); context.fill(-1, -7, 1, -5, ColorHelper.fullAlpha(dungeonClass.color())); context.getMatrices().pop(); } } - public static MapIdComponent getMapIdComponent(ItemStack stack) { - if (stack.isOf(Items.FILLED_MAP) && stack.contains(DataComponentTypes.MAP_ID)) { - MapIdComponent mapIdComponent = stack.get(DataComponentTypes.MAP_ID); - cachedMapIdComponent = mapIdComponent; - return mapIdComponent; - } else return cachedMapIdComponent != null ? cachedMapIdComponent : DEFAULT_MAP_ID_COMPONENT; - } - - private static void reset() { - cachedMapIdComponent = null; - } + private static void reset() { + cachedMapIdComponent = null; + mapPlayers.clear(); + } } diff --git a/src/main/resources/skyblocker.mixins.json b/src/main/resources/skyblocker.mixins.json index 0a8f2c93da..e71d3718dd 100644 --- a/src/main/resources/skyblocker.mixins.json +++ b/src/main/resources/skyblocker.mixins.json @@ -58,6 +58,7 @@ "accessors.FrustumInvoker", "accessors.HandledScreenAccessor", "accessors.InGameHudInvoker", + "accessors.MapStateAccessor", "accessors.MessageHandlerAccessor", "accessors.MinecraftClientAccessor", "accessors.PlayerListHudAccessor", From e60317c465343acb00d2a6feb6716f2b193cb4fc Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Fri, 4 Apr 2025 01:38:21 -0400 Subject: [PATCH 06/14] Add hover and click to teleport --- .../skyblock/dungeon/DungeonMap.java | 64 +++++++++++++------ .../skyblock/dungeon/LeapOverlay.java | 28 +++++++- 2 files changed, 71 insertions(+), 21 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java index 5b274a9ec8..6c5738c60f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java @@ -37,6 +37,7 @@ import net.minecraft.util.math.ColorHelper; import net.minecraft.util.math.RotationAxis; import org.apache.commons.lang3.mutable.MutableInt; +import org.jetbrains.annotations.Nullable; import org.joml.Vector2d; import org.joml.Vector2dc; @@ -109,12 +110,17 @@ private static void render(DrawContext context) { } public static void render(DrawContext context, int x, int y, float scale, boolean fancy) { + render(context, x, y, scale, fancy, Integer.MIN_VALUE, Integer.MIN_VALUE, null); + } + + @Nullable + public static UUID render(DrawContext context, int x, int y, float scale, boolean fancy, int mouseX, int mouseY, @Nullable UUID enlarge) { MinecraftClient client = MinecraftClient.getInstance(); - if (client.player == null || client.world == null) return; + if (client.player == null || client.world == null) return null; MapIdComponent mapId = getMapIdComponent(client.player.getInventory().main.get(8)); MapState state = FilledMapItem.getMapState(mapId, client.world); - if (state == null) return; + if (state == null) return null; VertexConsumerProvider.Immediate vertices = client.getBufferBuilders().getEffectVertexConsumers(); MapRenderer mapRenderer = client.getMapRenderer(); @@ -126,8 +132,10 @@ public static void render(DrawContext context, int x, int y, float scale, boolea mapRenderer.draw(MAP_RENDER_STATE, context.getMatrices(), vertices, false, LightmapTextureManager.MAX_LIGHT_COORDINATE); vertices.draw(); - if (fancy) renderPlayerHeads(client, context, state); + UUID hoveredHead = null; + if (fancy) hoveredHead = renderPlayerHeads(context, state, mouseX, mouseY, enlarge); context.getMatrices().pop(); + return hoveredHead; } public static MapIdComponent getMapIdComponent(ItemStack stack) { @@ -138,32 +146,52 @@ public static MapIdComponent getMapIdComponent(ItemStack stack) { } else return cachedMapIdComponent != null ? cachedMapIdComponent : DEFAULT_MAP_ID_COMPONENT; } - private static void renderPlayerHeads(MinecraftClient client, DrawContext context, MapState state) { - if (!DungeonManager.isClearingDungeon()) return; + private static UUID renderPlayerHeads(DrawContext context, MapState state, int mouseX, int mouseY, @Nullable UUID enlarge) { + if (!DungeonManager.isClearingDungeon()) return null; - for (Map.Entry mapPlayerDecoration : ((MapStateAccessor) state).getDecorations().entrySet()) { - if (!mapPlayers.containsKey(mapPlayerDecoration.getKey())) continue; - // Get the player uuid and name pair with the highest count (therefore most likely to be the correct player) - Pair mapPlayer = mapPlayers.get(mapPlayerDecoration.getKey()).entrySet().stream() - .max(Map.Entry.comparingByValue()).orElseThrow().getKey(); - // Use the player entity if it exists, since it gives the most accurate position and rotation - PlayerEntity player = client.world.getPlayerByUuid(mapPlayer.left()); - Vector2dc mapPos = player != null ? DungeonMapUtils.getMapPosFromPhysical(DungeonManager.getPhysicalEntrancePos(), DungeonManager.getMapEntrancePos(), DungeonManager.getMapRoomSize(), player.getPos()) : new Vector2d(mapPlayerDecoration.getValue().x() / 2d + 64, mapPlayerDecoration.getValue().z() / 2d + 64); - float deg = player != null ? player.getYaw() : mapPlayerDecoration.getValue().rotation() * 360 / 16.0F; - DungeonClass dungeonClass = DungeonPlayerManager.getClassFromPlayer(mapPlayer.right()); + UUID hovered = null; + for (Map.Entry mapDecoration : ((MapStateAccessor) state).getDecorations().entrySet()) { + PlayerRenderState player = PlayerRenderState.of(mapDecoration); + if (player == null) continue; + DungeonClass dungeonClass = DungeonPlayerManager.getClassFromPlayer(player.name()); context.getMatrices().push(); - context.getMatrices().translate(mapPos.x(), mapPos.y(), 0); - context.getMatrices().multiply(RotationAxis.POSITIVE_Z.rotationDegrees(deg + 180)); - RealmsUtil.drawPlayerHead(context, -4, -4, 8, mapPlayer.left()); + context.getMatrices().translate(player.mapPos().x(), player.mapPos().y(), 0); + context.getMatrices().multiply(RotationAxis.POSITIVE_Z.rotationDegrees(player.deg() + 180)); + + if (player.uuid().equals(enlarge)) { + // Enlarge the player head when the corresponding button is hovered + context.getMatrices().scale(2, 2, 1); + } else if (hovered == null && player.mapPos().distanceSquared(mouseX, mouseY) < 16) { + // Enlarge the player head when hovered + context.getMatrices().scale(2, 2, 1); + hovered = player.uuid(); + } + RealmsUtil.drawPlayerHead(context, -4, -4, 8, player.uuid()); context.drawBorder(-5, -5, 10, 10, ColorHelper.fullAlpha(dungeonClass.color())); context.fill(-1, -7, 1, -5, ColorHelper.fullAlpha(dungeonClass.color())); context.getMatrices().pop(); } + return hovered; } private static void reset() { cachedMapIdComponent = null; mapPlayers.clear(); } + + public record PlayerRenderState(UUID uuid, String name, Vector2dc mapPos, float deg) { + public static PlayerRenderState of(Map.Entry mapDecoration) { + if (!mapPlayers.containsKey(mapDecoration.getKey())) return null; + // Get the player uuid and name pair with the highest count (therefore most likely to be the correct player) + Pair mapPlayer = mapPlayers.get(mapDecoration.getKey()).entrySet().stream() + .max(Map.Entry.comparingByValue()).orElseThrow().getKey(); + // Use the player entity if it exists, since it gives the most accurate position and rotation + PlayerEntity player = MinecraftClient.getInstance().world.getPlayerByUuid(mapPlayer.left()); + Vector2dc mapPos = player != null ? DungeonMapUtils.getMapPosFromPhysical(DungeonManager.getPhysicalEntrancePos(), DungeonManager.getMapEntrancePos(), DungeonManager.getMapRoomSize(), player.getPos()) : new Vector2d(mapDecoration.getValue().x() / 2d + 64, mapDecoration.getValue().z() / 2d + 64); + float deg = player != null ? player.getYaw() : mapDecoration.getValue().rotation() * 360 / 16.0F; + + return new PlayerRenderState(mapPlayer.left(), mapPlayer.right(), mapPos, deg); + } + } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java index 46b92ba774..d6d9c67a23 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java @@ -8,6 +8,7 @@ import org.lwjgl.glfw.GLFW; import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.mixins.accessors.MapStateAccessor; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonPlayerManager; import de.hysky.skyblocker.utils.ItemUtils; import net.minecraft.client.MinecraftClient; @@ -21,6 +22,7 @@ import net.minecraft.client.render.RenderLayer; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.ProfileComponent; +import net.minecraft.item.FilledMapItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.screen.GenericContainerScreenHandler; @@ -42,6 +44,8 @@ public class LeapOverlay extends Screen implements ScreenHandlerListener { private static final int BUTTON_HEIGHT = 50; private final GenericContainerScreenHandler handler; private final SortedSet references = new TreeSet<>(); + @Nullable + private UUID hovered; public LeapOverlay(GenericContainerScreenHandler handler) { super(Text.literal("Skyblocker Leap Overlay")); @@ -107,10 +111,28 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { int x = (width >> 1) - 64; int y = (height >> 2) - 64; - DungeonMap.render(context, x, y, 1, true); + hovered = DungeonMap.render(context, x, y, 1, true, mouseX - x, mouseY - y, hoveredElement(mouseX, mouseY).filter(PlayerButton.class::isInstance).map(PlayerButton.class::cast).map(p -> p.reference.uuid()).orElse(null)); context.drawBorder(x, y, 128, 128, -1); } + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + int x = (width >> 1) - 64; + int y = (height >> 2) - 64; + if (x <= mouseX && mouseX <= x + 128 && y <= mouseY && mouseY <= y + 128) { + assert client != null && client.player != null && client.interactionManager != null; + Optional.ofNullable(FilledMapItem.getMapState(DungeonMap.getMapIdComponent(client.player.getInventory().main.get(8)), client.world)) + .stream().map(MapStateAccessor.class::cast).map(MapStateAccessor::getDecorations).map(Map::entrySet).flatMap(Set::stream) + .map(DungeonMap.PlayerRenderState::of) + .filter(Objects::nonNull).filter(player -> player.mapPos().distanceSquared(mouseX - x, mouseY - y) <= 16) + .flatMap(player -> references.stream().filter(ref -> ref.uuid().equals(player.uuid()))) + .findAny().ifPresent(ref -> client.interactionManager.clickSlot(ref.syncId(), ref.slotId(), GLFW.GLFW_MOUSE_BUTTON_LEFT, SlotActionType.PICKUP, client.player)); + return true; + } + + return super.mouseClicked(mouseX, mouseY, button); + } + @Override public void tick() { super.tick(); @@ -134,7 +156,7 @@ public void removed() { } } - private static class PlayerButton extends ButtonWidget { + private class PlayerButton extends ButtonWidget { private static final int BORDER_THICKNESS = 2; private static final int HEAD_SIZE = 32; private final PlayerReference reference; @@ -146,7 +168,7 @@ private PlayerButton(int x, int y, int width, int height, PlayerReference refere @Override protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { - Identifier texture = this.isSelected() ? BUTTON_HIGHLIGHTED : BUTTON; + Identifier texture = this.isSelected() || reference.uuid().equals(LeapOverlay.this.hovered) ? BUTTON_HIGHLIGHTED : BUTTON; context.drawGuiTexture(RenderLayer::getGuiTextured, texture, this.getX(), this.getY(), this.getWidth(), this.getHeight()); int baseX = this.getX() + BORDER_THICKNESS; From cd3241eb5f44c8c5e9aa328d31f868f8bf371b81 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Mon, 7 Apr 2025 10:53:27 -0400 Subject: [PATCH 07/14] Apply suggestions * Add show self head option * Only show map in leap overlay while clearing * Add inventory key to close leap overlay --- .../config/categories/DungeonsCategory.java | 7 +++ .../config/configs/DungeonsConfig.java | 3 ++ .../skyblock/dungeon/DungeonMap.java | 2 +- .../skyblock/dungeon/LeapOverlay.java | 53 +++++++++++++------ .../assets/skyblocker/lang/en_us.json | 1 + 5 files changed, 49 insertions(+), 17 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java index 74e5fefaf1..700df581b3 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java @@ -118,6 +118,13 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig newValue -> config.dungeons.dungeonMap.fancyMap = newValue) .controller(ConfigUtils::createBooleanController) .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.map.showSelfHead")) + .binding(defaults.dungeons.dungeonMap.showSelfHead, + () -> config.dungeons.dungeonMap.showSelfHead, + newValue -> config.dungeons.dungeonMap.showSelfHead = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) .option(Option.createBuilder() .name(Text.translatable("skyblocker.config.dungeons.map.mapScaling")) .binding(defaults.dungeons.dungeonMap.mapScaling, diff --git a/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java index 082a3e0ae0..60de6b8a87 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java @@ -79,6 +79,9 @@ public static class DungeonMap { @SerialEntry public boolean fancyMap = true; + @SerialEntry + public boolean showSelfHead = true; + @SerialEntry public float mapScaling = 1f; diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java index 6c5738c60f..dead81976b 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java @@ -152,7 +152,7 @@ private static UUID renderPlayerHeads(DrawContext context, MapState state, int m UUID hovered = null; for (Map.Entry mapDecoration : ((MapStateAccessor) state).getDecorations().entrySet()) { PlayerRenderState player = PlayerRenderState.of(mapDecoration); - if (player == null) continue; + if (player == null || player.uuid().equals(MinecraftClient.getInstance().player.getUuid()) && !SkyblockerConfigManager.get().dungeons.dungeonMap.showSelfHead) continue; DungeonClass dungeonClass = DungeonPlayerManager.getClassFromPlayer(player.name()); context.getMatrices().push(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java index d6d9c67a23..5f7777729d 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java @@ -3,6 +3,7 @@ import java.util.*; import java.util.function.Supplier; +import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; @@ -68,7 +69,7 @@ protected void init() { } gridWidget.refreshPositions(); - SimplePositioningWidget.setPos(gridWidget, 0, 0, this.width, this.height, 0.5f, 0.75f); + SimplePositioningWidget.setPos(gridWidget, 0, 0, this.width, this.height, 0.5f, DungeonManager.isClearingDungeon() ? 0.75f : 0.5f); gridWidget.forEachChild(this::addDrawableChild); } @@ -109,30 +110,45 @@ private void updateReference(PlayerReference reference) { public void render(DrawContext context, int mouseX, int mouseY, float delta) { super.render(context, mouseX, mouseY, delta); - int x = (width >> 1) - 64; - int y = (height >> 2) - 64; - hovered = DungeonMap.render(context, x, y, 1, true, mouseX - x, mouseY - y, hoveredElement(mouseX, mouseY).filter(PlayerButton.class::isInstance).map(PlayerButton.class::cast).map(p -> p.reference.uuid()).orElse(null)); - context.drawBorder(x, y, 128, 128, -1); + if (DungeonManager.isClearingDungeon()) { + int x = (width >> 1) - 64; + int y = (height >> 2) - 64; + hovered = DungeonMap.render(context, x, y, 1, true, mouseX - x, mouseY - y, hoveredElement(mouseX, mouseY).filter(PlayerButton.class::isInstance).map(PlayerButton.class::cast).map(p -> p.reference.uuid()).orElse(null)); + context.drawBorder(x, y, 128, 128, -1); + } } @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - int x = (width >> 1) - 64; - int y = (height >> 2) - 64; - if (x <= mouseX && mouseX <= x + 128 && y <= mouseY && mouseY <= y + 128) { - assert client != null && client.player != null && client.interactionManager != null; - Optional.ofNullable(FilledMapItem.getMapState(DungeonMap.getMapIdComponent(client.player.getInventory().main.get(8)), client.world)) - .stream().map(MapStateAccessor.class::cast).map(MapStateAccessor::getDecorations).map(Map::entrySet).flatMap(Set::stream) - .map(DungeonMap.PlayerRenderState::of) - .filter(Objects::nonNull).filter(player -> player.mapPos().distanceSquared(mouseX - x, mouseY - y) <= 16) - .flatMap(player -> references.stream().filter(ref -> ref.uuid().equals(player.uuid()))) - .findAny().ifPresent(ref -> client.interactionManager.clickSlot(ref.syncId(), ref.slotId(), GLFW.GLFW_MOUSE_BUTTON_LEFT, SlotActionType.PICKUP, client.player)); - return true; + if (DungeonManager.isClearingDungeon()) { + int x = (width >> 1) - 64; + int y = (height >> 2) - 64; + if (x <= mouseX && mouseX <= x + 128 && y <= mouseY && mouseY <= y + 128) { + assert client != null && client.player != null && client.interactionManager != null; + Optional.ofNullable(FilledMapItem.getMapState(DungeonMap.getMapIdComponent(client.player.getInventory().main.get(8)), client.world)) + .stream().map(MapStateAccessor.class::cast).map(MapStateAccessor::getDecorations).map(Map::entrySet).flatMap(Set::stream) + .map(DungeonMap.PlayerRenderState::of) + .filter(Objects::nonNull).filter(player -> player.mapPos().distanceSquared(mouseX - x, mouseY - y) <= 16) + .flatMap(player -> references.stream().filter(ref -> ref.uuid().equals(player.uuid()))) + .findAny().ifPresent(ref -> client.interactionManager.clickSlot(ref.syncId(), ref.slotId(), GLFW.GLFW_MOUSE_BUTTON_LEFT, SlotActionType.PICKUP, client.player)); + return true; + } } return super.mouseClicked(mouseX, mouseY, button); } + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (super.keyPressed(keyCode, scanCode, modifiers)) { + return true; + } else if (this.client.options.inventoryKey.matchesKey(keyCode, scanCode)) { + this.close(); + return true; + } + return false; + } + @Override public void tick() { super.tick(); @@ -211,6 +227,11 @@ public boolean equals(Object obj) { return obj instanceof PlayerReference playerRef && uuid.equals(playerRef.uuid); } + @Override + public int hashCode() { + return uuid.hashCode(); + } + @Override public int compareTo(@NotNull LeapOverlay.PlayerReference o) { return COMPARATOR.compare(this, o); diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index c5681a5d21..cf8595d1ab 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -164,6 +164,7 @@ "skyblocker.config.dungeons.map": "Map", "skyblocker.config.dungeons.map.enableMap": "Enable Map", "skyblocker.config.dungeons.map.fancyMap": "Fancy Dungeon Map", + "skyblocker.config.dungeons.map.showSelfHead": "Show Self Head", "skyblocker.config.dungeons.map.mapScaling": "Map Scaling", "skyblocker.config.dungeons.map.mapScreen": "Dungeon Map & Score Placement Config...", From f7a6088f79a4c0f80437b180eb78503150eaa289 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Mon, 7 Apr 2025 14:26:15 -0400 Subject: [PATCH 08/14] Add leap overlay scaling and migrate config --- .../config/categories/DungeonsCategory.java | 37 ++++++++++++---- .../config/configs/DungeonsConfig.java | 17 +++++-- .../mixins/HandledScreenProviderMixin.java | 2 +- .../skyblock/dungeon/LeapOverlay.java | 44 ++++++++++++++----- .../assets/skyblocker/lang/en_us.json | 5 ++- 5 files changed, 81 insertions(+), 24 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java index 700df581b3..80fc9ca182 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java @@ -7,6 +7,7 @@ import de.hysky.skyblocker.utils.waypoint.Waypoint.Type; import dev.isxander.yacl3.api.*; import dev.isxander.yacl3.api.controller.FloatFieldControllerBuilder; +import dev.isxander.yacl3.api.controller.FloatSliderControllerBuilder; import dev.isxander.yacl3.api.controller.IntegerFieldControllerBuilder; import dev.isxander.yacl3.api.controller.StringControllerBuilder; import net.minecraft.client.MinecraftClient; @@ -59,14 +60,6 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig newValue -> config.dungeons.classBasedPlayerGlow = newValue) .controller(ConfigUtils::createBooleanController) .build()) - .option(Option.createBuilder() - .name(Text.translatable("skyblocker.config.dungeons.spiritLeapOverlay")) - .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.spiritLeapOverlay.@Tooltip"))) - .binding(defaults.dungeons.spiritLeapOverlay, - () -> config.dungeons.spiritLeapOverlay, - newValue -> config.dungeons.spiritLeapOverlay = newValue) - .controller(ConfigUtils::createBooleanController) - .build()) .option(Option.createBuilder() .name(Text.translatable("skyblocker.config.dungeons.starredMobGlow")) .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.starredMobGlow.@Tooltip"))) @@ -139,6 +132,34 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig .build()) .build()) + // Spirit Leap Overlay + .group(OptionGroup.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.spiritLeapOverlay")) + .collapsed(true) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.spiritLeapOverlay.enableLeapOverlay")) + .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.spiritLeapOverlay.enableLeapOverlay.@Tooltip"))) + .binding(defaults.dungeons.spiritLeapOverlay.enableLeapOverlay, + () -> config.dungeons.spiritLeapOverlay.enableLeapOverlay, + newValue -> config.dungeons.spiritLeapOverlay.enableLeapOverlay = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.spiritLeapOverlay.showMap")) + .binding(defaults.dungeons.spiritLeapOverlay.showMap, + () -> config.dungeons.spiritLeapOverlay.showMap, + newValue -> config.dungeons.spiritLeapOverlay.showMap = newValue) + .controller(ConfigUtils::createBooleanController) + .build()) + .option(Option.createBuilder() + .name(Text.translatable("skyblocker.config.dungeons.spiritLeapOverlay.scale")) + .binding(defaults.dungeons.spiritLeapOverlay.scale, + () -> config.dungeons.spiritLeapOverlay.scale, + newValue -> config.dungeons.spiritLeapOverlay.scale = newValue) + .controller(opt -> FloatSliderControllerBuilder.create(opt).range(1f, 2f).step(0.05f).formatValue(ConfigUtils.FLOAT_TWO_FORMATTER)) + .build()) + .build()) + // Puzzle Solver .group(OptionGroup.createBuilder() .name(Text.translatable("skyblocker.config.dungeons.puzzle")) diff --git a/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java index 60de6b8a87..688bc73bad 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java @@ -21,9 +21,6 @@ public class DungeonsConfig { @SerialEntry public boolean classBasedPlayerGlow = true; - @SerialEntry - public boolean spiritLeapOverlay = true; - @SerialEntry public boolean starredMobGlow = false; @@ -39,6 +36,9 @@ public class DungeonsConfig { @SerialEntry public DungeonMap dungeonMap = new DungeonMap(); + @SerialEntry + public SpiritLeapOverlay spiritLeapOverlay = new SpiritLeapOverlay(); + @SerialEntry public PuzzleSolvers puzzleSolvers = new PuzzleSolvers(); @@ -92,6 +92,17 @@ public static class DungeonMap { public int mapY = 2; } + public static class SpiritLeapOverlay { + @SerialEntry + public boolean enableLeapOverlay = true; + + @SerialEntry + public boolean showMap = true; + + @SerialEntry + public float scale = 1.2f; + } + public static class PuzzleSolvers { @SerialEntry public boolean solveTicTacToe = true; diff --git a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenProviderMixin.java b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenProviderMixin.java index 5d04fea46b..744e865d97 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenProviderMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenProviderMixin.java @@ -105,7 +105,7 @@ public interface HandledScreenProviderMixin { } // Leap Overlay - case GenericContainerScreenHandler containerScreenHandler when Utils.isInDungeons() && SkyblockerConfigManager.get().dungeons.spiritLeapOverlay && nameLowercase.contains(LeapOverlay.TITLE.toLowerCase()) -> { + case GenericContainerScreenHandler containerScreenHandler when Utils.isInDungeons() && SkyblockerConfigManager.get().dungeons.spiritLeapOverlay.enableLeapOverlay && nameLowercase.contains(LeapOverlay.TITLE.toLowerCase()) -> { client.player.currentScreenHandler = containerScreenHandler; client.setScreen(new LeapOverlay(containerScreenHandler)); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java index 5f7777729d..d7c6b00ccd 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java @@ -3,13 +3,15 @@ import java.util.*; import java.util.function.Supplier; -import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; import de.hysky.skyblocker.SkyblockerMod; +import de.hysky.skyblocker.config.SkyblockerConfigManager; +import de.hysky.skyblocker.config.configs.DungeonsConfig; import de.hysky.skyblocker.mixins.accessors.MapStateAccessor; +import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonPlayerManager; import de.hysky.skyblocker.utils.ItemUtils; import net.minecraft.client.MinecraftClient; @@ -21,6 +23,7 @@ import net.minecraft.client.gui.widget.SimplePositioningWidget; import net.minecraft.client.realms.util.RealmsUtil; import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.util.math.MatrixStack; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.ProfileComponent; import net.minecraft.item.FilledMapItem; @@ -40,6 +43,7 @@ public class LeapOverlay extends Screen implements ScreenHandlerListener { private static final MinecraftClient CLIENT = MinecraftClient.getInstance(); private static final Identifier BUTTON = Identifier.of(SkyblockerMod.NAMESPACE, "button/button"); private static final Identifier BUTTON_HIGHLIGHTED = Identifier.of(SkyblockerMod.NAMESPACE, "button/button_highlighted"); + private static final DungeonsConfig.SpiritLeapOverlay CONFIG = SkyblockerConfigManager.get().dungeons.spiritLeapOverlay; private static final int BUTTON_SPACING = 8; private static final int BUTTON_WIDTH = 130; private static final int BUTTON_HEIGHT = 50; @@ -57,6 +61,10 @@ public LeapOverlay(GenericContainerScreenHandler handler) { handler.addListener(this); } + public static boolean shouldShowMap() { + return DungeonManager.isClearingDungeon() && CONFIG.showMap; + } + @Override protected void init() { GridWidget gridWidget = new GridWidget(); @@ -65,11 +73,11 @@ protected void init() { Adder adder = gridWidget.createAdder(2); for (PlayerReference reference : references) { - adder.add(new PlayerButton(0, 0, BUTTON_WIDTH, BUTTON_HEIGHT, reference)); + adder.add(new PlayerButton(0, 0, (int) (BUTTON_WIDTH * CONFIG.scale), (int) (BUTTON_HEIGHT * CONFIG.scale), reference)); } gridWidget.refreshPositions(); - SimplePositioningWidget.setPos(gridWidget, 0, 0, this.width, this.height, 0.5f, DungeonManager.isClearingDungeon() ? 0.75f : 0.5f); + SimplePositioningWidget.setPos(gridWidget, 0, 0, this.width, this.height, 0.5f, shouldShowMap() ? 0.75f : 0.5f); gridWidget.forEachChild(this::addDrawableChild); } @@ -110,7 +118,7 @@ private void updateReference(PlayerReference reference) { public void render(DrawContext context, int mouseX, int mouseY, float delta) { super.render(context, mouseX, mouseY, delta); - if (DungeonManager.isClearingDungeon()) { + if (shouldShowMap()) { int x = (width >> 1) - 64; int y = (height >> 2) - 64; hovered = DungeonMap.render(context, x, y, 1, true, mouseX - x, mouseY - y, hoveredElement(mouseX, mouseY).filter(PlayerButton.class::isInstance).map(PlayerButton.class::cast).map(p -> p.reference.uuid()).orElse(null)); @@ -120,7 +128,7 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (DungeonManager.isClearingDungeon()) { + if (shouldShowMap()) { int x = (width >> 1) - 64; int y = (height >> 2) - 64; if (x <= mouseX && mouseX <= x + 128 && y <= mouseY && mouseY <= y + 128) { @@ -174,7 +182,7 @@ public void removed() { private class PlayerButton extends ButtonWidget { private static final int BORDER_THICKNESS = 2; - private static final int HEAD_SIZE = 32; + private static final int HEAD_SIZE = 24; private final PlayerReference reference; private PlayerButton(int x, int y, int width, int height, PlayerReference reference) { @@ -187,23 +195,37 @@ protected void renderWidget(DrawContext context, int mouseX, int mouseY, float d Identifier texture = this.isSelected() || reference.uuid().equals(LeapOverlay.this.hovered) ? BUTTON_HIGHLIGHTED : BUTTON; context.drawGuiTexture(RenderLayer::getGuiTextured, texture, this.getX(), this.getY(), this.getWidth(), this.getHeight()); + MatrixStack matrices = context.getMatrices(); + float scale = CONFIG.scale; int baseX = this.getX() + BORDER_THICKNESS; int centreX = this.getX() + (this.getWidth() >> 1); int centreY = this.getY() + (this.getHeight() >> 1); - int halfFontHeight = CLIENT.textRenderer.fontHeight >> 1; + int halfFontHeight = (int) (CLIENT.textRenderer.fontHeight * scale) >> 1; //Draw Player Head - RealmsUtil.drawPlayerHead(context, baseX + 4, centreY - (HEAD_SIZE >> 1), HEAD_SIZE, reference.uuid()); + RealmsUtil.drawPlayerHead(context, baseX + 4, centreY - ((int) (HEAD_SIZE * scale) >> 1), (int) (HEAD_SIZE * scale), reference.uuid()); //Draw class as heading - context.drawCenteredTextWithShadow(CLIENT.textRenderer, reference.dungeonClass().displayName(), centreX, this.getY() + halfFontHeight, ColorHelper.fullAlpha(reference.dungeonClass().color())); + matrices.push(); + matrices.translate(centreX, this.getY() + halfFontHeight, 0f); + matrices.scale(scale, scale, 1f); + context.drawCenteredTextWithShadow(CLIENT.textRenderer, reference.dungeonClass().displayName(), 0, 0, ColorHelper.fullAlpha(reference.dungeonClass().color())); + matrices.pop(); //Draw name next to head - context.drawTextWithShadow(CLIENT.textRenderer, Text.literal(reference.name()), baseX + HEAD_SIZE + 8, centreY - halfFontHeight, Colors.WHITE); + matrices.push(); + matrices.translate(baseX + HEAD_SIZE * scale + 8, centreY - halfFontHeight, 0f); + matrices.scale(scale, scale, 1f); + context.drawTextWithShadow(CLIENT.textRenderer, Text.literal(reference.name()), 0, 0, Colors.WHITE); + matrices.pop(); if (reference.status() != null) { //Text - context.drawCenteredTextWithShadow(CLIENT.textRenderer, reference.status().text.get(), centreX, this.getY() + this.getHeight() - (halfFontHeight * 3), Colors.WHITE); + matrices.push(); + matrices.translate(centreX, this.getY() + this.getHeight() - (halfFontHeight * 3), 0f); + matrices.scale(scale, scale, 1f); + context.drawCenteredTextWithShadow(CLIENT.textRenderer, reference.status().text.get(), 0, 0, Colors.WHITE); + matrices.pop(); //Overlay context.fill(this.getX(), this.getY(), this.getX() + this.getWidth(), this.getY() + this.getHeight(), reference.status().overlayColor); diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json index cf8595d1ab..46b46e51af 100644 --- a/src/main/resources/assets/skyblocker/lang/en_us.json +++ b/src/main/resources/assets/skyblocker/lang/en_us.json @@ -225,7 +225,10 @@ "skyblocker.config.dungeons.secretWaypoints.waypointType": "Waypoint Type", "skyblocker.config.dungeons.spiritLeapOverlay": "Spirit Leap Overlay", - "skyblocker.config.dungeons.spiritLeapOverlay.@Tooltip": "Shows a custom overlay for the Spirit Leap screen that makes leaping to teammates easy and consistent.", + "skyblocker.config.dungeons.spiritLeapOverlay.enableLeapOverlay": "Enable Spirit Leap Overlay", + "skyblocker.config.dungeons.spiritLeapOverlay.enableLeapOverlay.@Tooltip": "Shows a custom overlay for the Spirit Leap screen that makes leaping to teammates easy and consistent.", + "skyblocker.config.dungeons.spiritLeapOverlay.showMap": "Show Dungeon Map in Spirit Leap Overlay", + "skyblocker.config.dungeons.spiritLeapOverlay.scale": "Spirit Leap Overlay Scale", "skyblocker.config.dungeons.starredMobBoundingBoxes": "Starred Mob Bounding Boxes", "skyblocker.config.dungeons.starredMobBoundingBoxes.@Tooltip": "Draws the bounding boxes of starred mobs.", From 01489086aaca7c98ed74ccef32549deda2587f19 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Mon, 7 Apr 2025 17:41:57 -0400 Subject: [PATCH 09/14] Add layout widget --- .../skyblock/dungeon/DungeonMap.java | 10 ++- .../skyblock/dungeon/LeapOverlay.java | 78 +++++++++---------- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java index dead81976b..c00bc0b9d6 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java @@ -133,7 +133,7 @@ public static UUID render(DrawContext context, int x, int y, float scale, boolea vertices.draw(); UUID hoveredHead = null; - if (fancy) hoveredHead = renderPlayerHeads(context, state, mouseX, mouseY, enlarge); + if (fancy) hoveredHead = renderPlayerHeads(context, state, mouseX / scale, mouseY / scale, enlarge); context.getMatrices().pop(); return hoveredHead; } @@ -146,7 +146,7 @@ public static MapIdComponent getMapIdComponent(ItemStack stack) { } else return cachedMapIdComponent != null ? cachedMapIdComponent : DEFAULT_MAP_ID_COMPONENT; } - private static UUID renderPlayerHeads(DrawContext context, MapState state, int mouseX, int mouseY, @Nullable UUID enlarge) { + private static UUID renderPlayerHeads(DrawContext context, MapState state, double mouseX, double mouseY, @Nullable UUID enlarge) { if (!DungeonManager.isClearingDungeon()) return null; UUID hovered = null; @@ -162,7 +162,7 @@ private static UUID renderPlayerHeads(DrawContext context, MapState state, int m if (player.uuid().equals(enlarge)) { // Enlarge the player head when the corresponding button is hovered context.getMatrices().scale(2, 2, 1); - } else if (hovered == null && player.mapPos().distanceSquared(mouseX, mouseY) < 16) { + } else if (hovered == null && isPlayerHovered(player, mouseX, mouseY)) { // Enlarge the player head when hovered context.getMatrices().scale(2, 2, 1); hovered = player.uuid(); @@ -175,6 +175,10 @@ private static UUID renderPlayerHeads(DrawContext context, MapState state, int m return hovered; } + public static boolean isPlayerHovered(PlayerRenderState player, double mouseX, double mouseY) { + return player.mapPos().distanceSquared(mouseX, mouseY) < 16; + } + private static void reset() { cachedMapIdComponent = null; mapPlayers.clear(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java index d7c6b00ccd..796a5869f7 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java @@ -17,10 +17,9 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.client.gui.widget.GridWidget; +import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; +import net.minecraft.client.gui.widget.*; import net.minecraft.client.gui.widget.GridWidget.Adder; -import net.minecraft.client.gui.widget.SimplePositioningWidget; import net.minecraft.client.realms.util.RealmsUtil; import net.minecraft.client.render.RenderLayer; import net.minecraft.client.util.math.MatrixStack; @@ -67,18 +66,21 @@ public static boolean shouldShowMap() { @Override protected void init() { - GridWidget gridWidget = new GridWidget(); - gridWidget.setSpacing(BUTTON_SPACING); + DirectionalLayoutWidget layout = DirectionalLayoutWidget.vertical(); + layout.spacing(32).getMainPositioner().alignHorizontalCenter(); - Adder adder = gridWidget.createAdder(2); + if (shouldShowMap()) layout.add(new MapWidget(0, 0)); + GridWidget gridWidget = new GridWidget().setSpacing(BUTTON_SPACING); + Adder adder = gridWidget.createAdder(2); for (PlayerReference reference : references) { adder.add(new PlayerButton(0, 0, (int) (BUTTON_WIDTH * CONFIG.scale), (int) (BUTTON_HEIGHT * CONFIG.scale), reference)); } + layout.add(gridWidget); - gridWidget.refreshPositions(); - SimplePositioningWidget.setPos(gridWidget, 0, 0, this.width, this.height, 0.5f, shouldShowMap() ? 0.75f : 0.5f); - gridWidget.forEachChild(this::addDrawableChild); + layout.refreshPositions(); + SimplePositioningWidget.setPos(layout, 0, 0, this.width, this.height); + layout.forEachChild(this::addDrawableChild); } @Override @@ -114,38 +116,6 @@ private void updateReference(PlayerReference reference) { clearAndInit(); } - @Override - public void render(DrawContext context, int mouseX, int mouseY, float delta) { - super.render(context, mouseX, mouseY, delta); - - if (shouldShowMap()) { - int x = (width >> 1) - 64; - int y = (height >> 2) - 64; - hovered = DungeonMap.render(context, x, y, 1, true, mouseX - x, mouseY - y, hoveredElement(mouseX, mouseY).filter(PlayerButton.class::isInstance).map(PlayerButton.class::cast).map(p -> p.reference.uuid()).orElse(null)); - context.drawBorder(x, y, 128, 128, -1); - } - } - - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - if (shouldShowMap()) { - int x = (width >> 1) - 64; - int y = (height >> 2) - 64; - if (x <= mouseX && mouseX <= x + 128 && y <= mouseY && mouseY <= y + 128) { - assert client != null && client.player != null && client.interactionManager != null; - Optional.ofNullable(FilledMapItem.getMapState(DungeonMap.getMapIdComponent(client.player.getInventory().main.get(8)), client.world)) - .stream().map(MapStateAccessor.class::cast).map(MapStateAccessor::getDecorations).map(Map::entrySet).flatMap(Set::stream) - .map(DungeonMap.PlayerRenderState::of) - .filter(Objects::nonNull).filter(player -> player.mapPos().distanceSquared(mouseX - x, mouseY - y) <= 16) - .flatMap(player -> references.stream().filter(ref -> ref.uuid().equals(player.uuid()))) - .findAny().ifPresent(ref -> client.interactionManager.clickSlot(ref.syncId(), ref.slotId(), GLFW.GLFW_MOUSE_BUTTON_LEFT, SlotActionType.PICKUP, client.player)); - return true; - } - } - - return super.mouseClicked(mouseX, mouseY, button); - } - @Override public boolean keyPressed(int keyCode, int scanCode, int modifiers) { if (super.keyPressed(keyCode, scanCode, modifiers)) { @@ -180,6 +150,32 @@ public void removed() { } } + public class MapWidget extends ClickableWidget { + public MapWidget(int x, int y) { + super(x, y, (int) (128 * CONFIG.scale), (int) (128 * CONFIG.scale), Text.translatable("skyblocker.config.dungeons.map.fancyMap")); + } + + @Override + protected void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) { + LeapOverlay.this.hovered = DungeonMap.render(context, getX(), getY(), CONFIG.scale, true, mouseX - getX(), mouseY - getY(), hoveredElement(mouseX, mouseY).filter(PlayerButton.class::isInstance).map(PlayerButton.class::cast).map(p -> p.reference.uuid()).orElse(null)); + context.drawBorder(getX(), getY(), (int) (128 * CONFIG.scale), (int) (128 * CONFIG.scale), -1); + } + + @Override + public void onClick(double mouseX, double mouseY) { + assert client != null && client.player != null && client.interactionManager != null; + Optional.ofNullable(FilledMapItem.getMapState(DungeonMap.getMapIdComponent(client.player.getInventory().main.get(8)), client.world)) + .stream().map(MapStateAccessor.class::cast).map(MapStateAccessor::getDecorations).map(Map::entrySet).flatMap(Set::stream) + .map(DungeonMap.PlayerRenderState::of) + .filter(Objects::nonNull).filter(player -> DungeonMap.isPlayerHovered(player, (mouseX - getX()) / CONFIG.scale, (mouseY - getY()) / CONFIG.scale)) + .flatMap(player -> references.stream().filter(ref -> ref.uuid().equals(player.uuid()))) + .findAny().ifPresent(ref -> client.interactionManager.clickSlot(ref.syncId(), ref.slotId(), GLFW.GLFW_MOUSE_BUTTON_LEFT, SlotActionType.PICKUP, client.player)); + } + + @Override + protected void appendClickableNarrations(NarrationMessageBuilder builder) {} + } + private class PlayerButton extends ButtonWidget { private static final int BORDER_THICKNESS = 2; private static final int HEAD_SIZE = 24; From f7f81ecfbb095b8449a776805600355435acc807 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Tue, 8 Apr 2025 14:50:04 -0400 Subject: [PATCH 10/14] Add cache invalidation * keep only the past 100 player matches (5 seconds) --- .../skyblock/dungeon/DungeonMap.java | 61 ++++++++++---- .../skyblock/dungeon/LeapOverlay.java | 4 +- .../DungeonMapPlayerMatchDataTest.java | 83 +++++++++++++++++++ 3 files changed, 129 insertions(+), 19 deletions(-) create mode 100644 src/test/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapPlayerMatchDataTest.java diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java index c00bc0b9d6..70ca6f7046 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java @@ -41,10 +41,7 @@ import org.joml.Vector2d; import org.joml.Vector2dc; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; +import java.util.*; public class DungeonMap { private static final Identifier DUNGEON_MAP = Identifier.of(SkyblockerMod.NAMESPACE, "dungeon_map"); @@ -56,7 +53,7 @@ public class DungeonMap { * This does so by counting how many times a map decoration and a player was closest to each other. * The higher the number, the more likely that the map decoration is the player. */ - private static final Map, MutableInt>> mapPlayers = HashMap.newHashMap(5); + private static final Map>> mapPlayers = HashMap.newHashMap(5); @Init public static void init() { @@ -98,7 +95,7 @@ private static void update() { .filter(e -> e.getValue().type() == MapDecorationTypes.FRAME || e.getValue().type() == MapDecorationTypes.BLUE_MARKER) .filter(e -> mapPos.distanceSquared(e.getValue().x() / 2d + 64, e.getValue().z() / 2d + 64) <= 8) .min(Comparator.comparingDouble(e -> mapPos.distanceSquared(e.getValue().x() / 2d + 64, e.getValue().z() / 2d + 64))) - .ifPresent(e -> mapPlayers.computeIfAbsent(e.getKey(), _key -> new HashMap<>()).computeIfAbsent(Pair.of(player.getUuid(), player.getGameProfile().getName()), _key -> new MutableInt(0)).increment()); + .ifPresent(e -> mapPlayers.computeIfAbsent(e.getKey(), _key -> new PlayerMatchData<>()).addMatch(Pair.of(player.getUuid(), player.getGameProfile().getName()))); } } @@ -151,7 +148,7 @@ private static UUID renderPlayerHeads(DrawContext context, MapState state, doubl UUID hovered = null; for (Map.Entry mapDecoration : ((MapStateAccessor) state).getDecorations().entrySet()) { - PlayerRenderState player = PlayerRenderState.of(mapDecoration); + PlayerRenderState player = PlayerRenderState.of(mapDecoration).orElse(null); if (player == null || player.uuid().equals(MinecraftClient.getInstance().player.getUuid()) && !SkyblockerConfigManager.get().dungeons.dungeonMap.showSelfHead) continue; DungeonClass dungeonClass = DungeonPlayerManager.getClassFromPlayer(player.name()); @@ -184,18 +181,48 @@ private static void reset() { mapPlayers.clear(); } + /** + * Data structure that stores the past 100 matches of type {@code T} and the number of times each instance of {@code T} was matched. + */ + public record PlayerMatchData(Queue matches, Map counts) { + private static final int MAX_MATCHES = 100; + + public PlayerMatchData() { + this(new ArrayDeque<>(MAX_MATCHES), new HashMap<>()); + } + + public void addMatch(T newEntry) { + // Remove the oldest entry if the queue is full + if (matches.size() >= MAX_MATCHES) { + T remove = matches.poll(); + if (counts.get(remove) instanceof MutableInt count && count.decrementAndGet() <= 0) { + counts.remove(remove); + } + } + // Add the new entry to the queue and increment its count in the map + matches.add(newEntry); + counts.computeIfAbsent(newEntry, _key -> new MutableInt()).increment(); + } + + public Optional getMostFrequent() { + return counts.entrySet().stream() + .max(Map.Entry.comparingByValue()) + .map(Map.Entry::getKey); + } + } + public record PlayerRenderState(UUID uuid, String name, Vector2dc mapPos, float deg) { - public static PlayerRenderState of(Map.Entry mapDecoration) { - if (!mapPlayers.containsKey(mapDecoration.getKey())) return null; + public static Optional of(Map.Entry mapDecoration) { + if (!mapPlayers.containsKey(mapDecoration.getKey())) return Optional.empty(); // Get the player uuid and name pair with the highest count (therefore most likely to be the correct player) - Pair mapPlayer = mapPlayers.get(mapDecoration.getKey()).entrySet().stream() - .max(Map.Entry.comparingByValue()).orElseThrow().getKey(); - // Use the player entity if it exists, since it gives the most accurate position and rotation - PlayerEntity player = MinecraftClient.getInstance().world.getPlayerByUuid(mapPlayer.left()); - Vector2dc mapPos = player != null ? DungeonMapUtils.getMapPosFromPhysical(DungeonManager.getPhysicalEntrancePos(), DungeonManager.getMapEntrancePos(), DungeonManager.getMapRoomSize(), player.getPos()) : new Vector2d(mapDecoration.getValue().x() / 2d + 64, mapDecoration.getValue().z() / 2d + 64); - float deg = player != null ? player.getYaw() : mapDecoration.getValue().rotation() * 360 / 16.0F; - - return new PlayerRenderState(mapPlayer.left(), mapPlayer.right(), mapPos, deg); + return mapPlayers.get(mapDecoration.getKey()).getMostFrequent().map(mapPlayer -> { + // Use the player entity if it exists, since it gives the most accurate position and rotation + PlayerEntity player = MinecraftClient.getInstance().world.getPlayerByUuid(mapPlayer.left()); + Vector2dc mapPos = player != null ? DungeonMapUtils.getMapPosFromPhysical(DungeonManager.getPhysicalEntrancePos(), DungeonManager.getMapEntrancePos(), DungeonManager.getMapRoomSize(), player.getPos()) : new Vector2d(mapDecoration.getValue().x() / 2d + 64, mapDecoration.getValue().z() / 2d + 64); + float deg = player != null ? player.getYaw() : mapDecoration.getValue().rotation() * 360 / 16.0F; + + return new PlayerRenderState(mapPlayer.left(), mapPlayer.right(), mapPos, deg); + }); } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java index 796a5869f7..01769ac331 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java @@ -166,8 +166,8 @@ public void onClick(double mouseX, double mouseY) { assert client != null && client.player != null && client.interactionManager != null; Optional.ofNullable(FilledMapItem.getMapState(DungeonMap.getMapIdComponent(client.player.getInventory().main.get(8)), client.world)) .stream().map(MapStateAccessor.class::cast).map(MapStateAccessor::getDecorations).map(Map::entrySet).flatMap(Set::stream) - .map(DungeonMap.PlayerRenderState::of) - .filter(Objects::nonNull).filter(player -> DungeonMap.isPlayerHovered(player, (mouseX - getX()) / CONFIG.scale, (mouseY - getY()) / CONFIG.scale)) + .map(DungeonMap.PlayerRenderState::of).flatMap(Optional::stream) + .filter(player -> DungeonMap.isPlayerHovered(player, (mouseX - getX()) / CONFIG.scale, (mouseY - getY()) / CONFIG.scale)) .flatMap(player -> references.stream().filter(ref -> ref.uuid().equals(player.uuid()))) .findAny().ifPresent(ref -> client.interactionManager.clickSlot(ref.syncId(), ref.slotId(), GLFW.GLFW_MOUSE_BUTTON_LEFT, SlotActionType.PICKUP, client.player)); } diff --git a/src/test/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapPlayerMatchDataTest.java b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapPlayerMatchDataTest.java new file mode 100644 index 0000000000..bea467632a --- /dev/null +++ b/src/test/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapPlayerMatchDataTest.java @@ -0,0 +1,83 @@ +package de.hysky.skyblocker.skyblock.dungeon; + +import it.unimi.dsi.fastutil.Pair; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.UUID; +import java.util.stream.IntStream; + +public class DungeonMapPlayerMatchDataTest { + private final DungeonMap.PlayerMatchData> playerMatchData = new DungeonMap.PlayerMatchData<>(); + + @Test + void testAddMatch() { + List> keys = IntStream.range(0, 10).mapToObj(i -> Pair.of(UUID.randomUUID(), String.valueOf(i))).toList(); + for (int i = 0; i < 10; i++) { + for (Pair key : keys) { + playerMatchData.addMatch(key); + } + Assertions.assertEquals(10 * (i + 1), playerMatchData.matches().size()); + Assertions.assertEquals(10, playerMatchData.counts().size()); + } + Assertions.assertEquals(100, playerMatchData.matches().size()); + Assertions.assertEquals(10, playerMatchData.counts().size()); + + playerMatchData.addMatch(keys.getFirst()); + Assertions.assertEquals(100, playerMatchData.matches().size()); + Assertions.assertEquals(10, playerMatchData.counts().size()); + + for (Pair key : keys) { + playerMatchData.addMatch(key); + } + Assertions.assertEquals(100, playerMatchData.matches().size()); + Assertions.assertEquals(10, playerMatchData.counts().size()); + } + + @Test + void testMostFrequent() { + List> keys = IntStream.range(0, 11).mapToObj(i -> Pair.of(UUID.randomUUID(), String.valueOf(i))).toList(); + playerMatchData.addMatch(keys.getFirst()); + for (int i = 0; i < keys.size(); i++) { + Pair key = keys.get(i); + for (int j = 0; j < 9; j++) { + playerMatchData.addMatch(key); + } + Assertions.assertEquals(9 * (i + 1) + 1, playerMatchData.matches().size()); + Assertions.assertEquals(i + 1, playerMatchData.counts().size()); + Assertions.assertTrue(playerMatchData.getMostFrequent().isPresent()); + Assertions.assertEquals(keys.getFirst(), playerMatchData.getMostFrequent().get()); + } + + playerMatchData.addMatch(keys.get(1)); + Assertions.assertEquals(100, playerMatchData.matches().size()); + Assertions.assertEquals(11, playerMatchData.counts().size()); + Assertions.assertTrue(playerMatchData.getMostFrequent().isPresent()); + Assertions.assertEquals(keys.get(1), playerMatchData.getMostFrequent().get()); + } + + @Test + void testRemove() { + List> keys = IntStream.range(0, 2).mapToObj(i -> Pair.of(UUID.randomUUID(), String.valueOf(i))).toList(); + Assertions.assertEquals(0, playerMatchData.matches().size()); + Assertions.assertEquals(0, playerMatchData.counts().size()); + Assertions.assertTrue(playerMatchData.getMostFrequent().isEmpty()); + + for (int i = 0; i < 100; i++) { + playerMatchData.addMatch(keys.getFirst()); + } + Assertions.assertEquals(100, playerMatchData.matches().size()); + Assertions.assertEquals(1, playerMatchData.counts().size()); + Assertions.assertTrue(playerMatchData.getMostFrequent().isPresent()); + Assertions.assertEquals(keys.getFirst(), playerMatchData.getMostFrequent().get()); + + for (int i = 0; i < 100; i++) { + playerMatchData.addMatch(keys.getLast()); + } + Assertions.assertEquals(100, playerMatchData.matches().size()); + Assertions.assertEquals(1, playerMatchData.counts().size()); + Assertions.assertTrue(playerMatchData.getMostFrequent().isPresent()); + Assertions.assertEquals(keys.getLast(), playerMatchData.getMostFrequent().get()); + } +} From cba3d563840de8cd308a95dcc0b74b8a8f0f7921 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Tue, 15 Apr 2025 12:01:00 -0400 Subject: [PATCH 11/14] Add player head render helper and clean up RenderHelper --- .../skyblocker/config/HudConfigScreen.java | 4 +- .../skyblocker/skyblock/FishingHelper.java | 3 +- .../crimson/kuudra/ArrowPoisonWarning.java | 6 +-- .../crimson/kuudra/DangerWarning.java | 3 +- .../skyblock/dungeon/DungeonMap.java | 4 +- .../dungeon/DungeonMapConfigScreen.java | 6 +-- .../skyblock/dungeon/LeapOverlay.java | 4 +- .../dungeon/puzzle/boulder/Boulder.java | 3 +- .../skyblock/events/JacobEventToast.java | 4 +- .../skyblock/fancybars/StatusBar.java | 6 +-- .../SkyblockCraftingRecipeResults.java | 4 +- .../recipebook/UpcomingEventsTab.java | 6 +-- .../dungeons/DungeonClassWidget.java | 4 +- .../profileviewer/skills/SkillWidget.java | 4 +- .../profileviewer/slayers/SlayerWidget.java | 4 +- .../skyblock/rift/HealingMelonIndicator.java | 5 +- .../boss/demonlord/FirePillarAnnouncer.java | 3 +- .../slayers/boss/vampire/ManiaIndicator.java | 3 +- .../slayers/boss/vampire/StakeIndicator.java | 3 +- .../boss/vampire/TwinClawsIndicator.java | 3 +- .../skyblocker/utils/render/HudHelper.java | 46 +++++++++++++++++ .../skyblocker/utils/render/RenderHelper.java | 49 ------------------- .../utils/render/title/TitleContainer.java | 45 +++++++++++++++-- 23 files changed, 127 insertions(+), 95 deletions(-) create mode 100644 src/main/java/de/hysky/skyblocker/utils/render/HudHelper.java diff --git a/src/main/java/de/hysky/skyblocker/config/HudConfigScreen.java b/src/main/java/de/hysky/skyblocker/config/HudConfigScreen.java index 06bec73751..94a3981001 100644 --- a/src/main/java/de/hysky/skyblocker/config/HudConfigScreen.java +++ b/src/main/java/de/hysky/skyblocker/config/HudConfigScreen.java @@ -1,6 +1,6 @@ package de.hysky.skyblocker.config; -import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.render.HudHelper; import de.hysky.skyblocker.utils.render.gui.AbstractWidget; import it.unimi.dsi.fastutil.ints.IntIntMutablePair; import net.minecraft.client.gui.DrawContext; @@ -84,7 +84,7 @@ public final boolean mouseDragged(double mouseX, double mouseY, int button, doub public final boolean mouseClicked(double mouseX, double mouseY, int button) { if (button == 0) { for (AbstractWidget widget : widgets) { - if (RenderHelper.pointIsInArea(mouseX, mouseY, widget.getX() + getWidgetXOffset(widget), widget.getY(), widget.getX() + getWidgetXOffset(widget) + widget.getWidth(), widget.getY() + widget.getHeight())) { + if (HudHelper.pointIsInArea(mouseX, mouseY, widget.getX() + getWidgetXOffset(widget), widget.getY(), widget.getX() + getWidgetXOffset(widget) + widget.getWidth(), widget.getY() + widget.getHeight())) { draggingWidget = widget; mouseClickRelativeX = mouseX - widget.getX() - getWidgetXOffset(widget); mouseClickRelativeY = mouseY - widget.getY(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/FishingHelper.java b/src/main/java/de/hysky/skyblocker/skyblock/FishingHelper.java index dacce71346..3e24be47ec 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/FishingHelper.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/FishingHelper.java @@ -5,6 +5,7 @@ import de.hysky.skyblocker.utils.Utils; import de.hysky.skyblocker.utils.render.RenderHelper; import de.hysky.skyblocker.utils.render.title.Title; +import de.hysky.skyblocker.utils.render.title.TitleContainer; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.fabricmc.fabric.api.event.player.UseItemCallback; @@ -70,7 +71,7 @@ public static void onSound(PlaySoundS2CPacket packet) { if (player != null && player.fishHook != null) { Vec3d soundToFishHook = player.fishHook.getPos().subtract(packet.getX(), 0, packet.getZ()); if (Math.abs(normalYawVector.x * soundToFishHook.z - normalYawVector.z * soundToFishHook.x) < 0.2D && Math.abs(normalYawVector.dotProduct(soundToFishHook)) < 4D && player.squaredDistanceTo(packet.getX(), packet.getY(), packet.getZ()) > 1D) { - RenderHelper.displayInTitleContainerAndPlaySound(title, 10); + TitleContainer.addTitleAndPlaySound(title, 10); resetFish(); } } else { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/ArrowPoisonWarning.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/ArrowPoisonWarning.java index c0d371deb4..17f6416c83 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/ArrowPoisonWarning.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/ArrowPoisonWarning.java @@ -7,8 +7,8 @@ import de.hysky.skyblocker.skyblock.crimson.kuudra.Kuudra.KuudraPhase; import de.hysky.skyblocker.utils.ItemUtils; import de.hysky.skyblocker.utils.Utils; -import de.hysky.skyblocker.utils.render.RenderHelper; import de.hysky.skyblocker.utils.render.title.Title; +import de.hysky.skyblocker.utils.render.title.TitleContainer; import net.minecraft.client.MinecraftClient; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.BowItem; @@ -44,9 +44,9 @@ public static void tryWarn(int newSlot) { } if (!hasToxicArrowPoison) { - RenderHelper.displayInTitleContainerAndPlaySound(NONE_TITLE, THREE_SECONDS); + TitleContainer.addTitleAndPlaySound(NONE_TITLE, THREE_SECONDS); } else if (arrowPoisonAmount < CONFIG.get().arrowPoisonThreshold) { - RenderHelper.displayInTitleContainerAndPlaySound(LOW_TITLE, THREE_SECONDS); + TitleContainer.addTitleAndPlaySound(LOW_TITLE, THREE_SECONDS); } } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/DangerWarning.java b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/DangerWarning.java index 80028405e8..db9e1e962a 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/DangerWarning.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/crimson/kuudra/DangerWarning.java @@ -5,7 +5,6 @@ import de.hysky.skyblocker.annotations.Init; import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Utils; -import de.hysky.skyblocker.utils.render.RenderHelper; import de.hysky.skyblocker.utils.render.title.Title; import de.hysky.skyblocker.utils.render.title.TitleContainer; import de.hysky.skyblocker.utils.scheduler.Scheduler; @@ -37,7 +36,7 @@ private static void updateIndicator() { Title title = getDangerTitle(under); if (title != null) { - RenderHelper.displayInTitleContainerAndPlaySound(title); + TitleContainer.addTitleAndPlaySound(title); return; } else if (i == 5) { //Prevent removing the title prematurely diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java index 70ca6f7046..41c0e7f4f4 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java @@ -9,6 +9,7 @@ import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonMapUtils; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonPlayerManager; import de.hysky.skyblocker.utils.Utils; +import de.hysky.skyblocker.utils.render.HudHelper; import de.hysky.skyblocker.utils.scheduler.Scheduler; import it.unimi.dsi.fastutil.Pair; import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager; @@ -18,7 +19,6 @@ import net.fabricmc.fabric.api.client.rendering.v1.IdentifiedLayer; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.realms.util.RealmsUtil; import net.minecraft.client.render.LightmapTextureManager; import net.minecraft.client.render.MapRenderState; import net.minecraft.client.render.MapRenderer; @@ -164,7 +164,7 @@ private static UUID renderPlayerHeads(DrawContext context, MapState state, doubl context.getMatrices().scale(2, 2, 1); hovered = player.uuid(); } - RealmsUtil.drawPlayerHead(context, -4, -4, 8, player.uuid()); + HudHelper.drawPlayerHead(context, -4, -4, 8, player.uuid()); context.drawBorder(-5, -5, 10, 10, ColorHelper.fullAlpha(dungeonClass.color())); context.fill(-1, -7, 1, -5, ColorHelper.fullAlpha(dungeonClass.color())); context.getMatrices().pop(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java index ee3f747a14..357f6dcf5e 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMapConfigScreen.java @@ -1,7 +1,7 @@ package de.hysky.skyblocker.skyblock.dungeon; import de.hysky.skyblocker.config.SkyblockerConfigManager; -import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.render.HudHelper; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.render.RenderLayer; @@ -42,10 +42,10 @@ public boolean mouseDragged(double mouseX, double mouseY, int button, double del float scoreScaling = SkyblockerConfigManager.get().dungeons.dungeonScore.scoreScaling; int scoreWidth = (int) (textRenderer.getWidth(DungeonScoreHUD.getFormattedScoreText()) * scoreScaling); int scoreHeight = (int) (textRenderer.fontHeight * scoreScaling); - if (RenderHelper.pointIsInArea(mouseX, mouseY, mapX, mapY, mapX + mapSize, mapY + mapSize) && button == 0) { + if (HudHelper.pointIsInArea(mouseX, mouseY, mapX, mapY, mapX + mapSize, mapY + mapSize) && button == 0) { mapX = (int) Math.max(Math.min(mouseX - (mapSize >> 1), this.width - mapSize), 0); mapY = (int) Math.max(Math.min(mouseY - (mapSize >> 1), this.height - mapSize), 0); - } else if (RenderHelper.pointIsInArea(mouseX, mouseY, scoreX, scoreY, scoreX + scoreWidth, scoreY + scoreHeight) && button == 0) { + } else if (HudHelper.pointIsInArea(mouseX, mouseY, scoreX, scoreY, scoreX + scoreWidth, scoreY + scoreHeight) && button == 0) { scoreX = (int) Math.max(Math.min(mouseX - (scoreWidth >> 1), this.width - scoreWidth), 0); scoreY = (int) Math.max(Math.min(mouseY - (scoreHeight >> 1), this.height - scoreHeight), 0); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java index 01769ac331..c9990201eb 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java @@ -14,13 +14,13 @@ import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonManager; import de.hysky.skyblocker.skyblock.dungeon.secrets.DungeonPlayerManager; import de.hysky.skyblocker.utils.ItemUtils; +import de.hysky.skyblocker.utils.render.HudHelper; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder; import net.minecraft.client.gui.widget.*; import net.minecraft.client.gui.widget.GridWidget.Adder; -import net.minecraft.client.realms.util.RealmsUtil; import net.minecraft.client.render.RenderLayer; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.component.DataComponentTypes; @@ -199,7 +199,7 @@ protected void renderWidget(DrawContext context, int mouseX, int mouseY, float d int halfFontHeight = (int) (CLIENT.textRenderer.fontHeight * scale) >> 1; //Draw Player Head - RealmsUtil.drawPlayerHead(context, baseX + 4, centreY - ((int) (HEAD_SIZE * scale) >> 1), (int) (HEAD_SIZE * scale), reference.uuid()); + HudHelper.drawPlayerHead(context, baseX + 4, centreY - ((int) (HEAD_SIZE * scale) >> 1), (int) (HEAD_SIZE * scale), reference.uuid()); //Draw class as heading matrices.push(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/boulder/Boulder.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/boulder/Boulder.java index 1250b76364..af321b6259 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/boulder/Boulder.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/puzzle/boulder/Boulder.java @@ -8,6 +8,7 @@ import de.hysky.skyblocker.utils.ColorUtils; import de.hysky.skyblocker.utils.render.RenderHelper; import de.hysky.skyblocker.utils.render.title.Title; +import de.hysky.skyblocker.utils.render.title.TitleContainer; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.minecraft.block.Block; import net.minecraft.block.Blocks; @@ -119,7 +120,7 @@ public void tick(MinecraftClient client) { } else { // If no solution is found, display a title message and reset the puzzle Title title = new Title("skyblocker.dungeons.puzzle.boulder.noSolution", Formatting.GREEN); - RenderHelper.displayInTitleContainerAndPlaySound(title, 15); + TitleContainer.addTitleAndPlaySound(title, 15); reset(); } } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/events/JacobEventToast.java b/src/main/java/de/hysky/skyblocker/skyblock/events/JacobEventToast.java index 67e761a5fa..fa433eb07f 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/events/JacobEventToast.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/events/JacobEventToast.java @@ -1,7 +1,7 @@ package de.hysky.skyblocker.skyblock.events; import de.hysky.skyblocker.skyblock.tabhud.widget.JacobsContestWidget; -import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.render.HudHelper; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.render.RenderLayer; @@ -45,7 +45,7 @@ public void draw(DrawContext context, TextRenderer textRenderer, long startTime) // IDK how to make the items transparent, so I just redraw the texture on top matrices.push(); matrices.translate(0, 0, 400f); - RenderHelper.renderNineSliceColored(context, TEXTURE, 0, 0, getWidth(), getHeight(), ColorHelper.fromFloats((k >> 24) / 255f, 1f, 1f, 1f)); + HudHelper.renderNineSliceColored(context, TEXTURE, 0, 0, getWidth(), getHeight(), ColorHelper.fromFloats((k >> 24) / 255f, 1f, 1f, 1f)); matrices.pop(); y += textRenderer.fontHeight * message.size(); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBar.java b/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBar.java index 06c079a322..913cab55f0 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBar.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/fancybars/StatusBar.java @@ -5,7 +5,7 @@ import com.google.gson.JsonObject; import de.hysky.skyblocker.SkyblockerMod; -import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.render.HudHelper; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.*; @@ -136,11 +136,11 @@ public void render(DrawContext context, int mouseX, int mouseY, float delta) { int barWith = iconPosition.equals(IconPosition.OFF) ? width : width - 10; int barX = iconPosition.equals(IconPosition.LEFT) ? x + 10 : x; context.drawGuiTexture(RenderLayer::getGuiTextured, BAR_BACK, barX, y + 1, barWith, 7, transparency); - RenderHelper.renderNineSliceColored(context, BAR_FILL, barX + 1, y + 2, (int) ((barWith - 2) * fill), 5, transparency(colors[0].getRGB())); + HudHelper.renderNineSliceColored(context, BAR_FILL, barX + 1, y + 2, (int) ((barWith - 2) * fill), 5, transparency(colors[0].getRGB())); if (hasOverflow && overflowFill > 0) { - RenderHelper.renderNineSliceColored(context, BAR_FILL, barX + 1, y + 2, (int) ((barWith - 2) * Math.min(overflowFill, 1)), 5, transparency(colors[1].getRGB())); + HudHelper.renderNineSliceColored(context, BAR_FILL, barX + 1, y + 2, (int) ((barWith - 2) * Math.min(overflowFill, 1)), 5, transparency(colors[1].getRGB())); } //context.drawText(MinecraftClient.getInstance().textRenderer, gridX + " " + gridY + " s:" + size , x, y-9, Colors.WHITE, true); if (showText()) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/recipebook/SkyblockCraftingRecipeResults.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/recipebook/SkyblockCraftingRecipeResults.java index 834440a55d..29d90d8b15 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/recipebook/SkyblockCraftingRecipeResults.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/recipebook/SkyblockCraftingRecipeResults.java @@ -11,7 +11,7 @@ import de.hysky.skyblocker.skyblock.itemlist.ItemRepository; import de.hysky.skyblocker.skyblock.itemlist.SkyblockCraftingRecipe; import de.hysky.skyblocker.utils.ItemUtils; -import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.render.HudHelper; import de.hysky.skyblocker.utils.scheduler.MessageScheduler; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; @@ -168,7 +168,7 @@ public void drawTooltip(DrawContext context, int x, int y) { * Returns true if the mouse is hovering over the text at this location. */ private boolean isMouseHoveringText(int textX, int textY, int mouseX, int mouseY) { - return RenderHelper.pointIsInArea(mouseX, mouseY, textX, textY, textX + MAX_TEXT_WIDTH + 4, textY + this.client.textRenderer.fontHeight); + return HudHelper.pointIsInArea(mouseX, mouseY, textX, textY, textX + MAX_TEXT_WIDTH + 4, textY + this.client.textRenderer.fontHeight); } protected void closeRecipeView() { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/recipebook/UpcomingEventsTab.java b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/recipebook/UpcomingEventsTab.java index e5878c651f..7317145f4a 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/itemlist/recipebook/UpcomingEventsTab.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/itemlist/recipebook/UpcomingEventsTab.java @@ -5,7 +5,7 @@ import de.hysky.skyblocker.skyblock.tabhud.widget.JacobsContestWidget; import de.hysky.skyblocker.utils.Formatters; import de.hysky.skyblocker.utils.SkyblockTime; -import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.render.HudHelper; import de.hysky.skyblocker.utils.scheduler.MessageScheduler; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; @@ -64,7 +64,7 @@ public void draw(DrawContext context, int x, int y, int mouseX, int mouseY, floa eventRenderer.render(context, x + 1, eventsY, mouseX, mouseY); //If we're hovering over this event then set it as the hovered one to show a tooltip - if (RenderHelper.pointIsInArea(mouseX, mouseY, x, y, x + 131, y + 150) && EventRenderer.isMouseOver(mouseX, mouseY, x + 1, eventsY)) this.hovered = eventRenderer; + if (HudHelper.pointIsInArea(mouseX, mouseY, x, y, x + 131, y + 150) && EventRenderer.isMouseOver(mouseX, mouseY, x + 1, eventsY)) this.hovered = eventRenderer; eventsY += EventRenderer.HEIGHT; } @@ -121,7 +121,7 @@ private void render(DrawContext context, int x, int y, int mouseX, int mouseY) { } private static boolean isMouseOver(int mouseX, int mouseY, int x, int y) { - return RenderHelper.pointIsInArea(mouseX, mouseY, x, y, x + 131, y + HEIGHT); + return HudHelper.pointIsInArea(mouseX, mouseY, x, y, x + 131, y + HEIGHT); } private List getTooltip() { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/dungeons/DungeonClassWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/dungeons/DungeonClassWidget.java index d4a79f7fa7..b5121d4834 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/dungeons/DungeonClassWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/dungeons/DungeonClassWidget.java @@ -5,7 +5,7 @@ import de.hysky.skyblocker.skyblock.profileviewer.utils.LevelFinder; import de.hysky.skyblocker.skyblock.tabhud.util.Ico; import de.hysky.skyblocker.utils.Formatters; -import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.render.HudHelper; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; @@ -62,7 +62,7 @@ public void render(DrawContext context, int mouseX, int mouseY, int x, int y) { context.drawText(textRenderer, className + " " + classLevel.level, x + 31, y + 5, Color.WHITE.getRGB(), false); Color fillColor = classLevel.level >= CLASS_CAP ? Color.MAGENTA : Color.GREEN; context.drawGuiTexture(RenderLayer::getGuiTextured, BAR_BACK, x + 30, y + 15, 75, 6); - RenderHelper.renderNineSliceColored(context, BAR_FILL, x + 30, y + 15, (int) (75 * classLevel.fill), 6, fillColor); + HudHelper.renderNineSliceColored(context, BAR_FILL, x + 30, y + 15, (int) (75 * classLevel.fill), 6, fillColor); if (mouseX > x + 30 && mouseX < x + 105 && mouseY > y + 12 && mouseY < y + 22){ List tooltipText = new ArrayList<>(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/skills/SkillWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/skills/SkillWidget.java index 1ae6b0be7d..a0921d27ef 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/skills/SkillWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/skills/SkillWidget.java @@ -5,7 +5,7 @@ import de.hysky.skyblocker.skyblock.profileviewer.utils.ProfileViewerUtils; import de.hysky.skyblocker.skyblock.tabhud.util.Ico; import de.hysky.skyblocker.utils.Formatters; -import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.render.HudHelper; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMaps; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; @@ -97,7 +97,7 @@ public void render(DrawContext context, int mouseX, int mouseY, int x, int y) { } context.drawGuiTexture(RenderLayer::getGuiTextured, BAR_BACK, x + 30, y + 12, 75, 6); - RenderHelper.renderNineSliceColored(context, BAR_FILL, x + 30, y + 12, (int) (75 * SKILL_LEVEL.fill), 6, fillColor); + HudHelper.renderNineSliceColored(context, BAR_FILL, x + 30, y + 12, (int) (75 * SKILL_LEVEL.fill), 6, fillColor); if (mouseX > x + 30 && mouseX < x + 105 && mouseY > y + 10 && mouseY < y + 19){ List tooltipText = new ArrayList<>(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/slayers/SlayerWidget.java b/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/slayers/SlayerWidget.java index 9c77c37b91..aba494dd73 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/slayers/SlayerWidget.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/profileviewer/slayers/SlayerWidget.java @@ -5,7 +5,7 @@ import de.hysky.skyblocker.skyblock.profileviewer.utils.LevelFinder; import de.hysky.skyblocker.skyblock.tabhud.util.Ico; import de.hysky.skyblocker.utils.Formatters; -import de.hysky.skyblocker.utils.render.RenderHelper; +import de.hysky.skyblocker.utils.render.HudHelper; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; @@ -72,7 +72,7 @@ public void render(DrawContext context, int mouseX, int mouseY, int x, int y) { context.drawGuiTexture(RenderLayer::getGuiTextured, BAR_BACK, x + 30, y + 15, 75, 6); Color fillColor = slayerLevel.fill == 1 ? Color.MAGENTA : Color.green; - RenderHelper.renderNineSliceColored(context, BAR_FILL, x + 30, y + 15, (int) (75 * slayerLevel.fill), 6, fillColor); + HudHelper.renderNineSliceColored(context, BAR_FILL, x + 30, y + 15, (int) (75 * slayerLevel.fill), 6, fillColor); if (mouseX > x + 30 && mouseX < x + 105 && mouseY > y + 12 && mouseY < y + 22){ List tooltipText = new ArrayList<>(); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/rift/HealingMelonIndicator.java b/src/main/java/de/hysky/skyblocker/skyblock/rift/HealingMelonIndicator.java index c5b22576e0..f1e3d565eb 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/rift/HealingMelonIndicator.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/rift/HealingMelonIndicator.java @@ -2,7 +2,6 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.utils.Utils; -import de.hysky.skyblocker.utils.render.RenderHelper; import de.hysky.skyblocker.utils.render.title.Title; import de.hysky.skyblocker.utils.render.title.TitleContainer; import net.minecraft.client.MinecraftClient; @@ -19,9 +18,9 @@ public static void updateHealth() { } ClientPlayerEntity player = MinecraftClient.getInstance().player; if (player != null && player.getHealth() <= SkyblockerConfigManager.get().slayers.vampireSlayer.healingMelonHealthThreshold * 2F) { - RenderHelper.displayInTitleContainerAndPlaySound(title); + TitleContainer.addTitleAndPlaySound(title); } else { TitleContainer.removeTitle(title); } } -} \ No newline at end of file +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/demonlord/FirePillarAnnouncer.java b/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/demonlord/FirePillarAnnouncer.java index cd5ecb9ad7..40a9295221 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/demonlord/FirePillarAnnouncer.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/demonlord/FirePillarAnnouncer.java @@ -5,7 +5,6 @@ import de.hysky.skyblocker.skyblock.slayers.SlayerManager; import de.hysky.skyblocker.skyblock.slayers.SlayerType; import de.hysky.skyblocker.utils.Utils; -import de.hysky.skyblocker.utils.render.RenderHelper; import de.hysky.skyblocker.utils.render.title.Title; import de.hysky.skyblocker.utils.render.title.TitleContainer; import net.minecraft.client.MinecraftClient; @@ -52,7 +51,7 @@ private static void announceFirePillarDetails(String entityName) { Title title = new Title(Text.literal(entityName).formatted(Formatting.BOLD, Formatting.DARK_PURPLE)); if (SkyblockerConfigManager.get().slayers.blazeSlayer.firePillarCountdown == SlayersConfig.BlazeSlayer.FirePillar.SOUND_AND_VISUAL) { - RenderHelper.displayInTitleContainerAndPlaySound(title, 15); + TitleContainer.addTitleAndPlaySound(title, 15); } else { TitleContainer.addTitle(title, 15); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/vampire/ManiaIndicator.java b/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/vampire/ManiaIndicator.java index c4c38035cb..117c629471 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/vampire/ManiaIndicator.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/vampire/ManiaIndicator.java @@ -3,7 +3,6 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.slayers.SlayerManager; import de.hysky.skyblocker.skyblock.slayers.SlayerType; -import de.hysky.skyblocker.utils.render.RenderHelper; import de.hysky.skyblocker.utils.render.title.Title; import de.hysky.skyblocker.utils.render.title.TitleContainer; import net.minecraft.block.Blocks; @@ -32,7 +31,7 @@ public static void updateMania() { BlockPos pos = MinecraftClient.getInstance().player.getBlockPos().down(); boolean isGreen = MinecraftClient.getInstance().world.getBlockState(pos).getBlock() == Blocks.GREEN_TERRACOTTA; title.setText(Text.translatable("skyblocker.rift.mania").formatted(isGreen ? Formatting.GREEN : Formatting.RED)); - RenderHelper.displayInTitleContainerAndPlaySound(title); + TitleContainer.addTitleAndPlaySound(title); } } if (!anyMania) { diff --git a/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/vampire/StakeIndicator.java b/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/vampire/StakeIndicator.java index 0e9c8f98da..9e867222e6 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/vampire/StakeIndicator.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/vampire/StakeIndicator.java @@ -3,7 +3,6 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.slayers.SlayerManager; import de.hysky.skyblocker.skyblock.slayers.SlayerType; -import de.hysky.skyblocker.utils.render.RenderHelper; import de.hysky.skyblocker.utils.render.title.Title; import de.hysky.skyblocker.utils.render.title.TitleContainer; import net.minecraft.entity.Entity; @@ -19,7 +18,7 @@ public static void updateStake() { } Entity slayerEntity = SlayerManager.getSlayerBossArmorStand(); if (slayerEntity != null && slayerEntity.getDisplayName().toString().contains("҉")) { - RenderHelper.displayInTitleContainerAndPlaySound(title); + TitleContainer.addTitleAndPlaySound(title); } else { TitleContainer.removeTitle(title); } diff --git a/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/vampire/TwinClawsIndicator.java b/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/vampire/TwinClawsIndicator.java index e03e56d339..2ba6cc08c0 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/vampire/TwinClawsIndicator.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/slayers/boss/vampire/TwinClawsIndicator.java @@ -3,7 +3,6 @@ import de.hysky.skyblocker.config.SkyblockerConfigManager; import de.hysky.skyblocker.skyblock.slayers.SlayerManager; import de.hysky.skyblocker.skyblock.slayers.SlayerType; -import de.hysky.skyblocker.utils.render.RenderHelper; import de.hysky.skyblocker.utils.render.title.Title; import de.hysky.skyblocker.utils.render.title.TitleContainer; import de.hysky.skyblocker.utils.scheduler.Scheduler; @@ -30,7 +29,7 @@ public static void updateIce() { if (!TitleContainer.containsTitle(title) && !scheduled) { scheduled = true; Scheduler.INSTANCE.schedule(() -> { - RenderHelper.displayInTitleContainerAndPlaySound(title); + TitleContainer.addTitleAndPlaySound(title); scheduled = false; }, SkyblockerConfigManager.get().slayers.vampireSlayer.holyIceIndicatorTickDelay); } diff --git a/src/main/java/de/hysky/skyblocker/utils/render/HudHelper.java b/src/main/java/de/hysky/skyblocker/utils/render/HudHelper.java new file mode 100644 index 0000000000..7343d4eccb --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/utils/render/HudHelper.java @@ -0,0 +1,46 @@ +package de.hysky.skyblocker.utils.render; + +import net.minecraft.block.entity.SkullBlockEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.PlayerSkinDrawer; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.util.DefaultSkinHelper; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.ColorHelper; + +import java.awt.*; +import java.util.Optional; +import java.util.UUID; + +public class HudHelper { + private static final MinecraftClient CLIENT = MinecraftClient.getInstance(); + + public static boolean pointIsInArea(double x, double y, double x1, double y1, double x2, double y2) { + return x >= x1 && x <= x2 && y >= y1 && y <= y2; + } + + public static void renderNineSliceColored(DrawContext context, Identifier texture, int x, int y, int width, int height, int argb) { + context.drawGuiTexture(RenderLayer::getGuiTextured, texture, x, y, width, height, argb); + } + + public static void renderNineSliceColored(DrawContext context, Identifier texture, int x, int y, int width, int height, Color color) { + renderNineSliceColored(context, texture, x, y, width, height, ColorHelper.getArgb(color.getAlpha(), color.getRed(), color.getGreen(), color.getBlue())); + } + + /** + * Draws a player head without blocking or nothing if profile is not available immediately. + * This fetches the profile so it will be available for future calls to this method. + */ + public static void drawPlayerHead(DrawContext context, int x, int y, int size, String name) { + SkullBlockEntity.fetchProfileByName(name).getNow(Optional.empty()).map(CLIENT.getSkinProvider()::getSkinTextures).ifPresent(skinTexture -> PlayerSkinDrawer.draw(context, skinTexture, x, y, size)); + } + + /** + * Draws a player head without blocking or a default head if profile is not available immediately. + * This fetches the profile so it will be available for future calls to this method. + */ + public static void drawPlayerHead(DrawContext context, int x, int y, int size, UUID uuid) { + PlayerSkinDrawer.draw(context, SkullBlockEntity.fetchProfileByUuid(uuid).getNow(Optional.empty()).map(CLIENT.getSkinProvider()::getSkinTextures).orElseGet(() -> DefaultSkinHelper.getSkinTextures(uuid)), x, y, size); + } +} diff --git a/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java b/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java index 6262df61f4..1a5b1b9454 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/RenderHelper.java @@ -6,21 +6,17 @@ import de.hysky.skyblocker.annotations.Init; import de.hysky.skyblocker.mixins.accessors.BeaconBlockEntityRendererInvoker; import de.hysky.skyblocker.utils.render.culling.OcclusionCulling; -import de.hysky.skyblocker.utils.render.title.Title; -import de.hysky.skyblocker.utils.render.title.TitleContainer; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.fabricmc.fabric.api.event.Event; import net.minecraft.block.BlockState; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.DrawContext; import net.minecraft.client.render.*; import net.minecraft.client.render.VertexFormat.DrawMode; import net.minecraft.client.util.BufferAllocator; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.world.ClientWorld; -import net.minecraft.sound.SoundEvents; import net.minecraft.text.OrderedText; import net.minecraft.text.Text; import net.minecraft.util.Identifier; @@ -34,8 +30,6 @@ import org.joml.Vector3f; import org.lwjgl.opengl.GL11; -import java.awt.*; - public class RenderHelper { private static final Identifier TRANSLUCENT_DRAW = Identifier.of(SkyblockerMod.NAMESPACE, "translucent_draw"); private static final int MAX_OVERWORLD_BUILD_HEIGHT = 319; @@ -356,47 +350,4 @@ public static Box getBlockBoundingBox(ClientWorld world, BlockPos pos) { public static Box getBlockBoundingBox(ClientWorld world, BlockState state, BlockPos pos) { return state.getOutlineShape(world, pos).asCuboid().getBoundingBox().offset(pos); } - - /** - * Adds the title to {@link TitleContainer} and {@link #playNotificationSound() plays the notification sound} if the title is not in the {@link TitleContainer} already. - * No checking needs to be done on whether the title is in the {@link TitleContainer} already by the caller. - * - * @param title the title - */ - public static void displayInTitleContainerAndPlaySound(Title title) { - if (TitleContainer.addTitle(title)) { - playNotificationSound(); - } - } - - /** - * Adds the title to {@link TitleContainer} for a set number of ticks and {@link #playNotificationSound() plays the notification sound} if the title is not in the {@link TitleContainer} already. - * No checking needs to be done on whether the title is in the {@link TitleContainer} already by the caller. - * - * @param title the title - * @param ticks the number of ticks the title will remain - */ - public static void displayInTitleContainerAndPlaySound(Title title, int ticks) { - if (TitleContainer.addTitle(title, ticks)) { - playNotificationSound(); - } - } - - private static void playNotificationSound() { - if (CLIENT.player != null) { - CLIENT.player.playSound(SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, 100f, 0.1f); - } - } - - public static boolean pointIsInArea(double x, double y, double x1, double y1, double x2, double y2) { - return x >= x1 && x <= x2 && y >= y1 && y <= y2; - } - - public static void renderNineSliceColored(DrawContext context, Identifier texture, int x, int y, int width, int height, int argb) { - context.drawGuiTexture(RenderLayer::getGuiTextured, texture, x, y, width, height, argb); - } - - public static void renderNineSliceColored(DrawContext context, Identifier texture, int x, int y, int width, int height, Color color) { - renderNineSliceColored(context, texture, x, y, width, height, ColorHelper.getArgb(color.getAlpha(), color.getRed(), color.getGreen(), color.getBlue())); - } } diff --git a/src/main/java/de/hysky/skyblocker/utils/render/title/TitleContainer.java b/src/main/java/de/hysky/skyblocker/utils/render/title/TitleContainer.java index 261b6cf340..3284d0c370 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/title/TitleContainer.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/title/TitleContainer.java @@ -13,6 +13,7 @@ import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.DrawContext; import net.minecraft.client.render.RenderTickCounter; +import net.minecraft.sound.SoundEvents; import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; @@ -21,6 +22,7 @@ public class TitleContainer { private static final Identifier TITLE_CONTAINER = Identifier.of(SkyblockerMod.NAMESPACE, "title_container"); + private static final MinecraftClient CLIENT = MinecraftClient.getInstance(); /** * The set of titles which will be rendered. * @@ -44,7 +46,7 @@ public static void init() { * Returns {@code true} if the title is currently shown. * * @param title the title to check - * @return whether the title in currently shown + * @return whether the title is currently shown already */ public static boolean containsTitle(Title title) { return titles.contains(title); @@ -54,7 +56,7 @@ public static boolean containsTitle(Title title) { * Adds a title to be shown * * @param title the title to be shown - * @return whether the title is already currently being shown + * @return whether the title is currently shown already */ public static boolean addTitle(Title title) { if (titles.add(title)) { @@ -69,7 +71,7 @@ public static boolean addTitle(Title title) { * * @param title the title to be shown * @param ticks the number of ticks to show the title - * @return whether the title is already currently being shown + * @return whether the title is currently shown already */ public static boolean addTitle(Title title, int ticks) { if (addTitle(title)) { @@ -79,6 +81,43 @@ public static boolean addTitle(Title title, int ticks) { return false; } + /** + * Adds the title to {@link TitleContainer} and {@link #playNotificationSound() plays the notification sound} if the title is not in the {@link TitleContainer} already. + * No checking needs to be done on whether the title is in the {@link TitleContainer} already by the caller. + * + * @param title the title + * @return whether the title is currently shown already + */ + public static boolean addTitleAndPlaySound(Title title) { + if (addTitle(title)) { + playNotificationSound(); + return true; + } + return false; + } + + /** + * Adds the title to {@link TitleContainer} for a set number of ticks and {@link #playNotificationSound() plays the notification sound} if the title is not in the {@link TitleContainer} already. + * No checking needs to be done on whether the title is in the {@link TitleContainer} already by the caller. + * + * @param title the title + * @param ticks the number of ticks the title will remain + * @return whether the title is currently shown already + */ + public static boolean addTitleAndPlaySound(Title title, int ticks) { + if (addTitle(title, ticks)) { + playNotificationSound(); + return true; + } + return false; + } + + public static void playNotificationSound() { + if (CLIENT.player != null) { + CLIENT.player.playSound(SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, 100f, 0.1f); + } + } + /** * Stops showing a title * From 7f1cb0567d6eeefa5190cfe8036982f6a7cc6fda Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Tue, 15 Apr 2025 12:26:16 -0400 Subject: [PATCH 12/14] Rename config field --- .../config/categories/DungeonsCategory.java | 18 +++++++++--------- .../config/configs/DungeonsConfig.java | 2 +- .../mixins/HandledScreenProviderMixin.java | 2 +- .../skyblock/dungeon/LeapOverlay.java | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java index 80fc9ca182..98c97049ce 100644 --- a/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java +++ b/src/main/java/de/hysky/skyblocker/config/categories/DungeonsCategory.java @@ -139,23 +139,23 @@ public static ConfigCategory create(SkyblockerConfig defaults, SkyblockerConfig .option(Option.createBuilder() .name(Text.translatable("skyblocker.config.dungeons.spiritLeapOverlay.enableLeapOverlay")) .description(OptionDescription.of(Text.translatable("skyblocker.config.dungeons.spiritLeapOverlay.enableLeapOverlay.@Tooltip"))) - .binding(defaults.dungeons.spiritLeapOverlay.enableLeapOverlay, - () -> config.dungeons.spiritLeapOverlay.enableLeapOverlay, - newValue -> config.dungeons.spiritLeapOverlay.enableLeapOverlay = newValue) + .binding(defaults.dungeons.leapOverlay.enableLeapOverlay, + () -> config.dungeons.leapOverlay.enableLeapOverlay, + newValue -> config.dungeons.leapOverlay.enableLeapOverlay = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.createBuilder() .name(Text.translatable("skyblocker.config.dungeons.spiritLeapOverlay.showMap")) - .binding(defaults.dungeons.spiritLeapOverlay.showMap, - () -> config.dungeons.spiritLeapOverlay.showMap, - newValue -> config.dungeons.spiritLeapOverlay.showMap = newValue) + .binding(defaults.dungeons.leapOverlay.showMap, + () -> config.dungeons.leapOverlay.showMap, + newValue -> config.dungeons.leapOverlay.showMap = newValue) .controller(ConfigUtils::createBooleanController) .build()) .option(Option.createBuilder() .name(Text.translatable("skyblocker.config.dungeons.spiritLeapOverlay.scale")) - .binding(defaults.dungeons.spiritLeapOverlay.scale, - () -> config.dungeons.spiritLeapOverlay.scale, - newValue -> config.dungeons.spiritLeapOverlay.scale = newValue) + .binding(defaults.dungeons.leapOverlay.scale, + () -> config.dungeons.leapOverlay.scale, + newValue -> config.dungeons.leapOverlay.scale = newValue) .controller(opt -> FloatSliderControllerBuilder.create(opt).range(1f, 2f).step(0.05f).formatValue(ConfigUtils.FLOAT_TWO_FORMATTER)) .build()) .build()) diff --git a/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java b/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java index 688bc73bad..5aa8cf5f98 100644 --- a/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java +++ b/src/main/java/de/hysky/skyblocker/config/configs/DungeonsConfig.java @@ -37,7 +37,7 @@ public class DungeonsConfig { public DungeonMap dungeonMap = new DungeonMap(); @SerialEntry - public SpiritLeapOverlay spiritLeapOverlay = new SpiritLeapOverlay(); + public SpiritLeapOverlay leapOverlay = new SpiritLeapOverlay(); @SerialEntry public PuzzleSolvers puzzleSolvers = new PuzzleSolvers(); diff --git a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenProviderMixin.java b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenProviderMixin.java index 744e865d97..e756204423 100644 --- a/src/main/java/de/hysky/skyblocker/mixins/HandledScreenProviderMixin.java +++ b/src/main/java/de/hysky/skyblocker/mixins/HandledScreenProviderMixin.java @@ -105,7 +105,7 @@ public interface HandledScreenProviderMixin { } // Leap Overlay - case GenericContainerScreenHandler containerScreenHandler when Utils.isInDungeons() && SkyblockerConfigManager.get().dungeons.spiritLeapOverlay.enableLeapOverlay && nameLowercase.contains(LeapOverlay.TITLE.toLowerCase()) -> { + case GenericContainerScreenHandler containerScreenHandler when Utils.isInDungeons() && SkyblockerConfigManager.get().dungeons.leapOverlay.enableLeapOverlay && nameLowercase.contains(LeapOverlay.TITLE.toLowerCase()) -> { client.player.currentScreenHandler = containerScreenHandler; client.setScreen(new LeapOverlay(containerScreenHandler)); diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java index c9990201eb..f61c76a0d2 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/LeapOverlay.java @@ -42,7 +42,7 @@ public class LeapOverlay extends Screen implements ScreenHandlerListener { private static final MinecraftClient CLIENT = MinecraftClient.getInstance(); private static final Identifier BUTTON = Identifier.of(SkyblockerMod.NAMESPACE, "button/button"); private static final Identifier BUTTON_HIGHLIGHTED = Identifier.of(SkyblockerMod.NAMESPACE, "button/button_highlighted"); - private static final DungeonsConfig.SpiritLeapOverlay CONFIG = SkyblockerConfigManager.get().dungeons.spiritLeapOverlay; + private static final DungeonsConfig.SpiritLeapOverlay CONFIG = SkyblockerConfigManager.get().dungeons.leapOverlay; private static final int BUTTON_SPACING = 8; private static final int BUTTON_WIDTH = 130; private static final int BUTTON_HEIGHT = 50; From 7842a2f0dbc575065f7a4a46957c454696c199cb Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Wed, 16 Apr 2025 18:21:17 -0400 Subject: [PATCH 13/14] Remove draw head by name --- .../java/de/hysky/skyblocker/utils/render/HudHelper.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/main/java/de/hysky/skyblocker/utils/render/HudHelper.java b/src/main/java/de/hysky/skyblocker/utils/render/HudHelper.java index 7343d4eccb..a08d4d2969 100644 --- a/src/main/java/de/hysky/skyblocker/utils/render/HudHelper.java +++ b/src/main/java/de/hysky/skyblocker/utils/render/HudHelper.java @@ -28,14 +28,6 @@ public static void renderNineSliceColored(DrawContext context, Identifier textur renderNineSliceColored(context, texture, x, y, width, height, ColorHelper.getArgb(color.getAlpha(), color.getRed(), color.getGreen(), color.getBlue())); } - /** - * Draws a player head without blocking or nothing if profile is not available immediately. - * This fetches the profile so it will be available for future calls to this method. - */ - public static void drawPlayerHead(DrawContext context, int x, int y, int size, String name) { - SkullBlockEntity.fetchProfileByName(name).getNow(Optional.empty()).map(CLIENT.getSkinProvider()::getSkinTextures).ifPresent(skinTexture -> PlayerSkinDrawer.draw(context, skinTexture, x, y, size)); - } - /** * Draws a player head without blocking or a default head if profile is not available immediately. * This fetches the profile so it will be available for future calls to this method. From 517fb25b363f42ca3853f5199683507e7ba3c375 Mon Sep 17 00:00:00 2001 From: Kevinthegreat <92656833+kevinthegreat1@users.noreply.github.com> Date: Sat, 19 Apr 2025 11:16:15 -0400 Subject: [PATCH 14/14] Prevent default decorations --- .../hysky/skyblocker/mixins/MapRendererMixin.java | 15 +++++++++++++++ .../skyblocker/skyblock/dungeon/DungeonMap.java | 2 +- src/main/resources/skyblocker.mixins.json | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/main/java/de/hysky/skyblocker/mixins/MapRendererMixin.java diff --git a/src/main/java/de/hysky/skyblocker/mixins/MapRendererMixin.java b/src/main/java/de/hysky/skyblocker/mixins/MapRendererMixin.java new file mode 100644 index 0000000000..c5570a3db5 --- /dev/null +++ b/src/main/java/de/hysky/skyblocker/mixins/MapRendererMixin.java @@ -0,0 +1,15 @@ +package de.hysky.skyblocker.mixins; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import de.hysky.skyblocker.utils.Utils; +import net.minecraft.client.render.MapRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +@Mixin(MapRenderer.class) +public class MapRendererMixin { + @ModifyExpressionValue(method = "draw", at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/MapRenderState$Decoration;alwaysRendered:Z")) + private boolean preventDecorationInDungeons(boolean alwaysRendered) { + return !Utils.isInDungeons() && alwaysRendered; + } +} diff --git a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java index 41c0e7f4f4..75a9a4bee5 100644 --- a/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java +++ b/src/main/java/de/hysky/skyblocker/skyblock/dungeon/DungeonMap.java @@ -126,7 +126,7 @@ public static UUID render(DrawContext context, int x, int y, float scale, boolea context.getMatrices().translate(x, y, 0); context.getMatrices().scale(scale, scale, 0f); mapRenderer.update(mapId, state, MAP_RENDER_STATE); - mapRenderer.draw(MAP_RENDER_STATE, context.getMatrices(), vertices, false, LightmapTextureManager.MAX_LIGHT_COORDINATE); + mapRenderer.draw(MAP_RENDER_STATE, context.getMatrices(), vertices, fancy, LightmapTextureManager.MAX_LIGHT_COORDINATE); vertices.draw(); UUID hoveredHead = null; diff --git a/src/main/resources/skyblocker.mixins.json b/src/main/resources/skyblocker.mixins.json index e71d3718dd..9fcff37ea8 100644 --- a/src/main/resources/skyblocker.mixins.json +++ b/src/main/resources/skyblocker.mixins.json @@ -31,6 +31,7 @@ "InventoryScreenMixin", "ItemStackMixin", "LeverBlockMixin", + "MapRendererMixin", "MessageHandlerMixin", "MinecraftClientMixin", "MouseMixin",