Files
CypherCore/Source/Framework/Dynamic/EventMap.cs
T
Fabian a3dc7b3f48 Ported .Net Core commits:
hondacrx:
- Initial commit: Switch to .Net Core 2.0
- Fix build and removed not needed files
Fabi:
- Updated solution platforms.
- Changed folder structure.
- Change library target framework to netstandard2.0.
- Updated solution platforms again...
- Removed windows specific kernel32 function usage (Ctrl-C handler).
2017-10-26 17:23:44 +02:00

400 lines
15 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
namespace Framework.Dynamic
{
public class EventMap
{
/// <summary>
/// Removes all scheduled events and resets time and phase.
/// </summary>
public void Reset()
{
_eventMap.Clear();
_time = 0;
_phase = 0;
}
/// <summary>
/// Updates the timer of the event map.
/// </summary>
/// <param name="time">Value in ms to be added to time.</param>
public void Update(uint time)
{
_time += time;
}
/// <summary>
///
/// </summary>
/// <returns>Current timer in ms value.</returns>
uint GetTimer()
{
return _time;
}
/// <summary>
///
/// </summary>
/// <returns>Active phases as mask.</returns>
byte GetPhaseMask()
{
return _phase;
}
/// <summary>
///
/// </summary>
/// <returns>True, if there are no events scheduled.</returns>
public bool Empty()
{
return _eventMap.Empty();
}
/// <summary>
/// Sets the phase of the map (absolute).
/// </summary>
/// <param name="phase">Phase which should be set. Values: 1 - 8. 0 resets phase.</param>
public void SetPhase(byte phase)
{
if (phase == 0)
_phase = 0;
else if (phase <= 8)
_phase = (byte)(1 << (phase - 1));
}
/// <summary>
/// Activates the given phase (bitwise).
/// </summary>
/// <param name="phase">Phase which should be activated. Values: 1 - 8</param>
void AddPhase(byte phase)
{
if (phase != 0 && phase <= 8)
_phase |= (byte)(1 << (phase - 1));
}
/// <summary>
/// Deactivates the given phase (bitwise).
/// </summary>
/// <param name="phase">Phase which should be deactivated. Values: 1 - 8.</param>
void RemovePhase(byte phase)
{
if (phase != 0 && phase <= 8)
_phase &= (byte)~(1 << (phase - 1));
}
/// <summary>
/// Creates new event entry in map.
/// </summary>
/// <param name="eventId">The id of the new event.</param>
/// <param name="time">The time in milliseconds as TimeSpan until the event occurs.</param>
/// <param name="group">The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.</param>
/// <param name="phase">The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.</param>
public void ScheduleEvent(uint eventId, TimeSpan time, uint group = 0, byte phase = 0)
{
ScheduleEvent(eventId, (uint)time.TotalMilliseconds, group, phase);
}
/// <summary>
/// Creates new event entry in map.
/// </summary>
/// <param name="eventId">The id of the new event.</param>
/// <param name="minTime">The minimum time until the event occurs as TimeSpan type.</param>
/// <param name="maxTime">The maximum time until the event occurs as TimeSpan type.</param>
/// <param name="group">The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.</param>
/// <param name="phase">The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.</param>
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);
}
/// <summary>
/// Creates new event entry in map.
/// </summary>
/// <param name="eventId">The id of the new event.</param>
/// <param name="time">The time in milliseconds until the event occurs.</param>
/// <param name="group">The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.</param>
/// <param name="phase">The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.</param>
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);
}
/// <summary>
/// Cancels the given event and reschedules it.
/// </summary>
/// <param name="eventId">The id of the event.</param>
/// <param name="time">The time in milliseconds as TimeSpan until the event occurs.</param>
/// <param name="group">The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.</param>
/// <param name="phase">The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.</param>
public void RescheduleEvent(uint eventId, TimeSpan time, uint group = 0, byte phase = 0)
{
RescheduleEvent(eventId, (uint)time.TotalMilliseconds, group, phase);
}
/// <summary>
/// Cancels the given event and reschedules it.
/// </summary>
/// <param name="eventId">The id of the event.</param>
/// <param name="minTime">The minimum time until the event occurs as TimeSpan type.</param>
/// <param name="maxTime">The maximum time until the event occurs as TimeSpan type.</param>
/// <param name="group">The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.</param>
/// <param name="phase">The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.</param>
void RescheduleEvent(uint eventId, TimeSpan minTime, TimeSpan maxTime, uint group = 0, byte phase = 0)
{
RescheduleEvent(eventId, RandomHelper.URand(minTime.TotalMilliseconds, maxTime.TotalMilliseconds), group, phase);
}
/// <summary>
/// Cancels the given event and reschedules it.
/// </summary>
/// <param name="eventId">The id of the event.</param>
/// <param name="time">The time in milliseconds until the event occurs.</param>
/// <param name="group">The group which the event is associated to. Has to be between 1 and 8. 0 means it has no group.</param>
/// <param name="phase">The phase in which the event can occur. Has to be between 1 and 8. 0 means it can occur in all phases.</param>
public void RescheduleEvent(uint eventId, uint time, uint group = 0, byte phase = 0)
{
CancelEvent(eventId);
ScheduleEvent(eventId, time, group, phase);
}
/// <summary>
/// Repeats the mostly recently executed event.
/// </summary>
/// <param name="time">Time until in ms as TimeSpan the event occurs</param>
public void Repeat(TimeSpan time)
{
Repeat((uint)time.TotalMilliseconds);
}
/// <summary>
/// Repeats the mostly recently executed event.
/// </summary>
/// <param name="time">Time until the event occurs</param>
public void Repeat(uint time)
{
_eventMap.Add(_time + time, _lastEvent);
}
/// <summary>
/// Repeats the mostly recently executed event. Equivalent to Repeat(urand(minTime, maxTime)
/// </summary>
/// <param name="minTime">Min Time as TimeSpan until the event occurs.</param>
/// <param name="maxTime">Max Time as TimeSpan until the event occurs.</param>
public void Repeat(TimeSpan minTime, TimeSpan maxTime)
{
Repeat((uint)minTime.TotalMilliseconds, (uint)maxTime.TotalMilliseconds);
}
/// <summary>
/// Repeats the mostly recently executed event. Equivalent to Repeat(urand(minTime, maxTime)
/// </summary>
/// <param name="minTime">Min Time until the event occurs.</param>
/// <param name="maxTime">Max Time until the event occurs.</param>
public void Repeat(uint minTime, uint maxTime)
{
Repeat(RandomHelper.URand(minTime, maxTime));
}
/// <summary>
/// Returns the next event to execute and removes it from map.
/// </summary>
/// <returns>Id of the event to execute.</returns>
///
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<uint> action)
{
uint id;
while ((id = ExecuteEvent()) != 0)
action(id);
}
/// <summary>
/// Delays all events in the map. If delay is greater than or equal internal timer, delay will be 0.
/// </summary>
/// <param name="delay">Amount of delay in ms as TimeSpan.</param>
public void DelayEvents(TimeSpan delay)
{
DelayEvents((uint)delay.TotalMilliseconds);
}
/// <summary>
/// Delays all events in the map. If delay is greater than or equal internal timer, delay will be 0.
/// </summary>
/// <param name="delay">Amount of delay.</param>
public void DelayEvents(uint delay)
{
_time = delay < _time ? _time - delay : 0;
}
/// <summary>
/// Delay all events of the same group.
/// </summary>
/// <param name="delay">Amount of delay.</param>
/// <param name="group">Group of the events.</param>
public void DelayEvents(uint delay, uint group)
{
if (group == 0 || group > 8 || Empty())
return;
MultiMap<uint, uint> delayed = new MultiMap<uint, uint>();
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);
}
/// <summary>
/// Cancels all events of the specified id.
/// </summary>
/// <param name="eventId">Event id to cancel.</param>
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);
}
}
/// <summary>
/// Cancel events belonging to specified group.
/// </summary>
/// <param name="group">Group to cancel.</param>
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);
}
}
/// <summary>
/// Returns closest occurence of specified event.
/// </summary>
/// <param name="eventId">Wanted event id.</param>
/// <returns>Time of found event.</returns>
uint GetNextEventTime(uint eventId)
{
if (Empty())
return 0;
foreach (var pair in _eventMap.KeyValueList)
if (eventId == (pair.Value & 0x0000FFFF))
return pair.Key;
return 0;
}
/// <summary>
///
/// </summary>
/// <returns>Time of next event.</returns>
uint GetNextEventTime()
{
return Empty() ? 0 : _eventMap[0][0];
}
/// <summary>
/// Returns time in milliseconds until next event.
/// </summary>
/// <param name="eventId">Id of the event.</param>
/// <returns>Time of next event.</returns>
public uint GetTimeUntilEvent(uint eventId)
{
foreach (var pair in _eventMap)
if (eventId == (pair.Value & 0x0000FFFF))
return pair.Key - _time;
return uint.MaxValue;
}
/// <summary>
/// Returns wether event map is in specified phase or not.
/// </summary>
/// <param name="phase">Wanted phase.</param>
/// <returns>True, if phase of event map contains specified phase.</returns>
public bool IsInPhase(byte phase)
{
return phase <= 8 && (phase == 0 || Convert.ToBoolean(_phase & (1 << (phase - 1))));
}
/// <summary>
/// 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.
/// </summary>
uint _time;
/// <summary>
/// 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.
/// </summary>
byte _phase;
/// <summary>
/// Stores information on the most recently executed event
/// </summary>
uint _lastEvent;
/// <summary>
/// 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
/// </summary>
SortedMultiMap<uint, uint> _eventMap = new SortedMultiMap<uint, uint>();
}
}