From a3fe1bf737b7b224da7bea1220a5cbe2ce91ad52 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Elias=20M=C3=BCller?= <elias@elias-mueller.com>
Date: Fri, 29 Dec 2023 01:30:29 +0100
Subject: [PATCH] Event advertisements and bugfixes

---
 .../spawn/appliances/event/Event.java         | 56 +++++++++++++++++--
 .../event/command/EventAdvertiseCommand.java  | 18 ++++++
 .../spawn/appliances/outlawed/Outlawed.java   |  3 +-
 .../spawn/util/text/Countdown.java            |  4 ++
 src/main/resources/plugin.yml                 |  1 +
 5 files changed, 76 insertions(+), 6 deletions(-)
 create mode 100644 src/main/java/eu/mhsl/craftattack/spawn/appliances/event/command/EventAdvertiseCommand.java

diff --git a/src/main/java/eu/mhsl/craftattack/spawn/appliances/event/Event.java b/src/main/java/eu/mhsl/craftattack/spawn/appliances/event/Event.java
index d6580c4..1dad133 100644
--- a/src/main/java/eu/mhsl/craftattack/spawn/appliances/event/Event.java
+++ b/src/main/java/eu/mhsl/craftattack/spawn/appliances/event/Event.java
@@ -5,15 +5,15 @@ import eu.mhsl.craftattack.spawn.Main;
 import eu.mhsl.craftattack.spawn.api.HttpServer;
 import eu.mhsl.craftattack.spawn.appliance.Appliance;
 import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
-import eu.mhsl.craftattack.spawn.appliances.event.command.EventCommand;
-import eu.mhsl.craftattack.spawn.appliances.event.command.EventEndSessionCommand;
-import eu.mhsl.craftattack.spawn.appliances.event.command.EventOpenSessionCommand;
-import eu.mhsl.craftattack.spawn.appliances.event.command.MoveEventVillagerCommand;
+import eu.mhsl.craftattack.spawn.appliances.event.command.*;
 import eu.mhsl.craftattack.spawn.appliances.event.listener.ApplyPendingRewardsListener;
+import eu.mhsl.craftattack.spawn.util.IteratorUtil;
 import eu.mhsl.craftattack.spawn.util.entity.DisplayVillager;
 import eu.mhsl.craftattack.spawn.util.server.PluginMessage;
 import eu.mhsl.craftattack.spawn.util.listener.DismissInventoryOpenFromHolder;
 import eu.mhsl.craftattack.spawn.util.listener.PlayerInteractAtEntityEventListener;
+import eu.mhsl.craftattack.spawn.util.text.ComponentUtil;
+import eu.mhsl.craftattack.spawn.util.text.Countdown;
 import net.kyori.adventure.text.Component;
 import net.kyori.adventure.text.format.NamedTextColor;
 import org.bukkit.Bukkit;
@@ -23,6 +23,7 @@ import org.bukkit.entity.Villager;
 import org.bukkit.event.Listener;
 import org.bukkit.inventory.ItemStack;
 import org.bukkit.inventory.meta.ItemMeta;
+import org.eclipse.jetty.util.security.CertificateUtils;
 import org.jetbrains.annotations.NotNull;
 
 import java.io.IOException;
@@ -34,8 +35,25 @@ import java.net.http.HttpResponse;
 import java.util.*;
 
 public class Event extends Appliance {
+    enum AdvertisementStatus {
+        BEFORE,
+        ADVERTISED,
+        DONE
+    }
+    Countdown advertiseCountdown = new Countdown(
+            120,
+            announcementData -> Component.text()
+                    .append(ComponentUtil.createRainbowText("Event", 30))
+                    .append(Component.text(" Start in ", NamedTextColor.GOLD))
+                    .append(Component.text(announcementData.count(), NamedTextColor.AQUA))
+                    .append(Component.text(" " + announcementData.unit() + "!", NamedTextColor.GOLD))
+                    .build(),
+            component -> IteratorUtil.onlinePlayers(player -> player.sendMessage(component)),
+            () -> this.advertiseStatus = AdvertisementStatus.DONE
+    );
     public DisplayVillager.ConfigBound villager;
     private boolean isOpen = false;
+    private AdvertisementStatus advertiseStatus = AdvertisementStatus.BEFORE;
     private UUID roomId;
     private final HttpClient eventServerClient = HttpClient.newHttpClient();
     private final List<Reward> pendingRewards = new ArrayList<>();
@@ -84,6 +102,16 @@ public class Event extends Appliance {
             return;
         }
 
+        if(!p.hasPermission("admin") && advertiseStatus == AdvertisementStatus.BEFORE) {
+            p.sendMessage(Component.text("Die Event befinden sich noch in der Vorbereitung.", NamedTextColor.RED));
+            return;
+        }
+
+        if(!p.hasPermission("admin") && advertiseStatus == AdvertisementStatus.DONE) {
+            p.sendMessage(Component.text("Die Events laufen bereits. Ein nachträgliches Beitreten ist nicht möglich.", NamedTextColor.RED));
+            return;
+        }
+
         try {
             Main.instance().getLogger().info("Verbinde mit eventserver: " + p.getName());
             p.sendMessage(Component.text("Authentifiziere...", NamedTextColor.GREEN));
@@ -162,6 +190,23 @@ public class Event extends Appliance {
         givenRewards.forEach(this::giveReward);
     }
 
+    public void advertise() {
+        advertiseCountdown.cancelIfRunning();
+        this.advertiseStatus = AdvertisementStatus.ADVERTISED;
+        IteratorUtil.onlinePlayers(player -> {
+            player.sendMessage(
+                    Component.text()
+                            .append(Component.text("-".repeat(10), NamedTextColor.GRAY)).appendNewline()
+                            .append(Component.text("Ein Event wurde gestartet!", NamedTextColor.GOLD)).appendNewline()
+                            .append(Component.text("Nutze "))
+                            .append(Component.text("/event", NamedTextColor.AQUA))
+                            .append(Component.text(", um dem Event beizutreten!")).appendNewline()
+                            .append(Component.text("-".repeat(10), NamedTextColor.GRAY)).appendNewline()
+            );
+        });
+        advertiseCountdown.start();
+    }
+
     @Override
     public void httpApi(HttpServer.ApiBuilder apiBuilder) {
         apiBuilder.post("reward", RewardConfiguration.class, (rewardConfiguration, request) -> {
@@ -176,7 +221,8 @@ public class Event extends Appliance {
                 new EventCommand(),
                 new MoveEventVillagerCommand(),
                 new EventOpenSessionCommand(),
-                new EventEndSessionCommand()
+                new EventEndSessionCommand(),
+                new EventAdvertiseCommand()
         );
     }
 
diff --git a/src/main/java/eu/mhsl/craftattack/spawn/appliances/event/command/EventAdvertiseCommand.java b/src/main/java/eu/mhsl/craftattack/spawn/appliances/event/command/EventAdvertiseCommand.java
new file mode 100644
index 0000000..cfd486a
--- /dev/null
+++ b/src/main/java/eu/mhsl/craftattack/spawn/appliances/event/command/EventAdvertiseCommand.java
@@ -0,0 +1,18 @@
+package eu.mhsl.craftattack.spawn.appliances.event.command;
+
+import eu.mhsl.craftattack.spawn.appliance.ApplianceCommand;
+import eu.mhsl.craftattack.spawn.appliances.event.Event;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.jetbrains.annotations.NotNull;
+
+public class EventAdvertiseCommand extends ApplianceCommand<Event> {
+    public EventAdvertiseCommand() {
+        super("eventAdvertise");
+    }
+
+    @Override
+    protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception {
+        getAppliance().advertise();
+    }
+}
diff --git a/src/main/java/eu/mhsl/craftattack/spawn/appliances/outlawed/Outlawed.java b/src/main/java/eu/mhsl/craftattack/spawn/appliances/outlawed/Outlawed.java
index 2e55f90..cabca11 100644
--- a/src/main/java/eu/mhsl/craftattack/spawn/appliances/outlawed/Outlawed.java
+++ b/src/main/java/eu/mhsl/craftattack/spawn/appliances/outlawed/Outlawed.java
@@ -34,6 +34,7 @@ public class Outlawed extends Appliance {
                 Main.instance(),
                 () -> {
                     playerStatusMap.forEach((player, status) -> {
+                        if(!player.isOnline()) return;
                         if(status != Status.FORCED) return;
                         try {
                             Main.instance().getAppliance(Whitelist.class).integrityCheck(player);
@@ -89,7 +90,7 @@ public class Outlawed extends Appliance {
     public Component getStatusDescription(Status status) {
         return switch (status) {
             case DISABLED -> Component.text("Vogelfreistatus inaktiv: ", NamedTextColor.GREEN)
-                    .append(Component.text("Es gelten die Standart Regeln!", NamedTextColor.GOLD));
+                    .append(Component.text("Es gelten die Standard Regeln!", NamedTextColor.GOLD));
 
             case VOLUNTARILY, FORCED -> Component.text("Vogelfreistatus aktiv: ", NamedTextColor.RED)
                     .append(Component.text("Du darfst von jedem angegriffen und getötet werden!", NamedTextColor.GOLD));
diff --git a/src/main/java/eu/mhsl/craftattack/spawn/util/text/Countdown.java b/src/main/java/eu/mhsl/craftattack/spawn/util/text/Countdown.java
index 5fc8b9a..87ca702 100644
--- a/src/main/java/eu/mhsl/craftattack/spawn/util/text/Countdown.java
+++ b/src/main/java/eu/mhsl/craftattack/spawn/util/text/Countdown.java
@@ -66,6 +66,10 @@ public class Countdown {
         this.current = countdownFrom;
     }
 
+    public void cancelIfRunning() {
+        if(this.running) cancel();
+    }
+
     private void tick() {
         AnnouncementData defaultAnnouncementData = this.defaultAnnouncements.apply(current);
         if(defaultAnnouncementData != null) {
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 9b5866b..a30cb7f 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -23,6 +23,7 @@ commands:
   event:
   eventOpenSession:
   eventEndSession:
+  eventAdvertise:
   help:
   spawn:
   teamspeak: