playermanager: add. (#1952)

* playermanager: add.
playerscouter: update to use new player manager.
playerscouter: add minify option.

* playermanager: use concurrent maps over standard hash maps.

* playermanager: add attackStyleChanged event.

* playermanager: add all attacking method.

* prayagainst: completely rework it to use playerManager.
playermanager: add friend/clan methods.

* playermanager: utilize new event rather than gametick.

* playermanager: remove gam tick update.

* playermanager: remove gametick method reference.

* hideunder: use playermanager.

* equipmentinspector: use playermanager.

* events: add new docs.

* playermanager: add combat stats sub-class.

* playermanager: add timeout to updateStats

* playermanager: gamepack update.

* playermanager: remove debugging.

* playerscouter: remove unused import
This commit is contained in:
Ganom
2019-12-01 01:09:27 -05:00
committed by GitHub
parent 00ce4ee51c
commit 129ccd2de9
21 changed files with 1048 additions and 1574 deletions

View File

@@ -0,0 +1,13 @@
package net.runelite.api.events;
import lombok.Value;
import net.runelite.api.Player;
/**
* This will fire whenever the {@link net.runelite.api.PlayerAppearance} hash changes.
*/
@Value
public class PlayerAppearanceChanged implements Event
{
private Player player;
}

View File

@@ -62,6 +62,7 @@ import net.runelite.client.eventbus.EventBus;
import net.runelite.client.game.ClanManager;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.LootManager;
import net.runelite.client.game.PlayerManager;
import net.runelite.client.game.XpDropManager;
import net.runelite.client.game.chatbox.ChatboxPanelManager;
import net.runelite.client.graphics.ModelOutlineRenderer;
@@ -158,6 +159,9 @@ public class RuneLite
@Inject
private Provider<XpDropManager> xpDropManager;
@Inject
private Provider<PlayerManager> playerManager;
@Inject
private Provider<ChatboxPanelManager> chatboxPanelManager;
@@ -366,6 +370,7 @@ public class RuneLite
commandManager.get();
lootManager.get();
xpDropManager.get();
playerManager.get();
chatboxPanelManager.get();
eventBus.subscribe(GameStateChanged.class, this, hooks::onGameStateChanged);

View File

@@ -0,0 +1,34 @@
package net.runelite.client.events;
import lombok.Value;
import net.runelite.api.Player;
import net.runelite.api.events.Event;
import net.runelite.client.game.AttackStyle;
/**
* This will fire when {@link net.runelite.client.game.PlayerManager} detects
* a change in the player appearance that resulted in the shifting of an attack style.
* For example, ranged str went to 0, but melee str went to 108.
*/
@Value
public class AttackStyleChanged implements Event
{
/**
* The player that changed styles.
*/
private final Player player;
/**
* Can be Unknown(nullable)
*
* @see net.runelite.client.game.AttackStyle
*/
private final AttackStyle oldStyle;
/**
* Can be Unknown(nullable)
*
* @see net.runelite.client.game.AttackStyle
*/
private final AttackStyle newStyle;
}

View File

@@ -21,25 +21,23 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.hideunder;
package net.runelite.client.game;
import lombok.AccessLevel;
import java.awt.Color;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import net.runelite.api.Player;
import net.runelite.api.Prayer;
@Getter(AccessLevel.PACKAGE)
@Setter(AccessLevel.PACKAGE)
class PlayerContainer
@AllArgsConstructor
@Getter
public enum AttackStyle
{
private Player player;
private boolean target;
private int timer;
MAGE("Mage", Color.CYAN, Prayer.PROTECT_FROM_MAGIC),
RANGE("Range", Color.GREEN, Prayer.PROTECT_FROM_MISSILES),
MELEE("Melee", Color.RED, Prayer.PROTECT_FROM_MELEE),
UNKNOWN("Unknown", Color.WHITE, null);
PlayerContainer(Player player)
{
this.player = player;
this.target = false;
this.timer = 0;
}
}
private String name;
private Color color;
private Prayer prayer;
}

View File

@@ -0,0 +1,24 @@
package net.runelite.client.game;
import lombok.Value;
@Value
public class CombatStats
{
private int magicAttack;
private int magicDefence;
private int magicStr;
private int meleeAtkCrush;
private int meleeAtkSlash;
private int meleeAtkStab;
private int meleeAttack;
private int meleeDefCrush;
private int meleeDefence;
private int meleeDefSlash;
private int meleeDefStab;
private int meleeStr;
private int rangeAttack;
private int rangeDefence;
private int rangeStr;
private int speed;
}

View File

@@ -21,7 +21,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.playerscouter;
package net.runelite.client.game;
import java.util.LinkedHashMap;
import lombok.AccessLevel;
@@ -31,41 +31,73 @@ import lombok.ToString;
import net.runelite.api.Player;
import net.runelite.http.api.hiscore.HiscoreResult;
@Getter(AccessLevel.PACKAGE)
@Setter(AccessLevel.PACKAGE)
@Getter
@Setter
@ToString(exclude = "player")
class PlayerContainer
public class PlayerContainer
{
private AttackStyle attackStyle;
private AttackStyle weakness;
private HiscoreResult skills;
private LinkedHashMap<Integer, Integer> gear;
private LinkedHashMap<Integer, Integer> riskedGear;
private MeleeStyle meleeStyle;
private Player player;
private String location;
private String name;
private String targetString;
private CombatStats combatStats;
private boolean httpRetry;
private boolean scouted;
private int prayer;
private boolean attacking;
private boolean friend;
private boolean clan;
private int hpLevel;
private int potionBoost;
private int prayerLevel;
private int risk;
private int scoutTimer;
private int shield;
private int timer;
private int weapon;
private int wildyLevel;
PlayerContainer(Player player)
{
this.attackStyle = AttackStyle.UNKNOWN;
this.gear = new LinkedHashMap<>();
this.httpRetry = false;
this.hpLevel = 0;
this.location = "N/A";
this.meleeStyle = MeleeStyle.STAB;
this.name = player.getName();
this.player = player;
this.prayer = -1;
this.risk = 0;
this.riskedGear = new LinkedHashMap<>();
this.scoutTimer = 500;
this.scouted = false;
this.skills = null;
this.targetString = "";
this.weapon = 0;
this.wildyLevel = 0;
this.weakness = AttackStyle.UNKNOWN;
}
void reset()
{
setMeleeStyle(MeleeStyle.NONE);
if (getTimer() > 0)
{
setTimer(getTimer() - 1);
if (getTimer() == 0)
{
setAttacking(false);
}
}
}
@Getter(AccessLevel.PACKAGE)
enum MeleeStyle
{
CRUSH,
SLASH,
STAB,
NONE
}
}

View File

@@ -0,0 +1,551 @@
package net.runelite.client.game;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Actor;
import net.runelite.api.Client;
import net.runelite.api.ItemDefinition;
import net.runelite.api.ItemID;
import net.runelite.api.NPC;
import net.runelite.api.Player;
import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.PlayerAppearanceChanged;
import net.runelite.api.events.PlayerDespawned;
import net.runelite.api.events.PlayerSpawned;
import net.runelite.api.kit.KitType;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.EventScheduler;
import net.runelite.client.events.AttackStyleChanged;
import net.runelite.client.util.PvPUtil;
import net.runelite.http.api.hiscore.HiscoreClient;
import net.runelite.http.api.hiscore.HiscoreResult;
import net.runelite.http.api.item.ItemEquipmentStats;
import net.runelite.http.api.item.ItemStats;
@Singleton
@Slf4j
@SuppressWarnings("unused")
public class PlayerManager
{
private static final HiscoreClient HISCORE_CLIENT = new HiscoreClient();
private final Client client;
private final ItemManager itemManager;
private final EventBus eventBus;
private final Map<String, PlayerContainer> playerMap = new ConcurrentHashMap<>();
private final Map<String, HiscoreResult> resultCache = new ConcurrentHashMap<>();
private final ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
@Inject
PlayerManager(
final Client client,
final EventBus eventBus,
final ItemManager itemManager
)
{
this.client = client;
this.itemManager = itemManager;
this.eventBus = eventBus;
eventBus.subscribe(PlayerDespawned.class, this, this::onPlayerDespawned);
eventBus.subscribe(PlayerSpawned.class, this, this::onPlayerSpawned);
eventBus.subscribe(AnimationChanged.class, this, this::onAnimationChanged);
eventBus.subscribe(PlayerAppearanceChanged.class, this, this::onAppearenceChanged, -1, EventScheduler.DEFAULT, EventScheduler.COMPUTATION);
}
/**
* @return Collection of {@link PlayerContainer} that are attacking you, this can be empty.
*/
public Set<PlayerContainer> getAllAttackers()
{
final Set<PlayerContainer> set = new HashSet<>();
for (PlayerContainer p : playerMap.values())
{
if (p.isAttacking())
{
set.add(p);
}
}
return set;
}
/**
* @return Collection of {@link PlayerContainer}, this can be empty.
*/
public Collection<PlayerContainer> getPlayerContainers()
{
return playerMap.values();
}
/**
* @param name Players name.
* @return {@link PlayerContainer} if provided with proper name, else null.
*/
@Nullable
public PlayerContainer getPlayer(String name)
{
return playerMap.get(name);
}
/**
* @param player Player object.
* @return {@link PlayerContainer} if provided with proper name, else null.
*/
@Nullable
public PlayerContainer getPlayer(Player player)
{
if (player == null)
{
return null;
}
return playerMap.get(player.getName());
}
/**
* This will keep submitting an http request until it successfully updates.
*
* @param name The player name you wish to update.
*/
public void updateStats(String name)
{
final PlayerContainer p = playerMap.get(name);
if (p == null)
{
return;
}
updateStats(p.getPlayer());
}
/**
* This will keep submitting an http request until it successfully updates.
*
* @param requestedPlayer The player object you wish to update.
*/
public void updateStats(Player requestedPlayer)
{
if (requestedPlayer == null)
{
return;
}
final PlayerContainer player = playerMap.get(requestedPlayer.getName());
if (player == null)
{
return;
}
if (resultCache.containsKey(player.getName()))
{
player.setSkills(resultCache.get(player.getName()));
player.setPrayerLevel(player.getSkills().getPrayer().getLevel());
player.setHpLevel(player.getSkills().getHitpoints().getLevel());
return;
}
executorService.submit(() ->
{
player.setHttpRetry(true);
int timeout = 0;
HiscoreResult result;
do
{
try
{
result = HISCORE_CLIENT.lookup(player.getName());
}
catch (IOException ex)
{
if (timeout == 10)
{
log.error("HiScore Lookup timed out on: {}", player.getName());
return;
}
result = null;
timeout++;
try
{
Thread.sleep(1000);
}
catch (InterruptedException ignored)
{
}
}
}
while (result == null);
resultCache.put(player.getName(), result);
player.setSkills(result);
player.setPrayerLevel(player.getSkills().getPrayer().getLevel());
player.setHpLevel(player.getSkills().getHitpoints().getLevel());
player.setHttpRetry(false);
});
}
private void onAppearenceChanged(PlayerAppearanceChanged event)
{
final PlayerContainer player = playerMap.get(event.getPlayer().getName());
if (player == null)
{
return;
}
update(player);
player.reset();
player.setFriend(client.isFriended(player.getName(), false));
player.setClan(client.isClanMember(player.getName()));
}
private void onPlayerDespawned(PlayerDespawned event)
{
final Player player = event.getPlayer();
playerMap.remove(player.getName());
}
private void onPlayerSpawned(PlayerSpawned event)
{
final Player player = event.getPlayer();
playerMap.put(player.getName(), new PlayerContainer(player));
}
private void onAnimationChanged(AnimationChanged event)
{
final Actor actor = event.getActor();
if (actor.getInteracting() != client.getLocalPlayer() || !(actor instanceof Player) || actor.getAnimation() == -1)
{
return;
}
final PlayerContainer player = playerMap.getOrDefault(actor.getName(), null);
if (player == null)
{
return;
}
if (player.getPlayer().getInteracting() != null &&
player.getPlayer().getInteracting() == client.getLocalPlayer())
{
if (player.getSkills() == null)
{
updateStats(player.getPlayer());
}
player.setAttacking(true);
player.setTimer(8);
}
}
private void update(PlayerContainer player)
{
player.setRisk(0);
updatePlayerGear(player);
updateAttackStyle(player);
updateWeakness(player);
player.setLocation(WorldLocation.location(player.getPlayer().getWorldLocation()));
player.setWildyLevel(PvPUtil.getWildernessLevelFrom(player.getPlayer().getWorldLocation()));
player.setTargetString(targetStringBuilder(player));
}
private void updatePlayerGear(PlayerContainer player)
{
final Map<Integer, Integer> prices = new HashMap<>();
if (player.getPlayer().getPlayerAppearance() == null)
{
return;
}
int magicAttack = 0,
magicDefence = 0,
magicStr = 0,
meleeAtkCrush = 0,
meleeAtkStab = 0,
meleeAtkSlash = 0,
meleeDefCrush = 0,
meleeDefStab = 0,
meleeDefSlash = 0,
meleeStr = 0,
rangeAttack = 0,
rangeDefence = 0,
rangeStr = 0,
speed = 0;
for (KitType kitType : KitType.values())
{
if (kitType.equals(KitType.RING) || kitType.equals(KitType.AMMUNITION))
{
continue;
}
final int id = player.getPlayer().getPlayerAppearance().getEquipmentId(kitType);
if (id == -1)
{
continue;
}
if (kitType.equals(KitType.WEAPON))
{
player.setWeapon(id);
switch (id)
{
case ItemID.HEAVY_BALLISTA:
case ItemID.HEAVY_BALLISTA_23630:
case ItemID.LIGHT_BALLISTA:
rangeStr += 150;
break;
case ItemID.MAPLE_LONGBOW:
case ItemID.MAPLE_SHORTBOW:
rangeStr += 31;
break;
case ItemID.MAGIC_SHORTBOW:
case ItemID.MAGIC_SHORTBOW_20558:
case ItemID.MAGIC_SHORTBOW_I:
rangeStr += +55;
break;
case ItemID.DARK_BOW:
case ItemID.DARK_BOW_12765:
case ItemID.DARK_BOW_12766:
case ItemID.DARK_BOW_12767:
case ItemID.DARK_BOW_12768:
case ItemID.DARK_BOW_20408:
rangeStr += +60;
break;
case ItemID.RUNE_CROSSBOW:
case ItemID.RUNE_CROSSBOW_23601:
rangeStr += +117;
break;
case ItemID.DRAGON_CROSSBOW:
case ItemID.ARMADYL_CROSSBOW:
case ItemID.ARMADYL_CROSSBOW_23611:
rangeStr += +122;
break;
}
}
final ItemStats item = itemManager.getItemStats(id, false);
final ItemDefinition itemDefinition = itemManager.getItemDefinition(id);
if (item == null)
{
log.debug("Item is null: {}", id);
continue;
}
final ItemEquipmentStats stats = item.getEquipment();
speed += stats.getAspeed();
meleeAtkCrush += stats.getAcrush();
meleeAtkStab += stats.getAstab();
meleeAtkSlash += stats.getAslash();
meleeDefCrush += stats.getDcrush();
meleeDefStab += stats.getDstab();
meleeDefSlash += stats.getDslash();
magicAttack += stats.getAmagic();
rangeAttack += stats.getArange();
magicDefence += stats.getDmagic();
rangeDefence += stats.getDrange();
rangeStr += stats.getRstr();
meleeStr += stats.getStr();
magicStr += stats.getMdmg();
if (ItemReclaimCost.breaksOnDeath(id))
{
prices.put(id, itemManager.getRepairValue(id));
log.debug("Item has a broken value: Id {}, Value {}", id, itemManager.getRepairValue(id));
continue;
}
if (!itemDefinition.isTradeable() && !ItemMapping.isMapped(id))
{
prices.put(id, itemDefinition.getPrice());
}
else if (itemDefinition.isTradeable())
{
prices.put(id, itemManager.getItemPrice(id, false));
}
}
player.setCombatStats(new CombatStats(
magicAttack,
magicDefence,
magicStr,
meleeAtkCrush,
meleeAtkSlash,
meleeAtkStab,
(meleeAtkCrush + meleeAtkSlash + meleeAtkStab) / 3,
meleeDefCrush,
(meleeDefCrush + meleeDefSlash + meleeDefStab) / 3,
meleeDefSlash,
meleeDefStab,
meleeStr,
rangeAttack,
rangeDefence,
rangeStr,
speed
));
updateGear(player, prices);
updateMeleeStyle(player);
}
private void updateGear(PlayerContainer player, Map<Integer, Integer> prices)
{
player.setGear(prices.entrySet()
.stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new))
);
player.setRiskedGear(prices.entrySet()
.stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new))
);
if (player.getPlayer().getSkullIcon() == null)
{
removeEntries(player.getRiskedGear(), player.getPrayerLevel() <= 25 ? 3 : 4);
}
else
{
removeEntries(player.getRiskedGear(), player.getPrayerLevel() <= 25 ? 0 : 1);
}
player.getRiskedGear().values().forEach(price -> player.setRisk(player.getRisk() + price));
prices.clear();
}
private void updateMeleeStyle(PlayerContainer player)
{
final CombatStats stats = player.getCombatStats();
if (stats.getMeleeAtkCrush() >= stats.getMeleeAtkSlash() && stats.getMeleeAtkCrush() >= stats.getMeleeAtkStab())
{
player.setMeleeStyle(PlayerContainer.MeleeStyle.CRUSH);
}
else if (stats.getMeleeAtkSlash() >= stats.getMeleeAtkCrush() && stats.getMeleeAtkSlash() >= stats.getMeleeAtkStab())
{
player.setMeleeStyle(PlayerContainer.MeleeStyle.SLASH);
}
else
{
player.setMeleeStyle(PlayerContainer.MeleeStyle.STAB);
}
}
private void updateAttackStyle(PlayerContainer player)
{
final AttackStyle oldStyle = player.getAttackStyle();
boolean staff = false;
for (int id : player.getGear().keySet())
{
ItemDefinition def = itemManager.getItemDefinition(id);
if (def.getName().toLowerCase().contains("staff"))
{
player.setAttackStyle(AttackStyle.MAGE);
staff = true;
break;
}
}
if (staff)
{
if (oldStyle != player.getAttackStyle())
{
eventBus.post(AttackStyleChanged.class, new AttackStyleChanged(
player.getPlayer(), oldStyle, player.getAttackStyle())
);
}
return;
}
final CombatStats stats = player.getCombatStats();
if (stats.getMagicStr() >= stats.getRangeStr() && stats.getMagicStr() >= stats.getMeleeStr())
{
player.setAttackStyle(AttackStyle.MAGE);
}
else if (stats.getRangeStr() >= stats.getMagicStr() && stats.getRangeStr() >= stats.getMeleeStr())
{
player.setAttackStyle(AttackStyle.RANGE);
}
else
{
player.setAttackStyle(AttackStyle.MELEE);
}
if (oldStyle != player.getAttackStyle())
{
eventBus.post(AttackStyleChanged.class, new AttackStyleChanged(
player.getPlayer(), oldStyle, player.getAttackStyle())
);
}
}
private void updateWeakness(PlayerContainer player)
{
final CombatStats stats = player.getCombatStats();
if (stats.getMagicDefence() <= stats.getRangeDefence() && stats.getMagicDefence() <= stats.getMeleeDefence())
{
player.setWeakness(AttackStyle.MAGE);
}
else if (stats.getRangeDefence() <= stats.getMagicDefence() && stats.getRangeDefence() <= stats.getMeleeDefence())
{
player.setWeakness(AttackStyle.RANGE);
}
else
{
player.setWeakness(AttackStyle.MELEE);
}
}
private static void removeEntries(LinkedHashMap<Integer, Integer> map, int quantity)
{
for (int i = 0; i < quantity; i++)
{
if (!map.entrySet().iterator().hasNext())
{
return;
}
map.entrySet().remove(map.entrySet().iterator().next());
}
}
private String targetStringBuilder(PlayerContainer player)
{
if (player.getPlayer().getInteracting() != null)
{
Actor actor = player.getPlayer().getInteracting();
if (actor instanceof Player)
{
return "(Player) " + actor.getName();
}
else if (actor instanceof NPC)
{
return "(NPC) " + actor.getName();
}
}
return "No Target Detected";
}
}

View File

@@ -38,7 +38,7 @@ public interface EquipmentInspectorConfig extends Config
description = "shows the total value of the items",
position = 1
)
default boolean ShowValue()
default boolean showValue()
{
return true;
}
@@ -49,11 +49,11 @@ public interface EquipmentInspectorConfig extends Config
)
@ConfigItem(
keyName = "protecteditems",
name = "protected items",
description = "Limit 4",
name = "Protected Items",
description = "Limited to 4",
position = 2
)
default int protecteditems()
default int protectedItems()
{
return 1;
}
@@ -64,7 +64,7 @@ public interface EquipmentInspectorConfig extends Config
description = "shows the excact gp value",
position = 3
)
default boolean ExactValue()
default boolean exactValue()
{
return false;
}

View File

@@ -29,12 +29,9 @@ import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.List;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.swing.SwingUtilities;
@@ -42,7 +39,6 @@ import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.ItemDefinition;
import net.runelite.api.Player;
import net.runelite.api.events.PlayerMenuOptionClicked;
import net.runelite.api.kit.KitType;
import net.runelite.api.util.Text;
@@ -54,6 +50,8 @@ import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.PlayerContainer;
import net.runelite.client.game.PlayerManager;
import net.runelite.client.menus.MenuManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
@@ -61,6 +59,7 @@ import net.runelite.client.plugins.PluginType;
import net.runelite.client.ui.ClientToolbar;
import net.runelite.client.ui.NavigationButton;
import net.runelite.client.util.ImageUtil;
import net.runelite.client.util.QuantityFormatter;
@PluginDescriptor(
name = "Equipment Inspector",
@@ -74,37 +73,27 @@ public class EquipmentInspectorPlugin extends Plugin
private static final String INSPECT_EQUIPMENT = "Gear";
@Inject
@Nullable
private Client client;
@Inject
private ItemManager itemManager;
@Inject
private EquipmentInspectorConfig config;
@Inject
private ChatMessageManager chatMessageManager;
@Inject
private MenuManager menuManager;
@Inject
private ScheduledExecutorService executor;
@Inject
private ClientToolbar pluginToolbar;
@Inject
private PlayerManager playerManager;
private NavigationButton navButton;
private EquipmentInspectorPanel equipmentInspectorPanel;
private int TotalPrice = 0;
private int Prot1 = 0;
private int Prot2 = 0;
private int Prot3 = 0;
private int Prot4 = 0;
private boolean ShowValue;
private int protecteditems;
private boolean ExactValue;
private boolean showValue;
private int protectedItems;
private boolean exactValue;
@Provides
EquipmentInspectorConfig provideConfig(ConfigManager configManager)
@@ -146,152 +135,88 @@ public class EquipmentInspectorPlugin extends Plugin
@Subscribe
private void onPlayerMenuOptionClicked(PlayerMenuOptionClicked event)
{
if (event.getMenuOption().equals(INSPECT_EQUIPMENT))
if (!event.getMenuOption().equals(INSPECT_EQUIPMENT))
{
executor.execute(() ->
{
try
{
SwingUtilities.invokeAndWait(() ->
{
if (!navButton.isSelected())
{
navButton.getOnSelect().run();
}
});
}
catch (InterruptedException | InvocationTargetException e)
{
throw new RuntimeException(e);
}
String playerName = Text.removeTags(event.getMenuTarget());
// The player menu uses a non-breaking space in the player name, we need to replace this to compare
// against the playerName in the player cache.
String finalPlayerName = playerName.replace('\u00A0', ' ');
List<Player> players = null;
if (client != null)
{
players = client.getPlayers();
}
Optional<Player> targetPlayer = Optional.empty();
if (players != null)
{
targetPlayer = players.stream()
.filter(Objects::nonNull)
.filter(p -> p.getName().equals(finalPlayerName)).findFirst();
}
if (targetPlayer.isPresent())
{
TotalPrice = 0;
Prot1 = 0;
Prot2 = 0;
Prot3 = 0;
Prot4 = 0;
Player p = targetPlayer.get();
Map<KitType, ItemDefinition> playerEquipment = new HashMap<>();
for (KitType kitType : KitType.values())
{
if (kitType == KitType.RING)
{
continue; //prevents the equipment inspector from breaking
}
if (kitType == KitType.AMMUNITION)
{
continue;
}
int itemId = p.getPlayerAppearance().getEquipmentId(kitType);
if (itemId != -1)
{
ItemDefinition itemComposition = client.getItemDefinition(itemId);
playerEquipment.put(kitType, itemComposition);
int ItemPrice = itemManager.getItemPrice(itemId);
TotalPrice += ItemPrice;
if (ItemPrice > Prot1)
{
Prot4 = Prot3;
Prot3 = Prot2;
Prot2 = Prot1;
Prot1 = ItemPrice;
}
else if (ItemPrice > Prot2)
{
Prot4 = Prot3;
Prot3 = Prot2;
Prot2 = ItemPrice;
}
else if (ItemPrice > Prot3)
{
Prot4 = Prot3;
Prot3 = ItemPrice;
}
else if (ItemPrice > Prot4)
{
Prot4 = ItemPrice;
}
}
}
int IgnoredItems = this.protecteditems;
if (IgnoredItems != 0 && IgnoredItems != 1 && IgnoredItems != 2 && IgnoredItems != 3)
{
IgnoredItems = 4;
}
if (this.ShowValue)
{
switch (IgnoredItems)
{
case 1:
TotalPrice = TotalPrice - Prot1;
break;
case 2:
TotalPrice = TotalPrice - Prot1;
TotalPrice = TotalPrice - Prot2;
break;
case 3:
TotalPrice = TotalPrice - Prot1;
TotalPrice = TotalPrice - Prot2;
TotalPrice = TotalPrice - Prot3;
break;
case 4:
TotalPrice = TotalPrice - Prot1;
TotalPrice = TotalPrice - Prot2;
TotalPrice = TotalPrice - Prot3;
TotalPrice = TotalPrice - Prot4;
break;
}
String StringPrice = "";
if (!this.ExactValue)
{
TotalPrice = TotalPrice / 1000;
StringPrice = NumberFormat.getIntegerInstance().format(TotalPrice);
StringPrice = StringPrice + 'K';
}
if (this.ExactValue)
{
StringPrice = NumberFormat.getIntegerInstance().format(TotalPrice);
}
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.CONSOLE)
.runeLiteFormattedMessage(new ChatMessageBuilder()
.append(ChatColorType.HIGHLIGHT)
.append("Risked Value: ")
.append(ChatColorType.NORMAL)
.append(StringPrice)
.build())
.build());
}
equipmentInspectorPanel.update(playerEquipment, playerName);
}
});
return;
}
executor.execute(() ->
{
try
{
SwingUtilities.invokeAndWait(() ->
{
if (!navButton.isSelected())
{
navButton.getOnSelect().run();
}
});
}
catch (InterruptedException | InvocationTargetException e)
{
throw new RuntimeException(e);
}
String playerName = Text.removeTags(event.getMenuTarget()).replace('\u00A0', ' ');
final PlayerContainer player = playerManager.getPlayer(playerName);
final Map<KitType, ItemDefinition> playerEquipment = new HashMap<>();
if (player == null)
{
return;
}
for (KitType kitType : KitType.values())
{
if (kitType == KitType.RING || kitType == KitType.AMMUNITION ||
player.getPlayer().getPlayerAppearance() == null)
{
continue;
}
final int itemId = player.getPlayer().getPlayerAppearance().getEquipmentId(kitType);
if (itemId != -1)
{
ItemDefinition itemComposition = client.getItemDefinition(itemId);
playerEquipment.put(kitType, itemComposition);
}
}
if (this.showValue)
{
final LinkedHashMap<Integer, Integer> gear = new LinkedHashMap<>(player.getGear());
removeEntries(gear, this.protectedItems);
int risk = 0;
for (int value : gear.values())
{
risk += value;
}
String price;
if (!this.exactValue)
{
price = QuantityFormatter.quantityToRSDecimalStack(risk);
}
else
{
price = NumberFormat.getIntegerInstance().format(risk);
}
chatMessageManager.queue(QueuedMessage.builder()
.type(ChatMessageType.CONSOLE)
.runeLiteFormattedMessage(new ChatMessageBuilder()
.append(ChatColorType.HIGHLIGHT)
.append("Risked Value: ")
.append(ChatColorType.NORMAL)
.append(price)
.build())
.build());
}
equipmentInspectorPanel.update(playerEquipment, playerName);
});
}
@Subscribe
@@ -303,10 +228,22 @@ public class EquipmentInspectorPlugin extends Plugin
}
}
private static void removeEntries(LinkedHashMap<Integer, Integer> map, int quantity)
{
for (int i = 0; i < quantity; i++)
{
if (!map.entrySet().iterator().hasNext())
{
return;
}
map.entrySet().remove(map.entrySet().iterator().next());
}
}
private void updateConfig()
{
this.ShowValue = config.ShowValue();
this.protecteditems = config.protecteditems();
this.ExactValue = config.ExactValue();
this.showValue = config.showValue();
this.protectedItems = config.protectedItems();
this.exactValue = config.exactValue();
}
}

View File

@@ -23,23 +23,18 @@
*/
package net.runelite.client.plugins.hideunder;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Actor;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.Player;
import net.runelite.api.Varbits;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.InteractingChanged;
import net.runelite.api.events.PlayerDespawned;
import net.runelite.api.events.PlayerSpawned;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.PlayerContainer;
import net.runelite.client.game.PlayerManager;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginType;
@@ -56,35 +51,22 @@ public class HideUnder extends Plugin
{
@Inject
private Client client;
@Inject
private EventBus eventBus;
private PlayerManager playerManager;
private final Set<PlayerContainer> playerContainer = new HashSet<>();
@Override
protected void startUp()
{
addSubscriptions();
playerContainer.clear();
}
@Override
protected void shutDown()
{
eventBus.unregister(this);
}
private void addSubscriptions()
{
eventBus.subscribe(PlayerSpawned.class, this, this::onPlayerSpawned);
eventBus.subscribe(PlayerDespawned.class, this, this::onPlayerDespawned);
eventBus.subscribe(GameTick.class, this, this::onGameTick);
eventBus.subscribe(InteractingChanged.class, this, this::onInteractingChanged);
eventBus.subscribe(AnimationChanged.class, this, this::onAnimationChanged);
eventBus.subscribe(GameStateChanged.class, this, this::onGameStateChanged);
}
@Subscribe
private void onGameStateChanged(GameStateChanged event)
{
if (event.getGameState() == GameState.LOGGED_IN)
@@ -93,122 +75,32 @@ public class HideUnder extends Plugin
}
}
private void onInteractingChanged(InteractingChanged event)
{
if ((event.getSource() instanceof Player) && (event.getTarget() instanceof Player))
{
final Player source = (Player) event.getSource();
final Player target = (Player) event.getTarget();
if (source == client.getLocalPlayer())
{
for (PlayerContainer player : playerContainer)
{
if (player.getPlayer() == target)
{
player.setTimer(16);
player.setTarget(true);
}
}
}
else if (target == client.getLocalPlayer())
{
for (PlayerContainer player : playerContainer)
{
if (player.getPlayer() == source)
{
player.setTimer(16);
player.setTarget(true);
}
}
}
}
}
private void onAnimationChanged(AnimationChanged event)
{
final Actor actor = event.getActor();
if (actor.getInteracting() != client.getLocalPlayer() || !(actor instanceof Player))
{
return;
}
if (actor.getAnimation() != -1 && actor.getInteracting() != null && actor.getInteracting() == client.getLocalPlayer())
{
for (PlayerContainer player : playerContainer)
{
if (player.getPlayer() == actor)
{
player.setTimer(16);
player.setTarget(true);
}
}
}
}
private void onPlayerSpawned(PlayerSpawned event)
{
final Player player = event.getPlayer();
if (player == client.getLocalPlayer())
{
return;
}
playerContainer.add(new PlayerContainer(player));
}
private void onPlayerDespawned(PlayerDespawned event)
{
final Player player = event.getPlayer();
playerContainer.removeIf(playa -> playa.getPlayer() == player);
}
@Subscribe
private void onGameTick(GameTick event)
{
if (playerContainer.isEmpty() || client.getLocalPlayer() == null)
if (client.getLocalPlayer() == null)
{
return;
}
final WorldPoint lp = client.getLocalPlayer().getWorldLocation();
final WorldPoint localPlayerWp = WorldPoint.fromLocalInstance(client, client.getLocalPlayer().getLocalLocation());
client.setLocalPlayerHidden(false);
if (localPlayerWp == null)
final WorldPoint localPlayerWp = WorldPoint.fromLocalInstance(client, client.getLocalPlayer().getLocalLocation());
final WorldPoint lp = client.getLocalPlayer().getWorldLocation();
for (PlayerContainer player : playerManager.getAllAttackers())
{
return;
}
for (PlayerContainer player : playerContainer)
{
if (player.getTimer() > 0)
{
player.setTimer(player.getTimer() - 1);
}
else
{
player.setTarget(false);
}
if (!player.isTarget())
{
continue;
}
if (client.getVar(Varbits.LMS_IN_GAME) == 1)
{
final WorldPoint playerWp = WorldPoint.fromLocalInstance(client, player.getPlayer().getLocalLocation());
if (playerWp != null && localPlayerWp.distanceTo(playerWp) == 0)
if (localPlayerWp != null && localPlayerWp.distanceTo(playerWp) == 0)
{
client.setLocalPlayerHidden(true);
}
continue;
}
if (player.getPlayer().getWorldLocation().distanceTo(lp) == 0)
if (lp != null && player.getPlayer().getWorldLocation().distanceTo(lp) == 0)
{
client.setLocalPlayerHidden(true);
}

View File

@@ -24,52 +24,34 @@
package net.runelite.client.plugins.playerscouter;
import com.google.inject.Provides;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
import javax.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Actor;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.ItemDefinition;
import net.runelite.api.NPC;
import net.runelite.api.Player;
import net.runelite.api.Varbits;
import net.runelite.api.WorldType;
import net.runelite.api.coords.WorldArea;
import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.PlayerDespawned;
import net.runelite.api.events.PlayerSpawned;
import net.runelite.api.kit.KitType;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.ItemMapping;
import net.runelite.client.game.ItemReclaimCost;
import net.runelite.client.game.PlayerContainer;
import net.runelite.client.game.PlayerManager;
import net.runelite.client.game.WorldLocation;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginType;
import net.runelite.client.util.PvPUtil;
import net.runelite.client.util.QuantityFormatter;
import net.runelite.http.api.discord.DiscordClient;
import net.runelite.http.api.discord.DiscordEmbed;
@@ -78,8 +60,6 @@ import net.runelite.http.api.discord.embed.AuthorEmbed;
import net.runelite.http.api.discord.embed.FieldEmbed;
import net.runelite.http.api.discord.embed.FooterEmbed;
import net.runelite.http.api.discord.embed.ThumbnailEmbed;
import net.runelite.http.api.hiscore.HiscoreClient;
import net.runelite.http.api.hiscore.HiscoreResult;
import net.runelite.http.api.item.ItemStats;
import okhttp3.HttpUrl;
@@ -92,27 +72,19 @@ import okhttp3.HttpUrl;
@Slf4j
public class PlayerScouter extends Plugin
{
private static final HiscoreClient HISCORE_CLIENT = new HiscoreClient();
private static final DiscordClient DISCORD_CLIENT = new DiscordClient();
private static final Map<WorldArea, String> WILD_LOCS = WorldLocation.getLOCATION_MAP();
private static final SimpleDateFormat SDF = new SimpleDateFormat("MMM dd h:mm a z");
private static final String ICON_URL = "https://www.osrsbox.com/osrsbox-db/items-icons/"; // Add item id + ".png"
@Inject
private Client client;
@Inject
private ItemManager itemManager;
@Inject
private PlayerScouterConfig config;
@Inject
private EventBus eventBus;
private PlayerManager playerManager;
private final ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
private final Set<PlayerContainer> playerContainer = new HashSet<>();
private final Map<String, HiscoreResult> resultCache = new HashMap<>();
private final Map<String, Integer> blacklist = new HashMap<>();
private HttpUrl webhook;
private int minimumRisk;
@@ -135,31 +107,13 @@ public class PlayerScouter extends Plugin
protected void startUp()
{
blacklist.clear();
addSubscriptions();
updateConfig();
if (client.getGameState() == GameState.LOGGED_IN)
{
for (Player player : client.getPlayers())
{
addPlayer(player);
}
}
}
@Override
protected void shutDown()
{
playerContainer.clear();
blacklist.clear();
eventBus.unregister(this);
}
private void addSubscriptions()
{
eventBus.subscribe(GameStateChanged.class, this, this::onGameStateChanged);
eventBus.subscribe(GameTick.class, this, this::onGameTick);
eventBus.subscribe(PlayerDespawned.class, this, this::onPlayerDespawned);
eventBus.subscribe(PlayerSpawned.class, this, this::onPlayerSpawned);
}
@Subscribe
@@ -173,6 +127,7 @@ public class PlayerScouter extends Plugin
updateConfig();
}
@Subscribe
private void onGameStateChanged(GameStateChanged event)
{
if (event.getGameState() == GameState.LOGGED_IN)
@@ -183,48 +138,68 @@ public class PlayerScouter extends Plugin
blacklist.clear();
}
@Subscribe
private void onGameTick(GameTick event)
{
resetBlacklist();
if (!checkWildy() || playerContainer.isEmpty() || this.webhook == null)
if (!checkWildy() || this.webhook == null)
{
return;
}
playerContainer.forEach(player ->
final List<PlayerContainer> players = new ArrayList<>();
for (PlayerContainer player : playerManager.getPlayerContainers())
{
update(player);
if (player.getPlayer().getCombatLevel() < this.minimumCombat
|| player.getPlayer().getCombatLevel() > this.maximumCombat)
if (player.isScouted())
{
return;
player.setScoutTimer(player.getScoutTimer() - 1);
if (player.getScoutTimer() <= 0)
{
player.setScouted(false);
player.setScoutTimer(500);
}
continue;
}
if ((player.getPlayer().getCombatLevel() >= this.minimumCombat
&& player.getPlayer().getCombatLevel() <= this.maximumCombat) && player.getRisk() > this.minimumRisk)
if (player.getPlayer().getCombatLevel() < this.minimumCombat || player.getPlayer().getCombatLevel() > this.maximumCombat)
{
scoutPlayer(player);
continue;
}
});
if ((player.getPlayer().getCombatLevel() >= this.minimumCombat &&
player.getPlayer().getCombatLevel() <= this.maximumCombat) &&
player.getRisk() > this.minimumRisk)
{
if (player.getSkills() == null)
{
if (player.isHttpRetry())
{
continue;
}
playerManager.updateStats(player.getPlayer());
continue;
}
if (config.mini())
{
players.add(player);
continue;
}
addPlayer(player);
}
}
if (config.mini())
{
players.sort(Comparator.comparingInt(PlayerContainer::getRisk).reversed());
scoutMini(players);
}
}
private void onPlayerDespawned(PlayerDespawned event)
private void addPlayer(PlayerContainer player)
{
final Player player = event.getPlayer();
playerContainer.removeIf(p -> p.getPlayer() == player);
}
private void onPlayerSpawned(PlayerSpawned event)
{
final Player player = event.getPlayer();
addPlayer(player);
}
private void addPlayer(Player player)
{
if (player == client.getLocalPlayer()
if (player.getPlayer() == client.getLocalPlayer()
|| (!blacklist.isEmpty() && blacklist.containsKey(player.getName()))
|| (!this.scoutFriends && client.isFriended(player.getName(), false)
|| (!this.scoutClan && client.isClanMember(player.getName()))))
@@ -233,8 +208,8 @@ public class PlayerScouter extends Plugin
return;
}
playerContainer.add(new PlayerContainer(player));
blacklist.put(player.getName(), client.getTickCount() + this.timeout);
scoutPlayer(player);
}
private void resetBlacklist()
@@ -279,203 +254,79 @@ public class PlayerScouter extends Plugin
this.maximumCombat = config.maximumCombat();
}
private void update(PlayerContainer player)
private void scoutMini(List<PlayerContainer> players)
{
if (player.isScouted())
{
player.setScoutTimer(player.getScoutTimer() - 1);
if (player.getScoutTimer() <= 0)
{
player.setScouted(false);
player.setScoutTimer(500);
}
return;
}
player.setRisk(0);
updatePlayerGear(player);
updateStats(player);
player.setLocation(location(player));
player.setWildyLevel(PvPUtil.getWildernessLevelFrom(player.getPlayer().getWorldLocation()));
player.setTargetString(targetStringBuilder(player));
log.debug(player.toString());
}
private void updateStats(PlayerContainer player)
{
if (player.isHttpRetry() || player.getSkills() != null)
if (client.getLocalPlayer() == null)
{
return;
}
executorService.submit(() ->
final List<FieldEmbed> fieldList = new ArrayList<>();
final String location = WorldLocation.location(client.getLocalPlayer().getWorldLocation());
final int cap = Math.min(players.size(), 25);
int highestValue = 0;
int id = 0;
int risk = 0;
for (int i = 0; i < cap; i++)
{
player.setHttpRetry(true);
HiscoreResult result;
if (resultCache.containsKey(player.getName()))
final PlayerContainer player = players.get(i);
final Map.Entry entry = getEntry(player.getGear());
risk += player.getRisk();
if (entry != null)
{
result = resultCache.get(player.getName());
}
else
{
try
final int mostValued = (int) entry.getValue();
final int mostValuedId = (int) entry.getKey();
if (mostValued > highestValue)
{
result = HISCORE_CLIENT.lookup(player.getName());
}
catch (IOException ex)
{
log.warn("Error fetching Hiscore data " + ex.getMessage());
player.setHttpRetry(false);
return;
highestValue = mostValued;
id = mostValuedId;
}
}
if (result == null)
String name = "☠️ " + player.getName() + " ☠️";
if (player.getPlayer().getSkullIcon() == null)
{
player.setHttpRetry(false);
return;
name = player.getName();
}
resultCache.put(player.getName(), result);
player.setSkills(result);
player.setPrayer(player.getSkills().getPrayer().getLevel());
});
}
private void updatePlayerGear(PlayerContainer player)
{
Map<Integer, Integer> prices = new HashMap<>();
fieldList.add(FieldEmbed.builder()
.name(name)
.value(QuantityFormatter.quantityToRSDecimalStack(player.getRisk()))
.inline(true)
.build());
if (player.getPlayer().getPlayerAppearance() == null)
{
return;
player.setScouted(true);
}
for (KitType kitType : KitType.values())
String iconId = String.valueOf(id);
String icon = ICON_URL + iconId + ".png";
ThumbnailEmbed image = ThumbnailEmbed.builder()
.url(ICON_URL + iconId + ".png")
.build();
String color = "8388352";
if (risk < 1000000 && risk > 150000)
{
if (kitType.equals(KitType.RING) || kitType.equals(KitType.AMMUNITION))
{
continue;
}
final int id = player.getPlayer().getPlayerAppearance().getEquipmentId(kitType);
if (id == -1)
{
continue;
}
if (kitType.equals(KitType.WEAPON))
{
player.setWeapon(id);
}
final ItemStats item = itemManager.getItemStats(id, false);
final ItemDefinition itemDefinition = itemManager.getItemDefinition(id);
if (item == null)
{
log.debug("Item is null: {}", id);
continue;
}
if (ItemReclaimCost.breaksOnDeath(id))
{
prices.put(id, itemManager.getRepairValue(id));
log.debug("Item has a broken value: Id {}, Value {}", id, itemManager.getRepairValue(id));
continue;
}
if (!itemDefinition.isTradeable() && !ItemMapping.isMapped(id))
{
prices.put(id, itemDefinition.getPrice());
}
else if (itemDefinition.isTradeable())
{
prices.put(id, itemManager.getItemPrice(id, false));
}
//blue
color = "32767";
}
updateGear(player, prices);
}
private void updateGear(PlayerContainer player, Map<Integer, Integer> prices)
{
player.setGear(prices.entrySet()
.stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new))
);
player.setRiskedGear(prices.entrySet()
.stream()
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (oldValue, newValue) -> oldValue, LinkedHashMap::new))
);
if (player.getPlayer().getSkullIcon() == null)
else if (risk > 1000000)
{
removeEntries(player.getRiskedGear(), player.getPrayer() <= 25 ? 3 : 4);
}
else
{
removeEntries(player.getRiskedGear(), player.getPrayer() <= 25 ? 0 : 1);
//orange
color = "16744448";
}
player.getRiskedGear().values().forEach(price -> player.setRisk(player.getRisk() + price));
prices.clear();
}
private static void removeEntries(LinkedHashMap<Integer, Integer> map, int quantity)
{
if (map.size() < quantity)
{
log.debug("Size is lower than removal quantity.");
}
for (int i = 0; i < quantity; i++)
{
if (!map.entrySet().iterator().hasNext())
{
log.debug("Attempted to remove entries, but there was not enough to remove.");
return;
}
log.debug("Entry Removed: " + map.entrySet().iterator().next());
map.entrySet().remove(map.entrySet().iterator().next());
}
}
private static Map.Entry getEntry(LinkedHashMap<Integer, Integer> map)
{
if (!map.isEmpty())
{
Iterator<Map.Entry<Integer, Integer>> entry = map.entrySet().iterator();
for (int i = 0; i < 1; i++)
{
entry.next();
}
return entry.next();
}
return null;
}
private String targetStringBuilder(PlayerContainer player)
{
if (player.getPlayer().getInteracting() != null)
{
Actor actor = player.getPlayer().getInteracting();
if (actor instanceof Player)
{
return "(Player) " + actor.getName();
}
else if (actor instanceof NPC)
{
return "(NPC) " + actor.getName();
}
}
return "No Target Detected";
message(location, icon, image, fieldList, color);
}
private void scoutPlayer(PlayerContainer player)
{
if (player.isScouted() || player.getSkills() == null)
if (player.isScouted())
{
return;
}
@@ -516,6 +367,7 @@ public class PlayerScouter extends Plugin
.value(Integer.toString(player.getPlayer().getCombatLevel()))
.inline(true)
.build());
if (client.getVar(Varbits.IN_WILDERNESS) == 1)
{
fieldList.add(FieldEmbed.builder()
@@ -582,7 +434,10 @@ public class PlayerScouter extends Plugin
}
}
String icon = ICON_URL + Objects.requireNonNull(getEntry(player.getGear())).getKey() + ".png";
Map.Entry entry = getEntry(player.getGear());
String iconId = entry == null ? String.valueOf(1) : String.valueOf(entry.getKey());
String icon = ICON_URL + iconId + ".png";
String name = "☠️ " + player.getName() + " ☠️";
if (player.getPlayer().getSkullIcon() == null)
@@ -601,7 +456,7 @@ public class PlayerScouter extends Plugin
if (name.isEmpty() || fields.isEmpty())
{
log.error("Discord message will fail with a missing name/description/field");
log.debug("Discord message will fail with a missing name/description/field");
return;
}
@@ -627,50 +482,12 @@ public class PlayerScouter extends Plugin
DISCORD_CLIENT.message(this.webhook, discordMessage);
}
private String location(PlayerContainer player)
private static Map.Entry getEntry(LinkedHashMap<Integer, Integer> map)
{
final WorldPoint wl = player.getPlayer().getWorldLocation();
int dist = 10000;
String s = "";
WorldArea closestArea = null;
for (Map.Entry<WorldArea, String> entry : WILD_LOCS.entrySet())
if (!map.isEmpty())
{
WorldArea worldArea = entry.getKey();
if (worldArea.toWorldPointList().contains(wl))
{
s = entry.getValue();
return s;
}
int distTo = worldArea.distanceTo(wl);
if (distTo < dist)
{
dist = distTo;
closestArea = worldArea;
}
return map.entrySet().iterator().next();
}
if (wl.getY() > (Objects.requireNonNull(closestArea).toWorldPoint().getY() + closestArea.getHeight()))
{
s = s + "N";
}
if (wl.getY() < closestArea.toWorldPoint().getY())
{
s = s + "S";
}
if (wl.getX() < closestArea.toWorldPoint().getX())
{
s = s + "W";
}
if (wl.getX() > (closestArea.toWorldPoint().getX() + closestArea.getWidth()))
{
s = s + "E";
}
s = s + " of ";
s = s + WILD_LOCS.get(closestArea);
if (s.startsWith(" of "))
{
s = s.substring(3);
}
return s;
return null;
}
}

View File

@@ -43,6 +43,18 @@ public interface PlayerScouterConfig extends Config
return "";
}
@ConfigItem(
keyName = "mini",
name = "Minify Output",
description = "",
position = 0,
secret = true
)
default boolean mini()
{
return true;
}
@ConfigItem(
keyName = "onlyWildy",
name = "Only Scout in Wildy",

View File

@@ -1,64 +0,0 @@
/*
* Copyright (c) 2019, gazivodag <https://github.com/gazivodag>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.prayagainstplayer;
import net.runelite.api.Player;
/**
* Contains a player object
* When they attacked me
* And (in milliseconds) when to expire the overlay around them
*/
public class PlayerContainer
{
private final Player player;
private final long whenTheyAttackedMe;
private final int millisToExpireHighlight;
PlayerContainer(final Player player, final long whenTheyAttackedMe, final int millisToExpireHighlight)
{
this.player = player;
this.whenTheyAttackedMe = whenTheyAttackedMe;
this.millisToExpireHighlight = millisToExpireHighlight;
}
//getters
public Player getPlayer()
{
return player;
}
long getWhenTheyAttackedMe()
{
return whenTheyAttackedMe;
}
int getMillisToExpireHighlight()
{
return millisToExpireHighlight;
}
}

View File

@@ -24,7 +24,6 @@
package net.runelite.client.plugins.prayagainstplayer;
import java.awt.Color;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@@ -32,63 +31,8 @@ import net.runelite.client.config.ConfigItem;
@ConfigGroup("prayagainstplayer")
public interface PrayAgainstPlayerConfig extends Config
{
@ConfigItem(
position = 0,
keyName = "attackerPlayerColor",
name = "Attacker color",
description = "This is the color that will be used to highlight attackers."
)
default Color attackerPlayerColor()
{
return new Color(0xFF0006);
}
@ConfigItem(
position = 1,
keyName = "potentialPlayerColor",
name = "Potential Attacker color",
description = "This is the color that will be used to highlight potential attackers."
)
default Color potentialPlayerColor()
{
return new Color(0xFFFF00);
}
@ConfigItem(
position = 2,
keyName = "attackerTargetTimeout",
name = "Attacker Timeout",
description = "Seconds until attacker is no longer highlighted."
)
default int attackerTargetTimeout()
{
return 10;
}
@ConfigItem(
position = 3,
keyName = "potentialTargetTimeout",
name = "Potential Attacker Timeout",
description = "Seconds until potential attacker is no longer highlighted."
)
default int potentialTargetTimeout()
{
return 10;
}
@ConfigItem(
position = 4,
keyName = "newSpawnTimeout",
name = "New Player Timeout",
description = "Seconds until logged in/spawned player is no longer highlighted."
)
default int newSpawnTimeout()
{
return 5;
}
@ConfigItem(
position = 5,
keyName = "ignoreFriends",
name = "Ignore Friends",
description = "This lets you decide whether you want friends to be highlighted by this plugin."
@@ -99,7 +43,7 @@ public interface PrayAgainstPlayerConfig extends Config
}
@ConfigItem(
position = 6,
position = 2,
keyName = "ignoreClanMates",
name = "Ignore Clan Mates",
description = "This lets you decide whether you want clan mates to be highlighted by this plugin."
@@ -110,40 +54,7 @@ public interface PrayAgainstPlayerConfig extends Config
}
@ConfigItem(
position = 7,
keyName = "markNewPlayer",
name = "Mark new player as potential attacker",
description = "Marks someone that logged in or teleported as a potential attacker for your safety\nDO NOT RUN THIS IN WORLD 1-2 GRAND EXCHANGE!"
)
default boolean markNewPlayer()
{
return false;
}
@ConfigItem(
position = 8,
keyName = "drawTargetPrayAgainst",
name = "Draw what to pray on attacker",
description = "Tells you what to pray from what weapon the attacker is holding"
)
default boolean drawTargetPrayAgainst()
{
return true;
}
@ConfigItem(
position = 9,
keyName = "drawPotentialTargetPrayAgainst",
name = "Draw what to pray on potential attacker",
description = "Tells you what to pray from what weapon the potential attacker is holding"
)
default boolean drawPotentialTargetPrayAgainst()
{
return true;
}
@ConfigItem(
position = 10,
position = 3,
keyName = "drawTargetPrayAgainstPrayerTab",
name = "Draw what to pray from prayer tab",
description = "Tells you what to pray from what weapon the attacker is holding from the prayer tab"
@@ -152,81 +63,4 @@ public interface PrayAgainstPlayerConfig extends Config
{
return false;
}
@ConfigItem(
position = 11,
keyName = "drawTargetsName",
name = "Draw name on attacker",
description = "Configures whether or not the attacker\'s name should be shown"
)
default boolean drawTargetsName()
{
return true;
}
@ConfigItem(
position = 12,
keyName = "drawPotentialTargetsName",
name = "Draw name on potential attacker",
description = "Configures whether or not the potential attacker\'s name should be shown"
)
default boolean drawPotentialTargetsName()
{
return true;
}
@ConfigItem(
position = 13,
keyName = "drawTargetHighlight",
name = "Draw highlight around attacker",
description = "Configures whether or not the attacker should be highlighted"
)
default boolean drawTargetHighlight()
{
return true;
}
@ConfigItem(
position = 14,
keyName = "drawPotentialTargetHighlight",
name = "Draw highlight around potential attacker",
description = "Configures whether or not the potential attacker should be highlighted"
)
default boolean drawPotentialTargetHighlight()
{
return true;
}
@ConfigItem(
position = 15,
keyName = "drawTargetTile",
name = "Draw tile under attacker",
description = "Configures whether or not the attacker\'s tile be highlighted"
)
default boolean drawTargetTile()
{
return false;
}
@ConfigItem(
position = 16,
keyName = "drawPotentialTargetTile",
name = "Draw tile under potential attacker",
description = "Configures whether or not the potential attacker\'s tile be highlighted"
)
default boolean drawPotentialTargetTile()
{
return false;
}
@ConfigItem(
position = 17,
keyName = "drawUnknownWeapons",
name = "Draw unknown weapons",
description = "Configures whether or not the unknown weapons should be shown when a player equips one"
)
default boolean drawUnknownWeapons()
{
return false;
}
}

View File

@@ -24,204 +24,55 @@
package net.runelite.client.plugins.prayagainstplayer;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.image.BufferedImage;
import java.util.ConcurrentModificationException;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.api.ItemDefinition;
import net.runelite.api.Player;
import net.runelite.api.Point;
import net.runelite.api.kit.KitType;
import net.runelite.api.util.Text;
import net.runelite.client.game.PlayerContainer;
import net.runelite.client.game.PlayerManager;
import net.runelite.client.graphics.ModelOutlineRenderer;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayPriority;
import net.runelite.client.ui.overlay.OverlayUtil;
@Singleton
class PrayAgainstPlayerOverlay extends Overlay
{
private final PrayAgainstPlayerPlugin plugin;
private final Client client;
private final PlayerManager playerManager;
private final ModelOutlineRenderer outlineRenderer;
@Inject
private PrayAgainstPlayerOverlay(final PrayAgainstPlayerPlugin plugin, final Client client)
private PrayAgainstPlayerOverlay(
final PrayAgainstPlayerPlugin plugin,
final PlayerManager playerManager,
final ModelOutlineRenderer outlineRenderer
)
{
super(plugin);
this.plugin = plugin;
this.client = client;
this.playerManager = playerManager;
this.outlineRenderer = outlineRenderer;
setLayer(OverlayLayer.ABOVE_SCENE);
setPosition(OverlayPosition.DYNAMIC);
setPriority(OverlayPriority.HIGH);
}
@Override
public Dimension render(Graphics2D graphics)
{
renderPotentialPlayers(graphics);
renderAttackingPlayers(graphics);
for (PlayerContainer player : playerManager.getAllAttackers())
{
if (player.getPlayer() == null
|| (plugin.isIgnoreFriends() && player.isFriend()
|| (plugin.isIgnoreClanMates() && player.isClan()))
)
{
continue;
}
outlineRenderer.drawOutline(player.getPlayer(), 4, player.getAttackStyle().getColor());
}
return null;
}
private void renderPotentialPlayers(Graphics2D graphics)
{
if (plugin.getPotentialPlayersAttackingMe() == null || !plugin.getPotentialPlayersAttackingMe().isEmpty())
{
try
{
if (plugin.getPotentialPlayersAttackingMe() != null)
{
for (PlayerContainer container : plugin.getPotentialPlayersAttackingMe())
{
if ((System.currentTimeMillis() > (container.getWhenTheyAttackedMe() + container.getMillisToExpireHighlight())) && (container.getPlayer().getInteracting() != client.getLocalPlayer()))
{
plugin.removePlayerFromPotentialContainer(container);
}
if (plugin.isDrawPotentialTargetsName())
{
renderNameAboveHead(graphics, container.getPlayer(), plugin.getPotentialPlayerColor());
}
if (plugin.isDrawPotentialTargetHighlight())
{
renderHighlightedPlayer(graphics, container.getPlayer(), plugin.getPotentialPlayerColor());
}
if (plugin.isDrawPotentialTargetTile())
{
renderTileUnderPlayer(graphics, container.getPlayer(), plugin.getPotentialPlayerColor());
}
if (plugin.isDrawPotentialTargetPrayAgainst())
{
renderPrayAgainstOnPlayer(graphics, container.getPlayer(), plugin.getPotentialPlayerColor());
}
}
}
}
catch (ConcurrentModificationException ignored)
{
}
}
}
private void renderAttackingPlayers(Graphics2D graphics)
{
if (plugin.getPlayersAttackingMe() == null || !plugin.getPlayersAttackingMe().isEmpty())
{
try
{
if (plugin.getPlayersAttackingMe() != null)
{
for (PlayerContainer container : plugin.getPlayersAttackingMe())
{
if ((System.currentTimeMillis() > (container.getWhenTheyAttackedMe() + container.getMillisToExpireHighlight())) && (container.getPlayer().getInteracting() != client.getLocalPlayer()))
{
plugin.removePlayerFromAttackerContainer(container);
}
if (plugin.isDrawTargetsName())
{
renderNameAboveHead(graphics, container.getPlayer(), plugin.getAttackerPlayerColor());
}
if (plugin.isDrawTargetHighlight())
{
renderHighlightedPlayer(graphics, container.getPlayer(), plugin.getAttackerPlayerColor());
}
if (plugin.isDrawTargetTile())
{
renderTileUnderPlayer(graphics, container.getPlayer(), plugin.getAttackerPlayerColor());
}
if (plugin.isDrawTargetPrayAgainst())
{
renderPrayAgainstOnPlayer(graphics, container.getPlayer(), plugin.getAttackerPlayerColor());
}
}
}
}
catch (ConcurrentModificationException ignored)
{
}
}
}
private void renderNameAboveHead(Graphics2D graphics, Player player, Color color)
{
final String name = Text.sanitize(player.getName());
final int offset = player.getLogicalHeight() + 40;
Point textLocation = player.getCanvasTextLocation(graphics, name, offset);
if (textLocation != null)
{
OverlayUtil.renderTextLocation(graphics, textLocation, name, color);
}
}
private void renderHighlightedPlayer(Graphics2D graphics, Player player, Color color)
{
try
{
OverlayUtil.renderPolygon(graphics, player.getConvexHull(), color);
}
catch (NullPointerException ignored)
{
}
}
private void renderTileUnderPlayer(Graphics2D graphics, Player player, Color color)
{
Polygon poly = player.getCanvasTilePoly();
OverlayUtil.renderPolygon(graphics, poly, color);
}
private void renderPrayAgainstOnPlayer(Graphics2D graphics, Player player, Color color)
{
final int offset = (player.getLogicalHeight() / 2) + 75;
BufferedImage icon;
switch (WeaponType.checkWeaponOnPlayer(client, player))
{
case WEAPON_MELEE:
icon = plugin.getProtectionIcon(WeaponType.WEAPON_MELEE);
break;
case WEAPON_MAGIC:
icon = plugin.getProtectionIcon(WeaponType.WEAPON_MAGIC);
break;
case WEAPON_RANGED:
icon = plugin.getProtectionIcon(WeaponType.WEAPON_RANGED);
break;
default:
icon = null;
break;
}
try
{
if (icon != null)
{
Point point = player.getCanvasImageLocation(icon, offset);
OverlayUtil.renderImageLocation(graphics, point, icon);
}
else
{
if (plugin.isDrawUnknownWeapons())
{
int itemId = player.getPlayerAppearance().getEquipmentId(KitType.WEAPON);
ItemDefinition itemComposition = client.getItemDefinition(itemId);
final String str = itemComposition.getName().toUpperCase();
Point point = player.getCanvasTextLocation(graphics, str, offset);
OverlayUtil.renderTextLocation(graphics, point, str, color);
}
}
}
catch (Exception ignored)
{
}
}
}

View File

@@ -29,13 +29,15 @@ import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.util.ConcurrentModificationException;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.api.Player;
import net.runelite.api.VarClientInt;
import net.runelite.api.vars.InterfaceTab;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.game.AttackStyle;
import net.runelite.client.game.PlayerContainer;
import net.runelite.client.game.PlayerManager;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition;
@@ -46,16 +48,17 @@ import net.runelite.client.ui.overlay.OverlayUtil;
class PrayAgainstPlayerOverlayPrayerTab extends Overlay
{
private final PrayAgainstPlayerPlugin plugin;
private final PlayerManager playerManager;
private final Client client;
@Inject
private PrayAgainstPlayerOverlayPrayerTab(final PrayAgainstPlayerPlugin plugin, final Client client)
private PrayAgainstPlayerOverlayPrayerTab(
final PlayerManager playerManager,
final Client client
)
{
super(plugin);
this.plugin = plugin;
this.client = client;
this.playerManager = playerManager;
setPosition(OverlayPosition.DETACHED);
setLayer(OverlayLayer.ALWAYS_ON_TOP);
setPriority(OverlayPriority.MED);
@@ -65,55 +68,30 @@ class PrayAgainstPlayerOverlayPrayerTab extends Overlay
@Override
public Dimension render(Graphics2D graphics)
{
if (plugin.getPlayersAttackingMe() == null || !plugin.getPlayersAttackingMe().isEmpty())
for (PlayerContainer player : playerManager.getAllAttackers())
{
try
if (player.getAttackStyle() == AttackStyle.UNKNOWN)
{
if (plugin.getPlayersAttackingMe() != null)
{
for (PlayerContainer container : plugin.getPlayersAttackingMe())
{
if (plugin.getPlayersAttackingMe() != null && plugin.getPlayersAttackingMe().size() == 1 &&
plugin.isDrawTargetPrayAgainstPrayerTab())
{
renderPrayerToClick(graphics, container.getPlayer());
}
}
}
continue;
}
catch (ConcurrentModificationException ignored)
final Widget widget = client.getWidget(player.getAttackStyle().getPrayer().getWidgetInfo());
if (widget == null)
{
continue;
}
if (client.getVar(VarClientInt.INTERFACE_TAB) == InterfaceTab.PRAYER.getId() &&
!client.isPrayerActive(player.getAttackStyle().getPrayer()))
{
OverlayUtil.renderPolygon(graphics, rectangleToPolygon(widget.getBounds()), Color.RED);
break;
}
}
return null;
}
private void renderPrayerToClick(Graphics2D graphics, Player player)
{
Widget PROTECT_FROM_MAGIC = client.getWidget(WidgetInfo.PRAYER_PROTECT_FROM_MAGIC);
Widget PROTECT_FROM_RANGED = client.getWidget(WidgetInfo.PRAYER_PROTECT_FROM_MISSILES);
Widget PROTECT_FROM_MELEE = client.getWidget(WidgetInfo.PRAYER_PROTECT_FROM_MELEE);
Color color = Color.RED;
if (PROTECT_FROM_MELEE.isHidden())
{
return;
}
switch (WeaponType.checkWeaponOnPlayer(client, player))
{
case WEAPON_MAGIC:
OverlayUtil.renderPolygon(graphics, rectangleToPolygon(PROTECT_FROM_MAGIC.getBounds()), color);
break;
case WEAPON_MELEE:
OverlayUtil.renderPolygon(graphics, rectangleToPolygon(PROTECT_FROM_MELEE.getBounds()), color);
break;
case WEAPON_RANGED:
OverlayUtil.renderPolygon(graphics, rectangleToPolygon(PROTECT_FROM_RANGED.getBounds()), color);
break;
default:
break;
}
}
private static Polygon rectangleToPolygon(Rectangle rect)
{
int[] xpoints = {rect.x, rect.x + rect.width, rect.x + rect.width, rect.x};
@@ -121,5 +99,4 @@ class PrayAgainstPlayerOverlayPrayerTab extends Overlay
return new Polygon(xpoints, ypoints, 4);
}
}

View File

@@ -25,28 +25,11 @@
package net.runelite.client.plugins.prayagainstplayer;
import com.google.inject.Provides;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.WritableRaster;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.AccessLevel;
import lombok.Getter;
import net.runelite.api.AnimationID;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.Player;
import net.runelite.api.SpriteID;
import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.InteractingChanged;
import net.runelite.api.events.PlayerDespawned;
import net.runelite.api.events.PlayerSpawned;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ConfigChanged;
@@ -55,7 +38,6 @@ import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginType;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.util.ImageUtil;
@PluginDescriptor(
name = "Pray Against Player",
@@ -64,75 +46,26 @@ import net.runelite.client.util.ImageUtil;
type = PluginType.PVP,
enabledByDefault = false
)
/**
* I am fully aware that there is plenty of overhead and is a MESS!
* If you'd like to contribute please do!
*/
@Singleton
@Getter(AccessLevel.PACKAGE)
public class PrayAgainstPlayerPlugin extends Plugin
{
private static final int[] PROTECTION_ICONS = {
SpriteID.PRAYER_PROTECT_FROM_MISSILES,
SpriteID.PRAYER_PROTECT_FROM_MELEE,
SpriteID.PRAYER_PROTECT_FROM_MAGIC
};
private static final Dimension PROTECTION_ICON_DIMENSION = new Dimension(33, 33);
private static final Color PROTECTION_ICON_OUTLINE_COLOR = new Color(33, 33, 33);
private final BufferedImage[] ProtectionIcons = new BufferedImage[PROTECTION_ICONS.length];
private List<PlayerContainer> potentialPlayersAttackingMe;
private List<PlayerContainer> playersAttackingMe;
@Inject
private Client client;
@Inject
private SpriteManager spriteManager;
@Inject
private OverlayManager overlayManager;
@Inject
private PrayAgainstPlayerOverlay overlay;
@Inject
private PrayAgainstPlayerOverlayPrayerTab overlayPrayerTab;
@Inject
private PrayAgainstPlayerConfig config;
@Getter(AccessLevel.PACKAGE)
private Color attackerPlayerColor;
@Getter(AccessLevel.PACKAGE)
private Color potentialPlayerColor;
private int attackerTargetTimeout;
private int potentialTargetTimeout;
private int newSpawnTimeout;
private boolean ignoreFriends;
private boolean ignoreClanMates;
private boolean markNewPlayer;
@Getter(AccessLevel.PACKAGE)
private boolean drawTargetPrayAgainst;
@Getter(AccessLevel.PACKAGE)
private boolean drawPotentialTargetPrayAgainst;
@Getter(AccessLevel.PACKAGE)
private boolean drawTargetPrayAgainstPrayerTab;
@Getter(AccessLevel.PACKAGE)
private boolean drawTargetsName;
@Getter(AccessLevel.PACKAGE)
private boolean drawPotentialTargetsName;
@Getter(AccessLevel.PACKAGE)
private boolean drawTargetHighlight;
@Getter(AccessLevel.PACKAGE)
private boolean drawPotentialTargetHighlight;
@Getter(AccessLevel.PACKAGE)
private boolean drawTargetTile;
@Getter(AccessLevel.PACKAGE)
private boolean drawPotentialTargetTile;
@Getter(AccessLevel.PACKAGE)
private boolean drawUnknownWeapons;
@Provides
PrayAgainstPlayerConfig provideConfig(ConfigManager configManager)
@@ -140,22 +73,10 @@ public class PrayAgainstPlayerPlugin extends Plugin
return configManager.getConfig(PrayAgainstPlayerConfig.class);
}
@Subscribe
private void onGameStateChanged(GameStateChanged gameStateChanged)
{
if (gameStateChanged.getGameState() == GameState.LOGGED_IN)
{
loadProtectionIcons();
}
}
@Override
protected void startUp()
{
updateConfig();
potentialPlayersAttackingMe = new ArrayList<>();
playersAttackingMe = new ArrayList<>();
overlayManager.add(overlay);
overlayManager.add(overlayPrayerTab);
}
@@ -167,253 +88,6 @@ public class PrayAgainstPlayerPlugin extends Plugin
overlayManager.remove(overlayPrayerTab);
}
@Subscribe
private void onAnimationChanged(AnimationChanged animationChanged)
{
if ((animationChanged.getActor() instanceof Player) && (animationChanged.getActor().getInteracting() instanceof Player) && (animationChanged.getActor().getInteracting() == client.getLocalPlayer()))
{
Player sourcePlayer = (Player) animationChanged.getActor();
// is the client is a friend/clan and the config is set to ignore friends/clan dont add them to list
if (client.isFriended(sourcePlayer.getName(), true) && this.ignoreFriends)
{
return;
}
if (client.isClanMember(sourcePlayer.getName()) && this.ignoreClanMates)
{
return;
}
if ((sourcePlayer.getAnimation() != -1) && (!isBlockAnimation(sourcePlayer.getAnimation())))
{
// if attacker attacks again, reset his timer so overlay doesn't go away
if (findPlayerInAttackerList(sourcePlayer) != null)
{
resetPlayerFromAttackerContainerTimer(findPlayerInAttackerList(sourcePlayer));
}
// if he attacks and he was in the potential attackers list, remove him
if (!potentialPlayersAttackingMe.isEmpty() && potentialPlayersAttackingMe.contains(findPlayerInPotentialList(sourcePlayer)))
{
removePlayerFromPotentialContainer(findPlayerInPotentialList(sourcePlayer));
}
// if he's not in the attackers list, add him
if (findPlayerInAttackerList(sourcePlayer) == null)
{
PlayerContainer container = new PlayerContainer(sourcePlayer, System.currentTimeMillis(), (this.attackerTargetTimeout * 1000));
playersAttackingMe.add(container);
}
}
}
}
@Subscribe
private void onInteractingChanged(InteractingChanged interactingChanged)
{
// if someone interacts with you, add them to the potential attackers list
if ((interactingChanged.getSource() instanceof Player) && (interactingChanged.getTarget() instanceof Player))
{
Player sourcePlayer = (Player) interactingChanged.getSource();
Player targetPlayer = (Player) interactingChanged.getTarget();
if ((targetPlayer == client.getLocalPlayer()) && (findPlayerInPotentialList(sourcePlayer) == null))
{ //we're being interacted with
// is the client is a friend/clan and the config is set to ignore friends/clan dont add them to list
if (client.isFriended(sourcePlayer.getName(), true) && this.ignoreFriends)
{
return;
}
if (client.isClanMember(sourcePlayer.getName()) && this.ignoreClanMates)
{
return;
}
PlayerContainer container = new PlayerContainer(sourcePlayer, System.currentTimeMillis(), (this.potentialTargetTimeout * 1000));
potentialPlayersAttackingMe.add(container);
}
}
}
@Subscribe
private void onPlayerDespawned(PlayerDespawned playerDespawned)
{
PlayerContainer container = findPlayerInAttackerList(playerDespawned.getPlayer());
PlayerContainer container2 = findPlayerInPotentialList(playerDespawned.getPlayer());
if (container != null)
{
playersAttackingMe.remove(container);
}
if (container2 != null)
{
potentialPlayersAttackingMe.remove(container2);
}
}
@Subscribe
private void onPlayerSpawned(PlayerSpawned playerSpawned)
{
if (this.markNewPlayer)
{
Player p = playerSpawned.getPlayer();
if (client.isFriended(p.getName(), true) && this.ignoreFriends)
{
return;
}
if (client.isClanMember(p.getName()) && this.ignoreClanMates)
{
return;
}
PlayerContainer container = findPlayerInPotentialList(p);
if (container == null)
{
container = new PlayerContainer(p, System.currentTimeMillis(), (this.newSpawnTimeout * 1000));
potentialPlayersAttackingMe.add(container);
}
}
}
private PlayerContainer findPlayerInAttackerList(Player player)
{
if (playersAttackingMe.isEmpty())
{
return null;
}
for (PlayerContainer container : playersAttackingMe)
{
if (container.getPlayer() == player)
{
return container;
}
}
return null;
}
private PlayerContainer findPlayerInPotentialList(Player player)
{
if (potentialPlayersAttackingMe.isEmpty())
{
return null;
}
for (PlayerContainer container : potentialPlayersAttackingMe)
{
if (container.getPlayer() == player)
{
return container;
}
}
return null;
}
/**
* Resets player timer in case he attacks again, so his highlight doesn't go away so easily
*
* @param container
*/
private void resetPlayerFromAttackerContainerTimer(PlayerContainer container)
{
removePlayerFromAttackerContainer(container);
PlayerContainer newContainer = new PlayerContainer(container.getPlayer(), System.currentTimeMillis(), (this.attackerTargetTimeout * 1000));
playersAttackingMe.add(newContainer);
}
void removePlayerFromPotentialContainer(PlayerContainer container)
{
if ((potentialPlayersAttackingMe != null) && (!potentialPlayersAttackingMe.isEmpty()))
{
potentialPlayersAttackingMe.remove(container);
}
}
void removePlayerFromAttackerContainer(PlayerContainer container)
{
if ((playersAttackingMe != null) && (!playersAttackingMe.isEmpty()))
{
playersAttackingMe.remove(container);
}
}
private boolean isBlockAnimation(int anim)
{
switch (anim)
{
case AnimationID.BLOCK_DEFENDER:
case AnimationID.BLOCK_NO_SHIELD:
case AnimationID.BLOCK_SHIELD:
case AnimationID.BLOCK_SWORD:
case AnimationID.BLOCK_UNARMED:
return true;
default:
return false;
}
}
List<PlayerContainer> getPotentialPlayersAttackingMe()
{
return potentialPlayersAttackingMe;
}
List<PlayerContainer> getPlayersAttackingMe()
{
return playersAttackingMe;
}
//All of the methods below are from the Zulrah plugin!!! Credits to it's respective owner
private void loadProtectionIcons()
{
for (int i = 0; i < PROTECTION_ICONS.length; i++)
{
final int resource = PROTECTION_ICONS[i];
ProtectionIcons[i] = rgbaToIndexedBufferedImage(ProtectionIconFromSprite(spriteManager.getSprite(resource, 0)));
}
}
private static BufferedImage rgbaToIndexedBufferedImage(final BufferedImage sourceBufferedImage)
{
final BufferedImage indexedImage = new BufferedImage(
sourceBufferedImage.getWidth(),
sourceBufferedImage.getHeight(),
BufferedImage.TYPE_BYTE_INDEXED);
final ColorModel cm = indexedImage.getColorModel();
final IndexColorModel icm = (IndexColorModel) cm;
final int size = icm.getMapSize();
final byte[] reds = new byte[size];
final byte[] greens = new byte[size];
final byte[] blues = new byte[size];
icm.getReds(reds);
icm.getGreens(greens);
icm.getBlues(blues);
final WritableRaster raster = indexedImage.getRaster();
final int pixel = raster.getSample(0, 0, 0);
final IndexColorModel resultIcm = new IndexColorModel(8, size, reds, greens, blues, pixel);
final BufferedImage resultIndexedImage = new BufferedImage(resultIcm, raster, sourceBufferedImage.isAlphaPremultiplied(), null);
resultIndexedImage.getGraphics().drawImage(sourceBufferedImage, 0, 0, null);
return resultIndexedImage;
}
private static BufferedImage ProtectionIconFromSprite(final BufferedImage freezeSprite)
{
final BufferedImage freezeCanvas = ImageUtil.resizeCanvas(freezeSprite, PROTECTION_ICON_DIMENSION.width, PROTECTION_ICON_DIMENSION.height);
return ImageUtil.outlineImage(freezeCanvas, PROTECTION_ICON_OUTLINE_COLOR);
}
BufferedImage getProtectionIcon(WeaponType weaponType)
{
switch (weaponType)
{
case WEAPON_RANGED:
return ProtectionIcons[0];
case WEAPON_MELEE:
return ProtectionIcons[1];
case WEAPON_MAGIC:
return ProtectionIcons[2];
}
return null;
}
@Subscribe
private void onConfigChanged(ConfigChanged event)
{
@@ -427,23 +101,17 @@ public class PrayAgainstPlayerPlugin extends Plugin
private void updateConfig()
{
this.attackerPlayerColor = config.attackerPlayerColor();
this.potentialPlayerColor = config.potentialPlayerColor();
this.attackerTargetTimeout = config.attackerTargetTimeout();
this.potentialTargetTimeout = config.potentialTargetTimeout();
this.newSpawnTimeout = config.newSpawnTimeout();
this.ignoreFriends = config.ignoreFriends();
this.ignoreClanMates = config.ignoreClanMates();
this.markNewPlayer = config.markNewPlayer();
this.drawTargetPrayAgainst = config.drawTargetPrayAgainst();
this.drawPotentialTargetPrayAgainst = config.drawPotentialTargetPrayAgainst();
this.drawTargetPrayAgainstPrayerTab = config.drawTargetPrayAgainstPrayerTab();
this.drawTargetsName = config.drawTargetsName();
this.drawPotentialTargetsName = config.drawPotentialTargetsName();
this.drawTargetHighlight = config.drawTargetHighlight();
this.drawPotentialTargetHighlight = config.drawPotentialTargetHighlight();
this.drawTargetTile = config.drawTargetTile();
this.drawPotentialTargetTile = config.drawPotentialTargetTile();
this.drawUnknownWeapons = config.drawUnknownWeapons();
if (this.drawTargetPrayAgainstPrayerTab)
{
overlayManager.add(overlayPrayerTab);
}
else
{
overlayManager.remove(overlayPrayerTab);
}
}
}

View File

@@ -1,140 +0,0 @@
/*
* Copyright (c) 2019, gazivodag <https://github.com/gazivodag>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.prayagainstplayer;
import net.runelite.api.Client;
import net.runelite.api.ItemDefinition;
import net.runelite.api.Player;
import net.runelite.api.kit.KitType;
enum WeaponType
{
WEAPON_MELEE,
WEAPON_RANGED,
WEAPON_MAGIC,
WEAPON_UNKNOWN;
/**
* im fully aware this could of been done better!!!
*
* @param client
* @param attacker
* @return
*/
public static WeaponType checkWeaponOnPlayer(Client client, Player attacker)
{
int itemId = attacker.getPlayerAppearance().getEquipmentId(KitType.WEAPON);
ItemDefinition itemComposition = client.getItemDefinition(itemId);
String weaponNameGivenLowerCase = itemComposition.getName().toLowerCase();
if (itemId == -1)
{
return WEAPON_MELEE;
}
if (weaponNameGivenLowerCase.toLowerCase().contains("null"))
{
return WEAPON_MELEE;
}
for (String meleeWeaponName : meleeWeaponNames)
{
if (weaponNameGivenLowerCase.contains(meleeWeaponName) && !weaponNameGivenLowerCase.contains("thrownaxe"))
{
return WEAPON_MELEE;
}
}
for (String rangedWeaponName : rangedWeaponNames)
{
if (weaponNameGivenLowerCase.contains(rangedWeaponName))
{
return WEAPON_RANGED;
}
}
for (String magicWeaponName : magicWeaponNames)
{
if (weaponNameGivenLowerCase.contains(magicWeaponName))
{
return WEAPON_MAGIC;
}
}
return WEAPON_UNKNOWN;
}
private static final String[] meleeWeaponNames = {
"sword",
"scimitar",
"dagger",
"spear",
"mace",
"axe",
"whip",
"tentacle",
"-ket-",
"-xil-",
"warhammer",
"halberd",
"claws",
"hasta",
"scythe",
"maul",
"anchor",
"sabre",
"excalibur",
"machete",
"dragon hunter lance",
"event rpg",
"silverlight",
"darklight",
"arclight",
"flail",
"granite hammer",
"rapier",
"bulwark"
};
private static final String[] rangedWeaponNames = {
"bow",
"blowpipe",
"xil-ul",
"knife",
"dart",
"thrownaxe",
"chinchompa",
"ballista"
};
private static final String[] magicWeaponNames = {
"staff",
"trident",
"wand",
"dawnbringer"
};
}

View File

@@ -45,12 +45,14 @@ import static net.runelite.api.SkullIcon.DEAD_MAN_TWO;
import static net.runelite.api.SkullIcon.SKULL;
import static net.runelite.api.SkullIcon.SKULL_FIGHT_PIT;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.events.PlayerAppearanceChanged;
import net.runelite.api.mixins.Copy;
import net.runelite.api.mixins.Inject;
import net.runelite.api.mixins.MethodHook;
import net.runelite.api.mixins.Mixin;
import net.runelite.api.mixins.Replace;
import net.runelite.api.mixins.Shadow;
import net.runelite.rs.api.RSBuffer;
import net.runelite.rs.api.RSClient;
import net.runelite.rs.api.RSModel;
import net.runelite.rs.api.RSPlayer;
@@ -236,4 +238,20 @@ public abstract class RSPlayerMixin implements RSPlayer
{
friended = client.getFriendManager().isFriended(getRsName(), false);
}
@Copy("read")
public abstract void rs$read(RSBuffer buffer);
@Replace("read")
public void rl$read(RSBuffer buffer)
{
final long appearanceHash = getPlayerAppearance() == null ? 0 : getPlayerAppearance().getHash();
rs$read(buffer);
if (getPlayerAppearance().getHash() != appearanceHash)
{
client.getCallbacks().post(PlayerAppearanceChanged.class, new PlayerAppearanceChanged(this));
}
}
}

View File

@@ -11,6 +11,9 @@ public interface RSPlayerAppearance extends PlayerAppearance
@Import("bodyColors")
int[] getBodyPartColours();
@Import("hash")
long getHash();
@Import("equipment")
@Override
int[] getEquipmentIds();

View File

@@ -41,7 +41,8 @@ public class PlayerAppearance {
@ObfuscatedGetter(
longValue = 8570520165784208047L
)
long field2547;
@Export("hash")
long hash;
@ObfuscatedName("p")
@ObfuscatedGetter(
longValue = -3088053679670010611L
@@ -186,40 +187,47 @@ public class PlayerAppearance {
garbageValue = "1306042907"
)
@Export("setHash")
void setHash() {
long var1 = this.field2547;
void setHash()
{
long var1 = this.hash;
int var3 = this.equipment[5];
int var4 = this.equipment[9];
this.equipment[5] = var4;
this.equipment[9] = var3;
this.field2547 = 0L;
this.hash = 0L;
int var5;
for (var5 = 0; var5 < 12; ++var5) {
this.field2547 <<= 4;
if (this.equipment[var5] >= 256) {
this.field2547 += (long)(this.equipment[var5] - 256);
for (var5 = 0; var5 < 12; ++var5)
{
this.hash <<= 4;
if (this.equipment[var5] >= 256)
{
this.hash += (long) (this.equipment[var5] - 256);
}
}
if (this.equipment[0] >= 256) {
this.field2547 += (long)(this.equipment[0] - 256 >> 4);
if (this.equipment[0] >= 256)
{
this.hash += (long) (this.equipment[0] - 256 >> 4);
}
if (this.equipment[1] >= 256) {
this.field2547 += (long)(this.equipment[1] - 256 >> 8);
if (this.equipment[1] >= 256)
{
this.hash += (long) (this.equipment[1] - 256 >> 8);
}
for (var5 = 0; var5 < 5; ++var5) {
this.field2547 <<= 3;
this.field2547 += (long)this.bodyColors[var5];
for (var5 = 0; var5 < 5; ++var5)
{
this.hash <<= 3;
this.hash += (long) this.bodyColors[var5];
}
this.field2547 <<= 1;
this.field2547 += (long)(this.isFemale ? 1 : 0);
this.hash <<= 1;
this.hash += (long) (this.isFemale ? 1 : 0);
this.equipment[5] = var3;
this.equipment[9] = var4;
if (0L != var1 && this.field2547 != var1) {
if (0L != var1 && this.hash != var1)
{
PlayerAppearance_cachedModels.remove(var1);
}
@@ -234,18 +242,22 @@ public class PlayerAppearance {
public Model getModel(SequenceDefinition var1, int var2, SequenceDefinition var3, int var4) {
if (this.npcTransformId != -1) {
return VarcInt.getNpcDefinition(this.npcTransformId).getModel(var1, var2, var3, var4);
} else {
long var5 = this.field2547;
} else
{
long var5 = this.hash;
int[] var7 = this.equipment;
if (var1 != null && (var1.shield >= 0 || var1.weapon >= 0)) {
if (var1 != null && (var1.shield >= 0 || var1.weapon >= 0))
{
var7 = new int[12];
for (int var15 = 0; var15 < 12; ++var15) {
for (int var15 = 0; var15 < 12; ++var15)
{
var7[var15] = this.equipment[var15];
}
if (var1.shield >= 0) {
var5 += (long)(var1.shield - this.equipment[5] << 40);
if (var1.shield >= 0)
{
var5 += (long) (var1.shield - this.equipment[5] << 40);
var7[5] = var1.shield;
}