From a47a14fe95f097e6116883ad3984ff1c8622c806 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Wed, 13 Jul 2022 18:16:04 +0200 Subject: [PATCH] Use correct collections on login screen. --- .../Interop/Resolver/PathResolver.Data.cs | 90 ++++++++++--------- Penumbra/UI/ConfigWindow.DebugTab.cs | 10 ++- 2 files changed, 58 insertions(+), 42 deletions(-) diff --git a/Penumbra/Interop/Resolver/PathResolver.Data.cs b/Penumbra/Interop/Resolver/PathResolver.Data.cs index e5ac64cd..84272421 100644 --- a/Penumbra/Interop/Resolver/PathResolver.Data.cs +++ b/Penumbra/Interop/Resolver/PathResolver.Data.cs @@ -11,6 +11,7 @@ using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Component.GUI; +using Lumina.Data.Parsing.Uld; using Penumbra.Api; using Penumbra.Collections; using Penumbra.GameData.ByteString; @@ -151,14 +152,11 @@ public unsafe partial class PathResolver // Check that a linked DrawObject still corresponds to the correct actor and that it still exists, otherwise remove it. private bool VerifyEntry( IntPtr drawObject, int gameObjectIdx, out GameObject* gameObject ) { - var tmp = Dalamud.Objects[ gameObjectIdx ]; - if( tmp != null ) + gameObject = ( GameObject* )Dalamud.Objects.GetObjectAddress( gameObjectIdx ); + var draw = ( DrawObject* )drawObject; + if( gameObject != null && gameObject->DrawObject == draw || gameObject->DrawObject == draw->Object.ParentObject ) { - gameObject = ( GameObject* )tmp.Address; - if( gameObject->DrawObject == ( DrawObject* )drawObject ) - { - return true; - } + return true; } gameObject = null; @@ -294,45 +292,56 @@ public unsafe partial class PathResolver try { - // Housing Retainers - if( Penumbra.Config.UseDefaultCollectionForRetainers - && gameObject->ObjectKind == ( byte )ObjectKind.EventNpc - && gameObject->DataID is 1011832 or 1011021 ) // cf. "E8 ?? ?? ?? ?? 0F B6 F8 88 45", male or female retainer + // Login screen. Names are populated after actors are drawn, + // so it is not possible to fetch names from the ui list. + // Actors are also not named. So use Yourself > Players > Racial > Default. + if( !Dalamud.ClientState.IsLoggedIn ) { - return Penumbra.CollectionManager.Default; + return Penumbra.CollectionManager.ByType( CollectionType.Yourself ) + ?? ( CollectionByActor( string.Empty, gameObject, out var c ) ? c : Penumbra.CollectionManager.Default ); } - - string? actorName = null; - if( Penumbra.Config.PreferNamedCollectionsOverOwners ) + else { - // Early return if we prefer the actors own name over its owner. - actorName = new Utf8String( gameObject->Name ).ToString(); - if( actorName.Length > 0 - && CollectionByActorName( actorName, out var actorCollection ) ) + // Housing Retainers + if( Penumbra.Config.UseDefaultCollectionForRetainers + && gameObject->ObjectKind == ( byte )ObjectKind.EventNpc + && gameObject->DataID is 1011832 or 1011021 ) // cf. "E8 ?? ?? ?? ?? 0F B6 F8 88 45", male or female retainer { - return actorCollection; + return Penumbra.CollectionManager.Default; } - } - // All these special cases are relevant for an empty name, so never collide with the above setting. - // Only OwnerName can be applied to something with a non-empty name, and that is the specific case we want to handle. - var actualName = gameObject->ObjectIndex switch + string? actorName = null; + if( Penumbra.Config.PreferNamedCollectionsOverOwners ) { - 240 => Penumbra.Config.UseCharacterCollectionInMainWindow ? GetPlayerName() : null, // character window - 241 => GetInspectName() ?? GetCardName() ?? GetGlamourName(), // inspect, character card, glamour plate editor. - 242 => Penumbra.Config.UseCharacterCollectionInTryOn ? GetPlayerName() : null, // try-on - 243 => Penumbra.Config.UseCharacterCollectionInTryOn ? GetPlayerName() : null, // dye preview - >= 200 => GetCutsceneName( gameObject ), - _ => null, + // Early return if we prefer the actors own name over its owner. + actorName = new Utf8String( gameObject->Name ).ToString(); + if( actorName.Length > 0 + && CollectionByActorName( actorName, out var actorCollection ) ) + { + return actorCollection; + } } - ?? GetOwnerName( gameObject ) ?? actorName ?? new Utf8String( gameObject->Name ).ToString(); - // First check temporary character collections, then the own configuration, then special collections. - return CollectionByActorName( actualName, out var c ) - ? c - : CollectionByActor( actualName, gameObject, out c ) + // All these special cases are relevant for an empty name, so never collide with the above setting. + // Only OwnerName can be applied to something with a non-empty name, and that is the specific case we want to handle. + var actualName = gameObject->ObjectIndex switch + { + 240 => Penumbra.Config.UseCharacterCollectionInMainWindow ? GetPlayerName() : null, // character window + 241 => GetInspectName() ?? GetCardName() ?? GetGlamourName(), // inspect, character card, glamour plate editor. + 242 => Penumbra.Config.UseCharacterCollectionInTryOn ? GetPlayerName() : null, // try-on + 243 => Penumbra.Config.UseCharacterCollectionInTryOn ? GetPlayerName() : null, // dye preview + >= 200 => GetCutsceneName( gameObject ), + _ => null, + } + ?? GetOwnerName( gameObject ) ?? actorName ?? new Utf8String( gameObject->Name ).ToString(); + + // First check temporary character collections, then the own configuration, then special collections. + return CollectionByActorName( actualName, out var c ) ? c - : Penumbra.CollectionManager.Default; + : CollectionByActor( actualName, gameObject, out c ) + ? c + : Penumbra.CollectionManager.Default; + } } catch( Exception e ) { @@ -459,7 +468,7 @@ public unsafe partial class PathResolver // Update collections linked to Game/DrawObjects due to a change in collection configuration. private void CheckCollections( CollectionType type, ModCollection? _1, ModCollection? _2, string? name ) { - if( type is not (CollectionType.Character or CollectionType.Default) ) + if( type is CollectionType.Inactive or CollectionType.Current ) { return; } @@ -515,12 +524,13 @@ public unsafe partial class PathResolver } // Find all current DrawObjects used in the GameObject table. + // We do not iterate the Dalamud table because it does not work when not logged in. private void InitializeDrawObjects() { - foreach( var gameObject in Dalamud.Objects ) + for( var i = 0; i < Dalamud.Objects.Length; ++i ) { - var ptr = ( GameObject* )gameObject.Address; - if( ptr->IsCharacter() && ptr->DrawObject != null ) + var ptr = ( GameObject* )Dalamud.Objects.GetObjectAddress( i ); + if( ptr != null && ptr->IsCharacter() && ptr->DrawObject != null ) { DrawObjectToObject[ ( IntPtr )ptr->DrawObject ] = ( IdentifyCollection( ptr ), ptr->ObjectIndex ); } diff --git a/Penumbra/UI/ConfigWindow.DebugTab.cs b/Penumbra/UI/ConfigWindow.DebugTab.cs index f7a3d53b..62d136ff 100644 --- a/Penumbra/UI/ConfigWindow.DebugTab.cs +++ b/Penumbra/UI/ConfigWindow.DebugTab.cs @@ -3,11 +3,13 @@ using System.IO; using System.Linq; using System.Numerics; using FFXIVClientStructs.FFXIV.Client.Game.Character; +using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.System.Resource; using ImGuiNET; using OtterGui; using OtterGui.Raii; +using Penumbra.GameData.ByteString; using Penumbra.Interop.Loader; using Penumbra.Interop.Structs; using CharacterUtility = Penumbra.Interop.CharacterUtility; @@ -166,9 +168,12 @@ public partial class ConfigWindow ImGui.TableNextColumn(); ImGui.TextUnformatted( idx.ToString() ); ImGui.TableNextColumn(); - ImGui.TextUnformatted( Dalamud.Objects[ idx ]?.Address.ToString() ?? "NULL" ); + var obj = ( GameObject* )Dalamud.Objects.GetObjectAddress( idx ); + var (address, name) = + obj != null ? ( $"0x{( ulong )obj:X}", new Utf8String( obj->Name ).ToString() ) : ( "NULL", "NULL" ); + ImGui.TextUnformatted( address ); ImGui.TableNextColumn(); - ImGui.TextUnformatted( Dalamud.Objects[ idx ]?.Name.ToString() ?? "NULL" ); + ImGui.TextUnformatted( name ); ImGui.TableNextColumn(); ImGui.TextUnformatted( c.Name ); } @@ -399,6 +404,7 @@ public partial class ConfigWindow { return; } + _window._penumbra.Ipc.Tester.Draw(); }