Merge pull request #7773 from Adam-/ge2

Add GE history tracker
This commit is contained in:
Adam
2019-02-12 18:00:44 -05:00
committed by GitHub
12 changed files with 596 additions and 16 deletions

View File

@@ -0,0 +1,78 @@
/*
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* 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.http.api.ge;
import com.google.gson.Gson;
import java.io.IOException;
import java.util.UUID;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.runelite.http.api.RuneLiteAPI;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.HttpUrl;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
@Slf4j
@AllArgsConstructor
public class GrandExchangeClient
{
private static final MediaType JSON = MediaType.parse("application/json");
private static final Gson GSON = RuneLiteAPI.GSON;
private final UUID uuid;
public void submit(GrandExchangeTrade grandExchangeTrade)
{
final HttpUrl url = RuneLiteAPI.getApiBase().newBuilder()
.addPathSegment("ge")
.build();
Request request = new Request.Builder()
.header(RuneLiteAPI.RUNELITE_AUTH, uuid.toString())
.post(RequestBody.create(JSON, GSON.toJson(grandExchangeTrade)))
.url(url)
.build();
RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback()
{
@Override
public void onFailure(Call call, IOException e)
{
log.debug("unable to submit trade", e);
}
@Override
public void onResponse(Call call, Response response)
{
log.debug("Submitted trade");
response.close();
}
});
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* 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.http.api.ge;
import java.time.Instant;
import lombok.Data;
@Data
public class GrandExchangeTrade
{
private boolean buy;
private int itemId;
private int quantity;
private int price;
private Instant time;
}

View File

@@ -35,9 +35,9 @@ import okhttp3.Request;
import okhttp3.Response;
@Slf4j
public class GrandExchangeClient
public class OSBGrandExchangeClient
{
public GrandExchangeResult lookupItem(int itemId) throws IOException
public OSBGrandExchangeResult lookupItem(int itemId) throws IOException
{
final HttpUrl url = RuneLiteAPI.getApiBase().newBuilder()
.addPathSegment("osb")
@@ -59,7 +59,7 @@ public class GrandExchangeClient
}
final InputStream in = response.body().byteStream();
return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), GrandExchangeResult.class);
return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), OSBGrandExchangeResult.class);
}
catch (JsonParseException ex)
{

View File

@@ -28,7 +28,7 @@ import java.time.Instant;
import lombok.Data;
@Data
public class GrandExchangeResult
public class OSBGrandExchangeResult
{
private int item_id;
private int buy_average;

View File

@@ -0,0 +1,111 @@
/*
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* 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.http.service.ge;
import java.io.IOException;
import java.util.Collection;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.runelite.http.api.ge.GrandExchangeTrade;
import net.runelite.http.service.account.AuthFilter;
import net.runelite.http.service.account.beans.SessionEntry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/ge")
public class GrandExchangeController
{
private final GrandExchangeService grandExchangeService;
private final AuthFilter authFilter;
@Autowired
public GrandExchangeController(GrandExchangeService grandExchangeService, AuthFilter authFilter)
{
this.grandExchangeService = grandExchangeService;
this.authFilter = authFilter;
}
@PostMapping
public void submit(HttpServletRequest request, HttpServletResponse response, @RequestBody GrandExchangeTrade grandExchangeTrade) throws IOException
{
SessionEntry session = authFilter.handle(request, response);
if (session == null)
{
return;
}
grandExchangeService.add(session.getUser(), grandExchangeTrade);
}
@GetMapping
public Collection<GrandExchangeTrade> get(HttpServletRequest request, HttpServletResponse response,
@RequestParam(required = false, defaultValue = "1024") int limit,
@RequestParam(required = false, defaultValue = "0") int offset) throws IOException
{
SessionEntry session = authFilter.handle(request, response);
if (session == null)
{
return null;
}
return grandExchangeService.get(session.getUser(), limit, offset).stream()
.map(GrandExchangeController::convert)
.collect(Collectors.toList());
}
private static GrandExchangeTrade convert(TradeEntry tradeEntry)
{
GrandExchangeTrade grandExchangeTrade = new GrandExchangeTrade();
grandExchangeTrade.setBuy(tradeEntry.getAction() == TradeAction.BUY);
grandExchangeTrade.setItemId(tradeEntry.getItem());
grandExchangeTrade.setQuantity(tradeEntry.getQuantity());
grandExchangeTrade.setPrice(tradeEntry.getPrice());
grandExchangeTrade.setTime(tradeEntry.getTime());
return grandExchangeTrade;
}
@DeleteMapping
public void delete(HttpServletRequest request, HttpServletResponse response) throws IOException
{
SessionEntry session = authFilter.handle(request, response);
if (session == null)
{
return;
}
grandExchangeService.delete(session.getUser());
}
}

View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* 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.http.service.ge;
import java.util.Collection;
import net.runelite.http.api.ge.GrandExchangeTrade;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.sql2o.Connection;
import org.sql2o.Sql2o;
@Service
public class GrandExchangeService
{
private static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS `ge_trades` (\n" +
" `id` int(11) NOT NULL AUTO_INCREMENT,\n" +
" `user` int(11) NOT NULL,\n" +
" `action` enum('BUY','SELL') NOT NULL,\n" +
" `item` int(11) NOT NULL,\n" +
" `quantity` int(11) NOT NULL,\n" +
" `price` int(11) NOT NULL,\n" +
" `time` timestamp NOT NULL DEFAULT current_timestamp(),\n" +
" PRIMARY KEY (`id`),\n" +
" KEY `user_time` (`user`, `time`),\n" +
" KEY `time` (`time`),\n" +
" CONSTRAINT `ge_trades_ibfk_1` FOREIGN KEY (`user`) REFERENCES `users` (`id`)\n" +
") ENGINE=InnoDB;";
private final Sql2o sql2o;
@Autowired
public GrandExchangeService(@Qualifier("Runelite SQL2O") Sql2o sql2o)
{
this.sql2o = sql2o;
// Ensure necessary tables exist
try (Connection con = sql2o.open())
{
con.createQuery(CREATE_TABLE).executeUpdate();
}
}
public void add(int userId, GrandExchangeTrade grandExchangeTrade)
{
try (Connection con = sql2o.open())
{
con.createQuery("insert into ge_trades (user, action, item, quantity, price) values (:user," +
" :action, :item, :quantity, :price)")
.addParameter("user", userId)
.addParameter("action", grandExchangeTrade.isBuy() ? "BUY" : "SELL")
.addParameter("item", grandExchangeTrade.getItemId())
.addParameter("quantity", grandExchangeTrade.getQuantity())
.addParameter("price", grandExchangeTrade.getPrice())
.executeUpdate();
}
}
public Collection<TradeEntry> get(int userId, int limit, int offset)
{
try (Connection con = sql2o.open())
{
return con.createQuery("select id, user, action, item, quantity, price, time from ge_trades where user = :user limit :limit offset :offset")
.addParameter("user", userId)
.addParameter("limit", limit)
.addParameter("offset", offset)
.executeAndFetch(TradeEntry.class);
}
}
public void delete(int userId)
{
try (Connection con = sql2o.open())
{
con.createQuery("delete from ge_trades where user = :user")
.addParameter("user", userId)
.executeUpdate();
}
}
@Scheduled(fixedDelay = 60 * 60 * 1000)
public void expire()
{
try (Connection con = sql2o.open())
{
con.createQuery("delete from ge_trades where time < current_timestamp - interval 1 month")
.executeUpdate();
}
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* 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.http.service.ge;
enum TradeAction
{
BUY,
SELL;
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* 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.http.service.ge;
import java.time.Instant;
import lombok.Data;
@Data
class TradeEntry
{
private int id;
private int user;
private TradeAction action;
private int item;
private int quantity;
private int price;
private Instant time;
}

View File

@@ -35,12 +35,12 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/osb/ge")
public class GrandExchangeController
public class OSBGrandExchangeController
{
private final GrandExchangeService grandExchangeService;
private final OSBGrandExchangeService grandExchangeService;
@Autowired
public GrandExchangeController(GrandExchangeService grandExchangeService)
public OSBGrandExchangeController(OSBGrandExchangeService grandExchangeService)
{
this.grandExchangeService = grandExchangeService;
}

View File

@@ -40,7 +40,7 @@ import org.sql2o.Sql2o;
@Service
@Slf4j
public class GrandExchangeService
public class OSBGrandExchangeService
{
private static final String CREATE_GRAND_EXCHANGE_PRICES = "CREATE TABLE IF NOT EXISTS `osb_ge` (\n"
+ " `item_id` int(11) NOT NULL,\n"
@@ -56,7 +56,7 @@ public class GrandExchangeService
private final Sql2o sql2o;
@Autowired
public GrandExchangeService(@Qualifier("Runelite SQL2O") Sql2o sql2o)
public OSBGrandExchangeService(@Qualifier("Runelite SQL2O") Sql2o sql2o)
{
this.sql2o = sql2o;

View File

@@ -1,5 +1,5 @@
/*
*
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* Copyright (c) 2017, Robbie <https://github.com/rbbi>
* Copyright (c) 2018, SomeoneWithAnInternetConnection
* All rights reserved.
@@ -46,6 +46,7 @@ import net.runelite.api.ChatMessageType;
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.MenuAction;
import net.runelite.api.MenuEntry;
@@ -56,11 +57,15 @@ import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.GrandExchangeOfferChanged;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.SessionClose;
import net.runelite.api.events.SessionOpen;
import net.runelite.api.events.WidgetLoaded;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.Notifier;
import net.runelite.client.account.AccountSession;
import net.runelite.client.account.SessionManager;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.ItemManager;
@@ -73,8 +78,10 @@ import net.runelite.client.ui.NavigationButton;
import net.runelite.client.util.ImageUtil;
import net.runelite.client.util.StackFormatter;
import net.runelite.client.util.Text;
import net.runelite.http.api.osbuddy.GrandExchangeClient;
import net.runelite.http.api.osbuddy.GrandExchangeResult;
import net.runelite.http.api.ge.GrandExchangeClient;
import net.runelite.http.api.ge.GrandExchangeTrade;
import net.runelite.http.api.osbuddy.OSBGrandExchangeClient;
import net.runelite.http.api.osbuddy.OSBGrandExchangeResult;
@PluginDescriptor(
name = "Grand Exchange",
@@ -86,7 +93,7 @@ public class GrandExchangePlugin extends Plugin
{
private static final int OFFER_CONTAINER_ITEM = 21;
private static final int OFFER_DEFAULT_ITEM_ID = 6512;
private static final GrandExchangeClient CLIENT = new GrandExchangeClient();
private static final OSBGrandExchangeClient CLIENT = new OSBGrandExchangeClient();
private static final String OSB_GE_TEXT = "<br>OSBuddy Actively traded price: ";
private static final String BUY_LIMIT_GE_TEXT = "<br>Buy limit: ";
@@ -134,10 +141,38 @@ public class GrandExchangePlugin extends Plugin
@Inject
private ScheduledExecutorService executorService;
@Inject
private SessionManager sessionManager;
@Inject
private ConfigManager configManager;
private Widget grandExchangeText;
private Widget grandExchangeItem;
private Map<Integer, Integer> itemGELimits;
private GrandExchangeClient grandExchangeClient;
private SavedOffer getOffer(int slot)
{
String offer = configManager.getConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot));
if (offer == null)
{
return null;
}
return GSON.fromJson(offer, SavedOffer.class);
}
private void setOffer(int slot, SavedOffer offer)
{
configManager.setConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot), GSON.toJson(offer));
}
private void deleteOffer(int slot)
{
configManager.unsetConfiguration("geoffer." + client.getUsername().toLowerCase(), Integer.toString(slot));
}
@Provides
GrandExchangeConfig provideConfig(ConfigManager configManager)
{
@@ -167,6 +202,12 @@ public class GrandExchangePlugin extends Plugin
mouseManager.registerMouseListener(inputListener);
keyManager.registerKeyListener(inputListener);
}
AccountSession accountSession = sessionManager.getAccountSession();
if (accountSession != null)
{
grandExchangeClient = new GrandExchangeClient(accountSession.getUuid());
}
}
@Override
@@ -178,6 +219,27 @@ public class GrandExchangePlugin extends Plugin
grandExchangeText = null;
grandExchangeItem = null;
itemGELimits = null;
grandExchangeClient = null;
}
@Subscribe
public void onSessionOpen(SessionOpen sessionOpen)
{
AccountSession accountSession = sessionManager.getAccountSession();
if (accountSession.getUuid() != null)
{
grandExchangeClient = new GrandExchangeClient(accountSession.getUuid());
}
else
{
grandExchangeClient = null;
}
}
@Subscribe
public void onSessionClose(SessionClose sessionClose)
{
grandExchangeClient = null;
}
@Subscribe
@@ -204,11 +266,79 @@ public class GrandExchangePlugin extends Plugin
@Subscribe
public void onGrandExchangeOfferChanged(GrandExchangeOfferChanged offerEvent)
{
GrandExchangeOffer offer = offerEvent.getOffer();
final int slot = offerEvent.getSlot();
final GrandExchangeOffer offer = offerEvent.getOffer();
ItemComposition offerItem = itemManager.getItemComposition(offer.getItemId());
boolean shouldStack = offerItem.isStackable() || offer.getTotalQuantity() > 1;
BufferedImage itemImage = itemManager.getImage(offer.getItemId(), offer.getTotalQuantity(), shouldStack);
SwingUtilities.invokeLater(() -> panel.getOffersPanel().updateOffer(offerItem, itemImage, offerEvent.getOffer(), offerEvent.getSlot()));
SwingUtilities.invokeLater(() -> panel.getOffersPanel().updateOffer(offerItem, itemImage, offer, slot));
submitTrades(slot, offer);
updateConfig(slot, offer);
}
private void submitTrades(int slot, GrandExchangeOffer offer)
{
if (grandExchangeClient == null)
{
return;
}
// Only interested in offers which are fully bought/sold
if (offer.getState() != GrandExchangeOfferState.BOUGHT && offer.getState() != GrandExchangeOfferState.SOLD)
{
return;
}
SavedOffer savedOffer = getOffer(slot);
if (!shouldUpdate(savedOffer, offer))
{
return;
}
// getPrice() is the price of the offer, not necessarily what the item bought at
int priceEach = offer.getSpent() / offer.getTotalQuantity();
GrandExchangeTrade grandExchangeTrade = new GrandExchangeTrade();
grandExchangeTrade.setBuy(offer.getState() == GrandExchangeOfferState.BOUGHT);
grandExchangeTrade.setItemId(offer.getItemId());
grandExchangeTrade.setQuantity(offer.getTotalQuantity());
grandExchangeTrade.setPrice(priceEach);
log.debug("Submitting trade: {}", grandExchangeTrade);
grandExchangeClient.submit(grandExchangeTrade);
}
private void updateConfig(int slot, GrandExchangeOffer offer)
{
if (offer.getState() == GrandExchangeOfferState.EMPTY)
{
deleteOffer(slot);
}
else
{
SavedOffer savedOffer = new SavedOffer();
savedOffer.setItemId(offer.getItemId());
savedOffer.setQuantitySold(offer.getQuantitySold());
savedOffer.setTotalQuantity(offer.getTotalQuantity());
savedOffer.setPrice(offer.getPrice());
savedOffer.setSpent(offer.getSpent());
savedOffer.setState(offer.getState());
setOffer(slot, savedOffer);
}
}
private boolean shouldUpdate(SavedOffer savedOffer, GrandExchangeOffer grandExchangeOffer)
{
if (savedOffer == null)
{
return false;
}
// Only update offer if state has changed
return savedOffer.getState() != grandExchangeOffer.getState();
}
@Subscribe
@@ -346,7 +476,7 @@ public class GrandExchangePlugin extends Plugin
try
{
final GrandExchangeResult result = CLIENT.lookupItem(itemId);
final OSBGrandExchangeResult result = CLIENT.lookupItem(itemId);
final String text = geText.getText() + OSB_GE_TEXT + StackFormatter.formatNumber(result.getOverall_average());
geText.setText(text);
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* 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.grandexchange;
import lombok.Data;
import net.runelite.api.GrandExchangeOfferState;
@Data
class SavedOffer
{
private int itemId;
private int quantitySold;
private int totalQuantity;
private int price;
private int spent;
private GrandExchangeOfferState state;
}