fix ipc probably add individual syncshells and shit don't show shared data from paused people change text fix reverting Use InputText/Combo hybrids for MCDO ACLs (#81) * Use InputText/Combo hybrids for MCDO ACLs * Hybrid combo factoring, filtering, ordering, caching fix selecting latest created data on creation rename close to direct pairs add toggle to keep nearby poses active constantly fix gpose hanging fix potential cancelaltion on updateshareddata
159 lines
6.1 KiB
C#
159 lines
6.1 KiB
C#
using Dalamud.Game.ClientState.Objects.Types;
|
|
using Dalamud.Plugin;
|
|
using Dalamud.Plugin.Ipc;
|
|
using MareSynchronos.MareConfiguration;
|
|
using MareSynchronos.PlayerData.Handlers;
|
|
using MareSynchronos.Services;
|
|
using MareSynchronos.Services.Mediator;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace MareSynchronos.Interop.Ipc;
|
|
|
|
public class IpcProvider : IHostedService, IMediatorSubscriber
|
|
{
|
|
private readonly ILogger<IpcProvider> _logger;
|
|
private readonly IDalamudPluginInterface _pi;
|
|
private readonly MareConfigService _mareConfig;
|
|
private readonly CharaDataManager _charaDataManager;
|
|
private ICallGateProvider<string, IGameObject, bool>? _loadFileProvider;
|
|
private ICallGateProvider<string, IGameObject, Task<bool>>? _loadFileAsyncProvider;
|
|
private ICallGateProvider<List<nint>>? _handledGameAddresses;
|
|
private readonly List<GameObjectHandler> _activeGameObjectHandlers = [];
|
|
|
|
private ICallGateProvider<string, IGameObject, bool>? _loadFileProviderMare;
|
|
private ICallGateProvider<string, IGameObject, Task<bool>>? _loadFileAsyncProviderMare;
|
|
private ICallGateProvider<List<nint>>? _handledGameAddressesMare;
|
|
|
|
private bool _marePluginEnabled = false;
|
|
private bool _impersonating = false;
|
|
|
|
public bool MarePluginEnabled => _marePluginEnabled;
|
|
public bool ImpersonationActive => _impersonating;
|
|
|
|
public MareMediator Mediator { get; init; }
|
|
|
|
public IpcProvider(ILogger<IpcProvider> logger, IDalamudPluginInterface pi, MareConfigService mareConfig,
|
|
CharaDataManager charaDataManager, MareMediator mareMediator)
|
|
{
|
|
_logger = logger;
|
|
_pi = pi;
|
|
_mareConfig = mareConfig;
|
|
_charaDataManager = charaDataManager;
|
|
Mediator = mareMediator;
|
|
|
|
Mediator.Subscribe<GameObjectHandlerCreatedMessage>(this, (msg) =>
|
|
{
|
|
if (msg.OwnedObject) return;
|
|
_activeGameObjectHandlers.Add(msg.GameObjectHandler);
|
|
});
|
|
Mediator.Subscribe<GameObjectHandlerDestroyedMessage>(this, (msg) =>
|
|
{
|
|
if (msg.OwnedObject) return;
|
|
_activeGameObjectHandlers.Remove(msg.GameObjectHandler);
|
|
});
|
|
|
|
_marePluginEnabled = pi.InstalledPlugins.Any(p => p.InternalName == "MareSynchronos" && p.IsLoaded);
|
|
Mediator.SubscribeKeyed<PluginChangeMessage>(this, "MareSynchronos", p => {
|
|
_marePluginEnabled = p.IsLoaded;
|
|
HandleMareImpersonation();
|
|
});
|
|
}
|
|
|
|
public Task StartAsync(CancellationToken cancellationToken)
|
|
{
|
|
_logger.LogDebug("Starting IpcProvider Service");
|
|
_loadFileProvider = _pi.GetIpcProvider<string, IGameObject, bool>("LoporritSync.LoadMcdf");
|
|
_loadFileProvider.RegisterFunc(LoadMcdf);
|
|
_loadFileAsyncProvider = _pi.GetIpcProvider<string, IGameObject, Task<bool>>("LoporritSync.LoadMcdfAsync");
|
|
_loadFileAsyncProvider.RegisterFunc(LoadMcdfAsync);
|
|
_handledGameAddresses = _pi.GetIpcProvider<List<nint>>("LoporritSync.GetHandledAddresses");
|
|
_handledGameAddresses.RegisterFunc(GetHandledAddresses);
|
|
|
|
_loadFileProviderMare = _pi.GetIpcProvider<string, IGameObject, bool>("MareSynchronos.LoadMcdf");
|
|
_loadFileAsyncProviderMare = _pi.GetIpcProvider<string, IGameObject, Task<bool>>("MareSynchronos.LoadMcdfAsync");
|
|
_handledGameAddressesMare = _pi.GetIpcProvider<List<nint>>("MareSynchronos.GetHandledAddresses");
|
|
HandleMareImpersonation();
|
|
|
|
_logger.LogInformation("Started IpcProviderService");
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public void HandleMareImpersonation()
|
|
{
|
|
if (_marePluginEnabled)
|
|
{
|
|
if (_impersonating)
|
|
{
|
|
// Do not attempt to unregister the functions at this point, otherwise we risk unregistering Mare's
|
|
// This may leave the APIs hanging if Mare did not initialize to the point of registering its API though
|
|
_impersonating = false;
|
|
_logger.LogDebug("Releasing MareSynchronos API");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_mareConfig.Current.MareAPI)
|
|
{
|
|
_loadFileProviderMare?.RegisterFunc(LoadMcdf);
|
|
_loadFileAsyncProviderMare?.RegisterFunc(LoadMcdfAsync);
|
|
_handledGameAddressesMare?.RegisterFunc(GetHandledAddresses);
|
|
_impersonating = true;
|
|
_logger.LogDebug("Registered MareSynchronos API");
|
|
}
|
|
else
|
|
{
|
|
_loadFileProviderMare?.UnregisterFunc();
|
|
_loadFileAsyncProviderMare?.UnregisterFunc();
|
|
_handledGameAddressesMare?.UnregisterFunc();
|
|
_impersonating = false;
|
|
_logger.LogDebug("Unregistered MareSynchronos API");
|
|
}
|
|
}
|
|
}
|
|
|
|
public Task StopAsync(CancellationToken cancellationToken)
|
|
{
|
|
_logger.LogDebug("Stopping IpcProvider Service");
|
|
_loadFileProvider?.UnregisterFunc();
|
|
_loadFileAsyncProvider?.UnregisterFunc();
|
|
_handledGameAddresses?.UnregisterFunc();
|
|
|
|
if (_impersonating)
|
|
{
|
|
_loadFileProviderMare?.UnregisterFunc();
|
|
_loadFileAsyncProviderMare?.UnregisterFunc();
|
|
_handledGameAddressesMare?.UnregisterFunc();
|
|
}
|
|
|
|
Mediator.UnsubscribeAll(this);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private async Task<bool> LoadMcdfAsync(string path, IGameObject target)
|
|
{
|
|
await ApplyFileAsync(path, target).ConfigureAwait(false);
|
|
|
|
return true;
|
|
}
|
|
|
|
private bool LoadMcdf(string path, IGameObject target)
|
|
{
|
|
_ = Task.Run(async () => await ApplyFileAsync(path, target).ConfigureAwait(false)).ConfigureAwait(false);
|
|
|
|
return true;
|
|
}
|
|
|
|
private async Task ApplyFileAsync(string path, IGameObject target)
|
|
{
|
|
_charaDataManager.LoadMcdf(path);
|
|
await (_charaDataManager.LoadedMcdfHeader ?? Task.CompletedTask).ConfigureAwait(false);
|
|
_charaDataManager.McdfApplyToTarget(target.Name.TextValue);
|
|
}
|
|
|
|
private List<nint> GetHandledAddresses()
|
|
{
|
|
return _activeGameObjectHandlers.Where(g => g.Address != nint.Zero).Select(g => g.Address).Distinct().ToList();
|
|
}
|
|
}
|