diff --git a/MareSynchronos/PlayerData/Handlers/PairHandler.cs b/MareSynchronos/PlayerData/Handlers/PairHandler.cs index 5213db8..fa52bf3 100644 --- a/MareSynchronos/PlayerData/Handlers/PairHandler.cs +++ b/MareSynchronos/PlayerData/Handlers/PairHandler.cs @@ -29,7 +29,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase private readonly FileCacheManager _fileDbManager; private readonly GameObjectHandlerFactory _gameObjectHandlerFactory; private readonly IpcManager _ipcManager; - private readonly IHostApplicationLifetime _lifetime; private readonly PlayerPerformanceService _playerPerformanceService; private readonly ServerConfigurationManager _serverConfigManager; private readonly PluginWarningNotificationService _pluginWarningNotificationManager; @@ -65,7 +64,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase _downloadManager = transferManager; _pluginWarningNotificationManager = pluginWarningNotificationManager; _dalamudUtil = dalamudUtil; - _lifetime = lifetime; _fileDbManager = fileDbManager; _playerPerformanceService = playerPerformanceService; _serverConfigManager = serverConfigManager; @@ -290,8 +288,7 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase Mediator.Publish(new EventMessage(new Event(name, Pair.UserData, nameof(PairHandler), EventSeverity.Informational, "Disposing User"))); } - if (!_lifetime.ApplicationStopping.IsCancellationRequested) - UndoApplicationAsync(applicationId).GetAwaiter().GetResult(); + UndoApplicationAsync(applicationId).GetAwaiter().GetResult(); _applicationCancellationTokenSource?.Dispose(); _applicationCancellationTokenSource = null; diff --git a/MareSynchronos/PlayerData/Pairs/Pair.cs b/MareSynchronos/PlayerData/Pairs/Pair.cs index b77267a..d2f108c 100644 --- a/MareSynchronos/PlayerData/Pairs/Pair.cs +++ b/MareSynchronos/PlayerData/Pairs/Pair.cs @@ -171,6 +171,11 @@ public class Pair : DisposableMediatorSubscriberBase if (_serverConfigurationManager.IsUidBlacklisted(UserData.UID)) HoldApplication("Blacklist", maxValue: 1); + if (NoSnapService.AnyLoaded) + HoldApplication("NoSnap", maxValue: 1); + else + UnholdApplication("NoSnap", skipApplication: true); + CachedPlayer.ApplyCharacterData(Guid.NewGuid(), RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone())!, forced); } diff --git a/MareSynchronos/Plugin.cs b/MareSynchronos/Plugin.cs index 3560652..221d511 100644 --- a/MareSynchronos/Plugin.cs +++ b/MareSynchronos/Plugin.cs @@ -141,6 +141,7 @@ public sealed class Plugin : IDalamudPlugin collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); + collection.AddSingleton(); collection.AddSingleton((s) => new MareConfigService(pluginInterface.ConfigDirectory.FullName)); collection.AddSingleton((s) => new ServerConfigService(pluginInterface.ConfigDirectory.FullName)); @@ -204,6 +205,7 @@ public sealed class Plugin : IDalamudPlugin collection.AddHostedService(p => p.GetRequiredService()); collection.AddHostedService(p => p.GetRequiredService()); collection.AddHostedService(p => p.GetRequiredService()); + collection.AddHostedService(p => p.GetRequiredService()); }) .Build(); diff --git a/MareSynchronos/Services/NoSnapService.cs b/MareSynchronos/Services/NoSnapService.cs new file mode 100644 index 0000000..ebd84b3 --- /dev/null +++ b/MareSynchronos/Services/NoSnapService.cs @@ -0,0 +1,72 @@ +using Dalamud.Plugin; +using MareSynchronos.MareConfiguration.Models; +using MareSynchronos.Services.Mediator; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +namespace MareSynchronos.Services; + +public class NoSnapService : IHostedService, IMediatorSubscriber +{ + private readonly ILogger _logger; + private readonly Dictionary _listOfPlugins = new(StringComparer.Ordinal) + { + ["Snapper"] = false, + ["Snappy"] = false, + ["Meddle.Plugin"] = false + }; + + public static bool AnyLoaded { get; private set; } = false; + + public MareMediator Mediator { get; init; } + + public NoSnapService(ILogger logger, IDalamudPluginInterface pi, MareMediator mediator) + { + _logger = logger; + Mediator = mediator; + + foreach (var pluginName in _listOfPlugins.Keys) + { + var plugin = pi.InstalledPlugins.FirstOrDefault(p => p.InternalName.Equals(pluginName, StringComparison.Ordinal)); + if (plugin?.IsLoaded ?? false) + _listOfPlugins[pluginName] = true; + Mediator.SubscribeKeyed(this, pluginName, (msg) => + { + _logger.LogInformation("{pluginName} isLoaded = {isLoaded}", pluginName, msg.IsLoaded); + _listOfPlugins[pluginName] = msg.IsLoaded; + Update(); + }); + } + + Update(); + } + + public Task StartAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + private void Update() + { + bool anyLoadedNow = _listOfPlugins.Values.Any(p => p); + + if (AnyLoaded != anyLoadedNow) + { + _logger.LogInformation("AnyLoaded is now {AnyLoaded}", AnyLoaded); + AnyLoaded = anyLoadedNow; + Mediator.Publish(new RecalculatePerformanceMessage(null)); + + if (AnyLoaded) + { + var pluginList = string.Join(", ", _listOfPlugins.Where(p => p.Value).Select(p => p.Key)); + Mediator.Publish(new NotificationMessage("Incompatible plugin loaded", $"Synced player appearances will not apply until incompatible plugins are disabled: {pluginList}.", + NotificationType.Error)); + } + } + } +} \ No newline at end of file diff --git a/MareSynchronos/Services/PluginWatcherService.cs b/MareSynchronos/Services/PluginWatcherService.cs index 1707b38..98af785 100644 --- a/MareSynchronos/Services/PluginWatcherService.cs +++ b/MareSynchronos/Services/PluginWatcherService.cs @@ -37,7 +37,6 @@ SOFTWARE. public class PluginWatcherService : MediatorSubscriberBase { - private readonly ConcurrentDictionary _cachedOptionalPluginWarnings = new(UserDataComparer.Instance); private readonly IDalamudPluginInterface _pluginInterface; private CapturedPluginState[] _prevInstalledPluginState = [];