using Dalamud.Plugin; using LightlessSync.Interop.Ipc.Framework; using LightlessSync.PlayerData.Handlers; using LightlessSync.Services; using LightlessSync.Services.ActorTracking; using LightlessSync.Services.Mediator; using Microsoft.Extensions.Logging; using Penumbra.Api.Helpers; using Penumbra.Api.IpcSubscribers; namespace LightlessSync.Interop.Ipc.Penumbra; public sealed class PenumbraResource : PenumbraBase { private readonly ActorObjectService _actorObjectService; private readonly GetGameObjectResourcePaths _gameObjectResourcePaths; private readonly ResolveGameObjectPath _resolveGameObjectPath; private readonly ReverseResolveGameObjectPath _reverseResolveGameObjectPath; private readonly ResolvePlayerPathsAsync _resolvePlayerPaths; private readonly GetPlayerMetaManipulations _getPlayerMetaManipulations; private readonly EventSubscriber _gameObjectResourcePathResolved; public PenumbraResource( ILogger logger, IDalamudPluginInterface pluginInterface, DalamudUtilService dalamudUtil, LightlessMediator mediator, ActorObjectService actorObjectService) : base(logger, pluginInterface, dalamudUtil, mediator) { _actorObjectService = actorObjectService; _gameObjectResourcePaths = new GetGameObjectResourcePaths(pluginInterface); _resolveGameObjectPath = new ResolveGameObjectPath(pluginInterface); _reverseResolveGameObjectPath = new ReverseResolveGameObjectPath(pluginInterface); _resolvePlayerPaths = new ResolvePlayerPathsAsync(pluginInterface); _getPlayerMetaManipulations = new GetPlayerMetaManipulations(pluginInterface); _gameObjectResourcePathResolved = GameObjectResourcePathResolved.Subscriber(pluginInterface, HandleResourceLoaded); } public override string Name => "Penumbra.Resources"; public async Task>?> GetCharacterDataAsync(ILogger logger, GameObjectHandler handler) { if (!IsAvailable) { return null; } return await DalamudUtil.RunOnFrameworkThread(() => { logger.LogTrace("Calling On IPC: Penumbra.GetGameObjectResourcePaths"); var idx = handler.GetGameObject()?.ObjectIndex; if (idx == null) { return null; } return _gameObjectResourcePaths.Invoke(idx.Value)[0]; }).ConfigureAwait(false); } public string GetMetaManipulations() => IsAvailable ? _getPlayerMetaManipulations.Invoke() : string.Empty; public async Task<(string[] forward, string[][] reverse)> ResolvePathsAsync(string[] forwardPaths, string[] reversePaths) { if (!IsAvailable) { return (Array.Empty(), Array.Empty()); } return await _resolvePlayerPaths.Invoke(forwardPaths, reversePaths).ConfigureAwait(false); } public string ResolveGameObjectPath(string gamePath, int gameObjectIndex) => IsAvailable ? _resolveGameObjectPath.Invoke(gamePath, gameObjectIndex) : gamePath; public string[] ReverseResolveGameObjectPath(string moddedPath, int gameObjectIndex) => IsAvailable ? _reverseResolveGameObjectPath.Invoke(moddedPath, gameObjectIndex) : Array.Empty(); private void HandleResourceLoaded(nint ptr, string gamePath, string resolvedPath) { if (ptr == nint.Zero) { return; } if (!_actorObjectService.TryGetOwnedKind(ptr, out _)) { return; } if (string.Compare(gamePath, resolvedPath, StringComparison.OrdinalIgnoreCase) == 0) { return; } Mediator.Publish(new PenumbraResourceLoadMessage(ptr, gamePath, resolvedPath)); } protected override void HandleStateChange(IpcConnectionState previous, IpcConnectionState current) { } public override void Dispose() { base.Dispose(); _gameObjectResourcePathResolved.Dispose(); } }