Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "Hide Predict on Voted/Flagged" setting #172

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Identifies bots by sending nearby players' information to a third-party machine
| 'Predict' Settings | 'Predict' Default Color | If set, highlights unflagged/unfeedbacked players' 'Predict' option in the given color so that you can easily spot it on the in-game menu. |
| 'Predict' Settings | 'Predict' Voted/Flagged Color | If set, highlights flagged/feedbacked players' 'Predict' option in the given color so that you can easily spot it on the in-game menu. |
| 'Predict' Settings | Apply Colors to 'Report' | If set, applies the above 'Predict' color options to the in-game 'Report' option as well.<br>⚠️ May cause issues with other plugins that rely on the 'Report' option being unchanged.⚠️ |
| 'Predict' Settings | Hide 'Predict' after Voted/Flagged | If set, hides flagged/feedbacked players' 'Predict' option on the in-game menu. |
| Other Settings | Enable Chat Status Messages | Inserts chat messages in your chatbox to inform you about your uploads being sent. |
| Other Settings | '!bdstats' Chat Command Detail Level | Enable processing the '!bdstats' command when it appears in the chatbox, which will fetch the message author's plugin stats and display them. Disable to reduce spam. |

Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/botdetector/BotDetectorConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,18 @@ default boolean applyPredictColorsOnReportOption()
return false;
}

@ConfigItem(
position = 7,
keyName = "hidePredictOnFlag",
name = "Hide 'Predict' after Voted/Flagged",
description = "Hides the 'Predict' option on the in-game menu for players after being flagged or being given feedback.",
section = predictSection
)
default boolean hidePredictOnFlag()
{
return false;
}

@ConfigItem(
position = 1,
keyName = "enableChatNotifications",
Expand Down
196 changes: 128 additions & 68 deletions src/main/java/com/botdetector/BotDetectorPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
Expand Down Expand Up @@ -87,7 +88,6 @@
import net.runelite.api.events.CommandExecuted;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOpened;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.PlayerSpawned;
import net.runelite.api.events.WorldChanged;
Expand Down Expand Up @@ -952,8 +952,23 @@ private void statsChatCommand(ChatMessage chatMessage, String message)
});
}

@Subscribe
private void onMenuEntryAdded(MenuEntryAdded event)
private void onPredictClick(String playerName)
{
if (playerName == null)
{
return;
}

String toPredict = Text.removeTags(playerName);
if (config.predictOptionCopyName())
{
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(toPredict), null);
}

predictPlayer(toPredict);
}

private void handleInterfacePredictEntry(MenuEntryAdded event)
{
if (!config.addPredictOption())
{
Expand All @@ -975,98 +990,133 @@ private void onMenuEntryAdded(MenuEntryAdded event)
return;
}

// TODO: Properly use the new menu entry callbacks
// Don't add the option if hide on flag is set and player is flagged
if (config.hidePredictOnFlag() && isPlayerFeedbackedOrFlagged(event.getTarget()))
{
return;
}

final String name = event.getTarget();
client.createMenuEntry(-1)
.setOption(getPredictOption(event.getTarget()))
.setTarget(event.getTarget())
.setOption(getPredictOption(name))
.setTarget(name)
.setType(MenuAction.RUNELITE)
.setParam0(event.getActionParam0())
.setParam1(event.getActionParam1())
.setIdentifier(event.getIdentifier());
.setIdentifier(event.getIdentifier())
.onClick(c -> onPredictClick(name));
}
}

@Subscribe
private void onMenuOpened(MenuOpened event)
private void handlePlayerPredictEntry(MenuEntryAdded event)
{
// If neither color changing options are set, this is unnecessary
if (config.predictOptionDefaultColor() == null && config.predictOptionFlaggedColor() == null)
// Player menu section
int type = event.getType();
if (type >= MenuAction.MENU_ACTION_DEPRIORITIZE_OFFSET)
{
type -= MenuAction.MENU_ACTION_DEPRIORITIZE_OFFSET;
}

if (type != MenuAction.RUNELITE_PLAYER.getId()
|| !event.getOption().equals(PREDICT_OPTION))
{
return;
}

boolean changeReportOption = config.applyPredictColorsOnReportOption();
// Do this once when the menu opens
// Avoids having to loop the menu entries on every 'added' event
MenuEntry[] menuEntries = event.getMenuEntries();
for (MenuEntry entry : menuEntries)
Player player = client.getCachedPlayers()[event.getIdentifier()];
if (player == null)
{
int type = entry.getType().getId();
if (type >= MenuAction.MENU_ACTION_DEPRIORITIZE_OFFSET)
{
type -= MenuAction.MENU_ACTION_DEPRIORITIZE_OFFSET;
}
return;
}
final String name = player.getName();

if (type == MenuAction.RUNELITE_PLAYER.getId()
&& entry.getOption().equals(PREDICT_OPTION))
if (config.hidePredictOnFlag() && isPlayerFeedbackedOrFlagged(name))
{
MenuEntry[] entries = client.getMenuEntries();
// Sanity check
if (event.getMenuEntry() == entries[entries.length - 1])
{
Player player = client.getCachedPlayers()[entry.getIdentifier()];
if (player != null)
{
entry.setOption(getPredictOption(player.getName()));
}
// Delete the entry
client.setMenuEntries(Arrays.copyOf(entries, entries.length - 1));
}
}
else
{
// Set the color and callback
event.getMenuEntry().setOption(getPredictOption(name));
event.getMenuEntry().onClick(c -> onPredictClick(name));
}
}

private void handleJagexReportEntry(MenuEntryAdded event)
{
if (!config.applyPredictColorsOnReportOption()
|| !event.getOption().equals(REPORT_OPTION))
{
return;
}

// Check for Report option
if (changeReportOption && entry.getOption().equals(REPORT_OPTION)
&& (PLAYER_MENU_ACTIONS.contains(entry.getType()) || entry.getType() == MenuAction.CC_OP_LOW_PRIORITY))
final String name;
// Player menu version
if (PLAYER_MENU_ACTIONS.contains(MenuAction.of(event.getType())))
{
Player player = client.getCachedPlayers()[event.getIdentifier()];
if (player == null)
{
Player player = client.getCachedPlayers()[entry.getIdentifier()];
if (player != null)
{
entry.setOption(getReportOption(player.getName()));
}
return;
}
name = player.getName();
}
// Interface version (e.g. Chatbox)
else if (event.getType() == MenuAction.CC_OP_LOW_PRIORITY.getId())
{
name = event.getTarget();
}
else
{
return;
}

event.getMenuEntry().setOption(getReportOption(name));
}

@Subscribe
private void onMenuOptionClicked(MenuOptionClicked event)
private void onMenuEntryAdded(MenuEntryAdded event)
{
String optionText = Text.removeTags(event.getMenuOption());
if (((event.getMenuAction() == MenuAction.RUNELITE || event.getMenuAction() == MenuAction.RUNELITE_PLAYER)
&& optionText.equals(PREDICT_OPTION))
|| (config.predictOnReport() && (PLAYER_MENU_ACTIONS.contains(event.getMenuAction()) || event.getMenuAction() == MenuAction.CC_OP_LOW_PRIORITY)
&& optionText.equals(REPORT_OPTION)))
{
String name;
if (event.getMenuAction() == MenuAction.RUNELITE_PLAYER
|| PLAYER_MENU_ACTIONS.contains(event.getMenuAction()))
{
Player player = client.getCachedPlayers()[event.getId()];

if (player == null)
{
return;
}
handleInterfacePredictEntry(event);
handlePlayerPredictEntry(event);
handleJagexReportEntry(event);
}

name = player.getName();
}
else
{
name = event.getMenuTarget();
}
// Have to use MenuOptionClicked on Report to avoid potentially having the callback overwritten by someone else
@Subscribe
private void onMenuOptionClicked(MenuOptionClicked event)
{
if (!config.predictOnReport() || !Text.removeTags(event.getMenuOption()).equals(REPORT_OPTION))
{
return;
}

if (name != null)
final String name;
if (PLAYER_MENU_ACTIONS.contains(event.getMenuAction()))
{
Player player = client.getCachedPlayers()[event.getId()];
if (player == null)
{
String toPredict = Text.removeTags(name);
if (config.predictOptionCopyName())
{
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(toPredict), null);
}
predictPlayer(toPredict);
return;
}
name = player.getName();
}
else if (event.getMenuAction() == MenuAction.CC_OP_LOW_PRIORITY)
{
name = event.getMenuTarget();
}
else
{
return;
}

onPredictClick(name);
}

@Subscribe
Expand Down Expand Up @@ -1200,13 +1250,23 @@ private String getReportOption(String playerName)
*/
private String getMenuOption(String playerName, String option)
{
CaseInsensitiveString name = normalizeAndWrapPlayerName(playerName);
Color prepend = (feedbackedPlayers.containsKey(name) || flaggedPlayers.containsKey(name)) ?
Color prepend = isPlayerFeedbackedOrFlagged(playerName) ?
config.predictOptionFlaggedColor() : config.predictOptionDefaultColor();

return prepend != null ? ColorUtil.prependColorTag(option, prepend) : option;
}

/**
* Checks whether the given {@code player} has been feedbacked or flagged.
* @param playerName The player to check.
* @return True if appears in memory as flagged or feedbacked, false otherwise.
*/
private boolean isPlayerFeedbackedOrFlagged(String playerName)
{
CaseInsensitiveString name = normalizeAndWrapPlayerName(playerName);
return feedbackedPlayers.containsKey(name) || flaggedPlayers.containsKey(name);
}

/**
* Normalizes the given {@code playerName} by sanitizing the player name string,
* removing any Jagex tags and replacing any {@code _} or {@code -} with spaces.
Expand Down