From d2cd880fd3cd5f13f4858d7532fec81ea6b6ad1d Mon Sep 17 00:00:00 2001 From: Magic fTail Date: Sun, 16 Dec 2018 01:23:31 +0100 Subject: [PATCH 1/4] Add the ability to use models in widgets Adds functions for setting rotation, id, and zoom of models --- .../java/net/runelite/api/widgets/Widget.java | 77 +++++++++++++++++-- .../java/net/runelite/rs/api/RSWidget.java | 35 ++++++++- 2 files changed, 101 insertions(+), 11 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java b/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java index 3aa6e23f13..63a188247a 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java @@ -240,13 +240,6 @@ public interface Widget */ void setName(String name); - /** - * Gets the model ID displayed in the widget. - * - * @return the model ID - */ - int getModelId(); - /** * Gets the sprite ID displayed in the widget. * @@ -292,6 +285,76 @@ public interface Widget */ int getIndex(); + /** + * Gets the model ID displayed in the widget. + * + * @return the model ID + */ + int getModelId(); + + /** + * Sets the model ID displayed in the widget + * + * @param modelId the new model ID + */ + void setModelId(int modelId); + + /** + * Gets the x rotation of the model displayed in the widget + * + * @return the x rotation + */ + int getRotationX(); + + /** + * Sets the x rotation of the model displayed in the widget + * + * @param rotationX 0 = no rotation, 2047 = full rotation, outside range = crash + */ + void setRotationX(int rotationX); + + /** + * Gets the y rotation of the model displayed in the widget + * + * @return the y rotation + */ + int getRotationY(); + + /** + * Sets the y rotation of the model displayed in the widget + * + * @param rotationY 0 = no rotation, 2047 = full rotation, outside range = crash + */ + void setRotationY(int rotationY); + + /** + * Gets the z rotation of the model displayed in the widget + * + * @return the z rotation + */ + int getRotationZ(); + + /** + * Sets the z rotation of the model displayed in the widget + * + * @param rotationZ 0 = no rotation, 2047 = full rotation, outside range = crash + */ + void setRotationZ(int rotationZ); + + /** + * Gets the amount zoomed in on the model displayed in the widget + * + * @return the amount zoomed in + */ + int getModelZoom(); + + /** + * Sets the amount zoomed in on the model displayed in the widget + * + * @param modelZoom the new zoom amount + */ + void setModelZoom(int modelZoom); + /** * Gets the location the widget is being drawn on the canvas. *

diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java b/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java index 75315b0514..773f44450f 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java @@ -65,10 +65,6 @@ public interface RSWidget extends Widget @Import("boundsIndex") int getBoundsIndex(); - @Import("modelId") - @Override - int getModelId(); - @Import("itemIds") int[] getItemIds(); @@ -156,15 +152,46 @@ public interface RSWidget extends Widget @Import("index") void setIndex(int index); + @Import("modelId") + @Override + int getModelId(); + + @Import("modelId") + @Override + void setModelId(int modelId); + @Import("rotationX") + @Override int getRotationX(); + @Import("rotationX") + @Override + void setRotationX(int rotationX); + @Import("rotationY") + @Override int getRotationY(); + @Import("rotationY") + @Override + void setRotationY(int rotationY); + @Import("rotationZ") + @Override int getRotationZ(); + @Import("rotationZ") + @Override + void setRotationZ(int rotationZ); + + @Import("modelZoom") + @Override + int getModelZoom(); + + @Import("modelZoom") + @Override + void setModelZoom(int modelZoom); + @Import("contentType") @Override int getContentType(); From 3bdf8aa2fcdcd0eaf7bdfbb8085cd25737a3a561 Mon Sep 17 00:00:00 2001 From: Magic fTail Date: Mon, 17 Dec 2018 03:04:20 +0100 Subject: [PATCH 2/4] Add level up message for virtual levels --- .../main/java/net/runelite/api/ModelID.java | 54 ++++ .../plugins/virtuallevels/SkillModel.java | 101 +++++++ .../virtuallevels/VirtualLevelsConfig.java | 44 +++ .../virtuallevels/VirtualLevelsPlugin.java | 260 +++++++++++++++++- 4 files changed, 458 insertions(+), 1 deletion(-) create mode 100644 runelite-api/src/main/java/net/runelite/api/ModelID.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/SkillModel.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/VirtualLevelsConfig.java diff --git a/runelite-api/src/main/java/net/runelite/api/ModelID.java b/runelite-api/src/main/java/net/runelite/api/ModelID.java new file mode 100644 index 0000000000..0a2ea46816 --- /dev/null +++ b/runelite-api/src/main/java/net/runelite/api/ModelID.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2018 Magic fTail + * 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.api; + +public final class ModelID +{ + public static final int ANVIL = 1251; + public static final int WILLOW_TREE = 1570; + public static final int SLAYER_SKILL_MODEL = 1733; + public static final int FIREMAKING_SKILL_MODEL = 2260; + public static final int STEEL_KITESHIELD = 2339; + public static final int PURE_ESSENCE = 2349; + public static final int RAW_TUNA = 2355; + public static final int CLEAN_HERB = 2364; + public static final int HAMMER = 2376; + public static final int BLUE_WIZARD_HAT = 2483; + public static final int CHISEL = 2489; + public static final int HIGHWAYMAN_MASK = 2500; + public static final int STEEL_PICKAXE = 2529; + public static final int SHORTBOW = 2562; + public static final int STEEL_LONGSWORD = 2602; + public static final int STEEL_SWORD = 2604; + public static final int STEEL_ARROW = 2711; + public static final int PRAYER_SKILL_MODEL = 3325; + public static final int STRENGTH_SKILL_MODEL = 3327; + public static final int AGILITY_SKILL_MODEL = 3328; + public static final int HEARTH = 3326; + public static final int WATERING_CAN = 7331; + public static final int SAW = 12309; + public static final int FOOTPRINT = 19980; + public static final int COOKING_SKILL_MODEL = 27611; +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/SkillModel.java b/runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/SkillModel.java new file mode 100644 index 0000000000..4076be73c7 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/SkillModel.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2018, Magic fTail + * 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.virtuallevels; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ListMultimap; +import java.util.List; +import lombok.Getter; +import net.runelite.api.ModelID; +import net.runelite.api.Skill; + +@Getter +public enum SkillModel +{ + CONSTRUCTION1(Skill.CONSTRUCTION, ModelID.HAMMER, 10, 14, 669, 0, 15, 329), + CONSTRUCTION2(Skill.CONSTRUCTION, ModelID.SAW, 11, 14, 615, 0, 111, 451), + COOKING(Skill.COOKING, ModelID.COOKING_SKILL_MODEL, 31, 59, 169, 0, 1593, 963), + CRAFTING1(Skill.CRAFTING, ModelID.HAMMER, 30, 24, 418, 0, 14, 496), + CRAFTING2(Skill.CRAFTING, ModelID.CHISEL, 39, 45, 353, 0, 18, 400), + DEFENCE(Skill.DEFENCE, ModelID.STEEL_KITESHIELD, 34, 37, 337, 0, 1074, 598), + FARMING(Skill.FARMING, ModelID.WATERING_CAN, 31, 52, 118, 0, 1278, 451), + FIREMAKING(Skill.FIREMAKING, ModelID.FIREMAKING_SKILL_MODEL, 29, 55, 115, 0, 1689, 771), + FISHING(Skill.FISHING, ModelID.RAW_TUNA, 33, 30, 351, 0, 1865, 517), + FLETCHING1(Skill.FLETCHING, ModelID.STEEL_ARROW, 43, 19, 254, 0, 1257, 408), + FLETCHING2(Skill.FLETCHING, ModelID.STEEL_ARROW, 46, 44, 223, 0, 177, 444), + HERBLORE(Skill.HERBLORE, ModelID.CLEAN_HERB, 20, 35, 550, 0, 2024, 344), + HITPOINTS(Skill.HITPOINTS, ModelID.HEARTH, 35, 58, 538, 0, 0, 250), + MAGIC(Skill.MAGIC, ModelID.BLUE_WIZARD_HAT, 29, 50, 131, 0, 1913, 344), + MINING(Skill.MINING, ModelID.STEEL_PICKAXE, 38, 33, 292, 0, 1166, 413), + PRAYER(Skill.PRAYER, ModelID.PRAYER_SKILL_MODEL, 29, 27, 582, 0, 504, 505), + RANGED1(Skill.RANGED, ModelID.STEEL_ARROW, 28, 34, 206, 0, 195, 405), + RANGED2(Skill.RANGED, ModelID.SHORTBOW, 42, 17, 422, 0, 1618, 397), + RUNECRAFT(Skill.RUNECRAFT, ModelID.PURE_ESSENCE, 35, 38, 242, 0, 1979, 328), + SLAYER(Skill.SLAYER, ModelID.SLAYER_SKILL_MODEL, 34, 60, 221, 0, 1944, 649), + SMITHING(Skill.SMITHING, ModelID.ANVIL, 34, 53, 97, 0, 1868, 716), + STRENGTH(Skill.STRENGTH, ModelID.STRENGTH_SKILL_MODEL, 35, 23, 512, 0, 14, 631), + AGILITY(Skill.AGILITY, ModelID.AGILITY_SKILL_MODEL, 29, 29, 533, 0, 2040, 685), + THIEVING(Skill.THIEVING, ModelID.HIGHWAYMAN_MASK, 42, 31, 366, 0, 55, 155), + WOODCUTTING(Skill.WOODCUTTING, ModelID.WILLOW_TREE, 20, 69, 116, 0, 1978, 1800), + ATTACK1(Skill.ATTACK, ModelID.STEEL_SWORD, 65, 38, 234, 0, 148, 444), + ATTACK2(Skill.ATTACK, ModelID.STEEL_LONGSWORD, 27, 29, 198, 0, 1419, 330), + HUNTER(Skill.HUNTER, ModelID.FOOTPRINT, 45, 48, 512, 0, 0, 1000); + + private static final ListMultimap skillModels = ArrayListMultimap.create(); + + private final Skill skill; + private final int modelID; + private final int originalX; + private final int originalY; + private final int rotationX; + private final int rotationY; + private final int rotationZ; + private final int modelZoom; + + SkillModel(Skill skill, int modelID, int originalX, int originalY, int rotationX, int rotationY, int rotationZ, int modelZoom) + { + this.skill = skill; + this.modelID = modelID; + this.originalX = originalX; + this.originalY = originalY; + this.rotationX = rotationX; + this.rotationY = rotationY; + this.rotationZ = rotationZ; + this.modelZoom = modelZoom; + } + + static + { + for (SkillModel skillModel : values()) + { + skillModels.put(skillModel.skill, skillModel); + } + } + + public static List getSkillModels(Skill skill) + { + return skillModels.get(skill); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/VirtualLevelsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/VirtualLevelsConfig.java new file mode 100644 index 0000000000..83e611f737 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/VirtualLevelsConfig.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2018, Magic fTail + * 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.virtuallevels; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("virtualLvl") +public interface VirtualLevelsConfig extends Config +{ + @ConfigItem( + keyName = "virtualMessage", + name = "Enable level up message for virtual levels", + description = "Configures whether or not to show level up messages for virtual levels", + position = 0 + ) + default boolean virtualMessage() + { + return true; + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/VirtualLevelsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/VirtualLevelsPlugin.java index 879110bb2b..05a2b597ab 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/VirtualLevelsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/VirtualLevelsPlugin.java @@ -1,6 +1,7 @@ /* * Copyright (c) 2018, Joshua Filby * Copyright (c) 2018, Jordan Atwood + * Copyright (c) 2018, Magic fTail * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,14 +26,37 @@ */ package net.runelite.client.plugins.virtuallevels; +import com.google.inject.Provides; +import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.List; +import java.util.Map; import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.Experience; +import net.runelite.api.FontID; +import net.runelite.api.GameState; +import net.runelite.api.ScriptID; import net.runelite.api.Skill; +import net.runelite.api.events.ExperienceChanged; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.GameTick; import net.runelite.api.events.ScriptCallbackEvent; +import net.runelite.api.widgets.JavaScriptCallback; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.api.widgets.WidgetPositionMode; +import net.runelite.api.widgets.WidgetSizeMode; +import net.runelite.api.widgets.WidgetTextAlignment; +import net.runelite.api.widgets.WidgetType; import net.runelite.client.callback.ClientThread; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.EventBus; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.PluginChanged; +import net.runelite.client.input.KeyListener; +import net.runelite.client.input.KeyManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; @@ -42,9 +66,11 @@ import net.runelite.client.plugins.PluginDescriptor; tags = {"skill", "total", "max"}, enabledByDefault = false ) -public class VirtualLevelsPlugin extends Plugin +public class VirtualLevelsPlugin extends Plugin implements KeyListener { private static final String TOTAL_LEVEL_TEXT_PREFIX = "Total level:
"; + private static final int X_OFFSET = 13; + private static final int Y_OFFSET = 16; @Inject private Client client; @@ -52,10 +78,33 @@ public class VirtualLevelsPlugin extends Plugin @Inject private ClientThread clientThread; + @Inject + private VirtualLevelsConfig config; + + @Inject + private EventBus eventBus; + + @Inject + private KeyManager keyManager; + + private final Map previousXpMap = new EnumMap<>(Skill.class); + + private final List skillsLeveledUp = new ArrayList<>(); + + private boolean closeMessage; + private boolean messageOpen; + + @Provides + VirtualLevelsConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(VirtualLevelsConfig.class); + } + @Override protected void shutDown() { clientThread.invoke(this::simulateSkillChange); + keyManager.unregisterKeyListener(this); } @Subscribe @@ -64,6 +113,7 @@ public class VirtualLevelsPlugin extends Plugin // this is guaranteed to be called after the plugin has been registered by the eventbus. startUp is not. if (pluginChanged.getPlugin() == this) { + keyManager.registerKeyListener(this); clientThread.invoke(this::simulateSkillChange); } } @@ -121,4 +171,212 @@ public class VirtualLevelsPlugin extends Plugin } } } + + private void buildVirtualLevelUp(Skill skill) + { + Widget chatboxContainer = client.getWidget(WidgetInfo.CHATBOX_CONTAINER); + + if (chatboxContainer == null) + { + return; + } + + String skillName = skill.getName(); + int skillLevel = Experience.getLevelForXp(client.getSkillExperience(skill)); + List skillModels = SkillModel.getSkillModels(skill); + String prefix = (skill == Skill.AGILITY || skill == Skill.ATTACK) ? "an " : "a "; + + Widget levelUpLevel = chatboxContainer.createChild(-1, WidgetType.TEXT); + Widget levelUpText = chatboxContainer.createChild(-1, WidgetType.TEXT); + Widget levelUpContinue = chatboxContainer.createChild(-1, WidgetType.TEXT); + + levelUpLevel.setText("Congratulations, you just advanced " + prefix + skillName + " level."); + levelUpLevel.setTextColor(0x000080); + levelUpLevel.setFontId(FontID.QUILL_8); + levelUpLevel.setXPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + levelUpLevel.setOriginalX(73 + X_OFFSET); + levelUpLevel.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + levelUpLevel.setOriginalY(15 + Y_OFFSET); + levelUpLevel.setOriginalWidth(390); + levelUpLevel.setOriginalHeight(30); + levelUpLevel.setXTextAlignment(WidgetTextAlignment.CENTER); + levelUpLevel.setYTextAlignment(WidgetTextAlignment.LEFT); + levelUpLevel.setWidthMode(WidgetSizeMode.ABSOLUTE); + levelUpLevel.revalidate(); + + levelUpText.setText((skill == Skill.HITPOINTS ? "Your Hitpoints are now " + skillLevel : + "Your " + skillName + " level is now " + skillLevel) + "."); + levelUpText.setFontId(FontID.QUILL_8); + levelUpText.setXPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + levelUpText.setOriginalX(73 + X_OFFSET); + levelUpText.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + levelUpText.setOriginalY(44 + Y_OFFSET); + levelUpText.setOriginalWidth(390); + levelUpText.setOriginalHeight(30); + levelUpText.setXTextAlignment(WidgetTextAlignment.CENTER); + levelUpText.setYTextAlignment(WidgetTextAlignment.LEFT); + levelUpText.setWidthMode(WidgetSizeMode.ABSOLUTE); + levelUpText.revalidate(); + + levelUpContinue.setText("Click here to continue"); + levelUpContinue.setTextColor(0x0000ff); + levelUpContinue.setFontId(FontID.QUILL_8); + levelUpContinue.setXPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + levelUpContinue.setOriginalX(73 + X_OFFSET); + levelUpContinue.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + levelUpContinue.setOriginalY(74 + Y_OFFSET); + levelUpContinue.setOriginalWidth(390); + levelUpContinue.setOriginalHeight(17); + levelUpContinue.setXTextAlignment(WidgetTextAlignment.CENTER); + levelUpContinue.setYTextAlignment(WidgetTextAlignment.LEFT); + levelUpContinue.setWidthMode(WidgetSizeMode.ABSOLUTE); + levelUpContinue.setAction(0, "Continue"); + levelUpContinue.setOnOpListener((JavaScriptCallback) ev -> closeNextTick()); + levelUpContinue.setOnMouseOverListener((JavaScriptCallback) ev -> levelUpContinue.setTextColor(0xFFFFFF)); + levelUpContinue.setOnMouseLeaveListener((JavaScriptCallback) ev -> levelUpContinue.setTextColor(0x0000ff)); + levelUpContinue.setHasListener(true); + levelUpContinue.revalidate(); + + for (SkillModel skillModel : skillModels) + { + buildWidgetModel(chatboxContainer, skillModel); + } + + messageOpen = true; + } + + private void buildWidgetModel(Widget chatboxContainer, SkillModel model) + { + int iconWidth = 32; + int iconHeight = 32; + + if (model.getSkill() == Skill.CONSTRUCTION) + { + iconWidth = 49; + iconHeight = 61; + } + + Widget levelUpModel = chatboxContainer.createChild(-1, WidgetType.MODEL); + + levelUpModel.setModelId(model.getModelID()); + levelUpModel.setXPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + levelUpModel.setOriginalX(model.getOriginalX() + X_OFFSET); + levelUpModel.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + levelUpModel.setOriginalY(model.getOriginalY() + Y_OFFSET); + levelUpModel.setOriginalWidth(iconWidth); + levelUpModel.setOriginalHeight(iconHeight); + levelUpModel.setRotationX(model.getRotationX()); + levelUpModel.setRotationY(model.getRotationY()); + levelUpModel.setRotationZ(model.getRotationZ()); + levelUpModel.setModelZoom(model.getModelZoom()); + levelUpModel.revalidate(); + } + + private void closeNextTick() + { + if (!messageOpen) + { + return; + } + + Widget levelUpContinue = client.getWidget(WidgetInfo.CHATBOX_CONTAINER).getChild(2); + + levelUpContinue.setText("Please wait..."); + + messageOpen = false; + closeMessage = true; + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + if (event.getGameState() != GameState.LOGGED_IN) + { + return; + } + + for (Skill skill : Skill.values()) + { + previousXpMap.put(skill, client.getSkillExperience(skill)); + } + } + + @Subscribe + public void onExperienceChanged(ExperienceChanged event) + { + Skill skill = event.getSkill(); + + int xpAfter = client.getSkillExperience(skill); + int levelAfter = Experience.getLevelForXp(xpAfter); + + int xpBefore = previousXpMap.get(skill); + int levelBefore = Experience.getLevelForXp(xpBefore); + + previousXpMap.put(skill, xpAfter); + + if (!config.virtualMessage() || levelAfter < 100 || levelBefore >= levelAfter) + { + return; + } + + skillsLeveledUp.add(skill); + } + + @Subscribe + public void onGameTick(GameTick event) + { + if (closeMessage) + { + clientThread.invoke(() -> client.runScript( + ScriptID.RESET_CHATBOX_INPUT, + 1, + 1 + )); + + closeMessage = false; + } + + if (skillsLeveledUp.isEmpty()) + { + return; + } + + Widget chatboxContainer = client.getWidget(WidgetInfo.CHATBOX_CONTAINER); + + if (chatboxContainer != null && !chatboxContainer.isHidden()) + { + return; + } + + Skill skill = skillsLeveledUp.get(0); + + skillsLeveledUp.remove(skill); + + clientThread.invoke(() -> client.runScript(ScriptID.CLEAR_CHATBOX_PANEL)); + clientThread.invoke(() -> buildVirtualLevelUp(skill)); + } + + @Override + public void keyTyped(KeyEvent e) + { + if (e.getKeyChar() != ' ') + { + return; + } + + if (messageOpen) + { + closeNextTick(); + } + } + + @Override + public void keyPressed(KeyEvent e) + { + } + + @Override + public void keyReleased(KeyEvent e) + { + } } From e0aa7dc67f492d6c1172ecdd8a874afb68210b02 Mon Sep 17 00:00:00 2001 From: Magic fTail Date: Mon, 17 Dec 2018 08:50:08 +0100 Subject: [PATCH 3/4] Add support for the virtual level up message to screenshot plugin --- .../plugins/screenshot/ScreenshotPlugin.java | 22 +++++++----- .../virtuallevels/VirtualLevelsPlugin.java | 5 +++ .../screenshot/ScreenshotPluginTest.java | 34 +++++++++---------- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java index 9cfd1c8d68..02ffc71bb8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java @@ -68,6 +68,7 @@ import net.runelite.api.events.WidgetLoaded; import net.runelite.api.widgets.Widget; import static net.runelite.api.widgets.WidgetID.BARROWS_REWARD_GROUP_ID; import static net.runelite.api.widgets.WidgetID.CHAMBERS_OF_XERIC_REWARD_GROUP_ID; +import static net.runelite.api.widgets.WidgetID.CHATBOX_GROUP_ID; import static net.runelite.api.widgets.WidgetID.CLUE_SCROLL_REWARD_GROUP_ID; import static net.runelite.api.widgets.WidgetID.DIALOG_SPRITE_GROUP_ID; import static net.runelite.api.widgets.WidgetID.KINGDOM_GROUP_ID; @@ -265,11 +266,11 @@ public class ScreenshotPlugin extends Plugin String fileName = null; if (client.getWidget(WidgetInfo.LEVEL_UP_LEVEL) != null) { - fileName = parseLevelUpWidget(WidgetInfo.LEVEL_UP_LEVEL); + fileName = parseLevelUpWidget(client.getWidget(WidgetInfo.LEVEL_UP_LEVEL)); } else if (client.getWidget(WidgetInfo.DIALOG_SPRITE_TEXT) != null) { - fileName = parseLevelUpWidget(WidgetInfo.DIALOG_SPRITE_TEXT); + fileName = parseLevelUpWidget(client.getWidget(WidgetInfo.DIALOG_SPRITE_TEXT)); } else if (client.getWidget(WidgetInfo.QUEST_COMPLETED_NAME_TEXT) != null) { @@ -277,6 +278,10 @@ public class ScreenshotPlugin extends Plugin String text = client.getWidget(WidgetInfo.QUEST_COMPLETED_NAME_TEXT).getText(); fileName = "Quest(" + text.substring(19, text.length() - 1) + ")"; } + else if (client.getWidget(WidgetInfo.CHATBOX_CONTAINER).getChild(1) != null) + { + fileName = parseLevelUpWidget(client.getWidget(WidgetInfo.CHATBOX_CONTAINER).getChild(1)); + } if (fileName != null) { @@ -401,6 +406,7 @@ public class ScreenshotPlugin extends Plugin break; case LEVEL_UP_GROUP_ID: case DIALOG_SPRITE_GROUP_ID: + case CHATBOX_GROUP_ID: if (!config.screenshotLevels()) { return; @@ -458,6 +464,7 @@ public class ScreenshotPlugin extends Plugin case LEVEL_UP_GROUP_ID: case DIALOG_SPRITE_GROUP_ID: case QUEST_COMPLETED_GROUP_ID: + case CHATBOX_GROUP_ID: { // level up widget gets loaded prior to the text being set, so wait until the next tick shouldTakeScreenshot = true; @@ -483,22 +490,21 @@ public class ScreenshotPlugin extends Plugin } /** - * Receives a WidgetInfo pointing to the middle widget of the level-up dialog, + * Receives a Widget containing the level-up dialog, * and parses it into a shortened string for filename usage. * - * @param levelUpLevel WidgetInfo pointing to the required text widget, + * @param levelUpWidget Widget containing the level-up text, * with the format "Your Skill (level is/are) now 99." * @return Shortened string in the format "Skill(99)" */ - String parseLevelUpWidget(WidgetInfo levelUpLevel) + String parseLevelUpWidget(Widget levelUpWidget) { - Widget levelChild = client.getWidget(levelUpLevel); - if (levelChild == null) + if (levelUpWidget == null) { return null; } - Matcher m = LEVEL_UP_PATTERN.matcher(levelChild.getText()); + Matcher m = LEVEL_UP_PATTERN.matcher(levelUpWidget.getText()); if (!m.matches()) { return null; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/VirtualLevelsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/VirtualLevelsPlugin.java index 05a2b597ab..1bdfcdbb53 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/VirtualLevelsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/virtuallevels/VirtualLevelsPlugin.java @@ -43,8 +43,10 @@ import net.runelite.api.events.ExperienceChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.api.events.ScriptCallbackEvent; +import net.runelite.api.events.WidgetLoaded; import net.runelite.api.widgets.JavaScriptCallback; import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetInfo; import net.runelite.api.widgets.WidgetPositionMode; import net.runelite.api.widgets.WidgetSizeMode; @@ -354,6 +356,9 @@ public class VirtualLevelsPlugin extends Plugin implements KeyListener clientThread.invoke(() -> client.runScript(ScriptID.CLEAR_CHATBOX_PANEL)); clientThread.invoke(() -> buildVirtualLevelUp(skill)); + WidgetLoaded widgetLoaded = new WidgetLoaded(); + widgetLoaded.setGroupId(WidgetID.CHATBOX_GROUP_ID); + eventBus.post(widgetLoaded); } @Override diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/screenshot/ScreenshotPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/screenshot/ScreenshotPluginTest.java index 765ca672df..b2ddb21f68 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/screenshot/ScreenshotPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/screenshot/ScreenshotPluginTest.java @@ -167,12 +167,12 @@ public class ScreenshotPluginTest Widget widget = mock(Widget.class); when(widget.getId()).thenReturn(PACK(LEVEL_UP_GROUP_ID, 0)); - Widget levelChild = mock(Widget.class); - when(client.getWidget(Matchers.eq(LEVEL_UP_LEVEL))).thenReturn(levelChild); + Widget levelUpWidget = mock(Widget.class); + when(client.getWidget(Matchers.eq(LEVEL_UP_LEVEL))).thenReturn(levelUpWidget); - when(levelChild.getText()).thenReturn("Your Hitpoints are now 99."); + when(levelUpWidget.getText()).thenReturn("Your Hitpoints are now 99."); - assertEquals("Hitpoints(99)", screenshotPlugin.parseLevelUpWidget(LEVEL_UP_LEVEL)); + assertEquals("Hitpoints(99)", screenshotPlugin.parseLevelUpWidget(levelUpWidget)); WidgetLoaded event = new WidgetLoaded(); event.setGroupId(LEVEL_UP_GROUP_ID); @@ -190,12 +190,12 @@ public class ScreenshotPluginTest Widget widget = mock(Widget.class); when(widget.getId()).thenReturn(PACK(LEVEL_UP_GROUP_ID, 0)); - Widget levelChild = mock(Widget.class); - when(client.getWidget(Matchers.eq(LEVEL_UP_LEVEL))).thenReturn(levelChild); + Widget levelUpWidget = mock(Widget.class); + when(client.getWidget(Matchers.eq(LEVEL_UP_LEVEL))).thenReturn(levelUpWidget); - when(levelChild.getText()).thenReturn("Your Firemaking level is now 9."); + when(levelUpWidget.getText()).thenReturn("Your Firemaking level is now 9."); - assertEquals("Firemaking(9)", screenshotPlugin.parseLevelUpWidget(LEVEL_UP_LEVEL)); + assertEquals("Firemaking(9)", screenshotPlugin.parseLevelUpWidget(levelUpWidget)); WidgetLoaded event = new WidgetLoaded(); event.setGroupId(LEVEL_UP_GROUP_ID); @@ -213,12 +213,12 @@ public class ScreenshotPluginTest Widget widget = mock(Widget.class); when(widget.getId()).thenReturn(PACK(LEVEL_UP_GROUP_ID, 0)); - Widget levelChild = mock(Widget.class); - when(client.getWidget(Matchers.eq(LEVEL_UP_LEVEL))).thenReturn(levelChild); + Widget levelUpWidget = mock(Widget.class); + when(client.getWidget(Matchers.eq(LEVEL_UP_LEVEL))).thenReturn(levelUpWidget); - when(levelChild.getText()).thenReturn("Your Attack level is now 70."); + when(levelUpWidget.getText()).thenReturn("Your Attack level is now 70."); - assertEquals("Attack(70)", screenshotPlugin.parseLevelUpWidget(LEVEL_UP_LEVEL)); + assertEquals("Attack(70)", screenshotPlugin.parseLevelUpWidget(levelUpWidget)); WidgetLoaded event = new WidgetLoaded(); event.setGroupId(LEVEL_UP_GROUP_ID); @@ -236,12 +236,12 @@ public class ScreenshotPluginTest Widget widget = mock(Widget.class); when(widget.getId()).thenReturn(PACK(DIALOG_SPRITE_GROUP_ID, 0)); - Widget levelChild = mock(Widget.class); - when(client.getWidget(Matchers.eq(DIALOG_SPRITE_TEXT))).thenReturn(levelChild); + Widget levelUpWidget = mock(Widget.class); + when(client.getWidget(Matchers.eq(DIALOG_SPRITE_TEXT))).thenReturn(levelUpWidget); - when(levelChild.getText()).thenReturn("Congratulations, you've just advanced a Hunter level.

Your Hunter level is now 2."); + when(levelUpWidget.getText()).thenReturn("Congratulations, you've just advanced a Hunter level.

Your Hunter level is now 2."); - assertEquals("Hunter(2)", screenshotPlugin.parseLevelUpWidget(DIALOG_SPRITE_TEXT)); + assertEquals("Hunter(2)", screenshotPlugin.parseLevelUpWidget(levelUpWidget)); WidgetLoaded event = new WidgetLoaded(); event.setGroupId(DIALOG_SPRITE_GROUP_ID); @@ -252,4 +252,4 @@ public class ScreenshotPluginTest verify(drawManager).requestNextFrameListener(Matchers.any(Consumer.class)); } -} +} \ No newline at end of file From 79c2acaf378ad00114daa63864df4b63df7e31c9 Mon Sep 17 00:00:00 2001 From: Owain van Brakel Date: Thu, 28 Nov 2019 03:45:54 +0100 Subject: [PATCH 4/4] devtools: Add new widget values to the widget inspector --- .../client/plugins/devtools/WidgetInfoTableModel.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java index 91180a5125..3e6898ebb3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java @@ -175,6 +175,10 @@ class WidgetInfoTableModel extends AbstractTableModel out.add(new WidgetField<>("RelativeY", Widget::getRelativeY, Widget::setRelativeY, Integer.class)); out.add(new WidgetField<>("Width", Widget::getWidth, Widget::setWidth, Integer.class)); out.add(new WidgetField<>("Height", Widget::getHeight, Widget::setHeight, Integer.class)); + out.add(new WidgetField<>("RotationX", Widget::getRotationX, Widget::setRotationX, Integer.class)); + out.add(new WidgetField<>("RotationY", Widget::getRotationY, Widget::setRotationY, Integer.class)); + out.add(new WidgetField<>("RotationZ", Widget::getRotationZ, Widget::setRotationZ, Integer.class)); + out.add(new WidgetField<>("ModelZoom", Widget::getModelZoom, Widget::setModelZoom, Integer.class)); out.add(new WidgetField<>("CanvasLocation", Widget::getCanvasLocation)); out.add(new WidgetField<>("Bounds", Widget::getBounds)); out.add(new WidgetField<>("ScrollX", Widget::getScrollX, Widget::setScrollX, Integer.class));