Skip to content

Commit

Permalink
Merge pull request #53 from PeaceBear0/esspouch
Browse files Browse the repository at this point in the history
Make essence pouch plugin look for chat messages when filling/emptying an already full/empty pouch
  • Loading branch information
Adam- authored Nov 21, 2022
2 parents 78c77d6 + f0a23c8 commit 57a0f35
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 28 deletions.
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ repositories {
mavenCentral()
}

def runeLiteVersion = '1.8.15'
def runeLiteVersion = '1.9.3'

dependencies {
compileOnly group: 'net.runelite', name:'client', version: runeLiteVersion
Expand Down
45 changes: 36 additions & 9 deletions src/main/java/info/sigterm/plugins/esspouch/EssPouchPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public class EssPouchPlugin extends Plugin
private static final int INVENTORY_SIZE = 28;
private static final int GOTR_WIDGET_ID = 48889876;

private static final String POUCH_ADD_FULL_MESSAGE = "You cannot add any more essence to the pouch.";
private static final Pattern POUCH_CHECK_MESSAGE = Pattern.compile("^There (?:is|are) ([a-z-]+)(?: pure| daeyalt| guardian)? essences? in this pouch\\.$");
private static final ImmutableMap<String, Integer> TEXT_TO_NUMBER = ImmutableMap.<String, Integer>builder()
.put("no", 0)
Expand Down Expand Up @@ -141,6 +142,19 @@ protected void shutDown()
overlayManager.remove(essencePouchOverlay);
}

// Pops ClickOperations from checkedPouches until it finds one that is still valid this tick and returns that one.
// Returns null if there are no valid pouches in the list.
private ClickOperation popFirstValidCheckedPouch()
{
ClickOperation op = checkedPouches.pollFirst();
while (op != null && op.tick < client.getTickCount())
{
op = checkedPouches.pollFirst();
}
return op;
}


@Subscribe
public void onChatMessage(ChatMessage event)
{
Expand All @@ -163,23 +177,34 @@ public void onChatMessage(ChatMessage event)

if (!checkedPouches.isEmpty())
{
Matcher matcher = POUCH_CHECK_MESSAGE.matcher(event.getMessage());
if (matcher.matches())
if (event.getMessage().equals(POUCH_ADD_FULL_MESSAGE))
{
ClickOperation op = popFirstValidCheckedPouch();
// Make sure it was a filling operation that produced this message
if (op != null && op.delta == 1)
{
Pouch pouch = op.pouch;
// It's gotta be all the way full now.
pouch.setHolding(pouch.getHoldAmount());
pouch.setUnknown(false);
}
}
else
{
final int num = TEXT_TO_NUMBER.get(matcher.group(1));
// Keep getting operations until we get a valid one
do
Matcher matcher = POUCH_CHECK_MESSAGE.matcher(event.getMessage());
if (matcher.matches())
{
final ClickOperation op = checkedPouches.pop();
if (op.tick >= client.getTickCount())
final int num = TEXT_TO_NUMBER.get(matcher.group(1));
ClickOperation op = popFirstValidCheckedPouch();
// Update if it was a check operation (delta == 0) or an empty operation and it is now empty. The
// empty operation only produces the message if it was already completely empty
if (op != null && (op.delta == 0 || (op.delta == -1 && num == 0)))
{
Pouch pouch = op.pouch;
pouch.setHolding(num);
pouch.setUnknown(false);
break;
}
}
while (!checkedPouches.isEmpty());
}
}
}
Expand Down Expand Up @@ -370,9 +395,11 @@ public void onMenuOptionClicked(MenuOptionClicked event)
{
case "Fill":
clickedItems.add(new ClickOperation(pouch, tick, 1));
checkedPouches.add(new ClickOperation(pouch, tick, 1));
break;
case "Empty":
clickedItems.add(new ClickOperation(pouch, tick, -1));
checkedPouches.add(new ClickOperation(pouch, tick, -1));
break;
case "Check":
checkedPouches.add(new ClickOperation(pouch, tick));
Expand Down
121 changes: 103 additions & 18 deletions src/test/java/info/sigterm/plugins/esspouch/EssPouchPluginTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import net.runelite.api.MenuAction;
import net.runelite.api.events.ItemContainerChanged;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.ChatMessage;
import net.runelite.api.ChatMessageType;
import net.runelite.client.Notifier;
import net.runelite.client.ui.overlay.OverlayManager;
import static org.junit.Assert.assertEquals;
Expand Down Expand Up @@ -69,20 +71,48 @@ public class EssPouchPluginTest
@Inject
EssPouchPlugin runecraftPlugin;

@Mock
ItemContainer inventory;

@Before
public void before()
{
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
when(client.getItemContainer(InventoryID.INVENTORY)).thenReturn(inventory);
}

// Tells the plugin that there was a click on empty option on the pouch with id @pouchId.
void clickEmptyPouch(int pouchId) {
MenuOptionClicked menuOptionClicked = mock(MenuOptionClicked.class);
when(menuOptionClicked.getMenuAction()).thenReturn(MenuAction.ITEM_FIRST_OPTION);
when(menuOptionClicked.getId()).thenReturn(pouchId);
when(menuOptionClicked.getMenuOption()).thenReturn("Empty");
runecraftPlugin.onMenuOptionClicked(menuOptionClicked);
}

// Tells the plugin that there was a click on fill option on the pouch with id @pouchId.
void clickFillPouch(int pouchId) {
MenuOptionClicked menuOptionClicked = mock(MenuOptionClicked.class);
when(menuOptionClicked.getMenuAction()).thenReturn(MenuAction.ITEM_FIRST_OPTION);
when(menuOptionClicked.getId()).thenReturn(pouchId);
when(menuOptionClicked.getMenuOption()).thenReturn("Fill");
runecraftPlugin.onMenuOptionClicked(menuOptionClicked);
}

// Tells the plugin that there was a game message that says @msg.
void injectGameMessage(String msg) {
ChatMessage empty_message = mock(ChatMessage.class);
when(empty_message.getType()).thenReturn(ChatMessageType.GAMEMESSAGE);
when(empty_message.getMessage()).thenReturn(msg);
runecraftPlugin.onChatMessage(empty_message);
}


@Test
public void testPouches()
{
ItemContainer itemContainer = mock(ItemContainer.class);
when(client.getItemContainer(InventoryID.INVENTORY)).thenReturn(itemContainer);

// Add 4 pouches
when(itemContainer.getItems()).thenReturn(new Item[]{
when(inventory.getItems()).thenReturn(new Item[]{
new Item(ItemID.SMALL_POUCH, 1),
new Item(ItemID.MEDIUM_POUCH, 1),
new Item(ItemID.LARGE_POUCH, 1),
Expand All @@ -97,27 +127,19 @@ public void testPouches()
}

// Initialize last counters
ItemContainerChanged itemContainerChanged = new ItemContainerChanged(InventoryID.INVENTORY.getId(), itemContainer);
ItemContainerChanged itemContainerChanged = new ItemContainerChanged(InventoryID.INVENTORY.getId(), inventory);
runecraftPlugin.onItemContainerChanged(itemContainerChanged);

// Empty small
MenuOptionClicked menuOptionClicked = new MenuOptionClicked();
menuOptionClicked.setMenuAction(MenuAction.ITEM_FIRST_OPTION);
menuOptionClicked.setId(ItemID.SMALL_POUCH);
menuOptionClicked.setMenuOption("Empty");
runecraftPlugin.onMenuOptionClicked(menuOptionClicked);
clickEmptyPouch(ItemID.SMALL_POUCH);

// <server tick here>

// Empty medium
menuOptionClicked = new MenuOptionClicked();
menuOptionClicked.setMenuAction(MenuAction.ITEM_FIRST_OPTION);
menuOptionClicked.setId(ItemID.MEDIUM_POUCH);
menuOptionClicked.setMenuOption("Empty");
runecraftPlugin.onMenuOptionClicked(menuOptionClicked);
clickEmptyPouch(ItemID.MEDIUM_POUCH);

// Update inventory with 3 pess
when(itemContainer.getItems()).thenReturn(new Item[]{
when(inventory.getItems()).thenReturn(new Item[]{
new Item(ItemID.SMALL_POUCH, 1),
new Item(ItemID.MEDIUM_POUCH, 1),
new Item(ItemID.LARGE_POUCH, 1),
Expand All @@ -133,7 +155,7 @@ public void testPouches()
assertEquals(6, Pouch.MEDIUM.getHolding());

// Add 6 more pess
when(itemContainer.getItems()).thenReturn(new Item[]{
when(inventory.getItems()).thenReturn(new Item[]{
new Item(ItemID.SMALL_POUCH, 1),
new Item(ItemID.MEDIUM_POUCH, 1),
new Item(ItemID.LARGE_POUCH, 1),
Expand All @@ -154,4 +176,67 @@ public void testPouches()
assertEquals(0, Pouch.SMALL.getHolding());
assertEquals(0, Pouch.MEDIUM.getHolding());
}
}

// Tests that if a pouch is empty but this plugin thinks it has essence, the plugin updates to show that it's actually empty
@Test
public void testEmptyCorrection()
{
// At start, we "know" it has 10 essence (even though it actually is empty!)
Pouch.COLOSSAL.setHolding(10);
Pouch.COLOSSAL.setUnknown(false);

// It should think there's 10 items
assertEquals(10, Pouch.COLOSSAL.getHolding());

clickEmptyPouch(ItemID.COLOSSAL_POUCH);

// Inject a chat message saying it was empty
injectGameMessage("There are no guardian essences in this pouch.");

// It should now think that the pouch is empty
assertEquals(0, Pouch.COLOSSAL.getHolding());
}

@Test
public void testFullCorrection()
{
// At start, we "know" it has 10 essence (even though it actually is empty!)
Pouch.COLOSSAL.setHolding(10);
Pouch.COLOSSAL.setUnknown(false);

// It should think there's 10 items
assertEquals(10, Pouch.COLOSSAL.getHolding());

clickFillPouch(ItemID.COLOSSAL_POUCH);

injectGameMessage("You cannot add any more essence to the pouch.");

// It should now think that the pouch is full
assertEquals(40, Pouch.COLOSSAL.getHolding());
}

@Test
public void testMultiPouchFullEmptyCorrection()
{
Pouch.GIANT.setHolding(10);
Pouch.GIANT.setUnknown(false);
Pouch.MEDIUM.setHolding(2);
Pouch.MEDIUM.setUnknown(false);

assertEquals(10, Pouch.GIANT.getHolding());
assertEquals(2, Pouch.MEDIUM.getHolding());

// Click fill on one and empty on the other before any messagse appear
clickFillPouch(ItemID.MEDIUM_POUCH);
clickEmptyPouch(ItemID.GIANT_POUCH);

// Have the first game message say it was full, then the second say it was empty
injectGameMessage("You cannot add any more essence to the pouch.");
injectGameMessage("There are no guardian essences in this pouch.");

// Now it should realize that full message referred to the medium pouch, and the empty message referred to the
// giant pouch.
assertEquals(6, Pouch.MEDIUM.getHolding());
assertEquals(0, Pouch.GIANT.getHolding());
}
}

0 comments on commit 57a0f35

Please sign in to comment.