From ce917dae1175cb40aaacf0349bed639afc864915 Mon Sep 17 00:00:00 2001 From: QWERTZexe Date: Sun, 15 Mar 2026 13:45:54 +0100 Subject: [PATCH 1/9] Added Group functionality --- .../java/cc/aabss/eventutils/EventUtils.java | 47 +++++++- .../cc/aabss/eventutils/KeybindManager.java | 19 +++- .../aabss/eventutils/NotificationToast.java | 18 +-- .../cc/aabss/eventutils/UpdateChecker.java | 8 +- .../eventutils/commands/CommandRegister.java | 16 +++ .../eventutils/commands/GroupMsgCmd.java | 38 +++++++ .../eventutils/commands/PriorityCmd.java | 16 +-- .../aabss/eventutils/config/ConfigScreen.java | 11 ++ .../eventutils/config/EditGroupScreen.java | 105 ++++++++++++++++++ .../aabss/eventutils/config/EventConfig.java | 6 + .../eventutils/config/GroupManagerScreen.java | 80 +++++++++++++ .../aabss/eventutils/config/PlayerGroup.java | 61 ++++++++++ .../aabss/eventutils/mixin/EntityMixin.java | 4 +- .../mixin/EntityRenderDispatcherMixin.java | 4 +- .../mixin/PlayerEntityRendererMixin.java | 17 ++- .../eventutils/utility/ConnectUtility.java | 8 +- .../assets/eventutils/lang/en_us.json | 15 +++ stonecutter.gradle.kts | 2 +- 18 files changed, 434 insertions(+), 41 deletions(-) create mode 100644 src/main/java/cc/aabss/eventutils/commands/GroupMsgCmd.java create mode 100644 src/main/java/cc/aabss/eventutils/config/EditGroupScreen.java create mode 100644 src/main/java/cc/aabss/eventutils/config/GroupManagerScreen.java create mode 100644 src/main/java/cc/aabss/eventutils/config/PlayerGroup.java diff --git a/src/main/java/cc/aabss/eventutils/EventUtils.java b/src/main/java/cc/aabss/eventutils/EventUtils.java index d01906b..222a522 100644 --- a/src/main/java/cc/aabss/eventutils/EventUtils.java +++ b/src/main/java/cc/aabss/eventutils/EventUtils.java @@ -5,6 +5,7 @@ import cc.aabss.eventutils.websocket.SocketEndpoint; import cc.aabss.eventutils.websocket.WebSocketClient; import cc.aabss.eventutils.config.EventConfig; +import cc.aabss.eventutils.config.PlayerGroup; import com.google.gson.JsonObject; @@ -59,7 +60,8 @@ public class EventUtils implements ClientModInitializer { public KeybindManager keybindManager; @NotNull public final EventServerManager eventServerManager = new EventServerManager(this); @NotNull public final Map lastIps = new EnumMap<>(EventType.class); - public boolean hidePlayers = false; + /** 0 = first group (or hide-all when no groups), 1 = second group, ... ; groups.size() = players revealed */ + public int hidePlayersViewMode = 0; public EventUtils() { MOD = this; @@ -146,6 +148,49 @@ public static boolean isNPC(@NotNull String name) { return isNPC(name, false); } + /** Whether the current view mode is "players revealed" (show everyone). */ + public static boolean isHidePlayersRevealed() { + final int n = MOD.config.groups.size(); + if (n == 0) return MOD.hidePlayersViewMode == 1; + return MOD.hidePlayersViewMode >= n; + } + + /** Whether we are in a "hide" mode (any group or hide-all). */ + public static boolean isInHidePlayersMode() { + final int n = MOD.config.groups.size(); + if (n == 0) return MOD.hidePlayersViewMode == 0; + return MOD.hidePlayersViewMode < n; + } + + /** Current group when in group view mode, or null if revealed or no groups. */ + @Nullable + public static PlayerGroup getCurrentViewGroup() { + final var groups = MOD.config.groups; + if (groups.isEmpty() || MOD.hidePlayersViewMode >= groups.size()) return null; + return groups.get(MOD.hidePlayersViewMode); + } + + /** + * True if the player (by lowercased name) should be visible with current view mode. + * Caller must exclude main player. + */ + public static boolean isPlayerVisible(@NotNull String nameLower) { + if (isHidePlayersRevealed()) return true; + if (MOD.config.whitelistedPlayers.contains(nameLower) || isNPC(nameLower)) return true; + final PlayerGroup group = getCurrentViewGroup(); + if (group == null) return false; // no groups, hide mode: only whitelist/NPC + return group.containsPlayer(nameLower); + } + + /** True if the nametag for this visible player should be drawn (per-group setting when in group view). */ + public static boolean shouldShowNametagFor(@NotNull String nameLower) { + if (!isInHidePlayersMode()) return true; + final PlayerGroup group = getCurrentViewGroup(); + if (group == null) return true; // hide-all with no groups: use default + if (!group.containsPlayer(nameLower)) return true; // whitelist/NPC visibility: show nametag + return group.isShowNametags(); + } + @Contract(pure = true) public static int max(int... values) { int max = Integer.MIN_VALUE; diff --git a/src/main/java/cc/aabss/eventutils/KeybindManager.java b/src/main/java/cc/aabss/eventutils/KeybindManager.java index 0232d61..a28160a 100644 --- a/src/main/java/cc/aabss/eventutils/KeybindManager.java +++ b/src/main/java/cc/aabss/eventutils/KeybindManager.java @@ -19,6 +19,7 @@ import java.util.HashMap; import java.util.Map; +import static net.minecraft.text.Text.literal; import static net.minecraft.text.Text.translatable; @@ -79,11 +80,21 @@ public KeybindManager(@NotNull EventUtils mod) { // In-game keybinds if (client.player == null) return; - // Hide players key + // Hide players key: cycle Group 1 -> Group 2 -> ... -> Players Revealed -> repeat if (hidePlayersKey.wasPressed()) { - mod.hidePlayers = !mod.hidePlayers; - client.player.sendMessage(translatable(mod.hidePlayers ? "eventutils.hideplayers.enabled" : "eventutils.hideplayers.disabled") - .formatted(mod.hidePlayers ? Formatting.GREEN : Formatting.RED), true); + final int groupCount = mod.config.groups.size(); + final int totalStates = groupCount == 0 ? 2 : groupCount + 1; + mod.hidePlayersViewMode = (mod.hidePlayersViewMode + 1) % totalStates; + final boolean revealed = EventUtils.isHidePlayersRevealed(); + final Text message; + if (revealed) { + message = translatable("eventutils.hideplayers.view_revealed").formatted(Formatting.GREEN); + } else { + final var group = EventUtils.getCurrentViewGroup(); + message = (group != null ? literal(group.getName()) : translatable("eventutils.hideplayers.view_whitelist_only")) + .formatted(Formatting.GREEN); + } + client.player.sendMessage(translatable("eventutils.hideplayers.view_prefix").append(message), true); } }); } diff --git a/src/main/java/cc/aabss/eventutils/NotificationToast.java b/src/main/java/cc/aabss/eventutils/NotificationToast.java index af7bc45..63d30ca 100644 --- a/src/main/java/cc/aabss/eventutils/NotificationToast.java +++ b/src/main/java/cc/aabss/eventutils/NotificationToast.java @@ -13,7 +13,7 @@ import net.minecraft.text.Text; import net.minecraft.util.Identifier; //? if >=1.21.6 -/*import net.minecraft.client.gl.RenderPipelines;*/ +import net.minecraft.client.gl.RenderPipelines; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -90,10 +90,10 @@ public void draw(DrawContext drawContext, TextRenderer textRenderer, long startT //? if <1.21.2 { /*drawContext.drawGuiTexture(TEXTURE, 0, 0, width, height); *///?} else if >=1.21.6 { - /*drawContext.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 - *///?} else { - drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 - //?} + drawContext.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 + //?} else { + /*drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 + *///?} } else { int minHeight = Math.min(4, height - 28); drawPart(drawContext, 0, 0, 28); @@ -123,14 +123,14 @@ private void drawPart(@NotNull DrawContext context, int j, int k, int l) { for (int o = m; o < widthN; o += 64) context.drawGuiTexture(TEXTURE, 160, 32, 32, j, o, k, Math.min(64, widthN - o), l); context.drawGuiTexture(TEXTURE, 160, 32, 160 - n, j, widthN, k, n, l); *///?} else if >=1.21.6 { - /*context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 0, j, 0, k, m, l); + context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 0, j, 0, k, m, l); for (int o = m; o < widthN; o += 64) context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 32, j, o, k, Math.min(64, widthN - o), l); context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 160 - n, j, widthN, k, n, l); - *///?} else { - context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 0, j, 0, k, m, l); + //?} else { + /*context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 0, j, 0, k, m, l); for (int o = m; o < widthN; o += 64) context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 32, j, o, k, Math.min(64, widthN - o), l); context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 160 - n, j, widthN, k, n, l); - //?} + *///?} } @Environment(value = EnvType.CLIENT) diff --git a/src/main/java/cc/aabss/eventutils/UpdateChecker.java b/src/main/java/cc/aabss/eventutils/UpdateChecker.java index 5f69363..744ec6a 100644 --- a/src/main/java/cc/aabss/eventutils/UpdateChecker.java +++ b/src/main/java/cc/aabss/eventutils/UpdateChecker.java @@ -31,7 +31,7 @@ private void notifyUpdate(@NotNull String latestVersion) { client.send(() -> { if (client.player == null) return; //? if >=1.21.5 { - /*client.player.sendMessage( + client.player.sendMessage( EventUtils.MESSAGE_PREFIX.copy().append(" §e" + EventUtils.translate("eventutils.updatechecker.new")+"§r §7(v" + Versions.EU_VERSION + " -> v" + latestVersion.replace(Versions.MC_VERSION + "-", "") + ")" + "\n") .setStyle(EventUtils.MESSAGE_PREFIX.getStyle() .withHoverEvent(new HoverEvent.ShowText(translatable("eventutils.updatechecker.hover"))) @@ -39,8 +39,8 @@ private void notifyUpdate(@NotNull String latestVersion) { .append(Text.literal("§7§o" + EventUtils.translate("eventutils.updatechecker.config")) .setStyle(Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/event utils")))), false); - *///?} else { - client.player.sendMessage( + //?} else { + /*client.player.sendMessage( EventUtils.MESSAGE_PREFIX.copy().append(" §e" + EventUtils.translate("eventutils.updatechecker.new")+"§r §7(v" + Versions.EU_VERSION + " -> v" + latestVersion.replace(Versions.MC_VERSION + "-", "") + ")" + "\n") .setStyle(EventUtils.MESSAGE_PREFIX.getStyle() .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, translatable("eventutils.updatechecker.hover"))) @@ -48,7 +48,7 @@ private void notifyUpdate(@NotNull String latestVersion) { .append(Text.literal("§7§o" + EventUtils.translate("eventutils.updatechecker.config")) .setStyle(Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils config")))), false); - //?} + *///?} }); } diff --git a/src/main/java/cc/aabss/eventutils/commands/CommandRegister.java b/src/main/java/cc/aabss/eventutils/commands/CommandRegister.java index 1c85e2a..5d6d387 100644 --- a/src/main/java/cc/aabss/eventutils/commands/CommandRegister.java +++ b/src/main/java/cc/aabss/eventutils/commands/CommandRegister.java @@ -1,6 +1,8 @@ package cc.aabss.eventutils.commands; import cc.aabss.eventutils.EventType; +import cc.aabss.eventutils.EventUtils; +import cc.aabss.eventutils.config.PlayerGroup; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.IntegerArgumentType; @@ -96,6 +98,19 @@ public static void register(@NotNull CommandDispatcher groupMsg = ClientCommandManager + .literal("groupmsg") + .then(ClientCommandManager.argument("group", StringArgumentType.word()) + .suggests((context, builder) -> { + for (final PlayerGroup g : EventUtils.MOD.config.groups) builder.suggest(g.getName()); + return builder.buildFuture(); + }) + .then(ClientCommandManager.argument("message", StringArgumentType.greedyString()) + .executes(context -> GroupMsgCmd.groupMsg(context, + StringArgumentType.getString(context, "group"), + StringArgumentType.getString(context, "message"))))) + .build(); + // Build command tree dispatcher.getRoot().addChild(main); main.addChild(config); @@ -103,5 +118,6 @@ public static void register(@NotNull CommandDispatcher context, @NotNull String groupNameArg, @NotNull String message) { + final var groups = EventUtils.MOD.config.groups; + final String search = groupNameArg.toLowerCase(); + PlayerGroup group = null; + for (final PlayerGroup g : groups) { + if (g.getName().toLowerCase().equals(search)) { + group = g; + break; + } + } + if (group == null) { + context.getSource().sendError(translatable("eventutils.command.groupmsg.no_group", EventUtils.ERROR_MESSAGE_PREFIX, groupNameArg)); + return 0; + } + final String toSend = "[" + group.getName() + "] " + message; + if (context.getSource().getPlayer() != null && context.getSource().getPlayer().networkHandler != null) { + context.getSource().getPlayer().networkHandler.sendChatMessage(toSend); + } + return 1; + } +} diff --git a/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java b/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java index f28afa9..ab5f0e4 100644 --- a/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java +++ b/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java @@ -110,10 +110,10 @@ public static void priority(@NotNull CommandContext c page - 1 ).setStyle( //? if <=1.21.4 { - Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page - 1))) - //?} else { - /*Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page - 1))) - *///?} + /*Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page - 1))) + *///?} else { + Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page - 1))) + //?} ); } @@ -123,10 +123,10 @@ public static void priority(@NotNull CommandContext c page + 1 ).setStyle( //? if <=1.21.4 { - Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page + 1))) - //?} else { - /*Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page + 1))) - *///?} + /*Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page + 1))) + *///?} else { + Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page + 1))) + //?} ); } diff --git a/src/main/java/cc/aabss/eventutils/config/ConfigScreen.java b/src/main/java/cc/aabss/eventutils/config/ConfigScreen.java index ced5eac..71dd83e 100644 --- a/src/main/java/cc/aabss/eventutils/config/ConfigScreen.java +++ b/src/main/java/cc/aabss/eventutils/config/ConfigScreen.java @@ -6,6 +6,8 @@ import dev.isxander.yacl3.api.*; import dev.isxander.yacl3.api.controller.*; +import net.minecraft.client.MinecraftClient; + import net.minecraft.client.gui.screen.Screen; import net.minecraft.entity.EntityType; import net.minecraft.registry.Registries; @@ -135,6 +137,15 @@ public static Screen getConfigScreen(@Nullable Screen parent) { .controller(ConfigScreen::getBooleanBuilder).build()) .build()); + // Groups + builder.category(ConfigCategory.createBuilder().name(translatable("eventutils.config.groups.category")) + .option(ButtonOption.createBuilder() + .name(translatable("eventutils.config.groups.manage_title")) + .description(OptionDescription.of(translatable("eventutils.config.groups.manage_description"))) + .action((yaclScreen, option) -> MinecraftClient.getInstance().setScreen(new GroupManagerScreen(yaclScreen))) + .build()) + .build()); + // Alerts & notification sounds final OptionGroup.Builder alertsGroup = OptionGroup.createBuilder() .name(translatable("eventutils.config.alerts.toggles")); diff --git a/src/main/java/cc/aabss/eventutils/config/EditGroupScreen.java b/src/main/java/cc/aabss/eventutils/config/EditGroupScreen.java new file mode 100644 index 0000000..fb792c2 --- /dev/null +++ b/src/main/java/cc/aabss/eventutils/config/EditGroupScreen.java @@ -0,0 +1,105 @@ +package cc.aabss.eventutils.config; + +import cc.aabss.eventutils.EventUtils; + +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.TextFieldWidget; + +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static net.minecraft.text.Text.translatable; + + +public class EditGroupScreen extends Screen { + private static final int PADDING = 20; + private static final int ROW = 24; + private static final int FIELD_HEIGHT = 20; + + @Nullable private final Screen parent; + private final int groupIndex; + private TextFieldWidget nameField; + private TextFieldWidget playersField; + private boolean showNametags = true; + + public EditGroupScreen(@Nullable Screen parent, int groupIndex) { + super(translatable("eventutils.config.groups.edit_title")); + this.parent = parent; + this.groupIndex = groupIndex; + } + + @Override + protected void init() { + final EventConfig config = EventUtils.MOD.config; + if (groupIndex < 0 || groupIndex >= config.groups.size()) { + if (client != null) client.setScreen(parent); + return; + } + final PlayerGroup group = config.groups.get(groupIndex); + showNametags = group.isShowNametags(); + + final int centerX = width / 2; + final int fieldWidth = Math.min(320, width - PADDING * 4); + int y = 40; + + nameField = new TextFieldWidget(textRenderer, centerX - fieldWidth / 2, y, fieldWidth, FIELD_HEIGHT, translatable("eventutils.config.groups.name_hint")); + nameField.setMaxLength(64); + nameField.setText(group.getName()); + nameField.setPlaceholder(translatable("eventutils.config.groups.name_hint")); + addDrawableChild(nameField); + + y += ROW + 8; + playersField = new TextFieldWidget(textRenderer, centerX - fieldWidth / 2, y, fieldWidth, FIELD_HEIGHT, translatable("eventutils.config.groups.players_hint")); + playersField.setMaxLength(1024); + playersField.setText(String.join(", ", group.getPlayers())); + playersField.setPlaceholder(translatable("eventutils.config.groups.players_hint")); + addDrawableChild(playersField); + + y += ROW + 16; + addDrawableChild(ButtonWidget.builder(showNametags ? translatable("eventutils.config.groups.nametags_on") : translatable("eventutils.config.groups.nametags_off"), button -> { + showNametags = !showNametags; + button.setMessage(showNametags ? translatable("eventutils.config.groups.nametags_on") : translatable("eventutils.config.groups.nametags_off")); + }).dimensions(centerX - 100, y, 200, 20).build()); + + y += ROW + 24; + addDrawableChild(ButtonWidget.builder(translatable("gui.done"), button -> saveAndClose()) + .dimensions(centerX - 60, y, 120, 20).build()); + } + + private void saveAndClose() { + final EventConfig config = EventUtils.MOD.config; + if (groupIndex < 0 || groupIndex >= config.groups.size()) { + if (client != null) client.setScreen(parent); + return; + } + final PlayerGroup group = config.groups.get(groupIndex); + group.setName(nameField.getText().trim().isEmpty() ? "New Group" : nameField.getText().trim()); + final String playersText = playersField.getText().trim(); + final List players = playersText.isEmpty() + ? List.of() + : Arrays.stream(playersText.split(",")) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .map(String::toLowerCase) + .collect(Collectors.toList()); + group.setPlayers(players); + group.setShowNametags(showNametags); + config.setSave("groups", config.groups); + if (client != null) client.setScreen(parent); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + context.fill(0, 0, width, height, 0xC0101010); + context.drawCenteredTextWithShadow(textRenderer, title, width / 2, 12, 0xFFFFFF); + final int centerX = width / 2; + context.drawTextWithShadow(textRenderer, translatable("eventutils.config.groups.name_label"), centerX - 160, 44, 0xA0A0A0); + context.drawTextWithShadow(textRenderer, translatable("eventutils.config.groups.players_label"), centerX - 160, 44 + ROW + 8, 0xA0A0A0); + super.render(context, mouseX, mouseY, delta); + } +} diff --git a/src/main/java/cc/aabss/eventutils/config/EventConfig.java b/src/main/java/cc/aabss/eventutils/config/EventConfig.java index 13a2431..93858fb 100644 --- a/src/main/java/cc/aabss/eventutils/config/EventConfig.java +++ b/src/main/java/cc/aabss/eventutils/config/EventConfig.java @@ -33,6 +33,7 @@ public class EventConfig extends FileLoader { @NotNull public String defaultFamousIp; @NotNull public List> hiddenEntityTypes; @NotNull public List whitelistedPlayers; + @NotNull public List groups; public boolean useTestingApi; @NotNull public final List eventTypes; @NotNull public final Map notificationSounds; @@ -63,6 +64,7 @@ public EventConfig() { hideNPCs = get("hide_npcs", Defaults.HIDE_NPCS); hiddenEntityTypes = get("hidden_entity_types", Defaults.hiddenEntityTypes(), new TypeToken>>(){}.getType()); whitelistedPlayers = get("whitelisted_players", Defaults.whitelistedPlayers(), new TypeToken>(){}.getType()); + groups = get("groups", Defaults.groups(), new TypeToken>(){}.getType()); useTestingApi = get("use_testing_api", Defaults.USE_TESTING_API); eventTypes = get("notifications", Defaults.eventTypes(), new TypeToken>(){}.getType()); notificationSounds = get("notification_sounds", Defaults.notificationSounds(), new TypeToken>(){}.getType()); @@ -164,6 +166,10 @@ public static List whitelistedPlayers() { return new ArrayList<>(WHITELISTED_PLAYERS); } @NotNull + public static List groups() { + return new ArrayList<>(); + } + @NotNull public static List eventTypes() { return new ArrayList<>(EVENT_TYPES); } diff --git a/src/main/java/cc/aabss/eventutils/config/GroupManagerScreen.java b/src/main/java/cc/aabss/eventutils/config/GroupManagerScreen.java new file mode 100644 index 0000000..969093e --- /dev/null +++ b/src/main/java/cc/aabss/eventutils/config/GroupManagerScreen.java @@ -0,0 +1,80 @@ +package cc.aabss.eventutils.config; + +import cc.aabss.eventutils.EventUtils; + +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.text.TextColor; +import net.minecraft.util.Formatting; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + + +import static net.minecraft.text.Text.literal; +import static net.minecraft.text.Text.translatable; + + +public class GroupManagerScreen extends Screen { + private static final int ROW_HEIGHT = 24; + private static final int PADDING = 20; + private static final int BUTTON_WIDTH = 120; + private static final int REMOVE_WIDTH = 50; + + @Nullable private final Screen parent; + + public GroupManagerScreen(@Nullable Screen parent) { + super(translatable("eventutils.config.groups.manage_title")); + this.parent = parent; + } + + @Override + protected void init() { + final EventConfig config = EventUtils.MOD.config; + final int listTop = 40; + + for (int i = 0; i < config.groups.size(); i++) { + final int index = i; + final PlayerGroup group = config.groups.get(i); + final int y = listTop + i * ROW_HEIGHT; + if (y >= height - 60) break; + + final ButtonWidget editBtn = ButtonWidget.builder( + literal(group.getName()).fillStyle(Style.EMPTY.withColor(TextColor.fromRgb(0xE0E0E0))), + button -> client.setScreen(new EditGroupScreen(this, index)) + ).dimensions(PADDING, y, width - PADDING * 2 - REMOVE_WIDTH - 4, 20).build(); + addDrawableChild(editBtn); + + addDrawableChild(ButtonWidget.builder(literal("X").formatted(Formatting.RED), button -> { + config.groups.remove(index); + config.setSave("groups", config.groups); + if (client != null) client.setScreen(new GroupManagerScreen(parent)); + }).dimensions(width - PADDING - REMOVE_WIDTH, y, REMOVE_WIDTH, 20).build()); + } + + final ButtonWidget addBtn = ButtonWidget.builder(translatable("eventutils.config.groups.add"), button -> { + config.groups.add(new PlayerGroup()); + config.setSave("groups", config.groups); + client.setScreen(new GroupManagerScreen(parent)); + }).dimensions(width / 2 - BUTTON_WIDTH - 4, height - 32, BUTTON_WIDTH, 20).build(); + addDrawableChild(addBtn); + + addDrawableChild(ButtonWidget.builder(translatable("gui.done"), button -> goBack()) + .dimensions(width / 2 + 4, height - 32, BUTTON_WIDTH, 20).build()); + } + + private void goBack() { + if (client != null) client.setScreen(parent); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + context.fill(0, 0, width, height, 0xC0101010); + context.drawCenteredTextWithShadow(textRenderer, title, width / 2, 12, 0xFFFFFF); + super.render(context, mouseX, mouseY, delta); + } + +} diff --git a/src/main/java/cc/aabss/eventutils/config/PlayerGroup.java b/src/main/java/cc/aabss/eventutils/config/PlayerGroup.java new file mode 100644 index 0000000..a725286 --- /dev/null +++ b/src/main/java/cc/aabss/eventutils/config/PlayerGroup.java @@ -0,0 +1,61 @@ +package cc.aabss.eventutils.config; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + + +/** + * A named group of players with optional nametag visibility. + * Used for cycling visibility (hide players keybind) and group chat. + */ +public class PlayerGroup { + @NotNull private String name; + @NotNull private List players; + private boolean showNametags; + + public PlayerGroup(@NotNull String name, @NotNull List players, boolean showNametags) { + this.name = name; + this.players = new ArrayList<>(players); + this.showNametags = showNametags; + } + + /** For Gson deserialization */ + public PlayerGroup() { + this.name = "New Group"; + this.players = new ArrayList<>(); + this.showNametags = true; + } + + @NotNull + public String getName() { + return name; + } + + public void setName(@NotNull String name) { + this.name = name; + } + + @NotNull + public List getPlayers() { + return players; + } + + public void setPlayers(@NotNull List players) { + this.players = new ArrayList<>(players); + } + + public boolean isShowNametags() { + return showNametags; + } + + public void setShowNametags(boolean showNametags) { + this.showNametags = showNametags; + } + + /** Returns true if the given (lowercased) player name is in this group. */ + public boolean containsPlayer(@NotNull String nameLower) { + return players.contains(nameLower); + } +} diff --git a/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java b/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java index b8a1a9b..c09a146 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java @@ -24,7 +24,7 @@ public abstract class EntityMixin { @Inject(method = "spawnSprintingParticles", at = @At("HEAD"), cancellable = true) private void spawnSprintingParticles(CallbackInfo ci) { - if (!EventUtils.MOD.hidePlayers) return; + if (!EventUtils.isInHidePlayersMode()) return; final ClientPlayerEntity mainPlayer = MinecraftClient.getInstance().player; if (mainPlayer == null) return; final EntityType type = getType(); @@ -32,7 +32,7 @@ private void spawnSprintingParticles(CallbackInfo ci) { if (type == EntityType.PLAYER) { // Players final String name = getName().getString().toLowerCase(); - if (mainPlayer.getName().getString().toLowerCase().equals(name) || EventUtils.MOD.config.whitelistedPlayers.contains(name) || EventUtils.isNPC(name)) return; + if (mainPlayer.getName().getString().toLowerCase().equals(name) || EventUtils.isPlayerVisible(name)) return; } else { // Non-players (mob) if (!EventUtils.MOD.config.hiddenEntityTypes.contains(type)) return; diff --git a/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java b/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java index 4031cb5..6080e9c 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java @@ -24,13 +24,13 @@ public class EntityRenderDispatcherMixin { *///?} else { private void render(E entity, double x, double y, double z, float tickDelta, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, CallbackInfo ci) { //?} - if (!EventUtils.MOD.hidePlayers) return; + if (!EventUtils.isInHidePlayersMode()) return; if (entity instanceof PlayerEntity player) { // Players if (player.isMainPlayer()) return; final String name = player.getName().getString().toLowerCase(); - if (EventUtils.MOD.config.whitelistedPlayers.contains(name) || EventUtils.isNPC(name)) return; + if (EventUtils.isPlayerVisible(name)) return; } else { // Non-players (mob) if (!EventUtils.MOD.config.hiddenEntityTypes.contains(entity.getType())) return; diff --git a/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java b/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java index 42a1f6f..2d0910d 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java @@ -31,7 +31,7 @@ public class PlayerEntityRendererMixin { *///?} else { public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { //?} - if (!EventUtils.MOD.hidePlayers) return; + if (!EventUtils.isInHidePlayersMode()) return; final ClientPlayerEntity clientPlayer = MinecraftClient.getInstance().player; if (clientPlayer == null) return; @@ -51,14 +51,19 @@ public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, Matr if (name.equals(clientPlayer.getName().getString().toLowerCase())) return; //?} - // Checks - if (EventUtils.MOD.config.whitelistedPlayers.contains(name) || EventUtils.isNPC(name)) return; - - // Any radius - if (EventUtils.MOD.config.hidePlayersRadius == 0) { + // Not visible in current view mode -> hide nametag + if (!EventUtils.isPlayerVisible(name)) { ci.cancel(); return; } + // Visible: respect per-group nametag setting + if (!EventUtils.shouldShowNametagFor(name)) { + ci.cancel(); + return; + } + + // Any radius + if (EventUtils.MOD.config.hidePlayersRadius == 0) return; // Get player position //? if <1.21.3 { diff --git a/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java b/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java index 081bdf5..508b1b5 100644 --- a/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java +++ b/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java @@ -38,10 +38,10 @@ public static void connect(@NotNull String ip) { client.execute(() -> { try { //? if >=1.21.6 { - /*client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false); - *///?} else { - client.disconnect(); - //?} + client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false); + //?} else { + /*client.disconnect(); + *///?} //? if <=1.20.4 { /*ConnectScreen.connect(screen, client, address, new ServerInfo("EventUtils Event Server", ip, ServerInfo.ServerType.OTHER), true); diff --git a/src/main/resources/assets/eventutils/lang/en_us.json b/src/main/resources/assets/eventutils/lang/en_us.json index 89abe08..895c7c9 100644 --- a/src/main/resources/assets/eventutils/lang/en_us.json +++ b/src/main/resources/assets/eventutils/lang/en_us.json @@ -31,6 +31,9 @@ "key.eventutils.eventinfo": "Event Info", "eventutils.hideplayers.enabled": "Enabled hide players!", "eventutils.hideplayers.disabled": "Disabled hide players!", + "eventutils.hideplayers.view_prefix": "View: ", + "eventutils.hideplayers.view_revealed": "Players Revealed", + "eventutils.hideplayers.view_whitelist_only": "Whitelist Only", "eventutils.updatechecker.new": "There is a new update available!", "eventutils.updatechecker.hover": "Click to open download", @@ -80,6 +83,17 @@ "eventutils.config.radius.description": "Hides all the players in the specified radius, set to 0 to ignore distance", "eventutils.config.use_testing_api.title": "Use Testing API", "eventutils.config.use_testing_api.description": "(ADVANCED) Whether to use the testing API for the mod", + "eventutils.config.groups.category": "Groups", + "eventutils.config.groups.manage_title": "Manage Groups", + "eventutils.config.groups.manage_description": "Create and edit groups for player visibility and group chat. Use the Hide Players key to cycle: Group 1 → Group 2 → ... → Players Revealed.", + "eventutils.config.groups.add": "Add Group", + "eventutils.config.groups.edit_title": "Edit Group", + "eventutils.config.groups.name_label": "Name:", + "eventutils.config.groups.name_hint": "Group name", + "eventutils.config.groups.players_label": "Players:", + "eventutils.config.groups.players_hint": "player1, player2, ...", + "eventutils.config.groups.nametags_on": "Nametags: On", + "eventutils.config.groups.nametags_off": "Nametags: Off", "eventutils.sound.alarm": "Alarm", "eventutils.sound.alert": "Alert", @@ -108,6 +122,7 @@ "eventutils.command.countname.noplayers": "%s§c No players found with '%s§c' in their name!", "eventutils.command.countname.count": "%s§e Found %s §eplayer%s §ewith '%s§e' in their name.", "eventutils.command.countname.list": "%s§e Found %s §eplayer%s §ewith '%s§e' in their name§e: %s", + "eventutils.command.groupmsg.no_group": "%s§c No group named '%s§c' found.", "eventutils.word.plural": "s" } \ No newline at end of file diff --git a/stonecutter.gradle.kts b/stonecutter.gradle.kts index 10efe16..f5a87a6 100644 --- a/stonecutter.gradle.kts +++ b/stonecutter.gradle.kts @@ -1,6 +1,6 @@ plugins { id("dev.kikugie.stonecutter") } -stonecutter active "1.21.4" /* [SC] DO NOT EDIT */ +stonecutter active "1.21.6" /* [SC] DO NOT EDIT */ stonecutter.registerChiseled(tasks.register("chiseledBuild", stonecutter.chiseled) { group = "project" From b03eb8e13297498a8d2ceb8c7168e8eb89b89e5a Mon Sep 17 00:00:00 2001 From: QWERTZexe Date: Sun, 15 Mar 2026 13:46:02 +0100 Subject: [PATCH 2/9] Added german translations --- .../assets/eventutils/lang/de_de.json | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/main/resources/assets/eventutils/lang/de_de.json diff --git a/src/main/resources/assets/eventutils/lang/de_de.json b/src/main/resources/assets/eventutils/lang/de_de.json new file mode 100644 index 0000000..a067316 --- /dev/null +++ b/src/main/resources/assets/eventutils/lang/de_de.json @@ -0,0 +1,128 @@ +{ + "key.category.eventutils": "EventUtils", + "key.eventutils.screen": "Bildschirm öffnen", + "subtitles.eventutils.alert": "Event Benachrichtigung", + + "eventutils.skeppy.display": "Skeppy Events", + "eventutils.potential_famous.display": "Mögliche Skeppy Events", + "eventutils.sighting.display": "Skeppy Sichtungen", + "eventutils.famous.display": "Berühmte Events", + "eventutils.partner.display": "Partner Events", + "eventutils.community.display": "Community Events", + "eventutils.money.display": "Geld Events", + "eventutils.fun.display": "Spaß Events", + "eventutils.housing.display": "Housing Events", + "eventutils.civilization.display": "Zivilisation Events", + + "eventutils.skeppy.new": "Neues Skeppy Event!", + "eventutils.potential_famous.new": "Neues Potentielles Skeppy Event!", + "eventutils.sighting.new": "Neue Skeppy Sichtung!", + "eventutils.famous.new": "Neues Berühmtes Event!", + "eventutils.partner.new": "Neues Partner Event!", + "eventutils.community.new": "Neues Community Event!", + "eventutils.money.new": "Neues Geld Event!", + "eventutils.fun.new": "Neues Spaß Event!", + "eventutils.housing.new": "Neues Housing Event!", + "eventutils.civilization.new": "Neues Zivilisation Event!", + + "eventutils.event.teleport": "Schreibe '{command}', um zu teleportieren!", + + "key.eventutils.hideplayers": "Verstecke Spieler", + "key.eventutils.eventinfo": "Event Details", + "eventutils.hideplayers.enabled": "Aktiviere Verstecke Spieler!", + "eventutils.hideplayers.disabled": "Deaktiviere Verstecke Spieler!", + "eventutils.hideplayers.view_prefix": "Ansicht: ", + "eventutils.hideplayers.view_revealed": "Alle Spieler sichtbar", + "eventutils.hideplayers.view_whitelist_only": "Nur Whitelist", + + "eventutils.updatechecker.new": "Neues Update verfügbar!", + "eventutils.updatechecker.hover": "Klicke, um den Download zu öffnen", + "eventutils.updatechecker.config": "Du kannst diese Nachricht in der Konfiguration deaktivieren", + + "eventutils.command.no_event_specified": "Kein Event Typ angegeben!", + "eventutils.command.no_event_found": "Kein Event/IP gefunden für ", + "eventutils.command.config": "Öffne EventUtils' Konfigurationsbildschirm", + "eventutils.command.teleport": "Teleportiere zum letzten geposteten Event dieses Typs", + + "eventutils.confirm_exit.title": "Spiel beenden bestätigen", + "eventutils.confirm_exit.message": "Bist du sicher, dass du das Spiel beenden möchtest?", + + "eventutils.confirm_disconnect.title": "Verbindung trennen bestätigen", + "eventutils.confirm_disconnect.message": "Bist du sicher, dass du die Verbindung trennen möchtest?", + + "eventutils.no_recent_event.message": "Kein Event ist vor kurzem passiert!", + + "eventutils.config.title": "EventUtils Mod Konfiguration", + "eventutils.config.general": "Generell", + "eventutils.config.alerts": "Alarme", + "eventutils.config.alerts.toggles": "Umschalter", + "eventutils.config.alerts.sounds": "Sounds", + "eventutils.config.event_description": "Ob du für {event} gepingt werden sollst", + "eventutils.config.sound_description": "Der Sound, der abgespielt werden soll, wenn {event} gepingt wird", + "eventutils.config.teleport.title": "Automatischer Teleport", + "eventutils.config.teleport.description": "Teleportiere automatisch zum Server, wenn ein Event startet", + "eventutils.config.queue.title": "Einfache Warteschlangennachricht", + "eventutils.config.queue.description": "Vereinfacht die Warteschlangennachricht für InvadedLands", + "eventutils.config.discord.title": "Discord RPC", + "eventutils.config.discord.description": "Ob die Discord Rich Presence angezeigt werden soll", + "eventutils.config.update.title": "Mod Update Checker", + "eventutils.config.update.description": "Ob der Mod Update Checker aktiviert werden soll", + "eventutils.config.window.title": "Spielfenster schließen bestätigen", + "eventutils.config.window.description": "Ob eine Bestätigung angezeigt werden soll, um zu bestätigen, dass du das Spielfenster schließen möchtest", + "eventutils.config.disconnect.title": "Verbindung trennen bestätigen", + "eventutils.config.disconnect.description": "Ob eine Bestätigung angezeigt werden soll, um zu bestätigen, dass du die Verbindung trennen möchtest", + "eventutils.config.famous.title": "Standard IP für berühmte Events", + "eventutils.config.famous.description": "Die Standard IP für berühmte Events, wenn keine IP eingegeben wird", + "eventutils.config.entity.title": "Verborgene Entity Typen", + "eventutils.config.entity.description": "Die Typen von Entitäten, die verborgen werden sollen", + "eventutils.config.players.title": "Erlaubte Spieler", + "eventutils.config.players.description": "Die Namen der Spieler, die du sehen kannst, wenn Spieler verborgen sind", + "eventutils.config.npchide.title": "Verstecke NPCs", + "eventutils.config.npchide.description": "Ob der Mod NPCs verstecken wird", + "eventutils.config.radius.title": "Verstecke Spieler in Radius", + "eventutils.config.radius.description": "Versteckt alle Spieler in dem angegebenen Radius, setzt auf 0, um die Entfernung zu ignorieren", + "eventutils.config.use_testing_api.title": "Testing API benutzen", + "eventutils.config.use_testing_api.description": "(FORTGESCHRITTEN) Ob die Testing API für den Mod benutzt werden soll", + "eventutils.config.groups.category": "Gruppen", + "eventutils.config.groups.manage_title": "Gruppen verwalten", + "eventutils.config.groups.manage_description": "Gruppen für Sichtbarkeit und Gruppenchat anlegen und bearbeiten. Nutze die Taste „Verstecke Spieler“, um zu wechseln: Gruppe 1 → Gruppe 2 → … → Alle sichtbar.", + "eventutils.config.groups.add": "Gruppe hinzufügen", + "eventutils.config.groups.edit_title": "Gruppe bearbeiten", + "eventutils.config.groups.name_label": "Name:", + "eventutils.config.groups.name_hint": "Gruppenname", + "eventutils.config.groups.players_label": "Spieler:", + "eventutils.config.groups.players_hint": "spieler1, spieler2, ...", + "eventutils.config.groups.nametags_on": "Namensschilder: An", + "eventutils.config.groups.nametags_off": "Namensschilder: Aus", + + "eventutils.sound.alarm": "Alarm", + "eventutils.sound.alert": "Benachrichtigung", + "eventutils.sound.calm": "Ruhe", + "eventutils.sound.cat": "Katze", + "eventutils.sound.chime": "Glocke", + "eventutils.sound.goofy": "Lächerlich", + "eventutils.sound.pluck": "Pflücken", + "eventutils.sound.reverb": "Echoverb", + "eventutils.sound.shakey": "Schütteln", + "eventutils.sound.time_of_war": "Zeit des Kriegs", + + "eventutils.screen.settings": "Einstellungen", + + "eventutils.command.priority.self": "%s§e Du hast Pickup Priorität %s §ebasiert auf den Leuten um dich herum.", + "eventutils.command.priority.player": "%s§e %s§e hat Pickup Priorität %s §ebasiert auf den Leuten um dich herum.", + "eventutils.command.priority.noplayer": "%s§c Spieler nicht gefunden!", + + "eventutils.command.prioritytop.page": "%s§e Seite %s §evon %s\n\n", + "eventutils.command.prioritytop.emptypage": "%s§c Keine Spieler gefunden!", + "eventutils.command.prioritytop.notapage": "%s§c Diese Seite wurde nicht gefunden! (Höchste Seite ist Seite %s§c)", + "eventutils.command.prioritytop.nextpage": "§6[§7>%s§6 Nächste Seite] ", + "eventutils.command.prioritytop.lastpage": "§6[§7%s<§6 Letzte Seite] ", + "eventutils.command.prioritytop.pagebutton": "%s§e %s%s§7(Klicken)", + + "eventutils.command.countname.noplayers": "%s§c Keine Spieler gefunden mit '%s§c' in ihrem Namen!", + "eventutils.command.countname.count": "%s§e Gefunden %s §eSpieler%s §ewith '%s§e' in ihrem Namen.", + "eventutils.command.countname.list": "%s§e Gefunden %s §eSpieler%s §emit '%s§e' im Namen§e: %s", + "eventutils.command.groupmsg.no_group": "%s§c Keine Gruppe mit dem Namen '%s§c' gefunden.", + + "eventutils.word.plural": "" +} \ No newline at end of file From 8814113d759575bde1f941d6edc72d3fc4f4d85c Mon Sep 17 00:00:00 2001 From: QWERTZexe Date: Sun, 15 Mar 2026 18:03:47 +0100 Subject: [PATCH 3/9] Added 1.21.11 support, Added Plus Tags --- .github/workflows/publish.yml | 1 + build.gradle.kts | 2 +- crop_sheet.py | 81 +++++++ gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle.kts | 1 + sheet.png | Bin 0 -> 31517 bytes src/main/java/app/qwertz/EventAlertsApi.java | 212 ++++++++++++++++++ src/main/java/app/qwertz/PlusTag.java | 86 +++++++ src/main/java/app/qwertz/PlusTagRenderer.java | 27 +++ src/main/java/app/qwertz/PlusTagScreen.java | 96 ++++++++ src/main/java/app/qwertz/commands/TagCmd.java | 34 +++ .../app/qwertz/mixin/PlayerListHudMixin.java | 83 +++++++ .../cc/aabss/eventutils/EventInfoScreen.java | 6 +- .../java/cc/aabss/eventutils/EventUtils.java | 16 ++ .../cc/aabss/eventutils/KeybindManager.java | 33 ++- .../eventutils/commands/CommandRegister.java | 7 + .../eventutils/commands/CountNameCmd.java | 16 ++ .../aabss/eventutils/config/EventConfig.java | 21 ++ .../aabss/eventutils/mixin/EntityMixin.java | 12 +- .../mixin/EntityRenderDispatcherMixin.java | 18 +- .../mixin/PlayerEntityRendererMixin.java | 6 +- .../eventutils/utility/ConnectUtility.java | 6 +- .../assets/eventutils/lang/de_de.json | 15 ++ .../assets/eventutils/lang/en_us.json | 15 ++ .../assets/eventutils/textures/gui/README.txt | 11 + .../assets/eventutils/textures/gui/admin.png | Bin 0 -> 4099 bytes .../assets/eventutils/textures/gui/bee.png | Bin 0 -> 3916 bytes .../eventutils/textures/gui/booster.png | Bin 0 -> 4127 bytes .../eventutils/textures/gui/contrib.png | Bin 0 -> 4152 bytes .../assets/eventutils/textures/gui/linked.png | Bin 0 -> 3753 bytes .../eventutils/textures/gui/plus_sheet.png | Bin 0 -> 31517 bytes .../assets/eventutils/textures/gui/white.png | Bin 0 -> 3919 bytes src/main/resources/eventutils.mixin.json | 3 +- stonecutter.gradle.kts | 2 +- versions/1.21.11/gradle.properties | 6 + 35 files changed, 798 insertions(+), 20 deletions(-) create mode 100644 crop_sheet.py create mode 100644 sheet.png create mode 100644 src/main/java/app/qwertz/EventAlertsApi.java create mode 100644 src/main/java/app/qwertz/PlusTag.java create mode 100644 src/main/java/app/qwertz/PlusTagRenderer.java create mode 100644 src/main/java/app/qwertz/PlusTagScreen.java create mode 100644 src/main/java/app/qwertz/commands/TagCmd.java create mode 100644 src/main/java/app/qwertz/mixin/PlayerListHudMixin.java create mode 100644 src/main/resources/assets/eventutils/textures/gui/README.txt create mode 100644 src/main/resources/assets/eventutils/textures/gui/admin.png create mode 100644 src/main/resources/assets/eventutils/textures/gui/bee.png create mode 100644 src/main/resources/assets/eventutils/textures/gui/booster.png create mode 100644 src/main/resources/assets/eventutils/textures/gui/contrib.png create mode 100644 src/main/resources/assets/eventutils/textures/gui/linked.png create mode 100644 src/main/resources/assets/eventutils/textures/gui/plus_sheet.png create mode 100644 src/main/resources/assets/eventutils/textures/gui/white.png create mode 100644 versions/1.21.11/gradle.properties diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f967e81..6badfbd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -48,6 +48,7 @@ jobs: strategy: matrix: game_version: [ # Update this when adding new game versions! + "1.21.11", "1.21.6", "1.21.5", "1.21.4", diff --git a/build.gradle.kts b/build.gradle.kts index 2a4629d..3074c9f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ import xyz.srnyx.gradlegalaxy.utility.setupJava plugins { java - id("fabric-loom") version "1.11-SNAPSHOT" + id("fabric-loom") version "1.14-SNAPSHOT" id("xyz.srnyx.gradle-galaxy") version "2.0.2" } diff --git a/crop_sheet.py b/crop_sheet.py new file mode 100644 index 0000000..a18b17f --- /dev/null +++ b/crop_sheet.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python3 +# Copyright 2026 QWERTZexe ALL RIGHTS RESERVED +"""Crop sheet.png (3 cols x 2 rows) into individual plus-tag icons with transparent background.""" +from pathlib import Path + +try: + from PIL import Image +except ImportError: + print("Install Pillow: pip install Pillow") + raise + +# Order: row0 = bee, white, linked; row1 = booster, contrib, admin +NAMES = ["bee", "white", "linked", "booster", "contrib", "admin"] +ICON_SIZE = 64 # match PlusTagRenderer.TEX_SIZE for sharp in-game scaling +# Pixels within this distance of the sheet background color become transparent (0–255 per channel) +BG_TOLERANCE = 25 + +SCRIPT_DIR = Path(__file__).resolve().parent +OUT_DIR = SCRIPT_DIR / "src" / "main" / "resources" / "assets" / "eventutils" / "textures" / "gui" +# Prefer sheet in project root, then plus_sheet in gui folder +SHEET_CANDIDATES = [SCRIPT_DIR / "sheet.png", OUT_DIR / "plus_sheet.png"] + + +def make_bg_transparent(img: Image.Image, bg_rgba: tuple, tolerance: int) -> Image.Image: + """Replace pixels matching the background color (within tolerance) with transparent.""" + data = img.getdata() + r0, g0, b0, a0 = bg_rgba + out = [] + for p in data: + if len(p) == 3: + r, g, b = p + if abs(r - r0) <= tolerance and abs(g - g0) <= tolerance and abs(b - b0) <= tolerance: + out.append((0, 0, 0, 0)) + else: + out.append((r, g, b, 255)) + else: + r, g, b, a = p + if abs(r - r0) <= tolerance and abs(g - g0) <= tolerance and abs(b - b0) <= tolerance: + out.append((0, 0, 0, 0)) + else: + out.append((r, g, b, a)) + img.putdata(out) + return img + + +def main(): + SHEET = next((p for p in SHEET_CANDIDATES if p.exists()), None) + if SHEET is None: + print(f"Not found: tried {SHEET_CANDIDATES}") + return 1 + print(f"Using sheet: {SHEET}") + img = Image.open(SHEET).convert("RGBA") + w, h = img.size + # Use top-left corner as background color + bg_rgba = img.getpixel((0, 0)) + if len(bg_rgba) == 3: + bg_rgba = (bg_rgba[0], bg_rgba[1], bg_rgba[2], 255) + print(f"Background color (will be made transparent): {bg_rgba}") + + col_w = w // 3 + row_h = h // 2 + OUT_DIR.mkdir(parents=True, exist_ok=True) + idx = 0 + for row in range(2): + for col in range(3): + x = col * col_w + y = row * row_h + cw = (w - x) if col == 2 else col_w + ch = (h - y) if row == 1 else row_h + crop = img.crop((x, y, x + cw, y + ch)) + crop = crop.resize((ICON_SIZE, ICON_SIZE), Image.Resampling.LANCZOS) + crop = make_bg_transparent(crop, bg_rgba, BG_TOLERANCE) + out_path = OUT_DIR / f"{NAMES[idx]}.png" + crop.save(out_path) + print(f"Saved {out_path.name} ({ICON_SIZE}x{ICON_SIZE}, transparent bg)") + idx += 1 + print("Done.") + return 0 + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2e11132..23449a2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/settings.gradle.kts b/settings.gradle.kts index d0b80aa..028f65a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -10,6 +10,7 @@ stonecutter { centralScript = "build.gradle.kts" shared { versions( // Make sure to update .github/workflows/publish.yml when changing versions! + "1.21.11", "1.21.6", "1.21.5", "1.21.4", diff --git a/sheet.png b/sheet.png new file mode 100644 index 0000000000000000000000000000000000000000..3848d161b8df939fdbcd9a10fe23a4843bef4c8b GIT binary patch literal 31517 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 z%0D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 EAEKTY$p8QV literal 0 HcmV?d00001 diff --git a/src/main/java/app/qwertz/EventAlertsApi.java b/src/main/java/app/qwertz/EventAlertsApi.java new file mode 100644 index 0000000..a72028e --- /dev/null +++ b/src/main/java/app/qwertz/EventAlertsApi.java @@ -0,0 +1,212 @@ +/* + * Copyright 2026 QWERTZexe ALL RIGHTS RESERVED + */ + +package app.qwertz; + +import cc.aabss.eventutils.EventUtils; +import cc.aabss.eventutils.Versions; +import cc.aabss.eventutils.config.EventConfig; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.EnumSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + + +/** + * Fetches player data from Event Alerts API to determine unlocked plus tags. + * API: GET https://eventalerts.gg/api/v1/players/minecraft/uuid/{uuid} + */ +public final class EventAlertsApi { + private static final String API_BASE = "https://eventalerts.gg"; + private static final String API_PATH = "/api/v1/players/minecraft/uuid/"; + + private static final HttpClient HTTP = HttpClient.newBuilder().build(); + /** Cache: UUID (no dashes) -> unlocked tags. Cleared on world unload. */ + private static final ConcurrentHashMap> CACHE = new ConcurrentHashMap<>(); + /** UUIDs we've already scheduled a fetch for (avoid duplicate requests until cache clear). */ + private static final Set FETCH_SCHEDULED = ConcurrentHashMap.newKeySet(); + + private EventAlertsApi() {} + + @NotNull + public static String getApiBase() { + return EventUtils.MOD.config.useTestingApi ? "http://localhost:9090" : API_BASE; + } + + /** Convert 32-char hex (no dashes) to standard UUID form with dashes: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx */ + @NotNull + private static String toDashedUuid(@NotNull String key32) { + return key32.substring(0, 8) + "-" + key32.substring(8, 12) + "-" + key32.substring(12, 16) + "-" + key32.substring(16, 20) + "-" + key32.substring(20, 32); + } + + /** Fetch unlocked plus tags for a Minecraft UUID (with or without dashes). Returns empty set on failure. */ + @NotNull + public static Set fetchUnlockedTags(@NotNull String minecraftUuid) { + String key = minecraftUuid.replace("-", "").toLowerCase(); + if (key.length() != 32) { + EventUtils.LOGGER.debug("[EventAlerts] fetchUnlockedTags: invalid UUID length key={} len={}", key, key.length()); + return Set.of(); + } + + Set cached = CACHE.get(key); + if (cached != null) { + EventUtils.LOGGER.debug("[EventAlerts] fetchUnlockedTags: cache HIT uuid={} tags={}", key, cached); + return cached; + } + + EventUtils.LOGGER.info("[EventAlerts] Fetching tags for uuid={}", key); + try { + String url = getApiBase() + API_PATH + toDashedUuid(key); + EventUtils.LOGGER.debug("[EventAlerts] GET {}", url); + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(url)) + .header("User-Agent", "EventUtils/" + Versions.EU_VERSION + " (Minecraft/" + Versions.MC_VERSION + ")") + .GET() + .build(); + HttpResponse response = HTTP.send(request, HttpResponse.BodyHandlers.ofString()); + EventUtils.LOGGER.debug("[EventAlerts] response status={} bodyLength={}", response.statusCode(), response.body().length()); + if (response.statusCode() != 200) { + EventUtils.LOGGER.warn("[EventAlerts] API returned status={} body={}", response.statusCode(), response.body()); + return Set.of(); + } + + JsonObject root = JsonParser.parseString(response.body()).getAsJsonObject(); + // API may wrap data in "player": { ... } (player can be null if not found) + JsonObject data; + if (root.has("player") && !root.get("player").isJsonNull() && root.get("player").isJsonObject()) { + data = root.getAsJsonObject("player"); + EventUtils.LOGGER.debug("[EventAlerts] using wrapped player object"); + } else if (!root.has("player")) { + data = root; + EventUtils.LOGGER.debug("[EventAlerts] using root as data (no player wrapper)"); + } else { + EventUtils.LOGGER.info("[EventAlerts] API response: player=null (not linked or not found)"); + return Set.of(); // player: null + } + Set unlocked = parseUnlockedTags(data); + EventUtils.LOGGER.debug("[EventAlerts] parsed unlocked tags={} for uuid={}", unlocked, key); + CACHE.put(key, unlocked); + EventUtils.LOGGER.info("[EventAlerts] Fetched uuid={} tags={}", key, unlocked); + return unlocked; + } catch (Exception e) { + EventUtils.LOGGER.warn("[EventAlerts] Fetch failed uuid={} error={}", key, e.getMessage(), e); + return Set.of(); + } + } + + /** Parse API response into unlocked tags. Expects player object: id, discord, minecraft, subscription (1=premium/Bee), anniversaries, roles (optional). */ + @NotNull + private static Set parseUnlockedTags(@NotNull JsonObject root) { + Set out = EnumSet.noneOf(PlusTag.class); + + // Linked: has discord and minecraft + if (root.has("discord") && root.has("minecraft")) { + JsonObject mc = root.getAsJsonObject("minecraft"); + if (mc != null && mc.has("uuid")) { + out.add(PlusTag.NONE); // "Linked" icon + EventUtils.LOGGER.debug("[EventAlerts] parse: +NONE (linked, discord+minecraft.uuid)"); + } + } + + // Bee / Premium: subscription tier, premium flag, or subscription object + if (root.has("subscription")) { + JsonElement sub = root.get("subscription"); + if (sub != null && !sub.isJsonNull()) { + if (sub.isJsonPrimitive()) { + if (sub.getAsJsonPrimitive().isNumber()) { + int v = sub.getAsInt(); + if (v >= 1) { + out.add(PlusTag.ORANGE); + EventUtils.LOGGER.debug("[EventAlerts] parse: +ORANGE (subscription number={})", v); + } + } else if (sub.getAsJsonPrimitive().isBoolean() && sub.getAsBoolean()) { + out.add(PlusTag.ORANGE); + EventUtils.LOGGER.debug("[EventAlerts] parse: +ORANGE (subscription boolean true)"); + } + } else if (sub.isJsonObject()) { + JsonObject obj = sub.getAsJsonObject(); + if (obj.has("tier") && obj.get("tier").getAsInt() >= 1) { + out.add(PlusTag.ORANGE); + EventUtils.LOGGER.debug("[EventAlerts] parse: +ORANGE (subscription.tier)"); + } else if (obj.has("active") && obj.get("active").getAsBoolean()) { + out.add(PlusTag.ORANGE); + EventUtils.LOGGER.debug("[EventAlerts] parse: +ORANGE (subscription.active)"); + } + } + } + } + if (root.has("premium") && root.get("premium").getAsBoolean()) { + out.add(PlusTag.ORANGE); + EventUtils.LOGGER.debug("[EventAlerts] parse: +ORANGE (premium)"); + } + if (root.has("isPremium") && root.get("isPremium").getAsBoolean()) { + out.add(PlusTag.ORANGE); + EventUtils.LOGGER.debug("[EventAlerts] parse: +ORANGE (isPremium)"); + } + + // Booster: often a role or field. Check for "booster" boolean or roles array + if (root.has("booster") && root.get("booster").getAsBoolean()) { + out.add(PlusTag.PINK); + EventUtils.LOGGER.debug("[EventAlerts] parse: +PINK (booster)"); + } + if (root.has("roles")) { + JsonArray roles = root.getAsJsonArray("roles"); + for (JsonElement e : roles) { + String r = e.getAsString().toUpperCase(); + if (r.contains("BOOSTER")) { out.add(PlusTag.PINK); EventUtils.LOGGER.debug("[EventAlerts] parse: +PINK (roles contains BOOSTER)"); } + if (r.contains("ADMIN")) { out.add(PlusTag.RED); EventUtils.LOGGER.debug("[EventAlerts] parse: +RED (roles contains ADMIN)"); } + if (r.contains("DEV") || r.contains("CONTRIBUTOR")) { out.add(PlusTag.BLUE); EventUtils.LOGGER.debug("[EventAlerts] parse: +BLUE (roles DEV/CONTRIBUTOR)"); } + } + } + + // Some APIs use role names instead of IDs + if (root.has("rolesNamed")) { + JsonArray roles = root.getAsJsonArray("rolesNamed"); + for (JsonElement e : roles) { + String r = e.getAsString().toUpperCase(); + if ("BOOSTER".equals(r)) { out.add(PlusTag.PINK); EventUtils.LOGGER.debug("[EventAlerts] parse: +PINK (rolesNamed BOOSTER)"); } + if ("ADMIN".equals(r)) { out.add(PlusTag.RED); EventUtils.LOGGER.debug("[EventAlerts] parse: +RED (rolesNamed ADMIN)"); } + if ("DEVELOPER".equals(r) || "CONTRIBUTOR".equals(r)) { out.add(PlusTag.BLUE); EventUtils.LOGGER.debug("[EventAlerts] parse: +BLUE (rolesNamed)"); } + } + } + + return out; + } + + /** Clear cache (e.g. on disconnect). */ + public static void clearCache() { + int size = CACHE.size(); + CACHE.clear(); + FETCH_SCHEDULED.clear(); + EventUtils.LOGGER.info("[EventAlerts] Cache cleared (was {} entries)", size); + } + + /** Schedule a fetch for this UUID if not cached and not already scheduled. Call from main thread. */ + public static void scheduleFetchIfNeeded(@NotNull String minecraftUuid) { + String key = minecraftUuid.replace("-", "").toLowerCase(); + if (key.length() != 32) return; + if (CACHE.containsKey(key)) return; + if (!FETCH_SCHEDULED.add(key)) return; // already scheduled + EventUtils.LOGGER.info("[EventAlerts] Scheduling fetch for uuid={}", key); + EventUtils.MOD.scheduler.execute(() -> EventAlertsApi.fetchUnlockedTags(minecraftUuid)); + } + + /** Get cached unlocked tags for UUID, or null if not cached. (No per-call debug log to avoid spam from tab list.) */ + @Nullable + public static Set getCached(@NotNull String minecraftUuid) { + return CACHE.get(minecraftUuid.replace("-", "").toLowerCase()); + } +} diff --git a/src/main/java/app/qwertz/PlusTag.java b/src/main/java/app/qwertz/PlusTag.java new file mode 100644 index 0000000..5b79114 --- /dev/null +++ b/src/main/java/app/qwertz/PlusTag.java @@ -0,0 +1,86 @@ +/* + * Copyright 2026 QWERTZexe ALL RIGHTS RESERVED + */ + +package app.qwertz; + +import cc.aabss.eventutils.EventUtils; + +import net.minecraft.util.Identifier; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +/** + * Plus (+) icon tag displayed next to names. Unlocked by linking Discord and roles. + * Each tag uses its own texture file (no in-game slicing). + */ +public enum PlusTag { + /** Linked (gray) - from linking Discord */ + NONE("none", "linked", "eventutils.plustag.unlock.linked"), + /** Unused (white +) */ + WHITE("white", "white", null), + /** Admin */ + RED("red", "admin", "eventutils.plustag.unlock.admin"), + /** Developer / Contributor */ + BLUE("blue", "contrib", "eventutils.plustag.unlock.contributor"), + /** Bee subscription */ + ORANGE("orange", "bee", "eventutils.plustag.unlock.bee"), + /** Booster */ + PINK("pink", "booster", "eventutils.plustag.unlock.booster"); + + private final String key; + @NotNull private final Identifier textureId; + @NotNull private final String unlockKey; + + PlusTag(@NotNull String key, @NotNull String textureName, String unlockKey) { + this.key = key; + this.textureId = Identifier.of("eventutils", "textures/gui/" + textureName + ".png"); + this.unlockKey = unlockKey != null ? unlockKey : "eventutils.plustag.unlock.none"; + } + + @NotNull + public String getKey() { + return key; + } + + @NotNull + public Identifier getTextureId() { + return textureId; + } + + @NotNull + public String getUnlockKey() { + return unlockKey; + } + + /** Priority for "best" tag when we don't know the player's choice (higher = show first). */ + private int displayPriority() { + return switch (this) { + case RED -> 5; + case BLUE -> 4; + case ORANGE -> 3; + case PINK -> 2; + case NONE -> 1; + case WHITE -> 0; + }; + } + + /** Pick the best tag to show for another player from their unlocked set (admin > contrib > bee > booster > linked). */ + @Nullable + public static PlusTag pickBestForDisplay(@Nullable Set unlocked) { + if (unlocked == null || unlocked.isEmpty()) { + EventUtils.LOGGER.debug("[PlusTag] pickBestForDisplay: unlocked={} -> null", unlocked); + return null; + } + PlusTag best = null; + for (PlusTag t : unlocked) { + if (t == WHITE) continue; + if (best == null || t.displayPriority() > best.displayPriority()) best = t; + } + EventUtils.LOGGER.debug("[PlusTag] pickBestForDisplay: unlocked={} -> best={}", unlocked, best); + return best; + } +} diff --git a/src/main/java/app/qwertz/PlusTagRenderer.java b/src/main/java/app/qwertz/PlusTagRenderer.java new file mode 100644 index 0000000..c2d4b67 --- /dev/null +++ b/src/main/java/app/qwertz/PlusTagRenderer.java @@ -0,0 +1,27 @@ +/* + * Copyright 2026 QWERTZexe ALL RIGHTS RESERVED + */ + +package app.qwertz; + +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gl.RenderPipelines; + +import org.jetbrains.annotations.NotNull; + +/** + * Draws the plus tag icon (full texture, no slicing). + * Expects 64x64 textures in assets/eventutils/textures/gui/ (drawn at the given size for a sharp look): + * linked.png, bee.png, booster.png, contrib.png, admin.png, white.png. + */ +public final class PlusTagRenderer { + private static final int TEX_SIZE = 64; + + private PlusTagRenderer() {} + + /** Draw the icon at (x, y) with the given size (e.g. 8 for tab list). Samples full 64x64 texture, scaled to size. */ + public static void draw(@NotNull DrawContext context, @NotNull PlusTag tag, int x, int y, int size) { + if (tag == PlusTag.WHITE) return; // unused, skip + context.drawTexture(RenderPipelines.GUI_TEXTURED, tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE, TEX_SIZE, TEX_SIZE); + } +} diff --git a/src/main/java/app/qwertz/PlusTagScreen.java b/src/main/java/app/qwertz/PlusTagScreen.java new file mode 100644 index 0000000..4d0b3ad --- /dev/null +++ b/src/main/java/app/qwertz/PlusTagScreen.java @@ -0,0 +1,96 @@ +/* + * Copyright 2026 QWERTZexe ALL RIGHTS RESERVED + */ + +package app.qwertz; + +import cc.aabss.eventutils.EventUtils; + +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.tooltip.Tooltip; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.text.Text; + +import org.jetbrains.annotations.Nullable; + +import java.util.Set; + +import static net.minecraft.text.Text.translatable; + + +/** + * Screen to choose which plus tag to display next to your name. + * Shows only unlocked tags; hover shows how each was unlocked. + */ +public class PlusTagScreen extends Screen { + @Nullable private final Screen parent; + private final Set unlocked; + + public PlusTagScreen(@Nullable Screen parent, @Nullable Set unlocked) { + super(translatable("eventutils.plustag.title")); + this.parent = parent; + this.unlocked = unlocked != null ? unlocked : Set.of(); + } + + @Override + protected void init() { + final PlusTag current = EventUtils.MOD.config.selectedPlusTag; + int y = 40; + final int centerX = width / 2; + final int btnWidth = 200; + final int spacing = 26; + + // Option: None (hide / linked) + addTagButton(centerX - btnWidth / 2, y, btnWidth, PlusTag.NONE, current); + y += spacing; + + if (unlocked.contains(PlusTag.WHITE)) { + addTagButton(centerX - btnWidth / 2, y, btnWidth, PlusTag.WHITE, current); + y += spacing; + } + + if (unlocked.contains(PlusTag.RED)) { + addTagButton(centerX - btnWidth / 2, y, btnWidth, PlusTag.RED, current); + y += spacing; + } + + if (unlocked.contains(PlusTag.BLUE)) { + addTagButton(centerX - btnWidth / 2, y, btnWidth, PlusTag.BLUE, current); + y += spacing; + } + + if (unlocked.contains(PlusTag.ORANGE)) { + addTagButton(centerX - btnWidth / 2, y, btnWidth, PlusTag.ORANGE, current); + y += spacing; + } + + if (unlocked.contains(PlusTag.PINK)) { + addTagButton(centerX - btnWidth / 2, y, btnWidth, PlusTag.PINK, current); + y += spacing; + } + + addDrawableChild(ButtonWidget.builder(translatable("gui.done"), btn -> { + if (client != null) client.setScreen(parent); + }).dimensions(centerX - 60, height - 28, 120, 20).build()); + } + + private void addTagButton(int x, int y, int w, PlusTag tag, PlusTag current) { + Text label = translatable("eventutils.plustag." + tag.getKey()); + Text tooltipText = translatable(tag.getUnlockKey()); + boolean selected = current == tag; + ButtonWidget btn = ButtonWidget.builder(selected ? label.copy().append(" ✓") : label, b -> { + EventUtils.MOD.config.setSelectedPlusTag(tag); + if (client != null) client.setScreen(new PlusTagScreen(parent, unlocked)); + }).dimensions(x, y, w, 20).tooltip(Tooltip.of(tooltipText)).build(); + addDrawableChild(btn); + } + + @Override + public void render(DrawContext context, int mouseX, int mouseY, float delta) { + context.fill(0, 0, width, height, 0xC0101010); + context.drawCenteredTextWithShadow(textRenderer, title, width / 2, 14, 0xFFFFFF); + context.drawCenteredTextWithShadow(textRenderer, translatable("eventutils.plustag.subtitle"), width / 2, 24, 0xA0A0A0); + super.render(context, mouseX, mouseY, delta); + } +} diff --git a/src/main/java/app/qwertz/commands/TagCmd.java b/src/main/java/app/qwertz/commands/TagCmd.java new file mode 100644 index 0000000..aac4990 --- /dev/null +++ b/src/main/java/app/qwertz/commands/TagCmd.java @@ -0,0 +1,34 @@ +/* + * Copyright 2026 QWERTZexe ALL RIGHTS RESERVED + */ + +package app.qwertz.commands; + +import app.qwertz.EventAlertsApi; +import app.qwertz.PlusTagScreen; + +import cc.aabss.eventutils.EventUtils; + +import com.mojang.brigadier.context.CommandContext; + +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; + +import net.minecraft.client.MinecraftClient; + +import org.jetbrains.annotations.NotNull; + + +public class TagCmd { + public static int openTagScreen(@NotNull CommandContext context) { + MinecraftClient client = context.getSource().getClient(); + client.send(() -> { + var player = context.getSource().getPlayer(); + var unlocked = player != null + ? EventAlertsApi.getCached(player.getUuid().toString()) + : null; + EventUtils.LOGGER.debug("[TagCmd] openTagScreen: player={} uuid={} cachedUnlocked={}", player != null ? player.getName().getString() : null, player != null ? player.getUuid() : null, unlocked); + client.setScreen(new PlusTagScreen(client.currentScreen, unlocked)); + }); + return 1; + } +} diff --git a/src/main/java/app/qwertz/mixin/PlayerListHudMixin.java b/src/main/java/app/qwertz/mixin/PlayerListHudMixin.java new file mode 100644 index 0000000..61eac9c --- /dev/null +++ b/src/main/java/app/qwertz/mixin/PlayerListHudMixin.java @@ -0,0 +1,83 @@ +/* + * Copyright 2026 QWERTZexe ALL RIGHTS RESERVED + */ + +package app.qwertz.mixin; + +import app.qwertz.EventAlertsApi; +import app.qwertz.PlusTag; +import app.qwertz.PlusTagRenderer; + +import cc.aabss.eventutils.EventUtils; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.hud.PlayerListHud; +import net.minecraft.client.network.PlayerListEntry; +import net.minecraft.scoreboard.Scoreboard; +import net.minecraft.scoreboard.ScoreboardObjective; + +import java.util.Set; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + + +@Mixin(PlayerListHud.class) +public abstract class PlayerListHudMixin { + @Shadow @Final private MinecraftClient client; + + /** Draw + icon for every tab list row (local player = selected tag, others = best unlocked from Event Alerts). */ + @Inject(method = "renderLatencyIcon", at = @At("TAIL")) + private void eventutils$drawPlusTagNextToName(DrawContext context, int width, int x, int y, PlayerListEntry entry, CallbackInfo ci) { + if (client.player == null) return; + + //? if >=1.21.11 { + String name = entry.getProfile().name(); + final boolean isLocal = entry.getProfile().id().equals(client.player.getUuid()); + //?} else { + /*String name = entry.getProfile().getName(); + final boolean isLocal = entry.getProfile().getId().equals(client.player.getUuid()); + *///?} + final PlusTag tag; + + if (isLocal) { + // Fallback: if we never got a fetch (e.g. JOIN ran before player was ready), trigger it when tab list is drawn + String localUuid = client.player.getUuid().toString(); + if (EventAlertsApi.getCached(localUuid) == null) { + EventUtils.LOGGER.info("[EventUtils] Tab list: local player not cached, scheduling Event Alerts fetch uuid={}", localUuid); + EventAlertsApi.scheduleFetchIfNeeded(localUuid); + } + tag = EventUtils.MOD.config.selectedPlusTag; + EventUtils.LOGGER.debug("[TabList] entry={} isLocal=true tag=config.selectedPlusTag={}", name, tag); + } else { + //? if >=1.21.11 { + String uuid = entry.getProfile().id().toString(); + //?} else { + /*String uuid = entry.getProfile().getId().toString(); + *///?} + Set cached = EventAlertsApi.getCached(uuid); + if (cached == null) { + EventUtils.LOGGER.debug("[TabList] entry={} uuid={} cache MISS, scheduling fetch", name, uuid); + EventAlertsApi.scheduleFetchIfNeeded(uuid); + return; + } + tag = PlusTag.pickBestForDisplay(cached); + EventUtils.LOGGER.debug("[TabList] entry={} uuid={} cache HIT unlocked={} pickBest={}", name, uuid, cached, tag); + } + + if (tag == null || tag == PlusTag.WHITE) { + EventUtils.LOGGER.debug("[TabList] entry={} skip draw: tag={} (null or WHITE)", name, tag); + return; + } + + int iconSize = 8; + int iconX = x - 8; + PlusTagRenderer.draw(context, tag, iconX, y, iconSize); + EventUtils.LOGGER.debug("[TabList] entry={} DRAW tag={} at ({}, {}) size={}", name, tag, iconX, y, iconSize); + } +} diff --git a/src/main/java/cc/aabss/eventutils/EventInfoScreen.java b/src/main/java/cc/aabss/eventutils/EventInfoScreen.java index 9f2da09..0802c0b 100644 --- a/src/main/java/cc/aabss/eventutils/EventInfoScreen.java +++ b/src/main/java/cc/aabss/eventutils/EventInfoScreen.java @@ -26,7 +26,11 @@ public class EventInfoScreen extends Screen { @NotNull private final JsonObject json; public EventInfoScreen(@NotNull JsonObject json) { - super(Text.translatable(EventUtils.MOD.keybindManager.eventInfoKey.getTranslationKey())); + //? if >=1.21.11 { + super(Text.translatable(EventUtils.MOD.keybindManager.eventInfoKey.getId())); + //?} else { + /*super(Text.translatable(EventUtils.MOD.keybindManager.eventInfoKey.getTranslationKey())); + *///?} this.json = json; } diff --git a/src/main/java/cc/aabss/eventutils/EventUtils.java b/src/main/java/cc/aabss/eventutils/EventUtils.java index 222a522..67d3f7c 100644 --- a/src/main/java/cc/aabss/eventutils/EventUtils.java +++ b/src/main/java/cc/aabss/eventutils/EventUtils.java @@ -6,6 +6,7 @@ import cc.aabss.eventutils.websocket.WebSocketClient; import cc.aabss.eventutils.config.EventConfig; import cc.aabss.eventutils.config.PlayerGroup; +import app.qwertz.EventAlertsApi; import com.google.gson.JsonObject; @@ -87,6 +88,21 @@ public void onInitializeClient() { // Update checker ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> updateChecker.checkUpdate()); + // Fetch Event Alerts plus tags for local player (for tag menu) + ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> { + if (client.player != null) { + String uuid = client.player.getUuid().toString(); + LOGGER.info("[EventUtils] JOIN: scheduling Event Alerts fetch for local player uuid={}", uuid); + EventAlertsApi.scheduleFetchIfNeeded(uuid); + } else { + LOGGER.info("[EventUtils] JOIN: client.player is null, skipping fetch (will retry when tab list is opened)"); + } + }); + ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> { + LOGGER.info("[EventUtils] DISCONNECT: clearing Event Alerts cache"); + EventAlertsApi.clearCache(); + }); + // Initialize keybind manager keybindManager = new KeybindManager(this); diff --git a/src/main/java/cc/aabss/eventutils/KeybindManager.java b/src/main/java/cc/aabss/eventutils/KeybindManager.java index a28160a..2987319 100644 --- a/src/main/java/cc/aabss/eventutils/KeybindManager.java +++ b/src/main/java/cc/aabss/eventutils/KeybindManager.java @@ -10,6 +10,9 @@ import net.minecraft.client.util.InputUtil; import net.minecraft.text.Text; import net.minecraft.util.Formatting; +//? if >=1.21.11 { +import net.minecraft.util.Identifier; +//?} import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -32,22 +35,36 @@ public class KeybindManager { public KeybindManager(@NotNull EventUtils mod) { // Keybindings + //? if >=1.21.11 { + final KeyBinding.Category category = KeyBinding.Category.create(Identifier.of("eventutils", "key.category.eventutils")); eventInfoKey = KeyBindingHelper.registerKeyBinding(new KeyBinding( + "key.eventutils.eventinfo", + InputUtil.Type.KEYSYM, + GLFW.GLFW_KEY_RIGHT_SHIFT, + category)); + final KeyBinding hidePlayersKey = KeyBindingHelper.registerKeyBinding(new KeyBinding( + "key.eventutils.hideplayers", + InputUtil.Type.KEYSYM, + GLFW.GLFW_KEY_F10, + category)); + //?} else { + /*eventInfoKey = KeyBindingHelper.registerKeyBinding(new KeyBinding( "key.eventutils.eventinfo", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_RIGHT_SHIFT, CATEGORY)); + final KeyBinding hidePlayersKey = KeyBindingHelper.registerKeyBinding(new KeyBinding( + "key.eventutils.hideplayers", + InputUtil.Type.KEYSYM, + GLFW.GLFW_KEY_F10, + CATEGORY)); + *///?} // DEV: Uncomment to force test event // final KeyBindingMixin testEventKey = (KeyBindingMixin) KeyBindingHelper.registerKeyBinding(new KeyBinding( // "key.eventutils.testevent", // InputUtil.Type.KEYSYM, // GLFW.GLFW_KEY_SEMICOLON, // CATEGORY)); - final KeyBinding hidePlayersKey = KeyBindingHelper.registerKeyBinding(new KeyBinding( - "key.eventutils.hideplayers", - InputUtil.Type.KEYSYM, - GLFW.GLFW_KEY_F10, - CATEGORY)); ClientTickEvents.END_CLIENT_TICK.register(client -> { if (windowHandle == null) windowHandle = client.getWindow().getHandle(); @@ -100,7 +117,11 @@ public KeybindManager(@NotNull EventUtils mod) { } private boolean canNotPress(@NotNull KeyBinding keyBinding) { - final String translationKey = keyBinding.getTranslationKey(); + //? if >=1.21.11 { + final String translationKey = keyBinding.getId(); + //?} else { + /*final String translationKey = keyBinding.getTranslationKey(); + *///?} final Long lastPressTime = lastKeyPresses.get(translationKey); final long now = System.currentTimeMillis(); if (lastPressTime != null && now - lastPressTime < 500) return true; diff --git a/src/main/java/cc/aabss/eventutils/commands/CommandRegister.java b/src/main/java/cc/aabss/eventutils/commands/CommandRegister.java index 5d6d387..faeb221 100644 --- a/src/main/java/cc/aabss/eventutils/commands/CommandRegister.java +++ b/src/main/java/cc/aabss/eventutils/commands/CommandRegister.java @@ -1,5 +1,6 @@ package cc.aabss.eventutils.commands; +import app.qwertz.commands.TagCmd; import cc.aabss.eventutils.EventType; import cc.aabss.eventutils.EventUtils; import cc.aabss.eventutils.config.PlayerGroup; @@ -98,6 +99,11 @@ public static void register(@NotNull CommandDispatcher tag = ClientCommandManager + .literal("tag") + .executes(context -> TagCmd.openTagScreen(context)) + .build(); + final LiteralCommandNode groupMsg = ClientCommandManager .literal("groupmsg") .then(ClientCommandManager.argument("group", StringArgumentType.word()) @@ -118,6 +124,7 @@ public static void register(@NotNull CommandDispatcher cont return; } + //? if >=1.21.11 { final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() + .map(entry -> entry.getProfile().name()) + .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) + .filter(name -> !EventUtils.isNPC(name, true)) + .toList(); + //?} else { + /*final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() .map(entry -> entry.getProfile().getName()) .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) .filter(name -> !EventUtils.isNPC(name, true)) .toList(); + *///?} if (namesFiltered.isEmpty()) { context.getSource().sendFeedback(Text.translatable("eventutils.command.countname.noplayers", EventUtils.ERROR_MESSAGE_PREFIX, Text.literal(filter).formatted(Formatting.DARK_RED))); @@ -44,11 +52,19 @@ public static void list(@NotNull CommandContext conte return; } + //? if >=1.21.11 { final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() + .map(entry -> entry.getProfile().name()) + .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) + .filter(name -> !EventUtils.isNPC(name, true)) + .toList(); + //?} else { + /*final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() .map(entry -> entry.getProfile().getName()) .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) .filter(name -> !EventUtils.isNPC(name, true)) .toList(); + *///?} if (namesFiltered.isEmpty()) { context.getSource().sendFeedback(Text.translatable("eventutils.command.countname.noplayers", EventUtils.ERROR_MESSAGE_PREFIX, Text.literal(filter).formatted(Formatting.DARK_RED))); diff --git a/src/main/java/cc/aabss/eventutils/config/EventConfig.java b/src/main/java/cc/aabss/eventutils/config/EventConfig.java index 93858fb..3eb446f 100644 --- a/src/main/java/cc/aabss/eventutils/config/EventConfig.java +++ b/src/main/java/cc/aabss/eventutils/config/EventConfig.java @@ -2,6 +2,7 @@ import cc.aabss.eventutils.EventType; import cc.aabss.eventutils.EventUtils; +import app.qwertz.PlusTag; import cc.aabss.eventutils.Versions; import com.google.common.reflect.TypeToken; @@ -35,6 +36,8 @@ public class EventConfig extends FileLoader { @NotNull public List whitelistedPlayers; @NotNull public List groups; public boolean useTestingApi; + /** Which plus tag to show next to name (from Event Alerts / Discord linking). */ + @NotNull public PlusTag selectedPlusTag; @NotNull public final List eventTypes; @NotNull public final Map notificationSounds; @@ -66,6 +69,7 @@ public EventConfig() { whitelistedPlayers = get("whitelisted_players", Defaults.whitelistedPlayers(), new TypeToken>(){}.getType()); groups = get("groups", Defaults.groups(), new TypeToken>(){}.getType()); useTestingApi = get("use_testing_api", Defaults.USE_TESTING_API); + selectedPlusTag = getPlusTag("selected_plus_tag", Defaults.SELECTED_PLUS_TAG); eventTypes = get("notifications", Defaults.eventTypes(), new TypeToken>(){}.getType()); notificationSounds = get("notification_sounds", Defaults.notificationSounds(), new TypeToken>(){}.getType()); @@ -134,6 +138,22 @@ public NotificationSound getNotificationSound(@NotNull EventType type) { return notificationSounds.getOrDefault(type, NotificationSound.ALERT); } + @NotNull + private PlusTag getPlusTag(@NotNull String key, @NotNull PlusTag defaultValue) { + String s = get(key, defaultValue.name()); + if (s == null) return defaultValue; + try { + return PlusTag.valueOf(s.toUpperCase()); + } catch (IllegalArgumentException e) { + return defaultValue; + } + } + + public void setSelectedPlusTag(@NotNull PlusTag tag) { + this.selectedPlusTag = tag; + setSave("selected_plus_tag", tag.name()); + } + // Collections need to have methods to create new instances of the collection! public static class Defaults { public static final boolean DISCORD_RPC = true; @@ -149,6 +169,7 @@ public static class Defaults { @NotNull private static final List HIDDEN_ENTITY_TYPES_STRING = List.of("minecraft:glow_item_frame"); @NotNull private static final List WHITELISTED_PLAYERS = List.of("skeppy", "badboyhalo"); public static final boolean USE_TESTING_API = false; + @NotNull public static final PlusTag SELECTED_PLUS_TAG = PlusTag.NONE; @NotNull private static final List EVENT_TYPES = List.of(EventType.values()); @NotNull private static final Map NOTIFICATION_SOUNDS = Arrays.stream(EventType.values()) .collect(HashMap::new, (map, type) -> map.put(type, NotificationSound.ALERT), HashMap::putAll); diff --git a/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java b/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java index c09a146..15c0ff4 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java @@ -19,7 +19,11 @@ @Mixin(Entity.class) public abstract class EntityMixin { @Shadow public abstract EntityType getType(); - @Shadow public abstract Vec3d getPos(); + //? if >=1.21.11 { + @Shadow public abstract Vec3d getSyncedPos(); + //?} else { + /*@Shadow public abstract Vec3d getPos(); + *///?} @Shadow public abstract Text getName(); @Inject(method = "spawnSprintingParticles", at = @At("HEAD"), cancellable = true) @@ -45,6 +49,10 @@ private void spawnSprintingParticles(CallbackInfo ci) { } // Specific radius - if (mainPlayer.getPos().distanceTo(getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + //? if >=1.21.11 { + if (mainPlayer.getSyncedPos().distanceTo(getSyncedPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + //?} else { + /*if (mainPlayer.getPos().distanceTo(getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + *///?} } } diff --git a/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java b/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java index 6080e9c..b5afcec 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java @@ -5,7 +5,11 @@ import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.render.VertexConsumerProvider; -import net.minecraft.client.render.entity.EntityRenderDispatcher; +//? if >=1.21.11 { +import net.minecraft.client.render.entity.EntityRenderManager; +//?} else { +/*import net.minecraft.client.render.entity.EntityRenderDispatcher; +*///?} import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; @@ -16,7 +20,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(EntityRenderDispatcher.class) +//? if >=1.21.11 { +@Mixin(EntityRenderManager.class) +//?} else { +/*@Mixin(EntityRenderDispatcher.class) +*///?} public class EntityRenderDispatcherMixin { @Inject(method = "render", at = @At("HEAD"), cancellable = true) //? if <=1.21.1 { @@ -44,6 +52,10 @@ private void render(E entity, double x, double y, double z, f // Specific radius final ClientPlayerEntity mainPlayer = MinecraftClient.getInstance().player; - if (mainPlayer != null && mainPlayer.getPos().distanceTo(entity.getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + //? if >=1.21.11 { + if (mainPlayer != null && mainPlayer.getSyncedPos().distanceTo(entity.getSyncedPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + //?} else { + /*if (mainPlayer != null && mainPlayer.getPos().distanceTo(entity.getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + *///?} } } diff --git a/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java b/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java index 2d0910d..ecf8963 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java @@ -73,6 +73,10 @@ public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, Matr //?} // Radius-specific - if (clientPlayer.getPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + //? if >=1.21.11 { + if (clientPlayer.getSyncedPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + //?} else { + /*if (clientPlayer.getPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + *///?} } } diff --git a/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java b/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java index 508b1b5..c042bb3 100644 --- a/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java +++ b/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java @@ -37,10 +37,10 @@ public static void connect(@NotNull String ip) { final ServerAddress address = ServerAddress.parse(ip); client.execute(() -> { try { - //? if >=1.21.6 { - client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false); + //? if >=1.21.11 { + client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false, false); //?} else { - /*client.disconnect(); + /*client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false); *///?} //? if <=1.20.4 { diff --git a/src/main/resources/assets/eventutils/lang/de_de.json b/src/main/resources/assets/eventutils/lang/de_de.json index a067316..7f11e2d 100644 --- a/src/main/resources/assets/eventutils/lang/de_de.json +++ b/src/main/resources/assets/eventutils/lang/de_de.json @@ -124,5 +124,20 @@ "eventutils.command.countname.list": "%s§e Gefunden %s §eSpieler%s §emit '%s§e' im Namen§e: %s", "eventutils.command.groupmsg.no_group": "%s§c Keine Gruppe mit dem Namen '%s§c' gefunden.", + "eventutils.plustag.title": "Plus-Tag", + "eventutils.plustag.subtitle": "Wähle, welches + neben deinem Namen angezeigt wird", + "eventutils.plustag.none": "[Verknüpft]", + "eventutils.plustag.white": "[Weiß]", + "eventutils.plustag.red": "[Rot]", + "eventutils.plustag.blue": "[Blau]", + "eventutils.plustag.orange": "[Orange]", + "eventutils.plustag.pink": "[Pink]", + "eventutils.plustag.unlock.linked": "Freigeschaltet durch Verknüpfung deines Discord-Kontos (Event Alerts)", + "eventutils.plustag.unlock.none": "—", + "eventutils.plustag.unlock.admin": "Freigeschaltet als Admin.", + "eventutils.plustag.unlock.contributor": "Freigeschaltet als Entwickler/Mitarbeiter.", + "eventutils.plustag.unlock.bee": "Freigeschaltet mit Bee (Abonnement).", + "eventutils.plustag.unlock.booster": "Freigeschaltet durch Boosten des Event Alerts Discord-Servers.", + "eventutils.word.plural": "" } \ No newline at end of file diff --git a/src/main/resources/assets/eventutils/lang/en_us.json b/src/main/resources/assets/eventutils/lang/en_us.json index 895c7c9..946a3c9 100644 --- a/src/main/resources/assets/eventutils/lang/en_us.json +++ b/src/main/resources/assets/eventutils/lang/en_us.json @@ -124,5 +124,20 @@ "eventutils.command.countname.list": "%s§e Found %s §eplayer%s §ewith '%s§e' in their name§e: %s", "eventutils.command.groupmsg.no_group": "%s§c No group named '%s§c' found.", + "eventutils.plustag.title": "Plus Tag", + "eventutils.plustag.subtitle": "Choose which + to show next to your name", + "eventutils.plustag.none": "[Linked]", + "eventutils.plustag.white": "[White]", + "eventutils.plustag.red": "[Red]", + "eventutils.plustag.blue": "[Blue]", + "eventutils.plustag.orange": "[Orange]", + "eventutils.plustag.pink": "[Pink]", + "eventutils.plustag.unlock.linked": "Unlocked by linking your Discord account (Event Alerts)", + "eventutils.plustag.unlock.none": "—", + "eventutils.plustag.unlock.admin": "Unlocked by being an Admin.", + "eventutils.plustag.unlock.contributor": "Unlocked by being a developer/contributor.", + "eventutils.plustag.unlock.bee": "Unlocked with Bee (subscription).", + "eventutils.plustag.unlock.booster": "Unlocked by boosting the Event Alerts Discord server.", + "eventutils.word.plural": "s" } \ No newline at end of file diff --git a/src/main/resources/assets/eventutils/textures/gui/README.txt b/src/main/resources/assets/eventutils/textures/gui/README.txt new file mode 100644 index 0000000..6e9bffd --- /dev/null +++ b/src/main/resources/assets/eventutils/textures/gui/README.txt @@ -0,0 +1,11 @@ +Plus tag icons (16x16 PNG each): + linked.png - gray/silver + (Discord linked) + bee.png - orange + (Bee subscription) + booster.png - pink + (Discord booster) + contrib.png - blue + (contributor/developer) + admin.png - red + (admin) + white.png - white + (unused) + +You can export these from your sheet.png (3 columns x 2 rows): + Row 0: bee, white, linked + Row 1: booster, contrib, admin diff --git a/src/main/resources/assets/eventutils/textures/gui/admin.png b/src/main/resources/assets/eventutils/textures/gui/admin.png new file mode 100644 index 0000000000000000000000000000000000000000..50f2b1b734a04b26270d5a3d6713d14a7befcc8b GIT binary patch literal 4099 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 B)gAx< literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/eventutils/textures/gui/bee.png b/src/main/resources/assets/eventutils/textures/gui/bee.png new file mode 100644 index 0000000000000000000000000000000000000000..86282c8b0633d1ab70f6bb62ebd9b1a76e985735 GIT binary patch literal 3916 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/eventutils/textures/gui/contrib.png b/src/main/resources/assets/eventutils/textures/gui/contrib.png new file mode 100644 index 0000000000000000000000000000000000000000..da72335577accd3d1c7f524afaccfb8498e0633c GIT binary patch literal 4152 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 T6Kbw?00000NkvXXu0mjfJ>(RS literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/eventutils/textures/gui/plus_sheet.png b/src/main/resources/assets/eventutils/textures/gui/plus_sheet.png new file mode 100644 index 0000000000000000000000000000000000000000..3848d161b8df939fdbcd9a10fe23a4843bef4c8b GIT binary patch literal 31517 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 z%0D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 EAEKTY$p8QV literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/eventutils/textures/gui/white.png b/src/main/resources/assets/eventutils/textures/gui/white.png new file mode 100644 index 0000000000000000000000000000000000000000..c631f076a066e2c5a9ac7af3837394f26944874a GIT binary patch literal 3919 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/eventutils.mixin.json b/src/main/resources/eventutils.mixin.json index 753caf6..e54f974 100644 --- a/src/main/resources/eventutils.mixin.json +++ b/src/main/resources/eventutils.mixin.json @@ -13,7 +13,8 @@ "EntryListWidgetAccessor", "KeyBindingMixin", "MultiplayerScreenMixin", - "PlayerEntityRendererMixin" + "PlayerEntityRendererMixin", + "app.qwertz.mixin.PlayerListHudMixin" ], "injectors": { "defaultRequire": 1 diff --git a/stonecutter.gradle.kts b/stonecutter.gradle.kts index f5a87a6..e9e836b 100644 --- a/stonecutter.gradle.kts +++ b/stonecutter.gradle.kts @@ -1,6 +1,6 @@ plugins { id("dev.kikugie.stonecutter") } -stonecutter active "1.21.6" /* [SC] DO NOT EDIT */ +stonecutter active "1.21.11" /* [SC] DO NOT EDIT */ stonecutter.registerChiseled(tasks.register("chiseledBuild", stonecutter.chiseled) { group = "project" diff --git a/versions/1.21.11/gradle.properties b/versions/1.21.11/gradle.properties new file mode 100644 index 0000000..5be05c9 --- /dev/null +++ b/versions/1.21.11/gradle.properties @@ -0,0 +1,6 @@ +deps.minecraft=1.21.11 +deps.yarn_mappings=1.21.11+build.1 +deps.fabric_api=0.141.0+1.21.11 + +deps.yacl=3.8.1+1.21.11-fabric +deps.modmenu=15.0.0-beta.3 From c49e309056e35b8a8e59d15fbbb38bac43087b8e Mon Sep 17 00:00:00 2001 From: QWERTZexe Date: Sun, 15 Mar 2026 18:21:46 +0100 Subject: [PATCH 4/9] Added QWERTZ to the author list --- src/main/resources/fabric.mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 1d6f537..73593a7 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -4,7 +4,7 @@ "version": "${mod_version}", "name": "${mod_name}", "description": "${description}", - "authors": ["Event Alerts", "aabss", "srnyx", "pvty"], + "authors": ["Event Alerts", "aabss", "srnyx", "pvty", "QWERTZ_EXE"], "contact": { "repo": "https://github.com/Event-Alerts/EventUtils", "discord": "https://discord.gg/uFPFNYzAWC" From 9dd1830b601bef741b1ebb998b7b55b96c6174cc Mon Sep 17 00:00:00 2001 From: QWERTZexe Date: Sun, 15 Mar 2026 18:37:59 +0100 Subject: [PATCH 5/9] fixed bug --- src/main/java/app/qwertz/PlusTagRenderer.java | 4 ++-- .../app/qwertz/mixin/PlayerListHudMixin.java | 16 ++++++------- .../cc/aabss/eventutils/EventInfoScreen.java | 8 +++---- .../cc/aabss/eventutils/KeybindManager.java | 20 ++++++++-------- .../aabss/eventutils/NotificationToast.java | 18 +++++++------- .../cc/aabss/eventutils/UpdateChecker.java | 8 +++---- .../eventutils/commands/CountNameCmd.java | 16 ++++++------- .../eventutils/commands/PriorityCmd.java | 16 ++++++------- .../aabss/eventutils/mixin/EntityMixin.java | 16 ++++++------- .../mixin/EntityRenderDispatcherMixin.java | 24 +++++++++---------- .../mixin/PlayerEntityRendererMixin.java | 8 +++---- .../eventutils/utility/ConnectUtility.java | 8 +++---- stonecutter.gradle.kts | 2 +- 13 files changed, 82 insertions(+), 82 deletions(-) diff --git a/src/main/java/app/qwertz/PlusTagRenderer.java b/src/main/java/app/qwertz/PlusTagRenderer.java index c2d4b67..d42cc3f 100644 --- a/src/main/java/app/qwertz/PlusTagRenderer.java +++ b/src/main/java/app/qwertz/PlusTagRenderer.java @@ -5,7 +5,7 @@ package app.qwertz; import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gl.RenderPipelines; +import net.minecraft.client.render.RenderLayer; import org.jetbrains.annotations.NotNull; @@ -22,6 +22,6 @@ private PlusTagRenderer() {} /** Draw the icon at (x, y) with the given size (e.g. 8 for tab list). Samples full 64x64 texture, scaled to size. */ public static void draw(@NotNull DrawContext context, @NotNull PlusTag tag, int x, int y, int size) { if (tag == PlusTag.WHITE) return; // unused, skip - context.drawTexture(RenderPipelines.GUI_TEXTURED, tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE, TEX_SIZE, TEX_SIZE); + context.drawTexture(RenderLayer::getGuiTextured, tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE, TEX_SIZE, TEX_SIZE); } } diff --git a/src/main/java/app/qwertz/mixin/PlayerListHudMixin.java b/src/main/java/app/qwertz/mixin/PlayerListHudMixin.java index 61eac9c..bfb4c72 100644 --- a/src/main/java/app/qwertz/mixin/PlayerListHudMixin.java +++ b/src/main/java/app/qwertz/mixin/PlayerListHudMixin.java @@ -37,12 +37,12 @@ public abstract class PlayerListHudMixin { if (client.player == null) return; //? if >=1.21.11 { - String name = entry.getProfile().name(); + /*String name = entry.getProfile().name(); final boolean isLocal = entry.getProfile().id().equals(client.player.getUuid()); - //?} else { - /*String name = entry.getProfile().getName(); + *///?} else { + String name = entry.getProfile().getName(); final boolean isLocal = entry.getProfile().getId().equals(client.player.getUuid()); - *///?} + //?} final PlusTag tag; if (isLocal) { @@ -56,10 +56,10 @@ public abstract class PlayerListHudMixin { EventUtils.LOGGER.debug("[TabList] entry={} isLocal=true tag=config.selectedPlusTag={}", name, tag); } else { //? if >=1.21.11 { - String uuid = entry.getProfile().id().toString(); - //?} else { - /*String uuid = entry.getProfile().getId().toString(); - *///?} + /*String uuid = entry.getProfile().id().toString(); + *///?} else { + String uuid = entry.getProfile().getId().toString(); + //?} Set cached = EventAlertsApi.getCached(uuid); if (cached == null) { EventUtils.LOGGER.debug("[TabList] entry={} uuid={} cache MISS, scheduling fetch", name, uuid); diff --git a/src/main/java/cc/aabss/eventutils/EventInfoScreen.java b/src/main/java/cc/aabss/eventutils/EventInfoScreen.java index 0802c0b..041c2ef 100644 --- a/src/main/java/cc/aabss/eventutils/EventInfoScreen.java +++ b/src/main/java/cc/aabss/eventutils/EventInfoScreen.java @@ -27,10 +27,10 @@ public class EventInfoScreen extends Screen { public EventInfoScreen(@NotNull JsonObject json) { //? if >=1.21.11 { - super(Text.translatable(EventUtils.MOD.keybindManager.eventInfoKey.getId())); - //?} else { - /*super(Text.translatable(EventUtils.MOD.keybindManager.eventInfoKey.getTranslationKey())); - *///?} + /*super(Text.translatable(EventUtils.MOD.keybindManager.eventInfoKey.getId())); + *///?} else { + super(Text.translatable(EventUtils.MOD.keybindManager.eventInfoKey.getTranslationKey())); + //?} this.json = json; } diff --git a/src/main/java/cc/aabss/eventutils/KeybindManager.java b/src/main/java/cc/aabss/eventutils/KeybindManager.java index 2987319..f4cb063 100644 --- a/src/main/java/cc/aabss/eventutils/KeybindManager.java +++ b/src/main/java/cc/aabss/eventutils/KeybindManager.java @@ -11,8 +11,8 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; //? if >=1.21.11 { -import net.minecraft.util.Identifier; -//?} +/*import net.minecraft.util.Identifier; +*///?} import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,7 +36,7 @@ public class KeybindManager { public KeybindManager(@NotNull EventUtils mod) { // Keybindings //? if >=1.21.11 { - final KeyBinding.Category category = KeyBinding.Category.create(Identifier.of("eventutils", "key.category.eventutils")); + /*final KeyBinding.Category category = KeyBinding.Category.create(Identifier.of("eventutils", "key.category.eventutils")); eventInfoKey = KeyBindingHelper.registerKeyBinding(new KeyBinding( "key.eventutils.eventinfo", InputUtil.Type.KEYSYM, @@ -47,8 +47,8 @@ public KeybindManager(@NotNull EventUtils mod) { InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_F10, category)); - //?} else { - /*eventInfoKey = KeyBindingHelper.registerKeyBinding(new KeyBinding( + *///?} else { + eventInfoKey = KeyBindingHelper.registerKeyBinding(new KeyBinding( "key.eventutils.eventinfo", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_RIGHT_SHIFT, @@ -58,7 +58,7 @@ public KeybindManager(@NotNull EventUtils mod) { InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_F10, CATEGORY)); - *///?} + //?} // DEV: Uncomment to force test event // final KeyBindingMixin testEventKey = (KeyBindingMixin) KeyBindingHelper.registerKeyBinding(new KeyBinding( // "key.eventutils.testevent", @@ -118,10 +118,10 @@ public KeybindManager(@NotNull EventUtils mod) { private boolean canNotPress(@NotNull KeyBinding keyBinding) { //? if >=1.21.11 { - final String translationKey = keyBinding.getId(); - //?} else { - /*final String translationKey = keyBinding.getTranslationKey(); - *///?} + /*final String translationKey = keyBinding.getId(); + *///?} else { + final String translationKey = keyBinding.getTranslationKey(); + //?} final Long lastPressTime = lastKeyPresses.get(translationKey); final long now = System.currentTimeMillis(); if (lastPressTime != null && now - lastPressTime < 500) return true; diff --git a/src/main/java/cc/aabss/eventutils/NotificationToast.java b/src/main/java/cc/aabss/eventutils/NotificationToast.java index 63d30ca..af7bc45 100644 --- a/src/main/java/cc/aabss/eventutils/NotificationToast.java +++ b/src/main/java/cc/aabss/eventutils/NotificationToast.java @@ -13,7 +13,7 @@ import net.minecraft.text.Text; import net.minecraft.util.Identifier; //? if >=1.21.6 -import net.minecraft.client.gl.RenderPipelines; +/*import net.minecraft.client.gl.RenderPipelines;*/ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -90,10 +90,10 @@ public void draw(DrawContext drawContext, TextRenderer textRenderer, long startT //? if <1.21.2 { /*drawContext.drawGuiTexture(TEXTURE, 0, 0, width, height); *///?} else if >=1.21.6 { - drawContext.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 - //?} else { - /*drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 - *///?} + /*drawContext.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 + *///?} else { + drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 + //?} } else { int minHeight = Math.min(4, height - 28); drawPart(drawContext, 0, 0, 28); @@ -123,14 +123,14 @@ private void drawPart(@NotNull DrawContext context, int j, int k, int l) { for (int o = m; o < widthN; o += 64) context.drawGuiTexture(TEXTURE, 160, 32, 32, j, o, k, Math.min(64, widthN - o), l); context.drawGuiTexture(TEXTURE, 160, 32, 160 - n, j, widthN, k, n, l); *///?} else if >=1.21.6 { - context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 0, j, 0, k, m, l); + /*context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 0, j, 0, k, m, l); for (int o = m; o < widthN; o += 64) context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 32, j, o, k, Math.min(64, widthN - o), l); context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 160 - n, j, widthN, k, n, l); - //?} else { - /*context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 0, j, 0, k, m, l); + *///?} else { + context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 0, j, 0, k, m, l); for (int o = m; o < widthN; o += 64) context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 32, j, o, k, Math.min(64, widthN - o), l); context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 160 - n, j, widthN, k, n, l); - *///?} + //?} } @Environment(value = EnvType.CLIENT) diff --git a/src/main/java/cc/aabss/eventutils/UpdateChecker.java b/src/main/java/cc/aabss/eventutils/UpdateChecker.java index 744ec6a..5f69363 100644 --- a/src/main/java/cc/aabss/eventutils/UpdateChecker.java +++ b/src/main/java/cc/aabss/eventutils/UpdateChecker.java @@ -31,7 +31,7 @@ private void notifyUpdate(@NotNull String latestVersion) { client.send(() -> { if (client.player == null) return; //? if >=1.21.5 { - client.player.sendMessage( + /*client.player.sendMessage( EventUtils.MESSAGE_PREFIX.copy().append(" §e" + EventUtils.translate("eventutils.updatechecker.new")+"§r §7(v" + Versions.EU_VERSION + " -> v" + latestVersion.replace(Versions.MC_VERSION + "-", "") + ")" + "\n") .setStyle(EventUtils.MESSAGE_PREFIX.getStyle() .withHoverEvent(new HoverEvent.ShowText(translatable("eventutils.updatechecker.hover"))) @@ -39,8 +39,8 @@ private void notifyUpdate(@NotNull String latestVersion) { .append(Text.literal("§7§o" + EventUtils.translate("eventutils.updatechecker.config")) .setStyle(Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/event utils")))), false); - //?} else { - /*client.player.sendMessage( + *///?} else { + client.player.sendMessage( EventUtils.MESSAGE_PREFIX.copy().append(" §e" + EventUtils.translate("eventutils.updatechecker.new")+"§r §7(v" + Versions.EU_VERSION + " -> v" + latestVersion.replace(Versions.MC_VERSION + "-", "") + ")" + "\n") .setStyle(EventUtils.MESSAGE_PREFIX.getStyle() .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, translatable("eventutils.updatechecker.hover"))) @@ -48,7 +48,7 @@ private void notifyUpdate(@NotNull String latestVersion) { .append(Text.literal("§7§o" + EventUtils.translate("eventutils.updatechecker.config")) .setStyle(Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils config")))), false); - *///?} + //?} }); } diff --git a/src/main/java/cc/aabss/eventutils/commands/CountNameCmd.java b/src/main/java/cc/aabss/eventutils/commands/CountNameCmd.java index 53af868..b09d5a9 100644 --- a/src/main/java/cc/aabss/eventutils/commands/CountNameCmd.java +++ b/src/main/java/cc/aabss/eventutils/commands/CountNameCmd.java @@ -22,18 +22,18 @@ public static void count(@NotNull CommandContext cont } //? if >=1.21.11 { - final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() + /*final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() .map(entry -> entry.getProfile().name()) .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) .filter(name -> !EventUtils.isNPC(name, true)) .toList(); - //?} else { - /*final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() + *///?} else { + final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() .map(entry -> entry.getProfile().getName()) .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) .filter(name -> !EventUtils.isNPC(name, true)) .toList(); - *///?} + //?} if (namesFiltered.isEmpty()) { context.getSource().sendFeedback(Text.translatable("eventutils.command.countname.noplayers", EventUtils.ERROR_MESSAGE_PREFIX, Text.literal(filter).formatted(Formatting.DARK_RED))); @@ -53,18 +53,18 @@ public static void list(@NotNull CommandContext conte } //? if >=1.21.11 { - final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() + /*final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() .map(entry -> entry.getProfile().name()) .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) .filter(name -> !EventUtils.isNPC(name, true)) .toList(); - //?} else { - /*final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() + *///?} else { + final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() .map(entry -> entry.getProfile().getName()) .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) .filter(name -> !EventUtils.isNPC(name, true)) .toList(); - *///?} + //?} if (namesFiltered.isEmpty()) { context.getSource().sendFeedback(Text.translatable("eventutils.command.countname.noplayers", EventUtils.ERROR_MESSAGE_PREFIX, Text.literal(filter).formatted(Formatting.DARK_RED))); diff --git a/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java b/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java index ab5f0e4..f28afa9 100644 --- a/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java +++ b/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java @@ -110,10 +110,10 @@ public static void priority(@NotNull CommandContext c page - 1 ).setStyle( //? if <=1.21.4 { - /*Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page - 1))) - *///?} else { - Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page - 1))) - //?} + Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page - 1))) + //?} else { + /*Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page - 1))) + *///?} ); } @@ -123,10 +123,10 @@ public static void priority(@NotNull CommandContext c page + 1 ).setStyle( //? if <=1.21.4 { - /*Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page + 1))) - *///?} else { - Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page + 1))) - //?} + Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page + 1))) + //?} else { + /*Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page + 1))) + *///?} ); } diff --git a/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java b/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java index 15c0ff4..c181d93 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java @@ -20,10 +20,10 @@ public abstract class EntityMixin { @Shadow public abstract EntityType getType(); //? if >=1.21.11 { - @Shadow public abstract Vec3d getSyncedPos(); - //?} else { - /*@Shadow public abstract Vec3d getPos(); - *///?} + /*@Shadow public abstract Vec3d getSyncedPos(); + *///?} else { + @Shadow public abstract Vec3d getPos(); + //?} @Shadow public abstract Text getName(); @Inject(method = "spawnSprintingParticles", at = @At("HEAD"), cancellable = true) @@ -50,9 +50,9 @@ private void spawnSprintingParticles(CallbackInfo ci) { // Specific radius //? if >=1.21.11 { - if (mainPlayer.getSyncedPos().distanceTo(getSyncedPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - //?} else { - /*if (mainPlayer.getPos().distanceTo(getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - *///?} + /*if (mainPlayer.getSyncedPos().distanceTo(getSyncedPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + *///?} else { + if (mainPlayer.getPos().distanceTo(getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + //?} } } diff --git a/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java b/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java index b5afcec..520ec15 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java @@ -6,10 +6,10 @@ import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.render.VertexConsumerProvider; //? if >=1.21.11 { -import net.minecraft.client.render.entity.EntityRenderManager; -//?} else { -/*import net.minecraft.client.render.entity.EntityRenderDispatcher; -*///?} +/*import net.minecraft.client.render.entity.EntityRenderManager; +*///?} else { +import net.minecraft.client.render.entity.EntityRenderDispatcher; +//?} import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; @@ -21,10 +21,10 @@ //? if >=1.21.11 { -@Mixin(EntityRenderManager.class) -//?} else { -/*@Mixin(EntityRenderDispatcher.class) -*///?} +/*@Mixin(EntityRenderManager.class) +*///?} else { +@Mixin(EntityRenderDispatcher.class) +//?} public class EntityRenderDispatcherMixin { @Inject(method = "render", at = @At("HEAD"), cancellable = true) //? if <=1.21.1 { @@ -53,9 +53,9 @@ private void render(E entity, double x, double y, double z, f // Specific radius final ClientPlayerEntity mainPlayer = MinecraftClient.getInstance().player; //? if >=1.21.11 { - if (mainPlayer != null && mainPlayer.getSyncedPos().distanceTo(entity.getSyncedPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - //?} else { - /*if (mainPlayer != null && mainPlayer.getPos().distanceTo(entity.getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - *///?} + /*if (mainPlayer != null && mainPlayer.getSyncedPos().distanceTo(entity.getSyncedPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + *///?} else { + if (mainPlayer != null && mainPlayer.getPos().distanceTo(entity.getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + //?} } } diff --git a/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java b/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java index ecf8963..0b28d5c 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java @@ -74,9 +74,9 @@ public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, Matr // Radius-specific //? if >=1.21.11 { - if (clientPlayer.getSyncedPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - //?} else { - /*if (clientPlayer.getPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - *///?} + /*if (clientPlayer.getSyncedPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + *///?} else { + if (clientPlayer.getPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + //?} } } diff --git a/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java b/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java index c042bb3..5127595 100644 --- a/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java +++ b/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java @@ -38,10 +38,10 @@ public static void connect(@NotNull String ip) { client.execute(() -> { try { //? if >=1.21.11 { - client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false, false); - //?} else { - /*client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false); - *///?} + /*client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false, false); + *///?} else { + client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false); + //?} //? if <=1.20.4 { /*ConnectScreen.connect(screen, client, address, new ServerInfo("EventUtils Event Server", ip, ServerInfo.ServerType.OTHER), true); diff --git a/stonecutter.gradle.kts b/stonecutter.gradle.kts index e9e836b..10efe16 100644 --- a/stonecutter.gradle.kts +++ b/stonecutter.gradle.kts @@ -1,6 +1,6 @@ plugins { id("dev.kikugie.stonecutter") } -stonecutter active "1.21.11" /* [SC] DO NOT EDIT */ +stonecutter active "1.21.4" /* [SC] DO NOT EDIT */ stonecutter.registerChiseled(tasks.register("chiseledBuild", stonecutter.chiseled) { group = "project" From bd3ae24dc6d3772acfea0ab10299e8b837a6ca10 Mon Sep 17 00:00:00 2001 From: QWERTZexe Date: Sun, 15 Mar 2026 18:47:26 +0100 Subject: [PATCH 6/9] fixed more bugs --- src/main/java/app/qwertz/PlusTagRenderer.java | 10 +++++ .../aabss/eventutils/NotificationToast.java | 32 +++++++-------- .../mixin/EntityRenderDispatcherMixin.java | 8 ++-- .../mixin/PlayerEntityRendererMixin.java | 40 +++++++++---------- .../eventutils/utility/ConnectUtility.java | 24 ++++++----- .../eventutils/websocket/WebSocketClient.java | 2 +- stonecutter.gradle.kts | 2 +- 7 files changed, 65 insertions(+), 53 deletions(-) diff --git a/src/main/java/app/qwertz/PlusTagRenderer.java b/src/main/java/app/qwertz/PlusTagRenderer.java index d42cc3f..3ba0c98 100644 --- a/src/main/java/app/qwertz/PlusTagRenderer.java +++ b/src/main/java/app/qwertz/PlusTagRenderer.java @@ -5,7 +5,11 @@ package app.qwertz; import net.minecraft.client.gui.DrawContext; +//? if >=1.21.6 { +import net.minecraft.client.gl.RenderPipelines; +//?} else if >=1.21.4 { import net.minecraft.client.render.RenderLayer; +//?} import org.jetbrains.annotations.NotNull; @@ -22,6 +26,12 @@ private PlusTagRenderer() {} /** Draw the icon at (x, y) with the given size (e.g. 8 for tab list). Samples full 64x64 texture, scaled to size. */ public static void draw(@NotNull DrawContext context, @NotNull PlusTag tag, int x, int y, int size) { if (tag == PlusTag.WHITE) return; // unused, skip + //? if >=1.21.6 { + context.drawTexture(RenderPipelines.GUI_TEXTURED, tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE, TEX_SIZE, TEX_SIZE); + //?} else if >=1.21.4 { context.drawTexture(RenderLayer::getGuiTextured, tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE, TEX_SIZE, TEX_SIZE); + //?} else { + context.drawTexture(tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE); + //?} } } diff --git a/src/main/java/cc/aabss/eventutils/NotificationToast.java b/src/main/java/cc/aabss/eventutils/NotificationToast.java index af7bc45..60a745a 100644 --- a/src/main/java/cc/aabss/eventutils/NotificationToast.java +++ b/src/main/java/cc/aabss/eventutils/NotificationToast.java @@ -54,7 +54,7 @@ public NotificationToast(@NotNull Text title, @Nullable Text description, boolea } //? if >=1.21.2 { - @Override + /*@Override public Visibility getVisibility() { return visibility; } @@ -63,7 +63,7 @@ public Visibility getVisibility() { public void update(ToastManager toastManager, long startTime) { visibility = startTime >= Type.DEFAULT.displayDuration ? Toast.Visibility.HIDE : Toast.Visibility.SHOW; } - //?} + *///?} @Override @NotNull public NotificationToast.Type getType() { @@ -82,18 +82,18 @@ public int getHeight() { @Override //? if <1.21.2 { - /*public Toast.Visibility draw(DrawContext drawContext, ToastManager manager, long startTime) { - *///?} else { - public void draw(DrawContext drawContext, TextRenderer textRenderer, long startTime) { - //?} + public Toast.Visibility draw(DrawContext drawContext, ToastManager manager, long startTime) { + //?} else { + /*public void draw(DrawContext drawContext, TextRenderer textRenderer, long startTime) { + *///?} if (width == 160 && lines.size() <= 1) { //? if <1.21.2 { - /*drawContext.drawGuiTexture(TEXTURE, 0, 0, width, height); - *///?} else if >=1.21.6 { + drawContext.drawGuiTexture(TEXTURE, 0, 0, width, height); + //?} else if >=1.21.6 { /*drawContext.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 *///?} else { - drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 - //?} + /*drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 + *///?} } else { int minHeight = Math.min(4, height - 28); drawPart(drawContext, 0, 0, 28); @@ -102,7 +102,7 @@ public void draw(DrawContext drawContext, TextRenderer textRenderer, long startT } //? if <1.21.2 - /*final TextRenderer textRenderer = manager.getClient().textRenderer;*/ + final TextRenderer textRenderer = manager.getClient().textRenderer; if (lines.isEmpty()) { drawContext.drawText(textRenderer, title, 24, 12, Color.YELLOW.getRGB(), false); } else { @@ -110,7 +110,7 @@ public void draw(DrawContext drawContext, TextRenderer textRenderer, long startT for (int i = 0; i < lines.size(); ++i) drawContext.drawText(textRenderer, lines.get(i), 24, 18 + i * 12, -1, false); } //? if <1.21.2 - /*return startTime >= Type.DEFAULT.displayDuration ? Toast.Visibility.HIDE : Toast.Visibility.SHOW;*/ + return startTime >= Type.DEFAULT.displayDuration ? Toast.Visibility.HIDE : Toast.Visibility.SHOW; } @@ -119,18 +119,18 @@ private void drawPart(@NotNull DrawContext context, int j, int k, int l) { final int n = Math.min(60, width - m); final int widthN = width - n; //? if <=1.21.1 { - /*context.drawGuiTexture(TEXTURE, 160, 32, 0, j, 0, k, m, l); + context.drawGuiTexture(TEXTURE, 160, 32, 0, j, 0, k, m, l); for (int o = m; o < widthN; o += 64) context.drawGuiTexture(TEXTURE, 160, 32, 32, j, o, k, Math.min(64, widthN - o), l); context.drawGuiTexture(TEXTURE, 160, 32, 160 - n, j, widthN, k, n, l); - *///?} else if >=1.21.6 { + //?} else if >=1.21.6 { /*context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 0, j, 0, k, m, l); for (int o = m; o < widthN; o += 64) context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 32, j, o, k, Math.min(64, widthN - o), l); context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 160 - n, j, widthN, k, n, l); *///?} else { - context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 0, j, 0, k, m, l); + /*context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 0, j, 0, k, m, l); for (int o = m; o < widthN; o += 64) context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 32, j, o, k, Math.min(64, widthN - o), l); context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 160 - n, j, widthN, k, n, l); - //?} + *///?} } @Environment(value = EnvType.CLIENT) diff --git a/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java b/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java index 520ec15..70a68c5 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java @@ -28,10 +28,10 @@ public class EntityRenderDispatcherMixin { @Inject(method = "render", at = @At("HEAD"), cancellable = true) //? if <=1.21.1 { - /*private void render(Entity entity, double x, double y, double z, float yaw, float tickDelta, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, CallbackInfo ci) { - *///?} else { - private void render(E entity, double x, double y, double z, float tickDelta, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, CallbackInfo ci) { - //?} + private void render(Entity entity, double x, double y, double z, float yaw, float tickDelta, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, CallbackInfo ci) { + //?} else { + /*private void render(E entity, double x, double y, double z, float tickDelta, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, CallbackInfo ci) { + *///?} if (!EventUtils.isInHidePlayersMode()) return; if (entity instanceof PlayerEntity player) { diff --git a/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java b/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java index 0b28d5c..78dbc17 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java @@ -10,10 +10,10 @@ import net.minecraft.text.Text; import net.minecraft.util.math.Vec3d; //? if <1.21.3 { -/*import net.minecraft.client.network.AbstractClientPlayerEntity; -*///?} else { -import net.minecraft.client.render.entity.state.PlayerEntityRenderState; -//?} +import net.minecraft.client.network.AbstractClientPlayerEntity; +//?} else { +/*import net.minecraft.client.render.entity.state.PlayerEntityRenderState; +*///?} import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -25,31 +25,31 @@ public class PlayerEntityRendererMixin { @Inject(at = {@At("HEAD")}, method = "renderLabelIfPresent*", cancellable = true) //? if <=1.20.4 { - /*public void renderLabelIfPresent(AbstractClientPlayerEntity player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { - *///?} else if <1.21.3 { + public void renderLabelIfPresent(AbstractClientPlayerEntity player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { + //?} else if <1.21.3 { /*public void renderLabelIfPresent(AbstractClientPlayerEntity player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, float f, CallbackInfo ci) { *///?} else { - public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { - //?} + /*public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { + *///?} if (!EventUtils.isInHidePlayersMode()) return; final ClientPlayerEntity clientPlayer = MinecraftClient.getInstance().player; if (clientPlayer == null) return; // Get player name //? if <1.21.3 { - /*final Text nameText = player.getName(); - *///?} else { - final Text nameText = player.playerName; + final Text nameText = player.getName(); + //?} else { + /*final Text nameText = player.playerName; if (nameText == null) return; - //?} + *///?} final String name = nameText.getString().toLowerCase(); // Check if main player //? if <1.21.3 { - /*if (player.isMainPlayer()) return; - *///?} else { - if (name.equals(clientPlayer.getName().getString().toLowerCase())) return; - //?} + if (player.isMainPlayer()) return; + //?} else { + /*if (name.equals(clientPlayer.getName().getString().toLowerCase())) return; + *///?} // Not visible in current view mode -> hide nametag if (!EventUtils.isPlayerVisible(name)) { @@ -67,10 +67,10 @@ public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, Matr // Get player position //? if <1.21.3 { - /*final Vec3d playerPos = player.getPos(); - *///?} else { - final Vec3d playerPos = new Vec3d(player.x, player.y, player.z); - //?} + final Vec3d playerPos = player.getPos(); + //?} else { + /*final Vec3d playerPos = new Vec3d(player.x, player.y, player.z); + *///?} // Radius-specific //? if >=1.21.11 { diff --git a/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java b/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java index 5127595..c4be12f 100644 --- a/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java +++ b/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java @@ -38,16 +38,18 @@ public static void connect(@NotNull String ip) { client.execute(() -> { try { //? if >=1.21.11 { - /*client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false, false); - *///?} else { + client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false, false); + //?} else if >=1.21 { client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false); + //?} else { + client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic"))); //?} //? if <=1.20.4 { - /*ConnectScreen.connect(screen, client, address, new ServerInfo("EventUtils Event Server", ip, ServerInfo.ServerType.OTHER), true); - *///?} else { - ConnectScreen.connect(screen, client, address, new ServerInfo("EventUtils Event Server", ip, ServerInfo.ServerType.OTHER), true, null); - //?} + ConnectScreen.connect(screen, client, address, new ServerInfo("EventUtils Event Server", ip, ServerInfo.ServerType.OTHER), true); + //?} else { + /*ConnectScreen.connect(screen, client, address, new ServerInfo("EventUtils Event Server", ip, ServerInfo.ServerType.OTHER), true, null); + *///?} } catch (final Exception e) { EventUtils.LOGGER.error("Failed to connect to server: {}", e.getMessage()); throw new RuntimeException(e); @@ -106,10 +108,10 @@ public static String getIp(@NotNull String message) { final int size = strings.size(); if (size == 1) { //? if java: <21 { - /*return strings.get(0); - *///?} else { - return strings.getFirst(); - //?} + return strings.get(0); + //?} else { + /*return strings.getFirst(); + *///?} } if (size > 1) for (final String string : strings) if (isValidIp(string)) return string; @@ -131,7 +133,7 @@ private static boolean isValidIp(@NotNull String ip) { try { final String body = client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).get().body(); //? if java: >=21 - client.close(); + /*client.close();*/ return !body.endsWith(":null}") && !body.endsWith("Not Found") && !body.endsWith("Invalid address value"); } catch (final InterruptedException e) { Thread.currentThread().interrupt(); diff --git a/src/main/java/cc/aabss/eventutils/websocket/WebSocketClient.java b/src/main/java/cc/aabss/eventutils/websocket/WebSocketClient.java index 12db3b3..a18865e 100644 --- a/src/main/java/cc/aabss/eventutils/websocket/WebSocketClient.java +++ b/src/main/java/cc/aabss/eventutils/websocket/WebSocketClient.java @@ -74,7 +74,7 @@ public void close(@NotNull String reason) { private void closeTasks() { //? if java: >=21 - if (httpClient != null) httpClient.close(); + /*if (httpClient != null) httpClient.close();*/ if (keepAlive != null) keepAlive.cancel(true); } diff --git a/stonecutter.gradle.kts b/stonecutter.gradle.kts index 10efe16..e7f29ce 100644 --- a/stonecutter.gradle.kts +++ b/stonecutter.gradle.kts @@ -1,6 +1,6 @@ plugins { id("dev.kikugie.stonecutter") } -stonecutter active "1.21.4" /* [SC] DO NOT EDIT */ +stonecutter active "1.20.4" /* [SC] DO NOT EDIT */ stonecutter.registerChiseled(tasks.register("chiseledBuild", stonecutter.chiseled) { group = "project" From a8d7d719ac168b0644e35417291c73c26fab3058 Mon Sep 17 00:00:00 2001 From: QWERTZexe Date: Sun, 15 Mar 2026 18:51:50 +0100 Subject: [PATCH 7/9] fixed more bugs --- src/main/java/app/qwertz/PlusTagRenderer.java | 12 ++--- .../app/qwertz/mixin/PlayerListHudMixin.java | 16 +++---- .../cc/aabss/eventutils/EventInfoScreen.java | 8 ++-- .../cc/aabss/eventutils/KeybindManager.java | 20 ++++---- .../aabss/eventutils/NotificationToast.java | 34 ++++++------- .../cc/aabss/eventutils/UpdateChecker.java | 8 ++-- .../eventutils/commands/CountNameCmd.java | 16 +++---- .../eventutils/commands/PriorityCmd.java | 16 +++---- .../aabss/eventutils/mixin/EntityMixin.java | 16 +++---- .../mixin/EntityRenderDispatcherMixin.java | 32 ++++++------- .../mixin/PlayerEntityRendererMixin.java | 48 +++++++++---------- .../eventutils/utility/ConnectUtility.java | 26 +++++----- .../eventutils/websocket/WebSocketClient.java | 2 +- .../resources/eventutils-qwertz.mixin.json | 12 +++++ src/main/resources/eventutils.mixin.json | 3 +- src/main/resources/fabric.mod.json | 3 +- stonecutter.gradle.kts | 2 +- 17 files changed, 143 insertions(+), 131 deletions(-) create mode 100644 src/main/resources/eventutils-qwertz.mixin.json diff --git a/src/main/java/app/qwertz/PlusTagRenderer.java b/src/main/java/app/qwertz/PlusTagRenderer.java index 3ba0c98..886326d 100644 --- a/src/main/java/app/qwertz/PlusTagRenderer.java +++ b/src/main/java/app/qwertz/PlusTagRenderer.java @@ -8,8 +8,8 @@ //? if >=1.21.6 { import net.minecraft.client.gl.RenderPipelines; //?} else if >=1.21.4 { -import net.minecraft.client.render.RenderLayer; -//?} +/*import net.minecraft.client.render.RenderLayer; +*///?} import org.jetbrains.annotations.NotNull; @@ -29,9 +29,9 @@ public static void draw(@NotNull DrawContext context, @NotNull PlusTag tag, int //? if >=1.21.6 { context.drawTexture(RenderPipelines.GUI_TEXTURED, tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE, TEX_SIZE, TEX_SIZE); //?} else if >=1.21.4 { - context.drawTexture(RenderLayer::getGuiTextured, tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE, TEX_SIZE, TEX_SIZE); - //?} else { - context.drawTexture(tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE); - //?} + /*context.drawTexture(RenderLayer::getGuiTextured, tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE, TEX_SIZE, TEX_SIZE); + *///?} else { + /*context.drawTexture(tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE); + *///?} } } diff --git a/src/main/java/app/qwertz/mixin/PlayerListHudMixin.java b/src/main/java/app/qwertz/mixin/PlayerListHudMixin.java index bfb4c72..61eac9c 100644 --- a/src/main/java/app/qwertz/mixin/PlayerListHudMixin.java +++ b/src/main/java/app/qwertz/mixin/PlayerListHudMixin.java @@ -37,12 +37,12 @@ public abstract class PlayerListHudMixin { if (client.player == null) return; //? if >=1.21.11 { - /*String name = entry.getProfile().name(); + String name = entry.getProfile().name(); final boolean isLocal = entry.getProfile().id().equals(client.player.getUuid()); - *///?} else { - String name = entry.getProfile().getName(); + //?} else { + /*String name = entry.getProfile().getName(); final boolean isLocal = entry.getProfile().getId().equals(client.player.getUuid()); - //?} + *///?} final PlusTag tag; if (isLocal) { @@ -56,10 +56,10 @@ public abstract class PlayerListHudMixin { EventUtils.LOGGER.debug("[TabList] entry={} isLocal=true tag=config.selectedPlusTag={}", name, tag); } else { //? if >=1.21.11 { - /*String uuid = entry.getProfile().id().toString(); - *///?} else { - String uuid = entry.getProfile().getId().toString(); - //?} + String uuid = entry.getProfile().id().toString(); + //?} else { + /*String uuid = entry.getProfile().getId().toString(); + *///?} Set cached = EventAlertsApi.getCached(uuid); if (cached == null) { EventUtils.LOGGER.debug("[TabList] entry={} uuid={} cache MISS, scheduling fetch", name, uuid); diff --git a/src/main/java/cc/aabss/eventutils/EventInfoScreen.java b/src/main/java/cc/aabss/eventutils/EventInfoScreen.java index 041c2ef..0802c0b 100644 --- a/src/main/java/cc/aabss/eventutils/EventInfoScreen.java +++ b/src/main/java/cc/aabss/eventutils/EventInfoScreen.java @@ -27,10 +27,10 @@ public class EventInfoScreen extends Screen { public EventInfoScreen(@NotNull JsonObject json) { //? if >=1.21.11 { - /*super(Text.translatable(EventUtils.MOD.keybindManager.eventInfoKey.getId())); - *///?} else { - super(Text.translatable(EventUtils.MOD.keybindManager.eventInfoKey.getTranslationKey())); - //?} + super(Text.translatable(EventUtils.MOD.keybindManager.eventInfoKey.getId())); + //?} else { + /*super(Text.translatable(EventUtils.MOD.keybindManager.eventInfoKey.getTranslationKey())); + *///?} this.json = json; } diff --git a/src/main/java/cc/aabss/eventutils/KeybindManager.java b/src/main/java/cc/aabss/eventutils/KeybindManager.java index f4cb063..2987319 100644 --- a/src/main/java/cc/aabss/eventutils/KeybindManager.java +++ b/src/main/java/cc/aabss/eventutils/KeybindManager.java @@ -11,8 +11,8 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; //? if >=1.21.11 { -/*import net.minecraft.util.Identifier; -*///?} +import net.minecraft.util.Identifier; +//?} import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,7 +36,7 @@ public class KeybindManager { public KeybindManager(@NotNull EventUtils mod) { // Keybindings //? if >=1.21.11 { - /*final KeyBinding.Category category = KeyBinding.Category.create(Identifier.of("eventutils", "key.category.eventutils")); + final KeyBinding.Category category = KeyBinding.Category.create(Identifier.of("eventutils", "key.category.eventutils")); eventInfoKey = KeyBindingHelper.registerKeyBinding(new KeyBinding( "key.eventutils.eventinfo", InputUtil.Type.KEYSYM, @@ -47,8 +47,8 @@ public KeybindManager(@NotNull EventUtils mod) { InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_F10, category)); - *///?} else { - eventInfoKey = KeyBindingHelper.registerKeyBinding(new KeyBinding( + //?} else { + /*eventInfoKey = KeyBindingHelper.registerKeyBinding(new KeyBinding( "key.eventutils.eventinfo", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_RIGHT_SHIFT, @@ -58,7 +58,7 @@ public KeybindManager(@NotNull EventUtils mod) { InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_F10, CATEGORY)); - //?} + *///?} // DEV: Uncomment to force test event // final KeyBindingMixin testEventKey = (KeyBindingMixin) KeyBindingHelper.registerKeyBinding(new KeyBinding( // "key.eventutils.testevent", @@ -118,10 +118,10 @@ public KeybindManager(@NotNull EventUtils mod) { private boolean canNotPress(@NotNull KeyBinding keyBinding) { //? if >=1.21.11 { - /*final String translationKey = keyBinding.getId(); - *///?} else { - final String translationKey = keyBinding.getTranslationKey(); - //?} + final String translationKey = keyBinding.getId(); + //?} else { + /*final String translationKey = keyBinding.getTranslationKey(); + *///?} final Long lastPressTime = lastKeyPresses.get(translationKey); final long now = System.currentTimeMillis(); if (lastPressTime != null && now - lastPressTime < 500) return true; diff --git a/src/main/java/cc/aabss/eventutils/NotificationToast.java b/src/main/java/cc/aabss/eventutils/NotificationToast.java index 60a745a..63d30ca 100644 --- a/src/main/java/cc/aabss/eventutils/NotificationToast.java +++ b/src/main/java/cc/aabss/eventutils/NotificationToast.java @@ -13,7 +13,7 @@ import net.minecraft.text.Text; import net.minecraft.util.Identifier; //? if >=1.21.6 -/*import net.minecraft.client.gl.RenderPipelines;*/ +import net.minecraft.client.gl.RenderPipelines; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -54,7 +54,7 @@ public NotificationToast(@NotNull Text title, @Nullable Text description, boolea } //? if >=1.21.2 { - /*@Override + @Override public Visibility getVisibility() { return visibility; } @@ -63,7 +63,7 @@ public Visibility getVisibility() { public void update(ToastManager toastManager, long startTime) { visibility = startTime >= Type.DEFAULT.displayDuration ? Toast.Visibility.HIDE : Toast.Visibility.SHOW; } - *///?} + //?} @Override @NotNull public NotificationToast.Type getType() { @@ -82,16 +82,16 @@ public int getHeight() { @Override //? if <1.21.2 { - public Toast.Visibility draw(DrawContext drawContext, ToastManager manager, long startTime) { - //?} else { - /*public void draw(DrawContext drawContext, TextRenderer textRenderer, long startTime) { - *///?} + /*public Toast.Visibility draw(DrawContext drawContext, ToastManager manager, long startTime) { + *///?} else { + public void draw(DrawContext drawContext, TextRenderer textRenderer, long startTime) { + //?} if (width == 160 && lines.size() <= 1) { //? if <1.21.2 { - drawContext.drawGuiTexture(TEXTURE, 0, 0, width, height); - //?} else if >=1.21.6 { - /*drawContext.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 - *///?} else { + /*drawContext.drawGuiTexture(TEXTURE, 0, 0, width, height); + *///?} else if >=1.21.6 { + drawContext.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 + //?} else { /*drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 *///?} } else { @@ -102,7 +102,7 @@ public Toast.Visibility draw(DrawContext drawContext, ToastManager manager, long } //? if <1.21.2 - final TextRenderer textRenderer = manager.getClient().textRenderer; + /*final TextRenderer textRenderer = manager.getClient().textRenderer;*/ if (lines.isEmpty()) { drawContext.drawText(textRenderer, title, 24, 12, Color.YELLOW.getRGB(), false); } else { @@ -110,7 +110,7 @@ public Toast.Visibility draw(DrawContext drawContext, ToastManager manager, long for (int i = 0; i < lines.size(); ++i) drawContext.drawText(textRenderer, lines.get(i), 24, 18 + i * 12, -1, false); } //? if <1.21.2 - return startTime >= Type.DEFAULT.displayDuration ? Toast.Visibility.HIDE : Toast.Visibility.SHOW; + /*return startTime >= Type.DEFAULT.displayDuration ? Toast.Visibility.HIDE : Toast.Visibility.SHOW;*/ } @@ -119,14 +119,14 @@ private void drawPart(@NotNull DrawContext context, int j, int k, int l) { final int n = Math.min(60, width - m); final int widthN = width - n; //? if <=1.21.1 { - context.drawGuiTexture(TEXTURE, 160, 32, 0, j, 0, k, m, l); + /*context.drawGuiTexture(TEXTURE, 160, 32, 0, j, 0, k, m, l); for (int o = m; o < widthN; o += 64) context.drawGuiTexture(TEXTURE, 160, 32, 32, j, o, k, Math.min(64, widthN - o), l); context.drawGuiTexture(TEXTURE, 160, 32, 160 - n, j, widthN, k, n, l); - //?} else if >=1.21.6 { - /*context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 0, j, 0, k, m, l); + *///?} else if >=1.21.6 { + context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 0, j, 0, k, m, l); for (int o = m; o < widthN; o += 64) context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 32, j, o, k, Math.min(64, widthN - o), l); context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 160 - n, j, widthN, k, n, l); - *///?} else { + //?} else { /*context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 0, j, 0, k, m, l); for (int o = m; o < widthN; o += 64) context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 32, j, o, k, Math.min(64, widthN - o), l); context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 160 - n, j, widthN, k, n, l); diff --git a/src/main/java/cc/aabss/eventutils/UpdateChecker.java b/src/main/java/cc/aabss/eventutils/UpdateChecker.java index 5f69363..744ec6a 100644 --- a/src/main/java/cc/aabss/eventutils/UpdateChecker.java +++ b/src/main/java/cc/aabss/eventutils/UpdateChecker.java @@ -31,7 +31,7 @@ private void notifyUpdate(@NotNull String latestVersion) { client.send(() -> { if (client.player == null) return; //? if >=1.21.5 { - /*client.player.sendMessage( + client.player.sendMessage( EventUtils.MESSAGE_PREFIX.copy().append(" §e" + EventUtils.translate("eventutils.updatechecker.new")+"§r §7(v" + Versions.EU_VERSION + " -> v" + latestVersion.replace(Versions.MC_VERSION + "-", "") + ")" + "\n") .setStyle(EventUtils.MESSAGE_PREFIX.getStyle() .withHoverEvent(new HoverEvent.ShowText(translatable("eventutils.updatechecker.hover"))) @@ -39,8 +39,8 @@ private void notifyUpdate(@NotNull String latestVersion) { .append(Text.literal("§7§o" + EventUtils.translate("eventutils.updatechecker.config")) .setStyle(Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/event utils")))), false); - *///?} else { - client.player.sendMessage( + //?} else { + /*client.player.sendMessage( EventUtils.MESSAGE_PREFIX.copy().append(" §e" + EventUtils.translate("eventutils.updatechecker.new")+"§r §7(v" + Versions.EU_VERSION + " -> v" + latestVersion.replace(Versions.MC_VERSION + "-", "") + ")" + "\n") .setStyle(EventUtils.MESSAGE_PREFIX.getStyle() .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, translatable("eventutils.updatechecker.hover"))) @@ -48,7 +48,7 @@ private void notifyUpdate(@NotNull String latestVersion) { .append(Text.literal("§7§o" + EventUtils.translate("eventutils.updatechecker.config")) .setStyle(Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils config")))), false); - //?} + *///?} }); } diff --git a/src/main/java/cc/aabss/eventutils/commands/CountNameCmd.java b/src/main/java/cc/aabss/eventutils/commands/CountNameCmd.java index b09d5a9..53af868 100644 --- a/src/main/java/cc/aabss/eventutils/commands/CountNameCmd.java +++ b/src/main/java/cc/aabss/eventutils/commands/CountNameCmd.java @@ -22,18 +22,18 @@ public static void count(@NotNull CommandContext cont } //? if >=1.21.11 { - /*final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() + final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() .map(entry -> entry.getProfile().name()) .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) .filter(name -> !EventUtils.isNPC(name, true)) .toList(); - *///?} else { - final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() + //?} else { + /*final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() .map(entry -> entry.getProfile().getName()) .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) .filter(name -> !EventUtils.isNPC(name, true)) .toList(); - //?} + *///?} if (namesFiltered.isEmpty()) { context.getSource().sendFeedback(Text.translatable("eventutils.command.countname.noplayers", EventUtils.ERROR_MESSAGE_PREFIX, Text.literal(filter).formatted(Formatting.DARK_RED))); @@ -53,18 +53,18 @@ public static void list(@NotNull CommandContext conte } //? if >=1.21.11 { - /*final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() + final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() .map(entry -> entry.getProfile().name()) .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) .filter(name -> !EventUtils.isNPC(name, true)) .toList(); - *///?} else { - final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() + //?} else { + /*final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() .map(entry -> entry.getProfile().getName()) .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) .filter(name -> !EventUtils.isNPC(name, true)) .toList(); - //?} + *///?} if (namesFiltered.isEmpty()) { context.getSource().sendFeedback(Text.translatable("eventutils.command.countname.noplayers", EventUtils.ERROR_MESSAGE_PREFIX, Text.literal(filter).formatted(Formatting.DARK_RED))); diff --git a/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java b/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java index f28afa9..ab5f0e4 100644 --- a/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java +++ b/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java @@ -110,10 +110,10 @@ public static void priority(@NotNull CommandContext c page - 1 ).setStyle( //? if <=1.21.4 { - Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page - 1))) - //?} else { - /*Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page - 1))) - *///?} + /*Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page - 1))) + *///?} else { + Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page - 1))) + //?} ); } @@ -123,10 +123,10 @@ public static void priority(@NotNull CommandContext c page + 1 ).setStyle( //? if <=1.21.4 { - Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page + 1))) - //?} else { - /*Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page + 1))) - *///?} + /*Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page + 1))) + *///?} else { + Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page + 1))) + //?} ); } diff --git a/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java b/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java index c181d93..15c0ff4 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java @@ -20,10 +20,10 @@ public abstract class EntityMixin { @Shadow public abstract EntityType getType(); //? if >=1.21.11 { - /*@Shadow public abstract Vec3d getSyncedPos(); - *///?} else { - @Shadow public abstract Vec3d getPos(); - //?} + @Shadow public abstract Vec3d getSyncedPos(); + //?} else { + /*@Shadow public abstract Vec3d getPos(); + *///?} @Shadow public abstract Text getName(); @Inject(method = "spawnSprintingParticles", at = @At("HEAD"), cancellable = true) @@ -50,9 +50,9 @@ private void spawnSprintingParticles(CallbackInfo ci) { // Specific radius //? if >=1.21.11 { - /*if (mainPlayer.getSyncedPos().distanceTo(getSyncedPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - *///?} else { - if (mainPlayer.getPos().distanceTo(getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - //?} + if (mainPlayer.getSyncedPos().distanceTo(getSyncedPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + //?} else { + /*if (mainPlayer.getPos().distanceTo(getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + *///?} } } diff --git a/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java b/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java index 70a68c5..b5afcec 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java @@ -6,10 +6,10 @@ import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.render.VertexConsumerProvider; //? if >=1.21.11 { -/*import net.minecraft.client.render.entity.EntityRenderManager; -*///?} else { -import net.minecraft.client.render.entity.EntityRenderDispatcher; -//?} +import net.minecraft.client.render.entity.EntityRenderManager; +//?} else { +/*import net.minecraft.client.render.entity.EntityRenderDispatcher; +*///?} import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; @@ -21,17 +21,17 @@ //? if >=1.21.11 { -/*@Mixin(EntityRenderManager.class) -*///?} else { -@Mixin(EntityRenderDispatcher.class) -//?} +@Mixin(EntityRenderManager.class) +//?} else { +/*@Mixin(EntityRenderDispatcher.class) +*///?} public class EntityRenderDispatcherMixin { @Inject(method = "render", at = @At("HEAD"), cancellable = true) //? if <=1.21.1 { - private void render(Entity entity, double x, double y, double z, float yaw, float tickDelta, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, CallbackInfo ci) { - //?} else { - /*private void render(E entity, double x, double y, double z, float tickDelta, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, CallbackInfo ci) { - *///?} + /*private void render(Entity entity, double x, double y, double z, float yaw, float tickDelta, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, CallbackInfo ci) { + *///?} else { + private void render(E entity, double x, double y, double z, float tickDelta, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, CallbackInfo ci) { + //?} if (!EventUtils.isInHidePlayersMode()) return; if (entity instanceof PlayerEntity player) { @@ -53,9 +53,9 @@ private void render(Entity entity, double x, double y, double // Specific radius final ClientPlayerEntity mainPlayer = MinecraftClient.getInstance().player; //? if >=1.21.11 { - /*if (mainPlayer != null && mainPlayer.getSyncedPos().distanceTo(entity.getSyncedPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - *///?} else { - if (mainPlayer != null && mainPlayer.getPos().distanceTo(entity.getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - //?} + if (mainPlayer != null && mainPlayer.getSyncedPos().distanceTo(entity.getSyncedPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + //?} else { + /*if (mainPlayer != null && mainPlayer.getPos().distanceTo(entity.getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + *///?} } } diff --git a/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java b/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java index 78dbc17..ecf8963 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java @@ -10,10 +10,10 @@ import net.minecraft.text.Text; import net.minecraft.util.math.Vec3d; //? if <1.21.3 { -import net.minecraft.client.network.AbstractClientPlayerEntity; -//?} else { -/*import net.minecraft.client.render.entity.state.PlayerEntityRenderState; -*///?} +/*import net.minecraft.client.network.AbstractClientPlayerEntity; +*///?} else { +import net.minecraft.client.render.entity.state.PlayerEntityRenderState; +//?} import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -25,31 +25,31 @@ public class PlayerEntityRendererMixin { @Inject(at = {@At("HEAD")}, method = "renderLabelIfPresent*", cancellable = true) //? if <=1.20.4 { - public void renderLabelIfPresent(AbstractClientPlayerEntity player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { - //?} else if <1.21.3 { + /*public void renderLabelIfPresent(AbstractClientPlayerEntity player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { + *///?} else if <1.21.3 { /*public void renderLabelIfPresent(AbstractClientPlayerEntity player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, float f, CallbackInfo ci) { *///?} else { - /*public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { - *///?} + public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { + //?} if (!EventUtils.isInHidePlayersMode()) return; final ClientPlayerEntity clientPlayer = MinecraftClient.getInstance().player; if (clientPlayer == null) return; // Get player name //? if <1.21.3 { - final Text nameText = player.getName(); - //?} else { - /*final Text nameText = player.playerName; + /*final Text nameText = player.getName(); + *///?} else { + final Text nameText = player.playerName; if (nameText == null) return; - *///?} + //?} final String name = nameText.getString().toLowerCase(); // Check if main player //? if <1.21.3 { - if (player.isMainPlayer()) return; - //?} else { - /*if (name.equals(clientPlayer.getName().getString().toLowerCase())) return; - *///?} + /*if (player.isMainPlayer()) return; + *///?} else { + if (name.equals(clientPlayer.getName().getString().toLowerCase())) return; + //?} // Not visible in current view mode -> hide nametag if (!EventUtils.isPlayerVisible(name)) { @@ -67,16 +67,16 @@ public void renderLabelIfPresent(AbstractClientPlayerEntity player, Text text, M // Get player position //? if <1.21.3 { - final Vec3d playerPos = player.getPos(); - //?} else { - /*final Vec3d playerPos = new Vec3d(player.x, player.y, player.z); - *///?} + /*final Vec3d playerPos = player.getPos(); + *///?} else { + final Vec3d playerPos = new Vec3d(player.x, player.y, player.z); + //?} // Radius-specific //? if >=1.21.11 { - /*if (clientPlayer.getSyncedPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - *///?} else { - if (clientPlayer.getPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - //?} + if (clientPlayer.getSyncedPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + //?} else { + /*if (clientPlayer.getPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + *///?} } } diff --git a/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java b/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java index c4be12f..bf8ef7f 100644 --- a/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java +++ b/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java @@ -40,16 +40,16 @@ public static void connect(@NotNull String ip) { //? if >=1.21.11 { client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false, false); //?} else if >=1.21 { - client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false); - //?} else { - client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic"))); - //?} + /*client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false); + *///?} else { + /*client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic"))); + *///?} //? if <=1.20.4 { - ConnectScreen.connect(screen, client, address, new ServerInfo("EventUtils Event Server", ip, ServerInfo.ServerType.OTHER), true); - //?} else { - /*ConnectScreen.connect(screen, client, address, new ServerInfo("EventUtils Event Server", ip, ServerInfo.ServerType.OTHER), true, null); - *///?} + /*ConnectScreen.connect(screen, client, address, new ServerInfo("EventUtils Event Server", ip, ServerInfo.ServerType.OTHER), true); + *///?} else { + ConnectScreen.connect(screen, client, address, new ServerInfo("EventUtils Event Server", ip, ServerInfo.ServerType.OTHER), true, null); + //?} } catch (final Exception e) { EventUtils.LOGGER.error("Failed to connect to server: {}", e.getMessage()); throw new RuntimeException(e); @@ -108,10 +108,10 @@ public static String getIp(@NotNull String message) { final int size = strings.size(); if (size == 1) { //? if java: <21 { - return strings.get(0); - //?} else { - /*return strings.getFirst(); - *///?} + /*return strings.get(0); + *///?} else { + return strings.getFirst(); + //?} } if (size > 1) for (final String string : strings) if (isValidIp(string)) return string; @@ -133,7 +133,7 @@ private static boolean isValidIp(@NotNull String ip) { try { final String body = client.sendAsync(request, HttpResponse.BodyHandlers.ofString()).get().body(); //? if java: >=21 - /*client.close();*/ + client.close(); return !body.endsWith(":null}") && !body.endsWith("Not Found") && !body.endsWith("Invalid address value"); } catch (final InterruptedException e) { Thread.currentThread().interrupt(); diff --git a/src/main/java/cc/aabss/eventutils/websocket/WebSocketClient.java b/src/main/java/cc/aabss/eventutils/websocket/WebSocketClient.java index a18865e..12db3b3 100644 --- a/src/main/java/cc/aabss/eventutils/websocket/WebSocketClient.java +++ b/src/main/java/cc/aabss/eventutils/websocket/WebSocketClient.java @@ -74,7 +74,7 @@ public void close(@NotNull String reason) { private void closeTasks() { //? if java: >=21 - /*if (httpClient != null) httpClient.close();*/ + if (httpClient != null) httpClient.close(); if (keepAlive != null) keepAlive.cancel(true); } diff --git a/src/main/resources/eventutils-qwertz.mixin.json b/src/main/resources/eventutils-qwertz.mixin.json new file mode 100644 index 0000000..812d351 --- /dev/null +++ b/src/main/resources/eventutils-qwertz.mixin.json @@ -0,0 +1,12 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "app.qwertz.mixin", + "compatibilityLevel": "JAVA_17", + "client": [ + "PlayerListHudMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/src/main/resources/eventutils.mixin.json b/src/main/resources/eventutils.mixin.json index e54f974..753caf6 100644 --- a/src/main/resources/eventutils.mixin.json +++ b/src/main/resources/eventutils.mixin.json @@ -13,8 +13,7 @@ "EntryListWidgetAccessor", "KeyBindingMixin", "MultiplayerScreenMixin", - "PlayerEntityRendererMixin", - "app.qwertz.mixin.PlayerListHudMixin" + "PlayerEntityRendererMixin" ], "injectors": { "defaultRequire": 1 diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 73593a7..1afbe46 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -13,7 +13,8 @@ "icon": "assets/eventutils/textures/icon.png", "environment": "*", "mixins": [ - "eventutils.mixin.json" + "eventutils.mixin.json", + "eventutils-qwertz.mixin.json" ], "entrypoints": { "client": [ diff --git a/stonecutter.gradle.kts b/stonecutter.gradle.kts index e7f29ce..e9e836b 100644 --- a/stonecutter.gradle.kts +++ b/stonecutter.gradle.kts @@ -1,6 +1,6 @@ plugins { id("dev.kikugie.stonecutter") } -stonecutter active "1.20.4" /* [SC] DO NOT EDIT */ +stonecutter active "1.21.11" /* [SC] DO NOT EDIT */ stonecutter.registerChiseled(tasks.register("chiseledBuild", stonecutter.chiseled) { group = "project" From 0e2444ac368264a9128314ba89c9be7e59b89cf0 Mon Sep 17 00:00:00 2001 From: QWERTZexe Date: Sun, 15 Mar 2026 19:37:30 +0100 Subject: [PATCH 8/9] fixed EVEN MORE bugs --- build.gradle.kts | 4 +- .../mixin/EntityRenderDispatcherMixin.java | 46 +++++++++---- .../mixin/PlayerEntityRendererMixin.java | 66 +++++++++++++------ .../resources/eventutils-1.21.11.mixin.json | 19 ++++++ src/main/resources/fabric.mod.json | 2 +- 5 files changed, 101 insertions(+), 36 deletions(-) create mode 100644 src/main/resources/eventutils-1.21.11.mixin.json diff --git a/build.gradle.kts b/build.gradle.kts index 3074c9f..fde16cf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -37,10 +37,12 @@ dependencies { if (hasProperty("deps.placeholder_api")) dependencies.modCompileOnly("eu.pb4", "placeholder-api", property("deps.placeholder_api").toString()) // Replacements for fabric.mod.json and config.json +val mixinConfig = if (stonecutter.current.version == "1.21.11") "eventutils-1.21.11.mixin.json" else "eventutils.mixin.json" addReplacementsTask(setOf("fabric.mod.json"), getDefaultReplacements() + mapOf( "mod_name" to property("mod.name").toString(), "mod_version" to property("mod.version").toString(), - "deps_minecraft" to property("deps.minecraft").toString())) + "deps_minecraft" to property("deps.minecraft").toString(), + "mixin_config" to mixinConfig)) base { archivesName = rootProject.name diff --git a/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java b/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java index b5afcec..d9c17ca 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java @@ -6,12 +6,17 @@ import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.render.VertexConsumerProvider; //? if >=1.21.11 { +import net.minecraft.client.render.command.OrderedRenderCommandQueue; import net.minecraft.client.render.entity.EntityRenderManager; +import net.minecraft.client.render.entity.state.EntityRenderState; +import net.minecraft.client.render.state.CameraRenderState; +import net.minecraft.util.math.Vec3d; //?} else { /*import net.minecraft.client.render.entity.EntityRenderDispatcher; *///?} import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; import net.minecraft.entity.player.PlayerEntity; import org.spongepowered.asm.mixin.Mixin; @@ -26,36 +31,51 @@ /*@Mixin(EntityRenderDispatcher.class) *///?} public class EntityRenderDispatcherMixin { + //? if >=1.21.11 { @Inject(method = "render", at = @At("HEAD"), cancellable = true) - //? if <=1.21.1 { - /*private void render(Entity entity, double x, double y, double z, float yaw, float tickDelta, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, CallbackInfo ci) { - *///?} else { + private void render(EntityRenderState renderState, CameraRenderState cameraRenderState, double x, double y, double z, MatrixStack matrixStack, OrderedRenderCommandQueue orderedRenderCommandQueue, CallbackInfo ci) { + if (!EventUtils.isInHidePlayersMode()) return; + + if (renderState.entityType == EntityType.PLAYER) { + final ClientPlayerEntity mainPlayer = MinecraftClient.getInstance().player; + if (mainPlayer != null && renderState.displayName != null && mainPlayer.getName().getString().equalsIgnoreCase(renderState.displayName.getString())) return; + final String name = renderState.displayName != null ? renderState.displayName.getString().toLowerCase() : ""; + if (EventUtils.isPlayerVisible(name)) return; + } else { + if (!EventUtils.MOD.config.hiddenEntityTypes.contains(renderState.entityType)) return; + } + + if (EventUtils.MOD.config.hidePlayersRadius == 0) { + ci.cancel(); + return; + } + + final ClientPlayerEntity mainPlayer = MinecraftClient.getInstance().player; + if (mainPlayer != null) { + final Vec3d entityPos = new Vec3d(renderState.x, renderState.y, renderState.z); + if (mainPlayer.getSyncedPos().distanceTo(entityPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + } + } + //?} else { + /*@Inject(method = "render", at = @At("HEAD"), cancellable = true) private void render(E entity, double x, double y, double z, float tickDelta, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, CallbackInfo ci) { - //?} if (!EventUtils.isInHidePlayersMode()) return; if (entity instanceof PlayerEntity player) { - // Players if (player.isMainPlayer()) return; final String name = player.getName().getString().toLowerCase(); if (EventUtils.isPlayerVisible(name)) return; } else { - // Non-players (mob) if (!EventUtils.MOD.config.hiddenEntityTypes.contains(entity.getType())) return; } - // Any radius if (EventUtils.MOD.config.hidePlayersRadius == 0) { ci.cancel(); return; } - // Specific radius final ClientPlayerEntity mainPlayer = MinecraftClient.getInstance().player; - //? if >=1.21.11 { - if (mainPlayer != null && mainPlayer.getSyncedPos().distanceTo(entity.getSyncedPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - //?} else { - /*if (mainPlayer != null && mainPlayer.getPos().distanceTo(entity.getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - *///?} + if (mainPlayer != null && mainPlayer.getPos().distanceTo(entity.getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); } + *///?} } diff --git a/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java b/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java index ecf8963..60ba7cd 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java @@ -6,14 +6,18 @@ import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.entity.PlayerEntityRenderer; +//? if >=1.21.11 { +import net.minecraft.client.render.command.OrderedRenderCommandQueue; +import net.minecraft.client.render.state.CameraRenderState; +//?} +//? if >=1.21.3 { +import net.minecraft.client.render.entity.state.PlayerEntityRenderState; +//?} else { +/*import net.minecraft.client.network.AbstractClientPlayerEntity; +*///?} import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.Text; import net.minecraft.util.math.Vec3d; -//? if <1.21.3 { -/*import net.minecraft.client.network.AbstractClientPlayerEntity; -*///?} else { -import net.minecraft.client.render.entity.state.PlayerEntityRenderState; -//?} import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -23,12 +27,35 @@ @Mixin(PlayerEntityRenderer.class) public class PlayerEntityRendererMixin { - @Inject(at = {@At("HEAD")}, method = "renderLabelIfPresent*", cancellable = true) + //? if >=1.21.11 { + @Inject(at = @At("HEAD"), method = "renderLabelIfPresent", cancellable = true) + public void renderLabelIfPresent(PlayerEntityRenderState player, MatrixStack matrixStack, OrderedRenderCommandQueue orderedRenderCommandQueue, CameraRenderState cameraRenderState, CallbackInfo ci) { + if (!EventUtils.isInHidePlayersMode()) return; + final ClientPlayerEntity clientPlayer = MinecraftClient.getInstance().player; + if (clientPlayer == null) return; + final Text nameText = player.playerName; + if (nameText == null) return; + final String name = nameText.getString().toLowerCase(); + if (name.equals(clientPlayer.getName().getString().toLowerCase())) return; + if (!EventUtils.isPlayerVisible(name)) { + ci.cancel(); + return; + } + if (!EventUtils.shouldShowNametagFor(name)) { + ci.cancel(); + return; + } + if (EventUtils.MOD.config.hidePlayersRadius == 0) return; + final Vec3d playerPos = new Vec3d(player.x, player.y, player.z); + if (clientPlayer.getSyncedPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + } + //?} else { + /*@Inject(at = {@At("HEAD")}, method = "renderLabelIfPresent*", cancellable = true) //? if <=1.20.4 { - /*public void renderLabelIfPresent(AbstractClientPlayerEntity player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { - *///?} else if <1.21.3 { - /*public void renderLabelIfPresent(AbstractClientPlayerEntity player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, float f, CallbackInfo ci) { - *///?} else { + /^public void renderLabelIfPresent(AbstractClientPlayerEntity player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { + ^///?} else if <1.21.3 { + /^public void renderLabelIfPresent(AbstractClientPlayerEntity player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, float f, CallbackInfo ci) { + ^///?} else { public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { //?} if (!EventUtils.isInHidePlayersMode()) return; @@ -37,8 +64,8 @@ public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, Matr // Get player name //? if <1.21.3 { - /*final Text nameText = player.getName(); - *///?} else { + /^final Text nameText = player.getName(); + ^///?} else { final Text nameText = player.playerName; if (nameText == null) return; //?} @@ -46,8 +73,8 @@ public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, Matr // Check if main player //? if <1.21.3 { - /*if (player.isMainPlayer()) return; - *///?} else { + /^if (player.isMainPlayer()) return; + ^///?} else { if (name.equals(clientPlayer.getName().getString().toLowerCase())) return; //?} @@ -67,16 +94,13 @@ public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, Matr // Get player position //? if <1.21.3 { - /*final Vec3d playerPos = player.getPos(); - *///?} else { + /^final Vec3d playerPos = player.getPos(); + ^///?} else { final Vec3d playerPos = new Vec3d(player.x, player.y, player.z); //?} // Radius-specific - //? if >=1.21.11 { - if (clientPlayer.getSyncedPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - //?} else { - /*if (clientPlayer.getPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - *///?} + if (clientPlayer.getPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); } + *///?} } diff --git a/src/main/resources/eventutils-1.21.11.mixin.json b/src/main/resources/eventutils-1.21.11.mixin.json new file mode 100644 index 0000000..ed49b7e --- /dev/null +++ b/src/main/resources/eventutils-1.21.11.mixin.json @@ -0,0 +1,19 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "cc.aabss.eventutils.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "EntityMixin" + ], + "client": [ + "ClientMixin", + "EntityRenderDispatcherMixin", + "EntryListWidgetAccessor", + "KeyBindingMixin", + "PlayerEntityRendererMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 1afbe46..b572eec 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -13,7 +13,7 @@ "icon": "assets/eventutils/textures/icon.png", "environment": "*", "mixins": [ - "eventutils.mixin.json", + "${mixin_config}", "eventutils-qwertz.mixin.json" ], "entrypoints": { From 41a8f9d3a20330ff22cb7785f36edb9c8dfc7d62 Mon Sep 17 00:00:00 2001 From: QWERTZexe Date: Tue, 17 Mar 2026 17:20:12 +0100 Subject: [PATCH 9/9] fixed all srnyx --- crop_sheet.py | 1 - src/main/java/app/qwertz/PlusTagScreen.java | 96 ------------------- src/main/java/app/qwertz/commands/TagCmd.java | 34 ------- .../app/qwertz/mixin/PlayerListHudMixin.java | 83 ---------------- .../cc/aabss/eventutils/EventInfoScreen.java | 8 +- .../java/cc/aabss/eventutils/EventUtils.java | 38 ++++---- .../cc/aabss/eventutils/KeybindManager.java | 24 ++--- .../aabss/eventutils/NotificationToast.java | 18 ++-- .../cc/aabss/eventutils/UpdateChecker.java | 8 +- .../eventutils/commands/CommandRegister.java | 7 -- .../eventutils/commands/CountNameCmd.java | 16 ++-- .../eventutils/commands/PriorityCmd.java | 16 ++-- .../aabss/eventutils/config/EventConfig.java | 21 ---- .../aabss/eventutils/mixin/EntityMixin.java | 20 ++-- .../mixin/EntityRenderDispatcherMixin.java | 32 +++---- .../mixin/PlayerEntityRendererMixin.java | 44 ++++----- .../eventutils/mixin/PlayerListHudMixin.java | 69 +++++++++++++ .../eventutils/plustag}/EventAlertsApi.java | 88 ++++++++--------- .../aabss/eventutils/plustag}/PlusTag.java | 12 +-- .../eventutils/plustag}/PlusTagRenderer.java | 22 ++--- .../eventutils/utility/ConnectUtility.java | 8 +- .../resources/eventutils-1.21.11.mixin.json | 1 + .../resources/eventutils-qwertz.mixin.json | 12 --- src/main/resources/eventutils.mixin.json | 1 + src/main/resources/fabric.mod.json | 5 +- stonecutter.gradle.kts | 2 +- 26 files changed, 248 insertions(+), 438 deletions(-) delete mode 100644 src/main/java/app/qwertz/PlusTagScreen.java delete mode 100644 src/main/java/app/qwertz/commands/TagCmd.java delete mode 100644 src/main/java/app/qwertz/mixin/PlayerListHudMixin.java create mode 100644 src/main/java/cc/aabss/eventutils/mixin/PlayerListHudMixin.java rename src/main/java/{app/qwertz => cc/aabss/eventutils/plustag}/EventAlertsApi.java (78%) rename src/main/java/{app/qwertz => cc/aabss/eventutils/plustag}/PlusTag.java (91%) rename src/main/java/{app/qwertz => cc/aabss/eventutils/plustag}/PlusTagRenderer.java (61%) delete mode 100644 src/main/resources/eventutils-qwertz.mixin.json diff --git a/crop_sheet.py b/crop_sheet.py index a18b17f..ab67395 100644 --- a/crop_sheet.py +++ b/crop_sheet.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# Copyright 2026 QWERTZexe ALL RIGHTS RESERVED """Crop sheet.png (3 cols x 2 rows) into individual plus-tag icons with transparent background.""" from pathlib import Path diff --git a/src/main/java/app/qwertz/PlusTagScreen.java b/src/main/java/app/qwertz/PlusTagScreen.java deleted file mode 100644 index 4d0b3ad..0000000 --- a/src/main/java/app/qwertz/PlusTagScreen.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2026 QWERTZexe ALL RIGHTS RESERVED - */ - -package app.qwertz; - -import cc.aabss.eventutils.EventUtils; - -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.screen.Screen; -import net.minecraft.client.gui.tooltip.Tooltip; -import net.minecraft.client.gui.widget.ButtonWidget; -import net.minecraft.text.Text; - -import org.jetbrains.annotations.Nullable; - -import java.util.Set; - -import static net.minecraft.text.Text.translatable; - - -/** - * Screen to choose which plus tag to display next to your name. - * Shows only unlocked tags; hover shows how each was unlocked. - */ -public class PlusTagScreen extends Screen { - @Nullable private final Screen parent; - private final Set unlocked; - - public PlusTagScreen(@Nullable Screen parent, @Nullable Set unlocked) { - super(translatable("eventutils.plustag.title")); - this.parent = parent; - this.unlocked = unlocked != null ? unlocked : Set.of(); - } - - @Override - protected void init() { - final PlusTag current = EventUtils.MOD.config.selectedPlusTag; - int y = 40; - final int centerX = width / 2; - final int btnWidth = 200; - final int spacing = 26; - - // Option: None (hide / linked) - addTagButton(centerX - btnWidth / 2, y, btnWidth, PlusTag.NONE, current); - y += spacing; - - if (unlocked.contains(PlusTag.WHITE)) { - addTagButton(centerX - btnWidth / 2, y, btnWidth, PlusTag.WHITE, current); - y += spacing; - } - - if (unlocked.contains(PlusTag.RED)) { - addTagButton(centerX - btnWidth / 2, y, btnWidth, PlusTag.RED, current); - y += spacing; - } - - if (unlocked.contains(PlusTag.BLUE)) { - addTagButton(centerX - btnWidth / 2, y, btnWidth, PlusTag.BLUE, current); - y += spacing; - } - - if (unlocked.contains(PlusTag.ORANGE)) { - addTagButton(centerX - btnWidth / 2, y, btnWidth, PlusTag.ORANGE, current); - y += spacing; - } - - if (unlocked.contains(PlusTag.PINK)) { - addTagButton(centerX - btnWidth / 2, y, btnWidth, PlusTag.PINK, current); - y += spacing; - } - - addDrawableChild(ButtonWidget.builder(translatable("gui.done"), btn -> { - if (client != null) client.setScreen(parent); - }).dimensions(centerX - 60, height - 28, 120, 20).build()); - } - - private void addTagButton(int x, int y, int w, PlusTag tag, PlusTag current) { - Text label = translatable("eventutils.plustag." + tag.getKey()); - Text tooltipText = translatable(tag.getUnlockKey()); - boolean selected = current == tag; - ButtonWidget btn = ButtonWidget.builder(selected ? label.copy().append(" ✓") : label, b -> { - EventUtils.MOD.config.setSelectedPlusTag(tag); - if (client != null) client.setScreen(new PlusTagScreen(parent, unlocked)); - }).dimensions(x, y, w, 20).tooltip(Tooltip.of(tooltipText)).build(); - addDrawableChild(btn); - } - - @Override - public void render(DrawContext context, int mouseX, int mouseY, float delta) { - context.fill(0, 0, width, height, 0xC0101010); - context.drawCenteredTextWithShadow(textRenderer, title, width / 2, 14, 0xFFFFFF); - context.drawCenteredTextWithShadow(textRenderer, translatable("eventutils.plustag.subtitle"), width / 2, 24, 0xA0A0A0); - super.render(context, mouseX, mouseY, delta); - } -} diff --git a/src/main/java/app/qwertz/commands/TagCmd.java b/src/main/java/app/qwertz/commands/TagCmd.java deleted file mode 100644 index aac4990..0000000 --- a/src/main/java/app/qwertz/commands/TagCmd.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2026 QWERTZexe ALL RIGHTS RESERVED - */ - -package app.qwertz.commands; - -import app.qwertz.EventAlertsApi; -import app.qwertz.PlusTagScreen; - -import cc.aabss.eventutils.EventUtils; - -import com.mojang.brigadier.context.CommandContext; - -import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; - -import net.minecraft.client.MinecraftClient; - -import org.jetbrains.annotations.NotNull; - - -public class TagCmd { - public static int openTagScreen(@NotNull CommandContext context) { - MinecraftClient client = context.getSource().getClient(); - client.send(() -> { - var player = context.getSource().getPlayer(); - var unlocked = player != null - ? EventAlertsApi.getCached(player.getUuid().toString()) - : null; - EventUtils.LOGGER.debug("[TagCmd] openTagScreen: player={} uuid={} cachedUnlocked={}", player != null ? player.getName().getString() : null, player != null ? player.getUuid() : null, unlocked); - client.setScreen(new PlusTagScreen(client.currentScreen, unlocked)); - }); - return 1; - } -} diff --git a/src/main/java/app/qwertz/mixin/PlayerListHudMixin.java b/src/main/java/app/qwertz/mixin/PlayerListHudMixin.java deleted file mode 100644 index 61eac9c..0000000 --- a/src/main/java/app/qwertz/mixin/PlayerListHudMixin.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2026 QWERTZexe ALL RIGHTS RESERVED - */ - -package app.qwertz.mixin; - -import app.qwertz.EventAlertsApi; -import app.qwertz.PlusTag; -import app.qwertz.PlusTagRenderer; - -import cc.aabss.eventutils.EventUtils; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.DrawContext; -import net.minecraft.client.gui.hud.PlayerListHud; -import net.minecraft.client.network.PlayerListEntry; -import net.minecraft.scoreboard.Scoreboard; -import net.minecraft.scoreboard.ScoreboardObjective; - -import java.util.Set; - -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - - -@Mixin(PlayerListHud.class) -public abstract class PlayerListHudMixin { - @Shadow @Final private MinecraftClient client; - - /** Draw + icon for every tab list row (local player = selected tag, others = best unlocked from Event Alerts). */ - @Inject(method = "renderLatencyIcon", at = @At("TAIL")) - private void eventutils$drawPlusTagNextToName(DrawContext context, int width, int x, int y, PlayerListEntry entry, CallbackInfo ci) { - if (client.player == null) return; - - //? if >=1.21.11 { - String name = entry.getProfile().name(); - final boolean isLocal = entry.getProfile().id().equals(client.player.getUuid()); - //?} else { - /*String name = entry.getProfile().getName(); - final boolean isLocal = entry.getProfile().getId().equals(client.player.getUuid()); - *///?} - final PlusTag tag; - - if (isLocal) { - // Fallback: if we never got a fetch (e.g. JOIN ran before player was ready), trigger it when tab list is drawn - String localUuid = client.player.getUuid().toString(); - if (EventAlertsApi.getCached(localUuid) == null) { - EventUtils.LOGGER.info("[EventUtils] Tab list: local player not cached, scheduling Event Alerts fetch uuid={}", localUuid); - EventAlertsApi.scheduleFetchIfNeeded(localUuid); - } - tag = EventUtils.MOD.config.selectedPlusTag; - EventUtils.LOGGER.debug("[TabList] entry={} isLocal=true tag=config.selectedPlusTag={}", name, tag); - } else { - //? if >=1.21.11 { - String uuid = entry.getProfile().id().toString(); - //?} else { - /*String uuid = entry.getProfile().getId().toString(); - *///?} - Set cached = EventAlertsApi.getCached(uuid); - if (cached == null) { - EventUtils.LOGGER.debug("[TabList] entry={} uuid={} cache MISS, scheduling fetch", name, uuid); - EventAlertsApi.scheduleFetchIfNeeded(uuid); - return; - } - tag = PlusTag.pickBestForDisplay(cached); - EventUtils.LOGGER.debug("[TabList] entry={} uuid={} cache HIT unlocked={} pickBest={}", name, uuid, cached, tag); - } - - if (tag == null || tag == PlusTag.WHITE) { - EventUtils.LOGGER.debug("[TabList] entry={} skip draw: tag={} (null or WHITE)", name, tag); - return; - } - - int iconSize = 8; - int iconX = x - 8; - PlusTagRenderer.draw(context, tag, iconX, y, iconSize); - EventUtils.LOGGER.debug("[TabList] entry={} DRAW tag={} at ({}, {}) size={}", name, tag, iconX, y, iconSize); - } -} diff --git a/src/main/java/cc/aabss/eventutils/EventInfoScreen.java b/src/main/java/cc/aabss/eventutils/EventInfoScreen.java index 0802c0b..041c2ef 100644 --- a/src/main/java/cc/aabss/eventutils/EventInfoScreen.java +++ b/src/main/java/cc/aabss/eventutils/EventInfoScreen.java @@ -27,10 +27,10 @@ public class EventInfoScreen extends Screen { public EventInfoScreen(@NotNull JsonObject json) { //? if >=1.21.11 { - super(Text.translatable(EventUtils.MOD.keybindManager.eventInfoKey.getId())); - //?} else { - /*super(Text.translatable(EventUtils.MOD.keybindManager.eventInfoKey.getTranslationKey())); - *///?} + /*super(Text.translatable(EventUtils.MOD.keybindManager.eventInfoKey.getId())); + *///?} else { + super(Text.translatable(EventUtils.MOD.keybindManager.eventInfoKey.getTranslationKey())); + //?} this.json = json; } diff --git a/src/main/java/cc/aabss/eventutils/EventUtils.java b/src/main/java/cc/aabss/eventutils/EventUtils.java index 67d3f7c..4b40628 100644 --- a/src/main/java/cc/aabss/eventutils/EventUtils.java +++ b/src/main/java/cc/aabss/eventutils/EventUtils.java @@ -6,7 +6,7 @@ import cc.aabss.eventutils.websocket.WebSocketClient; import cc.aabss.eventutils.config.EventConfig; import cc.aabss.eventutils.config.PlayerGroup; -import app.qwertz.EventAlertsApi; +import cc.aabss.eventutils.plustag.EventAlertsApi; import com.google.gson.JsonObject; @@ -88,12 +88,12 @@ public void onInitializeClient() { // Update checker ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> updateChecker.checkUpdate()); - // Fetch Event Alerts plus tags for local player (for tag menu) + // Fetch Event Alerts plus tags for local player ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> { if (client.player != null) { - String uuid = client.player.getUuid().toString(); + var uuid = client.player.getUuid(); LOGGER.info("[EventUtils] JOIN: scheduling Event Alerts fetch for local player uuid={}", uuid); - EventAlertsApi.scheduleFetchIfNeeded(uuid); + EventAlertsApi.scheduleFetchIfNeeded(uuid.toString()); } else { LOGGER.info("[EventUtils] JOIN: client.player is null, skipping fetch (will retry when tab list is opened)"); } @@ -165,41 +165,41 @@ public static boolean isNPC(@NotNull String name) { } /** Whether the current view mode is "players revealed" (show everyone). */ - public static boolean isHidePlayersRevealed() { - final int n = MOD.config.groups.size(); - if (n == 0) return MOD.hidePlayersViewMode == 1; - return MOD.hidePlayersViewMode >= n; + public boolean isHidePlayersRevealed() { + final int n = config.groups.size(); + if (n == 0) return hidePlayersViewMode == 1; + return hidePlayersViewMode >= n; } /** Whether we are in a "hide" mode (any group or hide-all). */ - public static boolean isInHidePlayersMode() { - final int n = MOD.config.groups.size(); - if (n == 0) return MOD.hidePlayersViewMode == 0; - return MOD.hidePlayersViewMode < n; + public boolean isInHidePlayersMode() { + final int n = config.groups.size(); + if (n == 0) return hidePlayersViewMode == 0; + return hidePlayersViewMode < n; } /** Current group when in group view mode, or null if revealed or no groups. */ @Nullable - public static PlayerGroup getCurrentViewGroup() { - final var groups = MOD.config.groups; - if (groups.isEmpty() || MOD.hidePlayersViewMode >= groups.size()) return null; - return groups.get(MOD.hidePlayersViewMode); + public PlayerGroup getCurrentViewGroup() { + final var groups = config.groups; + if (groups.isEmpty() || hidePlayersViewMode >= groups.size()) return null; + return groups.get(hidePlayersViewMode); } /** * True if the player (by lowercased name) should be visible with current view mode. * Caller must exclude main player. */ - public static boolean isPlayerVisible(@NotNull String nameLower) { + public boolean isPlayerVisible(@NotNull String nameLower) { if (isHidePlayersRevealed()) return true; - if (MOD.config.whitelistedPlayers.contains(nameLower) || isNPC(nameLower)) return true; + if (config.whitelistedPlayers.contains(nameLower) || isNPC(nameLower)) return true; final PlayerGroup group = getCurrentViewGroup(); if (group == null) return false; // no groups, hide mode: only whitelist/NPC return group.containsPlayer(nameLower); } /** True if the nametag for this visible player should be drawn (per-group setting when in group view). */ - public static boolean shouldShowNametagFor(@NotNull String nameLower) { + public boolean shouldShowNametagFor(@NotNull String nameLower) { if (!isInHidePlayersMode()) return true; final PlayerGroup group = getCurrentViewGroup(); if (group == null) return true; // hide-all with no groups: use default diff --git a/src/main/java/cc/aabss/eventutils/KeybindManager.java b/src/main/java/cc/aabss/eventutils/KeybindManager.java index 2987319..24d30a4 100644 --- a/src/main/java/cc/aabss/eventutils/KeybindManager.java +++ b/src/main/java/cc/aabss/eventutils/KeybindManager.java @@ -11,8 +11,8 @@ import net.minecraft.text.Text; import net.minecraft.util.Formatting; //? if >=1.21.11 { -import net.minecraft.util.Identifier; -//?} +/*import net.minecraft.util.Identifier; +*///?} import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -36,7 +36,7 @@ public class KeybindManager { public KeybindManager(@NotNull EventUtils mod) { // Keybindings //? if >=1.21.11 { - final KeyBinding.Category category = KeyBinding.Category.create(Identifier.of("eventutils", "key.category.eventutils")); + /*final KeyBinding.Category category = KeyBinding.Category.create(Identifier.of("eventutils", "key.category.eventutils")); eventInfoKey = KeyBindingHelper.registerKeyBinding(new KeyBinding( "key.eventutils.eventinfo", InputUtil.Type.KEYSYM, @@ -47,8 +47,8 @@ public KeybindManager(@NotNull EventUtils mod) { InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_F10, category)); - //?} else { - /*eventInfoKey = KeyBindingHelper.registerKeyBinding(new KeyBinding( + *///?} else { + eventInfoKey = KeyBindingHelper.registerKeyBinding(new KeyBinding( "key.eventutils.eventinfo", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_RIGHT_SHIFT, @@ -58,7 +58,7 @@ public KeybindManager(@NotNull EventUtils mod) { InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_F10, CATEGORY)); - *///?} + //?} // DEV: Uncomment to force test event // final KeyBindingMixin testEventKey = (KeyBindingMixin) KeyBindingHelper.registerKeyBinding(new KeyBinding( // "key.eventutils.testevent", @@ -102,12 +102,12 @@ public KeybindManager(@NotNull EventUtils mod) { final int groupCount = mod.config.groups.size(); final int totalStates = groupCount == 0 ? 2 : groupCount + 1; mod.hidePlayersViewMode = (mod.hidePlayersViewMode + 1) % totalStates; - final boolean revealed = EventUtils.isHidePlayersRevealed(); + final boolean revealed = EventUtils.MOD.isHidePlayersRevealed(); final Text message; if (revealed) { message = translatable("eventutils.hideplayers.view_revealed").formatted(Formatting.GREEN); } else { - final var group = EventUtils.getCurrentViewGroup(); + final var group = EventUtils.MOD.getCurrentViewGroup(); message = (group != null ? literal(group.getName()) : translatable("eventutils.hideplayers.view_whitelist_only")) .formatted(Formatting.GREEN); } @@ -118,10 +118,10 @@ public KeybindManager(@NotNull EventUtils mod) { private boolean canNotPress(@NotNull KeyBinding keyBinding) { //? if >=1.21.11 { - final String translationKey = keyBinding.getId(); - //?} else { - /*final String translationKey = keyBinding.getTranslationKey(); - *///?} + /*final String translationKey = keyBinding.getId(); + *///?} else { + final String translationKey = keyBinding.getTranslationKey(); + //?} final Long lastPressTime = lastKeyPresses.get(translationKey); final long now = System.currentTimeMillis(); if (lastPressTime != null && now - lastPressTime < 500) return true; diff --git a/src/main/java/cc/aabss/eventutils/NotificationToast.java b/src/main/java/cc/aabss/eventutils/NotificationToast.java index 63d30ca..af7bc45 100644 --- a/src/main/java/cc/aabss/eventutils/NotificationToast.java +++ b/src/main/java/cc/aabss/eventutils/NotificationToast.java @@ -13,7 +13,7 @@ import net.minecraft.text.Text; import net.minecraft.util.Identifier; //? if >=1.21.6 -import net.minecraft.client.gl.RenderPipelines; +/*import net.minecraft.client.gl.RenderPipelines;*/ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -90,10 +90,10 @@ public void draw(DrawContext drawContext, TextRenderer textRenderer, long startT //? if <1.21.2 { /*drawContext.drawGuiTexture(TEXTURE, 0, 0, width, height); *///?} else if >=1.21.6 { - drawContext.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 - //?} else { - /*drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 - *///?} + /*drawContext.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 + *///?} else { + drawContext.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 0, 0, width, height); // work on 1.21.4 and 1.21.5 + //?} } else { int minHeight = Math.min(4, height - 28); drawPart(drawContext, 0, 0, 28); @@ -123,14 +123,14 @@ private void drawPart(@NotNull DrawContext context, int j, int k, int l) { for (int o = m; o < widthN; o += 64) context.drawGuiTexture(TEXTURE, 160, 32, 32, j, o, k, Math.min(64, widthN - o), l); context.drawGuiTexture(TEXTURE, 160, 32, 160 - n, j, widthN, k, n, l); *///?} else if >=1.21.6 { - context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 0, j, 0, k, m, l); + /*context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 0, j, 0, k, m, l); for (int o = m; o < widthN; o += 64) context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 32, j, o, k, Math.min(64, widthN - o), l); context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, TEXTURE, 160, 32, 160 - n, j, widthN, k, n, l); - //?} else { - /*context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 0, j, 0, k, m, l); + *///?} else { + context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 0, j, 0, k, m, l); for (int o = m; o < widthN; o += 64) context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 32, j, o, k, Math.min(64, widthN - o), l); context.drawGuiTexture(RenderLayer::getGuiTextured, TEXTURE, 160, 32, 160 - n, j, widthN, k, n, l); - *///?} + //?} } @Environment(value = EnvType.CLIENT) diff --git a/src/main/java/cc/aabss/eventutils/UpdateChecker.java b/src/main/java/cc/aabss/eventutils/UpdateChecker.java index 744ec6a..5f69363 100644 --- a/src/main/java/cc/aabss/eventutils/UpdateChecker.java +++ b/src/main/java/cc/aabss/eventutils/UpdateChecker.java @@ -31,7 +31,7 @@ private void notifyUpdate(@NotNull String latestVersion) { client.send(() -> { if (client.player == null) return; //? if >=1.21.5 { - client.player.sendMessage( + /*client.player.sendMessage( EventUtils.MESSAGE_PREFIX.copy().append(" §e" + EventUtils.translate("eventutils.updatechecker.new")+"§r §7(v" + Versions.EU_VERSION + " -> v" + latestVersion.replace(Versions.MC_VERSION + "-", "") + ")" + "\n") .setStyle(EventUtils.MESSAGE_PREFIX.getStyle() .withHoverEvent(new HoverEvent.ShowText(translatable("eventutils.updatechecker.hover"))) @@ -39,8 +39,8 @@ private void notifyUpdate(@NotNull String latestVersion) { .append(Text.literal("§7§o" + EventUtils.translate("eventutils.updatechecker.config")) .setStyle(Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/event utils")))), false); - //?} else { - /*client.player.sendMessage( + *///?} else { + client.player.sendMessage( EventUtils.MESSAGE_PREFIX.copy().append(" §e" + EventUtils.translate("eventutils.updatechecker.new")+"§r §7(v" + Versions.EU_VERSION + " -> v" + latestVersion.replace(Versions.MC_VERSION + "-", "") + ")" + "\n") .setStyle(EventUtils.MESSAGE_PREFIX.getStyle() .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, translatable("eventutils.updatechecker.hover"))) @@ -48,7 +48,7 @@ private void notifyUpdate(@NotNull String latestVersion) { .append(Text.literal("§7§o" + EventUtils.translate("eventutils.updatechecker.config")) .setStyle(Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils config")))), false); - *///?} + //?} }); } diff --git a/src/main/java/cc/aabss/eventutils/commands/CommandRegister.java b/src/main/java/cc/aabss/eventutils/commands/CommandRegister.java index faeb221..5d6d387 100644 --- a/src/main/java/cc/aabss/eventutils/commands/CommandRegister.java +++ b/src/main/java/cc/aabss/eventutils/commands/CommandRegister.java @@ -1,6 +1,5 @@ package cc.aabss.eventutils.commands; -import app.qwertz.commands.TagCmd; import cc.aabss.eventutils.EventType; import cc.aabss.eventutils.EventUtils; import cc.aabss.eventutils.config.PlayerGroup; @@ -99,11 +98,6 @@ public static void register(@NotNull CommandDispatcher tag = ClientCommandManager - .literal("tag") - .executes(context -> TagCmd.openTagScreen(context)) - .build(); - final LiteralCommandNode groupMsg = ClientCommandManager .literal("groupmsg") .then(ClientCommandManager.argument("group", StringArgumentType.word()) @@ -124,7 +118,6 @@ public static void register(@NotNull CommandDispatcher cont } //? if >=1.21.11 { - final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() + /*final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() .map(entry -> entry.getProfile().name()) .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) .filter(name -> !EventUtils.isNPC(name, true)) .toList(); - //?} else { - /*final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() + *///?} else { + final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() .map(entry -> entry.getProfile().getName()) .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) .filter(name -> !EventUtils.isNPC(name, true)) .toList(); - *///?} + //?} if (namesFiltered.isEmpty()) { context.getSource().sendFeedback(Text.translatable("eventutils.command.countname.noplayers", EventUtils.ERROR_MESSAGE_PREFIX, Text.literal(filter).formatted(Formatting.DARK_RED))); @@ -53,18 +53,18 @@ public static void list(@NotNull CommandContext conte } //? if >=1.21.11 { - final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() + /*final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() .map(entry -> entry.getProfile().name()) .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) .filter(name -> !EventUtils.isNPC(name, true)) .toList(); - //?} else { - /*final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() + *///?} else { + final List namesFiltered = client.getNetworkHandler().getPlayerList().stream() .map(entry -> entry.getProfile().getName()) .filter(name -> name.toLowerCase().contains(filter.toLowerCase())) .filter(name -> !EventUtils.isNPC(name, true)) .toList(); - *///?} + //?} if (namesFiltered.isEmpty()) { context.getSource().sendFeedback(Text.translatable("eventutils.command.countname.noplayers", EventUtils.ERROR_MESSAGE_PREFIX, Text.literal(filter).formatted(Formatting.DARK_RED))); diff --git a/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java b/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java index ab5f0e4..f28afa9 100644 --- a/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java +++ b/src/main/java/cc/aabss/eventutils/commands/PriorityCmd.java @@ -110,10 +110,10 @@ public static void priority(@NotNull CommandContext c page - 1 ).setStyle( //? if <=1.21.4 { - /*Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page - 1))) - *///?} else { - Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page - 1))) - //?} + Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page - 1))) + //?} else { + /*Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page - 1))) + *///?} ); } @@ -123,10 +123,10 @@ public static void priority(@NotNull CommandContext c page + 1 ).setStyle( //? if <=1.21.4 { - /*Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page + 1))) - *///?} else { - Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page + 1))) - //?} + Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/eventutils prioritytop " + (page + 1))) + //?} else { + /*Style.EMPTY.withClickEvent(new ClickEvent.RunCommand("/eventutils prioritytop " + (page + 1))) + *///?} ); } diff --git a/src/main/java/cc/aabss/eventutils/config/EventConfig.java b/src/main/java/cc/aabss/eventutils/config/EventConfig.java index 3eb446f..93858fb 100644 --- a/src/main/java/cc/aabss/eventutils/config/EventConfig.java +++ b/src/main/java/cc/aabss/eventutils/config/EventConfig.java @@ -2,7 +2,6 @@ import cc.aabss.eventutils.EventType; import cc.aabss.eventutils.EventUtils; -import app.qwertz.PlusTag; import cc.aabss.eventutils.Versions; import com.google.common.reflect.TypeToken; @@ -36,8 +35,6 @@ public class EventConfig extends FileLoader { @NotNull public List whitelistedPlayers; @NotNull public List groups; public boolean useTestingApi; - /** Which plus tag to show next to name (from Event Alerts / Discord linking). */ - @NotNull public PlusTag selectedPlusTag; @NotNull public final List eventTypes; @NotNull public final Map notificationSounds; @@ -69,7 +66,6 @@ public EventConfig() { whitelistedPlayers = get("whitelisted_players", Defaults.whitelistedPlayers(), new TypeToken>(){}.getType()); groups = get("groups", Defaults.groups(), new TypeToken>(){}.getType()); useTestingApi = get("use_testing_api", Defaults.USE_TESTING_API); - selectedPlusTag = getPlusTag("selected_plus_tag", Defaults.SELECTED_PLUS_TAG); eventTypes = get("notifications", Defaults.eventTypes(), new TypeToken>(){}.getType()); notificationSounds = get("notification_sounds", Defaults.notificationSounds(), new TypeToken>(){}.getType()); @@ -138,22 +134,6 @@ public NotificationSound getNotificationSound(@NotNull EventType type) { return notificationSounds.getOrDefault(type, NotificationSound.ALERT); } - @NotNull - private PlusTag getPlusTag(@NotNull String key, @NotNull PlusTag defaultValue) { - String s = get(key, defaultValue.name()); - if (s == null) return defaultValue; - try { - return PlusTag.valueOf(s.toUpperCase()); - } catch (IllegalArgumentException e) { - return defaultValue; - } - } - - public void setSelectedPlusTag(@NotNull PlusTag tag) { - this.selectedPlusTag = tag; - setSave("selected_plus_tag", tag.name()); - } - // Collections need to have methods to create new instances of the collection! public static class Defaults { public static final boolean DISCORD_RPC = true; @@ -169,7 +149,6 @@ public static class Defaults { @NotNull private static final List HIDDEN_ENTITY_TYPES_STRING = List.of("minecraft:glow_item_frame"); @NotNull private static final List WHITELISTED_PLAYERS = List.of("skeppy", "badboyhalo"); public static final boolean USE_TESTING_API = false; - @NotNull public static final PlusTag SELECTED_PLUS_TAG = PlusTag.NONE; @NotNull private static final List EVENT_TYPES = List.of(EventType.values()); @NotNull private static final Map NOTIFICATION_SOUNDS = Arrays.stream(EventType.values()) .collect(HashMap::new, (map, type) -> map.put(type, NotificationSound.ALERT), HashMap::putAll); diff --git a/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java b/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java index 15c0ff4..7c4bf22 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/EntityMixin.java @@ -20,15 +20,15 @@ public abstract class EntityMixin { @Shadow public abstract EntityType getType(); //? if >=1.21.11 { - @Shadow public abstract Vec3d getSyncedPos(); - //?} else { - /*@Shadow public abstract Vec3d getPos(); - *///?} + /*@Shadow public abstract Vec3d getSyncedPos(); + *///?} else { + @Shadow public abstract Vec3d getPos(); + //?} @Shadow public abstract Text getName(); @Inject(method = "spawnSprintingParticles", at = @At("HEAD"), cancellable = true) private void spawnSprintingParticles(CallbackInfo ci) { - if (!EventUtils.isInHidePlayersMode()) return; + if (!EventUtils.MOD.isInHidePlayersMode()) return; final ClientPlayerEntity mainPlayer = MinecraftClient.getInstance().player; if (mainPlayer == null) return; final EntityType type = getType(); @@ -36,7 +36,7 @@ private void spawnSprintingParticles(CallbackInfo ci) { if (type == EntityType.PLAYER) { // Players final String name = getName().getString().toLowerCase(); - if (mainPlayer.getName().getString().toLowerCase().equals(name) || EventUtils.isPlayerVisible(name)) return; + if (mainPlayer.getName().getString().toLowerCase().equals(name) || EventUtils.MOD.isPlayerVisible(name)) return; } else { // Non-players (mob) if (!EventUtils.MOD.config.hiddenEntityTypes.contains(type)) return; @@ -50,9 +50,9 @@ private void spawnSprintingParticles(CallbackInfo ci) { // Specific radius //? if >=1.21.11 { - if (mainPlayer.getSyncedPos().distanceTo(getSyncedPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - //?} else { - /*if (mainPlayer.getPos().distanceTo(getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); - *///?} + /*if (mainPlayer.getSyncedPos().distanceTo(getSyncedPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + *///?} else { + if (mainPlayer.getPos().distanceTo(getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); + //?} } } diff --git a/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java b/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java index d9c17ca..63a064e 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/EntityRenderDispatcherMixin.java @@ -6,14 +6,14 @@ import net.minecraft.client.network.ClientPlayerEntity; import net.minecraft.client.render.VertexConsumerProvider; //? if >=1.21.11 { -import net.minecraft.client.render.command.OrderedRenderCommandQueue; +/*import net.minecraft.client.render.command.OrderedRenderCommandQueue; import net.minecraft.client.render.entity.EntityRenderManager; import net.minecraft.client.render.entity.state.EntityRenderState; import net.minecraft.client.render.state.CameraRenderState; import net.minecraft.util.math.Vec3d; -//?} else { -/*import net.minecraft.client.render.entity.EntityRenderDispatcher; -*///?} +*///?} else { +import net.minecraft.client.render.entity.EntityRenderDispatcher; +//?} import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; @@ -26,21 +26,21 @@ //? if >=1.21.11 { -@Mixin(EntityRenderManager.class) -//?} else { -/*@Mixin(EntityRenderDispatcher.class) -*///?} +/*@Mixin(EntityRenderManager.class) +*///?} else { +@Mixin(EntityRenderDispatcher.class) +//?} public class EntityRenderDispatcherMixin { //? if >=1.21.11 { - @Inject(method = "render", at = @At("HEAD"), cancellable = true) + /*@Inject(method = "render", at = @At("HEAD"), cancellable = true) private void render(EntityRenderState renderState, CameraRenderState cameraRenderState, double x, double y, double z, MatrixStack matrixStack, OrderedRenderCommandQueue orderedRenderCommandQueue, CallbackInfo ci) { - if (!EventUtils.isInHidePlayersMode()) return; + if (!EventUtils.MOD.isInHidePlayersMode()) return; if (renderState.entityType == EntityType.PLAYER) { final ClientPlayerEntity mainPlayer = MinecraftClient.getInstance().player; if (mainPlayer != null && renderState.displayName != null && mainPlayer.getName().getString().equalsIgnoreCase(renderState.displayName.getString())) return; final String name = renderState.displayName != null ? renderState.displayName.getString().toLowerCase() : ""; - if (EventUtils.isPlayerVisible(name)) return; + if (EventUtils.MOD.isPlayerVisible(name)) return; } else { if (!EventUtils.MOD.config.hiddenEntityTypes.contains(renderState.entityType)) return; } @@ -56,15 +56,15 @@ private void render(EntityRenderState renderState, CameraRenderState cameraRende if (mainPlayer.getSyncedPos().distanceTo(entityPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); } } - //?} else { - /*@Inject(method = "render", at = @At("HEAD"), cancellable = true) + *///?} else { + @Inject(method = "render", at = @At("HEAD"), cancellable = true) private void render(E entity, double x, double y, double z, float tickDelta, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, CallbackInfo ci) { - if (!EventUtils.isInHidePlayersMode()) return; + if (!EventUtils.MOD.isInHidePlayersMode()) return; if (entity instanceof PlayerEntity player) { if (player.isMainPlayer()) return; final String name = player.getName().getString().toLowerCase(); - if (EventUtils.isPlayerVisible(name)) return; + if (EventUtils.MOD.isPlayerVisible(name)) return; } else { if (!EventUtils.MOD.config.hiddenEntityTypes.contains(entity.getType())) return; } @@ -77,5 +77,5 @@ private void render(E entity, double x, double y, double z, f final ClientPlayerEntity mainPlayer = MinecraftClient.getInstance().player; if (mainPlayer != null && mainPlayer.getPos().distanceTo(entity.getPos()) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); } - *///?} + //?} } diff --git a/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java b/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java index 60ba7cd..f73d027 100644 --- a/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java +++ b/src/main/java/cc/aabss/eventutils/mixin/PlayerEntityRendererMixin.java @@ -7,9 +7,9 @@ import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.entity.PlayerEntityRenderer; //? if >=1.21.11 { -import net.minecraft.client.render.command.OrderedRenderCommandQueue; +/*import net.minecraft.client.render.command.OrderedRenderCommandQueue; import net.minecraft.client.render.state.CameraRenderState; -//?} +*///?} //? if >=1.21.3 { import net.minecraft.client.render.entity.state.PlayerEntityRenderState; //?} else { @@ -28,20 +28,20 @@ @Mixin(PlayerEntityRenderer.class) public class PlayerEntityRendererMixin { //? if >=1.21.11 { - @Inject(at = @At("HEAD"), method = "renderLabelIfPresent", cancellable = true) + /*@Inject(at = @At("HEAD"), method = "renderLabelIfPresent", cancellable = true) public void renderLabelIfPresent(PlayerEntityRenderState player, MatrixStack matrixStack, OrderedRenderCommandQueue orderedRenderCommandQueue, CameraRenderState cameraRenderState, CallbackInfo ci) { - if (!EventUtils.isInHidePlayersMode()) return; + if (!EventUtils.MOD.isInHidePlayersMode()) return; final ClientPlayerEntity clientPlayer = MinecraftClient.getInstance().player; if (clientPlayer == null) return; final Text nameText = player.playerName; if (nameText == null) return; final String name = nameText.getString().toLowerCase(); if (name.equals(clientPlayer.getName().getString().toLowerCase())) return; - if (!EventUtils.isPlayerVisible(name)) { + if (!EventUtils.MOD.isPlayerVisible(name)) { ci.cancel(); return; } - if (!EventUtils.shouldShowNametagFor(name)) { + if (!EventUtils.MOD.shouldShowNametagFor(name)) { ci.cancel(); return; } @@ -49,23 +49,23 @@ public void renderLabelIfPresent(PlayerEntityRenderState player, MatrixStack mat final Vec3d playerPos = new Vec3d(player.x, player.y, player.z); if (clientPlayer.getSyncedPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); } - //?} else { - /*@Inject(at = {@At("HEAD")}, method = "renderLabelIfPresent*", cancellable = true) + *///?} else { + @Inject(at = {@At("HEAD")}, method = "renderLabelIfPresent*", cancellable = true) //? if <=1.20.4 { - /^public void renderLabelIfPresent(AbstractClientPlayerEntity player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { - ^///?} else if <1.21.3 { - /^public void renderLabelIfPresent(AbstractClientPlayerEntity player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, float f, CallbackInfo ci) { - ^///?} else { + /*public void renderLabelIfPresent(AbstractClientPlayerEntity player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { + *///?} else if <1.21.3 { + /*public void renderLabelIfPresent(AbstractClientPlayerEntity player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, float f, CallbackInfo ci) { + *///?} else { public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) { //?} - if (!EventUtils.isInHidePlayersMode()) return; + if (!EventUtils.MOD.isInHidePlayersMode()) return; final ClientPlayerEntity clientPlayer = MinecraftClient.getInstance().player; if (clientPlayer == null) return; // Get player name //? if <1.21.3 { - /^final Text nameText = player.getName(); - ^///?} else { + /*final Text nameText = player.getName(); + *///?} else { final Text nameText = player.playerName; if (nameText == null) return; //?} @@ -73,18 +73,18 @@ public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, Matr // Check if main player //? if <1.21.3 { - /^if (player.isMainPlayer()) return; - ^///?} else { + /*if (player.isMainPlayer()) return; + *///?} else { if (name.equals(clientPlayer.getName().getString().toLowerCase())) return; //?} // Not visible in current view mode -> hide nametag - if (!EventUtils.isPlayerVisible(name)) { + if (!EventUtils.MOD.isPlayerVisible(name)) { ci.cancel(); return; } // Visible: respect per-group nametag setting - if (!EventUtils.shouldShowNametagFor(name)) { + if (!EventUtils.MOD.shouldShowNametagFor(name)) { ci.cancel(); return; } @@ -94,13 +94,13 @@ public void renderLabelIfPresent(PlayerEntityRenderState player, Text text, Matr // Get player position //? if <1.21.3 { - /^final Vec3d playerPos = player.getPos(); - ^///?} else { + /*final Vec3d playerPos = player.getPos(); + *///?} else { final Vec3d playerPos = new Vec3d(player.x, player.y, player.z); //?} // Radius-specific if (clientPlayer.getPos().distanceTo(playerPos) <= EventUtils.MOD.config.hidePlayersRadius) ci.cancel(); } - *///?} + //?} } diff --git a/src/main/java/cc/aabss/eventutils/mixin/PlayerListHudMixin.java b/src/main/java/cc/aabss/eventutils/mixin/PlayerListHudMixin.java new file mode 100644 index 0000000..78650cf --- /dev/null +++ b/src/main/java/cc/aabss/eventutils/mixin/PlayerListHudMixin.java @@ -0,0 +1,69 @@ +package cc.aabss.eventutils.mixin; + +import cc.aabss.eventutils.EventUtils; +import cc.aabss.eventutils.plustag.EventAlertsApi; +import cc.aabss.eventutils.plustag.PlusTag; +import cc.aabss.eventutils.plustag.PlusTagRenderer; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.hud.PlayerListHud; +import net.minecraft.client.network.PlayerListEntry; + +import java.util.EnumSet; +import java.util.UUID; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + + +@Mixin(PlayerListHud.class) +public abstract class PlayerListHudMixin { + @Shadow @Final private MinecraftClient client; + + /** Draw + icon for every tab list row (local player = selected tag, others = best unlocked from Event Alerts). */ + @Inject(method = "renderLatencyIcon", at = @At("TAIL")) + private void eventutils$drawPlusTagNextToName(DrawContext context, int width, int x, int y, PlayerListEntry entry, CallbackInfo ci) { + if (client.player == null) return; + + //? if >=1.21.11 { + /*String name = entry.getProfile().name(); + final boolean isLocal = entry.getProfile().id().equals(client.player.getUuid()); + UUID uuid = entry.getProfile().id(); + *///?} else { + String name = entry.getProfile().getName(); + final boolean isLocal = entry.getProfile().getId().equals(client.player.getUuid()); + UUID uuid = entry.getProfile().getId(); + //?} + + if (isLocal && EventAlertsApi.getCached(uuid) == null) { + // If JOIN ran before player was ready, trigger it when tab list is drawn + EventUtils.LOGGER.info("[EventUtils] Tab list: local player not cached, scheduling Event Alerts fetch uuid={}", uuid); + EventAlertsApi.scheduleFetchIfNeeded(uuid); + } + + EnumSet cached = EventAlertsApi.getCached(uuid); + if (cached == null) { + EventUtils.LOGGER.debug("[TabList] entry={} uuid={} cache MISS, scheduling fetch", name, uuid); + EventAlertsApi.scheduleFetchIfNeeded(uuid); + return; + } + + final PlusTag tag = PlusTag.pickBestForDisplay(cached); + EventUtils.LOGGER.debug("[TabList] entry={} uuid={} cache HIT unlocked={} pickBest={}", name, uuid, cached, tag); + + if (tag == null || tag == PlusTag.WHITE) { + EventUtils.LOGGER.debug("[TabList] entry={} skip draw: tag={} (null or WHITE)", name, tag); + return; + } + + int iconSize = 8; + int iconX = x - 8; + PlusTagRenderer.draw(context, tag, iconX, y, iconSize); + EventUtils.LOGGER.debug("[TabList] entry={} DRAW tag={} at ({}, {}) size={}", name, tag, iconX, y, iconSize); + } +} diff --git a/src/main/java/app/qwertz/EventAlertsApi.java b/src/main/java/cc/aabss/eventutils/plustag/EventAlertsApi.java similarity index 78% rename from src/main/java/app/qwertz/EventAlertsApi.java rename to src/main/java/cc/aabss/eventutils/plustag/EventAlertsApi.java index a72028e..1238895 100644 --- a/src/main/java/app/qwertz/EventAlertsApi.java +++ b/src/main/java/cc/aabss/eventutils/plustag/EventAlertsApi.java @@ -1,12 +1,7 @@ -/* - * Copyright 2026 QWERTZexe ALL RIGHTS RESERVED - */ - -package app.qwertz; +package cc.aabss.eventutils.plustag; import cc.aabss.eventutils.EventUtils; import cc.aabss.eventutils.Versions; -import cc.aabss.eventutils.config.EventConfig; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -22,6 +17,7 @@ import java.net.http.HttpResponse; import java.util.EnumSet; import java.util.Set; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -34,10 +30,10 @@ public final class EventAlertsApi { private static final String API_PATH = "/api/v1/players/minecraft/uuid/"; private static final HttpClient HTTP = HttpClient.newBuilder().build(); - /** Cache: UUID (no dashes) -> unlocked tags. Cleared on world unload. */ - private static final ConcurrentHashMap> CACHE = new ConcurrentHashMap<>(); + /** Cache: Minecraft UUID -> unlocked tags. Cleared on world unload. */ + private static final ConcurrentHashMap> CACHE = new ConcurrentHashMap<>(); /** UUIDs we've already scheduled a fetch for (avoid duplicate requests until cache clear). */ - private static final Set FETCH_SCHEDULED = ConcurrentHashMap.newKeySet(); + private static final Set FETCH_SCHEDULED = ConcurrentHashMap.newKeySet(); private EventAlertsApi() {} @@ -46,30 +42,27 @@ public static String getApiBase() { return EventUtils.MOD.config.useTestingApi ? "http://localhost:9090" : API_BASE; } - /** Convert 32-char hex (no dashes) to standard UUID form with dashes: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx */ - @NotNull - private static String toDashedUuid(@NotNull String key32) { - return key32.substring(0, 8) + "-" + key32.substring(8, 12) + "-" + key32.substring(12, 16) + "-" + key32.substring(16, 20) + "-" + key32.substring(20, 32); + @Nullable + private static UUID parseMinecraftUuid(@NotNull String uuidString) { + try { + return UUID.fromString(uuidString); + } catch (IllegalArgumentException ignored) { + return null; + } } - /** Fetch unlocked plus tags for a Minecraft UUID (with or without dashes). Returns empty set on failure. */ + /** Fetch unlocked plus tags for a Minecraft UUID. Returns empty set on failure. */ @NotNull - public static Set fetchUnlockedTags(@NotNull String minecraftUuid) { - String key = minecraftUuid.replace("-", "").toLowerCase(); - if (key.length() != 32) { - EventUtils.LOGGER.debug("[EventAlerts] fetchUnlockedTags: invalid UUID length key={} len={}", key, key.length()); - return Set.of(); - } - - Set cached = CACHE.get(key); + public static EnumSet fetchUnlockedTags(@NotNull UUID minecraftUuid) { + EnumSet cached = CACHE.get(minecraftUuid); if (cached != null) { - EventUtils.LOGGER.debug("[EventAlerts] fetchUnlockedTags: cache HIT uuid={} tags={}", key, cached); + EventUtils.LOGGER.debug("[EventAlerts] fetchUnlockedTags: cache HIT uuid={} tags={}", minecraftUuid, cached); return cached; } - EventUtils.LOGGER.info("[EventAlerts] Fetching tags for uuid={}", key); + EventUtils.LOGGER.info("[EventAlerts] Fetching tags for uuid={}", minecraftUuid); try { - String url = getApiBase() + API_PATH + toDashedUuid(key); + String url = getApiBase() + API_PATH + minecraftUuid; EventUtils.LOGGER.debug("[EventAlerts] GET {}", url); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) @@ -80,7 +73,7 @@ public static Set fetchUnlockedTags(@NotNull String minecraftUuid) { EventUtils.LOGGER.debug("[EventAlerts] response status={} bodyLength={}", response.statusCode(), response.body().length()); if (response.statusCode() != 200) { EventUtils.LOGGER.warn("[EventAlerts] API returned status={} body={}", response.statusCode(), response.body()); - return Set.of(); + return EnumSet.noneOf(PlusTag.class); } JsonObject root = JsonParser.parseString(response.body()).getAsJsonObject(); @@ -94,23 +87,23 @@ public static Set fetchUnlockedTags(@NotNull String minecraftUuid) { EventUtils.LOGGER.debug("[EventAlerts] using root as data (no player wrapper)"); } else { EventUtils.LOGGER.info("[EventAlerts] API response: player=null (not linked or not found)"); - return Set.of(); // player: null + return EnumSet.noneOf(PlusTag.class); // player: null } - Set unlocked = parseUnlockedTags(data); - EventUtils.LOGGER.debug("[EventAlerts] parsed unlocked tags={} for uuid={}", unlocked, key); - CACHE.put(key, unlocked); - EventUtils.LOGGER.info("[EventAlerts] Fetched uuid={} tags={}", key, unlocked); + EnumSet unlocked = parseUnlockedTags(data); + EventUtils.LOGGER.debug("[EventAlerts] parsed unlocked tags={} for uuid={}", unlocked, minecraftUuid); + CACHE.put(minecraftUuid, unlocked); + EventUtils.LOGGER.info("[EventAlerts] Fetched uuid={} tags={}", minecraftUuid, unlocked); return unlocked; } catch (Exception e) { - EventUtils.LOGGER.warn("[EventAlerts] Fetch failed uuid={} error={}", key, e.getMessage(), e); - return Set.of(); + EventUtils.LOGGER.warn("[EventAlerts] Fetch failed uuid={} error={}", minecraftUuid, e.getMessage(), e); + return EnumSet.noneOf(PlusTag.class); } } /** Parse API response into unlocked tags. Expects player object: id, discord, minecraft, subscription (1=premium/Bee), anniversaries, roles (optional). */ @NotNull - private static Set parseUnlockedTags(@NotNull JsonObject root) { - Set out = EnumSet.noneOf(PlusTag.class); + private static EnumSet parseUnlockedTags(@NotNull JsonObject root) { + EnumSet out = EnumSet.noneOf(PlusTag.class); // Linked: has discord and minecraft if (root.has("discord") && root.has("minecraft")) { @@ -195,18 +188,27 @@ public static void clearCache() { } /** Schedule a fetch for this UUID if not cached and not already scheduled. Call from main thread. */ - public static void scheduleFetchIfNeeded(@NotNull String minecraftUuid) { - String key = minecraftUuid.replace("-", "").toLowerCase(); - if (key.length() != 32) return; - if (CACHE.containsKey(key)) return; - if (!FETCH_SCHEDULED.add(key)) return; // already scheduled - EventUtils.LOGGER.info("[EventAlerts] Scheduling fetch for uuid={}", key); + public static void scheduleFetchIfNeeded(@NotNull UUID minecraftUuid) { + if (CACHE.containsKey(minecraftUuid)) return; + if (!FETCH_SCHEDULED.add(minecraftUuid)) return; // already scheduled + EventUtils.LOGGER.info("[EventAlerts] Scheduling fetch for uuid={}", minecraftUuid); EventUtils.MOD.scheduler.execute(() -> EventAlertsApi.fetchUnlockedTags(minecraftUuid)); } + public static void scheduleFetchIfNeeded(@NotNull String minecraftUuid) { + UUID uuid = parseMinecraftUuid(minecraftUuid); + if (uuid != null) scheduleFetchIfNeeded(uuid); + } + /** Get cached unlocked tags for UUID, or null if not cached. (No per-call debug log to avoid spam from tab list.) */ @Nullable - public static Set getCached(@NotNull String minecraftUuid) { - return CACHE.get(minecraftUuid.replace("-", "").toLowerCase()); + public static EnumSet getCached(@NotNull UUID minecraftUuid) { + return CACHE.get(minecraftUuid); + } + + @Nullable + public static EnumSet getCached(@NotNull String minecraftUuid) { + UUID uuid = parseMinecraftUuid(minecraftUuid); + return uuid != null ? CACHE.get(uuid) : null; } } diff --git a/src/main/java/app/qwertz/PlusTag.java b/src/main/java/cc/aabss/eventutils/plustag/PlusTag.java similarity index 91% rename from src/main/java/app/qwertz/PlusTag.java rename to src/main/java/cc/aabss/eventutils/plustag/PlusTag.java index 5b79114..2289c9f 100644 --- a/src/main/java/app/qwertz/PlusTag.java +++ b/src/main/java/cc/aabss/eventutils/plustag/PlusTag.java @@ -1,8 +1,4 @@ -/* - * Copyright 2026 QWERTZexe ALL RIGHTS RESERVED - */ - -package app.qwertz; +package cc.aabss.eventutils.plustag; import cc.aabss.eventutils.EventUtils; @@ -76,9 +72,9 @@ public static PlusTag pickBestForDisplay(@Nullable Set unlocked) { return null; } PlusTag best = null; - for (PlusTag t : unlocked) { - if (t == WHITE) continue; - if (best == null || t.displayPriority() > best.displayPriority()) best = t; + for (PlusTag tag : unlocked) { + if (tag == WHITE) continue; + if (best == null || tag.displayPriority() > best.displayPriority()) best = tag; } EventUtils.LOGGER.debug("[PlusTag] pickBestForDisplay: unlocked={} -> best={}", unlocked, best); return best; diff --git a/src/main/java/app/qwertz/PlusTagRenderer.java b/src/main/java/cc/aabss/eventutils/plustag/PlusTagRenderer.java similarity index 61% rename from src/main/java/app/qwertz/PlusTagRenderer.java rename to src/main/java/cc/aabss/eventutils/plustag/PlusTagRenderer.java index 886326d..e6d5386 100644 --- a/src/main/java/app/qwertz/PlusTagRenderer.java +++ b/src/main/java/cc/aabss/eventutils/plustag/PlusTagRenderer.java @@ -1,15 +1,11 @@ -/* - * Copyright 2026 QWERTZexe ALL RIGHTS RESERVED - */ - -package app.qwertz; +package cc.aabss.eventutils.plustag; import net.minecraft.client.gui.DrawContext; //? if >=1.21.6 { -import net.minecraft.client.gl.RenderPipelines; -//?} else if >=1.21.4 { -/*import net.minecraft.client.render.RenderLayer; -*///?} +/*import net.minecraft.client.gl.RenderPipelines; +*///?} else if >=1.21.4 { +import net.minecraft.client.render.RenderLayer; +//?} import org.jetbrains.annotations.NotNull; @@ -27,10 +23,10 @@ private PlusTagRenderer() {} public static void draw(@NotNull DrawContext context, @NotNull PlusTag tag, int x, int y, int size) { if (tag == PlusTag.WHITE) return; // unused, skip //? if >=1.21.6 { - context.drawTexture(RenderPipelines.GUI_TEXTURED, tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE, TEX_SIZE, TEX_SIZE); - //?} else if >=1.21.4 { - /*context.drawTexture(RenderLayer::getGuiTextured, tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE, TEX_SIZE, TEX_SIZE); - *///?} else { + /*context.drawTexture(RenderPipelines.GUI_TEXTURED, tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE, TEX_SIZE, TEX_SIZE); + *///?} else if >=1.21.4 { + context.drawTexture(RenderLayer::getGuiTextured, tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE, TEX_SIZE, TEX_SIZE); + //?} else { /*context.drawTexture(tag.getTextureId(), x, y, 0f, 0f, size, size, TEX_SIZE, TEX_SIZE); *///?} } diff --git a/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java b/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java index bf8ef7f..e2fedbb 100644 --- a/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java +++ b/src/main/java/cc/aabss/eventutils/utility/ConnectUtility.java @@ -38,10 +38,10 @@ public static void connect(@NotNull String ip) { client.execute(() -> { try { //? if >=1.21.11 { - client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false, false); - //?} else if >=1.21 { - /*client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false); - *///?} else { + /*client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false, false); + *///?} else if >=1.21 { + client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic")), false); + //?} else { /*client.disconnect(new MessageScreen(translatable("multiplayer.disconnect.generic"))); *///?} diff --git a/src/main/resources/eventutils-1.21.11.mixin.json b/src/main/resources/eventutils-1.21.11.mixin.json index ed49b7e..134f8c2 100644 --- a/src/main/resources/eventutils-1.21.11.mixin.json +++ b/src/main/resources/eventutils-1.21.11.mixin.json @@ -11,6 +11,7 @@ "EntityRenderDispatcherMixin", "EntryListWidgetAccessor", "KeyBindingMixin", + "PlayerListHudMixin", "PlayerEntityRendererMixin" ], "injectors": { diff --git a/src/main/resources/eventutils-qwertz.mixin.json b/src/main/resources/eventutils-qwertz.mixin.json deleted file mode 100644 index 812d351..0000000 --- a/src/main/resources/eventutils-qwertz.mixin.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "package": "app.qwertz.mixin", - "compatibilityLevel": "JAVA_17", - "client": [ - "PlayerListHudMixin" - ], - "injectors": { - "defaultRequire": 1 - } -} diff --git a/src/main/resources/eventutils.mixin.json b/src/main/resources/eventutils.mixin.json index 753caf6..5d26e58 100644 --- a/src/main/resources/eventutils.mixin.json +++ b/src/main/resources/eventutils.mixin.json @@ -13,6 +13,7 @@ "EntryListWidgetAccessor", "KeyBindingMixin", "MultiplayerScreenMixin", + "PlayerListHudMixin", "PlayerEntityRendererMixin" ], "injectors": { diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index b572eec..d11e515 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -4,7 +4,7 @@ "version": "${mod_version}", "name": "${mod_name}", "description": "${description}", - "authors": ["Event Alerts", "aabss", "srnyx", "pvty", "QWERTZ_EXE"], + "authors": ["Event Alerts", "aabss", "srnyx", "pvty"], "contact": { "repo": "https://github.com/Event-Alerts/EventUtils", "discord": "https://discord.gg/uFPFNYzAWC" @@ -13,8 +13,7 @@ "icon": "assets/eventutils/textures/icon.png", "environment": "*", "mixins": [ - "${mixin_config}", - "eventutils-qwertz.mixin.json" + "${mixin_config}" ], "entrypoints": { "client": [ diff --git a/stonecutter.gradle.kts b/stonecutter.gradle.kts index e9e836b..10efe16 100644 --- a/stonecutter.gradle.kts +++ b/stonecutter.gradle.kts @@ -1,6 +1,6 @@ plugins { id("dev.kikugie.stonecutter") } -stonecutter active "1.21.11" /* [SC] DO NOT EDIT */ +stonecutter active "1.21.4" /* [SC] DO NOT EDIT */ stonecutter.registerChiseled(tasks.register("chiseledBuild", stonecutter.chiseled) { group = "project"