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).
This commit is contained in:
@@ -0,0 +1,399 @@
|
||||
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>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 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;
|
||||
|
||||
namespace Framework.Dynamic
|
||||
{
|
||||
public class FlagArray128
|
||||
{
|
||||
public FlagArray128(params uint[] parts)
|
||||
{
|
||||
_values = new uint[4];
|
||||
for (var i = 0; i < parts.Length; ++i)
|
||||
_values[i] = parts[i];
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return base.GetHashCode();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
public bool IsEqual(params uint[] parts)
|
||||
{
|
||||
for (var i = 0; i < _values.Length; ++i)
|
||||
if (_values[i] == parts[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Set(params uint[] parts)
|
||||
{
|
||||
for (var i = 0; i < parts.Length; ++i)
|
||||
_values[i] = parts[i];
|
||||
}
|
||||
|
||||
public static bool operator <(FlagArray128 left, FlagArray128 right)
|
||||
{
|
||||
for (var i = left._values.Length; i > 0; --i)
|
||||
{
|
||||
if (left._values[i - 1] < right._values[i - 1])
|
||||
return true;
|
||||
else if (left._values[i - 1] > right._values[i - 1])
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public static bool operator >(FlagArray128 left, FlagArray128 right)
|
||||
{
|
||||
for (var i = left._values.Length; i > 0; --i)
|
||||
{
|
||||
if (left._values[i - 1] > right._values[i - 1])
|
||||
return true;
|
||||
else if (left._values[i - 1] < right._values[i - 1])
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static FlagArray128 operator &(FlagArray128 left, FlagArray128 right)
|
||||
{
|
||||
FlagArray128 fl = new FlagArray128();
|
||||
for (var i = 0; i < left._values.Length; ++i)
|
||||
fl[i] = left._values[i] & right._values[i];
|
||||
return fl;
|
||||
}
|
||||
public static FlagArray128 operator |(FlagArray128 left, FlagArray128 right)
|
||||
{
|
||||
FlagArray128 fl = new FlagArray128();
|
||||
for (var i = 0; i < left._values.Length; ++i)
|
||||
fl[i] = left._values[i] | right._values[i];
|
||||
return fl;
|
||||
}
|
||||
public static FlagArray128 operator ^(FlagArray128 left, FlagArray128 right)
|
||||
{
|
||||
FlagArray128 fl = new FlagArray128();
|
||||
for (var i = 0; i < left._values.Length; ++i)
|
||||
fl[i] = left._values[i] ^ right._values[i];
|
||||
return fl;
|
||||
}
|
||||
|
||||
public static implicit operator bool (FlagArray128 left)
|
||||
{
|
||||
for (var i = 0; i < left._values.Length; ++i)
|
||||
if (left._values[i] != 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public uint this[int i]
|
||||
{
|
||||
get
|
||||
{
|
||||
return _values[i];
|
||||
}
|
||||
set
|
||||
{
|
||||
_values[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
uint[] _values { get; set; }
|
||||
}
|
||||
|
||||
public class FlaggedArray<T> where T : struct
|
||||
{
|
||||
int[] m_values;
|
||||
uint m_flags;
|
||||
|
||||
public FlaggedArray(byte arraysize)
|
||||
{
|
||||
m_values = new int[4 * arraysize];
|
||||
}
|
||||
|
||||
public uint GetFlags() { return m_flags; }
|
||||
public bool HasFlag(T flag) { return Convert.ToBoolean(Convert.ToInt32(m_flags) & 1 << Convert.ToInt32(flag)); }
|
||||
public void AddFlag(T flag) { m_flags |= (uint)(1 << Convert.ToInt32(flag)); }
|
||||
public void DelFlag(T flag) { m_flags &= ~(uint)(1 << Convert.ToInt32(flag)); }
|
||||
|
||||
public int GetValue(T flag) { return m_values[Convert.ToInt32(flag)]; }
|
||||
public void SetValue(T flag, object value) { m_values[Convert.ToInt32(flag)] = Convert.ToInt32(value); }
|
||||
public void AddValue(T flag, object value) { m_values[Convert.ToInt32(flag)] += Convert.ToInt32(value); }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 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/>.
|
||||
*/
|
||||
|
||||
namespace Framework.Dynamic
|
||||
{
|
||||
public struct Optional<T> where T : new()
|
||||
{
|
||||
private bool _hasValue;
|
||||
public T Value;
|
||||
|
||||
public bool HasValue
|
||||
{
|
||||
get { return _hasValue; }
|
||||
set
|
||||
{
|
||||
_hasValue = value;
|
||||
Value = _hasValue ? new T() : default(T);
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(T v)
|
||||
{
|
||||
_hasValue = true;
|
||||
Value = v;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_hasValue = false;
|
||||
Value = default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 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 Framework.Collections;
|
||||
using System.Diagnostics.Contracts;
|
||||
|
||||
namespace Framework.Dynamic
|
||||
{
|
||||
public class Reference<TO, FROM> : LinkedListElement where TO : class where FROM : class
|
||||
{
|
||||
TO _RefTo;
|
||||
FROM _RefFrom;
|
||||
|
||||
// Tell our refTo (target) object that we have a link
|
||||
public virtual void targetObjectBuildLink() { }
|
||||
|
||||
// Tell our refTo (taget) object, that the link is cut
|
||||
public virtual void targetObjectDestroyLink() { }
|
||||
|
||||
// Tell our refFrom (source) object, that the link is cut (Target destroyed)
|
||||
public virtual void sourceObjectDestroyLink() { }
|
||||
|
||||
public Reference()
|
||||
{
|
||||
_RefTo = null; _RefFrom = null;
|
||||
}
|
||||
|
||||
// Create new link
|
||||
public void link(TO toObj, FROM fromObj)
|
||||
{
|
||||
Contract.Assert(fromObj != null); // fromObj MUST not be NULL
|
||||
if (isValid())
|
||||
unlink();
|
||||
if (toObj != null)
|
||||
{
|
||||
_RefTo = toObj;
|
||||
_RefFrom = fromObj;
|
||||
targetObjectBuildLink();
|
||||
}
|
||||
}
|
||||
|
||||
// We don't need the reference anymore. Call comes from the refFrom object
|
||||
// Tell our refTo object, that the link is cut
|
||||
public void unlink()
|
||||
{
|
||||
targetObjectDestroyLink();
|
||||
delink();
|
||||
_RefTo = null;
|
||||
_RefFrom = null;
|
||||
}
|
||||
|
||||
// Link is invalid due to destruction of referenced target object. Call comes from the refTo object
|
||||
// Tell our refFrom object, that the link is cut
|
||||
public void invalidate() // the iRefFrom MUST remain!!
|
||||
{
|
||||
sourceObjectDestroyLink();
|
||||
delink();
|
||||
_RefTo = null;
|
||||
}
|
||||
|
||||
public bool isValid() // Only check the iRefTo
|
||||
{
|
||||
return _RefTo != null;
|
||||
}
|
||||
|
||||
public Reference<TO, FROM> next() { return ((Reference<TO, FROM>)GetNextElement()); }
|
||||
public Reference<TO, FROM> prev() { return ((Reference<TO, FROM>)GetPrevElement()); }
|
||||
|
||||
public TO getTarget() { return _RefTo; }
|
||||
|
||||
public FROM GetSource() { return _RefFrom; }
|
||||
}
|
||||
|
||||
public class RefManager<TO, FROM> : LinkedListHead where TO : class where FROM : class
|
||||
{
|
||||
~RefManager() { clearReferences(); }
|
||||
|
||||
public Reference<TO, FROM> getFirst() { return (Reference<TO, FROM>)base.GetFirstElement(); }
|
||||
public Reference<TO, FROM> getLast() { return (Reference<TO, FROM>)base.GetLastElement(); }
|
||||
|
||||
public void clearReferences()
|
||||
{
|
||||
Reference<TO, FROM> refe;
|
||||
while ((refe = getFirst()) != null)
|
||||
refe.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,846 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2017 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Linq;
|
||||
|
||||
namespace Framework.Dynamic
|
||||
{
|
||||
public class TaskScheduler
|
||||
{
|
||||
public TaskScheduler()
|
||||
{
|
||||
_now = DateTime.Now;
|
||||
_task_holder = new TaskQueue();
|
||||
_asyncHolder = new List<Action>();
|
||||
_predicate = EmptyValidator;
|
||||
}
|
||||
|
||||
public TaskScheduler(predicate_t predicate)
|
||||
{
|
||||
_now = DateTime.Now;
|
||||
_task_holder = new TaskQueue();
|
||||
_asyncHolder = new List<Action>();
|
||||
_predicate = predicate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the validator which is asked if tasks are allowed to be executed.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
TaskScheduler ClearValidator()
|
||||
{
|
||||
_predicate = EmptyValidator;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a validator which is asked if tasks are allowed to be executed.
|
||||
/// </summary>
|
||||
/// <param name="predicate"></param>
|
||||
/// <returns></returns>
|
||||
public TaskScheduler SetValidator(predicate_t predicate)
|
||||
{
|
||||
_predicate = predicate;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the scheduler to the current time.
|
||||
/// Calls the optional callback on successfully finish.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public TaskScheduler Update(success_t callback = null)
|
||||
{
|
||||
_now = DateTime.Now;
|
||||
Dispatch(callback);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the scheduler with a difftime in ms.
|
||||
/// Calls the optional callback on successfully finish.
|
||||
/// </summary>
|
||||
/// <param name="milliseconds"></param>
|
||||
/// <returns></returns>
|
||||
public TaskScheduler Update(uint milliseconds, success_t callback = null)
|
||||
{
|
||||
return Update(TimeSpan.FromMilliseconds(milliseconds), callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the scheduler with a difftime.
|
||||
/// Calls the optional callback on successfully finish.
|
||||
/// </summary>
|
||||
/// <param name="difftime"></param>
|
||||
/// <returns></returns>
|
||||
TaskScheduler Update(TimeSpan difftime, success_t callback = null)
|
||||
{
|
||||
_now += difftime;
|
||||
Dispatch(callback);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TaskScheduler Async(Action callable)
|
||||
{
|
||||
_asyncHolder.Add(callable);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schedule an event with a fixed rate.
|
||||
/// Never call this from within a task context! Use TaskContext.Schedule instead!
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
/// <param name="task"></param>
|
||||
/// <returns></returns>
|
||||
public TaskScheduler Schedule(TimeSpan time, Action<TaskContext> task)
|
||||
{
|
||||
return ScheduleAt(_now, time, task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schedule an event with a fixed rate.
|
||||
/// Never call this from within a task context! Use TaskContext.Schedule instead!
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="task"></param>
|
||||
/// <returns></returns>
|
||||
public TaskScheduler Schedule(TimeSpan time, uint group, Action<TaskContext> task)
|
||||
{
|
||||
return ScheduleAt(_now, time, group, task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schedule an event with a randomized rate between min and max rate.
|
||||
/// Never call this from within a task context! Use TaskContext.Schedule instead!
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <param name="task"></param>
|
||||
/// <returns></returns>
|
||||
public TaskScheduler Schedule(TimeSpan min, TimeSpan max, Action<TaskContext> task)
|
||||
{
|
||||
return Schedule(RandomDurationBetween(min, max), task);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schedule an event with a fixed rate.
|
||||
/// Never call this from within a task context! Use TaskContext.Schedule instead!
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="task"></param>
|
||||
/// <returns></returns>
|
||||
public TaskScheduler Schedule(TimeSpan min, TimeSpan max, uint group, Action<TaskContext> task)
|
||||
{
|
||||
return Schedule(RandomDurationBetween(min, max), group, task);
|
||||
}
|
||||
|
||||
public TaskScheduler CancelAll()
|
||||
{
|
||||
/// Clear the task holder
|
||||
_task_holder.Clear();
|
||||
_asyncHolder.Clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
public TaskScheduler CancelGroup(uint group)
|
||||
{
|
||||
_task_holder.RemoveIf(task =>
|
||||
{
|
||||
return task.IsInGroup(group);
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public TaskScheduler CancelGroupsOf(List<uint> groups)
|
||||
{
|
||||
groups.ForEach(group => CancelGroup(group));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delays all tasks with the given duration.
|
||||
/// </summary>
|
||||
/// <param name="duration"></param>
|
||||
/// <returns></returns>
|
||||
public TaskScheduler DelayAll(TimeSpan duration)
|
||||
{
|
||||
_task_holder.ModifyIf(task =>
|
||||
{
|
||||
task._end += duration;
|
||||
return true;
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delays all tasks with a random duration between min and max.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <returns></returns>
|
||||
public TaskScheduler DelayAll(TimeSpan min, TimeSpan max)
|
||||
{
|
||||
return DelayAll(RandomDurationBetween(min, max));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delays all tasks of a group with the given duration.
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="duration"></param>
|
||||
/// <returns></returns>
|
||||
public TaskScheduler DelayGroup(uint group, TimeSpan duration)
|
||||
{
|
||||
_task_holder.ModifyIf(task =>
|
||||
{
|
||||
if (task.IsInGroup(group))
|
||||
{
|
||||
task._end += duration;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delays all tasks of a group with a random duration between min and max.
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <returns></returns>
|
||||
public TaskScheduler DelayGroup(uint group, TimeSpan min, TimeSpan max)
|
||||
{
|
||||
return DelayGroup(group, RandomDurationBetween(min, max));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reschedule all tasks with a given duration.
|
||||
/// </summary>
|
||||
/// <param name="duration"></param>
|
||||
/// <returns></returns>
|
||||
public TaskScheduler RescheduleAll(TimeSpan duration)
|
||||
{
|
||||
var end = _now + duration;
|
||||
_task_holder.ModifyIf(task =>
|
||||
{
|
||||
task._end = end;
|
||||
return true;
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reschedule all tasks with a random duration between min and max.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <returns></returns>
|
||||
public TaskScheduler RescheduleAll(TimeSpan min, TimeSpan max)
|
||||
{
|
||||
return RescheduleAll(RandomDurationBetween(min, max));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reschedule all tasks of a group with the given duration.
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="duration"></param>
|
||||
/// <returns></returns>
|
||||
public TaskScheduler RescheduleGroup(uint group, TimeSpan duration)
|
||||
{
|
||||
var end = _now + duration;
|
||||
_task_holder.ModifyIf(task =>
|
||||
{
|
||||
if (task.IsInGroup(group))
|
||||
{
|
||||
task._end = end;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reschedule all tasks of a group with a random duration between min and max.
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <returns></returns>
|
||||
public TaskScheduler RescheduleGroup(uint group, TimeSpan min, TimeSpan max)
|
||||
{
|
||||
return RescheduleGroup(group, RandomDurationBetween(min, max));
|
||||
}
|
||||
|
||||
internal TaskScheduler InsertTask(Task task)
|
||||
{
|
||||
_task_holder.Push(task);
|
||||
return this;
|
||||
}
|
||||
|
||||
internal TaskScheduler ScheduleAt(DateTime end, TimeSpan time, Action<TaskContext> task)
|
||||
{
|
||||
return InsertTask(new Task(end + time, time, task));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schedule an event with a fixed rate.
|
||||
/// Never call this from within a task context! Use TaskContext.schedule instead!
|
||||
/// </summary>
|
||||
/// <param name="end"></param>
|
||||
/// <param name="time"></param>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="task"></param>
|
||||
/// <returns></returns>
|
||||
internal TaskScheduler ScheduleAt(DateTime end, TimeSpan time, uint group, Action<TaskContext> task)
|
||||
{
|
||||
return InsertTask(new Task(end + time, time, group, 0, task));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a random duration between min and max
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <returns>TimeSpan</returns>
|
||||
public static TimeSpan RandomDurationBetween(TimeSpan min, TimeSpan max)
|
||||
{
|
||||
var milli_min = min.TotalMilliseconds;
|
||||
var milli_max = max.TotalMilliseconds;
|
||||
|
||||
// TC specific: use SFMT URandom
|
||||
return TimeSpan.FromMilliseconds(RandomHelper.URand(milli_min, milli_max));
|
||||
}
|
||||
|
||||
void Dispatch(success_t callback = null)
|
||||
{
|
||||
// If the validation failed abort the dispatching here.
|
||||
if (!_predicate())
|
||||
return;
|
||||
|
||||
// Process all asyncs
|
||||
while (!_asyncHolder.Empty())
|
||||
{
|
||||
_asyncHolder.First().Invoke();
|
||||
_asyncHolder.RemoveAt(0);
|
||||
|
||||
// If the validation failed abort the dispatching here.
|
||||
if (!_predicate())
|
||||
return;
|
||||
}
|
||||
|
||||
while (!_task_holder.IsEmpty())
|
||||
{
|
||||
if (_task_holder.First()._end > _now)
|
||||
break;
|
||||
|
||||
// Perfect forward the context to the handler
|
||||
// Use weak references to catch destruction before callbacks.
|
||||
TaskContext context = new TaskContext(_task_holder.Pop(), this);
|
||||
|
||||
// Invoke the context
|
||||
context.Invoke();
|
||||
|
||||
// If the validation failed abort the dispatching here.
|
||||
if (!_predicate())
|
||||
return;
|
||||
}
|
||||
|
||||
callback?.Invoke();
|
||||
}
|
||||
|
||||
// The current time point (now)
|
||||
DateTime _now;
|
||||
|
||||
// The Task Queue which contains all task objects.
|
||||
TaskQueue _task_holder;
|
||||
|
||||
// Contains all asynchronous tasks which will be invoked at
|
||||
// the next update tick.
|
||||
List<Action> _asyncHolder;
|
||||
|
||||
predicate_t _predicate;
|
||||
|
||||
static bool EmptyValidator()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Predicate type
|
||||
public delegate bool predicate_t();
|
||||
// Success handle type
|
||||
public delegate void success_t();
|
||||
}
|
||||
|
||||
public class Task : IComparable<Task>
|
||||
{
|
||||
public Task(DateTime end, TimeSpan duration, uint group, uint repeated, Action<TaskContext> task)
|
||||
{
|
||||
_end = end;
|
||||
_duration = duration;
|
||||
_group.Set(group);
|
||||
_repeated = repeated;
|
||||
_task = task;
|
||||
}
|
||||
|
||||
public Task(DateTime end, TimeSpan duration, Action<TaskContext> task)
|
||||
{
|
||||
_end = end;
|
||||
_duration = duration;
|
||||
_task = task;
|
||||
}
|
||||
|
||||
public int CompareTo(Task other)
|
||||
{
|
||||
return _end.CompareTo(other._end);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the task is in the given group
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsInGroup(uint group)
|
||||
{
|
||||
return _group.HasValue && _group.Value == group;
|
||||
}
|
||||
|
||||
internal DateTime _end;
|
||||
internal TimeSpan _duration;
|
||||
internal Optional<uint> _group;
|
||||
internal uint _repeated;
|
||||
internal Action<TaskContext> _task;
|
||||
}
|
||||
|
||||
class TaskQueue
|
||||
{
|
||||
/// <summary>
|
||||
/// Pushes the task in the container
|
||||
/// </summary>
|
||||
/// <param name="task"></param>
|
||||
public void Push(Task task)
|
||||
{
|
||||
if (!container.Add(task))
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pops the task out of the container
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Task Pop()
|
||||
{
|
||||
Task result = container.First();
|
||||
container.Remove(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public Task First()
|
||||
{
|
||||
return container.First();
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
container.Clear();
|
||||
}
|
||||
|
||||
public void RemoveIf(Predicate<Task> filter)
|
||||
{
|
||||
container.RemoveWhere(filter);
|
||||
}
|
||||
|
||||
public void ModifyIf(Func<Task, bool> filter)
|
||||
{
|
||||
List<Task> cache = new List<Task>();
|
||||
foreach (var task in container.Where(filter))
|
||||
{
|
||||
if (filter(task))
|
||||
{
|
||||
cache.Add(task);
|
||||
container.Remove(task);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var task in cache)
|
||||
container.Add(task);
|
||||
}
|
||||
|
||||
public bool IsEmpty()
|
||||
{
|
||||
return container.Empty();
|
||||
}
|
||||
|
||||
SortedSet<Task> container = new SortedSet<Task>();
|
||||
}
|
||||
|
||||
public class TaskContext
|
||||
{
|
||||
public TaskContext(Task task, TaskScheduler owner)
|
||||
{
|
||||
_task = task;
|
||||
_owner = owner;
|
||||
_consumed = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dispatches an action safe on the TaskScheduler
|
||||
/// </summary>
|
||||
/// <param name="apply"></param>
|
||||
/// <returns></returns>
|
||||
TaskContext Dispatch(Action apply)
|
||||
{
|
||||
apply();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
TaskContext Dispatch(Func<TaskScheduler, TaskScheduler> apply)
|
||||
{
|
||||
apply(_owner);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
bool IsExpired()
|
||||
{
|
||||
return _owner == null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the event is in the given group
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
/// <returns></returns>
|
||||
bool IsInGroup(uint group)
|
||||
{
|
||||
return _task.IsInGroup(group);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the event in the given group
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
/// <returns></returns>
|
||||
TaskContext SetGroup(uint group)
|
||||
{
|
||||
_task._group.Set(group);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the group from the event
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
TaskContext ClearGroup()
|
||||
{
|
||||
_task._group.HasValue = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the repeat counter which increases every time the task is repeated.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
uint GetRepeatCounter()
|
||||
{
|
||||
return _task._repeated;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schedule a callable function that is executed at the next update tick from within the context.
|
||||
/// Its safe to modify the TaskScheduler from within the callable.
|
||||
/// </summary>
|
||||
/// <param name="callable"></param>
|
||||
/// <returns></returns>
|
||||
TaskContext Async(Action callable)
|
||||
{
|
||||
return Dispatch(() => _owner.Async(callable));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancels all tasks from within the context.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public TaskContext CancelAll()
|
||||
{
|
||||
return Dispatch(() => _owner.CancelAll());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancel all tasks of a single group from within the context.
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext CancelGroup(uint group)
|
||||
{
|
||||
return Dispatch(() => CancelGroup(group));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancels all groups in the given std.vector from within the context.
|
||||
/// </summary>
|
||||
/// <param name="groups"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext CancelGroupsOf(List<uint> groups)
|
||||
{
|
||||
return Dispatch(() => CancelGroupsOf(groups));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asserts if the task was consumed already.
|
||||
/// </summary>
|
||||
void AssertOnConsumed()
|
||||
{
|
||||
// This was adapted to TC to prevent static analysis tools from complaining.
|
||||
// If you encounter this assertion check if you repeat a TaskContext more then 1 time!
|
||||
Contract.Assert(!_consumed, "Bad task logic, task context was consumed already!");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the associated hook of the task.
|
||||
/// </summary>
|
||||
public void Invoke()
|
||||
{
|
||||
_task._task(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Repeats the event and sets a new duration.
|
||||
/// This will consume the task context, its not possible to repeat the task again
|
||||
/// from the same task context!
|
||||
/// </summary>
|
||||
/// <param name="duration"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext Repeat(TimeSpan duration)
|
||||
{
|
||||
AssertOnConsumed();
|
||||
|
||||
// Set new duration, in-context timing and increment repeat counter
|
||||
_task._duration = duration;
|
||||
_task._end += duration;
|
||||
_task._repeated += 1;
|
||||
_consumed = true;
|
||||
return Dispatch(() => _owner.InsertTask(_task));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Repeats the event with the same duration.
|
||||
/// This will consume the task context, its not possible to repeat the task again
|
||||
/// from the same task context!
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public TaskContext Repeat()
|
||||
{
|
||||
return Repeat(_task._duration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Repeats the event and set a new duration that is randomized between min and max.
|
||||
/// This will consume the task context, its not possible to repeat the task again
|
||||
/// from the same task context!
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext Repeat(TimeSpan min, TimeSpan max)
|
||||
{
|
||||
return Repeat(TaskScheduler.RandomDurationBetween(min, max));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schedule an event with a fixed rate from within the context.
|
||||
/// Its possible that the new event is executed immediately!
|
||||
/// Use TaskScheduler.Async to create a task
|
||||
/// which will be called at the next update tick.
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
/// <param name="task"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext Schedule(TimeSpan time, Action<TaskContext> task)
|
||||
{
|
||||
var end = _task._end;
|
||||
return Dispatch(scheduler =>
|
||||
{
|
||||
return scheduler.ScheduleAt(end, time, task);
|
||||
});
|
||||
}
|
||||
public TaskContext Schedule(TimeSpan time, Action task) { return Schedule(time, delegate (TaskContext task1) { task(); }); }
|
||||
|
||||
/// <summary>
|
||||
/// Schedule an event with a fixed rate from within the context.
|
||||
/// Its possible that the new event is executed immediately!
|
||||
/// Use TaskScheduler.Async to create a task
|
||||
/// which will be called at the next update tick.
|
||||
/// </summary>
|
||||
/// <param name="time"></param>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="task"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext Schedule(TimeSpan time, uint group, Action<TaskContext> task)
|
||||
{
|
||||
var end = _task._end;
|
||||
return Dispatch(scheduler => { return scheduler.ScheduleAt(end, time, group, task); });
|
||||
}
|
||||
public TaskContext Schedule(TimeSpan time, uint group, Action task) { return Schedule(time, group, delegate (TaskContext task1) { task(); }); }
|
||||
|
||||
/// <summary>
|
||||
/// Schedule an event with a randomized rate between min and max rate from within the context.
|
||||
/// Its possible that the new event is executed immediately!
|
||||
/// Use TaskScheduler.Async to create a task
|
||||
/// which will be called at the next update tick.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <param name="task"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext Schedule(TimeSpan min, TimeSpan max, Action<TaskContext> task)
|
||||
{
|
||||
return Schedule(TaskScheduler.RandomDurationBetween(min, max), task);
|
||||
}
|
||||
public TaskContext Schedule(TimeSpan min, TimeSpan max, Action task) { return Schedule(min, max, delegate (TaskContext task1) { task(); }); }
|
||||
|
||||
/// <summary>
|
||||
/// Schedule an event with a randomized rate between min and max rate from within the context.
|
||||
/// Its possible that the new event is executed immediately!
|
||||
/// Use TaskScheduler.Async to create a task
|
||||
/// which will be called at the next update tick.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="task"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext Schedule(TimeSpan min, TimeSpan max, uint group, Action<TaskContext> task)
|
||||
{
|
||||
return Schedule(TaskScheduler.RandomDurationBetween(min, max), group, task);
|
||||
}
|
||||
public TaskContext Schedule(TimeSpan min, TimeSpan max, uint group, Action task) { return Schedule(min, max, group, delegate (TaskContext task1) { task(); }); }
|
||||
|
||||
/// <summary>
|
||||
/// Delays all tasks with the given duration from within the context.
|
||||
/// </summary>
|
||||
/// <param name="duration"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext DelayAll(TimeSpan duration)
|
||||
{
|
||||
return Dispatch(() => _owner.DelayAll(duration));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delays all tasks with a random duration between min and max from within the context.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext DelayAll(TimeSpan min, TimeSpan max)
|
||||
{
|
||||
return DelayAll(TaskScheduler.RandomDurationBetween(min, max));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delays all tasks of a group with the given duration from within the context.
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="duration"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext DelayGroup(uint group, TimeSpan duration)
|
||||
{
|
||||
return Dispatch(() => _owner.DelayGroup(group, duration));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delays all tasks of a group with a random duration between min and max from within the context.
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext DelayGroup(uint group, TimeSpan min, TimeSpan max)
|
||||
{
|
||||
return DelayGroup(group, TaskScheduler.RandomDurationBetween(min, max));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reschedule all tasks with the given duration.
|
||||
/// </summary>
|
||||
/// <param name="duration"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext RescheduleAll(TimeSpan duration)
|
||||
{
|
||||
return Dispatch(() => _owner.RescheduleAll(duration));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reschedule all tasks with a random duration between min and max.
|
||||
/// </summary>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext RescheduleAll(TimeSpan min, TimeSpan max)
|
||||
{
|
||||
return RescheduleAll(TaskScheduler.RandomDurationBetween(min, max));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reschedule all tasks of a group with the given duration.
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="duration"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext RescheduleGroup(uint group, TimeSpan duration)
|
||||
{
|
||||
return Dispatch(() => _owner.RescheduleGroup(group, duration));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reschedule all tasks of a group with a random duration between min and max.
|
||||
/// </summary>
|
||||
/// <param name="group"></param>
|
||||
/// <param name="min"></param>
|
||||
/// <param name="max"></param>
|
||||
/// <returns></returns>
|
||||
public TaskContext RescheduleGroup(uint group, TimeSpan min, TimeSpan max)
|
||||
{
|
||||
return RescheduleGroup(group, TaskScheduler.RandomDurationBetween(min, max));
|
||||
}
|
||||
|
||||
// Associated task
|
||||
Task _task;
|
||||
|
||||
// Owner
|
||||
TaskScheduler _owner;
|
||||
|
||||
// Marks the task as consumed
|
||||
bool _consumed = true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user