diff --git a/Projects/UOContent/Engines/CannedEvil/CannedEvilTimer.cs b/Projects/UOContent/Engines/CannedEvil/CannedEvilTimer.cs index d7ca9e1b7..2109f09ec 100644 --- a/Projects/UOContent/Engines/CannedEvil/CannedEvilTimer.cs +++ b/Projects/UOContent/Engines/CannedEvil/CannedEvilTimer.cs @@ -15,6 +15,7 @@ using System; using System.Collections.Generic; +using Server.Collections; using Server.Misc; namespace Server.Engines.CannedEvil @@ -29,8 +30,8 @@ namespace Server.Engines.CannedEvil Instance.OnTick(); } - private static readonly HashSet _dungeonSpawns = new(); - private static readonly HashSet _lostLandsSpawns = new(); + private static readonly HashSet _dungeonSpawns = new(); + private static readonly HashSet _lostLandsSpawns = new(); private static DateTime _sliceTime; public static CannedEvilTimer Instance { get; private set; } @@ -38,25 +39,25 @@ namespace Server.Engines.CannedEvil public static void AddSpawn(DungeonChampionSpawn spawn) { _dungeonSpawns.Add(spawn); - Instance?.OnSlice(_dungeonSpawns, false); + OnSlice(_dungeonSpawns, false); } public static void AddSpawn(LLChampionSpawn spawn) { _lostLandsSpawns.Add(spawn); - Instance?.OnSlice(_lostLandsSpawns, false); + OnSlice(_lostLandsSpawns, false); } public static void RemoveSpawn(DungeonChampionSpawn spawn) { _dungeonSpawns.Remove(spawn); - Instance?.OnSlice(_dungeonSpawns, false); + OnSlice(_dungeonSpawns, false); } public static void RemoveSpawn(LLChampionSpawn spawn) { _lostLandsSpawns.Remove(spawn); - Instance?.OnSlice(_lostLandsSpawns, false); + OnSlice(_lostLandsSpawns, false); } public CannedEvilTimer() : base(TimeSpan.Zero, TimeSpan.FromMinutes(1.0)) @@ -64,32 +65,34 @@ namespace Server.Engines.CannedEvil _sliceTime = Core.Now; } - public void OnSlice(ICollection list, bool rotate = true) where T : ChampionSpawn + public static void OnSlice(HashSet spawns, bool rotate = true) { - if (list.Count > 0) + if (spawns.Count <= 0) { - List valid = new List(); + return; + } - foreach (T spawn in list) + using var queue = rotate ? PooledRefQueue.Create() : default; + + foreach (var spawn in spawns) + { + if (spawn.AlwaysActive && !spawn.Active) { - if (spawn.AlwaysActive && !spawn.Active) - { - spawn.ReadyToActivate = true; - } - else if (rotate && (!spawn.Active || spawn.Kills == 0 && spawn.Level == 0)) - { - spawn.Active = false; - spawn.ReadyToActivate = false; - - valid.Add(spawn); - } + spawn.ReadyToActivate = true; } - - if (valid.Count > 0) + else if (rotate && (!spawn.Active || spawn.Kills == 0 && spawn.Level == 0)) { - valid[Utility.Random(valid.Count)].ReadyToActivate = true; + spawn.Active = false; + spawn.ReadyToActivate = false; + + queue.Enqueue(spawn); } } + + if (rotate && queue.Count > 0) + { + ((ChampionSpawn)queue.PeekRandom()).ReadyToActivate = true; + } } protected override void OnTick() diff --git a/Projects/UOContent/Engines/CannedEvil/DungeonChampionSpawn.cs b/Projects/UOContent/Engines/CannedEvil/DungeonChampionSpawn.cs index 534168848..280afe924 100644 --- a/Projects/UOContent/Engines/CannedEvil/DungeonChampionSpawn.cs +++ b/Projects/UOContent/Engines/CannedEvil/DungeonChampionSpawn.cs @@ -26,11 +26,6 @@ public partial class DungeonChampionSpawn : ChampionSpawn CannedEvilTimer.AddSpawn(this); } - public DungeonChampionSpawn(Serial serial) : base(serial) - { - CannedEvilTimer.AddSpawn(this); - } - public override bool ProximitySpawn => true; public override bool AlwaysActive => false; @@ -39,4 +34,7 @@ public partial class DungeonChampionSpawn : ChampionSpawn base.OnAfterDelete(); CannedEvilTimer.RemoveSpawn(this); } + + [AfterDeserialization] + private void AfterDeserialization() => CannedEvilTimer.AddSpawn(this); } diff --git a/Projects/UOContent/Engines/CannedEvil/GenChampEntry.cs b/Projects/UOContent/Engines/CannedEvil/GenChampEntry.cs index 148ac59d7..dc106d22c 100644 --- a/Projects/UOContent/Engines/CannedEvil/GenChampEntry.cs +++ b/Projects/UOContent/Engines/CannedEvil/GenChampEntry.cs @@ -15,35 +15,34 @@ using System; -namespace Server.Engines.CannedEvil +namespace Server.Engines.CannedEvil; + +public class ChampionEntry { - public record ChampionEntry + public readonly bool _randomizeType; + public readonly ChampionSpawnType _type; + public readonly Point3D _signLocation; + public readonly Type _champType; + public readonly Map _map; + public readonly Point3D _ejectLocation; + public readonly Map _ejectMap; + + public ChampionEntry(Type champtype, Point3D signloc, Map map, Point3D ejectloc, Map ejectmap) : + this(champtype, ChampionSpawnType.Abyss, signloc, map, ejectloc, ejectmap, true) { - public readonly bool m_RandomizeType; - public readonly ChampionSpawnType m_Type; - public readonly Point3D m_SignLocation; - public readonly Type m_ChampType; - public readonly Map m_Map; - public readonly Point3D m_EjectLocation; - public readonly Map m_EjectMap; + } - public ChampionEntry(Type champtype, Point3D signloc, Map map, Point3D ejectloc, Map ejectmap) : - this(champtype, ChampionSpawnType.Abyss, signloc, map, ejectloc, ejectmap, true) - { - } - - public ChampionEntry( - Type champtype, ChampionSpawnType type, Point3D signloc, Map map, Point3D ejectloc, Map ejectmap, - bool randomizetype = false - ) - { - m_ChampType = champtype; - m_RandomizeType = randomizetype; - m_Type = type; - m_SignLocation = signloc; - m_Map = map; - m_EjectLocation = ejectloc; - m_EjectMap = ejectmap; - } + public ChampionEntry( + Type champtype, ChampionSpawnType type, Point3D signloc, Map map, Point3D ejectloc, Map ejectmap, + bool randomizetype = false + ) + { + _champType = champtype; + _randomizeType = randomizetype; + _type = type; + _signLocation = signloc; + _map = map; + _ejectLocation = ejectloc; + _ejectMap = ejectmap; } } diff --git a/Projects/UOContent/Engines/CannedEvil/GenChamps.cs b/Projects/UOContent/Engines/CannedEvil/GenChamps.cs index 0a3b526ea..22a7f03a0 100644 --- a/Projects/UOContent/Engines/CannedEvil/GenChamps.cs +++ b/Projects/UOContent/Engines/CannedEvil/GenChamps.cs @@ -17,105 +17,106 @@ using System; using System.Collections.Generic; using Server.Logging; -namespace Server.Engines.CannedEvil +namespace Server.Engines.CannedEvil; + +public static class ChampionGenerator { - public static class ChampionGenerator + private static readonly ILogger logger = LogFactory.GetLogger(typeof(ChampionGenerator)); + + public static void Configure() { - private static readonly ILogger logger = LogFactory.GetLogger(typeof(ChampionGenerator)); + CommandSystem.Register("GenChamps", AccessLevel.Developer, ChampGen_OnCommand); + } - public static void Configure() + private static readonly ChampionEntry[] LLLocations = + [ + new(typeof(LLChampionSpawn), new Point3D(5511, 2360, 42), Map.Felucca, new Point3D(5439, 2323, 26), Map.Felucca), + new(typeof(LLChampionSpawn), new Point3D(6038, 2401, 47), Map.Felucca, new Point3D(5988, 2340, 24), Map.Felucca), + new(typeof(LLChampionSpawn), new Point3D(5549, 2640, 16), Map.Felucca, new Point3D(5645, 2696, -8), Map.Felucca), + new(typeof(LLChampionSpawn), new Point3D(5636, 2916, 37), Map.Felucca, new Point3D(5721, 2949, 28), Map.Felucca), + new(typeof(LLChampionSpawn), new Point3D(6035, 2943, 50), Map.Felucca, new Point3D(6098, 2997, 17), Map.Felucca), + new(typeof(LLChampionSpawn), new Point3D(5265, 3171, 105), Map.Felucca, new Point3D(5314, 3232, 2), Map.Felucca), + new(typeof(LLChampionSpawn), new Point3D(5282, 3368, 50), Map.Felucca, new Point3D(5215, 3318, 3), Map.Felucca), + new(typeof(LLChampionSpawn), new Point3D(5207, 3637, 20), Map.Felucca, new Point3D(5263, 3687, 0), Map.Felucca), + new(typeof(LLChampionSpawn), new Point3D(5954, 3475, 25), Map.Felucca, new Point3D(6013, 3529, 0), Map.Felucca), + new(typeof(LLChampionSpawn), new Point3D(5982, 3882, 20), Map.Felucca, new Point3D(5929, 3820, -1), Map.Felucca), + new(typeof(LLChampionSpawn), new Point3D(5724, 3991, 41), Map.Felucca, new Point3D(5774, 4041, 26), Map.Felucca), + new(typeof(LLChampionSpawn), ChampionSpawnType.ForestLord, new Point3D(5559, 3757, 21), Map.Felucca, new Point3D(5513, 3878, 3), Map.Felucca) + ]; + + private static readonly ChampionEntry[] DungeonLocations = + [ + new(typeof(DungeonChampionSpawn), ChampionSpawnType.UnholyTerror, new Point3D(5179, 709, 20), Map.Felucca, new Point3D(4111, 432, 5), Map.Felucca), + new(typeof(DungeonChampionSpawn), ChampionSpawnType.VerminHorde, new Point3D(5557, 827, 65), Map.Felucca, new Point3D(5580, 632, 30), Map.Felucca), + new(typeof(DungeonChampionSpawn), ChampionSpawnType.ColdBlood, new Point3D(5259, 837, 64), Map.Felucca, new Point3D(1176, 2637, 0), Map.Felucca), + new(typeof(DungeonChampionSpawn), ChampionSpawnType.Abyss, new Point3D(5815, 1352, 5), Map.Felucca, new Point3D(2923, 3406, 8), Map.Felucca), + new(typeof(DungeonChampionSpawn), ChampionSpawnType.Arachnid, new Point3D(5190, 1607, 20), Map.Felucca, new Point3D(5482, 3161, -54), Map.Felucca) + ]; + + [Usage("GenChamps")] + [Description("Generates champions for Felucca Dungeons & Lost Lands.")] + private static void ChampGen_OnCommand(CommandEventArgs e) + { + /* + //We take the assumption that we are spawning managed champions + for (int i = CannedEvilTimer.DungeonSpawns.Count - 1; i >= 0; i--) + CannedEvilTimer.DungeonSpawns[i].Delete(); + + for (int i = CannedEvilTimer.LLSpawns.Count - 1; i >= 0; i--) + CannedEvilTimer.LLSpawns[i].Delete(); + */ + + //We assume that all champion spawns are generated here. + List spawns = []; + foreach (Item item in World.Items.Values) { - CommandSystem.Register("GenChamps", AccessLevel.Developer, ChampGen_OnCommand); + if (item is ChampionSpawn spawn) + { + spawns.Add(spawn); + } } - private static readonly ChampionEntry[] LLLocations = { - new(typeof(LLChampionSpawn), new Point3D(5511, 2360, 42), Map.Felucca, new Point3D(5439, 2323, 26 ), Map.Felucca), - new(typeof(LLChampionSpawn), new Point3D(6038, 2401, 47), Map.Felucca, new Point3D(5988, 2340, 24), Map.Felucca), - new(typeof(LLChampionSpawn), new Point3D(5549, 2640, 16), Map.Felucca, new Point3D(5645, 2696, -8), Map.Felucca), - new(typeof(LLChampionSpawn), new Point3D(5636, 2916, 37), Map.Felucca, new Point3D(5721, 2949, 28), Map.Felucca), - new(typeof(LLChampionSpawn), new Point3D(6035, 2943, 50), Map.Felucca, new Point3D(6098, 2997, 17), Map.Felucca), - new(typeof(LLChampionSpawn), new Point3D(5265, 3171, 105), Map.Felucca, new Point3D(5314, 3232, 2), Map.Felucca), - new(typeof(LLChampionSpawn), new Point3D(5282, 3368, 50), Map.Felucca, new Point3D(5215, 3318, 3), Map.Felucca), - new(typeof(LLChampionSpawn), new Point3D(5207, 3637, 20), Map.Felucca, new Point3D(5263, 3687, 0), Map.Felucca), - new(typeof(LLChampionSpawn), new Point3D(5954, 3475, 25), Map.Felucca, new Point3D(6013, 3529, 0), Map.Felucca), - new(typeof(LLChampionSpawn), new Point3D(5982, 3882, 20), Map.Felucca, new Point3D(5929, 3820, -1), Map.Felucca), - new(typeof(LLChampionSpawn), new Point3D(5724, 3991, 41), Map.Felucca, new Point3D(5774, 4041, 26), Map.Felucca), - new(typeof(LLChampionSpawn), ChampionSpawnType.ForestLord, new Point3D(5559, 3757, 21), Map.Felucca, new Point3D(5513, 3878, 3), Map.Felucca), - }; - - private static readonly ChampionEntry[] DungeonLocations = { - new(typeof(DungeonChampionSpawn), ChampionSpawnType.UnholyTerror, new Point3D(5179, 709, 20), Map.Felucca, new Point3D(4111, 432, 5), Map.Felucca), - new(typeof(DungeonChampionSpawn), ChampionSpawnType.VerminHorde, new Point3D(5557, 827, 65), Map.Felucca, new Point3D(5580, 632, 30), Map.Felucca), - new(typeof(DungeonChampionSpawn), ChampionSpawnType.ColdBlood, new Point3D(5259, 837, 64), Map.Felucca, new Point3D(1176, 2637, 0), Map.Felucca), - new(typeof(DungeonChampionSpawn), ChampionSpawnType.Abyss, new Point3D(5815, 1352, 5), Map.Felucca, new Point3D(2923, 3406, 8), Map.Felucca), - new(typeof(DungeonChampionSpawn), ChampionSpawnType.Arachnid, new Point3D(5190, 1607, 20), Map.Felucca, new Point3D(5482, 3161, -54), Map.Felucca), - }; - - [Usage("GenChamps")] - [Description("Generates champions for Felucca Dungeons & Lost Lands.")] - private static void ChampGen_OnCommand(CommandEventArgs e) + for (int i = spawns.Count - 1; i >= 0; i--) { - /* - //We take the assumption that we are spawning managed champions - for (int i = CannedEvilTimer.DungeonSpawns.Count - 1; i >= 0; i--) - CannedEvilTimer.DungeonSpawns[i].Delete(); - - for (int i = CannedEvilTimer.LLSpawns.Count - 1; i >= 0; i--) - CannedEvilTimer.LLSpawns[i].Delete(); - */ - - //We assume that all champion spawns are generated here. - List spawns = new List(); - foreach (Item item in World.Items.Values) - { - if (item is ChampionSpawn spawn) - { - spawns.Add(spawn); - } - } - - for (int i = spawns.Count - 1; i >= 0; i--) - { - spawns[i].Delete(); - } - - Process(DungeonLocations); - Process(LLLocations); - //ProcessIlshenar(); - //ProcessTokuno(); + spawns[i].Delete(); } - private static void Process(ChampionEntry[] entries) - { - for (int i = 0; i < entries.Length; i++) - { - ChampionEntry entry = entries[i]; + Process(DungeonLocations); + Process(LLLocations); + //ProcessIlshenar(); + //ProcessTokuno(); + } - try + private static void Process(ChampionEntry[] entries) + { + for (int i = 0; i < entries.Length; i++) + { + ChampionEntry entry = entries[i]; + + try + { + if (Activator.CreateInstance(entry._champType) is ChampionSpawn spawn) { - if (Activator.CreateInstance(entry.m_ChampType) is ChampionSpawn spawn) + spawn.RandomizeType = entry._randomizeType; + spawn.Type = entry._type; + spawn.MoveToWorld(entry._signLocation, entry._map); + spawn.EjectLocation = entry._ejectLocation; + spawn.EjectMap = entry._ejectMap; + if (spawn.AlwaysActive) { - spawn.RandomizeType = entry.m_RandomizeType; - spawn.Type = entry.m_Type; - spawn.MoveToWorld(entry.m_SignLocation, entry.m_Map); - spawn.EjectLocation = entry.m_EjectLocation; - spawn.EjectMap = entry.m_EjectMap; - if (spawn.AlwaysActive) - { - spawn.ReadyToActivate = true; - } + spawn.ReadyToActivate = true; } } - catch (Exception e) - { - logger.Error( - e, - "Failed to generate champion \"{Type}\" at {Location} ({Map}).", - entry.m_ChampType.FullName, - entry.m_SignLocation, - entry.m_Map - ); - } + } + catch (Exception e) + { + logger.Error( + e, + "Failed to generate champion \"{Type}\" at {Location} ({Map}).", + entry._champType.FullName, + entry._signLocation, + entry._map + ); } } } diff --git a/Projects/UOContent/Engines/CannedEvil/LLChampionSpawn.cs b/Projects/UOContent/Engines/CannedEvil/LLChampionSpawn.cs index 17768f81e..d7cb89c4d 100644 --- a/Projects/UOContent/Engines/CannedEvil/LLChampionSpawn.cs +++ b/Projects/UOContent/Engines/CannedEvil/LLChampionSpawn.cs @@ -28,11 +28,6 @@ public partial class LLChampionSpawn : ChampionSpawn CannedEvilTimer.AddSpawn(this); } - public LLChampionSpawn(Serial serial) : base(serial) - { - CannedEvilTimer.AddSpawn(this); - } - public override bool AlwaysActive => false; public override void OnAfterDelete() @@ -40,4 +35,7 @@ public partial class LLChampionSpawn : ChampionSpawn base.OnAfterDelete(); CannedEvilTimer.RemoveSpawn(this); } + + [AfterDeserialization] + private void AfterDeserialization() => CannedEvilTimer.AddSpawn(this); }