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\IPoolable.cs" />
|
||||||
<Compile Include="Support\BasicObjectPool.cs" />
|
<Compile Include="Support\BasicObjectPool.cs" />
|
||||||
<Compile Include="Support\ObjectPools.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>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -155,6 +159,7 @@
|
||||||
<Folder Include="Support\" />
|
<Folder Include="Support\" />
|
||||||
<Folder Include="Graphics\CustomShaders\" />
|
<Folder Include="Graphics\CustomShaders\" />
|
||||||
<Folder Include="Graphics\Helpers\" />
|
<Folder Include="Graphics\Helpers\" />
|
||||||
|
<Folder Include="Events\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="Resources\Fonts\Vera.ttf" />
|
<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