Skip to content

Commit

Permalink
feat: add party to kc metadata (#587)
Browse files Browse the repository at this point in the history
  • Loading branch information
iProdigy authored Nov 11, 2024
1 parent 809f618 commit 0a30d8b
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 48 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## Unreleased

- Minor: Add raid party members to kill count notification metadata. (#587)
- Minor: Add `::DinkMigrate` command to import configuration from other Discord webhook plugins. (#564)
- Minor: Remove boss image embed from kill count notifications with screenshots disabled. (#578)
- Dev: Add current tier, total possible points, and next tier to combat task metadata. (#586)
Expand Down
7 changes: 5 additions & 2 deletions docs/json-examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -326,16 +326,19 @@ JSON for Kill Count Notifications:
{
"content": "%USERNAME% has defeated %BOSS% with a completion count of %COUNT%",
"extra": {
"boss": "King Black Dragon",
"boss": "Chambers of Xeric",
"count": 69,
"gameMessage": "Your King Black Dragon kill count is: 69."
"gameMessage": "Your completed Chambers of Xeric count is: 69.",
"party": ["%USERNAME%", "another RSN", "yet another RSN"]
},
"type": "KILL_COUNT"
}
```

Note: when `boss` is `Penance Queen`, `count` refers to the high level gamble count, rather than kill count.

Also, `extra.party` is only populated for certain bosses (see [Loot](#loot) for more details).

### Combat Achievements

JSON for Combat Achievement Notifications:
Expand Down
14 changes: 8 additions & 6 deletions src/main/java/dinkplugin/notifiers/KillCountNotifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import dinkplugin.message.NotificationType;
import dinkplugin.notifiers.data.BossNotificationData;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.Varbits;
import net.runelite.api.annotations.Varbit;
import net.runelite.api.events.WidgetLoaded;
Expand Down Expand Up @@ -72,7 +73,7 @@ public void reset() {

public void onGameMessage(String message) {
if (isEnabled())
parse(message).ifPresent(this::updateData);
parse(client, message).ifPresent(this::updateData);
}

public void onFriendsChatNotification(String message) {
Expand All @@ -91,7 +92,7 @@ public void onWidget(WidgetLoaded event) {
// https://oldschool.runescape.wiki/w/Barbarian_Assault/Rewards#Earning_Honour_points
if (widget != null && widget.getText().contains("80 ") && widget.getText().contains("5 ")) {
int gambleCount = client.getVarbitValue(Varbits.BA_GC);
this.data.set(new BossNotificationData(BA_BOSS_NAME, gambleCount, "The Queen is dead!", null, null));
this.data.set(new BossNotificationData(BA_BOSS_NAME, gambleCount, "The Queen is dead!", null, null, null));
}
}
}
Expand Down Expand Up @@ -170,18 +171,19 @@ private void updateData(BossNotificationData updated) {
defaultIfNull(updated.getCount(), old.getCount()),
defaultIfNull(updated.getGameMessage(), old.getGameMessage()),
defaultIfNull(updated.getTime(), old.getTime()),
defaultIfNull(updated.isPersonalBest(), old.isPersonalBest())
defaultIfNull(updated.isPersonalBest(), old.isPersonalBest()),
defaultIfNull(updated.getParty(), old.getParty())
);
}
});
}

private static Optional<BossNotificationData> parse(String message) {
private static Optional<BossNotificationData> parse(Client client, String message) {
if (message.startsWith("Preparation")) return Optional.empty();
Optional<Pair<String, Integer>> boss = parseBoss(message);
if (boss.isPresent())
return boss.map(pair -> new BossNotificationData(pair.getLeft(), pair.getRight(), message, null, null));
return parseTime(message).map(t -> new BossNotificationData(null, null, null, t.getLeft(), t.getRight()));
return boss.map(pair -> new BossNotificationData(pair.getLeft(), pair.getRight(), message, null, null, Utils.getBossParty(client, pair.getLeft())));
return parseTime(message).map(t -> new BossNotificationData(null, null, null, t.getLeft(), t.getRight(), null));
}

private static Optional<Pair<Duration, Boolean>> parseTime(String message) {
Expand Down
18 changes: 1 addition & 17 deletions src/main/java/dinkplugin/notifiers/LootNotifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@
import net.runelite.client.util.QuantityFormatter;
import net.runelite.http.api.loottracker.LootRecordType;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import javax.inject.Inject;
import javax.inject.Singleton;
Expand Down Expand Up @@ -241,7 +239,7 @@ private void handleNotify(Collection<ItemStack> items, String dropper, LootRecor
}
Double rarity = rarest != null ? rarest.getRarity() : null;
boolean screenshot = config.lootSendImage() && totalStackValue >= config.lootImageMinValue();
Collection<String> party = type == LootRecordType.EVENT ? getParty(dropper) : null;
Collection<String> party = type == LootRecordType.EVENT ? Utils.getBossParty(client, dropper) : null;
Evaluable source = type == LootRecordType.PLAYER
? Replacements.ofLink(dropper, config.playerLookupService().getPlayerUrl(dropper))
: Replacements.ofWiki(dropper);
Expand All @@ -265,20 +263,6 @@ private void handleNotify(Collection<ItemStack> items, String dropper, LootRecor
}
}

@Nullable
private Collection<String> getParty(@NotNull String source) {
switch (source) {
case "Chambers of Xeric":
return Utils.getXericChambersParty(client);
case "Tombs of Amascut":
return Utils.getAmascutTombsParty(client);
case "Theatre of Blood":
return Utils.getBloodTheatreParty(client);
default:
return null;
}
}

private static boolean matches(Collection<Pattern> regexps, String input) {
for (Pattern regex : regexps) {
if (regex.matcher(input).find())
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/dinkplugin/notifiers/data/BossNotificationData.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
package dinkplugin.notifiers.data;

import com.google.gson.annotations.JsonAdapter;
import dinkplugin.message.Field;
import dinkplugin.util.DurationAdapter;
import lombok.EqualsAndHashCode;
import lombok.Value;
import lombok.experimental.Accessors;
import org.jetbrains.annotations.Nullable;

import java.time.Duration;
import java.util.Collection;
import java.util.List;

@Value
@EqualsAndHashCode(callSuper = false)
Expand All @@ -18,4 +22,14 @@ public class BossNotificationData extends NotificationData {
Duration time;
@Accessors(fluent = true)
Boolean isPersonalBest;
@Nullable
Collection<String> party;

@Override
public List<Field> getFields() {
if (party != null && !party.isEmpty()) {
return List.of(new Field("Party Size", Field.formatBlock("", String.valueOf(party.size()))));
}
return super.getFields();
}
}
31 changes: 25 additions & 6 deletions src/main/java/dinkplugin/util/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import okhttp3.Response;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.VisibleForTesting;

import javax.imageio.ImageIO;
import javax.swing.SwingUtilities;
Expand Down Expand Up @@ -71,8 +72,8 @@ public class Utils {

private final char ELLIPSIS = '\u2026'; // '…'

@SuppressWarnings("MagicConstant")
private final @VarCStr int TOA_MEMBER_NAME = 1099, TOB_MEMBER_NAME = 330;
@VisibleForTesting
public final @VarCStr int TOA_MEMBER_NAME = 1099, TOB_MEMBER_NAME = 330;
private final int TOA_PARTY_MAX_SIZE = 8, TOB_PARTY_MAX_SIZE = 5;

private final @Component int PRIVATE_CHAT_WIDGET = WidgetUtil.packComponentId(InterfaceID.PRIVATE_CHAT, 0);
Expand Down Expand Up @@ -212,7 +213,26 @@ public String getChatBadge(@NotNull AccountType type, boolean seasonal) {
}
}

public Collection<String> getXericChambersParty(@NotNull Client client) {
@Nullable
public Collection<String> getBossParty(@NotNull Client client, @NotNull String source) {
switch (source) {
case "Chambers of Xeric":
case "Chambers of Xeric Challenge Mode":
return Utils.getXericChambersParty(client);
case "Tombs of Amascut":
case "Tombs of Amascut: Entry Mode":
case "Tombs of Amascut: Expert Mode":
return Utils.getAmascutTombsParty(client);
case "Theatre of Blood":
case "Theatre of Blood: Entry Mode":
case "Theatre of Blood: Hard Mode":
return Utils.getBloodTheatreParty(client);
default:
return null;
}
}

private Collection<String> getXericChambersParty(@NotNull Client client) {
Widget widget = client.getWidget(InterfaceID.RAIDING_PARTY, 10);
if (widget == null) return Collections.emptyList();

Expand All @@ -229,18 +249,17 @@ public Collection<String> getXericChambersParty(@NotNull Client client) {
return names;
}

public Collection<String> getAmascutTombsParty(@NotNull Client client) {
private Collection<String> getAmascutTombsParty(@NotNull Client client) {
return getVarcStrings(client, TOA_MEMBER_NAME, TOA_PARTY_MAX_SIZE);
}

public Collection<String> getBloodTheatreParty(@NotNull Client client) {
private Collection<String> getBloodTheatreParty(@NotNull Client client) {
return getVarcStrings(client, TOB_MEMBER_NAME, TOB_PARTY_MAX_SIZE);
}

private List<String> getVarcStrings(@NotNull Client client, @VarCStr final int initialVarcId, final int maxSize) {
List<String> strings = new ArrayList<>(maxSize);
for (int i = 0; i < maxSize; i++) {
// noinspection MagicConstant
String name = client.getVarcStrValue(initialVarcId + i);
if (name == null || name.isEmpty()) continue;
strings.add(name.replace('\u00A0', ' '));
Expand Down
Loading

0 comments on commit 0a30d8b

Please sign in to comment.