Add party plugin

Co-authored-by: Adam <Adam@sigterm.info>
Signed-off-by: Tomas Slusny <slusnucky@gmail.com>
This commit is contained in:
Tomas Slusny
2019-01-31 12:13:32 +00:00
committed by Adam
parent c62941855d
commit 1a7946660c
12 changed files with 1157 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
* 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;
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
* 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<PartyTilePingData> 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()));
}
}

View File

@@ -0,0 +1,483 @@
/*
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
* 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<UUID, PartyData> partyDataMap = new HashMap<>();
@Getter
private final List<PartyTilePingData> 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;
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* 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);
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* 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);
}
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
* 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<UUID, PartyData> 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);
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
* 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;
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
* 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;
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
* 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;
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
* 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;
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
* 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;
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2019, Tomas Slusny <slusnucky@gmail.com>
* 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;
}