using MareSynchronos.API.Data.Enum; using MareSynchronos.Interop.Ipc; using MareSynchronos.PlayerData.Factories; using MareSynchronos.PlayerData.Handlers; using MareSynchronos.Services.CharaData.Models; using MareSynchronos.Services.Mediator; using Microsoft.Extensions.Logging; namespace MareSynchronos.Services; public sealed class CharaDataCharacterHandler : DisposableMediatorSubscriberBase { private readonly GameObjectHandlerFactory _gameObjectHandlerFactory; private readonly DalamudUtilService _dalamudUtilService; private readonly IpcManager _ipcManager; private readonly Dictionary _handledCharaData = new(StringComparer.Ordinal); public IReadOnlyDictionary HandledCharaData => _handledCharaData; public CharaDataCharacterHandler(ILogger logger, MareMediator mediator, GameObjectHandlerFactory gameObjectHandlerFactory, DalamudUtilService dalamudUtilService, IpcManager ipcManager) : base(logger, mediator) { _gameObjectHandlerFactory = gameObjectHandlerFactory; _dalamudUtilService = dalamudUtilService; _ipcManager = ipcManager; mediator.Subscribe(this, msg => { foreach (var chara in _handledCharaData) { _ = RevertHandledChara(chara.Value); } }); mediator.Subscribe(this, (_) => HandleCutsceneFrameworkUpdate()); } private void HandleCutsceneFrameworkUpdate() { if (!_dalamudUtilService.IsInGpose) return; foreach (var entry in _handledCharaData.Values.ToList()) { var chara = _dalamudUtilService.GetGposeCharacterFromObjectTableByName(entry.Name, onlyGposeCharacters: true); if (chara is null) { _handledCharaData.Remove(entry.Name); _ = _dalamudUtilService.RunOnFrameworkThread(() => RevertChara(entry.Name, entry.CustomizePlus)); } } } protected override void Dispose(bool disposing) { base.Dispose(disposing); foreach (var chara in _handledCharaData.Values) { _ = RevertHandledChara(chara); } } public HandledCharaDataEntry? GetHandledCharacter(string name) { return _handledCharaData.GetValueOrDefault(name); } public async Task RevertChara(string name, Guid? cPlusId) { Guid applicationId = Guid.NewGuid(); await _ipcManager.Glamourer.RevertByNameAsync(Logger, name, applicationId).ConfigureAwait(false); if (cPlusId != null) { await _ipcManager.CustomizePlus.RevertByIdAsync(cPlusId).ConfigureAwait(false); } using var handler = await _gameObjectHandlerFactory.Create(ObjectKind.Player, () => _dalamudUtilService.GetGposeCharacterFromObjectTableByName(name, _dalamudUtilService.IsInGpose)?.Address ?? IntPtr.Zero, false) .ConfigureAwait(false); if (handler.Address != nint.Zero) await _ipcManager.Penumbra.RedrawAsync(Logger, handler, applicationId, CancellationToken.None).ConfigureAwait(false); } public async Task RevertHandledChara(string name) { var handled = _handledCharaData.GetValueOrDefault(name); return await RevertHandledChara(handled).ConfigureAwait(false); } public async Task RevertHandledChara(HandledCharaDataEntry? handled) { if (handled == null) return false; _handledCharaData.Remove(handled.Name); await _dalamudUtilService.RunOnFrameworkThread(async () => { await RevertChara(handled.Name, handled.CustomizePlus).ConfigureAwait(false); }).ConfigureAwait(false); return true; } internal void AddHandledChara(HandledCharaDataEntry handledCharaDataEntry) { _handledCharaData.Add(handledCharaDataEntry.Name, handledCharaDataEntry); } public void UpdateHandledData(Dictionary newData) { foreach (var handledData in _handledCharaData.Values) { if (newData.TryGetValue(handledData.MetaInfo.FullId, out var metaInfo) && metaInfo != null) { handledData.MetaInfo = metaInfo; } } } public async Task TryCreateGameObjectHandler(string name, bool gPoseOnly = false) { var handler = await _gameObjectHandlerFactory.Create(ObjectKind.Player, () => _dalamudUtilService.GetGposeCharacterFromObjectTableByName(name, gPoseOnly && _dalamudUtilService.IsInGpose)?.Address ?? IntPtr.Zero, false) .ConfigureAwait(false); if (handler.Address == nint.Zero) return null; return handler; } public async Task TryCreateGameObjectHandler(int index) { var handler = await _gameObjectHandlerFactory.Create(ObjectKind.Player, () => _dalamudUtilService.GetCharacterFromObjectTableByIndex(index)?.Address ?? IntPtr.Zero, false) .ConfigureAwait(false); if (handler.Address == nint.Zero) return null; return handler; } }