Files
hjha-server/ServerCore/TimerManager/TimerManager.cs
xiaoou e9616125ce feat: initial commit - HJHA game server full source
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
2026-07-07 12:02:15 +08:00

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
}
}