From 01431381c56d9364c6436474422b8bd628e0f186 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Mon, 24 Jul 2023 14:49:02 +0200 Subject: [PATCH] Fix owned NPCs not working with automation and some NPC customizations not working with automation. --- Glamourer/Automation/AutoDesignApplier.cs | 37 ++++++++++++------ Glamourer/Interop/ObjectManager.cs | 47 ++++++++++++++++------- 2 files changed, 58 insertions(+), 26 deletions(-) diff --git a/Glamourer/Automation/AutoDesignApplier.cs b/Glamourer/Automation/AutoDesignApplier.cs index 02e7887..68a55ce 100644 --- a/Glamourer/Automation/AutoDesignApplier.cs +++ b/Glamourer/Automation/AutoDesignApplier.cs @@ -85,7 +85,7 @@ public class AutoDesignApplier : IDisposable _state.ReapplyState(actor); } } - else if (_objects.TryGetValueAllWorld(id, out data)) + else if (_objects.TryGetValueAllWorld(id, out data) || _objects.TryGetValueNonOwned(id, out data)) { foreach (var actor in data.Objects) { @@ -210,7 +210,7 @@ public class AutoDesignApplier : IDisposable continue; var (equipFlags, customizeFlags, applyHat, applyVisor, applyWeapon, applyWet) = design.ApplyWhat(); - Reduce(state, data, applyHat, applyVisor, applyWeapon, applyWet, ref totalMetaFlags, respectManual, source); + Reduce(state, data, applyHat, applyVisor, applyWeapon, applyWet, ref totalMetaFlags, respectManual, source); Reduce(state, data, customizeFlags, ref totalCustomizeFlags, respectManual, source); Reduce(state, data, equipFlags, ref totalEquipFlags, respectManual, source); } @@ -219,17 +219,28 @@ public class AutoDesignApplier : IDisposable /// Get world-specific first and all-world afterwards. private bool GetPlayerSet(ActorIdentifier identifier, [NotNullWhen(true)] out AutoDesignSet? set) { - if (identifier.Type is not IdentifierType.Player) - return _manager.EnabledSets.TryGetValue(identifier, out set); + switch (identifier.Type) + { + case IdentifierType.Player: + if (_manager.EnabledSets.TryGetValue(identifier, out set)) + return true; - if (_manager.EnabledSets.TryGetValue(identifier, out set)) - return true; - - identifier = _actors.AwaitedService.CreatePlayer(identifier.PlayerName, ushort.MaxValue); - return _manager.EnabledSets.TryGetValue(identifier, out set); + identifier = _actors.AwaitedService.CreatePlayer(identifier.PlayerName, ushort.MaxValue); + return _manager.EnabledSets.TryGetValue(identifier, out set); + case IdentifierType.Retainer: + case IdentifierType.Special: + return _manager.EnabledSets.TryGetValue(identifier, out set); + case IdentifierType.Owned: + identifier = _actors.AwaitedService.CreateNpc(identifier.Kind, identifier.DataId); + return _manager.EnabledSets.TryGetValue(identifier, out set); + default: + set = null; + return false; + } } - private void Reduce(ActorState state, in DesignData design, EquipFlag equipFlags, ref EquipFlag totalEquipFlags, bool respectManual, StateChanged.Source source) + private void Reduce(ActorState state, in DesignData design, EquipFlag equipFlags, ref EquipFlag totalEquipFlags, bool respectManual, + StateChanged.Source source) { equipFlags &= ~totalEquipFlags; if (equipFlags == 0) @@ -347,9 +358,11 @@ public class AutoDesignApplier : IDisposable continue; var value = design.Customize[index]; - if (CustomizationService.IsCustomizationValid(set, face, index, value, out var data) - && (data.HasValue && (!_config.UnlockedItemMode || _customizeUnlocks.IsUnlocked(data.Value, out _)))) + if (CustomizationService.IsCustomizationValid(set, face, index, value, out var data)) { + if (data.HasValue && _config.UnlockedItemMode && !_customizeUnlocks.IsUnlocked(data.Value, out _)) + continue; + if (!respectManual || state[index] is not StateChanged.Source.Manual) _state.ChangeCustomize(state, index, value, source); totalCustomizeFlags |= flag; diff --git a/Glamourer/Interop/ObjectManager.cs b/Glamourer/Interop/ObjectManager.cs index 328c4c6..3995076 100644 --- a/Glamourer/Interop/ObjectManager.cs +++ b/Glamourer/Interop/ObjectManager.cs @@ -7,6 +7,7 @@ using Dalamud.Game.ClientState.Objects; using Glamourer.Interop.Structs; using Glamourer.Services; using Penumbra.GameData.Actors; +using Penumbra.String; namespace Glamourer.Interop; @@ -34,6 +35,7 @@ public class ObjectManager : IReadOnlyDictionary private readonly Dictionary _identifiers = new(200); private readonly Dictionary _allWorldIdentifiers = new(200); + private readonly Dictionary _nonOwnedIdentifiers = new(200); public IReadOnlyDictionary Identifiers => _identifiers; @@ -110,21 +112,35 @@ public class ObjectManager : IReadOnlyDictionary data.Objects.Add(character); } - if (identifier.Type is not (IdentifierType.Player or IdentifierType.Owned)) - return; - - var allWorld = _actors.AwaitedService.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue, - identifier.Kind, - identifier.DataId); - - if (!_allWorldIdentifiers.TryGetValue(allWorld, out var allWorldData)) + if (identifier.Type is IdentifierType.Player or IdentifierType.Owned) { - allWorldData = new ActorData(character, allWorld.ToString()); - _allWorldIdentifiers[allWorld] = allWorldData; + var allWorld = _actors.AwaitedService.CreateIndividualUnchecked(identifier.Type, identifier.PlayerName, ushort.MaxValue, + identifier.Kind, + identifier.DataId); + + if (!_allWorldIdentifiers.TryGetValue(allWorld, out var allWorldData)) + { + allWorldData = new ActorData(character, allWorld.ToString()); + _allWorldIdentifiers[allWorld] = allWorldData; + } + else + { + allWorldData.Objects.Add(character); + } } - else + + if (identifier.Type is IdentifierType.Owned) { - allWorldData.Objects.Add(character); + var nonOwned = _actors.AwaitedService.CreateNpc(identifier.Kind, identifier.DataId); + if (!_nonOwnedIdentifiers.TryGetValue(nonOwned, out var allWorldData)) + { + allWorldData = new ActorData(character, nonOwned.ToString()); + _allWorldIdentifiers[nonOwned] = allWorldData; + } + else + { + allWorldData.Objects.Add(character); + } } } @@ -174,9 +190,9 @@ public class ObjectManager : IReadOnlyDictionary public int Count => Identifiers.Count; - /// Also handles All Worlds players. + /// Also handles All Worlds players and non-owned NPCs. public bool ContainsKey(ActorIdentifier key) - => Identifiers.ContainsKey(key) || _allWorldIdentifiers.ContainsKey(key); + => Identifiers.ContainsKey(key) || _allWorldIdentifiers.ContainsKey(key) || _nonOwnedIdentifiers.ContainsKey(key); public bool TryGetValue(ActorIdentifier key, out ActorData value) => Identifiers.TryGetValue(key, out value); @@ -184,6 +200,9 @@ public class ObjectManager : IReadOnlyDictionary public bool TryGetValueAllWorld(ActorIdentifier key, out ActorData value) => _allWorldIdentifiers.TryGetValue(key, out value); + public bool TryGetValueNonOwned(ActorIdentifier key, out ActorData value) + => _nonOwnedIdentifiers.TryGetValue(key, out value); + public ActorData this[ActorIdentifier key] => Identifiers[key];