attempts to fix some waiting issues I guess
This commit is contained in:
@@ -3,13 +3,16 @@ using LZ4;
|
|||||||
using MareSynchronos.FileCache;
|
using MareSynchronos.FileCache;
|
||||||
using MareSynchronos.Managers;
|
using MareSynchronos.Managers;
|
||||||
using MareSynchronos.Utils;
|
using MareSynchronos.Utils;
|
||||||
using MareSynchronos.API.Data;
|
|
||||||
using MareSynchronos.API.Data.Enum;
|
using MareSynchronos.API.Data.Enum;
|
||||||
using MareSynchronos.MareConfiguration;
|
using MareSynchronos.MareConfiguration;
|
||||||
|
using MareSynchronos.Mediator;
|
||||||
|
using MareSynchronos.Models;
|
||||||
|
using CharacterData = MareSynchronos.API.Data.CharacterData;
|
||||||
|
|
||||||
namespace MareSynchronos.Export;
|
namespace MareSynchronos.Export;
|
||||||
public class MareCharaFileManager
|
public class MareCharaFileManager
|
||||||
{
|
{
|
||||||
|
private readonly MareMediator _mediator;
|
||||||
private readonly FileCacheManager _manager;
|
private readonly FileCacheManager _manager;
|
||||||
private readonly IpcManager _ipcManager;
|
private readonly IpcManager _ipcManager;
|
||||||
private readonly MareConfigService _configService;
|
private readonly MareConfigService _configService;
|
||||||
@@ -19,9 +22,10 @@ public class MareCharaFileManager
|
|||||||
public bool CurrentlyWorking { get; private set; } = false;
|
public bool CurrentlyWorking { get; private set; } = false;
|
||||||
private static int GlobalFileCounter = 0;
|
private static int GlobalFileCounter = 0;
|
||||||
|
|
||||||
public MareCharaFileManager(FileCacheManager manager, IpcManager ipcManager, MareConfigService configService, DalamudUtil dalamudUtil)
|
public MareCharaFileManager(MareMediator mediator, FileCacheManager manager, IpcManager ipcManager, MareConfigService configService, DalamudUtil dalamudUtil)
|
||||||
{
|
{
|
||||||
_factory = new(manager);
|
_factory = new(manager);
|
||||||
|
_mediator = mediator;
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
_ipcManager = ipcManager;
|
_ipcManager = ipcManager;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
@@ -119,7 +123,8 @@ public class MareCharaFileManager
|
|||||||
_ipcManager.PenumbraSetTemporaryMods(charaTarget.Name.TextValue,
|
_ipcManager.PenumbraSetTemporaryMods(charaTarget.Name.TextValue,
|
||||||
extractedFiles.Union(fileSwaps).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal),
|
extractedFiles.Union(fileSwaps).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal),
|
||||||
LoadedCharaFile.CharaFileData.ManipulationData);
|
LoadedCharaFile.CharaFileData.ManipulationData);
|
||||||
await _ipcManager.GlamourerApplyAll(LoadedCharaFile.CharaFileData.GlamourerData, charaTarget.Address, disposeCts.Token).ConfigureAwait(false);
|
using GameObjectHandler tempHandler = new(_mediator, ObjectKind.Player, () => charaTarget.Address, false);
|
||||||
|
await _ipcManager.GlamourerApplyAll(LoadedCharaFile.CharaFileData.GlamourerData, tempHandler, disposeCts.Token).ConfigureAwait(false);
|
||||||
_dalamudUtil.WaitWhileGposeCharacterIsDrawing(charaTarget.Address, 30000);
|
_dalamudUtil.WaitWhileGposeCharacterIsDrawing(charaTarget.Address, 30000);
|
||||||
_ipcManager.PenumbraRemoveTemporaryCollection(charaTarget.Name.TextValue);
|
_ipcManager.PenumbraRemoveTemporaryCollection(charaTarget.Name.TextValue);
|
||||||
_ipcManager.ToggleGposeQueueMode(on: false);
|
_ipcManager.ToggleGposeQueueMode(on: false);
|
||||||
|
|||||||
@@ -120,7 +120,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(playerRelatedObject.ObjectKind.ToString(), playerRelatedObject.Address, 30000, ct: token);
|
_dalamudUtil.WaitWhileCharacterIsDrawing(playerRelatedObject, 30000, ct: token);
|
||||||
var chara = _dalamudUtil.CreateGameObject(charaPointer)!;
|
var chara = _dalamudUtil.CreateGameObject(charaPointer)!;
|
||||||
while (!DalamudUtil.IsObjectPresent(chara))
|
while (!DalamudUtil.IsObjectPresent(chara))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -281,18 +281,18 @@ public class CachedPlayer : MediatorSubscriberBase, IDisposable
|
|||||||
switch (objectKind)
|
switch (objectKind)
|
||||||
{
|
{
|
||||||
case ObjectKind.Player:
|
case ObjectKind.Player:
|
||||||
_dalamudUtil.WaitWhileCharacterIsDrawing(PlayerName!, PlayerCharacter, 30000);
|
_dalamudUtil.WaitWhileCharacterIsDrawing(_currentOtherChara!, 30000);
|
||||||
_ipcManager.HeelsSetOffsetForPlayer(_cachedData.HeelsOffset, PlayerCharacter);
|
_ipcManager.HeelsSetOffsetForPlayer(_cachedData.HeelsOffset, PlayerCharacter);
|
||||||
_ipcManager.CustomizePlusSetBodyScale(PlayerCharacter, _cachedData.CustomizePlusData);
|
_ipcManager.CustomizePlusSetBodyScale(PlayerCharacter, _cachedData.CustomizePlusData);
|
||||||
_ipcManager.PalettePlusSetPalette(PlayerCharacter, _cachedData.PalettePlusData);
|
_ipcManager.PalettePlusSetPalette(PlayerCharacter, _cachedData.PalettePlusData);
|
||||||
Logger.Debug($"Request Redraw for {PlayerName}");
|
Logger.Debug($"Request Redraw for {PlayerName}");
|
||||||
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
||||||
{
|
{
|
||||||
await _ipcManager.GlamourerApplyAll(glamourerData, PlayerCharacter, applicationTokenSource.Token).ConfigureAwait(false);
|
await _ipcManager.GlamourerApplyAll(glamourerData, _currentOtherChara!, applicationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _ipcManager.PenumbraRedraw(PlayerCharacter, applicationTokenSource.Token).ConfigureAwait(false);
|
await _ipcManager.PenumbraRedraw(_currentOtherChara!, applicationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -301,15 +301,18 @@ public class CachedPlayer : MediatorSubscriberBase, IDisposable
|
|||||||
var minionOrMount = _dalamudUtil.GetMinionOrMount(PlayerCharacter);
|
var minionOrMount = _dalamudUtil.GetMinionOrMount(PlayerCharacter);
|
||||||
if (minionOrMount != null)
|
if (minionOrMount != null)
|
||||||
{
|
{
|
||||||
|
using GameObjectHandler tempHandler = new(Mediator, ObjectKind.MinionOrMount,
|
||||||
|
() => minionOrMount.Value, false);
|
||||||
|
|
||||||
Logger.Debug($"Request Redraw for {PlayerName} Minion/Mount");
|
Logger.Debug($"Request Redraw for {PlayerName} Minion/Mount");
|
||||||
_dalamudUtil.WaitWhileCharacterIsDrawing(PlayerName! + " minion or mount", (IntPtr)minionOrMount, 30000);
|
_dalamudUtil.WaitWhileCharacterIsDrawing(tempHandler, 30000);
|
||||||
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
||||||
{
|
{
|
||||||
await _ipcManager.GlamourerApplyAll(glamourerData, (IntPtr)minionOrMount, applicationTokenSource.Token).ConfigureAwait(false);
|
await _ipcManager.GlamourerApplyAll(glamourerData, tempHandler, applicationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _ipcManager.PenumbraRedraw((IntPtr)minionOrMount, applicationTokenSource.Token).ConfigureAwait(false);
|
await _ipcManager.PenumbraRedraw(tempHandler, applicationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,13 +337,15 @@ public class CachedPlayer : MediatorSubscriberBase, IDisposable
|
|||||||
newPet = _dalamudUtil.GetPet(PlayerCharacter);
|
newPet = _dalamudUtil.GetPet(PlayerCharacter);
|
||||||
} while (newPet == pet && totalWait < maxWait);
|
} while (newPet == pet && totalWait < maxWait);
|
||||||
|
|
||||||
|
using var tempHandler = new GameObjectHandler(Mediator, ObjectKind.Pet, () => newPet, false);
|
||||||
|
|
||||||
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
||||||
{
|
{
|
||||||
await _ipcManager.GlamourerApplyAll(glamourerData, newPet, applicationTokenSource.Token).ConfigureAwait(false);
|
await _ipcManager.GlamourerApplyAll(glamourerData, tempHandler, applicationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _ipcManager.PenumbraRedraw(newPet, applicationTokenSource.Token).ConfigureAwait(false);
|
await _ipcManager.PenumbraRedraw(tempHandler, applicationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,14 +358,17 @@ public class CachedPlayer : MediatorSubscriberBase, IDisposable
|
|||||||
if (companion != IntPtr.Zero)
|
if (companion != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
Logger.Debug($"Request Redraw for {PlayerName} Companion");
|
Logger.Debug($"Request Redraw for {PlayerName} Companion");
|
||||||
_dalamudUtil.WaitWhileCharacterIsDrawing(PlayerName! + " companion", companion, 30000);
|
|
||||||
|
using GameObjectHandler tempHandler = new(Mediator, ObjectKind.Companion, () => companion, false);
|
||||||
|
|
||||||
|
_dalamudUtil.WaitWhileCharacterIsDrawing(tempHandler, 30000);
|
||||||
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
if (_ipcManager.CheckGlamourerApi() && !string.IsNullOrEmpty(glamourerData))
|
||||||
{
|
{
|
||||||
await _ipcManager.GlamourerApplyAll(glamourerData, companion, applicationTokenSource.Token).ConfigureAwait(false);
|
await _ipcManager.GlamourerApplyAll(glamourerData, tempHandler, applicationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _ipcManager.PenumbraRedraw(companion, applicationTokenSource.Token).ConfigureAwait(false);
|
await _ipcManager.PenumbraRedraw(tempHandler, applicationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,7 +473,7 @@ public class CachedPlayer : MediatorSubscriberBase, IDisposable
|
|||||||
|
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
_dalamudUtil.WaitWhileCharacterIsDrawing(PlayerName!, PlayerCharacter, ct: token);
|
_dalamudUtil.WaitWhileCharacterIsDrawing(_currentOtherChara!, ct: token);
|
||||||
Logger.Debug("Unauthorized character change detected");
|
Logger.Debug("Unauthorized character change detected");
|
||||||
await ApplyCustomizationData(ObjectKind.Player).ConfigureAwait(false);
|
await ApplyCustomizationData(ObjectKind.Player).ConfigureAwait(false);
|
||||||
}, token);
|
}, token);
|
||||||
@@ -481,9 +489,9 @@ public class CachedPlayer : MediatorSubscriberBase, IDisposable
|
|||||||
if (objectKind == ObjectKind.Player)
|
if (objectKind == ObjectKind.Player)
|
||||||
{
|
{
|
||||||
Logger.Debug($"Restoring Customization for {OnlineUser.User.AliasOrUID}/{PlayerName}: {_originalGlamourerData}");
|
Logger.Debug($"Restoring Customization for {OnlineUser.User.AliasOrUID}/{PlayerName}: {_originalGlamourerData}");
|
||||||
await _ipcManager.GlamourerApplyOnlyCustomization(_originalGlamourerData, PlayerCharacter, cancelToken.Token, fireAndForget: true).ConfigureAwait(false);
|
await _ipcManager.GlamourerApplyOnlyCustomization(_originalGlamourerData, _currentOtherChara!, cancelToken.Token, fireAndForget: true).ConfigureAwait(false);
|
||||||
Logger.Debug($"Restoring Equipment for {OnlineUser.User.AliasOrUID}/{PlayerName}: {_lastGlamourerData}");
|
Logger.Debug($"Restoring Equipment for {OnlineUser.User.AliasOrUID}/{PlayerName}: {_lastGlamourerData}");
|
||||||
await _ipcManager.GlamourerApplyOnlyEquipment(_lastGlamourerData, PlayerCharacter, cancelToken.Token, fireAndForget: true).ConfigureAwait(false);
|
await _ipcManager.GlamourerApplyOnlyEquipment(_lastGlamourerData, _currentOtherChara!, cancelToken.Token, fireAndForget: true).ConfigureAwait(false);
|
||||||
Logger.Debug($"Restoring Heels for {OnlineUser.User.AliasOrUID}/{PlayerName}");
|
Logger.Debug($"Restoring Heels for {OnlineUser.User.AliasOrUID}/{PlayerName}");
|
||||||
_ipcManager.HeelsRestoreOffsetForPlayer(PlayerCharacter);
|
_ipcManager.HeelsRestoreOffsetForPlayer(PlayerCharacter);
|
||||||
Logger.Debug($"Restoring C+ for {OnlineUser.User.AliasOrUID}/{PlayerName}");
|
Logger.Debug($"Restoring C+ for {OnlineUser.User.AliasOrUID}/{PlayerName}");
|
||||||
@@ -495,7 +503,9 @@ public class CachedPlayer : MediatorSubscriberBase, IDisposable
|
|||||||
var minionOrMount = _dalamudUtil.GetMinionOrMount(PlayerCharacter);
|
var minionOrMount = _dalamudUtil.GetMinionOrMount(PlayerCharacter);
|
||||||
if (minionOrMount != null)
|
if (minionOrMount != null)
|
||||||
{
|
{
|
||||||
await _ipcManager.PenumbraRedraw(minionOrMount.Value, cancelToken.Token, fireAndForget: true).ConfigureAwait(false);
|
using GameObjectHandler tempHandler = new(Mediator, ObjectKind.MinionOrMount, () => minionOrMount.Value,
|
||||||
|
false);
|
||||||
|
await _ipcManager.PenumbraRedraw(tempHandler, cancelToken.Token, fireAndForget: true).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (objectKind == ObjectKind.Pet)
|
else if (objectKind == ObjectKind.Pet)
|
||||||
@@ -503,7 +513,9 @@ public class CachedPlayer : MediatorSubscriberBase, IDisposable
|
|||||||
var pet = _dalamudUtil.GetPet(PlayerCharacter);
|
var pet = _dalamudUtil.GetPet(PlayerCharacter);
|
||||||
if (pet != IntPtr.Zero)
|
if (pet != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
await _ipcManager.PenumbraRedraw(pet, cancelToken.Token, fireAndForget: true).ConfigureAwait(false);
|
using GameObjectHandler tempHandler = new(Mediator, ObjectKind.Pet, () => pet,
|
||||||
|
false);
|
||||||
|
await _ipcManager.PenumbraRedraw(tempHandler, cancelToken.Token, fireAndForget: true).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (objectKind == ObjectKind.Companion)
|
else if (objectKind == ObjectKind.Companion)
|
||||||
@@ -511,7 +523,9 @@ public class CachedPlayer : MediatorSubscriberBase, IDisposable
|
|||||||
var companion = _dalamudUtil.GetCompanion(PlayerCharacter);
|
var companion = _dalamudUtil.GetCompanion(PlayerCharacter);
|
||||||
if (companion != IntPtr.Zero)
|
if (companion != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
await _ipcManager.PenumbraRedraw(companion, cancelToken.Token, fireAndForget: true).ConfigureAwait(false);
|
using GameObjectHandler tempHandler = new(Mediator, ObjectKind.Pet, () => companion,
|
||||||
|
false);
|
||||||
|
await _ipcManager.PenumbraRedraw(tempHandler, cancelToken.Token, fireAndForget: true).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using Penumbra.Api.Enums;
|
|||||||
using Penumbra.Api.Helpers;
|
using Penumbra.Api.Helpers;
|
||||||
using MareSynchronos.Mediator;
|
using MareSynchronos.Mediator;
|
||||||
using Dalamud.Interface.Internal.Notifications;
|
using Dalamud.Interface.Internal.Notifications;
|
||||||
|
using MareSynchronos.Models;
|
||||||
|
|
||||||
namespace MareSynchronos.Managers;
|
namespace MareSynchronos.Managers;
|
||||||
|
|
||||||
@@ -396,10 +397,11 @@ public class IpcManager : MediatorSubscriberBase, IDisposable
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PenumbraRedrawAction(IntPtr obj, Action action, CancellationToken token, bool fireAndForget)
|
private async Task PenumbraRedrawAction(GameObjectHandler obj, Action action, CancellationToken token, bool fireAndForget)
|
||||||
{
|
{
|
||||||
Mediator.Publish(new PenumbraStartRedrawMessage(obj));
|
Mediator.Publish(new PenumbraStartRedrawMessage(obj.Address));
|
||||||
_penumbraRedrawRequests[obj] = !fireAndForget;
|
|
||||||
|
_penumbraRedrawRequests[obj.Address] = !fireAndForget;
|
||||||
|
|
||||||
ActionQueue.Enqueue(action);
|
ActionQueue.Enqueue(action);
|
||||||
|
|
||||||
@@ -407,48 +409,45 @@ public class IpcManager : MediatorSubscriberBase, IDisposable
|
|||||||
{
|
{
|
||||||
var disposeToken = _disposalCts.Token;
|
var disposeToken = _disposalCts.Token;
|
||||||
var combinedToken = CancellationTokenSource.CreateLinkedTokenSource(disposeToken, token).Token;
|
var combinedToken = CancellationTokenSource.CreateLinkedTokenSource(disposeToken, token).Token;
|
||||||
while (_penumbraRedrawRequests[obj] && !combinedToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
Logger.Debug("Waiting for Penumbra Reply");
|
|
||||||
await Task.Delay(100).ConfigureAwait(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.Debug("Received Penumbra reply, waiting for draw");
|
await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
|
||||||
|
|
||||||
if (!combinedToken.IsCancellationRequested)
|
if (!combinedToken.IsCancellationRequested)
|
||||||
_dalamudUtil.WaitWhileCharacterIsDrawing(obj.ToString("X"), obj, 10000, combinedToken);
|
_dalamudUtil.WaitWhileCharacterIsDrawing(obj, 30000, combinedToken);
|
||||||
}
|
|
||||||
|
_penumbraRedrawRequests[obj.Address] = false;
|
||||||
|
}
|
||||||
|
Mediator.Publish(new PenumbraEndRedrawMessage(obj.Address));
|
||||||
|
|
||||||
Mediator.Publish(new PenumbraEndRedrawMessage(obj));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GlamourerApplyAll(string? customization, IntPtr obj, CancellationToken token, bool fireAndForget = false)
|
public async Task GlamourerApplyAll(string? customization, GameObjectHandler handler, CancellationToken token, bool fireAndForget = false)
|
||||||
{
|
{
|
||||||
if (!CheckGlamourerApi() || string.IsNullOrEmpty(customization)) return;
|
if (!CheckGlamourerApi() || string.IsNullOrEmpty(customization)) return;
|
||||||
var gameObj = _dalamudUtil.CreateGameObject(obj);
|
var gameObj = _dalamudUtil.CreateGameObject(handler.Address);
|
||||||
if (gameObj is Character c)
|
if (gameObj is Character c)
|
||||||
{
|
{
|
||||||
await PenumbraRedrawAction(obj, () => _glamourerApplyAll!.InvokeAction(customization, c), token, fireAndForget).ConfigureAwait(false);
|
await PenumbraRedrawAction(handler, () => _glamourerApplyAll!.InvokeAction(customization, c), token, fireAndForget).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GlamourerApplyOnlyEquipment(string customization, IntPtr obj, CancellationToken token, bool fireAndForget = false)
|
public async Task GlamourerApplyOnlyEquipment(string customization, GameObjectHandler handler, CancellationToken token, bool fireAndForget = false)
|
||||||
{
|
{
|
||||||
if (!CheckGlamourerApi() || string.IsNullOrEmpty(customization)) return;
|
if (!CheckGlamourerApi() || string.IsNullOrEmpty(customization)) return;
|
||||||
var gameObj = _dalamudUtil.CreateGameObject(obj);
|
var gameObj = _dalamudUtil.CreateGameObject(handler.Address);
|
||||||
if (gameObj is Character c)
|
if (gameObj is Character c)
|
||||||
{
|
{
|
||||||
await PenumbraRedrawAction(obj, () => _glamourerApplyOnlyEquipment!.InvokeAction(customization, c), token, fireAndForget).ConfigureAwait(false);
|
await PenumbraRedrawAction(handler, () => _glamourerApplyOnlyEquipment!.InvokeAction(customization, c), token, fireAndForget).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GlamourerApplyOnlyCustomization(string customization, IntPtr obj, CancellationToken token, bool fireAndForget = false)
|
public async Task GlamourerApplyOnlyCustomization(string customization, GameObjectHandler handler, CancellationToken token, bool fireAndForget = false)
|
||||||
{
|
{
|
||||||
if (!CheckGlamourerApi() || string.IsNullOrEmpty(customization)) return;
|
if (!CheckGlamourerApi() || string.IsNullOrEmpty(customization)) return;
|
||||||
var gameObj = _dalamudUtil.CreateGameObject(obj);
|
var gameObj = _dalamudUtil.CreateGameObject(handler.Address);
|
||||||
if (gameObj is Character c)
|
if (gameObj is Character c)
|
||||||
{
|
{
|
||||||
await PenumbraRedrawAction(obj, () => _glamourerApplyOnlyCustomization!.InvokeAction(customization, c), token, fireAndForget).ConfigureAwait(false);
|
await PenumbraRedrawAction(handler, () => _glamourerApplyOnlyCustomization!.InvokeAction(customization, c), token, fireAndForget).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -495,13 +494,13 @@ public class IpcManager : MediatorSubscriberBase, IDisposable
|
|||||||
return _penumbraResolveModDir!.Invoke().ToLowerInvariant();
|
return _penumbraResolveModDir!.Invoke().ToLowerInvariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PenumbraRedraw(IntPtr obj, CancellationToken token, bool fireAndForget = false)
|
public async Task PenumbraRedraw(GameObjectHandler handler, CancellationToken token, bool fireAndForget = false)
|
||||||
{
|
{
|
||||||
if (!CheckPenumbraApi()) return;
|
if (!CheckPenumbraApi()) return;
|
||||||
var gameObj = _dalamudUtil.CreateGameObject(obj);
|
var gameObj = _dalamudUtil.CreateGameObject(handler.Address);
|
||||||
if (gameObj is Character c)
|
if (gameObj is Character c)
|
||||||
{
|
{
|
||||||
await PenumbraRedrawAction(obj, () => _penumbraRedrawObject!.Invoke(c, RedrawType.Redraw), token, fireAndForget).ConfigureAwait(false);
|
await PenumbraRedrawAction(handler, () => _penumbraRedrawObject!.Invoke(c, RedrawType.Redraw), token, fireAndForget).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ public class MareMediator : IDisposable
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Error("Error executing " + subscriber.Action.Method, ex);
|
Logger.Error("Error executing " + subscriber, ex);
|
||||||
|
subscribers.RemoveWhere(s => s == subscriber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||||
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using MareSynchronos.Utils;
|
using MareSynchronos.Utils;
|
||||||
using Penumbra.String;
|
using Penumbra.String;
|
||||||
using MareSynchronos.API.Data.Enum;
|
|
||||||
using MareSynchronos.Mediator;
|
using MareSynchronos.Mediator;
|
||||||
|
using ObjectKind = MareSynchronos.API.Data.Enum.ObjectKind;
|
||||||
|
|
||||||
namespace MareSynchronos.Models;
|
namespace MareSynchronos.Models;
|
||||||
|
|
||||||
@@ -18,9 +20,15 @@ public class GameObjectHandler : MediatorSubscriberBase
|
|||||||
public string Name { get; private set; }
|
public string Name { get; private set; }
|
||||||
public ObjectKind ObjectKind { get; }
|
public ObjectKind ObjectKind { get; }
|
||||||
public IntPtr Address { get; set; }
|
public IntPtr Address { get; set; }
|
||||||
public IntPtr DrawObjectAddress { get; set; }
|
private IntPtr DrawObjectAddress { get; set; }
|
||||||
private Task? _delayedZoningTask;
|
private Task? _delayedZoningTask;
|
||||||
private CancellationTokenSource _zoningCts = new();
|
private CancellationTokenSource _zoningCts = new();
|
||||||
|
private bool _haltProcessing = false;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{Name} (Addr: {Address.ToString("X")}, DrawObj: {DrawObjectAddress.ToString("X")})";
|
||||||
|
}
|
||||||
|
|
||||||
public IntPtr CurrentAddress
|
public IntPtr CurrentAddress
|
||||||
{
|
{
|
||||||
@@ -63,26 +71,24 @@ public class GameObjectHandler : MediatorSubscriberBase
|
|||||||
|
|
||||||
Mediator.Subscribe<CutsceneStartMessage>(this, (_) =>
|
Mediator.Subscribe<CutsceneStartMessage>(this, (_) =>
|
||||||
{
|
{
|
||||||
Mediator.Unsubscribe<ZoneSwitchStartMessage>(this);
|
_haltProcessing = true;
|
||||||
Mediator.Unsubscribe<FrameworkUpdateMessage>(this);
|
|
||||||
});
|
});
|
||||||
Mediator.Subscribe<CutsceneEndMessage>(this, (_) =>
|
Mediator.Subscribe<CutsceneEndMessage>(this, (_) =>
|
||||||
{
|
{
|
||||||
Mediator.Subscribe<ZoneSwitchStartMessage>(this, (_) => ZoneSwitchStart());
|
_haltProcessing = false;
|
||||||
Mediator.Subscribe<FrameworkUpdateMessage>(this, (_) => FrameworkUpdate());
|
|
||||||
});
|
});
|
||||||
Mediator.Subscribe<PenumbraStartRedrawMessage>(this, (msg) =>
|
Mediator.Subscribe<PenumbraStartRedrawMessage>(this, (msg) =>
|
||||||
{
|
{
|
||||||
if (((PenumbraStartRedrawMessage)msg).Address == Address)
|
if (((PenumbraStartRedrawMessage)msg).Address == Address)
|
||||||
{
|
{
|
||||||
Mediator.Unsubscribe<FrameworkUpdateMessage>(this);
|
_haltProcessing = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Mediator.Subscribe<PenumbraEndRedrawMessage>(this, (msg) =>
|
Mediator.Subscribe<PenumbraEndRedrawMessage>(this, (msg) =>
|
||||||
{
|
{
|
||||||
if (((PenumbraEndRedrawMessage)msg).Address == Address)
|
if (((PenumbraEndRedrawMessage)msg).Address == Address)
|
||||||
{
|
{
|
||||||
Mediator.Subscribe<FrameworkUpdateMessage>(this, (_) => FrameworkUpdate());
|
_haltProcessing = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -97,7 +103,7 @@ public class GameObjectHandler : MediatorSubscriberBase
|
|||||||
|
|
||||||
private void ZoneSwitchEnd()
|
private void ZoneSwitchEnd()
|
||||||
{
|
{
|
||||||
if (!_sendUpdates) return;
|
if (!_sendUpdates || _haltProcessing) return;
|
||||||
|
|
||||||
_clearCts?.Cancel();
|
_clearCts?.Cancel();
|
||||||
_clearCts?.Dispose();
|
_clearCts?.Dispose();
|
||||||
@@ -107,7 +113,7 @@ public class GameObjectHandler : MediatorSubscriberBase
|
|||||||
|
|
||||||
private void ZoneSwitchStart()
|
private void ZoneSwitchStart()
|
||||||
{
|
{
|
||||||
if (!_sendUpdates) return;
|
if (!_sendUpdates || _haltProcessing) return;
|
||||||
|
|
||||||
_zoningCts = new();
|
_zoningCts = new();
|
||||||
Logger.Debug("Starting Delay After Zoning for " + ObjectKind + " " + Name);
|
Logger.Debug("Starting Delay After Zoning for " + ObjectKind + " " + Name);
|
||||||
@@ -126,18 +132,37 @@ public class GameObjectHandler : MediatorSubscriberBase
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] EquipSlotData { get; set; } = new byte[40];
|
public bool IsBeingDrawn { get; private set; }
|
||||||
public byte[] CustomizeData { get; set; } = new byte[26];
|
private byte[] EquipSlotData { get; set; } = new byte[40];
|
||||||
|
private byte[] CustomizeData { get; set; } = new byte[26];
|
||||||
private Task? _clearTask;
|
private Task? _clearTask;
|
||||||
private CancellationTokenSource? _clearCts = new();
|
private CancellationTokenSource? _clearCts = new();
|
||||||
public byte? HatState { get; set; }
|
private byte? HatState { get; set; }
|
||||||
public byte? VisorWeaponState { get; set; }
|
private byte? VisorWeaponState { get; set; }
|
||||||
private bool _doNotSendUpdate;
|
private bool _doNotSendUpdate;
|
||||||
|
|
||||||
private unsafe bool CheckAndUpdateObject()
|
private unsafe void CheckAndUpdateObject()
|
||||||
{
|
{
|
||||||
var curPtr = CurrentAddress;
|
var curPtr = CurrentAddress;
|
||||||
if (curPtr != IntPtr.Zero && (IntPtr)((Character*)curPtr)->GameObject.DrawObject != IntPtr.Zero)
|
bool drawObj = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var drawObjAddr = (IntPtr)((GameObject*)curPtr)->GetDrawObject();
|
||||||
|
drawObj = drawObjAddr != DrawObjectAddress;
|
||||||
|
DrawObjectAddress = drawObjAddr;
|
||||||
|
|
||||||
|
IsBeingDrawn = (((CharacterBase*)drawObjAddr)->HasModelInSlotLoaded != 0)
|
||||||
|
|| (((CharacterBase*)drawObjAddr)->HasModelFilesInSlotLoaded != 0)
|
||||||
|
|| (((GameObject*)curPtr)->RenderFlags & 0b100000000000) == 0b100000000000;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
IsBeingDrawn = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_haltProcessing) return;
|
||||||
|
|
||||||
|
if (curPtr != IntPtr.Zero && DrawObjectAddress != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
if (_clearCts != null)
|
if (_clearCts != null)
|
||||||
{
|
{
|
||||||
@@ -149,7 +174,6 @@ public class GameObjectHandler : MediatorSubscriberBase
|
|||||||
bool addr = Address == IntPtr.Zero || Address != curPtr;
|
bool addr = Address == IntPtr.Zero || Address != curPtr;
|
||||||
bool equip = CompareAndUpdateEquipByteData(chara->EquipSlotData);
|
bool equip = CompareAndUpdateEquipByteData(chara->EquipSlotData);
|
||||||
var customize = CompareAndUpdateCustomizeData(chara->CustomizeData);
|
var customize = CompareAndUpdateCustomizeData(chara->CustomizeData);
|
||||||
bool drawObj = (IntPtr)chara->GameObject.DrawObject != DrawObjectAddress;
|
|
||||||
var name = new ByteString(chara->GameObject.Name).ToString();
|
var name = new ByteString(chara->GameObject.Name).ToString();
|
||||||
bool nameChange = (!string.Equals(name, Name, StringComparison.Ordinal));
|
bool nameChange = (!string.Equals(name, Name, StringComparison.Ordinal));
|
||||||
if (addr || equip || customize || drawObj || nameChange)
|
if (addr || equip || customize || drawObj || nameChange)
|
||||||
@@ -169,8 +193,6 @@ public class GameObjectHandler : MediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
Mediator.Publish(new CharacterChangedMessage(this));
|
Mediator.Publish(new CharacterChangedMessage(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Address != IntPtr.Zero || DrawObjectAddress != IntPtr.Zero)
|
else if (Address != IntPtr.Zero || DrawObjectAddress != IntPtr.Zero)
|
||||||
@@ -187,8 +209,6 @@ public class GameObjectHandler : MediatorSubscriberBase
|
|||||||
_clearTask = Task.Run(() => ClearTask(token), token);
|
_clearTask = Task.Run(() => ClearTask(token), token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ClearTask(CancellationToken token)
|
private async Task ClearTask(CancellationToken token)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
|||||||
using FFXIVClientStructs.FFXIV.Client.Game.Control;
|
using FFXIVClientStructs.FFXIV.Client.Game.Control;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||||
using MareSynchronos.Mediator;
|
using MareSynchronos.Mediator;
|
||||||
|
using MareSynchronos.Models;
|
||||||
using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject;
|
using GameObject = FFXIVClientStructs.FFXIV.Client.Game.Object.GameObject;
|
||||||
|
|
||||||
namespace MareSynchronos.Utils;
|
namespace MareSynchronos.Utils;
|
||||||
@@ -249,42 +250,33 @@ public class DalamudUtil : IDisposable
|
|||||||
return await _framework.RunOnFrameworkThread(func).ConfigureAwait(false);
|
return await _framework.RunOnFrameworkThread(func).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe void WaitWhileCharacterIsDrawing(string name, IntPtr characterAddress, int timeOut = 5000, CancellationToken? ct = null)
|
public unsafe void WaitWhileCharacterIsDrawing(GameObjectHandler handler, int timeOut = 5000, CancellationToken? ct = null)
|
||||||
{
|
{
|
||||||
if (!_clientState.IsLoggedIn || characterAddress == IntPtr.Zero) return;
|
if (!_clientState.IsLoggedIn || handler.Address == IntPtr.Zero) return;
|
||||||
|
|
||||||
Logger.Verbose($"Starting wait for {name} to draw");
|
Logger.Verbose($"Starting wait for {handler} to draw");
|
||||||
|
|
||||||
var obj = (GameObject*)characterAddress;
|
|
||||||
const int tick = 250;
|
const int tick = 250;
|
||||||
int curWaitTime = 0;
|
int curWaitTime = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// ReSharper disable once LoopVariableIsNeverChangedInsideLoop
|
// ReSharper disable once LoopVariableIsNeverChangedInsideLoop
|
||||||
var stillDrawing = _framework.RunOnFrameworkThread(() => ((obj->GetDrawObject() == null
|
|
||||||
|| ((CharacterBase*)obj->GetDrawObject())->HasModelInSlotLoaded != 0
|
|
||||||
|| ((CharacterBase*)obj->GetDrawObject())->HasModelFilesInSlotLoaded != 0))
|
|
||||||
|| ((obj->RenderFlags & 0b100000000000) == 0b100000000000)).Result;
|
|
||||||
while ((!ct?.IsCancellationRequested ?? true)
|
while ((!ct?.IsCancellationRequested ?? true)
|
||||||
&& curWaitTime < timeOut
|
&& curWaitTime < timeOut
|
||||||
&& stillDrawing) // 0b100000000000 is "still rendering" or something
|
&& handler.IsBeingDrawn) // 0b100000000000 is "still rendering" or something
|
||||||
{
|
{
|
||||||
Logger.Verbose($"Waiting for {name} to finish drawing");
|
Logger.Verbose($"Waiting for {handler} to finish drawing");
|
||||||
curWaitTime += tick;
|
curWaitTime += tick;
|
||||||
Thread.Sleep(tick);
|
Thread.Sleep(tick);
|
||||||
stillDrawing = _framework.RunOnFrameworkThread(() => ((obj->GetDrawObject() == null
|
|
||||||
|| ((CharacterBase*)obj->GetDrawObject())->HasModelInSlotLoaded != 0
|
|
||||||
|| ((CharacterBase*)obj->GetDrawObject())->HasModelFilesInSlotLoaded != 0))
|
|
||||||
|| ((obj->RenderFlags & 0b100000000000) == 0b100000000000)).Result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (NullReferenceException ex)
|
catch (NullReferenceException ex)
|
||||||
{
|
{
|
||||||
Logger.Warn("Error accessing " + characterAddress.ToString("X") + ", object does not exist anymore?", ex);
|
Logger.Warn("Error accessing " + handler + ", object does not exist anymore?", ex);
|
||||||
}
|
}
|
||||||
catch (AccessViolationException ex)
|
catch (AccessViolationException ex)
|
||||||
{
|
{
|
||||||
Logger.Warn("Error accessing " + characterAddress.ToString("X") + ", object does not exist anymore?", ex);
|
Logger.Warn("Error accessing " + handler + ", object does not exist anymore?", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user