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

128 lines
4.3 KiB
Java
Raw Normal View History

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.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 {
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 ScheduledFuture<?> countdownFuture = null;
private BossBarService bossBarService;
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() {
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));
}
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;
startCountdown(warmupDuration, () -> {
GameStageHandler.handleCountdownEnd();
nextStage();
scheduleNextStage(0);
});
}
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) {
List<GameStage> gameStageList = Config.ROUND.STAGES;
if (gameStageList.size() <= index) {
nextStage();
return;
}
GameStage gameStage = gameStageList.get(index);
Duration duration = gameStage.getDuration();
startCountdown(duration, () -> {
GameStageHandler.handleStageChange(gameStage.getWorldBorderSize());
scheduleNextStage(index + 1);
});
}
public void setBossBarService(BossBarService bossBarService) {
this.bossBarService = bossBarService;
}
}