diff --git a/Dalamud/Dalamud.cs b/Dalamud/Dalamud.cs index be0acb0a2..336666704 100644 --- a/Dalamud/Dalamud.cs +++ b/Dalamud/Dalamud.cs @@ -151,6 +151,8 @@ namespace Dalamud { IsReady = true; }); + + this.conditionDebugWindow = new ConditionDebugWindow( this ); } public void Start() { @@ -209,12 +211,15 @@ namespace Dalamud { private bool isImguiDrawPluginWindow = false; private bool isImguiDrawCreditsWindow = false; private bool isImguiDrawSettingsWindow = false; + private bool isImguiDrawPluginStatWindow = false; private DalamudLogWindow logWindow; private DalamudDataWindow dataWindow; private DalamudCreditsWindow creditsWindow; private DalamudSettingsWindow settingsWindow; private PluginInstallerWindow pluginWindow; + private ConditionDebugWindow conditionDebugWindow; + private DalamudPluginStatWindow pluginStatWindow; private void BuildDalamudUi() { @@ -274,6 +279,16 @@ namespace Dalamud { ImGui.EndMenu(); } + if( ImGui.BeginMenu( "Game" ) ) + { + if( ImGui.MenuItem( "Condition Debug" ) ) + { + this.conditionDebugWindow.Enabled = !this.conditionDebugWindow.Enabled; + } + + ImGui.EndMenu(); + } + if (ImGui.BeginMenu("Plugins")) { if (ImGui.MenuItem("Open Plugin installer")) @@ -281,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? @@ -378,6 +399,19 @@ namespace Dalamud { if (this.isImguiDrawDemoWindow) ImGui.ShowDemoWindow(); + + if( this.conditionDebugWindow.Enabled ) + { + 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/Game/ClientState/Actors/ActorTable.cs b/Dalamud/Game/ClientState/Actors/ActorTable.cs index 205f15faa..b21f5c4fb 100644 --- a/Dalamud/Game/ClientState/Actors/ActorTable.cs +++ b/Dalamud/Game/ClientState/Actors/ActorTable.cs @@ -85,34 +85,12 @@ 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 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/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); 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)] 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(); } }