diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java index 240ea3b8d4..95a154221e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java @@ -119,7 +119,9 @@ import org.apache.commons.text.similarity.FuzzyScore; @Slf4j public class GrandExchangePlugin extends Plugin { - private static final int GE_SLOTS = 8; + @VisibleForTesting + static final int GE_SLOTS = 8; + private static final int GE_LOGIN_BURST_WINDOW = 2; // ticks private static final int OFFER_CONTAINER_ITEM = 21; private static final int OFFER_DEFAULT_ITEM_ID = 6512; private static final String OSB_GE_TEXT = "
OSBuddy Actively traded price: "; @@ -141,6 +143,7 @@ public class GrandExchangePlugin extends Plugin private NavigationButton button; @Getter(AccessLevel.PACKAGE) + @Setter(AccessLevel.PACKAGE) private GrandExchangePanel panel; @Getter(AccessLevel.PACKAGE) @@ -189,7 +192,7 @@ public class GrandExchangePlugin extends Plugin @Inject private GrandExchangeClient grandExchangeClient; - private boolean loginBurstGeUpdates; + private int lastLoginTick; @Inject private OSBGrandExchangeClient osbGrandExchangeClient; @@ -314,6 +317,8 @@ public class GrandExchangePlugin extends Plugin osbItem = -1; osbGrandExchangeResult = null; + + lastLoginTick = -1; } @Override @@ -370,12 +375,12 @@ public class GrandExchangePlugin extends Plugin if (offer.getState() == GrandExchangeOfferState.EMPTY && client.getGameState() != GameState.LOGGED_IN) { // Trades are cleared by the client during LOGIN_SCREEN/HOPPING/LOGGING_IN, ignore those so we don't - // zero and re-submit the trade on login as an update + // clear the offer config. return; } - log.debug("GE offer updated: state: {}, slot: {}, item: {}, qty: {}, login: {}", - offer.getState(), slot, offer.getItemId(), offer.getQuantitySold(), loginBurstGeUpdates); + log.debug("GE offer updated: state: {}, slot: {}, item: {}, qty: {}, lastLoginTick: {}", + offer.getState(), slot, offer.getItemId(), offer.getQuantitySold(), lastLoginTick); ItemComposition offerItem = itemManager.getItemComposition(offer.getItemId()); boolean shouldStack = offerItem.isStackable() || offer.getTotalQuantity() > 1; @@ -385,11 +390,6 @@ public class GrandExchangePlugin extends Plugin submitTrade(slot, offer); updateConfig(slot, offer); - - if (loginBurstGeUpdates && slot == GE_SLOTS - 1) // slots are sent sequentially on login; this is the last one - { - loginBurstGeUpdates = false; - } } @VisibleForTesting @@ -403,6 +403,7 @@ public class GrandExchangePlugin extends Plugin } SavedOffer savedOffer = getOffer(slot); + boolean login = client.getTickCount() <= lastLoginTick + GE_LOGIN_BURST_WINDOW; if (savedOffer == null && (state == GrandExchangeOfferState.BUYING || state == GrandExchangeOfferState.SELLING) && offer.getQuantitySold() == 0) { // new offer @@ -413,7 +414,7 @@ public class GrandExchangePlugin extends Plugin grandExchangeTrade.setOffer(offer.getPrice()); grandExchangeTrade.setSlot(slot); grandExchangeTrade.setWorldType(getGeWorldType()); - grandExchangeTrade.setLogin(loginBurstGeUpdates); + grandExchangeTrade.setLogin(login); log.debug("Submitting new trade: {}", grandExchangeTrade); grandExchangeClient.submit(grandExchangeTrade); @@ -444,7 +445,7 @@ public class GrandExchangePlugin extends Plugin grandExchangeTrade.setOffer(offer.getPrice()); grandExchangeTrade.setSlot(slot); grandExchangeTrade.setWorldType(getGeWorldType()); - grandExchangeTrade.setLogin(loginBurstGeUpdates); + grandExchangeTrade.setLogin(login); log.debug("Submitting cancelled: {}", grandExchangeTrade); grandExchangeClient.submit(grandExchangeTrade); @@ -469,7 +470,7 @@ public class GrandExchangePlugin extends Plugin grandExchangeTrade.setOffer(offer.getPrice()); grandExchangeTrade.setSlot(slot); grandExchangeTrade.setWorldType(getGeWorldType()); - grandExchangeTrade.setLogin(loginBurstGeUpdates); + grandExchangeTrade.setLogin(login); log.debug("Submitting trade: {}", grandExchangeTrade); grandExchangeClient.submit(grandExchangeTrade); @@ -532,14 +533,19 @@ public class GrandExchangePlugin extends Plugin @Subscribe public void onGameStateChanged(GameStateChanged gameStateChanged) { - if (gameStateChanged.getGameState() == GameState.LOGIN_SCREEN) + switch (gameStateChanged.getGameState()) { - panel.getOffersPanel().resetOffers(); - loginBurstGeUpdates = true; - } - else if (gameStateChanged.getGameState() == GameState.LOGGED_IN) - { - grandExchangeClient.setMachineId(getMachineUuid()); + case LOGIN_SCREEN: + panel.getOffersPanel().resetOffers(); + break; + case LOGGING_IN: + case HOPPING: + case CONNECTION_LOST: + lastLoginTick = client.getTickCount(); + break; + case LOGGED_IN: + grandExchangeClient.setMachineId(getMachineUuid()); + break; } } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/grandexchange/GrandExchangePluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/grandexchange/GrandExchangePluginTest.java index 71db8a25db..e627dac19b 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/grandexchange/GrandExchangePluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/grandexchange/GrandExchangePluginTest.java @@ -29,15 +29,19 @@ import com.google.inject.testing.fieldbinder.Bind; import com.google.inject.testing.fieldbinder.BoundFieldModule; import java.util.Arrays; import java.util.EnumSet; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.ScheduledExecutorService; import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.GameState; import net.runelite.api.GrandExchangeOffer; import net.runelite.api.GrandExchangeOfferState; +import net.runelite.api.ItemComposition; import net.runelite.api.ItemID; import net.runelite.api.WorldType; +import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GrandExchangeOfferChanged; import net.runelite.client.Notifier; import net.runelite.client.account.SessionManager; @@ -52,14 +56,18 @@ import net.runelite.http.api.ge.GrandExchangeClient; import net.runelite.http.api.ge.GrandExchangeTrade; import net.runelite.http.api.osbuddy.OSBGrandExchangeClient; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import org.mockito.Mock; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -243,4 +251,82 @@ public class GrandExchangePluginTest verify(configManager, never()).unsetRSProfileConfiguration(anyString(), anyString()); } + + @Test + public void testLogin() + { + GrandExchangePanel panel = mock(GrandExchangePanel.class); + when(panel.getOffersPanel()).thenReturn(mock(GrandExchangeOffersPanel.class)); + grandExchangePlugin.setPanel(panel); + + when(itemManager.getItemComposition(anyInt())).thenReturn(mock(ItemComposition.class)); + + // provide config support so getOffer and setOffer work + final Map config = new HashMap<>(); + doAnswer(a -> + { + Object[] arguments = a.getArguments(); + config.put((String) arguments[1], arguments[2]); + return null; + }).when(configManager).setRSProfileConfiguration(eq("geoffer"), anyString(), anyString()); + + when(configManager.getRSProfileConfiguration(eq("geoffer"), anyString())).thenAnswer(a -> + { + Object[] arguments = a.getArguments(); + return config.get((String) arguments[1]); + }); + + // set loginBurstGeUpdates + GameStateChanged gameStateChanged = new GameStateChanged(); + gameStateChanged.setGameState(GameState.LOGIN_SCREEN); + + grandExchangePlugin.onGameStateChanged(gameStateChanged); + + // 8x buy 10 whip @ 1k ea, bought 1 sofar. + for (int i = 0; i < GrandExchangePlugin.GE_SLOTS; ++i) + { + GrandExchangeOffer grandExchangeOffer = mock(GrandExchangeOffer.class); + when(grandExchangeOffer.getQuantitySold()).thenReturn(1); + when(grandExchangeOffer.getItemId()).thenReturn(ItemID.ABYSSAL_WHIP); + when(grandExchangeOffer.getTotalQuantity()).thenReturn(10); + when(grandExchangeOffer.getPrice()).thenReturn(1000); + when(grandExchangeOffer.getSpent()).thenReturn(1000); + when(grandExchangeOffer.getState()).thenReturn(GrandExchangeOfferState.SELLING); + + GrandExchangeOfferChanged grandExchangeOfferChanged = new GrandExchangeOfferChanged(); + grandExchangeOfferChanged.setSlot(i); + grandExchangeOfferChanged.setOffer(grandExchangeOffer); + grandExchangePlugin.onGrandExchangeOfferChanged(grandExchangeOfferChanged); + } + + // Now send update for one of the slots + GrandExchangeOffer grandExchangeOffer = mock(GrandExchangeOffer.class); + when(grandExchangeOffer.getQuantitySold()).thenReturn(2); + when(grandExchangeOffer.getItemId()).thenReturn(ItemID.ABYSSAL_WHIP); + when(grandExchangeOffer.getTotalQuantity()).thenReturn(10); + when(grandExchangeOffer.getPrice()).thenReturn(1000); + when(grandExchangeOffer.getSpent()).thenReturn(2000); + when(grandExchangeOffer.getState()).thenReturn(GrandExchangeOfferState.SELLING); + + GrandExchangeOfferChanged grandExchangeOfferChanged = new GrandExchangeOfferChanged(); + grandExchangeOfferChanged.setSlot(2); + grandExchangeOfferChanged.setOffer(grandExchangeOffer); + grandExchangePlugin.onGrandExchangeOfferChanged(grandExchangeOfferChanged); + + // verify trade update + ArgumentCaptor captor = ArgumentCaptor.forClass(GrandExchangeTrade.class); + verify(grandExchangeClient).submit(captor.capture()); + + GrandExchangeTrade trade = captor.getValue(); + assertFalse(trade.isBuy()); + assertEquals(ItemID.ABYSSAL_WHIP, trade.getItemId()); + assertEquals(2, trade.getQty()); + assertEquals(1, trade.getDqty()); + assertEquals(10, trade.getTotal()); + assertEquals(1000, trade.getDspent()); + assertEquals(2000, trade.getSpent()); + assertEquals(1000, trade.getOffer()); + assertEquals(2, trade.getSlot()); + assertTrue(trade.isLogin()); + } } \ No newline at end of file