From 6a6eac1c3b0425d476fcbdb2ba44bc1fed4843b1 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Thu, 17 Nov 2022 15:22:31 +0100 Subject: [PATCH] Use IndividualCollections in PathResolver. --- Penumbra.GameData/Actors/ActorIdentifier.cs | 5 +- Penumbra.GameData/Actors/ActorManager.Data.cs | 6 +- .../Collections/CollectionManager.Active.cs | 5 +- Penumbra/Collections/CollectionManager.cs | 2 +- .../IndividualCollections.Access.cs | 27 +- Penumbra/Collections/ModCollection.cs | 3 + .../Resolver/PathResolver.Identification.cs | 310 ++++++------------ Penumbra/Interop/Resolver/PathResolver.cs | 9 + Penumbra/Penumbra.cs | 4 +- .../ConfigWindow.CollectionsTab.Individual.cs | 2 +- 10 files changed, 128 insertions(+), 245 deletions(-) diff --git a/Penumbra.GameData/Actors/ActorIdentifier.cs b/Penumbra.GameData/Actors/ActorIdentifier.cs index dc3ffff6..0903c312 100644 --- a/Penumbra.GameData/Actors/ActorIdentifier.cs +++ b/Penumbra.GameData/Actors/ActorIdentifier.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; using Dalamud.Game.ClientState.Objects.Enums; -using FFXIVClientStructs.FFXIV.Client.Game.Character; using Newtonsoft.Json.Linq; using Penumbra.String; @@ -38,7 +37,7 @@ public readonly struct ActorIdentifier : IEquatable IdentifierType.Player => HomeWorld == other.HomeWorld && PlayerName.EqualsCi(other.PlayerName), IdentifierType.Owned => HomeWorld == other.HomeWorld && PlayerName.EqualsCi(other.PlayerName) && Manager.DataIdEquals(this, other), IdentifierType.Special => Special == other.Special, - IdentifierType.Npc => Index == other.Index && DataId == other.DataId && Manager.DataIdEquals(this, other), + IdentifierType.Npc => Manager.DataIdEquals(this, other) && (Index == other.Index || Index == ushort.MaxValue || other.Index == ushort.MaxValue), _ => false, }; } @@ -75,7 +74,7 @@ public readonly struct ActorIdentifier : IEquatable IdentifierType.Player => HashCode.Combine(IdentifierType.Player, PlayerName, HomeWorld), IdentifierType.Owned => HashCode.Combine(IdentifierType.Owned, Kind, PlayerName, HomeWorld, DataId), IdentifierType.Special => HashCode.Combine(IdentifierType.Special, Special), - IdentifierType.Npc => HashCode.Combine(IdentifierType.Npc, Kind, Index, DataId), + IdentifierType.Npc => HashCode.Combine(IdentifierType.Npc, Kind, DataId), _ => 0, }; diff --git a/Penumbra.GameData/Actors/ActorManager.Data.cs b/Penumbra.GameData/Actors/ActorManager.Data.cs index f1c3c4bf..0907d2ff 100644 --- a/Penumbra.GameData/Actors/ActorManager.Data.cs +++ b/Penumbra.GameData/Actors/ActorManager.Data.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Text; using Dalamud; @@ -70,7 +69,10 @@ public sealed partial class ActorManager : DataSharer public unsafe ActorIdentifier GetCurrentPlayer() { var address = (Character*)(_objects[0]?.Address ?? IntPtr.Zero); - return address == null ? ActorIdentifier.Invalid : CreatePlayer(new ByteString(address->GameObject.Name), address->HomeWorld); + return address == null + ? ActorIdentifier.Invalid + : CreateIndividualUnchecked(IdentifierType.Player, new ByteString(address->GameObject.Name), address->HomeWorld, + ObjectKind.None, uint.MaxValue); } public ActorIdentifier GetInspectPlayer() diff --git a/Penumbra/Collections/CollectionManager.Active.cs b/Penumbra/Collections/CollectionManager.Active.cs index 53db52ee..47977d08 100644 --- a/Penumbra/Collections/CollectionManager.Active.cs +++ b/Penumbra/Collections/CollectionManager.Active.cs @@ -8,7 +8,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using Penumbra.GameData.Actors; namespace Penumbra.Collections; @@ -44,8 +43,8 @@ public partial class ModCollection => _characters; // If a name does not correspond to a character, return the default collection instead. - public ModCollection Individual( ActorIdentifier identifier ) - => Individuals.Individuals.TryGetValue( identifier, out var c ) ? c : Default; + public ModCollection Character( string name ) + => _characters.TryGetValue( name, out var c ) ? c : Default; // Special Collections private readonly ModCollection?[] _specialCollections = new ModCollection?[Enum.GetValues< CollectionType >().Length - 4]; diff --git a/Penumbra/Collections/CollectionManager.cs b/Penumbra/Collections/CollectionManager.cs index 961478b5..05dc797f 100644 --- a/Penumbra/Collections/CollectionManager.cs +++ b/Penumbra/Collections/CollectionManager.cs @@ -149,7 +149,7 @@ public partial class ModCollection foreach( var (characterName, _) in _characters.Where( c => c.Value.Index == idx ).ToList() ) { - SetCollection( Empty, CollectionType.Character, characterName ); + SetCollection( Empty, CollectionType.Individual, characterName ); } var collection = _collections[ idx ]; diff --git a/Penumbra/Collections/IndividualCollections.Access.cs b/Penumbra/Collections/IndividualCollections.Access.cs index 933121f7..f6d927ad 100644 --- a/Penumbra/Collections/IndividualCollections.Access.cs +++ b/Penumbra/Collections/IndividualCollections.Access.cs @@ -2,8 +2,10 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; +using Dalamud.Game.ClientState.Objects.Enums; using Dalamud.Game.ClientState.Objects.Types; using Penumbra.GameData.Actors; +using Penumbra.String; namespace Penumbra.Collections; @@ -34,8 +36,8 @@ public sealed partial class IndividualCollections : IReadOnlyList< (string Displ } // Handle generic NPC - var npcIdentifier = _manager.CreateNpc( identifier.Kind, identifier.DataId ); - if( npcIdentifier.IsValid && _individuals.TryGetValue( identifier, out collection ) ) + var npcIdentifier = _manager.CreateIndividualUnchecked( IdentifierType.Npc, ByteString.Empty, ushort.MaxValue, identifier.Kind, identifier.DataId ); + if( npcIdentifier.IsValid && _individuals.TryGetValue( npcIdentifier, out collection ) ) { return true; } @@ -43,7 +45,7 @@ public sealed partial class IndividualCollections : IReadOnlyList< (string Displ // Handle Ownership. if( Penumbra.Config.UseOwnerNameForCharacterCollection ) { - identifier = _manager.CreatePlayer( identifier.PlayerName, identifier.HomeWorld ); + identifier = _manager.CreateIndividualUnchecked( IdentifierType.Player, identifier.PlayerName, identifier.HomeWorld, ObjectKind.None, uint.MaxValue ); return CheckWorlds( identifier, out collection ); } @@ -60,22 +62,9 @@ public sealed partial class IndividualCollections : IReadOnlyList< (string Displ return CheckWorlds( _manager.GetCurrentPlayer(), out collection ); case SpecialActor.ExamineScreen: { - if( CheckWorlds( _manager.GetInspectPlayer(), out collection! ) ) - { - return true; - } - - if( CheckWorlds( _manager.GetCardPlayer(), out collection! ) ) - { - return true; - } - - if( CheckWorlds( _manager.GetGlamourPlayer(), out collection! ) ) - { - return true; - } - - break; + return CheckWorlds( _manager.GetInspectPlayer(), out collection! ) + || CheckWorlds( _manager.GetCardPlayer(), out collection! ) + || CheckWorlds( _manager.GetGlamourPlayer(), out collection! ); } } diff --git a/Penumbra/Collections/ModCollection.cs b/Penumbra/Collections/ModCollection.cs index b01a8fad..e6a71fdf 100644 --- a/Penumbra/Collections/ModCollection.cs +++ b/Penumbra/Collections/ModCollection.cs @@ -172,4 +172,7 @@ public partial class ModCollection Save(); } } + + public override string ToString() + => Name; } \ No newline at end of file diff --git a/Penumbra/Interop/Resolver/PathResolver.Identification.cs b/Penumbra/Interop/Resolver/PathResolver.Identification.cs index ec975dfa..d7b25cd3 100644 --- a/Penumbra/Interop/Resolver/PathResolver.Identification.cs +++ b/Penumbra/Interop/Resolver/PathResolver.Identification.cs @@ -1,141 +1,21 @@ using System; -using System.Diagnostics.CodeAnalysis; -using Dalamud.Utility.Signatures; -using FFXIVClientStructs.FFXIV.Client.Game.Character; -using FFXIVClientStructs.FFXIV.Client.Game.Object; -using FFXIVClientStructs.FFXIV.Client.UI.Agent; -using FFXIVClientStructs.FFXIV.Component.GUI; +using System.Collections; +using System.Linq; +using Dalamud.Data; +using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using Lumina.Excel.GeneratedSheets; +using OtterGui; using Penumbra.Collections; +using Penumbra.GameData.Actors; using Penumbra.GameData.Enums; -using Penumbra.String; -using CustomizeData = Penumbra.GameData.Structs.CustomizeData; +using Character = FFXIVClientStructs.FFXIV.Client.Game.Character.Character; +using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject; using ObjectKind = Dalamud.Game.ClientState.Objects.Enums.ObjectKind; namespace Penumbra.Interop.Resolver; public unsafe partial class PathResolver { - [Signature( "0F B7 0D ?? ?? ?? ?? C7 85", ScanType = ScanType.StaticAddress )] - private static ushort* _inspectTitleId = null!; - - // Obtain the name of the current player, if one exists. - private static string? GetPlayerName() - => Dalamud.Objects[ 0 ]?.Name.ToString(); - - // Obtain the name of the inspect target from its window, if it exists. - private static string? GetInspectName() - { - if( !Penumbra.Config.UseCharacterCollectionInInspect ) - { - return null; - } - - var addon = Dalamud.GameGui.GetAddonByName( "CharacterInspect", 1 ); - if( addon == IntPtr.Zero ) - { - return null; - } - - var ui = ( AtkUnitBase* )addon; - var nodeId = Dalamud.GameData.GetExcelSheet< Title >()?.GetRow( *_inspectTitleId )?.IsPrefix == true ? 7u : 6u; - - var text = ( AtkTextNode* )ui->UldManager.SearchNodeById( nodeId ); - return text != null && text->AtkResNode.Type == NodeType.Text ? text->NodeText.ToString() : null; - } - - // Obtain the name displayed in the Character Card from the agent. - private static string? GetCardName() - { - // TODO: Update to ClientStructs when merged. - if( !Penumbra.Config.UseCharacterCollectionsInCards ) - { - return null; - } - - var agent = AgentCharaCard.Instance(); - if( agent == null ) - { - return null; - } - - var data = *( byte** )( ( byte* )agent + 0x28 ); - if( data == null ) - { - return null; - } - - var block = data + 0x7A; - return new ByteString( block ).ToString(); - } - - // Obtain the name of the player character if the glamour plate edit window is open. - private static string? GetGlamourName() - { - if( !Penumbra.Config.UseCharacterCollectionInTryOn ) - { - return null; - } - - var addon = Dalamud.GameGui.GetAddonByName( "MiragePrismMiragePlate", 1 ); - return addon == IntPtr.Zero ? null : GetPlayerName(); - } - - // Guesstimate whether an unnamed cutscene actor corresponds to the player or not, - // and if so, return the player name. - private static string? GetCutsceneName( GameObject* gameObject ) - { - if( gameObject->Name[ 0 ] != 0 || gameObject->ObjectKind != ( byte )ObjectKind.Player ) - { - return null; - } - - var parent = Cutscenes[ gameObject->ObjectIndex ]; - if( parent != null ) - { - return parent.Name.ToString(); - } - - // should not really happen but keep it in as a emergency case. - var player = Dalamud.Objects[ 0 ]; - if( player == null ) - { - return null; - } - - var customize1 = ( CustomizeData* )( ( Character* )gameObject )->CustomizeData; - var customize2 = ( CustomizeData* )( ( Character* )player.Address )->CustomizeData; - return customize1->Equals( *customize2 ) ? player.Name.ToString() : null; - } - - // Identify the owner of a companion, mount or monster and apply the corresponding collection. - // Companions and mounts get set to the actor before them in the table if it exists. - // Monsters with a owner use that owner if it exists. - private static string? GetOwnerName( GameObject* gameObject ) - { - if( !Penumbra.Config.UseOwnerNameForCharacterCollection ) - { - return null; - } - - GameObject* owner = null; - if( ( ObjectKind )gameObject->GetObjectKind() is ObjectKind.Companion or ObjectKind.MountType && gameObject->ObjectIndex > 0 ) - { - owner = ( GameObject* )Dalamud.Objects[ gameObject->ObjectIndex - 1 ]?.Address; - } - else if( gameObject->OwnerID != 0xE0000000 ) - { - owner = ( GameObject* )( Dalamud.Objects.SearchById( gameObject->OwnerID )?.Address ?? IntPtr.Zero ); - } - - if( owner != null ) - { - return new ByteString( owner->Name ).ToString(); - } - - return null; - } - // Identify the correct collection for a GameObject by index and name. private static ResolveData IdentifyCollection( GameObject* gameObject ) { @@ -152,51 +32,18 @@ public unsafe partial class PathResolver if( !Dalamud.ClientState.IsLoggedIn ) { var collection = Penumbra.CollectionManager.ByType( CollectionType.Yourself ) - ?? ( CollectionByActor( string.Empty, gameObject, out var c ) ? c : Penumbra.CollectionManager.Default ); + ?? CollectionByAttributes( gameObject ) + ?? Penumbra.CollectionManager.Default; return collection.ToResolveData( gameObject ); } else { - // 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 Penumbra.CollectionManager.Default.ToResolveData( gameObject ); - } - - string? actorName = null; - if( Penumbra.Config.PreferNamedCollectionsOverOwners ) - { - // Early return if we prefer the actors own name over its owner. - actorName = new ByteString( gameObject->Name ).ToString(); - if( actorName.Length > 0 - && CollectionByActorName( actorName, out var actorCollection ) ) - { - return actorCollection.ToResolveData( gameObject ); - } - } - - // 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 - 244 => Penumbra.Config.UseCharacterCollectionsInCards ? GetPlayerName() : null, // portrait list and editor - >= CutsceneCharacters.CutsceneStartIdx and < CutsceneCharacters.CutsceneEndIdx => GetCutsceneName( gameObject ), - _ => null, - } - ?? GetOwnerName( gameObject ) ?? actorName ?? new ByteString( gameObject->Name ).ToString(); - - // First check temporary character collections, then the own configuration, then special collections. - var collection = CollectionByActorName( actualName, out var c ) - ? c - : CollectionByActor( actualName, gameObject, out c ) - ? c - : Penumbra.CollectionManager.Default; + var identifier = Penumbra.Actors.FromObject( gameObject ); + var collection = CollectionByIdentifier( identifier ) + ?? CheckYourself( identifier, gameObject ) + ?? CollectionByAttributes( gameObject ) + ?? CheckOwnedCollection( identifier, gameObject ) + ?? Penumbra.CollectionManager.Default; return collection.ToResolveData( gameObject ); } } @@ -211,67 +58,102 @@ public unsafe partial class PathResolver // or the default collection if no player exists. public static ModCollection PlayerCollection() { - var player = Dalamud.ClientState.LocalPlayer; - if( player == null ) + var player = Penumbra.Actors.GetCurrentPlayer(); + if( !player.IsValid ) { return Penumbra.CollectionManager.Default; } - var name = player.Name.TextValue; - if( CollectionByActorName( name, out var c ) ) - { - return c; - } - - if( CollectionByActor( name, ( GameObject* )player.Address, out c ) ) - { - return c; - } - - return Penumbra.CollectionManager.Default; + return CollectionByIdentifier( player ) + ?? CollectionByAttributes( ( GameObject* )Dalamud.Objects[ 0 ]!.Address ) + ?? Penumbra.CollectionManager.Default; } // Check both temporary and permanent character collections. Temporary first. - private static bool CollectionByActorName( string name, [NotNullWhen( true )] out ModCollection? collection ) - => Penumbra.TempMods.Collections.TryGetValue( name, out collection ) - || Penumbra.CollectionManager.Characters.TryGetValue( name, out collection ); + private static ModCollection? CollectionByIdentifier( ActorIdentifier identifier ) + => Penumbra.TempMods.Collections.TryGetValue( identifier.ToString(), out var collection ) + || Penumbra.CollectionManager.Individuals.TryGetCollection( identifier, out collection ) + ? collection + : null; - // Check special collections given the actor. - private static bool CollectionByActor( string name, GameObject* actor, [NotNullWhen( true )] out ModCollection? collection ) + + // Check for the Yourself collection. + private static ModCollection? CheckYourself( ActorIdentifier identifier, GameObject* actor ) { - collection = null; - // Check for the Yourself collection. if( actor->ObjectIndex == 0 || Cutscenes.GetParentIndex( actor->ObjectIndex ) == 0 - || name == Dalamud.ClientState.LocalPlayer?.Name.ToString() ) + || identifier.Equals( Penumbra.Actors.GetCurrentPlayer() ) ) { - collection = Penumbra.CollectionManager.ByType( CollectionType.Yourself ); - if( collection != null ) - { - return true; - } + return Penumbra.CollectionManager.ByType( CollectionType.Yourself ); } - if( actor->IsCharacter() ) - { - var character = ( Character* )actor; - // Only handle human models. - if( character->ModelCharaId == 0 ) - { - var race = ( SubRace )character->CustomizeData[ 4 ]; - var gender = ( Gender )( character->CustomizeData[ 1 ] + 1 ); - var isNpc = actor->ObjectKind != ( byte )ObjectKind.Player; + return null; + } - var type = CollectionTypeExtensions.FromParts( race, gender, isNpc ); - collection = Penumbra.CollectionManager.ByType( type ); - collection ??= Penumbra.CollectionManager.ByType( CollectionTypeExtensions.FromParts( gender, isNpc ) ); - if( collection != null ) - { - return true; - } - } + // Check special collections given the actor. + private static ModCollection? CollectionByAttributes( GameObject* actor ) + { + if( !actor->IsCharacter() ) + { + return null; } - return false; + // Only handle human models. + var character = ( Character* )actor; + if( character->ModelCharaId >= 0 && character->ModelCharaId < ValidHumanModels.Count && ValidHumanModels[ character->ModelCharaId ] ) + { + var race = ( SubRace )character->CustomizeData[ 4 ]; + var gender = ( Gender )( character->CustomizeData[ 1 ] + 1 ); + var isNpc = actor->ObjectKind != ( byte )ObjectKind.Player; + + var type = CollectionTypeExtensions.FromParts( race, gender, isNpc ); + var collection = Penumbra.CollectionManager.ByType( type ); + collection ??= Penumbra.CollectionManager.ByType( CollectionTypeExtensions.FromParts( gender, isNpc ) ); + return collection; + } + + return null; + } + + // Get the collection applying to the owner if it is available. + private static ModCollection? CheckOwnedCollection( ActorIdentifier identifier, GameObject* obj ) + { + 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 ) + { + return null; + } + + var id = Penumbra.Actors.CreateIndividualUnchecked( IdentifierType.Player, identifier.PlayerName, identifier.HomeWorld, ObjectKind.None, uint.MaxValue ); + return CheckYourself( id, owner ) + ?? CollectionByAttributes( owner ); + } + + /// + /// Go through all ModelChara rows and return a bitfield of those that resolve to human models. + /// + private static BitArray GetValidHumanModels( DataManager gameData ) + { + var sheet = gameData.GetExcelSheet< ModelChara >()!; + var ret = new BitArray( ( int )sheet.RowCount, false ); + foreach( var (row, idx) in sheet.WithIndex().Where( p => p.Value.Type == ( byte )CharacterBase.ModelType.Human ) ) + { + ret[ idx ] = true; + } + + return ret; } } \ No newline at end of file diff --git a/Penumbra/Interop/Resolver/PathResolver.cs b/Penumbra/Interop/Resolver/PathResolver.cs index c2f4f3ef..4f9b5059 100644 --- a/Penumbra/Interop/Resolver/PathResolver.cs +++ b/Penumbra/Interop/Resolver/PathResolver.cs @@ -1,9 +1,14 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.Linq; +using Dalamud.Data; using Dalamud.Utility.Signatures; using FFXIVClientStructs.FFXIV.Client.Game.Object; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.System.Resource; +using Lumina.Excel.GeneratedSheets; +using OtterGui; using Penumbra.Collections; using Penumbra.GameData.Enums; using Penumbra.Interop.Loader; @@ -24,11 +29,15 @@ public partial class PathResolver : IDisposable private readonly ResourceLoader _loader; private static readonly CutsceneCharacters Cutscenes = new(); private static readonly DrawObjectState DrawObjects = new(); + private static readonly BitArray ValidHumanModels; private readonly AnimationState _animations; private readonly PathState _paths; private readonly MetaState _meta; private readonly MaterialState _materials; + static PathResolver() + => ValidHumanModels = GetValidHumanModels( Dalamud.GameData ); + public unsafe PathResolver( ResourceLoader loader ) { SignatureHelper.Initialise( this ); diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index 6744462d..91561644 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -332,7 +332,7 @@ public class Penumbra : IDalamudPlugin } string? characterName = null; - if( type is CollectionType.Character ) + if( type is CollectionType.Individual ) { var split = collectionName.Split( '|', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries ); if( split.Length < 2 || split[ 0 ].Length == 0 || split[ 1 ].Length == 0 ) @@ -368,7 +368,7 @@ public class Penumbra : IDalamudPlugin { CollectionManager.CreateSpecialCollection( type ); } - else if( type is CollectionType.Character ) + else if( type is CollectionType.Individual ) { CollectionManager.CreateCharacterCollection( characterName! ); } diff --git a/Penumbra/UI/ConfigWindow.CollectionsTab.Individual.cs b/Penumbra/UI/ConfigWindow.CollectionsTab.Individual.cs index c850b418..a7a0f65b 100644 --- a/Penumbra/UI/ConfigWindow.CollectionsTab.Individual.cs +++ b/Penumbra/UI/ConfigWindow.CollectionsTab.Individual.cs @@ -126,7 +126,7 @@ public partial class ConfigWindow { var (name, collection) = Penumbra.CollectionManager.Individuals[ i ]; using var id = ImRaii.PushId( i ); - DrawCollectionSelector( string.Empty, _window._inputTextWidth.X, CollectionType.Character, true, name ); + DrawCollectionSelector( string.Empty, _window._inputTextWidth.X, CollectionType.Individual, true, name ); ImGui.SameLine(); if( ImGuiUtil.DrawDisabledButton( FontAwesomeIcon.Trash.ToIconString(), _window._iconButtonSize, string.Empty, false, true ) )