fix(core): Fixes a timer bug where Stop wasn't called internally (#664)
This commit is contained in:
parent
26592f202e
commit
06a577332d
7 changed files with 71 additions and 50 deletions
|
|
@ -18,7 +18,7 @@ namespace Server.Tests
|
|||
// Configure the world
|
||||
World.Configure();
|
||||
|
||||
Timer.Initialize(0);
|
||||
Timer.Init(0);
|
||||
|
||||
// Load the world
|
||||
World.Load();
|
||||
|
|
@ -26,7 +26,7 @@ namespace Server.Tests
|
|||
|
||||
public void Dispose()
|
||||
{
|
||||
Timer.Initialize(0);
|
||||
Timer.Init(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Server.Tests
|
|||
timerTicks.ExecutedCount++;
|
||||
}
|
||||
|
||||
Timer.Initialize(timerTicks.Ticks);
|
||||
Timer.Init(timerTicks.Ticks);
|
||||
|
||||
var timer = Timer.DelayCall(TimeSpan.FromMilliseconds(ticks), action);
|
||||
timer.Start();
|
||||
|
|
@ -51,7 +51,7 @@ namespace Server.Tests
|
|||
Assert.Equal(timerTicks.ExpectedTicks, timerTicks.Ticks);
|
||||
}
|
||||
|
||||
Timer.Initialize(timerTicks.Ticks);
|
||||
Timer.Init(timerTicks.Ticks);
|
||||
|
||||
var timer = Timer.DelayCall(TimeSpan.FromMilliseconds(delay), TimeSpan.FromMilliseconds(interval), count, action);
|
||||
timer.Start();
|
||||
|
|
|
|||
|
|
@ -467,7 +467,7 @@ namespace Server
|
|||
|
||||
VerifySerialization();
|
||||
|
||||
Timer.Initialize(TickCount);
|
||||
Timer.Init(TickCount);
|
||||
|
||||
AssemblyHandler.Invoke("Configure");
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ using System;
|
|||
|
||||
namespace Server
|
||||
{
|
||||
public delegate void TimerCallback();
|
||||
|
||||
public delegate void TimerStateCallback<in T>(T state);
|
||||
|
||||
public delegate void TimerStateCallback<in T1, in T2>(T1 t1, T2 t2);
|
||||
|
|
@ -32,15 +30,15 @@ namespace Server
|
|||
private static string FormatDelegate(Delegate callback) =>
|
||||
callback == null ? "null" : $"{callback.Method.DeclaringType?.FullName ?? ""}.{callback.Method.Name}";
|
||||
|
||||
public static Timer DelayCall(TimerCallback callback) => DelayCall(TimeSpan.Zero, TimeSpan.Zero, 1, callback);
|
||||
public static Timer DelayCall(Action callback) => DelayCall(TimeSpan.Zero, TimeSpan.Zero, 1, callback);
|
||||
|
||||
public static Timer DelayCall(TimeSpan delay, TimerCallback callback) =>
|
||||
public static Timer DelayCall(TimeSpan delay, Action callback) =>
|
||||
DelayCall(delay, TimeSpan.Zero, 1, callback);
|
||||
|
||||
public static Timer DelayCall(TimeSpan delay, TimeSpan interval, TimerCallback callback) =>
|
||||
public static Timer DelayCall(TimeSpan delay, TimeSpan interval, Action callback) =>
|
||||
DelayCall(delay, interval, 0, callback);
|
||||
|
||||
public static Timer DelayCall(TimeSpan delay, TimeSpan interval, int count, TimerCallback callback)
|
||||
public static Timer DelayCall(TimeSpan delay, TimeSpan interval, int count, Action callback)
|
||||
{
|
||||
Timer t = new DelayCallTimer(delay, interval, count, callback);
|
||||
t.Start();
|
||||
|
|
@ -143,7 +141,7 @@ namespace Server
|
|||
|
||||
private class DelayCallTimer : Timer
|
||||
{
|
||||
public DelayCallTimer(TimeSpan delay, TimeSpan interval, int count, TimerCallback callback) : base(
|
||||
public DelayCallTimer(TimeSpan delay, TimeSpan interval, int count, Action callback) : base(
|
||||
delay,
|
||||
interval,
|
||||
count
|
||||
|
|
@ -152,7 +150,7 @@ namespace Server
|
|||
Callback = callback;
|
||||
}
|
||||
|
||||
public TimerCallback Callback { get; }
|
||||
public Action Callback { get; }
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace Server
|
|||
private static readonly Timer[][] _rings = new Timer[_ringLayers][];
|
||||
private static readonly int[] _ringIndexes = new int[_ringLayers];
|
||||
|
||||
public static void Initialize(long tickCount)
|
||||
public static void Init(long tickCount)
|
||||
{
|
||||
_lastTickTurned = tickCount;
|
||||
|
||||
|
|
@ -107,21 +107,26 @@ namespace Server
|
|||
{
|
||||
var next = timer._nextTimer;
|
||||
var prof = timer.GetProfile();
|
||||
var finished = timer.Count != 0 && ++timer.Index >= timer.Count;
|
||||
|
||||
// We remove it before `OnTick()` so time references can be nulled and returned to cache safely from within OnTick.
|
||||
// This can be done in OnTick by checking if Index < Count - 1 (still more iterations left)
|
||||
RemoveTimer(timer);
|
||||
|
||||
if (finished)
|
||||
{
|
||||
timer.InternalStop();
|
||||
}
|
||||
|
||||
prof?.Start();
|
||||
timer.OnTick();
|
||||
prof?.Finish();
|
||||
|
||||
if (timer.Running)
|
||||
if (timer.Running && !finished)
|
||||
{
|
||||
RemoveTimer(timer);
|
||||
|
||||
if (timer.Count == 0 || ++timer.Index < timer.Count)
|
||||
{
|
||||
timer.Delay = timer.Interval;
|
||||
timer.Next = Core.Now + timer.Interval;
|
||||
AddTimer(timer, (long)timer.Delay.TotalMilliseconds);
|
||||
}
|
||||
timer.Delay = timer.Interval;
|
||||
timer.Next = Core.Now + timer.Interval;
|
||||
AddTimer(timer, (long)timer.Delay.TotalMilliseconds);
|
||||
}
|
||||
|
||||
timer = next;
|
||||
|
|
@ -166,12 +171,7 @@ namespace Server
|
|||
slot -= _ringSize;
|
||||
}
|
||||
|
||||
timer._nextTimer = _rings[i][slot];
|
||||
if (timer._nextTimer != null)
|
||||
{
|
||||
timer._nextTimer._prevTimer = timer;
|
||||
}
|
||||
|
||||
timer.Attach(_rings[i][slot]);
|
||||
timer._remaining = remaining;
|
||||
timer._ring = i;
|
||||
timer._slot = (int)slot;
|
||||
|
|
@ -188,22 +188,12 @@ namespace Server
|
|||
|
||||
private static void RemoveTimer(Timer timer)
|
||||
{
|
||||
if (timer._prevTimer != null)
|
||||
{
|
||||
timer._prevTimer._nextTimer = timer._nextTimer;
|
||||
}
|
||||
else
|
||||
if (timer._prevTimer == null)
|
||||
{
|
||||
_rings[timer._ring][timer._slot] = timer._nextTimer;
|
||||
}
|
||||
|
||||
if (timer._nextTimer != null)
|
||||
{
|
||||
timer._nextTimer._prevTimer = timer._prevTimer;
|
||||
}
|
||||
|
||||
timer._nextTimer = null;
|
||||
timer._prevTimer = null;
|
||||
timer.Detach();
|
||||
}
|
||||
|
||||
public static void DumpInfo(TextWriter tw)
|
||||
|
|
|
|||
|
|
@ -15,11 +15,14 @@
|
|||
|
||||
using System;
|
||||
using Server.Diagnostics;
|
||||
using Server.Logging;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public partial class Timer
|
||||
{
|
||||
private static readonly ILogger logger = LogFactory.GetLogger(typeof(Timer));
|
||||
|
||||
// We need to know what ring/slot we are in so we can be removed if we are "head" of the link list.
|
||||
private int _ring;
|
||||
private int _slot;
|
||||
|
|
@ -32,8 +35,11 @@ namespace Server
|
|||
{
|
||||
}
|
||||
|
||||
public Timer(TimeSpan delay, TimeSpan interval, int count = 0)
|
||||
public Timer(TimeSpan delay, TimeSpan interval, int count = 0) => Init(delay, interval, count);
|
||||
|
||||
public void Init(TimeSpan delay, TimeSpan interval, int count)
|
||||
{
|
||||
Running = false;
|
||||
Delay = delay;
|
||||
Interval = interval;
|
||||
Count = count;
|
||||
|
|
@ -53,7 +59,8 @@ namespace Server
|
|||
public TimeSpan Delay { get; set; }
|
||||
public TimeSpan Interval { get; set; }
|
||||
public int Index { get; private set; }
|
||||
public int Count { get; }
|
||||
public int Count { get; private set; }
|
||||
public int RemainingCount => Count - Index;
|
||||
public bool Running { get; private set; }
|
||||
|
||||
public TimerProfile GetProfile() => !Core.Profiling ? null : TimerProfile.Acquire(ToString() ?? "null");
|
||||
|
|
@ -87,21 +94,50 @@ namespace Server
|
|||
return this;
|
||||
}
|
||||
|
||||
Running = false;
|
||||
RemoveTimer(this);
|
||||
InternalStop();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private void InternalStop()
|
||||
{
|
||||
Running = false;
|
||||
var prof = GetProfile();
|
||||
|
||||
if (prof != null)
|
||||
{
|
||||
prof.Stopped++;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
protected virtual void OnTick()
|
||||
{
|
||||
}
|
||||
|
||||
private void Attach(Timer timer)
|
||||
{
|
||||
_nextTimer = timer;
|
||||
if (timer != null)
|
||||
{
|
||||
timer._prevTimer = this;
|
||||
}
|
||||
}
|
||||
|
||||
private void Detach()
|
||||
{
|
||||
if (_prevTimer != null)
|
||||
{
|
||||
_prevTimer._nextTimer = _nextTimer;
|
||||
}
|
||||
|
||||
if (_nextTimer != null)
|
||||
{
|
||||
_nextTimer._prevTimer = _prevTimer;
|
||||
}
|
||||
|
||||
_nextTimer = null;
|
||||
_prevTimer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1615,8 +1615,6 @@ namespace Server.Engines.ConPVP
|
|||
|
||||
private Timer m_FinishTimer;
|
||||
|
||||
private TimerCallback m_UnhideCallback;
|
||||
|
||||
public BRGame(BRController controller, DuelContext context) : base(context) => Controller = controller;
|
||||
|
||||
public BRController Controller { get; }
|
||||
|
|
@ -1641,10 +1639,9 @@ namespace Server.Engines.ConPVP
|
|||
{
|
||||
if (m_Bomb != null && Controller != null)
|
||||
{
|
||||
m_UnhideCallback ??= UnhideBomb;
|
||||
m_Bomb.Visible = false;
|
||||
m_Bomb.MoveToWorld(Controller.BombHome, Controller.Map);
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(Utility.RandomMinMax(5, 15)), m_UnhideCallback);
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(Utility.RandomMinMax(5, 15)), UnhideBomb);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue