Merge remote-tracking branch 'upstream/master' into master
@@ -522,6 +522,11 @@ public interface Client extends GameEngine
|
|||||||
*/
|
*/
|
||||||
void setDraggedOnWidget(Widget widget);
|
void setDraggedOnWidget(Widget widget);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets Interface ID of the root widget
|
||||||
|
*/
|
||||||
|
int getTopLevelInterfaceId();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the root widgets.
|
* Gets the root widgets.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -983,13 +983,13 @@ public final class SpriteID
|
|||||||
public static final int UNKNOWN_SLANTED_TAB_LONG_HOVERED = 1016;
|
public static final int UNKNOWN_SLANTED_TAB_LONG_HOVERED = 1016;
|
||||||
public static final int CHATBOX = 1017;
|
public static final int CHATBOX = 1017;
|
||||||
public static final int CHATBOX_BUTTONS_BACKGROUND_STONES = 1018;
|
public static final int CHATBOX_BUTTONS_BACKGROUND_STONES = 1018;
|
||||||
public static final int CHATBOX_BUTTON = 1019;
|
public static final int CHATBOX_BUTTON = 3051;
|
||||||
public static final int CHATBOX_BUTTON_HOVERED = 1020;
|
public static final int CHATBOX_BUTTON_HOVERED = 3052;
|
||||||
public static final int CHATBOX_BUTTON_NEW_MESSAGES = 1021;
|
public static final int CHATBOX_BUTTON_NEW_MESSAGES = 3055;
|
||||||
public static final int CHATBOX_BUTTON_SELECTED = 1022;
|
public static final int CHATBOX_BUTTON_SELECTED = 3053;
|
||||||
public static final int CHATBOX_BUTTON_SELECTED_HOVERED = 1023;
|
public static final int CHATBOX_BUTTON_SELECTED_HOVERED = 3054;
|
||||||
public static final int CHATBOX_REPORT_BUTTON = 1024;
|
public static final int CHATBOX_REPORT_BUTTON = 3057;
|
||||||
public static final int CHATBOX_REPORT_BUTTON_HOVERED = 1025;
|
public static final int CHATBOX_REPORT_BUTTON_HOVERED = 3058;
|
||||||
public static final int TAB_STONE_TOP_LEFT_SELECTED = 1026;
|
public static final int TAB_STONE_TOP_LEFT_SELECTED = 1026;
|
||||||
public static final int TAB_STONE_TOP_RIGHT_SELECTED = 1027;
|
public static final int TAB_STONE_TOP_RIGHT_SELECTED = 1027;
|
||||||
public static final int TAB_STONE_BOTTOM_LEFT_SELECTED = 1028;
|
public static final int TAB_STONE_BOTTOM_LEFT_SELECTED = 1028;
|
||||||
@@ -1065,7 +1065,6 @@ public final class SpriteID
|
|||||||
public static final int ABLEGAMERS_PROMO_BANNER = 1098;
|
public static final int ABLEGAMERS_PROMO_BANNER = 1098;
|
||||||
public static final int YOUNGMINDS_PROMO_BANNER = 1099;
|
public static final int YOUNGMINDS_PROMO_BANNER = 1099;
|
||||||
public static final int DONATEGAMES_PROMO_BANNER = 1100;
|
public static final int DONATEGAMES_PROMO_BANNER = 1100;
|
||||||
public static final int UNKNOWN_GREEN_FRIEND_ICON = 1101;
|
|
||||||
public static final int MINIMAP_ORB_HITPOINTS_VENOM = 1102;
|
public static final int MINIMAP_ORB_HITPOINTS_VENOM = 1102;
|
||||||
public static final int PAYPAL_DONATE_BUTTON = 1103;
|
public static final int PAYPAL_DONATE_BUTTON = 1103;
|
||||||
public static final int GAMEBLAST15_PROMO_BANNER = 1104;
|
public static final int GAMEBLAST15_PROMO_BANNER = 1104;
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Jonathan Rousseau <https://github.com/JoRouss>
|
||||||
|
* 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.image.BufferedImage;
|
||||||
|
import java.util.UUID;
|
||||||
|
import lombok.Value;
|
||||||
|
|
||||||
|
@Value
|
||||||
|
public class PartyMemberAvatar
|
||||||
|
{
|
||||||
|
private final UUID memberId;
|
||||||
|
private final BufferedImage image;
|
||||||
|
}
|
||||||
@@ -171,42 +171,42 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati
|
|||||||
.put(new WorldPoint(3143, 3774, 0), new CoordinateClueInfo("In level 32 Wilderness, by the black chinchompa hunting area.", ZAMORAK_WIZARD))
|
.put(new WorldPoint(3143, 3774, 0), new CoordinateClueInfo("In level 32 Wilderness, by the black chinchompa hunting area.", ZAMORAK_WIZARD))
|
||||||
.put(new WorldPoint(2992, 3941, 0), new CoordinateClueInfo("Wilderness Agility Course, past the log balance.", ZAMORAK_WIZARD))
|
.put(new WorldPoint(2992, 3941, 0), new CoordinateClueInfo("Wilderness Agility Course, past the log balance.", ZAMORAK_WIZARD))
|
||||||
// Elite
|
// Elite
|
||||||
.put(new WorldPoint(2357, 3151, 0), new CoordinateClueInfo("Lletya.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2357, 3151, 0), new CoordinateClueInfo("Lletya.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(3587, 3180, 0), new CoordinateClueInfo("Meiyerditch.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(3587, 3180, 0), new CoordinateClueInfo("Meiyerditch.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2820, 3078, 0), new CoordinateClueInfo("Tai Bwo Wannai. Hardwood Grove. 100 Trading sticks or elite Karamja diary completion is needed to enter.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2820, 3078, 0), new CoordinateClueInfo("Tai Bwo Wannai. Hardwood Grove. 100 Trading sticks or elite Karamja diary completion is needed to enter.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(3811, 3060, 0), new CoordinateClueInfo("Small island north-east of Mos Le'Harmless.", ARMADYLIAN_OR_BANDOSIAN_GUARD, true, Varbits.FIRE_PIT_MOS_LE_HARMLESS))
|
.put(new WorldPoint(3811, 3060, 0), new CoordinateClueInfo("Small island north-east of Mos Le'Harmless.", ARMADYLEAN_OR_BANDOSIAN_GUARD, true, Varbits.FIRE_PIT_MOS_LE_HARMLESS))
|
||||||
.put(new WorldPoint(2180, 3282, 0), new CoordinateClueInfo("North of Iorwerth Camp.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2180, 3282, 0), new CoordinateClueInfo("North of Iorwerth Camp.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2870, 2997, 0), new CoordinateClueInfo("North-east corner in Shilo Village.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2870, 2997, 0), new CoordinateClueInfo("North-east corner in Shilo Village.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(3302, 2988, 0), new CoordinateClueInfo("On top of a cliff to the west of Pollnivneach.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(3302, 2988, 0), new CoordinateClueInfo("On top of a cliff to the west of Pollnivneach.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2511, 2980, 0), new CoordinateClueInfo("Just south of Gu'Tanoth, west of gnome glider.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2511, 2980, 0), new CoordinateClueInfo("Just south of Gu'Tanoth, west of gnome glider.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2732, 3372, 0), new CoordinateClueInfo("Legends' Guild.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2732, 3372, 0), new CoordinateClueInfo("Legends' Guild.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(3573, 3425, 0), new CoordinateClueInfo("North of Dessous's tomb from Desert Treasure.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(3573, 3425, 0), new CoordinateClueInfo("North of Dessous's tomb from Desert Treasure.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(3828, 2848, 0), new CoordinateClueInfo("East of Harmony Island.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(3828, 2848, 0), new CoordinateClueInfo("East of Harmony Island.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(3225, 2838, 0), new CoordinateClueInfo("South of Desert Treasure pyramid.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(3225, 2838, 0), new CoordinateClueInfo("South of Desert Treasure pyramid.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(1773, 3510, 0), new CoordinateClueInfo("Ruins north of the Hosidius mine.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(1773, 3510, 0), new CoordinateClueInfo("Ruins north of the Hosidius mine.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(3822, 3562, 0), new CoordinateClueInfo("North-east of Dragontooth Island. Bring a Ghostspeak Amulet and 25 Ecto-tokens to reach the island.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(3822, 3562, 0), new CoordinateClueInfo("North-east of Dragontooth Island. Bring a Ghostspeak Amulet and 25 Ecto-tokens to reach the island.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(3603, 3564, 0), new CoordinateClueInfo("North of the wrecked ship, outside of Port Phasmatys.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(3603, 3564, 0), new CoordinateClueInfo("North of the wrecked ship, outside of Port Phasmatys.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2936, 2721, 0), new CoordinateClueInfo("Eastern shore of Crash Island.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2936, 2721, 0), new CoordinateClueInfo("Eastern shore of Crash Island.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2697, 2705, 0), new CoordinateClueInfo("South-west of Ape Atoll.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2697, 2705, 0), new CoordinateClueInfo("South-west of Ape Atoll.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2778, 3678, 0), new CoordinateClueInfo("Mountain Camp.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2778, 3678, 0), new CoordinateClueInfo("Mountain Camp.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2827, 3740, 0), new CoordinateClueInfo("West of the entrance to the Ice Path, where the Troll child resides.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2827, 3740, 0), new CoordinateClueInfo("West of the entrance to the Ice Path, where the Troll child resides.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2359, 3799, 0), new CoordinateClueInfo("Neitiznot.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2359, 3799, 0), new CoordinateClueInfo("Neitiznot.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2194, 3807, 0), new CoordinateClueInfo("Pirates' Cove.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2194, 3807, 0), new CoordinateClueInfo("Pirates' Cove.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2700, 3808, 0), new CoordinateClueInfo("Northwestern part of the Trollweiss and Rellekka Hunter area (DKS).", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2700, 3808, 0), new CoordinateClueInfo("Northwestern part of the Trollweiss and Rellekka Hunter area (DKS).", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(3215, 3835, 0), new CoordinateClueInfo("Wilderness. Lava Dragon Isle.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(3215, 3835, 0), new CoordinateClueInfo("Wilderness. Lava Dragon Isle.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(3369, 3894, 0), new CoordinateClueInfo("Wilderness. Fountain of Rune.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(3369, 3894, 0), new CoordinateClueInfo("Wilderness. Fountain of Rune.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2065, 3923, 0), new CoordinateClueInfo("Outside the western wall on Lunar Isle.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2065, 3923, 0), new CoordinateClueInfo("Outside the western wall on Lunar Isle.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(3188, 3933, 0), new CoordinateClueInfo("Wilderness. Resource Area.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(3188, 3933, 0), new CoordinateClueInfo("Wilderness. Resource Area.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2997, 3953, 0), new CoordinateClueInfo("Wilderness. Inside Agility Training Area.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2997, 3953, 0), new CoordinateClueInfo("Wilderness. Inside Agility Training Area.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(3380, 3963, 0), new CoordinateClueInfo("Wilderness. North of Volcano.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(3380, 3963, 0), new CoordinateClueInfo("Wilderness. North of Volcano.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(3051, 3736, 0), new CoordinateClueInfo("East of the Wilderness Obelisk in 28 Wilderness.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(3051, 3736, 0), new CoordinateClueInfo("East of the Wilderness Obelisk in 28 Wilderness.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2316, 3814, 0), new CoordinateClueInfo("West of Neitiznot, near the bridge.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2316, 3814, 0), new CoordinateClueInfo("West of Neitiznot, near the bridge.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2872, 3937, 0), new CoordinateClueInfo("Weiss.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2872, 3937, 0), new CoordinateClueInfo("Weiss.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2484, 4016, 0), new CoordinateClueInfo("Northeast corner of the Island of Stone.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2484, 4016, 0), new CoordinateClueInfo("Northeast corner of the Island of Stone.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2222, 3331, 0), new CoordinateClueInfo("Prifddinas, west of the Tower of Voices", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2222, 3331, 0), new CoordinateClueInfo("Prifddinas, west of the Tower of Voices", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(3560, 3987, 0), new CoordinateClueInfo("Lithkren. Digsite pendant teleport if unlocked, otherwise take rowboat from west of Mushroom Meadow Mushtree.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(3560, 3987, 0), new CoordinateClueInfo("Lithkren. Digsite pendant teleport if unlocked, otherwise take rowboat from west of Mushroom Meadow Mushtree.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2318, 2954, 0), new CoordinateClueInfo("North-east corner of the Isle of Souls.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2318, 2954, 0), new CoordinateClueInfo("North-east corner of the Isle of Souls.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
.put(new WorldPoint(2094, 2889, 0), new CoordinateClueInfo("West side of the Isle of Souls.", ARMADYLIAN_OR_BANDOSIAN_GUARD))
|
.put(new WorldPoint(2094, 2889, 0), new CoordinateClueInfo("West side of the Isle of Souls.", ARMADYLEAN_OR_BANDOSIAN_GUARD))
|
||||||
// Master
|
// Master
|
||||||
.put(new WorldPoint(2178, 3209, 0), new CoordinateClueInfo("South of Iorwerth Camp.", BRASSICAN_MAGE))
|
.put(new WorldPoint(2178, 3209, 0), new CoordinateClueInfo("South of Iorwerth Camp.", BRASSICAN_MAGE))
|
||||||
.put(new WorldPoint(2155, 3100, 0), new CoordinateClueInfo("South of Port Tyras (BJS if 76 Agility).", BRASSICAN_MAGE))
|
.put(new WorldPoint(2155, 3100, 0), new CoordinateClueInfo("South of Port Tyras (BJS if 76 Agility).", BRASSICAN_MAGE))
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public enum Enemy
|
|||||||
//appears for hard clue coordinate steps not in the wilderness
|
//appears for hard clue coordinate steps not in the wilderness
|
||||||
SARADOMIN_WIZARD("Saradomin Wizard"),
|
SARADOMIN_WIZARD("Saradomin Wizard"),
|
||||||
//appears for elite clue coordinate steps all areas
|
//appears for elite clue coordinate steps all areas
|
||||||
ARMADYLIAN_OR_BANDOSIAN_GUARD("Armadylian OR Bandosian Guard"),
|
ARMADYLEAN_OR_BANDOSIAN_GUARD("Armadylean OR Bandosian Guard"),
|
||||||
//appears for master clue coordinate and hot cold clues when single-way combat
|
//appears for master clue coordinate and hot cold clues when single-way combat
|
||||||
BRASSICAN_MAGE("Brassican Mage"),
|
BRASSICAN_MAGE("Brassican Mage"),
|
||||||
//appears for master clue coordinate and hot cold clues when multi-way combat
|
//appears for master clue coordinate and hot cold clues when multi-way combat
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||||
* Copyright (c) 2018, PandahRS <https://github.com/PandahRS>
|
* Copyright (c) 2018, PandahRS <https://github.com/PandahRS>
|
||||||
|
* Copyright (c) 2021, Jonathan Rousseau <https://github.com/JoRouss>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -25,6 +26,7 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.client.plugins.discord;
|
package net.runelite.client.plugins.discord;
|
||||||
|
|
||||||
|
import com.google.common.base.CharMatcher;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
@@ -49,7 +51,6 @@ import net.runelite.api.events.StatChanged;
|
|||||||
import net.runelite.client.config.ConfigManager;
|
import net.runelite.client.config.ConfigManager;
|
||||||
import net.runelite.client.discord.DiscordService;
|
import net.runelite.client.discord.DiscordService;
|
||||||
import net.runelite.client.discord.events.DiscordJoinGame;
|
import net.runelite.client.discord.events.DiscordJoinGame;
|
||||||
import net.runelite.client.discord.events.DiscordJoinRequest;
|
|
||||||
import net.runelite.client.discord.events.DiscordReady;
|
import net.runelite.client.discord.events.DiscordReady;
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
import net.runelite.client.events.ConfigChanged;
|
import net.runelite.client.events.ConfigChanged;
|
||||||
@@ -214,20 +215,6 @@ public class DiscordPlugin extends Plugin
|
|||||||
partyService.setUsername(event.getUsername() + "#" + event.getDiscriminator());
|
partyService.setUsername(event.getUsername() + "#" + event.getDiscriminator());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
public void onDiscordJoinRequest(DiscordJoinRequest request)
|
|
||||||
{
|
|
||||||
// In order for the "Invite to join" message to work we need to have a valid party in Discord presence.
|
|
||||||
// We lazily create the party here in order to avoid the (1 of 15) being permanently in the Discord status.
|
|
||||||
if (!partyService.isInParty())
|
|
||||||
{
|
|
||||||
// Change to my party id, which is advertised in the Discord presence secret. This will open the socket,
|
|
||||||
// send a join, and cause a UserJoin later for me, which will then update the presence and allow the
|
|
||||||
// "Invite to join" to continue.
|
|
||||||
partyService.changeParty(partyService.getLocalPartyId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onDiscordJoinGame(DiscordJoinGame joinGame)
|
public void onDiscordJoinGame(DiscordJoinGame joinGame)
|
||||||
{
|
{
|
||||||
@@ -246,18 +233,30 @@ public class DiscordPlugin extends Plugin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String url = "https://cdn.discordapp.com/avatars/" + event.getUserId() + "/" + event.getAvatarId() + ".png";
|
CharMatcher matcher = CharMatcher.anyOf("abcdef0123456789");
|
||||||
|
if (!matcher.matchesAllOf(event.getUserId()) || !matcher.matchesAllOf(event.getAvatarId()))
|
||||||
|
{
|
||||||
|
// userid is actually a snowflake, but the matcher is sufficient
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String url;
|
||||||
|
|
||||||
if (Strings.isNullOrEmpty(event.getAvatarId()))
|
if (Strings.isNullOrEmpty(event.getAvatarId()))
|
||||||
{
|
{
|
||||||
final String[] split = memberById.getName().split("#", 2);
|
final String[] split = memberById.getName().split("#", 2);
|
||||||
|
if (split.length != 2)
|
||||||
if (split.length == 2)
|
|
||||||
{
|
{
|
||||||
int disc = Integer.valueOf(split[1]);
|
return;
|
||||||
int avatarId = disc % 5;
|
|
||||||
url = "https://cdn.discordapp.com/embed/avatars/" + avatarId + ".png";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int disc = Integer.parseInt(split[1]);
|
||||||
|
int avatarId = disc % 5;
|
||||||
|
url = "https://cdn.discordapp.com/embed/avatars/" + avatarId + ".png";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
url = "https://cdn.discordapp.com/avatars/" + event.getUserId() + "/" + event.getAvatarId() + ".png";
|
||||||
}
|
}
|
||||||
|
|
||||||
log.debug("Got user avatar {}", url);
|
log.debug("Got user avatar {}", url);
|
||||||
@@ -290,7 +289,8 @@ public class DiscordPlugin extends Plugin
|
|||||||
{
|
{
|
||||||
image = ImageIO.read(inputStream);
|
image = ImageIO.read(inputStream);
|
||||||
}
|
}
|
||||||
memberById.setAvatar(image);
|
|
||||||
|
partyService.setPartyMemberAvatar(memberById.getMemberId(), image);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||||
|
* Copyright (c) 2021, Jonathan Rousseau <https://github.com/JoRouss>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -31,7 +32,6 @@ import java.time.Instant;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -55,7 +55,6 @@ class DiscordState
|
|||||||
private Instant updated;
|
private Instant updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final UUID partyId = UUID.randomUUID();
|
|
||||||
private final List<EventWithTime> events = new ArrayList<>();
|
private final List<EventWithTime> events = new ArrayList<>();
|
||||||
private final DiscordService discordService;
|
private final DiscordService discordService;
|
||||||
private final DiscordConfig config;
|
private final DiscordConfig config;
|
||||||
@@ -106,15 +105,10 @@ class DiscordState
|
|||||||
.largeImageText(lastPresence.getLargeImageText())
|
.largeImageText(lastPresence.getLargeImageText())
|
||||||
.startTimestamp(lastPresence.getStartTimestamp())
|
.startTimestamp(lastPresence.getStartTimestamp())
|
||||||
.smallImageKey(lastPresence.getSmallImageKey())
|
.smallImageKey(lastPresence.getSmallImageKey())
|
||||||
.partyMax(lastPresence.getPartyMax())
|
.partyMax(lastPresence.getPartyMax());
|
||||||
.partySize(party.getMembers().size());
|
|
||||||
|
|
||||||
if (!party.isInParty() || party.isPartyOwner())
|
|
||||||
{
|
setPresencePartyInfo(presenceBuilder);
|
||||||
// This is only used to identify the invites on Discord's side. Our party ids are the secret.
|
|
||||||
presenceBuilder.partyId(partyId.toString());
|
|
||||||
presenceBuilder.joinSecret(party.getLocalPartyId().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
discordService.updatePresence(presenceBuilder.build());
|
discordService.updatePresence(presenceBuilder.build());
|
||||||
}
|
}
|
||||||
@@ -205,8 +199,7 @@ class DiscordState
|
|||||||
.details(MoreObjects.firstNonNull(details, ""))
|
.details(MoreObjects.firstNonNull(details, ""))
|
||||||
.largeImageText(runeliteTitle + " v" + versionShortHand)
|
.largeImageText(runeliteTitle + " v" + versionShortHand)
|
||||||
.smallImageKey(imageKey)
|
.smallImageKey(imageKey)
|
||||||
.partyMax(PARTY_MAX)
|
.partyMax(PARTY_MAX);
|
||||||
.partySize(party.getMembers().size());
|
|
||||||
|
|
||||||
final Instant startTime;
|
final Instant startTime;
|
||||||
switch (config.elapsedTimeType())
|
switch (config.elapsedTimeType())
|
||||||
@@ -233,11 +226,7 @@ class DiscordState
|
|||||||
|
|
||||||
presenceBuilder.startTimestamp(startTime);
|
presenceBuilder.startTimestamp(startTime);
|
||||||
|
|
||||||
if (!party.isInParty() || party.isPartyOwner())
|
setPresencePartyInfo(presenceBuilder);
|
||||||
{
|
|
||||||
presenceBuilder.partyId(partyId.toString());
|
|
||||||
presenceBuilder.joinSecret(party.getLocalPartyId().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
final DiscordPresence presence = presenceBuilder.build();
|
final DiscordPresence presence = presenceBuilder.build();
|
||||||
|
|
||||||
@@ -286,4 +275,16 @@ class DiscordState
|
|||||||
updatePresenceWithLatestEvent();
|
updatePresenceWithLatestEvent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setPresencePartyInfo(DiscordPresence.DiscordPresenceBuilder presenceBuilder)
|
||||||
|
{
|
||||||
|
if (party.isInParty())
|
||||||
|
{
|
||||||
|
presenceBuilder.partySize(party.getMembers().size());
|
||||||
|
|
||||||
|
// Set public party id and secret
|
||||||
|
presenceBuilder.partyId(party.getPublicPartyId().toString());
|
||||||
|
presenceBuilder.joinSecret(party.getPartyId().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public class InfoPlugin extends Plugin
|
|||||||
navButton = NavigationButton.builder()
|
navButton = NavigationButton.builder()
|
||||||
.tooltip("Info")
|
.tooltip("Info")
|
||||||
.icon(icon)
|
.icon(icon)
|
||||||
.priority(9)
|
.priority(10)
|
||||||
.panel(panel)
|
.panel(panel)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|||||||
@@ -28,69 +28,19 @@ import java.awt.Color;
|
|||||||
import net.runelite.client.config.Config;
|
import net.runelite.client.config.Config;
|
||||||
import net.runelite.client.config.ConfigGroup;
|
import net.runelite.client.config.ConfigGroup;
|
||||||
import net.runelite.client.config.ConfigItem;
|
import net.runelite.client.config.ConfigItem;
|
||||||
|
import net.runelite.client.config.ConfigSection;
|
||||||
|
|
||||||
@ConfigGroup("minimap")
|
@ConfigGroup(MinimapConfig.GROUP)
|
||||||
public interface MinimapConfig extends Config
|
public interface MinimapConfig extends Config
|
||||||
{
|
{
|
||||||
@ConfigItem(
|
String GROUP = "minimap";
|
||||||
keyName = "item",
|
|
||||||
name = "Item color",
|
|
||||||
description = "Set the minimap color items are drawn in"
|
|
||||||
)
|
|
||||||
default Color itemColor() //mapdot 0
|
|
||||||
{
|
|
||||||
return new Color(255, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigSection(
|
||||||
keyName = "npc",
|
name = "Minimap dot colors",
|
||||||
name = "NPC color",
|
description = "The colors of dots on the minimap.",
|
||||||
description = "Set the minimap color NPCs are drawn in"
|
position = 0
|
||||||
)
|
)
|
||||||
default Color npcColor() //mapdot 1
|
String minimapDotSection = "minimapDotSection";
|
||||||
{
|
|
||||||
return new Color(255, 255, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ConfigItem(
|
|
||||||
keyName = "player",
|
|
||||||
name = "Player color",
|
|
||||||
description = "Set the minimap Color players are drawn in"
|
|
||||||
)
|
|
||||||
default Color playerColor() //mapdot 2
|
|
||||||
{
|
|
||||||
return new Color(255, 255, 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ConfigItem(
|
|
||||||
keyName = "friend",
|
|
||||||
name = "Friends color",
|
|
||||||
description = "Set the minimap color your friends are drawn in"
|
|
||||||
)
|
|
||||||
default Color friendColor() //mapdot 3
|
|
||||||
{
|
|
||||||
return new Color(0, 255, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ConfigItem(
|
|
||||||
keyName = "team",
|
|
||||||
name = "Team color",
|
|
||||||
description = "Set the minimap color your team is drawn in"
|
|
||||||
)
|
|
||||||
default Color teamColor() //mapdot 4
|
|
||||||
{
|
|
||||||
return new Color(19, 110, 247);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ConfigItem(
|
|
||||||
keyName = "clan",
|
|
||||||
name = "Friends Chat color",
|
|
||||||
description = "Set the minimap color your friends chat members are drawn in"
|
|
||||||
)
|
|
||||||
default Color friendsChatColor() //mapdot 5
|
|
||||||
{
|
|
||||||
return new Color(170, 0, 190);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
keyName = "hideMinimap",
|
keyName = "hideMinimap",
|
||||||
@@ -101,4 +51,60 @@ public interface MinimapConfig extends Config
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "item",
|
||||||
|
name = "Item color",
|
||||||
|
description = "Set the minimap color items are drawn in",
|
||||||
|
section = minimapDotSection
|
||||||
|
)
|
||||||
|
Color itemColor();
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "npc",
|
||||||
|
name = "NPC color",
|
||||||
|
description = "Set the minimap color NPCs are drawn in",
|
||||||
|
section = minimapDotSection
|
||||||
|
)
|
||||||
|
Color npcColor();
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "player",
|
||||||
|
name = "Player color",
|
||||||
|
description = "Set the minimap Color players are drawn in",
|
||||||
|
section = minimapDotSection
|
||||||
|
)
|
||||||
|
Color playerColor();
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "friend",
|
||||||
|
name = "Friends color",
|
||||||
|
description = "Set the minimap color your friends are drawn in",
|
||||||
|
section = minimapDotSection
|
||||||
|
)
|
||||||
|
Color friendColor();
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "team",
|
||||||
|
name = "Team color",
|
||||||
|
description = "Set the minimap color your team is drawn in",
|
||||||
|
section = minimapDotSection
|
||||||
|
)
|
||||||
|
Color teamColor();
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "clan", // old name from prior to clans
|
||||||
|
name = "Friends Chat color",
|
||||||
|
description = "Set the minimap color your friends chat members are drawn in",
|
||||||
|
section = minimapDotSection
|
||||||
|
)
|
||||||
|
Color friendsChatColor();
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "clanchat",
|
||||||
|
name = "Clan Chat color",
|
||||||
|
description = "Set the minimap color your clan chat members are drawn in",
|
||||||
|
section = minimapDotSection
|
||||||
|
)
|
||||||
|
Color clanChatColor();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import java.awt.Color;
|
|||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.SpritePixels;
|
import net.runelite.api.SpritePixels;
|
||||||
|
|
||||||
public class MinimapDot
|
class MinimapDot
|
||||||
{
|
{
|
||||||
private static final int MAP_DOT_WIDTH = 4;
|
private static final int MAP_DOT_WIDTH = 4;
|
||||||
private static final int MAP_DOT_HEIGHT = 5;
|
private static final int MAP_DOT_HEIGHT = 5;
|
||||||
@@ -67,12 +67,9 @@ public class MinimapDot
|
|||||||
return pixels;
|
return pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SpritePixels create(Client client, Color color)
|
static SpritePixels create(Client client, Color color)
|
||||||
{
|
{
|
||||||
int[] pixels = createPixels(color);
|
int[] pixels = createPixels(color);
|
||||||
|
return client.createSpritePixels(pixels, MAP_DOT_WIDTH, MAP_DOT_HEIGHT);
|
||||||
SpritePixels dotSprite = client.createSpritePixels(pixels, MAP_DOT_WIDTH, MAP_DOT_HEIGHT);
|
|
||||||
|
|
||||||
return dotSprite;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,12 +44,18 @@ import net.runelite.client.plugins.PluginDescriptor;
|
|||||||
|
|
||||||
@PluginDescriptor(
|
@PluginDescriptor(
|
||||||
name = "Minimap",
|
name = "Minimap",
|
||||||
description = "Customize the color of minimap dots",
|
description = "Customize the color of minimap dots, and hide the minimap",
|
||||||
tags = {"items", "npcs", "players"}
|
tags = {"items", "npcs", "players"}
|
||||||
)
|
)
|
||||||
public class MinimapPlugin extends Plugin
|
public class MinimapPlugin extends Plugin
|
||||||
{
|
{
|
||||||
private static final int NUM_MAPDOTS = 6;
|
private static final int DOT_ITEM = 0;
|
||||||
|
private static final int DOT_NPC = 1;
|
||||||
|
private static final int DOT_PLAYER = 2;
|
||||||
|
private static final int DOT_FRIEND = 3;
|
||||||
|
private static final int DOT_TEAM = 4;
|
||||||
|
private static final int DOT_FRIENDSCHAT = 5;
|
||||||
|
private static final int DOT_CLAN = 6;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private Client client;
|
private Client client;
|
||||||
@@ -66,7 +72,7 @@ public class MinimapPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void startUp() throws Exception
|
protected void startUp()
|
||||||
{
|
{
|
||||||
updateMinimapWidgetVisibility(config.hideMinimap());
|
updateMinimapWidgetVisibility(config.hideMinimap());
|
||||||
storeOriginalDots();
|
storeOriginalDots();
|
||||||
@@ -74,7 +80,7 @@ public class MinimapPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void shutDown() throws Exception
|
protected void shutDown()
|
||||||
{
|
{
|
||||||
updateMinimapWidgetVisibility(false);
|
updateMinimapWidgetVisibility(false);
|
||||||
restoreOriginalDots();
|
restoreOriginalDots();
|
||||||
@@ -93,7 +99,7 @@ public class MinimapPlugin extends Plugin
|
|||||||
@Subscribe
|
@Subscribe
|
||||||
public void onConfigChanged(ConfigChanged event)
|
public void onConfigChanged(ConfigChanged event)
|
||||||
{
|
{
|
||||||
if (!event.getGroup().equals("minimap"))
|
if (!event.getGroup().equals(MinimapConfig.GROUP))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -149,23 +155,21 @@ public class MinimapPlugin extends Plugin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color[] minimapDotColors = getColors();
|
applyDot(mapDots, DOT_ITEM, config.itemColor());
|
||||||
for (int i = 0; i < mapDots.length && i < minimapDotColors.length; ++i)
|
applyDot(mapDots, DOT_NPC, config.npcColor());
|
||||||
{
|
applyDot(mapDots, DOT_PLAYER, config.playerColor());
|
||||||
mapDots[i] = MinimapDot.create(this.client, minimapDotColors[i]);
|
applyDot(mapDots, DOT_FRIEND, config.friendColor());
|
||||||
}
|
applyDot(mapDots, DOT_TEAM, config.teamColor());
|
||||||
|
applyDot(mapDots, DOT_FRIENDSCHAT, config.friendsChatColor());
|
||||||
|
applyDot(mapDots, DOT_CLAN, config.clanChatColor());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Color[] getColors()
|
private void applyDot(SpritePixels[] mapDots, int id, Color color)
|
||||||
{
|
{
|
||||||
Color[] colors = new Color[NUM_MAPDOTS];
|
if (id < mapDots.length && color != null)
|
||||||
colors[0] = config.itemColor();
|
{
|
||||||
colors[1] = config.npcColor();
|
mapDots[id] = MinimapDot.create(client, color);
|
||||||
colors[2] = config.playerColor();
|
}
|
||||||
colors[3] = config.friendColor();
|
|
||||||
colors[4] = config.teamColor();
|
|
||||||
colors[5] = config.friendsChatColor();
|
|
||||||
return colors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void storeOriginalDots()
|
private void storeOriginalDots()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||||
|
* Copyright (c) 2021, Jonathan Rousseau <https://github.com/JoRouss>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -28,23 +29,16 @@ import net.runelite.client.config.Config;
|
|||||||
import net.runelite.client.config.ConfigGroup;
|
import net.runelite.client.config.ConfigGroup;
|
||||||
import net.runelite.client.config.ConfigItem;
|
import net.runelite.client.config.ConfigItem;
|
||||||
|
|
||||||
@ConfigGroup("party")
|
@ConfigGroup(PartyConfig.GROUP)
|
||||||
public interface PartyConfig extends Config
|
public interface PartyConfig extends Config
|
||||||
{
|
{
|
||||||
@ConfigItem(
|
String GROUP = "party";
|
||||||
keyName = "stats",
|
|
||||||
name = "Stats",
|
|
||||||
description = "Enables party stats overlay showing HP, prayer and player name"
|
|
||||||
)
|
|
||||||
default boolean stats()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
keyName = "pings",
|
keyName = "pings",
|
||||||
name = "Pings",
|
name = "Pings",
|
||||||
description = "Enables party pings (shift + left-click)"
|
description = "Enables party pings (shift + left-click)",
|
||||||
|
position = 1
|
||||||
)
|
)
|
||||||
default boolean pings()
|
default boolean pings()
|
||||||
{
|
{
|
||||||
@@ -54,7 +48,8 @@ public interface PartyConfig extends Config
|
|||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
keyName = "sounds",
|
keyName = "sounds",
|
||||||
name = "Sound on ping",
|
name = "Sound on ping",
|
||||||
description = "Enables sound notification on party ping"
|
description = "Enables sound notification on party ping",
|
||||||
|
position = 2
|
||||||
)
|
)
|
||||||
default boolean sounds()
|
default boolean sounds()
|
||||||
{
|
{
|
||||||
@@ -64,7 +59,8 @@ public interface PartyConfig extends Config
|
|||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
keyName = "messages",
|
keyName = "messages",
|
||||||
name = "Join messages",
|
name = "Join messages",
|
||||||
description = "Enables join/leave game messages"
|
description = "Enables members join/leave game messages",
|
||||||
|
position = 3
|
||||||
)
|
)
|
||||||
default boolean messages()
|
default boolean messages()
|
||||||
{
|
{
|
||||||
@@ -74,10 +70,33 @@ public interface PartyConfig extends Config
|
|||||||
@ConfigItem(
|
@ConfigItem(
|
||||||
keyName = "recolorNames",
|
keyName = "recolorNames",
|
||||||
name = "Recolor names",
|
name = "Recolor names",
|
||||||
description = "Recolor stats overlay names based on unique color hash"
|
description = "Recolor party members names based on unique color hash",
|
||||||
|
position = 4
|
||||||
)
|
)
|
||||||
default boolean recolorNames()
|
default boolean recolorNames()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "autoOverlay",
|
||||||
|
name = "Auto overlay",
|
||||||
|
description = "Automatically add an overlay with player data when a member joins",
|
||||||
|
position = 5
|
||||||
|
)
|
||||||
|
default boolean autoOverlay()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConfigItem(
|
||||||
|
keyName = "includeSelf",
|
||||||
|
name = "Include yourself",
|
||||||
|
description = "Shows yourself in the panel as part of the party",
|
||||||
|
position = 6
|
||||||
|
)
|
||||||
|
default boolean includeSelf()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Jonathan Rousseau <https://github.com/JoRouss>
|
||||||
|
* 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.party;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import javax.swing.BorderFactory;
|
||||||
|
import javax.swing.ImageIcon;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
|
import javax.swing.border.Border;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.Getter;
|
||||||
|
import net.runelite.client.plugins.party.data.PartyData;
|
||||||
|
import net.runelite.client.ui.ColorScheme;
|
||||||
|
import net.runelite.client.ui.DynamicGridLayout;
|
||||||
|
import net.runelite.client.ui.FontManager;
|
||||||
|
import net.runelite.client.ui.components.MouseDragEventForwarder;
|
||||||
|
import net.runelite.client.ui.components.ProgressBar;
|
||||||
|
import net.runelite.client.util.ImageUtil;
|
||||||
|
|
||||||
|
class PartyMemberBox extends JPanel
|
||||||
|
{
|
||||||
|
private static final Color HP_FG = new Color(0, 146, 54, 230);
|
||||||
|
private static final Color HP_BG = new Color(102, 15, 16, 230);
|
||||||
|
private static final Color PRAY_FG = new Color(0, 149, 151);
|
||||||
|
private static final Color PRAY_BG = Color.black;
|
||||||
|
|
||||||
|
@Getter(AccessLevel.PACKAGE)
|
||||||
|
private final PartyData memberPartyData;
|
||||||
|
|
||||||
|
private final ProgressBar hpBar = new ProgressBar();
|
||||||
|
private final ProgressBar prayerBar = new ProgressBar();
|
||||||
|
|
||||||
|
private final JLabel topName = new JLabel();
|
||||||
|
private final JLabel bottomName = new JLabel();
|
||||||
|
|
||||||
|
private final JLabel avatar = new JLabel();
|
||||||
|
|
||||||
|
private final PartyConfig config;
|
||||||
|
|
||||||
|
private boolean avatarSet;
|
||||||
|
|
||||||
|
PartyMemberBox(final PartyConfig config, final JComponent panel, final PartyData memberPartyData)
|
||||||
|
{
|
||||||
|
this.config = config;
|
||||||
|
this.memberPartyData = memberPartyData;
|
||||||
|
|
||||||
|
setLayout(new BorderLayout());
|
||||||
|
setBorder(new EmptyBorder(5, 0, 0, 0));
|
||||||
|
|
||||||
|
/* The box's wrapping container */
|
||||||
|
final JPanel container = new JPanel();
|
||||||
|
container.setLayout(new BorderLayout());
|
||||||
|
container.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||||
|
container.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||||
|
|
||||||
|
// Create Toggle overlay
|
||||||
|
final JMenuItem overlay = new JMenuItem("Toggle overlay");
|
||||||
|
overlay.addActionListener(e -> memberPartyData.setShowOverlay(!memberPartyData.isShowOverlay()));
|
||||||
|
|
||||||
|
// Create popup menu
|
||||||
|
final JPopupMenu popupMenu = new JPopupMenu();
|
||||||
|
popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||||
|
popupMenu.add(overlay);
|
||||||
|
|
||||||
|
// create a line border with the specified color and width
|
||||||
|
Border border = BorderFactory.createLineBorder(Color.gray, 1);
|
||||||
|
avatar.setBorder(border);
|
||||||
|
|
||||||
|
avatar.setHorizontalAlignment(SwingConstants.CENTER);
|
||||||
|
avatar.setVerticalAlignment(SwingConstants.CENTER);
|
||||||
|
avatar.setPreferredSize(new Dimension(35, 35));
|
||||||
|
|
||||||
|
/* Contains the avatar and the names */
|
||||||
|
final JPanel headerPanel = new JPanel();
|
||||||
|
headerPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||||
|
headerPanel.setLayout(new BorderLayout());
|
||||||
|
headerPanel.setBorder(new EmptyBorder(0, 0, 3, 0));
|
||||||
|
|
||||||
|
/* Contains ServiceName name and osrs name */
|
||||||
|
final JPanel namesPanel = new JPanel();
|
||||||
|
namesPanel.setLayout(new DynamicGridLayout(2, 1));
|
||||||
|
namesPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||||
|
namesPanel.setBorder(new EmptyBorder(2, 5, 2, 5));
|
||||||
|
|
||||||
|
topName.setFont(FontManager.getRunescapeSmallFont());
|
||||||
|
bottomName.setFont(FontManager.getRunescapeSmallFont());
|
||||||
|
|
||||||
|
topName.putClientProperty("html.disable", Boolean.TRUE);
|
||||||
|
bottomName.putClientProperty("html.disable", Boolean.TRUE);
|
||||||
|
|
||||||
|
namesPanel.add(topName); // top
|
||||||
|
namesPanel.add(bottomName); // bottom
|
||||||
|
|
||||||
|
headerPanel.add(avatar, BorderLayout.WEST);
|
||||||
|
headerPanel.add(namesPanel, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
JPanel progressWrapper = new JPanel();
|
||||||
|
progressWrapper.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||||
|
progressWrapper.setLayout(new DynamicGridLayout(2, 1, 0, 2));
|
||||||
|
|
||||||
|
hpBar.setBackground(HP_BG);
|
||||||
|
hpBar.setForeground(HP_FG);
|
||||||
|
|
||||||
|
prayerBar.setBackground(PRAY_BG);
|
||||||
|
prayerBar.setForeground(PRAY_FG);
|
||||||
|
|
||||||
|
progressWrapper.add(hpBar); // top
|
||||||
|
progressWrapper.add(prayerBar); // bottom
|
||||||
|
|
||||||
|
container.add(headerPanel, BorderLayout.NORTH);
|
||||||
|
container.add(progressWrapper, BorderLayout.SOUTH);
|
||||||
|
|
||||||
|
container.setComponentPopupMenu(popupMenu);
|
||||||
|
|
||||||
|
// forward mouse drag events to parent panel for drag and drop reordering
|
||||||
|
MouseDragEventForwarder mouseDragEventForwarder = new MouseDragEventForwarder(panel);
|
||||||
|
container.addMouseListener(mouseDragEventForwarder);
|
||||||
|
container.addMouseMotionListener(mouseDragEventForwarder);
|
||||||
|
|
||||||
|
add(container, BorderLayout.NORTH);
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void update()
|
||||||
|
{
|
||||||
|
// Avatar
|
||||||
|
if (!avatarSet && memberPartyData.getMember().getAvatar() != null)
|
||||||
|
{
|
||||||
|
ImageIcon icon = new ImageIcon(ImageUtil.resizeImage(memberPartyData.getMember().getAvatar(), 32, 32));
|
||||||
|
icon.getImage().flush();
|
||||||
|
avatar.setIcon(icon);
|
||||||
|
|
||||||
|
avatarSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update progress bars
|
||||||
|
hpBar.setValue(memberPartyData.getHitpoints());
|
||||||
|
hpBar.setMaximumValue(memberPartyData.getMaxHitpoints());
|
||||||
|
hpBar.setCenterLabel(progressBarLabel(memberPartyData.getHitpoints(), memberPartyData.getMaxHitpoints()));
|
||||||
|
|
||||||
|
prayerBar.setValue(memberPartyData.getPrayer());
|
||||||
|
prayerBar.setMaximumValue(memberPartyData.getMaxPrayer());
|
||||||
|
prayerBar.setCenterLabel(progressBarLabel(memberPartyData.getPrayer(), memberPartyData.getMaxPrayer()));
|
||||||
|
|
||||||
|
// Update name labels
|
||||||
|
Color playerColor = config.recolorNames() ? memberPartyData.getColor() : Color.WHITE;
|
||||||
|
boolean isLoggedIn = !memberPartyData.getCharacterName().isEmpty();
|
||||||
|
|
||||||
|
topName.setForeground(playerColor);
|
||||||
|
topName.setText(memberPartyData.getMember().getName());
|
||||||
|
|
||||||
|
bottomName.setForeground(isLoggedIn ? playerColor : Color.GRAY);
|
||||||
|
bottomName.setText(isLoggedIn ? memberPartyData.getCharacterName() : "Logged out");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String progressBarLabel(int current, int max)
|
||||||
|
{
|
||||||
|
return current + "/" + max;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,214 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Jonathan Rousseau <https://github.com/JoRouss>
|
||||||
|
* 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.party;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
import javax.swing.BoxLayout;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import net.runelite.client.plugins.party.data.PartyData;
|
||||||
|
import net.runelite.client.ui.ColorScheme;
|
||||||
|
import net.runelite.client.ui.PluginPanel;
|
||||||
|
import net.runelite.client.ui.components.DragAndDropReorderPane;
|
||||||
|
import net.runelite.client.ui.components.PluginErrorPanel;
|
||||||
|
import net.runelite.client.ws.PartyService;
|
||||||
|
|
||||||
|
class PartyPanel extends PluginPanel
|
||||||
|
{
|
||||||
|
private static final String BTN_CREATE_TEXT = "Create party";
|
||||||
|
private static final String BTN_LEAVE_TEXT = "Leave party";
|
||||||
|
|
||||||
|
private final PartyPlugin plugin;
|
||||||
|
private final PartyService party;
|
||||||
|
private final PartyConfig config;
|
||||||
|
|
||||||
|
private final Map<String, PartyRequestBox> requestBoxes = new HashMap<>();
|
||||||
|
private final Map<UUID, PartyMemberBox> memberBoxes = new HashMap<>();
|
||||||
|
|
||||||
|
private final JButton startButton = new JButton();
|
||||||
|
|
||||||
|
private final PluginErrorPanel noPartyPanel = new PluginErrorPanel();
|
||||||
|
private final PluginErrorPanel partyEmptyPanel = new PluginErrorPanel();
|
||||||
|
private final JComponent memberBoxPanel = new DragAndDropReorderPane();
|
||||||
|
private final JComponent requestBoxPanel = new DragAndDropReorderPane();
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
PartyPanel(final PartyPlugin plugin, final PartyConfig config, final PartyService party)
|
||||||
|
{
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.party = party;
|
||||||
|
this.config = config;
|
||||||
|
|
||||||
|
setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||||
|
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||||
|
setLayout(new BorderLayout());
|
||||||
|
|
||||||
|
final JPanel layoutPanel = new JPanel();
|
||||||
|
BoxLayout boxLayout = new BoxLayout(layoutPanel, BoxLayout.Y_AXIS);
|
||||||
|
layoutPanel.setLayout(boxLayout);
|
||||||
|
add(layoutPanel, BorderLayout.NORTH);
|
||||||
|
|
||||||
|
final JPanel topPanel = new JPanel();
|
||||||
|
|
||||||
|
topPanel.setBorder(new EmptyBorder(0, 0, 10, 0));
|
||||||
|
topPanel.setLayout(new BorderLayout());
|
||||||
|
|
||||||
|
topPanel.add(startButton, BorderLayout.CENTER);
|
||||||
|
|
||||||
|
layoutPanel.add(topPanel);
|
||||||
|
layoutPanel.add(requestBoxPanel);
|
||||||
|
layoutPanel.add(memberBoxPanel);
|
||||||
|
|
||||||
|
startButton.setText(party.isInParty() ? BTN_LEAVE_TEXT : BTN_CREATE_TEXT);
|
||||||
|
startButton.setFocusable(false);
|
||||||
|
|
||||||
|
topPanel.add(startButton);
|
||||||
|
|
||||||
|
startButton.addActionListener(e ->
|
||||||
|
{
|
||||||
|
if (party.isInParty())
|
||||||
|
{
|
||||||
|
// Leave party
|
||||||
|
final int result = JOptionPane.showOptionDialog(startButton,
|
||||||
|
"Are you sure you want to leave the party?",
|
||||||
|
"Leave party?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
|
||||||
|
null, new String[]{"Yes", "No"}, "No");
|
||||||
|
|
||||||
|
if (result == JOptionPane.YES_OPTION)
|
||||||
|
{
|
||||||
|
plugin.leaveParty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create party
|
||||||
|
party.changeParty(party.getLocalPartyId());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
noPartyPanel.setContent("Not in a party", "Create a party to begin.");
|
||||||
|
partyEmptyPanel.setContent("Party created", "You can now invite friends!");
|
||||||
|
|
||||||
|
updateParty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateParty()
|
||||||
|
{
|
||||||
|
remove(noPartyPanel);
|
||||||
|
remove(partyEmptyPanel);
|
||||||
|
|
||||||
|
startButton.setText(party.isInParty() ? BTN_LEAVE_TEXT : BTN_CREATE_TEXT);
|
||||||
|
|
||||||
|
if (!party.isInParty())
|
||||||
|
{
|
||||||
|
add(noPartyPanel);
|
||||||
|
}
|
||||||
|
else if (plugin.getPartyDataMap().size() <= 1)
|
||||||
|
{
|
||||||
|
add(partyEmptyPanel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addMember(PartyData partyData)
|
||||||
|
{
|
||||||
|
if (!memberBoxes.containsKey(partyData.getMember().getMemberId()))
|
||||||
|
{
|
||||||
|
PartyMemberBox partyMemberBox = new PartyMemberBox(config, memberBoxPanel, partyData);
|
||||||
|
memberBoxes.put(partyData.getMember().getMemberId(), partyMemberBox);
|
||||||
|
memberBoxPanel.add(partyMemberBox);
|
||||||
|
memberBoxPanel.revalidate();
|
||||||
|
}
|
||||||
|
updateParty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeAllMembers()
|
||||||
|
{
|
||||||
|
memberBoxes.forEach((key, value) -> memberBoxPanel.remove(value));
|
||||||
|
memberBoxPanel.revalidate();
|
||||||
|
memberBoxes.clear();
|
||||||
|
updateParty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeMember(UUID memberId)
|
||||||
|
{
|
||||||
|
final PartyMemberBox memberBox = memberBoxes.remove(memberId);
|
||||||
|
|
||||||
|
if (memberBox != null)
|
||||||
|
{
|
||||||
|
memberBoxPanel.remove(memberBox);
|
||||||
|
memberBoxPanel.revalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateParty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateMember(UUID userId)
|
||||||
|
{
|
||||||
|
final PartyMemberBox memberBox = memberBoxes.get(userId);
|
||||||
|
|
||||||
|
if (memberBox != null)
|
||||||
|
{
|
||||||
|
memberBox.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateAll()
|
||||||
|
{
|
||||||
|
memberBoxes.forEach((key, value) -> value.update());
|
||||||
|
}
|
||||||
|
|
||||||
|
void addRequest(String userId, String userName)
|
||||||
|
{
|
||||||
|
PartyRequestBox partyRequestBox = new PartyRequestBox(plugin, requestBoxPanel, userId, userName);
|
||||||
|
requestBoxes.put(userId, partyRequestBox);
|
||||||
|
requestBoxPanel.add(partyRequestBox);
|
||||||
|
requestBoxPanel.revalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeAllRequests()
|
||||||
|
{
|
||||||
|
requestBoxes.forEach((key, value) -> requestBoxPanel.remove(value));
|
||||||
|
requestBoxPanel.revalidate();
|
||||||
|
requestBoxes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeRequest(String userId)
|
||||||
|
{
|
||||||
|
final PartyRequestBox requestBox = requestBoxes.remove(userId);
|
||||||
|
|
||||||
|
if (requestBox != null)
|
||||||
|
{
|
||||||
|
requestBoxPanel.remove(requestBox);
|
||||||
|
requestBoxPanel.revalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
|
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
|
||||||
|
* Copyright (c) 2021, Jonathan Rousseau <https://github.com/JoRouss>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -24,9 +25,11 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.client.plugins.party;
|
package net.runelite.client.plugins.party;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.inject.Binder;
|
import com.google.inject.Binder;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -37,6 +40,7 @@ import java.util.UUID;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.runelite.api.ChatMessageType;
|
import net.runelite.api.ChatMessageType;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
@@ -44,11 +48,13 @@ import net.runelite.api.GameState;
|
|||||||
import net.runelite.api.KeyCode;
|
import net.runelite.api.KeyCode;
|
||||||
import net.runelite.api.MenuAction;
|
import net.runelite.api.MenuAction;
|
||||||
import net.runelite.api.MenuEntry;
|
import net.runelite.api.MenuEntry;
|
||||||
|
import net.runelite.api.Player;
|
||||||
import net.runelite.api.Skill;
|
import net.runelite.api.Skill;
|
||||||
import net.runelite.api.SoundEffectID;
|
import net.runelite.api.SoundEffectID;
|
||||||
import net.runelite.api.Tile;
|
import net.runelite.api.Tile;
|
||||||
import net.runelite.api.coords.WorldPoint;
|
import net.runelite.api.coords.WorldPoint;
|
||||||
import net.runelite.api.events.CommandExecuted;
|
import net.runelite.api.events.CommandExecuted;
|
||||||
|
import net.runelite.api.events.GameStateChanged;
|
||||||
import net.runelite.api.events.GameTick;
|
import net.runelite.api.events.GameTick;
|
||||||
import net.runelite.api.events.MenuOptionClicked;
|
import net.runelite.api.events.MenuOptionClicked;
|
||||||
import net.runelite.client.callback.ClientThread;
|
import net.runelite.client.callback.ClientThread;
|
||||||
@@ -57,21 +63,30 @@ import net.runelite.client.chat.ChatMessageBuilder;
|
|||||||
import net.runelite.client.chat.ChatMessageManager;
|
import net.runelite.client.chat.ChatMessageManager;
|
||||||
import net.runelite.client.chat.QueuedMessage;
|
import net.runelite.client.chat.QueuedMessage;
|
||||||
import net.runelite.client.config.ConfigManager;
|
import net.runelite.client.config.ConfigManager;
|
||||||
|
import net.runelite.client.discord.DiscordService;
|
||||||
|
import net.runelite.client.discord.events.DiscordJoinRequest;
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
import net.runelite.client.events.OverlayMenuClicked;
|
import net.runelite.client.events.OverlayMenuClicked;
|
||||||
|
import net.runelite.client.events.ConfigChanged;
|
||||||
import net.runelite.client.events.PartyChanged;
|
import net.runelite.client.events.PartyChanged;
|
||||||
|
import net.runelite.client.events.PartyMemberAvatar;
|
||||||
import net.runelite.client.plugins.Plugin;
|
import net.runelite.client.plugins.Plugin;
|
||||||
import net.runelite.client.plugins.PluginDescriptor;
|
import net.runelite.client.plugins.PluginDescriptor;
|
||||||
import net.runelite.client.plugins.party.data.PartyData;
|
import net.runelite.client.plugins.party.data.PartyData;
|
||||||
import net.runelite.client.plugins.party.data.PartyTilePingData;
|
import net.runelite.client.plugins.party.data.PartyTilePingData;
|
||||||
|
import net.runelite.client.plugins.party.messages.CharacterNameUpdate;
|
||||||
import net.runelite.client.plugins.party.messages.LocationUpdate;
|
import net.runelite.client.plugins.party.messages.LocationUpdate;
|
||||||
import net.runelite.client.plugins.party.messages.SkillUpdate;
|
import net.runelite.client.plugins.party.messages.SkillUpdate;
|
||||||
import net.runelite.client.plugins.party.messages.TilePing;
|
import net.runelite.client.plugins.party.messages.TilePing;
|
||||||
import net.runelite.client.task.Schedule;
|
import net.runelite.client.task.Schedule;
|
||||||
|
import net.runelite.client.ui.ClientToolbar;
|
||||||
|
import net.runelite.client.ui.NavigationButton;
|
||||||
import net.runelite.client.ui.overlay.OverlayManager;
|
import net.runelite.client.ui.overlay.OverlayManager;
|
||||||
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
|
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
|
||||||
import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager;
|
import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager;
|
||||||
import net.runelite.client.util.ColorUtil;
|
import net.runelite.client.util.ColorUtil;
|
||||||
|
import net.runelite.client.util.ImageUtil;
|
||||||
|
import net.runelite.client.util.Text;
|
||||||
import net.runelite.client.ws.PartyMember;
|
import net.runelite.client.ws.PartyMember;
|
||||||
import net.runelite.client.ws.PartyService;
|
import net.runelite.client.ws.PartyService;
|
||||||
import net.runelite.client.ws.WSClient;
|
import net.runelite.client.ws.WSClient;
|
||||||
@@ -81,7 +96,8 @@ import net.runelite.http.api.ws.messages.party.UserSync;
|
|||||||
|
|
||||||
@PluginDescriptor(
|
@PluginDescriptor(
|
||||||
name = "Party",
|
name = "Party",
|
||||||
description = "Shows useful information about current party"
|
description = "Party management and basic info",
|
||||||
|
enabledByDefault = false
|
||||||
)
|
)
|
||||||
public class PartyPlugin extends Plugin
|
public class PartyPlugin extends Plugin
|
||||||
{
|
{
|
||||||
@@ -118,6 +134,12 @@ public class PartyPlugin extends Plugin
|
|||||||
@Inject
|
@Inject
|
||||||
private ClientThread clientThread;
|
private ClientThread clientThread;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private ClientToolbar clientToolbar;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private DiscordService discordService;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@Named("developerMode")
|
@Named("developerMode")
|
||||||
boolean developerMode;
|
boolean developerMode;
|
||||||
@@ -128,8 +150,12 @@ public class PartyPlugin extends Plugin
|
|||||||
@Getter
|
@Getter
|
||||||
private final List<PartyTilePingData> pendingTilePings = Collections.synchronizedList(new ArrayList<>());
|
private final List<PartyTilePingData> pendingTilePings = Collections.synchronizedList(new ArrayList<>());
|
||||||
|
|
||||||
|
private PartyPanel panel;
|
||||||
|
private NavigationButton navButton;
|
||||||
|
|
||||||
private int lastHp, lastPray;
|
private int lastHp, lastPray;
|
||||||
private boolean doSync;
|
private String lastCharacterName = "";
|
||||||
|
private WorldPoint lastLocation;
|
||||||
private boolean sendAlert;
|
private boolean sendAlert;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -141,17 +167,36 @@ public class PartyPlugin extends Plugin
|
|||||||
@Override
|
@Override
|
||||||
protected void startUp() throws Exception
|
protected void startUp() throws Exception
|
||||||
{
|
{
|
||||||
|
panel = injector.getInstance(PartyPanel.class);
|
||||||
|
|
||||||
|
final BufferedImage icon = ImageUtil.loadImageResource(PartyPlugin.class, "panel_icon.png");
|
||||||
|
|
||||||
|
navButton = NavigationButton.builder()
|
||||||
|
.tooltip("Party")
|
||||||
|
.icon(icon)
|
||||||
|
.priority(9)
|
||||||
|
.panel(panel)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
clientToolbar.addNavigation(navButton);
|
||||||
|
|
||||||
overlayManager.add(partyStatsOverlay);
|
overlayManager.add(partyStatsOverlay);
|
||||||
overlayManager.add(partyPingOverlay);
|
overlayManager.add(partyPingOverlay);
|
||||||
wsClient.registerMessage(SkillUpdate.class);
|
wsClient.registerMessage(SkillUpdate.class);
|
||||||
wsClient.registerMessage(TilePing.class);
|
wsClient.registerMessage(TilePing.class);
|
||||||
wsClient.registerMessage(LocationUpdate.class);
|
wsClient.registerMessage(LocationUpdate.class);
|
||||||
doSync = true; // Delay sync so eventbus can process correctly.
|
wsClient.registerMessage(CharacterNameUpdate.class);
|
||||||
|
// Delay sync so the eventbus can register prior to the sync response
|
||||||
|
SwingUtilities.invokeLater(this::requestSync);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void shutDown() throws Exception
|
protected void shutDown() throws Exception
|
||||||
{
|
{
|
||||||
|
clientToolbar.removeNavigation(navButton);
|
||||||
|
|
||||||
|
panel = null;
|
||||||
|
|
||||||
partyDataMap.clear();
|
partyDataMap.clear();
|
||||||
pendingTilePings.clear();
|
pendingTilePings.clear();
|
||||||
worldMapManager.removeIf(PartyWorldMapPoint.class::isInstance);
|
worldMapManager.removeIf(PartyWorldMapPoint.class::isInstance);
|
||||||
@@ -160,8 +205,9 @@ public class PartyPlugin extends Plugin
|
|||||||
wsClient.unregisterMessage(SkillUpdate.class);
|
wsClient.unregisterMessage(SkillUpdate.class);
|
||||||
wsClient.unregisterMessage(TilePing.class);
|
wsClient.unregisterMessage(TilePing.class);
|
||||||
wsClient.unregisterMessage(LocationUpdate.class);
|
wsClient.unregisterMessage(LocationUpdate.class);
|
||||||
doSync = false;
|
wsClient.unregisterMessage(CharacterNameUpdate.class);
|
||||||
sendAlert = false;
|
sendAlert = false;
|
||||||
|
lastLocation = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -177,22 +223,53 @@ public class PartyPlugin extends Plugin
|
|||||||
event.getEntry().getTarget().equals("Party") &&
|
event.getEntry().getTarget().equals("Party") &&
|
||||||
event.getEntry().getOption().equals("Leave"))
|
event.getEntry().getOption().equals("Leave"))
|
||||||
{
|
{
|
||||||
party.changeParty(null);
|
leaveParty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!config.messages())
|
void leaveParty()
|
||||||
|
{
|
||||||
|
party.changeParty(null);
|
||||||
|
|
||||||
|
if (!config.messages())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String leaveMessage = new ChatMessageBuilder()
|
||||||
|
.append(ChatColorType.HIGHLIGHT)
|
||||||
|
.append("You have left the party.")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
chatMessageManager.queue(QueuedMessage.builder()
|
||||||
|
.type(ChatMessageType.FRIENDSCHATNOTIFICATION)
|
||||||
|
.runeLiteFormattedMessage(leaveMessage)
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onConfigChanged(ConfigChanged event)
|
||||||
|
{
|
||||||
|
if (event.getGroup().equals(PartyConfig.GROUP))
|
||||||
|
{
|
||||||
|
final PartyMember localMember = party.getLocalMember();
|
||||||
|
|
||||||
|
if (localMember != null)
|
||||||
{
|
{
|
||||||
return;
|
if (config.includeSelf())
|
||||||
|
{
|
||||||
|
final PartyData partyData = getPartyData(localMember.getMemberId());
|
||||||
|
assert partyData != null;
|
||||||
|
SwingUtilities.invokeLater(() -> panel.addMember(partyData));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SwingUtilities.invokeLater(() -> panel.removeMember(localMember.getMemberId()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final String leaveMessage = new ChatMessageBuilder()
|
// rebuild the panel in the event the "Recolor names" option changes
|
||||||
.append(ChatColorType.HIGHLIGHT)
|
SwingUtilities.invokeLater(panel::updateAll);
|
||||||
.append("You have left the party.")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
chatMessageManager.queue(QueuedMessage.builder()
|
|
||||||
.type(ChatMessageType.FRIENDSCHATNOTIFICATION)
|
|
||||||
.runeLiteFormattedMessage(leaveMessage)
|
|
||||||
.build());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,6 +313,35 @@ public class PartyPlugin extends Plugin
|
|||||||
wsClient.send(tilePing);
|
wsClient.send(tilePing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onDiscordJoinRequest(DiscordJoinRequest request)
|
||||||
|
{
|
||||||
|
final String requestMessage = new ChatMessageBuilder()
|
||||||
|
.append(ChatColorType.HIGHLIGHT)
|
||||||
|
.append("New join request received. Check your Party panel.")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
chatMessageManager.queue(QueuedMessage.builder()
|
||||||
|
.type(ChatMessageType.FRIENDSCHATNOTIFICATION)
|
||||||
|
.runeLiteFormattedMessage(requestMessage)
|
||||||
|
.build());
|
||||||
|
|
||||||
|
String userName = request.getUsername() + "#" + request.getDiscriminator();
|
||||||
|
SwingUtilities.invokeLater(() -> panel.addRequest(request.getUserId(), userName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onGameStateChanged(GameStateChanged event)
|
||||||
|
{
|
||||||
|
checkStateChanged(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void replyToRequest(String userId, int reply)
|
||||||
|
{
|
||||||
|
discordService.respondToRequest(userId, reply);
|
||||||
|
panel.removeRequest(userId);
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onTilePing(TilePing event)
|
public void onTilePing(TilePing event)
|
||||||
{
|
{
|
||||||
@@ -277,7 +383,15 @@ public class PartyPlugin extends Plugin
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final LocationUpdate locationUpdate = new LocationUpdate(client.getLocalPlayer().getWorldLocation());
|
WorldPoint location = client.getLocalPlayer().getWorldLocation();
|
||||||
|
if (location.equals(lastLocation))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastLocation = location;
|
||||||
|
|
||||||
|
final LocationUpdate locationUpdate = new LocationUpdate(location);
|
||||||
locationUpdate.setMemberId(localMember.getMemberId());
|
locationUpdate.setMemberId(localMember.getMemberId());
|
||||||
wsClient.send(locationUpdate);
|
wsClient.send(locationUpdate);
|
||||||
}
|
}
|
||||||
@@ -291,41 +405,35 @@ public class PartyPlugin extends Plugin
|
|||||||
sendInstructionMessage();
|
sendInstructionMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doSync && !party.getMembers().isEmpty())
|
checkStateChanged(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void requestSync()
|
||||||
|
{
|
||||||
|
if (!party.getMembers().isEmpty())
|
||||||
{
|
{
|
||||||
// Request sync
|
// Request sync
|
||||||
final UserSync userSync = new UserSync();
|
final UserSync userSync = new UserSync();
|
||||||
userSync.setMemberId(party.getLocalMember().getMemberId());
|
userSync.setMemberId(party.getLocalMember().getMemberId());
|
||||||
ws.send(userSync);
|
ws.send(userSync);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
doSync = false;
|
@Subscribe
|
||||||
|
public void onCharacterNameUpdate(final CharacterNameUpdate event)
|
||||||
|
{
|
||||||
|
final PartyData partyData = getPartyData(event.getMemberId());
|
||||||
|
|
||||||
final int currentHealth = client.getBoostedSkillLevel(Skill.HITPOINTS);
|
if (partyData == null)
|
||||||
final int currentPrayer = client.getBoostedSkillLevel(Skill.PRAYER);
|
|
||||||
final int realHealth = client.getRealSkillLevel(Skill.HITPOINTS);
|
|
||||||
final int realPrayer = client.getRealSkillLevel(Skill.PRAYER);
|
|
||||||
final PartyMember localMember = party.getLocalMember();
|
|
||||||
|
|
||||||
if (localMember != null)
|
|
||||||
{
|
{
|
||||||
if (currentHealth != lastHp)
|
return;
|
||||||
{
|
|
||||||
final SkillUpdate update = new SkillUpdate(Skill.HITPOINTS, currentHealth, realHealth);
|
|
||||||
update.setMemberId(localMember.getMemberId());
|
|
||||||
ws.send(update);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentPrayer != lastPray)
|
|
||||||
{
|
|
||||||
final SkillUpdate update = new SkillUpdate(Skill.PRAYER, currentPrayer, realPrayer);
|
|
||||||
update.setMemberId(localMember.getMemberId());
|
|
||||||
ws.send(update);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lastHp = currentHealth;
|
String name = event.getCharacterName();
|
||||||
lastPray = currentPrayer;
|
name = Text.removeTags(Text.toJagexName(name));
|
||||||
|
|
||||||
|
partyData.setCharacterName(name);
|
||||||
|
SwingUtilities.invokeLater(() -> panel.updateMember(partyData.getMember().getMemberId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
@@ -348,6 +456,8 @@ public class PartyPlugin extends Plugin
|
|||||||
partyData.setPrayer(event.getValue());
|
partyData.setPrayer(event.getValue());
|
||||||
partyData.setMaxPrayer(event.getMax());
|
partyData.setMaxPrayer(event.getMax());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(() -> panel.updateMember(partyData.getMember().getMemberId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
@@ -375,7 +485,7 @@ public class PartyPlugin extends Plugin
|
|||||||
|
|
||||||
final String joinMessage = new ChatMessageBuilder()
|
final String joinMessage = new ChatMessageBuilder()
|
||||||
.append(ChatColorType.HIGHLIGHT)
|
.append(ChatColorType.HIGHLIGHT)
|
||||||
.append(partyData.getName())
|
.append(partyData.getMember().getName())
|
||||||
.append(" has joined the party!")
|
.append(" has joined the party!")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@@ -386,7 +496,7 @@ public class PartyPlugin extends Plugin
|
|||||||
|
|
||||||
final PartyMember localMember = party.getLocalMember();
|
final PartyMember localMember = party.getLocalMember();
|
||||||
|
|
||||||
if (localMember != null && partyData.getMemberId().equals(localMember.getMemberId()))
|
if (localMember != null && partyData.getMember().getMemberId().equals(localMember.getMemberId()))
|
||||||
{
|
{
|
||||||
sendAlert = true;
|
sendAlert = true;
|
||||||
}
|
}
|
||||||
@@ -394,6 +504,12 @@ public class PartyPlugin extends Plugin
|
|||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onUserSync(final UserSync event)
|
public void onUserSync(final UserSync event)
|
||||||
|
{
|
||||||
|
checkStateChanged(true);
|
||||||
|
lastLocation = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkStateChanged(boolean forceSend)
|
||||||
{
|
{
|
||||||
final int currentHealth = client.getBoostedSkillLevel(Skill.HITPOINTS);
|
final int currentHealth = client.getBoostedSkillLevel(Skill.HITPOINTS);
|
||||||
final int currentPrayer = client.getBoostedSkillLevel(Skill.PRAYER);
|
final int currentPrayer = client.getBoostedSkillLevel(Skill.PRAYER);
|
||||||
@@ -401,16 +517,36 @@ public class PartyPlugin extends Plugin
|
|||||||
final int realPrayer = client.getRealSkillLevel(Skill.PRAYER);
|
final int realPrayer = client.getRealSkillLevel(Skill.PRAYER);
|
||||||
final PartyMember localMember = party.getLocalMember();
|
final PartyMember localMember = party.getLocalMember();
|
||||||
|
|
||||||
|
final Player localPlayer = client.getLocalPlayer();
|
||||||
|
final String characterName = Strings.nullToEmpty(localPlayer != null && client.getGameState().getState() >= GameState.LOADING.getState() ? localPlayer.getName() : null);
|
||||||
|
|
||||||
if (localMember != null)
|
if (localMember != null)
|
||||||
{
|
{
|
||||||
final SkillUpdate hpUpdate = new SkillUpdate(Skill.HITPOINTS, currentHealth, realHealth);
|
if (forceSend || currentHealth != lastHp)
|
||||||
hpUpdate.setMemberId(localMember.getMemberId());
|
{
|
||||||
ws.send(hpUpdate);
|
final SkillUpdate update = new SkillUpdate(Skill.HITPOINTS, currentHealth, realHealth);
|
||||||
|
update.setMemberId(localMember.getMemberId());
|
||||||
|
ws.send(update);
|
||||||
|
}
|
||||||
|
|
||||||
final SkillUpdate prayUpdate = new SkillUpdate(Skill.PRAYER, currentPrayer, realPrayer);
|
if (forceSend || currentPrayer != lastPray)
|
||||||
prayUpdate.setMemberId(localMember.getMemberId());
|
{
|
||||||
ws.send(prayUpdate);
|
final SkillUpdate update = new SkillUpdate(Skill.PRAYER, currentPrayer, realPrayer);
|
||||||
|
update.setMemberId(localMember.getMemberId());
|
||||||
|
ws.send(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forceSend || !characterName.equals(lastCharacterName))
|
||||||
|
{
|
||||||
|
final CharacterNameUpdate update = new CharacterNameUpdate(characterName);
|
||||||
|
update.setMemberId(localMember.getMemberId());
|
||||||
|
ws.send(update);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastHp = currentHealth;
|
||||||
|
lastPray = currentPrayer;
|
||||||
|
lastCharacterName = characterName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
@@ -424,7 +560,7 @@ public class PartyPlugin extends Plugin
|
|||||||
{
|
{
|
||||||
final String joinMessage = new ChatMessageBuilder()
|
final String joinMessage = new ChatMessageBuilder()
|
||||||
.append(ChatColorType.HIGHLIGHT)
|
.append(ChatColorType.HIGHLIGHT)
|
||||||
.append(removed.getName())
|
.append(removed.getMember().getName())
|
||||||
.append(" has left the party!")
|
.append(" has left the party!")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@@ -435,6 +571,8 @@ public class PartyPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
worldMapManager.remove(removed.getWorldMapPoint());
|
worldMapManager.remove(removed.getWorldMapPoint());
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(() -> panel.removeMember(event.getMemberId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,6 +583,12 @@ public class PartyPlugin extends Plugin
|
|||||||
partyDataMap.clear();
|
partyDataMap.clear();
|
||||||
pendingTilePings.clear();
|
pendingTilePings.clear();
|
||||||
worldMapManager.removeIf(PartyWorldMapPoint.class::isInstance);
|
worldMapManager.removeIf(PartyWorldMapPoint.class::isInstance);
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(() ->
|
||||||
|
{
|
||||||
|
panel.removeAllMembers();
|
||||||
|
panel.removeAllRequests();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
@@ -464,6 +608,12 @@ public class PartyPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onPartyMemberAvatar(PartyMemberAvatar event)
|
||||||
|
{
|
||||||
|
SwingUtilities.invokeLater(() -> panel.updateMember(event.getMemberId()));
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
PartyData getPartyData(final UUID uuid)
|
PartyData getPartyData(final UUID uuid)
|
||||||
{
|
{
|
||||||
@@ -479,18 +629,32 @@ public class PartyPlugin extends Plugin
|
|||||||
|
|
||||||
return partyDataMap.computeIfAbsent(uuid, (u) ->
|
return partyDataMap.computeIfAbsent(uuid, (u) ->
|
||||||
{
|
{
|
||||||
final String name = memberById.getName();
|
|
||||||
final WorldMapPoint worldMapPoint = new PartyWorldMapPoint(new WorldPoint(0, 0, 0), memberById);
|
final WorldMapPoint worldMapPoint = new PartyWorldMapPoint(new WorldPoint(0, 0, 0), memberById);
|
||||||
worldMapPoint.setTooltip(name);
|
worldMapPoint.setTooltip(memberById.getName());
|
||||||
|
|
||||||
// When first joining a party, other members can join before getting a join for self
|
// When first joining a party, other members can join before getting a join for self
|
||||||
PartyMember partyMember = party.getLocalMember();
|
PartyMember partyMember = party.getLocalMember();
|
||||||
if (partyMember == null || !u.equals(partyMember.getMemberId()))
|
|
||||||
|
boolean isSelf = partyMember != null && u.equals(partyMember.getMemberId());
|
||||||
|
|
||||||
|
if (!isSelf)
|
||||||
{
|
{
|
||||||
worldMapManager.add(worldMapPoint);
|
worldMapManager.add(worldMapPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PartyData(u, name, worldMapPoint, ColorUtil.fromObject(name));
|
PartyData partyData = new PartyData(memberById, worldMapPoint, ColorUtil.fromObject(memberById.getName()));
|
||||||
|
partyData.setShowOverlay(config.autoOverlay());
|
||||||
|
|
||||||
|
if (config.includeSelf() || !isSelf)
|
||||||
|
{
|
||||||
|
SwingUtilities.invokeLater(() -> panel.addMember(partyData));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SwingUtilities.invokeLater(panel::updateParty);
|
||||||
|
}
|
||||||
|
|
||||||
|
return partyData;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,7 +662,7 @@ public class PartyPlugin extends Plugin
|
|||||||
{
|
{
|
||||||
final String helpMessage = new ChatMessageBuilder()
|
final String helpMessage = new ChatMessageBuilder()
|
||||||
.append(ChatColorType.HIGHLIGHT)
|
.append(ChatColorType.HIGHLIGHT)
|
||||||
.append("To leave party hold SHIFT and right click party stats overlay.")
|
.append("To leave the party, click \"Leave party\" on the party panel.")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
chatMessageManager.queue(QueuedMessage.builder()
|
chatMessageManager.queue(QueuedMessage.builder()
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Jonathan Rousseau <https://github.com/JoRouss>
|
||||||
|
* 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.party;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.GridLayout;
|
||||||
|
import javax.swing.ImageIcon;
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import net.runelite.client.ui.ColorScheme;
|
||||||
|
import net.runelite.client.ui.DynamicGridLayout;
|
||||||
|
import net.runelite.client.ui.FontManager;
|
||||||
|
import net.runelite.client.ui.components.MouseDragEventForwarder;
|
||||||
|
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
|
||||||
|
import net.runelite.client.util.ImageUtil;
|
||||||
|
import net.runelite.client.util.SwingUtil;
|
||||||
|
import net.runelite.discord.DiscordRPC;
|
||||||
|
|
||||||
|
class PartyRequestBox extends JPanel
|
||||||
|
{
|
||||||
|
private static final ImageIcon CONFIRM_ICON = new ImageIcon(ImageUtil.loadImageResource(PartyPlugin.class, "confirm_icon.png"));
|
||||||
|
private static final ImageIcon CONFIRM_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(ImageUtil.bufferedImageFromImage(CONFIRM_ICON.getImage()), 0.54f));
|
||||||
|
private static final ImageIcon CANCEL_ICON = new ImageIcon(ImageUtil.loadImageResource(PartyPlugin.class, "cancel_icon.png"));
|
||||||
|
private static final ImageIcon CANCEL_HOVER_ICON = new ImageIcon(ImageUtil.alphaOffset(ImageUtil.bufferedImageFromImage(CANCEL_ICON.getImage()), 0.6f));
|
||||||
|
|
||||||
|
PartyRequestBox(final PartyPlugin plugin, final JComponent panel, String userId, String userName)
|
||||||
|
{
|
||||||
|
setLayout(new BorderLayout());
|
||||||
|
setBorder(new EmptyBorder(5, 0, 0, 0));
|
||||||
|
|
||||||
|
/* The box's wrapping container */
|
||||||
|
final JPanel container = new JPanel();
|
||||||
|
container.setLayout(new BorderLayout());
|
||||||
|
container.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||||
|
container.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||||
|
|
||||||
|
JPanel namesPanel = new JPanel();
|
||||||
|
namesPanel.setLayout(new DynamicGridLayout(2, 1));
|
||||||
|
namesPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||||
|
namesPanel.setBorder(new EmptyBorder(2, 5, 2, 5));
|
||||||
|
|
||||||
|
JShadowedLabel nameLabel = new JShadowedLabel();
|
||||||
|
nameLabel.setFont(FontManager.getRunescapeSmallFont());
|
||||||
|
nameLabel.setForeground(Color.WHITE);
|
||||||
|
nameLabel.setText(userName);
|
||||||
|
|
||||||
|
JShadowedLabel messageLabel = new JShadowedLabel();
|
||||||
|
messageLabel.setFont(FontManager.getRunescapeSmallFont());
|
||||||
|
messageLabel.setForeground(Color.WHITE);
|
||||||
|
messageLabel.setText("Wants to join your party!");
|
||||||
|
|
||||||
|
namesPanel.add(nameLabel);
|
||||||
|
namesPanel.add(messageLabel);
|
||||||
|
|
||||||
|
JPanel actionsContainer = new JPanel(new GridLayout(1, 2, 8, 0));
|
||||||
|
actionsContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||||
|
|
||||||
|
JButton confirmButton = new JButton(CONFIRM_ICON);
|
||||||
|
SwingUtil.removeButtonDecorations(confirmButton);
|
||||||
|
confirmButton.setToolTipText("Invite");
|
||||||
|
confirmButton.setRolloverIcon(CONFIRM_HOVER_ICON);
|
||||||
|
confirmButton.addActionListener(e -> plugin.replyToRequest(userId, DiscordRPC.DISCORD_REPLY_YES));
|
||||||
|
confirmButton.setPreferredSize(new Dimension(18, 18));
|
||||||
|
|
||||||
|
JButton cancelButton = new JButton(CANCEL_ICON);
|
||||||
|
SwingUtil.removeButtonDecorations(cancelButton);
|
||||||
|
cancelButton.setToolTipText("Reject");
|
||||||
|
cancelButton.setRolloverIcon(CANCEL_HOVER_ICON);
|
||||||
|
cancelButton.addActionListener(e -> plugin.replyToRequest(userId, DiscordRPC.DISCORD_REPLY_NO));
|
||||||
|
cancelButton.setPreferredSize(new Dimension(18, 18));
|
||||||
|
|
||||||
|
actionsContainer.add(confirmButton);
|
||||||
|
actionsContainer.add(cancelButton);
|
||||||
|
|
||||||
|
container.add(namesPanel, BorderLayout.WEST);
|
||||||
|
container.add(actionsContainer, BorderLayout.EAST);
|
||||||
|
|
||||||
|
// forward mouse drag events to parent panel for drag and drop reordering
|
||||||
|
MouseDragEventForwarder mouseDragEventForwarder = new MouseDragEventForwarder(panel);
|
||||||
|
container.addMouseListener(mouseDragEventForwarder);
|
||||||
|
container.addMouseMotionListener(mouseDragEventForwarder);
|
||||||
|
|
||||||
|
add(container, BorderLayout.NORTH);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
|
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
|
||||||
|
* Copyright (c) 2021, Jonathan Rousseau <https://github.com/JoRouss>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -68,11 +69,6 @@ public class PartyStatsOverlay extends OverlayPanel
|
|||||||
@Override
|
@Override
|
||||||
public Dimension render(Graphics2D graphics)
|
public Dimension render(Graphics2D graphics)
|
||||||
{
|
{
|
||||||
if (!config.stats())
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Map<UUID, PartyData> partyDataMap = plugin.getPartyDataMap();
|
final Map<UUID, PartyData> partyDataMap = plugin.getPartyDataMap();
|
||||||
if (partyDataMap.isEmpty())
|
if (partyDataMap.isEmpty())
|
||||||
{
|
{
|
||||||
@@ -81,22 +77,14 @@ public class PartyStatsOverlay extends OverlayPanel
|
|||||||
|
|
||||||
panelComponent.setBackgroundColor(null);
|
panelComponent.setBackgroundColor(null);
|
||||||
|
|
||||||
boolean only1 = plugin.getPartyDataMap().size() == 1;
|
|
||||||
|
|
||||||
synchronized (plugin.getPartyDataMap())
|
synchronized (plugin.getPartyDataMap())
|
||||||
{
|
{
|
||||||
partyDataMap.forEach((k, v) ->
|
partyDataMap.forEach((k, v) ->
|
||||||
{
|
{
|
||||||
if (party.getLocalMember() != null && party.getLocalMember().getMemberId().equals(k))
|
boolean isSelf = party.getLocalMember() != null && party.getLocalMember().getMemberId().equals(k);
|
||||||
{
|
|
||||||
if (only1)
|
|
||||||
{
|
|
||||||
panelComponent.getChildren().add(TitleComponent.builder()
|
|
||||||
.text("No other party members")
|
|
||||||
.color(Color.RED)
|
|
||||||
.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (!v.isShowOverlay() || (!config.includeSelf() && isSelf))
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +92,7 @@ public class PartyStatsOverlay extends OverlayPanel
|
|||||||
panel.getChildren().clear();
|
panel.getChildren().clear();
|
||||||
|
|
||||||
final TitleComponent name = TitleComponent.builder()
|
final TitleComponent name = TitleComponent.builder()
|
||||||
.text(v.getName())
|
.text(v.getCharacterName().isEmpty() ? v.getMember().getName() : v.getCharacterName())
|
||||||
.color(config.recolorNames() ? v.getColor() : Color.WHITE)
|
.color(config.recolorNames() ? v.getColor() : Color.WHITE)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
|
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
|
||||||
|
* Copyright (c) 2021, Jonathan Rousseau <https://github.com/JoRouss>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -25,20 +26,19 @@
|
|||||||
package net.runelite.client.plugins.party.data;
|
package net.runelite.client.plugins.party.data;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.util.UUID;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import net.runelite.client.ui.overlay.components.PanelComponent;
|
import net.runelite.client.ui.overlay.components.PanelComponent;
|
||||||
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
|
import net.runelite.client.ui.overlay.worldmap.WorldMapPoint;
|
||||||
|
import net.runelite.client.ws.PartyMember;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@Getter
|
@Getter
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class PartyData
|
public class PartyData
|
||||||
{
|
{
|
||||||
private final UUID memberId;
|
private final PartyMember member;
|
||||||
private final String name;
|
|
||||||
private final WorldMapPoint worldMapPoint;
|
private final WorldMapPoint worldMapPoint;
|
||||||
private final PanelComponent panel = new PanelComponent();
|
private final PanelComponent panel = new PanelComponent();
|
||||||
private final Color color;
|
private final Color color;
|
||||||
@@ -47,4 +47,6 @@ public class PartyData
|
|||||||
private int maxHitpoints;
|
private int maxHitpoints;
|
||||||
private int prayer;
|
private int prayer;
|
||||||
private int maxPrayer;
|
private int maxPrayer;
|
||||||
|
private String characterName = "";
|
||||||
|
private boolean showOverlay;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Jonathan Rousseau <https://github.com/JoRouss>
|
||||||
|
* 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.party.messages;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import net.runelite.http.api.ws.messages.party.PartyMemberMessage;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class CharacterNameUpdate extends PartyMemberMessage
|
||||||
|
{
|
||||||
|
private final String characterName;
|
||||||
|
}
|
||||||
@@ -50,7 +50,7 @@ import net.runelite.client.ui.overlay.OverlayPriority;
|
|||||||
class ScreenshotOverlay extends Overlay
|
class ScreenshotOverlay extends Overlay
|
||||||
{
|
{
|
||||||
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MMM. dd, yyyy");
|
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("MMM. dd, yyyy");
|
||||||
private static final int REPORT_BUTTON_X_OFFSET = 404;
|
private static final int REPORT_BUTTON_X_OFFSET = 437;
|
||||||
|
|
||||||
private final Client client;
|
private final Client client;
|
||||||
private final DrawManager drawManager;
|
private final DrawManager drawManager;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ package net.runelite.client.plugins.screenshot;
|
|||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
@@ -34,6 +35,7 @@ import java.awt.image.BufferedImage;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
@@ -56,6 +58,7 @@ import net.runelite.api.events.GameTick;
|
|||||||
import net.runelite.api.events.ScriptCallbackEvent;
|
import net.runelite.api.events.ScriptCallbackEvent;
|
||||||
import net.runelite.api.events.WidgetLoaded;
|
import net.runelite.api.events.WidgetLoaded;
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
|
import net.runelite.api.widgets.WidgetID;
|
||||||
import static net.runelite.api.widgets.WidgetID.BARROWS_REWARD_GROUP_ID;
|
import static net.runelite.api.widgets.WidgetID.BARROWS_REWARD_GROUP_ID;
|
||||||
import static net.runelite.api.widgets.WidgetID.CHAMBERS_OF_XERIC_REWARD_GROUP_ID;
|
import static net.runelite.api.widgets.WidgetID.CHAMBERS_OF_XERIC_REWARD_GROUP_ID;
|
||||||
import static net.runelite.api.widgets.WidgetID.CLUE_SCROLL_REWARD_GROUP_ID;
|
import static net.runelite.api.widgets.WidgetID.CLUE_SCROLL_REWARD_GROUP_ID;
|
||||||
@@ -110,6 +113,10 @@ public class ScreenshotPlugin extends Plugin
|
|||||||
"You feel something weird sneaking into your backpack",
|
"You feel something weird sneaking into your backpack",
|
||||||
"You have a funny feeling like you would have been followed");
|
"You have a funny feeling like you would have been followed");
|
||||||
private static final Pattern BA_HIGH_GAMBLE_REWARD_PATTERN = Pattern.compile("(?<reward>.+)!<br>High level gamble count: <col=7f0000>(?<gambleCount>.+)</col>");
|
private static final Pattern BA_HIGH_GAMBLE_REWARD_PATTERN = Pattern.compile("(?<reward>.+)!<br>High level gamble count: <col=7f0000>(?<gambleCount>.+)</col>");
|
||||||
|
private static final Set<Integer> REPORT_BUTTON_TLIS = ImmutableSet.of(
|
||||||
|
WidgetID.FIXED_VIEWPORT_GROUP_ID,
|
||||||
|
WidgetID.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX_GROUP_ID,
|
||||||
|
WidgetID.RESIZABLE_VIEWPORT_BOTTOM_LINE_GROUP_ID);
|
||||||
|
|
||||||
private String clueType;
|
private String clueType;
|
||||||
private Integer clueNumber;
|
private Integer clueNumber;
|
||||||
@@ -689,7 +696,7 @@ public class ScreenshotPlugin extends Plugin
|
|||||||
executor.submit(() -> takeScreenshot(fileName, subDir, img));
|
executor.submit(() -> takeScreenshot(fileName, subDir, img));
|
||||||
};
|
};
|
||||||
|
|
||||||
if (config.displayDate())
|
if (config.displayDate() && REPORT_BUTTON_TLIS.contains(client.getTopLevelInterfaceId()))
|
||||||
{
|
{
|
||||||
screenshotOverlay.queueForTimestamp(imageCallback);
|
screenshotOverlay.queueForTimestamp(imageCallback);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -304,14 +304,11 @@ class XpInfoBox extends JPanel
|
|||||||
tooltipLabel == XpProgressBarLabel.PERCENTAGE ? "of goal" : "till goal lvl"));
|
tooltipLabel == XpProgressBarLabel.PERCENTAGE ? "of goal" : "till goal lvl"));
|
||||||
|
|
||||||
progressBar.setDimmed(skillPaused);
|
progressBar.setDimmed(skillPaused);
|
||||||
|
|
||||||
progressBar.repaint();
|
|
||||||
}
|
}
|
||||||
else if (!paused && skillPaused)
|
else if (!paused && skillPaused)
|
||||||
{
|
{
|
||||||
// React to the skill state now being paused
|
// React to the skill state now being paused
|
||||||
progressBar.setDimmed(true);
|
progressBar.setDimmed(true);
|
||||||
progressBar.repaint();
|
|
||||||
paused = true;
|
paused = true;
|
||||||
pauseSkill.setText("Unpause");
|
pauseSkill.setText("Unpause");
|
||||||
}
|
}
|
||||||
@@ -319,7 +316,6 @@ class XpInfoBox extends JPanel
|
|||||||
{
|
{
|
||||||
// React to the skill being unpaused (without update)
|
// React to the skill being unpaused (without update)
|
||||||
progressBar.setDimmed(false);
|
progressBar.setDimmed(false);
|
||||||
progressBar.repaint();
|
|
||||||
paused = false;
|
paused = false;
|
||||||
pauseSkill.setText("Pause");
|
pauseSkill.setText("Pause");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import java.util.List;
|
|||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.SwingConstants;
|
import javax.swing.SwingConstants;
|
||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
import lombok.Setter;
|
|
||||||
import net.runelite.client.ui.FontManager;
|
import net.runelite.client.ui.FontManager;
|
||||||
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
|
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
|
||||||
|
|
||||||
@@ -42,13 +41,8 @@ import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
|
|||||||
*/
|
*/
|
||||||
public class ProgressBar extends DimmableJPanel
|
public class ProgressBar extends DimmableJPanel
|
||||||
{
|
{
|
||||||
@Setter
|
|
||||||
private int maximumValue;
|
private int maximumValue;
|
||||||
|
|
||||||
@Setter
|
|
||||||
private int value;
|
private int value;
|
||||||
|
|
||||||
@Setter
|
|
||||||
private List<Integer> positions = Collections.emptyList();
|
private List<Integer> positions = Collections.emptyList();
|
||||||
|
|
||||||
private final JLabel leftLabel = new JShadowedLabel();
|
private final JLabel leftLabel = new JShadowedLabel();
|
||||||
@@ -157,4 +151,22 @@ public class ProgressBar extends DimmableJPanel
|
|||||||
|
|
||||||
return (value * 100) / maximumValue;
|
return (value * 100) / maximumValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMaximumValue(int maximumValue)
|
||||||
|
{
|
||||||
|
this.maximumValue = maximumValue;
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(int value)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPositions(List<Integer> positions)
|
||||||
|
{
|
||||||
|
this.positions = positions;
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||||
|
* Copyright (c) 2021, Jonathan Rousseau <https://github.com/JoRouss>
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -24,10 +25,14 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.client.ws;
|
package net.runelite.client.ws;
|
||||||
|
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
|
import com.google.common.hash.Hashing;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@@ -41,6 +46,8 @@ import net.runelite.client.chat.QueuedMessage;
|
|||||||
import net.runelite.client.eventbus.EventBus;
|
import net.runelite.client.eventbus.EventBus;
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
import net.runelite.client.events.PartyChanged;
|
import net.runelite.client.events.PartyChanged;
|
||||||
|
import net.runelite.client.util.Text;
|
||||||
|
import net.runelite.client.events.PartyMemberAvatar;
|
||||||
import static net.runelite.client.util.Text.JAGEX_PRINTABLE_CHAR_MATCHER;
|
import static net.runelite.client.util.Text.JAGEX_PRINTABLE_CHAR_MATCHER;
|
||||||
import net.runelite.http.api.ws.messages.party.Join;
|
import net.runelite.http.api.ws.messages.party.Join;
|
||||||
import net.runelite.http.api.ws.messages.party.Part;
|
import net.runelite.http.api.ws.messages.party.Part;
|
||||||
@@ -55,6 +62,7 @@ public class PartyService
|
|||||||
{
|
{
|
||||||
public static final int PARTY_MAX = 15;
|
public static final int PARTY_MAX = 15;
|
||||||
private static final int MAX_MESSAGE_LEN = 150;
|
private static final int MAX_MESSAGE_LEN = 150;
|
||||||
|
private static final int MAX_USERNAME_LEN = 32; // same as Discord
|
||||||
|
|
||||||
private final WSClient wsClient;
|
private final WSClient wsClient;
|
||||||
private final SessionManager sessionManager;
|
private final SessionManager sessionManager;
|
||||||
@@ -66,7 +74,10 @@ public class PartyService
|
|||||||
private UUID localPartyId = UUID.randomUUID();
|
private UUID localPartyId = UUID.randomUUID();
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private UUID partyId;
|
private UUID publicPartyId; // public party id, for advertising on discord, derived from the secret
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private UUID partyId; // secret party id
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
private String username;
|
private String username;
|
||||||
@@ -81,8 +92,14 @@ public class PartyService
|
|||||||
eventBus.register(this);
|
eventBus.register(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void changeParty(UUID newParty)
|
public void changeParty(@Nullable UUID newParty)
|
||||||
{
|
{
|
||||||
|
if (username == null)
|
||||||
|
{
|
||||||
|
log.warn("Tried to join a party with no username");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (wsClient.sessionExists())
|
if (wsClient.sessionExists())
|
||||||
{
|
{
|
||||||
wsClient.send(new Part());
|
wsClient.send(new Part());
|
||||||
@@ -91,6 +108,8 @@ public class PartyService
|
|||||||
log.debug("Party change to {}", newParty);
|
log.debug("Party change to {}", newParty);
|
||||||
members.clear();
|
members.clear();
|
||||||
partyId = newParty;
|
partyId = newParty;
|
||||||
|
// The public party ID needs to be consistent across party members, but not a secret
|
||||||
|
publicPartyId = newParty != null ? UUID.nameUUIDFromBytes(Hashing.sha256().hashString(newParty.toString(), Charsets.UTF_8).asBytes()) : null;
|
||||||
|
|
||||||
if (partyId == null)
|
if (partyId == null)
|
||||||
{
|
{
|
||||||
@@ -129,7 +148,7 @@ public class PartyService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final PartyMember partyMember = new PartyMember(message.getMemberId(), message.getName());
|
final PartyMember partyMember = new PartyMember(message.getMemberId(), cleanUsername(message.getName()));
|
||||||
members.add(partyMember);
|
members.add(partyMember);
|
||||||
|
|
||||||
final PartyMember localMember = getLocalMember();
|
final PartyMember localMember = getLocalMember();
|
||||||
@@ -143,7 +162,7 @@ public class PartyService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe(priority = 1) // run prior to plugins so that the member is removed by the time the plugins see it.
|
||||||
public void onUserPart(final UserPart message)
|
public void onUserPart(final UserPart message)
|
||||||
{
|
{
|
||||||
members.removeIf(member -> member.getMemberId().equals(message.getMemberId()));
|
members.removeIf(member -> member.getMemberId().equals(message.getMemberId()));
|
||||||
@@ -215,4 +234,25 @@ public class PartyService
|
|||||||
{
|
{
|
||||||
return localPartyId.equals(partyId);
|
return localPartyId.equals(partyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPartyMemberAvatar(UUID memberID, BufferedImage image)
|
||||||
|
{
|
||||||
|
final PartyMember memberById = getMemberById(memberID);
|
||||||
|
|
||||||
|
if (memberById != null)
|
||||||
|
{
|
||||||
|
memberById.setAvatar(image);
|
||||||
|
eventBus.post(new PartyMemberAvatar(memberID, image));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String cleanUsername(String username)
|
||||||
|
{
|
||||||
|
String s = Text.removeTags(JAGEX_PRINTABLE_CHAR_MATCHER.retainFrom(username));
|
||||||
|
if (s.length() >= MAX_USERNAME_LEN)
|
||||||
|
{
|
||||||
|
s = s.substring(0, MAX_USERNAME_LEN);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ public class WSClient extends WebSocketListener implements AutoCloseable
|
|||||||
@Override
|
@Override
|
||||||
public void onFailure(WebSocket webSocket, Throwable t, Response response)
|
public void onFailure(WebSocket webSocket, Throwable t, Response response)
|
||||||
{
|
{
|
||||||
log.warn("Error in websocket {}:{}", response, t);
|
log.warn("Error in websocket: {}", response, t);
|
||||||
this.webSocket = null;
|
this.webSocket = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 299 B |
|
After Width: | Height: | Size: 273 B |
|
After Width: | Height: | Size: 710 B |
@@ -1077,7 +1077,13 @@ LABEL913:
|
|||||||
LABEL927:
|
LABEL927:
|
||||||
jump LABEL942
|
jump LABEL942
|
||||||
LABEL928:
|
LABEL928:
|
||||||
|
iload 10 ; The id of the messageNode of the message being built
|
||||||
|
sconst ""
|
||||||
|
sconst "addTimestamp"
|
||||||
|
runelite_callback
|
||||||
|
pop_int ; pop message id
|
||||||
sload 14
|
sload 14
|
||||||
|
join_string 2 ; prepend the timestamp
|
||||||
iload 8
|
iload 8
|
||||||
iload 9
|
iload 9
|
||||||
iconst 10616888
|
iconst 10616888
|
||||||
|
|||||||
@@ -27,9 +27,7 @@ package net.runelite.client.plugins.discord;
|
|||||||
import com.google.inject.Guice;
|
import com.google.inject.Guice;
|
||||||
import com.google.inject.testing.fieldbinder.Bind;
|
import com.google.inject.testing.fieldbinder.Bind;
|
||||||
import com.google.inject.testing.fieldbinder.BoundFieldModule;
|
import com.google.inject.testing.fieldbinder.BoundFieldModule;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
@@ -83,7 +81,6 @@ public class DiscordStateTest
|
|||||||
public void before()
|
public void before()
|
||||||
{
|
{
|
||||||
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
|
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
|
||||||
when(partyService.getLocalPartyId()).thenReturn(UUID.nameUUIDFromBytes("test".getBytes(StandardCharsets.UTF_8)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -600,7 +600,7 @@ public abstract class RSClientMixin implements RSClient
|
|||||||
@Override
|
@Override
|
||||||
public Widget[] getWidgetRoots()
|
public Widget[] getWidgetRoots()
|
||||||
{
|
{
|
||||||
int topGroup = getWidgetRoot();
|
int topGroup = getTopLevelInterfaceId();
|
||||||
if (topGroup == -1)
|
if (topGroup == -1)
|
||||||
{
|
{
|
||||||
return new Widget[]{};
|
return new Widget[]{};
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ public abstract class RSWidgetMixin implements RSWidget
|
|||||||
}
|
}
|
||||||
|
|
||||||
final int id = getId();
|
final int id = getId();
|
||||||
if (TO_GROUP(id) == client.getWidgetRoot())
|
if (TO_GROUP(id) == client.getTopLevelInterfaceId())
|
||||||
{
|
{
|
||||||
// this is a root widget
|
// this is a root widget
|
||||||
return -1;
|
return -1;
|
||||||
@@ -261,7 +261,7 @@ public abstract class RSWidgetMixin implements RSWidget
|
|||||||
// If the parent is hidden, this widget is also hidden.
|
// If the parent is hidden, this widget is also hidden.
|
||||||
// Widget has no parent and is not the root widget (which is always visible),
|
// Widget has no parent and is not the root widget (which is always visible),
|
||||||
// so it's not visible.
|
// so it's not visible.
|
||||||
return parent == null ? TO_GROUP(getId()) != client.getWidgetRoot() : parent.isHidden();
|
return parent == null ? TO_GROUP(getId()) != client.getTopLevelInterfaceId() : parent.isHidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
|||||||
@@ -547,7 +547,7 @@ public interface RSClient extends RSGameEngine, Client
|
|||||||
* parentId -1, which are the widget roots.
|
* parentId -1, which are the widget roots.
|
||||||
*/
|
*/
|
||||||
@Import("rootInterface")
|
@Import("rootInterface")
|
||||||
int getWidgetRoot();
|
int getTopLevelInterfaceId();
|
||||||
|
|
||||||
@Import("WorldMapElement_cached")
|
@Import("WorldMapElement_cached")
|
||||||
@Override
|
@Override
|
||||||
|
|||||||