using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Plugin; using Dalamud.Plugin.Ipc; using LightlessSync.Interop.Ipc.Framework; using LightlessSync.Services; using LightlessSync.Services.Mediator; using Microsoft.Extensions.Logging; using System.Text; namespace LightlessSync.Interop.Ipc; public sealed class IpcCallerHonorific : IpcServiceBase { private static readonly IpcServiceDescriptor HonorificDescriptor = new("Honorific", "Honorific", new Version(0, 0, 0, 0)); private readonly ICallGateSubscriber<(uint major, uint minor)> _honorificApiVersion; private readonly ICallGateSubscriber _honorificClearCharacterTitle; private readonly ICallGateSubscriber _honorificDisposing; private readonly ICallGateSubscriber _honorificGetLocalCharacterTitle; private readonly ICallGateSubscriber _honorificLocalCharacterTitleChanged; private readonly ICallGateSubscriber _honorificReady; private readonly ICallGateSubscriber _honorificSetCharacterTitle; private readonly ILogger _logger; private readonly LightlessMediator _lightlessMediator; private readonly DalamudUtilService _dalamudUtil; public IpcCallerHonorific(ILogger logger, IDalamudPluginInterface pi, DalamudUtilService dalamudUtil, LightlessMediator lightlessMediator) : base(logger, lightlessMediator, pi, HonorificDescriptor) { _logger = logger; _lightlessMediator = lightlessMediator; _dalamudUtil = dalamudUtil; _honorificApiVersion = pi.GetIpcSubscriber<(uint, uint)>("Honorific.ApiVersion"); _honorificGetLocalCharacterTitle = pi.GetIpcSubscriber("Honorific.GetLocalCharacterTitle"); _honorificClearCharacterTitle = pi.GetIpcSubscriber("Honorific.ClearCharacterTitle"); _honorificSetCharacterTitle = pi.GetIpcSubscriber("Honorific.SetCharacterTitle"); _honorificLocalCharacterTitleChanged = pi.GetIpcSubscriber("Honorific.LocalCharacterTitleChanged"); _honorificDisposing = pi.GetIpcSubscriber("Honorific.Disposing"); _honorificReady = pi.GetIpcSubscriber("Honorific.Ready"); _honorificLocalCharacterTitleChanged.Subscribe(OnHonorificLocalCharacterTitleChanged); _honorificDisposing.Subscribe(OnHonorificDisposing); _honorificReady.Subscribe(OnHonorificReady); CheckAPI(); } protected override void Dispose(bool disposing) { base.Dispose(disposing); if (!disposing) { return; } _honorificLocalCharacterTitleChanged.Unsubscribe(OnHonorificLocalCharacterTitleChanged); _honorificDisposing.Unsubscribe(OnHonorificDisposing); _honorificReady.Unsubscribe(OnHonorificReady); } public async Task ClearTitleAsync(nint character) { if (!APIAvailable) return; await _dalamudUtil.RunOnFrameworkThread(() => { var gameObj = _dalamudUtil.CreateGameObject(character); if (gameObj is IPlayerCharacter c) { _logger.LogTrace("Honorific removing for {addr}", c.Address.ToString("X")); _honorificClearCharacterTitle!.InvokeAction(c.ObjectIndex); } }).ConfigureAwait(false); } public async Task GetTitle() { if (!APIAvailable) return string.Empty; string title = await _dalamudUtil.RunOnFrameworkThread(() => _honorificGetLocalCharacterTitle.InvokeFunc()).ConfigureAwait(false); return string.IsNullOrEmpty(title) ? string.Empty : Convert.ToBase64String(Encoding.UTF8.GetBytes(title)); } public async Task SetTitleAsync(IntPtr character, string honorificDataB64) { if (!APIAvailable) return; _logger.LogTrace("Applying Honorific data to {chara}", character.ToString("X")); try { await _dalamudUtil.RunOnFrameworkThread(() => { var gameObj = _dalamudUtil.CreateGameObject(character); if (gameObj is IPlayerCharacter pc) { string honorificData = string.IsNullOrEmpty(honorificDataB64) ? string.Empty : Encoding.UTF8.GetString(Convert.FromBase64String(honorificDataB64)); if (string.IsNullOrEmpty(honorificData)) { _honorificClearCharacterTitle!.InvokeAction(pc.ObjectIndex); } else { _honorificSetCharacterTitle!.InvokeAction(pc.ObjectIndex, honorificData); } } }).ConfigureAwait(false); } catch (Exception e) { _logger.LogWarning(e, "Could not apply Honorific data"); } } protected override IpcConnectionState EvaluateState() { var state = base.EvaluateState(); if (state != IpcConnectionState.Available) { return state; } try { return _honorificApiVersion.InvokeFunc() is { Item1: 3, Item2: >= 1 } ? IpcConnectionState.Available : IpcConnectionState.VersionMismatch; } catch (Exception ex) { _logger.LogDebug(ex, "Failed to query Honorific API version"); return IpcConnectionState.Error; } } private void OnHonorificDisposing() { _lightlessMediator.Publish(new HonorificMessage(string.Empty)); } private void OnHonorificLocalCharacterTitleChanged(string titleJson) { string titleData = string.IsNullOrEmpty(titleJson) ? string.Empty : Convert.ToBase64String(Encoding.UTF8.GetBytes(titleJson)); _lightlessMediator.Publish(new HonorificMessage(titleData)); } private void OnHonorificReady() { CheckAPI(); _lightlessMediator.Publish(new HonorificReadyMessage()); } }