Repository: pajlads/DinkPlugin (java)

Issue:
Pet: Add completions/XP from Clan chat to Dink notification
**Dink version:** 1.3.0

Since the pet notifications now show up with a name. I wonder if it's possible to add the completion / XP section from the GIM / Clan chat notification to the Dink notification?

What the notification now looks like:
![Dink pet notification without KC](https://user-images.githubusercontent.com/11279045/218856837-2642a3da-942c-430a-ad12-d1867ff69cd6.png)

The GIM / Clan chat notification:
![Notification Pet Youngleff](https://user-images.githubusercontent.com/11279045/218856790-fa4fc509-4a91-470f-abdf-460c7b07d418.png)


Pull request description:
feat: parse pet acquisition milestone
Closes #168

![image](https://user-images.githubusercontent.com/8106344/218918213-51d0300c-5a71-4a4b-be82-0e9f92b55a27.png)


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 18dad92..ea348ba 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
 ## Unreleased
 
+- Minor: Include pet acquisition milestone in webhook metadata from clan message. (#169)
 - Minor: Add setting to skip death notifications with low value of items lost. (#166)
 - Bugfix: Fire skill notification when jumping over a level that matches the configured interval. (#164)
 - Dev: Upgrade Gradle from v7.6 to v8.0. (#167, #170)
diff --git a/README.md b/README.md
index 77a82b9..b76d6e8 100644
--- a/README.md
+++ b/README.md
@@ -400,13 +400,14 @@ The examples below omit `embeds` and `playerName` keys because they are always t
 {
   "content": "%USERNAME% has a funny feeling they are being followed",
   "extra": {
-    "petName": "Ikkle hydra"
+    "petName": "Ikkle hydra",
+    "milestone": "5,000 killcount"
   },
   "type": "PET"
 }
 ```
 
-Note: `petName` is only included if the game sent it to your chat via untradeable drop or collection log or clan notifications.
+Note: `petName` is only included if the game sent it to your chat via untradeable drop or collection log or clan notifications. `milestone` is only included if a clan notification was triggered.
 </details>
 
 ### Speedrunning:
diff --git a/src/main/java/dinkplugin/message/Field.java b/src/main/java/dinkplugin/message/Field.java
index 9dfa628..3b572fa 100644
--- a/src/main/java/dinkplugin/message/Field.java
+++ b/src/main/java/dinkplugin/message/Field.java
@@ -3,6 +3,7 @@ package dinkplugin.message;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Value;
+import org.apache.commons.lang3.StringUtils;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -20,6 +21,10 @@ public class Field {
     @Nullable Boolean inline;
 
     public Field(String name, String value) {
-        this(name, value, null);
+        this(name, value, true);
+    }
+
+    public static String formatBlock(String codeBlockLanguage, String content) {
+        return String.format("```%s\n%s\n```", StringUtils.defaultString(codeBlockLanguage), content);
     }
 }
diff --git a/src/main/java/dinkplugin/notifiers/PetNotifier.java b/src/main/java/dinkplugin/notifiers/PetNotifier.java
index 64b7a81..d29055c 100644
--- a/src/main/java/dinkplugin/notifiers/PetNotifier.java
+++ b/src/main/java/dinkplugin/notifiers/PetNotifier.java
@@ -37,7 +37,7 @@ public class PetNotifier extends BaseNotifier {
     static final Pattern PET_REGEX = Pattern.compile("You (?:have a funny feeling like you|feel something weird sneaking).*");
 
     @VisibleForTesting
-    static final Pattern CLAN_REGEX = Pattern.compile("\\b(?<user>[\\w\\s]+) (?:has a funny feeling like .+ followed|feels something weird sneaking into .+ backpack): (?<pet>.+) at\\s");
+    static final Pattern CLAN_REGEX = Pattern.compile("\\b(?<user>[\\w\\s]+) (?:has a funny feeling like .+ followed|feels something weird sneaking into .+ backpack): (?<pet>.+) at (?<milestone>.+)");
 
     private static final Pattern UNTRADEABLE_REGEX = Pattern.compile("Untradeable drop: (.+)");
     private static final Set<String> PET_NAMES;
@@ -49,6 +49,8 @@ public class PetNotifier extends BaseNotifier {
     @Setter(AccessLevel.PRIVATE)
     private volatile String petName = null;
 
+    private volatile String milestone = null;
+
     @Override
     public boolean isEnabled() {
         return config.notifyPet() && super.isEnabled();
@@ -77,7 +79,7 @@ public class PetNotifier extends BaseNotifier {
     }
 
     public void onClanNotification(String message) {
-        if (!PRIMED_NAME.equals(petName)) {
+        if (petName == null) {
             // We have not received the normal message about a pet drop, so this clan message cannot be relevant to us
             return;
         }
@@ -87,6 +89,7 @@ public class PetNotifier extends BaseNotifier {
             String user = matcher.group("user").trim();
             if (user.equals(Utils.getPlayerName(client))) {
                 this.petName = matcher.group("pet");
+                this.milestone = StringUtils.removeEnd(matcher.group("milestone"), ".");
             }
         }
     }
@@ -98,6 +101,7 @@ public class PetNotifier extends BaseNotifier {
 
     public void reset() {
         this.petName = null;
+        this.milestone = null;
     }
 
     private void handleNotify() {
@@ -111,7 +115,7 @@ public class PetNotifier extends BaseNotifier {
             .map(ItemUtils::getItemImageUrl)
             .orElse(null);
 
-        PetNotificationData extra = new PetNotificationData(StringUtils.defaultIfEmpty(petName, null));
+        PetNotificationData extra = new PetNotificationData(StringUtils.defaultIfEmpty(petName, null), milestone);
 
         createMessage(config.petSendImage(), NotificationBody.builder()
             .extra(extra)
diff --git a/src/main/java/dinkplugin/notifiers/data/LevelNotificationData.java b/src/main/java/dinkplugin/notifiers/data/LevelNotificationData.java
index ec69128..04ad494 100644
--- a/src/main/java/dinkplugin/notifiers/data/LevelNotificationData.java
+++ b/src/main/java/dinkplugin/notifiers/data/LevelNotificationData.java
@@ -28,11 +28,7 @@ public class LevelNotificationData extends NotificationData {
             return Collections.singletonList(
                 new Field(
                     "Total Skills at Level 99+",
-                    String.format(
-                        "```\n%d: %s\n```",
-                        maxed.size(),
-                        String.join(", ", maxed)
-                    )
+                    Field.formatBlock("", maxed.size() + ": " + String.join(", ", maxed))
                 )
             );
         }
diff --git a/src/main/java/dinkplugin/notifiers/data/PetNotificationData.java b/src/main/java/dinkplugin/notifiers/data/PetNotificationData.java
index 80b83b1..da6ede8 100644
--- a/src/main/java/dinkplugin/notifiers/data/PetNotificationData.java
+++ b/src/main/java/dinkplugin/notifiers/data/PetNotificationData.java
@@ -4,21 +4,24 @@ import dinkplugin.message.Field;
 import lombok.EqualsAndHashCode;
 import lombok.Value;
 
-import java.util.Collections;
+import java.util.ArrayList;
 import java.util.List;
 
 @Value
 @EqualsAndHashCode(callSuper = false)
 public class PetNotificationData extends NotificationData {
     String petName;
+    String milestone;
 
     @Override
     public List<Field> getFields() {
         if (petName == null || petName.isEmpty())
             return super.getFields();
 
-        return Collections.singletonList(
-            new Field("Name", "```\n" + petName + "\n```")
-        );
+        List<Field> fields = new ArrayList<>(2);
+        fields.add(new Field("Name", Field.formatBlock("", petName)));
+        if (milestone != null)
+            fields.add(new Field("Milestone", Field.formatBlock("", milestone)));
+        return fields;
     }
 }
diff --git a/src/main/java/dinkplugin/util/ItemUtils.java b/src/main/java/dinkplugin/util/ItemUtils.java
index 7396314..368bfb9 100644
--- a/src/main/java/dinkplugin/util/ItemUtils.java
+++ b/src/main/java/dinkplugin/util/ItemUtils.java
@@ -2,6 +2,7 @@ package dinkplugin.util;
 
 import com.google.common.collect.ImmutableSet;
 import dinkplugin.message.Embed;
+import dinkplugin.message.Field;
 import dinkplugin.notifiers.data.SerializedItemStack;
 import lombok.experimental.UtilityClass;
 import net.runelite.api.Client;
@@ -130,7 +131,7 @@ public class ItemUtils {
     }
 
     public String formatGold(long amount) {
-        return String.format("```ldif\n%s gp\n```", QuantityFormatter.quantityToStackSize(amount));
+        return Field.formatBlock("ldif", QuantityFormatter.quantityToStackSize(amount) + " gp");
     }
 
 }


Test patch:
diff --git a/src/test/java/dinkplugin/notifiers/PetNotifierTest.java b/src/test/java/dinkplugin/notifiers/PetNotifierTest.java
index 12461db..c417be7 100644
--- a/src/test/java/dinkplugin/notifiers/PetNotifierTest.java
+++ b/src/test/java/dinkplugin/notifiers/PetNotifierTest.java
@@ -50,7 +50,7 @@ class PetNotifierTest extends MockedNotifierTest {
             PRIMARY_WEBHOOK_URL,
             false,
             NotificationBody.builder()
-                .extra(new PetNotificationData(null))
+                .extra(new PetNotificationData(null, null))
                 .text(PLAYER_NAME + " got a pet")
                 .type(NotificationType.PET)
                 .build()
@@ -75,7 +75,7 @@ class PetNotifierTest extends MockedNotifierTest {
             PRIMARY_WEBHOOK_URL,
             false,
             NotificationBody.builder()
-                .extra(new PetNotificationData(petName))
+                .extra(new PetNotificationData(petName, null))
                 .text(PLAYER_NAME + " got a pet")
                 .thumbnailUrl(ItemUtils.getItemImageUrl(itemId))
                 .type(NotificationType.PET)
@@ -101,7 +101,7 @@ class PetNotifierTest extends MockedNotifierTest {
             PRIMARY_WEBHOOK_URL,
             false,
             NotificationBody.builder()
-                .extra(new PetNotificationData(petName))
+                .extra(new PetNotificationData(petName, null))
                 .text(PLAYER_NAME + " got a pet")
                 .thumbnailUrl(ItemUtils.getItemImageUrl(itemId))
                 .type(NotificationType.PET)
@@ -124,7 +124,7 @@ class PetNotifierTest extends MockedNotifierTest {
             PRIMARY_WEBHOOK_URL,
             false,
             NotificationBody.builder()
-                .extra(new PetNotificationData(null))
+                .extra(new PetNotificationData(null, null))
                 .text(PLAYER_NAME + " got a pet")
                 .thumbnailUrl(ItemUtils.getItemImageUrl(itemId))
                 .type(NotificationType.PET)
@@ -145,7 +145,7 @@ class PetNotifierTest extends MockedNotifierTest {
         notifier.onChatMessage("Untradeable drop: " + petName);
         notifier.onClanNotification(
             String.format(
-                "[ClanName] %s has a funny feeling like he would have been followed: %s at 50 killcount",
+                "[ClanName] %s has a funny feeling like he would have been followed: %s at 50 killcount.",
                 PLAYER_NAME,
                 petName
             )
@@ -157,7 +157,7 @@ class PetNotifierTest extends MockedNotifierTest {
             PRIMARY_WEBHOOK_URL,
             false,
             NotificationBody.builder()
-                .extra(new PetNotificationData(petName))
+                .extra(new PetNotificationData(petName, "50 killcount"))
                 .text(PLAYER_NAME + " got a pet")
                 .thumbnailUrl(ItemUtils.getItemImageUrl(itemId))
                 .type(NotificationType.PET)
@@ -177,7 +177,7 @@ class PetNotifierTest extends MockedNotifierTest {
         notifier.onChatMessage("You have a funny feeling like you're being followed.");
         notifier.onClanNotification(
             String.format(
-                "[ClanName] %s has a funny feeling like he would have been followed: %s at 50 killcount",
+                "[ClanName] %s has a funny feeling like he would have been followed: %s at 50 killcount.",
                 PLAYER_NAME,
                 petName
             )
@@ -189,7 +189,7 @@ class PetNotifierTest extends MockedNotifierTest {
             PRIMARY_WEBHOOK_URL,
             false,
             NotificationBody.builder()
-                .extra(new PetNotificationData(petName))
+                .extra(new PetNotificationData(petName, "50 killcount"))
                 .text(PLAYER_NAME + " got a pet")
                 .thumbnailUrl(ItemUtils.getItemImageUrl(itemId))
                 .type(NotificationType.PET)
@@ -211,7 +211,7 @@ class PetNotifierTest extends MockedNotifierTest {
             "https://example.com",
             false,
             NotificationBody.builder()
-                .extra(new PetNotificationData(null))
+                .extra(new PetNotificationData(null, null))
                 .text(PLAYER_NAME + " got a pet")
                 .type(NotificationType.PET)
                 .build()
@@ -256,7 +256,7 @@ class PetNotifierTest extends MockedNotifierTest {
             PRIMARY_WEBHOOK_URL,
             false,
             NotificationBody.builder()
-                .extra(new PetNotificationData(null))
+                .extra(new PetNotificationData(null, null))
                 .text(PLAYER_NAME + " got a pet")
                 .type(NotificationType.PET)
                 .build()