diff --git a/MareSynchronos/Factories/CharacterDataFactory.cs b/MareSynchronos/Factories/CharacterDataFactory.cs index 90be2f5..91705c0 100644 --- a/MareSynchronos/Factories/CharacterDataFactory.cs +++ b/MareSynchronos/Factories/CharacterDataFactory.cs @@ -239,7 +239,7 @@ public class CharacterDataFactory Thread.Sleep(50); } - _dalamudUtil.WaitWhileCharacterIsDrawing(charaPointer); + _dalamudUtil.WaitWhileCharacterIsDrawing(objectKind.ToString(), charaPointer); Stopwatch st = Stopwatch.StartNew(); diff --git a/MareSynchronos/Managers/CachedPlayer.cs b/MareSynchronos/Managers/CachedPlayer.cs index 063d05f..f64364c 100644 --- a/MareSynchronos/Managers/CachedPlayer.cs +++ b/MareSynchronos/Managers/CachedPlayer.cs @@ -165,7 +165,7 @@ public class CachedPlayer foreach (var kind in objectKind) { - ApplyCustomizationData(kind); + ApplyCustomizationData(kind, downloadToken); } }, downloadToken).ContinueWith(task => { @@ -225,14 +225,15 @@ public class CachedPlayer _ipcManager.PenumbraSetTemporaryMods(PlayerName!, moddedPaths, _cachedData.ManipulationData); } - private unsafe void ApplyCustomizationData(ObjectKind objectKind) + private unsafe void ApplyCustomizationData(ObjectKind objectKind, CancellationToken ct) { if (PlayerCharacter == IntPtr.Zero) return; _cachedData.GlamourerData.TryGetValue(objectKind, out var glamourerData); if (objectKind == ObjectKind.Player) { - _dalamudUtil.WaitWhileCharacterIsDrawing(PlayerCharacter); + _dalamudUtil.WaitWhileCharacterIsDrawing(PlayerName!, PlayerCharacter, ct); + ct.ThrowIfCancellationRequested(); RequestedPenumbraRedraw = true; Logger.Debug( $"Request Redraw for {PlayerName}"); @@ -251,7 +252,8 @@ public class CachedPlayer if (minionOrMount != null) { Logger.Debug($"Request Redraw for Minion/Mount"); - _dalamudUtil.WaitWhileCharacterIsDrawing((IntPtr)minionOrMount); + _dalamudUtil.WaitWhileCharacterIsDrawing(PlayerName! + " minion or mount", (IntPtr)minionOrMount, ct); + ct.ThrowIfCancellationRequested(); if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData)) { _ipcManager.GlamourerApplyAll(glamourerData, obj: (IntPtr)minionOrMount); @@ -296,7 +298,8 @@ public class CachedPlayer if (companion != IntPtr.Zero) { Logger.Debug("Request Redraw for Companion"); - _dalamudUtil.WaitWhileCharacterIsDrawing(companion); + _dalamudUtil.WaitWhileCharacterIsDrawing(PlayerName! + " companion", companion, ct); + ct.ThrowIfCancellationRequested(); if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData)) { _ipcManager.GlamourerApplyAll(glamourerData, companion); @@ -441,14 +444,16 @@ public class CachedPlayer _penumbraRedrawEventTask = Task.Run(() => { PlayerCharacter = address; - using var cts = new CancellationTokenSource(); + var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromSeconds(5)); + _dalamudUtil.WaitWhileCharacterIsDrawing(PlayerName!, PlayerCharacter, cts.Token); + cts.Dispose(); + cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromSeconds(5)); - _dalamudUtil.WaitWhileCharacterIsDrawing(PlayerCharacter, cts.Token); - if (RequestedPenumbraRedraw == false) { Logger.Debug("Unauthorized character change detected"); - ApplyCustomizationData(ObjectKind.Player); + ApplyCustomizationData(ObjectKind.Player, cts.Token); } else { @@ -456,6 +461,7 @@ public class CachedPlayer Logger.Debug( $"Penumbra Redraw done for {PlayerName}"); } + cts.Dispose(); }); } diff --git a/MareSynchronos/Managers/IpcManager.cs b/MareSynchronos/Managers/IpcManager.cs index dcbc3f7..39cd723 100644 --- a/MareSynchronos/Managers/IpcManager.cs +++ b/MareSynchronos/Managers/IpcManager.cs @@ -142,10 +142,12 @@ namespace MareSynchronos.Managers int totalSleepTime = 0; while (actionQueue.Count > 0 && totalSleepTime < 2000) { + Logger.Verbose("Waiting for actionqueue to clear..."); System.Threading.Thread.Sleep(16); totalSleepTime += 16; } + Logger.Verbose("Action queue clear or not, disposing"); _dalamudUtil.FrameworkUpdate -= HandleActionQueue; actionQueue.Clear(); diff --git a/MareSynchronos/Managers/PlayerManager.cs b/MareSynchronos/Managers/PlayerManager.cs index ad37f3f..cdca271 100644 --- a/MareSynchronos/Managers/PlayerManager.cs +++ b/MareSynchronos/Managers/PlayerManager.cs @@ -200,7 +200,7 @@ namespace MareSynchronos.Managers { foreach(var item in unprocessedObjects) { - _dalamudUtil.WaitWhileCharacterIsDrawing(item.Address, token); + _dalamudUtil.WaitWhileCharacterIsDrawing("self " + item.ObjectKind.ToString(), item.Address, token); } CharacterCacheDto? cacheDto = (await CreateFullCharacterCacheDto(token)); diff --git a/MareSynchronos/Utils/DalamudUtil.cs b/MareSynchronos/Utils/DalamudUtil.cs index 24409a7..070a2ad 100644 --- a/MareSynchronos/Utils/DalamudUtil.cs +++ b/MareSynchronos/Utils/DalamudUtil.cs @@ -189,18 +189,18 @@ namespace MareSynchronos.Utils return null; } - public unsafe void WaitWhileCharacterIsDrawing(IntPtr characterAddress, CancellationToken? ct = null) + public unsafe void WaitWhileCharacterIsDrawing(string name, IntPtr characterAddress, CancellationToken? ct = null) { if (!_clientState.IsLoggedIn || characterAddress == IntPtr.Zero) return; var obj = (GameObject*)characterAddress; - const int maxWaitTime = 10000; + const int maxWaitTime = 5000; const int tick = 250; int curWaitTime = 0; // ReSharper disable once LoopVariableIsNeverChangedInsideLoop while ((obj->RenderFlags & 0b100000000000) == 0b100000000000 && (!ct?.IsCancellationRequested ?? true) && curWaitTime < maxWaitTime) // 0b100000000000 is "still rendering" or something { - Logger.Verbose("Waiting for character to finish drawing"); + Logger.Verbose($"Waiting for {name} to finish drawing"); curWaitTime += tick; Thread.Sleep(tick); } @@ -210,7 +210,7 @@ namespace MareSynchronos.Utils Thread.Sleep(tick); } - public void WaitWhileSelfIsDrawing(CancellationToken? token) => WaitWhileCharacterIsDrawing(_clientState.LocalPlayer?.Address ?? IntPtr.Zero, token); + public void WaitWhileSelfIsDrawing(CancellationToken? token) => WaitWhileCharacterIsDrawing("self", _clientState.LocalPlayer?.Address ?? IntPtr.Zero, token); public void Dispose() {