Compare commits
3 Commits
646b9a2a35
...
233cffd2df
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
233cffd2df | ||
|
|
dd060bce48 | ||
|
|
10a6103f32 |
|
|
@ -2,17 +2,13 @@ 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.LootItems;
|
||||
import com.alttd.hunger_games.config.Messages;
|
||||
import com.alttd.hunger_games.event_listeners.ChestListener;
|
||||
import com.alttd.hunger_games.event_listeners.PlayerDamageListener;
|
||||
import com.alttd.hunger_games.event_listeners.PlayerDisconnectListener;
|
||||
import com.alttd.hunger_games.event_listeners.PlayerJoinListener;
|
||||
import com.alttd.hunger_games.services.LootService;
|
||||
import com.alttd.hunger_games.services.PlayerService;
|
||||
import com.alttd.hunger_games.services.PlayerTeleporterService;
|
||||
import com.alttd.hunger_games.services.Round;
|
||||
import com.alttd.hunger_games.services.RoundService;
|
||||
import com.alttd.hunger_games.services.StatService;
|
||||
import com.alttd.hunger_games.services.*;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
|
@ -26,6 +22,7 @@ public final class Main extends JavaPlugin {
|
|||
private PlayerTeleporterService playerTeleporterService;
|
||||
private LootService lootService;
|
||||
private StatService statService;
|
||||
private BossBarService bossBarService;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
|
|
@ -44,6 +41,10 @@ public final class Main extends JavaPlugin {
|
|||
roundService = RoundService.createSingletonInstance(round, this, lootService, statService);
|
||||
playerTeleporterService = PlayerTeleporterService.createSingletonInstance();
|
||||
playerService = PlayerService.createSingletonInstance(round, roundService, playerTeleporterService);
|
||||
|
||||
bossBarService = BossBarService.createSingletonInstance(round, roundService);
|
||||
round.setBossBarService(bossBarService);
|
||||
roundService.setBossBarService(bossBarService);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -66,6 +67,7 @@ public final class Main extends JavaPlugin {
|
|||
public void reloadConfigs() {
|
||||
Config.reload();
|
||||
Messages.reload();
|
||||
LootItems.reload();
|
||||
}
|
||||
|
||||
private void registerSchedulers() {
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ public class LootItems extends AbstractConfig {
|
|||
@SuppressWarnings("unused")
|
||||
private static void load() {
|
||||
for (RARITY rarity : RARITY.values()) {
|
||||
List<String> materialNameList = ITEMS.get(rarity).stream().map(Material::name).toList();
|
||||
List<String> materialNameList = ITEMS.getOrDefault(rarity, List.of()).stream().map(Material::name).toList();
|
||||
List<String> materialList = config.getList(prefix, rarity.getConfigName(), materialNameList);
|
||||
ITEMS.put(rarity, materialList.stream().map(Material::getMaterial).toList());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,11 @@ public class Messages extends AbstractConfig {
|
|||
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 BOSSBAR_COUNTDOWN = "<gold>Loot phase in <time></gold>";
|
||||
public static String BOSSBAR_SAFE_PHASE = "<green>Kill phase in <time></green>";
|
||||
public static String BOSSBAR_KILL_PHASE = "<red>Border shrink in <time></red>";
|
||||
public static String BOSSBAR_FINALE = "<gold>Remaining Players: <remaining></gold>";
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static void load() {
|
||||
WARMUP = config.getString(prefix, "warmup", WARMUP);
|
||||
|
|
@ -92,6 +97,11 @@ public class Messages extends AbstractConfig {
|
|||
CHEST_EMPTY = config.getString(prefix, "chest-empty", CHEST_EMPTY);
|
||||
WINNER = config.getString(prefix, "winner", WINNER);
|
||||
PLAYER_DEATH = config.getString(prefix, "player-death", PLAYER_DEATH);
|
||||
|
||||
BOSSBAR_COUNTDOWN = config.getString(prefix, "bossbar-countdown", BOSSBAR_COUNTDOWN);
|
||||
BOSSBAR_SAFE_PHASE = config.getString(prefix, "bossbar-safe-phase", BOSSBAR_SAFE_PHASE);
|
||||
BOSSBAR_KILL_PHASE = config.getString(prefix, "bossbar-kill-phase", BOSSBAR_KILL_PHASE);
|
||||
BOSSBAR_FINALE = config.getString(prefix, "bossbar-finale", BOSSBAR_FINALE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,144 @@
|
|||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -66,7 +66,10 @@ public class PlayerTeleporterService implements RoundListener {
|
|||
double angleRadians = Math.toRadians(angleDegrees);
|
||||
double x = center.getX() + radius * Math.cos(angleRadians);
|
||||
double z = center.getZ() + radius * Math.sin(angleRadians);
|
||||
|
||||
Location location = new Location(center.getWorld(), x, center.getY(), z);
|
||||
location.setDirection(center.toVector().subtract(location.toVector()));
|
||||
|
||||
usedLocations.computeIfAbsent(destination, k -> new HashSet<>()).add(location);
|
||||
return location;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,13 @@ import com.alttd.hunger_games.data_objects.ROUND_STATE;
|
|||
import com.alttd.hunger_games.game.GameStageHandler;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
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.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class Round {
|
||||
|
|
@ -19,6 +21,8 @@ public class Round {
|
|||
private final List<RoundListener> listeners = new ArrayList<>();
|
||||
private ROUND_STATE roundState = ROUND_STATE.PLAYER_REGISTRATION;
|
||||
private ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
|
||||
private ScheduledFuture<?> countdownFuture = null;
|
||||
private BossBarService bossBarService;
|
||||
|
||||
private Round() {
|
||||
|
||||
|
|
@ -42,11 +46,17 @@ public class Round {
|
|||
}
|
||||
|
||||
public void stop() {
|
||||
if (countdownFuture != null) {
|
||||
countdownFuture.cancel(true);
|
||||
}
|
||||
roundState = ROUND_STATE.PLAYER_REGISTRATION;
|
||||
listeners.forEach(roundListener -> roundListener.stateChange(roundState));
|
||||
}
|
||||
|
||||
public void endRound() {
|
||||
if (countdownFuture != null) {
|
||||
countdownFuture.cancel(true);
|
||||
}
|
||||
roundState = ROUND_STATE.ENDED;
|
||||
listeners.forEach(roundListener -> roundListener.stateChange(roundState));
|
||||
}
|
||||
|
|
@ -70,11 +80,29 @@ public class Round {
|
|||
listeners.forEach(roundListener -> roundListener.stateChange(roundState));
|
||||
GameStageHandler.handleWarmup();
|
||||
Duration warmupDuration = Config.ROUND.COUNTDOWN;
|
||||
scheduledExecutorService.schedule(() -> {
|
||||
|
||||
startCountdown(warmupDuration, () -> {
|
||||
GameStageHandler.handleCountdownEnd();
|
||||
nextStage();
|
||||
scheduleNextStage(0);
|
||||
}, warmupDuration.toSeconds(), TimeUnit.SECONDS);
|
||||
});
|
||||
}
|
||||
|
||||
private void startCountdown(Duration duration, Runnable onEnd) {
|
||||
if (countdownFuture != null) {
|
||||
countdownFuture.cancel(true);
|
||||
}
|
||||
|
||||
final Instant endTime = Instant.now().plus(duration);
|
||||
countdownFuture = scheduledExecutorService.scheduleAtFixedRate(() -> {
|
||||
Duration timeLeft = Duration.between(Instant.now(), endTime);
|
||||
if (bossBarService != null) {
|
||||
bossBarService.updateCountdown(timeLeft, duration, roundState);
|
||||
}
|
||||
if (timeLeft.isZero() || timeLeft.isNegative()) {
|
||||
onEnd.run();
|
||||
}
|
||||
}, 0, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void scheduleNextStage(int index) {
|
||||
|
|
@ -86,9 +114,14 @@ public class Round {
|
|||
|
||||
GameStage gameStage = gameStageList.get(index);
|
||||
Duration duration = gameStage.getDuration();
|
||||
scheduledExecutorService.schedule(() -> {
|
||||
|
||||
startCountdown(duration, () -> {
|
||||
GameStageHandler.handleStageChange(gameStage.getWorldBorderSize());
|
||||
scheduleNextStage(index + 1);
|
||||
}, duration.toSeconds(), TimeUnit.SECONDS);
|
||||
});
|
||||
}
|
||||
|
||||
public void setBossBarService(BossBarService bossBarService) {
|
||||
this.bossBarService = bossBarService;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ public class RoundService implements RoundListener {
|
|||
private final HashMap<UUID, PLAYER_STATE> players = new HashMap<>();
|
||||
|
||||
private final Round round;
|
||||
private BossBarService bossBarService;
|
||||
|
||||
public static RoundService createSingletonInstance(Round round, Main main, LootService lootService, StatService statService) {
|
||||
if (instance != null) {
|
||||
|
|
@ -59,6 +60,9 @@ public class RoundService implements RoundListener {
|
|||
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)) {
|
||||
|
|
@ -121,4 +125,8 @@ public class RoundService implements RoundListener {
|
|||
playerMovementListener = new PlayerMovementListener(uuidSet);
|
||||
main.getServer().getPluginManager().registerEvents(playerMovementListener, main);
|
||||
}
|
||||
|
||||
public void setBossBarService(BossBarService bossBarService) {
|
||||
this.bossBarService = bossBarService;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user