95 lines
2.9 KiB
C#
95 lines
2.9 KiB
C#
using Dalamud.Game.ClientState.Objects.Types;
|
|
using System;
|
|
using MareSynchronos.PlayerData.Handlers;
|
|
using MareSynchronos.Services;
|
|
using MareSynchronos.Services.Mediator;
|
|
using Microsoft.Extensions.Logging;
|
|
using System.Collections.Concurrent;
|
|
|
|
namespace MareSynchronos.Interop.Ipc;
|
|
|
|
public class RedrawManager : IDisposable
|
|
{
|
|
private readonly MareMediator _mareMediator;
|
|
private readonly DalamudUtilService _dalamudUtil;
|
|
private readonly ConcurrentDictionary<nint, bool> _penumbraRedrawRequests = [];
|
|
private CancellationTokenSource? _disposalCts = new();
|
|
private bool _disposed;
|
|
|
|
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<ICharacter> 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, EnsureFreshCts(ref _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()
|
|
{
|
|
EnsureFreshCts(ref _disposalCts);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (_disposed) return;
|
|
if (disposing)
|
|
{
|
|
CancelAndDispose(ref _disposalCts);
|
|
}
|
|
|
|
_disposed = true;
|
|
}
|
|
|
|
private static CancellationTokenSource EnsureFreshCts(ref CancellationTokenSource? cts)
|
|
{
|
|
CancelAndDispose(ref cts);
|
|
cts = new CancellationTokenSource();
|
|
return cts;
|
|
}
|
|
|
|
private static void CancelAndDispose(ref CancellationTokenSource? cts)
|
|
{
|
|
if (cts == null) return;
|
|
try
|
|
{
|
|
cts.Cancel();
|
|
}
|
|
catch (ObjectDisposedException)
|
|
{
|
|
}
|
|
|
|
cts.Dispose();
|
|
cts = null;
|
|
}
|
|
}
|