diff --git a/Dalamud.DrunkenToad/Core/Services/Custom/PlayerEventDispatcher.cs b/Dalamud.DrunkenToad/Core/Services/Custom/PlayerEventDispatcher.cs index e8aafe3..41e295f 100644 --- a/Dalamud.DrunkenToad/Core/Services/Custom/PlayerEventDispatcher.cs +++ b/Dalamud.DrunkenToad/Core/Services/Custom/PlayerEventDispatcher.cs @@ -1,6 +1,8 @@ namespace Dalamud.DrunkenToad.Core.Services; +using System; using System.Collections.Generic; +using System.Threading; using Extensions; using Game.ClientState.Objects.SubKinds; using Models; @@ -9,11 +11,12 @@ /// /// Manages player character events, including addition, removal, and updates. /// -public class PlayerEventDispatcher +public class PlayerEventDispatcher : IDisposable { private readonly uint[] existingObjectIds = new uint[100]; private readonly IFramework gameFramework; private readonly IObjectTable objectCollection; + private readonly ReaderWriterLockSlim locker = new (); /// /// Initializes a new instance of the class. @@ -66,18 +69,26 @@ public PlayerEventDispatcher(IFramework gameFramework, IObjectTable objectCollec /// player if exists. public ToadPlayer? GetPlayerById(uint id) { - for (var i = 0; i < this.existingObjectIds.Length; i++) + this.locker.EnterReadLock(); + try { - if (this.existingObjectIds[i] == id) + for (var i = 0; i < this.existingObjectIds.Length; i++) { - if (this.objectCollection[i * 2] is PlayerCharacter playerCharacter) + if (this.existingObjectIds[i] == id) { - return MapToadPlayer(playerCharacter); + if (this.objectCollection[i * 2] is PlayerCharacter playerCharacter) + { + return MapToadPlayer(playerCharacter); + } } } - } - return null; + return null; + } + finally + { + this.locker.ExitReadLock(); + } } /// @@ -88,24 +99,37 @@ public PlayerEventDispatcher(IFramework gameFramework, IObjectTable objectCollec /// player if exists. public ToadPlayer? GetPlayerByNameAndWorldId(string name, uint worldId) { - foreach (var gameObject in this.objectCollection) + this.locker.EnterReadLock(); + try { - if (gameObject is PlayerCharacter playerCharacter) + foreach (var gameObject in this.objectCollection) { - if (playerCharacter.Name.ToString().Equals(name, System.StringComparison.Ordinal) && playerCharacter.HomeWorld.Id == worldId) + if (gameObject is PlayerCharacter playerCharacter) { - return MapToadPlayer(playerCharacter); + if (playerCharacter.Name.ToString().Equals(name, StringComparison.Ordinal) && playerCharacter.HomeWorld.Id == worldId) + { + return MapToadPlayer(playerCharacter); + } } } - } - return null; + return null; + } + finally + { + this.locker.ExitReadLock(); + } } /// /// Dispose manager. /// - public void Dispose() => this.gameFramework.Update -= this.OnFrameworkUpdate; + public void Dispose() + { + GC.SuppressFinalize(this); + this.gameFramework.Update -= this.OnFrameworkUpdate; + this.locker.Dispose(); + } private static ToadPlayer MapToadPlayer(PlayerCharacter character) => new () { @@ -120,67 +144,75 @@ public PlayerEventDispatcher(IFramework gameFramework, IObjectTable objectCollec IsDead = character.IsDead, }; - private void OnFrameworkUpdate(IFramework framework1) + private void OnFrameworkUpdate(IFramework framework) { - var addedPlayers = new List(); - var removedPlayers = new List(); - - for (var i = 2; i < 200; i += 2) + this.locker.EnterWriteLock(); + try { - var index = i / 2; - var currentObjectId = this.objectCollection[i]?.ObjectId ?? 0; - var existingId = this.existingObjectIds[index]; + var addedPlayers = new List(); + var removedPlayers = new List(); - // check if same - if (currentObjectId == existingId) + for (var i = 2; i < 200; i += 2) { - continue; - } + var index = i / 2; + var currentObjectId = this.objectCollection[i]?.ObjectId ?? 0; + var existingId = this.existingObjectIds[index]; - // check if removed - if (this.objectCollection[i] == null) - { - if (existingId != 0) + // check if same + if (currentObjectId == existingId) { - removedPlayers.Add(existingId); - this.existingObjectIds[i / 2] = 0; + continue; } - continue; - } + // check if removed + if (this.objectCollection[i] == null) + { + if (existingId != 0) + { + removedPlayers.Add(existingId); + this.existingObjectIds[i / 2] = 0; + } - PlayerCharacter character; - if (this.objectCollection[i].IsValidPlayerCharacter()) - { - character = (this.objectCollection[i] as PlayerCharacter) !; - } - else - { - continue; - } + continue; + } - // check if new - if (existingId == 0) - { + PlayerCharacter character; + if (this.objectCollection[i].IsValidPlayerCharacter()) + { + character = (this.objectCollection[i] as PlayerCharacter) !; + } + else + { + continue; + } + + // check if new + if (existingId == 0) + { + addedPlayers.Add(MapToadPlayer(character)); + this.existingObjectIds[i / 2] = currentObjectId; + continue; + } + + // otherwise replaced + removedPlayers.Add(existingId); addedPlayers.Add(MapToadPlayer(character)); this.existingObjectIds[i / 2] = currentObjectId; - continue; } - // otherwise replaced - removedPlayers.Add(existingId); - addedPlayers.Add(MapToadPlayer(character)); - this.existingObjectIds[i / 2] = currentObjectId; - } + if (removedPlayers.Count > 0) + { + this.RemovePlayers?.Invoke(removedPlayers); + } - if (removedPlayers.Count > 0) - { - this.RemovePlayers?.Invoke(removedPlayers); + if (addedPlayers.Count > 0) + { + this.AddPlayers?.Invoke(addedPlayers); + } } - - if (addedPlayers.Count > 0) + finally { - this.AddPlayers?.Invoke(addedPlayers); + this.locker.ExitWriteLock(); } } }