Add NoSnapService, undo application on plugin unload

This commit is contained in:
Loporrit
2025-07-24 16:32:45 +00:00
parent c455eb0009
commit 10366695f2
5 changed files with 80 additions and 5 deletions

View File

@@ -29,7 +29,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
private readonly FileCacheManager _fileDbManager; private readonly FileCacheManager _fileDbManager;
private readonly GameObjectHandlerFactory _gameObjectHandlerFactory; private readonly GameObjectHandlerFactory _gameObjectHandlerFactory;
private readonly IpcManager _ipcManager; private readonly IpcManager _ipcManager;
private readonly IHostApplicationLifetime _lifetime;
private readonly PlayerPerformanceService _playerPerformanceService; private readonly PlayerPerformanceService _playerPerformanceService;
private readonly ServerConfigurationManager _serverConfigManager; private readonly ServerConfigurationManager _serverConfigManager;
private readonly PluginWarningNotificationService _pluginWarningNotificationManager; private readonly PluginWarningNotificationService _pluginWarningNotificationManager;
@@ -65,7 +64,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
_downloadManager = transferManager; _downloadManager = transferManager;
_pluginWarningNotificationManager = pluginWarningNotificationManager; _pluginWarningNotificationManager = pluginWarningNotificationManager;
_dalamudUtil = dalamudUtil; _dalamudUtil = dalamudUtil;
_lifetime = lifetime;
_fileDbManager = fileDbManager; _fileDbManager = fileDbManager;
_playerPerformanceService = playerPerformanceService; _playerPerformanceService = playerPerformanceService;
_serverConfigManager = serverConfigManager; _serverConfigManager = serverConfigManager;
@@ -290,7 +288,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase
Mediator.Publish(new EventMessage(new Event(name, Pair.UserData, nameof(PairHandler), EventSeverity.Informational, "Disposing User"))); 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?.Dispose();

View File

@@ -171,6 +171,11 @@ public class Pair : DisposableMediatorSubscriberBase
if (_serverConfigurationManager.IsUidBlacklisted(UserData.UID)) if (_serverConfigurationManager.IsUidBlacklisted(UserData.UID))
HoldApplication("Blacklist", maxValue: 1); HoldApplication("Blacklist", maxValue: 1);
if (NoSnapService.AnyLoaded)
HoldApplication("NoSnap", maxValue: 1);
else
UnholdApplication("NoSnap", skipApplication: true);
CachedPlayer.ApplyCharacterData(Guid.NewGuid(), RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone())!, forced); CachedPlayer.ApplyCharacterData(Guid.NewGuid(), RemoveNotSyncedFiles(LastReceivedCharacterData.DeepClone())!, forced);
} }

View File

@@ -141,6 +141,7 @@ public sealed class Plugin : IDalamudPlugin
collection.AddSingleton<IpcCallerBrio>(); collection.AddSingleton<IpcCallerBrio>();
collection.AddSingleton<IpcManager>(); collection.AddSingleton<IpcManager>();
collection.AddSingleton<NotificationService>(); collection.AddSingleton<NotificationService>();
collection.AddSingleton<NoSnapService>();
collection.AddSingleton((s) => new MareConfigService(pluginInterface.ConfigDirectory.FullName)); collection.AddSingleton((s) => new MareConfigService(pluginInterface.ConfigDirectory.FullName));
collection.AddSingleton((s) => new ServerConfigService(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<MarePlugin>()); collection.AddHostedService(p => p.GetRequiredService<MarePlugin>());
collection.AddHostedService(p => p.GetRequiredService<IpcProvider>()); collection.AddHostedService(p => p.GetRequiredService<IpcProvider>());
collection.AddHostedService(p => p.GetRequiredService<RepoChangeService>()); collection.AddHostedService(p => p.GetRequiredService<RepoChangeService>());
collection.AddHostedService(p => p.GetRequiredService<NoSnapService>());
}) })
.Build(); .Build();

View File

@@ -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<NoSnapService> _logger;
private readonly Dictionary<string, bool> _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<NoSnapService> 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<PluginChangeMessage>(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));
}
}
}
}

View File

@@ -37,7 +37,6 @@ SOFTWARE.
public class PluginWatcherService : MediatorSubscriberBase public class PluginWatcherService : MediatorSubscriberBase
{ {
private readonly ConcurrentDictionary<UserData, OptionalPluginWarning> _cachedOptionalPluginWarnings = new(UserDataComparer.Instance);
private readonly IDalamudPluginInterface _pluginInterface; private readonly IDalamudPluginInterface _pluginInterface;
private CapturedPluginState[] _prevInstalledPluginState = []; private CapturedPluginState[] _prevInstalledPluginState = [];