using System; using System.Collections.Generic; using System.Linq; namespace Framework.Dynamic { public class EventMap { /// /// Removes all scheduled events and resets time and phase. /// public void Reset() { _eventMap.Clear(); _time = 0; _phase = 0; } /// /// Updates the timer of the event map. /// /// Value in ms to be added to time. public void Update(uint time) { _time += time; } /// /// /// /// Current timer in ms value. uint GetTimer() { return _time; } /// /// /// /// Active phases as mask. byte GetPhaseMask() { return _phase; } /// /// /// /// True, if there are no events scheduled. public bool Empty() { return _eventMap.Empty(); } /// /// Sets the phase of the map (absolute). /// /// Phase which should be set. Values: 1 - 8. 0 resets phase. public void SetPhase(byte phase) { if (phase == 0) _phase = 0; else if (phase <= 8) _phase = (byte)(1 << (phase - 1)); } /// /// Activates the given phase (bitwise). /// /// Phase which should be activated. Values: 1 - 8 void AddPhase(byte phase) { if (phase != 0 && phase <= 8) _phase |= (byte)(1 << (phase - 1)); } /// /// Deactivates the given phase (bitwise). /// /// Phase which should be deactivated. Values: 1 - 8. void RemovePhase(byte phase) { if (phase != 0 && phase <= 8) _phase &= (byte)~(1 << (phase - 1)); } /// /// Creates new event entry in map. /// /// The id of the new event. /// The time in milliseconds as TimeSpan until the event occurs. /// The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group. /// The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases. public void ScheduleEvent(uint eventId, TimeSpan time, uint group = 0, byte phase = 0) { ScheduleEvent(eventId, (uint)time.TotalMilliseconds, group, phase); } /// /// Creates new event entry in map. /// /// The id of the new event. /// The minimum time until the event occurs as TimeSpan type. /// The maximum time until the event occurs as TimeSpan type. /// The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group. /// The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases. public void ScheduleEvent(uint eventId, TimeSpan minTime, TimeSpan maxTime, uint group = 0, byte phase = 0) { ScheduleEvent(eventId, RandomHelper.URand(minTime.TotalMilliseconds, maxTime.TotalMilliseconds), group, phase); } /// /// Creates new event entry in map. /// /// The id of the new event. /// The time in milliseconds until the event occurs. /// The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group. /// The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases. public void ScheduleEvent(uint eventId, uint time, uint group = 0, byte phase = 0) { if (group != 0 && group <= 8) eventId |= (uint)(1 << ((int)group + 15)); if (phase != 0 && phase <= 8) eventId |= (uint)(1 << (phase + 23)); _eventMap.Add(_time + time, eventId); } /// /// Cancels the given event and reschedules it. /// /// The id of the event. /// The time in milliseconds as TimeSpan until the event occurs. /// The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group. /// The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases. public void RescheduleEvent(uint eventId, TimeSpan time, uint group = 0, byte phase = 0) { RescheduleEvent(eventId, (uint)time.TotalMilliseconds, group, phase); } /// /// Cancels the given event and reschedules it. /// /// The id of the event. /// The minimum time until the event occurs as TimeSpan type. /// The maximum time until the event occurs as TimeSpan type. /// The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group. /// The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases. void RescheduleEvent(uint eventId, TimeSpan minTime, TimeSpan maxTime, uint group = 0, byte phase = 0) { RescheduleEvent(eventId, RandomHelper.URand(minTime.TotalMilliseconds, maxTime.TotalMilliseconds), group, phase); } /// /// Cancels the given event and reschedules it. /// /// The id of the event. /// The time in milliseconds until the event occurs. /// The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group. /// The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases. public void RescheduleEvent(uint eventId, uint time, uint group = 0, byte phase = 0) { CancelEvent(eventId); ScheduleEvent(eventId, time, group, phase); } /// /// Repeats the mostly recently executed event. /// /// Time until in ms as TimeSpan the event occurs public void Repeat(TimeSpan time) { Repeat((uint)time.TotalMilliseconds); } /// /// Repeats the mostly recently executed event. /// /// Time until the event occurs public void Repeat(uint time) { _eventMap.Add(_time + time, _lastEvent); } /// /// Repeats the mostly recently executed event. Equivalent to Repeat(urand(minTime, maxTime) /// /// Min Time as TimeSpan until the event occurs. /// Max Time as TimeSpan until the event occurs. public void Repeat(TimeSpan minTime, TimeSpan maxTime) { Repeat((uint)minTime.TotalMilliseconds, (uint)maxTime.TotalMilliseconds); } /// /// Repeats the mostly recently executed event. Equivalent to Repeat(urand(minTime, maxTime) /// /// Min Time until the event occurs. /// Max Time until the event occurs. public void Repeat(uint minTime, uint maxTime) { Repeat(RandomHelper.URand(minTime, maxTime)); } /// /// Returns the next event to execute and removes it from map. /// /// Id of the event to execute. /// public uint ExecuteEvent() { while (!Empty()) { var pair = _eventMap.FirstOrDefault(); if (pair.Key > _time) return 0; else if (_phase != 0 && Convert.ToBoolean(pair.Value & 0xFF000000) && !Convert.ToBoolean((pair.Value >> 24) & _phase)) _eventMap.Remove(pair); else { uint eventId = (pair.Value & 0x0000FFFF); _lastEvent = pair.Value; // include phase/group _eventMap.Remove(pair); return eventId; } } return 0; } public void ExecuteEvents(Action action) { uint id; while ((id = ExecuteEvent()) != 0) action(id); } /// /// Delays all events in the map. If delay is greater than or equal internal timer, delay will be 0. /// /// Amount of delay in ms as TimeSpan. public void DelayEvents(TimeSpan delay) { DelayEvents((uint)delay.TotalMilliseconds); } /// /// Delays all events in the map. If delay is greater than or equal internal timer, delay will be 0. /// /// Amount of delay. public void DelayEvents(uint delay) { _time = delay < _time ? _time - delay : 0; } /// /// Delay all events of the same group. /// /// Amount of delay. /// Group of the events. public void DelayEvents(uint delay, uint group) { if (group == 0 || group > 8 || Empty()) return; MultiMap delayed = new MultiMap(); foreach (var pair in _eventMap.KeyValueList) { if (Convert.ToBoolean(pair.Value & (1 << (int)(group + 15)))) { delayed.Add(pair.Key + delay, pair.Value); _eventMap.Remove(pair.Key, pair.Value); } } foreach (var del in delayed) _eventMap.Add(del); } /// /// Cancels all events of the specified id. /// /// Event id to cancel. public void CancelEvent(uint eventId) { if (Empty()) return; foreach (var pair in _eventMap.KeyValueList) { if (eventId == (pair.Value & 0x0000FFFF)) _eventMap.Remove(pair.Key, pair.Value); } } /// /// Cancel events belonging to specified group. /// /// Group to cancel. void CancelEventGroup(uint group) { if (group == 0 || group > 8 || Empty()) return; foreach (var pair in _eventMap.KeyValueList) { if (Convert.ToBoolean(pair.Value & (uint)(1 << ((int)group + 15)))) _eventMap.Remove(pair.Key, pair.Value); } } /// /// Returns closest occurence of specified event. /// /// Wanted event id. /// Time of found event. uint GetNextEventTime(uint eventId) { if (Empty()) return 0; foreach (var pair in _eventMap.KeyValueList) if (eventId == (pair.Value & 0x0000FFFF)) return pair.Key; return 0; } /// /// /// /// Time of next event. uint GetNextEventTime() { return Empty() ? 0 : _eventMap[0][0]; } /// /// Returns time in milliseconds until next event. /// /// Id of the event. /// Time of next event. public uint GetTimeUntilEvent(uint eventId) { foreach (var pair in _eventMap) if (eventId == (pair.Value & 0x0000FFFF)) return pair.Key - _time; return uint.MaxValue; } /// /// Returns wether event map is in specified phase or not. /// /// Wanted phase. /// True, if phase of event map contains specified phase. public bool IsInPhase(byte phase) { return phase <= 8 && (phase == 0 || Convert.ToBoolean(_phase & (1 << (phase - 1)))); } /// /// Internal timer. /// This does not represent the real date/time value. /// It's more like a stopwatch: It can run, it can be stopped, /// it can be resetted and so on. Events occur when this timer /// has reached their time value. Its value is changed in the Update method. /// uint _time; /// /// Phase mask of the event map. /// Contains the phases the event map is in. Multiple /// phases from 1 to 8 can be set with SetPhase or /// AddPhase. RemovePhase deactives a phase. /// byte _phase; /// /// Stores information on the most recently executed event /// uint _lastEvent; /// /// Key: Time as uint when the event should occur. /// Value: The event data as uint. /// /// Structure of event data: /// - Bit 0 - 15: Event Id. /// - Bit 16 - 23: Group /// - Bit 24 - 31: Phase /// - Pattern: 0xPPGGEEEE /// SortedMultiMap _eventMap = new SortedMultiMap(); } }