/*
* PluggableRobot, by Robert J. Walker
* Home page: http://robowiki.net/cgi-bin/robowiki?PluggableRobot
* This software is made available under the RoboWiki Limited Public Code License (RWLPCL). The full
* text of the license may be found at http://robowiki.net/cgi-bin/robowiki?RWLPCL.
*/
package rjw.pluggablerobot;
import java.util.*;
import robocode.*;
/**
* Class that manages all the event listeners for a PluggableRobot and delegates events to the
* appropriate EventListeners. Unlike the default Robocode behavior, events are doled out first by
* listener (first registered, first notified), then by the order of the listener interfaces
* declared on the listener implementation. So a class with a declaration like this:
* public class MyClass implements ScannedRobotListener, EventListener.Death
* ...will get notified of the ScannedRobotEvent *before* the DeathEvent!
* @author Robert J. Walker
*/
public class ListenerDelegate {
private ArrayList<EventListener> _listeners = new ArrayList<EventListener>();
private static HashMap<Class<? extends EventListener>, ListenerInvoker> _invokers;
// Build the invoker map, allowing us to look up invokers by listener class
static {
_invokers = new HashMap<Class<? extends EventListener>, ListenerInvoker>();
_invokers.put(EventListener.Death.class,
new ListenerInvoker<EventListener.Death, DeathEvent>() {
protected Class<DeathEvent> eventClass() { return DeathEvent.class; }
protected void invokeListener(EventListener.Death listener, DeathEvent event) {
listener.notifyDeath(event);
}
}
);
_invokers.put(EventListener.Win.class,
new ListenerInvoker<EventListener.Win, WinEvent>() {
protected Class<WinEvent> eventClass() { return WinEvent.class; }
protected void invokeListener(EventListener.Win listener, WinEvent event) {
listener.notifyWin(event);
}
}
);
_invokers.put(EventListener.SkippedTurn.class,
new ListenerInvoker<EventListener.SkippedTurn, SkippedTurnEvent>() {
protected Class<SkippedTurnEvent> eventClass() { return SkippedTurnEvent.class; }
protected void invokeListener(EventListener.SkippedTurn listener, SkippedTurnEvent event) {
listener.notifySkippedTurn(event);
}
}
);
_invokers.put(EventListener.ScannedRobot.class,
new ListenerInvoker<EventListener.ScannedRobot, ScannedRobotEvent>() {
protected Class<ScannedRobotEvent> eventClass() { return ScannedRobotEvent.class; }
protected void invokeListener(EventListener.ScannedRobot listener, ScannedRobotEvent event) {
listener.notifyScannedRobot(event);
}
}
);
_invokers.put(EventListener.HitByBullet.class,
new ListenerInvoker<EventListener.HitByBullet, HitByBulletEvent>() {
protected Class<HitByBulletEvent> eventClass() { return HitByBulletEvent.class; }
protected void invokeListener(EventListener.HitByBullet listener, HitByBulletEvent event) {
listener.notifyHitByBullet(event);
}
}
);
_invokers.put(EventListener.BulletHit.class,
new ListenerInvoker<EventListener.BulletHit, BulletHitEvent>() {
protected Class<BulletHitEvent> eventClass() { return BulletHitEvent.class; }
protected void invokeListener(EventListener.BulletHit listener, BulletHitEvent event) {
listener.notifyBulletHit(event);
}
}
);
_invokers.put(EventListener.BulletHitBullet.class,
new ListenerInvoker<EventListener.BulletHitBullet, BulletHitBulletEvent>() {
protected Class<BulletHitBulletEvent> eventClass() { return BulletHitBulletEvent.class; }
protected void invokeListener(EventListener.BulletHitBullet listener, BulletHitBulletEvent event) {
listener.notifyBulletHitBullet(event);
}
}
);
_invokers.put(EventListener.BulletMissed.class,
new ListenerInvoker<EventListener.BulletMissed, BulletMissedEvent>() {
protected Class<BulletMissedEvent> eventClass() { return BulletMissedEvent.class; }
protected void invokeListener(EventListener.BulletMissed listener, BulletMissedEvent event) {
listener.notifyBulletMissed(event);
}
}
);
_invokers.put(EventListener.HitRobot.class,
new ListenerInvoker<EventListener.HitRobot, HitRobotEvent>() {
protected Class<HitRobotEvent> eventClass() { return HitRobotEvent.class; }
protected void invokeListener(EventListener.HitRobot listener, HitRobotEvent event) {
listener.notifyHitRobot(event);
}
}
);
_invokers.put(EventListener.HitWall.class,
new ListenerInvoker<EventListener.HitWall, HitWallEvent>() {
protected Class<HitWallEvent> eventClass() { return HitWallEvent.class; }
protected void invokeListener(EventListener.HitWall listener, HitWallEvent event) {
listener.notifyHitWall(event);
}
}
);
_invokers.put(EventListener.RobotDeath.class,
new ListenerInvoker<EventListener.RobotDeath, RobotDeathEvent>() {
protected Class<RobotDeathEvent> eventClass() { return RobotDeathEvent.class; }
protected void invokeListener(EventListener.RobotDeath listener, RobotDeathEvent event) {
listener.notifyRobotDeath(event);
}
}
);
}
/**
* Register a new EventListener.
*/
public void register(EventListener listener) {
_listeners.add(listener);
}
/**
* Hand out event notifications to the EventListeners.
*/
public void processEvents(Vector<Event> events) {
// Notify listeners in the order they were registered
for(EventListener listener : _listeners) {
Class[] interfaces = listener.getClass().getInterfaces();
// Iterate the interfaces on each listener that descend from EventListener
for(Class iface : interfaces) {
if(!EventListener.class.isAssignableFrom(iface)) continue;
// Get the invoker and the corresponding event class for this interface
ListenerInvoker invoker = _invokers.get(iface);
Class<? extends Event> eventClass = invoker.eventClass();
// Iterate the events and hand the ones of the proper type to the invoker
for(Event event : events) {
if(!eventClass.isAssignableFrom(event.getClass())) continue;
invoker.invokeListener(listener, event);
}
}
}
}
/**
* An object that knows about a Robocode Event class and how to invoke its corresponding
* EventListener.
* @author Robert J. Walker
*/
private static abstract class ListenerInvoker<K extends EventListener, V extends Event> {
/**
* Returns the Robocode Event class handled by this ListenerInvoker.
*/
protected abstract Class<V> eventClass();
/**
* Invokes the given EventListener, passing in a Robocode Event object.
*/
protected abstract void invokeListener(K listener, V event);
}
}