From e8b244febab43276b6d576e519e8a9f649676057 Mon Sep 17 00:00:00 2001 From: Caraxi Date: Thu, 28 May 2020 08:28:26 +0930 Subject: [PATCH 1/5] Add TargetActorID --- Dalamud/Game/ClientState/Actors/Types/Actor.cs | 5 +++++ .../Game/ClientState/Actors/Types/NonPlayer/BattleNpc.cs | 6 ++++++ Dalamud/Game/ClientState/Actors/Types/PlayerCharacter.cs | 6 ++++++ Dalamud/Game/ClientState/Structs/Actor.cs | 3 ++- 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Dalamud/Game/ClientState/Actors/Types/Actor.cs b/Dalamud/Game/ClientState/Actors/Types/Actor.cs index caed4962d..431f3163f 100644 --- a/Dalamud/Game/ClientState/Actors/Types/Actor.cs +++ b/Dalamud/Game/ClientState/Actors/Types/Actor.cs @@ -65,5 +65,10 @@ namespace Dalamud.Game.ClientState.Actors.Types { /// The Y distance from the local player in yalms. /// public byte YalmDistanceY => this.actorStruct.YalmDistanceFromPlayerY; + + /// + /// The target of the actor + /// + public virtual int TargetActorID => 0; } } diff --git a/Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpc.cs b/Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpc.cs index b4be1321e..dde8fd385 100644 --- a/Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpc.cs +++ b/Dalamud/Game/ClientState/Actors/Types/NonPlayer/BattleNpc.cs @@ -22,5 +22,11 @@ namespace Dalamud.Game.ClientState.Actors.Types.NonPlayer { /// The ID of this BattleNpc's owner. /// public int OwnerId => this.actorStruct.OwnerId; + + /// + /// Target of the Battle NPC + /// + public override int TargetActorID => this.actorStruct.BattleNpcTargetActorId; + } } diff --git a/Dalamud/Game/ClientState/Actors/Types/PlayerCharacter.cs b/Dalamud/Game/ClientState/Actors/Types/PlayerCharacter.cs index 366794513..1df1483da 100644 --- a/Dalamud/Game/ClientState/Actors/Types/PlayerCharacter.cs +++ b/Dalamud/Game/ClientState/Actors/Types/PlayerCharacter.cs @@ -29,5 +29,11 @@ namespace Dalamud.Game.ClientState.Actors.Types { /// The Free Company tag of this player. /// public string CompanyTag => Encoding.UTF8.GetString(this.actorStruct.CompanyTag).Substring(2).Replace("\0", ""); + + /// + /// Target of the PlayerCharacter + /// + public override int TargetActorID => this.actorStruct.PlayerCharacterTargetActorId; + } } diff --git a/Dalamud/Game/ClientState/Structs/Actor.cs b/Dalamud/Game/ClientState/Structs/Actor.cs index b8cf25680..0d7c9e50a 100644 --- a/Dalamud/Game/ClientState/Structs/Actor.cs +++ b/Dalamud/Game/ClientState/Structs/Actor.cs @@ -30,7 +30,8 @@ namespace Dalamud.Game.ClientState.Structs [FieldOffset(0x17B8)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)] public byte[] Customize; - [FieldOffset(0x17F8)] public int TargetActorId; + [FieldOffset(0x1F0)] public int PlayerCharacterTargetActorId; + [FieldOffset(0x17F8)] public int BattleNpcTargetActorId; // This field can't be correctly aligned, so we have to cut it manually. [FieldOffset(0x17d0)] [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)] From e95dfa83206e979fe3539aa98c91bd08d1e33415 Mon Sep 17 00:00:00 2001 From: Caraxi Date: Thu, 28 May 2020 08:44:41 +0930 Subject: [PATCH 2/5] Fix ActorTable Enumerator --- Dalamud/Game/ClientState/Actors/ActorTable.cs | 30 ++----------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/Dalamud/Game/ClientState/Actors/ActorTable.cs b/Dalamud/Game/ClientState/Actors/ActorTable.cs index 205f15faa..7c256c924 100644 --- a/Dalamud/Game/ClientState/Actors/ActorTable.cs +++ b/Dalamud/Game/ClientState/Actors/ActorTable.cs @@ -85,34 +85,10 @@ namespace Dalamud.Game.ClientState.Actors { } } - private class ActorTableEnumerator : IEnumerator { - private readonly ActorTable table; - - private int currentIndex; - - public ActorTableEnumerator(ActorTable table) { - this.table = table; - } - - public bool MoveNext() { - this.currentIndex++; - return this.currentIndex != this.table.Length; - } - - public void Reset() { - this.currentIndex = 0; - } - - public Actor Current => this.table[this.currentIndex]; - - object IEnumerator.Current => Current; - - // Required by IEnumerator even though we have nothing we want to dispose here. - public void Dispose() {} - } - public IEnumerator GetEnumerator() { - return new ActorTableEnumerator(this); + for (int i=0;i Date: Thu, 28 May 2020 08:48:48 +0930 Subject: [PATCH 3/5] Add null check https://discordapp.com/channels/581875019861328007/653504487352303619/715342854737625111 --- Dalamud/Game/ClientState/Actors/ActorTable.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Dalamud/Game/ClientState/Actors/ActorTable.cs b/Dalamud/Game/ClientState/Actors/ActorTable.cs index 7c256c924..b21f5c4fb 100644 --- a/Dalamud/Game/ClientState/Actors/ActorTable.cs +++ b/Dalamud/Game/ClientState/Actors/ActorTable.cs @@ -87,7 +87,9 @@ namespace Dalamud.Game.ClientState.Actors { public IEnumerator GetEnumerator() { for (int i=0;i Date: Thu, 28 May 2020 09:09:42 +0930 Subject: [PATCH 4/5] Update enumerator in PartyList to match ActorTable --- Dalamud/Game/ClientState/PartyList.cs | 33 ++++----------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/Dalamud/Game/ClientState/PartyList.cs b/Dalamud/Game/ClientState/PartyList.cs index 536af33e6..572122c05 100644 --- a/Dalamud/Game/ClientState/PartyList.cs +++ b/Dalamud/Game/ClientState/PartyList.cs @@ -73,37 +73,14 @@ namespace Dalamud.Game.ClientState } } - private class PartyListEnumerator : IEnumerator - { - private readonly PartyList party; - private int currentIndex; - - public PartyListEnumerator(PartyList list) - { - this.party = list; + public IEnumerator GetEnumerator() { + for (var i = 0; i < Length; i++) { + if (this[i] != null) { + yield return this[i]; + } } - - public bool MoveNext() - { - this.currentIndex++; - return this.currentIndex != this.party.Length; - } - - public void Reset() - { - this.currentIndex = 0; - } - - public PartyMember Current => this.party[this.currentIndex]; - - object IEnumerator.Current => Current; - - // Required by IEnumerator even though we have nothing we want to dispose here. - public void Dispose() {} } - public IEnumerator GetEnumerator() => new PartyListEnumerator(this); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public int Length => !this.isReady ? 0 : Marshal.ReadByte(partyListBegin + 0xF0); From 77d4502b60a93af15365e73c0981ae98b684e826 Mon Sep 17 00:00:00 2001 From: Caraxi Date: Wed, 3 Jun 2020 09:00:58 +0930 Subject: [PATCH 5/5] Create PluginStatsWindow and track times for plugin BuildUI event --- Dalamud/Dalamud.cs | 16 ++++ Dalamud/Interface/DalamudPluginStatWindow.cs | 87 ++++++++++++++++++++ Dalamud/Interface/UiBuilder.cs | 20 +++++ 3 files changed, 123 insertions(+) create mode 100644 Dalamud/Interface/DalamudPluginStatWindow.cs diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs index d09bf92c8..336666704 100644 --- a/Dalamud/Dalamud.cs +++ b/Dalamud/Dalamud.cs @@ -211,6 +211,7 @@ namespace Dalamud { private bool isImguiDrawPluginWindow = false; private bool isImguiDrawCreditsWindow = false; private bool isImguiDrawSettingsWindow = false; + private bool isImguiDrawPluginStatWindow = false; private DalamudLogWindow logWindow; private DalamudDataWindow dataWindow; @@ -218,6 +219,7 @@ namespace Dalamud { private DalamudSettingsWindow settingsWindow; private PluginInstallerWindow pluginWindow; private ConditionDebugWindow conditionDebugWindow; + private DalamudPluginStatWindow pluginStatWindow; private void BuildDalamudUi() { @@ -294,6 +296,12 @@ namespace Dalamud { this.pluginWindow = new PluginInstallerWindow(this.PluginManager, this.PluginRepository, this.StartInfo.GameVersion); this.isImguiDrawPluginWindow = true; } + if (ImGui.MenuItem("Open Plugin Stats")) { + if (!this.isImguiDrawPluginStatWindow) { + this.pluginStatWindow = new DalamudPluginStatWindow(this.PluginManager); + this.isImguiDrawPluginStatWindow = true; + } + } if (ImGui.MenuItem("Print plugin info")) { foreach (var plugin in this.PluginManager.Plugins) { // TODO: some more here, state maybe? @@ -396,6 +404,14 @@ namespace Dalamud { { this.conditionDebugWindow.Draw(); } + + if (this.isImguiDrawPluginStatWindow) { + this.isImguiDrawPluginStatWindow = this.pluginStatWindow != null && this.pluginStatWindow.Draw(); + if (!this.isImguiDrawPluginStatWindow) { + this.pluginStatWindow?.Dispose(); + this.pluginStatWindow = null; + } + } } #endregion diff --git a/Dalamud/Interface/DalamudPluginStatWindow.cs b/Dalamud/Interface/DalamudPluginStatWindow.cs new file mode 100644 index 000000000..7862075f1 --- /dev/null +++ b/Dalamud/Interface/DalamudPluginStatWindow.cs @@ -0,0 +1,87 @@ +using System; +using System.Linq; +using Dalamud.Plugin; +using ImGuiNET; + +namespace Dalamud.Interface { + class DalamudPluginStatWindow : IDisposable { + + private PluginManager pm; + public DalamudPluginStatWindow(PluginManager pm) { + this.pm = pm; + } + + public bool Draw() { + bool doDraw = true; + ImGui.PushID("DalamudPluginStatWindow"); + ImGui.Begin("Plugin Statistics", ref doDraw); + ImGui.BeginTabBar("Stat Tabs"); + + if (ImGui.BeginTabItem("Draw times")) { + + bool doStats = UiBuilder.DoStats; + + if (ImGui.Checkbox("Enable Draw Time Tracking", ref doStats)) { + UiBuilder.DoStats = doStats; + } + + if (doStats) { + + ImGui.SameLine(); + if (ImGui.Button("Reset")) { + foreach (var a in this.pm.Plugins) { + a.PluginInterface.UiBuilder.lastDrawTime = -1; + a.PluginInterface.UiBuilder.maxDrawTime = -1; + a.PluginInterface.UiBuilder.drawTimeHistory.Clear(); + } + } + + + ImGui.Columns(4); + ImGui.SetColumnWidth(0, 180f); + ImGui.SetColumnWidth(1, 100f); + ImGui.SetColumnWidth(2, 100f); + ImGui.SetColumnWidth(3, 100f); + ImGui.Text("Plugin"); + ImGui.NextColumn(); + ImGui.Text("Last"); + ImGui.NextColumn(); + ImGui.Text("Longest"); + ImGui.NextColumn(); + ImGui.Text("Average"); + ImGui.NextColumn(); + ImGui.Separator(); + foreach (var a in this.pm.Plugins) { + ImGui.Text(a.Definition.Name); + ImGui.NextColumn(); + ImGui.Text($"{a.PluginInterface.UiBuilder.lastDrawTime/10000f:F4}ms"); + ImGui.NextColumn(); + ImGui.Text($"{a.PluginInterface.UiBuilder.maxDrawTime/10000f:F4}ms"); + ImGui.NextColumn(); + if (a.PluginInterface.UiBuilder.drawTimeHistory.Count > 0) { + ImGui.Text($"{a.PluginInterface.UiBuilder.drawTimeHistory.Average()/10000f:F4}ms"); + } else { + ImGui.Text("-"); + } + ImGui.NextColumn(); + } + + ImGui.Columns(1); + + } + + } + + ImGui.EndTabBar(); + + ImGui.End(); + ImGui.PopID(); + + return doDraw; + } + + public void Dispose() { + + } + } +} diff --git a/Dalamud/Interface/UiBuilder.cs b/Dalamud/Interface/UiBuilder.cs index b6e4e0914..edddc2232 100644 --- a/Dalamud/Interface/UiBuilder.cs +++ b/Dalamud/Interface/UiBuilder.cs @@ -32,6 +32,15 @@ namespace Dalamud.Interface public event RawDX11Scene.BuildUIDelegate OnBuildUi; private readonly InterfaceManager interfaceManager; + #if DEBUG + internal static bool DoStats { get; set; } = true; + #else + internal static bool DoStats { get; set; } = false; + #endif + private System.Diagnostics.Stopwatch stopwatch; + internal long lastDrawTime = -1; + internal long maxDrawTime = -1; + internal List drawTimeHistory = new List(); /// /// Create a new UiBuilder and register it. You do not have to call this manually. @@ -43,6 +52,7 @@ namespace Dalamud.Interface this.interfaceManager = interfaceManager; this.interfaceManager.OnDraw += OnDraw; + this.stopwatch = new System.Diagnostics.Stopwatch(); } /// @@ -109,6 +119,9 @@ namespace Dalamud.Interface private void OnDraw() { ImGui.PushID(this.namespaceName); + if (DoStats) { + this.stopwatch.Restart(); + } if (this.hasErrorWindow && ImGui.Begin(string.Format("{0} Error", this.namespaceName), ref this.hasErrorWindow, ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize)) { @@ -132,6 +145,13 @@ namespace Dalamud.Interface this.hasErrorWindow = true; } + if (DoStats) { + this.stopwatch.Stop(); + this.lastDrawTime = this.stopwatch.ElapsedTicks; + this.maxDrawTime = Math.Max(this.lastDrawTime, this.maxDrawTime); + this.drawTimeHistory.Add(lastDrawTime); + while (drawTimeHistory.Count > 100) drawTimeHistory.RemoveAt(0); + } ImGui.PopID(); } }