diff --git a/MareSynchronos/Managers/CacheCreationService.cs b/MareSynchronos/Managers/CacheCreationService.cs index 06572b2..dc3e65c 100644 --- a/MareSynchronos/Managers/CacheCreationService.cs +++ b/MareSynchronos/Managers/CacheCreationService.cs @@ -16,8 +16,9 @@ public class CacheCreationService : MediatorSubscriberBase, IDisposable private readonly CancellationTokenSource _cts = new(); private readonly List _playerRelatedObjects = new(); private CancellationTokenSource _palettePlusCts = new(); + private SemaphoreSlim _cacheCreateLock = new(1); - public unsafe CacheCreationService(ILogger logger, MareMediator mediator, GameObjectHandlerFactory gameObjectHandlerFactory, + public CacheCreationService(ILogger logger, MareMediator mediator, GameObjectHandlerFactory gameObjectHandlerFactory, CharacterDataFactory characterDataFactory, DalamudUtil dalamudUtil) : base(logger, mediator) { _characterDataFactory = characterDataFactory; @@ -25,7 +26,9 @@ public class CacheCreationService : MediatorSubscriberBase, IDisposable Mediator.Subscribe(this, (msg) => { var actualMsg = (CreateCacheForObjectMessage)msg; + _cacheCreateLock.Wait(); _cachesToCreate[actualMsg.ObjectToCreateFor.ObjectKind] = actualMsg.ObjectToCreateFor; + _cacheCreateLock.Release(); }); _playerRelatedObjects.AddRange(new List() @@ -46,56 +49,44 @@ public class CacheCreationService : MediatorSubscriberBase, IDisposable Mediator.Publish(new CharacterDataCreatedMessage(_playerData.ToAPI())); }); }); + Mediator.Subscribe(this, (msg) => ProcessCacheCreation()); - Mediator.Subscribe(this, (msg) => CustomizePlusChanged((CustomizePlusMessage)msg)); - Mediator.Subscribe(this, (msg) => HeelsOffsetChanged((HeelsOffsetMessage)msg)); - Mediator.Subscribe(this, (msg) => PalettePlusChanged((PalettePlusMessage)msg)); - Mediator.Subscribe(this, (msg) => _cachesToCreate[ObjectKind.Player] = _playerRelatedObjects.First(p => p.ObjectKind == ObjectKind.Player)); + Mediator.Subscribe(this, async (_) => await AddPlayerCacheToCreate().ConfigureAwait(false)); + Mediator.Subscribe(this, async (_) => await AddPlayerCacheToCreate().ConfigureAwait(false)); + Mediator.Subscribe(this, (_) => PalettePlusChanged()); + Mediator.Subscribe(this, async (msg) => await AddPlayerCacheToCreate().ConfigureAwait(false)); } - private void PalettePlusChanged(PalettePlusMessage msg) + private async Task AddPlayerCacheToCreate() { - if (!string.Equals(msg.Data, _playerData.PalettePlusPalette, StringComparison.Ordinal)) - { - _playerData.PalettePlusPalette = msg.Data ?? string.Empty; - - _palettePlusCts?.Cancel(); - _palettePlusCts?.Dispose(); - _palettePlusCts = new(); - var token = _palettePlusCts.Token; - - Task.Run(async () => - { - await Task.Delay(TimeSpan.FromSeconds(1), token).ConfigureAwait(false); - Mediator.Publish(new CharacterDataCreatedMessage(_playerData.ToAPI())); - }, token); - } + await _cacheCreateLock.WaitAsync().ConfigureAwait(false); + _cachesToCreate[ObjectKind.Player] = _playerRelatedObjects.First(p => p.ObjectKind == ObjectKind.Player); + _cacheCreateLock.Release(); } - private void HeelsOffsetChanged(HeelsOffsetMessage msg) + private void PalettePlusChanged() { - if (msg.Offset != _playerData.HeelsOffset) - { - _playerData.HeelsOffset = msg.Offset; - Mediator.Publish(new CharacterDataCreatedMessage(_playerData.ToAPI())); - } - } + _palettePlusCts?.Cancel(); + _palettePlusCts?.Dispose(); + _palettePlusCts = new(); + var token = _palettePlusCts.Token; - private void CustomizePlusChanged(CustomizePlusMessage msg) - { - if (!string.Equals(msg.Data, _playerData.CustomizePlusScale, StringComparison.Ordinal)) + Task.Run(async () => { - _playerData.CustomizePlusScale = msg.Data ?? string.Empty; - Mediator.Publish(new CharacterDataCreatedMessage(_playerData.ToAPI())); - } + await Task.Delay(TimeSpan.FromSeconds(1), token).ConfigureAwait(false); + await AddPlayerCacheToCreate().ConfigureAwait(false); + }, token); } private void ProcessCacheCreation() { if (_cachesToCreate.Any() && (_cacheCreationTask?.IsCompleted ?? true)) { + _cacheCreateLock.Wait(); var toCreate = _cachesToCreate.ToList(); _cachesToCreate.Clear(); + _cacheCreateLock.Release(); + _cacheCreationTask = Task.Run(async () => { try diff --git a/MareSynchronos/Managers/IpcManager.cs b/MareSynchronos/Managers/IpcManager.cs index 76bf13b..2460701 100644 --- a/MareSynchronos/Managers/IpcManager.cs +++ b/MareSynchronos/Managers/IpcManager.cs @@ -508,15 +508,12 @@ public class IpcManager : MediatorSubscriberBase, IDisposable public void PenumbraRemoveTemporaryCollection(ILogger logger, Guid applicationId, string characterName) { if (!CheckPenumbraApi()) return; - ActionQueue.Enqueue(() => - { - var collName = "Mare_" + characterName; - logger.LogTrace("[{applicationId}] Removing temp collection for {collName}", applicationId, collName); - var ret = _penumbraRemoveTemporaryMod.Invoke("MareChara", collName, 0); - logger.LogTrace("[{applicationId}] RemoveTemporaryMod: {ret}", applicationId, ret); - var ret2 = _penumbraRemoveTemporaryCollection.Invoke(collName); - logger.LogTrace("[{applicationId}] RemoveTemporaryCollection: {ret2}", applicationId, ret2); - }); + var collName = "Mare_" + characterName; + logger.LogTrace("[{applicationId}] Removing temp collection for {collName}", applicationId, collName); + var ret = _penumbraRemoveTemporaryMod.Invoke("MareChara", collName, 0); + logger.LogTrace("[{applicationId}] RemoveTemporaryMod: {ret}", applicationId, ret); + var ret2 = _penumbraRemoveTemporaryCollection.Invoke(collName); + logger.LogTrace("[{applicationId}] RemoveTemporaryCollection: {ret2}", applicationId, ret2); } public string PenumbraResolvePath(string path) @@ -541,26 +538,23 @@ public class IpcManager : MediatorSubscriberBase, IDisposable { if (!CheckPenumbraApi()) return; - ActionQueue.Enqueue(() => + var idx = _dalamudUtil.GetIndexFromObjectTableByName(characterName); + if (idx == null) { - var idx = _dalamudUtil.GetIndexFromObjectTableByName(characterName); - if (idx == null) - { - return; - } - var collName = "Mare_" + characterName; - var ret = _penumbraCreateNamedTemporaryCollection.Invoke(collName); - logger.LogTrace("[{applicationId}] Creating Temp Collection {collName}, Success: {ret}", applicationId, collName, ret); - var retAssign = _penumbraAssignTemporaryCollection.Invoke(collName, idx.Value, c: true); - logger.LogTrace("[{applicationId}] Assigning Temp Collection {collName} to index {idx}", applicationId, collName, idx.Value); - foreach (var mod in modPaths) - { - logger.LogTrace("[{applicationId}] Change: {from} => {to}", applicationId, mod.Key, mod.Value); - } + return; + } + var collName = "Mare_" + characterName; + var ret = _penumbraCreateNamedTemporaryCollection.Invoke(collName); + logger.LogTrace("[{applicationId}] Creating Temp Collection {collName}, Success: {ret}", applicationId, collName, ret); + var retAssign = _penumbraAssignTemporaryCollection.Invoke(collName, idx.Value, c: true); + logger.LogTrace("[{applicationId}] Assigning Temp Collection {collName} to index {idx}", applicationId, collName, idx.Value); + foreach (var mod in modPaths) + { + logger.LogTrace("[{applicationId}] Change: {from} => {to}", applicationId, mod.Key, mod.Value); + } - var ret2 = _penumbraAddTemporaryMod.Invoke("MareChara", collName, modPaths, manipulationData, 0); - logger.LogTrace("[{applicationId}] Setting temp mods for {collName}, Success: {ret2}", applicationId, collName, ret2); - }); + var ret2 = _penumbraAddTemporaryMod.Invoke("MareChara", collName, modPaths, manipulationData, 0); + logger.LogTrace("[{applicationId}] Setting temp mods for {collName}, Success: {ret2}", applicationId, collName, ret2); } public (string[] forward, string[][] reverse) PenumbraResolvePaths(string[] forward, string[] reverse) @@ -589,20 +583,17 @@ public class IpcManager : MediatorSubscriberBase, IDisposable private void HeelsOffsetChange(float offset) { - Mediator.Publish(new HeelsOffsetMessage(offset)); + Mediator.Publish(new HeelsOffsetMessage()); } private void OnCustomizePlusScaleChange(string? scale) { - if (scale != null) scale = Convert.ToBase64String(Encoding.UTF8.GetBytes(scale)); - Mediator.Publish(new CustomizePlusMessage(scale)); + Mediator.Publish(new CustomizePlusMessage()); } private void OnPalettePlusPaletteChange(Character character, string palette) { - if (character.Address == 0 || character.Address != _dalamudUtil.PlayerPointer) return; - if (palette != null) palette = Convert.ToBase64String(Encoding.UTF8.GetBytes(palette)); - Mediator.Publish(new PalettePlusMessage(palette)); + Mediator.Publish(new PalettePlusMessage()); } public async Task PalettePlusSetPalette(IntPtr character, string palette) diff --git a/MareSynchronos/Mediator/Messages.cs b/MareSynchronos/Mediator/Messages.cs index fc2234e..720f6fe 100644 --- a/MareSynchronos/Mediator/Messages.cs +++ b/MareSynchronos/Mediator/Messages.cs @@ -25,10 +25,10 @@ public record PenumbraModSettingChangedMessage : IMessage; public record PenumbraInitializedMessage : IMessage; public record PenumbraDisposedMessage : IMessage; public record PenumbraRedrawMessage(IntPtr Address, int ObjTblIdx, bool WasRequested) : IMessage; -public record HeelsOffsetMessage(float Offset) : IMessage; +public record HeelsOffsetMessage() : IMessage; public record PenumbraResourceLoadMessage(IntPtr GameObject, string GamePath, string FilePath) : IMessage; -public record CustomizePlusMessage(string? Data) : IMessage; -public record PalettePlusMessage(string? Data) : IMessage; +public record CustomizePlusMessage() : IMessage; +public record PalettePlusMessage() : IMessage; public record PlayerChangedMessage(API.Data.CharacterData Data) : IMessage; public record CharacterChangedMessage(GameObjectHandler GameObjectHandler) : IMessage; public record TransientResourceChangedMessage(IntPtr Address) : IMessage; diff --git a/MareSynchronos/Models/GameObjectHandler.cs b/MareSynchronos/Models/GameObjectHandler.cs index 68d2297..224c752 100644 --- a/MareSynchronos/Models/GameObjectHandler.cs +++ b/MareSynchronos/Models/GameObjectHandler.cs @@ -119,7 +119,9 @@ public class GameObjectHandler : MediatorSubscriberBase private unsafe bool IsBeingDrawn(IntPtr drawObj, IntPtr curPtr) { - return drawObj == IntPtr.Zero || (((CharacterBase*)drawObj)->HasModelInSlotLoaded != 0) + _logger.LogTrace("IsBeingDrawn for ptr {curPtr} : {drawObj}", curPtr.ToString("X"), drawObj.ToString("X")); + return drawObj == IntPtr.Zero + || (((CharacterBase*)drawObj)->HasModelInSlotLoaded != 0) || (((CharacterBase*)drawObj)->HasModelFilesInSlotLoaded != 0) || (((GameObject*)curPtr)->RenderFlags & 0b100000000000) == 0b100000000000; }