diff --git a/client/Messages.cs b/client/Messages.cs index c274c24..c519a4d 100644 --- a/client/Messages.cs +++ b/client/Messages.cs @@ -199,7 +199,7 @@ internal class Messages : IDisposable { return; } - this.RemoveVfx(null, null); + this.RemoveVfx(); Task.Run(async () => { try { @@ -243,10 +243,6 @@ internal class Messages : IDisposable { } } - private void RemoveVfx(object? sender, EventArgs? e) { - this.RemoveVfx(); - } - internal void RemoveVfx() { this.Plugin.Vfx.RemoveAll(); } diff --git a/client/Vfx.cs b/client/Vfx.cs index 37f1791..8850b4b 100644 --- a/client/Vfx.cs +++ b/client/Vfx.cs @@ -1,43 +1,68 @@ using System.Numerics; using System.Runtime.InteropServices; using System.Text; +using Dalamud.Memory; +using Dalamud.Plugin.Services; using Dalamud.Utility.Signatures; namespace OrangeGuidanceTomestone; internal unsafe class Vfx : IDisposable { - private static readonly byte[] Pool = "Client.System.Scheduler.Instance.VfxObject"u8.ToArray(); + private static readonly byte[] Pool = "Client.System.Scheduler.Instance.VfxObject\0"u8.ToArray(); [Signature("E8 ?? ?? ?? ?? F3 0F 10 35 ?? ?? ?? ?? 48 89 43 08")] private delegate* unmanaged _staticVfxCreate; [Signature("E8 ?? ?? ?? ?? 8B 4B 7C 85 C9")] - private delegate* unmanaged _staticVfxRun; + private delegate* unmanaged _staticVfxRun; [Signature("40 53 48 83 EC 20 48 8B D9 48 8B 89 ?? ?? ?? ?? 48 85 C9 74 28 33 D2 E8 ?? ?? ?? ?? 48 8B 8B ?? ?? ?? ?? 48 85 C9")] - private delegate* unmanaged _staticVfxRemove; + private delegate* unmanaged _staticVfxRemove; - private Dictionary Spawned { get; } = new(); + private Plugin Plugin { get; } + private Dictionary Spawned { get; } = []; + private Queue RemoveQueue { get; } = []; + private bool _disposed; internal Vfx(Plugin plugin) { - plugin.GameInteropProvider.InitializeFromAttributes(this); + this.Plugin = plugin; + + this.Plugin.GameInteropProvider.InitializeFromAttributes(this); + this.Plugin.Framework.Update += this.OnFrameworkUpdate; } public void Dispose() { + if (this._disposed) { + return; + } + + this._disposed = true; this.RemoveAll(); } - internal void RemoveAll() { - foreach (var spawned in this.Spawned.Values) { - this.RemoveStatic((VfxStruct*) spawned); + private void OnFrameworkUpdate(IFramework framework) { + if (this._disposed && this.RemoveQueue.Count == 0) { + this.Plugin.Framework.Update -= this.OnFrameworkUpdate; } - this.Spawned.Clear(); + if (!this.RemoveQueue.TryDequeue(out var vfx)) { + return; + } + + if (!this.RemoveStatic((VfxStruct*) vfx)) { + this.RemoveQueue.Enqueue(vfx); + } + } + + internal void RemoveAll() { + foreach (var spawned in this.Spawned.Keys.ToArray()) { + this.RemoveStatic(spawned); + } } internal VfxStruct* SpawnStatic(Guid id, string path, Vector3 pos, Quaternion rotation) { VfxStruct* vfx; - fixed (byte* p = Encoding.UTF8.GetBytes(path)) { + fixed (byte* p = Encoding.UTF8.GetBytes(path).NullTerminate()) { fixed (byte* pool = Pool) { vfx = this._staticVfxCreate(p, pool); } @@ -47,11 +72,6 @@ internal unsafe class Vfx : IDisposable { return null; } - if (this._staticVfxRun(vfx, 0.0f, 0xFFFFFFFF) != 0) { - this.RemoveStatic(vfx); - return null; - } - // update position vfx->Position = new Vector3(pos.X, pos.Y, pos.Z); // update rotation @@ -60,19 +80,29 @@ internal unsafe class Vfx : IDisposable { // update vfx->Flags |= 2; - this.Spawned[id] = (IntPtr) vfx; + this._staticVfxRun(vfx, 0.0f, -1); + + this.Spawned[id] = (nint) vfx; return vfx; } - internal void RemoveStatic(VfxStruct* vfx) { - this._staticVfxRemove(vfx); + internal bool RemoveStatic(VfxStruct* vfx) { + var result = this._staticVfxRemove(vfx); + var success = result != 0; + if (!success) { + this.RemoveQueue.Enqueue((nint) vfx); + } + + return success; } internal void RemoveStatic(Guid id) { - if (this.Spawned.TryGetValue(id, out var vfx)) { - this.RemoveStatic((VfxStruct*) vfx); + if (!this.Spawned.Remove(id, out var vfx)) { + return; } + + this.RemoveStatic((VfxStruct*) vfx); } [StructLayout(LayoutKind.Explicit)]