diff --git a/client/PluginUi.cs b/client/PluginUi.cs index 86267a7..7122043 100644 --- a/client/PluginUi.cs +++ b/client/PluginUi.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Dalamud.Interface.Utility; using ImGuiNET; using OrangeGuidanceTomestone.Ui; @@ -102,11 +103,11 @@ public class PluginUi : IDisposable { var label = msg.Id.ToString("N"); var size = ImGui.CalcTextSize(label); ImGui.GetBackgroundDrawList().AddRectFilled( - screen, - screen + size, + screen - Vector2.One * 4 * ImGuiHelpers.GlobalScale, + screen + size + Vector2.One * 4 * ImGuiHelpers.GlobalScale, 0xff000000 ); - ImGui.GetForegroundDrawList().AddText(screen, 0xffffffff, label); + ImGui.GetBackgroundDrawList().AddText(screen, 0xffffffff, label); } } } diff --git a/client/Ui/MainWindowTabs/Settings.cs b/client/Ui/MainWindowTabs/Settings.cs index 96be8ff..9e7195d 100644 --- a/client/Ui/MainWindowTabs/Settings.cs +++ b/client/Ui/MainWindowTabs/Settings.cs @@ -4,6 +4,7 @@ using Dalamud.Utility; using ImGuiNET; using Lumina.Excel.GeneratedSheets; using OrangeGuidanceTomestone.Helpers; +using OrangeGuidanceTomestone.Util; namespace OrangeGuidanceTomestone.Ui.MainWindowTabs; @@ -21,6 +22,7 @@ internal class Settings : ITab { private IReadOnlyList<(string, DrawSettingsDelegate)> Tabs { get; } private string _filter = string.Empty; + private string _debugFilter = string.Empty; internal Settings(Plugin plugin) { this.Plugin = plugin; @@ -230,6 +232,47 @@ internal class Settings : ITab { private void DrawDebug(ref bool anyChanged, ref bool vfx) { ImGui.Checkbox("Show debug information", ref this.Plugin.Ui.Debug); + + ImGui.InputText("Filter", ref this._debugFilter, 64); + + if (ImGui.BeginTable("###debug-info", 2)) { + using var endTable = new OnDispose(ImGui.EndTable); + + ImGui.TableSetupColumn("ID", ImGuiTableColumnFlags.WidthStretch); + ImGui.TableSetupColumn("VFX pointer"); + ImGui.TableHeadersRow(); + + using var guard = this.Plugin.Vfx.Mutex.With(); + foreach (var (id, ptr) in this.Plugin.Vfx.Spawned) { + var idLabel = id.ToString("N"); + var ptrLabel = ptr.ToString("X"); + + if (!string.IsNullOrWhiteSpace(this._debugFilter)) { + if ( + !idLabel.Contains(this._debugFilter, StringComparison.CurrentCultureIgnoreCase) + && !ptrLabel.Contains(this._debugFilter, StringComparison.CurrentCultureIgnoreCase) + ) { + continue; + } + } + + ImGui.TableNextRow(); + + if (ImGui.TableSetColumnIndex(0)) { + ImGui.TextUnformatted(id.ToString("N")); + if (ImGui.IsItemClicked()) { + ImGui.SetClipboardText(id.ToString("N")); + } + } + + if (ImGui.TableSetColumnIndex(1)) { + ImGui.TextUnformatted(ptr.ToString("X")); + if (ImGui.IsItemClicked()) { + ImGui.SetClipboardText(ptr.ToString("X")); + } + } + } + } } private void ExtraCodeInput() { diff --git a/client/Vfx.cs b/client/Vfx.cs index 7139b0f..355b63a 100644 --- a/client/Vfx.cs +++ b/client/Vfx.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using System.Numerics; using System.Runtime.InteropServices; using System.Text; @@ -21,15 +22,11 @@ internal unsafe class Vfx : IDisposable { private readonly delegate* unmanaged _staticVfxRemove; private Plugin Plugin { get; } - private SemaphoreSlim Mutex { get; } = new(1, 1); - private Dictionary Spawned { get; } = []; + internal SemaphoreSlim Mutex { get; } = new(1, 1); + internal Dictionary Spawned { get; } = []; private Queue Queue { get; } = []; private bool _disposed; - - private enum Mode { - Add, - Remove, - } + private readonly Stopwatch _queueTimer = Stopwatch.StartNew(); internal Vfx(Plugin plugin) { this.Plugin = plugin; @@ -49,39 +46,44 @@ internal unsafe class Vfx : IDisposable { } private void HandleQueues(IFramework framework) { - if (!this.Queue.TryDequeue(out var action)) { - return; - } + this._queueTimer.Restart(); - switch (action) { - case AddQueueAction add: { - using var guard = this.Mutex.With(); - Plugin.Log.Debug($"adding vfx for {add.Id}"); - if (this.Spawned.Remove(add.Id, out var existing)) { - Plugin.Log.Warning($"vfx for {add.Id} already exists, queuing remove"); - this.Queue.Enqueue(new RemoveRawQueueAction(existing)); - } - - var vfx = this.SpawnStatic(add.Id, add.Path, add.Position, add.Rotation); - this.Spawned[add.Id] = (nint) vfx; - break; + while (this._queueTimer.Elapsed < TimeSpan.FromMilliseconds(1)) { + if (!this.Queue.TryDequeue(out var action)) { + return; } - case RemoveQueueAction remove: { - using var guard = this.Mutex.With(); - Plugin.Log.Debug($"removing vfx for {remove.Id}"); - if (!this.Spawned.Remove(remove.Id, out var ptr)) { + switch (action) { + case AddQueueAction add: { + using var guard = this.Mutex.With(); + Plugin.Log.Debug($"adding vfx for {add.Id}"); + if (this.Spawned.Remove(add.Id, out var existing)) { + Plugin.Log.Warning($"vfx for {add.Id} already exists, queuing remove"); + this.Queue.Enqueue(new RemoveRawQueueAction(existing)); + } + + var vfx = this.SpawnStatic(add.Path, add.Position, add.Rotation); + this.Spawned[add.Id] = (nint) vfx; break; } - this.RemoveStatic((VfxStruct*) ptr); - break; - }; + case RemoveQueueAction remove: { + using var guard = this.Mutex.With(); + Plugin.Log.Debug($"removing vfx for {remove.Id}"); + if (!this.Spawned.Remove(remove.Id, out var ptr)) { + break; + } - case RemoveRawQueueAction remove: { - Plugin.Log.Debug($"removing raw vfx at {remove.Pointer:X}"); - this.RemoveStatic((VfxStruct*) remove.Pointer); - break; + this.RemoveStatic((VfxStruct*) ptr); + break; + } + ; + + case RemoveRawQueueAction remove: { + Plugin.Log.Debug($"removing raw vfx at {remove.Pointer:X}"); + this.RemoveStatic((VfxStruct*) remove.Pointer); + break; + } } } } @@ -114,7 +116,7 @@ internal unsafe class Vfx : IDisposable { } } - private VfxStruct* SpawnStatic(Guid id, string path, Vector3 pos, Quaternion rotation) { + private VfxStruct* SpawnStatic(string path, Vector3 pos, Quaternion rotation) { VfxStruct* vfx; fixed (byte* p = Encoding.UTF8.GetBytes(path).NullTerminate()) { fixed (byte* pool = Pool) { @@ -131,6 +133,9 @@ internal unsafe class Vfx : IDisposable { // update rotation vfx->Rotation = new Quaternion(rotation.X, rotation.Y, rotation.Z, rotation.W); + // remove flag that sometimes causes vfx to not appear? + vfx->SomeFlags &= 0xF7; + // update vfx->Flags |= 2; @@ -168,6 +173,9 @@ internal unsafe class Vfx : IDisposable { [FieldOffset(0x1C0)] public int StaticTarget; + + [FieldOffset(0x248)] + public byte SomeFlags; } }