adapt to new glamourer
This commit is contained in:
@@ -17,19 +17,19 @@ namespace MareSynchronos.Interop;
|
|||||||
|
|
||||||
public sealed class IpcManager : DisposableMediatorSubscriberBase
|
public sealed class IpcManager : DisposableMediatorSubscriberBase
|
||||||
{
|
{
|
||||||
|
private readonly uint LockCode = 0x6D617265;
|
||||||
|
|
||||||
private readonly ICallGateSubscriber<(int, int)> _customizePlusApiVersion;
|
private readonly ICallGateSubscriber<(int, int)> _customizePlusApiVersion;
|
||||||
private readonly ICallGateSubscriber<Character?, string?> _customizePlusGetBodyScale;
|
private readonly ICallGateSubscriber<Character?, string?> _customizePlusGetBodyScale;
|
||||||
private readonly ICallGateSubscriber<string?, string?, object> _customizePlusOnScaleUpdate;
|
private readonly ICallGateSubscriber<string?, string?, object> _customizePlusOnScaleUpdate;
|
||||||
private readonly ICallGateSubscriber<Character?, object> _customizePlusRevertCharacter;
|
private readonly ICallGateSubscriber<Character?, object> _customizePlusRevertCharacter;
|
||||||
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, int)> _glamourerApiVersions;
|
private readonly ICallGateSubscriber<(int, int)> _glamourerApiVersions;
|
||||||
private readonly ICallGateSubscriber<string, GameObject?, object>? _glamourerApplyAll;
|
private readonly ICallGateSubscriber<string, GameObject?, uint, object>? _glamourerApplyAll;
|
||||||
private readonly ICallGateSubscriber<string, GameObject?, object>? _glamourerApplyOnlyCustomization;
|
|
||||||
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<Character?, uint, object?> _glamourerRevert;
|
||||||
|
private readonly ICallGateSubscriber<Character?, uint, bool> _glamourerUnlock;
|
||||||
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;
|
||||||
@@ -70,7 +70,6 @@ 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;
|
||||||
@@ -106,13 +105,11 @@ 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");
|
|
||||||
_glamourerApiVersions = pi.GetIpcSubscriber<(int, int)>("Glamourer.ApiVersions");
|
_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?, uint, object>("Glamourer.ApplyAllToCharacterLock");
|
||||||
_glamourerApplyOnlyCustomization = pi.GetIpcSubscriber<string, GameObject?, object>("Glamourer.ApplyOnlyCustomizationToCharacter");
|
_glamourerRevert = pi.GetIpcSubscriber<Character?, uint, object?>("Glamourer.RevertCharacterLock");
|
||||||
_glamourerApplyOnlyEquipment = pi.GetIpcSubscriber<string, GameObject?, object>("Glamourer.ApplyOnlyEquipmentToCharacter");
|
_glamourerUnlock = pi.GetIpcSubscriber<Character?, uint, bool>("Glamourer.Unlock");
|
||||||
_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");
|
||||||
@@ -167,8 +164,6 @@ 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;
|
||||||
@@ -248,18 +243,15 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
logger.LogDebug("[{appid}] Calling on IPC: GlamourerApplyAll", applicationId);
|
logger.LogDebug("[{appid}] Calling on IPC: GlamourerApplyAll", applicationId);
|
||||||
_glamourerApplyAll!.InvokeAction(customization, chara);
|
_glamourerApplyAll!.InvokeAction(customization, chara, LockCode);
|
||||||
|
logger.LogDebug("[{appid}] Calling on IPC: PenumbraRedraw", applicationId);
|
||||||
|
_penumbraRedrawObject.Invoke(chara, RedrawType.Redraw);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
logger.LogWarning("[{appid}] Failed to apply Glamourer data", applicationId);
|
logger.LogWarning("[{appid}] Failed to apply Glamourer data", applicationId);
|
||||||
}
|
}
|
||||||
if (_glamourerTestingAvailable)
|
|
||||||
{
|
|
||||||
logger.LogDebug("[{appid}] Calling on IPC: PenumbraRedraw", applicationId);
|
|
||||||
|
|
||||||
_penumbraRedrawObject.Invoke(chara, RedrawType.Redraw);
|
|
||||||
}
|
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -270,16 +262,17 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
|
|
||||||
public async Task GlamourerRevert(ILogger logger, GameObjectHandler handler, Guid applicationId, CancellationToken token)
|
public async Task GlamourerRevert(ILogger logger, GameObjectHandler handler, Guid applicationId, CancellationToken token)
|
||||||
{
|
{
|
||||||
if ((!CheckGlamourerApi() && !CheckGlamourerTestingApi()) || _dalamudUtil.IsZoning) return;
|
if ((!CheckGlamourerApi()) || _dalamudUtil.IsZoning) return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _redrawSemaphore.WaitAsync(token).ConfigureAwait(false);
|
await _redrawSemaphore.WaitAsync(token).ConfigureAwait(false);
|
||||||
await PenumbraRedrawInternalAsync(logger, handler, applicationId, (chara) =>
|
await PenumbraRedrawInternalAsync(logger, handler, applicationId, (chara) =>
|
||||||
{
|
{
|
||||||
logger.LogDebug("[{appid}] Calling On IPC: GlamourerRevert", applicationId);
|
logger.LogDebug("[{appid}] Calling On IPC: GlamourerRevert", applicationId);
|
||||||
_glamourerRevert.InvokeAction(chara);
|
_glamourerRevert.InvokeAction(chara, LockCode);
|
||||||
logger.LogDebug("[{appid}] Calling On IPC: PenumbraRedraw", applicationId);
|
logger.LogDebug("[{appid}] Calling On IPC: PenumbraRedraw", applicationId);
|
||||||
_penumbraRedrawObject.Invoke(chara, RedrawType.Redraw);
|
_penumbraRedrawObject.Invoke(chara, RedrawType.AfterGPose);
|
||||||
|
_glamourerUnlock.InvokeFunc(chara, LockCode);
|
||||||
|
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@@ -289,29 +282,6 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GlamourerApplyCustomizationAndEquipmentAsync(ILogger logger, GameObjectHandler handler, string customization, string equipment, Guid applicationid, CancellationToken token, bool fireAndForget = false)
|
|
||||||
{
|
|
||||||
if (!CheckGlamourerApi() || string.IsNullOrEmpty(customization) || _dalamudUtil.IsZoning) return;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await _redrawSemaphore.WaitAsync(token).ConfigureAwait(false);
|
|
||||||
await PenumbraRedrawInternalAsync(logger, handler, applicationid, (chara) =>
|
|
||||||
{
|
|
||||||
logger.LogDebug("[{appid}] Calling on IPC: GlamourerApplyOnlyCustomization", applicationid);
|
|
||||||
_glamourerApplyOnlyCustomization!.InvokeAction(customization, chara);
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
await PenumbraRedrawInternalAsync(logger, handler, applicationid, (chara) =>
|
|
||||||
{
|
|
||||||
logger.LogDebug("[{appid}] Calling on IPC: GlamourerApplyOnlyEquipment", applicationid);
|
|
||||||
_glamourerApplyOnlyEquipment!.InvokeAction(equipment, chara);
|
|
||||||
}).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_redrawSemaphore.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<string> GlamourerGetCharacterCustomizationAsync(IntPtr character)
|
public async Task<string> GlamourerGetCharacterCustomizationAsync(IntPtr character)
|
||||||
{
|
{
|
||||||
if (!CheckGlamourerApi()) return string.Empty;
|
if (!CheckGlamourerApi()) return string.Empty;
|
||||||
@@ -630,8 +600,13 @@ public sealed class IpcManager : DisposableMediatorSubscriberBase
|
|||||||
bool apiAvailable = false;
|
bool apiAvailable = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
apiAvailable = _glamourerApiVersion.InvokeFunc() >= 0;
|
var version = _glamourerApiVersions.InvokeFunc();
|
||||||
|
if (version.Item1 == 0 && version.Item2 >= 1)
|
||||||
|
{
|
||||||
|
apiAvailable = true;
|
||||||
|
}
|
||||||
_shownGlamourerUnavailable = _shownGlamourerUnavailable && !apiAvailable;
|
_shownGlamourerUnavailable = _shownGlamourerUnavailable && !apiAvailable;
|
||||||
|
|
||||||
return apiAvailable;
|
return apiAvailable;
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@@ -648,24 +623,6 @@ 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;
|
|
||||||
}
|
|
||||||
return apiAvailable;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return apiAvailable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CheckHeelsApiInternal()
|
private bool CheckHeelsApiInternal()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -805,7 +762,6 @@ 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();
|
||||||
|
|||||||
@@ -29,17 +29,17 @@
|
|||||||
<PackageReference Include="Dalamud.ContextMenu" Version="1.2.3" />
|
<PackageReference Include="Dalamud.ContextMenu" Version="1.2.3" />
|
||||||
<PackageReference Include="DalamudPackager" Version="2.1.11" />
|
<PackageReference Include="DalamudPackager" Version="2.1.11" />
|
||||||
<PackageReference Include="lz4net" Version="1.0.15.93" />
|
<PackageReference Include="lz4net" Version="1.0.15.93" />
|
||||||
<PackageReference Include="Meziantou.Analyzer" Version="2.0.82">
|
<PackageReference Include="Meziantou.Analyzer" Version="2.0.87">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.10" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="7.0.11" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="7.0.10" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="7.0.11" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
||||||
<PackageReference Include="Penumbra.Api" Version="1.0.9" />
|
<PackageReference Include="Penumbra.Api" Version="1.0.10" />
|
||||||
<PackageReference Include="Penumbra.String" Version="1.0.4" />
|
<PackageReference Include="Penumbra.String" Version="1.0.4" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.1" />
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.2" />
|
||||||
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.7.0.75501">
|
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.11.0.78383">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ using MareSynchronos.Interop;
|
|||||||
using MareSynchronos.Services;
|
using MareSynchronos.Services;
|
||||||
using MareSynchronos.Utils;
|
using MareSynchronos.Utils;
|
||||||
using MareSynchronos.PlayerData.Factories;
|
using MareSynchronos.PlayerData.Factories;
|
||||||
|
using MareSynchronos.Services.Mediator;
|
||||||
|
|
||||||
namespace MareSynchronos.PlayerData.Export;
|
namespace MareSynchronos.PlayerData.Export;
|
||||||
|
|
||||||
public class MareCharaFileManager
|
public class MareCharaFileManager : DisposableMediatorSubscriberBase
|
||||||
{
|
{
|
||||||
private readonly MareConfigService _configService;
|
private readonly MareConfigService _configService;
|
||||||
private readonly DalamudUtilService _dalamudUtil;
|
private readonly DalamudUtilService _dalamudUtil;
|
||||||
@@ -23,9 +24,12 @@ public class MareCharaFileManager
|
|||||||
private readonly ILogger<MareCharaFileManager> _logger;
|
private readonly ILogger<MareCharaFileManager> _logger;
|
||||||
private readonly FileCacheManager _manager;
|
private readonly FileCacheManager _manager;
|
||||||
private int _globalFileCounter = 0;
|
private int _globalFileCounter = 0;
|
||||||
|
private readonly List<GameObjectHandler> _gposeGameObjects;
|
||||||
|
private bool _isInGpose = false;
|
||||||
|
|
||||||
public MareCharaFileManager(ILogger<MareCharaFileManager> logger, GameObjectHandlerFactory gameObjectHandlerFactory,
|
public MareCharaFileManager(ILogger<MareCharaFileManager> logger, GameObjectHandlerFactory gameObjectHandlerFactory,
|
||||||
FileCacheManager manager, IpcManager ipcManager, MareConfigService configService, DalamudUtilService dalamudUtil)
|
FileCacheManager manager, IpcManager ipcManager, MareConfigService configService, DalamudUtilService dalamudUtil,
|
||||||
|
MareMediator mediator) : base(logger, mediator)
|
||||||
{
|
{
|
||||||
_factory = new(manager);
|
_factory = new(manager);
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
@@ -34,6 +38,19 @@ public class MareCharaFileManager
|
|||||||
_ipcManager = ipcManager;
|
_ipcManager = ipcManager;
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_dalamudUtil = dalamudUtil;
|
_dalamudUtil = dalamudUtil;
|
||||||
|
_gposeGameObjects = new();
|
||||||
|
Mediator.Subscribe<GposeStartMessage>(this, _ => _isInGpose = true);
|
||||||
|
Mediator.Subscribe<GposeEndMessage>(this, async _ =>
|
||||||
|
{
|
||||||
|
_isInGpose = false;
|
||||||
|
CancellationTokenSource cts = new();
|
||||||
|
foreach (var item in _gposeGameObjects)
|
||||||
|
{
|
||||||
|
await _ipcManager.GlamourerRevert(logger, item, Guid.NewGuid(), cts.Token);
|
||||||
|
item.Dispose();
|
||||||
|
}
|
||||||
|
_gposeGameObjects.Clear();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CurrentlyWorking { get; private set; } = false;
|
public bool CurrentlyWorking { get; private set; } = false;
|
||||||
@@ -41,11 +58,12 @@ public class MareCharaFileManager
|
|||||||
|
|
||||||
public async Task ApplyMareCharaFile(GameObject? charaTarget)
|
public async Task ApplyMareCharaFile(GameObject? charaTarget)
|
||||||
{
|
{
|
||||||
|
if (charaTarget == null) return;
|
||||||
Dictionary<string, string> extractedFiles = new(StringComparer.Ordinal);
|
Dictionary<string, string> extractedFiles = new(StringComparer.Ordinal);
|
||||||
CurrentlyWorking = true;
|
CurrentlyWorking = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (LoadedCharaFile == null || charaTarget == null || !File.Exists(LoadedCharaFile.FilePath)) return;
|
if (LoadedCharaFile == null || !File.Exists(LoadedCharaFile.FilePath)) return;
|
||||||
var unwrapped = File.OpenRead(LoadedCharaFile.FilePath);
|
var unwrapped = File.OpenRead(LoadedCharaFile.FilePath);
|
||||||
await using (unwrapped.ConfigureAwait(false))
|
await using (unwrapped.ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
@@ -69,7 +87,14 @@ public class MareCharaFileManager
|
|||||||
await _ipcManager.PenumbraAssignTemporaryCollectionAsync(_logger, coll, charaTarget.ObjectTableIndex()!.Value).ConfigureAwait(false);
|
await _ipcManager.PenumbraAssignTemporaryCollectionAsync(_logger, coll, charaTarget.ObjectTableIndex()!.Value).ConfigureAwait(false);
|
||||||
await _ipcManager.PenumbraSetTemporaryModsAsync(_logger, applicationId, coll, extractedFiles.Union(fileSwaps).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal)).ConfigureAwait(false);
|
await _ipcManager.PenumbraSetTemporaryModsAsync(_logger, applicationId, coll, extractedFiles.Union(fileSwaps).ToDictionary(d => d.Key, d => d.Value, StringComparer.Ordinal)).ConfigureAwait(false);
|
||||||
await _ipcManager.PenumbraSetManipulationDataAsync(_logger, applicationId, coll, LoadedCharaFile.CharaFileData.ManipulationData).ConfigureAwait(false);
|
await _ipcManager.PenumbraSetManipulationDataAsync(_logger, applicationId, coll, LoadedCharaFile.CharaFileData.ManipulationData).ConfigureAwait(false);
|
||||||
using GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.Player, () => charaTarget.Address, false).ConfigureAwait(false);
|
|
||||||
|
|
||||||
|
GameObjectHandler tempHandler = await _gameObjectHandlerFactory.Create(ObjectKind.Player,
|
||||||
|
() => _dalamudUtil.GetGposeCharacterFromObjectTableByName(charaTarget.Name.ToString(), _isInGpose)?.Address ?? IntPtr.Zero, false).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (!_gposeGameObjects.Exists(o => o.Address == tempHandler.Address))
|
||||||
|
_gposeGameObjects.Add(tempHandler);
|
||||||
|
|
||||||
await _ipcManager.GlamourerApplyAllAsync(_logger, tempHandler, LoadedCharaFile.CharaFileData.GlamourerData, applicationId, disposeCts.Token).ConfigureAwait(false);
|
await _ipcManager.GlamourerApplyAllAsync(_logger, tempHandler, LoadedCharaFile.CharaFileData.GlamourerData, applicationId, disposeCts.Token).ConfigureAwait(false);
|
||||||
_dalamudUtil.WaitWhileGposeCharacterIsDrawing(charaTarget.Address, 30000);
|
_dalamudUtil.WaitWhileGposeCharacterIsDrawing(charaTarget.Address, 30000);
|
||||||
await _ipcManager.PenumbraRemoveTemporaryCollectionAsync(_logger, applicationId, coll).ConfigureAwait(false);
|
await _ipcManager.PenumbraRemoveTemporaryCollectionAsync(_logger, applicationId, coll).ConfigureAwait(false);
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
|
|||||||
private byte[] CustomizeData { get; set; } = new byte[26];
|
private byte[] CustomizeData { get; set; } = new byte[26];
|
||||||
private IntPtr DrawObjectAddress { get; set; }
|
private IntPtr DrawObjectAddress { get; set; }
|
||||||
private byte[] EquipSlotData { get; set; } = new byte[40];
|
private byte[] EquipSlotData { get; set; } = new byte[40];
|
||||||
|
private ushort[] MainHandData { get; set; } = new ushort[3];
|
||||||
|
private ushort[] OffHandData { get; set; } = new ushort[3];
|
||||||
|
|
||||||
public async Task ActOnFrameworkAfterEnsureNoDrawAsync(Action<Dalamud.Game.ClientState.Objects.Types.Character> act, CancellationToken token)
|
public async Task ActOnFrameworkAfterEnsureNoDrawAsync(Action<Dalamud.Game.ClientState.Objects.Types.Character> act, CancellationToken token)
|
||||||
{
|
{
|
||||||
@@ -212,6 +214,9 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
|
|||||||
&& ((CharacterBase*)DrawObjectAddress)->GetModelType() == CharacterBase.ModelType.Human)
|
&& ((CharacterBase*)DrawObjectAddress)->GetModelType() == CharacterBase.ModelType.Human)
|
||||||
{
|
{
|
||||||
equipDiff = CompareAndUpdateEquipByteData((byte*)&((Human*)DrawObjectAddress)->Head);
|
equipDiff = CompareAndUpdateEquipByteData((byte*)&((Human*)DrawObjectAddress)->Head);
|
||||||
|
equipDiff |= CompareAndUpdateMainHand(*((Weapon**)&chara->DrawData.MainHand + 1));
|
||||||
|
equipDiff |= CompareAndUpdateOffHand(*((Weapon**)&chara->DrawData.OffHand + 1));
|
||||||
|
|
||||||
if (equipDiff)
|
if (equipDiff)
|
||||||
Logger.LogTrace("Checking [{this}] equip data as human from draw obj, result: {diff}", this, equipDiff);
|
Logger.LogTrace("Checking [{this}] equip data as human from draw obj, result: {diff}", this, equipDiff);
|
||||||
}
|
}
|
||||||
@@ -222,6 +227,8 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
|
|||||||
Logger.LogTrace("Checking [{this}] equip data from game obj, result: {diff}", this, equipDiff);
|
Logger.LogTrace("Checking [{this}] equip data from game obj, result: {diff}", this, equipDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
@@ -264,6 +271,32 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private unsafe bool CompareAndUpdateMainHand(Weapon* weapon)
|
||||||
|
{
|
||||||
|
if ((nint)weapon == nint.Zero) return false;
|
||||||
|
bool hasChanges = false;
|
||||||
|
hasChanges |= weapon->ModelSetId != MainHandData[0];
|
||||||
|
MainHandData[0] = weapon->ModelSetId;
|
||||||
|
hasChanges |= weapon->Variant != MainHandData[1];
|
||||||
|
MainHandData[1] = weapon->Variant;
|
||||||
|
hasChanges |= weapon->SecondaryId != MainHandData[2];
|
||||||
|
MainHandData[2] = weapon->SecondaryId;
|
||||||
|
return hasChanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe bool CompareAndUpdateOffHand(Weapon* weapon)
|
||||||
|
{
|
||||||
|
if ((nint)weapon == nint.Zero) return false;
|
||||||
|
bool hasChanges = false;
|
||||||
|
hasChanges |= weapon->ModelSetId != OffHandData[0];
|
||||||
|
OffHandData[0] = weapon->ModelSetId;
|
||||||
|
hasChanges |= weapon->Variant != OffHandData[1];
|
||||||
|
OffHandData[1] = weapon->Variant;
|
||||||
|
hasChanges |= weapon->SecondaryId != OffHandData[2];
|
||||||
|
OffHandData[2] = weapon->SecondaryId;
|
||||||
|
return hasChanges;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ClearAsync(CancellationToken token)
|
private async Task ClearAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
Logger.LogDebug("[{this}] Running Clear Task", this);
|
Logger.LogDebug("[{this}] Running Clear Task", this);
|
||||||
|
|||||||
@@ -33,8 +33,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
private GameObjectHandler? _charaHandler;
|
private GameObjectHandler? _charaHandler;
|
||||||
private CancellationTokenSource? _downloadCancellationTokenSource = new();
|
private CancellationTokenSource? _downloadCancellationTokenSource = new();
|
||||||
private bool _forceApplyMods = false;
|
private bool _forceApplyMods = false;
|
||||||
private string _lastGlamourerData = string.Empty;
|
|
||||||
private string _originalGlamourerData = string.Empty;
|
|
||||||
private string _penumbraCollection;
|
private string _penumbraCollection;
|
||||||
private CancellationTokenSource _redrawCts = new();
|
private CancellationTokenSource _redrawCts = new();
|
||||||
|
|
||||||
@@ -60,7 +58,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
Mediator.Subscribe<ZoneSwitchStartMessage>(this, (_) =>
|
Mediator.Subscribe<ZoneSwitchStartMessage>(this, (_) =>
|
||||||
{
|
{
|
||||||
_downloadCancellationTokenSource?.CancelDispose();
|
_downloadCancellationTokenSource?.CancelDispose();
|
||||||
MediatorUnsubscribeFromCharacterChanged();
|
|
||||||
_charaHandler?.Invalidate();
|
_charaHandler?.Invalidate();
|
||||||
IsVisible = false;
|
IsVisible = false;
|
||||||
});
|
});
|
||||||
@@ -413,9 +410,8 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
Logger.LogTrace("[BASE-{appBase}] {this} visibility changed, now: {visi}, cached data exists", appData, this, IsVisible);
|
Logger.LogTrace("[BASE-{appBase}] {this} visibility changed, now: {visi}, cached data exists", appData, this, IsVisible);
|
||||||
|
|
||||||
_ = Task.Run(async () =>
|
_ = Task.Run(() =>
|
||||||
{
|
{
|
||||||
_lastGlamourerData = await _ipcManager.GlamourerGetCharacterCustomizationAsync(PlayerCharacter).ConfigureAwait(false);
|
|
||||||
ApplyCharacterData(appData, _cachedData!, true);
|
ApplyCharacterData(appData, _cachedData!, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -423,8 +419,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
{
|
{
|
||||||
Logger.LogTrace("{this} visibility changed, now: {visi}, no cached data exists", this, IsVisible);
|
Logger.LogTrace("{this} visibility changed, now: {visi}, no cached data exists", this, IsVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
MediatorSubscribeToCharacterChanged();
|
|
||||||
}
|
}
|
||||||
else if (_charaHandler?.Address == nint.Zero && IsVisible)
|
else if (_charaHandler?.Address == nint.Zero && IsVisible)
|
||||||
{
|
{
|
||||||
@@ -432,7 +426,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
_charaHandler?.Invalidate();
|
_charaHandler?.Invalidate();
|
||||||
_downloadCancellationTokenSource?.CancelDispose();
|
_downloadCancellationTokenSource?.CancelDispose();
|
||||||
_downloadCancellationTokenSource = null;
|
_downloadCancellationTokenSource = null;
|
||||||
MediatorUnsubscribeFromCharacterChanged();
|
|
||||||
Logger.LogTrace("{this} visibility changed, now: {visi}", this, IsVisible);
|
Logger.LogTrace("{this} visibility changed, now: {visi}", this, IsVisible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -442,8 +435,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
PlayerName = name;
|
PlayerName = name;
|
||||||
_charaHandler = _gameObjectHandlerFactory.Create(ObjectKind.Player, () => _dalamudUtil.GetPlayerCharacterFromCachedTableByIdent(OnlineUser.Ident), false).GetAwaiter().GetResult();
|
_charaHandler = _gameObjectHandlerFactory.Create(ObjectKind.Player, () => _dalamudUtil.GetPlayerCharacterFromCachedTableByIdent(OnlineUser.Ident), false).GetAwaiter().GetResult();
|
||||||
|
|
||||||
_originalGlamourerData = _ipcManager.GlamourerGetCharacterCustomizationAsync(PlayerCharacter).ConfigureAwait(false).GetAwaiter().GetResult();
|
|
||||||
_lastGlamourerData = _originalGlamourerData;
|
|
||||||
Mediator.Subscribe<PenumbraRedrawMessage>(this, IpcManagerOnPenumbraRedrawEvent);
|
Mediator.Subscribe<PenumbraRedrawMessage>(this, IpcManagerOnPenumbraRedrawEvent);
|
||||||
Mediator.Subscribe<HonorificReadyMessage>(this, async (_) =>
|
Mediator.Subscribe<HonorificReadyMessage>(this, async (_) =>
|
||||||
{
|
{
|
||||||
@@ -477,33 +468,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
|
|||||||
}, token);
|
}, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MediatorSubscribeToCharacterChanged()
|
|
||||||
{
|
|
||||||
Mediator.Subscribe<CharacterChangedMessage>(this, (msg) =>
|
|
||||||
{
|
|
||||||
if (msg.GameObjectHandler == _charaHandler && (_applicationTask?.IsCompleted ?? true))
|
|
||||||
{
|
|
||||||
Guid appBase = Guid.NewGuid();
|
|
||||||
var newGlamData = _ipcManager.GlamourerGetCharacterCustomizationAsync(PlayerCharacter).ConfigureAwait(false).GetAwaiter().GetResult();
|
|
||||||
if (!string.Equals(_lastGlamourerData, newGlamData, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
Logger.LogTrace("[BASE-{appBase}] Saving new Glamourer Data for {this}", appBase, this);
|
|
||||||
|
|
||||||
_lastGlamourerData = newGlamData;
|
|
||||||
if (_cachedData != null)
|
|
||||||
{
|
|
||||||
ApplyCharacterData(appBase, _cachedData!, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MediatorUnsubscribeFromCharacterChanged()
|
|
||||||
{
|
|
||||||
Mediator.Unsubscribe<CharacterChangedMessage>(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task RevertCustomizationDataAsync(ObjectKind objectKind, string name, Guid applicationId)
|
private async Task RevertCustomizationDataAsync(ObjectKind objectKind, string name, Guid applicationId)
|
||||||
{
|
{
|
||||||
nint address = _dalamudUtil.GetPlayerCharacterFromCachedTableByIdent(OnlineUser.Ident);
|
nint address = _dalamudUtil.GetPlayerCharacterFromCachedTableByIdent(OnlineUser.Ident);
|
||||||
@@ -518,15 +482,8 @@ 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}", applicationId, OnlineUser.User.AliasOrUID, name);
|
||||||
if (!_ipcManager.CheckGlamourerTestingApi())
|
await _ipcManager.GlamourerRevert(Logger, tempHandler, applicationId, cancelToken.Token).ConfigureAwait(false);
|
||||||
{
|
|
||||||
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);
|
||||||
|
|||||||
@@ -92,6 +92,13 @@ public class DalamudUtilService : IHostedService
|
|||||||
return (Dalamud.Game.ClientState.Objects.Types.Character)objTableObj;
|
return (Dalamud.Game.ClientState.Objects.Types.Character)objTableObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Dalamud.Game.ClientState.Objects.Types.Character? GetGposeCharacterFromObjectTableByName(string name, bool onlyGposeCharacters = false)
|
||||||
|
{
|
||||||
|
EnsureIsOnFramework();
|
||||||
|
return (Dalamud.Game.ClientState.Objects.Types.Character?)_objectTable.Where(i => !onlyGposeCharacters || i.ObjectIndex >= 200)
|
||||||
|
.FirstOrDefault(f => f.Name.ToString() == name);
|
||||||
|
}
|
||||||
|
|
||||||
public unsafe IntPtr GetCompanion(IntPtr? playerPointer = null)
|
public unsafe IntPtr GetCompanion(IntPtr? playerPointer = null)
|
||||||
{
|
{
|
||||||
EnsureIsOnFramework();
|
EnsureIsOnFramework();
|
||||||
|
|||||||
Reference in New Issue
Block a user