Merge branch 'upstream-master' into runelite

# Conflicts:
#	runelite-client/src/main/java/net/runelite/client/plugins/tearsofguthix/TearsOfGuthixOverlay.java
#	runelite-client/src/main/java/net/runelite/client/plugins/tearsofguthix/TearsOfGuthixPlugin.java
This commit is contained in:
zeruth
2021-01-25 00:21:50 -05:00
58 changed files with 482 additions and 86 deletions

View File

@@ -28,20 +28,74 @@ import java.awt.Color;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.ConfigSection;
import net.runelite.client.config.Range;
@ConfigGroup("inventorytags")
@ConfigGroup(InventoryTagsConfig.GROUP)
public interface InventoryTagsConfig extends Config
{
enum DisplayMode
{
OUTLINE,
UNDERLINE
}
String GROUP = "inventorytags";
@ConfigSection(
name = "Tag display mode",
description = "How tags are displayed in the inventory",
position = 0
)
String tagStyleSection = "tagStyleSection";
@ConfigItem(
position = 0,
keyName = "showTagOutline",
name = "Outline",
description = "Configures whether or not item tags show be outlined",
section = tagStyleSection
)
default boolean showTagOutline()
{
return true;
}
@ConfigItem(
position = 1,
keyName = "tagUnderline",
name = "Underline",
description = "Configures whether or not item tags should be underlined",
section = tagStyleSection
)
default boolean showTagUnderline()
{
return false;
}
@ConfigItem(
position = 2,
keyName = "tagFill",
name = "Fill",
description = "Configures whether or not item tags should be filled",
section = tagStyleSection
)
default boolean showTagFill()
{
return false;
}
@Range(
max = 255
)
@ConfigItem(
position = 3,
keyName = "fillOpacity",
name = "Fill opacity",
description = "Configures the opacity of the tag \"Fill\"",
section = tagStyleSection
)
default int fillOpacity()
{
return 50;
}
@ConfigItem(
position = 1,
keyName = "groupColor1",
name = "Group 1 Color",
description = "Color of the Tag"
@@ -52,7 +106,7 @@ public interface InventoryTagsConfig extends Config
}
@ConfigItem(
position = 1,
position = 2,
keyName = "groupColor2",
name = "Group 2 Color",
description = "Color of the Tag"
@@ -63,7 +117,7 @@ public interface InventoryTagsConfig extends Config
}
@ConfigItem(
position = 2,
position = 3,
keyName = "groupColor3",
name = "Group 3 Color",
description = "Color of the Tag"
@@ -74,7 +128,7 @@ public interface InventoryTagsConfig extends Config
}
@ConfigItem(
position = 3,
position = 4,
keyName = "groupColor4",
name = "Group 4 Color",
description = "Color of the Tag"
@@ -85,7 +139,7 @@ public interface InventoryTagsConfig extends Config
}
@ConfigItem(
position = 4,
position = 5,
keyName = "groupColor5",
name = "Group 5 Color",
description = "Color of the Tag"
@@ -96,7 +150,7 @@ public interface InventoryTagsConfig extends Config
}
@ConfigItem(
position = 5,
position = 6,
keyName = "groupColor6",
name = "Group 6 Color",
description = "Color of the Tag"
@@ -105,15 +159,4 @@ public interface InventoryTagsConfig extends Config
{
return new Color(0, 255, 255);
}
@ConfigItem(
position = 6,
keyName = "displayMode",
name = "Display mode",
description = "How tags are displayed in the inventory"
)
default DisplayMode getDisplayMode()
{
return DisplayMode.OUTLINE;
}
}

View File

@@ -24,21 +24,26 @@
*/
package net.runelite.client.plugins.inventorytags;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import javax.inject.Inject;
import net.runelite.api.widgets.WidgetItem;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.inventorytags.InventoryTagsConfig.DisplayMode;
import net.runelite.client.ui.overlay.WidgetItemOverlay;
import net.runelite.client.util.ColorUtil;
import net.runelite.client.util.ImageUtil;
public class InventoryTagsOverlay extends WidgetItemOverlay
{
private final ItemManager itemManager;
private final InventoryTagsPlugin plugin;
private final InventoryTagsConfig config;
private final Cache<Long, Image> fillCache;
@Inject
private InventoryTagsOverlay(ItemManager itemManager, InventoryTagsPlugin plugin, InventoryTagsConfig config)
@@ -48,6 +53,10 @@ public class InventoryTagsOverlay extends WidgetItemOverlay
this.config = config;
showOnEquipment();
showOnInventory();
fillCache = CacheBuilder.newBuilder()
.concurrencyLevel(1)
.maximumSize(32)
.build();
}
@Override
@@ -57,16 +66,22 @@ public class InventoryTagsOverlay extends WidgetItemOverlay
if (group != null)
{
final Color color = plugin.getGroupNameColor(group);
final DisplayMode displayMode = config.getDisplayMode();
if (color != null)
{
Rectangle bounds = widgetItem.getCanvasBounds();
if (displayMode == DisplayMode.OUTLINE)
if (config.showTagOutline())
{
final BufferedImage outline = itemManager.getItemOutline(itemId, widgetItem.getQuantity(), color);
graphics.drawImage(outline, (int) bounds.getX(), (int) bounds.getY(), null);
}
else
if (config.showTagFill())
{
final Image image = getFillImage(color, widgetItem.getId(), widgetItem.getQuantity());
graphics.drawImage(image, (int) bounds.getX(), (int) bounds.getY(), null);
}
if (config.showTagUnderline())
{
int heightOffSet = (int) bounds.getY() + (int) bounds.getHeight() + 2;
graphics.setColor(color);
@@ -75,4 +90,22 @@ public class InventoryTagsOverlay extends WidgetItemOverlay
}
}
}
private Image getFillImage(Color color, int itemId, int qty)
{
long key = (((long) itemId) << 32) | qty;
Image image = fillCache.getIfPresent(key);
if (image == null)
{
final Color fillColor = ColorUtil.colorWithAlpha(color, config.fillOpacity());
image = ImageUtil.fillImage(itemManager.getImage(itemId, qty, false), fillColor);
fillCache.put(key, image);
}
return image;
}
void invalidateCache()
{
fillCache.invalidateAll();
}
}

View File

@@ -39,6 +39,7 @@ import net.runelite.api.events.WidgetMenuOptionClicked;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.menus.MenuManager;
import net.runelite.client.menus.WidgetMenuOption;
import net.runelite.client.plugins.Plugin;
@@ -147,6 +148,15 @@ public class InventoryTagsPlugin extends Plugin
editorMode = false;
}
@Subscribe
public void onConfigChanged(ConfigChanged configChanged)
{
if (configChanged.getGroup().equals(InventoryTagsConfig.GROUP))
{
overlay.invalidateCache();
}
}
@Subscribe
public void onWidgetMenuOptionClicked(final WidgetMenuOptionClicked event)
{

View File

@@ -60,7 +60,7 @@ import net.runelite.client.ws.WSClient;
@PluginDescriptor(
name = "Special Attack Counter",
description = "Track DWH, Arclight, Darklight, and BGS special attacks used on NPCs",
description = "Track special attacks used on NPCs",
tags = {"combat", "npcs", "overlay"},
enabledByDefault = false
)

View File

@@ -37,7 +37,13 @@ enum SpecialWeapon
ARCLIGHT("Arclight", ItemID.ARCLIGHT, false, SpecialCounterConfig::arclightThreshold),
DARKLIGHT("Darklight", ItemID.DARKLIGHT, false, SpecialCounterConfig::darklightThreshold),
BANDOS_GODSWORD("Bandos Godsword", ItemID.BANDOS_GODSWORD, true, SpecialCounterConfig::bandosGodswordThreshold),
BANDOS_GODSWORD_OR("Bandos Godsword", ItemID.BANDOS_GODSWORD_OR, true, SpecialCounterConfig::bandosGodswordThreshold);
BANDOS_GODSWORD_OR("Bandos Godsword", ItemID.BANDOS_GODSWORD_OR, true, SpecialCounterConfig::bandosGodswordThreshold),
BARRELCHEST_ANCHOR("Barrelchest Anchor", ItemID.BARRELCHEST_ANCHOR, true, (c) -> 0),
BONE_DAGGER("Bone Dagger", ItemID.BONE_DAGGER, true, (c) -> 0),
BONE_DAGGER_P("Bone Dagger (p)", ItemID.BONE_DAGGER_P, true, (c) -> 0),
BONE_DAGGER_P8876("Bone Dagger (p+)", ItemID.BONE_DAGGER_P_8876, true, (c) -> 0),
BONE_DAGGER_P8878("Bone Dagger (p++)", ItemID.BONE_DAGGER_P_8878, true, (c) -> 0),
DORGESHUUN_CROSSBOW("Dorgeshuun Crossbow", ItemID.DORGESHUUN_CROSSBOW, true, (c) -> 0);
private final String name;
private final int itemID;

View File

@@ -39,7 +39,7 @@ import net.runelite.client.ui.overlay.OverlayPriority;
import net.runelite.client.ui.overlay.components.ComponentOrientation;
import net.runelite.client.ui.overlay.components.ImageComponent;
public class TeamCapesOverlay extends OverlayPanel
class TeamCapesOverlay extends OverlayPanel
{
private final TeamCapesPlugin plugin;
private final TeamCapesConfig config;

View File

@@ -25,21 +25,24 @@
package net.runelite.client.plugins.teamcapes;
import com.google.inject.Provides;
import java.time.temporal.ChronoUnit;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.inject.Inject;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.Player;
import net.runelite.api.events.PlayerChanged;
import net.runelite.api.events.PlayerDespawned;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.task.Schedule;
import net.runelite.client.ui.overlay.OverlayManager;
@PluginDescriptor(
@@ -48,19 +51,26 @@ import net.runelite.client.ui.overlay.OverlayManager;
tags = {"overlay", "players"},
enabledByDefault = false
)
@Slf4j
public class TeamCapesPlugin extends Plugin
{
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private OverlayManager overlayManager;
@Inject
private TeamCapesOverlay overlay;
// Hashmap of team capes: Key is the teamCape #, Value is the count of teamcapes in the area.
private Map<Integer, Integer> teams = new HashMap<>();
// Team number -> Number of players
@Getter(AccessLevel.PACKAGE)
private Map<Integer, Integer> teams = new LinkedHashMap<>();
// Player -> Team number
private final Map<Player, Integer> playerTeam = new HashMap<>();
@Provides
TeamCapesConfig provideConfig(ConfigManager configManager)
@@ -72,6 +82,8 @@ public class TeamCapesPlugin extends Plugin
protected void startUp() throws Exception
{
overlayManager.add(overlay);
clientThread.invokeLater(() -> client.getPlayers().forEach(this::update));
}
@Override
@@ -79,48 +91,61 @@ public class TeamCapesPlugin extends Plugin
{
overlayManager.remove(overlay);
teams.clear();
playerTeam.clear();
}
@Schedule(
period = 1800,
unit = ChronoUnit.MILLIS
)
public void update()
@Subscribe
public void onPlayerChanged(PlayerChanged playerChanged)
{
if (client.getGameState() != GameState.LOGGED_IN)
Player player = playerChanged.getPlayer();
update(player);
}
private void update(Player player)
{
int oldTeam = playerTeam.getOrDefault(player, 0);
if (oldTeam == player.getTeam())
{
return;
}
List<Player> players = client.getPlayers();
teams.clear();
for (Player player : players)
log.debug("{} has changed teams: {} -> {}", player.getName(), oldTeam, player.getTeam());
if (oldTeam > 0)
{
int team = player.getTeam();
if (team > 0)
{
if (teams.containsKey(team))
{
teams.put(team, teams.get(team) + 1);
}
else
{
teams.put(team, 1);
}
}
teams.computeIfPresent(oldTeam, (key, value) -> value > 1 ? value - 1 : null);
playerTeam.remove(player);
}
if (player.getTeam() > 0)
{
teams.merge(player.getTeam(), 1, Integer::sum);
playerTeam.put(player, player.getTeam());
}
sort();
}
@Subscribe
public void onPlayerDespawned(PlayerDespawned playerDespawned)
{
Player player = playerDespawned.getPlayer();
Integer team = playerTeam.remove(player);
if (team != null)
{
teams.computeIfPresent(team, (key, value) -> value > 1 ? value - 1 : null);
sort();
}
}
private void sort()
{
// Sort teams by value in descending order and then by key in ascending order, limited to 5 entries
teams = teams.entrySet().stream()
.sorted(
Comparator.comparing(Map.Entry<Integer, Integer>::getValue, Comparator.reverseOrder())
.thenComparingInt(Map.Entry::getKey)
)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
.sorted(
Comparator.comparing(Map.Entry<Integer, Integer>::getValue, Comparator.reverseOrder())
.thenComparingInt(Map.Entry::getKey)
)
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new));
}
public Map<Integer, Integer> getTeams()
{
return teams;
}
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2020, cgati <https://github.com/cgati>
* 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.tearsofguthix;
import java.awt.Color;
import net.runelite.client.config.Alpha;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.util.ColorUtil;
@ConfigGroup("tearsofguthix")
public interface TearsOfGuthixConfig extends Config
{
@ConfigItem(
keyName = "showGreenTearsTimer",
name = "Enable Green Tears Timer",
description = "Configures whether to display a timer for green tears or not",
position = 1
)
default boolean showGreenTearsTimer()
{
return true;
}
@Alpha
@ConfigItem(
keyName = "blueTearsColor",
name = "Blue Tears Color",
description = "Color of Blue Tears timer",
position = 2
)
default Color getBlueTearsColor()
{
return ColorUtil.colorWithAlpha(Color.CYAN, 100);
}
@Alpha
@ConfigItem(
keyName = "greenTearsColor",
name = "Green Tears Color",
description = "Color of Green Tears timer",
position = 3
)
default Color getGreenTearsColor()
{
return ColorUtil.colorWithAlpha(Color.GREEN, 100);
}
}

View File

@@ -36,17 +36,18 @@ 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.components.ProgressPieComponent;
import net.runelite.client.util.ColorUtil;
class TearsOfGuthixOverlay extends Overlay
{
private static final Color CYAN_ALPHA = new Color(Color.CYAN.getRed(), Color.CYAN.getGreen(), Color.CYAN.getBlue(), 100);
private static final Color GREEN_ALPHA = new Color(Color.GREEN.getRed(), Color.GREEN.getGreen(), Color.GREEN.getBlue(), 100);
private static final Duration MAX_TIME = Duration.ofSeconds(9);
private final TearsOfGuthixConfig config;
private final TearsOfGuthixPlugin plugin;
@Inject
private TearsOfGuthixOverlay(TearsOfGuthixPlugin plugin)
private TearsOfGuthixOverlay(TearsOfGuthixConfig config, TearsOfGuthixPlugin plugin)
{
this.config = config;
this.plugin = plugin;
setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.ABOVE_SCENE);
@@ -55,8 +56,24 @@ class TearsOfGuthixOverlay extends Overlay
@Override
public Dimension render(Graphics2D graphics)
{
if (plugin.getStreams().isEmpty())
{
return null;
}
Color blueTearsFill = config.getBlueTearsColor();
Color greenTearsFill = config.getGreenTearsColor();
Color blueTearsBorder = ColorUtil.colorWithAlpha(blueTearsFill, 255);
Color greenTearsBorder = ColorUtil.colorWithAlpha(greenTearsFill, 255);
plugin.getStreams().forEach((object, timer) ->
{
if ((object.getId() == ObjectID.GREEN_TEARS || object.getId() == ObjectID.GREEN_TEARS_6666)
&& !config.showGreenTearsTimer())
{
return;
}
final Point position = object.getCanvasLocation(100);
if (position == null)
@@ -70,14 +87,14 @@ class TearsOfGuthixOverlay extends Overlay
if (object.getId() == ObjectID.BLUE_TEARS ||
object.getId() == ObjectID.BLUE_TEARS_6665)
{
progressPie.setFill(CYAN_ALPHA);
progressPie.setBorderColor(Color.CYAN);
progressPie.setFill(blueTearsFill);
progressPie.setBorderColor(blueTearsBorder);
}
else if (object.getId() == ObjectID.GREEN_TEARS ||
object.getId() == ObjectID.GREEN_TEARS_6666)
{
progressPie.setFill(GREEN_ALPHA);
progressPie.setBorderColor(Color.GREEN);
progressPie.setFill(greenTearsFill);
progressPie.setBorderColor(greenTearsBorder);
}
progressPie.setPosition(position);

View File

@@ -28,6 +28,7 @@ import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import javax.inject.Inject;
import com.google.inject.Provides;
import lombok.Getter;
import net.runelite.api.Client;
import net.runelite.api.DecorativeObject;
@@ -35,6 +36,7 @@ import net.runelite.api.ObjectID;
import net.runelite.api.events.DecorativeObjectDespawned;
import net.runelite.api.events.DecorativeObjectSpawned;
import net.runelite.api.events.GameStateChanged;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
@@ -61,6 +63,12 @@ public class TearsOfGuthixPlugin extends Plugin
@Getter
private final Map<DecorativeObject, Instant> streams = new HashMap<>();
@Provides
TearsOfGuthixConfig provideConfig(ConfigManager configManager)
{
return configManager.getConfig(TearsOfGuthixConfig.class);
}
@Override
protected void startUp()
{

View File

@@ -89,11 +89,22 @@ public interface XpGlobesConfig extends Config
return false;
}
@ConfigItem(
keyName = "showVirtualLevel",
name = "Show virtual level",
description = "Shows virtual level if over 99 in a skill and Hide maxed skill is not checked",
position = 5
)
default boolean showVirtualLevel()
{
return false;
}
@ConfigItem(
keyName = "enableCustomArcColor",
name = "Enable custom arc color",
description = "Enables the custom coloring of the globe's arc instead of using the skill's default color.",
position = 5
position = 6
)
default boolean enableCustomArcColor()
{
@@ -105,7 +116,7 @@ public interface XpGlobesConfig extends Config
keyName = "Progress arc color",
name = "Progress arc color",
description = "Change the color of the progress arc in the xp orb",
position = 6
position = 7
)
default Color progressArcColor()
{
@@ -117,7 +128,7 @@ public interface XpGlobesConfig extends Config
keyName = "Progress orb outline color",
name = "Progress orb outline color",
description = "Change the color of the progress orb outline",
position = 7
position = 8
)
default Color progressOrbOutLineColor()
{
@@ -129,7 +140,7 @@ public interface XpGlobesConfig extends Config
keyName = "Progress orb background color",
name = "Progress orb background color",
description = "Change the color of the progress orb background",
position = 8
position = 9
)
default Color progressOrbBackgroundColor()
{
@@ -140,7 +151,7 @@ public interface XpGlobesConfig extends Config
keyName = "Progress arc width",
name = "Progress arc width",
description = "Change the stroke width of the progress arc",
position = 9
position = 10
)
@Units(Units.PIXELS)
default int progressArcStrokeWidth()
@@ -152,7 +163,7 @@ public interface XpGlobesConfig extends Config
keyName = "Orb size",
name = "Size of orbs",
description = "Change the size of the xp orbs",
position = 10
position = 11
)
@Units(Units.PIXELS)
default int xpOrbSize()
@@ -164,7 +175,7 @@ public interface XpGlobesConfig extends Config
keyName = "Orb duration",
name = "Duration of orbs",
description = "Change the duration the xp orbs are visible",
position = 11
position = 12
)
@Units(Units.SECONDS)
default int xpOrbDuration()

View File

@@ -106,9 +106,17 @@ public class XpGlobesPlugin extends Plugin
return;
}
if (config.hideMaxed() && currentLevel >= Experience.MAX_REAL_LEVEL)
if (currentLevel >= Experience.MAX_REAL_LEVEL)
{
return;
if (config.hideMaxed())
{
return;
}
if (config.showVirtualLevel())
{
currentLevel = Experience.getLevelForXp(currentXp);
}
}
if (cachedGlobe != null)

View File

@@ -395,8 +395,9 @@ public class ImageUtil
{
for (int y = 0; y < filledImage.getHeight(); y++)
{
final Color pixelColor = new Color(image.getRGB(x, y), true);
if (pixelColor.getAlpha() == 0)
int pixel = image.getRGB(x, y);
int a = pixel >>> 24;
if (a == 0)
{
continue;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 958 B

After

Width:  |  Height:  |  Size: 876 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 969 B

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 648 B

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 697 B

After

Width:  |  Height:  |  Size: 594 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 364 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 745 B

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 952 B

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 985 B

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 910 B

After

Width:  |  Height:  |  Size: 471 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 B

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 998 B

After

Width:  |  Height:  |  Size: 616 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 977 B

After

Width:  |  Height:  |  Size: 861 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 881 B

After

Width:  |  Height:  |  Size: 863 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 697 B

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 688 B

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 697 B

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 368 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 890 B

After

Width:  |  Height:  |  Size: 531 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 904 B

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 884 B

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 766 B

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 807 B

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 848 B

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 720 B

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 800 B

After

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 811 B

After

Width:  |  Height:  |  Size: 609 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 648 B

After

Width:  |  Height:  |  Size: 627 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 884 B

After

Width:  |  Height:  |  Size: 488 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 706 B

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 994 B

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 823 B

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 909 B

After

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 788 B

After

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 700 B

After

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 868 B

After

Width:  |  Height:  |  Size: 583 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 764 B

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 882 B

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 728 B

After

Width:  |  Height:  |  Size: 391 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 957 B

After

Width:  |  Height:  |  Size: 873 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 929 B

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 489 B

After

Width:  |  Height:  |  Size: 374 B

View File

@@ -0,0 +1,162 @@
/*
* Copyright (c) 2021, Wright <eqomatic@gmail.com>
* 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.xpglobes;
import com.google.inject.Guice;
import com.google.inject.testing.fieldbinder.Bind;
import com.google.inject.testing.fieldbinder.BoundFieldModule;
import javax.inject.Inject;
import net.runelite.api.Experience;
import net.runelite.api.Skill;
import net.runelite.api.events.StatChanged;
import net.runelite.client.plugins.xptracker.XpTrackerService;
import net.runelite.client.ui.overlay.OverlayManager;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class XpGlobesPluginTest
{
private static final int VIRTUAL_LEVEL_TOTAL_XP = Experience.getXpForLevel(Experience.MAX_REAL_LEVEL + 1);
@Inject
private XpGlobesPlugin xpGlobesPlugin;
@Mock
@Bind
private OverlayManager overlayManager;
@Mock
@Bind
private XpGlobesOverlay xpGlobesOverlay;
@Mock
@Bind
private XpTrackerService xpTrackerService;
@Mock
@Bind
private XpGlobesConfig xpGlobesConfig;
@Before
public void before()
{
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
statChanged(VIRTUAL_LEVEL_TOTAL_XP, Skill.AGILITY);
assertTrue(xpGlobesPlugin.getXpGlobes().isEmpty());
}
@Test
public void testVirtualLevelInGlobeIsNotShownByDefault()
{
when(xpGlobesConfig.showVirtualLevel()).thenReturn(false);
statChanged(VIRTUAL_LEVEL_TOTAL_XP + 1, Skill.AGILITY);
assertEquals(Experience.MAX_REAL_LEVEL, xpGlobesPlugin.getXpGlobes().get(0).getCurrentLevel());
}
@Test
public void testVirtualLevelInGlobeIsShownWhenConfigured()
{
when(xpGlobesConfig.showVirtualLevel()).thenReturn(true);
statChanged(VIRTUAL_LEVEL_TOTAL_XP + 1, Skill.AGILITY);
assertEquals(Experience.getLevelForXp(VIRTUAL_LEVEL_TOTAL_XP + 1), xpGlobesPlugin.getXpGlobes().get(0).getCurrentLevel());
}
@Test
public void testGlobeIsNotShownWhenHideMaxAndShowVirtualLevelConfigured()
{
when(xpGlobesConfig.hideMaxed()).thenReturn(true);
lenient().when(xpGlobesConfig.showVirtualLevel()).thenReturn(true);
statChanged(VIRTUAL_LEVEL_TOTAL_XP + 1, Skill.AGILITY);
assertTrue(xpGlobesPlugin.getXpGlobes().isEmpty());
}
@Test
public void testGlobeIsNotShownWhenHideMaxConfigured()
{
when(xpGlobesConfig.hideMaxed()).thenReturn(true);
statChanged(VIRTUAL_LEVEL_TOTAL_XP + 1, Skill.AGILITY);
assertTrue(xpGlobesPlugin.getXpGlobes().isEmpty());
}
@Test
public void testGlobeIsShownOnXpGainBelowMaxWhenHideMaxConfigured()
{
lenient().when(xpGlobesConfig.hideMaxed()).thenReturn(true);
int totalXp = 1;
statChanged(totalXp, Skill.FARMING);
assertTrue(xpGlobesPlugin.getXpGlobes().isEmpty());
statChanged(totalXp + 150, Skill.FARMING);
assertEquals(Experience.getLevelForXp(totalXp + 150), xpGlobesPlugin.getXpGlobes().get(0).getCurrentLevel());
}
@Test
public void testStatChangesFromBoostDoNotAffectXpGlobes()
{
statChanged(VIRTUAL_LEVEL_TOTAL_XP, Skill.AGILITY, 5);
assertTrue(xpGlobesPlugin.getXpGlobes().isEmpty());
}
private void statChanged(int totalXp, Skill skill)
{
statChanged(totalXp, skill, 0);
}
private void statChanged(int totalXp, Skill skill, int boostedLevel)
{
// A statChanged event uses the max real level
int statChangedLevel = Math.min(Experience.getLevelForXp(totalXp), Experience.MAX_REAL_LEVEL);
StatChanged firstStatChangedEvent = new StatChanged(
skill,
totalXp,
statChangedLevel,
boostedLevel
);
// The first xp change is cached
xpGlobesPlugin.onStatChanged(firstStatChangedEvent);
}
}