From 22fc5046190183322e7ec2635828816dea4a316a Mon Sep 17 00:00:00 2001 From: Matt Low Date: Sat, 25 Jan 2020 00:15:12 +0400 Subject: [PATCH] Add Event/Listener framework to common/ecs --- core/src/com/me/common/ecs/Engine.java | 13 ++++ core/src/com/me/common/ecs/Entity.java | 4 ++ .../com/me/common/ecs/ListenerRegistry.java | 66 +++++++++++++++++++ core/src/com/me/common/ecs/event/Event.java | 19 ++++++ .../com/me/common/ecs/event/EventHandler.java | 14 ++++ .../src/com/me/common/ecs/event/Listener.java | 5 ++ .../common/ecs/event/RegisteredListener.java | 36 ++++++++++ 7 files changed, 157 insertions(+) create mode 100644 core/src/com/me/common/ecs/ListenerRegistry.java create mode 100644 core/src/com/me/common/ecs/event/Event.java create mode 100644 core/src/com/me/common/ecs/event/EventHandler.java create mode 100644 core/src/com/me/common/ecs/event/Listener.java create mode 100644 core/src/com/me/common/ecs/event/RegisteredListener.java diff --git a/core/src/com/me/common/ecs/Engine.java b/core/src/com/me/common/ecs/Engine.java index b62976c..cce1c9f 100644 --- a/core/src/com/me/common/ecs/Engine.java +++ b/core/src/com/me/common/ecs/Engine.java @@ -1,6 +1,8 @@ package com.me.common.ecs; import com.badlogic.gdx.utils.Array; +import com.me.common.ecs.event.Event; +import com.me.common.ecs.event.Listener; public class Engine { @@ -8,9 +10,12 @@ public class Engine { private ComponentBag[] components; private Array systems; + private ListenerRegistry listenerRegistry; + public Engine() { this.entities = new Array<>(); this.systems = new Array<>(); + this.listenerRegistry = new ListenerRegistry(); } public void registerComponentClass(Class clazz) { @@ -47,6 +52,14 @@ public class Engine { entities.removeValue(entity, true); } + public void registerListener(Listener listener) { + listenerRegistry.registerListener(listener); + } + + public void callEvent(Event event) { + listenerRegistry.callEvent(event); + } + private void removeAllEntityComponents(int entityId) { for (int i = 0; i < components.length; i++) { components[i].insert(entityId, null); diff --git a/core/src/com/me/common/ecs/Entity.java b/core/src/com/me/common/ecs/Entity.java index f820c24..444014c 100644 --- a/core/src/com/me/common/ecs/Entity.java +++ b/core/src/com/me/common/ecs/Entity.java @@ -33,6 +33,10 @@ public final class Entity { this.active = false; } + public Engine getEngine() { + return this.engine; + } + public T getComponent(Class clazz) { return engine.getEntityComponent(this, clazz); } diff --git a/core/src/com/me/common/ecs/ListenerRegistry.java b/core/src/com/me/common/ecs/ListenerRegistry.java new file mode 100644 index 0000000..aaabff0 --- /dev/null +++ b/core/src/com/me/common/ecs/ListenerRegistry.java @@ -0,0 +1,66 @@ +package com.me.common.ecs; + +import com.me.common.ecs.event.Event; +import com.me.common.ecs.event.RegisteredListener; +import com.me.common.ecs.event.EventHandler; +import com.me.common.ecs.event.Listener; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ListenerRegistry { + + private final Map, List> registeredListeners; + + protected ListenerRegistry() { + this.registeredListeners = new HashMap<>(); + } + + protected void registerListener(Listener listener) { + Method[] methods = listener.getClass().getMethods(); + + for (Method method : methods) { + EventHandler eh = method.getAnnotation(EventHandler.class); + if (eh == null) { + continue; + } + + Class[] parameters = method.getParameterTypes(); + if (parameters.length != 1 || !Event.class.isAssignableFrom(parameters[0])) { + System.err.println("Attempting to register an EventHandler with an invalid method signature: " + method.toGenericString() + " in " + listener.getClass()); + continue; + } + + Class eventClass = parameters[0].asSubclass(Event.class); + method.setAccessible(true); + + List executors = registeredListeners.get(eventClass); + if (executors == null) { + executors = new ArrayList<>(); + registeredListeners.put(eventClass, executors); + } + + executors.add(new RegisteredListener(listener, method, eventClass, eh)); + } + + } + + protected void callEvent(Event event) { + List listeners = registeredListeners.get(event.getClass()); + if (listeners == null) { + return; + } + + for (RegisteredListener listener : listeners) { + if (listener.isIgnoringCancelled() && event.isCancelled()) { + continue; + } + + listener.execute(event); + } + } + +} diff --git a/core/src/com/me/common/ecs/event/Event.java b/core/src/com/me/common/ecs/event/Event.java new file mode 100644 index 0000000..67cdf07 --- /dev/null +++ b/core/src/com/me/common/ecs/event/Event.java @@ -0,0 +1,19 @@ +package com.me.common.ecs.event; + +public abstract class Event { + + boolean cancelled; + + public Event() { + cancelled = false; + } + + public boolean isCancelled() { + return cancelled; + } + + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + +} diff --git a/core/src/com/me/common/ecs/event/EventHandler.java b/core/src/com/me/common/ecs/event/EventHandler.java new file mode 100644 index 0000000..0f3d984 --- /dev/null +++ b/core/src/com/me/common/ecs/event/EventHandler.java @@ -0,0 +1,14 @@ +package com.me.common.ecs.event; + +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 EventHandler { + + boolean ignoreCancelled() default false; + +} diff --git a/core/src/com/me/common/ecs/event/Listener.java b/core/src/com/me/common/ecs/event/Listener.java new file mode 100644 index 0000000..77ac2fb --- /dev/null +++ b/core/src/com/me/common/ecs/event/Listener.java @@ -0,0 +1,5 @@ +package com.me.common.ecs.event; + +public interface Listener { + +} diff --git a/core/src/com/me/common/ecs/event/RegisteredListener.java b/core/src/com/me/common/ecs/event/RegisteredListener.java new file mode 100644 index 0000000..73ca218 --- /dev/null +++ b/core/src/com/me/common/ecs/event/RegisteredListener.java @@ -0,0 +1,36 @@ +package com.me.common.ecs.event; + +import java.lang.reflect.Method; + +public class RegisteredListener { + + private Listener listener; + private Method method; + private Class eventType; + + public EventHandler eh; + + public RegisteredListener(Listener listener, Method method, Class eventType, EventHandler eh) { + this.listener = listener; + this.method = method; + this.eventType = eventType; + this.eh = eh; + } + + public boolean isIgnoringCancelled() { + return eh.ignoreCancelled(); + } + + public void execute(Event event) { + if (!eventType.isAssignableFrom(event.getClass())) { + return; + } + + try { + method.invoke(listener, event); + } catch (Throwable e) { + System.err.println("Could not call event " + event.toString() + ": " + e); + } + } + +}