diff --git a/MareSynchronos/MarePlugin.cs b/MareSynchronos/MarePlugin.cs index a4f2c3d..3ff9a2b 100644 --- a/MareSynchronos/MarePlugin.cs +++ b/MareSynchronos/MarePlugin.cs @@ -148,7 +148,7 @@ public class MarePlugin : MediatorSubscriberBase, IHostedService } _runtimeServiceScope.ServiceProvider.GetRequiredService(); _runtimeServiceScope.ServiceProvider.GetRequiredService(); - _runtimeServiceScope.ServiceProvider.GetRequiredService(); + _runtimeServiceScope.ServiceProvider.GetRequiredService(); _runtimeServiceScope.ServiceProvider.GetRequiredService(); #if !DEBUG diff --git a/MareSynchronos/PlayerData/Handlers/GameObjectHandler.cs b/MareSynchronos/PlayerData/Handlers/GameObjectHandler.cs index 963b2ca..15d0c1e 100644 --- a/MareSynchronos/PlayerData/Handlers/GameObjectHandler.cs +++ b/MareSynchronos/PlayerData/Handlers/GameObjectHandler.cs @@ -230,7 +230,6 @@ public sealed class GameObjectHandler : DisposableMediatorSubscriberBase, IHighP if (equipDiff && !_isOwnedObject) // send the message out immediately and cancel out, no reason to continue if not self { Logger.LogTrace("[{this}] Changed", this); - Mediator.Publish(new CharacterChangedMessage(this)); return; } diff --git a/MareSynchronos/PlayerData/Handlers/PairHandler.cs b/MareSynchronos/PlayerData/Handlers/PairHandler.cs index 23214a4..876f4db 100644 --- a/MareSynchronos/PlayerData/Handlers/PairHandler.cs +++ b/MareSynchronos/PlayerData/Handlers/PairHandler.cs @@ -295,9 +295,9 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase var handler = changes.Key switch { ObjectKind.Player => _charaHandler!, - ObjectKind.Companion => await _gameObjectHandlerFactory.Create(changes.Key, () => _dalamudUtil.GetCompanion(ptr), isWatched: false).ConfigureAwait(false), - ObjectKind.MinionOrMount => await _gameObjectHandlerFactory.Create(changes.Key, () => _dalamudUtil.GetMinionOrMount(ptr), isWatched: false).ConfigureAwait(false), - ObjectKind.Pet => await _gameObjectHandlerFactory.Create(changes.Key, () => _dalamudUtil.GetPet(ptr), isWatched: false).ConfigureAwait(false), + ObjectKind.Companion => await _gameObjectHandlerFactory.Create(changes.Key, () => _dalamudUtil.GetCompanionPtr(ptr), isWatched: false).ConfigureAwait(false), + ObjectKind.MinionOrMount => await _gameObjectHandlerFactory.Create(changes.Key, () => _dalamudUtil.GetMinionOrMountPtr(ptr), isWatched: false).ConfigureAwait(false), + ObjectKind.Pet => await _gameObjectHandlerFactory.Create(changes.Key, () => _dalamudUtil.GetPetPtr(ptr), isWatched: false).ConfigureAwait(false), _ => throw new NotSupportedException("ObjectKind not supported: " + changes.Key) }; @@ -540,7 +540,6 @@ public sealed class PairHandler : DisposableMediatorSubscriberBase { Guid appData = Guid.NewGuid(); IsVisible = true; - Mediator.Publish(new PairHandlerVisibleMessage(this)); if (_cachedData != null) { Logger.LogTrace("[BASE-{appBase}] {this} visibility changed, now: {visi}, cached data exists", appData, this, IsVisible); diff --git a/MareSynchronos/PlayerData/Pairs/OnlinePlayerManager.cs b/MareSynchronos/PlayerData/Pairs/OnlinePlayerManager.cs deleted file mode 100644 index 7655b72..0000000 --- a/MareSynchronos/PlayerData/Pairs/OnlinePlayerManager.cs +++ /dev/null @@ -1,75 +0,0 @@ -using MareSynchronos.API.Data; -using MareSynchronos.PlayerData.Handlers; -using MareSynchronos.Services; -using MareSynchronos.Services.Mediator; -using MareSynchronos.Utils; -using MareSynchronos.WebAPI; -using MareSynchronos.WebAPI.Files; -using Microsoft.Extensions.Logging; - -namespace MareSynchronos.PlayerData.Pairs; - -public class OnlinePlayerManager : DisposableMediatorSubscriberBase -{ - private readonly ApiController _apiController; - private readonly DalamudUtilService _dalamudUtil; - private readonly FileUploadManager _fileTransferManager; - private readonly HashSet _newVisiblePlayers = []; - private readonly PairManager _pairManager; - private CharacterData? _lastSentData; - - public OnlinePlayerManager(ILogger logger, ApiController apiController, DalamudUtilService dalamudUtil, - PairManager pairManager, MareMediator mediator, FileUploadManager fileTransferManager) : base(logger, mediator) - { - _apiController = apiController; - _dalamudUtil = dalamudUtil; - _pairManager = pairManager; - _fileTransferManager = fileTransferManager; - Mediator.Subscribe(this, (_) => PlayerManagerOnPlayerHasChanged()); - Mediator.Subscribe(this, (_) => FrameworkOnUpdate()); - Mediator.Subscribe(this, (msg) => - { - var newData = msg.CharacterData; - if (_lastSentData == null || (!string.Equals(newData.DataHash.Value, _lastSentData.DataHash.Value, StringComparison.Ordinal))) - { - Logger.LogDebug("Pushing data for visible players"); - _lastSentData = newData; - PushCharacterData(_pairManager.GetVisibleUsers()); - } - else - { - Logger.LogDebug("Not sending data for {hash}", newData.DataHash.Value); - } - }); - Mediator.Subscribe(this, (msg) => _newVisiblePlayers.Add(msg.Player)); - Mediator.Subscribe(this, (_) => PushCharacterData(_pairManager.GetVisibleUsers())); - } - - private void FrameworkOnUpdate() - { - if (!_dalamudUtil.GetIsPlayerPresent() || !_apiController.IsConnected) return; - - if (!_newVisiblePlayers.Any()) return; - var newVisiblePlayers = _newVisiblePlayers.ToList(); - _newVisiblePlayers.Clear(); - Logger.LogTrace("Has new visible players, pushing character data"); - PushCharacterData(newVisiblePlayers.Select(c => c.Pair.UserData).ToList()); - } - - private void PlayerManagerOnPlayerHasChanged() - { - PushCharacterData(_pairManager.GetVisibleUsers()); - } - - private void PushCharacterData(List visiblePlayers) - { - if (visiblePlayers.Any() && _lastSentData != null) - { - _ = Task.Run(async () => - { - var dataToSend = await _fileTransferManager.UploadFiles(_lastSentData.DeepClone(), visiblePlayers).ConfigureAwait(false); - await _apiController.PushCharacterData(dataToSend, visiblePlayers).ConfigureAwait(false); - }); - } - } -} \ No newline at end of file diff --git a/MareSynchronos/PlayerData/Pairs/PairManager.cs b/MareSynchronos/PlayerData/Pairs/PairManager.cs index 44c1269..cc4c95a 100644 --- a/MareSynchronos/PlayerData/Pairs/PairManager.cs +++ b/MareSynchronos/PlayerData/Pairs/PairManager.cs @@ -122,7 +122,7 @@ public sealed class PairManager : DisposableMediatorSubscriberBase public int GetVisibleUserCount() => _allClientPairs.Count(p => p.Value.IsVisible); - public List GetVisibleUsers() => _allClientPairs.Where(p => p.Value.IsVisible).Select(p => p.Key).ToList(); + public List GetVisibleUsers() => [.. _allClientPairs.Where(p => p.Value.IsVisible).Select(p => p.Key)]; public void MarkPairOffline(UserData user) { diff --git a/MareSynchronos/PlayerData/Pairs/VisibleUserDataDistributor.cs b/MareSynchronos/PlayerData/Pairs/VisibleUserDataDistributor.cs new file mode 100644 index 0000000..7720960 --- /dev/null +++ b/MareSynchronos/PlayerData/Pairs/VisibleUserDataDistributor.cs @@ -0,0 +1,96 @@ +using MareSynchronos.API.Data; +using MareSynchronos.Services; +using MareSynchronos.Services.Mediator; +using MareSynchronos.Utils; +using MareSynchronos.WebAPI; +using MareSynchronos.WebAPI.Files; +using MessagePack.Formatters; +using Microsoft.Extensions.Logging; + +namespace MareSynchronos.PlayerData.Pairs; + +public class VisibleUserDataDistributor : DisposableMediatorSubscriberBase +{ + private readonly ApiController _apiController; + private readonly DalamudUtilService _dalamudUtil; + private readonly FileUploadManager _fileTransferManager; + private readonly PairManager _pairManager; + private CharacterData? _lastCreatedData; + private readonly List _previouslyVisiblePlayers = []; + private Task? _fileUploadTask = null; + private readonly HashSet _usersToPushDataTo = []; + + public VisibleUserDataDistributor(ILogger logger, ApiController apiController, DalamudUtilService dalamudUtil, + PairManager pairManager, MareMediator mediator, FileUploadManager fileTransferManager) : base(logger, mediator) + { + _apiController = apiController; + _dalamudUtil = dalamudUtil; + _pairManager = pairManager; + _fileTransferManager = fileTransferManager; + Mediator.Subscribe(this, (_) => FrameworkOnUpdate()); + Mediator.Subscribe(this, (msg) => + { + var newData = msg.CharacterData; + if (_lastCreatedData == null || (!string.Equals(newData.DataHash.Value, _lastCreatedData.DataHash.Value, StringComparison.Ordinal))) + { + Logger.LogDebug("Pushing data for visible players"); + _lastCreatedData = newData; + PushToAllVisibleUsers(forced: true); + } + else + { + Logger.LogDebug("Not sending data for {hash}", newData.DataHash.Value); + } + }); + + Mediator.Subscribe(this, (_) => PushToAllVisibleUsers()); + Mediator.Subscribe(this, (_) => _previouslyVisiblePlayers.Clear()); + } + + private void PushToAllVisibleUsers(bool forced = false) + { + foreach (var user in _pairManager.GetVisibleUsers()) + { + _usersToPushDataTo.Add(user); + } + PushCharacterData(forced); + } + + private void FrameworkOnUpdate() + { + if (!_dalamudUtil.GetIsPlayerPresent() || !_apiController.IsConnected) return; + + var allVisibleUsers = _pairManager.GetVisibleUsers(); + var newVisibleUsers = allVisibleUsers.Except(_previouslyVisiblePlayers).ToList(); + _previouslyVisiblePlayers.Clear(); + _previouslyVisiblePlayers.AddRange(allVisibleUsers); + if (newVisibleUsers.Count == 0) return; + + Logger.LogTrace("Has new visible players, pushing character data to {users}", string.Join(", ", newVisibleUsers.Select(k => k.AliasOrUID))); + foreach (var user in newVisibleUsers) + { + _usersToPushDataTo.Add(user); + } + PushCharacterData(); + } + + private void PushCharacterData(bool forced = false) + { + if (_lastCreatedData == null) return; + + _ = Task.Run(async () => + { + if (_fileUploadTask == null || (_fileUploadTask?.IsCompleted ?? false) || forced) + { + _fileUploadTask = _fileTransferManager.UploadFiles(_lastCreatedData.DeepClone(), [.. _usersToPushDataTo]); + } + + if (_fileUploadTask != null) + { + var dataToSend = await _fileUploadTask.ConfigureAwait(false); + await _apiController.PushCharacterData(dataToSend, [.. _usersToPushDataTo]).ConfigureAwait(false); + _usersToPushDataTo.Clear(); + } + }); + } +} \ No newline at end of file diff --git a/MareSynchronos/PlayerData/Services/CacheCreationService.cs b/MareSynchronos/PlayerData/Services/CacheCreationService.cs index 2ee7b65..9df3262 100644 --- a/MareSynchronos/PlayerData/Services/CacheCreationService.cs +++ b/MareSynchronos/PlayerData/Services/CacheCreationService.cs @@ -42,13 +42,13 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase AddCacheToCreate(msg.ObjectToCreateFor.ObjectKind); }); - _playerRelatedObjects[ObjectKind.Player] = gameObjectHandlerFactory.Create(ObjectKind.Player, dalamudUtil.GetPlayerPointer, isWatched: true) + _playerRelatedObjects[ObjectKind.Player] = gameObjectHandlerFactory.Create(ObjectKind.Player, dalamudUtil.GetPlayerPtr, isWatched: true) .GetAwaiter().GetResult(); - _playerRelatedObjects[ObjectKind.MinionOrMount] = gameObjectHandlerFactory.Create(ObjectKind.MinionOrMount, () => dalamudUtil.GetMinionOrMount(), isWatched: true) + _playerRelatedObjects[ObjectKind.MinionOrMount] = gameObjectHandlerFactory.Create(ObjectKind.MinionOrMount, () => dalamudUtil.GetMinionOrMountPtr(), isWatched: true) .GetAwaiter().GetResult(); - _playerRelatedObjects[ObjectKind.Pet] = gameObjectHandlerFactory.Create(ObjectKind.Pet, () => dalamudUtil.GetPet(), isWatched: true) + _playerRelatedObjects[ObjectKind.Pet] = gameObjectHandlerFactory.Create(ObjectKind.Pet, () => dalamudUtil.GetPetPtr(), isWatched: true) .GetAwaiter().GetResult(); - _playerRelatedObjects[ObjectKind.Companion] = gameObjectHandlerFactory.Create(ObjectKind.Companion, () => dalamudUtil.GetCompanion(), isWatched: true) + _playerRelatedObjects[ObjectKind.Companion] = gameObjectHandlerFactory.Create(ObjectKind.Companion, () => dalamudUtil.GetCompanionPtr(), isWatched: true) .GetAwaiter().GetResult(); Mediator.Subscribe(this, (msg) => @@ -229,7 +229,6 @@ public sealed class CacheCreationService : DisposableMediatorSubscriberBase catch (OperationCanceledException) { Logger.LogDebug("Cache Creation cancelled"); - linkedCts.Dispose(); } catch (Exception ex) { diff --git a/MareSynchronos/Plugin.cs b/MareSynchronos/Plugin.cs index 4202a6c..89ac126 100644 --- a/MareSynchronos/Plugin.cs +++ b/MareSynchronos/Plugin.cs @@ -213,7 +213,7 @@ public sealed class Plugin : IDalamudPlugin collection.AddScoped(); collection.AddScoped(); collection.AddScoped(); - collection.AddScoped(); + collection.AddScoped(); collection.AddScoped((s) => new UiService(s.GetRequiredService>(), pluginInterface.UiBuilder, s.GetRequiredService(), s.GetRequiredService(), s.GetServices(), s.GetRequiredService(), diff --git a/MareSynchronos/Services/DalamudUtilService.cs b/MareSynchronos/Services/DalamudUtilService.cs index 8ded93e..fbd9e0e 100644 --- a/MareSynchronos/Services/DalamudUtilService.cs +++ b/MareSynchronos/Services/DalamudUtilService.cs @@ -172,18 +172,18 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber return (Dalamud.Game.ClientState.Objects.Types.ICharacter)objTableObj; } - public unsafe IntPtr GetCompanion(IntPtr? playerPointer = null) + public unsafe IntPtr GetCompanionPtr(IntPtr? playerPointer = null) { EnsureIsOnFramework(); var mgr = CharacterManager.Instance(); - playerPointer ??= GetPlayerPointer(); + playerPointer ??= GetPlayerPtr(); if (playerPointer == IntPtr.Zero || (IntPtr)mgr == IntPtr.Zero) return IntPtr.Zero; return (IntPtr)mgr->LookupBuddyByOwnerObject((BattleChara*)playerPointer); } public async Task GetCompanionAsync(IntPtr? playerPointer = null) { - return await RunOnFrameworkThread(() => GetCompanion(playerPointer)).ConfigureAwait(false); + return await RunOnFrameworkThread(() => GetCompanionPtr(playerPointer)).ConfigureAwait(false); } public async Task GetGposeCharacterFromObjectTableByNameAsync(string name, bool onlyGposeCharacters = false) @@ -214,32 +214,32 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber return await RunOnFrameworkThread(GetIsPlayerPresent).ConfigureAwait(false); } - public unsafe IntPtr GetMinionOrMount(IntPtr? playerPointer = null) + public unsafe IntPtr GetMinionOrMountPtr(IntPtr? playerPointer = null) { EnsureIsOnFramework(); - playerPointer ??= GetPlayerPointer(); + playerPointer ??= GetPlayerPtr(); if (playerPointer == IntPtr.Zero) return IntPtr.Zero; return _objectTable.GetObjectAddress(((GameObject*)playerPointer)->ObjectIndex + 1); } public async Task GetMinionOrMountAsync(IntPtr? playerPointer = null) { - return await RunOnFrameworkThread(() => GetMinionOrMount(playerPointer)).ConfigureAwait(false); + return await RunOnFrameworkThread(() => GetMinionOrMountPtr(playerPointer)).ConfigureAwait(false); } - public unsafe IntPtr GetPet(IntPtr? playerPointer = null) + public unsafe IntPtr GetPetPtr(IntPtr? playerPointer = null) { EnsureIsOnFramework(); if (_classJobIdsIgnoredForPets.Contains(_classJobId ?? 0)) return IntPtr.Zero; var mgr = CharacterManager.Instance(); - playerPointer ??= GetPlayerPointer(); + playerPointer ??= GetPlayerPtr(); if (playerPointer == IntPtr.Zero || (IntPtr)mgr == IntPtr.Zero) return IntPtr.Zero; return (IntPtr)mgr->LookupPetByOwnerObject((BattleChara*)playerPointer); } public async Task GetPetAsync(IntPtr? playerPointer = null) { - return await RunOnFrameworkThread(() => GetPet(playerPointer)).ConfigureAwait(false); + return await RunOnFrameworkThread(() => GetPetPtr(playerPointer)).ConfigureAwait(false); } public async Task GetPlayerCharacterAsync() @@ -284,7 +284,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber public async Task GetPlayerNameHashedAsync() { - return await RunOnFrameworkThread(() => GetHashedAccIdFromPlayerPointer(GetPlayerPointer())).ConfigureAwait(false); + return await RunOnFrameworkThread(() => GetHashedAccIdFromPlayerPointer(GetPlayerPtr())).ConfigureAwait(false); } private unsafe static string GetHashedAccIdFromPlayerPointer(nint ptr) @@ -293,7 +293,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber return ((BattleChara*)ptr)->Character.AccountId.ToString().GetHash256(); } - public IntPtr GetPlayerPointer() + public IntPtr GetPlayerPtr() { EnsureIsOnFramework(); return _clientState.LocalPlayer?.Address ?? IntPtr.Zero; @@ -301,7 +301,7 @@ public class DalamudUtilService : IHostedService, IMediatorSubscriber public async Task GetPlayerPointerAsync() { - return await RunOnFrameworkThread(GetPlayerPointer).ConfigureAwait(false); + return await RunOnFrameworkThread(GetPlayerPtr).ConfigureAwait(false); } public uint GetHomeWorldId() diff --git a/MareSynchronos/Services/Mediator/Messages.cs b/MareSynchronos/Services/Mediator/Messages.cs index d3c3bd3..54fb8bf 100644 --- a/MareSynchronos/Services/Mediator/Messages.cs +++ b/MareSynchronos/Services/Mediator/Messages.cs @@ -45,8 +45,6 @@ public record MoodlesMessage(IntPtr Address) : MessageBase; public record PetNamesReadyMessage : MessageBase; public record PetNamesMessage(string PetNicknamesData) : MessageBase; public record HonorificReadyMessage : MessageBase; -public record PlayerChangedMessage(CharacterData Data) : MessageBase; -public record CharacterChangedMessage(GameObjectHandler GameObjectHandler) : MessageBase; public record TransientResourceChangedMessage(IntPtr Address) : MessageBase; public record HaltScanMessage(string Source) : MessageBase; public record ResumeScanMessage(string Source) : MessageBase; @@ -73,7 +71,6 @@ public record ProfilePopoutToggle(Pair? Pair) : MessageBase; public record CompactUiChange(Vector2 Size, Vector2 Position) : MessageBase; public record ProfileOpenStandaloneMessage(Pair Pair) : MessageBase; public record RemoveWindowMessage(WindowMediatorSubscriberBase Window) : MessageBase; -public record PairHandlerVisibleMessage(PairHandler Player) : MessageBase; public record RefreshUiMessage : MessageBase; public record OpenBanUserPopupMessage(Pair PairToBan, GroupFullInfoDto GroupFullInfoDto) : MessageBase; public record OpenCensusPopupMessage() : MessageBase;