diff --git a/LightlessSync/Services/BroadcastScanningService.cs b/LightlessSync/Services/BroadcastScanningService.cs index 313abb8..4619a5e 100644 --- a/LightlessSync/Services/BroadcastScanningService.cs +++ b/LightlessSync/Services/BroadcastScanningService.cs @@ -28,11 +28,14 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos private readonly CancellationTokenSource _cleanupCts = new(); private Task? _cleanupTask; + private int _checkEveryFrames = 20; private int _frameCounter = 0; private int _lookupsThisFrame = 0; - private const int MaxLookupsPerFrame = 15; + private const int MaxLookupsPerFrame = 30; private const int MaxQueueSize = 100; + private volatile bool _batchRunning = false; + public IReadOnlyDictionary BroadcastCache => _broadcastCache; public readonly record struct BroadcastEntry(bool IsBroadcasting, DateTime ExpiryTime, string? GID); @@ -85,7 +88,7 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos _lookupQueue.Enqueue(cid); } - if (_frameCounter % 2 == 0 && _lookupQueue.Count > 0) + if (_frameCounter % _checkEveryFrames == 0 && _lookupQueue.Count > 0) { var cidsToLookup = new List(); while (_lookupQueue.Count > 0 && _lookupsThisFrame < MaxLookupsPerFrame) @@ -96,8 +99,11 @@ public class BroadcastScannerService : DisposableMediatorSubscriberBase, IDispos _lookupsThisFrame++; } - if (cidsToLookup.Count > 0) - _ = BatchUpdateBroadcastCacheAsync(cidsToLookup); + if (cidsToLookup.Count > 0 && !_batchRunning) + { + _batchRunning = true; + _ = BatchUpdateBroadcastCacheAsync(cidsToLookup).ContinueWith(_ => _batchRunning = false); + } } } diff --git a/LightlessSync/UI/CompactUI.cs b/LightlessSync/UI/CompactUI.cs index cd920b8..5a7439a 100644 --- a/LightlessSync/UI/CompactUI.cs +++ b/LightlessSync/UI/CompactUI.cs @@ -139,89 +139,6 @@ public class CompactUi : WindowMediatorSubscriberBase ImGui.EndTooltip(); } }, - new TitleBarButton() - { - Icon = FontAwesomeIcon.TowerCell, - Click = (_) => - { - Mediator.Publish(new UiToggleMessage(typeof(BroadcastUI))); - }, - IconOffset = new(2, 1), - - ShowTooltip = () => - { - ImGui.BeginTooltip(); - - ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("PairBlue")); - ImGui.Text("Lightfinder"); - ImGui.PopStyleColor(); - - ImGui.Text("This lets other Lightless users know you use Lightless."); - ImGui.Text("By enabling this, the server will allow other people to see that you are using Lightless."); - ImGui.Text("When disabled, pairing is still possible but both parties need to mutually send each other requests, receiving party will not be notified about the request unless the pairing is complete."); - ImGui.Text("At no point ever, even when Lightfinder is active that any Lightless data is getting sent to other people (including ID's), the server keeps this to itself."); - ImGui.Text("You can request to pair by right-clicking any (not yourself) character and using 'Send Pair Request'."); - - ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed")); - ImGui.Text("Use it only when you want to be visible."); - ImGui.PopStyleColor(); - - ImGuiHelpers.ScaledDummy(0.2f); - _uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f); - - if (_configService.Current.BroadcastEnabled) - { - ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("LightlessGreen")); - ImGui.Text("The Lightfinder calls, and somewhere, a soul may answer."); // cringe.. - ImGui.PopStyleColor(); - - var ttl = _broadcastService.RemainingTtl; - if (ttl is { } remaining && remaining > TimeSpan.Zero) - { - ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("LightlessYellow")); - ImGui.Text($"Still shining, for {remaining:hh\\:mm\\:ss}"); - ImGui.PopStyleColor(); - } - else - { - ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed")); - ImGui.Text("The Lightfinder's light wanes, but not in vain."); // cringe.. - ImGui.PopStyleColor(); - } - } - else - { - ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed")); - ImGui.Text("The Lightfinder rests, waiting to shine again."); // cringe.. - ImGui.PopStyleColor(); - } - - var cooldown = _broadcastService.RemainingCooldown; - if (cooldown is { } cd) - { - ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed")); - ImGui.Text($"The Lightfinder gathers its strength... ({Math.Ceiling(cd.TotalSeconds)}s)"); - ImGui.PopStyleColor(); - } - - ImGui.EndTooltip(); - } - }, - new TitleBarButton() - { - Icon = FontAwesomeIcon.NetworkWired, - Click = (msg) => - { - Mediator.Publish(new UiToggleMessage(typeof(SyncshellFinderUI))); - }, - IconOffset = new(2,1), - ShowTooltip = () => - { - ImGui.BeginTooltip(); - ImGui.Text("Nearby Syncshells"); - ImGui.EndTooltip(); - } - } }; _drawFolders = [.. GetDrawFolders()]; @@ -518,18 +435,102 @@ public class CompactUi : WindowMediatorSubscriberBase //Getting information of character and triangles threshold to show overlimit status in UID bar. _cachedAnalysis = _characterAnalyzer.LastAnalysis.DeepClone(); + Vector2 uidTextSize, iconSize; using (_uiSharedService.UidFont.Push()) + uidTextSize = ImGui.CalcTextSize(uidText); + + using (_uiSharedService.IconFont.Push()) + iconSize = ImGui.CalcTextSize(FontAwesomeIcon.PersonCirclePlus.ToIconString()); + + float contentWidth = ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X; + float uidStartX = (contentWidth - uidTextSize.X) / 2f; + float cursorY = ImGui.GetCursorPosY(); + + if (_configService.Current.BroadcastEnabled) { - var uidTextSize = ImGui.CalcTextSize(uidText); - ImGui.SetCursorPosX((ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X) / 2 - (uidTextSize.X / 2)); - ImGui.TextColored(GetUidColor(), uidText); + float iconYOffset = (uidTextSize.Y - iconSize.Y) * 0.5f; + var buttonSize = new Vector2(iconSize.X, uidTextSize.Y); + + ImGui.SetCursorPos(new Vector2(ImGui.GetStyle().ItemSpacing.X + 5f, cursorY)); + ImGui.InvisibleButton("BroadcastIcon", buttonSize); + + var iconPos = ImGui.GetItemRectMin() + new Vector2(0f, iconYOffset); + using (_uiSharedService.IconFont.Push()) + ImGui.GetWindowDrawList().AddText(iconPos, ImGui.GetColorU32(UIColors.Get("LightlessGreen")), FontAwesomeIcon.PersonCirclePlus.ToIconString()); + + + if (ImGui.IsItemHovered()) + { + ImGui.BeginTooltip(); + + ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("PairBlue")); + ImGui.Text("Lightfinder"); + ImGui.PopStyleColor(); + + ImGui.Text("This lets other Lightless users know you use Lightless."); + ImGui.Text("By enabling this, the server will allow other people to see that you are using Lightless."); + ImGui.Text("When disabled, pairing is still possible but both parties need to mutually send each other requests, receiving party will not be notified about the request unless the pairing is complete."); + ImGui.Text("At no point ever, even when Lightfinder is active that any Lightless data is getting sent to other people (including ID's), the server keeps this to itself."); + ImGui.Text("You can request to pair by right-clicking any (not yourself) character and using 'Send Pair Request'."); + + ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed")); + ImGui.Text("Use it only when you want to be visible."); + ImGui.PopStyleColor(); + + ImGuiHelpers.ScaledDummy(0.2f); + _uiSharedService.ColoredSeparator(UIColors.Get("LightlessPurple"), 2f); + + if (_configService.Current.BroadcastEnabled) + { + ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("LightlessGreen")); + ImGui.Text("The Lightfinder calls, and somewhere, a soul may answer."); // cringe.. + ImGui.PopStyleColor(); + + var ttl = _broadcastService.RemainingTtl; + if (ttl is { } remaining && remaining > TimeSpan.Zero) + { + ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("LightlessYellow")); + ImGui.Text($"Still shining, for {remaining:hh\\:mm\\:ss}"); + ImGui.PopStyleColor(); + } + else + { + ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed")); + ImGui.Text("The Lightfinder's light wanes, but not in vain."); // cringe.. + ImGui.PopStyleColor(); + } + } + else + { + ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed")); + ImGui.Text("The Lightfinder rests, waiting to shine again."); // cringe.. + ImGui.PopStyleColor(); + } + + var cooldown = _broadcastService.RemainingCooldown; + if (cooldown is { } cd) + { + ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("DimRed")); + ImGui.Text($"The Lightfinder gathers its strength... ({Math.Ceiling(cd.TotalSeconds)}s)"); + ImGui.PopStyleColor(); + } + + ImGui.EndTooltip(); + } + + if (ImGui.IsItemClicked()) + _lightlessMediator.Publish(new UiToggleMessage(typeof(BroadcastUI))); } - UiSharedService.AttachToolTip("Click to copy"); - if (ImGui.IsItemClicked()) + ImGui.SetCursorPosY(cursorY); + ImGui.SetCursorPosX(uidStartX); + using (_uiSharedService.UidFont.Push()) { - ImGui.SetClipboardText(uidText); + ImGui.TextColored(GetUidColor(), uidText); + if (ImGui.IsItemClicked()) + ImGui.SetClipboardText(uidText); } + UiSharedService.AttachToolTip("Click to copy"); if (_cachedAnalysis != null && _apiController.ServerState is ServerState.Connected) { diff --git a/LightlessSync/UI/TopTabMenu.cs b/LightlessSync/UI/TopTabMenu.cs index f5269a7..c7f5035 100644 --- a/LightlessSync/UI/TopTabMenu.cs +++ b/LightlessSync/UI/TopTabMenu.cs @@ -39,7 +39,7 @@ public class TopTabMenu None, Individual, Syncshell, - Filter, + Lightfinder, UserConfig } @@ -60,11 +60,6 @@ public class TopTabMenu { get => _selectedTab; set { - if (_selectedTab == SelectedTab.Filter && value != SelectedTab.Filter) - { - Filter = string.Empty; - } - _selectedTab = value; } } @@ -76,7 +71,7 @@ public class TopTabMenu var buttonY = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Pause).Y; var buttonSize = new Vector2(buttonX, buttonY); var drawList = ImGui.GetWindowDrawList(); - var underlineColor = ImGui.GetColorU32(ImGuiCol.Separator); + var underlineColor = ImGui.GetColorU32(UIColors.Get("LightlessPurpleActive")); // ImGui.GetColorU32(ImGuiCol.Separator); var btncolor = ImRaii.PushColor(ImGuiCol.Button, ImGui.ColorConvertFloat4ToU32(new(0, 0, 0, 0))); ImGuiHelpers.ScaledDummy(spacing.Y / 2f); @@ -117,19 +112,19 @@ public class TopTabMenu using (ImRaii.PushFont(UiBuilder.IconFont)) { var x = ImGui.GetCursorScreenPos(); - if (ImGui.Button(FontAwesomeIcon.Filter.ToIconString(), buttonSize)) + if (ImGui.Button(FontAwesomeIcon.Compass.ToIconString(), buttonSize)) { - TabSelection = TabSelection == SelectedTab.Filter ? SelectedTab.None : SelectedTab.Filter; + TabSelection = TabSelection == SelectedTab.Lightfinder ? SelectedTab.None : SelectedTab.Lightfinder; } ImGui.SameLine(); var xAfter = ImGui.GetCursorScreenPos(); - if (TabSelection == SelectedTab.Filter) + if (TabSelection == SelectedTab.Lightfinder) drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y }, xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X }, underlineColor, 2); } - UiSharedService.AttachToolTip("Filter"); + UiSharedService.AttachToolTip("Lightfinder"); ImGui.SameLine(); using (ImRaii.PushFont(UiBuilder.IconFont)) @@ -164,9 +159,9 @@ public class TopTabMenu DrawSyncshellMenu(availableWidth, spacing.X); DrawGlobalSyncshellButtons(availableWidth, spacing.X); } - else if (TabSelection == SelectedTab.Filter) + else if (TabSelection == SelectedTab.Lightfinder) { - DrawFilter(availableWidth, spacing.X); + DrawLightfinderMenu(availableWidth, spacing.X); } else if (TabSelection == SelectedTab.UserConfig) { @@ -175,6 +170,8 @@ public class TopTabMenu if (TabSelection != SelectedTab.None) ImGuiHelpers.ScaledDummy(3f); ImGui.Separator(); + + DrawFilter(availableWidth, spacing.X); } private void DrawAddPair(float availableXWidth, float spacingX) @@ -483,6 +480,23 @@ public class TopTabMenu } } + private void DrawLightfinderMenu(float availableWidth, float spacingX) + { + var buttonX = (availableWidth - (spacingX)) / 2f; + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.PersonCirclePlus, "Lightfinder", buttonX, center: true)) + { + _lightlessMediator.Publish(new UiToggleMessage(typeof(BroadcastUI))); + } + + ImGui.SameLine(); + + if (_uiSharedService.IconTextButton(FontAwesomeIcon.Globe, "Syncshell Finder", buttonX, center: true)) + { + _lightlessMediator.Publish(new UiToggleMessage(typeof(SyncshellFinderUI))); + } + } + private void DrawUserConfig(float availableWidth, float spacingX) { var buttonX = (availableWidth - spacingX) / 2f; diff --git a/LightlessSync/UI/UISharedService.cs b/LightlessSync/UI/UISharedService.cs index 9a45d15..e4753dc 100644 --- a/LightlessSync/UI/UISharedService.cs +++ b/LightlessSync/UI/UISharedService.cs @@ -1144,11 +1144,11 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase IconText(icon, color == null ? ImGui.GetColorU32(ImGuiCol.Text) : ImGui.GetColorU32(color.Value)); } - public bool IconTextButton(FontAwesomeIcon icon, string text, float? width = null, bool isInPopup = false) + public bool IconTextButton(FontAwesomeIcon icon, string text, float? width = null, bool isInPopup = false, bool? center = null) { return IconTextButtonInternal(icon, text, isInPopup ? ColorHelpers.RgbaUintToVector4(ImGui.GetColorU32(ImGuiCol.PopupBg)) : null, - width <= 0 ? null : width); + width <= 0 ? null : width, center); } public IDalamudTextureWrap LoadImage(byte[] imageData) @@ -1212,7 +1212,7 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase ImGui.TextUnformatted(text); } - private bool IconTextButtonInternal(FontAwesomeIcon icon, string text, Vector4? defaultColor = null, float? width = null) + private bool IconTextButtonInternal(FontAwesomeIcon icon, string text, Vector4? defaultColor = null, float? width = null, bool? center = null) { int num = 0; if (defaultColor.HasValue) @@ -1222,19 +1222,35 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase } ImGui.PushID(text); + Vector2 vector; using (IconFont.Push()) vector = ImGui.CalcTextSize(icon.ToIconString()); + Vector2 vector2 = ImGui.CalcTextSize(text); ImDrawListPtr windowDrawList = ImGui.GetWindowDrawList(); Vector2 cursorScreenPos = ImGui.GetCursorScreenPos(); float num2 = 3f * ImGuiHelpers.GlobalScale; - float x = width ?? vector.X + vector2.X + ImGui.GetStyle().FramePadding.X * 2f + num2; + + float totalTextWidth = vector.X + num2 + vector2.X; + float x = width ?? totalTextWidth + ImGui.GetStyle().FramePadding.X * 2f; float frameHeight = ImGui.GetFrameHeight(); + bool result = ImGui.Button(string.Empty, new Vector2(x, frameHeight)); - Vector2 pos = new Vector2(cursorScreenPos.X + ImGui.GetStyle().FramePadding.X, cursorScreenPos.Y + ImGui.GetStyle().FramePadding.Y); + + bool shouldCenter = center == true; + + Vector2 pos = shouldCenter + ? new Vector2( + cursorScreenPos.X + (x - totalTextWidth) / 2f, + cursorScreenPos.Y + (frameHeight - vector.Y) / 2f) + : new Vector2( + cursorScreenPos.X + ImGui.GetStyle().FramePadding.X, + cursorScreenPos.Y + ImGui.GetStyle().FramePadding.Y); + using (IconFont.Push()) windowDrawList.AddText(pos, ImGui.GetColorU32(ImGuiCol.Text), icon.ToIconString()); + Vector2 pos2 = new Vector2(pos.X + vector.X + num2, cursorScreenPos.Y + ImGui.GetStyle().FramePadding.Y); windowDrawList.AddText(pos2, ImGui.GetColorU32(ImGuiCol.Text), text); ImGui.PopID();