/* * Copyright (C) 2012-2017 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 . */ 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 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 m_events = new SortedMultiMap(); } 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 } }