Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rewrite code to have more cohesive events system #2

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.sylviameows.flask.api;

import io.github.sylviameows.flask.api.events.FlaskDispatcher;
import io.github.sylviameows.flask.api.manager.PlayerManager;
import io.github.sylviameows.flask.api.registry.GameRegistry;
import io.github.sylviameows.flask.api.services.MessageService;
Expand All @@ -14,6 +15,8 @@ public interface FlaskAPI {
WorldService getWorldService();
MessageService getMessageService();

FlaskDispatcher getDispatcher();

Plugin getPlugin();

Location getSpawnLocation();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package io.github.sylviameows.flask.api.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FlaskEvent {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package io.github.sylviameows.flask.api.events;

import io.github.sylviameows.flask.api.game.Lobby;
import org.bukkit.event.Event;
import org.bukkit.event.EventException;
import org.bukkit.event.Listener;
import org.bukkit.plugin.EventExecutor;
import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Method;

public interface FlaskDispatcher extends EventExecutor, Listener {
record ListenerInfo(Lobby<?> lobby, Method method, FlaskListener listener) {}

void registerEvent(Lobby<?> lobby, FlaskListener listener);
void unregisterEvent(Lobby<?> lobby, FlaskListener listener);

@Override
void execute(@NotNull Listener listener, @NotNull Event event) throws EventException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.github.sylviameows.flask.api.events;

/**
* This type of listener will automatically filter out irrelevant events to its target game.
*/
public interface FlaskListener {
}
29 changes: 14 additions & 15 deletions api/src/main/java/io/github/sylviameows/flask/api/game/Lobby.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
import org.bukkit.GameMode;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class Lobby<G extends Game> {
public class Lobby<G extends Game<?>> {
protected final G parent;

public List<Player> players;
Expand All @@ -21,44 +20,42 @@ public class Lobby<G extends Game> {
private World world;

public Lobby(G parent) {
this.parent = parent;
this.players = new ArrayList<>();

this.phase = parent.initialPhase();
Bukkit.getPluginManager().registerEvents(this.phase, parent.getPlugin());
this.phase.onEnabled(this);
this(parent, new ArrayList<>());
}

public Lobby(G parent, List<Player> players) {
this.parent = parent;
this.players = players;

var api = parent.getPlugin().getFlaskAPI();
FlaskAPI api = parent.getPlugin().getFlaskAPI();
players.forEach(player -> api.getPlayerManager().get(player).setLobby(this));

this.phase = parent.initialPhase();
Bukkit.getPluginManager().registerEvents(this.phase, parent.getPlugin());
api.getPlugin().getLogger().info("registering");
api.getDispatcher().registerEvent(this, this.phase);
this.phase.onEnabled(this);
}

// todo: call function in phase
public void addPlayer(Player player) {
var api = parent.getPlugin().getFlaskAPI();
FlaskAPI api = parent.getPlugin().getFlaskAPI();
api.getPlayerManager().get(player).setLobby(this);
players.add(player);
phase.onPlayerJoin(player);
}

public void removePlayer(Player player) {
var api = parent.getPlugin().getFlaskAPI();
FlaskAPI api = parent.getPlugin().getFlaskAPI();
api.getPlayerManager().get(player).setLobby(null);
players.remove(player);
phase.onPlayerLeave(player);
}

public void closeLobby() {
phase.onDisabled();
HandlerList.unregisterAll(phase);

FlaskAPI.instance().getPlugin().getLogger().info("unregistering");
FlaskAPI.instance().getDispatcher().unregisterEvent(this, phase);

// todo: replace with a requeue feature?
players.forEach(player -> {
Expand Down Expand Up @@ -86,12 +83,14 @@ public Phase getPhase() {
}
public void updatePhase(@NotNull Phase phase) {
this.phase.onDisabled();
HandlerList.unregisterAll(this.phase);
FlaskAPI.instance().getPlugin().getLogger().info("unregistering");
FlaskAPI.instance().getDispatcher().unregisterEvent(this, phase);

this.phase = phase;

this.phase.onEnabled(this);
Bukkit.getPluginManager().registerEvents(this.phase, parent.getPlugin());
FlaskAPI.instance().getPlugin().getLogger().info("registering");
FlaskAPI.instance().getDispatcher().registerEvent(this, phase);
}

public void nextPhase() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package io.github.sylviameows.flask.api.game;

import io.github.sylviameows.flask.api.events.FlaskListener;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;

public interface Phase extends Listener {
public interface Phase extends FlaskListener {
/* TODO */

void onEnabled(Lobby<?> parent);
Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
allprojects {
group = "io.github.sylviameows"
version = "0.9.0-ALPHA"
version = "0.10.0-ALPHA"
}
10 changes: 10 additions & 0 deletions core/src/main/java/io/github/sylviameows/flask/Flask.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.github.sylviameows.flask.api.FlaskAPI;
import io.github.sylviameows.flask.api.FlaskPlugin;
import io.github.sylviameows.flask.api.events.FlaskDispatcher;
import io.github.sylviameows.flask.api.manager.PlayerManager;
import io.github.sylviameows.flask.api.registry.GameRegistry;
import io.github.sylviameows.flask.api.services.MessageService;
Expand All @@ -11,6 +12,7 @@
import io.github.sylviameows.flask.commands.hologram.HologramCommand;
import io.github.sylviameows.flask.commands.queue.QueueCommand;
import io.github.sylviameows.flask.hub.holograms.GameHologram;
import io.github.sylviameows.flask.listeners.FlaskDispatcherImpl;
import io.github.sylviameows.flask.listeners.JoinListener;
import io.github.sylviameows.flask.listeners.LeaveListener;
import io.github.sylviameows.flask.listeners.RightClickEntity;
Expand Down Expand Up @@ -44,6 +46,7 @@ public class Flask extends FlaskPlugin implements FlaskAPI {
private static MessageServiceImpl messageService;
private static WorldService worldService;
private static Flask instance;
private static FlaskDispatcherImpl dispatcher;

@Override
public void onEnable() {
Expand All @@ -60,8 +63,10 @@ public void onEnable() {
JoinListener.register(this);
LeaveListener.register(this);

Flask.dispatcher = new FlaskDispatcherImpl();
Flask.messageService = new MessageServiceImpl(this);
Flask.worldService = new FileWorldService();

// commands
registerCommands();

Expand Down Expand Up @@ -156,6 +161,11 @@ public MessageService getMessageService() {
return messageService;
}

@Override
public FlaskDispatcher getDispatcher() {
return dispatcher;
}

@Override
public Plugin getPlugin() {
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ protected Component value() {
var component = Component.text(value ? "True" : "False").color(Palette.DARK_GRAY);
if (isOptional()) {
var d = (boolean) getDefault();
if (value == d) return component.append(Component.text("(default)").color(Palette.GRAY));
if (value == d) return component.append(Component.text(" (default)").color(Palette.GRAY));
}

return component;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package io.github.sylviameows.flask.listeners;

import io.github.sylviameows.flask.Flask;
import io.github.sylviameows.flask.api.FlaskPlayer;
import io.github.sylviameows.flask.api.annotations.FlaskEvent;
import io.github.sylviameows.flask.api.events.FlaskDispatcher;
import io.github.sylviameows.flask.api.events.FlaskListener;
import io.github.sylviameows.flask.api.game.Lobby;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.*;
import org.bukkit.event.block.BlockEvent;
import org.bukkit.event.entity.EntityEvent;
import org.bukkit.event.player.PlayerEvent;
import org.bukkit.event.vehicle.VehicleEvent;
import org.bukkit.event.world.WorldEvent;
import org.jetbrains.annotations.NotNull;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;

public class FlaskDispatcherImpl implements FlaskDispatcher {
Map<Class<? extends Event>, ArrayList<ListenerInfo>> methodMap = new HashMap<>();

@Override
public void registerEvent(Lobby<?> lobby, FlaskListener listener) {
for (Method method : listener.getClass().getDeclaredMethods()) {
if (method.isAnnotationPresent(FlaskEvent.class)) {
Parameter[] parameters = method.getParameters();
if (parameters.length == 1) {
Class<?> clazz = parameters[0].getType();

if (Event.class.isAssignableFrom(clazz)) {
//noinspection unchecked
Class<? extends Event> eventClass = (Class<? extends Event>) clazz;
method.setAccessible(true);

methodMap.computeIfAbsent(eventClass, k -> {
Bukkit.getPluginManager().registerEvent(
eventClass,
this,
EventPriority.HIGH,
this,
Flask.getInstance()
);

return new ArrayList<>();
}).add(new ListenerInfo(lobby, method, listener));
}
}
}
}
}

@Override
public void unregisterEvent(Lobby<?> lobby, FlaskListener listener) {
methodMap.forEach((clazz, listeners) -> {
Optional<ListenerInfo> optional = listeners.stream().filter(info -> (info.listener() == listener && info.lobby() == lobby)).findFirst();
if (optional.isEmpty()) return;
ListenerInfo info = optional.get();

listeners.remove(info);
if (listeners.isEmpty()) {
methodMap.remove(clazz);
// todo: find a way to unregister event fully
}
});
}

@Override
public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException {
ArrayList<ListenerInfo> listeners = new ArrayList<>();

Class<? extends Event> clazz = event.getClass();
methodMap.forEach((e, i) -> {if (e.isAssignableFrom(clazz)) listeners.addAll(i);});
if (listeners.isEmpty()) return;

ListenerInfo info = null;
switch (event) {
case PlayerEvent playerEvent -> {
Player player = playerEvent.getPlayer();
FlaskPlayer fp = Flask.getInstance().getPlayerManager().get(player);

Lobby<?> lobby = fp.getLobby();
for (ListenerInfo i : listeners) {
if (i.lobby() == lobby) {
info = i;
break;
}
}
}
case EntityEvent entityEvent -> {
Entity entity = entityEvent.getEntity();
World world = entity.getWorld();
info = findListenerMatchingWorld(listeners, world);
}
case WorldEvent worldEvent -> {
World world = worldEvent.getWorld();
info = findListenerMatchingWorld(listeners, world);
}
case BlockEvent blockEvent -> {
World world = blockEvent.getBlock().getWorld();
info = findListenerMatchingWorld(listeners, world);
}
case VehicleEvent vehicleEvent -> {
World world = vehicleEvent.getVehicle().getWorld();
info = findListenerMatchingWorld(listeners, world);
}
default -> {
}
}

if (info == null) return;

try {
info.method().invoke(info.listener(), event);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new EventException(e);
}
}

private ListenerInfo findListenerMatchingWorld(ArrayList<ListenerInfo> listeners, World world) {
for (ListenerInfo info : listeners) {
if (info.lobby().getWorld().getName().equals(world.getName())) {
return info;
}
}
return null;
}
}
9 changes: 8 additions & 1 deletion example/src/main/java/io/github/sylviameows/duels/Duels.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import io.github.sylviameows.duels.basic.ExampleGame;
import io.github.sylviameows.flask.api.FlaskAPI;
import io.github.sylviameows.flask.api.FlaskPlugin;
import io.github.sylviameows.flask.api.game.Lobby;
import org.bukkit.Bukkit;

import java.util.ArrayList;

public final class Duels extends FlaskPlugin {
private FlaskAPI flask;

Expand All @@ -16,8 +19,12 @@ public void onEnable() {
flask = api;
}

new ExampleGame(this).register("sword");
new ExampleGame(this).register("duel");

TestingGame eg = new TestingGame(this);
eg.register("test");

eg.createLobby(new ArrayList<>());
}

@Override
Expand Down
Loading