From c81a2d21612565be05f22a5e03fc4eda9b462d98 Mon Sep 17 00:00:00 2001 From: lars Date: Fri, 28 Nov 2025 16:52:42 +0100 Subject: [PATCH 01/15] started big events --- event/build.gradle | 9 ++++ .../event/appliances/deathrun/Deathrun.java | 11 ++++ .../appliances/eventController/Event.java | 5 ++ .../eventController/EventController.java | 17 +++++++ .../commands/EventCommand.java | 51 +++++++++++++++++++ settings.gradle | 1 + 6 files changed, 94 insertions(+) create mode 100644 event/build.gradle create mode 100644 event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java create mode 100644 event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java create mode 100644 event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java create mode 100644 event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java diff --git a/event/build.gradle b/event/build.gradle new file mode 100644 index 0000000..fa35910 --- /dev/null +++ b/event/build.gradle @@ -0,0 +1,9 @@ +dependencies { + implementation project(':common') + implementation project(':core') + + compileOnly 'io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT' + compileOnly 'org.geysermc.floodgate:api:2.2.4-SNAPSHOT' + implementation 'org.apache.httpcomponents:httpclient:4.5.14' + implementation 'com.sparkjava:spark-core:2.9.4' +} \ No newline at end of file diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java new file mode 100644 index 0000000..ac2bce0 --- /dev/null +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java @@ -0,0 +1,11 @@ +package eu.mhsl.craftattack.spawn.event.appliances.deathrun; + +import eu.mhsl.craftattack.spawn.core.appliance.Appliance; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.Event; + +public class Deathrun extends Appliance implements Event { + @Override + public String displayName() { + return "Deathrun"; + } +} diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java new file mode 100644 index 0000000..c458d23 --- /dev/null +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java @@ -0,0 +1,5 @@ +package eu.mhsl.craftattack.spawn.event.appliances.eventController; + +public interface Event { + String displayName(); +} diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java new file mode 100644 index 0000000..83d7559 --- /dev/null +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java @@ -0,0 +1,17 @@ +package eu.mhsl.craftattack.spawn.event.appliances.eventController; + +import eu.mhsl.craftattack.spawn.core.appliance.Appliance; +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.commands.EventCommand; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class EventController extends Appliance { + @Override + protected @NotNull List> commands() { + return List.of( + new EventCommand() + ); + } +} diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java new file mode 100644 index 0000000..487b7bb --- /dev/null +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java @@ -0,0 +1,51 @@ +package eu.mhsl.craftattack.spawn.event.appliances.eventController.commands; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.EventController; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class EventCommand extends ApplianceCommand { + public EventCommand() { + super("event"); + } + + @Override + protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if(args.length == 0) throw new Error("No argument selected!"); + + switch(args[0]) { + case "select": { + sender.sendMessage("select"); + break; + } + case "start": { + sender.sendMessage("start"); + break; + } + case "pause": { + sender.sendMessage("pause"); + break; + } + case "resume": { + sender.sendMessage("resume"); + break; + } + case "stop": { + sender.sendMessage("stop"); + break; + } + default: throw new Error("No such option: '%s' !".formatted(args[0])); + } + } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if(args.length == 1) return List.of("select", "start", "pause", "resume", "stop"); + return null; + } +} diff --git a/settings.gradle b/settings.gradle index 9efb310..618596b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,4 +4,5 @@ include 'core' include 'craftattack' include 'common' include 'varo' +include 'event' From f7430c8fc8aa847f18fe28127c9589849236652c Mon Sep 17 00:00:00 2001 From: lars Date: Fri, 28 Nov 2025 21:08:27 +0100 Subject: [PATCH 02/15] added possibility to disable appliances --- .../eu/mhsl/craftattack/spawn/core/Main.java | 38 ++++++++++++++----- .../spawn/core/appliance/Appliance.java | 11 ++++++ .../event/appliances/deathrun/Deathrun.java | 1 + .../appliances/eventController/Event.java | 1 + .../eventController/EventController.java | 24 ++++++++++++ .../commands/EventCommand.java | 25 ++++++------ 6 files changed, 80 insertions(+), 20 deletions(-) diff --git a/core/src/main/java/eu/mhsl/craftattack/spawn/core/Main.java b/core/src/main/java/eu/mhsl/craftattack/spawn/core/Main.java index e666a90..d7feeb3 100644 --- a/core/src/main/java/eu/mhsl/craftattack/spawn/core/Main.java +++ b/core/src/main/java/eu/mhsl/craftattack/spawn/core/Main.java @@ -67,10 +67,13 @@ public final class Main extends JavaPlugin { Main.logger().info(String.format("Loaded %d appliances!", this.appliances.size())); Main.logger().info("Initializing appliances..."); - this.appliances.forEach(appliance -> { - appliance.onEnable(); - appliance.initialize(this); - }); + this.appliances.stream() + .filter(appliance -> { + Appliance.Flags flags = appliance.getClass().getAnnotation(Appliance.Flags.class); + if(flags == null) return true; + return flags.autoload(); + }) + .forEach(appliance -> appliance.enableSequence(this)); Main.logger().info(String.format("Initialized %d appliances!", this.appliances.size())); if(Configuration.pluginConfig.getBoolean("httpServerEnabled", true)) { @@ -85,17 +88,34 @@ public final class Main extends JavaPlugin { @Override public void onDisable() { Main.logger().info("Disabling appliances..."); - this.appliances.forEach(appliance -> { - Main.logger().info("Disabling " + appliance.getClass().getSimpleName()); - appliance.onDisable(); - appliance.destruct(this); - }); + this.appliances.forEach(appliance -> appliance.disableSequence(this)); HandlerList.unregisterAll(this); Bukkit.getScheduler().cancelTasks(this); Main.logger().info("Disabled " + this.appliances.size() + " appliances!"); } + public Appliance restartAppliance(Class applianceClass) { + Appliance oldAppliance = this.appliances.stream() + .filter(appliance -> appliance.getClass().equals(applianceClass)) + .findFirst() + .orElseThrow(); + oldAppliance.disableSequence(this); + this.appliances.remove(oldAppliance); + Appliance newAppliance = this.createApplianceInstance(applianceClass); + this.appliances.add(newAppliance); + newAppliance.enableSequence(this); + return newAppliance; + } + + private Appliance createApplianceInstance(Class applianceClass) { + try { + return applianceClass.getDeclaredConstructor().newInstance(); + } catch(Exception e) { + throw new RuntimeException(String.format("Failed to create instance of '%s'", applianceClass.getName()), e); + } + } + public T getAppliance(Class clazz) { return this.appliances.stream() .filter(clazz::isInstance) diff --git a/core/src/main/java/eu/mhsl/craftattack/spawn/core/appliance/Appliance.java b/core/src/main/java/eu/mhsl/craftattack/spawn/core/appliance/Appliance.java index 9650759..f50da8a 100644 --- a/core/src/main/java/eu/mhsl/craftattack/spawn/core/appliance/Appliance.java +++ b/core/src/main/java/eu/mhsl/craftattack/spawn/core/appliance/Appliance.java @@ -28,6 +28,7 @@ public abstract class Appliance { @Retention(RetentionPolicy.RUNTIME) public @interface Flags { boolean enabled() default true; + boolean autoload() default true; } private String localConfigPath; @@ -104,6 +105,16 @@ public abstract class Appliance { this.listeners.forEach(HandlerList::unregisterAll); } + public void enableSequence(JavaPlugin plugin) { + this.onEnable(); + this.initialize(plugin); + } + + public void disableSequence(JavaPlugin plugin) { + this.onDisable(); + this.destruct(plugin); + } + protected T queryAppliance(Class clazz) { return Main.instance().getAppliance(clazz); } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java index ac2bce0..37bad35 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java @@ -3,6 +3,7 @@ package eu.mhsl.craftattack.spawn.event.appliances.deathrun; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; import eu.mhsl.craftattack.spawn.event.appliances.eventController.Event; +@Appliance.Flags(autoload = false) public class Deathrun extends Appliance implements Event { @Override public String displayName() { diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java index c458d23..1dcc3ed 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java @@ -2,4 +2,5 @@ package eu.mhsl.craftattack.spawn.event.appliances.eventController; public interface Event { String displayName(); + } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java index 83d7559..1c4986b 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java @@ -1,5 +1,6 @@ package eu.mhsl.craftattack.spawn.event.appliances.eventController; +import eu.mhsl.craftattack.spawn.core.Main; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; import eu.mhsl.craftattack.spawn.event.appliances.eventController.commands.EventCommand; @@ -8,6 +9,29 @@ import org.jetbrains.annotations.NotNull; import java.util.List; public class EventController extends Appliance { + private List eventAppliances = null; + + @Override + public void onEnable() { + this.eventAppliances = Main.instance().getAppliances().stream() + .filter(appliance -> appliance instanceof Event) + .toList(); + } + + public List getEventAppliances() { + if(eventAppliances == null) throw new IllegalStateException("Event appliances were not initialized"); + return eventAppliances; + } + + public void enableEvent(Appliance event) { + getEventAppliances().forEach(appliance -> appliance.disableSequence(Main.instance())); + Main.instance().restartAppliance(event.getClass()); + } + + public void disableEvent(Appliance event) { + event.disableSequence(Main.instance()); + } + @Override protected @NotNull List> commands() { return List.of( diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java index 487b7bb..7052233 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java @@ -1,5 +1,6 @@ package eu.mhsl.craftattack.spawn.event.appliances.eventController.commands; +import eu.mhsl.craftattack.spawn.core.appliance.Appliance; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; import eu.mhsl.craftattack.spawn.event.appliances.eventController.EventController; import org.bukkit.command.Command; @@ -24,28 +25,30 @@ public class EventCommand extends ApplianceCommand { break; } case "start": { - sender.sendMessage("start"); - break; - } - case "pause": { - sender.sendMessage("pause"); - break; - } - case "resume": { - sender.sendMessage("resume"); + if(args.length == 1) throw new Error("Not enough arguments for start."); + this.getAppliance().enableEvent(findApplianceFromString(args[1])); break; } case "stop": { - sender.sendMessage("stop"); + if(args.length == 1) throw new Error("Not enough arguments for stop."); + this.getAppliance().disableEvent(findApplianceFromString(args[1])); break; } default: throw new Error("No such option: '%s' !".formatted(args[0])); } } + private Appliance findApplianceFromString(String name) { + System.out.println(this.getAppliance().getEventAppliances()); + return this.getAppliance().getEventAppliances().stream() + .filter(appliance -> appliance.getClass().getSimpleName().equalsIgnoreCase(name)) + .findFirst() + .orElseThrow(); + } + @Override public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - if(args.length == 1) return List.of("select", "start", "pause", "resume", "stop"); + if(args.length == 1) return List.of("select", "start", "stop"); return null; } } From 212f84b6dea988088f463d605a46a624c5941a87 Mon Sep 17 00:00:00 2001 From: lars Date: Sun, 30 Nov 2025 18:07:15 +0100 Subject: [PATCH 03/15] added start, stop and getScore methods to Event --- .../event/appliances/deathrun/Deathrun.java | 34 +++++++++++++++++++ .../appliances/eventController/Event.java | 16 +++++++-- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java index 37bad35..3278d8e 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java @@ -2,9 +2,43 @@ package eu.mhsl.craftattack.spawn.event.appliances.deathrun; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; import eu.mhsl.craftattack.spawn.event.appliances.eventController.Event; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.title.Title; +import org.bukkit.Bukkit; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; @Appliance.Flags(autoload = false) public class Deathrun extends Appliance implements Event { + @Override + public void initialize(@NotNull JavaPlugin plugin) { + World world = Bukkit.getWorlds().getFirst(); + world.getWorldBorder().setCenter(world.getSpawnLocation()); + world.getWorldBorder().setSize(20); + } + + @Override + public void start() { + Title title = Title.title(Component.text("Start"), Component.text("Erreiche die höchste x-Koordinate!")); + Bukkit.getOnlinePlayers().forEach(player -> player.showTitle(title)); + + World world = Bukkit.getWorlds().getFirst(); + world.getWorldBorder().setSize(world.getWorldBorder().getMaxSize()); + } + + @Override + public int getScore(Player p) { + return (int) Math.ceil(p.getLocation().subtract(Bukkit.getWorlds().getFirst().getSpawnLocation()).x()); + } + + @Override + public void stop() { + Title title = Title.title(Component.text("Ende!"), Component.empty()); + Bukkit.getOnlinePlayers().forEach(player -> player.showTitle(title)); + } + @Override public String displayName() { return "Deathrun"; diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java index 1dcc3ed..e05b25b 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java @@ -1,6 +1,18 @@ package eu.mhsl.craftattack.spawn.event.appliances.eventController; -public interface Event { - String displayName(); +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scoreboard.Scoreboard; +public interface Event { + Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard(); + + String displayName(); + void start(); + void stop(); + int getScore(Player p); + + public default void updateSidebar() { + + } } From bff8cf24cd3d32ca74eeb5d996dd7c32723db3ae Mon Sep 17 00:00:00 2001 From: lars Date: Mon, 1 Dec 2025 22:28:15 +0100 Subject: [PATCH 04/15] added AbstractEvent and basic Scoreboard functionality --- .../eu/mhsl/craftattack/spawn/core/Main.java | 5 +- .../event/appliances/deathrun/Deathrun.java | 37 ++++++- .../appliances/deathrun/DeathrunListener.java | 15 +++ .../eventController/AbstractEvent.java | 30 ++++++ .../appliances/eventController/Event.java | 25 +++-- .../eventController/EventController.java | 7 +- .../Scoreboard/EventScoreEntry.java | 6 ++ .../Scoreboard/EventScoreboardBuilder.java | 97 +++++++++++++++++++ .../commands/EventCommand.java | 7 +- 9 files changed, 214 insertions(+), 15 deletions(-) create mode 100644 event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunListener.java create mode 100644 event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java create mode 100644 event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scoreboard/EventScoreEntry.java create mode 100644 event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scoreboard/EventScoreboardBuilder.java diff --git a/core/src/main/java/eu/mhsl/craftattack/spawn/core/Main.java b/core/src/main/java/eu/mhsl/craftattack/spawn/core/Main.java index d7feeb3..a0ace2f 100644 --- a/core/src/main/java/eu/mhsl/craftattack/spawn/core/Main.java +++ b/core/src/main/java/eu/mhsl/craftattack/spawn/core/Main.java @@ -10,6 +10,7 @@ import org.bukkit.plugin.java.JavaPlugin; import org.reflections.Reflections; import java.lang.reflect.ParameterizedType; +import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.logging.Level; @@ -49,7 +50,7 @@ public final class Main extends JavaPlugin { Main.logger().info(String.format("Loaded %d repositories!", this.repositoryLoader.getRepositories().size())); Main.logger().info("Loading appliances..."); - this.appliances = this.findSubtypesOf(Appliance.class).stream() + this.appliances = new ArrayList<>(this.findSubtypesOf(Appliance.class).stream() .filter(applianceClass -> !disabledAppliances.contains(applianceClass.getSimpleName())) .filter(appliance -> { Appliance.Flags flags = appliance.getAnnotation(Appliance.Flags.class); @@ -63,7 +64,7 @@ public final class Main extends JavaPlugin { throw new RuntimeException(String.format("Failed to create instance of '%s'", applianceClass.getName()), e); } }) - .toList(); + .toList()); Main.logger().info(String.format("Loaded %d appliances!", this.appliances.size())); Main.logger().info("Initializing appliances..."); diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java index 3278d8e..c9b8a50 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java @@ -1,22 +1,36 @@ package eu.mhsl.craftattack.spawn.event.appliances.deathrun; +import eu.mhsl.craftattack.spawn.core.Main; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; -import eu.mhsl.craftattack.spawn.event.appliances.eventController.Event; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.AbstractEvent; import net.kyori.adventure.text.Component; import net.kyori.adventure.title.Title; +import net.kyori.adventure.util.Ticks; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.entity.Player; +import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; +import java.util.*; + @Appliance.Flags(autoload = false) -public class Deathrun extends Appliance implements Event { +public class Deathrun extends AbstractEvent { + private int scoreboardUpdateTaskId; + @Override public void initialize(@NotNull JavaPlugin plugin) { World world = Bukkit.getWorlds().getFirst(); world.getWorldBorder().setCenter(world.getSpawnLocation()); world.getWorldBorder().setSize(20); + + this.start(); + } + + @Override + public void onDisable() { + if(this.scoreboardUpdateTaskId != -1) Bukkit.getScheduler().cancelTask(this.scoreboardUpdateTaskId); } @Override @@ -26,6 +40,18 @@ public class Deathrun extends Appliance implements Event { World world = Bukkit.getWorlds().getFirst(); world.getWorldBorder().setSize(world.getWorldBorder().getMaxSize()); + + this.updateScoreboards(); + this.scoreboardUpdateTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask( + Main.instance(), + this::updateScoreboards, + Ticks.TICKS_PER_SECOND, + Ticks.TICKS_PER_SECOND + ); + } + + private void updateScoreboards() { + Bukkit.getOnlinePlayers().forEach(this::updateScoreboard); } @Override @@ -43,4 +69,11 @@ public class Deathrun extends Appliance implements Event { public String displayName() { return "Deathrun"; } + + @Override + protected @NotNull List listeners() { + return List.of( + new DeathrunListener() + ); + } } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunListener.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunListener.java new file mode 100644 index 0000000..cd56f80 --- /dev/null +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunListener.java @@ -0,0 +1,15 @@ +package eu.mhsl.craftattack.spawn.event.appliances.deathrun; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerMoveEvent; + +class DeathrunListener extends ApplianceListener { + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + if(!event.hasChangedPosition()) return; + if(event.getTo().clone().subtract(event.getFrom()).x() == 0) return; + + this.getAppliance().updateScore(event.getPlayer()); + } +} diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java new file mode 100644 index 0000000..5948a09 --- /dev/null +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java @@ -0,0 +1,30 @@ +package eu.mhsl.craftattack.spawn.event.appliances.eventController; + +import eu.mhsl.craftattack.spawn.core.appliance.Appliance; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.Scoreboard.EventScoreEntry; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.Scoreboard.EventScoreboardBuilder; +import org.bukkit.scoreboard.Scoreboard; + +import java.util.*; + +@Appliance.Flags(enabled = false, autoload = false) +public abstract class AbstractEvent extends Appliance implements Event { + private final Map playerScoreboards = new HashMap<>(); + private final List playerScores = new ArrayList<>(); + private final EventScoreboardBuilder scoreboardBuilder = new EventScoreboardBuilder(3, 2, 3); + + @Override + public Map getPlayerScoreboards() { + return this.playerScoreboards; + } + + @Override + public List getPlayerScores() { + return this.playerScores; + } + + @Override + public EventScoreboardBuilder getScoreboardBuilder() { + return this.scoreboardBuilder; + } +} diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java index e05b25b..b3dbb96 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java @@ -1,18 +1,31 @@ package eu.mhsl.craftattack.spawn.event.appliances.eventController; -import org.bukkit.Bukkit; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.Scoreboard.EventScoreEntry; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.Scoreboard.EventScoreboardBuilder; import org.bukkit.entity.Player; import org.bukkit.scoreboard.Scoreboard; -public interface Event { - Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard(); +import java.util.List; +import java.util.Map; +import java.util.UUID; +public interface Event { String displayName(); + Map getPlayerScoreboards(); + List getPlayerScores(); + EventScoreboardBuilder getScoreboardBuilder(); + void start(); void stop(); int getScore(Player p); - - public default void updateSidebar() { - + default void updateScore(Player p) { + System.out.println(this.getPlayerScores().removeIf(entry -> entry.playerUuid().equals(p.getUniqueId()))); + this.getPlayerScores().add(new EventScoreEntry(p.getUniqueId(), p.getName(), this.getScore(p))); + } + default void updateScoreboard(Player p) { + this.updateScore(p); + Scoreboard scoreboard = this.getScoreboardBuilder().buildFor(p, this); + this.getPlayerScoreboards().put(p.getUniqueId(), scoreboard); + p.setScoreboard(scoreboard); } } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java index 1c4986b..0673815 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java @@ -19,13 +19,14 @@ public class EventController extends Appliance { } public List getEventAppliances() { - if(eventAppliances == null) throw new IllegalStateException("Event appliances were not initialized"); - return eventAppliances; + if(this.eventAppliances == null) throw new IllegalStateException("Event appliances were not initialized"); + return this.eventAppliances; } public void enableEvent(Appliance event) { - getEventAppliances().forEach(appliance -> appliance.disableSequence(Main.instance())); + this.getEventAppliances().forEach(appliance -> appliance.disableSequence(Main.instance())); Main.instance().restartAppliance(event.getClass()); +// Main.instance().getAppliance(event.getClass()) } public void disableEvent(Appliance event) { diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scoreboard/EventScoreEntry.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scoreboard/EventScoreEntry.java new file mode 100644 index 0000000..96fa63d --- /dev/null +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scoreboard/EventScoreEntry.java @@ -0,0 +1,6 @@ +package eu.mhsl.craftattack.spawn.event.appliances.eventController.Scoreboard; + +import java.util.UUID; + +public record EventScoreEntry(UUID playerUuid, String name, int score) { +} diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scoreboard/EventScoreboardBuilder.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scoreboard/EventScoreboardBuilder.java new file mode 100644 index 0000000..9ff6871 --- /dev/null +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scoreboard/EventScoreboardBuilder.java @@ -0,0 +1,97 @@ +package eu.mhsl.craftattack.spawn.event.appliances.eventController.Scoreboard; + +import eu.mhsl.craftattack.spawn.event.appliances.eventController.Event; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.scoreboard.DisplaySlot; +import org.bukkit.scoreboard.Objective; +import org.bukkit.scoreboard.Scoreboard; + +import java.util.Comparator; +import java.util.List; +import java.util.stream.IntStream; + +public class EventScoreboardBuilder { + private final int topPlaces; + private final int aroundPlaces; + private final int bottomPlaces; + + public EventScoreboardBuilder(int topPlaces, int aroundPlaces, int bottomPlaces) { + this.topPlaces = topPlaces; + this.aroundPlaces = aroundPlaces; + this.bottomPlaces = bottomPlaces; + } + + public Scoreboard buildFor(Player p, Event event) { + List scoreMap = event.getPlayerScores(); + Scoreboard newScoreboard = Bukkit.getScoreboardManager().getNewScoreboard(); + + Objective objective = newScoreboard.registerNewObjective( + "event", "dummy", + Component.text("Scoreboard %s".formatted(event.displayName()), NamedTextColor.GOLD) + ); + objective.setDisplaySlot(DisplaySlot.SIDEBAR); + + if(scoreMap.isEmpty()) return newScoreboard; + + scoreMap.sort(Comparator.comparingInt(EventScoreEntry::score).reversed()); + System.out.print(scoreMap); + + EventScoreEntry playerScoreEntry = scoreMap.stream() + .filter(entry -> entry.playerUuid().equals(p.getUniqueId())) + .findFirst() + .orElse(null); + if(playerScoreEntry == null) { + playerScoreEntry = new EventScoreEntry(p.getUniqueId(), p.getName(), event.getScore(p)); + scoreMap.add(playerScoreEntry); + } + + int playerIndex = scoreMap.indexOf(playerScoreEntry); + + IntStream topStream = IntStream.range(0, this.topPlaces); + IntStream aroundStream = IntStream.range(playerIndex - this.aroundPlaces, playerIndex + this.aroundPlaces); + IntStream bottomStream = IntStream.range(scoreMap.size() - this.bottomPlaces, scoreMap.size()); + + if(playerIndex <= this.topPlaces + this.aroundPlaces) { + aroundStream = IntStream.empty(); + topStream = IntStream.range(0, playerIndex + this.aroundPlaces); + } + if(playerIndex >= scoreMap.size() - this.bottomPlaces - this.aroundPlaces) { + aroundStream = IntStream.empty(); + bottomStream = IntStream.range(playerIndex - this.aroundPlaces, scoreMap.size()); + } + if(scoreMap.size() <= this.topPlaces + this.aroundPlaces * 2 + this.bottomPlaces + 2) { + topStream = IntStream.range(0, scoreMap.size()); + aroundStream = IntStream.empty(); + bottomStream = IntStream.empty(); + } + + IntStream indices = IntStream.concat( + IntStream.concat(topStream, aroundStream), + bottomStream + ).distinct().sorted(); + + indices.forEach(place -> { + EventScoreEntry entry = scoreMap.get(place); + String line = this.formattedLine(place, entry.name(), entry.score()); + objective.getScore(line).setScore(place); + }); + + return newScoreboard; + } + + private String formattedLine(int place, String name, int score) { + name = this.trimName(name); + return name + ": " + score; + } + + private String trimName(String name) { + if (name == null) return "Unknown"; + if (name.length() > 12) { + return name.substring(0, 12); + } + return name; + } +} diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java index 7052233..a6610ac 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java @@ -26,12 +26,12 @@ public class EventCommand extends ApplianceCommand { } case "start": { if(args.length == 1) throw new Error("Not enough arguments for start."); - this.getAppliance().enableEvent(findApplianceFromString(args[1])); + this.getAppliance().enableEvent(this.findApplianceFromString(args[1])); break; } case "stop": { if(args.length == 1) throw new Error("Not enough arguments for stop."); - this.getAppliance().disableEvent(findApplianceFromString(args[1])); + this.getAppliance().disableEvent(this.findApplianceFromString(args[1])); break; } default: throw new Error("No such option: '%s' !".formatted(args[0])); @@ -49,6 +49,9 @@ public class EventCommand extends ApplianceCommand { @Override public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { if(args.length == 1) return List.of("select", "start", "stop"); + if(args.length == 2) return this.getAppliance().getEventAppliances().stream() + .map(appliance -> appliance.getClass().getSimpleName().toLowerCase()) + .toList(); return null; } } From 6ed48895cab00057e65a8eadc04817659ddb6d4c Mon Sep 17 00:00:00 2001 From: lars Date: Mon, 1 Dec 2025 22:29:13 +0100 Subject: [PATCH 05/15] made appliance ignore destruct when no listeners --- .../java/eu/mhsl/craftattack/spawn/core/appliance/Appliance.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/eu/mhsl/craftattack/spawn/core/appliance/Appliance.java b/core/src/main/java/eu/mhsl/craftattack/spawn/core/appliance/Appliance.java index f50da8a..f59454b 100644 --- a/core/src/main/java/eu/mhsl/craftattack/spawn/core/appliance/Appliance.java +++ b/core/src/main/java/eu/mhsl/craftattack/spawn/core/appliance/Appliance.java @@ -102,6 +102,7 @@ public abstract class Appliance { } public void destruct(@NotNull JavaPlugin plugin) { + if(this.listeners == null) return; this.listeners.forEach(HandlerList::unregisterAll); } From 2ff95f84509f6b025a5621b9bf6389fb80ec77bc Mon Sep 17 00:00:00 2001 From: lars Date: Tue, 2 Dec 2025 12:52:18 +0100 Subject: [PATCH 06/15] changed scoreboard package name to lowercase --- .../spawn/event/appliances/eventController/AbstractEvent.java | 4 ++-- .../spawn/event/appliances/eventController/Event.java | 4 ++-- .../{Scoreboard => scoreboard}/EventScoreEntry.java | 2 +- .../{Scoreboard => scoreboard}/EventScoreboardBuilder.java | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) rename event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/{Scoreboard => scoreboard}/EventScoreEntry.java (91%) rename event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/{Scoreboard => scoreboard}/EventScoreboardBuilder.java (99%) diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java index 5948a09..63ca6ce 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java @@ -1,8 +1,8 @@ package eu.mhsl.craftattack.spawn.event.appliances.eventController; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; -import eu.mhsl.craftattack.spawn.event.appliances.eventController.Scoreboard.EventScoreEntry; -import eu.mhsl.craftattack.spawn.event.appliances.eventController.Scoreboard.EventScoreboardBuilder; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard.EventScoreEntry; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard.EventScoreboardBuilder; import org.bukkit.scoreboard.Scoreboard; import java.util.*; diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java index b3dbb96..8312404 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java @@ -1,7 +1,7 @@ package eu.mhsl.craftattack.spawn.event.appliances.eventController; -import eu.mhsl.craftattack.spawn.event.appliances.eventController.Scoreboard.EventScoreEntry; -import eu.mhsl.craftattack.spawn.event.appliances.eventController.Scoreboard.EventScoreboardBuilder; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard.EventScoreEntry; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard.EventScoreboardBuilder; import org.bukkit.entity.Player; import org.bukkit.scoreboard.Scoreboard; diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scoreboard/EventScoreEntry.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreEntry.java similarity index 91% rename from event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scoreboard/EventScoreEntry.java rename to event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreEntry.java index 96fa63d..3e78218 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scoreboard/EventScoreEntry.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreEntry.java @@ -1,4 +1,4 @@ -package eu.mhsl.craftattack.spawn.event.appliances.eventController.Scoreboard; +package eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard; import java.util.UUID; diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scoreboard/EventScoreboardBuilder.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java similarity index 99% rename from event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scoreboard/EventScoreboardBuilder.java rename to event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java index 9ff6871..c4941f5 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scoreboard/EventScoreboardBuilder.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java @@ -1,4 +1,4 @@ -package eu.mhsl.craftattack.spawn.event.appliances.eventController.Scoreboard; +package eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard; import eu.mhsl.craftattack.spawn.event.appliances.eventController.Event; import net.kyori.adventure.text.Component; From 04cb233604859c8016ef1c63508e775b1d98121a Mon Sep 17 00:00:00 2001 From: lars Date: Fri, 12 Dec 2025 12:09:25 +0100 Subject: [PATCH 07/15] WIP: moved scores and score updates to EventScoreboardBuilder --- .../event/appliances/deathrun/Deathrun.java | 32 ++-------- .../appliances/deathrun/DeathrunListener.java | 15 ----- .../eventController/AbstractEvent.java | 12 +--- .../appliances/eventController/Event.java | 17 +----- .../eventController/EventController.java | 1 - .../scoreboard/EventScoreboardBuilder.java | 60 ++++++++++++++++--- 6 files changed, 59 insertions(+), 78 deletions(-) delete mode 100644 event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunListener.java diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java index c9b8a50..ed6abef 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java @@ -1,15 +1,12 @@ package eu.mhsl.craftattack.spawn.event.appliances.deathrun; -import eu.mhsl.craftattack.spawn.core.Main; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; import eu.mhsl.craftattack.spawn.event.appliances.eventController.AbstractEvent; import net.kyori.adventure.text.Component; import net.kyori.adventure.title.Title; -import net.kyori.adventure.util.Ticks; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.entity.Player; -import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; @@ -17,8 +14,6 @@ import java.util.*; @Appliance.Flags(autoload = false) public class Deathrun extends AbstractEvent { - private int scoreboardUpdateTaskId; - @Override public void initialize(@NotNull JavaPlugin plugin) { World world = Bukkit.getWorlds().getFirst(); @@ -28,11 +23,6 @@ public class Deathrun extends AbstractEvent { this.start(); } - @Override - public void onDisable() { - if(this.scoreboardUpdateTaskId != -1) Bukkit.getScheduler().cancelTask(this.scoreboardUpdateTaskId); - } - @Override public void start() { Title title = Title.title(Component.text("Start"), Component.text("Erreiche die höchste x-Koordinate!")); @@ -41,17 +31,7 @@ public class Deathrun extends AbstractEvent { World world = Bukkit.getWorlds().getFirst(); world.getWorldBorder().setSize(world.getWorldBorder().getMaxSize()); - this.updateScoreboards(); - this.scoreboardUpdateTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask( - Main.instance(), - this::updateScoreboards, - Ticks.TICKS_PER_SECOND, - Ticks.TICKS_PER_SECOND - ); - } - - private void updateScoreboards() { - Bukkit.getOnlinePlayers().forEach(this::updateScoreboard); + this.getScoreboardBuilder().updateScoreboards(); } @Override @@ -66,14 +46,12 @@ public class Deathrun extends AbstractEvent { } @Override - public String displayName() { - return "Deathrun"; + public List getPlayers() { + return List.of(); } @Override - protected @NotNull List listeners() { - return List.of( - new DeathrunListener() - ); + public String displayName() { + return "Deathrun"; } } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunListener.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunListener.java deleted file mode 100644 index cd56f80..0000000 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunListener.java +++ /dev/null @@ -1,15 +0,0 @@ -package eu.mhsl.craftattack.spawn.event.appliances.deathrun; - -import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; -import org.bukkit.event.EventHandler; -import org.bukkit.event.player.PlayerMoveEvent; - -class DeathrunListener extends ApplianceListener { - @EventHandler - public void onPlayerMove(PlayerMoveEvent event) { - if(!event.hasChangedPosition()) return; - if(event.getTo().clone().subtract(event.getFrom()).x() == 0) return; - - this.getAppliance().updateScore(event.getPlayer()); - } -} diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java index 63ca6ce..540974b 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java @@ -11,17 +11,7 @@ import java.util.*; public abstract class AbstractEvent extends Appliance implements Event { private final Map playerScoreboards = new HashMap<>(); private final List playerScores = new ArrayList<>(); - private final EventScoreboardBuilder scoreboardBuilder = new EventScoreboardBuilder(3, 2, 3); - - @Override - public Map getPlayerScoreboards() { - return this.playerScoreboards; - } - - @Override - public List getPlayerScores() { - return this.playerScores; - } + private final EventScoreboardBuilder scoreboardBuilder = new EventScoreboardBuilder(this, 3, 2, 3); @Override public EventScoreboardBuilder getScoreboardBuilder() { diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java index 8312404..70e4f4d 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java @@ -1,31 +1,16 @@ package eu.mhsl.craftattack.spawn.event.appliances.eventController; -import eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard.EventScoreEntry; import eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard.EventScoreboardBuilder; import org.bukkit.entity.Player; -import org.bukkit.scoreboard.Scoreboard; import java.util.List; -import java.util.Map; -import java.util.UUID; public interface Event { String displayName(); - Map getPlayerScoreboards(); - List getPlayerScores(); EventScoreboardBuilder getScoreboardBuilder(); void start(); void stop(); + List getPlayers(); int getScore(Player p); - default void updateScore(Player p) { - System.out.println(this.getPlayerScores().removeIf(entry -> entry.playerUuid().equals(p.getUniqueId()))); - this.getPlayerScores().add(new EventScoreEntry(p.getUniqueId(), p.getName(), this.getScore(p))); - } - default void updateScoreboard(Player p) { - this.updateScore(p); - Scoreboard scoreboard = this.getScoreboardBuilder().buildFor(p, this); - this.getPlayerScoreboards().put(p.getUniqueId(), scoreboard); - p.setScoreboard(scoreboard); - } } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java index 0673815..0e92a99 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java @@ -26,7 +26,6 @@ public class EventController extends Appliance { public void enableEvent(Appliance event) { this.getEventAppliances().forEach(appliance -> appliance.disableSequence(Main.instance())); Main.instance().restartAppliance(event.getClass()); -// Main.instance().getAppliance(event.getClass()) } public void disableEvent(Appliance event) { diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java index c4941f5..80133d4 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java @@ -1,42 +1,58 @@ package eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard; +import eu.mhsl.craftattack.spawn.core.Main; import eu.mhsl.craftattack.spawn.event.appliances.eventController.Event; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.util.Ticks; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.scoreboard.DisplaySlot; import org.bukkit.scoreboard.Objective; import org.bukkit.scoreboard.Scoreboard; -import java.util.Comparator; -import java.util.List; +import java.util.*; import java.util.stream.IntStream; public class EventScoreboardBuilder { private final int topPlaces; private final int aroundPlaces; private final int bottomPlaces; + private final Event event; + private final Comparator scoreComparator; + private final List playerScores = new ArrayList<>(); + private final Map playerScoreboardMap = new HashMap<>(); + private int scoreboardUpdateTaskId = -1; - public EventScoreboardBuilder(int topPlaces, int aroundPlaces, int bottomPlaces) { + public EventScoreboardBuilder(Event event) { + this(event, 3, 2, 3); + } + + public EventScoreboardBuilder(Event event, int topPlaces, int aroundPlaces, int bottomPlaces) { + this(event, topPlaces, aroundPlaces, bottomPlaces, Comparator.comparingInt(EventScoreEntry::score).reversed()); + } + + public EventScoreboardBuilder(Event event, int topPlaces, int aroundPlaces, int bottomPlaces, Comparator scoreComparator) { + this.event = event; this.topPlaces = topPlaces; this.aroundPlaces = aroundPlaces; this.bottomPlaces = bottomPlaces; + this.scoreComparator = scoreComparator; } - public Scoreboard buildFor(Player p, Event event) { - List scoreMap = event.getPlayerScores(); + public Scoreboard buildFor(Player p) { + List scoreMap = this.playerScores; Scoreboard newScoreboard = Bukkit.getScoreboardManager().getNewScoreboard(); Objective objective = newScoreboard.registerNewObjective( "event", "dummy", - Component.text("Scoreboard %s".formatted(event.displayName()), NamedTextColor.GOLD) + Component.text("Scoreboard %s".formatted(this.event.displayName()), NamedTextColor.GOLD) ); objective.setDisplaySlot(DisplaySlot.SIDEBAR); if(scoreMap.isEmpty()) return newScoreboard; - scoreMap.sort(Comparator.comparingInt(EventScoreEntry::score).reversed()); + scoreMap.sort(this.scoreComparator); System.out.print(scoreMap); EventScoreEntry playerScoreEntry = scoreMap.stream() @@ -44,7 +60,7 @@ public class EventScoreboardBuilder { .findFirst() .orElse(null); if(playerScoreEntry == null) { - playerScoreEntry = new EventScoreEntry(p.getUniqueId(), p.getName(), event.getScore(p)); + playerScoreEntry = new EventScoreEntry(p.getUniqueId(), p.getName(), this.event.getScore(p)); scoreMap.add(playerScoreEntry); } @@ -79,9 +95,37 @@ public class EventScoreboardBuilder { objective.getScore(line).setScore(place); }); + this.playerScoreboardMap.put(p.getUniqueId(), newScoreboard); return newScoreboard; } + public void startAutomaticUpdates() { + this.scoreboardUpdateTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask( + Main.instance(), + this::updateScoreboards, + Ticks.TICKS_PER_SECOND, + Ticks.TICKS_PER_SECOND + ); + } + + public void stopAutomaticUpdates() { + if(this.scoreboardUpdateTaskId != -1) Bukkit.getScheduler().cancelTask(this.scoreboardUpdateTaskId); + this.scoreboardUpdateTaskId = -1; + } + + private void updateScore(Player p) { + this.playerScores.removeIf(entry -> entry.playerUuid().equals(p.getUniqueId())); + this.playerScores.add(new EventScoreEntry(p.getUniqueId(), p.getName(), this.event.getScore(p))); + } + + public void updateScoreboards() { + Bukkit.getOnlinePlayers().forEach(player -> { + this.updateScore(player); + Scoreboard scoreboard = this.buildFor(player); + player.setScoreboard(scoreboard); + }); + } + private String formattedLine(int place, String name, int score) { name = this.trimName(name); return name + ": " + score; From dd1518fce4c13410ee8ecfb88c61635330002b6d Mon Sep 17 00:00:00 2001 From: lars Date: Fri, 12 Dec 2025 19:30:21 +0100 Subject: [PATCH 08/15] split Event into Scorable and Event; removed AbstractEvent; added list, select and unselect commands --- .../event/appliances/deathrun/Deathrun.java | 34 +++++++++++-------- .../eventController/AbstractEvent.java | 20 ----------- .../appliances/eventController/Event.java | 10 ------ .../eventController/EventController.java | 31 ++++++++++++++--- .../appliances/eventController/Scorable.java | 10 ++++++ .../commands/EventCommand.java | 24 ++++++++----- .../scoreboard/EventScoreboardBuilder.java | 28 +++++++-------- 7 files changed, 83 insertions(+), 74 deletions(-) delete mode 100644 event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java create mode 100644 event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scorable.java diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java index ed6abef..a88ebfc 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java @@ -1,7 +1,9 @@ package eu.mhsl.craftattack.spawn.event.appliances.deathrun; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; -import eu.mhsl.craftattack.spawn.event.appliances.eventController.AbstractEvent; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.Event; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.Scorable; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard.EventScoreboardBuilder; import net.kyori.adventure.text.Component; import net.kyori.adventure.title.Title; import org.bukkit.Bukkit; @@ -10,17 +12,15 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; -import java.util.*; - @Appliance.Flags(autoload = false) -public class Deathrun extends AbstractEvent { +public class Deathrun extends Appliance implements Event, Scorable { + private final EventScoreboardBuilder scoreboardBuilder = new EventScoreboardBuilder(this, 3, 2, 3); + @Override public void initialize(@NotNull JavaPlugin plugin) { World world = Bukkit.getWorlds().getFirst(); world.getWorldBorder().setCenter(world.getSpawnLocation()); world.getWorldBorder().setSize(20); - - this.start(); } @Override @@ -31,27 +31,31 @@ public class Deathrun extends AbstractEvent { World world = Bukkit.getWorlds().getFirst(); world.getWorldBorder().setSize(world.getWorldBorder().getMaxSize()); - this.getScoreboardBuilder().updateScoreboards(); + this.getScoreboardBuilder().startAutomaticUpdates(); } @Override public int getScore(Player p) { - return (int) Math.ceil(p.getLocation().subtract(Bukkit.getWorlds().getFirst().getSpawnLocation()).x()); + return (int) Math.ceil(p.getLocation().x()); } @Override public void stop() { + this.getScoreboardBuilder().stopAutomaticUpdates(); Title title = Title.title(Component.text("Ende!"), Component.empty()); - Bukkit.getOnlinePlayers().forEach(player -> player.showTitle(title)); + Bukkit.getOnlinePlayers().forEach(player -> { + player.showTitle(title); + player.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard()); + }); } @Override - public List getPlayers() { - return List.of(); - } - - @Override - public String displayName() { + public String getScoreboardName() { return "Deathrun"; } + + @Override + public EventScoreboardBuilder getScoreboardBuilder() { + return this.scoreboardBuilder; + } } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java deleted file mode 100644 index 540974b..0000000 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/AbstractEvent.java +++ /dev/null @@ -1,20 +0,0 @@ -package eu.mhsl.craftattack.spawn.event.appliances.eventController; - -import eu.mhsl.craftattack.spawn.core.appliance.Appliance; -import eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard.EventScoreEntry; -import eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard.EventScoreboardBuilder; -import org.bukkit.scoreboard.Scoreboard; - -import java.util.*; - -@Appliance.Flags(enabled = false, autoload = false) -public abstract class AbstractEvent extends Appliance implements Event { - private final Map playerScoreboards = new HashMap<>(); - private final List playerScores = new ArrayList<>(); - private final EventScoreboardBuilder scoreboardBuilder = new EventScoreboardBuilder(this, 3, 2, 3); - - @Override - public EventScoreboardBuilder getScoreboardBuilder() { - return this.scoreboardBuilder; - } -} diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java index 70e4f4d..d457efa 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java @@ -1,16 +1,6 @@ package eu.mhsl.craftattack.spawn.event.appliances.eventController; -import eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard.EventScoreboardBuilder; -import org.bukkit.entity.Player; - -import java.util.List; - public interface Event { - String displayName(); - EventScoreboardBuilder getScoreboardBuilder(); - void start(); void stop(); - List getPlayers(); - int getScore(Player p); } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java index 0e92a99..f11f6af 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java @@ -6,10 +6,12 @@ import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; import eu.mhsl.craftattack.spawn.event.appliances.eventController.commands.EventCommand; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; import java.util.List; public class EventController extends Appliance { private List eventAppliances = null; + private final List selectedEvents = new ArrayList<>(); @Override public void onEnable() { @@ -23,13 +25,32 @@ public class EventController extends Appliance { return this.eventAppliances; } - public void enableEvent(Appliance event) { - this.getEventAppliances().forEach(appliance -> appliance.disableSequence(Main.instance())); - Main.instance().restartAppliance(event.getClass()); + public void loadEvent(Appliance appliance) { + if(!(appliance instanceof Event event)) throw new IllegalArgumentException("Appliance has to implement Event."); + this.getEventAppliances().forEach(appliance1 -> appliance1.disableSequence(Main.instance())); + Main.instance().restartAppliance(appliance.getClass()); + this.selectedEvents.add(event); } - public void disableEvent(Appliance event) { - event.disableSequence(Main.instance()); + public void unloadEvent(Appliance appliance) { + if(!(appliance instanceof Event event)) throw new Error("Appliance does not implement Event."); + event.stop(); + appliance.disableSequence(Main.instance()); + this.selectedEvents.remove(event); + } + + public void startEvents() { + this.selectedEvents.forEach(Event::start); + } + + public void stopEvents() { + this.selectedEvents.forEach(Event::stop); + } + + public List getSelectedEvents() { + return this.selectedEvents.stream() + .map(event -> event.getClass().getSimpleName().toLowerCase()) + .toList(); } @Override diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scorable.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scorable.java new file mode 100644 index 0000000..6b0ebd9 --- /dev/null +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scorable.java @@ -0,0 +1,10 @@ +package eu.mhsl.craftattack.spawn.event.appliances.eventController; + +import eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard.EventScoreboardBuilder; +import org.bukkit.entity.Player; + +public interface Scorable { + String getScoreboardName(); + EventScoreboardBuilder getScoreboardBuilder(); + int getScore(Player p); +} diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java index a6610ac..826bdbd 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java @@ -20,18 +20,26 @@ public class EventCommand extends ApplianceCommand { if(args.length == 0) throw new Error("No argument selected!"); switch(args[0]) { + case "unselect": { + if(args.length == 1) throw new Error("Not enough arguments for unselect."); + this.getAppliance().unloadEvent(this.findApplianceFromString(args[1])); + break; + } case "select": { - sender.sendMessage("select"); + if(args.length == 1) throw new Error("Not enough arguments for select."); + this.getAppliance().loadEvent(this.findApplianceFromString(args[1])); + break; + } + case "list": { + sender.sendMessage("These Events are currently selected: \n%s".formatted(this.getAppliance().getSelectedEvents())); break; } case "start": { - if(args.length == 1) throw new Error("Not enough arguments for start."); - this.getAppliance().enableEvent(this.findApplianceFromString(args[1])); + this.getAppliance().startEvents(); break; } case "stop": { - if(args.length == 1) throw new Error("Not enough arguments for stop."); - this.getAppliance().disableEvent(this.findApplianceFromString(args[1])); + this.getAppliance().stopEvents(); break; } default: throw new Error("No such option: '%s' !".formatted(args[0])); @@ -43,13 +51,13 @@ public class EventCommand extends ApplianceCommand { return this.getAppliance().getEventAppliances().stream() .filter(appliance -> appliance.getClass().getSimpleName().equalsIgnoreCase(name)) .findFirst() - .orElseThrow(); + .orElseThrow(() -> new Error("Event appliance '%s' not found.".formatted(name))); } @Override public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - if(args.length == 1) return List.of("select", "start", "stop"); - if(args.length == 2) return this.getAppliance().getEventAppliances().stream() + if(args.length == 1) return List.of("select", "unselect", "list", "start", "stop"); + if(args.length == 2 && List.of("select", "unselect").contains(args[0])) return this.getAppliance().getEventAppliances().stream() .map(appliance -> appliance.getClass().getSimpleName().toLowerCase()) .toList(); return null; diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java index 80133d4..187d4cd 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java @@ -1,7 +1,8 @@ package eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard; import eu.mhsl.craftattack.spawn.core.Main; -import eu.mhsl.craftattack.spawn.event.appliances.eventController.Event; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.Scorable; +import io.papermc.paper.scoreboard.numbers.NumberFormat; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.util.Ticks; @@ -18,22 +19,17 @@ public class EventScoreboardBuilder { private final int topPlaces; private final int aroundPlaces; private final int bottomPlaces; - private final Event event; + private final Scorable scorable; private final Comparator scoreComparator; private final List playerScores = new ArrayList<>(); - private final Map playerScoreboardMap = new HashMap<>(); private int scoreboardUpdateTaskId = -1; - public EventScoreboardBuilder(Event event) { - this(event, 3, 2, 3); + public EventScoreboardBuilder(Scorable scorable, int topPlaces, int aroundPlaces, int bottomPlaces) { + this(scorable, topPlaces, aroundPlaces, bottomPlaces, Comparator.comparingInt(EventScoreEntry::score).reversed()); } - public EventScoreboardBuilder(Event event, int topPlaces, int aroundPlaces, int bottomPlaces) { - this(event, topPlaces, aroundPlaces, bottomPlaces, Comparator.comparingInt(EventScoreEntry::score).reversed()); - } - - public EventScoreboardBuilder(Event event, int topPlaces, int aroundPlaces, int bottomPlaces, Comparator scoreComparator) { - this.event = event; + public EventScoreboardBuilder(Scorable scorable, int topPlaces, int aroundPlaces, int bottomPlaces, Comparator scoreComparator) { + this.scorable = scorable; this.topPlaces = topPlaces; this.aroundPlaces = aroundPlaces; this.bottomPlaces = bottomPlaces; @@ -46,9 +42,10 @@ public class EventScoreboardBuilder { Objective objective = newScoreboard.registerNewObjective( "event", "dummy", - Component.text("Scoreboard %s".formatted(this.event.displayName()), NamedTextColor.GOLD) + Component.text("Scoreboard %s".formatted(this.scorable.getScoreboardName()), NamedTextColor.GOLD) ); objective.setDisplaySlot(DisplaySlot.SIDEBAR); + objective.numberFormat(NumberFormat.blank()); if(scoreMap.isEmpty()) return newScoreboard; @@ -60,7 +57,7 @@ public class EventScoreboardBuilder { .findFirst() .orElse(null); if(playerScoreEntry == null) { - playerScoreEntry = new EventScoreEntry(p.getUniqueId(), p.getName(), this.event.getScore(p)); + playerScoreEntry = new EventScoreEntry(p.getUniqueId(), p.getName(), this.scorable.getScore(p)); scoreMap.add(playerScoreEntry); } @@ -95,7 +92,6 @@ public class EventScoreboardBuilder { objective.getScore(line).setScore(place); }); - this.playerScoreboardMap.put(p.getUniqueId(), newScoreboard); return newScoreboard; } @@ -115,7 +111,7 @@ public class EventScoreboardBuilder { private void updateScore(Player p) { this.playerScores.removeIf(entry -> entry.playerUuid().equals(p.getUniqueId())); - this.playerScores.add(new EventScoreEntry(p.getUniqueId(), p.getName(), this.event.getScore(p))); + this.playerScores.add(new EventScoreEntry(p.getUniqueId(), p.getName(), this.scorable.getScore(p))); } public void updateScoreboards() { @@ -128,7 +124,7 @@ public class EventScoreboardBuilder { private String formattedLine(int place, String name, int score) { name = this.trimName(name); - return name + ": " + score; + return "%s. %s: %s".formatted(place+1, name, score); } private String trimName(String name) { From ec262710ecb590990cebef8196595538cf002872 Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 13 Dec 2025 13:50:42 +0100 Subject: [PATCH 09/15] removed possibility for multiple events --- .../event/appliances/deathrun/Deathrun.java | 6 ++++ .../eventController/EventController.java | 36 ++++++++++--------- .../commands/EventCommand.java | 19 +++++----- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java index a88ebfc..4f053ba 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java @@ -23,6 +23,12 @@ public class Deathrun extends Appliance implements Event, Scorable { world.getWorldBorder().setSize(20); } + @Override + public void onDisable() { + World world = Bukkit.getWorlds().getFirst(); + world.getWorldBorder().setSize(world.getWorldBorder().getMaxSize()); + } + @Override public void start() { Title title = Title.title(Component.text("Start"), Component.text("Erreiche die höchste x-Koordinate!")); diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java index f11f6af..de70211 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java @@ -6,12 +6,11 @@ import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; import eu.mhsl.craftattack.spawn.event.appliances.eventController.commands.EventCommand; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; import java.util.List; public class EventController extends Appliance { private List eventAppliances = null; - private final List selectedEvents = new ArrayList<>(); + private Event selectedEvent = null; @Override public void onEnable() { @@ -27,30 +26,33 @@ public class EventController extends Appliance { public void loadEvent(Appliance appliance) { if(!(appliance instanceof Event event)) throw new IllegalArgumentException("Appliance has to implement Event."); - this.getEventAppliances().forEach(appliance1 -> appliance1.disableSequence(Main.instance())); + this.unloadEvent(); Main.instance().restartAppliance(appliance.getClass()); - this.selectedEvents.add(event); + this.selectedEvent = event; } - public void unloadEvent(Appliance appliance) { - if(!(appliance instanceof Event event)) throw new Error("Appliance does not implement Event."); - event.stop(); - appliance.disableSequence(Main.instance()); - this.selectedEvents.remove(event); + public void unloadEvent() { + if(this.selectedEvent == null) return; + this.selectedEvent.stop(); + if(this.selectedEvent instanceof Appliance appliance) { + appliance.disableSequence(Main.instance()); + } + this.selectedEvent = null; } - public void startEvents() { - this.selectedEvents.forEach(Event::start); + public void startEvent() { + if(this.selectedEvent == null) throw new ApplianceCommand.Error("There is no event selected!"); + this.selectedEvent.start(); } - public void stopEvents() { - this.selectedEvents.forEach(Event::stop); + public void stopEvent() { + if(this.selectedEvent == null) throw new ApplianceCommand.Error("There is no event selected!"); + this.selectedEvent.stop(); } - public List getSelectedEvents() { - return this.selectedEvents.stream() - .map(event -> event.getClass().getSimpleName().toLowerCase()) - .toList(); + public String getSelectedEvent() { + if(this.selectedEvent == null) return "nothing selected"; + return this.selectedEvent.getClass().getSimpleName().toLowerCase(); } @Override diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java index 826bdbd..a3aa611 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java @@ -20,26 +20,25 @@ public class EventCommand extends ApplianceCommand { if(args.length == 0) throw new Error("No argument selected!"); switch(args[0]) { - case "unselect": { - if(args.length == 1) throw new Error("Not enough arguments for unselect."); - this.getAppliance().unloadEvent(this.findApplianceFromString(args[1])); + case "unload": { + this.getAppliance().unloadEvent(); break; } - case "select": { + case "load": { if(args.length == 1) throw new Error("Not enough arguments for select."); this.getAppliance().loadEvent(this.findApplianceFromString(args[1])); break; } - case "list": { - sender.sendMessage("These Events are currently selected: \n%s".formatted(this.getAppliance().getSelectedEvents())); + case "selected": { + sender.sendMessage("This Event is currently selected: %s".formatted(this.getAppliance().getSelectedEvent())); break; } case "start": { - this.getAppliance().startEvents(); + this.getAppliance().startEvent(); break; } case "stop": { - this.getAppliance().stopEvents(); + this.getAppliance().stopEvent(); break; } default: throw new Error("No such option: '%s' !".formatted(args[0])); @@ -56,8 +55,8 @@ public class EventCommand extends ApplianceCommand { @Override public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { - if(args.length == 1) return List.of("select", "unselect", "list", "start", "stop"); - if(args.length == 2 && List.of("select", "unselect").contains(args[0])) return this.getAppliance().getEventAppliances().stream() + if(args.length == 1) return List.of("load", "unload", "selected", "start", "stop"); + if(args.length == 2 && args[0].equals("load")) return this.getAppliance().getEventAppliances().stream() .map(appliance -> appliance.getClass().getSimpleName().toLowerCase()) .toList(); return null; From 914aaff10bfcaba05798b2caafef344b2f11926f Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 13 Dec 2025 16:02:23 +0100 Subject: [PATCH 10/15] added deathrun listener for border; fixed listener problem when disabling appliance --- .../event/appliances/deathrun/Deathrun.java | 31 ++++++++++++++-- .../deathrun/DeathrunPlayerMoveListener.java | 35 +++++++++++++++++++ .../eventController/EventController.java | 7 ++-- 3 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunPlayerMoveListener.java diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java index 4f053ba..ca59167 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java @@ -7,22 +7,42 @@ import eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard.Eve import net.kyori.adventure.text.Component; import net.kyori.adventure.title.Title; import org.bukkit.Bukkit; +import org.bukkit.Particle; import org.bukkit.World; import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.event.Listener; import org.jetbrains.annotations.NotNull; +import java.util.List; + @Appliance.Flags(autoload = false) public class Deathrun extends Appliance implements Event, Scorable { private final EventScoreboardBuilder scoreboardBuilder = new EventScoreboardBuilder(this, 3, 2, 3); + private final double borderDistance = 100; @Override - public void initialize(@NotNull JavaPlugin plugin) { + public void onEnable() { World world = Bukkit.getWorlds().getFirst(); world.getWorldBorder().setCenter(world.getSpawnLocation()); world.getWorldBorder().setSize(20); } + public double getBorderDistance() { + return this.borderDistance; + } + + public void spawnParticleWall(Player p, double xMin, double xMax, double yMin, double yMax, double zMin, double zMax) { + Particle particle = Particle.WAX_ON; + + for (double y = yMin; y <= yMax; y += 0.5) { + for (double z = zMin; z <= zMax; z += 0.5) { + for (double x = xMin; x <= xMax; x += 0.5) { + p.spawnParticle(particle, x, y, z, 1, 0.05, 0.05, 0.05, 0); + } + } + } + } + @Override public void onDisable() { World world = Bukkit.getWorlds().getFirst(); @@ -64,4 +84,11 @@ public class Deathrun extends Appliance implements Event, Scorable { public EventScoreboardBuilder getScoreboardBuilder() { return this.scoreboardBuilder; } + + @Override + protected @NotNull List listeners() { + return List.of( + new DeathrunPlayerMoveListener() + ); + } } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunPlayerMoveListener.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunPlayerMoveListener.java new file mode 100644 index 0000000..45941fd --- /dev/null +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunPlayerMoveListener.java @@ -0,0 +1,35 @@ +package eu.mhsl.craftattack.spawn.event.appliances.deathrun; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerMoveEvent; + +public class DeathrunPlayerMoveListener extends ApplianceListener { + @EventHandler + public void onPlayerMove(PlayerMoveEvent event) { + Location spawnLocation = Bukkit.getWorlds().getFirst().getSpawnLocation(); + double minX = spawnLocation.x() - this.getAppliance().getBorderDistance(); + double minZ = spawnLocation.z() - this.getAppliance().getBorderDistance(); + double maxZ = spawnLocation.z() + this.getAppliance().getBorderDistance(); + if(event.getTo().x() < minX + 5) { + this.getAppliance().spawnParticleWall(event.getPlayer(), minX-0.2, minX-0.2, event.getTo().y()-0.5, event.getTo().y()+2.5, event.getTo().z()-1.5, event.getTo().z()+1.5); + if(event.getTo().x() < minX) { + event.setTo(event.getTo().clone().set(minX, event.getTo().y(), event.getTo().z())); + } + } + if(event.getTo().z() < minZ + 5) { + this.getAppliance().spawnParticleWall(event.getPlayer(), event.getTo().x()-1.5, event.getTo().x()+1.5, event.getTo().y()-0.5, event.getTo().y()+2.5, minZ-0.2, minZ-0.2); + if(event.getTo().z() < minZ) { + event.setTo(event.getTo().clone().set(event.getTo().x(), event.getTo().y(), minZ)); + } + } + if(event.getTo().z() > maxZ - 5) { + this.getAppliance().spawnParticleWall(event.getPlayer(), event.getTo().x()-1.5, event.getTo().x()+1.5, event.getTo().y()-0.5, event.getTo().y()+2.5, maxZ+0.2, maxZ+0.2); + if(event.getTo().z() > maxZ) { + event.setTo(event.getTo().clone().set(event.getTo().x(), event.getTo().y(), maxZ)); + } + } + } +} diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java index de70211..cde5154 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java @@ -25,10 +25,11 @@ public class EventController extends Appliance { } public void loadEvent(Appliance appliance) { - if(!(appliance instanceof Event event)) throw new IllegalArgumentException("Appliance has to implement Event."); + if(!(appliance instanceof Event)) throw new IllegalArgumentException("Appliance has to implement Event."); this.unloadEvent(); - Main.instance().restartAppliance(appliance.getClass()); - this.selectedEvent = event; + Appliance newAppliance = Main.instance().restartAppliance(appliance.getClass()); + if(!(newAppliance instanceof Event newEvent)) throw new IllegalArgumentException("Appliance has to implement Event."); + this.selectedEvent = newEvent; } public void unloadEvent() { From 36520a87f9dec645a424d45ff7e53ec3617ed3b1 Mon Sep 17 00:00:00 2001 From: lars Date: Fri, 19 Dec 2025 12:58:10 +0100 Subject: [PATCH 11/15] moved automatic scoreboard update start to EventController --- .../craftattack/spawn/event/appliances/deathrun/Deathrun.java | 2 -- .../event/appliances/eventController/EventController.java | 1 + .../spawn/event/appliances/eventController/Scorable.java | 3 +++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java index ca59167..a3cefdc 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java @@ -56,8 +56,6 @@ public class Deathrun extends Appliance implements Event, Scorable { World world = Bukkit.getWorlds().getFirst(); world.getWorldBorder().setSize(world.getWorldBorder().getMaxSize()); - - this.getScoreboardBuilder().startAutomaticUpdates(); } @Override diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java index cde5154..a156f42 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java @@ -44,6 +44,7 @@ public class EventController extends Appliance { public void startEvent() { if(this.selectedEvent == null) throw new ApplianceCommand.Error("There is no event selected!"); this.selectedEvent.start(); + if(this.selectedEvent instanceof Scorable scorable && scorable.automaticUpdates()) scorable.getScoreboardBuilder().startAutomaticUpdates(); } public void stopEvent() { diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scorable.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scorable.java index 6b0ebd9..dab46cf 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scorable.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Scorable.java @@ -5,6 +5,9 @@ import org.bukkit.entity.Player; public interface Scorable { String getScoreboardName(); + default boolean automaticUpdates() { + return true; + } EventScoreboardBuilder getScoreboardBuilder(); int getScore(Player p); } From 215259c6b9b90ac9a4bbf9d9144bc6a980c874db Mon Sep 17 00:00:00 2001 From: lars Date: Fri, 19 Dec 2025 13:01:01 +0100 Subject: [PATCH 12/15] added 'this' qualifier in Bloodmoon --- .../craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java index b4de47f..6cbaf46 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/gameplay/bloodmoon/Bloodmoon.java @@ -92,10 +92,10 @@ public class Bloodmoon extends Appliance { private final Map hordeSpawnTasks = new WeakHashMap<>(); private long lastBloodmoonStartTick = 0; public final int ticksPerDay = 24000; - public final int bloodmoonLength = ticksPerDay/2; + public final int bloodmoonLength = this.ticksPerDay /2; public final int preStartMessageTicks = Ticks.TICKS_PER_SECOND * 50; private final int bloodmoonFreeDaysAtStart = 3; - private final int bloodmoonStartTime = ticksPerDay/2; + private final int bloodmoonStartTime = this.ticksPerDay /2; private final int bloodmoonDayInterval = 30; private final int minBonusDrops = 1; private final int maxBonusDrops = 4; From de112f7e13169612db05fa759671a24a14a7e9e7 Mon Sep 17 00:00:00 2001 From: lars Date: Fri, 19 Dec 2025 14:04:36 +0100 Subject: [PATCH 13/15] added timer --- .../event/appliances/deathrun/Deathrun.java | 14 ++++++- .../deathrun/DeathrunPlayerMoveListener.java | 6 +-- .../appliances/eventController/Event.java | 3 +- .../eventController/EventController.java | 39 ++++++++++++++++++- .../commands/EventCommand.java | 13 ++++++- .../scoreboard/EventScoreboardBuilder.java | 2 +- 6 files changed, 68 insertions(+), 9 deletions(-) diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java index a3cefdc..43625af 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java @@ -19,6 +19,8 @@ import java.util.List; public class Deathrun extends Appliance implements Event, Scorable { private final EventScoreboardBuilder scoreboardBuilder = new EventScoreboardBuilder(this, 3, 2, 3); private final double borderDistance = 100; + private final int borderVisibilityDistance = 8; + private long durationSeconds; @Override public void onEnable() { @@ -31,6 +33,10 @@ public class Deathrun extends Appliance implements Event, Scorable { return this.borderDistance; } + public int getBorderVisibilityDistance() { + return this.borderVisibilityDistance; + } + public void spawnParticleWall(Player p, double xMin, double xMax, double yMin, double yMax, double zMin, double zMax) { Particle particle = Particle.WAX_ON; @@ -50,7 +56,8 @@ public class Deathrun extends Appliance implements Event, Scorable { } @Override - public void start() { + public void start(long durationSeconds) { + this.durationSeconds = durationSeconds; Title title = Title.title(Component.text("Start"), Component.text("Erreiche die höchste x-Koordinate!")); Bukkit.getOnlinePlayers().forEach(player -> player.showTitle(title)); @@ -73,6 +80,11 @@ public class Deathrun extends Appliance implements Event, Scorable { }); } + @Override + public long getDurationSeconds() { + return this.durationSeconds; + } + @Override public String getScoreboardName() { return "Deathrun"; diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunPlayerMoveListener.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunPlayerMoveListener.java index 45941fd..e65ab71 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunPlayerMoveListener.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunPlayerMoveListener.java @@ -13,19 +13,19 @@ public class DeathrunPlayerMoveListener extends ApplianceListener { double minX = spawnLocation.x() - this.getAppliance().getBorderDistance(); double minZ = spawnLocation.z() - this.getAppliance().getBorderDistance(); double maxZ = spawnLocation.z() + this.getAppliance().getBorderDistance(); - if(event.getTo().x() < minX + 5) { + if(event.getTo().x() < minX + this.getAppliance().getBorderVisibilityDistance()) { this.getAppliance().spawnParticleWall(event.getPlayer(), minX-0.2, minX-0.2, event.getTo().y()-0.5, event.getTo().y()+2.5, event.getTo().z()-1.5, event.getTo().z()+1.5); if(event.getTo().x() < minX) { event.setTo(event.getTo().clone().set(minX, event.getTo().y(), event.getTo().z())); } } - if(event.getTo().z() < minZ + 5) { + if(event.getTo().z() < minZ + this.getAppliance().getBorderVisibilityDistance()) { this.getAppliance().spawnParticleWall(event.getPlayer(), event.getTo().x()-1.5, event.getTo().x()+1.5, event.getTo().y()-0.5, event.getTo().y()+2.5, minZ-0.2, minZ-0.2); if(event.getTo().z() < minZ) { event.setTo(event.getTo().clone().set(event.getTo().x(), event.getTo().y(), minZ)); } } - if(event.getTo().z() > maxZ - 5) { + if(event.getTo().z() > maxZ - this.getAppliance().getBorderVisibilityDistance()) { this.getAppliance().spawnParticleWall(event.getPlayer(), event.getTo().x()-1.5, event.getTo().x()+1.5, event.getTo().y()-0.5, event.getTo().y()+2.5, maxZ+0.2, maxZ+0.2); if(event.getTo().z() > maxZ) { event.setTo(event.getTo().clone().set(event.getTo().x(), event.getTo().y(), maxZ)); diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java index d457efa..59af224 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/Event.java @@ -1,6 +1,7 @@ package eu.mhsl.craftattack.spawn.event.appliances.eventController; public interface Event { - void start(); + void start(long durationSeconds); void stop(); + long getDurationSeconds(); } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java index a156f42..26c16e1 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java @@ -4,6 +4,10 @@ import eu.mhsl.craftattack.spawn.core.Main; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; import eu.mhsl.craftattack.spawn.event.appliances.eventController.commands.EventCommand; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.util.Ticks; +import org.bukkit.Bukkit; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -11,6 +15,8 @@ import java.util.List; public class EventController extends Appliance { private List eventAppliances = null; private Event selectedEvent = null; + private long timerStart; + private int timerTaskId = -1; @Override public void onEnable() { @@ -41,15 +47,25 @@ public class EventController extends Appliance { this.selectedEvent = null; } - public void startEvent() { + public void startEvent(long durationMinutes) { if(this.selectedEvent == null) throw new ApplianceCommand.Error("There is no event selected!"); - this.selectedEvent.start(); + this.selectedEvent.start(durationMinutes * 60); if(this.selectedEvent instanceof Scorable scorable && scorable.automaticUpdates()) scorable.getScoreboardBuilder().startAutomaticUpdates(); + // TODO: possibility for other dimensions + this.timerStart = Bukkit.getWorlds().getFirst().getFullTime(); + this.timerTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask( + Main.instance(), + this::updateTimer, + Ticks.TICKS_PER_SECOND, + Ticks.TICKS_PER_SECOND + ); } public void stopEvent() { if(this.selectedEvent == null) throw new ApplianceCommand.Error("There is no event selected!"); this.selectedEvent.stop(); + if(this.timerTaskId != -1) Bukkit.getScheduler().cancelTask(this.timerTaskId); + this.timerTaskId = -1; } public String getSelectedEvent() { @@ -57,6 +73,25 @@ public class EventController extends Appliance { return this.selectedEvent.getClass().getSimpleName().toLowerCase(); } + private void updateTimer() { + long ticksLeft = this.timerStart - (Bukkit.getWorlds().getFirst().getFullTime() - this.selectedEvent.getDurationSeconds() * Ticks.TICKS_PER_SECOND); + if(ticksLeft <= 0) { + if(this.timerTaskId != -1) Bukkit.getScheduler().cancelTask(this.timerTaskId); + this.timerTaskId = -1; + this.selectedEvent.stop(); + Bukkit.getOnlinePlayers().forEach(player -> player.sendActionBar(Component.text("Fertig!"))); + return; + } + + Bukkit.getOnlinePlayers().forEach(player -> player.sendActionBar( + Component.text(formatSeconds(ticksLeft / Ticks.TICKS_PER_SECOND), NamedTextColor.GOLD) + )); + } + + public static String formatSeconds(long seconds){ + return String.format("%02d:%02d:%02d", seconds / 3600, (seconds / 60) % 60, seconds % 60); + } + @Override protected @NotNull List> commands() { return List.of( diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java index a3aa611..9b66702 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java @@ -34,7 +34,17 @@ public class EventCommand extends ApplianceCommand { break; } case "start": { - this.getAppliance().startEvent(); + if(args.length == 1) { + this.getAppliance().startEvent(60 * 2); + break; + } + if(args.length == 2) { + try { + this.getAppliance().startEvent(Long.parseLong(args[1])); + } catch(NumberFormatException e) { + throw new Error("Last argument has to be a long."); + } + } break; } case "stop": { @@ -59,6 +69,7 @@ public class EventCommand extends ApplianceCommand { if(args.length == 2 && args[0].equals("load")) return this.getAppliance().getEventAppliances().stream() .map(appliance -> appliance.getClass().getSimpleName().toLowerCase()) .toList(); + if(args.length == 2 && args[0].equals("start")) return List.of(""); return null; } } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java index 187d4cd..14a9675 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java @@ -42,7 +42,7 @@ public class EventScoreboardBuilder { Objective objective = newScoreboard.registerNewObjective( "event", "dummy", - Component.text("Scoreboard %s".formatted(this.scorable.getScoreboardName()), NamedTextColor.GOLD) + Component.text("Scoreboard %s".formatted(this.scorable.getScoreboardName()), NamedTextColor.DARK_PURPLE) ); objective.setDisplaySlot(DisplaySlot.SIDEBAR); objective.numberFormat(NumberFormat.blank()); From f0e0cfbb8511db32c2089bc5153b5d832715714f Mon Sep 17 00:00:00 2001 From: lars Date: Fri, 19 Dec 2025 14:33:01 +0100 Subject: [PATCH 14/15] fixed scoreboard order --- .../event/appliances/deathrun/Deathrun.java | 2 +- .../scoreboard/EventScoreboardBuilder.java | 92 ++++++++++--------- 2 files changed, 52 insertions(+), 42 deletions(-) diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java index 43625af..bebb36f 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/Deathrun.java @@ -58,7 +58,7 @@ public class Deathrun extends Appliance implements Event, Scorable { @Override public void start(long durationSeconds) { this.durationSeconds = durationSeconds; - Title title = Title.title(Component.text("Start"), Component.text("Erreiche die höchste x-Koordinate!")); + Title title = Title.title(Component.text("Start"), Component.text("Laufe Richtung Osten! (positiv x)")); Bukkit.getOnlinePlayers().forEach(player -> player.showTitle(title)); World world = Bukkit.getWorlds().getFirst(); diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java index 14a9675..282deb8 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/scoreboard/EventScoreboardBuilder.java @@ -5,6 +5,7 @@ import eu.mhsl.craftattack.spawn.event.appliances.eventController.Scorable; import io.papermc.paper.scoreboard.numbers.NumberFormat; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.TextDecoration; import net.kyori.adventure.util.Ticks; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -37,64 +38,73 @@ public class EventScoreboardBuilder { } public Scoreboard buildFor(Player p) { - List scoreMap = this.playerScores; - Scoreboard newScoreboard = Bukkit.getScoreboardManager().getNewScoreboard(); + List scoreList = new ArrayList<>(this.playerScores); - Objective objective = newScoreboard.registerNewObjective( + Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard(); + Objective objective = scoreboard.registerNewObjective( "event", "dummy", - Component.text("Scoreboard %s".formatted(this.scorable.getScoreboardName()), NamedTextColor.DARK_PURPLE) + Component.text( + "Scoreboard %s".formatted(this.scorable.getScoreboardName()), + NamedTextColor.GOLD, TextDecoration.BOLD + ) ); objective.setDisplaySlot(DisplaySlot.SIDEBAR); objective.numberFormat(NumberFormat.blank()); - if(scoreMap.isEmpty()) return newScoreboard; + UUID uuid = p.getUniqueId(); + scoreList.removeIf(e -> e.playerUuid().equals(uuid)); + scoreList.add(new EventScoreEntry(uuid, p.getName(), this.scorable.getScore(p))); - scoreMap.sort(this.scoreComparator); - System.out.print(scoreMap); + scoreList.sort(this.scoreComparator); - EventScoreEntry playerScoreEntry = scoreMap.stream() - .filter(entry -> entry.playerUuid().equals(p.getUniqueId())) + int size = scoreList.size(); + int playerIndex = IntStream.range(0, size) + .filter(i -> scoreList.get(i).playerUuid().equals(uuid)) .findFirst() - .orElse(null); - if(playerScoreEntry == null) { - playerScoreEntry = new EventScoreEntry(p.getUniqueId(), p.getName(), this.scorable.getScore(p)); - scoreMap.add(playerScoreEntry); + .orElse(0); + + IntStream top = IntStream.range(0, Math.min(this.topPlaces, size)); + + int aroundStart = Math.max(0, playerIndex - this.aroundPlaces); + int aroundEnd = Math.min(size, playerIndex + this.aroundPlaces + 1); + IntStream around = IntStream.range(aroundStart, aroundEnd); + + IntStream bottom = IntStream.range(Math.max(0, size - this.bottomPlaces), size); + + int threshold = this.topPlaces + this.bottomPlaces + this.aroundPlaces * 2 + 1; + + IntStream indices; + if (size <= threshold) { + indices = IntStream.range(0, size); + } else if (playerIndex <= this.topPlaces + this.aroundPlaces) { + indices = IntStream.concat( + IntStream.range(0, Math.min(size, playerIndex + this.aroundPlaces + 1)), + bottom + ); + } else if (playerIndex >= size - this.bottomPlaces - this.aroundPlaces - 1) { + indices = IntStream.concat( + top, + IntStream.range(Math.max(0, playerIndex - this.aroundPlaces), size) + ); + } else { + indices = IntStream.concat(IntStream.concat(top, around), bottom); } - int playerIndex = scoreMap.indexOf(playerScoreEntry); + int[] display = indices.distinct().sorted().toArray(); - IntStream topStream = IntStream.range(0, this.topPlaces); - IntStream aroundStream = IntStream.range(playerIndex - this.aroundPlaces, playerIndex + this.aroundPlaces); - IntStream bottomStream = IntStream.range(scoreMap.size() - this.bottomPlaces, scoreMap.size()); + for (int i = 0; i < display.length; i++) { + int idx = display[i]; + EventScoreEntry entry = scoreList.get(idx); - if(playerIndex <= this.topPlaces + this.aroundPlaces) { - aroundStream = IntStream.empty(); - topStream = IntStream.range(0, playerIndex + this.aroundPlaces); - } - if(playerIndex >= scoreMap.size() - this.bottomPlaces - this.aroundPlaces) { - aroundStream = IntStream.empty(); - bottomStream = IntStream.range(playerIndex - this.aroundPlaces, scoreMap.size()); - } - if(scoreMap.size() <= this.topPlaces + this.aroundPlaces * 2 + this.bottomPlaces + 2) { - topStream = IntStream.range(0, scoreMap.size()); - aroundStream = IntStream.empty(); - bottomStream = IntStream.empty(); + String line = this.formattedLine(idx, entry.name(), entry.score()); + + objective.getScore(line).setScore(display.length - i); } - IntStream indices = IntStream.concat( - IntStream.concat(topStream, aroundStream), - bottomStream - ).distinct().sorted(); - - indices.forEach(place -> { - EventScoreEntry entry = scoreMap.get(place); - String line = this.formattedLine(place, entry.name(), entry.score()); - objective.getScore(line).setScore(place); - }); - - return newScoreboard; + return scoreboard; } + public void startAutomaticUpdates() { this.scoreboardUpdateTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask( Main.instance(), From bd883a4fa10b48649aa0a4180ed70d84dfa776a0 Mon Sep 17 00:00:00 2001 From: lars Date: Sat, 20 Dec 2025 18:23:06 +0100 Subject: [PATCH 15/15] added big events in craftattack plugin --- .../appliances/metaGameplay/event/Event.java | 52 ++++++++++++------- .../command/EventOpenSessionCommand.java | 16 +++++- .../eventController/EventController.java | 4 +- ...EventCommand.java => BigEventCommand.java} | 4 +- 4 files changed, 53 insertions(+), 23 deletions(-) rename event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/{EventCommand.java => BigEventCommand.java} (96%) diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/metaGameplay/event/Event.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/metaGameplay/event/Event.java index 4c37244..1062918 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/metaGameplay/event/Event.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/metaGameplay/event/Event.java @@ -37,6 +37,11 @@ public class Event extends Appliance { DONE } + public enum EventType { + BIG, + SMALL + } + Countdown advertiseCountdown = new Countdown( 120, announcementData -> Component.text() @@ -50,6 +55,7 @@ public class Event extends Appliance { ); public DisplayVillager.ConfigBound villager; private boolean isOpen = false; + private EventType eventType; private AdvertisementStatus advertiseStatus = AdvertisementStatus.BEFORE; private UUID roomId; private final List pendingRewards = new ArrayList<>(); @@ -79,18 +85,24 @@ public class Event extends Appliance { if(this.isOpen) this.roomId = UUID.fromString(this.localConfig().getString("roomId", "")); } - public void openEvent() { + public void openEvent(EventType type) { if(this.isOpen) throw new ApplianceCommand.Error("Es läuft derzeit bereits ein Event!"); + this.eventType = type; - Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), () -> { - ReqResp sessionResponse = this.queryRepository(EventRepository.class).createSession(); + if(type.equals(EventType.SMALL)) { + Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), () -> { + ReqResp sessionResponse = this.queryRepository(EventRepository.class).createSession(); - if(sessionResponse.status() != HttpStatus.OK) - throw new ApplianceCommand.Error("Event-Server meldet Fehler: " + sessionResponse.status()); + if(sessionResponse.status() != HttpStatus.OK) + throw new ApplianceCommand.Error("Event-Server meldet Fehler: " + sessionResponse.status()); - this.isOpen = true; - this.roomId = sessionResponse.data().uuid(); - }); + this.isOpen = true; + this.roomId = sessionResponse.data().uuid(); + }); + return; + } + + this.isOpen = true; } public void joinEvent(Player p) { @@ -112,18 +124,22 @@ public class Event extends Appliance { Main.instance().getLogger().info("Verbinde mit eventserver: " + p.getName()); p.sendMessage(Component.text("Authentifiziere...", NamedTextColor.GREEN)); - Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), () -> { - ReqResp queueResponse = this.queryRepository(EventRepository.class) - .queueRoom(new EventRepository.QueueRoom(p.getUniqueId(), this.roomId)); + if(this.eventType.equals(EventType.SMALL)) { + Bukkit.getScheduler().runTaskAsynchronously(Main.instance(), () -> { + ReqResp queueResponse = this.queryRepository(EventRepository.class) + .queueRoom(new EventRepository.QueueRoom(p.getUniqueId(), this.roomId)); - if(queueResponse.status() != HttpStatus.OK || queueResponse.data().error() != null) { - p.sendMessage(Component.text("Fehler beim Betreten: " + queueResponse.data().error(), NamedTextColor.RED)); - return; - } + if(queueResponse.status() != HttpStatus.OK || queueResponse.data().error() != null) { + p.sendMessage(Component.text("Fehler beim Betreten: " + queueResponse.data().error(), NamedTextColor.RED)); + return; + } - p.sendMessage(Component.text("Betrete...", NamedTextColor.GREEN)); - PluginMessage.connect(p, this.localConfig().getString("connect-server-name")); - }); + p.sendMessage(Component.text("Betrete...", NamedTextColor.GREEN)); + PluginMessage.connect(p, this.localConfig().getString("connect-server-name")); + }); + } + + PluginMessage.connect(p, "grand-event"); } public void endEvent() { diff --git a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/metaGameplay/event/command/EventOpenSessionCommand.java b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/metaGameplay/event/command/EventOpenSessionCommand.java index e633640..1bf11fe 100644 --- a/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/metaGameplay/event/command/EventOpenSessionCommand.java +++ b/craftattack/src/main/java/eu/mhsl/craftattack/spawn/craftattack/appliances/metaGameplay/event/command/EventOpenSessionCommand.java @@ -7,6 +7,10 @@ import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; public class EventOpenSessionCommand extends ApplianceCommand { public EventOpenSessionCommand() { @@ -15,7 +19,17 @@ public class EventOpenSessionCommand extends ApplianceCommand { @Override protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) throws Exception { - this.getAppliance().openEvent(); + if(args.length == 1) { + this.getAppliance().openEvent(Event.EventType.SMALL); + } else { + this.getAppliance().openEvent(Event.EventType.valueOf(args[1])); + } sender.sendMessage(Component.text("Event-Server gestartet!", NamedTextColor.GREEN)); } + + @Override + public @Nullable List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if(args.length == 1) return Arrays.stream(Event.EventType.values()).map(Enum::toString).toList(); + return null; + } } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java index 26c16e1..ecc4019 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/EventController.java @@ -3,7 +3,7 @@ package eu.mhsl.craftattack.spawn.event.appliances.eventController; import eu.mhsl.craftattack.spawn.core.Main; import eu.mhsl.craftattack.spawn.core.appliance.Appliance; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; -import eu.mhsl.craftattack.spawn.event.appliances.eventController.commands.EventCommand; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.commands.BigEventCommand; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.util.Ticks; @@ -95,7 +95,7 @@ public class EventController extends Appliance { @Override protected @NotNull List> commands() { return List.of( - new EventCommand() + new BigEventCommand() ); } } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/BigEventCommand.java similarity index 96% rename from event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java rename to event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/BigEventCommand.java index 9b66702..21d67ae 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/EventCommand.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/BigEventCommand.java @@ -10,8 +10,8 @@ import org.jetbrains.annotations.Nullable; import java.util.List; -public class EventCommand extends ApplianceCommand { - public EventCommand() { +public class BigEventCommand extends ApplianceCommand { + public BigEventCommand() { super("event"); }