Compare commits

..
10 Commits
17 changed files with 260 additions and 48 deletions
@@ -20,6 +20,7 @@ public final class Main extends JavaPlugin {
private LootService lootService; private LootService lootService;
private StatService statService; private StatService statService;
private BossBarService bossBarService; private BossBarService bossBarService;
private TabListService tabListService;
@Override @Override
public void onEnable() { public void onEnable() {
@@ -37,6 +38,8 @@ public final class Main extends JavaPlugin {
statService = new StatService(this, round); statService = new StatService(this, round);
playerTeleporterService = PlayerTeleporterService.createSingletonInstance(); playerTeleporterService = PlayerTeleporterService.createSingletonInstance();
roundService = RoundService.createSingletonInstance(round, this, lootService, statService, playerTeleporterService); roundService = RoundService.createSingletonInstance(round, this, lootService, statService, playerTeleporterService);
tabListService = new TabListService(round, roundService);
roundService.setTabListService(tabListService);
playerService = PlayerService.createSingletonInstance(round, roundService, playerTeleporterService); playerService = PlayerService.createSingletonInstance(round, roundService, playerTeleporterService);
bossBarService = BossBarService.createSingletonInstance(round, roundService); bossBarService = BossBarService.createSingletonInstance(round, roundService);
@@ -50,13 +53,13 @@ public final class Main extends JavaPlugin {
} }
private void registerCommands() { private void registerCommands() {
BaseCommand command = new BaseCommand(this, roundService, playerService, round, statService); BaseCommand command = new BaseCommand(this, roundService, playerService, round, statService, tabListService);
} }
private void registerEvents() { private void registerEvents() {
PluginManager pluginManager = getServer().getPluginManager(); PluginManager pluginManager = getServer().getPluginManager();
pluginManager.registerEvents(new PlayerDisconnectListener(playerService), this); pluginManager.registerEvents(new PlayerDisconnectListener(playerService), this);
pluginManager.registerEvents(new PlayerJoinListener(playerService), this); pluginManager.registerEvents(new PlayerJoinListener(playerService, tabListService), this);
pluginManager.registerEvents(new PlayerDamageListener(roundService, playerService, statService), this); pluginManager.registerEvents(new PlayerDamageListener(roundService, playerService, statService), this);
pluginManager.registerEvents(new ChestListener(roundService, lootService), this); pluginManager.registerEvents(new ChestListener(roundService, lootService), this);
pluginManager.registerEvents(new ItemSpawnListener(roundService), this); pluginManager.registerEvents(new ItemSpawnListener(roundService), this);
@@ -3,10 +3,7 @@ package com.alttd.hunger_games.commands;
import com.alttd.hunger_games.Main; import com.alttd.hunger_games.Main;
import com.alttd.hunger_games.commands.subcommands.*; import com.alttd.hunger_games.commands.subcommands.*;
import com.alttd.hunger_games.config.Messages; import com.alttd.hunger_games.config.Messages;
import com.alttd.hunger_games.services.PlayerService; import com.alttd.hunger_games.services.*;
import com.alttd.hunger_games.services.Round;
import com.alttd.hunger_games.services.RoundService;
import com.alttd.hunger_games.services.StatService;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
@@ -23,7 +20,7 @@ import java.util.stream.Collectors;
public class BaseCommand implements CommandExecutor, TabExecutor { public class BaseCommand implements CommandExecutor, TabExecutor {
private final List<SubCommand> subCommands; private final List<SubCommand> subCommands;
public BaseCommand(Main main, RoundService roundService, PlayerService playerService, Round round, StatService statService) { public BaseCommand(Main main, RoundService roundService, PlayerService playerService, Round round, StatService statService, TabListService tablistService) {
PluginCommand command = main.getCommand("hungergames"); PluginCommand command = main.getCommand("hungergames");
if (command == null) { if (command == null) {
subCommands = null; subCommands = null;
@@ -37,12 +34,13 @@ public class BaseCommand implements CommandExecutor, TabExecutor {
subCommands = new ArrayList<>(List.of( subCommands = new ArrayList<>(List.of(
new Reload(main), new Reload(main),
new RoundState(roundService), new RoundState(roundService),
new Register(playerService), new Register(playerService, tablistService),
new StartRound(round, roundService), new StartRound(round, roundService, playerService),
new NextPhase(round), new NextPhase(round),
new EndRound(round), new EndRound(round),
new Stuck(main), new Stuck(main),
new Stats(statService) new Stats(statService),
new ListPlayers(roundService)
)); ));
} }
@@ -0,0 +1,71 @@
package com.alttd.hunger_games.commands.subcommands;
import com.alttd.hunger_games.commands.SubCommand;
import com.alttd.hunger_games.config.Messages;
import com.alttd.hunger_games.data_objects.PLAYER_STATE;
import com.alttd.hunger_games.services.RoundService;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.JoinConfiguration;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.*;
public class ListPlayers extends SubCommand {
private final RoundService roundService;
public ListPlayers(RoundService roundService) {
this.roundService = roundService;
}
@Override
public boolean onCommand(CommandSender commandSender, String[] args) {
Set<UUID> registeredUuids = roundService.getPlayers(PLAYER_STATE.REGISTERED);
Set<UUID> spectatingUuids = roundService.getPlayers(PLAYER_STATE.SPECTATING);
List<Component> registeredNames = registeredUuids.stream()
.map(Bukkit::getPlayer)
.filter(Objects::nonNull)
.map(Player::name)
.toList();
List<Component> spectatingNames = spectatingUuids.stream()
.map(Bukkit::getPlayer)
.filter(Objects::nonNull)
.map(Player::name)
.toList();
Component inGamePlayers = Component.join(JoinConfiguration.commas(true), registeredNames);
Component spectators = Component.join(JoinConfiguration.commas(true), spectatingNames);
int inGameCount = registeredNames.size();
int totalCount = inGameCount + spectatingNames.size();
commandSender.sendRichMessage(Messages.COMMANDS.LIST_PLAYERS,
Placeholder.unparsed("in_game", String.valueOf(inGameCount)),
Placeholder.unparsed("total", String.valueOf(totalCount)),
Placeholder.component("in_game_players", inGamePlayers),
Placeholder.component("spectators", spectators)
);
return true;
}
@Override
public String getName() {
return "list";
}
@Override
public List<String> getTabComplete(CommandSender commandSender, String[] args) {
return Collections.emptyList();
}
@Override
public String getHelpMessage() {
return Messages.HELP.LIST;
}
}
@@ -5,6 +5,8 @@ import com.alttd.hunger_games.commands.shared_parsers.OnlinePlayerParser;
import com.alttd.hunger_games.config.Messages; import com.alttd.hunger_games.config.Messages;
import com.alttd.hunger_games.data_objects.PLAYER_STATE; import com.alttd.hunger_games.data_objects.PLAYER_STATE;
import com.alttd.hunger_games.services.PlayerService; import com.alttd.hunger_games.services.PlayerService;
import com.alttd.hunger_games.services.TabListService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@@ -15,16 +17,14 @@ import javax.annotation.Nullable;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@RequiredArgsConstructor
@Slf4j @Slf4j
public class Register extends SubCommand { public class Register extends SubCommand {
private final static OnlinePlayerParser ONLINE_PLAYER_PARSER = new OnlinePlayerParser(); private final static OnlinePlayerParser ONLINE_PLAYER_PARSER = new OnlinePlayerParser();
private final static int PLAYER_ARG = 1; private final static int PLAYER_ARG = 1;
private final PlayerService playerService; private final PlayerService playerService;
private final TabListService tabListService;
public Register(PlayerService playerService) {
this.playerService = playerService;
}
@Override @Override
public boolean onCommand(CommandSender commandSender, String[] args) { public boolean onCommand(CommandSender commandSender, String[] args) {
@@ -44,6 +44,7 @@ public class Register extends SubCommand {
playerToRegister.sendRichMessage(Messages.REGISTER.FAILED_TO_REGISTER_YOU); playerToRegister.sendRichMessage(Messages.REGISTER.FAILED_TO_REGISTER_YOU);
} else { } else {
notifyRegisteredPlayer(playerToRegister, nullablePlayerState); notifyRegisteredPlayer(playerToRegister, nullablePlayerState);
tabListService.updatePlayerColor(playerToRegister);
} }
if (commandSender instanceof Player commandPlayer) { if (commandSender instanceof Player commandPlayer) {
@@ -3,10 +3,12 @@ package com.alttd.hunger_games.commands.subcommands;
import com.alttd.hunger_games.commands.SubCommand; import com.alttd.hunger_games.commands.SubCommand;
import com.alttd.hunger_games.config.Messages; import com.alttd.hunger_games.config.Messages;
import com.alttd.hunger_games.data_objects.ROUND_STATE; import com.alttd.hunger_games.data_objects.ROUND_STATE;
import com.alttd.hunger_games.services.PlayerService;
import com.alttd.hunger_games.services.Round; import com.alttd.hunger_games.services.Round;
import com.alttd.hunger_games.services.RoundService; import com.alttd.hunger_games.services.RoundService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import java.util.List; import java.util.List;
@@ -16,11 +18,15 @@ public class StartRound extends SubCommand {
private final Round round; private final Round round;
private final RoundService roundService; private final RoundService roundService;
private final PlayerService playerService;
@Override @Override
public boolean onCommand(CommandSender commandSender, String[] args) { public boolean onCommand(CommandSender commandSender, String[] args) {
ROUND_STATE roundState = roundService.getRoundState(); ROUND_STATE roundState = roundService.getRoundState();
if (roundState == ROUND_STATE.PLAYER_REGISTRATION) { if (roundState == ROUND_STATE.PLAYER_REGISTRATION || roundState == ROUND_STATE.ENDED) {
Bukkit.getOnlinePlayers().stream()
.filter(player -> !player.hasPermission("hungergames.auto-join-bypass"))
.forEach(playerService::registerPlayer);
round.startRound(); round.startRound();
} else { } else {
commandSender.sendRichMessage(Messages.START_ROUND.CAN_NOT_START_ROUND, commandSender.sendRichMessage(Messages.START_ROUND.CAN_NOT_START_ROUND,
@@ -40,6 +40,7 @@ public class Config extends AbstractConfig {
public static class ROUND { public static class ROUND {
private static final String prefix = "round."; private static final String prefix = "round.";
public static String HG_WORLD = "world";
public static Duration COUNTDOWN = Duration.ofSeconds(10); public static Duration COUNTDOWN = Duration.ofSeconds(10);
public static Duration SAFE_PHASE = Duration.ofSeconds(30); public static Duration SAFE_PHASE = Duration.ofSeconds(30);
public static Duration TIME_TO_FINALE = Duration.ofMinutes(5); public static Duration TIME_TO_FINALE = Duration.ofMinutes(5);
@@ -54,6 +55,7 @@ public class Config extends AbstractConfig {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static void load() { private static void load() {
HG_WORLD = config.getString(prefix, "hg-world", HG_WORLD);
int countdownSeconds = config.getInt(prefix, "countdown-seconds", Math.toIntExact(COUNTDOWN.toSeconds())); int countdownSeconds = config.getInt(prefix, "countdown-seconds", Math.toIntExact(COUNTDOWN.toSeconds()));
COUNTDOWN = Duration.ofSeconds(countdownSeconds); COUNTDOWN = Duration.ofSeconds(countdownSeconds);
int safePhaseSeconds = config.getInt(prefix, "safe-phase-seconds", Math.toIntExact(SAFE_PHASE.toSeconds())); int safePhaseSeconds = config.getInt(prefix, "safe-phase-seconds", Math.toIntExact(SAFE_PHASE.toSeconds()));
@@ -33,6 +33,7 @@ public class Messages extends AbstractConfig {
public static String RELOAD = "<green>Reload config and messages: <gold>/hg reload</gold></green>"; public static String RELOAD = "<green>Reload config and messages: <gold>/hg reload</gold></green>";
public static String STUCK = "<green>Teleport to safety if stuck: <gold>/hg stuck</gold></green>"; public static String STUCK = "<green>Teleport to safety if stuck: <gold>/hg stuck</gold></green>";
public static String STATS = "<green>Show player stats: <gold>/hg stats [player]</gold></green>"; public static String STATS = "<green>Show player stats: <gold>/hg stats [player]</gold></green>";
public static String LIST = "<green>List all players in the game and spectators: <gold>/hg list</gold></green>";
public static String END_ROUND = "<green>End the game: <gold>/hg end</gold></green>"; public static String END_ROUND = "<green>End the game: <gold>/hg end</gold></green>";
@SuppressWarnings("unused") @SuppressWarnings("unused")
@@ -46,6 +47,7 @@ public class Messages extends AbstractConfig {
RELOAD = config.getString(prefix, "reload", RELOAD); RELOAD = config.getString(prefix, "reload", RELOAD);
STUCK = config.getString(prefix, "stuck", STUCK); STUCK = config.getString(prefix, "stuck", STUCK);
STATS = config.getString(prefix, "stats", STATS); STATS = config.getString(prefix, "stats", STATS);
LIST = config.getString(prefix, "list", LIST);
END_ROUND = config.getString(prefix, "end-round", END_ROUND); END_ROUND = config.getString(prefix, "end-round", END_ROUND);
} }
} }
@@ -89,6 +91,7 @@ public class Messages extends AbstractConfig {
public static String CHEST_EMPTY = "<red>This chest is empty!</red>"; public static String CHEST_EMPTY = "<red>This chest is empty!</red>";
public static String WINNER = "<gold><player> has won the Hunger Games!</gold>"; public static String WINNER = "<gold><player> has won the Hunger Games!</gold>";
public static String PLAYER_DEATH = "<red><player> has died! <gold><remaining></gold> players remaining.</red>"; public static String PLAYER_DEATH = "<red><player> has died! <gold><remaining></gold> players remaining.</red>";
public static String PLAYER_KILLED = "<red><victim> was killed by <killer>! <gold><remaining></gold> players remaining.</red>";
public static String BOSSBAR_COUNTDOWN = "<gold>Loot phase in <time></gold>"; public static String BOSSBAR_COUNTDOWN = "<gold>Loot phase in <time></gold>";
public static String BOSSBAR_PVP_COUNTDOWN = "<green>PVP starts in <time></green>"; public static String BOSSBAR_PVP_COUNTDOWN = "<green>PVP starts in <time></green>";
@@ -106,6 +109,7 @@ public class Messages extends AbstractConfig {
CHEST_EMPTY = config.getString(prefix, "chest-empty", CHEST_EMPTY); CHEST_EMPTY = config.getString(prefix, "chest-empty", CHEST_EMPTY);
WINNER = config.getString(prefix, "winner", WINNER); WINNER = config.getString(prefix, "winner", WINNER);
PLAYER_DEATH = config.getString(prefix, "player-death", PLAYER_DEATH); PLAYER_DEATH = config.getString(prefix, "player-death", PLAYER_DEATH);
PLAYER_KILLED = config.getString(prefix, "player-killed", PLAYER_KILLED);
BOSSBAR_COUNTDOWN = config.getString(prefix, "bossbar-countdown", BOSSBAR_COUNTDOWN); BOSSBAR_COUNTDOWN = config.getString(prefix, "bossbar-countdown", BOSSBAR_COUNTDOWN);
BOSSBAR_PVP_COUNTDOWN = config.getString(prefix, "bossbar-pvp-countdown", BOSSBAR_PVP_COUNTDOWN); BOSSBAR_PVP_COUNTDOWN = config.getString(prefix, "bossbar-pvp-countdown", BOSSBAR_PVP_COUNTDOWN);
@@ -208,10 +212,15 @@ public class Messages extends AbstractConfig {
private static final String prefix = "commands."; private static final String prefix = "commands.";
public static String NEXT_PHASE_SUCCESS = "<green>Skipping to the next phase/stage.</green>"; public static String NEXT_PHASE_SUCCESS = "<green>Skipping to the next phase/stage.</green>";
public static String LIST_PLAYERS = """
<gold>HungerGames Players (<in_game>/<total>):</gold>
<green>In Game: <white><in_game_players></white></green>
<yellow>Spectators: <white><spectators></white></yellow>""";
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static void load() { private static void load() {
NEXT_PHASE_SUCCESS = config.getString(prefix + "next-phase", "success", NEXT_PHASE_SUCCESS); NEXT_PHASE_SUCCESS = config.getString(prefix + "next-phase", "success", NEXT_PHASE_SUCCESS);
LIST_PLAYERS = config.getString(prefix, "list-players", LIST_PLAYERS);
} }
} }
} }
@@ -4,22 +4,47 @@ import com.alttd.hunger_games.data_objects.ROUND_STATE;
import com.alttd.hunger_games.services.RoundService; import com.alttd.hunger_games.services.RoundService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.bukkit.entity.Item; import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.entity.ItemSpawnEvent;
import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerDropItemEvent;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@RequiredArgsConstructor @RequiredArgsConstructor
public class ItemSpawnListener implements Listener { public class ItemSpawnListener implements Listener {
private final RoundService roundService; private final RoundService roundService;
private final Set<UUID> deathDrops = new HashSet<>();
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onItemSpawn(ItemSpawnEvent event) { public void onItemSpawn(ItemSpawnEvent event) {
if (deathDrops.remove(event.getEntity().getUniqueId())) {
event.getEntity().setTicksLived(5400); // 300 seconds total - 5400 ticks = 30 seconds left
return;
}
setDespawnDelay(event.getEntity()); setDespawnDelay(event.getEntity());
} }
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerDeath(EntityDeathEvent event) {
if (!(event.getEntity() instanceof Player)) {
return;
}
ROUND_STATE roundState = roundService.getRoundState();
if (roundState == ROUND_STATE.SAFE_PHASE || roundState == ROUND_STATE.KILL_PHASE || roundState == ROUND_STATE.FINALE) {
event.getDrops().forEach(itemStack -> {
Item item = event.getEntity().getWorld().dropItemNaturally(event.getEntity().getLocation(), itemStack);
deathDrops.add(item.getUniqueId());
});
}
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onPlayerDropItem(PlayerDropItemEvent event) { public void onPlayerDropItem(PlayerDropItemEvent event) {
setDespawnDelay(event.getItemDrop()); setDespawnDelay(event.getItemDrop());
@@ -45,8 +45,6 @@ public class PlayerDamageListener implements Listener {
Player player = event.getPlayer(); Player player = event.getPlayer();
event.setShowDeathMessages(false); event.setShowDeathMessages(false);
event.deathMessage(null); event.deathMessage(null);
event.getDrops().clear();
player.getInventory().clear();
playerService.handlePlayerDeath(player); playerService.handlePlayerDeath(player);
statService.addDeath(player.getUniqueId()); statService.addDeath(player.getUniqueId());
@@ -1,18 +1,33 @@
package com.alttd.hunger_games.event_listeners; package com.alttd.hunger_games.event_listeners;
import com.alttd.hunger_games.services.PlayerService; import com.alttd.hunger_games.services.PlayerService;
import com.alttd.hunger_games.services.TabListService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandException;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
@Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
public class PlayerJoinListener implements Listener { public class PlayerJoinListener implements Listener {
private final PlayerService playerService; private final PlayerService playerService;
private final TabListService tabListService;
@EventHandler @EventHandler
public void onPlayerJoin(PlayerJoinEvent event) { public void onPlayerJoin(PlayerJoinEvent event) {
playerService.handleJoin(event.getPlayer()); Player player = event.getPlayer();
playerService.handleJoin(player);
tabListService.updatePlayerColor(player);
try {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(),
String.format("lp user %s permission settemp cmi.kit.hunger-games true 7d", player.getName()));
} catch (CommandException e) {
log.error("Failed to set participant permission for {}", player.getName(), e);
}
} }
} }
@@ -66,6 +66,10 @@ public class BossBarService implements RoundListener {
} }
private void updateBossBarColor(ROUND_STATE state) { private void updateBossBarColor(ROUND_STATE state) {
if (state == ROUND_STATE.ENDED || state == ROUND_STATE.PLAYER_REGISTRATION) {
hideAll();
return;
}
switch (state) { switch (state) {
case COUNTDOWN -> bossBar.color(BossBar.Color.YELLOW); case COUNTDOWN -> bossBar.color(BossBar.Color.YELLOW);
case SAFE_PHASE -> bossBar.color(BossBar.Color.GREEN); case SAFE_PHASE -> bossBar.color(BossBar.Color.GREEN);
@@ -92,27 +96,20 @@ public class BossBarService implements RoundListener {
} }
private void updateViewers() { private void updateViewers() {
Set<UUID> registeredPlayers = roundService.getPlayers(PLAYER_STATE.REGISTERED); if (roundService.getRoundState() == ROUND_STATE.ENDED || roundService.getRoundState() == ROUND_STATE.PLAYER_REGISTRATION) {
hideAll();
// Add new viewers return;
registeredPlayers.stream()
.filter(viewers::add)
.map(Bukkit::getPlayer)
.filter(Objects::nonNull)
.forEach(player -> player.showBossBar(bossBar));
// Remove old viewers
Set<UUID> toRemove = viewers.stream()
.filter(uuid -> !registeredPlayers.contains(uuid))
.collect(Collectors.toSet());
for (UUID uuid : toRemove) {
viewers.remove(uuid);
Player player = Bukkit.getPlayer(uuid);
if (player != null) {
player.hideBossBar(bossBar);
}
} }
Bukkit.getOnlinePlayers().forEach(player -> {
if (viewers.add(player.getUniqueId())) {
player.showBossBar(bossBar);
}
});
viewers.removeIf(uuid -> {
Player player = Bukkit.getPlayer(uuid);
return player == null || !player.isOnline();
});
} }
private void hideAll() { private void hideAll() {
@@ -91,6 +91,7 @@ public class PlayerService implements RoundListener {
} }
public void handleDisconnect(Player player) { public void handleDisconnect(Player player) {
player.playerListName(null);
UUID uuid = player.getUniqueId(); UUID uuid = player.getUniqueId();
roundService.setPlayerState(uuid, PLAYER_STATE.DISCONNECTED); roundService.setPlayerState(uuid, PLAYER_STATE.DISCONNECTED);
} }
@@ -113,9 +114,17 @@ public class PlayerService implements RoundListener {
roundService.setPlayerState(uuid, PLAYER_STATE.SPECTATING); roundService.setPlayerState(uuid, PLAYER_STATE.SPECTATING);
int remaining = roundService.getPlayers(PLAYER_STATE.REGISTERED).size(); int remaining = roundService.getPlayers(PLAYER_STATE.REGISTERED).size();
Bukkit.broadcast(MiniMessage.miniMessage().deserialize(Messages.GAME.PLAYER_DEATH, Player killer = player.getKiller();
Placeholder.component("player", player.name()), if (killer != null) {
Placeholder.unparsed("remaining", String.valueOf(remaining)))); Bukkit.broadcast(MiniMessage.miniMessage().deserialize(Messages.GAME.PLAYER_KILLED,
Placeholder.component("victim", player.name()),
Placeholder.component("killer", killer.name()),
Placeholder.unparsed("remaining", String.valueOf(remaining))));
} else {
Bukkit.broadcast(MiniMessage.miniMessage().deserialize(Messages.GAME.PLAYER_DEATH,
Placeholder.component("player", player.name()),
Placeholder.unparsed("remaining", String.valueOf(remaining))));
}
} }
public void handlePlayerRespawn(PlayerRespawnEvent event) { public void handlePlayerRespawn(PlayerRespawnEvent event) {
@@ -131,13 +140,18 @@ public class PlayerService implements RoundListener {
if (optionalPlayerState.isPresent()) { if (optionalPlayerState.isPresent()) {
PLAYER_STATE playerState = optionalPlayerState.get(); PLAYER_STATE playerState = optionalPlayerState.get();
return Optional.of(switch (playerState) { return Optional.of(switch (playerState) {
case DISCONNECTED, SPECTATING -> PLAYER_STATE.SPECTATING; case DISCONNECTED, SPECTATING -> {
if (roundState.equals(ROUND_STATE.ENDED)) {
yield PLAYER_STATE.REGISTERED;
}
yield PLAYER_STATE.SPECTATING;
}
case REGISTERED -> PLAYER_STATE.REGISTERED; case REGISTERED -> PLAYER_STATE.REGISTERED;
}); });
} }
return switch (roundState) { return switch (roundState) {
case PLAYER_REGISTRATION, COUNTDOWN -> Optional.of(PLAYER_STATE.REGISTERED); case PLAYER_REGISTRATION, COUNTDOWN, ENDED -> Optional.of(PLAYER_STATE.REGISTERED);
case KILL_PHASE, FINALE, ENDED, SAFE_PHASE -> Optional.of(PLAYER_STATE.SPECTATING); case KILL_PHASE, FINALE, SAFE_PHASE -> Optional.of(PLAYER_STATE.SPECTATING);
}; };
} }
} }
@@ -77,7 +77,7 @@ public class Round {
} }
public void startRound() { public void startRound() {
if (!roundState.equals(ROUND_STATE.PLAYER_REGISTRATION)) { if (!roundState.equals(ROUND_STATE.PLAYER_REGISTRATION) && !roundState.equals(ROUND_STATE.ENDED)) {
throw new IllegalStateException("Round can not be started before player registration."); throw new IllegalStateException("Round can not be started before player registration.");
} }
roundState = ROUND_STATE.COUNTDOWN; roundState = ROUND_STATE.COUNTDOWN;
@@ -15,6 +15,8 @@ import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.World;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
@@ -38,6 +40,8 @@ public class RoundService implements RoundListener {
private final Round round; private final Round round;
@Setter @Setter
private BossBarService bossBarService; private BossBarService bossBarService;
@Setter
private TabListService tabListService;
public static RoundService createSingletonInstance(Round round, Main main, LootService lootService, StatService statService, PlayerTeleporterService playerTeleporterService) { public static RoundService createSingletonInstance(Round round, Main main, LootService lootService, StatService statService, PlayerTeleporterService playerTeleporterService) {
if (instance != null) { if (instance != null) {
@@ -73,6 +77,13 @@ public class RoundService implements RoundListener {
} }
} }
if (tabListService != null) {
Player player = Bukkit.getPlayer(uuid);
if (player != null) {
tabListService.updatePlayerColor(player);
}
}
if (!roundState.equals(ROUND_STATE.KILL_PHASE) && !roundState.equals(ROUND_STATE.FINALE)) { if (!roundState.equals(ROUND_STATE.KILL_PHASE) && !roundState.equals(ROUND_STATE.FINALE)) {
return; return;
} }
@@ -117,7 +128,10 @@ public class RoundService implements RoundListener {
public void stateChange(ROUND_STATE roundState) { public void stateChange(ROUND_STATE roundState) {
this.roundState = roundState; this.roundState = roundState;
stopFreeze(); stopFreeze();
if (roundState.equals(ROUND_STATE.PLAYER_REGISTRATION)) { if (roundState.equals(ROUND_STATE.PLAYER_REGISTRATION) || roundState.equals(ROUND_STATE.ENDED)) {
if (roundState.equals(ROUND_STATE.ENDED)) {
cleanupItems();
}
clear(); clear();
lootService.clear(); lootService.clear();
} }
@@ -137,7 +151,7 @@ public class RoundService implements RoundListener {
WorldBorderUtil.resetBorder(); WorldBorderUtil.resetBorder();
} }
if (roundState.equals(ROUND_STATE.FINALE)) { if (roundState.equals(ROUND_STATE.FINALE)) {
WorldBorderUtil.setSize(Config.ROUND.FINALE_BORDER_SIZE); WorldBorderUtil.setSize(Config.ROUND.FINALE_BORDER_SIZE, 1);
} }
if (!roundState.equals(ROUND_STATE.ENDED) && !roundState.equals(ROUND_STATE.PLAYER_REGISTRATION)) { if (!roundState.equals(ROUND_STATE.ENDED) && !roundState.equals(ROUND_STATE.PLAYER_REGISTRATION)) {
Bukkit.broadcast(MiniMessage.miniMessage().deserialize(Messages.GAME.NEXT_STATE, Placeholder.parsed("round", roundState.getHumanReadableName()))); Bukkit.broadcast(MiniMessage.miniMessage().deserialize(Messages.GAME.NEXT_STATE, Placeholder.parsed("round", roundState.getHumanReadableName())));
@@ -159,4 +173,13 @@ public class RoundService implements RoundListener {
main.getServer().getPluginManager().registerEvents(playerMovementListener, main); main.getServer().getPluginManager().registerEvents(playerMovementListener, main);
} }
private void cleanupItems() {
World world = Bukkit.getWorld(Config.ROUND.HG_WORLD);
if (world == null) {
log.error("Unable to cleanup items, world {} not found", Config.ROUND.HG_WORLD);
return;
}
world.getEntitiesByClass(Item.class).forEach(Item::remove);
}
} }
@@ -45,7 +45,7 @@ public class StatService implements RoundListener {
@Override @Override
public void stateChange(ROUND_STATE roundState) { public void stateChange(ROUND_STATE roundState) {
if (roundState.equals(ROUND_STATE.FINALE)) { if (roundState.equals(ROUND_STATE.ENDED)) {
saveRoundStats(); saveRoundStats();
} }
if (roundState.equals(ROUND_STATE.PLAYER_REGISTRATION)) { if (roundState.equals(ROUND_STATE.PLAYER_REGISTRATION)) {
@@ -0,0 +1,46 @@
package com.alttd.hunger_games.services;
import com.alttd.hunger_games.data_objects.PLAYER_STATE;
import com.alttd.hunger_games.data_objects.ROUND_STATE;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.UUID;
public class TabListService implements RoundListener {
private final RoundService roundService;
private ROUND_STATE roundState;
public TabListService(Round round, RoundService roundService) {
this.roundService = roundService;
this.roundState = round.register(this);
}
public void updatePlayerColor(Player player) {
if (!player.isOnline()) {
return;
}
if (roundState == null || roundState == ROUND_STATE.ENDED || roundState == ROUND_STATE.PLAYER_REGISTRATION) {
player.playerListName(null);
return;
}
PLAYER_STATE state = roundService.getPlayerState(player.getUniqueId()).orElse(PLAYER_STATE.SPECTATING);
switch (state) {
case REGISTERED -> player.playerListName(player.name().color(NamedTextColor.GREEN));
case SPECTATING, DISCONNECTED -> player.playerListName(player.name().color(NamedTextColor.RED));
}
}
public void updateAllPlayers() {
Bukkit.getOnlinePlayers().forEach(this::updatePlayerColor);
}
@Override
public void stateChange(ROUND_STATE roundState) {
this.roundState = roundState;
updateAllPlayers();
}
}
+4
View File
@@ -3,6 +3,10 @@ version: ${version}
main: com.alttd.hunger_games.Main main: com.alttd.hunger_games.Main
api-version: "1.21" api-version: "1.21"
# Load after Multiverse-Core to be able to find the teleport locations
softdepend:
- Multiverse-Core
commands: commands:
hungergames: hungergames:
description: Main HungerGames command description: Main HungerGames command