using Dalamud.Game.ClientState.Objects.Types; using MareSynchronos.PlayerData.Handlers; using MareSynchronos.Services; using MareSynchronos.Services.Mediator; using MareSynchronos.Utils; using Microsoft.Extensions.Logging; using System.Collections.Concurrent; namespace MareSynchronos.Interop.Ipc; public class RedrawManager { private readonly MareMediator _mareMediator; private readonly DalamudUtilService _dalamudUtil; private readonly ConcurrentDictionary _penumbraRedrawRequests = []; private CancellationTokenSource _disposalCts = new(); public SemaphoreSlim RedrawSemaphore { get; init; } = new(2, 2); public RedrawManager(MareMediator mareMediator, DalamudUtilService dalamudUtil) { _mareMediator = mareMediator; _dalamudUtil = dalamudUtil; } public async Task PenumbraRedrawInternalAsync(ILogger logger, GameObjectHandler handler, Guid applicationId, Action action, CancellationToken token) { _mareMediator.Publish(new PenumbraStartRedrawMessage(handler.Address)); _penumbraRedrawRequests[handler.Address] = true; try { using CancellationTokenSource cancelToken = new CancellationTokenSource(); using CancellationTokenSource combinedCts = CancellationTokenSource.CreateLinkedTokenSource(cancelToken.Token, token, _disposalCts.Token); var combinedToken = combinedCts.Token; cancelToken.CancelAfter(TimeSpan.FromSeconds(15)); await handler.ActOnFrameworkAfterEnsureNoDrawAsync(action, combinedToken).ConfigureAwait(false); if (!_disposalCts.Token.IsCancellationRequested) await _dalamudUtil.WaitWhileCharacterIsDrawing(logger, handler, applicationId, 30000, combinedToken).ConfigureAwait(false); } finally { _penumbraRedrawRequests[handler.Address] = false; _mareMediator.Publish(new PenumbraEndRedrawMessage(handler.Address)); } } internal void Cancel() { _disposalCts = _disposalCts.CancelRecreate(); } }