diff --git a/TrueCraft.API/Server/IEventScheduler.cs b/TrueCraft.API/Server/IEventScheduler.cs index e010aff..734fd35 100644 --- a/TrueCraft.API/Server/IEventScheduler.cs +++ b/TrueCraft.API/Server/IEventScheduler.cs @@ -5,6 +5,7 @@ namespace TrueCraft.API.Server public interface IEventScheduler { void ScheduleEvent(DateTime when, Action action); - void Update(); + void Start(); + void Stop(); } } \ No newline at end of file diff --git a/TrueCraft/EventScheduler.cs b/TrueCraft/EventScheduler.cs index 398cf83..5ed094b 100644 --- a/TrueCraft/EventScheduler.cs +++ b/TrueCraft/EventScheduler.cs @@ -1,17 +1,23 @@ using System; using TrueCraft.API.Server; using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using TrueCraft.API.Logging; namespace TrueCraft { public class EventScheduler : IEventScheduler { - // TODO: This could be done more efficiently if the list were kept sorted - - private IList Events { get; set; } + private List Events { get; set; } private object EventLock = new object(); private IMultiplayerServer Server { get; set; } + private SemaphoreSlim Sem = new SemaphoreSlim(0, 1); + + private CancellationTokenSource Cancel; + public EventScheduler(IMultiplayerServer server) { Events = new List(); @@ -24,30 +30,99 @@ namespace TrueCraft { Events.Add(new ScheduledEvent { When = when, Action = action }); } + + if (Sem.CurrentCount == 0) + Sem.Release(); } - public void Update() + public void Start() { - lock (EventLock) + Cancel = new CancellationTokenSource(); + + Thread scheduleThread = new Thread(Update); + scheduleThread.IsBackground = true; + + scheduleThread.Start(); + } + + public void Stop() + { + Cancel.Cancel(); + } + + private void Update() + { + while (true) { - var start = DateTime.Now; - for (int i = 0; i < Events.Count; i++) + if (Cancel.IsCancellationRequested) + break; + + try { - var e = Events[i]; - if (e.When <= start) + ScheduledEvent? nextEvent = null; + lock (EventLock) { - e.Action(Server); - Events.RemoveAt(i); - i--; + var evts = Events.ToList(); + evts.Sort(); + + DateTime now = DateTime.Now; + for (int i = 0; i < evts.Count; i++) + { + ScheduledEvent evt = evts[i]; + + if (evt.When < now) + break; + + evts.RemoveAt(i); + i--; + + evt.Action(Server); + } + + if (evts.Count > 0) + nextEvent = evts.First(); + + Events = evts; } + + var tasks = new List { Sem.WaitAsync(Cancel.Token) }; + if (nextEvent != null) + { + TimeSpan ts = nextEvent.Value.When - DateTime.Now; + + if (ts < TimeSpan.Zero) + continue; + + tasks.Add(Task.Delay(ts, Cancel.Token)); + } + + Task.WhenAny(tasks).Wait(); + } + catch (OperationCanceledException) + { + return; + } + catch (Exception ex) + { + Server.Log(LogCategory.Error, "Scheduler Error", ex.ToString()); } } } - private struct ScheduledEvent + private struct ScheduledEvent : IComparable { public DateTime When; public Action Action; + + public int CompareTo(ScheduledEvent other) + { + if (When > other.When) + return 1; + if (When == other.When) + return 0; + + return -1; + } } } } \ No newline at end of file diff --git a/TrueCraft/MultiplayerServer.cs b/TrueCraft/MultiplayerServer.cs index 49f14f2..7248da3 100644 --- a/TrueCraft/MultiplayerServer.cs +++ b/TrueCraft/MultiplayerServer.cs @@ -113,6 +113,8 @@ namespace TrueCraft Listener.Start(); EndPoint = (IPEndPoint)Listener.LocalEndpoint; + Scheduler.Start(); + SocketAsyncEventArgs args = new SocketAsyncEventArgs(); args.Completed += AcceptClient; @@ -135,6 +137,8 @@ namespace TrueCraft w.Save(); foreach (var c in Clients) DisconnectClient(c); + + Scheduler.Stop(); } public void AddWorld(IWorld world) @@ -294,7 +298,6 @@ namespace TrueCraft { if (ShuttingDown) return; - Scheduler.Update(); foreach (var manager in EntityManagers) { manager.Update(); diff --git a/TrueCraft/TrueCraft.csproj b/TrueCraft/TrueCraft.csproj index affb812..72f37e5 100644 --- a/TrueCraft/TrueCraft.csproj +++ b/TrueCraft/TrueCraft.csproj @@ -9,6 +9,8 @@ TrueCraft 8.0.30703 2.0 + v4.5 + false @@ -16,11 +18,13 @@ 4 true false + false false bin\Release 4 + false @@ -75,6 +79,7 @@ + \ No newline at end of file diff --git a/TrueCraft/app.config b/TrueCraft/app.config new file mode 100644 index 0000000..51278a4 --- /dev/null +++ b/TrueCraft/app.config @@ -0,0 +1,3 @@ + + +