From 7569b15993a8d24de573eecf59af5bd896885052 Mon Sep 17 00:00:00 2001 From: azyges Date: Wed, 24 Sep 2025 22:28:32 +0900 Subject: [PATCH] seperate scanning service not relying on nameplate updates & other improvements/fixes --- LightlessSync/Plugin.cs | 8 +- .../Services/BroadcastScanningService.cs | 216 +++++++++++++++++ LightlessSync/Services/BroadcastService.cs | 2 + LightlessSync/Services/NameplateHandler.cs | 20 +- LightlessSync/Services/NameplateService.cs | 225 +----------------- LightlessSync/UI/BroadcastUI.cs | 22 +- LightlessSync/UI/SyncshellFinderUI.cs | 11 +- LightlessSync/UI/UIColors.cs | 1 + 8 files changed, 253 insertions(+), 252 deletions(-) create mode 100644 LightlessSync/Services/BroadcastScanningService.cs diff --git a/LightlessSync/Plugin.cs b/LightlessSync/Plugin.cs index 1cab3dd..b9a70fe 100644 --- a/LightlessSync/Plugin.cs +++ b/LightlessSync/Plugin.cs @@ -205,6 +205,8 @@ public sealed class Plugin : IDalamudPlugin collection.AddSingleton(); collection.AddSingleton(); collection.AddSingleton(); + collection.AddSingleton(s => new BroadcastScannerService( s.GetRequiredService>(), clientState, objectTable, framework, s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); + // add scoped services collection.AddScoped(); @@ -227,8 +229,8 @@ public sealed class Plugin : IDalamudPlugin s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); collection.AddScoped(); - collection.AddScoped((s) => new BroadcastUI(s.GetRequiredService>(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); - collection.AddScoped((s) => new SyncshellFinderUI(s.GetRequiredService>(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); + collection.AddScoped((s) => new BroadcastUI(s.GetRequiredService>(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); + collection.AddScoped((s) => new SyncshellFinderUI(s.GetRequiredService>(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); collection.AddScoped(); collection.AddScoped(); collection.AddScoped(); @@ -246,7 +248,7 @@ public sealed class Plugin : IDalamudPlugin pluginInterface, textureProvider, s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); collection.AddScoped((s) => new NameplateService(s.GetRequiredService>(), s.GetRequiredService(), namePlateGui, clientState, - s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService(), s.GetRequiredService())); + s.GetRequiredService(), s.GetRequiredService())); collection.AddHostedService(p => p.GetRequiredService()); collection.AddHostedService(p => p.GetRequiredService()); diff --git a/LightlessSync/Services/BroadcastScanningService.cs b/LightlessSync/Services/BroadcastScanningService.cs new file mode 100644 index 0000000..313abb8 --- /dev/null +++ b/LightlessSync/Services/BroadcastScanningService.cs @@ -0,0 +1,216 @@ +using Dalamud.Game.ClientState.Objects.SubKinds; +using Dalamud.Plugin.Services; +using LightlessSync.API.Dto.User; +using LightlessSync.LightlessConfiguration; +using LightlessSync.Services.Mediator; +using Microsoft.Extensions.Logging; +using System.Collections.Concurrent; + +namespace LightlessSync.Services; + +public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDisposable +{ + private readonly ILogger _logger; + private readonly IObjectTable _objectTable; + private readonly IFramework _framework; + + private readonly BroadcastService _broadcastService; + private readonly NameplateHandler _nameplateHandler; + + private readonly ConcurrentDictionary _broadcastCache = new(); + private readonly Queue _lookupQueue = new(); + private readonly HashSet _lookupQueuedCids = new(); + private readonly HashSet _syncshellCids = new(); + + private static readonly TimeSpan MaxAllowedTtl = TimeSpan.FromMinutes(4); + private static readonly TimeSpan RetryDelay = TimeSpan.FromMinutes(1); + + private readonly CancellationTokenSource _cleanupCts = new(); + private Task? _cleanupTask; + + private int _frameCounter = 0; + private int _lookupsThisFrame = 0; + private const int MaxLookupsPerFrame = 15; + private const int MaxQueueSize = 100; + + public IReadOnlyDictionary BroadcastCache => _broadcastCache; + public readonly record struct BroadcastEntry(bool IsBroadcasting, DateTime ExpiryTime, string? GID); + + public BroadcastScannerService(ILogger logger, + IClientState clientState, + IObjectTable objectTable, + IFramework framework, + BroadcastService broadcastService, + LightlessMediator mediator, + NameplateHandler nameplateHandler, + DalamudUtilService dalamudUtil, + LightlessConfigService configService) : base(logger, mediator) + { + _logger = logger; + _objectTable = objectTable; + _broadcastService = broadcastService; + _nameplateHandler = nameplateHandler; + + _logger = logger; + _framework = framework; + _framework.Update += OnFrameworkUpdate; + + Mediator.Subscribe(this, OnBroadcastStatusChanged); + _cleanupTask = Task.Run(ExpiredBroadcastCleanupLoop); + + _nameplateHandler.Init(); + } + + private void OnFrameworkUpdate(IFramework framework) => Update(); + + public void Update() + { + _frameCounter++; + _lookupsThisFrame = 0; + + if (!_broadcastService.IsBroadcasting) + return; + + var now = DateTime.UtcNow; + + foreach (var obj in _objectTable) + { + if (obj is not IPlayerCharacter player || player.Address == IntPtr.Zero) + continue; + + var cid = DalamudUtilService.GetHashedCIDFromPlayerPointer(player.Address); + var isStale = !_broadcastCache.TryGetValue(cid, out var entry) || entry.ExpiryTime <= now; + + if (isStale && _lookupQueuedCids.Add(cid) && _lookupQueue.Count < MaxQueueSize) + _lookupQueue.Enqueue(cid); + } + + if (_frameCounter % 2 == 0 && _lookupQueue.Count > 0) + { + var cidsToLookup = new List(); + while (_lookupQueue.Count > 0 && _lookupsThisFrame < MaxLookupsPerFrame) + { + var cid = _lookupQueue.Dequeue(); + _lookupQueuedCids.Remove(cid); + cidsToLookup.Add(cid); + _lookupsThisFrame++; + } + + if (cidsToLookup.Count > 0) + _ = BatchUpdateBroadcastCacheAsync(cidsToLookup); + } + } + + private async Task BatchUpdateBroadcastCacheAsync(List cids) + { + var results = await _broadcastService.AreUsersBroadcastingAsync(cids).ConfigureAwait(false); + var now = DateTime.UtcNow; + + foreach (var (cid, info) in results) + { + if (string.IsNullOrWhiteSpace(cid) || info == null) + continue; + + var ttl = info.IsBroadcasting && info.TTL.HasValue + ? TimeSpan.FromTicks(Math.Min(info.TTL.Value.Ticks, MaxAllowedTtl.Ticks)) + : RetryDelay; + + var expiry = now + ttl; + + _broadcastCache.AddOrUpdate(cid, + new BroadcastEntry(info.IsBroadcasting, expiry, info.GID), + (_, old) => new BroadcastEntry(info.IsBroadcasting, expiry, info.GID)); + } + + var activeCids = _broadcastCache + .Where(e => e.Value.IsBroadcasting && e.Value.ExpiryTime > now) + .Select(e => e.Key) + .ToList(); + + _nameplateHandler.UpdateBroadcastingCids(activeCids); + UpdateSyncshellBroadcasts(); + } + + private void OnBroadcastStatusChanged(BroadcastStatusChangedMessage msg) + { + if (!msg.Enabled) + { + _broadcastCache.Clear(); + _lookupQueue.Clear(); + _lookupQueuedCids.Clear(); + _syncshellCids.Clear(); + + _nameplateHandler.UpdateBroadcastingCids(Enumerable.Empty()); + } + } + + private void UpdateSyncshellBroadcasts() + { + var now = DateTime.UtcNow; + var newSet = _broadcastCache + .Where(e => e.Value.IsBroadcasting && e.Value.ExpiryTime > now && !string.IsNullOrEmpty(e.Value.GID)) + .Select(e => e.Key) + .ToHashSet(); + + if (!_syncshellCids.SetEquals(newSet)) + { + _syncshellCids.Clear(); + foreach (var cid in newSet) + _syncshellCids.Add(cid); + + Mediator.Publish(new SyncshellBroadcastsUpdatedMessage()); + } + } + + public List GetActiveSyncshellBroadcasts() + { + var now = DateTime.UtcNow; + + return _broadcastCache + .Where(e => e.Value.IsBroadcasting && e.Value.ExpiryTime > now && !string.IsNullOrEmpty(e.Value.GID)) + .Select(e => new BroadcastStatusInfoDto + { + HashedCID = e.Key, + IsBroadcasting = true, + TTL = e.Value.ExpiryTime - now, + GID = e.Value.GID + }) + .ToList(); + } + + private async Task ExpiredBroadcastCleanupLoop() + { + var token = _cleanupCts.Token; + + try + { + while (!token.IsCancellationRequested) + { + await Task.Delay(TimeSpan.FromSeconds(10), token); + + var now = DateTime.UtcNow; + foreach (var (cid, entry) in _broadcastCache.ToArray()) + { + if (entry.ExpiryTime <= now) + _broadcastCache.TryRemove(cid, out _); + } + } + } + catch (OperationCanceledException) { } + catch (Exception ex) + { + _logger.LogError(ex, "Broadcast cleanup loop crashed"); + } + + UpdateSyncshellBroadcasts(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + _framework.Update -= OnFrameworkUpdate; + _cleanupCts.Cancel(); + _cleanupTask?.Wait(100); + _nameplateHandler.Uninit(); + } +} diff --git a/LightlessSync/Services/BroadcastService.cs b/LightlessSync/Services/BroadcastService.cs index 1d50499..09a9674 100644 --- a/LightlessSync/Services/BroadcastService.cs +++ b/LightlessSync/Services/BroadcastService.cs @@ -151,6 +151,7 @@ public class BroadcastService : IHostedService, IMediatorSubscriber _config.Save(); _mediator.Publish(new BroadcastStatusChangedMessage(false, null)); + Mediator.Publish(new EventMessage(new Services.Events.Event(nameof(BroadcastService), Services.Events.EventSeverity.Informational,$"Disabled Lightfinder for Player: {msg.HashedCid}"))); return; } @@ -166,6 +167,7 @@ public class BroadcastService : IHostedService, IMediatorSubscriber _logger.LogInformation("Fetched TTL from server: {TTL}", remaining); _mediator.Publish(new BroadcastStatusChangedMessage(true, remaining)); + Mediator.Publish(new EventMessage(new Services.Events.Event(nameof(BroadcastService), Services.Events.EventSeverity.Informational, $"Enabled Lightfinder for Player: {msg.HashedCid}"))); } else { diff --git a/LightlessSync/Services/NameplateHandler.cs b/LightlessSync/Services/NameplateHandler.cs index cbb4777..762bc52 100644 --- a/LightlessSync/Services/NameplateHandler.cs +++ b/LightlessSync/Services/NameplateHandler.cs @@ -5,6 +5,7 @@ using FFXIVClientStructs.FFXIV.Client.System.Framework; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Component.GUI; using LightlessSync.Services.Mediator; +using LightlessSync.UI; using LightlessSync.Utils; // Created using https://github.com/PunishedPineapple/Distance as a reference, thank you! @@ -205,6 +206,9 @@ public unsafe class NameplateHandler : IMediatorSubscriber var nameContainer = nameplateObject.NameContainer; var nameText = nameplateObject.NameText; + var labelColor = UIColors.Get("LightlessPurple"); + var edgeColor = UIColors.Get("FullBlack"); + var labelY = nameContainer->Height - nameplateObject.TextH - (int)(24 * nameText->AtkResNode.ScaleY); pNode->AtkResNode.SetPositionShort(58, (short)labelY); @@ -213,15 +217,15 @@ public unsafe class NameplateHandler : IMediatorSubscriber pNode->AtkResNode.Color.A = 255; - pNode->TextColor.A = 255; - pNode->TextColor.R = 173; - pNode->TextColor.G = 138; - pNode->TextColor.B = 245; + pNode->TextColor.R = (byte)(labelColor.X * 255); + pNode->TextColor.G = (byte)(labelColor.Y * 255); + pNode->TextColor.B = (byte)(labelColor.Z * 255); + pNode->TextColor.A = (byte)(labelColor.W * 255); - pNode->EdgeColor.A = 255; - pNode->EdgeColor.R = 0; - pNode->EdgeColor.G = 0; - pNode->EdgeColor.B = 0; + pNode->EdgeColor.R = (byte)(edgeColor.X * 255); + pNode->EdgeColor.G = (byte)(edgeColor.Y * 255); + pNode->EdgeColor.B = (byte)(edgeColor.Z * 255); + pNode->EdgeColor.A = (byte)(edgeColor.W * 255); pNode->FontSize = 24; pNode->AlignmentType = AlignmentType.Center; diff --git a/LightlessSync/Services/NameplateService.cs b/LightlessSync/Services/NameplateService.cs index cb2d978..9de944e 100644 --- a/LightlessSync/Services/NameplateService.cs +++ b/LightlessSync/Services/NameplateService.cs @@ -3,13 +3,11 @@ using Dalamud.Game.Gui.NamePlate; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Plugin.Services; using Dalamud.Utility; -using LightlessSync.API.Dto.User; using LightlessSync.LightlessConfiguration; using LightlessSync.PlayerData.Pairs; using LightlessSync.Services.Mediator; using LightlessSync.UI; using Microsoft.Extensions.Logging; -using System.Collections.Concurrent; namespace LightlessSync.Services; @@ -20,80 +18,28 @@ public class NameplateService : DisposableMediatorSubscriberBase private readonly IClientState _clientState; private readonly INamePlateGui _namePlateGui; private readonly PairManager _pairManager; - private readonly BroadcastService _broadcastService; - private readonly DalamudUtilService _dalamudUtil; - private readonly NameplateHandler _nameplatehandler; - private readonly IFramework _framework; - private readonly IGameGui _gameGui; - - private readonly ConcurrentDictionary _broadcastCache = new(); - private static readonly TimeSpan MaxAllowedTtl = TimeSpan.FromMinutes(5); - private static readonly TimeSpan RetryDelay = TimeSpan.FromMinutes(1); - private readonly Queue _lookupQueue = new(); - private readonly HashSet _lookupQueuedCids = new(); - private readonly HashSet _syncshellCids = new(); - - private readonly CancellationTokenSource _cleanupCts = new(); - private Task? _cleanupTask; - - private const int MaxLookupsPerFrame = 15; - private const int MaxQueueSize = 100; - - private int _lookupsThisFrame = 0; - private int _frameCounter = 0; - - public IReadOnlyDictionary BroadcastCache => _broadcastCache; - - public readonly struct BroadcastEntry - { - public readonly bool IsBroadcasting; - public readonly DateTime ExpiryTime; - public readonly bool PrefixApplied; - public readonly string? GID; - - public BroadcastEntry(bool isBroadcasting, DateTime expiryTime, bool prefixApplied, string? gid = null) - { - IsBroadcasting = isBroadcasting; - ExpiryTime = expiryTime; - PrefixApplied = prefixApplied; - GID = gid; - } - } public NameplateService(ILogger logger, LightlessConfigService configService, INamePlateGui namePlateGui, IClientState clientState, PairManager pairManager, - BroadcastService broadcastService, - LightlessMediator lightlessMediator, - DalamudUtilService dalamudUtil, - NameplateHandler nameplatehandler, - IGameGui gameGui) : base(logger, lightlessMediator) + LightlessMediator lightlessMediator) : base(logger, lightlessMediator) { _logger = logger; _configService = configService; _namePlateGui = namePlateGui; _clientState = clientState; _pairManager = pairManager; - _broadcastService = broadcastService; - _dalamudUtil = dalamudUtil; - _nameplatehandler = nameplatehandler; - _gameGui = gameGui; _namePlateGui.OnNamePlateUpdate += OnNamePlateUpdate; _namePlateGui.RequestRedraw(); Mediator.Subscribe(this, (_) => _namePlateGui.RequestRedraw()); - Mediator.Subscribe(this, OnBroadcastStatusChanged); - _nameplatehandler.Init(); - _cleanupTask = Task.Run(ExpiredBroadcastCleanupLoop); } private void OnNamePlateUpdate(INamePlateUpdateContext context, IReadOnlyList handlers) { - _frameCounter++; - _lookupsThisFrame = 0; if (!_configService.Current.IsNameplateColorsEnabled || (_configService.Current.IsNameplateColorsEnabled && _clientState.IsPvPExcludingDen)) return; @@ -112,11 +58,6 @@ public class NameplateService : DisposableMediatorSubscriberBase if (playerCharacter == null) continue; - - var cid = DalamudUtilService.GetHashedCIDFromPlayerPointer(playerCharacter.Address); - var hasEntry = _broadcastCache.TryGetValue(cid, out var entry); - var isEntryStale = !hasEntry || entry.ExpiryTime <= now; - var isInParty = playerCharacter.StatusFlags.HasFlag(StatusFlags.PartyMember); var isFriend = playerCharacter.StatusFlags.HasFlag(StatusFlags.Friend); bool partyColorAllowed = (_configService.Current.overridePartyColor && isInParty); @@ -132,167 +73,7 @@ public class NameplateService : DisposableMediatorSubscriberBase handler.NameParts.TextWrap = CreateTextWrap(colors); } - if (!_broadcastService.IsBroadcasting) - continue; - - if (isEntryStale && _lookupQueuedCids.Add(cid) && _lookupQueue.Count < MaxQueueSize) - { - _lookupQueue.Enqueue(cid); - } } - - if (_broadcastService.IsBroadcasting && _frameCounter % 2 == 0) - { - var cidsToLookup = new List(); - while (_lookupQueue.Count > 0 && _lookupsThisFrame < MaxLookupsPerFrame) - { - var nextCid = _lookupQueue.Dequeue(); - _lookupQueuedCids.Remove(nextCid); - cidsToLookup.Add(nextCid); - _lookupsThisFrame++; - } - - if (cidsToLookup.Count > 0) - _ = BatchUpdateBroadcastCacheAsync(cidsToLookup); - } - } - - private async Task BatchUpdateBroadcastCacheAsync(List cidList) - { - var results = await _broadcastService.AreUsersBroadcastingAsync(cidList).ConfigureAwait(false); - var now = DateTime.UtcNow; - - foreach (var (cid, info) in results) - { - if (string.IsNullOrWhiteSpace(cid) || info == null) - { - _logger.LogWarning("Skipping broadcast entry: cid={Cid}, info=null or empty", cid); - continue; - } - - bool isBroadcasting = info.IsBroadcasting; - TimeSpan effectiveTtl = isBroadcasting && info.TTL.HasValue - ? TimeSpan.FromTicks(Math.Min(info.TTL.Value.Ticks, MaxAllowedTtl.Ticks)) - : RetryDelay; - - var expiryTime = now + effectiveTtl; - - _broadcastCache.AddOrUpdate(cid, - new BroadcastEntry(isBroadcasting, expiryTime, false, info.GID), - (_, old) => new BroadcastEntry(isBroadcasting, expiryTime, old.PrefixApplied, info.GID)); - } - - var activeCids = _broadcastCache - .Where(kvp => kvp.Value.IsBroadcasting) - .Select(kvp => kvp.Key) - .ToList(); - - _nameplatehandler.UpdateBroadcastingCids(activeCids); - _namePlateGui.RequestRedraw(); - - UpdateSyncshellBroadcasts(); - } - - private void OnBroadcastStatusChanged(BroadcastStatusChangedMessage msg) - { - if (!msg.Enabled) - { - _logger.LogInformation("Broadcast disabled, clearing prefix cache and queue"); - - _broadcastCache.Clear(); - _lookupQueue.Clear(); - _lookupQueuedCids.Clear(); - _syncshellCids.Clear(); - - _nameplatehandler.UpdateBroadcastingCids(Enumerable.Empty()); - _namePlateGui.RequestRedraw(); - } - } - - public List GetActiveSyncshellBroadcasts() - { - var now = DateTime.UtcNow; - - return _broadcastCache - .Where(kvp => - kvp.Value.IsBroadcasting && - kvp.Value.ExpiryTime > now && - !string.IsNullOrEmpty(kvp.Value.GID)) - .Select(kvp => new BroadcastStatusInfoDto - { - HashedCID = kvp.Key, - IsBroadcasting = true, - TTL = kvp.Value.ExpiryTime - now, - GID = kvp.Value.GID - }) - .ToList(); - } - - private void UpdateSyncshellBroadcasts() - { - var now = DateTime.UtcNow; - - var newSet = _broadcastCache - .Where(kvp => kvp.Value.IsBroadcasting && kvp.Value.ExpiryTime > now && !string.IsNullOrEmpty(kvp.Value.GID)) - .Select(kvp => kvp.Key) - .ToHashSet(); - - if (!_syncshellCids.SetEquals(newSet)) - { - _syncshellCids.Clear(); - foreach (var cid in newSet) - _syncshellCids.Add(cid); - - _logger.LogInformation("Syncshell broadcast entries changed, sending update lol"); - Mediator.Publish(new SyncshellBroadcastsUpdatedMessage()); - } - } - - public bool IsBroadcastingKnown(string cidHash, out bool isBroadcasting) - { - if (_broadcastCache.TryGetValue(cidHash, out var entry)) - { - isBroadcasting = entry.IsBroadcasting; - return true; - } - - isBroadcasting = false; - return false; - } - - private async Task ExpiredBroadcastCleanupLoop() - { - var token = _cleanupCts.Token; - - try - { - while (!token.IsCancellationRequested) - { - await Task.Delay(TimeSpan.FromSeconds(10), token); - - var now = DateTime.UtcNow; - foreach (var (cid, entry) in _broadcastCache.ToArray()) - { - if (entry.ExpiryTime <= now) - { - if (_broadcastCache.TryRemove(cid, out _)) - { - _logger.LogInformation("Removed expired broadcast entry: {Cid}", cid); - } - } - } - } - } - catch (OperationCanceledException) - { - - } - catch (Exception ex) - { - _logger.LogError(ex, "Error in ExpiredBroadcastCleanupLoop"); - } - - UpdateSyncshellBroadcasts(); } public void RequestRedraw() @@ -319,11 +100,7 @@ public class NameplateService : DisposableMediatorSubscriberBase { base.Dispose(disposing); - _cleanupCts.Cancel(); - _cleanupTask?.Wait(100); - _namePlateGui.OnNamePlateUpdate -= OnNamePlateUpdate; _namePlateGui.RequestRedraw(); - _nameplatehandler.Uninit(); } } \ No newline at end of file diff --git a/LightlessSync/UI/BroadcastUI.cs b/LightlessSync/UI/BroadcastUI.cs index 7799601..6f9cdc8 100644 --- a/LightlessSync/UI/BroadcastUI.cs +++ b/LightlessSync/UI/BroadcastUI.cs @@ -17,7 +17,7 @@ namespace LightlessSync.UI private readonly LightlessConfigService _configService; private readonly BroadcastService _broadcastService; private readonly UiSharedService _uiSharedService; - private readonly NameplateService _nameplateService; + private readonly BroadcastScannerService _broadcastScannerService; private IReadOnlyList _allSyncshells; private string _userUid = string.Empty; @@ -32,20 +32,20 @@ namespace LightlessSync.UI LightlessConfigService configService, UiSharedService uiShared, ApiController apiController, - NameplateService nameplateService + BroadcastScannerService broadcastScannerService ) : base(logger, mediator, "Lightfinder###LightlessLightfinderUI", performanceCollectorService) { _broadcastService = broadcastService; _uiSharedService = uiShared; _configService = configService; _apiController = apiController; - _nameplateService = nameplateService; + _broadcastScannerService = broadcastScannerService; IsOpen = false; this.SizeConstraints = new() { - MinimumSize = new(590, 340), - MaximumSize = new(590, 340) + MinimumSize = new(600, 340), + MaximumSize = new(750, 400) }; mediator.Subscribe(this, async _ => await RefreshSyncshells()); @@ -126,9 +126,7 @@ namespace LightlessSync.UI { if (!_broadcastService.IsLightFinderAvailable) { - ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("LightlessYellow")); - ImGui.TextWrapped("This server doesn't support LightFinder."); - ImGui.PopStyleColor(); + _uiSharedService.MediumText("This server doesn't support Lightfinder.", UIColors.Get("LightlessYellow")); ImGuiHelpers.ScaledDummy(0.25f); } @@ -203,7 +201,7 @@ namespace LightlessSync.UI else ImGui.PushStyleColor(ImGuiCol.Button, UIColors.Get("PairBlue")); - if (isOnCooldown) + if (isOnCooldown || !_broadcastService.IsLightFinderAvailable) ImGui.BeginDisabled(); string buttonText = isBroadcasting ? "Disable Lightfinder" : "Enable Lightfinder"; @@ -213,7 +211,7 @@ namespace LightlessSync.UI _broadcastService.ToggleBroadcast(); } - if (isOnCooldown) + if (isOnCooldown || !_broadcastService.IsLightFinderAvailable) ImGui.EndDisabled(); ImGui.PopStyleColor(); @@ -316,7 +314,7 @@ namespace LightlessSync.UI { ImGui.Text("Broadcast Cache"); - if (ImGui.BeginTable("##BroadcastCacheTable", 4, ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders | ImGuiTableFlags.ScrollY, new Vector2(-1, 200f))) + if (ImGui.BeginTable("##BroadcastCacheTable", 4, ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders | ImGuiTableFlags.ScrollY, new Vector2(-1, 225f))) { ImGui.TableSetupColumn("CID", ImGuiTableColumnFlags.WidthStretch); ImGui.TableSetupColumn("IsBroadcasting", ImGuiTableColumnFlags.WidthStretch); @@ -326,7 +324,7 @@ namespace LightlessSync.UI var now = DateTime.UtcNow; - foreach (var (cid, entry) in _nameplateService.BroadcastCache) + foreach (var (cid, entry) in _broadcastScannerService.BroadcastCache) { ImGui.TableNextRow(); diff --git a/LightlessSync/UI/SyncshellFinderUI.cs b/LightlessSync/UI/SyncshellFinderUI.cs index cd6983c..6f4050e 100644 --- a/LightlessSync/UI/SyncshellFinderUI.cs +++ b/LightlessSync/UI/SyncshellFinderUI.cs @@ -23,7 +23,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase private readonly LightlessConfigService _configService; private readonly BroadcastService _broadcastService; private readonly UiSharedService _uiSharedService; - private readonly NameplateService _nameplateService; + private readonly BroadcastScannerService _broadcastScannerService; private readonly List _nearbySyncshells = new(); private int _selectedNearbyIndex = -1; @@ -40,23 +40,24 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase LightlessConfigService configService, UiSharedService uiShared, ApiController apiController, - NameplateService nameplateService + BroadcastScannerService broadcastScannerService ) : base(logger, mediator, "Shellfinder###LightlessSyncshellFinderUI", performanceCollectorService) { _broadcastService = broadcastService; _uiSharedService = uiShared; _configService = configService; _apiController = apiController; - _nameplateService = nameplateService; + _broadcastScannerService = broadcastScannerService; IsOpen = false; SizeConstraints = new() { MinimumSize = new(600, 400), - MaximumSize = new(600, 400) + MaximumSize = new(600, 550) }; Mediator.Subscribe(this, async _ => await RefreshSyncshellsAsync()); + Mediator.Subscribe(this, async _ => await RefreshSyncshellsAsync()); } public override async void OnOpen() @@ -222,7 +223,7 @@ public class SyncshellFinderUI : WindowMediatorSubscriberBase private async Task RefreshSyncshellsAsync() { - var syncshellBroadcasts = _nameplateService.GetActiveSyncshellBroadcasts(); + var syncshellBroadcasts = _broadcastScannerService.GetActiveSyncshellBroadcasts(); if (syncshellBroadcasts.Count == 0) { diff --git a/LightlessSync/UI/UIColors.cs b/LightlessSync/UI/UIColors.cs index 8fceb33..3bd288f 100644 --- a/LightlessSync/UI/UIColors.cs +++ b/LightlessSync/UI/UIColors.cs @@ -13,6 +13,7 @@ namespace LightlessSync.UI { "LightlessPurpleDefault", "#9375d1" }, { "ButtonDefault", "#323232" }, + { "FullBlack", "#000000" }, { "LightlessBlue", "#a6c2ff" }, { "LightlessYellow", "#ffe97a" },