Use correct collections on login screen.

This commit is contained in:
Ottermandias 2022-07-13 18:16:04 +02:00
parent be2260dc51
commit a47a14fe95
2 changed files with 58 additions and 42 deletions

View file

@ -11,6 +11,7 @@ using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Client.UI;
using FFXIVClientStructs.FFXIV.Component.GUI; using FFXIVClientStructs.FFXIV.Component.GUI;
using Lumina.Data.Parsing.Uld;
using Penumbra.Api; using Penumbra.Api;
using Penumbra.Collections; using Penumbra.Collections;
using Penumbra.GameData.ByteString; 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. // 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 ) private bool VerifyEntry( IntPtr drawObject, int gameObjectIdx, out GameObject* gameObject )
{ {
var tmp = Dalamud.Objects[ gameObjectIdx ]; gameObject = ( GameObject* )Dalamud.Objects.GetObjectAddress( gameObjectIdx );
if( tmp != null ) var draw = ( DrawObject* )drawObject;
if( gameObject != null && gameObject->DrawObject == draw || gameObject->DrawObject == draw->Object.ParentObject )
{ {
gameObject = ( GameObject* )tmp.Address; return true;
if( gameObject->DrawObject == ( DrawObject* )drawObject )
{
return true;
}
} }
gameObject = null; gameObject = null;
@ -294,45 +292,56 @@ public unsafe partial class PathResolver
try try
{ {
// Housing Retainers // Login screen. Names are populated after actors are drawn,
if( Penumbra.Config.UseDefaultCollectionForRetainers // so it is not possible to fetch names from the ui list.
&& gameObject->ObjectKind == ( byte )ObjectKind.EventNpc // Actors are also not named. So use Yourself > Players > Racial > Default.
&& gameObject->DataID is 1011832 or 1011021 ) // cf. "E8 ?? ?? ?? ?? 0F B6 F8 88 45", male or female retainer 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 );
} }
else
string? actorName = null;
if( Penumbra.Config.PreferNamedCollectionsOverOwners )
{ {
// Early return if we prefer the actors own name over its owner. // Housing Retainers
actorName = new Utf8String( gameObject->Name ).ToString(); if( Penumbra.Config.UseDefaultCollectionForRetainers
if( actorName.Length > 0 && gameObject->ObjectKind == ( byte )ObjectKind.EventNpc
&& CollectionByActorName( actorName, out var actorCollection ) ) && 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. string? actorName = null;
// Only OwnerName can be applied to something with a non-empty name, and that is the specific case we want to handle. if( Penumbra.Config.PreferNamedCollectionsOverOwners )
var actualName = gameObject->ObjectIndex switch
{ {
240 => Penumbra.Config.UseCharacterCollectionInMainWindow ? GetPlayerName() : null, // character window // Early return if we prefer the actors own name over its owner.
241 => GetInspectName() ?? GetCardName() ?? GetGlamourName(), // inspect, character card, glamour plate editor. actorName = new Utf8String( gameObject->Name ).ToString();
242 => Penumbra.Config.UseCharacterCollectionInTryOn ? GetPlayerName() : null, // try-on if( actorName.Length > 0
243 => Penumbra.Config.UseCharacterCollectionInTryOn ? GetPlayerName() : null, // dye preview && CollectionByActorName( actorName, out var actorCollection ) )
>= 200 => GetCutsceneName( gameObject ), {
_ => null, return actorCollection;
}
} }
?? GetOwnerName( gameObject ) ?? actorName ?? new Utf8String( gameObject->Name ).ToString();
// First check temporary character collections, then the own configuration, then special collections. // All these special cases are relevant for an empty name, so never collide with the above setting.
return CollectionByActorName( actualName, out var c ) // Only OwnerName can be applied to something with a non-empty name, and that is the specific case we want to handle.
? c var actualName = gameObject->ObjectIndex switch
: CollectionByActor( actualName, gameObject, out c ) {
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 ? c
: Penumbra.CollectionManager.Default; : CollectionByActor( actualName, gameObject, out c )
? c
: Penumbra.CollectionManager.Default;
}
} }
catch( Exception e ) 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. // Update collections linked to Game/DrawObjects due to a change in collection configuration.
private void CheckCollections( CollectionType type, ModCollection? _1, ModCollection? _2, string? name ) 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; return;
} }
@ -515,12 +524,13 @@ public unsafe partial class PathResolver
} }
// Find all current DrawObjects used in the GameObject table. // 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() private void InitializeDrawObjects()
{ {
foreach( var gameObject in Dalamud.Objects ) for( var i = 0; i < Dalamud.Objects.Length; ++i )
{ {
var ptr = ( GameObject* )gameObject.Address; var ptr = ( GameObject* )Dalamud.Objects.GetObjectAddress( i );
if( ptr->IsCharacter() && ptr->DrawObject != null ) if( ptr != null && ptr->IsCharacter() && ptr->DrawObject != null )
{ {
DrawObjectToObject[ ( IntPtr )ptr->DrawObject ] = ( IdentifyCollection( ptr ), ptr->ObjectIndex ); DrawObjectToObject[ ( IntPtr )ptr->DrawObject ] = ( IdentifyCollection( ptr ), ptr->ObjectIndex );
} }

View file

@ -3,11 +3,13 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using FFXIVClientStructs.FFXIV.Client.Game.Character; using FFXIVClientStructs.FFXIV.Client.Game.Character;
using FFXIVClientStructs.FFXIV.Client.Game.Object;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using FFXIVClientStructs.FFXIV.Client.System.Resource; using FFXIVClientStructs.FFXIV.Client.System.Resource;
using ImGuiNET; using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
using Penumbra.GameData.ByteString;
using Penumbra.Interop.Loader; using Penumbra.Interop.Loader;
using Penumbra.Interop.Structs; using Penumbra.Interop.Structs;
using CharacterUtility = Penumbra.Interop.CharacterUtility; using CharacterUtility = Penumbra.Interop.CharacterUtility;
@ -166,9 +168,12 @@ public partial class ConfigWindow
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.TextUnformatted( idx.ToString() ); ImGui.TextUnformatted( idx.ToString() );
ImGui.TableNextColumn(); 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.TableNextColumn();
ImGui.TextUnformatted( Dalamud.Objects[ idx ]?.Name.ToString() ?? "NULL" ); ImGui.TextUnformatted( name );
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.TextUnformatted( c.Name ); ImGui.TextUnformatted( c.Name );
} }
@ -399,6 +404,7 @@ public partial class ConfigWindow
{ {
return; return;
} }
_window._penumbra.Ipc.Tester.Draw(); _window._penumbra.Ipc.Tester.Draw();
} }