From 36c77dedda88215e694cfcc0c954e3ebd839b9a7 Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Sun, 23 Jul 2023 15:34:18 +0200 Subject: [PATCH] glamourer 2099 updates --- MareSynchronos/Interop/IpcManager.cs | 62 +++++++++++++++++++ .../PlayerData/Handlers/GameObjectHandler.cs | 42 ++++++++++--- .../PlayerData/Handlers/PairHandler.cs | 11 +++- 3 files changed, 107 insertions(+), 8 deletions(-) diff --git a/MareSynchronos/Interop/IpcManager.cs b/MareSynchronos/Interop/IpcManager.cs index d0b7ad9..9c42b8a 100644 --- a/MareSynchronos/Interop/IpcManager.cs +++ b/MareSynchronos/Interop/IpcManager.cs @@ -24,10 +24,12 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase private readonly ICallGateSubscriber _customizePlusSetBodyScaleToCharacter; private readonly DalamudUtilService _dalamudUtil; private readonly ICallGateSubscriber _glamourerApiVersion; + private readonly ICallGateSubscriber<(int, int)> _glamourerApiVersions; private readonly ICallGateSubscriber? _glamourerApplyAll; private readonly ICallGateSubscriber? _glamourerApplyOnlyCustomization; private readonly ICallGateSubscriber? _glamourerApplyOnlyEquipment; private readonly ICallGateSubscriber? _glamourerGetAllCustomization; + private readonly ICallGateSubscriber _glamourerRevert; private readonly ICallGateSubscriber<(int, int)> _heelsGetApiVersion; private readonly ICallGateSubscriber _heelsGetOffset; private readonly ICallGateSubscriber _heelsOffsetUpdate; @@ -67,6 +69,7 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase private bool _customizePlusAvailable = false; private CancellationTokenSource _disposalCts = new(); private bool _glamourerAvailable = false; + private bool _glamourerTestingAvailable = false; private bool _heelsAvailable = false; private bool _honorificAvailable = false; private bool _palettePlusAvailable = false; @@ -102,10 +105,12 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase _penumbraGameObjectResourcePathResolved = Penumbra.Api.Ipc.GameObjectResourcePathResolved.Subscriber(pi, ResourceLoaded); _glamourerApiVersion = pi.GetIpcSubscriber("Glamourer.ApiVersion"); + _glamourerApiVersions = pi.GetIpcSubscriber<(int, int)>("Glamourer.ApiVersions"); _glamourerGetAllCustomization = pi.GetIpcSubscriber("Glamourer.GetAllCustomizationFromCharacter"); _glamourerApplyAll = pi.GetIpcSubscriber("Glamourer.ApplyAllToCharacter"); _glamourerApplyOnlyCustomization = pi.GetIpcSubscriber("Glamourer.ApplyOnlyCustomizationToCharacter"); _glamourerApplyOnlyEquipment = pi.GetIpcSubscriber("Glamourer.ApplyOnlyEquipmentToCharacter"); + _glamourerRevert = pi.GetIpcSubscriber("Glamourer.RevertCharacter"); _heelsGetApiVersion = pi.GetIpcSubscriber<(int, int)>("SimpleHeels.ApiVersion"); _heelsGetOffset = pi.GetIpcSubscriber("SimpleHeels.GetLocalPlayer"); @@ -160,6 +165,8 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase public bool CheckGlamourerApi() => _glamourerAvailable; + public bool CheckGlamourerTestingApi() => _glamourerTestingAvailable; + public bool CheckHeelsApi() => _heelsAvailable; public bool CheckHonorificApi() => _honorificAvailable; @@ -238,6 +245,33 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase { logger.LogDebug("[{appid}] Calling on IPC: GlamourerApplyAll", applicationId); _glamourerApplyAll!.InvokeAction(customization, chara); + if (_glamourerTestingAvailable) + { + logger.LogDebug("[{appid}] Calling on IPC: PenumbraRedraw", applicationId); + + _penumbraRedrawObject.Invoke(chara, RedrawType.Redraw); + } + }).ConfigureAwait(false); + } + finally + { + _redrawSemaphore.Release(); + } + } + + public async Task GlamourerRevert(ILogger logger, GameObjectHandler handler, Guid applicationId, CancellationToken token) + { + if ((!CheckGlamourerApi() && !CheckGlamourerTestingApi()) || _dalamudUtil.IsZoning) return; + try + { + await _redrawSemaphore.WaitAsync(token).ConfigureAwait(false); + await PenumbraRedrawInternalAsync(logger, handler, applicationId, (chara) => + { + logger.LogDebug("[{appid}] Calling On IPC: GlamourerRevert", applicationId); + _glamourerRevert.InvokeAction(chara); + logger.LogDebug("[{appid}] Calling On IPC: PenumbraRedraw", applicationId); + _penumbraRedrawObject.Invoke(chara, RedrawType.Redraw); + }).ConfigureAwait(false); } finally @@ -568,6 +602,33 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase } } + private bool CheckGlamourerTestingApiInternal() + { + bool apiAvailable = false; + try + { + var version = _glamourerApiVersions.InvokeFunc(); + if (version.Item1 == 0 && version.Item2 >= 1) + { + apiAvailable = true; + } + _shownGlamourerUnavailable = _shownGlamourerUnavailable && !apiAvailable; + return apiAvailable; + } + catch + { + return apiAvailable; + } + finally + { + if (!apiAvailable && !_shownGlamourerUnavailable) + { + _shownGlamourerUnavailable = true; + Mediator.Publish(new NotificationMessage("Glamourer inactive", "Your Glamourer installation is not active or out of date. Update Glamourer to continue to use Mare.", NotificationType.Error)); + } + } + } + private bool CheckHeelsApiInternal() { try @@ -707,6 +768,7 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase private void PeriodicApiStateCheck() { _glamourerAvailable = CheckGlamourerApiInternal(); + _glamourerTestingAvailable = CheckGlamourerTestingApiInternal(); _penumbraAvailable = CheckPenumbraApiInternal(); _heelsAvailable = CheckHeelsApiInternal(); _customizePlusAvailable = CheckCustomizePlusApiInternal(); diff --git a/MareSynchronos/PlayerData/Handlers/GameObjectHandler.cs b/MareSynchronos/PlayerData/Handlers/GameObjectHandler.cs index c0e0953..d605122 100644 --- a/MareSynchronos/PlayerData/Handlers/GameObjectHandler.cs +++ b/MareSynchronos/PlayerData/Handlers/GameObjectHandler.cs @@ -1,6 +1,7 @@ using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using MareSynchronos.Services; using MareSynchronos.Services.Mediator; +using MareSynchronos.Utils; using Microsoft.Extensions.Logging; using Penumbra.String; using System.Runtime.InteropServices; @@ -74,7 +75,7 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase if (msg.Address == Address) { _haltProcessing = false; - Task.Run(async () => + _ = Task.Run(async () => { _ignoreSendAfterRedraw = true; await Task.Delay(500).ConfigureAwait(false); @@ -195,14 +196,30 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase if (_clearCts != null) { Logger.LogDebug("[{this}] Cancelling Clear Task", this); - _clearCts?.Cancel(); + _clearCts?.CancelDispose(); _clearCts = null; } var chara = (FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)Address; var name = new ByteString(chara->GameObject.Name).ToString(); bool nameChange = !string.Equals(name, Name, StringComparison.Ordinal); - Name = name; - bool equipDiff = CompareAndUpdateEquipByteData(chara->EquipSlotData); + if (nameChange) + { + Name = name; + } + bool equipDiff = false; + + if (((DrawObject*)DrawObjectAddress)->Object.GetObjectType() == ObjectType.CharacterBase + && ((CharacterBase*)DrawObjectAddress)->GetModelType() == CharacterBase.ModelType.Human) + { + equipDiff = CompareAndUpdateEquipByteData((byte*)&((Human*)DrawObjectAddress)->Head); + if (equipDiff) + Logger.LogTrace("Checking [{this}] equip data as human from draw obj, result: {diff}", this, equipDiff); + } + else + { + equipDiff = CompareAndUpdateEquipByteData((byte*)&chara->DrawData.Head); + } + if (equipDiff && !_isOwnedObject && !_ignoreSendAfterRedraw) // send the message out immediately and cancel out, no reason to continue if not self { Logger.LogTrace("[{this}] Changed", this); @@ -210,7 +227,19 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase return; } - var customizeDiff = CompareAndUpdateCustomizeData(chara->CustomizeData); + bool customizeDiff = false; + + if (((DrawObject*)DrawObjectAddress)->Object.GetObjectType() == ObjectType.CharacterBase + && ((CharacterBase*)DrawObjectAddress)->GetModelType() == CharacterBase.ModelType.Human) + { + customizeDiff = CompareAndUpdateCustomizeData(((Human*)DrawObjectAddress)->Customize.Data); + if (customizeDiff) + Logger.LogTrace("Checking [{this}] customize data as human from draw obj, result: {diff}", this, customizeDiff); + } + else + { + customizeDiff = CompareAndUpdateEquipByteData(chara->DrawData.CustomizeData.Data); + } if ((addrDiff || drawObjDiff || equipDiff || customizeDiff || nameChange) && _isOwnedObject) { @@ -223,8 +252,7 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase Logger.LogTrace("[{this}] Changed", this); if (_isOwnedObject && ObjectKind != ObjectKind.Player) { - _clearCts?.Cancel(); - _clearCts?.Dispose(); + _clearCts?.CancelDispose(); _clearCts = new(); var token = _clearCts.Token; _ = Task.Run(() => ClearAsync(token), token); diff --git a/MareSynchronos/PlayerData/Handlers/PairHandler.cs b/MareSynchronos/PlayerData/Handlers/PairHandler.cs index feb2201..4385a28 100644 --- a/MareSynchronos/PlayerData/Handlers/PairHandler.cs +++ b/MareSynchronos/PlayerData/Handlers/PairHandler.cs @@ -518,7 +518,14 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.Player, () => address, false).ConfigureAwait(false); tempHandler.CompareNameAndThrow(name); Logger.LogDebug("[{applicationId}] Restoring Customization and Equipment for {alias}/{name}: {data}", applicationId, OnlineUser.User.AliasOrUID, name, _originalGlamourerData); - await _ipcManager.GlamourerApplyCustomizationAndEquipmentAsync(Logger, tempHandler, _originalGlamourerData, _lastGlamourerData, applicationId, cancelToken.Token, fireAndForget: false).ConfigureAwait(false); + if (!_ipcManager.CheckGlamourerTestingApi()) + { + await _ipcManager.GlamourerApplyCustomizationAndEquipmentAsync(Logger, tempHandler, _originalGlamourerData, _lastGlamourerData, applicationId, cancelToken.Token, fireAndForget: false).ConfigureAwait(false); + } + else + { + await _ipcManager.GlamourerRevert(Logger, tempHandler, applicationId, cancelToken.Token).ConfigureAwait(false); + } tempHandler.CompareNameAndThrow(name); Logger.LogDebug("[{applicationId}] Restoring Heels for {alias}/{name}", applicationId, OnlineUser.User.AliasOrUID, name); await _ipcManager.HeelsRestoreOffsetForPlayerAsync(address).ConfigureAwait(false); @@ -562,6 +569,8 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase await _ipcManager.PenumbraRedrawAsync(Logger, tempHandler, applicationId, cancelToken.Token).ConfigureAwait(false); } } + + cancelToken.CancelDispose(); } private List TryCalculateModdedDictionary(Guid applicationBase, CharacterData charaData, out Dictionary moddedDictionary, CancellationToken token)