6 major server modules (PdkFriendServer/GlobalSever/ServerCore/GameModule/GameNetModule) + game logic (GameFix/GameDAL/ServerData) + network layer (NetWorkMessage) + data layer (ObjectModel) + utilities (MrWu/Core/Config/CloudAPI/dll) + adapters (zyxAdapter/base) .NET 8.0 C# solution, 16 projects, 958 source files
288 lines
8.2 KiB
C#
288 lines
8.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading.Tasks;
|
|
using MrWu.Debug;
|
|
|
|
namespace Server.Core
|
|
{
|
|
public class TimerManager : ITimerManager
|
|
{
|
|
private enum TimerClass
|
|
{
|
|
None,
|
|
OnceTimer,
|
|
OnceWaitTimer,
|
|
RepeatedTimer,
|
|
}
|
|
|
|
private struct TimerAction
|
|
{
|
|
public TimerClass TimerClass;
|
|
|
|
public Action<object> Action;
|
|
|
|
public object Object;
|
|
|
|
public long StartTime;
|
|
|
|
public long Time;
|
|
|
|
public TimerAction(TimerClass timerClass, long startTime, long time, Action<object> action, object obj)
|
|
{
|
|
this.TimerClass = timerClass;
|
|
this.StartTime = startTime;
|
|
this.Time = time;
|
|
this.Action = action;
|
|
this.Object = obj;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// key: time 下次要运行的时间, value: timer id KEY 有排序功能
|
|
/// </summary>
|
|
private readonly NativeCollection.MultiMap<long, long> timeId = new NativeCollection.MultiMap<long, long>(1000);
|
|
|
|
private readonly Queue<long> timeOutTime = new Queue<long>();
|
|
|
|
private readonly Queue<long> timeOutTimerIds = new Queue<long>();
|
|
|
|
/// <summary>
|
|
/// 所有定时器
|
|
/// </summary>
|
|
private readonly Dictionary<long, TimerAction> timerActions = new Dictionary<long, TimerAction>();
|
|
|
|
private long idGenerator;
|
|
|
|
/// <summary>
|
|
/// 最小定时器时间
|
|
/// </summary>
|
|
private long minTime = long.MaxValue;
|
|
|
|
private long GetId()
|
|
{
|
|
return ++this.idGenerator;
|
|
}
|
|
|
|
public void Update()
|
|
{
|
|
if (this.timeId.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//Debug.Info($"定时器模块:{timeId.Count}");
|
|
|
|
long timeNow = this.GetNow();
|
|
if (timeNow < this.minTime)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//Debug.Info($"minTime:{minTime}");
|
|
|
|
foreach (var kv in this.timeId)
|
|
{
|
|
long k = kv.Key;
|
|
if (k > timeNow)
|
|
{
|
|
this.minTime = k;
|
|
break;
|
|
}
|
|
|
|
timeOutTime.Enqueue(k);
|
|
}
|
|
|
|
while (this.timeOutTime.Count > 0)
|
|
{
|
|
long time = this.timeOutTime.Dequeue();
|
|
var list = this.timeId[time];
|
|
for (int i = 0; i < list.Length; i++)
|
|
{
|
|
long timeOutId = list[i];
|
|
this.timeOutTimerIds.Enqueue(timeOutId);
|
|
}
|
|
|
|
this.timeId.Remove(time);
|
|
}
|
|
|
|
if (this.timeId.Count == 0)
|
|
{
|
|
this.minTime = long.MaxValue;
|
|
}
|
|
|
|
while (this.timeOutTimerIds.Count > 0)
|
|
{
|
|
long timeOutId = this.timeOutTimerIds.Dequeue();
|
|
|
|
if (!this.timerActions.TryGetValue(timeOutId, out TimerAction timerAction))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
this.timerActions.Remove(timeOutId);
|
|
|
|
Run(timeOutId, ref timerAction);
|
|
}
|
|
}
|
|
|
|
private void Run(long timeOutId, ref TimerAction timerAction)
|
|
{
|
|
switch (timerAction.TimerClass)
|
|
{
|
|
case TimerClass.OnceTimer:
|
|
{
|
|
InvokeTimer(ref timerAction);
|
|
}
|
|
break;
|
|
case TimerClass.OnceWaitTimer:
|
|
{
|
|
TaskCompletionSource<bool> tcs = timerAction.Object as TaskCompletionSource<bool>;
|
|
tcs.SetResult(true);
|
|
}
|
|
break;
|
|
case TimerClass.RepeatedTimer:
|
|
{
|
|
long timeNow = this.GetNow();
|
|
timerAction.StartTime = timeNow;
|
|
this.AddTimer(timeOutId, ref timerAction); //添加到定时器,继续执行
|
|
|
|
//执行定时器
|
|
InvokeTimer(ref timerAction);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void InvokeTimer(ref TimerAction timerAction)
|
|
{
|
|
try
|
|
{
|
|
timerAction.Action?.Invoke(timerAction.Object);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.Error($"定时器出错:{e.Message}");
|
|
}
|
|
}
|
|
|
|
private long GetNow()
|
|
{
|
|
return TimeInfo.Instance.ServerFrameTime();
|
|
}
|
|
|
|
private long NewRepeatedTimerInner(long time, Action<object> action, object args)
|
|
{
|
|
Debug.Info($"NewRepeatedTimerInner {time}");
|
|
if (time < 100)
|
|
{
|
|
Debug.Warning($"time too small:{time}");
|
|
}
|
|
|
|
long timeNow = GetNow();
|
|
long timerId = GetId();
|
|
|
|
TimerAction timer = new TimerAction(TimerClass.RepeatedTimer, timeNow, time, action, args);
|
|
this.AddTimer(timerId, ref timer);
|
|
return timerId;
|
|
}
|
|
|
|
private void AddTimer(long timerId, ref TimerAction timer)
|
|
{
|
|
long tillTime = timer.StartTime + timer.Time;
|
|
this.timeId.Add(tillTime, timerId);
|
|
this.timerActions.Add(timerId, timer);
|
|
if (tillTime < minTime)
|
|
{
|
|
minTime = tillTime;
|
|
}
|
|
|
|
//Debug.Info($"添加定时器:{tillTime} {timer.StartTime} {minTime}");
|
|
}
|
|
|
|
private bool Remove(long id)
|
|
{
|
|
if (id == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!this.timerActions.Remove(id))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
#region ITimerManager
|
|
|
|
public async Task WaitTillAsync(long tillTime)
|
|
{
|
|
long timeNow = GetNow();
|
|
if (timeNow > tillTime)
|
|
{
|
|
return;
|
|
}
|
|
|
|
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
|
|
long timerId = this.GetId();
|
|
TimerAction timer = new TimerAction(TimerClass.OnceWaitTimer, timeNow, tillTime - timeNow, null, tcs);
|
|
this.AddTimer(timerId, ref timer);
|
|
await tcs.Task;
|
|
}
|
|
|
|
public async Task WaitFrameAsync()
|
|
{
|
|
await this.WaitAsync(1);
|
|
}
|
|
|
|
public async Task WaitAsync(long time)
|
|
{
|
|
if (time == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
long timeNow = GetNow();
|
|
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
|
|
long timerId = this.GetId();
|
|
TimerAction timer = new TimerAction(TimerClass.OnceWaitTimer, timeNow, time, null, tcs);
|
|
this.AddTimer(timerId, ref timer);
|
|
await tcs.Task;
|
|
}
|
|
|
|
public long NewOnceTimer(long tillTime, Action<object> action, object args)
|
|
{
|
|
long timeNow = GetNow();
|
|
|
|
if (tillTime < timeNow)
|
|
{
|
|
Debug.Error($"now once time too small:{tillTime}");
|
|
}
|
|
|
|
long timeId = GetId();
|
|
TimerAction timer = new TimerAction(TimerClass.OnceTimer, timeNow, tillTime - timeNow, action, args);
|
|
this.AddTimer(timeId, ref timer);
|
|
return timeId;
|
|
}
|
|
|
|
public long NewFrameTimer(Action<object> action, object args)
|
|
{
|
|
return NewRepeatedTimerInner(0, action, args);
|
|
}
|
|
|
|
public long NewRepeatedTimer(long time, Action<object> action, object args)
|
|
{
|
|
return NewRepeatedTimerInner(time, action, args);
|
|
}
|
|
|
|
public bool Remove(ref long id)
|
|
{
|
|
long i = id;
|
|
id = 0;
|
|
return Remove(i);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |