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

Update Event handling #30

Merged
merged 9 commits into from
May 5, 2024
Merged
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ repositories {
}

dependencies {

implementation("com.github.Minestom", "Minestom", "6b8a4e4cc9") // minstom itself
implementation("com.google.code.gson:gson:2.10.1") // serializing
implementation("org.slf4j:slf4j-api:2.0.13") // logging
implementation("net.kyori:adventure-text-minimessage:4.16.0")// better components
implementation("mysql:mysql-connector-java:8.0.33") //mysql connector
compileOnly("org.projectlombok:lombok:1.18.32") // lombok
annotationProcessor("org.projectlombok:lombok:1.18.32") // lombok
implementation("org.tomlj:tomlj:1.1.1") // Config lang
implementation("com.rabbitmq:amqp-client:5.21.0") // Message broker
}
Expand All @@ -48,6 +49,5 @@ tasks {
}
mergeServiceFiles()
archiveFileName.set("cytosis.jar")
//destinationDirectory.set(file(providers.gradleProperty("server_dir").get()))
}
}
1 change: 1 addition & 0 deletions src/main/java/net/cytonic/cytosis/Cytosis.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ public static void completeNonEssentialTasks(long start) {

Logger.info("Setting up event handlers");
EVENT_HANDLER = new EventHandler(MinecraftServer.getGlobalEventHandler());
EVENT_HANDLER.init();

Logger.info("Initializing server events");
ServerEventListeners.initServerEvents();
Expand Down
190 changes: 181 additions & 9 deletions src/main/java/net/cytonic/cytosis/events/EventHandler.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,196 @@
package net.cytonic.cytosis.events;

import net.minestom.server.event.Event;
import net.minestom.server.event.EventListener;
import net.minestom.server.event.EventNode;
import net.minestom.server.event.GlobalEventHandler;
import org.jetbrains.annotations.NotNull;
import java.util.function.Consumer;
import net.minestom.server.event.book.EditBookEvent;
import net.minestom.server.event.entity.*;
import net.minestom.server.event.entity.projectile.ProjectileCollideWithBlockEvent;
import net.minestom.server.event.entity.projectile.ProjectileCollideWithEntityEvent;
import net.minestom.server.event.entity.projectile.ProjectileUncollideEvent;
import net.minestom.server.event.instance.*;
import net.minestom.server.event.inventory.*;
import net.minestom.server.event.item.*;
import net.minestom.server.event.player.*;
import net.minestom.server.event.server.ClientPingServerEvent;
import net.minestom.server.event.server.ServerListPingEvent;
import net.minestom.server.event.server.ServerTickMonitorEvent;
import net.minestom.server.event.trait.CancellableEvent;

import java.util.*;

/**
* EventHandler class is responsible for handling events and managing listeners.
* It provides methods to register, unregister listeners and to handle global events.
*
* @author Foxikle
*/
public class EventHandler {
private final GlobalEventHandler GLOBAL_HANDLER;
private final Map<String, EventListener<? extends Event>> NAMESPACED_HANDLERS = new HashMap<>();
private boolean initialized = false;

/**
* Constructor for EventHandler.
* Initializes the GlobalEventHandler instance.
*
* @param globalHandler The GlobalEventHandler instance to be used.
*/
public EventHandler(GlobalEventHandler globalHandler) {
GLOBAL_HANDLER = globalHandler;
}

public <T extends Event> EventNode<Event> registerGlobalEvent(EventListener<T> listener) {
return GLOBAL_HANDLER.addListener(listener);
public void init() {
if (initialized) throw new IllegalStateException("The event handler has already been initialized!");
setupInternalListeners();
initialized = true;
}

/**
* Unregisters a listener by its namespace.
*
* @param listener The listener to be unregistered.
* @return True if the listener was successfully unregistered, false otherwise.
*/
public boolean unregisterListener(EventListener<? extends Event> listener) {
return NAMESPACED_HANDLERS.remove(listener.getNamespace()) != null;
}

/**
* Unregisters a listener by its namespace.
*
* @param namespace The namespace of the listener to be unregistered.
* @return True if the listener was successfully unregistered, false otherwise.
*/
public boolean unregisterListener(String namespace) {
return NAMESPACED_HANDLERS.remove(namespace) != null;
}

public <E extends Event> @NotNull EventNode<Event> registerGlobalEvent(@NotNull Class<E> clazz, @NotNull Consumer<E> listener) {
return GLOBAL_HANDLER.addListener(EventListener.of(clazz, listener));
/**
* Registers a listener.
*
* @param listener The listener to be registered.
* @return True if the listener was successfully registered, false otherwise.
*/
public boolean registerListener(EventListener<? extends Event> listener) {
return NAMESPACED_HANDLERS.putIfAbsent(listener.getNamespace(), listener) == listener;
}

public <T extends Event> void handleEvent(T event) {
List<EventListener<? extends Event>> matchingListeners = new ArrayList<>();

for (EventListener<? extends Event> listener : NAMESPACED_HANDLERS.values()) {
if (listener.getEventClass() == event.getClass() &&
!(event instanceof CancellableEvent && ((CancellableEvent) event).isCancelled())) {
matchingListeners.add(listener);
}
}

// Sort listeners by priority
matchingListeners.sort(Comparator.comparingInt(EventListener::getPriority));

for (EventListener<? extends Event> listener : matchingListeners) {
if (!(event instanceof CancellableEvent && ((CancellableEvent) event).isCancelled()))
listener.complete(event);
}
}


private void setupInternalListeners() {
//book events
GLOBAL_HANDLER.addListener(EditBookEvent.class, (this::handleEvent));
// entity events
GLOBAL_HANDLER.addListener(EntityAttackEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(EntityDamageEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(EntityDeathEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(EntityDespawnEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(EntityFireEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(EntityItemMergeEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(EntityPotionAddEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(EntityPotionRemoveEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(EntityShootEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(EntitySpawnEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(EntityTickEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(EntityVelocityEvent.class, (this::handleEvent));

//projectile events
GLOBAL_HANDLER.addListener(ProjectileCollideWithBlockEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(ProjectileCollideWithEntityEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(ProjectileUncollideEvent.class, (this::handleEvent));

// Instance events
GLOBAL_HANDLER.addListener(AddEntityToInstanceEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(InstanceChunkLoadEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(InstanceChunkUnloadEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(InstanceRegisterEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(InstanceTickEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(InstanceUnregisterEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(RemoveEntityFromInstanceEvent.class, (this::handleEvent));

// Inventory Events
GLOBAL_HANDLER.addListener(InventoryClickEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(InventoryCloseEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(InventoryItemChangeEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(InventoryOpenEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(InventoryPreClickEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerInventoryItemChangeEvent.class, (this::handleEvent));

// Item Events
GLOBAL_HANDLER.addListener(EntityEquipEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(ItemDropEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(ItemUpdateStateEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PickupExperienceEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PickupItemEvent.class, (this::handleEvent));

// player events
GLOBAL_HANDLER.addListener(AdvancementTabEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(AsyncPlayerConfigurationEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(AsyncPlayerPreLoginEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerBlockBreakEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerBlockInteractEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerBlockPlaceEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerCancelDiggingEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerChangeHeldSlotEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerChatEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerChunkLoadEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerChunkUnloadEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerCommandEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerDeathEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerDisconnectEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerEatEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerEntityInteractEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerFinishDiggingEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerGameModeChangeEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerHandAnimationEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerItemAnimationEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerMoveEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerPacketEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerPacketOutEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerPluginMessageEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerPreEatEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerResourcePackStatusEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerRespawnEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerSettingsChangeEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerSkinInitEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerSpawnEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerSpectateEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerStartDiggingEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerStartFlyingEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerStartFlyingWithElytraEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerStartSprintingEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerStartSneakingEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerStopFlyingEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerStopFlyingWithElytraEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerStopSprintingEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerStopSneakingEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerSwapItemEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerTickEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerUseItemEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(PlayerUseItemOnBlockEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(UpdateTagListEvent.class, (this::handleEvent)); // deprecated

// Server
GLOBAL_HANDLER.addListener(ClientPingServerEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(ServerListPingEvent.class, (this::handleEvent));
GLOBAL_HANDLER.addListener(ServerTickMonitorEvent.class, (this::handleEvent));
}
}
}
63 changes: 63 additions & 0 deletions src/main/java/net/cytonic/cytosis/events/EventListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package net.cytonic.cytosis.events;

import lombok.Getter;
import net.minestom.server.event.Event;

import java.util.function.Consumer;

@Getter
public class EventListener<T extends Event> {
private final Class<T> eventClass;
private final Consumer<T> consumer;
private final boolean async;
private final int priority;
private final String namespace;

/**
* Constructs a new instance of {@link EventListener} with the specified namespace, priority, and consumer.
*
* @param namespace The namespace of the event listener.
* @param eventClass The class of the event that the listener will be triggered for.
* @param async A boolean value indicating whether the event listener should run asynchronously.
* @param priority The priority of the event listener.
* @param consumer The consumer that will be called when the event is triggered.
* @since 1.0.0
*/
public EventListener(String namespace, boolean async, int priority, Class<T> eventClass, Consumer<T> consumer) {
this.consumer = consumer;
this.eventClass = eventClass;
this.async = async;
this.priority = priority;
this.namespace = namespace;
}


/**
* Constructs a new instance of {@link EventListener} with the specified namespace, priority, and consumer. It will be executed synchronously.
*
* @param namespace The namespace of the event listener.
* @param priority The priority of the event listener.
* @param consumer The consumer that will be called when the event is triggered.
* @param eventClass The class of the event that the listener will be triggered for.
* @since 1.0.0
*/
public EventListener(String namespace, int priority, Class<T> eventClass, Consumer<T> consumer) {
this.consumer = consumer;
this.async = false;
this.eventClass = eventClass;
this.priority = priority;
this.namespace = namespace;
}

/**
* Completes the EventListener's consumer with the provided event object.
*
* @param event The event to complete the consumer with.
* @since 1.0.0
*/
public void complete(Object event) {
if (!eventClass.isInstance(event))
throw new IllegalArgumentException(STR."The specified event object isn't an instance of \{eventClass.getName()}");
consumer.accept(eventClass.cast(event));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,36 @@
import net.cytonic.cytosis.logging.Logger;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player;
import net.minestom.server.event.Event;
import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
import net.minestom.server.event.player.PlayerChatEvent;
import net.minestom.server.event.player.PlayerChatEvent;
import net.minestom.server.event.player.PlayerSpawnEvent;

public class ServerEventListeners {

public static void initServerEvents() {

Logger.info("Registering player configuration event.");
Cytosis.getEventHandler().registerGlobalEvent(AsyncPlayerConfigurationEvent.class, event -> {
Cytosis.getEventHandler().registerListener(new EventListener<>("core:player-configuration", true, 1, AsyncPlayerConfigurationEvent.class, (event -> {
final Player player = event.getPlayer();
event.setSpawningInstance(Cytosis.getDefaultInstance());
player.setRespawnPoint(new Pos(0, 45, 0));
});
})));

Logger.info("Registering player spawn event.");
Cytosis.getEventHandler().registerGlobalEvent(PlayerSpawnEvent.class, event -> {
Cytosis.getEventHandler().registerListener(new EventListener<>("core:player-spawn", false, 1, PlayerSpawnEvent.class, (event -> {
final Player player = event.getPlayer();
if (CytosisSettings.LOG_PLAYER_IPS)
Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined with the ip: \{player.getPlayerConnection().getServerAddress()}");
else
Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined.");
player.sendMessage("Hello!");
});
else Logger.info(STR."\{event.getPlayer().getUsername()} (\{event.getPlayer().getUuid()}) joined.");
})));

Logger.info("Registering player chat event.");
Cytosis.getEventHandler().registerGlobalEvent(PlayerChatEvent.class, event -> {
Cytosis.getEventHandler().registerListener(new EventListener<PlayerChatEvent>("core:player-chat", false, 1, PlayerChatEvent.class,event ->{
final Player player = event.getPlayer();
if (CytosisSettings.LOG_PLAYER_CHAT)
Cytosis.getDatabaseManager().getDatabase().addChat(player.getUuid(),event.getMessage());
});
}));
}
}