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