diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingManager.java new file mode 100644 index 0000000000..661071a786 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingManager.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing; + +import com.google.gson.Gson; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import javax.inject.Inject; +import javax.inject.Singleton; +import lombok.extern.slf4j.Slf4j; +import net.runelite.http.api.RuneLiteAPI; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +@Slf4j +@Singleton +public class CrowdsourcingManager +{ + private static final String CROWDSOURCING_BASE = "https://crowdsource.runescape.wiki/runelite"; + private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); + private static final Gson GSON = RuneLiteAPI.GSON; + + @Inject + private OkHttpClient okHttpClient; + + private List data = new ArrayList<>(); + + public void storeEvent(Object event) + { + synchronized (this) + { + data.add(event); + } + } + + protected void submitToAPI() + { + List temp; + synchronized (this) + { + if (data.isEmpty()) + { + return; + } + temp = data; + data = new ArrayList<>(); + } + + Request r = new Request.Builder() + .url(CROWDSOURCING_BASE) + .post(RequestBody.create(JSON, GSON.toJson(temp))) + .build(); + + okHttpClient.newCall(r).enqueue(new Callback() + { + @Override + public void onFailure(Call call, IOException e) + { + log.debug("Error sending crowdsourcing data", e); + } + + @Override + public void onResponse(Call call, Response response) + { + log.debug("Successfully sent crowdsourcing data"); + response.close(); + } + }); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingPlugin.java new file mode 100644 index 0000000000..5c639b6205 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingPlugin.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing; + +import java.time.temporal.ChronoUnit; +import javax.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import net.runelite.client.eventbus.EventBus; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.crowdsourcing.cooking.CrowdsourcingCooking; +import net.runelite.client.plugins.crowdsourcing.dialogue.CrowdsourcingDialogue; +import net.runelite.client.plugins.crowdsourcing.movement.CrowdsourcingMovement; +import net.runelite.client.plugins.crowdsourcing.music.CrowdsourcingMusic; +import net.runelite.client.plugins.crowdsourcing.thieving.CrowdsourcingThieving; +import net.runelite.client.plugins.crowdsourcing.woodcutting.CrowdsourcingWoodcutting; +import net.runelite.client.plugins.crowdsourcing.zmi.CrowdsourcingZMI; +import net.runelite.client.task.Schedule; + +@Slf4j +@PluginDescriptor( + name = "OSRS Wiki Crowdsourcing", + description = "Send data to the wiki to help figure out skilling success rates, burn rates, more. See osrs.wiki/RS:CROWD" +) +public class CrowdsourcingPlugin extends Plugin +{ + // Number of seconds to wait between trying to send data to the wiki. + private static final int SECONDS_BETWEEN_UPLOADS = 300; + + @Inject + private EventBus eventBus; + + @Inject + private CrowdsourcingManager manager; + + @Inject + private CrowdsourcingCooking cooking; + + @Inject + private CrowdsourcingDialogue dialogue; + + @Inject + private CrowdsourcingMovement movement; + + @Inject + private CrowdsourcingMusic music; + + @Inject + private CrowdsourcingThieving thieving; + + @Inject + private CrowdsourcingWoodcutting woodcutting; + + @Inject + private CrowdsourcingZMI zmi; + + @Override + protected void startUp() throws Exception + { + eventBus.register(cooking); + eventBus.register(dialogue); + eventBus.register(movement); + eventBus.register(music); + eventBus.register(thieving); + eventBus.register(woodcutting); + eventBus.register(zmi); + } + + @Override + protected void shutDown() throws Exception + { + eventBus.unregister(cooking); + eventBus.unregister(dialogue); + eventBus.unregister(movement); + eventBus.unregister(music); + eventBus.unregister(thieving); + eventBus.unregister(woodcutting); + eventBus.unregister(zmi); + } + + @Schedule( + period = SECONDS_BETWEEN_UPLOADS, + unit = ChronoUnit.SECONDS, + asynchronous = true + ) + public void submitToAPI() + { + manager.submitToAPI(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/cooking/CookingData.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/cooking/CookingData.java new file mode 100644 index 0000000000..568361823a --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/cooking/CookingData.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.cooking; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class CookingData +{ + private final String message; + private final boolean hasCookingGauntlets; + private final boolean inHosidiusKitchen; + private final boolean kourendElite; + private final int lastGameObjectClicked; + private final int level; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/cooking/CrowdsourcingCooking.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/cooking/CrowdsourcingCooking.java new file mode 100644 index 0000000000..37058b5dbe --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/cooking/CrowdsourcingCooking.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.cooking; + +import javax.inject.Inject; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.InventoryID; +import net.runelite.api.ItemContainer; +import net.runelite.api.ItemID; +import net.runelite.api.MenuAction; +import net.runelite.api.Player; +import net.runelite.api.Skill; +import net.runelite.api.Varbits; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.crowdsourcing.CrowdsourcingManager; + +public class CrowdsourcingCooking +{ + private static final int HOSIDIUS_KITCHEN_REGION = 6712; + + @Inject + private CrowdsourcingManager manager; + + @Inject + private Client client; + + private int lastGameObjectClicked; + + private boolean hasCookingGauntlets() + { + ItemContainer equipmentContainer = client.getItemContainer(InventoryID.EQUIPMENT); + if (equipmentContainer == null) + { + return false; + } + + return equipmentContainer.contains(ItemID.COOKING_GAUNTLETS); + } + + @Subscribe + public void onChatMessage(ChatMessage event) + { + if (event.getType() != ChatMessageType.SPAM) + { + return; + } + + final String message = event.getMessage(); + // Message prefixes taken from CookingPlugin + if (message.startsWith("You successfully cook") + || message.startsWith("You successfully bake") + || message.startsWith("You manage to cook") + || message.startsWith("You roast a") + || message.startsWith("You cook") + || message.startsWith("You accidentally burn") + || message.startsWith("You accidentally spoil")) + { + boolean inHosidiusKitchen = false; + Player local = client.getLocalPlayer(); + if (local != null && local.getWorldLocation().getRegionID() == HOSIDIUS_KITCHEN_REGION) + { + inHosidiusKitchen = true; + } + + int cookingLevel = client.getBoostedSkillLevel(Skill.COOKING); + boolean hasCookingGauntlets = hasCookingGauntlets(); + boolean kourendElite = client.getVar(Varbits.DIARY_KOUREND_ELITE) == 1; + CookingData data = new CookingData(message, hasCookingGauntlets, inHosidiusKitchen, kourendElite, lastGameObjectClicked, cookingLevel); + manager.storeEvent(data); + } + } + + @Subscribe + public void onMenuOptionClicked(MenuOptionClicked menuOptionClicked) + { + MenuAction action = menuOptionClicked.getMenuAction(); + if (action == MenuAction.ITEM_USE_ON_GAME_OBJECT + || action == MenuAction.GAME_OBJECT_FIRST_OPTION + || action == MenuAction.GAME_OBJECT_SECOND_OPTION + || action == MenuAction.GAME_OBJECT_THIRD_OPTION + || action == MenuAction.GAME_OBJECT_FOURTH_OPTION + || action == MenuAction.GAME_OBJECT_FIFTH_OPTION) + { + lastGameObjectClicked = menuOptionClicked.getId(); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/dialogue/CrowdsourcingDialogue.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/dialogue/CrowdsourcingDialogue.java new file mode 100644 index 0000000000..9f0a0e72ad --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/dialogue/CrowdsourcingDialogue.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.dialogue; + +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.events.GameTick; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.crowdsourcing.CrowdsourcingManager; + +public class CrowdsourcingDialogue +{ + private static final String USERNAME_TOKEN = "%USERNAME%"; + + @Inject + private Client client; + + @Inject + private CrowdsourcingManager manager; + + private String lastNpcDialogueText = null; + private String lastPlayerDialogueText = null; + private Widget[] dialogueOptions; + + private String sanitize(String dialogue) + { + String username = client.getLocalPlayer().getName(); + return dialogue.replaceAll(username, USERNAME_TOKEN); + } + + @Subscribe + public void onGameTick(GameTick tick) + { + Widget npcDialogueTextWidget = client.getWidget(WidgetInfo.DIALOG_NPC_TEXT); + if (npcDialogueTextWidget != null && !npcDialogueTextWidget.getText().equals(lastNpcDialogueText)) + { + lastNpcDialogueText = npcDialogueTextWidget.getText(); + String npcName = client.getWidget(WidgetInfo.DIALOG_NPC_NAME).getText(); + NpcDialogueData data = new NpcDialogueData(sanitize(lastNpcDialogueText), npcName); + manager.storeEvent(data); + } + + Widget playerDialogueTextWidget = client.getWidget(WidgetID.DIALOG_PLAYER_GROUP_ID, 4); + if (playerDialogueTextWidget != null && !playerDialogueTextWidget.getText().equals(lastPlayerDialogueText)) + { + lastPlayerDialogueText = playerDialogueTextWidget.getText(); + PlayerDialogueData data = new PlayerDialogueData(sanitize(lastPlayerDialogueText)); + manager.storeEvent(data); + } + + Widget playerDialogueOptionsWidget = client.getWidget(WidgetID.DIALOG_OPTION_GROUP_ID, 1); + if (playerDialogueOptionsWidget != null && playerDialogueOptionsWidget.getChildren() != dialogueOptions) + { + dialogueOptions = playerDialogueOptionsWidget.getChildren(); + String[] optionsText = new String[dialogueOptions.length]; + for (int i = 0; i < dialogueOptions.length; i++) + { + optionsText[i] = sanitize(dialogueOptions[i].getText()); + } + DialogueOptionsData data = new DialogueOptionsData(optionsText); + manager.storeEvent(data); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/dialogue/DialogueOptionsData.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/dialogue/DialogueOptionsData.java new file mode 100644 index 0000000000..141707fc00 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/dialogue/DialogueOptionsData.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.dialogue; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class DialogueOptionsData +{ + private final String[] options; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/dialogue/NpcDialogueData.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/dialogue/NpcDialogueData.java new file mode 100644 index 0000000000..18af3f88fa --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/dialogue/NpcDialogueData.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.dialogue; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class NpcDialogueData +{ + private final String message; + private final String name; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/dialogue/PlayerDialogueData.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/dialogue/PlayerDialogueData.java new file mode 100644 index 0000000000..b78db9407c --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/dialogue/PlayerDialogueData.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.dialogue; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class PlayerDialogueData +{ + private final String message; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/movement/CrowdsourcingMovement.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/movement/CrowdsourcingMovement.java new file mode 100644 index 0000000000..7f21c2fda2 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/movement/CrowdsourcingMovement.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.movement; + +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.MenuAction; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.crowdsourcing.CrowdsourcingManager; + +public class CrowdsourcingMovement +{ + @Inject + private Client client; + + @Inject + private CrowdsourcingManager manager; + + private WorldPoint lastPoint; + private int ticksStill; + private boolean lastIsInInstance; + private MenuOptionClicked lastClick; + + @Subscribe + public void onMenuOptionClicked(MenuOptionClicked menuOptionClicked) + { + if (menuOptionClicked.getMenuAction() != MenuAction.WALK + && !menuOptionClicked.getMenuOption().equals("Message")) + { + lastClick = menuOptionClicked; + } + } + + @Subscribe + public void onGameTick(GameTick tick) + { + LocalPoint local = LocalPoint.fromWorld(client, client.getLocalPlayer().getWorldLocation()); + WorldPoint nextPoint = WorldPoint.fromLocalInstance(client, local); + boolean nextIsInInstance = client.isInInstancedRegion(); + if (lastPoint != null) + { + int distance = nextPoint.distanceTo(lastPoint); + if (distance > 2 || nextIsInInstance != lastIsInInstance) + { + MovementData data = new MovementData(lastPoint, nextPoint, lastIsInInstance, nextIsInInstance, ticksStill, lastClick); + manager.storeEvent(data); + } + if (distance > 0) + { + ticksStill = 0; + } + } + ticksStill++; + lastPoint = nextPoint; + lastIsInInstance = nextIsInInstance; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/movement/MovementData.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/movement/MovementData.java new file mode 100644 index 0000000000..1b9c6aef9e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/movement/MovementData.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.movement; + +import lombok.AllArgsConstructor; +import lombok.Data; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.MenuOptionClicked; + +@Data +@AllArgsConstructor +public class MovementData +{ + private final WorldPoint start; + private final WorldPoint end; + private final boolean fromInstance; + private final boolean toInstance; + private final int ticks; + private MenuOptionClicked lastClick; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/music/CrowdsourcingMusic.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/music/CrowdsourcingMusic.java new file mode 100644 index 0000000000..abca2a624f --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/music/CrowdsourcingMusic.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.music; + +import javax.inject.Inject; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ChatMessage; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.crowdsourcing.CrowdsourcingManager; + +public class CrowdsourcingMusic +{ + private static final String MUSIC_UNLOCK_MESSAGE = "You have unlocked a new music track:"; + + @Inject + private Client client; + + @Inject + private ClientThread clientThread; + + @Inject + private CrowdsourcingManager manager; + + @Subscribe + public void onChatMessage(ChatMessage event) + { + if (event.getType() == ChatMessageType.GAMEMESSAGE) + { + String message = event.getMessage(); + if (message.contains(MUSIC_UNLOCK_MESSAGE)) + { + // Need to delay this by a tick because the location is not set until after the message + clientThread.invokeLater(() -> + { + LocalPoint local = LocalPoint.fromWorld(client, client.getLocalPlayer().getWorldLocation()); + WorldPoint location = WorldPoint.fromLocalInstance(client, local); + boolean isInInstance = client.isInInstancedRegion(); + MusicUnlockData data = new MusicUnlockData(location, isInInstance, message); + manager.storeEvent(data); + }); + } + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/music/MusicUnlockData.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/music/MusicUnlockData.java new file mode 100644 index 0000000000..55cdb96e62 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/music/MusicUnlockData.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.music; + +import lombok.AllArgsConstructor; +import lombok.Data; +import net.runelite.api.coords.WorldPoint; + +@Data +@AllArgsConstructor +public class MusicUnlockData +{ + private final WorldPoint location; + private final boolean isInInstance; + private final String message; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/skilling/SkillingEndReason.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/skilling/SkillingEndReason.java new file mode 100644 index 0000000000..7af79389f0 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/skilling/SkillingEndReason.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.skilling; + +public enum SkillingEndReason +{ + DEPLETED, + INVENTORY_FULL, + INTERRUPTED +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/skilling/SkillingState.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/skilling/SkillingState.java new file mode 100644 index 0000000000..85a4b87866 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/skilling/SkillingState.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.skilling; + +public enum SkillingState +{ + READY, + CLICKED, + CUTTING, + RECOVERING +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/thieving/CrowdsourcingThieving.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/thieving/CrowdsourcingThieving.java new file mode 100644 index 0000000000..698e359265 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/thieving/CrowdsourcingThieving.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.thieving; + +import java.util.regex.Pattern; +import javax.inject.Inject; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.InventoryID; +import net.runelite.api.ItemContainer; +import net.runelite.api.ItemID; +import net.runelite.api.NPC; +import net.runelite.api.Skill; +import net.runelite.api.Varbits; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.crowdsourcing.CrowdsourcingManager; + +public class CrowdsourcingThieving +{ + private static final String BLACKJACK_SUCCESS = "You smack the bandit over the head and render them unconscious."; + private static final String BLACKJACK_FAIL = "Your blow only glances off the bandit's head."; + private static final Pattern PICKPOCKET_SUCCESS = Pattern.compile("You pick .*'s pocket\\."); + private static final Pattern PICKPOCKET_FAIL = Pattern.compile("You fail to pick .*'s pocket\\."); + + @Inject + private Client client; + + @Inject + private CrowdsourcingManager manager; + + private int lastPickpocketTarget; + + private boolean hasGlovesOfSilence() + { + ItemContainer equipmentContainer = client.getItemContainer(InventoryID.EQUIPMENT); + if (equipmentContainer == null) + { + return false; + } + + return equipmentContainer.contains(ItemID.GLOVES_OF_SILENCE); + } + + private boolean hasThievingCape() + { + ItemContainer equipmentContainer = client.getItemContainer(InventoryID.EQUIPMENT); + if (equipmentContainer == null) + { + return false; + } + + return equipmentContainer.contains(ItemID.THIEVING_CAPE) || + equipmentContainer.contains(ItemID.THIEVING_CAPET) || + equipmentContainer.contains(ItemID.MAX_CAPE); + } + + private int getArdougneDiary() + { + int easy = client.getVar(Varbits.DIARY_ARDOUGNE_EASY); + int medium = client.getVar(Varbits.DIARY_ARDOUGNE_MEDIUM); + int hard = client.getVar(Varbits.DIARY_ARDOUGNE_HARD); + int elite = client.getVar(Varbits.DIARY_ARDOUGNE_ELITE); + return easy + 2 * medium + 4 * hard + 8 * elite; + } + + @Subscribe + public void onChatMessage(ChatMessage event) + { + if (event.getType() != ChatMessageType.SPAM) + { + return; + } + + String message = event.getMessage(); + if (BLACKJACK_SUCCESS.equals(message) + || BLACKJACK_FAIL.equals(message) + || PICKPOCKET_FAIL.matcher(message).matches() + || PICKPOCKET_SUCCESS.matcher(message).matches()) + { + WorldPoint location = client.getLocalPlayer().getWorldLocation(); + int ardougneDiary = getArdougneDiary(); + boolean silence = hasGlovesOfSilence(); + boolean thievingCape = hasThievingCape(); + int thievingLevel = client.getBoostedSkillLevel(Skill.THIEVING); + PickpocketData data = new PickpocketData(thievingLevel, lastPickpocketTarget, message, location, silence, thievingCape, ardougneDiary); + manager.storeEvent(data); + } + } + + @Subscribe + public void onMenuOptionClicked(MenuOptionClicked event) + { + if (event.getMenuOption().equals("Pickpocket") || event.getMenuOption().equals("Knock-Out")) + { + NPC[] cachedNPCs = client.getCachedNPCs(); + NPC npc = cachedNPCs[event.getId()]; + lastPickpocketTarget = npc.getId(); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/thieving/PickpocketData.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/thieving/PickpocketData.java new file mode 100644 index 0000000000..d45328b1a4 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/thieving/PickpocketData.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.thieving; + +import lombok.AllArgsConstructor; +import lombok.Data; +import net.runelite.api.coords.WorldPoint; + +@Data +@AllArgsConstructor +public class PickpocketData +{ + private final int level; + private final int target; + private final String message; + private final WorldPoint location; + private final boolean silence; + private final boolean thievingCape; + private final int ardougneDiary; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/woodcutting/CrowdsourcingWoodcutting.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/woodcutting/CrowdsourcingWoodcutting.java new file mode 100644 index 0000000000..b3e1189103 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/woodcutting/CrowdsourcingWoodcutting.java @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.woodcutting; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.inject.Inject; +import net.runelite.api.AnimationID; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.ItemID; +import net.runelite.api.MenuAction; +import net.runelite.api.ObjectID; +import net.runelite.api.Skill; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.GameObjectDespawned; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.crowdsourcing.CrowdsourcingManager; +import net.runelite.client.plugins.crowdsourcing.skilling.SkillingEndReason; +import net.runelite.client.plugins.crowdsourcing.skilling.SkillingState; + +public class CrowdsourcingWoodcutting +{ + private static final String CHOPPING_MESSAGE = "You swing your axe at the tree."; + private static final String INVENTORY_FULL_MESSAGE = "Your inventory is too full to hold any more logs."; + private static final String NEST_MESSAGE = "A bird's nest falls out of the tree"; + private static final Set TREE_OBJECTS = new ImmutableSet.Builder(). + add(ObjectID.OAK_10820). + add(ObjectID.YEW). + add(ObjectID.TREE). + add(ObjectID.TREE_1278). + add(ObjectID.WILLOW). + add(ObjectID.WILLOW_10829). + add(ObjectID.WILLOW_10831). + add(ObjectID.WILLOW_10833). + add(ObjectID.SCRAPEY_TREE). + add(ObjectID.JUNGLE_TREE_15951). + add(ObjectID.JUNGLE_TREE_15954). + add(ObjectID.JUNGLE_TREE_15948). + add(ObjectID.MAPLE_TREE_10832). + add(ObjectID.MAHOGANY). + add(ObjectID.TEAK). + add(ObjectID.MAGIC_TREE_10834). + add(ObjectID.HOLLOW_TREE_10821). + add(ObjectID.HOLLOW_TREE_10830). + add(ObjectID.ACHEY_TREE). + build(); + + private static final Map AXE_ANIMS = new ImmutableMap.Builder(). + put(AnimationID.WOODCUTTING_BRONZE, ItemID.BRONZE_AXE). + put(AnimationID.WOODCUTTING_IRON, ItemID.IRON_AXE). + put(AnimationID.WOODCUTTING_STEEL, ItemID.STEEL_AXE). + put(AnimationID.WOODCUTTING_BLACK, ItemID.BLACK_AXE). + put(AnimationID.WOODCUTTING_MITHRIL, ItemID.MITHRIL_AXE). + put(AnimationID.WOODCUTTING_ADAMANT, ItemID.ADAMANT_AXE). + put(AnimationID.WOODCUTTING_RUNE, ItemID.RUNE_AXE). + put(AnimationID.WOODCUTTING_DRAGON, ItemID.DRAGON_AXE). + put(AnimationID.WOODCUTTING_INFERNAL, ItemID.INFERNAL_AXE). + put(AnimationID.WOODCUTTING_3A_AXE, ItemID._3RD_AGE_AXE). + put(AnimationID.WOODCUTTING_CRYSTAL, ItemID.CRYSTAL_AXE).build(); + + private static final Set SUCCESS_MESSAGES = new ImmutableSet.Builder(). + add("You get some logs."). + add("You get some oak logs."). + add("You get some willow logs."). + add("You get some teak logs."). + add("You get some teak logs and give them to Carpenter Kjallak."). + add("You get some maple logs."). + add("You get some maple logs and give them to Lumberjack Leif."). + add("You get some mahogany logs."). + add("You get some mahogany logs and give them to Carpenter Kjallak."). + add("You get some yew logs."). + add("You get some magic logs."). + add("You get some scrapey tree logs."). + add("You get some bark."). + build(); + + @Inject + private CrowdsourcingManager manager; + + @Inject + private Client client; + + private SkillingState state = SkillingState.RECOVERING; + private int lastExperimentEnd = 0; + private WorldPoint treeLocation; + private int treeId; + private int startTick; + private int axe; + private List chopTicks = new ArrayList<>(); + private List nestTicks = new ArrayList<>(); + + private void endExperiment(SkillingEndReason reason) + { + if (state == SkillingState.CUTTING) + { + int endTick = client.getTickCount(); + int woodcuttingLevel = client.getBoostedSkillLevel(Skill.WOODCUTTING); + WoodcuttingData data = new WoodcuttingData( + woodcuttingLevel, + startTick, + endTick, + chopTicks, + nestTicks, + axe, + treeId, + treeLocation, + reason + ); + manager.storeEvent(data); + + chopTicks = new ArrayList<>(); + nestTicks = new ArrayList<>(); + } + state = SkillingState.RECOVERING; + lastExperimentEnd = client.getTickCount(); + } + + @Subscribe + public void onChatMessage(ChatMessage event) + { + final String message = event.getMessage(); + final ChatMessageType type = event.getType(); + if (state == SkillingState.CLICKED && type == ChatMessageType.SPAM && message.equals(CHOPPING_MESSAGE)) + { + startTick = client.getTickCount(); + state = SkillingState.CUTTING; + } + else if (state == SkillingState.CUTTING && type == ChatMessageType.SPAM && SUCCESS_MESSAGES.contains(message)) + { + chopTicks.add(client.getTickCount()); + } + else if (state == SkillingState.CUTTING && type == ChatMessageType.GAMEMESSAGE && message.equals(INVENTORY_FULL_MESSAGE)) + { + endExperiment(SkillingEndReason.INVENTORY_FULL); + } + else if (state == SkillingState.CUTTING && type == ChatMessageType.GAMEMESSAGE && message.contains(NEST_MESSAGE)) + { + nestTicks.add(client.getTickCount()); + } + } + + @Subscribe + public void onGameTick(GameTick tick) + { + int animId = client.getLocalPlayer().getAnimation(); + if (state == SkillingState.CUTTING) + { + if (AXE_ANIMS.containsKey(animId)) + { + axe = AXE_ANIMS.get(animId); + } + else + { + endExperiment(SkillingEndReason.INTERRUPTED); + } + } + else if (animId != -1) + { + endExperiment(SkillingEndReason.INTERRUPTED); + } + else if (state == SkillingState.RECOVERING && client.getTickCount() - lastExperimentEnd >= 4) + { + state = SkillingState.READY; + } + else if (state == SkillingState.CLICKED && client.getTickCount() - lastExperimentEnd >= 20) + { + state = SkillingState.READY; + } + } + + @Subscribe + public void onMenuOptionClicked(MenuOptionClicked menuOptionClicked) + { + MenuAction menuAction = menuOptionClicked.getMenuAction(); + int id = menuOptionClicked.getId(); + if (state == SkillingState.READY && menuAction == MenuAction.GAME_OBJECT_FIRST_OPTION && TREE_OBJECTS.contains(id)) + { + state = SkillingState.CLICKED; + lastExperimentEnd = client.getTickCount(); + treeId = id; + treeLocation = WorldPoint.fromScene(client, menuOptionClicked.getActionParam(), menuOptionClicked.getWidgetId(), client.getPlane()); + } + else + { + endExperiment(SkillingEndReason.INTERRUPTED); + } + } + + @Subscribe + public void onGameObjectDespawned(GameObjectDespawned event) + { + if (state != SkillingState.CUTTING) + { + return; + } + if (treeId == event.getGameObject().getId() && treeLocation.equals(event.getTile().getWorldLocation())) + { + endExperiment(SkillingEndReason.DEPLETED); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/woodcutting/WoodcuttingData.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/woodcutting/WoodcuttingData.java new file mode 100644 index 0000000000..2cb6ccb2f2 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/woodcutting/WoodcuttingData.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.woodcutting; + +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Data; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.plugins.crowdsourcing.skilling.SkillingEndReason; + +@Data +@AllArgsConstructor +public class WoodcuttingData +{ + private final int level; + private final int startTick; + private final int endTick; + private final List chopTicks; + private final List nestTicks; + private final int axe; + private final int treeId; + private final WorldPoint treeLocation; + private final SkillingEndReason reason; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/zmi/CrowdsourcingZMI.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/zmi/CrowdsourcingZMI.java new file mode 100644 index 0000000000..2f76cd4741 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/zmi/CrowdsourcingZMI.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.zmi; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.google.common.collect.Multisets; +import java.util.Arrays; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.InventoryID; +import net.runelite.api.ItemContainer; +import net.runelite.api.MenuAction; +import net.runelite.api.Skill; +import net.runelite.api.Varbits; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.ItemContainerChanged; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.api.events.StatChanged; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.crowdsourcing.CrowdsourcingManager; + +public class CrowdsourcingZMI +{ + private static final String CHAT_MESSAGE_ZMI = "You bind the temple's power into runes."; + + @Inject + private CrowdsourcingManager manager; + + @Inject + private Client client; + + private int gameTickZMI = -1; + private int illegalActionTick = -1; + private int previousRunecraftXp = 0; + private int runecraftXpGained = 0; + private Multiset previousInventorySnapshot; + + private Multiset getInventorySnapshot() + { + final ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY); + Multiset inventorySnapshot = HashMultiset.create(); + + if (inventory != null) + { + Arrays.stream(inventory.getItems()) + .forEach(item -> inventorySnapshot.add(item.getId(), item.getQuantity())); + } + + return inventorySnapshot; + } + + @Subscribe + public void onMenuOptionClicked(MenuOptionClicked menuOptionClicked) + { + MenuAction action = menuOptionClicked.getMenuAction(); + + switch (action) + { + case ITEM_FIRST_OPTION: + case ITEM_SECOND_OPTION: + case ITEM_THIRD_OPTION: + case ITEM_FOURTH_OPTION: + case ITEM_FIFTH_OPTION: + case GROUND_ITEM_FIRST_OPTION: + case GROUND_ITEM_SECOND_OPTION: + case GROUND_ITEM_THIRD_OPTION: + case GROUND_ITEM_FOURTH_OPTION: + case GROUND_ITEM_FIFTH_OPTION: + case ITEM_DROP: + illegalActionTick = client.getTickCount(); + break; + } + } + + @Subscribe + public void onChatMessage(ChatMessage chatMessage) + { + if (chatMessage.getMessage().equals(CHAT_MESSAGE_ZMI)) + { + gameTickZMI = client.getTickCount(); + previousRunecraftXp = client.getSkillExperience(Skill.RUNECRAFT); + previousInventorySnapshot = getInventorySnapshot(); + } + } + + @Subscribe + public void onStatChanged(StatChanged statChanged) + { + if (gameTickZMI == client.getTickCount()) + { + int currentRunecraftXp = statChanged.getXp(); + runecraftXpGained = currentRunecraftXp - previousRunecraftXp; + } + } + + @Subscribe + public void onItemContainerChanged(ItemContainerChanged event) + { + int itemContainerChangedTick = client.getTickCount(); + + if (event.getItemContainer() != client.getItemContainer(InventoryID.INVENTORY) || gameTickZMI != itemContainerChangedTick) + { + return; + } + + int tickDelta = itemContainerChangedTick - illegalActionTick; + boolean ardougneMedium = client.getVar(Varbits.DIARY_ARDOUGNE_MEDIUM) == 1; + int runecraftBoostedLevel = client.getBoostedSkillLevel(Skill.RUNECRAFT); + Multiset currentInventorySnapshot = getInventorySnapshot(); + final Multiset itemsReceived = Multisets.difference(currentInventorySnapshot, previousInventorySnapshot); + final Multiset itemsRemoved = Multisets.difference(previousInventorySnapshot, currentInventorySnapshot); + + ZMIData data = new ZMIData(tickDelta, ardougneMedium, runecraftBoostedLevel, runecraftXpGained, itemsReceived, itemsRemoved); + manager.storeEvent(data); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/zmi/ZMIData.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/zmi/ZMIData.java new file mode 100644 index 0000000000..5c51b4d8aa --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/zmi/ZMIData.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019, Weird Gloop + * 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.crowdsourcing.zmi; + +import com.google.common.collect.Multiset; +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class ZMIData +{ + private final int tickDelta; + private final boolean ardougneMedium; + private final int level; + private final int xpGained; + private final Multiset itemsReceived; + private final Multiset itemsRemoved; +}