reimport updated minigame api
This commit is contained in:
parent
dafb58155a
commit
ca60c10263
17 changed files with 341 additions and 253 deletions
|
|
@ -1,5 +1,4 @@
|
||||||
TODO
|
TODO
|
||||||
- chat prefix cache
|
|
||||||
- make core-lib-impl: a library -> avoid shading massive core-lib
|
- make core-lib-impl: a library -> avoid shading massive core-lib
|
||||||
- notification: Friend is now offline/online
|
- notification: Friend is now offline/online
|
||||||
- /ignore command
|
- /ignore command
|
||||||
|
|
|
||||||
|
|
@ -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<Phase> phases = new ArrayList<>();
|
||||||
|
private CompletableFuture<Void> 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<Void> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,13 @@
|
||||||
package de.kentoj.scrow.bukkit.minigame;
|
package de.kentoj.scrow.bukkit.minigame;
|
||||||
|
|
||||||
|
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
public interface Minigame {
|
public interface Minigame {
|
||||||
|
|
||||||
|
ScrowMessageStyle getMessageStyle();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Required participant count
|
* Required participant count
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package de.kentoj.scrow.bukkit.minigame.phase;
|
package de.kentoj.scrow.bukkit.minigame;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
|
|
@ -7,15 +7,17 @@ public interface PhaseFlow {
|
||||||
String getName();
|
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();
|
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 rewindPhase();
|
||||||
|
|
||||||
|
void handlePhaseError();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CompletableFuture is completed when the game finishes
|
* CompletableFuture is completed when the game finishes
|
||||||
*/
|
*/
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
package de.kentoj.scrow.bukkit.minigame.lobby;
|
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.Minigame;
|
||||||
import de.kentoj.scrow.bukkit.minigame.phase.AbstractPhase;
|
import de.kentoj.scrow.bukkit.minigame.phase.CompositePhase;
|
||||||
import de.kentoj.scrow.bukkit.minigame.phase.LinearPhaseFlow;
|
import de.kentoj.scrow.bukkit.minigame.phase.PhaseContext;
|
||||||
import de.kentoj.scrow.bukkit.minigame.phase.PhaseFlow;
|
import lombok.Getter;
|
||||||
import de.kentoj.scrow.bukkit.minigame.phase.event.EventCanceller;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.block.BlockBreakEvent;
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
import org.bukkit.event.block.BlockExplodeEvent;
|
import org.bukkit.event.block.BlockExplodeEvent;
|
||||||
import org.bukkit.event.block.BlockPlaceEvent;
|
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.hanging.HangingBreakByEntityEvent;
|
||||||
import org.bukkit.event.player.*;
|
import org.bukkit.event.player.*;
|
||||||
|
|
||||||
public class LobbyPhase extends AbstractPhase<Minigame> {
|
public class LobbyPhase<T extends Minigame> extends CompositePhase<T> {
|
||||||
|
|
||||||
private final Minigame game;
|
@Getter
|
||||||
private final PhaseFlow phaseFlow;
|
private final LinearPhaseFlow subPhaseFlow = new LinearPhaseFlow("lobby");
|
||||||
private final LinearPhaseFlow subPhaseFlow;
|
|
||||||
|
|
||||||
public LobbyPhase(Minigame game, PhaseFlow phaseFlow) {
|
public LobbyPhase(PhaseContext<T> ctx) {
|
||||||
super(game, phaseFlow);
|
super(ctx);
|
||||||
this.game = game;
|
var subCtx = new PhaseContext<>(ctx.game(), subPhaseFlow);
|
||||||
this.phaseFlow = phaseFlow;
|
subPhaseFlow.add(new WaitForMinimumPlayersPhase<>(subCtx));
|
||||||
subPhaseFlow = new LinearPhaseFlow("hunt.lobby");
|
subPhaseFlow.add(new WaitForMaximumPlayersPhase<>(subCtx));
|
||||||
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<>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
protected void onStart() {
|
||||||
subPhaseFlow.start().thenRun(phaseFlow::advancePhase);
|
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) {
|
private void onJoin(PlayerJoinEvent ev) {
|
||||||
game.getPlayerManager().addParticipant(ev.getPlayer());
|
ctx.players().addParticipant(ev.getPlayer());
|
||||||
game.getPlayerManager().getAllPlayers().forEach(p ->
|
ctx.players().getAllPlayers().forEach(p ->
|
||||||
p.sendMessage("§8[§a+§8] §7" + ev.getPlayer().getName()));
|
p.sendMessage("§8[§a+§8] §7" + ev.getPlayer().getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onQuit(PlayerQuitEvent ev) {
|
private void onQuit(PlayerQuitEvent ev) {
|
||||||
if (game.getPlayerManager().removeParticipant(ev.getPlayer()))
|
if (ctx.players().removeParticipant(ev.getPlayer()))
|
||||||
game.getPlayerManager().getAllPlayers().forEach(p ->
|
ctx.players().getAllPlayers().forEach(p ->
|
||||||
p.sendMessage("§8[§c-§8] §7" + ev.getPlayer().getName()));
|
p.sendMessage("§8[§c-§8] §7" + ev.getPlayer().getName()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,46 +2,40 @@ package de.kentoj.scrow.bukkit.minigame.lobby;
|
||||||
|
|
||||||
import de.kentoj.scrow.bukkit.minigame.Minigame;
|
import de.kentoj.scrow.bukkit.minigame.Minigame;
|
||||||
import de.kentoj.scrow.bukkit.minigame.phase.AbstractPhase;
|
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 net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.title.Title;
|
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
import java.time.Duration;
|
public class WaitForMaximumPlayersPhase<T extends Minigame> extends AbstractPhase<T> {
|
||||||
|
|
||||||
public class WaitForMaximumPlayersPhase extends AbstractPhase<Minigame> {
|
private int secsLeft;
|
||||||
|
|
||||||
private final Minigame game;
|
public WaitForMaximumPlayersPhase(PhaseContext<T> ctx) {
|
||||||
private final PhaseFlow phaseFlow;
|
super(ctx);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
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
|
@Override
|
||||||
protected void onTick(int tick) {
|
protected void onTick(int tick) {
|
||||||
if (tick % 20 == 0) {
|
if (tick % 20 == 0) {
|
||||||
game.getPlayerManager().getAllPlayers().forEach(player -> player.showTitle(Title.title(
|
ctx.players().getAllPlayers().forEach(player ->
|
||||||
Component.text("Game starting in " + left + " seconds"),
|
player.sendTitle("Game starting in " + secsLeft + " seconds", "have fun", 5, 20, 10)
|
||||||
Component.text("have fun"),
|
);
|
||||||
Title.Times.times(Duration.ofMillis(50), Duration.ZERO, Duration.ofMillis(50))
|
secsLeft--;
|
||||||
)));
|
if (secsLeft == 0) super.advancePhase();
|
||||||
left--;
|
|
||||||
if (left == 0) phaseFlow.advancePhase();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCancel() {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,23 +2,26 @@ package de.kentoj.scrow.bukkit.minigame.lobby;
|
||||||
|
|
||||||
import de.kentoj.scrow.bukkit.minigame.Minigame;
|
import de.kentoj.scrow.bukkit.minigame.Minigame;
|
||||||
import de.kentoj.scrow.bukkit.minigame.phase.AbstractPhase;
|
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;
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
|
|
||||||
public class WaitForMinimumPlayersPhase extends AbstractPhase<Minigame> {
|
public class WaitForMinimumPlayersPhase<T extends Minigame> extends AbstractPhase<T> {
|
||||||
|
|
||||||
private final Minigame game;
|
public WaitForMinimumPlayersPhase(PhaseContext<T> ctx) {
|
||||||
private final PhaseFlow phaseFlow;
|
super(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
WaitForMinimumPlayersPhase(Minigame game, PhaseFlow phaseFlow) {
|
@Override
|
||||||
super(game, phaseFlow);
|
protected void onStart() {
|
||||||
this.game = game;
|
ctx.listeners().on(PlayerJoinEvent.class, this::onJoin);
|
||||||
this.phaseFlow = phaseFlow;
|
|
||||||
this.addEventHandler(PlayerJoinEvent.class, this::onJoin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onJoin(PlayerJoinEvent ev) {
|
private void onJoin(PlayerJoinEvent ev) {
|
||||||
boolean isEnoughParticipants = game.getPlayerManager().getParticipantCount() >= game.getMinParticipants();
|
boolean isEnoughParticipants = ctx.players().getParticipantCount() >= ctx.game().getMinParticipants();
|
||||||
if (isEnoughParticipants) phaseFlow.advancePhase();
|
if (isEnoughParticipants) ctx.advancePhase();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCancel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,37 +3,27 @@ package de.kentoj.scrow.bukkit.minigame.phase;
|
||||||
import com.google.errorprone.annotations.ForOverride;
|
import com.google.errorprone.annotations.ForOverride;
|
||||||
import de.kentoj.scrow.bukkit.ScrowAPI;
|
import de.kentoj.scrow.bukkit.ScrowAPI;
|
||||||
import de.kentoj.scrow.bukkit.minigame.Minigame;
|
import de.kentoj.scrow.bukkit.minigame.Minigame;
|
||||||
import de.kentoj.scrow.bukkit.minigame.phase.event.EventHandler;
|
import de.kentoj.scrow.bukkit.minigame.PhaseFlow;
|
||||||
import de.kentoj.scrowlib.convention.ScrowMessageStyle;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
|
||||||
import org.bukkit.event.Event;
|
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
@RequiredArgsConstructor
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
public abstract class AbstractPhase<T extends Minigame> implements Phase {
|
public abstract class AbstractPhase<T extends Minigame> implements Phase {
|
||||||
|
|
||||||
private static final ScrowMessageStyle style = new ScrowMessageStyle("Game", NamedTextColor.RED);
|
protected final PhaseContext<T> ctx;
|
||||||
|
|
||||||
private final List<PhaseEventHandler<?>> handlers = new ArrayList<>();
|
private boolean isActive = false;
|
||||||
private CompletableFuture<Void> future;
|
|
||||||
|
|
||||||
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;
|
* Called together with {@link AbstractPhase#onEnd()} but only called when the phase was cancelled
|
||||||
this.phaseFlow = phaseFlow;
|
* due to an error
|
||||||
}
|
*/
|
||||||
|
protected abstract void onCancel();
|
||||||
@ForOverride
|
|
||||||
protected void onStart() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@ForOverride
|
@ForOverride
|
||||||
protected void onEnd() {
|
protected void onEnd() {
|
||||||
|
|
@ -44,42 +34,31 @@ public abstract class AbstractPhase<T extends Minigame> implements Phase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void start() {
|
public void cancel() {
|
||||||
if (isActive()) return;
|
onCancel();
|
||||||
future = new CompletableFuture<>();
|
end();
|
||||||
future.thenRun(() -> handlers.forEach(PhaseEventHandler::disable));
|
}
|
||||||
future.thenRun(() -> future = null);
|
|
||||||
future.thenRun(this::onEnd);
|
|
||||||
|
|
||||||
handlers.forEach(PhaseEventHandler::enable);
|
public final void start() {
|
||||||
try {
|
if (isActive) return;
|
||||||
onStart();
|
isActive = true;
|
||||||
} catch (Throwable throwable) {
|
onStart();
|
||||||
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."))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
runTicker();
|
runTicker();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void end() {
|
public final void end() {
|
||||||
if (!isActive()) return;
|
if (!isActive) return;
|
||||||
future.complete(null);
|
ctx.listeners().unregisterAll();
|
||||||
|
onEnd();
|
||||||
|
isActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final <E extends Event> void addEventHandler(Class<E> eventClass, EventPriority priority, EventHandler<E> handler) {
|
/**
|
||||||
handlers.add(new PhaseEventHandler<>(eventClass, priority, handler::handle));
|
* end the current phase and advance to the next.
|
||||||
}
|
* same as {@link PhaseFlow#advancePhase()}.
|
||||||
|
*/
|
||||||
public final <E extends Event> void addEventHandler(Class<E> eventClass, EventHandler<E> handler) {
|
public final void advancePhase() {
|
||||||
handlers.add(new PhaseEventHandler<>(eventClass, EventPriority.NORMAL, handler::handle));
|
ctx.phases().advancePhase();
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isActive() {
|
|
||||||
return future != null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runTicker() {
|
private void runTicker() {
|
||||||
|
|
@ -88,7 +67,7 @@ public abstract class AbstractPhase<T extends Minigame> implements Phase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (!isActive()) {
|
if (!isActive) {
|
||||||
this.cancel();
|
this.cancel();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<T extends Minigame> extends AbstractPhase<T> {
|
||||||
|
|
||||||
|
public CompositePhase(PhaseContext<T> ctx) {
|
||||||
|
super(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract PhaseFlow getSubPhaseFlow();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onStart() {
|
||||||
|
getSubPhaseFlow().start().thenRun(super::advancePhase);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCancel() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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<Phase> phases = new ArrayList<>();
|
|
||||||
private CompletableFuture<Void> 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<Void> start() {
|
|
||||||
Preconditions.checkState(onEnd == null, "attempting to start game that is already active");
|
|
||||||
onEnd = new CompletableFuture<>();
|
|
||||||
onEnd.thenRun(() -> onEnd = null);
|
|
||||||
advancePhase();
|
|
||||||
return onEnd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,15 +2,9 @@ package de.kentoj.scrow.bukkit.minigame.phase;
|
||||||
|
|
||||||
public interface Phase {
|
public interface Phase {
|
||||||
|
|
||||||
/**
|
|
||||||
* will do nothing if the phase is already active.
|
|
||||||
* Implementations shall advance the phase using {@link PhaseFlow#advancePhase()}.
|
|
||||||
*/
|
|
||||||
void start();
|
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 end();
|
||||||
|
|
||||||
|
void cancel();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<T extends Minigame> {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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<E extends Event> implements Listener {
|
|
||||||
private final Class<E> eventClass;
|
|
||||||
private final EventPriority priority;
|
|
||||||
private final Consumer<E> 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
package de.kentoj.scrow.bukkit.minigame.phase.event;
|
|
||||||
|
|
||||||
import org.bukkit.event.Cancellable;
|
|
||||||
|
|
||||||
public class EventCanceller<T extends Cancellable> implements EventHandler<T> {
|
|
||||||
@Override
|
|
||||||
public void handle(Cancellable ev) {
|
|
||||||
ev.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package de.kentoj.scrow.bukkit.minigame.phase.event;
|
package de.kentoj.scrow.bukkit.minigame.phase.event;
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface EventHandler<T> {
|
public interface EventHandler<E> {
|
||||||
|
|
||||||
void handle(T ev);
|
void handle(E ev);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
||||||
|
<E extends Event> void on(Class<E> eventClass, EventPriority priority, EventHandler<E> handler);
|
||||||
|
|
||||||
|
default <E extends Event> void on(Class<E> eventClass, EventHandler<E> handler) {
|
||||||
|
this.on(eventClass, EventPriority.NORMAL, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
default void cancel(Class<? extends Event>... 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();
|
||||||
|
}
|
||||||
|
|
@ -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 <E extends Event> void on(Class<E> clazz, EventPriority priority, EventHandler<E> handler) {
|
||||||
|
Bukkit.getPluginManager().registerEvent(clazz, this, priority, (__, ev) -> {
|
||||||
|
//noinspection unchecked
|
||||||
|
handler.handle((E) ev);
|
||||||
|
}, ScrowAPI.plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unregisterAll() {
|
||||||
|
HandlerList.unregisterAll(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue