tighten the check
This commit is contained in:
@@ -6,6 +6,7 @@ using FFXIVClientStructs.Interop;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using LightlessSync.PlayerData.Handlers;
|
||||
using LightlessSync.Services.Mediator;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -16,7 +17,7 @@ using LightlessObjectKind = LightlessSync.API.Data.Enum.ObjectKind;
|
||||
|
||||
namespace LightlessSync.Services.ActorTracking;
|
||||
|
||||
public sealed class ActorObjectService : IHostedService, IDisposable
|
||||
public sealed class ActorObjectService : IHostedService, IDisposable, IMediatorSubscriber
|
||||
{
|
||||
public readonly record struct ActorDescriptor(
|
||||
string Name,
|
||||
@@ -36,6 +37,8 @@ public sealed class ActorObjectService : IHostedService, IDisposable
|
||||
private readonly IClientState _clientState;
|
||||
private readonly ICondition _condition;
|
||||
private readonly LightlessMediator _mediator;
|
||||
private readonly object _playerRelatedHandlerLock = new();
|
||||
private readonly HashSet<GameObjectHandler> _playerRelatedHandlers = [];
|
||||
|
||||
private readonly ConcurrentDictionary<nint, ActorDescriptor> _activePlayers = new();
|
||||
private readonly ConcurrentDictionary<nint, ActorDescriptor> _gposePlayers = new();
|
||||
@@ -71,6 +74,25 @@ public sealed class ActorObjectService : IHostedService, IDisposable
|
||||
_clientState = clientState;
|
||||
_condition = condition;
|
||||
_mediator = mediator;
|
||||
|
||||
_mediator.Subscribe<GameObjectHandlerCreatedMessage>(this, (msg) =>
|
||||
{
|
||||
if (!msg.OwnedObject) return;
|
||||
lock (_playerRelatedHandlerLock)
|
||||
{
|
||||
_playerRelatedHandlers.Add(msg.GameObjectHandler);
|
||||
}
|
||||
RefreshTrackedActors(force: true);
|
||||
});
|
||||
_mediator.Subscribe<GameObjectHandlerDestroyedMessage>(this, (msg) =>
|
||||
{
|
||||
if (!msg.OwnedObject) return;
|
||||
lock (_playerRelatedHandlerLock)
|
||||
{
|
||||
_playerRelatedHandlers.Remove(msg.GameObjectHandler);
|
||||
}
|
||||
RefreshTrackedActors(force: true);
|
||||
});
|
||||
}
|
||||
|
||||
private bool IsZoning => _condition[ConditionFlag.BetweenAreas] || _condition[ConditionFlag.BetweenAreas51];
|
||||
@@ -84,6 +106,7 @@ public sealed class ActorObjectService : IHostedService, IDisposable
|
||||
public IReadOnlyList<ActorDescriptor> PlayerDescriptors => Snapshot.PlayerDescriptors;
|
||||
public IReadOnlyList<ActorDescriptor> OwnedDescriptors => Snapshot.OwnedDescriptors;
|
||||
public IReadOnlyList<ActorDescriptor> GposeDescriptors => CurrentGposeSnapshot.GposeDescriptors;
|
||||
public LightlessMediator Mediator => _mediator;
|
||||
|
||||
public bool TryGetActorByHash(string hash, out ActorDescriptor descriptor) => _actorsByHash.TryGetValue(hash, out descriptor);
|
||||
public bool TryGetValidatedActorByHash(string hash, out ActorDescriptor descriptor)
|
||||
@@ -324,6 +347,11 @@ public sealed class ActorObjectService : IHostedService, IDisposable
|
||||
_actorsByHash.Clear();
|
||||
_actorsByName.Clear();
|
||||
_pendingHashResolutions.Clear();
|
||||
_mediator.UnsubscribeAll(this);
|
||||
lock (_playerRelatedHandlerLock)
|
||||
{
|
||||
_playerRelatedHandlers.Clear();
|
||||
}
|
||||
Volatile.Write(ref _snapshot, ActorSnapshot.Empty);
|
||||
Volatile.Write(ref _gposeSnapshot, GposeSnapshot.Empty);
|
||||
return Task.CompletedTask;
|
||||
@@ -500,7 +528,9 @@ public sealed class ActorObjectService : IHostedService, IDisposable
|
||||
if (objectKind is DalamudObjectKind.MountType or DalamudObjectKind.Companion)
|
||||
{
|
||||
var expectedMinionOrMount = GetMinionOrMountAddress(localPlayerAddress, localEntityId);
|
||||
if (expectedMinionOrMount != nint.Zero && (nint)gameObject == expectedMinionOrMount)
|
||||
if (expectedMinionOrMount != nint.Zero
|
||||
&& (nint)gameObject == expectedMinionOrMount
|
||||
&& IsPlayerRelatedOwnedAddress(expectedMinionOrMount, LightlessObjectKind.MinionOrMount))
|
||||
{
|
||||
var resolvedOwner = ownerId != 0 ? ownerId : localEntityId;
|
||||
return (LightlessObjectKind.MinionOrMount, resolvedOwner);
|
||||
@@ -514,16 +544,37 @@ public sealed class ActorObjectService : IHostedService, IDisposable
|
||||
return (null, ownerId);
|
||||
|
||||
var expectedPet = GetPetAddress(localPlayerAddress, localEntityId);
|
||||
if (expectedPet != nint.Zero && (nint)gameObject == expectedPet)
|
||||
if (expectedPet != nint.Zero
|
||||
&& (nint)gameObject == expectedPet
|
||||
&& IsPlayerRelatedOwnedAddress(expectedPet, LightlessObjectKind.Pet))
|
||||
return (LightlessObjectKind.Pet, ownerId);
|
||||
|
||||
var expectedCompanion = GetCompanionAddress(localPlayerAddress, localEntityId);
|
||||
if (expectedCompanion != nint.Zero && (nint)gameObject == expectedCompanion)
|
||||
if (expectedCompanion != nint.Zero
|
||||
&& (nint)gameObject == expectedCompanion
|
||||
&& IsPlayerRelatedOwnedAddress(expectedCompanion, LightlessObjectKind.Companion))
|
||||
return (LightlessObjectKind.Companion, ownerId);
|
||||
|
||||
return (null, ownerId);
|
||||
}
|
||||
|
||||
private bool IsPlayerRelatedOwnedAddress(nint address, LightlessObjectKind expectedKind)
|
||||
{
|
||||
if (address == nint.Zero)
|
||||
return false;
|
||||
|
||||
lock (_playerRelatedHandlerLock)
|
||||
{
|
||||
foreach (var handler in _playerRelatedHandlers)
|
||||
{
|
||||
if (handler.Address == address && handler.ObjectKind == expectedKind)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private unsafe nint GetMinionOrMountAddress(nint localPlayerAddress, uint ownerEntityId)
|
||||
{
|
||||
if (localPlayerAddress == nint.Zero)
|
||||
@@ -531,20 +582,20 @@ public sealed class ActorObjectService : IHostedService, IDisposable
|
||||
|
||||
var playerObject = (GameObject*)localPlayerAddress;
|
||||
var candidateAddress = _objectTable.GetObjectAddress(playerObject->ObjectIndex + 1);
|
||||
if (ownerEntityId == 0)
|
||||
return nint.Zero;
|
||||
|
||||
if (candidateAddress != nint.Zero)
|
||||
{
|
||||
var candidate = (GameObject*)candidateAddress;
|
||||
var candidateKind = (DalamudObjectKind)candidate->ObjectKind;
|
||||
if (candidateKind is DalamudObjectKind.MountType or DalamudObjectKind.Companion)
|
||||
{
|
||||
if (ownerEntityId == 0 || ResolveOwnerId(candidate) == ownerEntityId)
|
||||
if (ResolveOwnerId(candidate) == ownerEntityId)
|
||||
return candidateAddress;
|
||||
}
|
||||
}
|
||||
|
||||
if (ownerEntityId == 0)
|
||||
return candidateAddress;
|
||||
|
||||
foreach (var obj in _objectTable)
|
||||
{
|
||||
if (obj is null || obj.Address == nint.Zero || obj.Address == localPlayerAddress)
|
||||
@@ -558,7 +609,7 @@ public sealed class ActorObjectService : IHostedService, IDisposable
|
||||
return obj.Address;
|
||||
}
|
||||
|
||||
return candidateAddress;
|
||||
return nint.Zero;
|
||||
}
|
||||
|
||||
private unsafe nint GetPetAddress(nint localPlayerAddress, uint ownerEntityId)
|
||||
@@ -1029,6 +1080,7 @@ public sealed class ActorObjectService : IHostedService, IDisposable
|
||||
public void Dispose()
|
||||
{
|
||||
DisposeHooks();
|
||||
_mediator.UnsubscribeAll(this);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user