diff --git a/Glamourer/Api/GlamourerIpc.cs b/Glamourer/Api/GlamourerIpc.cs index 24039b8..428a5c7 100644 --- a/Glamourer/Api/GlamourerIpc.cs +++ b/Glamourer/Api/GlamourerIpc.cs @@ -168,8 +168,7 @@ public sealed partial class GlamourerIpc : IDisposable return []; _objects.Update(); - return _objects.Where(i => i.Key is { IsValid: true, Type: IdentifierType.Player } && i.Key.PlayerName == byteString) - .Select(i => i.Key); + return _objects.Keys.Where(i => i is { IsValid: true, Type: IdentifierType.Player } && i.PlayerName == byteString); } private IEnumerable FindActorsRevert(string actorName) @@ -178,8 +177,8 @@ public sealed partial class GlamourerIpc : IDisposable yield break; _objects.Update(); - foreach (var id in _objects.Where(i => i.Key is { IsValid: true, Type: IdentifierType.Player } && i.Key.PlayerName == byteString) - .Select(i => i.Key)) + foreach (var id in _objects.Keys.Where(i => i is { IsValid: true, Type: IdentifierType.Player } && i.PlayerName == byteString) + .Select(i => i)) yield return id; foreach (var id in _stateManager.Keys.Where(s => s.Type is IdentifierType.Player && s.PlayerName == byteString)) diff --git a/Glamourer/Glamourer.cs b/Glamourer/Glamourer.cs index 8f88216..9ad0630 100644 --- a/Glamourer/Glamourer.cs +++ b/Glamourer/Glamourer.cs @@ -30,7 +30,7 @@ public class Glamourer : IDalamudPlugin { try { - _services = ServiceManagerA.CreateProvider(pluginInterface, Log); + _services = StaticServiceManager.CreateProvider(pluginInterface, Log); Messager = _services.GetService(); _services.EnsureRequiredServices(); diff --git a/Glamourer/Gui/Tabs/ActorTab/ActorSelector.cs b/Glamourer/Gui/Tabs/ActorTab/ActorSelector.cs index 3c23fbc..e688bce 100644 --- a/Glamourer/Gui/Tabs/ActorTab/ActorSelector.cs +++ b/Glamourer/Gui/Tabs/ActorTab/ActorSelector.cs @@ -56,7 +56,7 @@ public class ActorSelector(ObjectManager objects, ActorManager actors, Ephemeral objects.Update(); using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, _defaultItemSpacing); var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeight()); - var remainder = ImGuiClip.FilteredClippedDraw(objects, skips, CheckFilter, DrawSelectable); + var remainder = ImGuiClip.FilteredClippedDraw(objects.Identifiers, skips, CheckFilter, DrawSelectable); ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeight()); } diff --git a/Glamourer/Gui/Tabs/DebugTab/ActiveStatePanel.cs b/Glamourer/Gui/Tabs/DebugTab/ActiveStatePanel.cs index 00df06b..4aa0163 100644 --- a/Glamourer/Gui/Tabs/DebugTab/ActiveStatePanel.cs +++ b/Glamourer/Gui/Tabs/DebugTab/ActiveStatePanel.cs @@ -23,7 +23,7 @@ public class ActiveStatePanel(StateManager _stateManager, ObjectManager _objectM public void Draw() { _objectManager.Update(); - foreach (var (identifier, actors) in _objectManager) + foreach (var (identifier, actors) in _objectManager.Identifiers) { if (ImGuiUtil.DrawDisabledButton($"{FontAwesomeIcon.Trash.ToIconString()}##{actors.Label}", new Vector2(ImGui.GetFrameHeight()), string.Empty, !_stateManager.ContainsKey(identifier), true)) diff --git a/Glamourer/Gui/Tabs/DebugTab/IpcTesterPanel.cs b/Glamourer/Gui/Tabs/DebugTab/IpcTesterPanel.cs index 2130efe..d96aefa 100644 --- a/Glamourer/Gui/Tabs/DebugTab/IpcTesterPanel.cs +++ b/Glamourer/Gui/Tabs/DebugTab/IpcTesterPanel.cs @@ -1,5 +1,4 @@ -using Dalamud.Game.ClientState.Objects.Types; -using Dalamud.Plugin; +using Dalamud.Plugin; using Glamourer.Api; using Glamourer.Interop; using ImGuiNET; @@ -32,7 +31,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag private GlamourerIpc.GlamourerErrorCode _setItemByActorNameEc; private GlamourerIpc.GlamourerErrorCode _setItemOnceByActorNameEc; - public unsafe void Draw() + public void Draw() { ImGui.InputInt("Game Object Index", ref _gameObjectIndex, 0, 0); ImGui.InputTextWithHint("##gameObject", "Character Name...", ref _gameObjectName, 64); @@ -58,7 +57,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelGetAllCustomizationFromCharacter); ImGui.TableNextColumn(); base64 = GlamourerIpc.GetAllCustomizationFromCharacterSubscriber(_pluginInterface) - .Invoke(_objectManager.Objects.GetDalamudCharacter(_gameObjectIndex)); + .Invoke(_objectManager.GetDalamudCharacter(_gameObjectIndex)); if (base64 != null) ImGuiUtil.CopyOnClickSelectable(base64); else @@ -66,7 +65,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelGetAllCustomizationFromLockedCharacter); ImGui.TableNextColumn(); - var base64Locked = GlamourerIpc.GetAllCustomizationFromLockedCharacterSubscriber(_pluginInterface).Invoke(_objectManager.Objects.GetDalamudCharacter(_gameObjectIndex), 1337); + var base64Locked = GlamourerIpc.GetAllCustomizationFromLockedCharacterSubscriber(_pluginInterface).Invoke(_objectManager.GetDalamudCharacter(_gameObjectIndex), 1337); if (base64Locked != null) ImGuiUtil.CopyOnClickSelectable(base64Locked); else @@ -80,7 +79,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelRevertCharacter); ImGui.TableNextColumn(); if (ImGui.Button("Revert##Character")) - GlamourerIpc.RevertCharacterSubscriber(_pluginInterface).Invoke(_objectManager.Objects.GetDalamudCharacter(_gameObjectIndex)); + GlamourerIpc.RevertCharacterSubscriber(_pluginInterface).Invoke(_objectManager.GetDalamudCharacter(_gameObjectIndex)); ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyAll); ImGui.TableNextColumn(); @@ -96,13 +95,13 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag ImGui.TableNextColumn(); if (ImGui.Button("Apply##AllCharacter")) GlamourerIpc.ApplyAllToCharacterSubscriber(_pluginInterface) - .Invoke(_base64Apply, _objectManager.Objects.GetDalamudCharacter(_gameObjectIndex)); + .Invoke(_base64Apply, _objectManager.GetDalamudCharacter(_gameObjectIndex)); ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyAllOnceToCharacter); ImGui.TableNextColumn(); if (ImGui.Button("Apply Once##AllCharacter")) GlamourerIpc.ApplyAllOnceToCharacterSubscriber(_pluginInterface) - .Invoke(_base64Apply, _objectManager.Objects.GetDalamudCharacter(_gameObjectIndex)); + .Invoke(_base64Apply, _objectManager.GetDalamudCharacter(_gameObjectIndex)); ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyOnlyEquipment); ImGui.TableNextColumn(); @@ -113,7 +112,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag ImGui.TableNextColumn(); if (ImGui.Button("Apply##EquipCharacter")) GlamourerIpc.ApplyOnlyEquipmentToCharacterSubscriber(_pluginInterface) - .Invoke(_base64Apply, _objectManager.Objects.GetDalamudCharacter(_gameObjectIndex)); + .Invoke(_base64Apply, _objectManager.GetDalamudCharacter(_gameObjectIndex)); ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyOnlyCustomization); ImGui.TableNextColumn(); @@ -124,7 +123,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag ImGui.TableNextColumn(); if (ImGui.Button("Apply##CustomizeCharacter")) GlamourerIpc.ApplyOnlyCustomizationToCharacterSubscriber(_pluginInterface) - .Invoke(_base64Apply, _objectManager.Objects.GetDalamudCharacter(_gameObjectIndex)); + .Invoke(_base64Apply, _objectManager.GetDalamudCharacter(_gameObjectIndex)); ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyByGuid); ImGui.TableNextColumn(); @@ -140,25 +139,25 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag ImGui.TableNextColumn(); if (ImGui.Button("Apply##ByGuidCharacter") && Guid.TryParse(_designIdentifier, out var guid2)) GlamourerIpc.ApplyByGuidToCharacterSubscriber(_pluginInterface) - .Invoke(guid2, _objectManager.Objects.GetDalamudCharacter(_gameObjectIndex)); + .Invoke(guid2, _objectManager.GetDalamudCharacter(_gameObjectIndex)); ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyByGuidOnceToCharacter); ImGui.TableNextColumn(); if (ImGui.Button("Apply Once##ByGuidCharacter") && Guid.TryParse(_designIdentifier, out var guid2Once)) GlamourerIpc.ApplyByGuidOnceToCharacterSubscriber(_pluginInterface) - .Invoke(guid2Once, _objectManager.Objects.GetDalamudCharacter(_gameObjectIndex)); + .Invoke(guid2Once, _objectManager.GetDalamudCharacter(_gameObjectIndex)); ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelApplyAllLock); ImGui.TableNextColumn(); if (ImGui.Button("Apply With Lock##CustomizeCharacter")) GlamourerIpc.ApplyAllToCharacterLockSubscriber(_pluginInterface) - .Invoke(_base64Apply, _objectManager.Objects.GetDalamudCharacter(_gameObjectIndex), 1337); + .Invoke(_base64Apply, _objectManager.GetDalamudCharacter(_gameObjectIndex), 1337); ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelUnlock); ImGui.TableNextColumn(); if (ImGui.Button("Unlock##CustomizeCharacter")) GlamourerIpc.UnlockSubscriber(_pluginInterface) - .Invoke(_objectManager.Objects.GetDalamudCharacter(_gameObjectIndex), 1337); + .Invoke(_objectManager.GetDalamudCharacter(_gameObjectIndex), 1337); ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelUnlockAll); ImGui.TableNextColumn(); @@ -170,7 +169,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag ImGui.TableNextColumn(); if (ImGui.Button("Revert##CustomizeCharacter")) GlamourerIpc.RevertToAutomationCharacterSubscriber(_pluginInterface) - .Invoke(_objectManager.Objects.GetDalamudCharacter(_gameObjectIndex), 1337); + .Invoke(_objectManager.GetDalamudCharacter(_gameObjectIndex), 1337); ImGuiUtil.DrawTableColumn(GlamourerIpc.LabelGetDesignList); @@ -184,7 +183,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag ImGui.TableNextColumn(); if (ImGui.Button("Set##SetItem")) _setItemEc = (GlamourerIpc.GlamourerErrorCode)GlamourerIpc.SetItemSubscriber(_pluginInterface) - .Invoke(_objectManager.Objects.GetDalamudCharacter(_gameObjectIndex), (byte)_slot, _customItemId.Id, _stainId.Id, 1337); + .Invoke(_objectManager.GetDalamudCharacter(_gameObjectIndex), (byte)_slot, _customItemId.Id, _stainId.Id, 1337); if (_setItemEc != GlamourerIpc.GlamourerErrorCode.Success) { ImGui.SameLine(); @@ -195,7 +194,7 @@ public class IpcTesterPanel(DalamudPluginInterface _pluginInterface, ObjectManag ImGui.TableNextColumn(); if (ImGui.Button("Set Once##SetItem")) _setItemOnceEc = (GlamourerIpc.GlamourerErrorCode)GlamourerIpc.SetItemOnceSubscriber(_pluginInterface) - .Invoke(_objectManager.Objects.GetDalamudCharacter(_gameObjectIndex), (byte)_slot, _customItemId.Id, _stainId.Id, 1337); + .Invoke(_objectManager.GetDalamudCharacter(_gameObjectIndex), (byte)_slot, _customItemId.Id, _stainId.Id, 1337); if (_setItemOnceEc != GlamourerIpc.GlamourerErrorCode.Success) { ImGui.SameLine(); diff --git a/Glamourer/Gui/Tabs/DebugTab/ModelEvaluationPanel.cs b/Glamourer/Gui/Tabs/DebugTab/ModelEvaluationPanel.cs index 2268ee5..566ad52 100644 --- a/Glamourer/Gui/Tabs/DebugTab/ModelEvaluationPanel.cs +++ b/Glamourer/Gui/Tabs/DebugTab/ModelEvaluationPanel.cs @@ -31,7 +31,7 @@ public unsafe class ModelEvaluationPanel( public void Draw() { ImGui.InputInt("Game Object Index", ref _gameObjectIndex, 0, 0); - var actor = _objectManager.Objects[_gameObjectIndex]; + var actor = _objectManager[_gameObjectIndex]; var model = actor.Model; using var table = ImRaii.Table("##evaluationTable", 4, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.RowBg); ImGui.TableNextColumn(); diff --git a/Glamourer/Gui/Tabs/DebugTab/ObjectManagerPanel.cs b/Glamourer/Gui/Tabs/DebugTab/ObjectManagerPanel.cs index e4ea44b..e519ea5 100644 --- a/Glamourer/Gui/Tabs/DebugTab/ObjectManagerPanel.cs +++ b/Glamourer/Gui/Tabs/DebugTab/ObjectManagerPanel.cs @@ -69,7 +69,7 @@ public class ObjectManagerPanel(ObjectManager _objectManager, ActorManager _acto var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeightWithSpacing()); ImGui.TableNextRow(); - var remainder = ImGuiClip.FilteredClippedDraw(_objectManager, skips, + var remainder = ImGuiClip.FilteredClippedDraw(_objectManager.Identifiers, skips, p => p.Value.Label.Contains(_objectFilter, StringComparison.OrdinalIgnoreCase), p => { diff --git a/Glamourer/Interop/ObjectManager.cs b/Glamourer/Interop/ObjectManager.cs index 6a1d8a1..f59e95c 100644 --- a/Glamourer/Interop/ObjectManager.cs +++ b/Glamourer/Interop/ObjectManager.cs @@ -1,23 +1,31 @@ using Dalamud.Game.ClientState.Objects; +using Dalamud.Plugin; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Game.Control; using Glamourer.Interop.Structs; +using OtterGui.Log; using Penumbra.GameData.Actors; using Penumbra.GameData.Enums; using Penumbra.GameData.Interop; namespace Glamourer.Interop; -public class ObjectManager(IFramework framework, IClientState clientState, global::Penumbra.GameData.Interop.ObjectManager objects, ActorManager actors, ITargetManager targets) - : IReadOnlyDictionary +public class ObjectManager( + IFramework framework, + IClientState clientState, + IObjectTable objects, + DalamudPluginInterface pi, + Logger log, + ActorManager actors, + ITargetManager targets) + : global::Penumbra.GameData.Interop.ObjectManager(pi, log, framework, objects) { - public global::Penumbra.GameData.Interop.ObjectManager Objects - => objects; + public DateTime LastUpdate + => LastFrame; - public DateTime LastUpdate { get; private set; } - - public bool IsInGPose { get; private set; } - public ushort World { get; private set; } + private DateTime _identifierUpdate; + public bool IsInGPose { get; private set; } + public ushort World { get; private set; } private readonly Dictionary _identifiers = new(200); private readonly Dictionary _allWorldIdentifiers = new(200); @@ -26,40 +34,26 @@ public class ObjectManager(IFramework framework, IClientState clientState, globa public IReadOnlyDictionary Identifiers => _identifiers; - public void Update() + public override bool Update() { - var lastUpdate = framework.LastUpdate; - if (lastUpdate <= LastUpdate) - return; + if (!base.Update() && _identifierUpdate >= LastUpdate) + return false; - LastUpdate = lastUpdate; - World = (ushort)(clientState.LocalPlayer?.CurrentWorld.Id ?? 0u); + _identifierUpdate = LastUpdate; + World = (ushort)(this[0].Valid ? this[0].HomeWorld : 0); _identifiers.Clear(); _allWorldIdentifiers.Clear(); _nonOwnedIdentifiers.Clear(); - for (var i = 0; i < (int)ScreenActor.CutsceneStart; ++i) + foreach (var actor in BattleNpcs.Concat(CutsceneCharacters)) { - var character = objects[i]; - if (character.Identifier(actors, out var identifier)) - HandleIdentifier(identifier, character); - } - - for (var i = (int)ScreenActor.CutsceneStart; i < (int)ScreenActor.CutsceneEnd; ++i) - { - var character = objects[i]; - // Technically the game does not create holes in cutscenes or GPose. - // But for Brio compatibility, we allow holes in GPose. - // Since GPose always has the event actor in the first cutscene slot, we can still optimize in this case. - if (!character.Valid && i == (int)ScreenActor.CutsceneStart) - break; - - HandleIdentifier(character.GetIdentifier(actors), character); + if (actor.Identifier(actors, out var identifier)) + HandleIdentifier(identifier, actor); } void AddSpecial(ScreenActor idx, string label) { - var actor = objects[(int)idx]; + var actor = this[(int)idx]; if (actor.Identifier(actors, out var ident)) { var data = new ActorData(actor, label); @@ -76,15 +70,15 @@ public class ObjectManager(IFramework framework, IClientState clientState, globa AddSpecial(ScreenActor.Card7, "Card Actor 7"); AddSpecial(ScreenActor.Card8, "Card Actor 8"); - for (var i = (int)ScreenActor.ScreenEnd; i < objects.Count; ++i) + foreach (var actor in EventNpcs) { - var character = objects[i]; - if (character.Identifier(actors, out var identifier)) - HandleIdentifier(identifier, character); + if (actor.Identifier(actors, out var identifier)) + HandleIdentifier(identifier, actor); } var gPose = GPosePlayer; IsInGPose = gPose.Utf8Name.Length > 0; + return true; } private void HandleIdentifier(ActorIdentifier identifier, Actor character) @@ -135,10 +129,10 @@ public class ObjectManager(IFramework framework, IClientState clientState, globa } public Actor GPosePlayer - => objects[(int)ScreenActor.GPosePlayer]; + => this[(int)ScreenActor.GPosePlayer]; public Actor Player - => objects[0]; + => this[0]; public unsafe Actor Target => clientState.IsGPosing ? TargetSystem.Instance()->GPoseTarget : TargetSystem.Instance()->Target; @@ -171,15 +165,6 @@ public class ObjectManager(IFramework framework, IClientState clientState, globa } } - public IEnumerator> GetEnumerator() - => Identifiers.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() - => GetEnumerator(); - - public int Count - => Identifiers.Count; - /// Also handles All Worlds players and non-owned NPCs. public bool ContainsKey(ActorIdentifier key) => Identifiers.ContainsKey(key) || _allWorldIdentifiers.ContainsKey(key) || _nonOwnedIdentifiers.ContainsKey(key); diff --git a/Glamourer/Services/ServiceManager.cs b/Glamourer/Services/ServiceManager.cs index 24a3902..d5f92a9 100644 --- a/Glamourer/Services/ServiceManager.cs +++ b/Glamourer/Services/ServiceManager.cs @@ -26,12 +26,11 @@ using OtterGui.Services; using Penumbra.GameData.Actors; using Penumbra.GameData.Data; using Penumbra.GameData.DataContainers; -using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; namespace Glamourer.Services; -public static class ServiceManagerA +public static class StaticServiceManager { public static ServiceManager CreateProvider(DalamudPluginInterface pi, Logger log) { diff --git a/Penumbra.GameData b/Penumbra.GameData index 529e181..6668764 160000 --- a/Penumbra.GameData +++ b/Penumbra.GameData @@ -1 +1 @@ -Subproject commit 529e18115023732794994bfb8df4818b68951ea4 +Subproject commit 66687643da2163c938575ad6949c8d0fbd03afe7