diff --git a/Projects/Server/Timer/Timer.TimerWheel.cs b/Projects/Server/Timer/Timer.TimerWheel.cs index 239e8136a..e1af8df8e 100644 --- a/Projects/Server/Timer/Timer.TimerWheel.cs +++ b/Projects/Server/Timer/Timer.TimerWheel.cs @@ -74,22 +74,28 @@ namespace Server } var timer = _rings[i][ringIndex]; - if (timer != null) { events = true; - if (i > 0 && timer._remaining > 0) + do { - Promote(timer); - } - else - { - Execute(timer); - } + var next = _rings[i][ringIndex] = timer._nextTimer; - // Clear the slot - _rings[i][ringIndex] = null; + timer.Detach(); + + if (i > 0 && timer._remaining > 0) + { + // Promote + AddTimer(timer, timer._remaining); + } + else + { + Execute(timer); + } + + timer = next; + } while (timer != null); } if (!turnNextWheel) @@ -103,50 +109,29 @@ namespace Server private static void Execute(Timer timer) { - do + var finished = timer.Count != 0 && ++timer.Index >= timer.Count; + + var version = timer.Version; + + var prof = timer.GetProfile(); + prof?.Start(); + timer.OnTick(); + prof?.Finish(); + + // If the timer has not been stopped, and it has not been altered (restarted, returned etc) + if (timer.Running && timer.Version == version) { - 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); - - var version = timer.Version; - - prof?.Start(); - timer.OnTick(); - prof?.Finish(); - - // If the timer has not been stopped, and it has not been altered (shared timers) - if (timer.Running && timer.Version == version) + if (finished) { - if (finished) - { - timer.Stop(); - } - else - { - timer.Delay = timer.Interval; - timer.Next = Core.Now + timer.Interval; - AddTimer(timer, (long)timer.Delay.TotalMilliseconds); - } + timer.Stop(); } - - timer = next; - } while (timer != null); - } - - private static void Promote(Timer timer) - { - do - { - var next = timer._nextTimer; - RemoveTimer(timer); - AddTimer(timer, timer._remaining); - timer = next; - } while (timer != null); + else + { + timer.Delay = timer.Interval; + timer.Next = Core.Now + timer.Interval; + AddTimer(timer, (long)timer.Delay.TotalMilliseconds); + } + } } private static void AddTimer(Timer timer, long delay) @@ -182,6 +167,7 @@ namespace Server timer._slot = (int)slot; _rings[i][slot] = timer; + break; } @@ -191,16 +177,6 @@ namespace Server } } - private static void RemoveTimer(Timer timer) - { - if (timer._prevTimer == null) - { - _rings[timer._ring][timer._slot] = timer._nextTimer; - } - - timer.Detach(); - } - public static void DumpInfo(TextWriter tw) { tw.WriteLine("Date: {0}\n", Core.Now.ToLocalTime()); diff --git a/Projects/Server/Timer/Timer.cs b/Projects/Server/Timer/Timer.cs index abe3aa509..7d10bf441 100644 --- a/Projects/Server/Timer/Timer.cs +++ b/Projects/Server/Timer/Timer.cs @@ -81,6 +81,7 @@ namespace Server return this; } + Index = 0; Running = true; AddTimer(this, (long)Delay.TotalMilliseconds); @@ -101,8 +102,15 @@ namespace Server return; } - RemoveTimer(this); + // We are at the head + if (_rings[_ring][_slot] == this) + { + _rings[_ring][_slot] = _nextTimer; + } + + Detach(); Running = false; + Version++; var prof = GetProfile(); if (prof != null) diff --git a/Projects/Server/World/EntityPersistence.cs b/Projects/Server/World/EntityPersistence.cs index 2fe1d090f..93c597bba 100644 --- a/Projects/Server/World/EntityPersistence.cs +++ b/Projects/Server/World/EntityPersistence.cs @@ -162,6 +162,8 @@ namespace Server using FileStream bin = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read); BufferReader br = null; + var deleteAllFailures = false; + foreach (var entry in entities) { T t = entry.Entity; @@ -210,11 +212,21 @@ namespace Server Console.WriteLine($"***** Bad deserialize of {t.GetType()} *****"); Console.WriteLine(error); - Console.WriteLine("Delete the object and continue? (y/n)"); + ConsoleKey pressedKey; - if (Console.ReadKey(true).Key != ConsoleKey.Y) + if (!deleteAllFailures) { - throw new Exception("Deserialization failed."); + Console.WriteLine("Delete the object and continue? (y/n/a)"); + pressedKey = Console.ReadKey(true).Key; + + if (pressedKey == ConsoleKey.A) + { + deleteAllFailures = true; + } + else if (pressedKey != ConsoleKey.Y) + { + throw new Exception("Deserialization failed."); + } } t.Delete(); diff --git a/Projects/UOContent/Engines/Spawners/BaseSpawner.cs b/Projects/UOContent/Engines/Spawners/BaseSpawner.cs index 7a62c4578..dcd1689d9 100644 --- a/Projects/UOContent/Engines/Spawners/BaseSpawner.cs +++ b/Projects/UOContent/Engines/Spawners/BaseSpawner.cs @@ -110,7 +110,11 @@ namespace Server.Engines.Spawners { m_Count = value; - if (m_Timer != null && (!IsFull && !m_Timer.Running || IsFull && m_Timer.Running)) + if (IsFull) + { + m_Timer?.Stop(); + } + else if (m_Timer?.Running != true) { DoTimer(); } @@ -372,11 +376,8 @@ namespace Server.Engines.Spawners public void Stop() { - if (m_Running) - { - m_Timer?.Stop(); - m_Running = false; - } + m_Timer?.Stop(); + m_Running = false; } public void Defrag()