using Dalamud.Game.ClientState.Objects.Types; using LightlessSync.PlayerData.Handlers; using LightlessSync.Services; using LightlessSync.Services.Mediator; using LightlessSync.Utils; using Microsoft.Extensions.Logging; using System.Collections.Concurrent; namespace LightlessSync.Interop.Ipc; public class RedrawManager { private readonly LightlessMediator _lightlessMediator; private readonly DalamudUtilService _dalamudUtil; private readonly ConcurrentDictionary _penumbraRedrawRequests = []; private CancellationTokenSource _disposalCts = new(); public SemaphoreSlim RedrawSemaphore { get; init; } = new(2, 2); public RedrawManager(LightlessMediator lightlessMediator, DalamudUtilService dalamudUtil) { _lightlessMediator = lightlessMediator; _dalamudUtil = dalamudUtil; } public async Task PenumbraRedrawInternalAsync(ILogger logger, GameObjectHandler handler, Guid applicationId, Action action, CancellationToken token) { _lightlessMediator.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; _lightlessMediator.Publish(new PenumbraEndRedrawMessage(handler.Address)); } } internal void Cancel() { _disposalCts = _disposalCts.CancelRecreate(); } }