diff --git a/Penumbra.GameData/Actors/ActorManager.Identifiers.cs b/Penumbra.GameData/Actors/ActorManager.Identifiers.cs index fbfe235e..49af09c1 100644 --- a/Penumbra.GameData/Actors/ActorManager.Identifiers.cs +++ b/Penumbra.GameData/Actors/ActorManager.Identifiers.cs @@ -109,8 +109,10 @@ public partial class ActorManager /// /// Compute an ActorIdentifier from a GameObject. If check is true, the values are checked for validity. /// - public unsafe ActorIdentifier FromObject(FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* actor, bool check = true) + public unsafe ActorIdentifier FromObject(FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* actor, + out FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* owner, bool check = true) { + owner = null; if (actor == null) return ActorIdentifier.Invalid; @@ -136,13 +138,13 @@ public partial class ActorManager var nameId = actor->DataID == 952 ? 780 : ((Character*)actor)->NameID; if (ownerId != 0xE0000000) { - var owner = (Character*)HandleCutscene( + owner = HandleCutscene( (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)(_objects.SearchById(ownerId)?.Address ?? IntPtr.Zero)); if (owner == null) return ActorIdentifier.Invalid; - var name = new ByteString(owner->GameObject.Name); - var homeWorld = owner->HomeWorld; + var name = new ByteString(owner->Name); + var homeWorld = ((Character*)owner)->HomeWorld; return check ? CreateOwned(name, homeWorld, ObjectKind.BattleNpc, nameId) : CreateIndividualUnchecked(IdentifierType.Owned, name, homeWorld, ObjectKind.BattleNpc, nameId); @@ -183,16 +185,18 @@ public partial class ActorManager case ObjectKind.Companion: case (ObjectKind)15: // TODO: CS Update { - var owner = (Character*)HandleCutscene( + owner = HandleCutscene( (FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)_objects.GetObjectAddress(actor->ObjectIndex - 1)); if (owner == null) return ActorIdentifier.Invalid; - var dataId = GetCompanionId(actor, &owner->GameObject); + var dataId = GetCompanionId(actor, owner); + var name = new ByteString(owner->Name); + var homeWorld = ((Character*)owner)->HomeWorld; + var kind = (ObjectKind)actor->ObjectKind; return check - ? CreateOwned(new ByteString(owner->GameObject.Name), owner->HomeWorld, (ObjectKind)actor->ObjectKind, dataId) - : CreateIndividualUnchecked(IdentifierType.Owned, new ByteString(owner->GameObject.Name), owner->HomeWorld, - (ObjectKind)actor->ObjectKind, dataId); + ? CreateOwned(name, homeWorld, kind, dataId) + : CreateIndividualUnchecked(IdentifierType.Owned, name, homeWorld, kind, dataId); } case ObjectKind.Retainer: { @@ -225,8 +229,12 @@ public partial class ActorManager }; } + public unsafe ActorIdentifier FromObject(GameObject? actor, out FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* owner, + bool check = true) + => FromObject((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)(actor?.Address ?? IntPtr.Zero), out owner, check); + public unsafe ActorIdentifier FromObject(GameObject? actor, bool check = true) - => FromObject((FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject*)(actor?.Address ?? IntPtr.Zero), check); + => FromObject(actor, out _, check); public ActorIdentifier CreateIndividual(IdentifierType type, ByteString name, ushort homeWorld, ObjectKind kind, uint dataId) => type switch diff --git a/Penumbra/Collections/IndividualCollections.Access.cs b/Penumbra/Collections/IndividualCollections.Access.cs index 142b9131..79561243 100644 --- a/Penumbra/Collections/IndividualCollections.Access.cs +++ b/Penumbra/Collections/IndividualCollections.Access.cs @@ -26,6 +26,12 @@ public sealed partial class IndividualCollections : IReadOnlyList< (string Displ public bool TryGetCollection( ActorIdentifier identifier, [NotNullWhen( true )] out ModCollection? collection, out ActorIdentifier specialIdentifier ) { specialIdentifier = ActorIdentifier.Invalid; + if( Count == 0 ) + { + collection = null; + return false; + } + switch( identifier.Type ) { case IdentifierType.Player: return CheckWorlds( identifier, out collection ); @@ -94,7 +100,7 @@ public sealed partial class IndividualCollections : IReadOnlyList< (string Displ => TryGetCollection( _actorManager.FromObject( gameObject, false ), out collection, out specialIdentifier ); public unsafe bool TryGetCollection( FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject* gameObject, out ModCollection? collection, out ActorIdentifier specialIdentifier ) - => TryGetCollection( _actorManager.FromObject( gameObject, false ), out collection, out specialIdentifier ); + => TryGetCollection( _actorManager.FromObject( gameObject, out _, false ), out collection, out specialIdentifier ); private bool CheckWorlds( ActorIdentifier identifier, out ModCollection? collection ) { diff --git a/Penumbra/Interop/Resolver/PathResolver.Identification.cs b/Penumbra/Interop/Resolver/PathResolver.Identification.cs index f1d704f1..973fad13 100644 --- a/Penumbra/Interop/Resolver/PathResolver.Identification.cs +++ b/Penumbra/Interop/Resolver/PathResolver.Identification.cs @@ -43,11 +43,11 @@ public unsafe partial class PathResolver } else { - var identifier = Penumbra.Actors.FromObject( gameObject, false ); + var identifier = Penumbra.Actors.FromObject( gameObject, out var owner, false ); var collection = CollectionByIdentifier( identifier, out var specialIdentifier ) ?? CheckYourself( identifier.Type == IdentifierType.Special ? specialIdentifier : identifier, gameObject ) ?? CollectionByAttributes( gameObject ) - ?? CheckOwnedCollection( identifier, gameObject ) + ?? CheckOwnedCollection( identifier, owner ) ?? Penumbra.CollectionManager.Default; return IdentifiedCache.Set( collection, identifier, gameObject ); } @@ -124,23 +124,9 @@ public unsafe partial class PathResolver } // Get the collection applying to the owner if it is available. - private static ModCollection? CheckOwnedCollection( ActorIdentifier identifier, GameObject* obj ) + private static ModCollection? CheckOwnedCollection( ActorIdentifier identifier, GameObject* owner ) { - if( identifier.Type != IdentifierType.Owned || !Penumbra.Config.UseOwnerNameForCharacterCollection ) - { - return null; - } - - var owner = identifier.Kind switch - { - ObjectKind.BattleNpc when obj->OwnerID != 0xE0000000 => ( GameObject* )( Dalamud.Objects.SearchById( obj->OwnerID )?.Address ?? IntPtr.Zero ), - ObjectKind.MountType when obj->ObjectIndex % 2 == 1 => ( GameObject* )Dalamud.Objects.GetObjectAddress( obj->ObjectIndex - 1 ), - ObjectKind.Companion when obj->ObjectIndex % 2 == 1 => ( GameObject* )Dalamud.Objects.GetObjectAddress( obj->ObjectIndex - 1 ), - ( ObjectKind )15 when obj->ObjectIndex % 2 == 1 => ( GameObject* )Dalamud.Objects.GetObjectAddress( obj->ObjectIndex - 1 ), // TODO: CS Update - _ => null, - }; - - if( owner == null ) + if( identifier.Type != IdentifierType.Owned || !Penumbra.Config.UseOwnerNameForCharacterCollection || owner == null ) { return null; }