From 7b818cb12664d0a123e79996ba5a25b580923cd3 Mon Sep 17 00:00:00 2001 From: Teriuihi Date: Mon, 25 Sep 2023 22:05:29 +0200 Subject: [PATCH] Implemented timer and commands to start/stop the event Prevent players from fishing while the event is not active --- .../com/alttd/fishingevent/FishingEvent.java | 1 - .../fishingevent/commands/FishCommand.java | 6 +- .../commands/fish_subcommands/End.java | 31 ++++++++ .../fish_subcommands/Leaderboard.java | 6 +- .../commands/fish_subcommands/Points.java | 2 +- .../commands/fish_subcommands/Start.java | 48 ++++++++++++ .../alttd/fishingevent/config/Messages.java | 17 +++++ .../fishingevent/listeners/CatchFish.java | 6 ++ .../fishingevent/timer/EventAutoMessages.java | 68 +++++++++++++++++ .../fishingevent/timer/EventManager.java | 76 +++++++++++++++++++ 10 files changed, 255 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/alttd/fishingevent/commands/fish_subcommands/End.java create mode 100644 src/main/java/com/alttd/fishingevent/commands/fish_subcommands/Start.java create mode 100644 src/main/java/com/alttd/fishingevent/timer/EventAutoMessages.java create mode 100644 src/main/java/com/alttd/fishingevent/timer/EventManager.java diff --git a/src/main/java/com/alttd/fishingevent/FishingEvent.java b/src/main/java/com/alttd/fishingevent/FishingEvent.java index 040eafc..6e413d2 100644 --- a/src/main/java/com/alttd/fishingevent/FishingEvent.java +++ b/src/main/java/com/alttd/fishingevent/FishingEvent.java @@ -37,7 +37,6 @@ public final class FishingEvent extends JavaPlugin { } reloadFishConfigs(); registerEvents(getServer().getPluginManager()); - //add a way to stop and start the fishing event and a way to stop all fishing (so 3 modes normal, active, disabled) if (new LoadTask(PointsManagement.getInstance(), this, logger).loadOldPointsData()) logger.info("Loaded old points data"); saveTask = new SaveTask(PointsManagement.getInstance(), this, logger); diff --git a/src/main/java/com/alttd/fishingevent/commands/FishCommand.java b/src/main/java/com/alttd/fishingevent/commands/FishCommand.java index d1d3452..060fcef 100644 --- a/src/main/java/com/alttd/fishingevent/commands/FishCommand.java +++ b/src/main/java/com/alttd/fishingevent/commands/FishCommand.java @@ -1,8 +1,10 @@ package com.alttd.fishingevent.commands; import com.alttd.fishingevent.FishingEvent; +import com.alttd.fishingevent.commands.fish_subcommands.End; import com.alttd.fishingevent.commands.fish_subcommands.Leaderboard; import com.alttd.fishingevent.commands.fish_subcommands.Points; +import com.alttd.fishingevent.commands.fish_subcommands.Start; import com.alttd.fishingevent.config.Messages; import com.alttd.fishingevent.util.Logger; import org.bukkit.command.*; @@ -30,7 +32,9 @@ public class FishCommand implements CommandExecutor, TabExecutor { subCommands = Arrays.asList( new Points(), - new Leaderboard() + new Leaderboard(), + new Start(), + new End() ); } diff --git a/src/main/java/com/alttd/fishingevent/commands/fish_subcommands/End.java b/src/main/java/com/alttd/fishingevent/commands/fish_subcommands/End.java new file mode 100644 index 0000000..044a933 --- /dev/null +++ b/src/main/java/com/alttd/fishingevent/commands/fish_subcommands/End.java @@ -0,0 +1,31 @@ +package com.alttd.fishingevent.commands.fish_subcommands; + +import com.alttd.fishingevent.commands.SubCommand; +import com.alttd.fishingevent.timer.EventManager; +import org.bukkit.command.CommandSender; + +import java.util.List; + +public class End extends SubCommand { + @Override + public boolean onCommand(CommandSender commandSender, String[] args) { + EventManager.getInstance().stop(); + commandSender.sendMiniMessage("Stopped event", null); + return true; + } + + @Override + public String getName() { + return "end"; + } + + @Override + public List getTabComplete(CommandSender commandSender, String[] args) { + return List.of(); + } + + @Override + public String getHelpMessage() { + return "Invalid command use"; + } +} diff --git a/src/main/java/com/alttd/fishingevent/commands/fish_subcommands/Leaderboard.java b/src/main/java/com/alttd/fishingevent/commands/fish_subcommands/Leaderboard.java index 44e6f6e..f07bec2 100644 --- a/src/main/java/com/alttd/fishingevent/commands/fish_subcommands/Leaderboard.java +++ b/src/main/java/com/alttd/fishingevent/commands/fish_subcommands/Leaderboard.java @@ -25,7 +25,7 @@ public class Leaderboard extends SubCommand { component = component.append(Component.newline()).append(MiniMessage.miniMessage().deserialize("'s biggest fish was the at cm", Placeholder.component("player", playerScore.player().displayName()), Placeholder.parsed("length", String.format("%.2f", playerScore.biggestFish())), - Placeholder.parsed("rarity", playerScore.fish().getRarity().displayName()), + Placeholder.unparsed("rarity", playerScore.fish().getRarity().displayName()), Placeholder.component("fish", playerScore.fish().fishName()))); if (playerScore.player().getUniqueId().equals(uuid)) displayPlayerScore = false; @@ -36,7 +36,7 @@ public class Leaderboard extends SubCommand { component = component.append(Component.newline()).append(MiniMessage.miniMessage().deserialize("Your biggest fish was the at cm", Placeholder.component("player", playerScore.player().displayName()), Placeholder.parsed("length", String.format("%.2f", playerScore.biggestFish())), - Placeholder.parsed("rarity", playerScore.fish().getRarity().displayName()), + Placeholder.unparsed("rarity", playerScore.fish().getRarity().displayName()), Placeholder.component("fish", playerScore.fish().fishName()))); } @@ -56,6 +56,6 @@ public class Leaderboard extends SubCommand { @Override public String getHelpMessage() { - return ""; //TODO implement + return "Invalid command use"; } } diff --git a/src/main/java/com/alttd/fishingevent/commands/fish_subcommands/Points.java b/src/main/java/com/alttd/fishingevent/commands/fish_subcommands/Points.java index ee1be2d..d335743 100644 --- a/src/main/java/com/alttd/fishingevent/commands/fish_subcommands/Points.java +++ b/src/main/java/com/alttd/fishingevent/commands/fish_subcommands/Points.java @@ -70,6 +70,6 @@ public class Points extends SubCommand { @Override public String getHelpMessage() { - return ""; //TODO implement + return "Invalid command use"; } } diff --git a/src/main/java/com/alttd/fishingevent/commands/fish_subcommands/Start.java b/src/main/java/com/alttd/fishingevent/commands/fish_subcommands/Start.java new file mode 100644 index 0000000..bab80c3 --- /dev/null +++ b/src/main/java/com/alttd/fishingevent/commands/fish_subcommands/Start.java @@ -0,0 +1,48 @@ +package com.alttd.fishingevent.commands.fish_subcommands; + +import com.alttd.fishingevent.commands.SubCommand; +import com.alttd.fishingevent.timer.EventManager; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import org.bukkit.command.CommandSender; + +import java.time.Duration; +import java.util.List; + +public class Start extends SubCommand { + @Override + public boolean onCommand(CommandSender commandSender, String[] args) { + if (args.length != 2) { + commandSender.sendMiniMessage("Include the time (as an int in minutes)", null); + return true; + } + int minutes; + try { + minutes = Integer.parseInt(args[1]); + } catch (NumberFormatException e) { + commandSender.sendMiniMessage("Include the time (as an int in minutes)", null); + return true; + } + Duration duration = Duration.ofMinutes(minutes); + if (EventManager.getInstance().startEvent(commandSender.getServer(), duration)) { + commandSender.sendMiniMessage("Started event with duration of minutes", Placeholder.parsed("minutes", String.valueOf(minutes))); + } else { + commandSender.sendMiniMessage("Unable to start event", null); + } + return true; + } + + @Override + public String getName() { + return "start"; + } + + @Override + public List getTabComplete(CommandSender commandSender, String[] args) { + return List.of(); + } + + @Override + public String getHelpMessage() { + return "Invalid command use"; + } +} diff --git a/src/main/java/com/alttd/fishingevent/config/Messages.java b/src/main/java/com/alttd/fishingevent/config/Messages.java index d66e2ad..3aea166 100644 --- a/src/main/java/com/alttd/fishingevent/config/Messages.java +++ b/src/main/java/com/alttd/fishingevent/config/Messages.java @@ -130,4 +130,21 @@ public class Messages extends AbstractConfig { UNABLE_TO_UPDATE_ENCHANTMENT = config.getString(prefix, "unable-to-update-enchantment", UNABLE_TO_UPDATE_ENCHANTMENT); } } + + public static class TIMER { + private static final String prefix = "timer."; + + public static String TIME_REMAINING = "There are "; + public static String EVENT_START = "The fishing event has started! It will end in minutes, you will be able to sell your fishes and buy prizes during and after the event."; + public static String EVENT_END = "The Fishing Event has ended! Thank you all for coming and make sure to sell your remaining fish and spend your remaining points on prizes before leaving!\nWinners:"; + public static String WINNER_FORMAT = " with a cm"; + + @SuppressWarnings("unused") + private static void load() { + TIME_REMAINING = config.getString(prefix, "hours-remaining", TIME_REMAINING); + EVENT_START = config.getString(prefix, "event-start", EVENT_START); + EVENT_END = config.getString(prefix, "event-end", EVENT_END); + WINNER_FORMAT = config.getString(prefix, "winner-format", WINNER_FORMAT); + } + } } diff --git a/src/main/java/com/alttd/fishingevent/listeners/CatchFish.java b/src/main/java/com/alttd/fishingevent/listeners/CatchFish.java index 0887a35..1febe80 100644 --- a/src/main/java/com/alttd/fishingevent/listeners/CatchFish.java +++ b/src/main/java/com/alttd/fishingevent/listeners/CatchFish.java @@ -6,6 +6,7 @@ import com.alttd.fishingevent.fish_generator.FishGenerator; import com.alttd.fishingevent.objects.FishType; import com.alttd.fishingevent.points.PointsManagement; import com.alttd.fishingevent.scoreboard.ScoreboardManager; +import com.alttd.fishingevent.timer.EventManager; import com.alttd.fishingevent.util.Logger; import org.bukkit.Location; import org.bukkit.Material; @@ -25,6 +26,7 @@ public class CatchFish implements Listener { private final Logger logger; private final FishGenerator waterFishGenerator; private final PointsManagement pointsManagement; + private final EventManager eventManager = EventManager.getInstance(); public CatchFish(Logger logger, FishGenerator waterFishGenerator, PointsManagement pointsManagement) { this.logger = logger; @@ -35,6 +37,10 @@ public class CatchFish implements Listener { @EventHandler public void onPlayerFish(PlayerFishEvent event) { + if (!eventManager.isRunning()) { + event.setCancelled(true); + return; + } if (event.getState().equals(PlayerFishEvent.State.FISHING)) { //if fishing rod in lava continue else return // logger.debug("% might have caught a lava fish", event.getPlayer().getName()); diff --git a/src/main/java/com/alttd/fishingevent/timer/EventAutoMessages.java b/src/main/java/com/alttd/fishingevent/timer/EventAutoMessages.java new file mode 100644 index 0000000..2fa5019 --- /dev/null +++ b/src/main/java/com/alttd/fishingevent/timer/EventAutoMessages.java @@ -0,0 +1,68 @@ +package com.alttd.fishingevent.timer; + +import com.alttd.fishingevent.config.Messages; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import org.bukkit.Server; + +import java.time.Duration; +import java.time.Instant; +import java.util.List; + +public class EventAutoMessages implements Runnable { + + private final Instant eventStart; + private final Duration eventDuration; + private final Server server; + private Instant lastTimeNotified = Instant.now(); + private final List minutesList = List.of(30, 15, 10, 5, 2, 1); + private final List secondsList = List.of(30, 20, 10); + + public EventAutoMessages(Instant eventStart, Duration eventDuration, Server server) { + this.eventStart = eventStart; + this.eventDuration = eventDuration; + this.server = server; + } + + @Override + public void run() { + Instant currentTime = Instant.now(); + Duration timeElapsed = Duration.between(eventStart, currentTime); + Duration timeRemaining = eventDuration.minus(timeElapsed); + Duration timeSinceLastNotification = Duration.between(lastTimeNotified, currentTime); + + if (timeRemaining.isZero() || timeRemaining.isNegative()) { + EventManager.getInstance().end(server); + return; + } + + // Check if secondsRemaining matches one of the specified intervals + // or if any intervals were missed since the last notification + if (timeSinceLastNotification.toSeconds() > 5 && timeRemaining.toSecondsPart() < 2) { + if (timeRemaining.toHours() > 0) { + printTimeRemaining(timeRemaining); + } else if (minutesList.contains(timeRemaining.toMinutesPart())) { + printTimeRemaining(timeRemaining); + } else if (secondsList.contains(timeRemaining.toSecondsPart())) { + printTimeRemaining(timeRemaining); + } + } else if (timeRemaining.toSeconds() <= 5) { + printTimeRemaining(timeRemaining); + } + } + + private void printTimeRemaining(Duration timeRemaining) { + TagResolver tagResolver; + lastTimeNotified = Instant.now(); + + if (timeRemaining.toHours() > 0) + tagResolver = TagResolver.resolver(Placeholder.parsed("time_unit", "hours"), Placeholder.parsed("time", String.valueOf(timeRemaining.toHoursPart()))); + else if (timeRemaining.toMinutes() > 0) + tagResolver = TagResolver.resolver(Placeholder.parsed("time_unit", "minutes"), Placeholder.parsed("time", String.valueOf(timeRemaining.toMinutesPart()))); + else + tagResolver = TagResolver.resolver(Placeholder.parsed("time_unit", "seconds"), Placeholder.parsed("time", String.valueOf(timeRemaining.toSecondsPart()))); + server.broadcast(MiniMessage.miniMessage().deserialize(Messages.TIMER.TIME_REMAINING, tagResolver)); + } + +} diff --git a/src/main/java/com/alttd/fishingevent/timer/EventManager.java b/src/main/java/com/alttd/fishingevent/timer/EventManager.java new file mode 100644 index 0000000..362f317 --- /dev/null +++ b/src/main/java/com/alttd/fishingevent/timer/EventManager.java @@ -0,0 +1,76 @@ +package com.alttd.fishingevent.timer; + +import com.alttd.fishingevent.config.Messages; +import com.alttd.fishingevent.scoreboard.ScoreboardManager; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; +import org.bukkit.Server; + +import java.time.Duration; +import java.time.Instant; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +public class EventManager { + + private static EventManager instance = null; + private boolean running = false; + private Instant startTime; + private Duration duration; + private EventAutoMessages eventAutoMessages; + private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + + private EventManager() {} + + public static EventManager getInstance() { + if (instance == null) + instance = new EventManager(); + return instance; + } + + public boolean startEvent(Server server, Duration duration) { + if (running) + return false; + running = true; + startTime = Instant.now(); + this.duration = duration; + server.sendMessage(MiniMessage.miniMessage().deserialize(Messages.TIMER.EVENT_START, Placeholder.parsed("minutes", String.valueOf(duration.toMinutes())))); + eventAutoMessages = new EventAutoMessages(startTime, duration, server); + if (scheduler.isShutdown() || scheduler.isTerminated()) + scheduler = Executors.newScheduledThreadPool(1); + scheduler.scheduleAtFixedRate(eventAutoMessages, 5, 1, TimeUnit.SECONDS); + return true; + } + + public boolean isRunning() { + return running; + } + + + public void stop() { + if (!scheduler.isTerminated() && !scheduler.isShutdown()) { + scheduler.shutdownNow(); + } + running = false; + } + + protected void end(Server server) { + if (!scheduler.isTerminated() && !scheduler.isShutdown()) { + scheduler.shutdownNow(); + } + running = false; + AtomicReference message = new AtomicReference<>(MiniMessage.miniMessage().deserialize(Messages.TIMER.EVENT_END)); + ScoreboardManager.getInstance().getTop10().stream().limit(3).forEachOrdered(playerScore -> + message.set(message.get().append(Component.newline()).append(MiniMessage.miniMessage().deserialize(Messages.TIMER.WINNER_FORMAT, TagResolver.resolver( + Placeholder.component("player", playerScore.player().displayName()), + Placeholder.unparsed("rarity", playerScore.fish().getRarity().displayName()), + Placeholder.component("fish", playerScore.fish().fishName()), + Placeholder.parsed("length", String.format("%.2f", playerScore.biggestFish())) + ))))); + server.sendMessage(message.get()); + } +}