Compare commits

...

4 Commits

17 changed files with 637 additions and 11 deletions

View File

@ -102,10 +102,9 @@ A Minecraft survival/PvP plugin with configurable loot, shrinking world border,
### Player States
Track each registered player in one of these states:
- [ ] `REGISTERED` — signed up, round not yet started
- [ ] `ALIVE` — actively in the round
- [ ] `DEAD` — eliminated, waiting in the safe room
- [ ] `IN_GAME` — actively in the round
- [ ] `DISCONNECTED` — left the server mid-round
- [ ] `SPECTATING`admin/non-participant observer
- [ ] `SPECTATING` — non-participant/dead observer
### Disconnect Handling
- [ ] On disconnect during COUNTDOWN: remove from round, free their spawn slot

View File

@ -3,6 +3,9 @@ package com.alttd.hunger_games;
import com.alttd.hunger_games.commands.BaseCommand;
import com.alttd.hunger_games.config.Config;
import com.alttd.hunger_games.config.Messages;
import com.alttd.hunger_games.services.PlayerService;
import com.alttd.hunger_games.services.Round;
import com.alttd.hunger_games.services.RoundService;
import lombok.extern.slf4j.Slf4j;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
@ -10,24 +13,32 @@ import org.bukkit.plugin.java.JavaPlugin;
@Slf4j
public final class Main extends JavaPlugin {
private BaseCommand command;
private RoundService roundService;
private PlayerService playerService;
@Override
public void onEnable() {
log.info("Starting HungerGames");
reloadConfigs();
registerServices();
registerCommands();
registerEvents();
registerSchedulers();
}
private void registerServices() {
Round round = Round.createSingletonInstance();
roundService = new RoundService(round);
playerService = new PlayerService(roundService);
}
@Override
public void onDisable() {
log.info("Disabling HungerGames");
}
private void registerCommands() {
command = new BaseCommand(this);
BaseCommand command = new BaseCommand(this, roundService, playerService);
}
private void registerEvents() {

View File

@ -1,7 +1,11 @@
package com.alttd.hunger_games.commands;
import com.alttd.hunger_games.Main;
import com.alttd.hunger_games.commands.subcommands.Register;
import com.alttd.hunger_games.commands.subcommands.RoundState;
import com.alttd.hunger_games.config.Messages;
import com.alttd.hunger_games.services.PlayerService;
import com.alttd.hunger_games.services.RoundService;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
@ -17,7 +21,7 @@ import java.util.stream.Collectors;
public class BaseCommand implements CommandExecutor, TabExecutor {
private final List<SubCommand> subCommands;
public BaseCommand(Main main) {
public BaseCommand(Main main, RoundService roundService, PlayerService playerService) {
PluginCommand command = main.getCommand("hungergames");
if (command == null) {
subCommands = null;
@ -28,7 +32,10 @@ public class BaseCommand implements CommandExecutor, TabExecutor {
command.setTabCompleter(this);
command.setAliases(List.of("hg"));
subCommands = new ArrayList<>(List.of());
subCommands = new ArrayList<>(List.of(
new RoundState(roundService),
new Register(playerService)
));
}
@Override
@ -42,8 +49,9 @@ public class BaseCommand implements CommandExecutor, TabExecutor {
}
SubCommand subCommand = getSubCommand(args[0]);
if (subCommand == null)
if (subCommand == null) {
return false;
}
if (!commandSender.hasPermission(subCommand.getPermission())) {
commandSender.sendRichMessage(Messages.GENERIC.NO_PERMISSION, Placeholder.parsed("permission", subCommand.getPermission()));
@ -70,11 +78,12 @@ public class BaseCommand implements CommandExecutor, TabExecutor {
);
} else {
SubCommand subCommand = getSubCommand(args[0]);
if (subCommand != null && commandSender.hasPermission(subCommand.getPermission()))
if (subCommand != null && commandSender.hasPermission(subCommand.getPermission())) {
res.addAll(subCommand.getTabComplete(commandSender, args).stream()
.filter(str -> str.toLowerCase().startsWith(args[args.length - 1].toLowerCase()))
.toList());
}
}
return res;
}

View File

@ -0,0 +1,22 @@
package com.alttd.hunger_games.commands.shared_parsers;
import com.alttd.hunger_games.commands.ArgumentParser;
import com.alttd.hunger_games.config.Messages;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.Optional;
public class OnlinePlayerParser implements ArgumentParser<Player> {
@Override
public Optional<Player> parse(CommandSender commandSender, String playerName) {
Player player = commandSender.getServer().getPlayer(playerName);
if (player == null || !player.isOnline()) {
commandSender.sendRichMessage(Messages.GENERIC.PLAYER_NOT_FOUND, Placeholder.parsed("player", playerName));
return Optional.empty();
}
return Optional.of(player);
}
}

View File

@ -0,0 +1,110 @@
package com.alttd.hunger_games.commands.subcommands;
import com.alttd.hunger_games.commands.SubCommand;
import com.alttd.hunger_games.commands.shared_parsers.OnlinePlayerParser;
import com.alttd.hunger_games.config.Messages;
import com.alttd.hunger_games.data_objects.PLAYER_STATE;
import com.alttd.hunger_games.services.PlayerService;
import lombok.extern.slf4j.Slf4j;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Optional;
@Slf4j
public class Register extends SubCommand {
private final static OnlinePlayerParser ONLINE_PLAYER_PARSER = new OnlinePlayerParser();
private final static int PLAYER_ARG = 1;
private final PlayerService playerService;
public Register(PlayerService playerService) {
this.playerService = playerService;
}
@Override
public boolean onCommand(CommandSender commandSender, String[] args) {
if (args.length != 2) {
return false;
}
Optional<Player> optionalPlayer = ONLINE_PLAYER_PARSER.parse(commandSender, args[PLAYER_ARG]);
if (optionalPlayer.isEmpty()) {
return true;
}
Player playerToRegister = optionalPlayer.get();
Optional<PLAYER_STATE> optionalPlayerState = playerService.registerPlayer(playerToRegister);
PLAYER_STATE nullablePlayerState = optionalPlayerState.orElse(null);
if (optionalPlayerState.isEmpty()) {
playerToRegister.sendRichMessage(Messages.REGISTER.FAILED_TO_REGISTER_YOU);
} else {
notifyRegisteredPlayer(playerToRegister, nullablePlayerState);
}
if (commandSender instanceof Player commandPlayer) {
notifyPlayerCommandSender(commandPlayer, nullablePlayerState, playerToRegister);
}
logResult(nullablePlayerState, playerToRegister);
return true;
}
private void notifyRegisteredPlayer(Player playerToRegister, PLAYER_STATE nullablePlayerState) {
switch (nullablePlayerState) {
case REGISTERED -> playerToRegister.sendRichMessage(Messages.REGISTER.SUCCESSFUL_REGISTER);
case SPECTATING -> playerToRegister.sendRichMessage(Messages.REGISTER.GAME_RUNNING);
}
}
private void logResult(PLAYER_STATE nullablePlayerState, Player playerToRegister) {
if (nullablePlayerState == null) {
log.info("Failed to register player {}", playerToRegister.getName());
return;
}
switch (nullablePlayerState) {
case REGISTERED -> log.info("Registered player {} for the next round", playerToRegister.getName());
case IN_GAME -> log.info("Player {} is already in a round", playerToRegister.getName());
case DISCONNECTED -> log.info("Player {} is disconnected (should not be possible)", playerToRegister.getName());
case SPECTATING -> log.info("Player {} is now spectating the game", playerToRegister.getName());
}
}
private static void notifyPlayerCommandSender(Player commandPlayer, @Nullable PLAYER_STATE playerState, Player playerToRegister) {
if (playerState == null) {
commandPlayer.sendRichMessage(Messages.REGISTER.FAILED_TO_REGISTER_PLAYER,
Placeholder.component("player", playerToRegister.name()));
return;
}
switch (playerState) {
case REGISTERED -> commandPlayer.sendRichMessage(Messages.REGISTER.PLAYER_REGISTERED,
Placeholder.component("player", playerToRegister.name()));
case IN_GAME -> commandPlayer.sendRichMessage(Messages.REGISTER.PLAYER_ALREADY_IN_ROUND,
Placeholder.component("player", playerToRegister.name()));
case DISCONNECTED -> {
//should not be possible
}
case SPECTATING -> commandPlayer.sendRichMessage(Messages.REGISTER.PLAYER_SPECTATING,
Placeholder.component("player", playerToRegister.name()));
}
}
@Override
public String getName() {
return "register";
}
@Override
public List<String> getTabComplete(CommandSender commandSender, String[] args) {
return List.of();
}
@Override
public String getHelpMessage() {
return Messages.HELP.REGISTER;
}
}

View File

@ -0,0 +1,39 @@
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.services.RoundService;
import lombok.RequiredArgsConstructor;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.command.CommandSender;
import java.util.List;
@RequiredArgsConstructor
public class RoundState extends SubCommand {
private final RoundService roundService;
@Override
public boolean onCommand(CommandSender commandSender, String[] args) {
commandSender.sendRichMessage(Messages.ROUND_STATE.ROUND_STATE,
Placeholder.parsed("round_state",
roundService.getRoundState().getHumandReadableName()));
return true;
}
@Override
public String getName() {
return "roundstate";
}
@Override
public List<String> getTabComplete(CommandSender commandSender, String[] args) {
return List.of();
}
@Override
public String getHelpMessage() {
return Messages.HELP.ROUND_STATE;
}
}

View File

@ -0,0 +1,36 @@
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.services.Round;
import lombok.RequiredArgsConstructor;
import org.bukkit.command.CommandSender;
import java.util.List;
@RequiredArgsConstructor
public class StartRound extends SubCommand {
private final Round round;
@Override
public boolean onCommand(CommandSender commandSender, String[] args) {
round.startRound();
return true;
}
@Override
public String getName() {
return "start";
}
@Override
public List<String> getTabComplete(CommandSender commandSender, String[] args) {
return List.of();
}
@Override
public String getHelpMessage() {
return Messages.HELP.START_ROUND;
}
}

View File

@ -1,8 +1,14 @@
package com.alttd.hunger_games.config;
import com.alttd.hunger_games.data_objects.GameStage;
import lombok.extern.slf4j.Slf4j;
import org.bukkit.configuration.ConfigurationSection;
import java.io.File;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@Slf4j
public class Config extends AbstractConfig {
@ -31,4 +37,60 @@ public class Config extends AbstractConfig {
private static void load() {
}
}
public static class ROUND {
private static final String prefix = "round.";
public static Duration COUNTDOWN = Duration.ofSeconds(10);
public static List<GameStage> STAGES = List.of(
GameStage.builder().duration(Duration.ofMinutes(5)).worldBorderSize(1000).build(),
GameStage.builder().duration(Duration.ofMinutes(5)).worldBorderSize(750).build(),
GameStage.builder().duration(Duration.ofMinutes(5)).worldBorderSize(500).build()
);
@SuppressWarnings("unused")
private static void load() {
int countdownSeconds = config.getInt(prefix, "countdown-seconds", Math.toIntExact(COUNTDOWN.toSeconds()));
COUNTDOWN = Duration.ofSeconds(countdownSeconds);
ConfigurationSection configurationSection = config.getConfigurationSection(prefix + "stages");
Set<String> keys = configurationSection.getKeys(false);
STAGES = getGameStages(keys, configurationSection);
}
private static List<GameStage> getGameStages(Set<String> keys, ConfigurationSection configurationSection) {
if (keys.isEmpty()) {
int key = 0;
for (GameStage stage : STAGES) {
ConfigurationSection section = configurationSection.createSection(String.valueOf(key++));
section.set("duration-seconds", stage.getDuration().toSeconds());
section.set("world-border-size", stage.getWorldBorderSize());
}
return STAGES;
}
List<GameStage> gameStageList = new ArrayList<>();
for (String key : keys) {
ConfigurationSection section = configurationSection.getConfigurationSection(key);
if (section == null) {
throw new IllegalStateException("Stage section is null for key [" + key + "] but is in the list of retrieved keys");
}
if (!section.contains("duration-seconds")) {
log.error("Missing duration-seconds in stage {}.", key);
continue;
}
if (!section.contains("world-border-size")) {
log.error("Missing world-border-size in stage {}.", key);
continue;
}
int durationSeconds = section.getInt("duration-seconds");
int worldBorderSize = section.getInt("world-border-size");
gameStageList.add(GameStage.builder()
.duration(Duration.ofSeconds(durationSeconds))
.worldBorderSize(worldBorderSize)
.build());
}
return gameStageList;
}
}
}

View File

@ -1,5 +1,7 @@
package com.alttd.hunger_games.config;
import org.jetbrains.annotations.NotNull;
import java.io.File;
public class Messages extends AbstractConfig {
@ -24,11 +26,17 @@ public class Messages extends AbstractConfig {
public static String HELP_MESSAGE_WRAPPER = "<gold>HungerGames help:\n<commands></gold>";
public static String HELP_MESSAGE = "<green>Show this menu: <gold>/hg help</gold></green>";
public static String ROUND_STATE = "<green>Show the current round state: <gold>/hg roundstate</gold></green>";
public static String REGISTER = "<green>Register a player for the game: <gold>/hg register <player></gold></green>";
public static String START_ROUND = "<green>Start the game: <gold>/hg start</gold></green>";
@SuppressWarnings("unused")
private static void load() {
HELP_MESSAGE_WRAPPER = config.getString(prefix, "help-wrapper", HELP_MESSAGE_WRAPPER);
HELP_MESSAGE = config.getString(prefix, "help", HELP_MESSAGE);
ROUND_STATE = config.getString(prefix, "round-state", ROUND_STATE);
REGISTER = config.getString(prefix, "register", REGISTER);
START_ROUND = config.getString(prefix, "start", START_ROUND);
}
}
@ -46,4 +54,38 @@ public class Messages extends AbstractConfig {
PLAYER_NOT_FOUND = config.getString(prefix, "player-only", PLAYER_NOT_FOUND);
}
}
public static class ROUND_STATE {
private static final String prefix = "round-state.";
public static String ROUND_STATE = "<green>Current round state is: <gold>round_state</gold></green>";
@SuppressWarnings("unused")
private static void load() {
ROUND_STATE = config.getString(prefix, "round-state", ROUND_STATE);
}
}
public static class REGISTER {
private static final String prefix = "register.";
public static String FAILED_TO_REGISTER_YOU = "<red>You were unable to join HungerGames because no HungerGames round was found</red>";
public static String FAILED_TO_REGISTER_PLAYER = "<red>Unable to register player <player></red>";
public static String PLAYER_REGISTERED = "<green>Registered <player> for the game</green>";
public static String PLAYER_ALREADY_IN_ROUND = "<yellow><player> is already in a round</yellow>";
public static String PLAYER_SPECTATING = "<yellow><player> is now spectating the game</yellow>";
public static String SUCCESSFUL_REGISTER = "<green>Successfully registered you for the upcoming Hunger Games round</green>";
public static String GAME_RUNNING = "<yellow>The game is currently running, you will need to spectate the current round</yellow>";
@SuppressWarnings("unused")
private static void load() {
FAILED_TO_REGISTER_YOU = config.getString(prefix, "failed", FAILED_TO_REGISTER_YOU);
FAILED_TO_REGISTER_PLAYER = config.getString(prefix, "failed-player", FAILED_TO_REGISTER_PLAYER);
PLAYER_REGISTERED = config.getString(prefix, "player-registered", PLAYER_REGISTERED);
PLAYER_ALREADY_IN_ROUND = config.getString(prefix, "player-already-in-game", PLAYER_ALREADY_IN_ROUND);
PLAYER_SPECTATING = config.getString(prefix, "player-spectating", PLAYER_SPECTATING);
SUCCESSFUL_REGISTER = config.getString(prefix, "successful", SUCCESSFUL_REGISTER);
GAME_RUNNING = config.getString(prefix, "game-running", GAME_RUNNING);
}
}
}

View File

@ -0,0 +1,15 @@
package com.alttd.hunger_games.data_objects;
import lombok.Builder;
import lombok.Getter;
import java.time.Duration;
@Builder
@Getter
public class GameStage {
private final Duration duration;
private final int worldBorderSize;
}

View File

@ -0,0 +1,8 @@
package com.alttd.hunger_games.data_objects;
public enum PLAYER_STATE {
REGISTERED,
IN_GAME,
DISCONNECTED,
SPECTATING
}

View File

@ -0,0 +1,28 @@
package com.alttd.hunger_games.data_objects;
import java.util.Optional;
public enum ROUND_STATE {
PLAYER_REGISTRATION,
COUNTDOWN,
KILL_PHASE,
FINALE,
ENDED;
public Optional<ROUND_STATE> next() {
if (ordinal() == ENDED.ordinal()) {
return Optional.empty();
}
return Optional.of(values()[ordinal() + 1]);
}
public String getHumandReadableName() {
return switch (this) {
case PLAYER_REGISTRATION -> "Player Registration";
case COUNTDOWN -> "Countdown";
case KILL_PHASE -> "Kill Phase";
case FINALE -> "Finale";
case ENDED -> "Ended";
};
}
}

View File

@ -0,0 +1,19 @@
package com.alttd.hunger_games.game;
import lombok.experimental.UtilityClass;
@UtilityClass
public class GameStageHandler {
public static void handleStageChange(int worldBorderSize) {
//TODO change world border size and handle stage change
}
public static void handleCountdownEnd() {
//TODO free players and handle stage change
}
public static void handleWarmup() {
//TODO tp players to start area etc (might be handled by state change already, so maybe just messages)
}
}

View File

@ -0,0 +1,81 @@
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 lombok.RequiredArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.*;
@RequiredArgsConstructor
public class PlayerService implements RoundListener {
private final RoundService roundService;
private ROUND_STATE roundState;
@Override
public void stateChange(ROUND_STATE roundState) {
this.roundState = roundState;
switch (roundState) {
case PLAYER_REGISTRATION, KILL_PHASE -> {
//Nothing
}
case COUNTDOWN -> {
setNonRegisteredPlayersToSpectator();
//TODO: teleport players to spawn location
}
case FINALE -> {
//TODO: teleport players to finale location
}
case ENDED -> {
roundService.clear();
//TODO: teleport everyone to spawn (or spectator?) location
}
}
}
private void setNonRegisteredPlayersToSpectator() {
Set<UUID> playerUUIDs = roundService.getPlayers(PLAYER_STATE.REGISTERED);
List<Player> playerList = new ArrayList<>(Bukkit.getOnlinePlayers());
List<Player> unregisteredPlayers = playerList.stream().filter(player -> !playerUUIDs.contains(player.getUniqueId())).toList();
unregisteredPlayers.forEach(player -> roundService.setPlayerState(player.getUniqueId(), PLAYER_STATE.SPECTATING));
}
public Optional<PLAYER_STATE> registerPlayer(Player player) {
if (roundState == null) {
return Optional.empty();
}
Optional<PLAYER_STATE> optionalPlayerState = determinePlayerState(player.getUniqueId());
if (optionalPlayerState.isEmpty()) {
return Optional.empty();
}
PLAYER_STATE playerState = optionalPlayerState.get();
if (playerState == PLAYER_STATE.SPECTATING) {
//TODO: teleport player to spectator location
}
roundService.setPlayerState(player.getUniqueId(), playerState);
return optionalPlayerState;
}
private Optional<PLAYER_STATE> determinePlayerState(UUID playerUuid) {
if (roundState == null) {
return Optional.empty();
}
Optional<PLAYER_STATE> optionalPlayerState = roundService.getPlayerState(playerUuid);
if (optionalPlayerState.isPresent()) {
PLAYER_STATE playerState = optionalPlayerState.get();
return Optional.of(switch (playerState) {
case DISCONNECTED, SPECTATING -> PLAYER_STATE.SPECTATING;
case IN_GAME -> PLAYER_STATE.IN_GAME;
case REGISTERED -> PLAYER_STATE.REGISTERED;
});
}
return switch (roundState) {
case PLAYER_REGISTRATION, COUNTDOWN -> Optional.of(PLAYER_STATE.REGISTERED);
case KILL_PHASE, FINALE, ENDED -> Optional.of(PLAYER_STATE.SPECTATING);
};
}
}

View File

@ -0,0 +1,89 @@
package com.alttd.hunger_games.services;
import com.alttd.hunger_games.config.Config;
import com.alttd.hunger_games.data_objects.GameStage;
import com.alttd.hunger_games.data_objects.ROUND_STATE;
import com.alttd.hunger_games.game.GameStageHandler;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Round {
private static Round instance = null;
private final List<RoundListener> listeners = new ArrayList<>();
private ROUND_STATE roundState = ROUND_STATE.PLAYER_REGISTRATION;
private ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
private Round() {
}
public static Round createSingletonInstance() throws IllegalStateException {
if (instance != null) {
throw new IllegalStateException("Round is already initialized.");
}
instance = new Round();
return instance;
}
public ROUND_STATE register(RoundListener listener) {
listeners.add(listener);
return roundState;
}
public void unregister(RoundListener listener) {
listeners.remove(listener);
}
public void stop() {
roundState = ROUND_STATE.PLAYER_REGISTRATION;
listeners.forEach(roundListener -> roundListener.stateChange(roundState));
}
private void nextStage() {
Optional<ROUND_STATE> optionalNextRoundState = roundState.next();
if (optionalNextRoundState.isEmpty()) {
roundState = ROUND_STATE.PLAYER_REGISTRATION;
listeners.forEach(roundListener -> roundListener.stateChange(roundState));
return;
}
roundState = optionalNextRoundState.get();
listeners.forEach(roundListener -> roundListener.stateChange(roundState));
}
public void startRound() {
if (roundState.equals(ROUND_STATE.PLAYER_REGISTRATION)) {
throw new IllegalStateException("Round can not be started before player registration.");
}
roundState = ROUND_STATE.COUNTDOWN;
listeners.forEach(roundListener -> roundListener.stateChange(roundState));
GameStageHandler.handleWarmup();
Duration warmupDuration = Config.ROUND.COUNTDOWN;
scheduledExecutorService.schedule(() -> {
GameStageHandler.handleCountdownEnd();
nextStage();
scheduleNextStage(0);
}, warmupDuration.toSeconds(), TimeUnit.SECONDS);
}
private void scheduleNextStage(int index) {
List<GameStage> gameStageList = Config.ROUND.STAGES;
if (gameStageList.size() <= index) {
nextStage();
return;
}
GameStage gameStage = gameStageList.get(index);
Duration duration = gameStage.getDuration();
scheduledExecutorService.schedule(() -> {
GameStageHandler.handleStageChange(gameStage.getWorldBorderSize());
scheduleNextStage(index + 1);
}, duration.toSeconds(), TimeUnit.SECONDS);
}
}

View File

@ -0,0 +1,9 @@
package com.alttd.hunger_games.services;
import com.alttd.hunger_games.data_objects.ROUND_STATE;
public interface RoundListener {
void stateChange(ROUND_STATE roundState);
}

View File

@ -0,0 +1,47 @@
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 lombok.Getter;
import org.bukkit.entity.Player;
import java.util.*;
import java.util.stream.Collectors;
public class RoundService implements RoundListener {
@Getter
private ROUND_STATE roundState;
private final HashMap<UUID, PLAYER_STATE> players = new HashMap<>();
public RoundService(Round round) {
this.roundState = round.register(this);
}
public Set<UUID> getPlayers(PLAYER_STATE playerState) {
return players.entrySet().stream()
.filter(entry -> entry.getValue().equals(playerState))
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
}
protected void setPlayerState(UUID uuid, PLAYER_STATE playerState) {
players.put(uuid, playerState);
}
protected void clear() {
players.clear();
}
public Optional<PLAYER_STATE> getPlayerState(UUID uuid) {
return Optional.ofNullable(players.get(uuid));
}
@Override
public void stateChange(ROUND_STATE roundState) {
this.roundState = roundState;
if (roundState.equals(ROUND_STATE.PLAYER_REGISTRATION)) {
clear();
}
}
}