diff --git a/MareSynchronos/Interop/Ipc/IpcCallerPetNames.cs b/MareSynchronos/Interop/Ipc/IpcCallerPetNames.cs index ff5ae70..5954c37 100644 --- a/MareSynchronos/Interop/Ipc/IpcCallerPetNames.cs +++ b/MareSynchronos/Interop/Ipc/IpcCallerPetNames.cs @@ -1,4 +1,6 @@ -using Dalamud.Plugin; +using Dalamud.Game.ClientState.Objects.SubKinds; +using Dalamud.Plugin; +using Dalamud.Plugin.Ipc; using MareSynchronos.Services; using MareSynchronos.Services.Mediator; using Microsoft.Extensions.Logging; @@ -11,6 +13,16 @@ public sealed class IpcCallerPetNames : IIpcCaller private readonly DalamudUtilService _dalamudUtil; private readonly MareMediator _mareMediator; + private readonly ICallGateSubscriber _petnamesReady; + private readonly ICallGateSubscriber _petnamesDisposing; + private readonly ICallGateSubscriber<(uint, uint)> _apiVersion; + private readonly ICallGateSubscriber _enabled; + + private readonly ICallGateSubscriber _playerDataChanged; + private readonly ICallGateSubscriber _getPlayerData; + private readonly ICallGateSubscriber _setPlayerData; + private readonly ICallGateSubscriber _clearPlayerData; + public IpcCallerPetNames(ILogger logger, IDalamudPluginInterface pi, DalamudUtilService dalamudUtil, MareMediator mareMediator) { @@ -18,18 +30,128 @@ public sealed class IpcCallerPetNames : IIpcCaller _dalamudUtil = dalamudUtil; _mareMediator = mareMediator; - // todo: implement this, bitch, look at moodles as example implementation + _petnamesReady = pi.GetIpcSubscriber("PetRenamer.Ready"); + _petnamesDisposing = pi.GetIpcSubscriber("PetRenamer.Disposing"); + _apiVersion = pi.GetIpcSubscriber<(uint, uint)>("PetRenamer.ApiVersion"); + _enabled = pi.GetIpcSubscriber("PetRenamer.Enabled"); + + _playerDataChanged = pi.GetIpcSubscriber("PetRenamer.PlayerDataChanged"); + _getPlayerData = pi.GetIpcSubscriber("PetRenamer.GetPlayerData"); + _setPlayerData = pi.GetIpcSubscriber("PetRenamer.SetPlayerData"); + _clearPlayerData = pi.GetIpcSubscriber("PetRenamer.ClearPlayerData"); + + _petnamesReady.Subscribe(OnPetNicknamesReady); + _petnamesDisposing.Subscribe(OnPetNicknamesDispose); + _playerDataChanged.Subscribe(OnLocalPetNicknamesDataChange); + + CheckAPI(); } - public bool APIAvailable => throw new NotImplementedException(); + public bool APIAvailable { get; private set; } = false; public void CheckAPI() { - throw new NotImplementedException(); + try + { + APIAvailable = _enabled?.InvokeFunc() ?? false; + if (APIAvailable) + { + APIAvailable = _apiVersion?.InvokeFunc() is { Item1: 3, Item2: >= 1 }; + } + } + catch + { + APIAvailable = false; + } + } + + private void OnPetNicknamesReady() + { + CheckAPI(); + } + + private void OnPetNicknamesDispose() + { + _mareMediator.Publish(new PetNamesMessage(string.Empty)); + } + + public string GetLocalNames() + { + if (!APIAvailable) return string.Empty; + + try + { + string localNameData = _getPlayerData.InvokeFunc(); + return string.IsNullOrEmpty(localNameData) ? string.Empty : localNameData; + } + catch (Exception e) + { + _logger.LogWarning(e, "Could not obtain Pet Nicknames data"); + } + + return string.Empty; + } + + public async Task SetPlayerData(nint character, string playerData) + { + if (!APIAvailable) return; + + _logger.LogTrace("Applying Pet Nicknames data to {chara}", character.ToString("X")); + + try + { + await _dalamudUtil.RunOnFrameworkThread(() => + { + if (string.IsNullOrEmpty(playerData)) + { + var gameObj = _dalamudUtil.CreateGameObject(character); + if (gameObj is IPlayerCharacter pc) + { + _clearPlayerData.InvokeAction(pc.ObjectIndex); + } + } + else + { + _setPlayerData.InvokeAction(playerData); + } + }).ConfigureAwait(false); + } + catch (Exception e) + { + _logger.LogWarning(e, "Could not apply Pet Nicknames data"); + } + } + + public async Task ClearPlayerData(nint characterPointer) + { + if (!APIAvailable) return; + try + { + await _dalamudUtil.RunOnFrameworkThread(() => + { + var gameObj = _dalamudUtil.CreateGameObject(characterPointer); + if (gameObj is IPlayerCharacter pc) + { + _logger.LogTrace("Pet Nicknames removing for {addr}", pc.Address.ToString("X")); + _clearPlayerData.InvokeAction(pc.ObjectIndex); + } + }).ConfigureAwait(false); + } + catch (Exception e) + { + _logger.LogWarning(e, "Could not clear Pet Nicknames data"); + } + } + + private void OnLocalPetNicknamesDataChange(string data) + { + _mareMediator.Publish(new PetNamesMessage(data)); } public void Dispose() { - throw new NotImplementedException(); + _petnamesReady.Unsubscribe(OnPetNicknamesReady); + _petnamesDisposing.Unsubscribe(OnPetNicknamesDispose); + _playerDataChanged.Unsubscribe(OnLocalPetNicknamesDataChange); } } diff --git a/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs b/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs index ee2fc7b..53aa7ec 100644 --- a/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs +++ b/MareSynchronos/PlayerData/Factories/PlayerDataFactory.cs @@ -216,9 +216,11 @@ public class PlayerDataFactory _logger.LogDebug("Heels is now: {heels}", previousData.HeelsData); if (objectKind == ObjectKind.Player) { - // TODO: use petnames here and save it to moodles data for temporary transfer previousData.MoodlesData = await _ipcManager.Moodles.GetStatusAsync(playerRelatedObject.Address).ConfigureAwait(false) ?? string.Empty; _logger.LogDebug("Moodles is now: {moodles}", previousData.MoodlesData); + + previousData.MoodlesData = _ipcManager.PetNames.GetLocalNames(); + _logger.LogDebug("Pet Nicknames is now: {moodles}", previousData.MoodlesData); } if (previousData.FileReplacements.TryGetValue(objectKind, out HashSet? fileReplacements)) diff --git a/MareSynchronos/PlayerData/Handlers/PairHandler.cs b/MareSynchronos/PlayerData/Handlers/PairHandler.cs index a746bd8..b67e986 100644 --- a/MareSynchronos/PlayerData/Handlers/PairHandler.cs +++ b/MareSynchronos/PlayerData/Handlers/PairHandler.cs @@ -342,8 +342,9 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase break; case PlayerChanges.Moodles: - // TODO: send it to petnames ipc here instead await _ipcManager.Moodles.SetStatusAsync(handler.Address, charaData.MoodlesData).ConfigureAwait(false); + + await _ipcManager.PetNames.SetPlayerData(handler.Address, charaData.MoodlesData).ConfigureAwait(false); break; case PlayerChanges.ForcedRedraw: @@ -582,6 +583,8 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase await _ipcManager.Honorific.ClearTitleAsync(address).ConfigureAwait(false); Logger.LogDebug("[{applicationId}] Restoring Moodles for {alias}/{name}", applicationId, OnlineUser.User.AliasOrUID, name); await _ipcManager.Moodles.RevertStatusAsync(address).ConfigureAwait(false); + Logger.LogDebug("[{applicationId}] Restoring Pet Nicknames for {alias}/{name}", applicationId, OnlineUser.User.AliasOrUID, name); + await _ipcManager.PetNames.ClearPlayerData(address).ConfigureAwait(false); } else if (objectKind == ObjectKind.MinionOrMount) { diff --git a/MareSynchronos/PlayerData/Pairs/OptionalPluginWarning.cs b/MareSynchronos/PlayerData/Pairs/OptionalPluginWarning.cs index f27e536..29954c7 100644 --- a/MareSynchronos/PlayerData/Pairs/OptionalPluginWarning.cs +++ b/MareSynchronos/PlayerData/Pairs/OptionalPluginWarning.cs @@ -6,4 +6,5 @@ public record OptionalPluginWarning public bool ShownCustomizePlusWarning { get; set; } = false; public bool ShownHonorificWarning { get; set; } = false; public bool ShownMoodlesWarning { get; set; } = false; + public bool ShowPetNicknamesWarning { get; set; } = false; } \ No newline at end of file diff --git a/MareSynchronos/PlayerData/Services/CacheCreationService.cs b/MareSynchronos/PlayerData/Services/CacheCreationService.cs index 02fd9dd..16a5b72 100644 --- a/MareSynchronos/PlayerData/Services/CacheCreationService.cs +++ b/MareSynchronos/PlayerData/Services/CacheCreationService.cs @@ -21,6 +21,7 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase private Task? _cacheCreationTask; private CancellationTokenSource _honorificCts = new(); private CancellationTokenSource _moodlesCts = new(); + private CancellationTokenSource _petNicknamesCts = new(); private bool _isZoning = false; private readonly Dictionary _glamourerCts = new(); @@ -122,9 +123,15 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase MoodlesChanged(); } }); - - // TODO: if event is needed for petnames add it here similar to moodles - + Mediator.Subscribe(this, (msg) => + { + if (_isZoning) return; + if (!string.Equals(msg.PetNicknamesData, _playerData.MoodlesData, StringComparison.Ordinal)) + { + Logger.LogDebug("Received Pet Nicknames change, updating player"); + PetNicknamesChanged(); + } + }); Mediator.Subscribe(this, (msg) => { Logger.LogDebug("Received Penumbra Mod settings change, updating player"); @@ -194,6 +201,20 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase }, token); } + private void PetNicknamesChanged() + { + _petNicknamesCts?.Cancel(); + _petNicknamesCts?.Dispose(); + _petNicknamesCts = new(); + var token = _petNicknamesCts.Token; + + _ = Task.Run(async () => + { + await Task.Delay(TimeSpan.FromSeconds(3), token).ConfigureAwait(false); + await AddPlayerCacheToCreate().ConfigureAwait(false); + }, token); + } + private void ProcessCacheCreation() { if (_isZoning) return; diff --git a/MareSynchronos/Services/Mediator/Messages.cs b/MareSynchronos/Services/Mediator/Messages.cs index c350a48..15cc054 100644 --- a/MareSynchronos/Services/Mediator/Messages.cs +++ b/MareSynchronos/Services/Mediator/Messages.cs @@ -41,6 +41,7 @@ public record PenumbraResourceLoadMessage(IntPtr GameObject, string GamePath, st public record CustomizePlusMessage(string ProfileName) : MessageBase; public record HonorificMessage(string NewHonorificTitle) : MessageBase; public record MoodlesMessage(IntPtr Address) : MessageBase; +public record PetNamesMessage(string PetNicknamesData) : MessageBase; public record HonorificReadyMessage : MessageBase; public record PlayerChangedMessage(CharacterData Data) : MessageBase; public record CharacterChangedMessage(GameObjectHandler GameObjectHandler) : MessageBase; diff --git a/MareSynchronos/Services/PluginWarningNotificationService.cs b/MareSynchronos/Services/PluginWarningNotificationService.cs index 98bcc11..f883e8e 100644 --- a/MareSynchronos/Services/PluginWarningNotificationService.cs +++ b/MareSynchronos/Services/PluginWarningNotificationService.cs @@ -31,7 +31,8 @@ public class PluginWarningNotificationService ShownCustomizePlusWarning = _mareConfigService.Current.DisableOptionalPluginWarnings, ShownHeelsWarning = _mareConfigService.Current.DisableOptionalPluginWarnings, ShownHonorificWarning = _mareConfigService.Current.DisableOptionalPluginWarnings, - ShownMoodlesWarning = _mareConfigService.Current.DisableOptionalPluginWarnings + ShownMoodlesWarning = _mareConfigService.Current.DisableOptionalPluginWarnings, + ShowPetNicknamesWarning = _mareConfigService.Current.DisableOptionalPluginWarnings }; } @@ -53,13 +54,18 @@ public class PluginWarningNotificationService warning.ShownHonorificWarning = true; } - // todo: change the moodles apiavailable to petnames for testing if (changes.Contains(PlayerChanges.Moodles) && !warning.ShownMoodlesWarning && !_ipcManager.Moodles.APIAvailable) { missingPluginsForData.Add("Moodles"); warning.ShownMoodlesWarning = true; } + if (changes.Contains(PlayerChanges.Moodles) && !warning.ShowPetNicknamesWarning && !_ipcManager.PetNames.APIAvailable) + { + missingPluginsForData.Add("PetNicknames"); + warning.ShowPetNicknamesWarning = true; + } + if (missingPluginsForData.Any()) { _mediator.Publish(new NotificationMessage("Missing plugins for " + playerName,