diff --git a/http-api/src/main/java/net/runelite/http/api/examine/ExamineClient.java b/http-api/src/main/java/net/runelite/http/api/examine/ExamineClient.java new file mode 100644 index 0000000000..b02b91b6a9 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/examine/ExamineClient.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017, Adam + * 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.examine; + +import java.io.IOException; +import net.runelite.http.api.RuneliteAPI; +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ExamineClient +{ + private static final Logger logger = LoggerFactory.getLogger(ExamineClient.class); + + private static final MediaType TEXT = MediaType.parse("text"); + + public void submitObject(int id, String text) throws IOException + { + submit("object", id, text); + } + + public void submitNpc(int id, String text) throws IOException + { + submit("npc", id, text); + } + + public void submitItem(int id, String text) throws IOException + { + submit("item", id, text); + } + + private void submit(String type, int id, String text) throws IOException + { + HttpUrl url = RuneliteAPI.getApiBase().newBuilder() + .addPathSegment("examine") + .addPathSegment(type) + .addPathSegment(Integer.toString(id)) + .build(); + + logger.debug("Built URI: {}", url); + + Request request = new Request.Builder() + .url(url) + .post(RequestBody.create(TEXT, text)) + .build(); + + try (Response response = RuneliteAPI.CLIENT.newCall(request).execute()) + { + logger.debug("Submitted examine info for {} {}: {}", + type, id, text); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java index f8462371dd..a57b7f50c1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java @@ -39,6 +39,7 @@ import net.runelite.client.plugins.clanchat.ClanChat; import net.runelite.client.plugins.combatnotifier.CombatNotifier; import net.runelite.client.plugins.config.ConfigPlugin; import net.runelite.client.plugins.devtools.DevTools; +import net.runelite.client.plugins.examine.ExaminePlugin; import net.runelite.client.plugins.fpsinfo.FPS; import net.runelite.client.plugins.grounditems.GroundItems; import net.runelite.client.plugins.hiscore.Hiscore; @@ -89,6 +90,7 @@ public class PluginManager plugins.add(new XpGlobes()); plugins.add(new CombatNotifier()); plugins.add(new JewelryCount()); + plugins.add(new ExaminePlugin()); if (RuneLite.getOptions().has("developer-mode")) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/examine/CacheKey.java b/runelite-client/src/main/java/net/runelite/client/plugins/examine/CacheKey.java new file mode 100644 index 0000000000..135b300979 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/examine/CacheKey.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017, Adam + * 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.examine; + +import java.util.Objects; + +class CacheKey +{ + private final ExamineType type; + private final int id; + + public CacheKey(ExamineType type, int id) + { + this.type = type; + this.id = id; + } + + @Override + public int hashCode() + { + int hash = 3; + hash = 23 * hash + Objects.hashCode(this.type); + hash = 23 * hash + this.id; + return hash; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + final CacheKey other = (CacheKey) obj; + if (this.id != other.id) + { + return false; + } + if (this.type != other.type) + { + return false; + } + return true; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExaminePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExaminePlugin.java new file mode 100644 index 0000000000..bb7dc56831 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExaminePlugin.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2017, Adam + * 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.examine; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.eventbus.Subscribe; +import java.io.IOException; +import java.time.Instant; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.concurrent.ScheduledExecutorService; +import net.runelite.client.RuneLite; +import net.runelite.client.events.ChatMessage; +import net.runelite.client.events.GameStateChanged; +import net.runelite.client.events.MenuOptionClicked; +import net.runelite.client.plugins.Plugin; +import net.runelite.http.api.examine.ExamineClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Submits exammine info to the api + * + * @author Adam + */ +public class ExaminePlugin extends Plugin +{ + private static final Logger logger = LoggerFactory.getLogger(ExaminePlugin.class); + + private final RuneLite runelite = RuneLite.getRunelite(); + private final ExamineClient client = new ExamineClient(); + private final Deque pending = new ArrayDeque<>(); + private final Cache cache = CacheBuilder.newBuilder() + .maximumSize(128L) + .build(); + + @Override + protected void startUp() throws Exception + { + } + + @Override + protected void shutDown() throws Exception + { + } + + @Subscribe + public void onGameStateChange(GameStateChanged event) + { + pending.clear(); + } + + @Subscribe + public void onMenuOptionClicked(MenuOptionClicked event) + { + ExamineType type; + int id; + switch (event.getMenuAction()) + { + case EXAMINE_ITEM: + type = ExamineType.ITEM; + id = event.getId(); + break; + case EXAMINE_OBJECT: + type = ExamineType.OBJECT; + id = event.getId() >>> 14; + break; + case EXAMINE_NPC: + type = ExamineType.NPC; + id = event.getId(); + break; + default: + return; + } + + PendingExamine pendingExamine = new PendingExamine(type, id, Instant.now()); + pending.push(pendingExamine); + } + + @Subscribe + public void onChatMessage(ChatMessage event) + { + ExamineType type; + switch (event.getType()) + { + case EXAMINE_ITEM: + type = ExamineType.ITEM; + break; + case EXAMINE_OBJECT: + type = ExamineType.OBJECT; + break; + case EXAMINE_NPC: + type = ExamineType.NPC; + break; + default: + return; + } + + if (pending.isEmpty()) + { + logger.debug("Got examine without a pending examine?"); + return; + } + + PendingExamine pendingExamine = pending.pop(); + + if (pendingExamine.getType() != type) + { + logger.debug("Type mismatch for pending examine: {} != {}", pendingExamine.getType(), type); + pending.clear(); // eh + return; + } + + logger.debug("Got examine for {} {}: {}", pendingExamine.getType(), pendingExamine.getId(), event.getMessage()); + + CacheKey key = new CacheKey(type, pendingExamine.getId()); + Boolean cached = cache.getIfPresent(key); + if (cached != null) + { + return; + } + + cache.put(key, Boolean.TRUE); + + ScheduledExecutorService executor = runelite.getExecutor(); + executor.submit(() -> submit(pendingExamine, event.getMessage())); + } + + private void submit(PendingExamine examine, String text) + { + int id = examine.getId(); + + try + { + switch (examine.getType()) + { + case ITEM: + client.submitItem(id, text); + break; + case OBJECT: + client.submitObject(id, text); + break; + case NPC: + client.submitNpc(id, text); + break; + } + } + catch (IOException ex) + { + logger.warn("Error submitting examine", ex); + } + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExamineType.java b/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExamineType.java new file mode 100644 index 0000000000..b784deb016 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExamineType.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017, Adam + * 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.examine; + +public enum ExamineType +{ + ITEM, + NPC, + OBJECT; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/examine/PendingExamine.java b/runelite-client/src/main/java/net/runelite/client/plugins/examine/PendingExamine.java new file mode 100644 index 0000000000..a58ff59177 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/examine/PendingExamine.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2017, Adam + * 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.examine; + +import java.time.Instant; + +public class PendingExamine +{ + private final ExamineType type; + private final int id; + private final Instant created; + + public PendingExamine(ExamineType type, int id, Instant created) + { + this.type = type; + this.id = id; + this.created = created; + } + + public ExamineType getType() + { + return type; + } + + public int getId() + { + return id; + } + + public Instant getCreated() + { + return created; + } +}