feat: player tracker

This commit is contained in:
Hikyu
2026-10-05 21:04:27 +02:00
parent ddcbd2303c
commit c0868c2703
52 changed files with 9411 additions and 965 deletions
@@ -6,6 +6,7 @@ import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection;
import java.time.Instant;
import java.util.LinkedHashMap;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
@@ -17,15 +18,18 @@ import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.MenuAction;
import net.runelite.api.MenuEntry;
import net.runelite.api.MessageNode;
import net.runelite.api.Player;
import net.runelite.api.Point;
import net.runelite.api.ScriptID;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOpened;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.api.gameval.InterfaceID;
import net.runelite.api.widgets.ComponentID;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetUtil;
import net.runelite.client.callback.ClientThread;
@@ -183,10 +187,17 @@ public class ChatHelper
if (removedAny)
{
client.runScript(83);
refreshChat();
}
}
private void refreshChat()
{
// Invalidate the cached chat before rebuilding the chatbox and split PMs.
client.refreshChat();
client.runScript(ScriptID.SPLITPM_CHANGED);
}
private boolean shouldClearType(ChatMessageType type)
{
if (type == null)
@@ -204,13 +215,22 @@ public class ChatHelper
case SPAM:
case BROADCAST:
case CONSOLE:
case WELCOME:
case PLAYERRELATED:
case TENSECTIMEOUT:
case SNAPSHOTFEEDBACK:
case FRIENDNOTIFICATION:
case IGNORENOTIFICATION:
return config.chatClearGame();
case PUBLICCHAT:
case MODCHAT:
case AUTOTYPER:
case MODAUTOTYPER:
case TRADEREQ:
case TRADE:
case TRADE_SENT:
case CHALREQ_TRADE:
return config.chatClearPublic();
case PRIVATECHAT:
@@ -222,6 +242,8 @@ public class ChatHelper
case CLAN_GUEST_CHAT:
case FRIENDSCHAT:
case CLAN_MESSAGE:
case CLAN_GUEST_MESSAGE:
case FRIENDSCHATNOTIFICATION:
case CLAN_GIM_CHAT:
case CLAN_GIM_MESSAGE:
return config.chatClearClan();
@@ -349,7 +371,16 @@ public class ChatHelper
}
}
// 3. Highlight own name
// 3. Recolor clan chat text without changing public, private, or game messages.
if (isClanChatType(ChatMessageType.of(messageTypeVal)))
{
Color clanColor = config.chatClanMessageColor();
String hex = ColorUtil.colorToHexCode(clanColor != null ? clanColor : new Color(0x66FFFF));
message = "<col=" + hex + ">" + message + "</col>";
objectStack[objectStackSize - 1] = message;
}
// 4. Highlight own name
if (config.chatHighlightName() && isPlayerSpeechType(messageTypeVal))
{
String highlighted = highlightPlayerName(message);
@@ -360,6 +391,13 @@ public class ChatHelper
}
}
private boolean isClanChatType(ChatMessageType type)
{
return type == ChatMessageType.CLAN_CHAT
|| type == ChatMessageType.CLAN_GUEST_CHAT
|| type == ChatMessageType.CLAN_GIM_CHAT;
}
private boolean isCollapsible(ChatMessageType type)
{
if (type == null)
@@ -495,18 +533,17 @@ public class ChatHelper
if (config.chatCopyToClipboard() && "Report".equals(event.getOption()))
{
Widget lineWidget = client.getWidget(interfaceId, childId);
if (lineWidget != null && lineWidget.getParent() != null && lineWidget.getParent().getId() == ComponentID.CHATBOX_MESSAGE_LINES)
if (lineWidget != null && lineWidget.getParent() != null && lineWidget.getParent().getId() == InterfaceID.Chatbox.SCROLLAREA)
{
int lineIndex = (childId - WidgetUtil.componentToId(ComponentID.CHATBOX_FRAME)) * 4 + 1;
int lineIndex = (childId - WidgetUtil.componentToId(InterfaceID.Chatbox.LINE0)) * 4 + 1;
if (lineIndex < 1)
{
return;
}
Widget textWidget = lineWidget.getParent().getChild(lineIndex);
if (textWidget != null && textWidget.getText() != null)
{
String fullText = textWidget.getText();
client.createMenuEntry(1)
.setOption("Copy message")
.setTarget(event.getTarget())
.setType(MenuAction.RUNELITE)
.onClick(e -> copyToClipboard(fullText));
addCopyEntry(textWidget.getText(), event.getTarget());
}
}
}
@@ -522,7 +559,73 @@ public class ChatHelper
}
}
private void copyToClipboard(String text)
/** Game messages and transparent chat text do not necessarily have a Report action. */
@Subscribe(priority = -1)
public void onMenuOpened(MenuOpened event)
{
if (!config.chatHelper() || !config.chatCopyToClipboard())
{
return;
}
MenuEntry[] entries = client.getMenu().getMenuEntries();
if (Arrays.stream(entries).anyMatch(e -> "Copy message".equals(e.getOption())))
{
return;
}
// Do not intercept another interface or an overlay covering the chat.
if (Arrays.stream(entries).anyMatch(e -> e.getWidget() != null
&& WidgetUtil.componentToInterface(e.getWidget().getId()) != InterfaceID.CHATBOX))
{
return;
}
Widget scroll = client.getWidget(InterfaceID.Chatbox.SCROLLAREA);
Point mouse = client.getMouseCanvasPosition();
if (scroll == null || scroll.isHidden() || mouse == null
|| !scroll.getBounds().contains(mouse.getX(), mouse.getY()))
{
return;
}
Widget[] children = scroll.getDynamicChildren();
if (children == null || children.length == 0)
{
children = scroll.getChildren();
}
if (children == null)
{
return;
}
for (int i = 1; i < children.length; i += 4)
{
Widget message = children[i];
if (message != null && !message.isHidden() && message.getText() != null
&& !Text.removeTags(message.getText()).trim().isEmpty()
&& message.getBounds().contains(mouse.getX(), mouse.getY()))
{
// A world-only menu here is click-through from transparent chat.
boolean hasChatAction = Arrays.stream(entries).anyMatch(e ->
WidgetUtil.componentToInterface(e.getParam1()) == InterfaceID.CHATBOX);
if (!hasChatAction)
{
client.getMenu().setMenuEntries(Arrays.stream(entries)
.filter(e -> e.getType() == MenuAction.CANCEL).toArray(MenuEntry[]::new));
}
addCopyEntry(message.getText(), "");
return;
}
}
}
private void addCopyEntry(String text, String target)
{
// Capture the displayed text now: new messages can arrive while the menu is open.
client.createMenuEntry(Math.min(1, client.getMenu().getMenuEntries().length))
.setOption("Copy message")
.setTarget(target)
.setType(MenuAction.RUNELITE)
.onClick(e -> copyToClipboard(text));
}
void copyToClipboard(String text)
{
try
{
@@ -572,7 +675,8 @@ public class ChatHelper
}
}
client.runScript(83);
reset();
refreshChat();
});
}
}