From 1a7946660c2a6b11e1f518b1546591e1bffff1dc Mon Sep 17 00:00:00 2001 From: Tomas Slusny Date: Thu, 31 Jan 2019 12:13:32 +0000 Subject: [PATCH] Add party plugin Co-authored-by: Adam Signed-off-by: Tomas Slusny --- .../client/plugins/party/PartyConfig.java | 74 +++ .../plugins/party/PartyPingOverlay.java | 115 +++++ .../client/plugins/party/PartyPlugin.java | 483 ++++++++++++++++++ .../plugins/party/PartyPluginService.java | 40 ++ .../plugins/party/PartyPluginServiceImpl.java | 49 ++ .../plugins/party/PartyStatsOverlay.java | 134 +++++ .../plugins/party/PartyWorldMapPoint.java | 66 +++ .../client/plugins/party/data/PartyData.java | 48 ++ .../plugins/party/data/PartyTilePingData.java | 39 ++ .../party/messages/LocationUpdate.java | 35 ++ .../plugins/party/messages/SkillUpdate.java | 39 ++ .../plugins/party/messages/TilePing.java | 35 ++ 12 files changed, 1157 insertions(+) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPingOverlay.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPluginService.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPluginServiceImpl.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/party/PartyWorldMapPoint.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyData.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyTilePingData.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/party/messages/LocationUpdate.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/party/messages/SkillUpdate.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/party/messages/TilePing.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java new file mode 100644 index 0000000000..1bf03191c5 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyConfig.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018, Tomas Slusny + * 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 net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("party") +public interface PartyConfig extends Config +{ + @ConfigItem( + keyName = "stats", + name = "Stats", + description = "Enables party stats overlay showing HP, prayer and player name" + ) + default boolean stats() + { + return true; + } + + @ConfigItem( + keyName = "pings", + name = "Pings", + description = "Enables party pings (shift + left-click)" + ) + default boolean pings() + { + return true; + } + + @ConfigItem( + keyName = "sounds", + name = "Sound on ping", + description = "Enables sound notification on party ping" + ) + default boolean sounds() + { + return true; + } + + + @ConfigItem( + keyName = "messages", + name = "Join messages", + description = "Enables join/leave game messages" + ) + default boolean messages() + { + return true; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPingOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPingOverlay.java new file mode 100644 index 0000000000..faaf2774bc --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPingOverlay.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2019, Tomas Slusny + * 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.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.util.Iterator; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.coords.LocalPoint; +import net.runelite.client.plugins.party.data.PartyTilePingData; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayUtil; + +class PartyPingOverlay extends Overlay +{ + private final Client client; + private final PartyPlugin plugin; + + @Inject + private PartyPingOverlay(final Client client, final PartyPlugin plugin) + { + this.client = client; + this.plugin = plugin; + setPosition(OverlayPosition.DYNAMIC); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (plugin.getPartyDataMap().isEmpty()) + { + return null; + } + + // Update selected scene tile + if (!client.isMenuOpen()) + { + Point p = client.getMouseCanvasPosition(); + p = new Point( + p.getX() - client.getViewportXOffset(), + p.getY() - client.getViewportYOffset()); + + client.setCheckClick(true); + client.setMouseCanvasHoverPosition(p); + } + + synchronized (plugin.getPendingTilePings()) + { + final Iterator iterator = plugin.getPendingTilePings().iterator(); + + while (iterator.hasNext()) + { + PartyTilePingData next = iterator.next(); + + if (next.getAlpha() <= 0) + { + iterator.remove(); + continue; + } + + renderPing(graphics, next); + next.setAlpha(next.getAlpha() - 5); + } + } + + return null; + } + + private void renderPing(final Graphics2D graphics, final PartyTilePingData ping) + { + final LocalPoint localPoint = LocalPoint.fromWorld(client, ping.getPoint()); + + if (localPoint == null) + { + return; + } + + final Polygon poly = Perspective.getCanvasTilePoly(client, localPoint); + + if (poly == null) + { + return; + } + + OverlayUtil.renderPolygon(graphics, poly, new Color(255, 0, 0, ping.getAlpha())); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java new file mode 100644 index 0000000000..85d960f9b2 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPlugin.java @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2019, Tomas Slusny + * 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.Binder; +import com.google.inject.Provides; +import java.awt.event.KeyEvent; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import javax.annotation.Nullable; +import javax.inject.Inject; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.MenuAction; +import net.runelite.api.MenuEntry; +import net.runelite.api.Skill; +import net.runelite.api.SoundEffectID; +import net.runelite.api.Tile; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.FocusChanged; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.client.chat.ChatColorType; +import net.runelite.client.chat.ChatMessageBuilder; +import net.runelite.client.chat.ChatMessageManager; +import net.runelite.client.chat.QueuedMessage; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.OverlayMenuClicked; +import net.runelite.client.events.PartyChanged; +import net.runelite.client.input.KeyListener; +import net.runelite.client.input.KeyManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.party.data.PartyData; +import net.runelite.client.plugins.party.data.PartyTilePingData; +import net.runelite.client.plugins.party.messages.LocationUpdate; +import net.runelite.client.plugins.party.messages.SkillUpdate; +import net.runelite.client.plugins.party.messages.TilePing; +import net.runelite.client.task.Schedule; +import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; +import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager; +import net.runelite.client.ws.PartyMember; +import net.runelite.client.ws.PartyService; +import net.runelite.client.ws.WSClient; +import net.runelite.http.api.ws.messages.party.UserJoin; +import net.runelite.http.api.ws.messages.party.UserPart; +import net.runelite.http.api.ws.messages.party.UserSync; + +@PluginDescriptor( + name = "Party", + description = "Shows useful information about current party" +) +@Slf4j +public class PartyPlugin extends Plugin implements KeyListener +{ + @Inject + private Client client; + + @Inject + private PartyService party; + + @Inject + private WSClient ws; + + @Inject + private OverlayManager overlayManager; + + @Inject + private PartyStatsOverlay partyStatsOverlay; + + @Inject + private PartyPingOverlay partyPingOverlay; + + @Inject + private KeyManager keyManager; + + @Inject + private WSClient wsClient; + + @Inject + private WorldMapPointManager worldMapManager; + + @Inject + private PartyConfig config; + + @Inject + private ChatMessageManager chatMessageManager; + + @Getter + private final Map partyDataMap = new HashMap<>(); + + @Getter + private final List pendingTilePings = Collections.synchronizedList(new ArrayList<>()); + + private int lastHp, lastPray; + private boolean hotkeyDown; + + @Override + public void configure(Binder binder) + { + binder.bind(PartyPluginService.class).to(PartyPluginServiceImpl.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(partyStatsOverlay); + overlayManager.add(partyPingOverlay); + wsClient.registerMessage(SkillUpdate.class); + wsClient.registerMessage(TilePing.class); + wsClient.registerMessage(LocationUpdate.class); + keyManager.registerKeyListener(this); + } + + @Override + protected void shutDown() throws Exception + { + partyDataMap.clear(); + pendingTilePings.clear(); + worldMapManager.removeIf(PartyWorldMapPoint.class::isInstance); + overlayManager.remove(partyStatsOverlay); + overlayManager.remove(partyPingOverlay); + wsClient.unregisterMessage(SkillUpdate.class); + wsClient.unregisterMessage(TilePing.class); + wsClient.unregisterMessage(LocationUpdate.class); + keyManager.unregisterKeyListener(this); + hotkeyDown = false; + } + + @Provides + public PartyConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(PartyConfig.class); + } + + @Subscribe + public void onOverlayMenuClicked(OverlayMenuClicked event) + { + if (event.getEntry().getMenuAction() == MenuAction.RUNELITE_OVERLAY && + event.getEntry().getTarget().equals("Party") && + event.getEntry().getOption().equals("Leave")) + { + party.changeParty(null); + + final String leaveMessage = new ChatMessageBuilder() + .append(ChatColorType.HIGHLIGHT) + .append("You have left the party.") + .build(); + + chatMessageManager.queue(QueuedMessage.builder() + .type(ChatMessageType.GAME) + .runeLiteFormattedMessage(leaveMessage) + .build()); + } + } + + @Subscribe + public void onMenuOptionClicked(MenuOptionClicked event) + { + if (!hotkeyDown || client.isMenuOpen() || party.getMembers().isEmpty() || !config.pings()) + { + return; + } + + Tile selectedSceneTile = client.getSelectedSceneTile(); + if (selectedSceneTile == null) + { + return; + } + + boolean isOnCanvas = false; + + for (MenuEntry menuEntry : client.getMenuEntries()) + { + if (menuEntry == null) + { + continue; + } + + if ("walk here".equalsIgnoreCase(menuEntry.getOption())) + { + isOnCanvas = true; + } + } + + if (!isOnCanvas) + { + return; + } + + event.consume(); + wsClient.send(new TilePing(selectedSceneTile.getWorldLocation())); + } + + @Subscribe + public void onTilePing(TilePing event) + { + log.debug("Got tile ping {}", event); + + if (config.pings()) + { + pendingTilePings.add(new PartyTilePingData(event.getPoint())); + } + + if (config.sounds()) + { + client.playSoundEffect(SoundEffectID.SMITH_ANVIL_TINK); + } + } + + @Schedule( + period = 10, + unit = ChronoUnit.SECONDS + ) + public void shareLocation() + { + if (client.getGameState() != GameState.LOGGED_IN) + { + return; + } + + final PartyMember localMember = party.getLocalMember(); + + if (localMember == null) + { + return; + } + + final LocationUpdate locationUpdate = new LocationUpdate(client.getLocalPlayer().getWorldLocation()); + locationUpdate.setMemberId(localMember.getMemberId()); + wsClient.send(locationUpdate); + } + + @Subscribe + public void onGameTick(final GameTick event) + { + final int currentHealth = client.getBoostedSkillLevel(Skill.HITPOINTS); + 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) + { + 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; + lastPray = currentPrayer; + } + + @Subscribe + public void onSkillUpdate(final SkillUpdate event) + { + final PartyData partyData = getPartyData(event.getMemberId()); + + if (partyData == null) + { + return; + } + + if (event.getSkill() == Skill.HITPOINTS) + { + partyData.setHitpoints(event.getValue()); + partyData.setMaxHitpoints(event.getMax()); + } + else if (event.getSkill() == Skill.PRAYER) + { + partyData.setPrayer(event.getValue()); + partyData.setMaxPrayer(event.getMax()); + } + } + + @Subscribe + public void onLocationUpdate(final LocationUpdate event) + { + final PartyData partyData = getPartyData(event.getMemberId()); + + if (partyData == null) + { + return; + } + + partyData.getWorldMapPoint().setWorldPoint(event.getWorldPoint()); + } + + @Subscribe + public void onUserJoin(final UserJoin event) + { + final PartyData partyData = getPartyData(event.getMemberId()); + + if (partyData == null || !config.messages()) + { + return; + } + + final String joinMessage = new ChatMessageBuilder() + .append(ChatColorType.HIGHLIGHT) + .append(partyData.getName()) + .append(" has joined the party!") + .build(); + + chatMessageManager.queue(QueuedMessage.builder() + .type(ChatMessageType.GAME) + .runeLiteFormattedMessage(joinMessage) + .build()); + + if (partyData.getMemberId().equals(party.getLocalMember().getMemberId())) + { + final String helpMessage = new ChatMessageBuilder() + .append(ChatColorType.HIGHLIGHT) + .append("To leave party hold SHIFT and right click party stats overlay.") + .build(); + + chatMessageManager.queue(QueuedMessage.builder() + .type(ChatMessageType.GAME) + .runeLiteFormattedMessage(helpMessage) + .build()); + } + } + + @Subscribe + public void onUserSync(final UserSync event) + { + final int currentHealth = client.getBoostedSkillLevel(Skill.HITPOINTS); + 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) + { + final SkillUpdate hpUpdate = new SkillUpdate(Skill.HITPOINTS, currentHealth, realHealth); + hpUpdate.setMemberId(localMember.getMemberId()); + ws.send(hpUpdate); + + final SkillUpdate prayUpdate = new SkillUpdate(Skill.PRAYER, currentPrayer, realPrayer); + prayUpdate.setMemberId(localMember.getMemberId()); + ws.send(prayUpdate); + } + } + + @Subscribe + public void onUserPart(final UserPart event) + { + final PartyData removed = partyDataMap.remove(event.getMemberId()); + + if (removed != null) + { + if (config.messages()) + { + final String joinMessage = new ChatMessageBuilder() + .append(ChatColorType.HIGHLIGHT) + .append(removed.getName()) + .append(" has left the party!") + .build(); + + chatMessageManager.queue(QueuedMessage.builder() + .type(ChatMessageType.GAME) + .runeLiteFormattedMessage(joinMessage) + .build()); + } + + worldMapManager.remove(removed.getWorldMapPoint()); + } + } + + @Subscribe + public void onPartyChanged(final PartyChanged event) + { + // Reset party + partyDataMap.clear(); + pendingTilePings.clear(); + worldMapManager.removeIf(PartyWorldMapPoint.class::isInstance); + } + + @Nullable + PartyData getPartyData(final UUID uuid) + { + final PartyMember memberById = party.getMemberById(uuid); + + if (memberById == null) + { + // This happens when you are not in party but you still receive message. + // Can happen if you just left party and you received message before message went through + // in ws service + return null; + } + + return partyDataMap.computeIfAbsent(uuid, (u) -> + { + final String name = memberById.getName(); + final WorldMapPoint worldMapPoint = new PartyWorldMapPoint(new WorldPoint(0, 0, 0), memberById); + worldMapPoint.setTooltip(name); + + // When first joining a party, other members can join before getting a join for self + PartyMember partyMember = party.getLocalMember(); + if (partyMember == null || !u.equals(partyMember.getMemberId())) + { + worldMapManager.add(worldMapPoint); + } + + return new PartyData(u, name, worldMapPoint); + }); + } + + @Subscribe + public void onFocusChanged(FocusChanged event) + { + if (!event.isFocused()) + { + hotkeyDown = false; + } + } + + @Override + public void keyTyped(KeyEvent keyEvent) + { + + } + + @Override + public void keyPressed(KeyEvent keyEvent) + { + if (keyEvent.getKeyCode() == KeyEvent.VK_SHIFT) + { + hotkeyDown = true; + } + } + + @Override + public void keyReleased(KeyEvent keyEvent) + { + if (keyEvent.getKeyCode() == KeyEvent.VK_SHIFT) + { + hotkeyDown = false; + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPluginService.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPluginService.java new file mode 100644 index 0000000000..8f944eb833 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPluginService.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.party; + +import java.util.UUID; +import javax.annotation.Nullable; +import net.runelite.client.plugins.party.data.PartyData; + +public interface PartyPluginService +{ + /** + * Get the party data for a party member + * @param memberId member id + * @return party data for member + */ + @Nullable + PartyData getPartyData(UUID memberId); +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPluginServiceImpl.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPluginServiceImpl.java new file mode 100644 index 0000000000..042a5e7919 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPluginServiceImpl.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.party; + +import java.util.UUID; +import javax.inject.Inject; +import javax.inject.Singleton; +import net.runelite.client.plugins.party.data.PartyData; + +@Singleton +public class PartyPluginServiceImpl implements PartyPluginService +{ + private final PartyPlugin plugin; + + @Inject + private PartyPluginServiceImpl(final PartyPlugin plugin) + { + + this.plugin = plugin; + } + + @Override + public PartyData getPartyData(UUID memberId) + { + return plugin.getPartyData(memberId); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java new file mode 100644 index 0000000000..243c0c746c --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyStatsOverlay.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2019, Tomas Slusny + * 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.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.util.Map; +import java.util.UUID; +import javax.inject.Inject; +import net.runelite.api.MenuAction; +import net.runelite.client.plugins.party.data.PartyData; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayMenuEntry; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.components.ProgressBarComponent; +import net.runelite.client.ui.overlay.components.TitleComponent; +import net.runelite.client.ws.PartyService; + +public class PartyStatsOverlay extends Overlay +{ + 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; + + private final PartyPlugin plugin; + private final PartyService party; + private final PartyConfig config; + private final PanelComponent body = new PanelComponent(); + + @Inject + private PartyStatsOverlay(final PartyPlugin plugin, final PartyService party, final PartyConfig config) + { + super(plugin); + this.plugin = plugin; + this.party = party; + this.config = config; + getMenuEntries().add(new OverlayMenuEntry(MenuAction.RUNELITE_OVERLAY, "Leave", "Party")); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!config.stats()) + { + return null; + } + + final Map partyDataMap = plugin.getPartyDataMap(); + if (partyDataMap.isEmpty()) + { + return null; + } + + body.getChildren().clear(); + body.setBackgroundColor(null); + + boolean only1 = plugin.getPartyDataMap().size() == 1; + + partyDataMap.forEach((k, v) -> + { + if (party.getLocalMember() != null && party.getLocalMember().getMemberId().equals(k)) + { + if (only1) + { + body.getChildren().add(TitleComponent.builder() + .text("No other party members") + .color(Color.RED) + .build()); + } + + return; + } + + final PanelComponent panel = v.getPanel(); + panel.getChildren().clear(); + + final TitleComponent name = TitleComponent.builder() + .text(v.getName()) + .build(); + + panel.getChildren().add(name); + + if (v.getHitpoints() > 0) + { + final ProgressBarComponent hpBar = new ProgressBarComponent(); + hpBar.setBackgroundColor(HP_BG); + hpBar.setForegroundColor(HP_FG); + hpBar.setMaximum(v.getMaxHitpoints()); + hpBar.setValue(v.getHitpoints()); + hpBar.setLabelDisplayMode(ProgressBarComponent.LabelDisplayMode.FULL); + panel.getChildren().add(hpBar); + } + + if (v.getPrayer() > 0) + { + final ProgressBarComponent prayBar = new ProgressBarComponent(); + prayBar.setBackgroundColor(PRAY_BG); + prayBar.setForegroundColor(PRAY_FG); + prayBar.setMaximum(v.getMaxPrayer()); + prayBar.setValue(v.getPrayer()); + prayBar.setLabelDisplayMode(ProgressBarComponent.LabelDisplayMode.FULL); + panel.getChildren().add(prayBar); + } + + body.getChildren().add(panel); + }); + + return body.render(graphics); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyWorldMapPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyWorldMapPoint.java new file mode 100644 index 0000000000..a2ae27835b --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyWorldMapPoint.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2019, Tomas Slusny + * 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.Graphics; +import java.awt.image.BufferedImage; +import net.runelite.api.Point; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; +import net.runelite.client.util.ImageUtil; +import net.runelite.client.ws.PartyMember; + +class PartyWorldMapPoint extends WorldMapPoint +{ + private static final BufferedImage ARROW = ImageUtil.getResourceStreamFromClass(PartyWorldMapPoint.class, "/util/clue_arrow.png"); + + private BufferedImage partyImage; + private PartyMember member; + + PartyWorldMapPoint(WorldPoint worldPoint, PartyMember member) + { + super(worldPoint, null); + this.member = member; + this.setSnapToEdge(true); + this.setJumpOnClick(true); + this.setImagePoint(new Point( + ARROW.getWidth() / 2, + ARROW.getHeight())); + } + + @Override + public BufferedImage getImage() + { + if (partyImage == null && member != null && member.getAvatar() != null) + { + partyImage = new BufferedImage(ARROW.getWidth(), ARROW.getHeight(), BufferedImage.TYPE_INT_ARGB); + Graphics g = partyImage.getGraphics(); + g.drawImage(ARROW, 0, 0, null); + g.drawImage(ImageUtil.resizeImage(member.getAvatar(), 28, 28), 2, 2, null); + } + + return partyImage; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyData.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyData.java new file mode 100644 index 0000000000..a7ff8a3dbd --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyData.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019, Tomas Slusny + * 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.data; + +import java.util.UUID; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; + +@Setter +@Getter +@RequiredArgsConstructor +public class PartyData +{ + private final UUID memberId; + private final String name; + private final WorldMapPoint worldMapPoint; + private final PanelComponent panel = new PanelComponent(); + + private int hitpoints; + private int maxHitpoints; + private int prayer; + private int maxPrayer; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyTilePingData.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyTilePingData.java new file mode 100644 index 0000000000..9c01bf78e2 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/data/PartyTilePingData.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019, Tomas Slusny + * 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.data; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import net.runelite.api.coords.WorldPoint; + +@RequiredArgsConstructor +@Getter +@Setter +public class PartyTilePingData +{ + private final WorldPoint point; + private int alpha = 255; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/LocationUpdate.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/LocationUpdate.java new file mode 100644 index 0000000000..0ff6569379 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/LocationUpdate.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019, Tomas Slusny + * 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.Value; +import net.runelite.api.coords.WorldPoint; +import net.runelite.http.api.ws.messages.party.PartyMemberMessage; + +@Value +public class LocationUpdate extends PartyMemberMessage +{ + private final WorldPoint worldPoint; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/SkillUpdate.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/SkillUpdate.java new file mode 100644 index 0000000000..10f5810b0f --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/SkillUpdate.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019, Tomas Slusny + * 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.AllArgsConstructor; +import lombok.Getter; +import net.runelite.api.Skill; +import net.runelite.http.api.ws.messages.party.PartyMemberMessage; + +@AllArgsConstructor +@Getter +public class SkillUpdate extends PartyMemberMessage +{ + private final Skill skill; + private final int value; + private final int max; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/TilePing.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/TilePing.java new file mode 100644 index 0000000000..d43012669e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/messages/TilePing.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019, Tomas Slusny + * 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.Value; +import net.runelite.api.coords.WorldPoint; +import net.runelite.http.api.ws.messages.party.PartyMessage; + +@Value +public class TilePing extends PartyMessage +{ + private final WorldPoint point; +}