diff --git a/README.md b/README.md index a25537a..7a02d17 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ TODO -- chat prefix cache - make core-lib-impl: a library -> avoid shading massive core-lib - notification: Friend is now offline/online - /ignore command diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/LinearPhaseFlow.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/LinearPhaseFlow.java new file mode 100644 index 0000000..01064b9 --- /dev/null +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/LinearPhaseFlow.java @@ -0,0 +1,108 @@ +package de.kentoj.scrow.bukkit.minigame; + +import com.google.common.base.Preconditions; +import de.kentoj.scrow.bukkit.minigame.phase.Phase; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.jspecify.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +@Slf4j +@RequiredArgsConstructor +public class LinearPhaseFlow implements PhaseFlow { + + @Getter + private final String name; + + private final List phases = new ArrayList<>(); + private CompletableFuture onEnd = null; + private int curInd = -1; + + public void add(Phase phase) { + this.phases.add(phase); + } + + @Override + public void advancePhase() { + Phase cur; + cur = current(); + if (cur != null) { + cur.cancel(); + } + + curInd++; + cur = current(); + if (cur == null) { + onEnd.complete(null); + log.info("phase flow {} ended", getName()); + return; + } + startPhase(cur); + } + + @Override + public void rewindPhase() { + var cur = current(); + Preconditions.checkNotNull(cur, "trying to rewind phase but no phase is active"); + cur.cancel(); + + curInd--; + cur = current(); + if (cur != null) + startPhase(cur); + } + + @Override + public void handlePhaseError() { + var cur = current(); + Preconditions.checkNotNull(cur, "trying to rewind phase but no phase is active"); + cur.cancel(); + + if (curInd == 0) { + startPhase(cur, false); + return; + } + + curInd--; + cur = current(); + startPhase(cur); + } + + @Override + public CompletableFuture start() { + Preconditions.checkState(onEnd == null, "attempting to start game that is already active"); + onEnd = new CompletableFuture<>(); + onEnd.thenRun(() -> onEnd = null); + log.info("starting phase flow {}", getName()); + advancePhase(); + return onEnd; + } + + private void startPhase(Phase phase) { + this.startPhase(phase, true); + } + + private void startPhase(Phase phase, boolean recoverOnError) { + if (!recoverOnError) { + phase.start(); + return; + } + + try { + log.info("starting phase {}", phase.getClass().getCanonicalName()); + phase.start(); + } catch (Exception e) { + log.error("failed starting phase {}: rewinding phase", phase.getClass().getCanonicalName(), e); + handlePhaseError(); + } + } + + private @Nullable Phase current() { + if (curInd < 0 || curInd >= phases.size()) return null; + return phases.get(curInd); + } +} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/Minigame.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/Minigame.java index f99a8ba..817f650 100644 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/Minigame.java +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/Minigame.java @@ -1,9 +1,13 @@ package de.kentoj.scrow.bukkit.minigame; +import de.kentoj.scrowlib.convention.ScrowMessageStyle; + import java.util.concurrent.CompletableFuture; public interface Minigame { + ScrowMessageStyle getMessageStyle(); + /** * Required participant count */ diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/PhaseFlow.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/PhaseFlow.java similarity index 59% rename from core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/PhaseFlow.java rename to core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/PhaseFlow.java index 534ee61..65070a1 100644 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/PhaseFlow.java +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/PhaseFlow.java @@ -1,4 +1,4 @@ -package de.kentoj.scrow.bukkit.minigame.phase; +package de.kentoj.scrow.bukkit.minigame; import java.util.concurrent.CompletableFuture; @@ -7,15 +7,17 @@ public interface PhaseFlow { String getName(); /** - * end the current phase, go to the next phase and activate it + * end the current phase, go to the next phase and start it */ void advancePhase(); /** - * end the current phase, go to the previous phase and activate it + * end the current phase, go to the previous phase and start it */ void rewindPhase(); + void handlePhaseError(); + /** * CompletableFuture is completed when the game finishes */ diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/lobby/LobbyPhase.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/lobby/LobbyPhase.java index 29f49ca..e548520 100644 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/lobby/LobbyPhase.java +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/lobby/LobbyPhase.java @@ -1,10 +1,11 @@ package de.kentoj.scrow.bukkit.minigame.lobby; +import de.kentoj.scrow.bukkit.minigame.LinearPhaseFlow; import de.kentoj.scrow.bukkit.minigame.Minigame; -import de.kentoj.scrow.bukkit.minigame.phase.AbstractPhase; -import de.kentoj.scrow.bukkit.minigame.phase.LinearPhaseFlow; -import de.kentoj.scrow.bukkit.minigame.phase.PhaseFlow; -import de.kentoj.scrow.bukkit.minigame.phase.event.EventCanceller; +import de.kentoj.scrow.bukkit.minigame.phase.CompositePhase; +import de.kentoj.scrow.bukkit.minigame.phase.PhaseContext; +import lombok.Getter; +import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockExplodeEvent; import org.bukkit.event.block.BlockPlaceEvent; @@ -15,50 +16,50 @@ import org.bukkit.event.entity.FoodLevelChangeEvent; import org.bukkit.event.hanging.HangingBreakByEntityEvent; import org.bukkit.event.player.*; -public class LobbyPhase extends AbstractPhase { +public class LobbyPhase extends CompositePhase { - private final Minigame game; - private final PhaseFlow phaseFlow; - private final LinearPhaseFlow subPhaseFlow; + @Getter + private final LinearPhaseFlow subPhaseFlow = new LinearPhaseFlow("lobby"); - public LobbyPhase(Minigame game, PhaseFlow phaseFlow) { - super(game, phaseFlow); - this.game = game; - this.phaseFlow = phaseFlow; - subPhaseFlow = new LinearPhaseFlow("hunt.lobby"); - subPhaseFlow.addPhase(new WaitForMinimumPlayersPhase(game, subPhaseFlow)); - subPhaseFlow.addPhase(new WaitForMaximumPlayersPhase(game, subPhaseFlow)); - - addEventHandler(PlayerJoinEvent.class, this::onJoin); - addEventHandler(PlayerQuitEvent.class, this::onQuit); - - addEventHandler(HangingBreakByEntityEvent.class, new EventCanceller<>()); - addEventHandler(PlayerInteractAtEntityEvent.class, new EventCanceller<>()); - addEventHandler(PlayerInteractEntityEvent.class, new EventCanceller<>()); - addEventHandler(PlayerDropItemEvent.class, new EventCanceller<>()); - addEventHandler(BlockExplodeEvent.class, new EventCanceller<>()); - addEventHandler(EntityExplodeEvent.class, new EventCanceller<>()); - addEventHandler(EntityDamageEvent.class, new EventCanceller<>()); - addEventHandler(FoodLevelChangeEvent.class, new EventCanceller<>()); - addEventHandler(BlockBreakEvent.class, new EventCanceller<>()); - addEventHandler(BlockPlaceEvent.class, new EventCanceller<>()); - addEventHandler(EntityTargetLivingEntityEvent.class, new EventCanceller<>()); + public LobbyPhase(PhaseContext ctx) { + super(ctx); + var subCtx = new PhaseContext<>(ctx.game(), subPhaseFlow); + subPhaseFlow.add(new WaitForMinimumPlayersPhase<>(subCtx)); + subPhaseFlow.add(new WaitForMaximumPlayersPhase<>(subCtx)); } @Override - public void onStart() { - subPhaseFlow.start().thenRun(phaseFlow::advancePhase); + protected void onStart() { + super.onStart(); + + ctx.listeners().on(PlayerJoinEvent.class, EventPriority.LOWEST, this::onJoin); + ctx.listeners().on(PlayerQuitEvent.class, EventPriority.LOWEST, this::onQuit); + + //noinspection unchecked + ctx.listeners().cancel( + HangingBreakByEntityEvent.class, + PlayerInteractAtEntityEvent.class, + PlayerInteractEntityEvent.class, + PlayerDropItemEvent.class, + BlockExplodeEvent.class, + EntityExplodeEvent.class, + EntityDamageEvent.class, + FoodLevelChangeEvent.class, + BlockBreakEvent.class, + BlockPlaceEvent.class, + EntityTargetLivingEntityEvent.class + ); } private void onJoin(PlayerJoinEvent ev) { - game.getPlayerManager().addParticipant(ev.getPlayer()); - game.getPlayerManager().getAllPlayers().forEach(p -> + ctx.players().addParticipant(ev.getPlayer()); + ctx.players().getAllPlayers().forEach(p -> p.sendMessage("§8[§a+§8] §7" + ev.getPlayer().getName())); } private void onQuit(PlayerQuitEvent ev) { - if (game.getPlayerManager().removeParticipant(ev.getPlayer())) - game.getPlayerManager().getAllPlayers().forEach(p -> + if (ctx.players().removeParticipant(ev.getPlayer())) + ctx.players().getAllPlayers().forEach(p -> p.sendMessage("§8[§c-§8] §7" + ev.getPlayer().getName())); } } diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/lobby/WaitForMaximumPlayersPhase.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/lobby/WaitForMaximumPlayersPhase.java index f0a2108..8132672 100644 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/lobby/WaitForMaximumPlayersPhase.java +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/lobby/WaitForMaximumPlayersPhase.java @@ -2,46 +2,40 @@ package de.kentoj.scrow.bukkit.minigame.lobby; import de.kentoj.scrow.bukkit.minigame.Minigame; import de.kentoj.scrow.bukkit.minigame.phase.AbstractPhase; -import de.kentoj.scrow.bukkit.minigame.phase.PhaseFlow; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.title.Title; +import de.kentoj.scrow.bukkit.minigame.phase.PhaseContext; import org.bukkit.event.player.PlayerQuitEvent; -import java.time.Duration; +public class WaitForMaximumPlayersPhase extends AbstractPhase { -public class WaitForMaximumPlayersPhase extends AbstractPhase { + private int secsLeft; - private final Minigame game; - private final PhaseFlow phaseFlow; - private int left; - - WaitForMaximumPlayersPhase(Minigame game, PhaseFlow phaseFlow) { - super(game, phaseFlow); - this.game = game; - this.phaseFlow = phaseFlow; - addEventHandler(PlayerQuitEvent.class, this::onQuit); - } - - private void onQuit(PlayerQuitEvent ev) { - var isEnough = game.getPlayerManager().getParticipantCount() >= game.getMinParticipants(); - if (!isEnough) phaseFlow.rewindPhase(); + public WaitForMaximumPlayersPhase(PhaseContext ctx) { + super(ctx); } @Override public void onStart() { - this.left = 5; + this.secsLeft = 5; + ctx.listeners().on(PlayerQuitEvent.class, this::onQuit); + } + + private void onQuit(PlayerQuitEvent ev) { + var isEnough = ctx.players().getParticipantCount() >= ctx.game().getMinParticipants(); + if (!isEnough) ctx.phases().rewindPhase(); } @Override protected void onTick(int tick) { if (tick % 20 == 0) { - game.getPlayerManager().getAllPlayers().forEach(player -> player.showTitle(Title.title( - Component.text("Game starting in " + left + " seconds"), - Component.text("have fun"), - Title.Times.times(Duration.ofMillis(50), Duration.ZERO, Duration.ofMillis(50)) - ))); - left--; - if (left == 0) phaseFlow.advancePhase(); + ctx.players().getAllPlayers().forEach(player -> + player.sendTitle("Game starting in " + secsLeft + " seconds", "have fun", 5, 20, 10) + ); + secsLeft--; + if (secsLeft == 0) super.advancePhase(); } } + + @Override + protected void onCancel() { + } } diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/lobby/WaitForMinimumPlayersPhase.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/lobby/WaitForMinimumPlayersPhase.java index 41571f6..49c14fe 100644 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/lobby/WaitForMinimumPlayersPhase.java +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/lobby/WaitForMinimumPlayersPhase.java @@ -2,23 +2,26 @@ package de.kentoj.scrow.bukkit.minigame.lobby; import de.kentoj.scrow.bukkit.minigame.Minigame; import de.kentoj.scrow.bukkit.minigame.phase.AbstractPhase; -import de.kentoj.scrow.bukkit.minigame.phase.PhaseFlow; +import de.kentoj.scrow.bukkit.minigame.phase.PhaseContext; import org.bukkit.event.player.PlayerJoinEvent; -public class WaitForMinimumPlayersPhase extends AbstractPhase { +public class WaitForMinimumPlayersPhase extends AbstractPhase { - private final Minigame game; - private final PhaseFlow phaseFlow; + public WaitForMinimumPlayersPhase(PhaseContext ctx) { + super(ctx); + } - WaitForMinimumPlayersPhase(Minigame game, PhaseFlow phaseFlow) { - super(game, phaseFlow); - this.game = game; - this.phaseFlow = phaseFlow; - this.addEventHandler(PlayerJoinEvent.class, this::onJoin); + @Override + protected void onStart() { + ctx.listeners().on(PlayerJoinEvent.class, this::onJoin); } private void onJoin(PlayerJoinEvent ev) { - boolean isEnoughParticipants = game.getPlayerManager().getParticipantCount() >= game.getMinParticipants(); - if (isEnoughParticipants) phaseFlow.advancePhase(); + boolean isEnoughParticipants = ctx.players().getParticipantCount() >= ctx.game().getMinParticipants(); + if (isEnoughParticipants) ctx.advancePhase(); + } + + @Override + protected void onCancel() { } } diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/AbstractPhase.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/AbstractPhase.java index 90a695f..1e450b9 100644 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/AbstractPhase.java +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/AbstractPhase.java @@ -3,37 +3,27 @@ package de.kentoj.scrow.bukkit.minigame.phase; import com.google.errorprone.annotations.ForOverride; import de.kentoj.scrow.bukkit.ScrowAPI; import de.kentoj.scrow.bukkit.minigame.Minigame; -import de.kentoj.scrow.bukkit.minigame.phase.event.EventHandler; -import de.kentoj.scrowlib.convention.ScrowMessageStyle; -import lombok.extern.slf4j.Slf4j; -import net.kyori.adventure.text.format.NamedTextColor; -import org.bukkit.event.Event; -import org.bukkit.event.EventPriority; +import de.kentoj.scrow.bukkit.minigame.PhaseFlow; +import lombok.RequiredArgsConstructor; import org.bukkit.scheduler.BukkitRunnable; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; - -@Slf4j +@RequiredArgsConstructor public abstract class AbstractPhase implements Phase { - private static final ScrowMessageStyle style = new ScrowMessageStyle("Game", NamedTextColor.RED); + protected final PhaseContext ctx; - private final List> handlers = new ArrayList<>(); - private CompletableFuture future; + private boolean isActive = false; - private final T game; - private final PhaseFlow phaseFlow; + /** + * Shall call {@link PhaseFlow#advancePhase()} + */ + protected abstract void onStart(); - protected AbstractPhase(T game, PhaseFlow phaseFlow) { - this.game = game; - this.phaseFlow = phaseFlow; - } - - @ForOverride - protected void onStart() { - } + /** + * Called together with {@link AbstractPhase#onEnd()} but only called when the phase was cancelled + * due to an error + */ + protected abstract void onCancel(); @ForOverride protected void onEnd() { @@ -44,42 +34,31 @@ public abstract class AbstractPhase implements Phase { } @Override - public final void start() { - if (isActive()) return; - future = new CompletableFuture<>(); - future.thenRun(() -> handlers.forEach(PhaseEventHandler::disable)); - future.thenRun(() -> future = null); - future.thenRun(this::onEnd); + public void cancel() { + onCancel(); + end(); + } - handlers.forEach(PhaseEventHandler::enable); - try { - onStart(); - } catch (Throwable throwable) { - log.error("Error while starting phase {}. Rewinding to previous phase...", getClass().getCanonicalName(), throwable); - phaseFlow.rewindPhase(); - game.getPlayerManager().getAllPlayers().forEach(player -> - player.sendMessage(style.err("Rewinding phase due to an error.")) - ); - } + public final void start() { + if (isActive) return; + isActive = true; + onStart(); runTicker(); } - @Override public final void end() { - if (!isActive()) return; - future.complete(null); + if (!isActive) return; + ctx.listeners().unregisterAll(); + onEnd(); + isActive = false; } - public final void addEventHandler(Class eventClass, EventPriority priority, EventHandler handler) { - handlers.add(new PhaseEventHandler<>(eventClass, priority, handler::handle)); - } - - public final void addEventHandler(Class eventClass, EventHandler handler) { - handlers.add(new PhaseEventHandler<>(eventClass, EventPriority.NORMAL, handler::handle)); - } - - private boolean isActive() { - return future != null; + /** + * end the current phase and advance to the next. + * same as {@link PhaseFlow#advancePhase()}. + */ + public final void advancePhase() { + ctx.phases().advancePhase(); } private void runTicker() { @@ -88,7 +67,7 @@ public abstract class AbstractPhase implements Phase { @Override public void run() { - if (!isActive()) { + if (!isActive) { this.cancel(); return; } diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/CompositePhase.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/CompositePhase.java new file mode 100644 index 0000000..ff011d0 --- /dev/null +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/CompositePhase.java @@ -0,0 +1,22 @@ +package de.kentoj.scrow.bukkit.minigame.phase; + +import de.kentoj.scrow.bukkit.minigame.Minigame; +import de.kentoj.scrow.bukkit.minigame.PhaseFlow; + +public abstract class CompositePhase extends AbstractPhase { + + public CompositePhase(PhaseContext ctx) { + super(ctx); + } + + public abstract PhaseFlow getSubPhaseFlow(); + + @Override + protected void onStart() { + getSubPhaseFlow().start().thenRun(super::advancePhase); + } + + @Override + protected void onCancel() { + } +} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/LinearPhaseFlow.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/LinearPhaseFlow.java deleted file mode 100644 index 6093bc0..0000000 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/LinearPhaseFlow.java +++ /dev/null @@ -1,73 +0,0 @@ -package de.kentoj.scrow.bukkit.minigame.phase; - -import com.google.common.base.Preconditions; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import org.bukkit.Bukkit; -import org.jspecify.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; - -@RequiredArgsConstructor -public class LinearPhaseFlow implements PhaseFlow { - - @Getter - private final String name; - - private final List phases = new ArrayList<>(); - private CompletableFuture onEnd = null; - private int curInd = -1; - - public void addPhase(Phase phase) { - this.phases.add(phase); - } - - @Override - public void advancePhase() { - Phase cur; - - cur = getCurrent(); - if (cur != null) cur.end(); - - curInd++; - cur = getCurrent(); - if (cur == null) { - curInd--; - onEnd.complete(null); - return; - } - cur.start(); - } - - @Override - public void rewindPhase() { - Phase cur; - - cur = getCurrent(); - if (cur != null) cur.end(); - - curInd--; - cur = getCurrent(); - if (cur == null) { - curInd++; - throw new IllegalStateException("no previous phase"); - } - cur.start(); - } - - private @Nullable Phase getCurrent() { - if (curInd < 0 || curInd >= phases.size()) return null; - return phases.get(curInd); - } - - @Override - public CompletableFuture start() { - Preconditions.checkState(onEnd == null, "attempting to start game that is already active"); - onEnd = new CompletableFuture<>(); - onEnd.thenRun(() -> onEnd = null); - advancePhase(); - return onEnd; - } -} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/Phase.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/Phase.java index 295d509..14ee254 100644 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/Phase.java +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/Phase.java @@ -2,15 +2,9 @@ package de.kentoj.scrow.bukkit.minigame.phase; public interface Phase { - /** - * will do nothing if the phase is already active. - * Implementations shall advance the phase using {@link PhaseFlow#advancePhase()}. - */ void start(); - /** - * will do nothing if the phase is not active. - * THIS DOES NOT ADVANCE TO THE NEXT PHASE. USE {@link PhaseFlow#advancePhase()} INSTEAD. - **/ void end(); + + void cancel(); } diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/PhaseContext.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/PhaseContext.java new file mode 100644 index 0000000..e4d90d6 --- /dev/null +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/PhaseContext.java @@ -0,0 +1,40 @@ +package de.kentoj.scrow.bukkit.minigame.phase; + +import de.kentoj.kencommandapi.api.platform.MessageStyle; +import de.kentoj.scrow.bukkit.minigame.Minigame; +import de.kentoj.scrow.bukkit.minigame.PhaseFlow; +import de.kentoj.scrow.bukkit.minigame.PlayerManager; +import de.kentoj.scrow.bukkit.minigame.phase.event.PhaseListeners; +import de.kentoj.scrow.bukkit.minigame.phase.event.PhaseListenersImpl; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public class PhaseContext { + private final T game; + private final PhaseFlow phaseFlow; + private final PhaseListeners listeners = new PhaseListenersImpl(); + + public T game() { + return game; + } + + public PhaseFlow phases() { + return phaseFlow; + } + + public PlayerManager players() { + return game.getPlayerManager(); + } + + public MessageStyle style() { + return game.getMessageStyle(); + } + + public PhaseListeners listeners() { + return listeners; + } + + public void advancePhase() { + phaseFlow.advancePhase(); + } +} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/PhaseEventHandler.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/PhaseEventHandler.java deleted file mode 100644 index 69daff6..0000000 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/PhaseEventHandler.java +++ /dev/null @@ -1,28 +0,0 @@ -package de.kentoj.scrow.bukkit.minigame.phase; - -import de.kentoj.scrow.bukkit.ScrowAPI; -import lombok.RequiredArgsConstructor; -import org.bukkit.Bukkit; -import org.bukkit.event.Event; -import org.bukkit.event.EventPriority; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; - -import java.util.function.Consumer; - -@RequiredArgsConstructor -class PhaseEventHandler implements Listener { - private final Class eventClass; - private final EventPriority priority; - private final Consumer handler; - - @SuppressWarnings("unchecked") - public void enable() { - Bukkit.getPluginManager().registerEvent(eventClass, this, priority, - (__, ev) -> handler.accept((E) ev), ScrowAPI.plugin); - } - - public void disable() { - HandlerList.unregisterAll(this); - } -} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/event/EventCanceller.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/event/EventCanceller.java deleted file mode 100644 index 6962388..0000000 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/event/EventCanceller.java +++ /dev/null @@ -1,10 +0,0 @@ -package de.kentoj.scrow.bukkit.minigame.phase.event; - -import org.bukkit.event.Cancellable; - -public class EventCanceller implements EventHandler { - @Override - public void handle(Cancellable ev) { - ev.setCancelled(true); - } -} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/event/EventHandler.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/event/EventHandler.java index 0f88c2e..975b693 100644 --- a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/event/EventHandler.java +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/event/EventHandler.java @@ -1,7 +1,7 @@ package de.kentoj.scrow.bukkit.minigame.phase.event; @FunctionalInterface -public interface EventHandler { +public interface EventHandler { - void handle(T ev); + void handle(E ev); } diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/event/PhaseListeners.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/event/PhaseListeners.java new file mode 100644 index 0000000..6a3327f --- /dev/null +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/event/PhaseListeners.java @@ -0,0 +1,29 @@ +package de.kentoj.scrow.bukkit.minigame.phase.event; + +import com.google.common.base.Preconditions; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.EventPriority; + +public interface PhaseListeners { + + void on(Class eventClass, EventPriority priority, EventHandler handler); + + default void on(Class eventClass, EventHandler handler) { + this.on(eventClass, EventPriority.NORMAL, handler); + } + + default void cancel(Class... classes) { + for (var clazz : classes) { + Preconditions.checkArgument(Cancellable.class.isAssignableFrom(clazz), + clazz.getCanonicalName() + " does not implement Cancellable"); + on(clazz, ev -> ((Cancellable) ev).setCancelled(true)); + } + } + + /** + * Unregisters all listeners bound to this phase. + * Note: this is automatically called on phase end. + */ + void unregisterAll(); +} diff --git a/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/event/PhaseListenersImpl.java b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/event/PhaseListenersImpl.java new file mode 100644 index 0000000..a136525 --- /dev/null +++ b/core-bukkit-api/src/main/java/de/kentoj/scrow/bukkit/minigame/phase/event/PhaseListenersImpl.java @@ -0,0 +1,24 @@ +package de.kentoj.scrow.bukkit.minigame.phase.event; + +import de.kentoj.scrow.bukkit.ScrowAPI; +import org.bukkit.Bukkit; +import org.bukkit.event.Event; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; + +public class PhaseListenersImpl implements PhaseListeners, Listener { + + @Override + public final void on(Class clazz, EventPriority priority, EventHandler handler) { + Bukkit.getPluginManager().registerEvent(clazz, this, priority, (__, ev) -> { + //noinspection unchecked + handler.handle((E) ev); + }, ScrowAPI.plugin); + } + + @Override + public void unregisterAll() { + HandlerList.unregisterAll(this); + } +}