150 lines
5.2 KiB
Java
150 lines
5.2 KiB
Java
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_PVP_COUNTDOWN;
|
|
case KILL_PHASE -> Messages.GAME.BOSSBAR_SAFE_PHASE;
|
|
default -> {
|
|
if (state.ordinal() > ROUND_STATE.KILL_PHASE.ordinal()) {
|
|
yield Messages.GAME.BOSSBAR_KILL_PHASE;
|
|
}
|
|
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());
|
|
}
|
|
}
|
|
}
|