add port of event manangement code
This commit is contained in:
parent
6d27325155
commit
8098ea057d
|
@ -141,6 +141,10 @@
|
|||
<Compile Include="Support\IPoolable.cs" />
|
||||
<Compile Include="Support\BasicObjectPool.cs" />
|
||||
<Compile Include="Support\ObjectPools.cs" />
|
||||
<Compile Include="Events\Event.cs" />
|
||||
<Compile Include="Events\EventManager.cs" />
|
||||
<Compile Include="Events\IEventListener.cs" />
|
||||
<Compile Include="Events\EventHandler.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
@ -155,6 +159,7 @@
|
|||
<Folder Include="Support\" />
|
||||
<Folder Include="Graphics\CustomShaders\" />
|
||||
<Folder Include="Graphics\Helpers\" />
|
||||
<Folder Include="Events\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\Fonts\Vera.ttf" />
|
||||
|
|
11
Blarg.GameFramework/Events/Event.cs
Normal file
11
Blarg.GameFramework/Events/Event.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
using Blarg.GameFramework.Support;
|
||||
|
||||
namespace Blarg.GameFramework.Events
|
||||
{
|
||||
public abstract class Event : IPoolable
|
||||
{
|
||||
public abstract void Reset();
|
||||
}
|
||||
}
|
||||
|
30
Blarg.GameFramework/Events/EventHandler.cs
Normal file
30
Blarg.GameFramework/Events/EventHandler.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
|
||||
namespace Blarg.GameFramework.Events
|
||||
{
|
||||
public abstract class EventHandler : IEventListener
|
||||
{
|
||||
public readonly EventManager EventManager;
|
||||
|
||||
public EventHandler(EventManager eventManager)
|
||||
{
|
||||
if (eventManager == null)
|
||||
throw new ArgumentNullException("eventManager");
|
||||
|
||||
EventManager = eventManager;
|
||||
}
|
||||
|
||||
public bool ListenFor<T>() where T : Event
|
||||
{
|
||||
return EventManager.AddListener<T>(this);
|
||||
}
|
||||
|
||||
public bool StopListeningFor<T>() where T : Event
|
||||
{
|
||||
return EventManager.RemoveListener<T>(this);
|
||||
}
|
||||
|
||||
public abstract bool Handle(Event e);
|
||||
}
|
||||
}
|
||||
|
227
Blarg.GameFramework/Events/EventManager.cs
Normal file
227
Blarg.GameFramework/Events/EventManager.cs
Normal file
|
@ -0,0 +1,227 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Blarg.GameFramework.Support;
|
||||
|
||||
namespace Blarg.GameFramework.Events
|
||||
{
|
||||
using EventListenerList = IList<IEventListener>;
|
||||
using EventTypeSet = ISet<Type>;
|
||||
using EventListenerTable = IList<IEventListener>;
|
||||
using EventListenerMap = IDictionary<Type, IList<IEventListener>>;
|
||||
using EventQueue = LinkedList<Event>;
|
||||
|
||||
public class EventManager
|
||||
{
|
||||
const int NumEventQueues = 2;
|
||||
|
||||
EventTypeSet _typeList;
|
||||
EventListenerMap _registry;
|
||||
EventQueue[] _queues;
|
||||
int _activeQueue;
|
||||
|
||||
public EventManager()
|
||||
{
|
||||
_typeList = new HashSet<Type>();
|
||||
_registry = new Dictionary<Type, EventListenerList>();
|
||||
_queues = new EventQueue[NumEventQueues];
|
||||
for (int i = 0; i < _queues.Length; ++i)
|
||||
_queues[i] = new LinkedList<Event>();
|
||||
|
||||
_activeQueue = 0;
|
||||
}
|
||||
|
||||
public bool AddListener<T>(IEventListener listener) where T : Event
|
||||
{
|
||||
if (listener == null)
|
||||
throw new ArgumentNullException("listener");
|
||||
|
||||
var type = typeof(T);
|
||||
EventListenerTable listenerTable = null;
|
||||
|
||||
_registry.TryGetValue(type, out listenerTable);
|
||||
if (listenerTable == null)
|
||||
{
|
||||
// need to register this listener for the given type
|
||||
listenerTable = new List<IEventListener>();
|
||||
_registry.Add(type, listenerTable);
|
||||
}
|
||||
|
||||
// prevent duplicate listeners from being registered
|
||||
if (listenerTable.Contains(listener))
|
||||
throw new InvalidOperationException("Duplicate event listener registration.");
|
||||
|
||||
listenerTable.Add(listener);
|
||||
Platform.Logger.Debug("EventManager", "Added {0} as a listener for event type {1}", listener.GetType().Name, type.Name);
|
||||
|
||||
// also update the list of currently registered event types
|
||||
_typeList.Add(type);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool RemoveListener<T>(IEventListener listener) where T : Event
|
||||
{
|
||||
if (listener == null)
|
||||
throw new ArgumentNullException("listener");
|
||||
|
||||
var type = typeof(T);
|
||||
|
||||
// get the list of listeners for the given event type
|
||||
EventListenerTable listenersForType;
|
||||
_registry.TryGetValue(type, out listenersForType);
|
||||
if (listenersForType == null)
|
||||
return false; // either no listeners for this type, or the listener wasn't registered with us
|
||||
|
||||
if (listenersForType.Contains(listener))
|
||||
{
|
||||
listenersForType.Remove(listener);
|
||||
Platform.Logger.Debug("EventManager", "Removed {0} as a listener for event type {1}", listener.GetType().Name, type.Name);
|
||||
|
||||
// if there are no more listeners for this type, remove the type
|
||||
// from the list of registered event types
|
||||
if (listenersForType.Count == 0)
|
||||
_typeList.Remove(type);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Trigger(Event e)
|
||||
{
|
||||
if (e == null)
|
||||
throw new ArgumentNullException("e");
|
||||
|
||||
var type = e.GetType();
|
||||
|
||||
// find the listeners for the event type provided
|
||||
EventListenerTable listenersForType;
|
||||
_registry.TryGetValue(type, out listenersForType);
|
||||
if (listenersForType == null)
|
||||
return false; // no listeners for this event type have been registered -- we can't handle the event
|
||||
|
||||
bool result = false;
|
||||
|
||||
// trigger the event in each listener
|
||||
foreach (var listener in listenersForType)
|
||||
{
|
||||
if (listener.Handle(e))
|
||||
{
|
||||
// don't let other listeners handle the event if this one signals it handled it
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: maybe, for Trigger() only, it's better to force the calling code
|
||||
// to "putback" the event object being triggered? since we handle the
|
||||
// event immediately, unlike with Queue() where it makes a lot more
|
||||
// sense for us to place it back in the pool ourselves ...
|
||||
Free(e);
|
||||
|
||||
// a result of "false" merely indicates that no listener indicates
|
||||
// it "handled" the event
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool Queue(Event e)
|
||||
{
|
||||
if (e == null)
|
||||
throw new ArgumentNullException("e");
|
||||
|
||||
// validate that there is infact a listener for this event type
|
||||
// (otherwise, we don't queue this event)
|
||||
var type = e.GetType();
|
||||
if (!_typeList.Contains(type))
|
||||
return false;
|
||||
|
||||
_queues[_activeQueue].AddLast(e);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Abort<T>(bool stopAfterFirstRemoval = true) where T : Event
|
||||
{
|
||||
// validate that there is infact a listener for this event type
|
||||
// (otherwise, we don't queue this event)
|
||||
var type = typeof(T);
|
||||
if (!_typeList.Contains(type))
|
||||
return false;
|
||||
|
||||
bool result = false;
|
||||
|
||||
// walk through the queue and remove matching events
|
||||
// NOTE: foreach not used because we need to remove items while inside the loop
|
||||
var queue = _queues[_activeQueue];
|
||||
var node = queue.First;
|
||||
while (node != null)
|
||||
{
|
||||
// grab the next node first (so we have it before potentially removing
|
||||
// this node and then losing the link to the next one)
|
||||
var nextNode = node.Next;
|
||||
|
||||
if (node.Value.GetType() == type)
|
||||
{
|
||||
// found a match, remove it
|
||||
var e = node.Value;
|
||||
queue.Remove(node);
|
||||
Free(e);
|
||||
result = true;
|
||||
|
||||
if (stopAfterFirstRemoval)
|
||||
break;
|
||||
}
|
||||
|
||||
node = nextNode;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool ProcessQueue()
|
||||
{
|
||||
// swap active queues and empty the new queue
|
||||
int queueToProcess = _activeQueue;
|
||||
_activeQueue = (_activeQueue + 1) % NumEventQueues;
|
||||
_queues[_activeQueue].Clear();
|
||||
|
||||
// process the queue
|
||||
var queue = _queues[queueToProcess];
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
// pop the next event off the queue
|
||||
var e = queue.First.Value;
|
||||
queue.RemoveFirst();
|
||||
|
||||
var type = e.GetType();
|
||||
|
||||
EventListenerTable listenersForType;
|
||||
_registry.TryGetValue(type, out listenersForType);
|
||||
if (listenersForType != null)
|
||||
{
|
||||
foreach (var listener in listenersForType)
|
||||
{
|
||||
if (listener.Handle(e))
|
||||
break; // don't let other listeners handle the event if this one signals it handled it
|
||||
}
|
||||
}
|
||||
|
||||
Free(e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public T Create<T>() where T : Event
|
||||
{
|
||||
return ObjectPools.Take<T>();
|
||||
}
|
||||
|
||||
public void Free<T>(T e) where T : Event
|
||||
{
|
||||
ObjectPools.Free<T>(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
10
Blarg.GameFramework/Events/IEventListener.cs
Normal file
10
Blarg.GameFramework/Events/IEventListener.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
|
||||
namespace Blarg.GameFramework.Events
|
||||
{
|
||||
public interface IEventListener
|
||||
{
|
||||
bool Handle(Event e);
|
||||
}
|
||||
}
|
||||
|
Reference in a new issue