Files
CypherCore/Source/Framework/Dynamic/EventSystem.cs
T
2018-01-02 13:02:21 -05:00

150 lines
4.7 KiB
C#

/*
* Copyright (C) 2012-2018 CypherCore <http://github.com/CypherCore>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
namespace Framework.Dynamic
{
public class EventSystem
{
public EventSystem()
{
m_time = 0;
}
public void Update(uint p_time)
{
// update time
m_time += p_time;
// main event loop
KeyValuePair<ulong, BasicEvent> i;
while ((i = m_events.FirstOrDefault()).Value != null && i.Key <= m_time)
{
var Event = i.Value;
m_events.Remove(i);
if (Event.IsRunning())
{
Event.Execute(m_time, p_time);
continue;
}
if (Event.IsAbortScheduled())
{
Event.Abort(m_time);
// Mark the event as aborted
Event.SetAborted();
}
if (Event.IsDeletable())
continue;
// Reschedule non deletable events to be checked at
// the next update tick
AddEvent(Event, CalculateTime(1), false);
}
}
public void KillAllEvents(bool force)
{
foreach (var pair in m_events.KeyValueList)
{
// Abort events which weren't aborted already
if (!pair.Value.IsAborted())
{
pair.Value.SetAborted();
pair.Value.Abort(m_time);
}
// Skip non-deletable events when we are
// not forcing the event cancellation.
if (!force && !pair.Value.IsDeletable())
continue;
if (!force)
m_events.Remove(pair);
}
// fast clear event list (in force case)
if (force)
m_events.Clear();
}
public void AddEvent(BasicEvent Event, ulong e_time, bool set_addtime = true)
{
if (set_addtime)
Event.m_addTime = m_time;
Event.m_execTime = e_time;
m_events.Add(e_time, Event);
}
public ulong CalculateTime(ulong t_offset)
{
return (m_time + t_offset);
}
ulong m_time;
SortedMultiMap<ulong, BasicEvent> m_events = new SortedMultiMap<ulong, BasicEvent>();
}
public class BasicEvent
{
public BasicEvent() { m_abortState = AbortState.Running; }
public void ScheduleAbort()
{
Contract.Assert(IsRunning(), "Tried to scheduled the abortion of an event twice!");
m_abortState = AbortState.Scheduled;
}
public void SetAborted()
{
Contract.Assert(!IsAborted(), "Tried to abort an already aborted event!");
m_abortState = AbortState.Aborted;
}
// this method executes when the event is triggered
// return false if event does not want to be deleted
// e_time is execution time, p_time is update interval
public virtual bool Execute(ulong e_time, uint p_time) { return true; }
public virtual bool IsDeletable() { return true; } // this event can be safely deleted
public virtual void Abort(ulong e_time) { } // this method executes when the event is aborted
public bool IsRunning() { return m_abortState == AbortState.Running; }
public bool IsAbortScheduled() { return m_abortState == AbortState.Scheduled; }
public bool IsAborted() { return m_abortState == AbortState.Aborted; }
AbortState m_abortState; // set by externals when the event is aborted, aborted events don't execute
public ulong m_addTime; // time when the event was added to queue, filled by event handler
public ulong m_execTime; // planned time of next execution, filled by event handler
}
enum AbortState
{
Running,
Scheduled,
Aborted
}
}