Expanded upon EventScheduler
- Events are now sorted - Thread waits until either a new event is scheduled or an existing event is ready before continuing.
This commit is contained in:
parent
01b3742763
commit
2db4df9b5d
@ -5,6 +5,7 @@ namespace TrueCraft.API.Server
|
|||||||
public interface IEventScheduler
|
public interface IEventScheduler
|
||||||
{
|
{
|
||||||
void ScheduleEvent(DateTime when, Action<IMultiplayerServer> action);
|
void ScheduleEvent(DateTime when, Action<IMultiplayerServer> action);
|
||||||
void Update();
|
void Start();
|
||||||
|
void Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,17 +1,23 @@
|
|||||||
using System;
|
using System;
|
||||||
using TrueCraft.API.Server;
|
using TrueCraft.API.Server;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using TrueCraft.API.Logging;
|
||||||
|
|
||||||
namespace TrueCraft
|
namespace TrueCraft
|
||||||
{
|
{
|
||||||
public class EventScheduler : IEventScheduler
|
public class EventScheduler : IEventScheduler
|
||||||
{
|
{
|
||||||
// TODO: This could be done more efficiently if the list were kept sorted
|
private List<ScheduledEvent> Events { get; set; }
|
||||||
|
|
||||||
private IList<ScheduledEvent> Events { get; set; }
|
|
||||||
private object EventLock = new object();
|
private object EventLock = new object();
|
||||||
private IMultiplayerServer Server { get; set; }
|
private IMultiplayerServer Server { get; set; }
|
||||||
|
|
||||||
|
private SemaphoreSlim Sem = new SemaphoreSlim(0, 1);
|
||||||
|
|
||||||
|
private CancellationTokenSource Cancel;
|
||||||
|
|
||||||
public EventScheduler(IMultiplayerServer server)
|
public EventScheduler(IMultiplayerServer server)
|
||||||
{
|
{
|
||||||
Events = new List<ScheduledEvent>();
|
Events = new List<ScheduledEvent>();
|
||||||
@ -24,30 +30,99 @@ namespace TrueCraft
|
|||||||
{
|
{
|
||||||
Events.Add(new ScheduledEvent { When = when, Action = action });
|
Events.Add(new ScheduledEvent { When = when, Action = action });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Sem.CurrentCount == 0)
|
||||||
|
Sem.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Update()
|
public void Start()
|
||||||
{
|
{
|
||||||
|
Cancel = new CancellationTokenSource();
|
||||||
|
|
||||||
|
Thread scheduleThread = new Thread(Update);
|
||||||
|
scheduleThread.IsBackground = true;
|
||||||
|
|
||||||
|
scheduleThread.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
Cancel.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (Cancel.IsCancellationRequested)
|
||||||
|
break;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ScheduledEvent? nextEvent = null;
|
||||||
lock (EventLock)
|
lock (EventLock)
|
||||||
{
|
{
|
||||||
var start = DateTime.Now;
|
var evts = Events.ToList();
|
||||||
for (int i = 0; i < Events.Count; i++)
|
evts.Sort();
|
||||||
|
|
||||||
|
DateTime now = DateTime.Now;
|
||||||
|
for (int i = 0; i < evts.Count; i++)
|
||||||
{
|
{
|
||||||
var e = Events[i];
|
ScheduledEvent evt = evts[i];
|
||||||
if (e.When <= start)
|
|
||||||
{
|
if (evt.When < now)
|
||||||
e.Action(Server);
|
break;
|
||||||
Events.RemoveAt(i);
|
|
||||||
|
evts.RemoveAt(i);
|
||||||
i--;
|
i--;
|
||||||
|
|
||||||
|
evt.Action(Server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (evts.Count > 0)
|
||||||
|
nextEvent = evts.First();
|
||||||
|
|
||||||
|
Events = evts;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tasks = new List<Task> { 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<ScheduledEvent>
|
||||||
{
|
{
|
||||||
public DateTime When;
|
public DateTime When;
|
||||||
public Action<IMultiplayerServer> Action;
|
public Action<IMultiplayerServer> Action;
|
||||||
|
|
||||||
|
public int CompareTo(ScheduledEvent other)
|
||||||
|
{
|
||||||
|
if (When > other.When)
|
||||||
|
return 1;
|
||||||
|
if (When == other.When)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -113,6 +113,8 @@ namespace TrueCraft
|
|||||||
Listener.Start();
|
Listener.Start();
|
||||||
EndPoint = (IPEndPoint)Listener.LocalEndpoint;
|
EndPoint = (IPEndPoint)Listener.LocalEndpoint;
|
||||||
|
|
||||||
|
Scheduler.Start();
|
||||||
|
|
||||||
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
|
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
|
||||||
args.Completed += AcceptClient;
|
args.Completed += AcceptClient;
|
||||||
|
|
||||||
@ -135,6 +137,8 @@ namespace TrueCraft
|
|||||||
w.Save();
|
w.Save();
|
||||||
foreach (var c in Clients)
|
foreach (var c in Clients)
|
||||||
DisconnectClient(c);
|
DisconnectClient(c);
|
||||||
|
|
||||||
|
Scheduler.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddWorld(IWorld world)
|
public void AddWorld(IWorld world)
|
||||||
@ -294,7 +298,6 @@ namespace TrueCraft
|
|||||||
{
|
{
|
||||||
if (ShuttingDown)
|
if (ShuttingDown)
|
||||||
return;
|
return;
|
||||||
Scheduler.Update();
|
|
||||||
foreach (var manager in EntityManagers)
|
foreach (var manager in EntityManagers)
|
||||||
{
|
{
|
||||||
manager.Update();
|
manager.Update();
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
<AssemblyName>TrueCraft</AssemblyName>
|
<AssemblyName>TrueCraft</AssemblyName>
|
||||||
<ProductVersion>8.0.30703</ProductVersion>
|
<ProductVersion>8.0.30703</ProductVersion>
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<Optimize>false</Optimize>
|
<Optimize>false</Optimize>
|
||||||
@ -16,11 +18,13 @@
|
|||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
<ConsolePause>false</ConsolePause>
|
<ConsolePause>false</ConsolePause>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<Optimize>false</Optimize>
|
<Optimize>false</Optimize>
|
||||||
<OutputPath>bin\Release</OutputPath>
|
<OutputPath>bin\Release</OutputPath>
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
@ -75,6 +79,7 @@
|
|||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<None Include="app.config" />
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
3
TrueCraft/app.config
Normal file
3
TrueCraft/app.config
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>
|
Reference in New Issue
Block a user