using System; using System.Linq; using Dalamud.Plugin; using Dalamud.Plugin.Services; using Microsoft.Extensions.Logging; namespace Questionable.External; internal sealed class WigglyNavAvailability : IDisposable { private const int SupportedMajorVersion = 1; private const string WigglyNavInternalName = "WigglyNav"; private const long ReprobeIntervalMs = 5000L; private readonly IDalamudPluginInterface _pluginInterface; private readonly WigglyNavIpc _wigglyNavIpc; private readonly IFramework _framework; private readonly ILogger _logger; private readonly object _verdictLock = new object(); private volatile bool _isCompatible; private long _lastProbeTicks; public bool IsCompatible => _isCompatible; public event Action? CompatibilityChanged; public WigglyNavAvailability(IDalamudPluginInterface pluginInterface, WigglyNavIpc wigglyNavIpc, IFramework framework, ILogger logger) { _pluginInterface = pluginInterface; _wigglyNavIpc = wigglyNavIpc; _framework = framework; _logger = logger; TryRefreshVerdict(respectThrottle: false); _logger.LogInformation("WigglyNav native surface is {State} at startup", DescribeVerdict(_isCompatible)); _pluginInterface.ActivePluginsChanged += OnActivePluginsChanged; _framework.Update += OnFrameworkUpdate; } public void Dispose() { _framework.Update -= OnFrameworkUpdate; _pluginInterface.ActivePluginsChanged -= OnActivePluginsChanged; } private void OnActivePluginsChanged(IActivePluginsChangedEventArgs args) { if (args.AffectedInternalNames.Contains("WigglyNav") && TryRefreshVerdict(respectThrottle: false)) { _logger.LogInformation("WigglyNav native surface is now {State} (plugin list change: {Kind})", DescribeVerdict(_isCompatible), args.Kind); this.CompatibilityChanged?.Invoke(); } } private void OnFrameworkUpdate(IFramework framework) { if (!_isCompatible && TryRefreshVerdict(respectThrottle: true)) { _logger.LogInformation("WigglyNav native surface is now {State} (periodic re-probe)", DescribeVerdict(_isCompatible)); this.CompatibilityChanged?.Invoke(); } } private bool TryRefreshVerdict(bool respectThrottle) { lock (_verdictLock) { long tickCount = Environment.TickCount64; if (respectThrottle && tickCount - _lastProbeTicks < 5000) { return false; } _lastProbeTicks = tickCount; (int, int)? tuple = _wigglyNavIpc.TryGetApiVersion(); bool flag = tuple.HasValue && tuple.GetValueOrDefault().Item1 == 1; if (flag == _isCompatible) { return false; } _isCompatible = flag; return true; } } private static string DescribeVerdict(bool isCompatible) { if (!isCompatible) { return "unavailable or incompatible"; } return "compatible"; } }