glamourer 2099 updates

This commit is contained in:
rootdarkarchon
2023-07-23 15:34:18 +02:00
parent 71c510b0f4
commit 36c77dedda
3 changed files with 107 additions and 8 deletions

View File

@@ -24,10 +24,12 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
private readonly ICallGateSubscriber<string, Character?, object> _customizePlusSetBodyScaleToCharacter; private readonly ICallGateSubscriber<string, Character?, object> _customizePlusSetBodyScaleToCharacter;
private readonly DalamudUtilService _dalamudUtil; private readonly DalamudUtilService _dalamudUtil;
private readonly ICallGateSubscriber<int> _glamourerApiVersion; private readonly ICallGateSubscriber<int> _glamourerApiVersion;
private readonly ICallGateSubscriber<(int, int)> _glamourerApiVersions;
private readonly ICallGateSubscriber<string, GameObject?, object>? _glamourerApplyAll; private readonly ICallGateSubscriber<string, GameObject?, object>? _glamourerApplyAll;
private readonly ICallGateSubscriber<string, GameObject?, object>? _glamourerApplyOnlyCustomization; private readonly ICallGateSubscriber<string, GameObject?, object>? _glamourerApplyOnlyCustomization;
private readonly ICallGateSubscriber<string, GameObject?, object>? _glamourerApplyOnlyEquipment; private readonly ICallGateSubscriber<string, GameObject?, object>? _glamourerApplyOnlyEquipment;
private readonly ICallGateSubscriber<GameObject?, string>? _glamourerGetAllCustomization; private readonly ICallGateSubscriber<GameObject?, string>? _glamourerGetAllCustomization;
private readonly ICallGateSubscriber<Character?, object?> _glamourerRevert;
private readonly ICallGateSubscriber<(int, int)> _heelsGetApiVersion; private readonly ICallGateSubscriber<(int, int)> _heelsGetApiVersion;
private readonly ICallGateSubscriber<string> _heelsGetOffset; private readonly ICallGateSubscriber<string> _heelsGetOffset;
private readonly ICallGateSubscriber<string, object?> _heelsOffsetUpdate; private readonly ICallGateSubscriber<string, object?> _heelsOffsetUpdate;
@@ -67,6 +69,7 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
private bool _customizePlusAvailable = false; private bool _customizePlusAvailable = false;
private CancellationTokenSource _disposalCts = new(); private CancellationTokenSource _disposalCts = new();
private bool _glamourerAvailable = false; private bool _glamourerAvailable = false;
private bool _glamourerTestingAvailable = false;
private bool _heelsAvailable = false; private bool _heelsAvailable = false;
private bool _honorificAvailable = false; private bool _honorificAvailable = false;
private bool _palettePlusAvailable = false; private bool _palettePlusAvailable = false;
@@ -102,10 +105,12 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
_penumbraGameObjectResourcePathResolved = Penumbra.Api.Ipc.GameObjectResourcePathResolved.Subscriber(pi, ResourceLoaded); _penumbraGameObjectResourcePathResolved = Penumbra.Api.Ipc.GameObjectResourcePathResolved.Subscriber(pi, ResourceLoaded);
_glamourerApiVersion = pi.GetIpcSubscriber<int>("Glamourer.ApiVersion"); _glamourerApiVersion = pi.GetIpcSubscriber<int>("Glamourer.ApiVersion");
_glamourerApiVersions = pi.GetIpcSubscriber<(int, int)>("Glamourer.ApiVersions");
_glamourerGetAllCustomization = pi.GetIpcSubscriber<GameObject?, string>("Glamourer.GetAllCustomizationFromCharacter"); _glamourerGetAllCustomization = pi.GetIpcSubscriber<GameObject?, string>("Glamourer.GetAllCustomizationFromCharacter");
_glamourerApplyAll = pi.GetIpcSubscriber<string, GameObject?, object>("Glamourer.ApplyAllToCharacter"); _glamourerApplyAll = pi.GetIpcSubscriber<string, GameObject?, object>("Glamourer.ApplyAllToCharacter");
_glamourerApplyOnlyCustomization = pi.GetIpcSubscriber<string, GameObject?, object>("Glamourer.ApplyOnlyCustomizationToCharacter"); _glamourerApplyOnlyCustomization = pi.GetIpcSubscriber<string, GameObject?, object>("Glamourer.ApplyOnlyCustomizationToCharacter");
_glamourerApplyOnlyEquipment = pi.GetIpcSubscriber<string, GameObject?, object>("Glamourer.ApplyOnlyEquipmentToCharacter"); _glamourerApplyOnlyEquipment = pi.GetIpcSubscriber<string, GameObject?, object>("Glamourer.ApplyOnlyEquipmentToCharacter");
_glamourerRevert = pi.GetIpcSubscriber<Character?, object?>("Glamourer.RevertCharacter");
_heelsGetApiVersion = pi.GetIpcSubscriber<(int, int)>("SimpleHeels.ApiVersion"); _heelsGetApiVersion = pi.GetIpcSubscriber<(int, int)>("SimpleHeels.ApiVersion");
_heelsGetOffset = pi.GetIpcSubscriber<string>("SimpleHeels.GetLocalPlayer"); _heelsGetOffset = pi.GetIpcSubscriber<string>("SimpleHeels.GetLocalPlayer");
@@ -160,6 +165,8 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
public bool CheckGlamourerApi() => _glamourerAvailable; public bool CheckGlamourerApi() => _glamourerAvailable;
public bool CheckGlamourerTestingApi() => _glamourerTestingAvailable;
public bool CheckHeelsApi() => _heelsAvailable; public bool CheckHeelsApi() => _heelsAvailable;
public bool CheckHonorificApi() => _honorificAvailable; public bool CheckHonorificApi() => _honorificAvailable;
@@ -238,6 +245,33 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
{ {
logger.LogDebug("[{appid}] Calling on IPC: GlamourerApplyAll", applicationId); logger.LogDebug("[{appid}] Calling on IPC: GlamourerApplyAll", applicationId);
_glamourerApplyAll!.InvokeAction(customization, chara); _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); }).ConfigureAwait(false);
} }
finally 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() private bool CheckHeelsApiInternal()
{ {
try try
@@ -707,6 +768,7 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
private void PeriodicApiStateCheck() private void PeriodicApiStateCheck()
{ {
_glamourerAvailable = CheckGlamourerApiInternal(); _glamourerAvailable = CheckGlamourerApiInternal();
_glamourerTestingAvailable = CheckGlamourerTestingApiInternal();
_penumbraAvailable = CheckPenumbraApiInternal(); _penumbraAvailable = CheckPenumbraApiInternal();
_heelsAvailable = CheckHeelsApiInternal(); _heelsAvailable = CheckHeelsApiInternal();
_customizePlusAvailable = CheckCustomizePlusApiInternal(); _customizePlusAvailable = CheckCustomizePlusApiInternal();

View File

@@ -1,6 +1,7 @@
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using MareSynchronos.Services; using MareSynchronos.Services;
using MareSynchronos.Services.Mediator; using MareSynchronos.Services.Mediator;
using MareSynchronos.Utils;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Penumbra.String; using Penumbra.String;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@@ -74,7 +75,7 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
if (msg.Address == Address) if (msg.Address == Address)
{ {
_haltProcessing = false; _haltProcessing = false;
Task.Run(async () => _ = Task.Run(async () =>
{ {
_ignoreSendAfterRedraw = true; _ignoreSendAfterRedraw = true;
await Task.Delay(500).ConfigureAwait(false); await Task.Delay(500).ConfigureAwait(false);
@@ -195,14 +196,30 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
if (_clearCts != null) if (_clearCts != null)
{ {
Logger.LogDebug("[{this}] Cancelling Clear Task", this); Logger.LogDebug("[{this}] Cancelling Clear Task", this);
_clearCts?.Cancel(); _clearCts?.CancelDispose();
_clearCts = null; _clearCts = null;
} }
var chara = (FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)Address; var chara = (FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)Address;
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);
Name = name; if (nameChange)
bool equipDiff = CompareAndUpdateEquipByteData(chara->EquipSlotData); {
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 if (equipDiff && !_isOwnedObject && !_ignoreSendAfterRedraw) // send the message out immediately and cancel out, no reason to continue if not self
{ {
Logger.LogTrace("[{this}] Changed", this); Logger.LogTrace("[{this}] Changed", this);
@@ -210,7 +227,19 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
return; 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) if ((addrDiff || drawObjDiff || equipDiff || customizeDiff || nameChange) && _isOwnedObject)
{ {
@@ -223,8 +252,7 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
Logger.LogTrace("[{this}] Changed", this); Logger.LogTrace("[{this}] Changed", this);
if (_isOwnedObject && ObjectKind != ObjectKind.Player) if (_isOwnedObject && ObjectKind != ObjectKind.Player)
{ {
_clearCts?.Cancel(); _clearCts?.CancelDispose();
_clearCts?.Dispose();
_clearCts = new(); _clearCts = new();
var token = _clearCts.Token; var token = _clearCts.Token;
_ = Task.Run(() => ClearAsync(token), token); _ = Task.Run(() => ClearAsync(token), token);

View File

@@ -518,7 +518,14 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.Player, () => address, false).ConfigureAwait(false); using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.Player, () => address, false).ConfigureAwait(false);
tempHandler.CompareNameAndThrow(name); tempHandler.CompareNameAndThrow(name);
Logger.LogDebug("[{applicationId}] Restoring Customization and Equipment for {alias}/{name}: {data}", applicationId, OnlineUser.User.AliasOrUID, name, _originalGlamourerData); 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); tempHandler.CompareNameAndThrow(name);
Logger.LogDebug("[{applicationId}] Restoring Heels for {alias}/{name}", applicationId, OnlineUser.User.AliasOrUID, name); Logger.LogDebug("[{applicationId}] Restoring Heels for {alias}/{name}", applicationId, OnlineUser.User.AliasOrUID, name);
await _ipcManager.HeelsRestoreOffsetForPlayerAsync(address).ConfigureAwait(false); 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); await _ipcManager.PenumbraRedrawAsync(Logger, tempHandler, applicationId, cancelToken.Token).ConfigureAwait(false);
} }
} }
cancelToken.CancelDispose();
} }
private List<FileReplacementData> TryCalculateModdedDictionary(Guid applicationBase, CharacterData charaData, out Dictionary<string, string> moddedDictionary, CancellationToken token) private List<FileReplacementData> TryCalculateModdedDictionary(Guid applicationBase, CharacterData charaData, out Dictionary<string, string> moddedDictionary, CancellationToken token)