diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1dd21da
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,89 @@
+# Compiled class files
+*.class
+
+# Log files
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# Virtual machine crash logs
+hs_err_pid*
+replay_pid*
+
+# Maven
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+.mvn/wrapper/maven-wrapper.jar
+
+# IntelliJ IDEA
+.idea/
+*.iws
+*.iml
+*.ipr
+out/
+.idea_modules/
+
+# Eclipse
+.classpath
+.project
+.settings/
+bin/
+
+# NetBeans
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
+
+# VS Code
+.vscode/
+*.code-workspace
+
+# macOS
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Windows
+Thumbs.db
+ehthumbs.db
+Desktop.ini
+$RECYCLE.BIN/
+
+# Linux
+*~
+.directory
+.Trash-*
+
+# Backup files
+*.bak
+*.swp
+*.swo
+*~
+
+# Temporary files
+*.tmp
+*.temp
+
diff --git a/.idea/PlayerStats.iml b/.idea/PlayerStats.iml
index a591bfe..ad42100 100644
--- a/.idea/PlayerStats.iml
+++ b/.idea/PlayerStats.iml
@@ -7,6 +7,7 @@
SPIGOTADVENTURE
+ 1
diff --git a/.idea/copilot.data.migration.agent.xml b/.idea/copilot.data.migration.agent.xml
new file mode 100644
index 0000000..4ea72a9
--- /dev/null
+++ b/.idea/copilot.data.migration.agent.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/copilot.data.migration.ask.xml b/.idea/copilot.data.migration.ask.xml
new file mode 100644
index 0000000..7ef04e2
--- /dev/null
+++ b/.idea/copilot.data.migration.ask.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/copilot.data.migration.ask2agent.xml b/.idea/copilot.data.migration.ask2agent.xml
new file mode 100644
index 0000000..1f2ea11
--- /dev/null
+++ b/.idea/copilot.data.migration.ask2agent.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/copilot.data.migration.edit.xml b/.idea/copilot.data.migration.edit.xml
new file mode 100644
index 0000000..8648f94
--- /dev/null
+++ b/.idea/copilot.data.migration.edit.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/discord.xml b/.idea/discord.xml
new file mode 100644
index 0000000..912db82
--- /dev/null
+++ b/.idea/discord.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..da505a3
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/artemis/the/gr8/playerstats/api/events/StatCalculatedEvent.java b/src/main/java/com/artemis/the/gr8/playerstats/api/events/StatCalculatedEvent.java
new file mode 100644
index 0000000..438adb1
--- /dev/null
+++ b/src/main/java/com/artemis/the/gr8/playerstats/api/events/StatCalculatedEvent.java
@@ -0,0 +1,86 @@
+package com.artemis.the.gr8.playerstats.api.events;
+
+import com.artemis.the.gr8.playerstats.api.StatRequest;
+import com.artemis.the.gr8.playerstats.api.StatResult;
+import org.bukkit.command.CommandSender;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * This event is fired whenever PlayerStats calculates a statistic result.
+ * This includes player stats, server stats, and top stats.
+ *
+ * This event is called on the main thread after the statistic has been
+ * calculated but before it is sent to the requesting player.
+ *
+ * You can use this event to:
+ *
+ *
Send stat results to external systems (like Discord via DiscordSRV)
+ *
Log stat lookups
+ *
Perform additional actions based on stat results
+ *
+ */
+public class StatCalculatedEvent extends Event {
+
+ private static final HandlerList HANDLERS = new HandlerList();
+
+ private final CommandSender sender;
+ private final StatRequest> request;
+ private final StatResult> result;
+
+ public StatCalculatedEvent(@NotNull CommandSender sender, @NotNull StatRequest> request, @NotNull StatResult> result) {
+ this.sender = sender;
+ this.request = request;
+ this.result = result;
+ }
+
+ /**
+ * Gets the CommandSender who requested this statistic lookup.
+ *
+ * @return the CommandSender who initiated the stat request
+ */
+ @NotNull
+ public CommandSender getSender() {
+ return sender;
+ }
+
+ /**
+ * Gets the StatRequest that was used to calculate this statistic.
+ *
+ * @return the StatRequest containing the lookup parameters
+ */
+ @NotNull
+ public StatRequest> getRequest() {
+ return request;
+ }
+
+ /**
+ * Gets the calculated StatResult containing the formatted output.
+ *
+ * You can use:
+ *
+ *
{@link StatResult#getNumericalValue()} to get the raw number
+ *
{@link StatResult#getFormattedTextComponent()} to get the formatted Adventure TextComponent
+ *
{@link StatResult#formattedString()} to get a plain String representation
+ *
+ *
+ * @return the StatResult containing the calculated statistic
+ */
+ @NotNull
+ public StatResult> getResult() {
+ return result;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLERS;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLERS;
+ }
+}
+
diff --git a/src/main/java/com/artemis/the/gr8/playerstats/api/events/StatSharedEvent.java b/src/main/java/com/artemis/the/gr8/playerstats/api/events/StatSharedEvent.java
new file mode 100644
index 0000000..21e8a71
--- /dev/null
+++ b/src/main/java/com/artemis/the/gr8/playerstats/api/events/StatSharedEvent.java
@@ -0,0 +1,94 @@
+package com.artemis.the.gr8.playerstats.api.events;
+
+import net.kyori.adventure.text.TextComponent;
+import org.bukkit.command.CommandSender;
+import org.bukkit.event.Cancellable;
+import org.bukkit.event.Event;
+import org.bukkit.event.HandlerList;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * This event is fired when a player shares a statistic result to the server chat
+ * by clicking the share button or using the /statshare command.
+ *
+ * This event is cancellable. If cancelled, the stat result will not be broadcast
+ * to all players.
+ *
+ * You can use this event to:
+ *
+ *
Send shared stats to Discord via DiscordSRV
+ *
Log stat shares
+ *
Prevent certain stats from being shared
+ *
Send the stat to custom channels
+ *
+ */
+public class StatSharedEvent extends Event implements Cancellable {
+
+ private static final HandlerList HANDLERS = new HandlerList();
+
+ private final CommandSender sender;
+ private final TextComponent statResult;
+ private final int shareCode;
+ private boolean cancelled = false;
+
+ public StatSharedEvent(@NotNull CommandSender sender, @NotNull TextComponent statResult, int shareCode) {
+ this.sender = sender;
+ this.statResult = statResult;
+ this.shareCode = shareCode;
+ }
+
+ /**
+ * Gets the CommandSender who is sharing the statistic.
+ *
+ * @return the CommandSender sharing the stat
+ */
+ @NotNull
+ public CommandSender getSender() {
+ return sender;
+ }
+
+ /**
+ * Gets the formatted statistic result that is being shared.
+ * This is an Adventure TextComponent with formatting, colors, and hover text.
+ *
+ * For a plain String representation, you can serialize this component or
+ * use Adventure's PlainTextComponentSerializer.
+ *
+ * @return the formatted stat result as a TextComponent
+ */
+ @NotNull
+ public TextComponent getStatResult() {
+ return statResult;
+ }
+
+ /**
+ * Gets the share code that was used to retrieve this statistic.
+ * This is the unique identifier for this particular stat share.
+ *
+ * @return the share code
+ */
+ public int getShareCode() {
+ return shareCode;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+ @Override
+ public void setCancelled(boolean cancel) {
+ this.cancelled = cancel;
+ }
+
+ @NotNull
+ @Override
+ public HandlerList getHandlers() {
+ return HANDLERS;
+ }
+
+ @NotNull
+ public static HandlerList getHandlerList() {
+ return HANDLERS;
+ }
+}
diff --git a/src/main/java/com/artemis/the/gr8/playerstats/core/commands/ShareCommand.java b/src/main/java/com/artemis/the/gr8/playerstats/core/commands/ShareCommand.java
index 208bfd5..6f6b618 100644
--- a/src/main/java/com/artemis/the/gr8/playerstats/core/commands/ShareCommand.java
+++ b/src/main/java/com/artemis/the/gr8/playerstats/core/commands/ShareCommand.java
@@ -1,5 +1,6 @@
package com.artemis.the.gr8.playerstats.core.commands;
+import com.artemis.the.gr8.playerstats.api.events.StatSharedEvent;
import com.artemis.the.gr8.playerstats.core.sharing.ShareManager;
import com.artemis.the.gr8.playerstats.core.enums.StandardMessage;
import com.artemis.the.gr8.playerstats.core.msg.OutputManager;
@@ -45,7 +46,15 @@ else if (shareManager.isOnCoolDown(sender.getName())) {
outputManager.sendFeedbackMsg(sender, StandardMessage.STAT_RESULTS_TOO_OLD);
} else {
commandCounter.upShareCommandCount();
- outputManager.sendToAllPlayers(result.formattedValue());
+
+ // Fire the share event to expose the data, for things like DiscordSRV - DerexXD
+ StatSharedEvent event = new StatSharedEvent(sender, result.formattedValue(), shareCode);
+ org.bukkit.Bukkit.getPluginManager().callEvent(event);
+
+ // Only broadcast to all players if the event wasn't cancelled
+ if (!event.isCancelled()) {
+ outputManager.sendToAllPlayers(result.formattedValue());
+ }
}
}
}
diff --git a/src/main/java/com/artemis/the/gr8/playerstats/core/multithreading/StatThread.java b/src/main/java/com/artemis/the/gr8/playerstats/core/multithreading/StatThread.java
index f155a70..49f50cf 100644
--- a/src/main/java/com/artemis/the/gr8/playerstats/core/multithreading/StatThread.java
+++ b/src/main/java/com/artemis/the/gr8/playerstats/core/multithreading/StatThread.java
@@ -1,11 +1,13 @@
package com.artemis.the.gr8.playerstats.core.multithreading;
+import com.artemis.the.gr8.playerstats.api.events.StatCalculatedEvent;
import com.artemis.the.gr8.playerstats.core.msg.OutputManager;
import com.artemis.the.gr8.playerstats.core.statistic.StatRequestManager;
import com.artemis.the.gr8.playerstats.api.StatRequest;
import com.artemis.the.gr8.playerstats.api.StatResult;
import com.artemis.the.gr8.playerstats.core.utils.MyLogger;
import com.artemis.the.gr8.playerstats.core.enums.StandardMessage;
+import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.Nullable;
@@ -56,9 +58,13 @@ public void run() throws IllegalStateException {
try {
StatResult> result = StatRequestManager.execute(statRequest);
+
+ // Fire the event to expose the data, for things like DiscordSRV - DerexXD
+ StatCalculatedEvent event = new StatCalculatedEvent(statRequester, statRequest, result);
+ Bukkit.getPluginManager().callEvent(event);
+
outputManager.sendToCommandSender(statRequester, result.formattedComponent());
- }
- catch (ConcurrentModificationException e) {
+ } catch (ConcurrentModificationException e) {
if (!statRequest.getSettings().isConsoleSender()) {
outputManager.sendFeedbackMsg(statRequester, StandardMessage.UNKNOWN_ERROR);
}