From a6b3aab61a4d54644c7b06528aa204a3c4688c69 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sat, 3 Dec 2022 18:54:06 +0100 Subject: [PATCH] Add Mannequin-Handling for Retainer Individuals --- Penumbra.GameData/Actors/ActorManager.Data.cs | 20 ++++++++++++++++ .../Actors/ActorManager.Identifiers.cs | 23 ++++++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/Penumbra.GameData/Actors/ActorManager.Data.cs b/Penumbra.GameData/Actors/ActorManager.Data.cs index c54fafe4..3d962d0e 100644 --- a/Penumbra.GameData/Actors/ActorManager.Data.cs +++ b/Penumbra.GameData/Actors/ActorManager.Data.cs @@ -234,4 +234,24 @@ public sealed partial class ActorManager : IDisposable private static unsafe ushort InspectWorldId => *_inspectWorldId; + + public static readonly IReadOnlySet MannequinIds = new HashSet() + { + 1026228u, + 1026229u, + 1026986u, + 1026987u, + 1026988u, + 1026989u, + 1032291u, + 1032292u, + 1032293u, + 1032294u, + 1033046u, + 1033047u, + 1033658u, + 1033659u, + 1007137u, + // TODO: Female Hrothgar + }; } diff --git a/Penumbra.GameData/Actors/ActorManager.Identifiers.cs b/Penumbra.GameData/Actors/ActorManager.Identifiers.cs index 8b7ea937..a84f0e8f 100644 --- a/Penumbra.GameData/Actors/ActorManager.Identifiers.cs +++ b/Penumbra.GameData/Actors/ActorManager.Identifiers.cs @@ -76,7 +76,7 @@ public partial class ActorManager IdentifierType.Retainer => id.PlayerName.ToString(), IdentifierType.Owned => id.HomeWorld != _clientState.LocalPlayer?.HomeWorld.Id ? $"{id.PlayerName} ({Data.ToWorldName(id.HomeWorld)})'s {Data.ToName(id.Kind, id.DataId)}" - : $"{id.PlayerName}s {Data.ToName(id.Kind, id.DataId)}", + : $"{id.PlayerName}s {Data.ToName(id.Kind, id.DataId)}", IdentifierType.Special => id.Special.ToName(), IdentifierType.Npc => id.Index == ushort.MaxValue @@ -150,6 +150,23 @@ public partial class ActorManager // Special case for squadron that is also in the game functions, cf. E8 ?? ?? ?? ?? 89 87 ?? ?? ?? ?? 4C 89 BF if (dataId == 0xf845d) dataId = actor->GetNpcID(); + if (MannequinIds.Contains(dataId)) + { + static ByteString Get(byte* ptr) + => ptr == null ? ByteString.Empty : new ByteString(ptr); + + var actualName = Get(actor->GetName()); + var retainerName = Get(actor->Name); + if (!actualName.Equals(retainerName)) + { + var ident = check + ? CreateRetainer(retainerName) + : CreateIndividualUnchecked(IdentifierType.Retainer, retainerName, actor->ObjectIndex, ObjectKind.EventNpc, dataId); + if (ident.IsValid) + return ident; + } + } + return check ? CreateNpc(ObjectKind.EventNpc, dataId, actor->ObjectIndex) : CreateIndividualUnchecked(IdentifierType.Npc, ByteString.Empty, actor->ObjectIndex, ObjectKind.EventNpc, dataId); @@ -182,7 +199,7 @@ public partial class ActorManager { var name = new ByteString(actor->Name); var index = actor->ObjectIndex; - return CreateIndividualUnchecked(IdentifierType.UnkObject, name, index, ObjectKind.None, 0); + return CreateIndividualUnchecked(IdentifierType.UnkObject, name, index, ObjectKind.None, 0); } } } @@ -212,7 +229,7 @@ public partial class ActorManager IdentifierType.Retainer => CreateRetainer(name), IdentifierType.Owned => CreateOwned(name, homeWorld, kind, dataId), IdentifierType.Special => CreateSpecial((SpecialActor)homeWorld), - IdentifierType.Npc => CreateNpc(kind, dataId, homeWorld), + IdentifierType.Npc => CreateNpc(kind, dataId, homeWorld), IdentifierType.UnkObject => CreateIndividualUnchecked(IdentifierType.UnkObject, name, homeWorld, ObjectKind.None, 0), _ => ActorIdentifier.Invalid, };