Add Event/Listener framework to common/ecs

This commit is contained in:
Matt Low 2020-01-25 00:15:12 +04:00
parent 83113f3afd
commit 22fc504619
7 changed files with 157 additions and 0 deletions

View File

@ -1,6 +1,8 @@
package com.me.common.ecs; package com.me.common.ecs;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import com.me.common.ecs.event.Event;
import com.me.common.ecs.event.Listener;
public class Engine { public class Engine {
@ -8,9 +10,12 @@ public class Engine {
private ComponentBag[] components; private ComponentBag[] components;
private Array<EntitySystem> systems; private Array<EntitySystem> systems;
private ListenerRegistry listenerRegistry;
public Engine() { public Engine() {
this.entities = new Array<>(); this.entities = new Array<>();
this.systems = new Array<>(); this.systems = new Array<>();
this.listenerRegistry = new ListenerRegistry();
} }
public void registerComponentClass(Class<? extends Component> clazz) { public void registerComponentClass(Class<? extends Component> clazz) {
@ -47,6 +52,14 @@ public class Engine {
entities.removeValue(entity, true); 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) { private void removeAllEntityComponents(int entityId) {
for (int i = 0; i < components.length; i++) { for (int i = 0; i < components.length; i++) {
components[i].insert(entityId, null); components[i].insert(entityId, null);

View File

@ -33,6 +33,10 @@ public final class Entity {
this.active = false; this.active = false;
} }
public Engine getEngine() {
return this.engine;
}
public <T extends Component> T getComponent(Class<T> clazz) { public <T extends Component> T getComponent(Class<T> clazz) {
return engine.getEntityComponent(this, clazz); return engine.getEntityComponent(this, clazz);
} }

View File

@ -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<Class<? extends Event>, List<RegisteredListener>> 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<? extends Event> eventClass = parameters[0].asSubclass(Event.class);
method.setAccessible(true);
List<RegisteredListener> 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<RegisteredListener> listeners = registeredListeners.get(event.getClass());
if (listeners == null) {
return;
}
for (RegisteredListener listener : listeners) {
if (listener.isIgnoringCancelled() && event.isCancelled()) {
continue;
}
listener.execute(event);
}
}
}

View File

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

View File

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

View File

@ -0,0 +1,5 @@
package com.me.common.ecs.event;
public interface Listener {
}

View File

@ -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<? extends Event> eventType;
public EventHandler eh;
public RegisteredListener(Listener listener, Method method, Class<? extends Event> 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);
}
}
}