Merge remote-tracking branch 'runelite/master'
This commit is contained in:
@@ -27,6 +27,7 @@ package net.runelite.client.plugins.chatcommands;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
@@ -90,6 +91,7 @@ import net.runelite.client.hiscore.Skill;
|
||||
import net.runelite.client.input.KeyManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.util.AsyncBufferedImage;
|
||||
import net.runelite.client.util.ImageUtil;
|
||||
import net.runelite.client.util.QuantityFormatter;
|
||||
import net.runelite.client.util.Text;
|
||||
@@ -106,7 +108,7 @@ import org.apache.commons.text.WordUtils;
|
||||
@Slf4j
|
||||
public class ChatCommandsPlugin extends Plugin
|
||||
{
|
||||
private static final Pattern KILLCOUNT_PATTERN = Pattern.compile("Your (?:completion count for |subdued |completed )?(.+?) (?:(?:kill|harvest|lap|completion) )?(?:count )?is: <col=ff0000>(\\d+)</col>");
|
||||
private static final Pattern KILLCOUNT_PATTERN = Pattern.compile("Your (?<pre>completion count for |subdued |completed )?(?<boss>.+?) (?<post>(?:(?:kill|harvest|lap|completion) )?(?:count )?)is: <col=ff0000>(?<kc>\\d+)</col>");
|
||||
private static final String TEAM_SIZES = "(?<teamsize>\\d+(?:\\+|-\\d+)? players?|Solo)";
|
||||
private static final Pattern RAIDS_PB_PATTERN = Pattern.compile("<col=ef20ff>Congratulations - your raid is complete!</col><br>Team size: <col=ff0000>" + TEAM_SIZES + "</col> Duration:</col> <col=ff0000>(?<pb>[0-9:]+(?:\\.[0-9]+)?)</col> \\(new personal best\\)</col>");
|
||||
private static final Pattern RAIDS_DURATION_PATTERN = Pattern.compile("<col=ef20ff>Congratulations - your raid is complete!</col><br>Team size: <col=ff0000>" + TEAM_SIZES + "</col> Duration:</col> <col=ff0000>[0-9:.]+</col> Personal best: </col><col=ff0000>(?<pb>[0-9:]+(?:\\.[0-9]+)?)</col>");
|
||||
@@ -220,7 +222,15 @@ public class ChatCommandsPlugin extends Plugin
|
||||
chatCommandManager.registerCommandAsync(SOUL_WARS_ZEAL_COMMAND, this::soulWarsZealLookup);
|
||||
chatCommandManager.registerCommandAsync(PET_LIST_COMMAND, this::petListLookup, this::petListSubmit);
|
||||
|
||||
clientThread.invoke(this::loadPetIcons);
|
||||
clientThread.invoke(() ->
|
||||
{
|
||||
if (client.getModIcons() == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
loadPetIcons();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -295,13 +305,14 @@ public class ChatCommandsPlugin extends Plugin
|
||||
|
||||
private void loadPetIcons()
|
||||
{
|
||||
final IndexedSprite[] modIcons = client.getModIcons();
|
||||
if (modIconIdx != -1 || modIcons == null)
|
||||
if (modIconIdx != -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final Pet[] pets = Pet.values();
|
||||
final IndexedSprite[] modIcons = client.getModIcons();
|
||||
assert modIcons != null;
|
||||
final IndexedSprite[] newModIcons = Arrays.copyOf(modIcons, modIcons.length + pets.length);
|
||||
modIconIdx = modIcons.length;
|
||||
|
||||
@@ -309,9 +320,16 @@ public class ChatCommandsPlugin extends Plugin
|
||||
{
|
||||
final Pet pet = pets[i];
|
||||
|
||||
final BufferedImage image = ImageUtil.resizeImage(itemManager.getImage(pet.getIconID()), 18, 16);
|
||||
final IndexedSprite sprite = ImageUtil.getImageIndexedSprite(image, client);
|
||||
newModIcons[modIconIdx + i] = sprite;
|
||||
final AsyncBufferedImage abi = itemManager.getImage(pet.getIconID());
|
||||
final int idx = modIconIdx + i;
|
||||
Runnable r = () ->
|
||||
{
|
||||
final BufferedImage image = ImageUtil.resizeImage(abi, 18, 16);
|
||||
final IndexedSprite sprite = ImageUtil.getImageIndexedSprite(image, client);
|
||||
newModIcons[idx] = sprite;
|
||||
};
|
||||
abi.onLoaded(r);
|
||||
r.run();
|
||||
}
|
||||
|
||||
client.setModIcons(newModIcons);
|
||||
@@ -371,8 +389,16 @@ public class ChatCommandsPlugin extends Plugin
|
||||
Matcher matcher = KILLCOUNT_PATTERN.matcher(message);
|
||||
if (matcher.find())
|
||||
{
|
||||
String boss = matcher.group(1);
|
||||
int kc = Integer.parseInt(matcher.group(2));
|
||||
final String boss = matcher.group("boss");
|
||||
final int kc = Integer.parseInt(matcher.group("kc"));
|
||||
final String pre = matcher.group("pre");
|
||||
final String post = matcher.group("post");
|
||||
|
||||
if (Strings.isNullOrEmpty(pre) && Strings.isNullOrEmpty(post))
|
||||
{
|
||||
unsetKc(boss);
|
||||
return;
|
||||
}
|
||||
|
||||
String renamedBoss = KILLCOUNT_RENAMES
|
||||
.getOrDefault(boss, boss)
|
||||
@@ -784,9 +810,6 @@ public class ChatCommandsPlugin extends Plugin
|
||||
case HOPPING:
|
||||
pohOwner = null;
|
||||
break;
|
||||
case LOGGED_IN:
|
||||
loadPetIcons();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -164,4 +164,15 @@ public interface ChatFilterConfig extends Config
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "stripAccents",
|
||||
name = "Strip accents",
|
||||
description = "Remove accents before applying filters",
|
||||
position = 13
|
||||
)
|
||||
default boolean stripAccents()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ public class ChatFilterPlugin extends Plugin
|
||||
{
|
||||
String strippedMessage = jagexPrintableCharMatcher.retainFrom(message)
|
||||
.replace('\u00A0', ' ');
|
||||
String strippedAccents = StringUtils.stripAccents(strippedMessage);
|
||||
String strippedAccents = stripAccents(strippedMessage);
|
||||
assert strippedMessage.length() == strippedAccents.length();
|
||||
|
||||
if (username != null && shouldFilterByName(username))
|
||||
@@ -377,23 +377,28 @@ public class ChatFilterPlugin extends Plugin
|
||||
filteredNamePatterns.clear();
|
||||
|
||||
Text.fromCSV(config.filteredWords()).stream()
|
||||
.map(StringUtils::stripAccents)
|
||||
.map(this::stripAccents)
|
||||
.map(s -> Pattern.compile(Pattern.quote(s), Pattern.CASE_INSENSITIVE))
|
||||
.forEach(filteredPatterns::add);
|
||||
|
||||
NEWLINE_SPLITTER.splitToList(config.filteredRegex()).stream()
|
||||
.map(StringUtils::stripAccents)
|
||||
.map(this::stripAccents)
|
||||
.map(ChatFilterPlugin::compilePattern)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(filteredPatterns::add);
|
||||
|
||||
NEWLINE_SPLITTER.splitToList(config.filteredNames()).stream()
|
||||
.map(StringUtils::stripAccents)
|
||||
.map(this::stripAccents)
|
||||
.map(ChatFilterPlugin::compilePattern)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(filteredNamePatterns::add);
|
||||
}
|
||||
|
||||
private String stripAccents(String input)
|
||||
{
|
||||
return config.stripAccents() ? StringUtils.stripAccents(input) : input;
|
||||
}
|
||||
|
||||
private static Pattern compilePattern(String pattern)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -70,7 +70,20 @@ public class ClueScrollOverlay extends OverlayPanel
|
||||
item(KANDARIN_HEADGEAR_4),
|
||||
item(BRUMA_TORCH),
|
||||
item(MAX_CAPE),
|
||||
item(MAX_CAPE_13342));
|
||||
item(MAX_CAPE_13342),
|
||||
item(ABYSSAL_LANTERN_NORMAL_LOGS),
|
||||
item(ABYSSAL_LANTERN_BLUE_LOGS),
|
||||
item(ABYSSAL_LANTERN_RED_LOGS),
|
||||
item(ABYSSAL_LANTERN_WHITE_LOGS),
|
||||
item(ABYSSAL_LANTERN_PURPLE_LOGS),
|
||||
item(ABYSSAL_LANTERN_GREEN_LOGS),
|
||||
item(ABYSSAL_LANTERN_OAK_LOGS),
|
||||
item(ABYSSAL_LANTERN_WILLOW_LOGS),
|
||||
item(ABYSSAL_LANTERN_MAPLE_LOGS),
|
||||
item(ABYSSAL_LANTERN_YEW_LOGS),
|
||||
item(ABYSSAL_LANTERN_BLISTERWOOD_LOGS),
|
||||
item(ABYSSAL_LANTERN_MAGIC_LOGS),
|
||||
item(ABYSSAL_LANTERN_REDWOOD_LOGS));
|
||||
|
||||
public static final Color TITLED_CONTENT_COLOR = new Color(190, 190, 190);
|
||||
|
||||
|
||||
@@ -230,8 +230,8 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc
|
||||
.build(),
|
||||
AnagramClue.builder()
|
||||
.text("DEKAGRAM")
|
||||
.npc("Dark mage")
|
||||
.location(new WorldPoint(3039, 4835, 0))
|
||||
.npc("Dark Mage")
|
||||
.location(new WorldPoint(3039, 4834, 0))
|
||||
.area("Centre of the Abyss")
|
||||
.question("How many rifts are found here in the abyss?")
|
||||
.answer("13")
|
||||
|
||||
@@ -37,7 +37,6 @@ import net.runelite.api.IndexedSprite;
|
||||
import net.runelite.api.MessageNode;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.api.events.OverheadTextChanged;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
@@ -67,27 +66,27 @@ public class EmojiPlugin extends Plugin
|
||||
@Override
|
||||
protected void startUp()
|
||||
{
|
||||
clientThread.invoke(this::loadEmojiIcons);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameStateChanged(GameStateChanged gameStateChanged)
|
||||
{
|
||||
if (gameStateChanged.getGameState() == GameState.LOGGED_IN)
|
||||
clientThread.invoke(() ->
|
||||
{
|
||||
if (client.getModIcons() == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
loadEmojiIcons();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void loadEmojiIcons()
|
||||
{
|
||||
final IndexedSprite[] modIcons = client.getModIcons();
|
||||
if (modIconsStart != -1 || modIcons == null)
|
||||
if (modIconsStart != -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final Emoji[] emojis = Emoji.values();
|
||||
final IndexedSprite[] modIcons = client.getModIcons();
|
||||
assert modIcons != null;
|
||||
final IndexedSprite[] newModIcons = Arrays.copyOf(modIcons, modIcons.length + emojis.length);
|
||||
modIconsStart = modIcons.length;
|
||||
|
||||
|
||||
@@ -44,7 +44,6 @@ import net.runelite.api.IndexedSprite;
|
||||
import net.runelite.api.MenuAction;
|
||||
import net.runelite.api.Nameable;
|
||||
import net.runelite.api.ScriptID;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.api.events.MenuEntryAdded;
|
||||
import net.runelite.api.events.NameableNameChanged;
|
||||
import net.runelite.api.events.RemovedFriend;
|
||||
@@ -116,7 +115,15 @@ public class FriendNotesPlugin extends Plugin
|
||||
protected void startUp() throws Exception
|
||||
{
|
||||
overlayManager.add(overlay);
|
||||
clientThread.invoke(this::loadIcon);
|
||||
clientThread.invoke(() ->
|
||||
{
|
||||
if (client.getModIcons() == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
loadIcon();
|
||||
return true;
|
||||
});
|
||||
if (client.getGameState() == GameState.LOGGED_IN)
|
||||
{
|
||||
rebuildFriendsList();
|
||||
@@ -135,15 +142,6 @@ public class FriendNotesPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameStateChanged(GameStateChanged event)
|
||||
{
|
||||
if (event.getGameState() == GameState.LOGGED_IN)
|
||||
{
|
||||
loadIcon();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onConfigChanged(ConfigChanged event)
|
||||
{
|
||||
@@ -380,8 +378,7 @@ public class FriendNotesPlugin extends Plugin
|
||||
|
||||
private void loadIcon()
|
||||
{
|
||||
final IndexedSprite[] modIcons = client.getModIcons();
|
||||
if (iconIdx != -1 || modIcons == null)
|
||||
if (iconIdx != -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -394,6 +391,8 @@ public class FriendNotesPlugin extends Plugin
|
||||
|
||||
final BufferedImage resized = ImageUtil.resizeImage(iconImg, ICON_WIDTH, ICON_HEIGHT);
|
||||
|
||||
final IndexedSprite[] modIcons = client.getModIcons();
|
||||
assert modIcons != null;
|
||||
final IndexedSprite[] newIcons = Arrays.copyOf(modIcons, modIcons.length + 1);
|
||||
newIcons[newIcons.length - 1] = ImageUtil.getImageIndexedSprite(resized, client);
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ public enum MagicAction implements SkillAction
|
||||
FIRE_BLAST("Fire Blast", 59, 34.5f, SpriteID.SPELL_FIRE_BLAST),
|
||||
MARK_OF_DARKNESS("Mark of Darkness", 59, 70, SpriteID.SPELL_MARK_OF_DARKNESS),
|
||||
SENNTISTEN_TELEPORT("Senntisten Teleport", 60, 70, SpriteID.SPELL_SENNTISTEN_TELEPORT),
|
||||
CLAWS_OF_GUTHIX("Claws Of Guthix", 60, 35, SpriteID.SPELL_CLAWS_OF_GUTHIC),
|
||||
CLAWS_OF_GUTHIX("Claws Of Guthix", 60, 35, SpriteID.SPELL_CLAWS_OF_GUTHIX),
|
||||
FLAMES_OF_ZAMORAK("Flames Of Zamorak", 60, 35, SpriteID.SPELL_FLAMES_OF_ZAMORAK),
|
||||
SARADOMIN_STRIKE("Saradomin Strike", 60, 35, SpriteID.SPELL_SARADOMIN_STRIKE),
|
||||
CHARGE_EARTH_ORB("Charge Earth Orb", 60, 70, SpriteID.SPELL_CHARGE_EARTH_ORB),
|
||||
|
||||
@@ -29,9 +29,9 @@ import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.MenuEntry;
|
||||
@@ -39,8 +39,8 @@ import net.runelite.api.Point;
|
||||
import net.runelite.api.Prayer;
|
||||
import net.runelite.api.Skill;
|
||||
import net.runelite.api.SpriteID;
|
||||
import net.runelite.api.Varbits;
|
||||
import net.runelite.api.VarPlayer;
|
||||
import net.runelite.api.Varbits;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.client.game.AlternateSprites;
|
||||
@@ -86,10 +86,10 @@ class StatusBarsOverlay extends Overlay
|
||||
private final SpriteManager spriteManager;
|
||||
|
||||
private final Image prayerIcon;
|
||||
private final Image heartDisease;
|
||||
private final Image heartPoison;
|
||||
private final Image heartVenom;
|
||||
private Image heartIcon;
|
||||
private Image heartDisease;
|
||||
private Image heartPoison;
|
||||
private Image heartVenom;
|
||||
private Image specialIcon;
|
||||
private Image energyIcon;
|
||||
private final Map<BarMode, BarRenderer> barRenderers = new EnumMap<>(BarMode.class);
|
||||
@@ -106,6 +106,10 @@ class StatusBarsOverlay extends Overlay
|
||||
this.spriteManager = spriteManager;
|
||||
|
||||
prayerIcon = ImageUtil.resizeCanvas(ImageUtil.resizeImage(skillIconManager.getSkillImage(Skill.PRAYER, true), IMAGE_SIZE, IMAGE_SIZE), ICON_DIMENSIONS.width, ICON_DIMENSIONS.height);
|
||||
heartDisease = ImageUtil.resizeCanvas(ImageUtil.loadImageResource(AlternateSprites.class, AlternateSprites.DISEASE_HEART), ICON_DIMENSIONS.width, ICON_DIMENSIONS.height);
|
||||
heartPoison = ImageUtil.resizeCanvas(ImageUtil.loadImageResource(AlternateSprites.class, AlternateSprites.POISON_HEART), ICON_DIMENSIONS.width, ICON_DIMENSIONS.height);
|
||||
heartVenom = ImageUtil.resizeCanvas(ImageUtil.loadImageResource(AlternateSprites.class, AlternateSprites.VENOM_HEART), ICON_DIMENSIONS.width, ICON_DIMENSIONS.height);
|
||||
|
||||
initRenderers();
|
||||
}
|
||||
|
||||
@@ -321,16 +325,28 @@ class StatusBarsOverlay extends Overlay
|
||||
|
||||
private void buildIcons()
|
||||
{
|
||||
if (heartIcon != null && heartDisease != null && heartPoison != null && heartVenom != null && energyIcon != null && specialIcon != null)
|
||||
if (heartIcon == null)
|
||||
{
|
||||
return;
|
||||
heartIcon = loadAndResize(SpriteID.MINIMAP_ORB_HITPOINTS_ICON);
|
||||
}
|
||||
if (energyIcon == null)
|
||||
{
|
||||
energyIcon = loadAndResize(SpriteID.MINIMAP_ORB_WALK_ICON);
|
||||
}
|
||||
if (specialIcon == null)
|
||||
{
|
||||
specialIcon = loadAndResize(SpriteID.MINIMAP_ORB_SPECIAL_ICON);
|
||||
}
|
||||
}
|
||||
|
||||
private BufferedImage loadAndResize(int spriteId)
|
||||
{
|
||||
BufferedImage image = spriteManager.getSprite(spriteId, 0);
|
||||
if (image == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
heartIcon = ImageUtil.resizeCanvas(Objects.requireNonNull(spriteManager.getSprite(SpriteID.MINIMAP_ORB_HITPOINTS_ICON, 0)), ICON_DIMENSIONS.width, ICON_DIMENSIONS.height);
|
||||
heartDisease = ImageUtil.resizeCanvas(ImageUtil.loadImageResource(AlternateSprites.class, AlternateSprites.DISEASE_HEART), ICON_DIMENSIONS.width, ICON_DIMENSIONS.height);
|
||||
heartPoison = ImageUtil.resizeCanvas(ImageUtil.loadImageResource(AlternateSprites.class, AlternateSprites.POISON_HEART), ICON_DIMENSIONS.width, ICON_DIMENSIONS.height);
|
||||
heartVenom = ImageUtil.resizeCanvas(ImageUtil.loadImageResource(AlternateSprites.class, AlternateSprites.VENOM_HEART), ICON_DIMENSIONS.width, ICON_DIMENSIONS.height);
|
||||
energyIcon = ImageUtil.resizeCanvas(Objects.requireNonNull(spriteManager.getSprite(SpriteID.MINIMAP_ORB_WALK_ICON, 0)), ICON_DIMENSIONS.width, ICON_DIMENSIONS.height);
|
||||
specialIcon = ImageUtil.resizeCanvas(Objects.requireNonNull(spriteManager.getSprite(SpriteID.MINIMAP_ORB_SPECIAL_ICON, 0)), ICON_DIMENSIONS.width, ICON_DIMENSIONS.height);
|
||||
return ImageUtil.resizeCanvas(image, ICON_DIMENSIONS.width, ICON_DIMENSIONS.height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,6 @@ public class TimersPlugin extends Plugin
|
||||
private static final int NMZ_MAP_REGION_ID = 9033;
|
||||
private static final Pattern TZHAAR_WAVE_MESSAGE = Pattern.compile("Wave: (\\d+)");
|
||||
private static final String TZHAAR_DEFEATED_MESSAGE = "You have been defeated!";
|
||||
private static final Pattern TZHAAR_COMPLETE_MESSAGE = Pattern.compile("Your (?:TzTok-Jad|TzKal-Zuk) kill count is:");
|
||||
private static final Pattern TZHAAR_PAUSED_MESSAGE = Pattern.compile("The (?:Inferno|Fight Cave) has been paused. You may now log out.");
|
||||
|
||||
private TimerTimer freezeTimer;
|
||||
@@ -776,7 +775,7 @@ public class TimersPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
if (message.equals(TZHAAR_DEFEATED_MESSAGE) || TZHAAR_COMPLETE_MESSAGE.matcher(message).matches())
|
||||
if (message.equals(TZHAAR_DEFEATED_MESSAGE))
|
||||
{
|
||||
log.debug("Stopping tzhaar timer");
|
||||
removeTzhaarTimer();
|
||||
|
||||
@@ -43,6 +43,7 @@ public interface TimeTrackingConfig extends Config
|
||||
String PREFER_SOONEST = "preferSoonest";
|
||||
String NOTIFY = "notify";
|
||||
String BIRDHOUSE_NOTIFY = "birdHouseNotification";
|
||||
String COMPOST = "compost";
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "timeFormatMode",
|
||||
|
||||
@@ -44,6 +44,7 @@ import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.api.widgets.WidgetModalMode;
|
||||
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.events.RuneScapeProfileChanged;
|
||||
@@ -54,6 +55,7 @@ import static net.runelite.client.plugins.timetracking.TimeTrackingConfig.PREFER
|
||||
import static net.runelite.client.plugins.timetracking.TimeTrackingConfig.STOPWATCHES;
|
||||
import static net.runelite.client.plugins.timetracking.TimeTrackingConfig.TIMERS;
|
||||
import net.runelite.client.plugins.timetracking.clocks.ClockManager;
|
||||
import net.runelite.client.plugins.timetracking.farming.CompostTracker;
|
||||
import net.runelite.client.plugins.timetracking.farming.FarmingContractManager;
|
||||
import net.runelite.client.plugins.timetracking.farming.FarmingTracker;
|
||||
import net.runelite.client.plugins.timetracking.hunter.BirdHouseTracker;
|
||||
@@ -77,6 +79,12 @@ public class TimeTrackingPlugin extends Plugin
|
||||
@Inject
|
||||
private Client client;
|
||||
|
||||
@Inject
|
||||
private EventBus eventBus;
|
||||
|
||||
@Inject
|
||||
private CompostTracker compostTracker;
|
||||
|
||||
@Inject
|
||||
private FarmingTracker farmingTracker;
|
||||
|
||||
@@ -125,6 +133,8 @@ public class TimeTrackingPlugin extends Plugin
|
||||
birdHouseTracker.loadFromConfig();
|
||||
farmingTracker.loadCompletionTimes();
|
||||
|
||||
eventBus.register(compostTracker);
|
||||
|
||||
final BufferedImage icon = ImageUtil.loadImageResource(getClass(), "watch.png");
|
||||
|
||||
panel = injector.getInstance(TimeTrackingPanel.class);
|
||||
@@ -148,6 +158,8 @@ public class TimeTrackingPlugin extends Plugin
|
||||
lastTickLocation = null;
|
||||
lastTickPostLogin = false;
|
||||
|
||||
eventBus.unregister(compostTracker);
|
||||
|
||||
if (panelUpdateFuture != null)
|
||||
{
|
||||
panelUpdateFuture.cancel(true);
|
||||
|
||||
@@ -29,8 +29,11 @@ import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.image.BufferedImage;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
@@ -48,9 +51,20 @@ public class TimeablePanel<T> extends JPanel
|
||||
{
|
||||
private static final ImageIcon NOTIFY_ICON = new ImageIcon(ImageUtil.loadImageResource(TimeTrackingPlugin.class, "notify_icon.png"));
|
||||
private static final ImageIcon NOTIFY_SELECTED_ICON = new ImageIcon(ImageUtil.loadImageResource(TimeTrackingPlugin.class, "notify_selected_icon.png"));
|
||||
private static final Rectangle OVERLAY_ICON_BOUNDS;
|
||||
|
||||
static
|
||||
{
|
||||
int width = Constants.ITEM_SPRITE_WIDTH * 2 / 3;
|
||||
int height = Constants.ITEM_SPRITE_HEIGHT * 2 / 3;
|
||||
int x = Constants.ITEM_SPRITE_WIDTH - width;
|
||||
int y = Constants.ITEM_SPRITE_HEIGHT - height;
|
||||
OVERLAY_ICON_BOUNDS = new Rectangle(x, y, width, height);
|
||||
}
|
||||
|
||||
private final T timeable;
|
||||
private final JLabel icon = new JLabel();
|
||||
private final JLabel overlayIcon = new JLabel();
|
||||
private final JLabel farmingContractIcon = new JLabel();
|
||||
private final JToggleButton notifyButton = new JToggleButton();
|
||||
private final JLabel estimate = new JLabel();
|
||||
@@ -70,6 +84,7 @@ public class TimeablePanel<T> extends JPanel
|
||||
topContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
|
||||
icon.setMinimumSize(new Dimension(Constants.ITEM_SPRITE_WIDTH, Constants.ITEM_SPRITE_HEIGHT));
|
||||
overlayIcon.setMinimumSize(OVERLAY_ICON_BOUNDS.getSize());
|
||||
farmingContractIcon.setMinimumSize(new Dimension(Constants.ITEM_SPRITE_WIDTH, Constants.ITEM_SPRITE_HEIGHT));
|
||||
|
||||
JPanel infoPanel = new JPanel();
|
||||
@@ -105,8 +120,15 @@ public class TimeablePanel<T> extends JPanel
|
||||
iconPanel.add(notifyPanel, BorderLayout.EAST);
|
||||
iconPanel.add(farmingContractIcon, BorderLayout.WEST);
|
||||
|
||||
JLayeredPane layeredIconPane = new JLayeredPane();
|
||||
layeredIconPane.setPreferredSize(new Dimension(Constants.ITEM_SPRITE_WIDTH, Constants.ITEM_SPRITE_HEIGHT));
|
||||
layeredIconPane.add(icon, Integer.valueOf(0));
|
||||
layeredIconPane.add(overlayIcon, Integer.valueOf(1));
|
||||
icon.setBounds(0, 0, Constants.ITEM_SPRITE_WIDTH, Constants.ITEM_SPRITE_HEIGHT);
|
||||
overlayIcon.setBounds(OVERLAY_ICON_BOUNDS);
|
||||
|
||||
topContainer.add(iconPanel, BorderLayout.EAST);
|
||||
topContainer.add(icon, BorderLayout.WEST);
|
||||
topContainer.add(layeredIconPane, BorderLayout.WEST);
|
||||
topContainer.add(infoPanel, BorderLayout.CENTER);
|
||||
|
||||
progress.setValue(0);
|
||||
@@ -115,4 +137,21 @@ public class TimeablePanel<T> extends JPanel
|
||||
add(topContainer, BorderLayout.NORTH);
|
||||
add(progress, BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
public void setOverlayIconImage(BufferedImage overlayImg)
|
||||
{
|
||||
if (overlayImg == null)
|
||||
{
|
||||
overlayIcon.setIcon(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (OVERLAY_ICON_BOUNDS.width != overlayImg.getWidth() || OVERLAY_ICON_BOUNDS.height != overlayImg.getHeight())
|
||||
{
|
||||
overlayImg = ImageUtil.resizeImage(overlayImg, OVERLAY_ICON_BOUNDS.width, OVERLAY_ICON_BOUNDS.height);
|
||||
}
|
||||
|
||||
overlayIcon.setIcon(new ImageIcon(overlayImg));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2022 LlemonDuck
|
||||
* 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.timetracking.farming;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.runelite.api.ItemID;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum CompostState
|
||||
{
|
||||
|
||||
COMPOST(ItemID.COMPOST),
|
||||
SUPERCOMPOST(ItemID.SUPERCOMPOST),
|
||||
ULTRACOMPOST(ItemID.ULTRACOMPOST),
|
||||
;
|
||||
|
||||
private final int itemId;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright (c) 2022 LlemonDuck
|
||||
* 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.timetracking.farming;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Value;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameObject;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.api.ObjectComposition;
|
||||
import net.runelite.api.Tile;
|
||||
import net.runelite.api.annotations.Varbit;
|
||||
import net.runelite.api.coords.LocalPoint;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.api.events.MenuOptionClicked;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.eventbus.Subscribe;
|
||||
import net.runelite.client.plugins.timetracking.TimeTrackingConfig;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor(onConstructor = @__(@Inject))
|
||||
public class CompostTracker
|
||||
{
|
||||
|
||||
@Value
|
||||
@VisibleForTesting
|
||||
static class PendingCompost
|
||||
{
|
||||
Instant timeout;
|
||||
WorldPoint patchLocation;
|
||||
FarmingPatch farmingPatch;
|
||||
}
|
||||
|
||||
private static final Duration COMPOST_ACTION_TIMEOUT = Duration.ofSeconds(30);
|
||||
|
||||
private static final Pattern COMPOST_USED_ON_PATCH = Pattern.compile(
|
||||
"You treat the .+ with (?<compostType>ultra|super|)compost\\.");
|
||||
private static final Pattern FERTILE_SOIL_CAST = Pattern.compile(
|
||||
"The .+ has been treated with (?<compostType>ultra|super|)compost\\.");
|
||||
private static final Pattern ALREADY_TREATED = Pattern.compile(
|
||||
"This .+ has already been (treated|fertilised) with (?<compostType>ultra|super|)compost(?: - the spell can't make it any more fertile)?\\.");
|
||||
private static final Pattern INSPECT_PATCH = Pattern.compile(
|
||||
"This is an? .+\\. The soil has been treated with (?<compostType>ultra|super|)compost\\..*");
|
||||
|
||||
private static final ImmutableSet<Integer> COMPOST_ITEMS = ImmutableSet.of(
|
||||
ItemID.COMPOST,
|
||||
ItemID.SUPERCOMPOST,
|
||||
ItemID.ULTRACOMPOST,
|
||||
ItemID.BOTTOMLESS_COMPOST_BUCKET_22997
|
||||
);
|
||||
|
||||
private final Client client;
|
||||
private final FarmingWorld farmingWorld;
|
||||
private final ConfigManager configManager;
|
||||
|
||||
@VisibleForTesting
|
||||
final Map<FarmingPatch, PendingCompost> pendingCompostActions = new HashMap<>();
|
||||
|
||||
private static String configKey(FarmingPatch fp)
|
||||
{
|
||||
return fp.configKey() + "." + TimeTrackingConfig.COMPOST;
|
||||
}
|
||||
|
||||
public void setCompostState(FarmingPatch fp, CompostState state)
|
||||
{
|
||||
log.debug("Storing compost state [{}] for patch [{}]", state, fp);
|
||||
if (state == null)
|
||||
{
|
||||
configManager.unsetRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, configKey(fp));
|
||||
}
|
||||
else
|
||||
{
|
||||
configManager.setRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, configKey(fp), state);
|
||||
}
|
||||
}
|
||||
|
||||
public CompostState getCompostState(FarmingPatch fp)
|
||||
{
|
||||
return configManager.getRSProfileConfiguration(
|
||||
TimeTrackingConfig.CONFIG_GROUP,
|
||||
configKey(fp),
|
||||
CompostState.class
|
||||
);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onMenuOptionClicked(MenuOptionClicked e)
|
||||
{
|
||||
if (!isCompostAction(e))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ObjectComposition patchDef = client.getObjectDefinition(e.getId());
|
||||
WorldPoint actionLocation = WorldPoint.fromScene(client, e.getParam0(), e.getParam1(), client.getPlane());
|
||||
FarmingPatch targetPatch = farmingWorld.getRegionsForLocation(actionLocation)
|
||||
.stream()
|
||||
.flatMap(fr -> Arrays.stream(fr.getPatches()))
|
||||
.filter(fp -> fp.getVarbit() == patchDef.getVarbitId())
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (targetPatch == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
log.debug("Storing pending compost action for patch [{}]", targetPatch);
|
||||
PendingCompost pc = new PendingCompost(
|
||||
Instant.now().plus(COMPOST_ACTION_TIMEOUT),
|
||||
actionLocation,
|
||||
targetPatch
|
||||
);
|
||||
pendingCompostActions.put(targetPatch, pc);
|
||||
}
|
||||
|
||||
private boolean isCompostAction(MenuOptionClicked e)
|
||||
{
|
||||
switch (e.getMenuAction())
|
||||
{
|
||||
case WIDGET_TARGET_ON_GAME_OBJECT:
|
||||
Widget w = client.getSelectedWidget();
|
||||
assert w != null;
|
||||
return COMPOST_ITEMS.contains(w.getItemId()) || w.getId() == WidgetInfo.SPELL_LUNAR_FERTILE_SOIL.getPackedId();
|
||||
|
||||
case GAME_OBJECT_FIRST_OPTION:
|
||||
case GAME_OBJECT_SECOND_OPTION:
|
||||
case GAME_OBJECT_THIRD_OPTION:
|
||||
case GAME_OBJECT_FOURTH_OPTION:
|
||||
case GAME_OBJECT_FIFTH_OPTION:
|
||||
return "Inspect".equals(e.getMenuOption());
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onChatMessage(ChatMessage e)
|
||||
{
|
||||
if (e.getType() != ChatMessageType.GAMEMESSAGE && e.getType() != ChatMessageType.SPAM)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CompostState compostUsed = determineCompostUsed(e.getMessage());
|
||||
if (compostUsed == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.expirePendingActions();
|
||||
|
||||
pendingCompostActions.values()
|
||||
.stream()
|
||||
.filter(this::playerIsBesidePatch)
|
||||
.findFirst()
|
||||
.ifPresent(pc ->
|
||||
{
|
||||
setCompostState(pc.getFarmingPatch(), compostUsed);
|
||||
pendingCompostActions.remove(pc.getFarmingPatch());
|
||||
});
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameStateChanged(GameStateChanged e)
|
||||
{
|
||||
switch (e.getGameState())
|
||||
{
|
||||
case LOGGED_IN:
|
||||
case LOADING:
|
||||
return;
|
||||
|
||||
default:
|
||||
pendingCompostActions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean playerIsBesidePatch(PendingCompost pendingCompost)
|
||||
{
|
||||
// find gameobject instance in scene
|
||||
// it is possible that the scene has reloaded between use and action occurring so we use worldpoint
|
||||
// instead of storing scene coords in the menuoptionclicked event
|
||||
LocalPoint localPatchLocation = LocalPoint.fromWorld(client, pendingCompost.getPatchLocation());
|
||||
if (localPatchLocation == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Varbit int patchVarb = pendingCompost.getFarmingPatch().getVarbit();
|
||||
Tile patchTile = client.getScene()
|
||||
.getTiles()[client.getPlane()][localPatchLocation.getSceneX()][localPatchLocation.getSceneY()];
|
||||
GameObject patchObject = null;
|
||||
for (GameObject go : patchTile.getGameObjects())
|
||||
{
|
||||
if (go != null && client.getObjectDefinition(go.getId()).getVarbitId() == patchVarb)
|
||||
{
|
||||
patchObject = go;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert patchObject != null;
|
||||
|
||||
// player coords
|
||||
final WorldPoint playerPos = client.getLocalPlayer().getWorldLocation();
|
||||
final int playerX = playerPos.getX();
|
||||
final int playerY = playerPos.getY();
|
||||
|
||||
// patch coords
|
||||
final WorldPoint patchBase = pendingCompost.getPatchLocation();
|
||||
final int minX = patchBase.getX();
|
||||
final int minY = patchBase.getY();
|
||||
final int maxX = minX + patchObject.sizeX() - 1;
|
||||
final int maxY = minY + patchObject.sizeY() - 1;
|
||||
|
||||
// player should be within one tile of these coords
|
||||
return playerX >= (minX - 1) && playerX <= (maxX + 1) && playerY >= (minY - 1) && playerY <= (maxY + 1);
|
||||
}
|
||||
|
||||
private void expirePendingActions()
|
||||
{
|
||||
pendingCompostActions.values().removeIf(e -> Instant.now().isAfter(e.getTimeout()));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static CompostState determineCompostUsed(String chatMessage)
|
||||
{
|
||||
if (!chatMessage.contains("compost"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Matcher matcher;
|
||||
if ((matcher = COMPOST_USED_ON_PATCH.matcher(chatMessage)).matches() ||
|
||||
(matcher = FERTILE_SOIL_CAST.matcher(chatMessage)).matches() ||
|
||||
(matcher = ALREADY_TREATED.matcher(chatMessage)).matches() ||
|
||||
(matcher = INSPECT_PATCH.matcher(chatMessage)).matches())
|
||||
{
|
||||
String compostGroup = matcher.group("compostType");
|
||||
switch (compostGroup)
|
||||
{
|
||||
case "ultra":
|
||||
return CompostState.ULTRACOMPOST;
|
||||
case "super":
|
||||
return CompostState.SUPERCOMPOST;
|
||||
default:
|
||||
return CompostState.COMPOST;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import net.runelite.api.annotations.Varbit;
|
||||
import net.runelite.client.plugins.timetracking.TimeTrackingConfig;
|
||||
|
||||
@@ -35,13 +36,17 @@ import net.runelite.client.plugins.timetracking.TimeTrackingConfig;
|
||||
access = AccessLevel.PACKAGE
|
||||
)
|
||||
@Getter
|
||||
@ToString(onlyExplicitlyIncluded = true)
|
||||
class FarmingPatch
|
||||
{
|
||||
@Setter(AccessLevel.PACKAGE)
|
||||
@ToString.Include
|
||||
private FarmingRegion region;
|
||||
@ToString.Include
|
||||
private final String name;
|
||||
@Getter(onMethod_ = {@Varbit})
|
||||
private final int varbit;
|
||||
@ToString.Include
|
||||
private final PatchImplementation implementation;
|
||||
|
||||
String configKey()
|
||||
|
||||
@@ -43,10 +43,12 @@ import net.runelite.client.plugins.timetracking.TimeTrackingConfig;
|
||||
import net.runelite.client.plugins.timetracking.TimeablePanel;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.util.AsyncBufferedImage;
|
||||
|
||||
public class FarmingTabPanel extends TabContentPanel
|
||||
{
|
||||
private final FarmingTracker farmingTracker;
|
||||
private final CompostTracker compostTracker;
|
||||
private final ItemManager itemManager;
|
||||
private final ConfigManager configManager;
|
||||
private final TimeTrackingConfig config;
|
||||
@@ -55,6 +57,7 @@ public class FarmingTabPanel extends TabContentPanel
|
||||
|
||||
FarmingTabPanel(
|
||||
FarmingTracker farmingTracker,
|
||||
CompostTracker compostTracker,
|
||||
ItemManager itemManager,
|
||||
ConfigManager configManager,
|
||||
TimeTrackingConfig config,
|
||||
@@ -63,6 +66,7 @@ public class FarmingTabPanel extends TabContentPanel
|
||||
)
|
||||
{
|
||||
this.farmingTracker = farmingTracker;
|
||||
this.compostTracker = compostTracker;
|
||||
this.itemManager = itemManager;
|
||||
this.configManager = configManager;
|
||||
this.config = config;
|
||||
@@ -131,7 +135,6 @@ public class FarmingTabPanel extends TabContentPanel
|
||||
p.setBorder(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,10 +153,26 @@ public class FarmingTabPanel extends TabContentPanel
|
||||
FarmingPatch patch = panel.getTimeable();
|
||||
PatchPrediction prediction = farmingTracker.predictPatch(patch);
|
||||
|
||||
CompostState compostState = compostTracker.getCompostState(patch);
|
||||
String compostTooltip = "";
|
||||
if (compostState != null)
|
||||
{
|
||||
AsyncBufferedImage compostImg = itemManager.getImage(compostState.getItemId());
|
||||
Runnable compostOverlayRunnable = () -> panel.setOverlayIconImage(compostImg);
|
||||
compostImg.onLoaded(compostOverlayRunnable);
|
||||
compostOverlayRunnable.run();
|
||||
|
||||
compostTooltip = " with " + compostState.name().toLowerCase();
|
||||
}
|
||||
else
|
||||
{
|
||||
panel.setOverlayIconImage(null);
|
||||
}
|
||||
|
||||
if (prediction == null)
|
||||
{
|
||||
itemManager.getImage(Produce.WEEDS.getItemID()).addTo(panel.getIcon());
|
||||
panel.getIcon().setToolTipText("Unknown state");
|
||||
panel.getIcon().setToolTipText("Unknown state" + compostTooltip);
|
||||
panel.getProgress().setMaximumValue(0);
|
||||
panel.getProgress().setValue(0);
|
||||
panel.getProgress().setVisible(false);
|
||||
@@ -165,12 +184,12 @@ public class FarmingTabPanel extends TabContentPanel
|
||||
if (prediction.getProduce().getItemID() < 0)
|
||||
{
|
||||
panel.getIcon().setIcon(null);
|
||||
panel.getIcon().setToolTipText("Unknown state");
|
||||
panel.getIcon().setToolTipText("Unknown state" + compostTooltip);
|
||||
}
|
||||
else
|
||||
{
|
||||
itemManager.getImage(prediction.getProduce().getItemID()).addTo(panel.getIcon());
|
||||
panel.getIcon().setToolTipText(prediction.getProduce().getName());
|
||||
panel.getIcon().setToolTipText(prediction.getProduce().getName() + compostTooltip);
|
||||
}
|
||||
|
||||
switch (prediction.getCropState())
|
||||
|
||||
@@ -63,6 +63,7 @@ public class FarmingTracker
|
||||
private final TimeTrackingConfig config;
|
||||
private final FarmingWorld farmingWorld;
|
||||
private final Notifier notifier;
|
||||
private final CompostTracker compostTracker;
|
||||
|
||||
private final Map<Tab, SummaryState> summaries = new EnumMap<>(Tab.class);
|
||||
|
||||
@@ -78,7 +79,7 @@ public class FarmingTracker
|
||||
private boolean firstNotifyCheck = true;
|
||||
|
||||
@Inject
|
||||
private FarmingTracker(Client client, ItemManager itemManager, ConfigManager configManager, TimeTrackingConfig config, FarmingWorld farmingWorld, Notifier notifier)
|
||||
private FarmingTracker(Client client, ItemManager itemManager, ConfigManager configManager, TimeTrackingConfig config, FarmingWorld farmingWorld, Notifier notifier, CompostTracker compostTracker)
|
||||
{
|
||||
this.client = client;
|
||||
this.itemManager = itemManager;
|
||||
@@ -86,11 +87,12 @@ public class FarmingTracker
|
||||
this.config = config;
|
||||
this.farmingWorld = farmingWorld;
|
||||
this.notifier = notifier;
|
||||
this.compostTracker = compostTracker;
|
||||
}
|
||||
|
||||
public FarmingTabPanel createTabPanel(Tab tab, FarmingContractManager farmingContractManager)
|
||||
{
|
||||
return new FarmingTabPanel(this, itemManager, configManager, config, farmingWorld.getTabs().get(tab), farmingContractManager);
|
||||
return new FarmingTabPanel(this, compostTracker, itemManager, configManager, config, farmingWorld.getTabs().get(tab), farmingContractManager);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,6 +150,12 @@ public class FarmingTracker
|
||||
String strVarbit = Integer.toString(client.getVarbitValue(varbit));
|
||||
String storedValue = configManager.getRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, key);
|
||||
|
||||
PatchState currentPatchState = patch.getImplementation().forVarbitValue(client.getVarbitValue(varbit));
|
||||
if (currentPatchState == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (storedValue != null)
|
||||
{
|
||||
String[] parts = storedValue.split(":");
|
||||
@@ -172,9 +180,8 @@ public class FarmingTracker
|
||||
else if (!newRegionLoaded && timeSinceModalClose > 1)
|
||||
{
|
||||
PatchState previousPatchState = patch.getImplementation().forVarbitValue(Integer.parseInt(parts[0]));
|
||||
PatchState currentPatchState = patch.getImplementation().forVarbitValue(client.getVarbitValue(varbit));
|
||||
|
||||
if (previousPatchState == null || currentPatchState == null)
|
||||
if (previousPatchState == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -217,6 +224,11 @@ public class FarmingTracker
|
||||
}
|
||||
}
|
||||
|
||||
if (currentPatchState.getCropState() == CropState.DEAD || currentPatchState.getCropState() == CropState.HARVESTABLE)
|
||||
{
|
||||
compostTracker.setCompostState(patch, null);
|
||||
}
|
||||
|
||||
String value = strVarbit + ":" + unixNow;
|
||||
configManager.setRSProfileConfiguration(TimeTrackingConfig.CONFIG_GROUP, key, value);
|
||||
changed = true;
|
||||
|
||||
@@ -113,7 +113,7 @@ public enum Produce
|
||||
POTATO_CACTUS("Potato cactus", "Potato cacti", PatchImplementation.CACTUS, ItemID.POTATO_CACTUS, 10, 8, 5, 7),
|
||||
|
||||
// Hardwood
|
||||
TEAK("Teak", PatchImplementation.HARDWOOD_TREE, ItemID.TEAK_LOGS, 560, 8),
|
||||
TEAK("Teak", PatchImplementation.HARDWOOD_TREE, ItemID.TEAK_LOGS, 640, 8),
|
||||
MAHOGANY("Mahogany", PatchImplementation.HARDWOOD_TREE, ItemID.MAHOGANY_LOGS, 640, 9),
|
||||
|
||||
// Anima
|
||||
|
||||
@@ -66,12 +66,15 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.nullable;
|
||||
import org.mockito.Mock;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
@@ -1156,4 +1159,13 @@ public class ChatCommandsPluginTest
|
||||
|
||||
verify(configManager).setRSProfileConfiguration("killcount", "guardians of the rift", 167);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReward()
|
||||
{
|
||||
ChatMessage chatMessage = new ChatMessage(null, GAMEMESSAGE, "", "Your reward is: <col=ff0000>1</col> x <col=ff0000>Kebab</col>.", null, 0);
|
||||
chatCommandsPlugin.onChatMessage(chatMessage);
|
||||
|
||||
verify(configManager, never()).setRSProfileConfiguration(anyString(), anyString(), anyInt());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,6 +191,7 @@ public class ChatFilterPluginTest
|
||||
{
|
||||
when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_WORDS);
|
||||
when(chatFilterConfig.filteredWords()).thenReturn("filterme");
|
||||
when(chatFilterConfig.stripAccents()).thenReturn(true);
|
||||
|
||||
chatFilterPlugin.updateFilteredPatterns();
|
||||
assertEquals("plëäsë ******** plügïn", chatFilterPlugin.censorMessage("Blue", "plëäsë fïltërmë plügïn"));
|
||||
@@ -211,6 +212,7 @@ public class ChatFilterPluginTest
|
||||
{
|
||||
when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_WORDS);
|
||||
when(chatFilterConfig.filteredWords()).thenReturn("plëäsë, filterme");
|
||||
when(chatFilterConfig.stripAccents()).thenReturn(true);
|
||||
|
||||
chatFilterPlugin.updateFilteredPatterns();
|
||||
assertEquals("****** ******** plügïn", chatFilterPlugin.censorMessage("Blue", "plëäsë fïltërmë plügïn"));
|
||||
|
||||
@@ -28,24 +28,27 @@ import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.testing.fieldbinder.Bind;
|
||||
import com.google.inject.testing.fieldbinder.BoundFieldModule;
|
||||
import java.util.function.BooleanSupplier;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.IndexedSprite;
|
||||
import net.runelite.api.MessageNode;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.client.callback.ClientThread;
|
||||
import net.runelite.client.chat.ChatMessageManager;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import org.mockito.Mock;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class EmojiPluginTest
|
||||
@@ -58,6 +61,10 @@ public class EmojiPluginTest
|
||||
@Bind
|
||||
private ChatMessageManager chatMessageManager;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private ClientThread clientThread;
|
||||
|
||||
@Inject
|
||||
private EmojiPlugin emojiPlugin;
|
||||
|
||||
@@ -65,19 +72,23 @@ public class EmojiPluginTest
|
||||
public void before()
|
||||
{
|
||||
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
|
||||
|
||||
when(client.getModIcons()).thenReturn(new IndexedSprite[0]);
|
||||
when(client.createIndexedSprite()).thenReturn(mock(IndexedSprite.class));
|
||||
|
||||
doAnswer(a ->
|
||||
{
|
||||
final BooleanSupplier b = a.getArgument(0);
|
||||
return b.getAsBoolean();
|
||||
}).when(clientThread).invoke(any(BooleanSupplier.class));
|
||||
|
||||
emojiPlugin.startUp();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnChatMessage()
|
||||
{
|
||||
when(client.getGameState()).thenReturn(GameState.LOGGED_IN);
|
||||
when(client.getModIcons()).thenReturn(new IndexedSprite[0]);
|
||||
when(client.createIndexedSprite()).thenReturn(mock(IndexedSprite.class));
|
||||
|
||||
// Trip emoji loading
|
||||
GameStateChanged gameStateChanged = new GameStateChanged();
|
||||
gameStateChanged.setGameState(GameState.LOGGED_IN);
|
||||
emojiPlugin.onGameStateChanged(gameStateChanged);
|
||||
|
||||
MessageNode messageNode = mock(MessageNode.class);
|
||||
// With chat recolor, message may be wrapped in col tags
|
||||
@@ -96,13 +107,6 @@ public class EmojiPluginTest
|
||||
public void testGtLt()
|
||||
{
|
||||
when(client.getGameState()).thenReturn(GameState.LOGGED_IN);
|
||||
when(client.getModIcons()).thenReturn(new IndexedSprite[0]);
|
||||
when(client.createIndexedSprite()).thenReturn(mock(IndexedSprite.class));
|
||||
|
||||
// Trip emoji loading
|
||||
GameStateChanged gameStateChanged = new GameStateChanged();
|
||||
gameStateChanged.setGameState(GameState.LOGGED_IN);
|
||||
emojiPlugin.onGameStateChanged(gameStateChanged);
|
||||
|
||||
MessageNode messageNode = mock(MessageNode.class);
|
||||
when(messageNode.getValue()).thenReturn("<gt>:D<lt>");
|
||||
@@ -119,8 +123,8 @@ public class EmojiPluginTest
|
||||
@Test
|
||||
public void testEmojiUpdateMessage()
|
||||
{
|
||||
String PARTY_POPPER = "<img=" + (-1 + Emoji.getEmoji("@@@").ordinal()) + '>';
|
||||
String OPEN_MOUTH = "<img=" + (-1 + Emoji.getEmoji(":O").ordinal()) + '>';
|
||||
String PARTY_POPPER = "<img=" + Emoji.getEmoji("@@@").ordinal() + '>';
|
||||
String OPEN_MOUTH = "<img=" + Emoji.getEmoji(":O").ordinal() + '>';
|
||||
assertNull(emojiPlugin.updateMessage("@@@@@"));
|
||||
assertEquals(PARTY_POPPER, emojiPlugin.updateMessage("@@@"));
|
||||
assertEquals(PARTY_POPPER + ' ' + PARTY_POPPER, emojiPlugin.updateMessage("@@@ @@@"));
|
||||
|
||||
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright (c) 2022 LlemonDuck
|
||||
* 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.timetracking.farming;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.testing.fieldbinder.Bind;
|
||||
import com.google.inject.testing.fieldbinder.BoundFieldModule;
|
||||
import java.time.Instant;
|
||||
import java.util.Collections;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.ChatMessageType;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameObject;
|
||||
import net.runelite.api.ItemID;
|
||||
import net.runelite.api.MenuAction;
|
||||
import net.runelite.api.ObjectComposition;
|
||||
import net.runelite.api.Player;
|
||||
import net.runelite.api.Scene;
|
||||
import net.runelite.api.Tile;
|
||||
import net.runelite.api.coords.WorldPoint;
|
||||
import net.runelite.api.events.ChatMessage;
|
||||
import net.runelite.api.events.MenuOptionClicked;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetInfo;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ErrorCollector;
|
||||
import org.junit.runner.RunWith;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import org.mockito.Mock;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CompostTrackerTest
|
||||
{
|
||||
|
||||
@Inject
|
||||
private CompostTracker compostTracker;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private Client client;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private FarmingWorld farmingWorld;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private ConfigManager configManager;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private FarmingRegion farmingRegion;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private FarmingPatch farmingPatch;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private GameObject patchObject;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private Player player;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private Scene scene;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private Tile tile;
|
||||
|
||||
@Mock
|
||||
@Bind
|
||||
private ObjectComposition patchDef;
|
||||
|
||||
@Rule
|
||||
public ErrorCollector collector = new ErrorCollector();
|
||||
|
||||
private static final int PATCH_ID = 12345;
|
||||
private static final int PATCH_VARBIT = 54321;
|
||||
private static final WorldPoint worldPoint = new WorldPoint(1, 2, 0);
|
||||
|
||||
@Before
|
||||
public void before()
|
||||
{
|
||||
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
|
||||
compostTracker.pendingCompostActions.clear();
|
||||
|
||||
when(client.getBaseX()).thenReturn(0);
|
||||
when(client.getBaseY()).thenReturn(0);
|
||||
when(client.getPlane()).thenReturn(0);
|
||||
when(client.getLocalPlayer()).thenReturn(player);
|
||||
when(player.getWorldLocation()).thenReturn(worldPoint);
|
||||
when(client.getScene()).thenReturn(scene);
|
||||
when(client.getObjectDefinition(PATCH_ID)).thenReturn(patchDef);
|
||||
|
||||
when(scene.getTiles()).thenReturn(new Tile[][][]{{null, {null, null, tile}}}); // indices match worldPoint
|
||||
when(tile.getGameObjects()).thenReturn(new GameObject[]{patchObject});
|
||||
|
||||
when(farmingWorld.getRegionsForLocation(any())).thenReturn(Collections.singleton(farmingRegion));
|
||||
|
||||
when(farmingRegion.getPatches()).thenReturn(new FarmingPatch[]{farmingPatch});
|
||||
|
||||
when(farmingPatch.getVarbit()).thenReturn(PATCH_VARBIT);
|
||||
when(farmingPatch.configKey()).thenReturn("MOCK");
|
||||
|
||||
when(patchObject.getId()).thenReturn(PATCH_ID);
|
||||
when(patchObject.sizeX()).thenReturn(1);
|
||||
when(patchObject.sizeY()).thenReturn(1);
|
||||
|
||||
when(patchDef.getVarbitId()).thenReturn(PATCH_VARBIT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCompostState_storesNonNullChangesToConfig()
|
||||
{
|
||||
compostTracker.setCompostState(farmingPatch, CompostState.COMPOST);
|
||||
verify(configManager).setRSProfileConfiguration("timetracking", "MOCK.compost", CompostState.COMPOST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setCompostState_storesNullChangesByClearingConfig()
|
||||
{
|
||||
compostTracker.setCompostState(farmingPatch, null);
|
||||
verify(configManager).unsetRSProfileConfiguration("timetracking", "MOCK.compost");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCompostState_directlyReturnsFromConfig()
|
||||
{
|
||||
when(configManager.getRSProfileConfiguration("timetracking", "MOCK.compost", CompostState.class)).thenReturn(
|
||||
CompostState.SUPERCOMPOST);
|
||||
assertThat(compostTracker.getCompostState(farmingPatch), is(CompostState.SUPERCOMPOST));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void determineCompostUsed_returnsAppropriateCompostValues()
|
||||
{
|
||||
// invalid
|
||||
collector.checkThat(
|
||||
CompostTracker.determineCompostUsed("This is not a farming chat message."),
|
||||
is((CompostState) null)
|
||||
);
|
||||
collector.checkThat(
|
||||
CompostTracker.determineCompostUsed("Contains word compost but is not examine message."),
|
||||
is((CompostState) null)
|
||||
);
|
||||
|
||||
// inspect
|
||||
collector.checkThat(
|
||||
CompostTracker.determineCompostUsed("This is an allotment. The soil has been treated with supercompost. The patch is empty and weeded."),
|
||||
is(CompostState.SUPERCOMPOST)
|
||||
);
|
||||
|
||||
// fertile soil on existing patch
|
||||
collector.checkThat(
|
||||
CompostTracker.determineCompostUsed("This patch has already been fertilised with ultracompost - the spell can't make it any more fertile."),
|
||||
is(CompostState.ULTRACOMPOST)
|
||||
);
|
||||
// fertile soil on cleared patch
|
||||
collector.checkThat(
|
||||
CompostTracker.determineCompostUsed("The herb patch has been treated with supercompost."),
|
||||
is(CompostState.SUPERCOMPOST)
|
||||
);
|
||||
|
||||
// bucket on cleared patch
|
||||
collector.checkThat(
|
||||
CompostTracker.determineCompostUsed("You treat the herb patch with ultracompost."),
|
||||
is(CompostState.ULTRACOMPOST)
|
||||
);
|
||||
collector.checkThat(
|
||||
CompostTracker.determineCompostUsed("You treat the tree patch with compost."),
|
||||
is(CompostState.COMPOST)
|
||||
);
|
||||
collector.checkThat(
|
||||
CompostTracker.determineCompostUsed("You treat the fruit tree patch with supercompost."),
|
||||
is(CompostState.SUPERCOMPOST)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMenuOptionClicked_queuesPendingCompostForInspectActions()
|
||||
{
|
||||
MenuOptionClicked inspectPatchAction = mock(MenuOptionClicked.class);
|
||||
when(inspectPatchAction.getMenuAction()).thenReturn(MenuAction.GAME_OBJECT_SECOND_OPTION);
|
||||
when(inspectPatchAction.getMenuOption()).thenReturn("Inspect");
|
||||
when(inspectPatchAction.getId()).thenReturn(PATCH_ID);
|
||||
when(inspectPatchAction.getParam0()).thenReturn(1);
|
||||
when(inspectPatchAction.getParam1()).thenReturn(2);
|
||||
|
||||
compostTracker.onMenuOptionClicked(inspectPatchAction);
|
||||
CompostTracker.PendingCompost actual = compostTracker.pendingCompostActions.get(farmingPatch);
|
||||
|
||||
assertThat(actual.getFarmingPatch(), is(farmingPatch));
|
||||
assertThat(actual.getPatchLocation(), is(new WorldPoint(1, 2, 0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMenuOptionClicked_queuesPendingCompostForCompostActions()
|
||||
{
|
||||
Widget widget = mock(Widget.class);
|
||||
when(client.getSelectedWidget()).thenReturn(widget);
|
||||
when(widget.getItemId()).thenReturn(ItemID.ULTRACOMPOST);
|
||||
|
||||
MenuOptionClicked inspectPatchAction = mock(MenuOptionClicked.class);
|
||||
when(inspectPatchAction.getMenuAction()).thenReturn(MenuAction.WIDGET_TARGET_ON_GAME_OBJECT);
|
||||
when(inspectPatchAction.getId()).thenReturn(PATCH_ID);
|
||||
when(inspectPatchAction.getParam0()).thenReturn(1);
|
||||
when(inspectPatchAction.getParam1()).thenReturn(2);
|
||||
|
||||
compostTracker.onMenuOptionClicked(inspectPatchAction);
|
||||
CompostTracker.PendingCompost actual = compostTracker.pendingCompostActions.get(farmingPatch);
|
||||
|
||||
assertThat(actual.getFarmingPatch(), is(farmingPatch));
|
||||
assertThat(actual.getPatchLocation(), is(new WorldPoint(1, 2, 0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onMenuOptionClicked_queuesPendingCompostForFertileSoilSpellActions()
|
||||
{
|
||||
Widget widget = mock(Widget.class);
|
||||
when(client.getSelectedWidget()).thenReturn(widget);
|
||||
when(widget.getId()).thenReturn(WidgetInfo.SPELL_LUNAR_FERTILE_SOIL.getPackedId());
|
||||
|
||||
MenuOptionClicked inspectPatchAction = mock(MenuOptionClicked.class);
|
||||
when(inspectPatchAction.getMenuAction()).thenReturn(MenuAction.WIDGET_TARGET_ON_GAME_OBJECT);
|
||||
when(inspectPatchAction.getId()).thenReturn(PATCH_ID);
|
||||
when(inspectPatchAction.getParam0()).thenReturn(1);
|
||||
when(inspectPatchAction.getParam1()).thenReturn(2);
|
||||
|
||||
compostTracker.onMenuOptionClicked(inspectPatchAction);
|
||||
CompostTracker.PendingCompost actual = compostTracker.pendingCompostActions.get(farmingPatch);
|
||||
|
||||
assertThat(actual.getFarmingPatch(), is(farmingPatch));
|
||||
assertThat(actual.getPatchLocation(), is(new WorldPoint(1, 2, 0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onChatMessage_ignoresInvalidTypes()
|
||||
{
|
||||
ChatMessage chatEvent = mock(ChatMessage.class);
|
||||
when(chatEvent.getType()).thenReturn(ChatMessageType.PUBLICCHAT);
|
||||
|
||||
compostTracker.onChatMessage(chatEvent);
|
||||
|
||||
verifyNoInteractions(client);
|
||||
verifyNoInteractions(farmingWorld);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onChatMessage_handlesInspectMessages()
|
||||
{
|
||||
ChatMessage chatEvent = mock(ChatMessage.class);
|
||||
when(chatEvent.getType()).thenReturn(ChatMessageType.SPAM);
|
||||
when(chatEvent.getMessage()).thenReturn("This is a tree patch. The soil has been treated with ultracompost. The patch is empty and weeded.");
|
||||
|
||||
compostTracker.pendingCompostActions.put(farmingPatch, new CompostTracker.PendingCompost(Instant.MAX, worldPoint, farmingPatch));
|
||||
compostTracker.onChatMessage(chatEvent);
|
||||
|
||||
verify(configManager).setRSProfileConfiguration("timetracking", "MOCK.compost", CompostState.ULTRACOMPOST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onChatMessage_handlesBucketUseMessages()
|
||||
{
|
||||
ChatMessage chatEvent = mock(ChatMessage.class);
|
||||
when(chatEvent.getType()).thenReturn(ChatMessageType.SPAM);
|
||||
when(chatEvent.getMessage()).thenReturn("You treat the herb patch with compost.");
|
||||
|
||||
compostTracker.pendingCompostActions.put(farmingPatch, new CompostTracker.PendingCompost(Instant.MAX, worldPoint, farmingPatch));
|
||||
compostTracker.onChatMessage(chatEvent);
|
||||
|
||||
verify(configManager).setRSProfileConfiguration("timetracking", "MOCK.compost", CompostState.COMPOST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onChatMessage_handlesFertileSoilMessages()
|
||||
{
|
||||
ChatMessage chatEvent = mock(ChatMessage.class);
|
||||
when(chatEvent.getType()).thenReturn(ChatMessageType.SPAM);
|
||||
when(chatEvent.getMessage()).thenReturn("The allotment has been treated with supercompost.");
|
||||
|
||||
compostTracker.pendingCompostActions.put(farmingPatch, new CompostTracker.PendingCompost(Instant.MAX, worldPoint, farmingPatch));
|
||||
compostTracker.onChatMessage(chatEvent);
|
||||
|
||||
verify(configManager).setRSProfileConfiguration("timetracking", "MOCK.compost", CompostState.SUPERCOMPOST);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user