package com.alttd.hunger_games.services; import com.alttd.hunger_games.Main; import com.alttd.hunger_games.config.Messages; import com.alttd.hunger_games.data_objects.DESTINATION; import com.alttd.hunger_games.data_objects.GameStage; import com.alttd.hunger_games.data_objects.PLAYER_STATE; import com.alttd.hunger_games.data_objects.ROUND_STATE; import com.alttd.hunger_games.event_listeners.PlayerMovementListener; import com.alttd.hunger_games.utils.WorldBorderUtil; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.entity.Player; import org.bukkit.event.HandlerList; import java.util.*; import java.util.stream.Collectors; @Slf4j public class RoundService implements RoundListener { private static RoundService instance = null; private final PlayerTeleporterService playerTeleporterService; private final Main main; private final LootService lootService; private final StatService statService; private PlayerMovementListener playerMovementListener; @Getter private ROUND_STATE roundState; private final HashMap players = new HashMap<>(); private final Round round; @Setter private BossBarService bossBarService; public static RoundService createSingletonInstance(Round round, Main main, LootService lootService, StatService statService, PlayerTeleporterService playerTeleporterService) { if (instance != null) { throw new IllegalStateException("RoundService is already initialized."); } instance = new RoundService(round, main, lootService, statService, playerTeleporterService); return instance; } private RoundService(Round round, Main main, LootService lootService, StatService statService, PlayerTeleporterService playerTeleporterService) { this.round = round; this.roundState = round.register(this); this.main = main; this.lootService = lootService; this.statService = statService; this.playerTeleporterService = playerTeleporterService; } public Set 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) { PLAYER_STATE oldState = players.put(uuid, playerState); if (playerState == PLAYER_STATE.SPECTATING && oldState == PLAYER_STATE.REGISTERED) { int remaining = getPlayers(PLAYER_STATE.REGISTERED).size(); statService.setPlacement(uuid, remaining + 1); if (roundState == ROUND_STATE.FINALE && bossBarService != null) { bossBarService.updateFinale(remaining); } } if (!roundState.equals(ROUND_STATE.KILL_PHASE) && !roundState.equals(ROUND_STATE.FINALE)) { return; } Set uuidSet = getPlayers(PLAYER_STATE.REGISTERED); if (uuidSet.size() != 1) { return; } declareWinner(uuidSet.iterator().next()); } private void declareWinner(UUID winnerUUID) { Player player = Bukkit.getPlayer(winnerUUID); if (player == null) { log.error("Winner {} not found", winnerUUID); Bukkit.broadcast(MiniMessage.miniMessage().deserialize("Winner not found")); return; } statService.setPlacement(winnerUUID, 1); statService.setWon(winnerUUID, true); Bukkit.broadcast(MiniMessage.miniMessage().deserialize(Messages.GAME.WINNER, Placeholder.component("player", player.name()))); playerTeleporterService.teleportPlayer(player, DESTINATION.SPECTATOR_AREA); player.setHealth(20); player.setFoodLevel(20); player.getInventory().clear(); player.setTotalExperience(0); player.setExp(0.0f); player.setLevel(0); round.endRound(); } protected void clear() { players.clear(); } public Optional getPlayerState(UUID uuid) { return Optional.ofNullable(players.get(uuid)); } @Override public void stateChange(ROUND_STATE roundState) { this.roundState = roundState; stopFreeze(); if (roundState.equals(ROUND_STATE.PLAYER_REGISTRATION)) { clear(); lootService.clear(); } if (roundState.equals(ROUND_STATE.COUNTDOWN)) { Bukkit.getOnlinePlayers().stream() .filter(player -> PLAYER_STATE.REGISTERED.equals(getPlayerState(player.getUniqueId()).orElse(null))) .forEach(player -> { player.setHealth(20); player.setFoodLevel(20); player.setGameMode(GameMode.ADVENTURE); player.getInventory().clear(); player.setTotalExperience(0); player.setExp(0.0f); player.setLevel(0); }); startFreeze(); WorldBorderUtil.resetBorder(); } if (roundState.equals(ROUND_STATE.FINALE)) { WorldBorderUtil.setSize(60); } 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()))); } } private void stopFreeze() { if (playerMovementListener == null) { return; } HandlerList.unregisterAll(playerMovementListener); playerMovementListener = null; } private void startFreeze() { stopFreeze(); Set uuidSet = getPlayers(PLAYER_STATE.REGISTERED); playerMovementListener = new PlayerMovementListener(uuidSet); main.getServer().getPluginManager().registerEvents(playerMovementListener, main); } }