From 669ee7447328d8e85c9c322d8fb9dad1544bb25a Mon Sep 17 00:00:00 2001 From: Kurochi51 Date: Mon, 15 Apr 2024 19:30:36 +0300 Subject: [PATCH] Perfectly reasonable compat code for penumbra api. --- TickTracker/IPC/PenumbraEnums.cs | 96 +++++++++++++++++++++ TickTracker/IPC/PenumbraIpc.cs | 140 ++++++++++++++++++++++++------- TickTracker/TickTracker.csproj | 2 +- TickTracker/packages.lock.json | 6 +- 4 files changed, 212 insertions(+), 32 deletions(-) diff --git a/TickTracker/IPC/PenumbraEnums.cs b/TickTracker/IPC/PenumbraEnums.cs index 383751f..c00020d 100644 --- a/TickTracker/IPC/PenumbraEnums.cs +++ b/TickTracker/IPC/PenumbraEnums.cs @@ -37,4 +37,100 @@ public enum ModSettingChange MultiEnableState, } +public enum ApiCollectionType : byte +{ + Yourself = 0, + + MalePlayerCharacter, + FemalePlayerCharacter, + MaleNonPlayerCharacter, + FemaleNonPlayerCharacter, + NonPlayerChild, + NonPlayerElderly, + + MaleMidlander, + FemaleMidlander, + MaleHighlander, + FemaleHighlander, + + MaleWildwood, + FemaleWildwood, + MaleDuskwight, + FemaleDuskwight, + + MalePlainsfolk, + FemalePlainsfolk, + MaleDunesfolk, + FemaleDunesfolk, + + MaleSeekerOfTheSun, + FemaleSeekerOfTheSun, + MaleKeeperOfTheMoon, + FemaleKeeperOfTheMoon, + + MaleSeawolf, + FemaleSeawolf, + MaleHellsguard, + FemaleHellsguard, + + MaleRaen, + FemaleRaen, + MaleXaela, + FemaleXaela, + + MaleHelion, + FemaleHelion, + MaleLost, + FemaleLost, + + MaleRava, + FemaleRava, + MaleVeena, + FemaleVeena, + + MaleMidlanderNpc, + FemaleMidlanderNpc, + MaleHighlanderNpc, + FemaleHighlanderNpc, + + MaleWildwoodNpc, + FemaleWildwoodNpc, + MaleDuskwightNpc, + FemaleDuskwightNpc, + + MalePlainsfolkNpc, + FemalePlainsfolkNpc, + MaleDunesfolkNpc, + FemaleDunesfolkNpc, + + MaleSeekerOfTheSunNpc, + FemaleSeekerOfTheSunNpc, + MaleKeeperOfTheMoonNpc, + FemaleKeeperOfTheMoonNpc, + + MaleSeawolfNpc, + FemaleSeawolfNpc, + MaleHellsguardNpc, + FemaleHellsguardNpc, + + MaleRaenNpc, + FemaleRaenNpc, + MaleXaelaNpc, + FemaleXaelaNpc, + + MaleHelionNpc, + FemaleHelionNpc, + MaleLostNpc, + FemaleLostNpc, + + MaleRavaNpc, + FemaleRavaNpc, + MaleVeenaNpc, + FemaleVeenaNpc, + + Default = 0xE0, + Interface = 0xE1, + Current = 0xE2, +} + diff --git a/TickTracker/IPC/PenumbraIpc.cs b/TickTracker/IPC/PenumbraIpc.cs index f2bf69b..3bd4355 100644 --- a/TickTracker/IPC/PenumbraIpc.cs +++ b/TickTracker/IPC/PenumbraIpc.cs @@ -13,15 +13,28 @@ public sealed class PenumbraIpc : IDisposable { private readonly IPluginLog log; + private readonly ICallGateSubscriber<(int Breaking, int FeatureLevel)> apiVersions; private readonly ICallGateSubscriber penumbraModsState; private readonly ICallGateSubscriber penumbraInit; private readonly ICallGateSubscriber penumbraDispose; - private readonly ICallGateSubscriber interfaceCollection; - private readonly ICallGateSubscriber<(int Breaking, int FeatureLevel)> apiVersions; - private readonly ICallGateSubscriber> mods; - private readonly ICallGateSubscriber> optionDetails, bool settingsInherited)? settings)> modSettings; - private readonly ICallGateSubscriber modSettingsChanged; private readonly ICallGateSubscriber?> penumbraEnabledChange; + /// + /// Key is directory name, Value is mod name. + /// + private readonly ICallGateSubscriber> modList; + private readonly ICallGateSubscriber> optionDetails, bool ignoreInheritance)? settings)> modSettings; + private readonly ICallGateSubscriber modSettingsChanged; + private readonly (Guid Id, string Name) interfaceCollection; + + [Obsolete("Changed with Penumbra API rework")] + private readonly ICallGateSubscriber oldInterfaceCollection; + [Obsolete("Changed with Penumbra API rework")] + private readonly ICallGateSubscriber> oldModList; + [Obsolete("Changed with Penumbra API rework")] + private readonly ICallGateSubscriber> optionDetails, bool settingsInherited)? settings)> oldModSettings; + [Obsolete("Changed with Penumbra API rework")] + private readonly ICallGateSubscriber oldModSettingsChanged; public bool NativeUiBanned { get; private set; } @@ -55,57 +68,113 @@ private bool penumbraModsEnabled } } +#pragma warning disable CS8618 public PenumbraIpc(DalamudPluginInterface _pluginInterface, IPluginLog _pluginLog) { log = _pluginLog; - apiVersions = _pluginInterface.GetIpcSubscriber<(int, int)>("Penumbra.ApiVersions"); - - if (penumbraApiVersion.Breaking is not 4) + try { - throw new NotSupportedException("Penumbra API out of date. Version " + penumbraApiVersion.Breaking.ToString(CultureInfo.InvariantCulture)); + apiVersions = _pluginInterface.GetIpcSubscriber<(int, int)>("Penumbra.ApiVersions"); } - if (penumbraApiVersion.FeatureLevel is not 0 and not 23) + catch { - log.Debug("Penumbra API Feature Level changed {ver}", penumbraApiVersion.FeatureLevel); + apiVersions = _pluginInterface.GetIpcSubscriber<(int, int)>("Penumbra.ApiVersion"); + } + + if (penumbraApiVersion.Breaking is not 4 and not 5) + { + throw new NotSupportedException("Penumbra API out of date. Version " + penumbraApiVersion.Breaking.ToString(CultureInfo.InvariantCulture)); } penumbraModsState = _pluginInterface.GetIpcSubscriber("Penumbra.GetEnabledState"); - interfaceCollection = _pluginInterface.GetIpcSubscriber("Penumbra.GetInterfaceCollectionName"); - mods = _pluginInterface.GetIpcSubscriber>("Penumbra.GetMods"); - modSettings = _pluginInterface.GetIpcSubscriber> optionDetails, bool settingsInherited)? settings)>("Penumbra.GetCurrentModSettings"); penumbraInit = _pluginInterface.GetIpcSubscriber("Penumbra.Initialized"); penumbraDispose = _pluginInterface.GetIpcSubscriber("Penumbra.Disposed"); penumbraEnabledChange = _pluginInterface.GetIpcSubscriber?>("Penumbra.EnabledChange"); - modSettingsChanged = _pluginInterface.GetIpcSubscriber("Penumbra.ModSettingChanged"); + if (penumbraApiVersion.Breaking is 4) + { + oldInterfaceCollection = _pluginInterface.GetIpcSubscriber("Penumbra.GetInterfaceCollectionName"); + oldModList = _pluginInterface.GetIpcSubscriber>("Penumbra.GetMods"); + oldModSettings = _pluginInterface.GetIpcSubscriber> optionDetails, bool settingsInherited)? settings)>("Penumbra.GetCurrentModSettings"); + oldModSettingsChanged = _pluginInterface.GetIpcSubscriber("Penumbra.ModSettingChanged"); + oldModSettingsChanged.Subscribe(OldCheckModChanges); + } + else if (penumbraApiVersion.Breaking is 5) + { + interfaceCollection = _pluginInterface.GetIpcSubscriber("Penumbra.GetCollection").InvokeFunc(ApiCollectionType.Interface); + modList = _pluginInterface.GetIpcSubscriber>("Penumbra.GetModList"); + modSettings = _pluginInterface.GetIpcSubscriber> optionDetails, bool ignoreInheritance)? settings)> + ("Penumbra.GetCurrentModSettings"); + modSettingsChanged = _pluginInterface.GetIpcSubscriber("Penumbra.ModSettingChanged"); + modSettingsChanged.Subscribe(CheckModChanges); + } penumbraEnabledChange.Subscribe(CheckState); - modSettingsChanged.Subscribe(CheckModChanges); penumbraInit.Subscribe(PenumbraInit); penumbraDispose.Subscribe(PenumbraDispose); if (penumbraModsEnabled) { - NativeUiBanned = CheckMUIPresence(mods.InvokeFunc(), interfaceCollection.InvokeFunc()); + NativeUiBanned = penumbraApiVersion.Breaking is 4 ? OldCheckMUIPresence(oldModList!.InvokeFunc(), oldInterfaceCollection!.InvokeFunc()) + : CheckMUIPresence(modList!.InvokeFunc(), interfaceCollection.Id); } } +#pragma warning restore CS8618 private void CheckState(bool penumbraEnabled) { - NativeUiBanned = penumbraEnabled && CheckMUIPresence(mods.InvokeFunc(), interfaceCollection.InvokeFunc()); + NativeUiBanned = penumbraEnabled + && penumbraApiVersion.Breaking == 4 ? OldCheckMUIPresence(oldModList.InvokeFunc(), oldInterfaceCollection.InvokeFunc()) + : CheckMUIPresence(modList.InvokeFunc(), interfaceCollection.Id); + } + + private void CheckModChanges(ModSettingChange type, Guid collectionId, string modDirectory, bool inherited) + { + if ((type is not ModSettingChange.EnableState && type is not ModSettingChange.Inheritance) || interfaceCollection.Id != collectionId) + { + return; + } + var currentMods = modList.InvokeFunc().Where(currentMod => currentMod.Key.Equals(modDirectory, StringComparison.Ordinal)).ToDictionary(StringComparer.Ordinal); + NativeUiBanned = CheckMUIPresence(currentMods, collectionId); + } + + private bool CheckMUIPresence(Dictionary modList, Guid collection) + { + if (modList.Count < 1) + { + return false; + } + foreach (var mod in modList) + { + if (!mod.Value.Contains("Material UI", StringComparison.OrdinalIgnoreCase) + && !mod.Key.Contains("Material UI", StringComparison.OrdinalIgnoreCase)) + { + continue; + } + var modDetails = modSettings.InvokeFunc(collection, mod.Key, mod.Value, arg4: false); + if (modDetails.status is not PenumbraApiEc.Success || !modDetails.settings.HasValue) + { + log.Error("Failed to retrieve mod details. {status}", modDetails.status); + continue; + } + return modDetails.settings.Value.modEnabled; + } + return false; } - private void CheckModChanges(ModSettingChange type, string collectionName, string modDirectory, bool inherited) + + private void OldCheckModChanges(ModSettingChange type, string collectionName, string modDirectory, bool inherited) { - if ((type is not ModSettingChange.EnableState && type is not ModSettingChange.Inheritance) || !interfaceCollection.InvokeFunc().Equals(collectionName, StringComparison.Ordinal)) + if ((type is not ModSettingChange.EnableState && type is not ModSettingChange.Inheritance) || !oldInterfaceCollection.InvokeFunc().Equals(collectionName, StringComparison.Ordinal)) { return; } - var modList = mods.InvokeFunc().Where(currentMod => currentMod.modDirectory.Equals(modDirectory, StringComparison.Ordinal)); - NativeUiBanned = CheckMUIPresence(modList, collectionName); + var currentMods = oldModList.InvokeFunc().Where(currentMod => currentMod.modDirectory.Equals(modDirectory, StringComparison.Ordinal)); + NativeUiBanned = OldCheckMUIPresence(currentMods, collectionName); } - private bool CheckMUIPresence(IEnumerable<(string modDirectory, string modName)> modList, string collection) + private bool OldCheckMUIPresence(IEnumerable<(string modDirectory, string modName)> modList, string collection) { if (!modList.Any()) { @@ -117,8 +186,7 @@ private bool CheckMUIPresence(IEnumerable<(string modDirectory, string modName)> { continue; } - // Inheritance bool arg4 is flipped - var modDetails = modSettings.InvokeFunc(collection, mod.modDirectory, mod.modName, arg4: false); + var modDetails = oldModSettings.InvokeFunc(collection, mod.modDirectory, mod.modName, arg4: false); if (modDetails.status is not PenumbraApiEc.Success || !modDetails.settings.HasValue) { log.Error("Failed to retrieve mod details. {stat}", modDetails.status); @@ -128,21 +196,37 @@ private bool CheckMUIPresence(IEnumerable<(string modDirectory, string modName)> } return false; } + private void PenumbraInit() { penumbraEnabledChange.Subscribe(CheckState); - modSettingsChanged.Subscribe(CheckModChanges); + if (penumbraApiVersion.Breaking is 4) + { + oldModSettingsChanged.Subscribe(OldCheckModChanges); + } + else if (penumbraApiVersion.Breaking is 5) + { + modSettingsChanged.Subscribe(CheckModChanges); + } if (penumbraModsEnabled) { - NativeUiBanned = CheckMUIPresence(mods.InvokeFunc(), interfaceCollection.InvokeFunc()); + NativeUiBanned = penumbraApiVersion.Breaking is 4 ? OldCheckMUIPresence(oldModList.InvokeFunc(), oldInterfaceCollection.InvokeFunc()) + : CheckMUIPresence(modList.InvokeFunc(), interfaceCollection.Id); } } private void PenumbraDispose() { penumbraEnabledChange.Unsubscribe(CheckState); - modSettingsChanged.Unsubscribe(CheckModChanges); + if (penumbraApiVersion.Breaking is 4) + { + oldModSettingsChanged.Unsubscribe(OldCheckModChanges); + } + else if (penumbraApiVersion.Breaking is 5) + { + modSettingsChanged.Unsubscribe(CheckModChanges); + } NativeUiBanned = false; } diff --git a/TickTracker/TickTracker.csproj b/TickTracker/TickTracker.csproj index a991b1e..75539c5 100644 --- a/TickTracker/TickTracker.csproj +++ b/TickTracker/TickTracker.csproj @@ -39,7 +39,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/TickTracker/packages.lock.json b/TickTracker/packages.lock.json index 1a854ef..18e918d 100644 --- a/TickTracker/packages.lock.json +++ b/TickTracker/packages.lock.json @@ -10,9 +10,9 @@ }, "Meziantou.Analyzer": { "type": "Direct", - "requested": "[2.0.146, )", - "resolved": "2.0.146", - "contentHash": "pJ3k+3UjD2WwPsZR7fkgVYviXP3PCQM0hjwN1TuM4C0u1TuGKC9WdZCo0RAPZ+azhRPmYGSUjkjsN2fkQByghQ==" + "requested": "[2.0.147, )", + "resolved": "2.0.147", + "contentHash": "bloVeZFFQKeJ8QO65XgN1FTHvzKGU523otZjDvQU4Wu7FLWbd/AjWoDFlCaSpBiC+awD/B8Q7CuwINJEVMsk+Q==" } } }