From de37e22c20d3e94aad6a7a6c01c8e7dfd929b54e Mon Sep 17 00:00:00 2001 From: rootdarkarchon Date: Sun, 18 Dec 2022 15:31:25 +0100 Subject: [PATCH] change to penumbra.api, fix animations requiring a redraw to be picked up again --- .../Factories/CharacterDataFactory.cs | 9 ++ MareSynchronos/Managers/CachedPlayer.cs | 2 + MareSynchronos/Managers/IpcManager.cs | 132 ++++++++++-------- .../Managers/TransientResourceManager.cs | 33 +++-- MareSynchronos/MareSynchronos.csproj | 2 +- MareSynchronos/Utils/DalamudUtil.cs | 13 ++ 6 files changed, 126 insertions(+), 65 deletions(-) diff --git a/MareSynchronos/Factories/CharacterDataFactory.cs b/MareSynchronos/Factories/CharacterDataFactory.cs index 4529427..43654dc 100644 --- a/MareSynchronos/Factories/CharacterDataFactory.cs +++ b/MareSynchronos/Factories/CharacterDataFactory.cs @@ -344,6 +344,15 @@ public class CharacterDataFactory { _transientResourceManager.PersistTransientResources(charaPointer, objectKind, CreateFileReplacement); + // get rid of items that have no file replacements anymore + foreach (var entry in previousData.FileReplacements.ToList()) + { + foreach (var item in entry.Value.ToList()) + { + if (!item.HasFileReplacement) previousData.FileReplacements[entry.Key].Remove(item); + } + } + foreach (var item in _transientResourceManager.GetSemiTransientResources(objectKind)) { if (!previousData.FileReplacements.ContainsKey(objectKind)) diff --git a/MareSynchronos/Managers/CachedPlayer.cs b/MareSynchronos/Managers/CachedPlayer.cs index b0e65f1..d1b27f4 100644 --- a/MareSynchronos/Managers/CachedPlayer.cs +++ b/MareSynchronos/Managers/CachedPlayer.cs @@ -182,6 +182,8 @@ public class CachedPlayer { break; } + + await Task.Delay(TimeSpan.FromSeconds(2)).ConfigureAwait(false); } ApplyBaseData(moddedPaths); diff --git a/MareSynchronos/Managers/IpcManager.cs b/MareSynchronos/Managers/IpcManager.cs index e6df56c..c14f14b 100644 --- a/MareSynchronos/Managers/IpcManager.cs +++ b/MareSynchronos/Managers/IpcManager.cs @@ -7,6 +7,8 @@ using MareSynchronos.Utils; using Action = System.Action; using System.Collections.Concurrent; using System.Text; +using Penumbra.Api.Enums; +using Penumbra.Api.Helpers; namespace MareSynchronos.Managers; @@ -22,21 +24,24 @@ public class IpcManager : IDisposable 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? _penumbraRedrawObject; - private readonly ICallGateSubscriber _penumbraRemoveTemporaryCollection; - private readonly ICallGateSubscriber? _penumbraResolveModDir; - private readonly ICallGateSubscriber? _penumbraResolvePlayer; - private readonly ICallGateSubscriber? _reverseResolvePlayer; - private readonly ICallGateSubscriber, string, int, int> - _penumbraSetTemporaryMod; - private readonly ICallGateSubscriber _penumbraGameObjectResourcePathResolved; + + private readonly FuncSubscriber<(int, int)> _penumbraApiVersion; + private readonly FuncSubscriber _penumbraCreateNamedTemporaryCollection; + private readonly FuncSubscriber _penumbraGetMetaManipulations; + private readonly EventSubscriber _penumbraInit; + private readonly EventSubscriber _penumbraDispose; + private readonly EventSubscriber _penumbraObjectIsRedrawn; + private readonly ActionSubscriber _penumbraRedraw; + private readonly ActionSubscriber _penumbraRedrawObject; + private readonly FuncSubscriber _penumbraRemoveTemporaryCollection; + private readonly FuncSubscriber _penumbraRemoveTemporaryMod; + private readonly FuncSubscriber _penumbraAssignTemporaryCollection; + private readonly FuncSubscriber _penumbraResolveModDir; + private readonly FuncSubscriber _penumbraResolvePlayer; + private readonly FuncSubscriber _reverseResolvePlayer; + private readonly FuncSubscriber, string, int, PenumbraApiEc> _penumbraAddTemporaryMod; + private readonly EventSubscriber _penumbraGameObjectResourcePathResolved; + private readonly EventSubscriber _penumbraModSettingChanged; private readonly ICallGateSubscriber _heelsGetApiVersion; private readonly ICallGateSubscriber _heelsGetOffset; @@ -57,29 +62,24 @@ public class IpcManager : IDisposable { Logger.Verbose("Creating " + nameof(IpcManager)); - _penumbraInit = pi.GetIpcSubscriber("Penumbra.Initialized"); - _penumbraDispose = pi.GetIpcSubscriber("Penumbra.Disposed"); - _penumbraResolvePlayer = pi.GetIpcSubscriber("Penumbra.ResolvePlayerPath"); - _penumbraResolveModDir = pi.GetIpcSubscriber("Penumbra.GetModDirectory"); - _penumbraRedraw = pi.GetIpcSubscriber("Penumbra.RedrawObjectByName"); - _penumbraRedrawObject = pi.GetIpcSubscriber("Penumbra.RedrawObject"); - _reverseResolvePlayer = pi.GetIpcSubscriber("Penumbra.ReverseResolvePlayerPath"); - _penumbraApiVersion = pi.GetIpcSubscriber<(int, int)>("Penumbra.ApiVersions"); - _penumbraObjectIsRedrawn = pi.GetIpcSubscriber("Penumbra.GameObjectRedrawn"); - _penumbraGetMetaManipulations = - pi.GetIpcSubscriber("Penumbra.GetPlayerMetaManipulations"); - _penumbraSetTemporaryMod = pi.GetIpcSubscriber, string, int, - int>("Penumbra.AddTemporaryMod"); - _penumbraCreateTemporaryCollection = - pi.GetIpcSubscriber("Penumbra.CreateTemporaryCollection"); - _penumbraRemoveTemporaryCollection = - pi.GetIpcSubscriber("Penumbra.RemoveTemporaryCollection"); - _penumbraGameObjectResourcePathResolved = pi.GetIpcSubscriber("Penumbra.GameObjectResourcePathResolved"); + _penumbraInit = Penumbra.Api.Ipc.Initialized.Subscriber(pi, () => PenumbraInit()); + _penumbraDispose = Penumbra.Api.Ipc.Disposed.Subscriber(pi, () => PenumbraDispose()); + _penumbraResolvePlayer = Penumbra.Api.Ipc.ResolvePlayerPath.Subscriber(pi); + _penumbraResolveModDir = Penumbra.Api.Ipc.GetModDirectory.Subscriber(pi); + _penumbraRedraw = Penumbra.Api.Ipc.RedrawObjectByName.Subscriber(pi); + _penumbraRedrawObject = Penumbra.Api.Ipc.RedrawObject.Subscriber(pi); + _reverseResolvePlayer = Penumbra.Api.Ipc.ReverseResolvePlayerPath.Subscriber(pi); + _penumbraApiVersion = Penumbra.Api.Ipc.ApiVersions.Subscriber(pi); + _penumbraObjectIsRedrawn = Penumbra.Api.Ipc.GameObjectRedrawn.Subscriber(pi, (ptr, idx) => RedrawEvent((IntPtr)ptr, idx)); + _penumbraGetMetaManipulations = Penumbra.Api.Ipc.GetPlayerMetaManipulations.Subscriber(pi); + _penumbraAddTemporaryMod = Penumbra.Api.Ipc.AddTemporaryMod.Subscriber(pi); + _penumbraCreateNamedTemporaryCollection = Penumbra.Api.Ipc.CreateNamedTemporaryCollection.Subscriber(pi); + _penumbraRemoveTemporaryCollection = Penumbra.Api.Ipc.RemoveTemporaryCollectionByName.Subscriber(pi); + _penumbraRemoveTemporaryMod = Penumbra.Api.Ipc.RemoveTemporaryMod.Subscriber(pi); + _penumbraAssignTemporaryCollection = Penumbra.Api.Ipc.AssignTemporaryCollection.Subscriber(pi); - _penumbraGameObjectResourcePathResolved.Subscribe(ResourceLoaded); - _penumbraObjectIsRedrawn.Subscribe(RedrawEvent); - _penumbraInit.Subscribe(PenumbraInit); - _penumbraDispose.Subscribe(PenumbraDispose); + _penumbraGameObjectResourcePathResolved = Penumbra.Api.Ipc.GameObjectResourcePathResolved.Subscriber(pi, (ptr, arg1, arg2) => ResourceLoaded((IntPtr)ptr, arg1, arg2)); + _penumbraModSettingChanged = Penumbra.Api.Ipc.ModSettingChanged.Subscriber(pi, (modsetting, a, b, c) => PenumbraModSettingChangedHandler()); _glamourerApiVersion = pi.GetIpcSubscriber("Glamourer.ApiVersion"); _glamourerGetAllCustomization = pi.GetIpcSubscriber("Glamourer.GetAllCustomizationFromCharacter"); @@ -114,6 +114,11 @@ public class IpcManager : IDisposable _dalamudUtil.ZoneSwitchEnd += ClearActionQueue; } + private void PenumbraModSettingChangedHandler() + { + PenumbraModSettingChanged?.Invoke(); + } + private void ClearActionQueue() { actionQueue.Clear(); @@ -124,7 +129,6 @@ public class IpcManager : IDisposable if (ptr != IntPtr.Zero && string.Compare(arg1, arg2, true, System.Globalization.CultureInfo.InvariantCulture) != 0) { PenumbraResourceLoadEvent?.Invoke(ptr, arg1, arg2); - //Logger.Debug($"Resolved {ptr:X}: {arg1} => {arg2}"); } } @@ -138,6 +142,7 @@ public class IpcManager : IDisposable } } + public event VoidDelegate? PenumbraModSettingChanged; public event VoidDelegate? PenumbraInitialized; public event VoidDelegate? PenumbraDisposed; public event PenumbraRedrawEvent? PenumbraRedrawEvent; @@ -162,7 +167,7 @@ public class IpcManager : IDisposable { try { - return _penumbraApiVersion.InvokeFunc() is { Item1: 4, Item2: >= 13 }; + return _penumbraApiVersion.Invoke() is { Item1: 4, Item2: >= 13 }; } catch { @@ -216,10 +221,11 @@ public class IpcManager : IDisposable _dalamudUtil.ZoneSwitchEnd -= ClearActionQueue; actionQueue.Clear(); - _penumbraDispose.Unsubscribe(PenumbraDispose); - _penumbraInit.Unsubscribe(PenumbraInit); - _penumbraObjectIsRedrawn.Unsubscribe(RedrawEvent); - _penumbraGameObjectResourcePathResolved.Unsubscribe(ResourceLoaded); + _penumbraGameObjectResourcePathResolved.Dispose(); + _penumbraDispose.Dispose(); + _penumbraInit.Dispose(); + _penumbraObjectIsRedrawn.Dispose(); + _penumbraModSettingChanged.Dispose(); _heelsOffsetUpdate.Unsubscribe(HeelsOffsetChange); } @@ -261,7 +267,7 @@ public class IpcManager : IDisposable { if (!CheckCustomizePlusApi()) return string.Empty; var scale = _customizePlusGetBodyScale.InvokeFunc(_dalamudUtil.PlayerName); - if(string.IsNullOrEmpty(scale)) return string.Empty; + if (string.IsNullOrEmpty(scale)) return string.Empty; return Convert.ToBase64String(Encoding.UTF8.GetBytes(scale)); } @@ -368,13 +374,13 @@ public class IpcManager : IDisposable public string PenumbraGetMetaManipulations() { if (!CheckPenumbraApi()) return string.Empty; - return _penumbraGetMetaManipulations.InvokeFunc(); + return _penumbraGetMetaManipulations.Invoke(); } public string? PenumbraModDirectory() { if (!CheckPenumbraApi()) return null; - return _penumbraResolveModDir!.InvokeFunc().ToLowerInvariant(); + return _penumbraResolveModDir!.Invoke().ToLowerInvariant(); } public void PenumbraRedraw(IntPtr obj) @@ -386,7 +392,7 @@ public class IpcManager : IDisposable if (gameObj != null) { Logger.Verbose("Redrawing " + gameObj); - _penumbraRedrawObject!.InvokeAction(gameObj, 0); + _penumbraRedrawObject!.Invoke(gameObj, RedrawType.Redraw); } }); } @@ -394,7 +400,7 @@ public class IpcManager : IDisposable public void PenumbraRedraw(string actorName) { if (!CheckPenumbraApi()) return; - actionQueue.Enqueue(() => _penumbraRedraw!.InvokeAction(actorName, 0)); + actionQueue.Enqueue(() => _penumbraRedraw!.Invoke(actorName, RedrawType.Redraw)); } public void PenumbraRemoveTemporaryCollection(string characterName) @@ -402,22 +408,26 @@ public class IpcManager : IDisposable if (!CheckPenumbraApi()) return; actionQueue.Enqueue(() => { - Logger.Verbose("Removing temp collection for " + characterName); - _penumbraRemoveTemporaryCollection.InvokeFunc(characterName); + var collName = "Mare_" + characterName; + Logger.Verbose("Removing temp collection for " + collName); + var ret = _penumbraRemoveTemporaryMod.Invoke("MaraChara", collName, 0); + Logger.Verbose("RemoveTemporaryMod: " + ret); + var ret2 = _penumbraRemoveTemporaryCollection.Invoke(collName); + Logger.Verbose("RemoveTemporaryCollection: " + ret2); }); } public string PenumbraResolvePath(string path) { if (!CheckPenumbraApi()) return path; - var resolvedPath = _penumbraResolvePlayer!.InvokeFunc(path); + var resolvedPath = _penumbraResolvePlayer!.Invoke(path); return resolvedPath ?? path; } public string[] PenumbraReverseResolvePlayer(string path) { if (!CheckPenumbraApi()) return new[] { path }; - var resolvedPaths = _reverseResolvePlayer!.InvokeFunc(path); + var resolvedPaths = _reverseResolvePlayer.Invoke(path); if (resolvedPaths.Length == 0) { resolvedPaths = new[] { path }; @@ -431,13 +441,23 @@ public class IpcManager : IDisposable actionQueue.Enqueue(() => { - var ret = _penumbraCreateTemporaryCollection.InvokeFunc("MareSynchronos", characterName, true); - Logger.Verbose("Assigning temp mods for " + ret.Item2); + var idx = _dalamudUtil.GetIndexFromObjectTableByName(characterName); + if (idx == null) + { + return; + } + var collName = "Mare_" + characterName; + var ret = _penumbraCreateNamedTemporaryCollection.Invoke(collName); + Logger.Verbose("Creating Temp Collection " + collName + ", Success: " + ret); + var retAssign = _penumbraAssignTemporaryCollection.Invoke(collName, idx.Value, true); + Logger.Verbose("Assigning Temp Collection " + collName + " to index " + idx.Value); foreach (var mod in modPaths) { Logger.Verbose(mod.Key + " => " + mod.Value); } - _penumbraSetTemporaryMod.InvokeFunc("MareSynchronos", ret.Item2, modPaths, manipulationData, 0); + + var ret2 = _penumbraAddTemporaryMod.Invoke("MareChara", collName, modPaths, manipulationData, 0); + Logger.Verbose("Setting temp mods for " + collName + ", Success: " + ret2); }); } @@ -449,7 +469,7 @@ public class IpcManager : IDisposable private void PenumbraInit() { PenumbraInitialized?.Invoke(); - _penumbraRedraw!.InvokeAction("self", 0); + _penumbraRedraw!.Invoke("self", RedrawType.Redraw); } private void HeelsOffsetChange(float offset) diff --git a/MareSynchronos/Managers/TransientResourceManager.cs b/MareSynchronos/Managers/TransientResourceManager.cs index 5cba470..7aeaaff 100644 --- a/MareSynchronos/Managers/TransientResourceManager.cs +++ b/MareSynchronos/Managers/TransientResourceManager.cs @@ -29,6 +29,7 @@ public class TransientResourceManager : IDisposable public TransientResourceManager(IpcManager manager, DalamudUtil dalamudUtil, FileReplacementFactory fileReplacementFactory, string configurationDirectory) { manager.PenumbraResourceLoadEvent += Manager_PenumbraResourceLoadEvent; + manager.PenumbraModSettingChanged += Manager_PenumbraModSettingChanged; this.manager = manager; this.dalamudUtil = dalamudUtil; this.fileReplacementFactory = fileReplacementFactory; @@ -55,9 +56,7 @@ public class TransientResourceManager : IDisposable } catch (Exception ex) { - Logger.Warn("Error during loading persistent transient resource " + line); - Logger.Warn(ex.Message); - Logger.Warn(ex.StackTrace); + Logger.Warn("Error during loading persistent transient resource " + line, ex); } } @@ -65,6 +64,23 @@ public class TransientResourceManager : IDisposable } } + private void Manager_PenumbraModSettingChanged() + { + bool successfulValidation = true; + Logger.Debug("Penumbra Mod Settings changed, verifying SemiTransientResources"); + foreach (var item in SemiTransientResources) + { + item.Value.RemoveWhere(p => + { + var verified = p.Verify(); + successfulValidation &= verified; + return !verified; + }); + if (!successfulValidation) + TransientResourceLoaded?.Invoke(dalamudUtil.PlayerPointer); + } + } + private void DalamudUtil_ClassJobChanged() { if (SemiTransientResources.ContainsKey(ObjectKind.Pet)) @@ -139,8 +155,10 @@ public class TransientResourceManager : IDisposable var replacedGamePath = gamePath.ToLowerInvariant().Replace("\\", "/", StringComparison.OrdinalIgnoreCase); if (TransientResources[gameObject].Contains(replacedGamePath) || - SemiTransientResources.Any(r => r.Value.Any(f => string.Equals(f.GamePaths.First(), replacedGamePath, StringComparison.OrdinalIgnoreCase) - && string.Equals(f.ResolvedPath, filePath, StringComparison.OrdinalIgnoreCase)))) + SemiTransientResources.Any(r => r.Value.Any(f => + string.Equals(f.GamePaths.First(), replacedGamePath, StringComparison.OrdinalIgnoreCase) + && string.Equals(f.ResolvedPath, filePath, StringComparison.OrdinalIgnoreCase)) + )) { Logger.Verbose("Not adding " + replacedGamePath + ":" + filePath); Logger.Verbose("SemiTransientAny: " + SemiTransientResources.Any(r => r.Value.Any(f => string.Equals(f.GamePaths.First(), replacedGamePath, StringComparison.OrdinalIgnoreCase) @@ -207,9 +225,7 @@ public class TransientResourceManager : IDisposable } catch (Exception ex) { - Logger.Warn("Issue during transient file persistence"); - Logger.Warn(ex.Message); - Logger.Warn(ex.StackTrace.ToString()); + Logger.Warn("Issue during transient file persistence", ex); } } @@ -225,6 +241,7 @@ public class TransientResourceManager : IDisposable dalamudUtil.FrameworkUpdate -= DalamudUtil_FrameworkUpdate; manager.PenumbraResourceLoadEvent -= Manager_PenumbraResourceLoadEvent; dalamudUtil.ClassJobChanged -= DalamudUtil_ClassJobChanged; + manager.PenumbraModSettingChanged -= Manager_PenumbraModSettingChanged; TransientResources.Clear(); SemiTransientResources.Clear(); if (SemiTransientResources.ContainsKey(ObjectKind.Player)) diff --git a/MareSynchronos/MareSynchronos.csproj b/MareSynchronos/MareSynchronos.csproj index d5e05d6..6e27c96 100644 --- a/MareSynchronos/MareSynchronos.csproj +++ b/MareSynchronos/MareSynchronos.csproj @@ -3,7 +3,7 @@ - 0.5.14 + 0.5.15 https://github.com/Penumbra-Sync/client diff --git a/MareSynchronos/Utils/DalamudUtil.cs b/MareSynchronos/Utils/DalamudUtil.cs index fe23079..bcf19e1 100644 --- a/MareSynchronos/Utils/DalamudUtil.cs +++ b/MareSynchronos/Utils/DalamudUtil.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection.Metadata.Ecma335; using System.Threading; using System.Threading.Tasks; using Dalamud.Game; @@ -207,6 +208,18 @@ public class DalamudUtil : IDisposable return null; } + public int? GetIndexFromObjectTableByName(string characterName) + { + for (int i = 0; i < _objectTable.Length; i++) + { + if (_objectTable[i] == null) continue; + if (_objectTable[i]!.ObjectKind != Dalamud.Game.ClientState.Objects.Enums.ObjectKind.Player) continue; + if (string.Equals(_objectTable[i]!.Name.ToString(), characterName, StringComparison.Ordinal)) return i; + } + + return null; + } + public async Task RunOnFrameworkThread(Func func) { return await _framework.RunOnFrameworkThread(func).ConfigureAwait(false);