diff --git a/dependency-reduced-pom.xml b/dependency-reduced-pom.xml
index 1a59151..9890175 100644
--- a/dependency-reduced-pom.xml
+++ b/dependency-reduced-pom.xml
@@ -170,6 +170,13 @@
system
${basedir}/libs/TitleManager-2.3.6.jar
+
+ com.github.decentsoftware-eu
+ decentholograms
+ 2.8.6
+ system
+ ${basedir}/libs/DecentHolograms-2.8.6.jar
+
8
diff --git a/src/fr/maxlego08/koth/ZKoth.java b/src/fr/maxlego08/koth/ZKoth.java
index efb656c..647b244 100644
--- a/src/fr/maxlego08/koth/ZKoth.java
+++ b/src/fr/maxlego08/koth/ZKoth.java
@@ -1,9 +1,11 @@
package fr.maxlego08.koth;
import fr.maxlego08.koth.api.Koth;
+import fr.maxlego08.koth.api.KothEvent;
import fr.maxlego08.koth.api.KothStatus;
import fr.maxlego08.koth.api.KothTeam;
import fr.maxlego08.koth.api.KothType;
+import fr.maxlego08.koth.api.discord.DiscordWebhookConfig;
import fr.maxlego08.koth.api.events.KothCapEvent;
import fr.maxlego08.koth.api.events.KothCatchEvent;
import fr.maxlego08.koth.api.events.KothLooseEvent;
@@ -68,8 +70,9 @@ public class ZKoth extends ZUtils implements Koth {
private AtomicInteger remainingSeconds;
private TimerTask timerTask;
private TimerTask timerTaskStop;
+ private DiscordWebhookConfig discordWebhookConfig;
- public ZKoth(KothPlugin plugin, String fileName, KothType kothType, String name, int captureSeconds, Location minLocation, Location maxLocation, List startCommands, List endCommands, ScoreboardConfiguration cooldownScoreboard, ScoreboardConfiguration startScoreboard, int cooldownStart, int stopAfterSeconds, boolean enableStartCapMessage, boolean enableLooseCapMessage, boolean enableEverySecondsCapMessage, HologramConfig hologramConfig) {
+ public ZKoth(KothPlugin plugin, String fileName, KothType kothType, String name, int captureSeconds, Location minLocation, Location maxLocation, List startCommands, List endCommands, ScoreboardConfiguration cooldownScoreboard, ScoreboardConfiguration startScoreboard, int cooldownStart, int stopAfterSeconds, boolean enableStartCapMessage, boolean enableLooseCapMessage, boolean enableEverySecondsCapMessage, HologramConfig hologramConfig, DiscordWebhookConfig discordWebhookConfig) {
this.plugin = plugin;
this.fileName = fileName;
this.kothType = kothType;
@@ -87,6 +90,7 @@ public class ZKoth extends ZUtils implements Koth {
this.enableLooseCapMessage = enableLooseCapMessage;
this.enableEverySecondsCapMessage = enableEverySecondsCapMessage;
this.hologramConfig = hologramConfig;
+ this.discordWebhookConfig = discordWebhookConfig;
}
public ZKoth(KothPlugin plugin, String fileName, KothType kothType, String name, int captureSeconds, Location minLocation, Location maxLocation) {
@@ -105,6 +109,7 @@ public class ZKoth extends ZUtils implements Koth {
this.enableLooseCapMessage = true;
this.enableEverySecondsCapMessage = false;
this.hologramConfig = new HologramConfig(false, new ArrayList<>(), getCenter());
+ this.discordWebhookConfig = null;
}
@Override
@@ -234,10 +239,14 @@ public class ZKoth extends ZUtils implements Koth {
@Override
public void stop() {
+
+ if (this.kothStatus != KothStatus.STOP) return;
+
KothStopEvent event = new KothStopEvent(this);
event.call();
if (event.isCancelled()) return;
+ this.discordWebhookConfig.send(this.plugin, this, KothEvent.STOP);
broadcast(Message.EVENT_STOP);
@@ -279,6 +288,8 @@ public class ZKoth extends ZUtils implements Koth {
if (event.isCancelled()) return;
+ this.discordWebhookConfig.send(this.plugin, this, KothEvent.START);
+
if (this.cooldownScoreboard.isEnable()) {
ScoreBoardManager scoreBoardManager = this.plugin.getScoreBoardManager();
scoreBoardManager.setLinesAndSchedule(onScoreboard());
@@ -324,6 +335,7 @@ public class ZKoth extends ZUtils implements Koth {
event.call();
if (event.isCancelled()) return;
+ this.discordWebhookConfig.send(this.plugin, this, KothEvent.SPAWN);
this.remainingSeconds = new AtomicInteger(this.captureSeconds);
@@ -361,7 +373,7 @@ public class ZKoth extends ZUtils implements Koth {
this.timerTaskStop = new TimerTask() {
@Override
public void run() {
- // plugin.getKothHologram().end(koth);
+ plugin.getKothHologram().end(koth);
Bukkit.getScheduler().runTask(plugin, () -> stop(Bukkit.getConsoleSender()));
}
};
@@ -400,6 +412,8 @@ public class ZKoth extends ZUtils implements Koth {
KothLooseEvent event = new KothLooseEvent(this.currentPlayer, this);
event.call();
+ this.discordWebhookConfig.send(this.plugin, this, KothEvent.LOOSE);
+
if (event.isCancelled()) return;
this.plugin.getKothHologram().update(this);
@@ -433,6 +447,8 @@ public class ZKoth extends ZUtils implements Koth {
return;
}
+ this.discordWebhookConfig.send(this.plugin, this, KothEvent.START_CAP);
+
if (enableStartCapMessage) {
broadcast(Message.EVENT_CATCH);
}
@@ -473,9 +489,9 @@ public class ZKoth extends ZUtils implements Koth {
KothLooseEvent kothLooseEvent = new KothLooseEvent(null, this);
kothLooseEvent.call();
- if (kothLooseEvent.isCancelled()) {
- return;
- }
+ if (kothLooseEvent.isCancelled()) return;
+
+ this.discordWebhookConfig.send(this.plugin, this, KothEvent.LOOSE);
if (this.timerTask != null) {
this.timerTask.cancel();
@@ -533,6 +549,8 @@ public class ZKoth extends ZUtils implements Koth {
if (kothWinEvent.isCancelled()) return;
+ this.discordWebhookConfig.send(this.plugin, this, KothEvent.WIN);
+
this.plugin.getKothHologram().end(this);
task.cancel();
broadcast(Message.EVENT_WIN);
@@ -668,6 +686,8 @@ public class ZKoth extends ZUtils implements Koth {
@Override
public String replaceMessage(String string) {
+ if (string == null) return null;
+
string = string.replace("%playerName%", this.currentPlayer != null ? this.currentPlayer.getName() : Config.noPlayer);
string = string.replace("%teamName%", this.currentPlayer != null ? this.currentPlayer.getName() : Config.noPlayer);
@@ -678,6 +698,11 @@ public class ZKoth extends ZUtils implements Koth {
return replaceKothInformations(string);
}
+ @Override
+ public DiscordWebhookConfig getDiscordWebhookConfig() {
+ return this.discordWebhookConfig;
+ }
+
private String replaceKothInformations(String string) {
Location centerLocation = getCenter();
diff --git a/src/fr/maxlego08/koth/api/Koth.java b/src/fr/maxlego08/koth/api/Koth.java
index ce53cab..dc3dd36 100644
--- a/src/fr/maxlego08/koth/api/Koth.java
+++ b/src/fr/maxlego08/koth/api/Koth.java
@@ -1,6 +1,7 @@
package fr.maxlego08.koth.api;
import fr.maxlego08.koth.KothPlugin;
+import fr.maxlego08.koth.api.discord.DiscordWebhookConfig;
import fr.maxlego08.koth.api.utils.HologramConfig;
import fr.maxlego08.koth.api.utils.ScoreboardConfiguration;
import fr.maxlego08.koth.zcore.utils.Cuboid;
@@ -70,4 +71,6 @@ public interface Koth {
HologramConfig getHologramConfig();
String replaceMessage(String string);
+
+ DiscordWebhookConfig getDiscordWebhookConfig();
}
diff --git a/src/fr/maxlego08/koth/api/KothEvent.java b/src/fr/maxlego08/koth/api/KothEvent.java
new file mode 100644
index 0000000..53635dc
--- /dev/null
+++ b/src/fr/maxlego08/koth/api/KothEvent.java
@@ -0,0 +1,10 @@
+package fr.maxlego08.koth.api;
+
+public enum KothEvent {
+
+ START,
+ STOP,
+ START_CAP,
+ WIN, SPAWN, LOOSE,
+
+}
diff --git a/src/fr/maxlego08/koth/api/discord/DiscordColor.java b/src/fr/maxlego08/koth/api/discord/DiscordColor.java
new file mode 100644
index 0000000..598b9e5
--- /dev/null
+++ b/src/fr/maxlego08/koth/api/discord/DiscordColor.java
@@ -0,0 +1,49 @@
+package fr.maxlego08.koth.api.discord;
+
+import java.awt.Color;
+
+import org.bukkit.configuration.file.YamlConfiguration;
+
+public class DiscordColor {
+
+ private final int r;
+ private final int g;
+ private final int b;
+
+ public DiscordColor(int r, int g, int b) {
+ super();
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ }
+
+ public DiscordColor(YamlConfiguration configuration, String path) {
+ this(configuration.getInt(path + "r"), configuration.getInt(path + "g"), configuration.getInt(path + "b"));
+ }
+
+ /**
+ * @return the r
+ */
+ public int getR() {
+ return r;
+ }
+
+ /**
+ * @return the g
+ */
+ public int getG() {
+ return g;
+ }
+
+ /**
+ * @return the b
+ */
+ public int getB() {
+ return b;
+ }
+
+ public Color getColor() {
+ return new Color(this.r, this.g, this.b);
+ }
+
+}
diff --git a/src/fr/maxlego08/koth/api/discord/DiscordWebhook.java b/src/fr/maxlego08/koth/api/discord/DiscordWebhook.java
new file mode 100644
index 0000000..b98b69f
--- /dev/null
+++ b/src/fr/maxlego08/koth/api/discord/DiscordWebhook.java
@@ -0,0 +1,433 @@
+package fr.maxlego08.koth.api.discord;
+
+import fr.maxlego08.koth.api.Koth;
+import fr.maxlego08.koth.api.KothEvent;
+import fr.maxlego08.koth.zcore.utils.ZUtils;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import javax.net.ssl.HttpsURLConnection;
+import java.awt.*;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Array;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * Class used to execute Discord Webhooks with low effort
+ */
+public class DiscordWebhook extends ZUtils {
+
+ private final String url;
+ private transient final Pattern STRIP_EXTRAS_PATTERN = Pattern.compile("(?i)ยง[0-9A-FK-ORX]");
+ private String content;
+ private String username;
+ private String avatarUrl;
+ private boolean tts;
+ private List embeds = new ArrayList<>();
+
+ /**
+ * Constructs a new DiscordWebhook instance
+ *
+ * @param url The webhook URL obtained in Discord
+ */
+ public DiscordWebhook(String url) {
+ this.url = url;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public void setAvatarUrl(String avatarUrl) {
+ this.avatarUrl = avatarUrl;
+ }
+
+ public void setTts(boolean tts) {
+ this.tts = tts;
+ }
+
+ public void addEmbed(EmbedObject embed) {
+ this.embeds.add(embed);
+ }
+
+ public void execute(Koth koth) throws IOException {
+ if (this.content == null && this.embeds.isEmpty()) {
+ throw new IllegalArgumentException("Set content or add at least one EmbedObject");
+ }
+
+ JSONObject json = new JSONObject();
+
+ if (this.content != null) json.put("content", koth.replaceMessage(this.content));
+ if (this.username != null) json.put("username", koth.replaceMessage(this.username));
+ if (this.avatarUrl != null) json.put("avatar_url", this.avatarUrl);
+ if (this.tts) json.put("tts", true);
+
+ if (!this.embeds.isEmpty()) {
+ List embedObjects = new ArrayList<>();
+
+ for (EmbedObject embed : this.embeds) {
+ JSONObject jsonEmbed = new JSONObject();
+
+ jsonEmbed.put("title", koth.replaceMessage(embed.getTitle()));
+ jsonEmbed.put("description", koth.replaceMessage(embed.getDescription()));
+ jsonEmbed.put("url", koth.replaceMessage(embed.getUrl()));
+
+ if (embed.getColor() != null) {
+ Color color = embed.getColor().getColor();
+ int rgb = color.getRed();
+ rgb = (rgb << 8) + color.getGreen();
+ rgb = (rgb << 8) + color.getBlue();
+
+ jsonEmbed.put("color", rgb);
+ }
+
+ EmbedObject.Footer footer = embed.getFooter();
+ String image = embed.getImage();
+ String thumbnail = embed.getThumbnail();
+ EmbedObject.Author author = embed.getAuthor();
+ List fields = embed.getFields();
+
+ if (footer != null) {
+ JSONObject jsonFooter = new JSONObject();
+ if (footer.getText() != null) {
+ jsonFooter.put("text", koth.replaceMessage(footer.getText()));
+ }
+ if (footer.getIconUrl() != null) {
+ jsonFooter.put("icon_url", koth.replaceMessage(footer.getIconUrl()));
+ }
+ if (footer.getIconUrl() != null || footer.getText() != null) {
+ jsonEmbed.put("footer", jsonFooter);
+ }
+ }
+
+ if (image != null) {
+ JSONObject jsonImage = new JSONObject();
+ jsonImage.put("url", koth.replaceMessage(image));
+ jsonEmbed.put("image", jsonImage);
+ }
+
+ if (thumbnail != null) {
+ JSONObject jsonThumbnail = new JSONObject();
+ jsonThumbnail.put("url", koth.replaceMessage(thumbnail));
+ jsonEmbed.put("thumbnail", jsonThumbnail);
+ }
+
+ if (author != null) {
+
+ if (author.getName() != null && author.getUrl() != null && author.getIconUrl() != null) {
+ JSONObject jsonAuthor = new JSONObject();
+
+ jsonAuthor.put("url", koth.replaceMessage(author.getUrl()));
+ jsonAuthor.put("name", koth.replaceMessage(author.getName()));
+ jsonAuthor.put("icon_url", koth.replaceMessage(author.getIconUrl()));
+
+ jsonEmbed.put("author", jsonAuthor);
+ }
+ }
+
+ List jsonFields = new ArrayList<>();
+ for (EmbedObject.Field field : fields) {
+ JSONObject jsonField = new JSONObject();
+
+ jsonField.put("name", koth.replaceMessage(field.getName()));
+ jsonField.put("value", koth.replaceMessage(field.getValue()));
+ jsonField.put("inline", field.isInline());
+
+ jsonFields.add(jsonField);
+ }
+
+ jsonEmbed.put("fields", jsonFields.toArray());
+ embedObjects.add(jsonEmbed);
+ }
+
+ json.put("embeds", embedObjects.toArray());
+ }
+
+ URL url = new URL(this.url);
+ HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
+ connection.addRequestProperty("Content-Type", "application/json");
+ connection.addRequestProperty("User-Agent", "Java-DiscordWebhook-BY-Gelox_");
+ connection.setDoOutput(true);
+ connection.setRequestMethod("POST");
+
+ OutputStream stream = connection.getOutputStream();
+ stream.write(json.toString().getBytes(StandardCharsets.UTF_8));
+ stream.flush();
+ stream.close();
+
+ connection.getInputStream().close();
+ connection.disconnect();
+ }
+
+ public static class EmbedObject {
+
+ private KothEvent event;
+ private String title;
+ private String description;
+ private String url;
+ private DiscordColor color;
+
+ private Footer footer;
+ private String thumbnail;
+ private String image;
+ private Author author;
+ private List fields = new ArrayList<>();
+
+ public EmbedObject(YamlConfiguration configuration, String path) {
+
+ this.event = KothEvent.valueOf(configuration.getString(path + "event", "START").toUpperCase());
+ this.title = configuration.getString(path + "title", null);
+ this.description = configuration.getString(path + "description", null);
+ this.url = configuration.getString(path + "url", null);
+ this.color = new DiscordColor(configuration, path + "color.");
+ this.footer = new Footer(configuration, path);
+ this.thumbnail = configuration.getString(path + "thumbnail", null);
+ this.image = configuration.getString(path + "image", null);
+ this.author = new Author(configuration, path);
+ List> list = configuration.getList(path + "fields", new ArrayList<>());
+ this.fields = ((List