using Dalamud.Logging; using Dalamud.Plugin; using Dalamud.Plugin.Ipc; using System; using System.Collections.Generic; using System.Linq; using Dalamud.Game.ClientState.Objects.Types; using Lumina.Excel.GeneratedSheets; using MareSynchronos.Utils; namespace MareSynchronos.Managers { public class IpcManager : IDisposable { private readonly ICallGateSubscriber _glamourerApiVersion; private readonly ICallGateSubscriber? _glamourerApplyAll; private readonly ICallGateSubscriber? _glamourerGetAllCustomization; private readonly ICallGateSubscriber _glamourerRevertCustomization; private readonly ICallGateSubscriber? _glamourerApplyOnlyEquipment; private readonly ICallGateSubscriber? _glamourerApplyOnlyCustomization; private readonly ICallGateSubscriber<(int, int)> _penumbraApiVersion; private readonly ICallGateSubscriber _penumbraCreateTemporaryCollection; private readonly ICallGateSubscriber _penumbraGetMetaManipulations; private readonly ICallGateSubscriber _penumbraInit; private readonly ICallGateSubscriber _penumbraDispose; private readonly ICallGateSubscriber _penumbraObjectIsRedrawn; private readonly ICallGateSubscriber? _penumbraRedraw; private readonly ICallGateSubscriber _penumbraRemoveTemporaryCollection; private readonly ICallGateSubscriber? _penumbraResolveModDir; private readonly ICallGateSubscriber? _penumbraResolvePath; private readonly ICallGateSubscriber? _penumbraReverseResolvePath; private readonly ICallGateSubscriber, string, int, int> _penumbraSetTemporaryMod; public IpcManager(DalamudPluginInterface pi) { Logger.Debug("Creating " + nameof(IpcManager)); _penumbraInit = pi.GetIpcSubscriber("Penumbra.Initialized"); _penumbraDispose = pi.GetIpcSubscriber("Penumbra.Disposed"); _penumbraResolvePath = pi.GetIpcSubscriber("Penumbra.ResolveCharacterPath"); _penumbraResolveModDir = pi.GetIpcSubscriber("Penumbra.GetModDirectory"); _penumbraRedraw = pi.GetIpcSubscriber("Penumbra.RedrawObjectByName"); _penumbraReverseResolvePath = pi.GetIpcSubscriber("Penumbra.ReverseResolvePath"); _penumbraApiVersion = pi.GetIpcSubscriber<(int, int)>("Penumbra.ApiVersions"); _penumbraObjectIsRedrawn = pi.GetIpcSubscriber("Penumbra.GameObjectRedrawn"); _penumbraGetMetaManipulations = pi.GetIpcSubscriber("Penumbra.GetMetaManipulations"); _glamourerApiVersion = pi.GetIpcSubscriber("Glamourer.ApiVersion"); _glamourerGetAllCustomization = pi.GetIpcSubscriber("Glamourer.GetAllCustomizationFromCharacter"); _glamourerApplyAll = pi.GetIpcSubscriber("Glamourer.ApplyAllToCharacter"); _glamourerApplyOnlyCustomization = pi.GetIpcSubscriber("Glamourer.ApplyOnlyCustomizationToCharacter"); _glamourerApplyOnlyEquipment = pi.GetIpcSubscriber("Glamourer.ApplyOnlyEquipmentToCharacter"); _glamourerRevertCustomization = pi.GetIpcSubscriber("Glamourer.RevertCharacter"); _penumbraObjectIsRedrawn.Subscribe(RedrawEvent); _penumbraInit.Subscribe(PenumbraInit); _penumbraDispose.Subscribe(PenumbraDispose); _penumbraSetTemporaryMod = pi .GetIpcSubscriber, string, int, int>("Penumbra.AddTemporaryMod"); _penumbraCreateTemporaryCollection = pi.GetIpcSubscriber("Penumbra.CreateTemporaryCollection"); _penumbraRemoveTemporaryCollection = pi.GetIpcSubscriber("Penumbra.RemoveTemporaryCollection"); if (Initialized) { PenumbraInitialized?.Invoke(null, EventArgs.Empty); } } public event EventHandler? PenumbraInitialized; public event EventHandler? PenumbraDisposed; public event EventHandler? PenumbraRedrawEvent; public bool Initialized => CheckPenumbraApi(); public bool CheckGlamourerApi() { try { return _glamourerApiVersion.InvokeFunc() >= 0; } catch { return false; } } public bool CheckPenumbraApi() { try { return _penumbraApiVersion.InvokeFunc() is { Item1: 4, Item2: >=8 }; } catch { return false; } } public void Dispose() { Logger.Debug("Disposing " + nameof(IpcManager)); _penumbraDispose.Unsubscribe(PenumbraDispose); _penumbraInit.Unsubscribe(PenumbraInit); _penumbraObjectIsRedrawn.Unsubscribe(RedrawEvent); Logger.Debug("IPC Manager disposed"); } public void GlamourerApplyAll(string customization, GameObject character) { if (!CheckGlamourerApi()) return; Logger.Debug("Glamourer apply all to " + character); _glamourerApplyAll!.InvokeAction(customization, character); } public void GlamourerApplyOnlyEquipment(string customization, GameObject character) { if (!CheckGlamourerApi() || string.IsNullOrEmpty(customization)) return; Logger.Debug("Glamourer apply only equipment to " + character); _glamourerApplyOnlyEquipment!.InvokeAction(customization, character); } public void GlamourerApplyOnlyCustomization(string customization, GameObject character) { if (!CheckGlamourerApi() || string.IsNullOrEmpty(customization)) return; Logger.Debug("Glamourer apply only customization to " + character); _glamourerApplyOnlyCustomization!.InvokeAction(customization, character); } public string GlamourerGetCharacterCustomization(GameObject character) { if (!CheckGlamourerApi()) return string.Empty; return _glamourerGetAllCustomization!.InvokeFunc(character); } public void GlamourerRevertCharacterCustomization(GameObject character) { if (!CheckGlamourerApi()) return; _glamourerRevertCustomization!.InvokeAction(character); } public string PenumbraCreateTemporaryCollection(string characterName) { if (!CheckPenumbraApi()) return string.Empty; Logger.Debug("Creating temp collection for " + characterName); var ret = _penumbraCreateTemporaryCollection.InvokeFunc("MareSynchronos", characterName, true); return ret.Item2; } public string PenumbraGetMetaManipulations(string characterName) { if (!CheckPenumbraApi()) return string.Empty; return _penumbraGetMetaManipulations.InvokeFunc(characterName); } public string? PenumbraModDirectory() { if (!CheckPenumbraApi()) return null; return _penumbraResolveModDir!.InvokeFunc(); } public void PenumbraRedraw(string actorName) { if (!CheckPenumbraApi()) return; _penumbraRedraw!.InvokeAction(actorName, 0); } public void PenumbraRemoveTemporaryCollection(string characterName) { if (!CheckPenumbraApi()) return; Logger.Debug("Removing temp collection for " + characterName); _penumbraRemoveTemporaryCollection.InvokeFunc(characterName); } public string? PenumbraResolvePath(string path, string characterName) { if (!CheckPenumbraApi()) return null; var resolvedPath = _penumbraResolvePath!.InvokeFunc(path, characterName); PluginLog.Verbose("Resolving " + path + Environment.NewLine + "=>" + string.Join(", ", resolvedPath)); return resolvedPath; } public string[] PenumbraReverseResolvePath(string path, string characterName) { if (!CheckPenumbraApi()) return new[] { path }; var resolvedPaths = _penumbraReverseResolvePath!.InvokeFunc(path, characterName); PluginLog.Verbose("ReverseResolving " + path + Environment.NewLine + "=>" + string.Join(", ", resolvedPaths)); return resolvedPaths; } public void PenumbraSetTemporaryMods(string collectionName, Dictionary modPaths, string manipulationData) { if (!CheckPenumbraApi()) return; Logger.Debug("Assigning temp mods for " + collectionName); foreach (var mod in modPaths) { Logger.Verbose(mod.Key + " => " + mod.Value); } var ret = _penumbraSetTemporaryMod.InvokeFunc("MareSynchronos", collectionName, modPaths, manipulationData, 0); } private void RedrawEvent(IntPtr objectAddress, int objectTableIndex) { PenumbraRedrawEvent?.Invoke(objectTableIndex, EventArgs.Empty); } private void PenumbraInit() { PenumbraInitialized?.Invoke(null, EventArgs.Empty); _penumbraRedraw!.InvokeAction("self", 0); } private void PenumbraDispose() { PenumbraDisposed?.Invoke(null, EventArgs.Empty); } } }