package com.ftloverdrive.event;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
import com.badlogic.gdx.utils.Pool;
import com.badlogic.gdx.utils.Pools;
import com.ftloverdrive.core.OverdriveContext;
import com.ftloverdrive.event.OVDEvent;
import com.ftloverdrive.event.OVDEventListenerList;
import com.ftloverdrive.event.TickEvent;
import com.ftloverdrive.event.TickListener;
/**
* Queues and dispatches OVDEvents.
*
* TODO: Maybe coalesce repeat events when posting, like in
* java.awt.EventQueue?
*/
public class OVDEventManager {
private Deque<OVDEvent> outQueue = new LinkedBlockingDeque<OVDEvent>();
private Deque<OVDEvent> inQueue = new LinkedBlockingDeque<OVDEvent>();
OVDEventListenerList outListenerList = new OVDEventListenerList();
OVDEventListenerList inListenerList = new OVDEventListenerList();
Map<Class,OVDEventHandler> handlerMap = new HashMap<Class,OVDEventHandler>();
private final int tickRate = 1000; // Milliseconds per tick of game-time.
private int spareTime = 0; // Remembers leftover milliseconds between ticks.
private int elapsedTicks; // Micro-optimization to avoid redeclaring a variable.
private final Pool<TickEvent> tickEventPool;
public OVDEventManager() {
tickEventPool = Pools.get( TickEvent.class );
}
/**
* Dispatches any pending events and returns.
*/
public void processEvents( OverdriveContext context ) {
OVDEvent event;
while ( (event = inQueue.poll()) != null ) {
OVDEventHandler h = handlerMap.get( event.getClass() );
if ( h != null ) {
h.handle( context, event, inListenerList.getListenerList() );
h.disposeEvent( event );
}
else {
//System.out.println( "Unhandled event: "+ event );
}
}
while ( (event = outQueue.poll()) != null ) {
// TODO: A registry of handlers to dispatch various event types.
// Otherwise this will just be a hardcoded if/else instance check.
if ( !event.isCancelled() ) {
// Pretend it went to the server and back.
postDelayedInboundEvent( event );
}
}
}
/**
* Adds an event to the end of the inbound queue. (thread-safe)
* This should not normally be used.
*/
public void postDelayedInboundEvent( OVDEvent e ) {
inQueue.addLast( e );
}
/**
* Adds an event to the end of the outbound queue. (thread-safe)
*/
public void postDelayedEvent( OVDEvent e ) {
outQueue.addLast( e );
}
/**
* Adds an event to the start of the outbound queue. (thread-safe)
*/
public void postPreemptiveEvent( OVDEvent e ) {
outQueue.addFirst( e );
}
/**
* Signals that real-world time has elapsed since the last call.
*
* As enough time accumulates, TickEvents may be generated.
*/
public void secondsElapsed( float t ) {
spareTime += (int)(t * 1000); // Add as milliseconds.
elapsedTicks = spareTime / tickRate;
if ( elapsedTicks > 0 ) {
spareTime = spareTime % tickRate;
TickEvent tickEvent = tickEventPool.obtain();
tickEvent.init();
tickEvent.setTickCount( elapsedTicks );
// Pretend the server issued this event.
postDelayedInboundEvent( tickEvent );
}
}
/**
* Sets the handler for a specific event class.
*/
public void setEventHandler( Class eventClass, OVDEventHandler h ) {
handlerMap.put( eventClass, h );
}
/**
* Adds a listener for incoming events.
*
* @param l a listener to be notified
* @param listenerClass a class a handler expects that the listener can be cast as
*/
public <T extends OVDEventListener> void addEventListener( T l, Class<T> listenerClass ) {
inListenerList.add( listenerClass, l );
}
}