diff --git a/src/main/java/com/gmail/goosius/siegewar/SiegeController.java b/src/main/java/com/gmail/goosius/siegewar/SiegeController.java index a2d81bad0..864f390e4 100644 --- a/src/main/java/com/gmail/goosius/siegewar/SiegeController.java +++ b/src/main/java/com/gmail/goosius/siegewar/SiegeController.java @@ -17,6 +17,7 @@ import com.gmail.goosius.siegewar.enums.SiegeType; import com.gmail.goosius.siegewar.events.PreSiegeCampEvent; import com.gmail.goosius.siegewar.events.SiegeRemoveEvent; +import com.gmail.goosius.siegewar.events.SiegeCampStartEvent; import com.gmail.goosius.siegewar.events.SiegeWarStartEvent; import com.gmail.goosius.siegewar.settings.SiegeWarSettings; import com.gmail.goosius.siegewar.utils.DataCleanupUtil; @@ -481,7 +482,9 @@ public static void startSiege(Block bannerBlock, SiegeController.setSiege(targetTown, true); SiegeController.putTownInSiegeMap(targetTown, siege); - sendGlobalSiegeStartMessage(siege); + + Translatable startMessage = getGlobalSiegeStartMessage(siege); + Messaging.sendGlobalMessage(startMessage); SiegeWarMoneyUtil.payUpfrontSiegeStartCost(siege); @@ -510,36 +513,35 @@ public static void startSiege(Block bannerBlock, SiegeController.saveSiege(siege); //Call event - Bukkit.getPluginManager().callEvent(new SiegeWarStartEvent(siege, townOfSiegeStarter)); + Bukkit.getPluginManager().callEvent(new SiegeWarStartEvent(siege, townOfSiegeStarter, startMessage.defaultLocale())); } - private static void sendGlobalSiegeStartMessage(Siege siege) { + public static Translatable getGlobalSiegeStartMessage(Siege siege) { switch (siege.getSiegeType()) { - + case REVOLT: + return + Translatable.of("msg_revolt_siege_started", + siege.getTown().getName(), + siege.getAttacker().getName() + ); + default: case CONQUEST: if (siege.getTown().hasNation()) { - Messaging.sendGlobalMessage( + return Translatable.of("msg_conquest_siege_started_nation_town", - siege.getAttacker().getName(), - TownyAPI.getInstance().getTownNationOrNull(siege.getTown()).getName(), - siege.getTown().getName() - )); + siege.getAttacker().getName(), + TownyAPI.getInstance().getTownNationOrNull(siege.getTown()).getName(), + siege.getTown().getName() + ); } else { - Messaging.sendGlobalMessage( + return Translatable.of("msg_conquest_siege_started_neutral_town", - siege.getAttacker().getName(), - siege.getTown().getName() - )); + siege.getAttacker().getName(), + siege.getTown().getName() + ); } - break; - case REVOLT: - Messaging.sendGlobalMessage( - Translatable.of("msg_revolt_siege_started", - siege.getTown().getName(), - siege.getAttacker().getName() - )); - break; + } } @@ -631,10 +633,14 @@ public static void beginSiegeCamp(SiegeCamp camp) throws TownyException { if (SiegeCampUtil.hasFailedCamp(camp.getTargetTown(), camp.getTownOfSiegeStarter())) throw new TownyException(Translatable.of("msg_err_too_soon_since_your_last_siegecamp")); + Translatable translatable = Translatable.of("attacker_has_begun_a_siegecamp_session", camp.getTownOfSiegeStarter(), camp.getTargetTown(), SiegeWarSettings.getSiegeCampPointsForSuccess(), SiegeWarSettings.getSiegeCampDurationInMinutes()); + // Broadcast a message - Messaging.sendGlobalMessage(Translatable.of("attacker_has_begun_a_siegecamp_session", camp.getTownOfSiegeStarter(), camp.getTargetTown(), SiegeWarSettings.getSiegeCampPointsForSuccess(), SiegeWarSettings.getSiegeCampDurationInMinutes())); + Messaging.sendGlobalMessage(translatable); // Add to SiegeCamp list and begin Evaluating this SiegeCamp for success. addSiegeCamp(camp); SiegeWar.getSiegeWar().getScheduler().run(camp.getBannerBlock().getLocation(), ()-> SiegeCampUtil.evaluateCamp(camp, true)); + // Call event + Bukkit.getPluginManager().callEvent(new SiegeCampStartEvent(camp, translatable.defaultLocale())); } } diff --git a/src/main/java/com/gmail/goosius/siegewar/command/SiegeWarAdminCommand.java b/src/main/java/com/gmail/goosius/siegewar/command/SiegeWarAdminCommand.java index c45be2e33..ac1311fd5 100644 --- a/src/main/java/com/gmail/goosius/siegewar/command/SiegeWarAdminCommand.java +++ b/src/main/java/com/gmail/goosius/siegewar/command/SiegeWarAdminCommand.java @@ -617,6 +617,7 @@ private void parseSiegeWarSiegeCommand(CommandSender sender, String[] args) { case "remove": //Remove siege from system SiegeController.removeSiege(siege); + Messaging.sendGlobalMessage(Translatable.of("msg_swa_remove_siege")); Messaging.sendMsg(sender, Translatable.of("msg_swa_remove_siege_success")); return; } diff --git a/src/main/java/com/gmail/goosius/siegewar/events/BattleSessionEndedEvent.java b/src/main/java/com/gmail/goosius/siegewar/events/BattleSessionEndedEvent.java index 830620443..b79ee8b26 100644 --- a/src/main/java/com/gmail/goosius/siegewar/events/BattleSessionEndedEvent.java +++ b/src/main/java/com/gmail/goosius/siegewar/events/BattleSessionEndedEvent.java @@ -1,5 +1,6 @@ package com.gmail.goosius.siegewar.events; +import com.palmergames.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; @@ -8,9 +9,11 @@ public class BattleSessionEndedEvent extends Event { private static final HandlerList handlers = new HandlerList(); + private final String message; - public BattleSessionEndedEvent() { + public BattleSessionEndedEvent(String message) { super(!Bukkit.getServer().isPrimaryThread()); + this.message = message; } @NotNull @@ -22,4 +25,8 @@ public HandlerList getHandlers() { public static HandlerList getHandlerList() { return handlers; } + + public String getMessage() { + return LegacyComponentSerializer.legacySection().deserialize(message).content(); + } } diff --git a/src/main/java/com/gmail/goosius/siegewar/events/BattleSessionStartedEvent.java b/src/main/java/com/gmail/goosius/siegewar/events/BattleSessionStartedEvent.java index d5c940595..706d0b676 100644 --- a/src/main/java/com/gmail/goosius/siegewar/events/BattleSessionStartedEvent.java +++ b/src/main/java/com/gmail/goosius/siegewar/events/BattleSessionStartedEvent.java @@ -1,5 +1,6 @@ package com.gmail.goosius.siegewar.events; +import com.palmergames.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; @@ -8,9 +9,11 @@ public class BattleSessionStartedEvent extends Event { private static final HandlerList handlers = new HandlerList(); + private final String message; - public BattleSessionStartedEvent() { + public BattleSessionStartedEvent(String message) { super(!Bukkit.getServer().isPrimaryThread()); + this.message = message; } @NotNull @@ -23,4 +26,7 @@ public static HandlerList getHandlerList() { return handlers; } + public String getMessage() { + return LegacyComponentSerializer.legacySection().deserialize(message).content(); + } } diff --git a/src/main/java/com/gmail/goosius/siegewar/events/SiegeCampStartEvent.java b/src/main/java/com/gmail/goosius/siegewar/events/SiegeCampStartEvent.java new file mode 100644 index 000000000..f1af2d62d --- /dev/null +++ b/src/main/java/com/gmail/goosius/siegewar/events/SiegeCampStartEvent.java @@ -0,0 +1,77 @@ +package com.gmail.goosius.siegewar.events; +import com.gmail.goosius.siegewar.enums.SiegeType; +import com.gmail.goosius.siegewar.objects.SiegeCamp; +import com.gmail.goosius.siegewar.settings.SiegeWarSettings; +import com.palmergames.adventure.text.serializer.legacy.LegacyComponentSerializer; +import com.palmergames.bukkit.towny.object.Nation; +import com.palmergames.bukkit.towny.object.Town; +import com.palmergames.bukkit.towny.object.TownBlock; +import org.bukkit.Bukkit; +import org.bukkit.block.Block; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +/** + * An event that marks the start of a {@link SiegeCamp}. + * + * SiegeCamps precede Sieges, acting as a minigame of sorts, in which the + * Siege-starter must gain an amount of points: + * {@link SiegeWarSettings#getSiegeCampPointsForSuccess()}, in order for the + * Siege to begin in earnest. This gives towns an opportunity to disrupt two + * friendly towns from acting out a mock-siege, in order to get around being + * sieged by actual enemies. + * + * @author ewof + * @since 2.8.0 + */ +public class SiegeCampStartEvent extends Event { + + private static final HandlerList handlers = new HandlerList(); + private final SiegeCamp siegeCamp; + private final String message; + + public SiegeCampStartEvent(SiegeCamp camp, String message) { + super(!Bukkit.getServer().isPrimaryThread()); + this.siegeCamp = camp; + this.message = message; + } + + @NotNull + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } + + public Town getTownOfSiegeStarter() { + return siegeCamp.getTownOfSiegeStarter(); + } + + public Nation getNation() { + return siegeCamp.getSiegeType().equals(SiegeType.REVOLT) ? (Nation) siegeCamp.getDefender() : (Nation) siegeCamp.getAttacker(); + } + + public Block getFlag() { + return siegeCamp.getBannerBlock(); + } + + public TownBlock getTownBlock() { + return siegeCamp.getTownBlock(); + } + + public Town getTargetTown() { + return siegeCamp.getTargetTown(); + } + + public SiegeType getSiegeType() { + return siegeCamp.getSiegeType(); + } + + public String getMessage() { + return LegacyComponentSerializer.legacySection().deserialize(message).content(); + } +} \ No newline at end of file diff --git a/src/main/java/com/gmail/goosius/siegewar/events/SiegeEndEvent.java b/src/main/java/com/gmail/goosius/siegewar/events/SiegeEndEvent.java index 431360a53..1adee021f 100644 --- a/src/main/java/com/gmail/goosius/siegewar/events/SiegeEndEvent.java +++ b/src/main/java/com/gmail/goosius/siegewar/events/SiegeEndEvent.java @@ -1,10 +1,12 @@ package com.gmail.goosius.siegewar.events; import com.gmail.goosius.siegewar.objects.Siege; +import com.palmergames.bukkit.towny.object.Nation; import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * This event is triggered immediately after a siege ends @@ -27,6 +29,7 @@ public class SiegeEndEvent extends Event { private final String attackerName; private final String defenderName; private final String besiegedTownName; + private final Nation nation; public SiegeEndEvent(Siege siege) { super(!Bukkit.getServer().isPrimaryThread()); @@ -36,6 +39,7 @@ public SiegeEndEvent(Siege siege) { this.attackerName = siege.getAttackerName(); this.defenderName = siege.getDefenderName(); this.besiegedTownName = siege.getTown().getName(); + this.nation = siege.isRevoltSiege() ? siege.getTown().getNationOrNull() : (Nation)siege.getAttackingNationIfPossibleElseTown(); } @NotNull @@ -89,4 +93,8 @@ public String getBesiegedTownName() { public String getDefenderName() { return defenderName; } + + public Nation getNation() { + return nation; + } } diff --git a/src/main/java/com/gmail/goosius/siegewar/events/SiegeRemoveEvent.java b/src/main/java/com/gmail/goosius/siegewar/events/SiegeRemoveEvent.java index 62d7a2083..8962406a7 100644 --- a/src/main/java/com/gmail/goosius/siegewar/events/SiegeRemoveEvent.java +++ b/src/main/java/com/gmail/goosius/siegewar/events/SiegeRemoveEvent.java @@ -1,6 +1,9 @@ package com.gmail.goosius.siegewar.events; import com.gmail.goosius.siegewar.objects.Siege; +import com.palmergames.adventure.text.serializer.legacy.LegacyComponentSerializer; +import com.palmergames.bukkit.towny.object.Nation; +import com.palmergames.bukkit.towny.object.Translatable; import org.bukkit.Bukkit; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; @@ -24,6 +27,7 @@ public class SiegeRemoveEvent extends Event { private final String attackerName; private final String defenderName; private final String besiegedTownName; + private final Nation nation; public SiegeRemoveEvent(Siege siege) { super(!Bukkit.getServer().isPrimaryThread()); @@ -33,6 +37,7 @@ public SiegeRemoveEvent(Siege siege) { this.attackerName = siege.getAttackerName(); this.defenderName = siege.getDefenderName(); this.besiegedTownName = siege.getTown().getName(); + this.nation = siege.isRevoltSiege() ? siege.getTown().getNationOrNull() : (Nation)siege.getAttackingNationIfPossibleElseTown(); } @NotNull @@ -86,4 +91,12 @@ public String getBesiegedTownName() { public String getDefenderName() { return defenderName; } + + public Nation getNation() { + return nation; + } + + public String getMessage() { + return LegacyComponentSerializer.legacySection().deserialize(Translatable.of("msg_swa_remove_siege", getBesiegedTownName()).defaultLocale()).content(); + } } diff --git a/src/main/java/com/gmail/goosius/siegewar/events/SiegeWarStartEvent.java b/src/main/java/com/gmail/goosius/siegewar/events/SiegeWarStartEvent.java index 00ab16ee7..8e9ac2466 100644 --- a/src/main/java/com/gmail/goosius/siegewar/events/SiegeWarStartEvent.java +++ b/src/main/java/com/gmail/goosius/siegewar/events/SiegeWarStartEvent.java @@ -1,6 +1,7 @@ package com.gmail.goosius.siegewar.events; import com.gmail.goosius.siegewar.objects.Siege; +import com.palmergames.adventure.text.serializer.legacy.LegacyComponentSerializer; import com.palmergames.bukkit.towny.object.Nation; import com.palmergames.bukkit.towny.object.Town; import org.bukkit.block.Block; @@ -17,14 +18,16 @@ public class SiegeWarStartEvent extends Event { private final Nation nation; private final Block flag; private final Town targetTown; + private final String message; - public SiegeWarStartEvent(Siege siege, Town townOfSiegeStarter) { + public SiegeWarStartEvent(Siege siege, Town townOfSiegeStarter, String message) { this.siege = siege; this.siegeType = siege.getSiegeType().getName(); this.targetTown = siege.getTown(); this.townOfSiegeStarter = townOfSiegeStarter; this.nation = siege.isRevoltSiege() ? targetTown.getNationOrNull() : (Nation)siege.getAttackingNationIfPossibleElseTown(); this.flag = siege.getFlagLocation().getBlock(); + this.message = message; } @NotNull @@ -60,4 +63,8 @@ public Nation getNation() { public Town getTargetTown() { return targetTown; } + + public String getMessage() { + return LegacyComponentSerializer.legacySection().deserialize(message).content(); + } } diff --git a/src/main/java/com/gmail/goosius/siegewar/listeners/SiegeWarSelfListener.java b/src/main/java/com/gmail/goosius/siegewar/listeners/SiegeWarSelfListener.java index 44f7caaf5..164fe10ec 100644 --- a/src/main/java/com/gmail/goosius/siegewar/listeners/SiegeWarSelfListener.java +++ b/src/main/java/com/gmail/goosius/siegewar/listeners/SiegeWarSelfListener.java @@ -1,13 +1,23 @@ package com.gmail.goosius.siegewar.listeners; +import com.gmail.goosius.siegewar.events.BattleSessionEndedEvent; +import com.gmail.goosius.siegewar.events.BattleSessionPreStartEvent; +import com.gmail.goosius.siegewar.events.BattleSessionStartedEvent; +import com.gmail.goosius.siegewar.events.SiegeCampStartEvent; +import com.gmail.goosius.siegewar.events.SiegeWarStartEvent; +import com.gmail.goosius.siegewar.events.SiegeEndEvent; +import com.gmail.goosius.siegewar.events.SiegeRemoveEvent; +import com.gmail.goosius.siegewar.objects.Siege; +import com.gmail.goosius.siegewar.utils.DiscordWebhook; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import com.gmail.goosius.siegewar.SiegeController; -import com.gmail.goosius.siegewar.events.BattleSessionPreStartEvent; import com.gmail.goosius.siegewar.settings.SiegeWarSettings; import com.palmergames.bukkit.towny.object.Translatable; +import java.awt.Color; + public class SiegeWarSelfListener implements Listener { @EventHandler(ignoreCancelled = true) @@ -18,4 +28,53 @@ public void onBattleSessionPreStart(BattleSessionPreStartEvent event) { event.setCancellationMsg(Translatable.of("battle_session_cancelled_no_sieges").defaultLocale()); } } + + @EventHandler + public void onBattleSessionStarted(BattleSessionStartedEvent event) { + if (!SiegeWarSettings.isDiscordWebhookEnabled() || !SiegeWarSettings.isSessionStartNotificationEnabled()) + return; + + DiscordWebhook.sendWebhookNotification(SiegeWarSettings.getFallbackColor(), event.getMessage()); + } + + @EventHandler + public void onBattleSessionEnded(BattleSessionEndedEvent event) { + if (!SiegeWarSettings.isDiscordWebhookEnabled() || !SiegeWarSettings.isSessionEndNotificationEnabled()) + return; + + DiscordWebhook.sendWebhookNotification(SiegeWarSettings.getFallbackColor(), event.getMessage()); + } + + @EventHandler + public void onSiegeCampStart(SiegeCampStartEvent event) { + if (!SiegeWarSettings.isDiscordWebhookEnabled() || !SiegeWarSettings.isSiegeCampStartNotificationEnabled()) + return; + + DiscordWebhook.sendWebhookNotification(Color.decode("#" + event.getNation().getMapColorHexCode()), event.getMessage()); + } + + @EventHandler + public void onSiegeWarStart(SiegeWarStartEvent event) { + if (!SiegeWarSettings.isDiscordWebhookEnabled() || !SiegeWarSettings.isSiegeStartNotificationEnabled()) + return; + + DiscordWebhook.sendWebhookNotification(Color.decode("#" + event.getNation().getMapColorHexCode()), event.getMessage()); + } + + @EventHandler + public void onSiegeEnd(SiegeEndEvent event) { + Siege siege = event.getSiege(); + if (!SiegeWarSettings.isDiscordWebhookEnabled() || !SiegeWarSettings.isSiegeEndNotificationEnabled()) + return; + + DiscordWebhook.sendWebhookNotification(Color.decode("#" + event.getNation().getMapColorHexCode()), siege.getEndMessage(), siege.getStatus().isActive()); + } + + @EventHandler + public void onSiegeRemove(SiegeRemoveEvent event) { + if (!SiegeWarSettings.isDiscordWebhookEnabled() || !SiegeWarSettings.isSiegeRemoveNotificationEnabled()) + return; + + DiscordWebhook.sendWebhookNotification(Color.decode("#" + event.getNation().getMapColorHexCode()), event.getMessage()); + } } diff --git a/src/main/java/com/gmail/goosius/siegewar/objects/Siege.java b/src/main/java/com/gmail/goosius/siegewar/objects/Siege.java index 65fbdaff8..bcdf672b8 100644 --- a/src/main/java/com/gmail/goosius/siegewar/objects/Siege.java +++ b/src/main/java/com/gmail/goosius/siegewar/objects/Siege.java @@ -4,6 +4,7 @@ import com.gmail.goosius.siegewar.enums.SiegeStatus; import com.gmail.goosius.siegewar.enums.SiegeType; import com.gmail.goosius.siegewar.settings.SiegeWarSettings; +import com.palmergames.adventure.text.serializer.legacy.LegacyComponentSerializer; import com.palmergames.bukkit.towny.TownyAPI; import com.palmergames.bukkit.towny.object.Government; import com.palmergames.bukkit.towny.object.Resident; @@ -58,7 +59,8 @@ public class Siege { private int numberOfBannerControlReversals; private Resident attackingCommander; private Resident defendingCommander; - + private String endMessage; + public Siege(Town town) { this.town = town; siegeType = null; @@ -79,6 +81,7 @@ public Siege(Town town) { numberOfBannerControlReversals = 0; attackingCommander = null; defendingCommander = null; + endMessage = ""; } public Town getTown() { @@ -424,4 +427,12 @@ public Resident getDefendingCommander() { public void setDefendingCommander(Resident defendingCommander) { this.defendingCommander = defendingCommander; } + + public String getEndMessage() { + return LegacyComponentSerializer.legacySection().deserialize(endMessage).content(); + } + + public void setEndMessage(String message) { + this.endMessage = message; + } } \ No newline at end of file diff --git a/src/main/java/com/gmail/goosius/siegewar/playeractions/SurrenderDefence.java b/src/main/java/com/gmail/goosius/siegewar/playeractions/SurrenderDefence.java index b95294d9b..7b53cb60a 100644 --- a/src/main/java/com/gmail/goosius/siegewar/playeractions/SurrenderDefence.java +++ b/src/main/java/com/gmail/goosius/siegewar/playeractions/SurrenderDefence.java @@ -65,6 +65,7 @@ private static Translatable getSurrenderMessage(Siege siege) { key = String.format("msg_%s_siege_attacker_win_result", siege.getSiegeType().toLowerCase()); message.append(Translatable.of(key)); } + siege.setEndMessage(message.defaultLocale()); return message; } } diff --git a/src/main/java/com/gmail/goosius/siegewar/settings/ConfigNodes.java b/src/main/java/com/gmail/goosius/siegewar/settings/ConfigNodes.java index 21547c91e..d928b30e8 100644 --- a/src/main/java/com/gmail/goosius/siegewar/settings/ConfigNodes.java +++ b/src/main/java/com/gmail/goosius/siegewar/settings/ConfigNodes.java @@ -999,6 +999,56 @@ public enum ConfigNodes { "", "# If this value is not blank,", "# Then players attempting general chat during battle sessions, will be directed towards the server discord."), + DISCORD_WEBHOOK( + "discord_webhook", + "", + "", + "", + "############################################################", + "# +------------------------------------------------------+ #", + "# | DISCORD WEBHOOK | #", + "# +------------------------------------------------------+ #", + "############################################################", + ""), + DISCORD_WEBHOOK_ENABLED( + "discord_webhook.enabled", + "false", + "", + "# If this value is true, and a valid webhook is supplied, siegewar notifications will be announced in your discord server!"), + DISCORD_WEBHOOK_URL( + "discord_webhook.url", + "https://discord.com/api/webhooks/SECRET", + "", + "# See discord docs https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks"), + DISCORD_WEBHOOK_FALLBACK_COLOR( + "discord_webhook.fallback_color", + "#FF0000", + "", + "# If a color cannot be determined from a nation or the notification isn't associated with a nation (battle session notifications) the embed will use this color instead."), + DISCORD_WEBHOOK_NOTIFICATION_SESSION_START( + "discord_webhook.notifcation_session_start", + "true", + "# Announce when a battle session starts. Uses msg_war_siege_battle_session_started"), + DISCORD_WEBHOOK_NOTIFICATION_SESSION_END( + "discord_webhook.notifcation_session_end", + "true", + "# Announce when a battle session ends. Uses msg_war_siege_battle_session_ended_*"), + DISCORD_WEBHOOK_NOTIFICATION_SIEGECAMP_START( + "discord_webhook.notifcation_siegecamp_start", + "true", + "# Announce when a siege camp starts. Uses attacker_has_begun_a_siegecamp_session"), + DISCORD_WEBHOOK_NOTIFICATION_SIEGE_START( + "discord_webhook.notifcation_siege_start", + "true", + "# Announce when a siege starts. Uses msg_conquest_siege_started_*"), + DISCORD_WEBHOOK_NOTIFICATION_SIEGE_END( + "discord_webhook.notifcation_siege_end", + "true", + "# Announce when a siege ends. Uses msg_war_siege_battle_session_ended_*"), + DISCORD_WEBHOOK_NOTIFICATION_SIEGE_REMOVE( + "discord_webhook.notifcation_siege_REMOVE", + "true", + "# Announce when a siege is removed. Uses msg_swa_remove_siege_success"), BAD_CONFIG_WARNINGS( "bad_config_warnings", "", diff --git a/src/main/java/com/gmail/goosius/siegewar/settings/SiegeWarSettings.java b/src/main/java/com/gmail/goosius/siegewar/settings/SiegeWarSettings.java index 84ad4a1c2..64d999d0f 100644 --- a/src/main/java/com/gmail/goosius/siegewar/settings/SiegeWarSettings.java +++ b/src/main/java/com/gmail/goosius/siegewar/settings/SiegeWarSettings.java @@ -1,5 +1,6 @@ package com.gmail.goosius.siegewar.settings; +import java.awt.Color; import java.util.List; import java.util.ArrayList; import java.util.Locale; @@ -536,6 +537,42 @@ public static String getToxicityReductionServerDiscordLink() { return Settings.getString(ConfigNodes.TOXICITY_REDUCTION_DISCORD_LINK); } + public static boolean isDiscordWebhookEnabled() { + return Settings.getBoolean(ConfigNodes.DISCORD_WEBHOOK_ENABLED); + } + + public static String getDiscordWebhookUrl() { + return Settings.getString(ConfigNodes.DISCORD_WEBHOOK_URL); + } + + public static Color getFallbackColor() { + return Color.decode(Settings.getString(ConfigNodes.DISCORD_WEBHOOK_FALLBACK_COLOR)); + } + + public static boolean isSessionStartNotificationEnabled() { + return Settings.getBoolean(ConfigNodes.DISCORD_WEBHOOK_NOTIFICATION_SESSION_START); + } + + public static boolean isSessionEndNotificationEnabled() { + return Settings.getBoolean(ConfigNodes.DISCORD_WEBHOOK_NOTIFICATION_SESSION_END); + } + + public static boolean isSiegeCampStartNotificationEnabled() { + return Settings.getBoolean(ConfigNodes.DISCORD_WEBHOOK_NOTIFICATION_SIEGECAMP_START); + } + + public static boolean isSiegeStartNotificationEnabled() { + return Settings.getBoolean(ConfigNodes.DISCORD_WEBHOOK_NOTIFICATION_SIEGE_START); + } + + public static boolean isSiegeEndNotificationEnabled() { + return Settings.getBoolean(ConfigNodes.DISCORD_WEBHOOK_NOTIFICATION_SIEGE_END); + } + + public static boolean isSiegeRemoveNotificationEnabled() { + return Settings.getBoolean(ConfigNodes.DISCORD_WEBHOOK_NOTIFICATION_SIEGE_REMOVE); + } + public static boolean isBadConfigWarningsEnabled() { return Settings.getBoolean(ConfigNodes.BAD_CONFIG_WARNINGS_ENABLED); } diff --git a/src/main/java/com/gmail/goosius/siegewar/timeractions/AttackerTimedWin.java b/src/main/java/com/gmail/goosius/siegewar/timeractions/AttackerTimedWin.java index 964f82b91..b8d1ce00c 100644 --- a/src/main/java/com/gmail/goosius/siegewar/timeractions/AttackerTimedWin.java +++ b/src/main/java/com/gmail/goosius/siegewar/timeractions/AttackerTimedWin.java @@ -51,6 +51,7 @@ private static Translatable getStandardAttackerWinMessage(Siege siege) { //Standard effects message String key2 = String.format("msg_%s_siege_attacker_win_result", siege.getSiegeType().toLowerCase()); message.append(Translatable.of(key2)); + siege.setEndMessage(message.defaultLocale()); return message; } diff --git a/src/main/java/com/gmail/goosius/siegewar/timeractions/DefenderTimedWin.java b/src/main/java/com/gmail/goosius/siegewar/timeractions/DefenderTimedWin.java index 919063eb5..7c610104f 100644 --- a/src/main/java/com/gmail/goosius/siegewar/timeractions/DefenderTimedWin.java +++ b/src/main/java/com/gmail/goosius/siegewar/timeractions/DefenderTimedWin.java @@ -54,6 +54,7 @@ private static Translatable getStandardTimedDefenderWinMessage(Siege siege) { //Standard effects message String key2 = String.format("msg_%s_siege_defender_win_result", siege.getSiegeType().toLowerCase()); message.append(Translatable.of(key2)); + siege.setEndMessage(message.defaultLocale()); return message; } diff --git a/src/main/java/com/gmail/goosius/siegewar/utils/DiscordWebhook.java b/src/main/java/com/gmail/goosius/siegewar/utils/DiscordWebhook.java new file mode 100644 index 000000000..9de6c8d48 --- /dev/null +++ b/src/main/java/com/gmail/goosius/siegewar/utils/DiscordWebhook.java @@ -0,0 +1,410 @@ +package com.gmail.goosius.siegewar.utils; + +import com.gmail.goosius.siegewar.SiegeWar; +import com.gmail.goosius.siegewar.settings.SiegeWarSettings; + +import javax.net.ssl.HttpsURLConnection; +import java.awt.Color; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.reflect.Array; +import java.net.URL; +import java.util.*; + +//https://gist.github.com/k3kdude/fba6f6b37594eae3d6f9475330733bdb + +/** + * Class used to execute Discord Webhooks with low effort + */ +public class DiscordWebhook { + + private final String url; + 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() throws IOException { + if (this.content == null && this.embeds.isEmpty()) { + throw new IllegalArgumentException("Set content or add at least one EmbedObject"); + } + + JSONObject json = new JSONObject(); + + json.put("content", this.content); + json.put("username", this.username); + json.put("avatar_url", this.avatarUrl); + json.put("tts", this.tts); + + if (!this.embeds.isEmpty()) { + List embedObjects = new ArrayList<>(); + + for (EmbedObject embed : this.embeds) { + JSONObject jsonEmbed = new JSONObject(); + + jsonEmbed.put("title", embed.getTitle()); + jsonEmbed.put("description", embed.getDescription()); + jsonEmbed.put("url", embed.getUrl()); + + if (embed.getColor() != null) { + Color color = embed.getColor(); + int rgb = color.getRed(); + rgb = (rgb << 8) + color.getGreen(); + rgb = (rgb << 8) + color.getBlue(); + + jsonEmbed.put("color", rgb); + } + + EmbedObject.Footer footer = embed.getFooter(); + EmbedObject.Image image = embed.getImage(); + EmbedObject.Thumbnail thumbnail = embed.getThumbnail(); + EmbedObject.Author author = embed.getAuthor(); + List fields = embed.getFields(); + + if (footer != null) { + JSONObject jsonFooter = new JSONObject(); + + jsonFooter.put("text", footer.getText()); + jsonFooter.put("icon_url", footer.getIconUrl()); + jsonEmbed.put("footer", jsonFooter); + } + + if (image != null) { + JSONObject jsonImage = new JSONObject(); + + jsonImage.put("url", image.getUrl()); + jsonEmbed.put("image", jsonImage); + } + + if (thumbnail != null) { + JSONObject jsonThumbnail = new JSONObject(); + + jsonThumbnail.put("url", thumbnail.getUrl()); + jsonEmbed.put("thumbnail", jsonThumbnail); + } + + if (author != null) { + JSONObject jsonAuthor = new JSONObject(); + + jsonAuthor.put("name", author.getName()); + jsonAuthor.put("url", author.getUrl()); + jsonAuthor.put("icon_url", author.getIconUrl()); + jsonEmbed.put("author", jsonAuthor); + } + + List jsonFields = new ArrayList<>(); + for (EmbedObject.Field field : fields) { + JSONObject jsonField = new JSONObject(); + + jsonField.put("name", field.getName()); + jsonField.put("value", 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()); + stream.flush(); + stream.close(); + + connection.getInputStream().close(); //I'm not sure why but it doesn't work without getting the InputStream + connection.disconnect(); + } + + public static class EmbedObject { + private String title; + private String description; + private String url; + private Color color; + + private Footer footer; + private Thumbnail thumbnail; + private Image image; + private Author author; + private List fields = new ArrayList<>(); + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public String getUrl() { + return url; + } + + public Color getColor() { + return color; + } + + public Footer getFooter() { + return footer; + } + + public Thumbnail getThumbnail() { + return thumbnail; + } + + public Image getImage() { + return image; + } + + public Author getAuthor() { + return author; + } + + public List getFields() { + return fields; + } + + public EmbedObject setTitle(String title) { + this.title = title; + return this; + } + + public EmbedObject setDescription(String description) { + this.description = description; + return this; + } + + public EmbedObject setUrl(String url) { + this.url = url; + return this; + } + + public EmbedObject setColor(Color color) { + this.color = color; + return this; + } + + public EmbedObject setFooter(String text, String icon) { + this.footer = new Footer(text, icon); + return this; + } + + public EmbedObject setThumbnail(String url) { + this.thumbnail = new Thumbnail(url); + return this; + } + + public EmbedObject setImage(String url) { + this.image = new Image(url); + return this; + } + + public EmbedObject setAuthor(String name, String url, String icon) { + this.author = new Author(name, url, icon); + return this; + } + + public EmbedObject addField(String name, String value, boolean inline) { + this.fields.add(new Field(name, value, inline)); + return this; + } + + private class Footer { + private String text; + private String iconUrl; + + private Footer(String text, String iconUrl) { + this.text = text; + this.iconUrl = iconUrl; + } + + private String getText() { + return text; + } + + private String getIconUrl() { + return iconUrl; + } + } + + private class Thumbnail { + private String url; + + private Thumbnail(String url) { + this.url = url; + } + + private String getUrl() { + return url; + } + } + + private class Image { + private String url; + + private Image(String url) { + this.url = url; + } + + private String getUrl() { + return url; + } + } + + private class Author { + private String name; + private String url; + private String iconUrl; + + private Author(String name, String url, String iconUrl) { + this.name = name; + this.url = url; + this.iconUrl = iconUrl; + } + + private String getName() { + return name; + } + + private String getUrl() { + return url; + } + + private String getIconUrl() { + return iconUrl; + } + } + + private class Field { + private String name; + private String value; + private boolean inline; + + private Field(String name, String value, boolean inline) { + this.name = name; + this.value = value; + this.inline = inline; + } + + private String getName() { + return name; + } + + private String getValue() { + return value; + } + + private boolean isInline() { + return inline; + } + } + } + + private class JSONObject { + + private final HashMap map = new HashMap<>(); + + void put(String key, Object value) { + if (value != null) { + map.put(key, value); + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + Set> entrySet = map.entrySet(); + builder.append("{"); + + int i = 0; + for (Map.Entry entry : entrySet) { + Object val = entry.getValue(); + builder.append(quote(entry.getKey())).append(":"); + + if (val instanceof String) { + builder.append(quote(String.valueOf(val))); + } else if (val instanceof Integer) { + builder.append(Integer.valueOf(String.valueOf(val))); + } else if (val instanceof Boolean) { + builder.append(val); + } else if (val instanceof JSONObject) { + builder.append(val.toString()); + } else if (val.getClass().isArray()) { + builder.append("["); + int len = Array.getLength(val); + for (int j = 0; j < len; j++) { + builder.append(Array.get(val, j).toString()).append(j != len - 1 ? "," : ""); + } + builder.append("]"); + } + + builder.append(++i == entrySet.size() ? "}" : ","); + } + + return builder.toString(); + } + + private String quote(String string) { + return "\"" + string + "\""; + } + } + + public static void sendWebhookNotification(Color color, String message) { + sendWebhookNotification(color, message, true); + } + + public static void sendWebhookNotification(Color color, String message, boolean active) { + DiscordWebhook webhook = new DiscordWebhook(SiegeWarSettings.getDiscordWebhookUrl()); + + webhook.addEmbed(new DiscordWebhook.EmbedObject() + .setColor(color) + .setDescription(message) + ); + try { + webhook.execute(); + } catch (java.io.IOException e) { + if (active) + SiegeWar.getSiegeWar().getLogger().severe(Arrays.toString(e.getStackTrace())); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/gmail/goosius/siegewar/utils/SiegeWarBattleSessionUtil.java b/src/main/java/com/gmail/goosius/siegewar/utils/SiegeWarBattleSessionUtil.java index 79af106a3..866fad16c 100644 --- a/src/main/java/com/gmail/goosius/siegewar/utils/SiegeWarBattleSessionUtil.java +++ b/src/main/java/com/gmail/goosius/siegewar/utils/SiegeWarBattleSessionUtil.java @@ -54,13 +54,13 @@ public static void startBattleSession() { battleSession.setScheduledEndTime(System.currentTimeMillis() + (SiegeWarSettings.getWarSiegeBattleSessionsDurationMinutes() * 60000)); //Clear the scheduled start time battleSession.setScheduledStartTime(null); + //Send global message to let the server know that the battle session started + Translatable message = Translatable.of("msg_war_siege_battle_session_started"); //Send up the Bukkit event for other plugins to listen for. - Bukkit.getPluginManager().callEvent(new BattleSessionStartedEvent()); + Bukkit.getPluginManager().callEvent(new BattleSessionStartedEvent(message.defaultLocale())); //Recalculate recent battle sessions of players try { Thread.sleep(5000); //Sleep to ensure recalculation is good } catch (InterruptedException e) { e.printStackTrace();} - //Send global message to let the server know that the battle session started - Translatable message = Translatable.of("msg_war_siege_battle_session_started"); //If toxicity reduction is enabled, disable the general chat if(SiegeWarSettings.isToxicityReductionEnabled()) { battleSession.setChatDisabled(true); @@ -87,8 +87,12 @@ public static void endBattleSession() { */ for (Siege siege : SiegeController.getSieges()) endBattleSessionForSiege(siege); - - Bukkit.getPluginManager().callEvent(new BattleSessionEndedEvent()); + + StringBuilder message = new StringBuilder(getBattleSessionEndedMessageHeader(battleResults).defaultLocale()); + + getBattleSessionEndedMessageLines(battleResults).forEach(translatable -> message.append("\n").append(translatable.defaultLocale())); + + Bukkit.getPluginManager().callEvent(new BattleSessionEndedEvent(message.toString())); //Send message sendBattleSessionEndedMessage(battleResults); @@ -268,15 +272,29 @@ public static int calculateSiegeBalanceAdjustment(Siege siege) { * with a brief summary of who won any battles which were fought */ private static void sendBattleSessionEndedMessage(Map battleResults) { + Messaging.sendGlobalMessage(getBattleSessionEndedMessageHeader(battleResults),getBattleSessionEndedMessageLines(battleResults)); + } + + /** + * Send message to tell the server the current battle session has ended, + * with a brief summary of who won any battles which were fought + */ + private static Translatable getBattleSessionEndedMessageHeader(Map battleResults) { Translatable header; - List lines = new ArrayList<>(); //Compile message if(battleResults.size() == 0) { - header = Translatable.of("msg_war_siege_battle_session_ended_without_battles"); + return Translatable.of("msg_war_siege_battle_session_ended_without_battles"); } else { - header = Translatable.of("msg_war_siege_battle_session_ended_with_battles"); + return Translatable.of("msg_war_siege_battle_session_ended_with_battles"); + } + } + + private static List getBattleSessionEndedMessageLines(Map battleResults) { + List lines = new ArrayList<>(); + //Compile message + if(battleResults.size() != 0) { Translatable resultLine; for (Map.Entry battleResultEntry : battleResults.entrySet()) { if (battleResultEntry.getValue() > 0) { @@ -297,8 +315,7 @@ private static void sendBattleSessionEndedMessage(Map battleResu lines.add(resultLine); } } - //Send message - Messaging.sendGlobalMessage(header, lines); + return lines; } public static String getFormattedTimeUntilNextBattleSessionStarts() { diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 1cd52f0bf..875ef0e5b 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -653,4 +653,5 @@ msg_err_cannot_spawn_battle_commander_dead: "&cYou cannot spawn to the siege bec msg_err_cannot_spawn_battle_commander_not_in_siegezone: "&cYou cannot spawn to the siege because your team's battle commander is not in the Siege-Zone." msg_err_cannot_spawn_not_in_homeblock: "&cYou must be in your town homeblock to spawn to the siege." - +#Added in 2.8.0 +msg_swa_remove_siege: '&bSiege of %s removed via admin commands.'