diff --git a/Projects/UOContent.Tests/Tests/Engines/Events/EventSchedulerTests.cs b/Projects/UOContent.Tests/Tests/Engines/Events/EventSchedulerTests.cs index d44116a3b..b9925a0d2 100644 --- a/Projects/UOContent.Tests/Tests/Engines/Events/EventSchedulerTests.cs +++ b/Projects/UOContent.Tests/Tests/Engines/Events/EventSchedulerTests.cs @@ -86,7 +86,7 @@ public class EventSchedulerTests Assert.True(called); Assert.Equal(Core._now, evt.NextOccurrence); - EventScheduler.Shared.StopEvent(evt); + evt.Cancel(); } finally { @@ -131,9 +131,9 @@ public class EventSchedulerTests // Verify they executed in time order, not addition order Assert.Equal([1, 2, 3], executionOrder); - EventScheduler.Shared.StopEvent(evt1); - EventScheduler.Shared.StopEvent(evt2); - EventScheduler.Shared.StopEvent(evt3); + evt1.Cancel(); + evt2.Cancel(); + evt3.Cancel(); } finally { @@ -169,7 +169,7 @@ public class EventSchedulerTests Assert.Equal(3, callCount); Assert.Equal(3, evt.CallCount); - EventScheduler.Shared.StopEvent(evt); + evt.Cancel(); } finally { @@ -211,8 +211,8 @@ public class EventSchedulerTests Assert.True(failedEventCalled); Assert.True(laterEventCalled); - EventScheduler.Shared.StopEvent(failedEvt); - EventScheduler.Shared.StopEvent(laterEvt); + failedEvt.Cancel(); + laterEvt.Cancel(); } finally { @@ -235,7 +235,7 @@ public class EventSchedulerTests ); // Remove before execution - EventScheduler.Shared.StopEvent(evt); + evt.Cancel(); // Advance time Core._now = Core._now.AddSeconds(20); diff --git a/Projects/UOContent/Engines/Events/EventScheduler.cs b/Projects/UOContent/Engines/Events/EventScheduler.cs index cf681d33e..6656f829d 100644 --- a/Projects/UOContent/Engines/Events/EventScheduler.cs +++ b/Projects/UOContent/Engines/Events/EventScheduler.cs @@ -33,15 +33,12 @@ public enum DaysOfWeek : byte public abstract class ScheduledEvent { - private static Serial _nextSerial = (Serial)1; - - // Tie-breaker for sorted set - public Serial Serial { get; } public IRecurrencePattern Recurrence { get; } public TimeZoneInfo TimeZone { get; } public TimeOnly Time { get; } public DateTime EndDate { get; } public DateTime NextOccurrence { get; private set; } + public bool Cancelled { get; private set; } public ScheduledEvent(DateTime startOn, TimeZoneInfo timeZone = null) : this(startOn, startOn, TimeOnly.FromDateTime(startOn), null, timeZone) @@ -61,7 +58,6 @@ public abstract class ScheduledEvent TimeZoneInfo timeZone = null ) { - Serial = _nextSerial++; Time = time; Recurrence = recurrence; TimeZone = timeZone ?? TimeZoneInfo.Utc; @@ -71,18 +67,19 @@ public abstract class ScheduledEvent EndDate = endOn == DateTime.MaxValue || endOn.Kind == DateTimeKind.Utc ? endOn : endOn.LocalToUtc(TimeZone); } - public bool Advance() + public void Cancel() => Cancelled = true; + + public DateTime Advance() { OnEvent(); var next = Recurrence?.GetNextOccurrence(NextOccurrence, Time, TimeZone) ?? DateTime.MaxValue; if (next == DateTime.MaxValue || next > EndDate) { - return false; + return DateTime.MaxValue; } - NextOccurrence = next; - return true; + return NextOccurrence = next; } public abstract void OnEvent(); @@ -92,7 +89,7 @@ public class EventScheduler : Timer { private static readonly ILogger logger = LogFactory.GetLogger(typeof(EventScheduler)); - private readonly SortedSet _schedule = new(ScheduledEventComparer.Default); + private readonly PriorityQueue _schedule = new(); public static EventScheduler Shared { get; private set; } @@ -182,15 +179,7 @@ public class EventScheduler : Timer { if (entry != null) { - _schedule.Add(entry); - } - } - - public void StopEvent(ScheduledEvent entry) - { - if (entry != null) - { - _schedule.Remove(entry); + _schedule.Enqueue(entry, entry.NextOccurrence); } } @@ -200,55 +189,35 @@ public class EventScheduler : Timer while (_schedule.Count > 0) { - var entry = _schedule.Min!; - if (entry.NextOccurrence > now) + var entry = _schedule.Peek(); + var cancelled = entry.Cancelled; + if (!cancelled && entry.NextOccurrence > now) { break; } - _schedule.Remove(entry); + _schedule.Dequeue(); - bool advance; + if (cancelled) + { + continue; + } + + DateTime nextOccurrence; try { - advance = entry.Advance(); + nextOccurrence = entry.Advance(); } catch (Exception e) { logger.Error(e, "Error while executing scheduled event."); - advance = false; + nextOccurrence = DateTime.MaxValue; } - if (advance && entry.NextOccurrence < DateTime.MaxValue) + if (nextOccurrence < DateTime.MaxValue) { - _schedule.Add(entry); + _schedule.Enqueue(entry, nextOccurrence); } } } - - private sealed class ScheduledEventComparer : IComparer - { - public static readonly ScheduledEventComparer Default = new(); - - public int Compare(ScheduledEvent x, ScheduledEvent y) - { - if (x == null && y == null) - { - return 0; - } - - if (x == null) - { - return 1; - } - - if (y == null) - { - return -1; - } - - var next = x.NextOccurrence.CompareTo(y.NextOccurrence); - return next != 0 ? next : x.Serial.CompareTo(y.Serial); - } - } }