Merge branch 'master-big-events'

This commit is contained in:
2025-12-23 22:34:51 +01:00
9 changed files with 313 additions and 30 deletions

View File

@@ -1,32 +1,52 @@
package eu.mhsl.craftattack.spawn.event.appliances.deathrun; 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.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.Event;
import eu.mhsl.craftattack.spawn.event.appliances.eventController.Scorable; import eu.mhsl.craftattack.spawn.event.appliances.eventController.Scorable;
import eu.mhsl.craftattack.spawn.event.appliances.eventController.scoreboard.EventScoreboardBuilder; 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.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.title.Title; import net.kyori.adventure.title.Title;
import net.kyori.adventure.util.Ticks;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Particle; import org.bukkit.Particle;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.scheduler.BukkitTask;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
@Appliance.Flags(autoload = false) @Appliance.Flags(autoload = false)
public class Deathrun extends Appliance implements Event, Scorable { 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 double borderDistance = 100;
private final int borderVisibilityDistance = 8; private final int borderVisibilityDistance = 8;
private long durationSeconds; private long durationSeconds;
private boolean isBeforeStart = true;
private boolean pvpDisabled = true;
private final World world = Bukkit.getWorlds().getFirst();
private BukkitTask pvpTask;
public ArrayList<UUID> previouslyJoinedPlayers = new ArrayList<>();
@Override @Override
public void onEnable() { public void onEnable() {
World world = Bukkit.getWorlds().getFirst(); this.world.getWorldBorder().setCenter(this.world.getSpawnLocation());
world.getWorldBorder().setCenter(world.getSpawnLocation()); this.world.getWorldBorder().setSize(20);
world.getWorldBorder().setSize(20); Bukkit.getOnlinePlayers().forEach(player -> {
player.teleport(this.world.getSpawnLocation());
this.previouslyJoinedPlayers.add(player.getUniqueId());
});
this.pvpDisabled = true;
} }
public double getBorderDistance() { public double getBorderDistance() {
@@ -37,7 +57,7 @@ public class Deathrun extends Appliance implements Event, Scorable {
return this.borderVisibilityDistance; 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; Particle particle = Particle.WAX_ON;
for (double y = yMin; y <= yMax; y += 0.5) { for (double y = yMin; y <= yMax; y += 0.5) {
@@ -51,18 +71,51 @@ public class Deathrun extends Appliance implements Event, Scorable {
@Override @Override
public void onDisable() { public void onDisable() {
World world = Bukkit.getWorlds().getFirst(); this.world.getWorldBorder().setSize(this.world.getWorldBorder().getMaxSize());
world.getWorldBorder().setSize(world.getWorldBorder().getMaxSize());
} }
@Override @Override
public void start(long durationSeconds) { public void start(long durationSeconds) {
this.isBeforeStart = false;
this.durationSeconds = durationSeconds; this.durationSeconds = durationSeconds;
Title title = Title.title(Component.text("Start"), Component.text("Laufe Richtung Osten! (positiv x)")); Title title = Title.title(Component.text("Start", NamedTextColor.GOLD), Component.text("Laufe Richtung Osten! (positiv x)", NamedTextColor.YELLOW));
Bukkit.getOnlinePlayers().forEach(player -> player.showTitle(title)); // 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(); this.world.getWorldBorder().setSize(this.world.getWorldBorder().getMaxSize());
world.getWorldBorder().setSize(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 @Override
@@ -74,6 +127,8 @@ public class Deathrun extends Appliance implements Event, Scorable {
public void stop() { public void stop() {
this.getScoreboardBuilder().stopAutomaticUpdates(); this.getScoreboardBuilder().stopAutomaticUpdates();
Title title = Title.title(Component.text("Ende!"), Component.empty()); Title title = Title.title(Component.text("Ende!"), Component.empty());
this.pvpTask.cancel();
this.pvpDisabled = true;
Bukkit.getOnlinePlayers().forEach(player -> { Bukkit.getOnlinePlayers().forEach(player -> {
player.showTitle(title); player.showTitle(title);
player.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard()); player.setScoreboard(Bukkit.getScoreboardManager().getNewScoreboard());
@@ -98,7 +153,10 @@ public class Deathrun extends Appliance implements Event, Scorable {
@Override @Override
protected @NotNull List<Listener> listeners() { protected @NotNull List<Listener> listeners() {
return List.of( return List.of(
new DeathrunPlayerMoveListener() new DeathrunPlayerMoveListener(),
new DeathrunPlayerDamageListener(),
new DeathrunPlayerJoinListener(),
new DeathrunPortalListener()
); );
} }
} }

View File

@@ -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<Deathrun> {
@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);
}
}

View File

@@ -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<Deathrun> {
@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);
}
}
}

View File

@@ -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.core.appliance.ApplianceListener;
import eu.mhsl.craftattack.spawn.event.appliances.deathrun.Deathrun;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
public class DeathrunPlayerMoveListener extends ApplianceListener<Deathrun> { public class DeathrunPlayerMoveListener extends ApplianceListener<Deathrun> {
@EventHandler @EventHandler
@@ -14,22 +16,34 @@ public class DeathrunPlayerMoveListener extends ApplianceListener<Deathrun> {
double minZ = spawnLocation.z() - this.getAppliance().getBorderDistance(); double minZ = spawnLocation.z() - this.getAppliance().getBorderDistance();
double maxZ = spawnLocation.z() + this.getAppliance().getBorderDistance(); double maxZ = spawnLocation.z() + this.getAppliance().getBorderDistance();
if(event.getTo().x() < minX + this.getAppliance().getBorderVisibilityDistance()) { 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) { if(event.getTo().x() < minX) {
event.setTo(event.getTo().clone().set(minX, event.getTo().y(), event.getTo().z())); event.setTo(event.getTo().clone().set(minX, event.getTo().y(), event.getTo().z()));
} }
} }
if(event.getTo().z() < minZ + this.getAppliance().getBorderVisibilityDistance()) { 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) { if(event.getTo().z() < minZ) {
event.setTo(event.getTo().clone().set(event.getTo().x(), event.getTo().y(), minZ)); event.setTo(event.getTo().clone().set(event.getTo().x(), event.getTo().y(), minZ));
} }
} }
if(event.getTo().z() > maxZ - this.getAppliance().getBorderVisibilityDistance()) { 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) { if(event.getTo().z() > maxZ) {
event.setTo(event.getTo().clone().set(event.getTo().x(), event.getTo().y(), 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()));
}
}
} }

View File

@@ -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<Deathrun> {
@EventHandler
public void onPlayerPortal(PlayerPortalEvent event) {
event.setCancelled(true);
}
}

View File

@@ -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.Main;
import eu.mhsl.craftattack.spawn.core.appliance.Appliance; import eu.mhsl.craftattack.spawn.core.appliance.Appliance;
import eu.mhsl.craftattack.spawn.core.appliance.ApplianceCommand; 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.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.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.util.Ticks; import net.kyori.adventure.util.Ticks;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.GameRule;
import org.bukkit.Statistic;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
import java.util.Map;
import static java.util.Map.entry;
public class EventController extends Appliance { public class EventController extends Appliance {
private List<Appliance> eventAppliances = null; private List<Appliance> eventAppliances = null;
private Event selectedEvent = null; private Event selectedEvent = null;
private long timerStart;
private int timerTaskId = -1; private int timerTaskId = -1;
private long durationMinutes;
private final Countdown countdown = new Countdown(
10,
this::format,
this::announce,
this::startEvent
);
private final Map<GameRule<Boolean>, 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 @Override
public void onEnable() { public void onEnable() {
@@ -36,6 +68,8 @@ public class EventController extends Appliance {
Appliance newAppliance = Main.instance().restartAppliance(appliance.getClass()); Appliance newAppliance = Main.instance().restartAppliance(appliance.getClass());
if(!(newAppliance instanceof Event newEvent)) throw new IllegalArgumentException("Appliance has to implement Event."); if(!(newAppliance instanceof Event newEvent)) throw new IllegalArgumentException("Appliance has to implement Event.");
this.selectedEvent = newEvent; this.selectedEvent = newEvent;
Bukkit.getOnlinePlayers().forEach(player -> player.setGameMode(GameMode.ADVENTURE));
IteratorUtil.worlds(world -> IteratorUtil.setGameRules(this.gameRulesAfterStart, true));
} }
public void unloadEvent() { public void unloadEvent() {
@@ -47,12 +81,58 @@ public class EventController extends Appliance {
this.selectedEvent = null; 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) { public void startEvent(long durationMinutes) {
if(this.selectedEvent == null) throw new ApplianceCommand.Error("There is no event selected!"); 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); this.selectedEvent.start(durationMinutes * 60);
if(this.selectedEvent instanceof Scorable scorable && scorable.automaticUpdates()) scorable.getScoreboardBuilder().startAutomaticUpdates(); if(this.selectedEvent instanceof Scorable scorable && scorable.automaticUpdates()) scorable.getScoreboardBuilder().startAutomaticUpdates();
// TODO: possibility for other dimensions // TODO: possibility for other dimensions
this.timerStart = Bukkit.getWorlds().getFirst().getFullTime();
this.timerTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask( this.timerTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(
Main.instance(), Main.instance(),
this::updateTimer, this::updateTimer,
@@ -66,6 +146,17 @@ public class EventController extends Appliance {
this.selectedEvent.stop(); this.selectedEvent.stop();
if(this.timerTaskId != -1) Bukkit.getScheduler().cancelTask(this.timerTaskId); if(this.timerTaskId != -1) Bukkit.getScheduler().cancelTask(this.timerTaskId);
this.timerTaskId = -1; 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() { public String getSelectedEvent() {
@@ -74,12 +165,10 @@ public class EventController extends Appliance {
} }
private void updateTimer() { 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(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!"))); Bukkit.getOnlinePlayers().forEach(player -> player.sendActionBar(Component.text("Fertig!")));
this.stopEvent();
return; return;
} }
@@ -95,7 +184,8 @@ public class EventController extends Appliance {
@Override @Override
protected @NotNull List<ApplianceCommand<?>> commands() { protected @NotNull List<ApplianceCommand<?>> commands() {
return List.of( return List.of(
new BigEventCommand() new BigEventCommand(),
new JoinCraftattackCommand()
); );
} }
} }

View File

@@ -35,12 +35,12 @@ public class BigEventCommand extends ApplianceCommand<EventController> {
} }
case "start": { case "start": {
if(args.length == 1) { if(args.length == 1) {
this.getAppliance().startEvent(60 * 2); this.getAppliance().scheduleStart(60 * 2);
break; break;
} }
if(args.length == 2) { if(args.length == 2) {
try { try {
this.getAppliance().startEvent(Long.parseLong(args[1])); this.getAppliance().scheduleStart(Long.parseLong(args[1]));
} catch(NumberFormatException e) { } catch(NumberFormatException e) {
throw new Error("Last argument has to be a long."); throw new Error("Last argument has to be a long.");
} }
@@ -48,6 +48,7 @@ public class BigEventCommand extends ApplianceCommand<EventController> {
break; break;
} }
case "stop": { case "stop": {
this.getAppliance().cancelStart();
this.getAppliance().stopEvent(); this.getAppliance().stopEvent();
break; break;
} }

View File

@@ -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<EventController> {
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");
}
}

View File

@@ -8,6 +8,7 @@ import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextDecoration; import net.kyori.adventure.text.format.TextDecoration;
import net.kyori.adventure.util.Ticks; import net.kyori.adventure.util.Ticks;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.scoreboard.DisplaySlot; import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective; import org.bukkit.scoreboard.Objective;
@@ -92,18 +93,37 @@ public class EventScoreboardBuilder {
int[] display = indices.distinct().sorted().toArray(); int[] display = indices.distinct().sorted().toArray();
for (int i = 0; i < display.length; i++) { List<String> lines = new ArrayList<>();
int idx = display[i]; 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); 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; return scoreboard;
} }
private String separatorLine(int n) {
return ChatColor.GRAY + "..." + ChatColor.RESET + " ".repeat(n);
}
public void startAutomaticUpdates() { public void startAutomaticUpdates() {
this.scoreboardUpdateTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask( this.scoreboardUpdateTaskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(
@@ -137,6 +157,16 @@ public class EventScoreboardBuilder {
return "%s. %s : %s".formatted(place+1, name, score); return "%s. %s : %s".formatted(place+1, name, score);
} }
public List<String> getScores() {
List<EventScoreEntry> scoreList = new ArrayList<>(this.playerScores);
scoreList.sort(this.scoreComparator);
ArrayList<String> 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) { private String trimName(String name) {
if (name == null) return "Unknown"; if (name == null) return "Unknown";
if (name.length() > 12) { if (name.length() > 12) {