From 1b0cf969d78af6fd40bb3913b0cacac6b91501bb Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Tue, 11 Feb 2020 13:52:42 -0800 Subject: [PATCH 01/23] ClueScrollPlugin: Reset clue on empty dev command Fixes runelite/runelite#10775 --- .../plugins/cluescrolls/ClueScrollPlugin.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java index 8e09fd6a85..6946e1c64a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java @@ -458,9 +458,17 @@ public class ClueScrollPlugin extends Plugin if (developerMode && commandExecuted.getCommand().equals("clue")) { String text = Strings.join(commandExecuted.getArguments(), " "); - ClueScroll clueScroll = findClueScroll(text); - log.debug("Found clue scroll for '{}': {}", text, clueScroll); - updateClue(clueScroll); + + if (text.isEmpty()) + { + resetClue(true); + } + else + { + ClueScroll clueScroll = findClueScroll(text); + log.debug("Found clue scroll for '{}': {}", text, clueScroll); + updateClue(clueScroll); + } } } From 5b28f343ca01a7745d1c3bf8db51db6de411fe7d Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Tue, 11 Feb 2020 13:53:12 -0800 Subject: [PATCH 02/23] clues: Don't return clue instances for empty text This commit ensures that all clues providing a static `forText()` method return null when given an empty string as clue text. --- .../cluescrolls/clues/AnagramClue.java | 7 +++- .../plugins/cluescrolls/clues/CipherClue.java | 9 +++-- .../cluescrolls/clues/CrypticClue.java | 12 +++--- .../cluescrolls/clues/AnagramClueTest.java | 37 ++++++++++++++++++ .../cluescrolls/clues/CipherClueTest.java | 37 ++++++++++++++++++ .../cluescrolls/clues/CrypticClueTest.java | 37 ++++++++++++++++++ .../cluescrolls/clues/EmoteClueTest.java | 37 ++++++++++++++++++ .../cluescrolls/clues/FairyRingClueTest.java | 37 ++++++++++++++++++ .../clues/FaloTheBardClueTest.java | 38 +++++++++++++++++++ .../cluescrolls/clues/HotColdClueTest.java | 37 ++++++++++++++++++ .../cluescrolls/clues/MusicClueTest.java | 37 ++++++++++++++++++ .../clues/SkillChallengeClueTest.java | 37 ++++++++++++++++++ .../clues/ThreeStepCrypticClueTest.java | 37 ++++++++++++++++++ 13 files changed, 389 insertions(+), 10 deletions(-) create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClueTest.java create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CipherClueTest.java create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClueTest.java create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClueTest.java create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/FairyRingClueTest.java create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/FaloTheBardClueTest.java create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClueTest.java create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/MusicClueTest.java create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClueTest.java create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClueTest.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java index 5c8e38e72a..e4ab711031 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java @@ -28,6 +28,7 @@ import com.google.common.collect.ImmutableSet; import java.awt.Color; import java.awt.Graphics2D; import java.util.Set; +import javax.annotation.Nullable; import lombok.Getter; import net.runelite.api.NPC; import net.runelite.api.ObjectID; @@ -171,16 +172,18 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc private final String npc; private final WorldPoint location; private final String area; + @Nullable private final String question; + @Nullable private final String answer; private int objectId; private AnagramClue(String text, String npc, WorldPoint location, String area) { - this(text, npc, location, area, "", null); + this(text, npc, location, area, null, null); } - private AnagramClue(String text, String npc, WorldPoint location, String area, String question, String answer) + private AnagramClue(String text, String npc, WorldPoint location, String area, @Nullable String question, @Nullable String answer) { this.text = text; this.npc = npc; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java index e59e25eb56..68024e1c6a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java @@ -28,6 +28,7 @@ import com.google.common.collect.ImmutableSet; import java.awt.Color; import java.awt.Graphics2D; import java.util.Set; +import javax.annotation.Nullable; import lombok.Getter; import net.runelite.api.NPC; import net.runelite.api.coords.WorldPoint; @@ -64,15 +65,17 @@ public class CipherClue extends ClueScroll implements TextClueScroll, NpcClueScr private String npc; private WorldPoint location; private String area; + @Nullable private String question; + @Nullable private String answer; private CipherClue(String text, String npc, WorldPoint location, String area) { - this(text, npc, location, area, "", null); + this(text, npc, location, area, null, null); } - private CipherClue(String text, String npc, WorldPoint location, String area, String question, String answer) + private CipherClue(String text, String npc, WorldPoint location, String area, @Nullable String question, @Nullable String answer) { this.text = "The cipher reveals who to speak to next: " + text; this.npc = npc; @@ -129,7 +132,7 @@ public class CipherClue extends ClueScroll implements TextClueScroll, NpcClueScr { for (CipherClue clue : CLUES) { - if (clue.text.equalsIgnoreCase(text) || clue.question.equalsIgnoreCase(text)) + if (text.equalsIgnoreCase(clue.text) || text.equalsIgnoreCase(clue.question)) { return clue; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java index bd1c30c01c..636765cd61 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java @@ -28,6 +28,7 @@ import com.google.common.collect.ImmutableSet; import java.awt.Color; import java.awt.Graphics2D; import java.util.Set; +import javax.annotation.Nullable; import lombok.Getter; import net.runelite.api.NPC; import static net.runelite.api.NullObjectID.NULL_1293; @@ -331,6 +332,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc private final int objectId; private final WorldPoint location; private final String solution; + @Nullable private final String questionText; private CrypticClue(String text, WorldPoint location, String solution) @@ -340,12 +342,12 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc private CrypticClue(String text, int objectId, WorldPoint location, String solution) { - this(text, null, objectId, location, solution, ""); + this(text, null, objectId, location, solution, null); } private CrypticClue(String text, String npc, WorldPoint location, String solution) { - this(text, npc, -1, location, solution, ""); + this(text, npc, -1, location, solution, null); } private CrypticClue(String text, String npc, WorldPoint location, String solution, boolean requiresLight) @@ -366,10 +368,10 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc private CrypticClue(String text, String npc, int objectId, WorldPoint location, String solution) { - this(text, npc, objectId, location, solution, ""); + this(text, npc, objectId, location, solution, null); } - private CrypticClue(String text, String npc, int objectId, WorldPoint location, String solution, String questionText) + private CrypticClue(String text, String npc, int objectId, WorldPoint location, String solution, @Nullable String questionText) { this.text = text; this.npc = npc; @@ -465,7 +467,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc { for (CrypticClue clue : CLUES) { - if (clue.text.equalsIgnoreCase(text) || clue.questionText.equalsIgnoreCase(text)) + if (text.equalsIgnoreCase(clue.text) || text.equalsIgnoreCase(clue.questionText)) { return clue; } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClueTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClueTest.java new file mode 100644 index 0000000000..6e45d5b926 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClueTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, Jordan Atwood + * 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.cluescrolls.clues; + +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class AnagramClueTest +{ + @Test + public void forTextEmptyString() + { + assertNull(AnagramClue.forText("")); + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CipherClueTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CipherClueTest.java new file mode 100644 index 0000000000..def55ef922 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CipherClueTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, Jordan Atwood + * 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.cluescrolls.clues; + +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class CipherClueTest +{ + @Test + public void forTextEmptyString() + { + assertNull(CipherClue.forText("")); + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClueTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClueTest.java new file mode 100644 index 0000000000..27511a27c6 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClueTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, Jordan Atwood + * 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.cluescrolls.clues; + +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class CrypticClueTest +{ + @Test + public void forTextEmptyString() + { + assertNull(CrypticClue.forText("")); + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClueTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClueTest.java new file mode 100644 index 0000000000..cc82f9fca2 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClueTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, Jordan Atwood + * 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.cluescrolls.clues; + +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class EmoteClueTest +{ + @Test + public void forTextEmptyString() + { + assertNull(EmoteClue.forText("")); + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/FairyRingClueTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/FairyRingClueTest.java new file mode 100644 index 0000000000..db38dcab8e --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/FairyRingClueTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, Jordan Atwood + * 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.cluescrolls.clues; + +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class FairyRingClueTest +{ + @Test + public void forTextEmptyString() + { + assertNull(FairyRingClue.forText("")); + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/FaloTheBardClueTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/FaloTheBardClueTest.java new file mode 100644 index 0000000000..51853e4c85 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/FaloTheBardClueTest.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020, Jordan Atwood + * 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.cluescrolls.clues; + +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class FaloTheBardClueTest +{ + @Test + public void forTextEmptyString() + { + assertNull(FaloTheBardClue.forText("")); + } + +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClueTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClueTest.java new file mode 100644 index 0000000000..6906764624 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClueTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, Jordan Atwood + * 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.cluescrolls.clues; + +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class HotColdClueTest +{ + @Test + public void forTextEmptyString() + { + assertNull(HotColdClue.forText("")); + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/MusicClueTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/MusicClueTest.java new file mode 100644 index 0000000000..f5cd70f6ab --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/MusicClueTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, Jordan Atwood + * 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.cluescrolls.clues; + +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class MusicClueTest +{ + @Test + public void forTextEmptyString() + { + assertNull(MusicClue.forText("")); + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClueTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClueTest.java new file mode 100644 index 0000000000..d359bed2f4 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClueTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, Jordan Atwood + * 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.cluescrolls.clues; + +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class SkillChallengeClueTest +{ + @Test + public void forTextEmptyString() + { + assertNull(SkillChallengeClue.forText("", "")); + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClueTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClueTest.java new file mode 100644 index 0000000000..a3ca74a577 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/ThreeStepCrypticClueTest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, Jordan Atwood + * 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.cluescrolls.clues; + +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class ThreeStepCrypticClueTest +{ + @Test + public void forTextEmptyString() + { + assertNull(ThreeStepCrypticClue.forText("", "")); + } +} From c0913f2f7cd8899dd09630ab8e905e559f05061a Mon Sep 17 00:00:00 2001 From: Trevor Date: Sat, 8 Feb 2020 16:38:11 -0500 Subject: [PATCH 03/23] client: add notification fired event --- .../java/net/runelite/client/Notifier.java | 9 ++++- .../client/events/NotificationFired.java | 35 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/events/NotificationFired.java diff --git a/runelite-client/src/main/java/net/runelite/client/Notifier.java b/runelite-client/src/main/java/net/runelite/client/Notifier.java index 83cf8c0a3b..5a61dd592a 100644 --- a/runelite-client/src/main/java/net/runelite/client/Notifier.java +++ b/runelite-client/src/main/java/net/runelite/client/Notifier.java @@ -64,6 +64,8 @@ import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.chat.QueuedMessage; import net.runelite.client.config.FlashNotification; import net.runelite.client.config.RuneLiteConfig; +import net.runelite.client.eventbus.EventBus; +import net.runelite.client.events.NotificationFired; import net.runelite.client.ui.ClientUI; import net.runelite.client.util.OSType; @@ -107,6 +109,7 @@ public class Notifier private final ClientUI clientUI; private final ScheduledExecutorService executorService; private final ChatMessageManager chatMessageManager; + private final EventBus eventBus; private final Path notifyIconPath; private final boolean terminalNotifierAvailable; private Instant flashStart; @@ -118,13 +121,15 @@ public class Notifier final Client client, final RuneLiteConfig runeliteConfig, final ScheduledExecutorService executorService, - final ChatMessageManager chatMessageManager) + final ChatMessageManager chatMessageManager, + final EventBus eventBus) { this.client = client; this.clientUI = clientUI; this.runeLiteConfig = runeliteConfig; this.executorService = executorService; this.chatMessageManager = chatMessageManager; + this.eventBus = eventBus; this.notifyIconPath = RuneLite.RUNELITE_DIR.toPath().resolve("icon.png"); // First check if we are running in launcher @@ -142,6 +147,8 @@ public class Notifier public void notify(String message, TrayIcon.MessageType type) { + eventBus.post(new NotificationFired(message, type)); + if (!runeLiteConfig.sendNotificationsWhenFocused() && clientUI.isFocused()) { return; diff --git a/runelite-client/src/main/java/net/runelite/client/events/NotificationFired.java b/runelite-client/src/main/java/net/runelite/client/events/NotificationFired.java new file mode 100644 index 0000000000..ecf1ffaf2d --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/events/NotificationFired.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020, Trevor + * 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.events; + +import java.awt.TrayIcon; +import lombok.Value; + +@Value +public class NotificationFired +{ + final String message; + final TrayIcon.MessageType type; +} From 05c6297414a2e9b09cf3599154cc689023fc8879 Mon Sep 17 00:00:00 2001 From: Ben Dol Date: Wed, 12 Feb 2020 23:04:56 -0800 Subject: [PATCH 04/23] itemstats: Round item values for displaying This prevents some stats from displaying as X.XXXXXXXXXXXXX due to their values being stored as `double`s in the overlay. --- .../net/runelite/client/plugins/itemstats/ItemStatOverlay.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java index 32be872c91..2422bd1e09 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java @@ -42,6 +42,7 @@ import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.tooltip.Tooltip; import net.runelite.client.ui.overlay.tooltip.TooltipManager; import net.runelite.client.util.ColorUtil; +import net.runelite.client.util.QuantityFormatter; import net.runelite.http.api.item.ItemEquipmentStats; import net.runelite.http.api.item.ItemStats; @@ -182,7 +183,7 @@ public class ItemStatOverlay extends Overlay final String prefix = value > 0 ? "+" : ""; final String suffix = showPercent ? "%" : ""; - final String valueString = (int)value == value ? String.valueOf((int)value) : String.valueOf(value); + final String valueString = QuantityFormatter.formatNumber(value); return label + ": " + ColorUtil.wrapWithColorTag(prefix + valueString + suffix, color) + "
"; } From 68e40f64f38ee29658e24b30c3f561ebd40335d6 Mon Sep 17 00:00:00 2001 From: Ben Dol Date: Wed, 12 Feb 2020 22:54:42 -0800 Subject: [PATCH 05/23] itemstats: Add "Show Stats In Bank" option --- .../plugins/itemstats/ItemStatConfig.java | 10 ++++++++ .../plugins/itemstats/ItemStatOverlay.java | 24 +++++++++++++------ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java index 60bb256475..4e024cf30b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java @@ -102,6 +102,16 @@ public interface ItemStatConfig extends Config return true; } + @ConfigItem( + keyName = "showStatsInBank", + name = "Show Stats In Bank", + description = "Show item stats on bank items tooltip" + ) + default boolean showStatsInBank() + { + return true; + } + @ConfigItem( keyName = "colorBetterUncapped", name = "Better (Uncapped)", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java index 2422bd1e09..4f3f24fdbe 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java @@ -90,9 +90,13 @@ public class ItemStatOverlay extends Overlay final int child = WidgetInfo.TO_CHILD(entry.getParam1()); final Widget widget = client.getWidget(group, child); - if (widget == null || (group != WidgetInfo.INVENTORY.getGroupId() && - group != WidgetInfo.EQUIPMENT.getGroupId() && - group != WidgetInfo.EQUIPMENT_INVENTORY_ITEMS_CONTAINER.getGroupId())) + if (widget == null + || !(group == WidgetInfo.INVENTORY.getGroupId() + || group == WidgetInfo.EQUIPMENT.getGroupId() + || group == WidgetInfo.EQUIPMENT_INVENTORY_ITEMS_CONTAINER.getGroupId() + || (config.showStatsInBank() + && (group == WidgetInfo.BANK_ITEM_CONTAINER.getGroupId() + || group == WidgetInfo.BANK_INVENTORY_ITEMS_CONTAINER.getGroupId())))) { return null; } @@ -107,12 +111,18 @@ public class ItemStatOverlay extends Overlay itemId = widgetItem.getItemId(); } } - else if (group == WidgetInfo.EQUIPMENT_INVENTORY_ITEMS_CONTAINER.getGroupId()) + else if (group == WidgetInfo.EQUIPMENT_INVENTORY_ITEMS_CONTAINER.getGroupId() + || group == WidgetInfo.BANK_ITEM_CONTAINER.getGroupId() + || group == WidgetInfo.BANK_INVENTORY_ITEMS_CONTAINER.getGroupId()) { - final Widget widgetItem = widget.getChild(entry.getParam0()); - if (widgetItem != null) + int index = entry.getParam0(); + if (index > -1) { - itemId = widgetItem.getItemId(); + final Widget widgetItem = widget.getChild(index); + if (widgetItem != null) + { + itemId = widgetItem.getItemId(); + } } } From af00494ab87661247aa243851d1a9738cdffe9b2 Mon Sep 17 00:00:00 2001 From: Ben Dol Date: Wed, 12 Feb 2020 23:25:11 -0800 Subject: [PATCH 06/23] itemstats: Add "Always Show Base Stats" option This commit adds an option to display a more comprehensive tooltip which, alongside the stat changes, shows the base stats of any equipment hovered. --- .../plugins/itemstats/ItemStatConfig.java | 10 ++ .../plugins/itemstats/ItemStatOverlay.java | 97 +++++++++++++------ 2 files changed, 80 insertions(+), 27 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java index 4e024cf30b..8eaf997053 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java @@ -112,6 +112,16 @@ public interface ItemStatConfig extends Config return true; } + @ConfigItem( + keyName = "alwaysShowBaseStats", + name = "Always Show Base Stats", + description = "Always include the base items stats in the tooltip" + ) + default boolean alwaysShowBaseStats() + { + return false; + } + @ConfigItem( keyName = "colorBetterUncapped", name = "Better (Uncapped)", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java index 4f3f24fdbe..877dab9d3a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java @@ -167,7 +167,6 @@ public class ItemStatOverlay extends Overlay } private String getChangeString( - final String label, final double value, final boolean inverse, final boolean showPercent) @@ -194,17 +193,49 @@ public class ItemStatOverlay extends Overlay final String prefix = value > 0 ? "+" : ""; final String suffix = showPercent ? "%" : ""; final String valueString = QuantityFormatter.formatNumber(value); - return label + ": " + ColorUtil.wrapWithColorTag(prefix + valueString + suffix, color) + "
"; + return ColorUtil.wrapWithColorTag(prefix + valueString + suffix, color); + } + + private String buildStatRow( + final String label, + final double value, + final double diffValue, + final boolean inverse, + final boolean showPercent) + { + return buildStatRow(label, value, diffValue, inverse, showPercent, true); + } + + private String buildStatRow( + final String label, + final double value, + final double diffValue, + final boolean inverse, + final boolean showPercent, + final boolean showBase) + { + final StringBuilder b = new StringBuilder(); + + if (value != 0 || diffValue != 0) + { + final String changeStr = getChangeString(diffValue, inverse, showPercent); + + if (config.alwaysShowBaseStats() && showBase) + { + final String valueStr = QuantityFormatter.formatNumber(value); + b.append(label).append(": ").append(valueStr).append((!changeStr.isEmpty() ? " (" + changeStr + ") " : "")).append("
"); + } + else if (!changeStr.isEmpty()) + { + b.append(label).append(": ").append(changeStr).append("
"); + } + } + + return b.toString(); } private String buildStatBonusString(ItemStats s) { - final StringBuilder b = new StringBuilder(); - if (config.showWeight()) - { - b.append(getChangeString("Weight", s.getWeight(), true, false)); - } - ItemStats other = null; final ItemEquipmentStats currentEquipment = s.getEquipment(); @@ -233,32 +264,44 @@ public class ItemStatOverlay extends Overlay final ItemStats subtracted = s.subtract(other); final ItemEquipmentStats e = subtracted.getEquipment(); + final StringBuilder b = new StringBuilder(); + + if (config.showWeight()) + { + double sw = config.alwaysShowBaseStats() ? subtracted.getWeight() : s.getWeight(); + b.append(buildStatRow("Weight", s.getWeight(), sw, true, false, s.isEquipable())); + } + if (subtracted.isEquipable() && e != null) { - b.append(getChangeString("Prayer", e.getPrayer(), false, false)); - b.append(getChangeString("Speed", e.getAspeed(), true, false)); - b.append(getChangeString("Melee Str", e.getStr(), false, false)); - b.append(getChangeString("Range Str", e.getRstr(), false, false)); - b.append(getChangeString("Magic Dmg", e.getMdmg(), false, true)); + b.append(buildStatRow("Prayer", currentEquipment.getPrayer(), e.getPrayer(), false, false)); + b.append(buildStatRow("Speed", currentEquipment.getAspeed(), e.getAspeed(), true, false)); + b.append(buildStatRow("Melee Str", currentEquipment.getStr(), e.getStr(), false, false)); + b.append(buildStatRow("Range Str", currentEquipment.getRstr(), e.getRstr(), false, false)); + b.append(buildStatRow("Magic Dmg", currentEquipment.getMdmg(), e.getMdmg(), false, true)); - if (e.getAstab() != 0 || e.getAslash() != 0 || e.getAcrush() != 0 || e.getAmagic() != 0 || e.getArange() != 0) + final StringBuilder abb = new StringBuilder(); + abb.append(buildStatRow("Stab", currentEquipment.getAspeed(), e.getAspeed(), false, false)); + abb.append(buildStatRow("Slash", currentEquipment.getAslash(), e.getAslash(), false, false)); + abb.append(buildStatRow("Crush", currentEquipment.getAcrush(), e.getAcrush(), false, false)); + abb.append(buildStatRow("Magic", currentEquipment.getAmagic(), e.getAmagic(), false, false)); + abb.append(buildStatRow("Range", currentEquipment.getArange(), e.getArange(), false, false)); + + if (abb.length() > 0) { - b.append(ColorUtil.wrapWithColorTag("Attack Bonus
", JagexColors.MENU_TARGET)); - b.append(getChangeString("Stab", e.getAstab(), false, false)); - b.append(getChangeString("Slash", e.getAslash(), false, false)); - b.append(getChangeString("Crush", e.getAcrush(), false, false)); - b.append(getChangeString("Magic", e.getAmagic(), false, false)); - b.append(getChangeString("Range", e.getArange(), false, false)); + b.append(ColorUtil.wrapWithColorTag("Attack Bonus
", JagexColors.MENU_TARGET)).append(abb); } - if (e.getDstab() != 0 || e.getDslash() != 0 || e.getDcrush() != 0 || e.getDmagic() != 0 || e.getDrange() != 0) + final StringBuilder dbb = new StringBuilder(); + dbb.append(buildStatRow("Stab", currentEquipment.getDstab(), e.getDstab(), false, false)); + dbb.append(buildStatRow("Slash", currentEquipment.getDslash(), e.getDslash(), false, false)); + dbb.append(buildStatRow("Crush", currentEquipment.getDcrush(), e.getDcrush(), false, false)); + dbb.append(buildStatRow("Magic", currentEquipment.getDmagic(), e.getDmagic(), false, false)); + dbb.append(buildStatRow("Range", currentEquipment.getDrange(), e.getDrange(), false, false)); + + if (dbb.length() > 0) { - b.append(ColorUtil.wrapWithColorTag("Defence Bonus
", JagexColors.MENU_TARGET)); - b.append(getChangeString("Stab", e.getDstab(), false, false)); - b.append(getChangeString("Slash", e.getDslash(), false, false)); - b.append(getChangeString("Crush", e.getDcrush(), false, false)); - b.append(getChangeString("Magic", e.getDmagic(), false, false)); - b.append(getChangeString("Range", e.getDrange(), false, false)); + b.append(ColorUtil.wrapWithColorTag("Defence Bonus
", JagexColors.MENU_TARGET)).append(dbb); } } From e7679a870033439de9244c2f4b3dfa7bd045f1c2 Mon Sep 17 00:00:00 2001 From: Max Weber Date: Thu, 13 Feb 2020 09:55:19 -0700 Subject: [PATCH 07/23] PluginManager: try/catch Throwable all the plugin startup stuff If you loaded an external plugin that throws LinkageErrors it could cause the client not to start --- .../ExternalPluginManager.java | 6 ++- .../client/plugins/PluginManager.java | 53 ++++++++++++++----- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginManager.java b/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginManager.java index 2a3c3a828c..197eb31a53 100644 --- a/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginManager.java +++ b/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginManager.java @@ -305,7 +305,11 @@ public class ExternalPluginManager }); } } - catch (Exception e) + catch (ThreadDeath e) + { + throw e; + } + catch (Throwable e) { log.warn("Unable to start or load external plugin \"{}\"", manifest.getInternalName(), e); if (newPlugins != null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java index ed814d27cb..5dd3c6b231 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java @@ -160,17 +160,27 @@ public class PluginManager public Config getPluginConfigProxy(Plugin plugin) { - final Injector injector = plugin.getInjector(); - - for (Key key : injector.getAllBindings().keySet()) + try { - Class type = key.getTypeLiteral().getRawType(); - if (Config.class.isAssignableFrom(type)) + final Injector injector = plugin.getInjector(); + + for (Key key : injector.getAllBindings().keySet()) { - return (Config) injector.getInstance(key); + Class type = key.getTypeLiteral().getRawType(); + if (Config.class.isAssignableFrom(type)) + { + return (Config) injector.getInstance(key); + } } } - + catch (ThreadDeath e) + { + throw e; + } + catch (Throwable e) + { + log.warn("Unable to get plugin config", e); + } return null; } @@ -203,9 +213,20 @@ public class PluginManager public void loadDefaultPluginConfiguration(Collection plugins) { - for (Object config : getPluginConfigProxies(plugins)) + try { - configManager.setDefaultConfiguration(config, false); + for (Object config : getPluginConfigProxies(plugins)) + { + configManager.setDefaultConfiguration(config, false); + } + } + catch (ThreadDeath e) + { + throw e; + } + catch (Throwable ex) + { + log.warn("Unable to reset plugin configuration", ex); } } @@ -367,7 +388,11 @@ public class PluginManager schedule(plugin); eventBus.post(new PluginChanged(plugin, true)); } - catch (Exception ex) + catch (ThreadDeath e) + { + throw e; + } + catch (Throwable ex) { throw new PluginInstantiationException(ex); } @@ -440,9 +465,13 @@ public class PluginManager Plugin plugin; try { - plugin = clazz.newInstance(); + plugin = clazz.getDeclaredConstructor().newInstance(); } - catch (InstantiationException | IllegalAccessException ex) + catch (ThreadDeath e) + { + throw e; + } + catch (Throwable ex) { throw new PluginInstantiationException(ex); } From 37db307cda72379c3fa761102619d3f9db7547c9 Mon Sep 17 00:00:00 2001 From: Ron Young Date: Mon, 7 Oct 2019 09:19:16 -0500 Subject: [PATCH 08/23] runelite-api: add GE search event and variables --- .../main/java/net/runelite/api/Client.java | 15 ++++++ .../api/events/GrandExchangeSearched.java | 52 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 runelite-api/src/main/java/net/runelite/api/events/GrandExchangeSearched.java diff --git a/runelite-api/src/main/java/net/runelite/api/Client.java b/runelite-api/src/main/java/net/runelite/api/Client.java index 063e833f89..31feace4cf 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -1709,4 +1709,19 @@ public interface Client extends GameEngine * Makes all widgets behave as if they are {@link WidgetConfig#WIDGET_USE_TARGET} */ void setAllWidgetsAreOpTargetable(boolean value); + + /** + * Sets the result count for GE search + */ + void setGeSearchResultCount(int count); + + /** + * Sets the array of item ids for GE search + */ + void setGeSearchResultIds(short[] ids); + + /** + * Sets the starting index in the item id array for GE search + */ + void setGeSearchResultIndex(int index); } diff --git a/runelite-api/src/main/java/net/runelite/api/events/GrandExchangeSearched.java b/runelite-api/src/main/java/net/runelite/api/events/GrandExchangeSearched.java new file mode 100644 index 0000000000..aa96680d1c --- /dev/null +++ b/runelite-api/src/main/java/net/runelite/api/events/GrandExchangeSearched.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019, Ron Young + * 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.events; + +import lombok.Data; + +/** + * An event where the Grand Exchange has been searched. + */ +@Data +public class GrandExchangeSearched +{ + /** + * Whether or not the event has been consumed by a subscriber. + */ + private boolean consumed; + + /** + * Marks the event as having been consumed. + *

+ * Setting this state indicates that a plugin has set the GE + * search results and that the event will not be passed on + * for handling by vanilla client code. + */ + public void consume() + { + this.consumed = true; + } +} From b4780dd762a45fcd5bfbc52db6147ebcd906bb96 Mon Sep 17 00:00:00 2001 From: Ron Young Date: Mon, 7 Oct 2019 09:20:22 -0500 Subject: [PATCH 09/23] ItemVariations: add reverse mapping of variations --- .../client/game/ItemVariationMapping.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/game/ItemVariationMapping.java b/runelite-client/src/main/java/net/runelite/client/game/ItemVariationMapping.java index 9629bd99ac..a26f844a91 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/ItemVariationMapping.java +++ b/runelite-client/src/main/java/net/runelite/client/game/ItemVariationMapping.java @@ -26,11 +26,14 @@ package net.runelite.client.game; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.Multimap; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.Map; @@ -40,6 +43,7 @@ import java.util.Map; public class ItemVariationMapping { private static final Map MAPPINGS; + private static final Multimap INVERTED_MAPPINGS; static { @@ -52,6 +56,7 @@ public class ItemVariationMapping final Map> itemVariations = gson.fromJson(new InputStreamReader(geLimitData), typeToken.getType()); ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + ImmutableMultimap.Builder invertedBuilder = new ImmutableMultimap.Builder<>(); for (Collection value : itemVariations.values()) { final Iterator iterator = value.iterator(); @@ -59,9 +64,15 @@ public class ItemVariationMapping while (iterator.hasNext()) { - builder.put(iterator.next(), base); + final int id = iterator.next(); + builder.put(id, base); + invertedBuilder.put(base, id); } + + invertedBuilder.put(base, base); } + + INVERTED_MAPPINGS = invertedBuilder.build(); MAPPINGS = builder.build(); } @@ -75,4 +86,15 @@ public class ItemVariationMapping { return MAPPINGS.getOrDefault(itemId, itemId); } + + /** + * Get item ids for provided variation item id. + * + * @param itemId the item id + * @return the item ids + */ + public static Collection getVariations(int itemId) + { + return INVERTED_MAPPINGS.asMap().getOrDefault(itemId, Collections.singletonList(itemId)); + } } From 80398ae186c79cbc27a0a3c7bc93d0d8961f9b55 Mon Sep 17 00:00:00 2001 From: Ron Young Date: Mon, 7 Oct 2019 09:23:58 -0500 Subject: [PATCH 10/23] banktags: add tag searching for ge search --- .../plugins/banktags/BankTagsPlugin.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java index e0a795e1aa..26e2612955 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java @@ -27,12 +27,15 @@ package net.runelite.client.plugins.banktags; import com.google.common.collect.Lists; +import com.google.common.primitives.Shorts; import com.google.inject.Provides; import java.awt.event.KeyEvent; import java.awt.event.MouseWheelEvent; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Set; +import java.util.TreeSet; import java.util.List; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -50,6 +53,7 @@ import net.runelite.client.events.ConfigChanged; import net.runelite.api.events.DraggingWidgetChanged; import net.runelite.api.events.FocusChanged; import net.runelite.api.events.GameTick; +import net.runelite.api.events.GrandExchangeSearched; import net.runelite.api.events.MenuEntryAdded; import net.runelite.api.events.MenuOptionClicked; import net.runelite.api.events.ScriptCallbackEvent; @@ -62,6 +66,7 @@ import net.runelite.client.callback.ClientThread; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.game.ItemManager; +import net.runelite.client.game.ItemVariationMapping; import net.runelite.client.game.SpriteManager; import net.runelite.client.game.chatbox.ChatboxPanelManager; import net.runelite.client.input.KeyListener; @@ -93,6 +98,8 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis public static final String TAG_TABS_CONFIG = "tagtabs"; public static final String VAR_TAG_SUFFIX = "*"; + private static final int MAX_RESULT_COUNT = 250; + private static final String SEARCH_BANK_INPUT_TEXT = "Show items whose names or tags contain the following text:
" + "(To show only tagged items, start your search with 'tag:')"; @@ -248,6 +255,33 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener, KeyLis shiftPressed = false; } + @Subscribe + public void onGrandExchangeSearched(GrandExchangeSearched event) + { + final String input = client.getVar(VarClientStr.INPUT_TEXT); + if (!input.startsWith(TAG_SEARCH)) + { + return; + } + + event.consume(); + + final String tag = input.substring(TAG_SEARCH.length()).trim(); + final Set ids = tagManager.getItemsForTag(tag) + .stream() + .mapToInt(Math::abs) + .mapToObj(ItemVariationMapping::getVariations) + .flatMap(Collection::stream) + .distinct() + .filter(i -> itemManager.getItemComposition(i).isTradeable()) + .limit(MAX_RESULT_COUNT) + .collect(Collectors.toCollection(TreeSet::new)); + + client.setGeSearchResultIndex(0); + client.setGeSearchResultCount(ids.size()); + client.setGeSearchResultIds(Shorts.toArray(ids)); + } + @Subscribe public void onScriptCallbackEvent(ScriptCallbackEvent event) { From e8454a367ca7785e7710138436cf2fcc8c36e45d Mon Sep 17 00:00:00 2001 From: Ron Young Date: Sun, 9 Feb 2020 16:19:45 -0600 Subject: [PATCH 11/23] banktags: add tests --- .../plugins/banktags/BankTagsPluginTest.java | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/banktags/BankTagsPluginTest.java diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/banktags/BankTagsPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/banktags/BankTagsPluginTest.java new file mode 100644 index 0000000000..18198c9530 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/banktags/BankTagsPluginTest.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2020, Ron Young + * 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.banktags; + +import com.google.inject.Guice; +import com.google.inject.testing.fieldbinder.Bind; +import com.google.inject.testing.fieldbinder.BoundFieldModule; +import javax.inject.Inject; +import net.runelite.api.Client; +import static net.runelite.api.ItemID.ABYSSAL_WHIP; +import net.runelite.api.events.ScriptCallbackEvent; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.config.RuneLiteConfig; +import net.runelite.client.game.ItemManager; +import net.runelite.client.plugins.banktags.tabs.TabInterface; +import net.runelite.client.plugins.cluescrolls.ClueScrollService; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import static org.mockito.Mockito.when; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class BankTagsPluginTest +{ + @Mock + @Bind + private Client client; + + @Mock + @Bind + private ItemManager itemManager; + + @Mock + @Bind + private BankTagsConfig bankTagsConfig; + + @Mock + @Bind + private RuneLiteConfig runeLiteConfig; + + @Mock + @Bind + private TabInterface tabInterface; + + @Mock + @Bind + private ClueScrollService clueScrollService; + + @Mock + @Bind + private ConfigManager configManager; + + @Inject + private TagManager tagManager; + + @Inject + private BankTagsPlugin bankTagsPlugin; + + private final ScriptCallbackEvent EVENT = new ScriptCallbackEvent(); + + @Before + public void before() + { + Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this); + + EVENT.setEventName("bankSearchFilter"); + + when(itemManager.canonicalize(ABYSSAL_WHIP)).thenReturn(ABYSSAL_WHIP); + when(client.getIntStackSize()).thenReturn(2); + when(client.getStringStackSize()).thenReturn(1); + } + + @Test + public void testExplicitSearch() + { + when(client.getIntStack()).thenReturn(new int[]{0, ABYSSAL_WHIP}); + when(client.getStringStack()).thenReturn(new String[]{"tag:whip"}); + + when(configManager.getConfiguration(BankTagsPlugin.CONFIG_GROUP, + TagManager.ITEM_KEY_PREFIX + ABYSSAL_WHIP)).thenReturn("herb,bossing,whip"); + bankTagsPlugin.onScriptCallbackEvent(EVENT); + assertEquals(1, client.getIntStack()[0]); + + // Search should be found at the start of the tag + when(client.getIntStack()).thenReturn(new int[]{0, ABYSSAL_WHIP}); + when(configManager.getConfiguration(BankTagsPlugin.CONFIG_GROUP, + TagManager.ITEM_KEY_PREFIX + ABYSSAL_WHIP)).thenReturn("herb,bossing,whip long tag"); + bankTagsPlugin.onScriptCallbackEvent(EVENT); + assertEquals(1, client.getIntStack()[0]); + + // Search should not be be found in the middle of the tag + // and explicit search does not allow fall through + when(configManager.getConfiguration(BankTagsPlugin.CONFIG_GROUP, + TagManager.ITEM_KEY_PREFIX + ABYSSAL_WHIP)).thenReturn("herb,bossing whip"); + bankTagsPlugin.onScriptCallbackEvent(EVENT); + assertEquals(0, client.getIntStack()[0]); + } + + @Test + public void testFallThrough() + { + when(client.getIntStack()).thenReturn(new int[]{1, ABYSSAL_WHIP}); + when(client.getStringStack()).thenReturn(new String[]{"whip"}); + + when(configManager.getConfiguration(BankTagsPlugin.CONFIG_GROUP, + TagManager.ITEM_KEY_PREFIX + ABYSSAL_WHIP)).thenReturn("herb,bossing"); + + assertFalse(tagManager.findTag(ABYSSAL_WHIP, "whip")); + bankTagsPlugin.onScriptCallbackEvent(EVENT); + assertEquals(1, client.getIntStack()[0]); + } + + @Test + public void testNonExplicitSearch() + { + when(client.getIntStack()).thenReturn(new int[]{0, ABYSSAL_WHIP}); + when(client.getStringStack()).thenReturn(new String[]{"whip"}); + + when(configManager.getConfiguration(BankTagsPlugin.CONFIG_GROUP, + TagManager.ITEM_KEY_PREFIX + ABYSSAL_WHIP)).thenReturn("herb,bossing,whip long tag"); + + bankTagsPlugin.onScriptCallbackEvent(EVENT); + assertEquals(1, client.getIntStack()[0]); + } +} From 5356e7c47eb3fbaf268fd4e3946e3ebe0c4e5e86 Mon Sep 17 00:00:00 2001 From: dekvall Date: Sun, 17 Nov 2019 22:27:04 +0200 Subject: [PATCH 12/23] inventorygrid: re-add a delay to showing the overlay If a player for example tries to drop an entire inventory quickly with the overlay turned on, the inventory grid will flash for each small mouse movement if the left mouse key is held down. This change mitigates the issue by adding a delay option that controls the amount of time the user has to wait after pressing it before enabling any overlay functionality. Showing the grid still requires the mouse to be moved ~5px away from the first clicked position. This delay just delays the activation of the overlay, as the the delay countdown is started upon item press rather than the exit this ~5px range. Making it respect the exit is needlessly complex as desired functionality is reached with the current changeset. --- .../plugins/inventorygrid/InventoryGridConfig.java | 12 ++++++++++++ .../plugins/inventorygrid/InventoryGridOverlay.java | 5 ++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/inventorygrid/InventoryGridConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/inventorygrid/InventoryGridConfig.java index eda6b7cbb8..45551025b7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/inventorygrid/InventoryGridConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/inventorygrid/InventoryGridConfig.java @@ -27,6 +27,7 @@ package net.runelite.client.plugins.inventorygrid; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Units; @ConfigGroup("inventorygrid") public interface InventoryGridConfig extends Config @@ -60,4 +61,15 @@ public interface InventoryGridConfig extends Config { return true; } + + @ConfigItem( + keyName = "dragDelay", + name = "Drag delay", + description = "Time to wait after an item press before the overlay is enabled" + ) + @Units(Units.MILLISECONDS) + default int dragDelay() + { + return 0; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/inventorygrid/InventoryGridOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/inventorygrid/InventoryGridOverlay.java index ae3744fd6d..03d8596d7c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/inventorygrid/InventoryGridOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/inventorygrid/InventoryGridOverlay.java @@ -34,6 +34,7 @@ import java.awt.Point; import java.awt.Rectangle; import java.awt.image.BufferedImage; import net.runelite.api.Client; +import net.runelite.api.Constants; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; import net.runelite.api.widgets.WidgetItem; @@ -92,7 +93,9 @@ class InventoryGridOverlay extends Overlay initialMousePoint = mousePoint; } - if (draggedItem.getId() == -1 || !hoverActive && initialMousePoint.distance(mousePoint) < DISTANCE_TO_ACTIVATE_HOVER) + if (draggedItem.getId() == -1 + || client.getItemPressedDuration() < config.dragDelay() / Constants.CLIENT_TICK_LENGTH + || !hoverActive && initialMousePoint.distance(mousePoint) < DISTANCE_TO_ACTIVATE_HOVER) { return null; } From 9e560d91e392fee9bf27ad148d21563b98b8e769 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Sun, 26 Jan 2020 22:18:23 -0800 Subject: [PATCH 13/23] cluescroll plugin: Clear stale location clue hint arrows Location clue scrolls added a hint arrow when the player was nearby one of the clue's locations. It did not, however clear that arrow if the locations were changed and the previously-set hint arrow location was no longer marked. This commit updates this behavior to clear the active hint arrow each game tick before re-adding any location hint arrows. (and if no NPC hint arrows are set) Fixes runelite/runelite#10370 --- .../plugins/cluescrolls/ClueScrollPlugin.java | 11 +- .../cluescrolls/ClueScrollPluginTest.java | 104 +++++++++++++++++- 2 files changed, 110 insertions(+), 5 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java index 8e09fd6a85..49c8da9064 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java @@ -396,14 +396,17 @@ public class ClueScrollPlugin extends Plugin if (clue instanceof LocationClueScroll) { final WorldPoint[] locations = ((LocationClueScroll) clue).getLocations(); + final boolean npcHintArrowMarked = client.getHintArrowNpc() != null && npcsToMark.contains(client.getHintArrowNpc()); + + if (!npcHintArrowMarked) + { + client.clearHintArrow(); + } for (WorldPoint location : locations) { // Only set the location hint arrow if we do not already have more accurate location - if (location.isInScene(client) - && config.displayHintArrows() - && (client.getHintArrowNpc() == null - || !npcsToMark.contains(client.getHintArrowNpc()))) + if (location.isInScene(client) && config.displayHintArrows() && !npcHintArrowMarked) { client.setHintArrow(location); } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java index d1585382d4..3719dce654 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java @@ -25,13 +25,68 @@ */ package net.runelite.client.plugins.cluescrolls; +import com.google.inject.Guice; +import com.google.inject.Inject; +import com.google.inject.name.Named; +import com.google.inject.testing.fieldbinder.Bind; +import com.google.inject.testing.fieldbinder.BoundFieldModule; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.NPC; +import net.runelite.api.Player; import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.GameTick; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.game.ItemManager; +import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdLocation; +import net.runelite.client.ui.overlay.OverlayManager; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; +import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import static org.mockito.ArgumentMatchers.any; +import org.mockito.Mock; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import org.mockito.junit.MockitoJUnitRunner; +@RunWith(MockitoJUnitRunner.class) public class ClueScrollPluginTest { + @Mock + @Bind + Client client; + + @Inject + ClueScrollPlugin plugin; + + @Bind + @Named("developerMode") + boolean developerMode; + + @Mock + @Bind + ClueScrollConfig config; + + @Mock + @Bind + OverlayManager overlayManager; + + @Mock + @Bind + ItemManager itemManager; + + @Before + public void before() + { + Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this); + } + @Test public void getGetMirrorPoint() { @@ -61,4 +116,51 @@ public class ClueScrollPluginTest converted = ClueScrollPlugin.getMirrorPoint(point, false); assertEquals(point, converted); } -} \ No newline at end of file + + @Test + public void testLocationHintArrowCleared() + { + final Widget clueWidget = mock(Widget.class); + when(clueWidget.getText()).thenReturn("Buried beneath the ground, who knows where it's found. Lucky for you, A man called Reldo may have a clue."); + final ChatMessage hotColdMessage = new ChatMessage(); + hotColdMessage.setType(ChatMessageType.GAMEMESSAGE); + final Player localPlayer = mock(Player.class); + + when(client.getWidget(WidgetInfo.CLUE_SCROLL_TEXT)).thenReturn(clueWidget); + when(client.getLocalPlayer()).thenReturn(localPlayer); + when(client.getPlane()).thenReturn(0); + when(client.getCachedNPCs()).thenReturn(new NPC[] {}); + when(config.displayHintArrows()).thenReturn(true); + + // The hint arrow should be reset each game tick from when the clue is read onward + // This is to verify the arrow is cleared the correct number of times during the clue updating process. + int clueSetupHintArrowClears = 0; + + // Initialize a beginner hot-cold clue (which will have an end point of LUMBRIDGE_COW_FIELD) + plugin.onGameTick(new GameTick()); + verify(client, times(++clueSetupHintArrowClears)).clearHintArrow(); + + // Perform the first hot-cold check in Lumbridge near sheep pen (get 2 possible points: LUMBRIDGE_COW_FIELD and DRAYNOR_WHEAT_FIELD) + when(localPlayer.getWorldLocation()).thenReturn(new WorldPoint(3208, 3254, 0)); + hotColdMessage.setMessage("The device is hot."); + plugin.onChatMessage(hotColdMessage); + + // Move to SW of DRAYNOR_WHEAT_FIELD (hint arrow should be visible here) + when(localPlayer.getWorldLocation()).thenReturn(new WorldPoint(3105, 3265, 0)); + when(client.getBaseX()).thenReturn(3056); + when(client.getBaseY()).thenReturn(3216); + plugin.onGameTick(new GameTick()); + verify(client, times(++clueSetupHintArrowClears)).clearHintArrow(); + verify(client).setHintArrow(HotColdLocation.DRAYNOR_WHEAT_FIELD.getWorldPoint()); + + // Test in that location (get 1 possible location: LUMBRIDGE_COW_FIELD) + hotColdMessage.setMessage("The device is hot, and warmer than last time."); + plugin.onChatMessage(hotColdMessage); + plugin.onGameTick(new GameTick()); + + // Hint arrow should be cleared and not re-set now as the only remaining location is outside of the current + // scene + verify(client, times(++clueSetupHintArrowClears)).clearHintArrow(); + verify(client, times(1)).setHintArrow(any(WorldPoint.class)); + } +} From 4d6019634043c3748263295e1efa7f03c775a55a Mon Sep 17 00:00:00 2001 From: kmutchnick <31519990+kmutchnick@users.noreply.github.com> Date: Thu, 20 Feb 2020 12:27:24 -0800 Subject: [PATCH 14/23] clue plugin: add new Slepe anagram clue --- .../runelite/client/plugins/cluescrolls/clues/AnagramClue.java | 1 + 1 file changed, 1 insertion(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java index 5c8e38e72a..7c5f83864e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java @@ -77,6 +77,7 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc new AnagramClue("C ON GAME HOC", "Gnome Coach", new WorldPoint(2395, 3486, 0), "Gnome Ball course", "How many gnomes on the Gnome ball field have red patches on their uniforms?", "6"), new AnagramClue("COOL NERD", "Old crone", new WorldPoint(3462, 3557, 0), "East of the Slayer Tower", "What is the combined combat level of each species that live in Slayer tower?", "619"), new AnagramClue("COPPER ORE CRYPTS", "Prospector Percy", new WorldPoint(3061, 3377, 0), "Motherlode Mine", "During a party, everyone shook hands with everyone else. There were 66 handshakes. How many people were at the party?", "12"), + new AnagramClue("DARN DRAKE", "Daer Krand", new WorldPoint(3728, 3302, 0), "Sisterhood Sanctuary (Slepe Dungeon, northeast of Nightmare Arena)"), new AnagramClue("DED WAR", "Edward", new WorldPoint(3284, 3943, 0), "Inside Rogue's Castle"), new AnagramClue("DEKAGRAM", "Dark mage", new WorldPoint(3039, 4835, 0), "Centre of the Abyss", "How many rifts are found here in the abyss?", "13"), new AnagramClue("DO SAY MORE", "Doomsayer", new WorldPoint(3230, 3230, 0), "East of Lumbridge Castle", "What is 40 divided by 1/2 plus 15?", "95"), From 9108fb448ab515d78c15ef75fbdaedf8b148f9d7 Mon Sep 17 00:00:00 2001 From: kmutchnick <31519990+kmutchnick@users.noreply.github.com> Date: Thu, 20 Feb 2020 12:37:06 -0800 Subject: [PATCH 15/23] skill calc: fix skill requirement for compost potions --- .../runelite/client/plugins/skillcalculator/skill_herblore.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_herblore.json b/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_herblore.json index 242ca19943..e52d0fd6b6 100644 --- a/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_herblore.json +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_herblore.json @@ -61,7 +61,7 @@ "xp": 6.3 }, { - "level": 21, + "level": 22, "icon": 6472, "name": "Compost Potion (3)", "xp": 60 From 45d8fae5de600c52c4ed686439a0ada04fbeeb51 Mon Sep 17 00:00:00 2001 From: kmutchnick <31519990+kmutchnick@users.noreply.github.com> Date: Thu, 20 Feb 2020 12:44:22 -0800 Subject: [PATCH 16/23] clue plugin: update solution text for deep wilderness dungeon cryptic clue --- .../runelite/client/plugins/cluescrolls/clues/CrypticClue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java index bd1c30c01c..f588226039 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java @@ -228,7 +228,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("You might have to turn over a few stones to progress.", null, "Kill a rock crab."), new CrypticClue("Dig under Razorlor's toad batta.", new WorldPoint(3139, 4554, 0), "Dig on the toad batta spawn in Tarn's Lair."), new CrypticClue("Talk to Cassie in Falador.", "Cassie", new WorldPoint(2975, 3383, 0), "Cassie is found just south-east of the northern Falador gate."), - new CrypticClue("Faint sounds of 'Arr', fire giants found deep, the eastern tip of a lake, are the rewards you could reap.", new WorldPoint(3055, 10338, 0), "Dig south of the pillar at the end of the Deep Wilderness Dungeon."), + new CrypticClue("Faint sounds of 'Arr', fire giants found deep, the eastern tip of a lake, are the rewards you could reap.", new WorldPoint(3055, 10338, 0), "Dig south of the pillar in the Deep Wilderness Dungeon in the room with the fire giants."), new CrypticClue("If you're feeling brave, dig beneath the dragon's eye.", new WorldPoint(2410, 4714, 0), "Dig below the mossy rock under the Viyeldi caves (Legend's Quest). Items needed: Pickaxe, unpowered orb, lockpick, spade, and any charge orb spell."), new CrypticClue("Search the tents in the Imperial Guard camp in Burthorpe for some boxes.", BOXES_3686, new WorldPoint(2885, 3540, 0), "Search in the tents in northwest corner of the camp."), new CrypticClue("A dwarf, approaching death, but very much in the light.", "Thorgel", new WorldPoint(1863, 4639, 0), "Thorgel at the entrance to the Death altar"), From 3518fbbf4804e229df37c3b9f8c7c37bb3b992c5 Mon Sep 17 00:00:00 2001 From: kmutchnick <31519990+kmutchnick@users.noreply.github.com> Date: Thu, 20 Feb 2020 12:51:23 -0800 Subject: [PATCH 17/23] clue plugin: add pet rock and rune thrownaxe to DK clue --- .../runelite/client/plugins/cluescrolls/clues/CrypticClue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java index f588226039..3d1ee78e96 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java @@ -222,7 +222,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("Anger Abbot Langley.", "Abbot Langley", new WorldPoint(3058, 3487, 0), "Speak to Abbot Langley in the Edgeville Monastery while you have a negative prayer bonus (currently only possible with an Ancient staff)."), new CrypticClue("Dig where only the skilled, the wealthy, or the brave can choose not to visit again.", new WorldPoint(3221, 3219, 0), "Dig at Lumbridge spawn"), new CrypticClue("Scattered coins and gems fill the floor. The chest you seek is in the north east.", "King Black Dragon", CLOSED_CHEST_375, new WorldPoint(2288, 4702, 0), "Kill the King Black Dragon for a key (elite), and then open the closed chest in the NE corner of the lair."), - new CrypticClue("A ring of water surrounds 4 powerful rings, dig above the ladder located there.", new WorldPoint(1910, 4367, 0), "Dig by the ladder leading to the Dagannoth Kings room in the Waterbirth Island Dungeon."), + new CrypticClue("A ring of water surrounds 4 powerful rings, dig above the ladder located there.", new WorldPoint(1910, 4367, 0), "Dig by the ladder leading to the Dagannoth Kings room in the Waterbirth Island Dungeon. Bring a pet rock and rune thrownaxe."), new CrypticClue("This place sure is a mess.", "Ewesey", new WorldPoint(1646, 3631, 0), "Ewesey is located in the mess hall in Hosidius."), new CrypticClue("Here, there are tears, but nobody is crying. Speak to the guardian and show off your alignment to balance.", "Juna", JUNA, new WorldPoint(3252, 9517, 2), "Talk to Juna while wearing three Guthix related items."), new CrypticClue("You might have to turn over a few stones to progress.", null, "Kill a rock crab."), From 4f9c22c4c10aaabc46ee7982050c40ea327d4ab1 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Mon, 10 Feb 2020 21:29:41 -0800 Subject: [PATCH 18/23] util: Create RSTimeUnit enum This commit adds a list of time units used in some duration calculations, specifically client ticks and game ticks. --- .../net/runelite/client/util/RSTimeUnit.java | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 runelite-client/src/main/java/net/runelite/client/util/RSTimeUnit.java diff --git a/runelite-client/src/main/java/net/runelite/client/util/RSTimeUnit.java b/runelite-client/src/main/java/net/runelite/client/util/RSTimeUnit.java new file mode 100644 index 0000000000..bbf5f832a3 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/util/RSTimeUnit.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2020, Jordan Atwood + * 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.util; + +import java.time.Duration; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalUnit; +import lombok.Getter; +import net.runelite.api.Constants; + +@Getter +public enum RSTimeUnit implements TemporalUnit +{ + CLIENT_TICKS("Client tick", Duration.ofMillis(Constants.CLIENT_TICK_LENGTH)), + GAME_TICKS("Game tick", Duration.ofMillis(Constants.GAME_TICK_LENGTH)), + ; + + private final String name; + private final Duration duration; + + RSTimeUnit(String name, Duration estimatedDuration) + { + this.name = name; + duration = estimatedDuration; + } + + @Override + public boolean isDurationEstimated() + { + return false; + } + + @Override + public boolean isDateBased() + { + return false; + } + + @Override + public boolean isTimeBased() + { + return true; + } + + @Override + public boolean isSupportedBy(Temporal temporal) + { + return temporal.isSupported(this); + } + + @Override + public R addTo(R temporal, long amount) + { + return (R) temporal.plus(amount, this); + } + + @Override + public long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive) + { + return temporal1Inclusive.until(temporal2Exclusive, this); + } + + @Override + public String toString() + { + return name + " (" + duration.toMillis() + "ms)"; + } +} From e3db56804e451b6e269f9a0f3f05291ec842fec5 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Mon, 10 Feb 2020 21:31:15 -0800 Subject: [PATCH 19/23] plugins: Use RSTimeUnit util where applicable This replaces uses of `Duration#minusMillis()` and `TemporalUnit` referencing units of time defined in RSTimeUnits with their definitions. The Timers plugin constructors are changed to accept implementations of the `TemporalUnit` interface as they do not require any `ChronoUnit`-specific APIs. Furthermore, the timer lengths updated use the game tick lengths described in the OSRS wiki, which generally closely correspond to the previous length definitions we used. --- .../plugins/barbarianassault/GameTimer.java | 4 ++-- .../plugins/barbarianassault/Round.java | 4 ++-- .../client/plugins/timers/GameTimer.java | 24 ++++++++++--------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/GameTimer.java b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/GameTimer.java index 1aae11adbd..fbf33bae14 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/GameTimer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/GameTimer.java @@ -28,7 +28,7 @@ import java.time.Duration; import java.time.Instant; import java.time.LocalTime; import java.time.format.DateTimeFormatter; -import net.runelite.api.Constants; +import static net.runelite.client.util.RSTimeUnit.GAME_TICKS; class GameTimer { @@ -46,7 +46,7 @@ class GameTimer } else { - elapsed = Duration.between(startTime, now).minusMillis(Constants.GAME_TICK_LENGTH); + elapsed = Duration.between(startTime, now).minus(Duration.of(1, GAME_TICKS)); } return formatTime(LocalTime.ofSecondOfDay(elapsed.getSeconds())); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/Round.java b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/Round.java index 4428d504b4..9d13b74123 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/Round.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/Round.java @@ -29,7 +29,7 @@ import java.time.Instant; import javax.inject.Inject; import lombok.Getter; import lombok.Setter; -import net.runelite.api.Constants; +import static net.runelite.client.util.RSTimeUnit.GAME_TICKS; class Round { @@ -53,7 +53,7 @@ class Round public Round(Role role) { this.roundRole = role; - this.roundStartTime = Instant.now().plusMillis(2 * Constants.GAME_TICK_LENGTH); + this.roundStartTime = Instant.now().plus(Duration.of(2, GAME_TICKS)); } public long getRoundTime() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timers/GameTimer.java b/runelite-client/src/main/java/net/runelite/client/plugins/timers/GameTimer.java index 957f8867d3..a1aa1f5f21 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timers/GameTimer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timers/GameTimer.java @@ -28,12 +28,14 @@ package net.runelite.client.plugins.timers; import java.time.Duration; import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalUnit; import javax.annotation.Nullable; import lombok.AccessLevel; import lombok.Getter; import net.runelite.api.GraphicID; import net.runelite.api.ItemID; import net.runelite.api.SpriteID; +import static net.runelite.client.util.RSTimeUnit.GAME_TICKS; @Getter(AccessLevel.PACKAGE) enum GameTimer @@ -43,19 +45,19 @@ enum GameTimer EXANTIFIRE(ItemID.EXTENDED_ANTIFIRE4, GameTimerImageType.ITEM, "Extended antifire", 12, ChronoUnit.MINUTES), OVERLOAD(ItemID.OVERLOAD_4, GameTimerImageType.ITEM, "Overload", 5, ChronoUnit.MINUTES, true), CANNON(ItemID.CANNON_BARRELS, GameTimerImageType.ITEM, "Cannon", 25, ChronoUnit.MINUTES), - MAGICIMBUE(SpriteID.SPELL_MAGIC_IMBUE, GameTimerImageType.SPRITE, "Magic imbue", 12, ChronoUnit.SECONDS), + MAGICIMBUE(SpriteID.SPELL_MAGIC_IMBUE, GameTimerImageType.SPRITE, "Magic imbue", 21, GAME_TICKS), FULLTB(SpriteID.SPELL_TELE_BLOCK, GameTimerImageType.SPRITE, "Full Teleblock", 5, ChronoUnit.MINUTES, true), HALFTB(SpriteID.SPELL_TELE_BLOCK, GameTimerImageType.SPRITE, "Half Teleblock", 150, ChronoUnit.SECONDS, true), DMM_FULLTB(SpriteID.SPELL_TELE_BLOCK, GameTimerImageType.SPRITE, "Deadman Mode Full Teleblock", 150, ChronoUnit.SECONDS, true), DMM_HALFTB(SpriteID.SPELL_TELE_BLOCK, GameTimerImageType.SPRITE, "Deadman Mode Half Teleblock", 75, ChronoUnit.SECONDS, true), SUPERANTIFIRE(ItemID.SUPER_ANTIFIRE_POTION4, GameTimerImageType.ITEM, "Super antifire", 3, ChronoUnit.MINUTES), - BIND(SpriteID.SPELL_BIND, GameTimerImageType.SPRITE, "Bind", GraphicID.BIND, 5, ChronoUnit.SECONDS, true), - SNARE(SpriteID.SPELL_SNARE, GameTimerImageType.SPRITE, "Snare", GraphicID.SNARE, 10, ChronoUnit.SECONDS, true), - ENTANGLE(SpriteID.SPELL_ENTANGLE, GameTimerImageType.SPRITE, "Entangle", GraphicID.ENTANGLE, 15, ChronoUnit.SECONDS, true), - ICERUSH(SpriteID.SPELL_ICE_RUSH, GameTimerImageType.SPRITE, "Ice rush", GraphicID.ICE_RUSH, 5, ChronoUnit.SECONDS, true), - ICEBURST(SpriteID.SPELL_ICE_BURST, GameTimerImageType.SPRITE, "Ice burst", GraphicID.ICE_BURST, 10, ChronoUnit.SECONDS, true), - ICEBLITZ(SpriteID.SPELL_ICE_BLITZ, GameTimerImageType.SPRITE, "Ice blitz", GraphicID.ICE_BLITZ, 15, ChronoUnit.SECONDS, true), - ICEBARRAGE(SpriteID.SPELL_ICE_BARRAGE, GameTimerImageType.SPRITE, "Ice barrage", GraphicID.ICE_BARRAGE, 20, ChronoUnit.SECONDS, true), + BIND(SpriteID.SPELL_BIND, GameTimerImageType.SPRITE, "Bind", GraphicID.BIND, 8, GAME_TICKS, true), + SNARE(SpriteID.SPELL_SNARE, GameTimerImageType.SPRITE, "Snare", GraphicID.SNARE, 16, GAME_TICKS, true), + ENTANGLE(SpriteID.SPELL_ENTANGLE, GameTimerImageType.SPRITE, "Entangle", GraphicID.ENTANGLE, 24, GAME_TICKS, true), + ICERUSH(SpriteID.SPELL_ICE_RUSH, GameTimerImageType.SPRITE, "Ice rush", GraphicID.ICE_RUSH, 8, GAME_TICKS, true), + ICEBURST(SpriteID.SPELL_ICE_BURST, GameTimerImageType.SPRITE, "Ice burst", GraphicID.ICE_BURST, 16, GAME_TICKS, true), + ICEBLITZ(SpriteID.SPELL_ICE_BLITZ, GameTimerImageType.SPRITE, "Ice blitz", GraphicID.ICE_BLITZ, 24, GAME_TICKS, true), + ICEBARRAGE(SpriteID.SPELL_ICE_BARRAGE, GameTimerImageType.SPRITE, "Ice barrage", GraphicID.ICE_BARRAGE, 32, GAME_TICKS, true), IMBUEDHEART(ItemID.IMBUED_HEART, GameTimerImageType.ITEM, "Imbued heart", GraphicID.IMBUED_HEART, 420, ChronoUnit.SECONDS, true), VENGEANCE(SpriteID.SPELL_VENGEANCE, GameTimerImageType.SPRITE, "Vengeance", 30, ChronoUnit.SECONDS), EXSUPERANTIFIRE(ItemID.EXTENDED_SUPER_ANTIFIRE4, GameTimerImageType.ITEM, "Extended Super AntiFire", 6, ChronoUnit.MINUTES), @@ -86,7 +88,7 @@ enum GameTimer private final int imageId; private final GameTimerImageType imageType; - GameTimer(int imageId, GameTimerImageType idType, String description, Integer graphicId, long time, ChronoUnit unit, boolean removedOnDeath) + GameTimer(int imageId, GameTimerImageType idType, String description, Integer graphicId, long time, TemporalUnit unit, boolean removedOnDeath) { this.description = description; this.graphicId = graphicId; @@ -96,12 +98,12 @@ enum GameTimer this.removedOnDeath = removedOnDeath; } - GameTimer(int imageId, GameTimerImageType idType, String description, long time, ChronoUnit unit, boolean removeOnDeath) + GameTimer(int imageId, GameTimerImageType idType, String description, long time, TemporalUnit unit, boolean removeOnDeath) { this(imageId, idType, description, null, time, unit, removeOnDeath); } - GameTimer(int imageId, GameTimerImageType idType, String description, long time, ChronoUnit unit) + GameTimer(int imageId, GameTimerImageType idType, String description, long time, TemporalUnit unit) { this(imageId, idType, description, null, time, unit, false); } From b3b51108dc30c78ff4be45cfb2d0086d9b2ca281 Mon Sep 17 00:00:00 2001 From: Seth Date: Thu, 20 Feb 2020 16:14:09 -0600 Subject: [PATCH 20/23] clue plugin: update Trollweiss cryptic clue hint to include a sled --- .../runelite/client/plugins/cluescrolls/clues/CrypticClue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java index 5c6455ffb4..8071452ca5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java @@ -137,7 +137,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("'Small shoe.' Often found with rod on mushroom.", "Gnome trainer", new WorldPoint(2476, 3428, 0), "Talk to any Gnome trainer in the agility area of the Tree Gnome Stronghold."), new CrypticClue("I live in a deserted crack collecting soles.", "Genie", new WorldPoint(3371, 9320, 0), "Enter the crack west of Nardah Rug merchant, and talk to the Genie. You'll need a light source and a rope.", true), new CrypticClue("46 is my number. My body is the colour of burnt orange and crawls among those with eight. Three mouths I have, yet I cannot eat. My blinking blue eye hides my grave.", new WorldPoint(3170, 3885, 0), "Sapphire respawn in the Spider's Nest, lvl 46 Wilderness. Dig under the sapphire spawn."), - new CrypticClue("Green is the colour of my death as the winter-guise, I swoop towards the ground.", new WorldPoint(2780, 3783, 0), "Players need to slide down to where Trollweiss grows on Trollweiss Mountain."), + new CrypticClue("Green is the colour of my death as the winter-guise, I swoop towards the ground.", new WorldPoint(2780, 3783, 0), "Players need to slide down to where Trollweiss grows on Trollweiss Mountain. Bring a sled"), new CrypticClue("Talk to a party-goer in Falador.", "Lucy", new WorldPoint(3046, 3382, 0), "Lucy is the bartender on the first floor of the party room."), new CrypticClue("He knows just how easy it is to lose track of time.", "Brother Kojo", new WorldPoint(2570, 3250, 0), "Speak to Brother Kojo in the Clock Tower. Answer: 22", "On a clock, how many times a day do the minute hand and the hour hand overlap?"), new CrypticClue("A great view - watch the rapidly drying hides get splashed. Check the box you are sitting on.", BOXES, new WorldPoint(2523, 3493, 1), "Almera's House north of Baxtorian Falls, search boxes on the first floor."), From 640052607fe63c2ded98778f8001cc676fa30df3 Mon Sep 17 00:00:00 2001 From: Alfred Ababio Date: Thu, 20 Feb 2020 18:13:49 -0500 Subject: [PATCH 21/23] skill calc: add long and curved bones to construction calc --- .../plugins/skillcalculator/skill_construction.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_construction.json b/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_construction.json index 3d38ce9e0e..c53546241e 100644 --- a/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_construction.json +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_construction.json @@ -402,6 +402,18 @@ "name": "Oak Bed", "xp": 210 }, + { + "level": 30, + "icon": 10976, + "name": "Long Bone", + "xp": 4500 + }, + { + "level": 30, + "icon": 10977, + "name": "Curved Bone", + "xp": 6750 + }, { "level": 31, "icon": 8110, From eb02d508c41af1bd6e4e7549e4bf3f15b7f7e31f Mon Sep 17 00:00:00 2001 From: Sander de Groot Date: Thu, 20 Feb 2020 18:29:23 -0500 Subject: [PATCH 22/23] chat commands: add Bounty Hunter, Bounty Hunter Rogue, and Last Man Standing commands --- .../chatcommands/ChatCommandsConfig.java | 35 +++++- .../chatcommands/ChatCommandsPlugin.java | 102 ++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java index 9186a6106b..30fc30ab96 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java @@ -124,6 +124,39 @@ public interface ChatCommandsConfig extends Config @ConfigItem( position = 8, + keyName = "bh", + name = "BH Command", + description = "Configures whether the Bounty Hunter - Hunter command is enabled
!bh" + ) + default boolean bh() + { + return true; + } + + @ConfigItem( + position = 9, + keyName = "bhRogue", + name = "BH Rogue Command", + description = "Configures whether the Bounty Hunter - Rogue command is enabled
!bhrogue" + ) + default boolean bhRogue() + { + return true; + } + + @ConfigItem( + position = 10, + keyName = "lms", + name = "LMS Command", + description = "Configures whether the Last Man Standing command is enabled
!lms" + ) + default boolean lms() + { + return true; + } + + @ConfigItem( + position = 11, keyName = "clearSingleWord", name = "Clear Single Word", description = "Enable hot key to clear single word at a time" @@ -134,7 +167,7 @@ public interface ChatCommandsConfig extends Config } @ConfigItem( - position = 9, + position = 12, keyName = "clearEntireChatBox", name = "Clear Chat Box", description = "Enable hotkey to clear entire chat box" diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java index 283b09b750..10f6da6f98 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java @@ -99,7 +99,10 @@ public class ChatCommandsPlugin extends Plugin private static final String TOTAL_LEVEL_COMMAND_STRING = "!total"; private static final String PRICE_COMMAND_STRING = "!price"; private static final String LEVEL_COMMAND_STRING = "!lvl"; + private static final String BOUNTY_HUNTER_HUNTER_COMMAND = "!bh"; + private static final String BOUNTY_HUNTER_ROGUE_COMMAND = "!bhrogue"; private static final String CLUES_COMMAND_STRING = "!clues"; + private static final String LAST_MAN_STANDING_COMMAND = "!lms"; private static final String KILLCOUNT_COMMAND_STRING = "!kc"; private static final String CMB_COMMAND_STRING = "!cmb"; private static final String QP_COMMAND_STRING = "!qp"; @@ -151,7 +154,10 @@ public class ChatCommandsPlugin extends Plugin chatCommandManager.registerCommandAsync(CMB_COMMAND_STRING, this::combatLevelLookup); chatCommandManager.registerCommand(PRICE_COMMAND_STRING, this::itemPriceLookup); chatCommandManager.registerCommandAsync(LEVEL_COMMAND_STRING, this::playerSkillLookup); + chatCommandManager.registerCommandAsync(BOUNTY_HUNTER_HUNTER_COMMAND, this::bountyHunterHunterLookup); + chatCommandManager.registerCommandAsync(BOUNTY_HUNTER_ROGUE_COMMAND, this::bountyHunterRogueLookup); chatCommandManager.registerCommandAsync(CLUES_COMMAND_STRING, this::clueLookup); + chatCommandManager.registerCommandAsync(LAST_MAN_STANDING_COMMAND, this::lastManStandingLookup); chatCommandManager.registerCommandAsync(KILLCOUNT_COMMAND_STRING, this::killCountLookup, this::killCountSubmit); chatCommandManager.registerCommandAsync(QP_COMMAND_STRING, this::questPointsLookup, this::questPointsSubmit); chatCommandManager.registerCommandAsync(PB_COMMAND, this::personalBestLookup, this::personalBestSubmit); @@ -1055,6 +1061,102 @@ public class ChatCommandsPlugin extends Plugin } } + private void bountyHunterHunterLookup(ChatMessage chatMessage, String message) + { + if (!config.bh()) + { + return; + } + + minigameLookup(chatMessage, HiscoreSkill.BOUNTY_HUNTER_HUNTER); + } + + private void bountyHunterRogueLookup(ChatMessage chatMessage, String message) + { + if (!config.bhRogue()) + { + return; + } + + minigameLookup(chatMessage, HiscoreSkill.BOUNTY_HUNTER_ROGUE); + } + + private void lastManStandingLookup(ChatMessage chatMessage, String message) + { + if (!config.lms()) + { + return; + } + + minigameLookup(chatMessage, HiscoreSkill.LAST_MAN_STANDING); + } + + private void minigameLookup(ChatMessage chatMessage, HiscoreSkill minigame) + { + try + { + final Skill hiscoreSkill; + final HiscoreLookup lookup = getCorrectLookupFor(chatMessage); + final HiscoreResult result = hiscoreClient.lookup(lookup.getName(), lookup.getEndpoint()); + + if (result == null) + { + log.warn("error looking up {} score: not found", minigame.getName().toLowerCase()); + return; + } + + switch (minigame) + { + case BOUNTY_HUNTER_HUNTER: + hiscoreSkill = result.getBountyHunterHunter(); + break; + case BOUNTY_HUNTER_ROGUE: + hiscoreSkill = result.getBountyHunterRogue(); + break; + case LAST_MAN_STANDING: + hiscoreSkill = result.getLastManStanding(); + break; + default: + log.warn("error looking up {} score: not implemented", minigame.getName().toLowerCase()); + return; + } + + int score = hiscoreSkill.getLevel(); + if (score == -1) + { + return; + } + + ChatMessageBuilder chatMessageBuilder = new ChatMessageBuilder() + .append(ChatColorType.NORMAL) + .append(minigame.getName()) + .append(" Score: ") + .append(ChatColorType.HIGHLIGHT) + .append(Integer.toString(score)); + + int rank = hiscoreSkill.getRank(); + if (rank != -1) + { + chatMessageBuilder.append(ChatColorType.NORMAL) + .append(" Rank: ") + .append(ChatColorType.HIGHLIGHT) + .append(String.format("%,d", rank)); + } + + String response = chatMessageBuilder.build(); + + log.debug("Setting response {}", response); + final MessageNode messageNode = chatMessage.getMessageNode(); + messageNode.setRuneLiteFormatMessage(response); + chatMessageManager.update(messageNode); + client.refreshChat(); + } + catch (IOException ex) + { + log.warn("error looking up {}", minigame.getName().toLowerCase(), ex); + } + } + private void clueLookup(ChatMessage chatMessage, String message) { if (!config.clue()) From 8db705120604d9278719a0260c15a1c905aa1f73 Mon Sep 17 00:00:00 2001 From: Rolf Don Date: Fri, 21 Feb 2020 01:07:44 +0100 Subject: [PATCH 23/23] skill calc: strip out non-digits characters --- .../client/plugins/skillcalculator/UICalculatorInputArea.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/UICalculatorInputArea.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/UICalculatorInputArea.java index 3aa1bff236..a15565bd34 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/UICalculatorInputArea.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/UICalculatorInputArea.java @@ -98,7 +98,7 @@ class UICalculatorInputArea extends JPanel { try { - return Integer.parseInt(field.getText()); + return Integer.parseInt(field.getText().replaceAll("\\D", "")); } catch (NumberFormatException e) {