diff --git a/Penumbra/Interop/PathResolving/CollectionResolver.cs b/Penumbra/Interop/PathResolving/CollectionResolver.cs index cb271d7e..65fc0771 100644 --- a/Penumbra/Interop/PathResolving/CollectionResolver.cs +++ b/Penumbra/Interop/PathResolving/CollectionResolver.cs @@ -31,7 +31,7 @@ public unsafe class CollectionResolver private readonly CutsceneService _cutscenes; private readonly Configuration _config; - private readonly CollectionManager _collectionManager; + private readonly CollectionManager _collectionManager; private readonly TempCollectionManager _tempCollections; private readonly DrawObjectState _drawObjectState; @@ -65,9 +65,10 @@ public unsafe class CollectionResolver ?? _collectionManager.Default; var player = _actors.AwaitedService.GetCurrentPlayer(); + var _ = false; return CollectionByIdentifier(player) ?? CheckYourself(player, gameObject) - ?? CollectionByAttributes(gameObject) + ?? CollectionByAttributes(gameObject, ref _) ?? _collectionManager.Default; } @@ -101,7 +102,7 @@ public unsafe class CollectionResolver /// Identify the correct collection for the last created game object. public ResolveData IdentifyLastGameObjectCollection(bool useCache) - => IdentifyCollection((GameObject*)_drawObjectState.LastGameObject, useCache); + => IdentifyCollection((GameObject*)_drawObjectState.LastGameObject, useCache); /// Identify the correct collection for a draw object. public ResolveData IdentifyCollection(DrawObject* drawObject, bool useCache) @@ -126,7 +127,7 @@ public unsafe class CollectionResolver /// Actors are also not named. So use Yourself > Players > Racial > Default. /// private bool LoginScreen(GameObject* gameObject, out ResolveData ret) - { + { // Also check for empty names because sometimes named other characters // might be loaded before being officially logged in. if (_clientState.IsLoggedIn || gameObject->Name[0] != '\0') @@ -135,10 +136,11 @@ public unsafe class CollectionResolver return false; } - var collection2 = _collectionManager.ByType(CollectionType.Yourself) - ?? CollectionByAttributes(gameObject) + var notYetReady = false; + var collection = _collectionManager.ByType(CollectionType.Yourself) + ?? CollectionByAttributes(gameObject, ref notYetReady) ?? _collectionManager.Default; - ret = _cache.Set(collection2, ActorIdentifier.Invalid, gameObject); + ret = notYetReady ? collection.ToResolveData(gameObject) : _cache.Set(collection, ActorIdentifier.Invalid, gameObject); return true; } @@ -151,12 +153,13 @@ public unsafe class CollectionResolver return false; } - var player = _actors.AwaitedService.GetCurrentPlayer(); - var collection2 = (player.IsValid ? CollectionByIdentifier(player) : null) + var player = _actors.AwaitedService.GetCurrentPlayer(); + var notYetReady = false; + var collection = (player.IsValid ? CollectionByIdentifier(player) : null) ?? _collectionManager.ByType(CollectionType.Yourself) - ?? CollectionByAttributes(gameObject) + ?? CollectionByAttributes(gameObject, ref notYetReady) ?? _collectionManager.Default; - ret = _cache.Set(collection2, ActorIdentifier.Invalid, gameObject); + ret = notYetReady ? collection.ToResolveData(gameObject) : _cache.Set(collection, ActorIdentifier.Invalid, gameObject); return true; } @@ -174,13 +177,14 @@ public unsafe class CollectionResolver return _cache.Set(ModCollection.Empty, identifier, gameObject); } + var notYetReady = false; var collection = CollectionByIdentifier(identifier) ?? CheckYourself(identifier, gameObject) - ?? CollectionByAttributes(gameObject) - ?? CheckOwnedCollection(identifier, owner) + ?? CollectionByAttributes(gameObject, ref notYetReady) + ?? CheckOwnedCollection(identifier, owner, ref notYetReady) ?? _collectionManager.Default; - return _cache.Set(collection, identifier, gameObject); + return notYetReady ? collection.ToResolveData(gameObject) : _cache.Set(collection, identifier, gameObject); } /// Check both temporary and permanent character collections. Temporary first. @@ -201,8 +205,8 @@ public unsafe class CollectionResolver return null; } - /// Check special collections given the actor. - private ModCollection? CollectionByAttributes(GameObject* actor) + /// Check special collections given the actor. Returns notYetReady if the customize array is not filled. + private ModCollection? CollectionByAttributes(GameObject* actor, ref bool notYetReady) { if (!actor->IsCharacter()) return null; @@ -212,6 +216,12 @@ public unsafe class CollectionResolver if (!IsModelHuman((uint)character->ModelCharaId)) return null; + if (character->CustomizeData[0] == 0) + { + notYetReady = true; + return null; + } + var bodyType = character->CustomizeData[2]; var collection = bodyType switch { @@ -233,7 +243,7 @@ public unsafe class CollectionResolver } /// Get the collection applying to the owner if it is available. - private ModCollection? CheckOwnedCollection(ActorIdentifier identifier, GameObject* owner) + private ModCollection? CheckOwnedCollection(ActorIdentifier identifier, GameObject* owner, ref bool notYetReady) { if (identifier.Type != IdentifierType.Owned || !_config.UseOwnerNameForCharacterCollection || owner == null) return null; @@ -242,7 +252,7 @@ public unsafe class CollectionResolver ObjectKind.None, uint.MaxValue); return CheckYourself(id, owner) - ?? CollectionByAttributes(owner); + ?? CollectionByAttributes(owner, ref notYetReady); } ///