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 bebb36f..74d782e 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,32 +1,52 @@ 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.deathrun.listeners.DeathrunPlayerDamageListener; +import eu.mhsl.craftattack.spawn.event.appliances.deathrun.listeners.DeathrunPlayerJoinListener; +import eu.mhsl.craftattack.spawn.event.appliances.deathrun.listeners.DeathrunPlayerMoveListener; +import eu.mhsl.craftattack.spawn.event.appliances.deathrun.listeners.DeathrunPortalListener; 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.sound.Sound; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.title.Title; +import net.kyori.adventure.util.Ticks; import org.bukkit.Bukkit; import org.bukkit.Particle; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.Listener; +import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; import java.util.List; +import java.util.UUID; @Appliance.Flags(autoload = false) public class Deathrun extends Appliance implements Event, Scorable { - private final EventScoreboardBuilder scoreboardBuilder = new EventScoreboardBuilder(this, 3, 2, 3); + private final EventScoreboardBuilder scoreboardBuilder = new EventScoreboardBuilder(this, 3, 2, 0); private final double borderDistance = 100; private final int borderVisibilityDistance = 8; private long durationSeconds; + private boolean isBeforeStart = true; + private boolean pvpDisabled = true; + private final World world = Bukkit.getWorlds().getFirst(); + private BukkitTask pvpTask; + public ArrayList previouslyJoinedPlayers = new ArrayList<>(); @Override public void onEnable() { - World world = Bukkit.getWorlds().getFirst(); - world.getWorldBorder().setCenter(world.getSpawnLocation()); - world.getWorldBorder().setSize(20); + this.world.getWorldBorder().setCenter(this.world.getSpawnLocation()); + this.world.getWorldBorder().setSize(20); + Bukkit.getOnlinePlayers().forEach(player -> { + player.teleport(this.world.getSpawnLocation()); + this.previouslyJoinedPlayers.add(player.getUniqueId()); + }); + this.pvpDisabled = true; } public double getBorderDistance() { @@ -37,7 +57,7 @@ public class Deathrun extends Appliance implements Event, Scorable { return this.borderVisibilityDistance; } - public void spawnParticleWall(Player p, double xMin, double xMax, double yMin, double yMax, double zMin, double zMax) { + public void spawnParticles(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) { @@ -51,18 +71,51 @@ public class Deathrun extends Appliance implements Event, Scorable { @Override public void onDisable() { - World world = Bukkit.getWorlds().getFirst(); - world.getWorldBorder().setSize(world.getWorldBorder().getMaxSize()); + this.world.getWorldBorder().setSize(this.world.getWorldBorder().getMaxSize()); } @Override public void start(long durationSeconds) { + this.isBeforeStart = false; this.durationSeconds = durationSeconds; - Title title = Title.title(Component.text("Start"), Component.text("Laufe Richtung Osten! (positiv x)")); - Bukkit.getOnlinePlayers().forEach(player -> player.showTitle(title)); + Title title = Title.title(Component.text("Start", NamedTextColor.GOLD), Component.text("Laufe Richtung Osten! (positiv x)", NamedTextColor.YELLOW)); + // TODO: Soll PvP überhaupt aktiviert werden? Soll Respawn erlaubt sein? + Bukkit.getOnlinePlayers().forEach(player -> { + player.showTitle(title); + player.sendMessage(Component.text("Start! Laufe Richtung Osten (positiv x)!", NamedTextColor.YELLOW)); + }); + Bukkit.getScheduler().runTaskLater( + Main.instance(), + () -> Bukkit.getOnlinePlayers().forEach(player -> + player.sendMessage(Component.text("PvP wird in 10 Minuten aktiviert!", NamedTextColor.GOLD)) + ), + Ticks.TICKS_PER_SECOND * 5 + ); - World world = Bukkit.getWorlds().getFirst(); - world.getWorldBorder().setSize(world.getWorldBorder().getMaxSize()); + this.world.getWorldBorder().setSize(this.world.getWorldBorder().getMaxSize()); + this.pvpTask = Bukkit.getScheduler().runTaskLater( + Main.instance(), + () -> { + this.pvpDisabled = false; + Bukkit.getOnlinePlayers().forEach(player -> { + player.sendMessage(Component.text("PvP ist jetzt aktiviert!", NamedTextColor.GOLD)); + player.playSound(Sound.sound(org.bukkit.Sound.ENTITY_EXPERIENCE_ORB_PICKUP, Sound.Source.MASTER, 500f, 2f)); + }); + }, + Ticks.TICKS_PER_SECOND * 60 * 10 + ); + } + + public boolean isBeforeStart() { + return this.isBeforeStart; + } + + public World getWorld() { + return this.world; + } + + public boolean isPvpDisabled() { + return this.pvpDisabled; } @Override @@ -74,6 +127,8 @@ public class Deathrun extends Appliance implements Event, Scorable { public void stop() { this.getScoreboardBuilder().stopAutomaticUpdates(); Title title = Title.title(Component.text("Ende!"), Component.empty()); + this.pvpTask.cancel(); + this.pvpDisabled = true; Bukkit.getOnlinePlayers().forEach(player -> { player.showTitle(title); player.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard()); @@ -98,7 +153,10 @@ public class Deathrun extends Appliance implements Event, Scorable { @Override protected @NotNull List listeners() { return List.of( - new DeathrunPlayerMoveListener() + new DeathrunPlayerMoveListener(), + new DeathrunPlayerDamageListener(), + new DeathrunPlayerJoinListener(), + new DeathrunPortalListener() ); } } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/listeners/DeathrunPlayerDamageListener.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/listeners/DeathrunPlayerDamageListener.java new file mode 100644 index 0000000..2a98a42 --- /dev/null +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/listeners/DeathrunPlayerDamageListener.java @@ -0,0 +1,31 @@ +package eu.mhsl.craftattack.spawn.event.appliances.deathrun.listeners; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import eu.mhsl.craftattack.spawn.event.appliances.deathrun.Deathrun; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.FoodLevelChangeEvent; + +public class DeathrunPlayerDamageListener extends ApplianceListener { + @EventHandler + public void onPlayerDamagePlayer(EntityDamageByEntityEvent event) { + if(!this.getAppliance().isPvpDisabled()) return; + if(!(event.getDamager() instanceof Player)) return; + if(!(event.getEntity() instanceof Player)) return; + event.setCancelled(true); + } + + @EventHandler + public void onPlayerDamage(EntityDamageEvent event) { + if(!this.getAppliance().isBeforeStart()) return; + if(!(event.getEntity() instanceof Player)) return; + event.setCancelled(true); + } + + @EventHandler + public void onHunger(FoodLevelChangeEvent event) { + if(!this.getAppliance().isBeforeStart()) event.setCancelled(true); + } +} diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/listeners/DeathrunPlayerJoinListener.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/listeners/DeathrunPlayerJoinListener.java new file mode 100644 index 0000000..ce7c72c --- /dev/null +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/listeners/DeathrunPlayerJoinListener.java @@ -0,0 +1,27 @@ +package eu.mhsl.craftattack.spawn.event.appliances.deathrun.listeners; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import eu.mhsl.craftattack.spawn.event.appliances.deathrun.Deathrun; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerJoinEvent; + +public class DeathrunPlayerJoinListener extends ApplianceListener { + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + if( + this.getAppliance().isBeforeStart() || + !this.getAppliance().previouslyJoinedPlayers.contains(player.getUniqueId()) + ) { + player.teleport(this.getAppliance().getWorld().getSpawnLocation()); + player.setGameMode(GameMode.ADVENTURE); + this.getAppliance().previouslyJoinedPlayers.add(player.getUniqueId()); + } + + if(!this.getAppliance().isBeforeStart() && player.getGameMode().equals(GameMode.ADVENTURE)) { + player.setGameMode(GameMode.SURVIVAL); + } + } +} 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/listeners/DeathrunPlayerMoveListener.java similarity index 51% rename from event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/DeathrunPlayerMoveListener.java rename to event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/listeners/DeathrunPlayerMoveListener.java index e65ab71..bd906e2 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/listeners/DeathrunPlayerMoveListener.java @@ -1,10 +1,12 @@ -package eu.mhsl.craftattack.spawn.event.appliances.deathrun; +package eu.mhsl.craftattack.spawn.event.appliances.deathrun.listeners; import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import eu.mhsl.craftattack.spawn.event.appliances.deathrun.Deathrun; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.event.EventHandler; import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerTeleportEvent; public class DeathrunPlayerMoveListener extends ApplianceListener { @EventHandler @@ -14,22 +16,34 @@ public class DeathrunPlayerMoveListener extends ApplianceListener { double minZ = spawnLocation.z() - this.getAppliance().getBorderDistance(); double maxZ = spawnLocation.z() + this.getAppliance().getBorderDistance(); 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); + this.getAppliance().spawnParticles(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 + 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); + this.getAppliance().spawnParticles(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 - 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); + this.getAppliance().spawnParticles(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)); } } } + + @EventHandler + public void onPlayerTeleport(PlayerTeleportEvent event) throws Exception { + 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 || event.getTo().z() < minZ || event.getTo().z() > maxZ) { + event.setCancelled(true); + throw new Exception("Player %s teleported outside the border.".formatted(event.getPlayer())); + } + } } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/listeners/DeathrunPortalListener.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/listeners/DeathrunPortalListener.java new file mode 100644 index 0000000..4123d2b --- /dev/null +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/deathrun/listeners/DeathrunPortalListener.java @@ -0,0 +1,13 @@ +package eu.mhsl.craftattack.spawn.event.appliances.deathrun.listeners; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceListener; +import eu.mhsl.craftattack.spawn.event.appliances.deathrun.Deathrun; +import org.bukkit.event.EventHandler; +import org.bukkit.event.player.PlayerPortalEvent; + +public class DeathrunPortalListener extends ApplianceListener { + @EventHandler + public void onPlayerPortal(PlayerPortalEvent event) { + event.setCancelled(true); + } +} 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 ecc4019..a043079 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,20 +3,52 @@ 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.core.util.IteratorUtil; +import eu.mhsl.craftattack.spawn.core.util.entity.PlayerUtils; +import eu.mhsl.craftattack.spawn.core.util.server.PluginMessage; +import eu.mhsl.craftattack.spawn.core.util.text.ComponentUtil; +import eu.mhsl.craftattack.spawn.core.util.text.Countdown; import eu.mhsl.craftattack.spawn.event.appliances.eventController.commands.BigEventCommand; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.commands.JoinCraftattackCommand; +import net.kyori.adventure.sound.Sound; 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.GameMode; +import org.bukkit.GameRule; +import org.bukkit.Statistic; import org.jetbrains.annotations.NotNull; import java.util.List; +import java.util.Map; + +import static java.util.Map.entry; public class EventController extends Appliance { private List eventAppliances = null; private Event selectedEvent = null; - private long timerStart; private int timerTaskId = -1; + private long durationMinutes; + private final Countdown countdown = new Countdown( + 10, + this::format, + this::announce, + this::startEvent + ); + + private final Map, Boolean> gameRulesAfterStart = Map.ofEntries( + entry(GameRule.DO_DAYLIGHT_CYCLE, true), + entry(GameRule.DO_INSOMNIA, true), + entry(GameRule.DISABLE_RAIDS, false), + entry(GameRule.DO_FIRE_TICK, true), + entry(GameRule.DO_ENTITY_DROPS, true), + entry(GameRule.DO_PATROL_SPAWNING, true), + entry(GameRule.DO_TRADER_SPAWNING, true), + entry(GameRule.DO_WEATHER_CYCLE, true), + entry(GameRule.FALL_DAMAGE, true), + entry(GameRule.FIRE_DAMAGE, true) + ); @Override public void onEnable() { @@ -36,6 +68,8 @@ public class EventController extends Appliance { Appliance newAppliance = Main.instance().restartAppliance(appliance.getClass()); if(!(newAppliance instanceof Event newEvent)) throw new IllegalArgumentException("Appliance has to implement Event."); this.selectedEvent = newEvent; + Bukkit.getOnlinePlayers().forEach(player -> player.setGameMode(GameMode.ADVENTURE)); + IteratorUtil.worlds(world -> IteratorUtil.setGameRules(this.gameRulesAfterStart, true)); } public void unloadEvent() { @@ -47,12 +81,58 @@ public class EventController extends Appliance { this.selectedEvent = null; } + public void scheduleStart(long durationMinutes) { + if(this.selectedEvent == null) throw new ApplianceCommand.Error("There is no event selected!"); + this.durationMinutes = durationMinutes; + this.countdown.start(); + } + + public void cancelStart() { + this.countdown.cancel(); + } + + private Component format(Countdown.AnnouncementData data) { + return Component.text() + .append(ComponentUtil.createRainbowText(this.selectedEvent.getClass().getSimpleName(), 10)) + .append(Component.text(" startet in ", NamedTextColor.GOLD)) + .append(Component.text(data.count(), NamedTextColor.AQUA)) + .append(Component.text(" " + data.unit() + "!", NamedTextColor.GOLD)) + .build(); + } + + private void announce(Component message) { + IteratorUtil.onlinePlayers(player -> { + player.sendMessage(message); + player.playSound(Sound.sound(org.bukkit.Sound.ENTITY_EXPERIENCE_ORB_PICKUP, Sound.Source.MASTER, 500f, 1f)); + }); + } + + private void startEvent() { + this.startEvent(this.durationMinutes); + } + public void startEvent(long durationMinutes) { if(this.selectedEvent == null) throw new ApplianceCommand.Error("There is no event selected!"); + IteratorUtil.worlds(world -> IteratorUtil.setGameRules(this.gameRulesAfterStart, false)); + IteratorUtil.worlds(world -> world.setFullTime(0)); + Bukkit.getOnlinePlayers().forEach(player -> { + player.setFoodLevel(20); + player.setHealth(20); + player.getInventory().clear(); + player.setGameMode(GameMode.SURVIVAL); + player.setExp(0); + player.setLevel(0); + + player.playSound(Sound.sound(org.bukkit.Sound.ITEM_GOAT_HORN_SOUND_6, Sound.Source.MASTER, 500f, 1f)); + + player.sendMessage(Component.text("Viel Spaß bei %s!".formatted(this.selectedEvent.getClass().getSimpleName()), NamedTextColor.GREEN)); + + player.setStatistic(Statistic.TIME_SINCE_REST, 0); + PlayerUtils.resetStatistics(player); + }); 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, @@ -66,6 +146,17 @@ public class EventController extends Appliance { this.selectedEvent.stop(); if(this.timerTaskId != -1) Bukkit.getScheduler().cancelTask(this.timerTaskId); this.timerTaskId = -1; + if(this.selectedEvent instanceof Scorable scorable) { + String scores = String.join("\n", scorable.getScoreboardBuilder().getScores()); + Bukkit.getOnlinePlayers().forEach(player -> player.sendMessage(scores)); + Main.instance().getLogger().info(scores); + } + + Bukkit.getScheduler().runTaskLater( + Main.instance(), + () -> Bukkit.getOnlinePlayers().forEach(player -> PluginMessage.connect(player, "craftattack")), + Ticks.TICKS_PER_SECOND * 7 + ); } public String getSelectedEvent() { @@ -74,12 +165,10 @@ public class EventController extends Appliance { } private void updateTimer() { - long ticksLeft = this.timerStart - (Bukkit.getWorlds().getFirst().getFullTime() - this.selectedEvent.getDurationSeconds() * Ticks.TICKS_PER_SECOND); + long ticksLeft = -(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!"))); + this.stopEvent(); return; } @@ -95,7 +184,8 @@ public class EventController extends Appliance { @Override protected @NotNull List> commands() { return List.of( - new BigEventCommand() + new BigEventCommand(), + new JoinCraftattackCommand() ); } } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/BigEventCommand.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/BigEventCommand.java index 21d67ae..f1733ed 100644 --- a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/BigEventCommand.java +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/BigEventCommand.java @@ -35,12 +35,12 @@ public class BigEventCommand extends ApplianceCommand { } case "start": { if(args.length == 1) { - this.getAppliance().startEvent(60 * 2); + this.getAppliance().scheduleStart(60 * 2); break; } if(args.length == 2) { try { - this.getAppliance().startEvent(Long.parseLong(args[1])); + this.getAppliance().scheduleStart(Long.parseLong(args[1])); } catch(NumberFormatException e) { throw new Error("Last argument has to be a long."); } @@ -48,6 +48,7 @@ public class BigEventCommand extends ApplianceCommand { break; } case "stop": { + this.getAppliance().cancelStart(); this.getAppliance().stopEvent(); break; } diff --git a/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/JoinCraftattackCommand.java b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/JoinCraftattackCommand.java new file mode 100644 index 0000000..1f41a4b --- /dev/null +++ b/event/src/main/java/eu/mhsl/craftattack/spawn/event/appliances/eventController/commands/JoinCraftattackCommand.java @@ -0,0 +1,19 @@ +package eu.mhsl.craftattack.spawn.event.appliances.eventController.commands; + +import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; +import eu.mhsl.craftattack.spawn.core.util.server.PluginMessage; +import eu.mhsl.craftattack.spawn.event.appliances.eventController.EventController; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +public class JoinCraftattackCommand extends ApplianceCommand.PlayerChecked { + public JoinCraftattackCommand() { + super("craftattack"); + } + + @Override + protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + PluginMessage.connect(this.getPlayer(), "craftattack"); + } +} 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 282deb8..7cb2965 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 @@ -8,6 +8,7 @@ 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.ChatColor; import org.bukkit.entity.Player; import org.bukkit.scoreboard.DisplaySlot; import org.bukkit.scoreboard.Objective; @@ -92,18 +93,37 @@ public class EventScoreboardBuilder { int[] display = indices.distinct().sorted().toArray(); - for (int i = 0; i < display.length; i++) { - int idx = display[i]; + List lines = new ArrayList<>(); + int prevIdx = -1; + int sepNo = 0; + + for (int idx : display) { + if (prevIdx != -1 && idx > prevIdx + 1) { + lines.add(this.separatorLine(sepNo++)); + } + EventScoreEntry entry = scoreList.get(idx); + if(!entry.playerUuid().equals(p.getUniqueId())) { + lines.add(this.formattedLine(idx, entry.name(), entry.score())); + } else { + lines.add(ChatColor.YELLOW + this.formattedLine(idx, entry.name(), entry.score()) + ChatColor.RESET); + } - String line = this.formattedLine(idx, entry.name(), entry.score()); + prevIdx = idx; + } - objective.getScore(line).setScore(display.length - i); + int score = lines.size(); + for (String line : lines) { + objective.getScore(line).setScore(score--); } return scoreboard; } + private String separatorLine(int n) { + return ChatColor.GRAY + "..." + ChatColor.RESET + " ".repeat(n); + } + public void startAutomaticUpdates() { this.scoreboardUpdateTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask( @@ -134,7 +154,17 @@ public class EventScoreboardBuilder { private String formattedLine(int place, String name, int score) { name = this.trimName(name); - return "%s. %s: %s".formatted(place+1, name, score); + return "%s. %s : %s".formatted(place+1, name, score); + } + + public List getScores() { + List scoreList = new ArrayList<>(this.playerScores); + scoreList.sort(this.scoreComparator); + ArrayList result = new ArrayList<>(); + for(int i = 0; i < scoreList.size(); i++) { + result.add(this.formattedLine(i, scoreList.get(i).name(), scoreList.get(i).score())); + } + return result; } private String trimName(String name) {