async waitwhilecharacterisdrawing

This commit is contained in:
rootdarkarchon
2023-02-27 02:30:50 +01:00
parent 1aef3b1d2e
commit d1514472c1
6 changed files with 50 additions and 20 deletions

View File

@@ -131,7 +131,7 @@ public class CharacterDataFactory : MediatorSubscriberBase
} }
// wait until chara is not drawing and present so nothing spontaneously explodes // wait until chara is not drawing and present so nothing spontaneously explodes
_dalamudUtil.WaitWhileCharacterIsDrawing(_logger, playerRelatedObject, Guid.NewGuid(), 30000, ct: token); await _dalamudUtil.WaitWhileCharacterIsDrawing(_logger, playerRelatedObject, Guid.NewGuid(), 30000, ct: token).ConfigureAwait(false);
int totalWaitTime = 10000; int totalWaitTime = 10000;
while (!DalamudUtil.IsObjectPresent(_dalamudUtil.CreateGameObject(charaPointer)) && totalWaitTime > 0) while (!DalamudUtil.IsObjectPresent(_dalamudUtil.CreateGameObject(charaPointer)) && totalWaitTime > 0)
{ {

View File

@@ -11,16 +11,18 @@ public class GameObjectHandlerFactory
private readonly ILoggerFactory _loggerFactory; private readonly ILoggerFactory _loggerFactory;
private readonly MareMediator _mediator; private readonly MareMediator _mediator;
private readonly PerformanceCollector _performanceCollector; private readonly PerformanceCollector _performanceCollector;
private readonly DalamudUtil _dalamudUtil;
public GameObjectHandlerFactory(ILoggerFactory loggerFactory, MareMediator mediator, PerformanceCollector performanceCollector) public GameObjectHandlerFactory(ILoggerFactory loggerFactory, MareMediator mediator, PerformanceCollector performanceCollector, DalamudUtil dalamudUtil)
{ {
_loggerFactory = loggerFactory; _loggerFactory = loggerFactory;
_mediator = mediator; _mediator = mediator;
_performanceCollector = performanceCollector; _performanceCollector = performanceCollector;
_dalamudUtil = dalamudUtil;
} }
public GameObjectHandler Create(ObjectKind objectKind, Func<IntPtr> getAddress, bool isWatched) public GameObjectHandler Create(ObjectKind objectKind, Func<IntPtr> getAddress, bool isWatched)
{ {
return new GameObjectHandler(_loggerFactory.CreateLogger<GameObjectHandler>(), _performanceCollector, _mediator, objectKind, getAddress, isWatched); return new GameObjectHandler(_loggerFactory.CreateLogger<GameObjectHandler>(), _performanceCollector, _mediator, _dalamudUtil, objectKind, getAddress, isWatched);
} }
} }

View File

@@ -310,7 +310,7 @@ public class CachedPlayer : MediatorSubscriberBase, IDisposable
} }
_logger.LogDebug("[{applicationId}] Applying Customization Data for {handler}", applicationId, handler); _logger.LogDebug("[{applicationId}] Applying Customization Data for {handler}", applicationId, handler);
_dalamudUtil.WaitWhileCharacterIsDrawing(_logger, handler, applicationId, 30000); await _dalamudUtil.WaitWhileCharacterIsDrawing(_logger, handler, applicationId, 30000).ConfigureAwait(false);
foreach (var change in changes.Value) foreach (var change in changes.Value)
{ {
_logger.LogDebug("[{applicationId}] Processing {change} for {handler}", applicationId, change, handler); _logger.LogDebug("[{applicationId}] Processing {change} for {handler}", applicationId, change, handler);
@@ -445,7 +445,7 @@ public class CachedPlayer : MediatorSubscriberBase, IDisposable
Task.Run(async () => Task.Run(async () =>
{ {
var applicationId = Guid.NewGuid(); var applicationId = Guid.NewGuid();
_dalamudUtil.WaitWhileCharacterIsDrawing(_logger, _currentOtherChara!, applicationId, ct: token); await _dalamudUtil.WaitWhileCharacterIsDrawing(_logger, _currentOtherChara!, applicationId, ct: token).ConfigureAwait(false);
_logger.LogDebug("Unauthorized character change detected"); _logger.LogDebug("Unauthorized character change detected");
await ApplyCustomizationData(applicationId, new(ObjectKind.Player, await ApplyCustomizationData(applicationId, new(ObjectKind.Player,
new HashSet<PlayerChanges>(new[] { PlayerChanges.Palette, PlayerChanges.Customize, PlayerChanges.Heels, PlayerChanges.Mods })), new HashSet<PlayerChanges>(new[] { PlayerChanges.Palette, PlayerChanges.Customize, PlayerChanges.Heels, PlayerChanges.Mods })),

View File

@@ -414,7 +414,7 @@ public class IpcManager : MediatorSubscriberBase, IDisposable
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
if (!combinedToken.IsCancellationRequested) if (!combinedToken.IsCancellationRequested)
_dalamudUtil.WaitWhileCharacterIsDrawing(logger, obj, applicationId, 30000, combinedToken); await _dalamudUtil.WaitWhileCharacterIsDrawing(logger, obj, applicationId, 30000, combinedToken).ConfigureAwait(false);
_penumbraRedrawRequests[obj.Address] = false; _penumbraRedrawRequests[obj.Address] = false;
} }

View File

@@ -15,6 +15,7 @@ public class GameObjectHandler : MediatorSubscriberBase
private readonly Func<IntPtr> _getAddress; private readonly Func<IntPtr> _getAddress;
private readonly bool _isOwnedObject; private readonly bool _isOwnedObject;
private readonly MareMediator _mediator; private readonly MareMediator _mediator;
private readonly DalamudUtil _dalamudUtil;
private readonly PerformanceCollector _performanceCollector; private readonly PerformanceCollector _performanceCollector;
private CancellationTokenSource? _clearCts = new(); private CancellationTokenSource? _clearCts = new();
private Task? _clearTask; private Task? _clearTask;
@@ -22,11 +23,13 @@ public class GameObjectHandler : MediatorSubscriberBase
private bool _haltProcessing = false; private bool _haltProcessing = false;
private bool _ignoreSendAfterRedraw = false; private bool _ignoreSendAfterRedraw = false;
private CancellationTokenSource _zoningCts = new(); private CancellationTokenSource _zoningCts = new();
public GameObjectHandler(ILogger<GameObjectHandler> logger, PerformanceCollector performanceCollector, MareMediator mediator, ObjectKind objectKind, Func<IntPtr> getAddress, bool watchedObject = true) : base(logger, mediator) public GameObjectHandler(ILogger<GameObjectHandler> logger, PerformanceCollector performanceCollector,
MareMediator mediator, DalamudUtil dalamudUtil, ObjectKind objectKind, Func<IntPtr> getAddress, bool watchedObject = true) : base(logger, mediator)
{ {
_performanceCollector = performanceCollector; _performanceCollector = performanceCollector;
_mediator = mediator; _mediator = mediator;
ObjectKind = objectKind; ObjectKind = objectKind;
_dalamudUtil = dalamudUtil;
_getAddress = getAddress; _getAddress = getAddress;
_isOwnedObject = watchedObject; _isOwnedObject = watchedObject;
Name = string.Empty; Name = string.Empty;
@@ -86,7 +89,6 @@ public class GameObjectHandler : MediatorSubscriberBase
public unsafe Character* Character => (Character*)Address; public unsafe Character* Character => (Character*)Address;
public IntPtr CurrentAddress => _getAddress.Invoke(); public IntPtr CurrentAddress => _getAddress.Invoke();
public bool IsBeingDrawn { get; private set; }
public string Name { get; private set; } public string Name { get; private set; }
public ObjectKind ObjectKind { get; } public ObjectKind ObjectKind { get; }
private byte[] CustomizeData { get; set; } = new byte[26]; private byte[] CustomizeData { get; set; } = new byte[26];
@@ -110,6 +112,41 @@ public class GameObjectHandler : MediatorSubscriberBase
return $"{owned}/{ObjectKind}:{Name} ({Address:X},{DrawObjectAddress:X})"; return $"{owned}/{ObjectKind}:{Name} ({Address:X},{DrawObjectAddress:X})";
} }
private unsafe IntPtr GetDrawObj()
{
return (IntPtr)((GameObject*)_getAddress.Invoke())->GetDrawObject();
}
private unsafe bool IsBeingDrawn(IntPtr drawObj, IntPtr curPtr)
{
return drawObj == IntPtr.Zero || (((CharacterBase*)drawObj)->HasModelInSlotLoaded != 0)
|| (((CharacterBase*)drawObj)->HasModelFilesInSlotLoaded != 0)
|| (((GameObject*)curPtr)->RenderFlags & 0b100000000000) == 0b100000000000;
}
public async Task<bool> IsBeingDrawn()
{
var curPtr = _getAddress.Invoke();
try
{
return await _dalamudUtil.RunOnFrameworkThread(() =>
{
var drawObj = GetDrawObj();
return IsBeingDrawn(drawObj, curPtr);
}).ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error during checking for draw object for {name}", curPtr);
if (curPtr != IntPtr.Zero)
{
return true;
}
}
return false;
}
private unsafe void CheckAndUpdateObject() private unsafe void CheckAndUpdateObject()
{ {
if (_haltProcessing) return; if (_haltProcessing) return;
@@ -123,21 +160,12 @@ public class GameObjectHandler : MediatorSubscriberBase
var drawObjAddr = (IntPtr)((GameObject*)curPtr)->GetDrawObject(); var drawObjAddr = (IntPtr)((GameObject*)curPtr)->GetDrawObject();
drawObjDiff = drawObjAddr != DrawObjectAddress; drawObjDiff = drawObjAddr != DrawObjectAddress;
DrawObjectAddress = drawObjAddr; DrawObjectAddress = drawObjAddr;
IsBeingDrawn = DrawObjectAddress == IntPtr.Zero || (((CharacterBase*)DrawObjectAddress)->HasModelInSlotLoaded != 0)
|| (((CharacterBase*)DrawObjectAddress)->HasModelFilesInSlotLoaded != 0)
|| (((GameObject*)curPtr)->RenderFlags & 0b100000000000) == 0b100000000000;
} }
} }
catch (Exception ex) catch (Exception ex)
{ {
var name = new ByteString(((Character*)curPtr)->GameObject.Name).ToString(); var name = new ByteString(((Character*)curPtr)->GameObject.Name).ToString();
_logger.LogError(ex, "Error during checking for draw object for {name}", this); _logger.LogError(ex, "Error during checking for draw object for {name}", this);
if (curPtr != IntPtr.Zero)
{
IsBeingDrawn = true;
}
} }
if (curPtr != IntPtr.Zero && DrawObjectAddress != IntPtr.Zero) if (curPtr != IntPtr.Zero && DrawObjectAddress != IntPtr.Zero)
@@ -206,7 +234,7 @@ public class GameObjectHandler : MediatorSubscriberBase
private unsafe bool CompareAndUpdateCustomizeData(byte* customizeData) private unsafe bool CompareAndUpdateCustomizeData(byte* customizeData)
{ {
bool hasChanges = false; bool hasChanges = false;
for (int i = 0; i < CustomizeData.Length; i++) for (int i = 0; i < CustomizeData.Length; i++)
{ {
var data = Marshal.ReadByte((IntPtr)customizeData, i); var data = Marshal.ReadByte((IntPtr)customizeData, i);

View File

@@ -262,7 +262,7 @@ public class DalamudUtil : IDisposable
return await _framework.RunOnFrameworkThread(func).ConfigureAwait(false); return await _framework.RunOnFrameworkThread(func).ConfigureAwait(false);
} }
public unsafe void WaitWhileCharacterIsDrawing(ILogger logger, GameObjectHandler handler, Guid redrawId, int timeOut = 5000, CancellationToken? ct = null) public async Task WaitWhileCharacterIsDrawing(ILogger logger, GameObjectHandler handler, Guid redrawId, int timeOut = 5000, CancellationToken? ct = null)
{ {
if (!_clientState.IsLoggedIn || handler.Address == IntPtr.Zero) return; if (!_clientState.IsLoggedIn || handler.Address == IntPtr.Zero) return;
@@ -275,7 +275,7 @@ public class DalamudUtil : IDisposable
// ReSharper disable once LoopVariableIsNeverChangedInsideLoop // ReSharper disable once LoopVariableIsNeverChangedInsideLoop
while ((!ct?.IsCancellationRequested ?? true) while ((!ct?.IsCancellationRequested ?? true)
&& curWaitTime < timeOut && curWaitTime < timeOut
&& handler.IsBeingDrawn) // 0b100000000000 is "still rendering" or something && await handler.IsBeingDrawn().ConfigureAwait(false)) // 0b100000000000 is "still rendering" or something
{ {
logger.LogTrace($"[{redrawId}] Waiting for {handler} to finish drawing"); logger.LogTrace($"[{redrawId}] Waiting for {handler} to finish drawing");
curWaitTime += tick; curWaitTime += tick;