From aad63f174e7964bc86b9449628af5e29587e7395 Mon Sep 17 00:00:00 2001 From: Teriuihi Date: Tue, 11 Feb 2025 21:41:33 +0100 Subject: [PATCH] Refactor phase transitions and add particle effects for flags Simplified phase transition logic by removing unnecessary parameters and added proper executor shutdown at the end of the game. Enhanced visuals by introducing particle effects around flags when a team wins. Also implemented a method to skip the current game phase. --- src/main/java/com/alttd/ctf/flag/Flag.java | 28 ++++++++++++++++ .../java/com/alttd/ctf/game/GameManager.java | 2 +- .../java/com/alttd/ctf/game/RunningGame.java | 33 ++++++++++++------- 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/alttd/ctf/flag/Flag.java b/src/main/java/com/alttd/ctf/flag/Flag.java index d437af0..d2cebbb 100644 --- a/src/main/java/com/alttd/ctf/flag/Flag.java +++ b/src/main/java/com/alttd/ctf/flag/Flag.java @@ -96,12 +96,40 @@ public class Flag implements Runnable { Bukkit.getScheduler().runTask(main, () -> flagLocation.getBlock().setType(flagItem.getType())); } + private void spawnFlagParticleRing() { + Location center = flagLocation.clone(); + World world = center.getWorld(); + double radius = 0.7; + double gap = 0.2; + double circumference = 2 * Math.PI * radius; + int particleCount = (int) (circumference / gap); + + Particle particle = Particle.DUST; + TeamColor color = winningTeam.getColor(); + // Generate particle positions + for (double heightOffset = 0; heightOffset < 2; heightOffset += 0.5) { + center.setY(center.getY() + 0.5); + for (int i = 0; i < particleCount; i++) { + double angle = 2 * Math.PI * i / particleCount; + double x = center.getX() + radius * Math.cos(angle); + double z = center.getZ() + radius * Math.sin(angle); + double y = center.getY(); + + world.spawnParticle(particle, x, y, z, 1, 0, 0, 0, new Particle.DustOptions(Color.fromRGB(color.r(), color.g(), color.b()), 1)); + } + } + } + @Override public void run() { if (flagCarrier != null) { checkFlagCarrier(); return; } + if (winningTeam != null) { + spawnFlagParticleRing(); + return; + } if (flagLocation == null) { log.warn("Tried to run Flag without a flag location, spawn it first"); return; diff --git a/src/main/java/com/alttd/ctf/game/GameManager.java b/src/main/java/com/alttd/ctf/game/GameManager.java index ba1c4c9..1d70922 100644 --- a/src/main/java/com/alttd/ctf/game/GameManager.java +++ b/src/main/java/com/alttd/ctf/game/GameManager.java @@ -77,7 +77,7 @@ public class GameManager { executorService.shutdown(); executorService = Executors.newSingleThreadScheduledExecutor(); } - runningGame = new RunningGame(this, duration, flag); + runningGame = new RunningGame(this, duration, flag, executorService); executorService.scheduleAtFixedRate(runningGame, 0, 1, TimeUnit.SECONDS); } diff --git a/src/main/java/com/alttd/ctf/game/RunningGame.java b/src/main/java/com/alttd/ctf/game/RunningGame.java index 4e13ad8..3b4ed49 100644 --- a/src/main/java/com/alttd/ctf/game/RunningGame.java +++ b/src/main/java/com/alttd/ctf/game/RunningGame.java @@ -13,6 +13,7 @@ import javax.annotation.Nullable; import java.time.Duration; import java.time.Instant; import java.util.HashMap; +import java.util.concurrent.ScheduledExecutorService; @Slf4j public class RunningGame implements Runnable { @@ -20,14 +21,16 @@ public class RunningGame implements Runnable { private final HashMap phaseDurations = GameConfig.PHASES.getGAME_PHASE_DURATION(); private final GameManager gameManager; private final Flag flag; + private final ScheduledExecutorService executorService; @Getter private GamePhase currentPhase = GamePhase.values()[0]; private Instant phaseStartTime = null; private int lastMinuteBroadcast = 0; - public RunningGame(GameManager gameManager, Duration gameDuration, Flag flag) { + public RunningGame(GameManager gameManager, Duration gameDuration, Flag flag, ScheduledExecutorService executorService) { this.gameManager = gameManager; this.flag = flag; + this.executorService = executorService; phaseDurations.put(GamePhase.COMBAT, gameDuration); } @@ -37,16 +40,16 @@ public class RunningGame implements Runnable { GamePhase nextPhase = (currentPhase.ordinal() + 1 < GamePhase.values().length) ? GamePhase.values()[currentPhase.ordinal() + 1] : null; if (phaseStartTime == null) { phaseStartTime = Instant.now(); - nextPhaseActions(null, currentPhase, nextPhase); + nextPhaseActions(null, currentPhase); } - if (Duration.between(phaseStartTime, Instant.now()).compareTo(phaseDurations.get(currentPhase)) >= 0) { - GamePhase previousPhase = currentPhase; - currentPhase = GamePhase.values()[currentPhase.ordinal() + 1]; //TODO fix this running out of bounds - nextPhaseActions(previousPhase, currentPhase, nextPhase); + if (nextPhase != null && Duration.between(phaseStartTime, Instant.now()).compareTo(phaseDurations.get(currentPhase)) >= 0) { + nextPhaseActions(currentPhase, nextPhase); phaseStartTime = Instant.now(); } else if (nextPhase != null) { broadcastNextPhaseStartTime(currentPhase, nextPhase); + } else { + executorService.shutdown(); } } catch (Exception e) { log.error("Unexpected error in running game", e); @@ -54,15 +57,13 @@ public class RunningGame implements Runnable { } } - private void nextPhaseActions(@Nullable GamePhase previousPhase, @NotNull GamePhase phase, @Nullable GamePhase nextPhase) { + private void nextPhaseActions(@Nullable GamePhase previousPhase, @NotNull GamePhase phase) { //TODO command to go to next phase + this.currentPhase = phase; if (previousPhase != null) { gameManager.getPhaseExecutor(previousPhase).end(phase); } gameManager.getPhaseExecutor(phase).start(flag); - if (nextPhase != null) { - broadcastNextPhaseStartTime(phase, nextPhase); - } } private void broadcastNextPhaseStartTime(GamePhase currentPhase, GamePhase nextPhase) {//TODO check how this works/what it should do @@ -86,9 +87,17 @@ public class RunningGame implements Runnable { } } + public void skipCurrentPhase() { + GamePhase nextPhase = (currentPhase.ordinal() + 1 < GamePhase.values().length) ? GamePhase.values()[currentPhase.ordinal() + 1] : null; + if (nextPhase == null) { + log.warn("Tried to skip phase {} but there is no next phase", currentPhase); + return; + } + nextPhaseActions(currentPhase, nextPhase); + } + public void end() { //TODO say the phase ended early? - currentPhase = GamePhase.ENDED; - nextPhaseActions(null, currentPhase, null); + nextPhaseActions(currentPhase, GamePhase.ENDED); } }