Skip to content

Commit

Permalink
refactor: make player serv thread safe
Browse files Browse the repository at this point in the history
  • Loading branch information
kalilistic committed Nov 1, 2023
1 parent 94d2344 commit a249a99
Showing 1 changed file with 90 additions and 58 deletions.
148 changes: 90 additions & 58 deletions Dalamud.DrunkenToad/Core/Services/Custom/PlayerEventDispatcher.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -9,11 +11,12 @@
/// <summary>
/// Manages player character events, including addition, removal, and updates.
/// </summary>
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 ();

/// <summary>
/// Initializes a new instance of the <see cref="PlayerEventDispatcher" /> class.
Expand Down Expand Up @@ -66,18 +69,26 @@ public PlayerEventDispatcher(IFramework gameFramework, IObjectTable objectCollec
/// <returns>player if exists.</returns>
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();
}
}

/// <summary>
Expand All @@ -88,24 +99,37 @@ public PlayerEventDispatcher(IFramework gameFramework, IObjectTable objectCollec
/// <returns>player if exists.</returns>
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();
}
}

/// <summary>
/// Dispose manager.
/// </summary>
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 ()
{
Expand All @@ -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<ToadPlayer>();
var removedPlayers = new List<uint>();

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<ToadPlayer>();
var removedPlayers = new List<uint>();

// 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();
}
}
}

0 comments on commit a249a99

Please sign in to comment.