HungerGames/src/main/java/com/alttd/hunger_games/services/BossBarService.java

145 lines
5.0 KiB
Java
Raw Normal View History

package com.alttd.hunger_games.services;
import com.alttd.hunger_games.config.Messages;
import com.alttd.hunger_games.data_objects.PLAYER_STATE;
import com.alttd.hunger_games.data_objects.ROUND_STATE;
import net.kyori.adventure.bossbar.BossBar;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.time.Duration;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
public class BossBarService implements RoundListener {
private static BossBarService instance = null;
private final RoundService roundService;
private final BossBar bossBar;
private final Set<UUID> viewers = new HashSet<>();
private int maxPlayers = 0;
public BossBarService(Round round, RoundService roundService) {
this.roundService = roundService;
this.bossBar = BossBar.bossBar(Component.empty(), 1.0f, BossBar.Color.YELLOW, BossBar.Overlay.PROGRESS);
round.register(this);
}
public static BossBarService createSingletonInstance(Round round, RoundService roundService) {
if (instance != null) {
throw new IllegalStateException("BossBarService is already initialized.");
}
instance = new BossBarService(round, roundService);
return instance;
}
public void updateCountdown(Duration timeLeft, Duration totalTime, ROUND_STATE state) {
String message = switch (state) {
case COUNTDOWN -> Messages.GAME.BOSSBAR_COUNTDOWN;
case SAFE_PHASE -> Messages.GAME.BOSSBAR_SAFE_PHASE;
case KILL_PHASE -> Messages.GAME.BOSSBAR_KILL_PHASE;
default -> throw new IllegalArgumentException("Invalid round state: " + state);
};
if (message.isEmpty()) {
bossBar.name(Component.empty());
bossBar.progress(0.0f);
return;
}
bossBar.name(MiniMessage.miniMessage().deserialize(message, Placeholder.unparsed("time", formatTime(timeLeft))));
bossBar.progress(Math.clamp((float) timeLeft.toMillis() / totalTime.toMillis(), 0.0f, 1.0f));
updateBossBarColor(state);
updateViewers();
}
private void updateBossBarColor(ROUND_STATE state) {
switch (state) {
case COUNTDOWN -> bossBar.color(BossBar.Color.YELLOW);
case SAFE_PHASE -> bossBar.color(BossBar.Color.GREEN);
case KILL_PHASE -> bossBar.color(BossBar.Color.RED);
case FINALE -> bossBar.color(BossBar.Color.PURPLE);
default -> bossBar.color(BossBar.Color.WHITE);
}
}
public void updateFinale(int remainingPlayers) {
if (maxPlayers == 0) {
maxPlayers = remainingPlayers;
}
if (remainingPlayers <= 1) {
hideAll();
return;
}
bossBar.name(MiniMessage.miniMessage().deserialize(Messages.GAME.BOSSBAR_FINALE, Placeholder.unparsed("remaining", String.valueOf(remainingPlayers))));
bossBar.progress(Math.clamp((float) remainingPlayers / maxPlayers, 0.0f, 1.0f));
bossBar.color(BossBar.Color.PURPLE);
updateViewers();
}
private void updateViewers() {
Set<UUID> registeredPlayers = roundService.getPlayers(PLAYER_STATE.REGISTERED);
// Add new viewers
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);
}
}
}
private void hideAll() {
viewers.stream()
.map(Bukkit::getPlayer)
.filter(Objects::nonNull)
.forEach(player -> player.hideBossBar(bossBar));
viewers.clear();
}
private String formatTime(Duration duration) {
if (duration.isNegative()) {
return "0s";
}
long minutes = duration.toMinutesPart();
int seconds = duration.toSecondsPart();
if (minutes > 0) {
return "%dm %ds".formatted(minutes, seconds);
}
return "%ds".formatted(seconds);
}
@Override
public void stateChange(ROUND_STATE roundState) {
if (roundState == ROUND_STATE.PLAYER_REGISTRATION || roundState == ROUND_STATE.ENDED) {
hideAll();
maxPlayers = 0;
} else if (roundState == ROUND_STATE.FINALE) {
updateFinale(roundService.getPlayers(PLAYER_STATE.REGISTERED).size());
}
}
}