From 123ed256b129cf22b001f0920dbaccbddaaea2c1 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Mon, 16 Jan 2023 13:03:26 +0100 Subject: [PATCH] Try to resolve banner players better. --- Penumbra.GameData/Actors/ActorManager.Data.cs | 107 +++++++++++++++++- .../IndividualCollections.Access.cs | 7 ++ .../Resolver/PathResolver.Identification.cs | 16 ++- 3 files changed, 119 insertions(+), 11 deletions(-) diff --git a/Penumbra.GameData/Actors/ActorManager.Data.cs b/Penumbra.GameData/Actors/ActorManager.Data.cs index 9828fe5f..97655e16 100644 --- a/Penumbra.GameData/Actors/ActorManager.Data.cs +++ b/Penumbra.GameData/Actors/ActorManager.Data.cs @@ -5,20 +5,22 @@ using System.Linq; using System.Text; using Dalamud; using Dalamud.Data; -using Dalamud.Game; using Dalamud.Game.ClientState; using Dalamud.Game.ClientState.Objects; -using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.Gui; using Dalamud.Plugin; using Dalamud.Utility; using Dalamud.Utility.Signatures; +using FFXIVClientStructs.FFXIV.Client.Game.Group; +using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.UI.Agent; using Lumina.Excel.GeneratedSheets; using Lumina.Text; using Penumbra.GameData.Data; +using Penumbra.GameData.Structs; using Penumbra.String; using Character = FFXIVClientStructs.FFXIV.Client.Game.Character.Character; +using ObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind; namespace Penumbra.GameData.Actors; @@ -198,6 +200,107 @@ public sealed partial class ActorManager : IDisposable return CreatePlayer(InspectName, InspectWorldId); } + public unsafe bool ResolvePartyBannerPlayer(ScreenActor type, out ActorIdentifier id) + { + id = ActorIdentifier.Invalid; + var addon = _gameGui.GetAddonByName("BannerParty"); + if (addon == IntPtr.Zero) + return false; + + var idx = (ushort)type - (ushort)ScreenActor.CharacterScreen; + if (idx is < 0 or > 7) + return true; + + if (idx == 0) + { + id = GetCurrentPlayer(); + return true; + } + + var obj = GroupManager.Instance()->GetPartyMemberByIndex(idx - 1); + if (obj != null) + id = CreatePlayer(new ByteString(obj->Name), obj->HomeWorld); + + return true; + } + + private unsafe bool SearchPlayerCustomize(Character* character, int idx, out ActorIdentifier id) + { + var other = (Character*)_objects.GetObjectAddress(idx); + if (other == null || !CustomizeData.Equals((CustomizeData*)character->CustomizeData, (CustomizeData*)other->CustomizeData)) + { + id = ActorIdentifier.Invalid; + return false; + } + + id = FromObject(&other->GameObject, out _, false, true); + return true; + } + + private unsafe ActorIdentifier SearchPlayersCustomize(Character* gameObject, int idx1, int idx2, int idx3) + => SearchPlayerCustomize(gameObject, idx1, out var ret) + || SearchPlayerCustomize(gameObject, idx2, out ret) + || SearchPlayerCustomize(gameObject, idx3, out ret) + ? ret + : ActorIdentifier.Invalid; + + private unsafe ActorIdentifier SearchPlayersCustomize(Character* gameObject) + { + for (var i = 0; i < (int)ScreenActor.CutsceneStart; i += 2) + { + var obj = (GameObject*)_objects.GetObjectAddress(i); + if (obj != null + && obj->ObjectKind is (byte)ObjectKind.Player + && !CustomizeData.Equals((CustomizeData*)gameObject->CustomizeData, (CustomizeData*)((Character*)obj)->CustomizeData)) + return FromObject(obj, out _, false, true); + } + return ActorIdentifier.Invalid; + } + + public unsafe bool ResolveMahjongPlayer(ScreenActor type, out ActorIdentifier id) + { + id = ActorIdentifier.Invalid; + if (_clientState.TerritoryType != 831 && _gameGui.GetAddonByName("EmjIntro") == IntPtr.Zero) + return false; + + var obj = (Character*)_objects.GetObjectAddress((int)type); + if (obj == null) + return false; + + id = type switch + { + ScreenActor.CharacterScreen => GetCurrentPlayer(), + ScreenActor.ExamineScreen => SearchPlayersCustomize(obj, 2, 4, 6), + ScreenActor.FittingRoom => SearchPlayersCustomize(obj, 4, 2, 6), + ScreenActor.DyePreview => SearchPlayersCustomize(obj, 6, 2, 4), + _ => ActorIdentifier.Invalid, + }; + return true; + } + + public unsafe bool ResolvePvPBannerPlayer(ScreenActor type, out ActorIdentifier id) + { + id = ActorIdentifier.Invalid; + var addon = _gameGui.GetAddonByName("PvPMKSIntroduction"); + if (addon == IntPtr.Zero) + return false; + + var obj = (Character*)_objects.GetObjectAddress((int)type); + if (obj == null) + return false; + + var identifier = type switch + { + ScreenActor.CharacterScreen => SearchPlayersCustomize(obj), + ScreenActor.ExamineScreen => SearchPlayersCustomize(obj), + ScreenActor.FittingRoom => SearchPlayersCustomize(obj), + ScreenActor.DyePreview => SearchPlayersCustomize(obj), + ScreenActor.Portrait => SearchPlayersCustomize(obj), + _ => ActorIdentifier.Invalid, + }; + return true; + } + public unsafe ActorIdentifier GetCardPlayer() { var agent = AgentCharaCard.Instance(); diff --git a/Penumbra/Collections/IndividualCollections.Access.cs b/Penumbra/Collections/IndividualCollections.Access.cs index 0d96fc62..73e06fef 100644 --- a/Penumbra/Collections/IndividualCollections.Access.cs +++ b/Penumbra/Collections/IndividualCollections.Access.cs @@ -86,6 +86,13 @@ public sealed partial class IndividualCollections : IReadOnlyList< (string Displ return identifier; } + if( _actorManager.ResolvePartyBannerPlayer( identifier.Special, out var id ) + || _actorManager.ResolvePvPBannerPlayer( identifier.Special, out id ) + || _actorManager.ResolveMahjongPlayer( identifier.Special, out id ) ) + { + return identifier; + } + switch( identifier.Special ) { case ScreenActor.CharacterScreen when Penumbra.Config.UseCharacterCollectionInMainWindow: diff --git a/Penumbra/Interop/Resolver/PathResolver.Identification.cs b/Penumbra/Interop/Resolver/PathResolver.Identification.cs index 404f6c90..abf85749 100644 --- a/Penumbra/Interop/Resolver/PathResolver.Identification.cs +++ b/Penumbra/Interop/Resolver/PathResolver.Identification.cs @@ -88,12 +88,6 @@ public unsafe partial class PathResolver return IdentifiedCache.Set( collection2, ActorIdentifier.Invalid, gameObject ); } - // Mahjong special case. - if( Dalamud.ClientState.TerritoryType == 831 ) - { - return IdentifyMahjong( gameObject ); - } - // Aesthetician. The relevant actor is yourself, so use player collection when possible. if( Dalamud.GameGui.GetAddonByName( "ScreenLog", 1 ) == IntPtr.Zero ) { @@ -106,12 +100,16 @@ public unsafe partial class PathResolver } var identifier = Penumbra.Actors.FromObject( gameObject, out var owner, true, false ); - if( Penumbra.Config.UseNoModsInInspect && identifier.Type == IdentifierType.Special && identifier.Special == ScreenActor.ExamineScreen ) + if( identifier.Type is IdentifierType.Special ) { - return IdentifiedCache.Set( ModCollection.Empty, identifier, gameObject ); + if( Penumbra.Config.UseNoModsInInspect && identifier.Special == ScreenActor.ExamineScreen ) + { + return IdentifiedCache.Set( ModCollection.Empty, identifier, gameObject ); + } + + identifier = Penumbra.CollectionManager.Individuals.ConvertSpecialIdentifier( identifier ); } - identifier = Penumbra.CollectionManager.Individuals.ConvertSpecialIdentifier( identifier ); var collection = CollectionByIdentifier( identifier ) ?? CheckYourself( identifier, gameObject ) ?? CollectionByAttributes( gameObject )