diff --git a/src/main/java/net/minestom/server/MinecraftServer.java b/src/main/java/net/minestom/server/MinecraftServer.java index 545ab891b..134b4a8a7 100644 --- a/src/main/java/net/minestom/server/MinecraftServer.java +++ b/src/main/java/net/minestom/server/MinecraftServer.java @@ -125,8 +125,8 @@ public final class MinecraftServer { private static ExtensionManager extensionManager; - private static final GlobalEventHandler GLOBAL_EVENT_HANDLER = new GlobalEventHandler(); private static final EventNode GLOBAL_EVENT_NODE = EventNode.all(); + private static final GlobalEventHandler GLOBAL_EVENT_HANDLER = new GlobalEventHandler(); private static UpdateManager updateManager; private static MinecraftServer minecraftServer; diff --git a/src/main/java/net/minestom/server/entity/Entity.java b/src/main/java/net/minestom/server/entity/Entity.java index dddab7a40..4fc0276c0 100644 --- a/src/main/java/net/minestom/server/entity/Entity.java +++ b/src/main/java/net/minestom/server/entity/Entity.java @@ -16,11 +16,12 @@ import net.minestom.server.collision.CollisionUtils; import net.minestom.server.data.Data; import net.minestom.server.data.DataContainer; import net.minestom.server.entity.metadata.EntityMeta; -import net.minestom.server.event.Event; -import net.minestom.server.event.EventCallback; import net.minestom.server.event.EventDispatcher; +import net.minestom.server.event.EventFilter; +import net.minestom.server.event.EventNode; import net.minestom.server.event.entity.*; import net.minestom.server.event.handler.EventHandler; +import net.minestom.server.event.trait.EntityEvent; import net.minestom.server.instance.Chunk; import net.minestom.server.instance.Instance; import net.minestom.server.instance.InstanceManager; @@ -62,7 +63,7 @@ import java.util.function.UnaryOperator; *

* To create your own entity you probably want to extends {@link LivingEntity} or {@link EntityCreature} instead. */ -public class Entity implements Viewable, Tickable, EventHandler, DataContainer, PermissionHandler, HoverEventSource { +public class Entity implements Viewable, Tickable, EventHandler, DataContainer, PermissionHandler, HoverEventSource { private static final Map ENTITY_BY_ID = new ConcurrentHashMap<>(); private static final Map ENTITY_BY_UUID = new ConcurrentHashMap<>(); @@ -117,8 +118,7 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer, private long lastAbsoluteSynchronizationTime; // Events - private final Map, Collection> eventCallbacks = new ConcurrentHashMap<>(); - private final Map>> extensionCallbacks = new ConcurrentHashMap<>(); + private final EventNode eventNode = EventNode.type(EventFilter.ENTITY); protected Metadata metadata = new Metadata(this); protected EntityMeta entityMeta; @@ -155,6 +155,8 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer, Entity.ENTITY_BY_ID.put(id, this); Entity.ENTITY_BY_UUID.put(uuid, this); + + MinecraftServer.getGlobalEventNode().map(this, eventNode); } public Entity(@NotNull EntityType entityType) { @@ -769,16 +771,9 @@ public class Entity implements Viewable, Tickable, EventHandler, DataContainer, } } - @NotNull @Override - public Map, Collection> getEventCallbacksMap() { - return eventCallbacks; - } - - @NotNull - @Override - public Collection> getExtensionCallbacks(String extension) { - return extensionCallbacks.computeIfAbsent(extension, e -> new CopyOnWriteArrayList<>()); + public @NotNull EventNode getEventNode() { + return eventNode; } /** diff --git a/src/main/java/net/minestom/server/event/GlobalEventHandler.java b/src/main/java/net/minestom/server/event/GlobalEventHandler.java index 69c2d12b4..41d8a724a 100644 --- a/src/main/java/net/minestom/server/event/GlobalEventHandler.java +++ b/src/main/java/net/minestom/server/event/GlobalEventHandler.java @@ -1,31 +1,22 @@ package net.minestom.server.event; +import net.minestom.server.MinecraftServer; import net.minestom.server.event.handler.EventHandler; import org.jetbrains.annotations.NotNull; -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; - /** * Object containing all the global event listeners. */ -public final class GlobalEventHandler implements EventHandler { +public final class GlobalEventHandler implements EventHandler { - // Events - private final Map, Collection> eventCallbacks = new ConcurrentHashMap<>(); - private final Map>> extensionCallbacks = new ConcurrentHashMap<>(); + private final EventNode node = EventNode.all(); - @NotNull - @Override - public Map, Collection> getEventCallbacksMap() { - return eventCallbacks; + { + MinecraftServer.getGlobalEventNode().addChild(node); } - @NotNull @Override - public Collection> getExtensionCallbacks(String extension) { - return extensionCallbacks.computeIfAbsent(extension, e -> new CopyOnWriteArrayList<>()); + public @NotNull EventNode getEventNode() { + return node; } } diff --git a/src/main/java/net/minestom/server/event/handler/EventHandler.java b/src/main/java/net/minestom/server/event/handler/EventHandler.java index e3526c416..c78dcc9c3 100644 --- a/src/main/java/net/minestom/server/event/handler/EventHandler.java +++ b/src/main/java/net/minestom/server/event/handler/EventHandler.java @@ -1,126 +1,20 @@ package net.minestom.server.event.handler; -import net.minestom.server.MinecraftServer; import net.minestom.server.event.Event; import net.minestom.server.event.EventCallback; -import net.minestom.server.extensions.IExtensionObserver; -import net.minestom.server.extras.selfmodification.MinestomRootClassLoader; +import net.minestom.server.event.EventNode; import org.jetbrains.annotations.NotNull; -import java.util.Collection; -import java.util.Map; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.stream.Stream; - /** * Represents an element which can have {@link Event} listeners assigned to it. */ -public interface EventHandler extends IExtensionObserver { +public interface EventHandler { - /** - * Gets a {@link Map} containing all the listeners assigned to a specific {@link Event} type. - * - * @return a {@link Map} with all the listeners - */ - @NotNull - Map, Collection> getEventCallbacksMap(); + @NotNull EventNode getEventNode(); - /** - * Gets a {@link Collection} containing all the listeners assigned to a specific extension (represented by its name). - * Used to unload all callbacks when the extension is unloaded - * - * @return a {@link Collection} with all the listeners - */ - @NotNull - Collection> getExtensionCallbacks(String extension); - - /** - * Adds a new event callback for the specified type {@code eventClass}. - * - * @param eventClass the event class - * @param eventCallback the event callback - * @param the event type - * @return true if the callback collection changed as a result of the call - */ - default boolean addEventCallback(@NotNull Class eventClass, @NotNull EventCallback eventCallback) { - String extensionSource = MinestomRootClassLoader.findExtensionObjectOwner(eventCallback); - if (extensionSource != null) { - MinecraftServer.getExtensionManager().getExtension(extensionSource).observe(this); - getExtensionCallbacks(extensionSource).add(eventCallback); - } - - Collection callbacks = getEventCallbacks(eventClass); - return callbacks.add(eventCallback); + default boolean addEventCallback(@NotNull Class eventClass, @NotNull EventCallback eventCallback) { + var node = getEventNode(); + node.addListener(eventClass, eventCallback::run); + return true; } - - /** - * Removes an event callback. - * - * @param eventClass the event class - * @param eventCallback the event callback - * @param the event type - * @return true if the callback was removed as a result of this call - */ - default boolean removeEventCallback(@NotNull Class eventClass, @NotNull EventCallback eventCallback) { - Collection callbacks = getEventCallbacks(eventClass); - String extensionSource = MinestomRootClassLoader.findExtensionObjectOwner(eventCallback); - if (extensionSource != null) { - getExtensionCallbacks(extensionSource).remove(eventCallback); - } - - return callbacks.remove(eventCallback); - } - - /** - * Gets the event callbacks of a specific event type. - * - * @param eventClass the event class - * @param the event type - * @return all event callbacks for the specified type {@code eventClass} - */ - @NotNull - default Collection getEventCallbacks(@NotNull Class eventClass) { - return getEventCallbacksMap().computeIfAbsent(eventClass, clazz -> new CopyOnWriteArraySet<>()); - } - - /** - * Gets a {@link Stream} containing all the {@link EventCallback}, no matter to which {@link Event} they are linked. - * - * @return a {@link Stream} containing all the callbacks - */ - @NotNull - default Stream getEventCallbacks() { - return getEventCallbacksMap().values().stream().flatMap(Collection::stream); - } - - /** - * Remove all event callbacks owned by the given extension - * - * @param extension the extension to remove callbacks from - */ - default void removeCallbacksOwnedByExtension(String extension) { - Collection> extensionCallbacks = getExtensionCallbacks(extension); - for (EventCallback callback : extensionCallbacks) { - - // try to remove this callback from all callback collections - // we do this because we do not have information about the event class at this point - for (Collection eventCallbacks : getEventCallbacksMap().values()) { - eventCallbacks.remove(callback); - } - } - - extensionCallbacks.clear(); - } - - private void runEvent(@NotNull Collection eventCallbacks, @NotNull E event) { - for (EventCallback eventCallback : eventCallbacks) { - eventCallback.run(event); - } - } - - @Override - default void onExtensionUnload(String extensionName) { - removeCallbacksOwnedByExtension(extensionName); - } - } diff --git a/src/main/java/net/minestom/server/instance/Instance.java b/src/main/java/net/minestom/server/instance/Instance.java index 31dab30d1..00f1f1bf2 100644 --- a/src/main/java/net/minestom/server/instance/Instance.java +++ b/src/main/java/net/minestom/server/instance/Instance.java @@ -12,13 +12,14 @@ import net.minestom.server.entity.EntityCreature; import net.minestom.server.entity.ExperienceOrb; import net.minestom.server.entity.Player; import net.minestom.server.entity.pathfinding.PFInstanceSpace; -import net.minestom.server.event.Event; -import net.minestom.server.event.EventCallback; import net.minestom.server.event.EventDispatcher; +import net.minestom.server.event.EventFilter; +import net.minestom.server.event.EventNode; import net.minestom.server.event.handler.EventHandler; import net.minestom.server.event.instance.AddEntityToInstanceEvent; import net.minestom.server.event.instance.InstanceTickEvent; import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent; +import net.minestom.server.event.trait.InstanceEvent; import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.BlockManager; import net.minestom.server.instance.block.CustomBlock; @@ -43,7 +44,6 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; /** @@ -57,7 +57,7 @@ import java.util.function.Consumer; * you need to be sure to signal the {@link UpdateManager} of the changes using * {@link UpdateManager#signalChunkLoad(Chunk)} and {@link UpdateManager#signalChunkUnload(Chunk)}. */ -public abstract class Instance implements BlockModifier, Tickable, EventHandler, DataContainer, PacketGroupingAudience { +public abstract class Instance implements BlockModifier, Tickable, EventHandler, DataContainer, PacketGroupingAudience { protected static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager(); protected static final UpdateManager UPDATE_MANAGER = MinecraftServer.getUpdateManager(); @@ -80,8 +80,7 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler, // Field for tick events private long lastTickAge = System.currentTimeMillis(); - private final Map, Collection> eventCallbacks = new ConcurrentHashMap<>(); - private final Map>> extensionCallbacks = new ConcurrentHashMap<>(); + private final EventNode eventNode = EventNode.type(EventFilter.INSTANCE); // Entities present in this instance protected final Set entities = ConcurrentHashMap.newKeySet(); @@ -120,6 +119,7 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler, this.dimensionType = dimensionType; this.worldBorder = new WorldBorder(this); + MinecraftServer.getGlobalEventNode().map(this, eventNode); } /** @@ -834,16 +834,9 @@ public abstract class Instance implements BlockModifier, Tickable, EventHandler, this.data = data; } - @NotNull @Override - public Map, Collection> getEventCallbacksMap() { - return eventCallbacks; - } - - @NotNull - @Override - public Collection> getExtensionCallbacks(String extension) { - return extensionCallbacks.computeIfAbsent(extension, e -> new CopyOnWriteArrayList<>()); + public @NotNull EventNode getEventNode() { + return eventNode; } // UNSAFE METHODS (need most of time to be synchronized)