reimport updated minigame api

This commit is contained in:
kento2 2026-07-08 20:36:17 +02:00
parent dafb58155a
commit ca60c10263
17 changed files with 341 additions and 253 deletions

View file

@ -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

View file

@ -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);
}
}

View file

@ -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
*/ */

View file

@ -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
*/ */

View file

@ -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()));
} }
} }

View file

@ -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() {
}
} }

View file

@ -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() {
} }
} }

View file

@ -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;
} }

View file

@ -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() {
}
}

View file

@ -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;
}
}

View file

@ -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();
} }

View file

@ -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();
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
} }

View file

@ -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();
}

View file

@ -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);
}
}