Compare commits

...

5 Commits

Author SHA1 Message Date
defnotken
6f2213171c dev bump
All checks were successful
Tag and Release Lightless / tag-and-release (push) Successful in 34s
2025-10-21 13:47:26 -05:00
defnotken
da47d3be01 Merge branch '1.12.3' into dev 2025-10-21 13:46:41 -05:00
5d2c58bf3e Merge pull request 'some caching stuff and bug fixes' (#71) from some-garbage-optimization into 1.12.3
Reviewed-on: #71
2025-10-21 20:46:15 +02:00
azyges
6bb00c50d8 improve logging fallback 2025-10-22 03:33:51 +09:00
azyges
1a89c2caee some caching stuff and bug fixes 2025-10-22 03:20:13 +09:00
7 changed files with 337 additions and 120 deletions

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<Authors></Authors>
<Company></Company>
<Version>1.12.2.7</Version>
<Version>1.12.2.8</Version>
<Description></Description>
<Copyright></Copyright>
<PackageProjectUrl>https://github.com/Light-Public-Syncshells/LightlessClient</PackageProjectUrl>

View File

@@ -6,7 +6,11 @@ using LightlessSync.UI;
using LightlessSync.Utils;
using Lumina.Data.Files;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace LightlessSync.Services;
public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable
@@ -16,6 +20,7 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable
private CancellationTokenSource? _analysisCts;
private CancellationTokenSource _baseAnalysisCts = new();
private string _lastDataHash = string.Empty;
private CharacterAnalysisSummary _latestSummary = CharacterAnalysisSummary.Empty;
public CharacterAnalyzer(ILogger<CharacterAnalyzer> logger, LightlessMediator mediator, FileCacheManager fileCacheManager, XivDataAnalyzer modelAnalyzer)
: base(logger, mediator)
@@ -34,6 +39,7 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable
public bool IsAnalysisRunning => _analysisCts != null;
public int TotalFiles { get; internal set; }
internal Dictionary<ObjectKind, Dictionary<string, FileDataEntry>> LastAnalysis { get; } = [];
public CharacterAnalysisSummary LatestSummary => _latestSummary;
public void CancelAnalyze()
{
@@ -80,6 +86,8 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable
}
}
RecalculateSummary();
Mediator.Publish(new CharacterDataAnalyzedMessage());
_analysisCts.CancelDispose();
@@ -137,11 +145,39 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable
LastAnalysis[obj.Key] = data;
}
RecalculateSummary();
Mediator.Publish(new CharacterDataAnalyzedMessage());
_lastDataHash = charaData.DataHash.Value;
}
private void RecalculateSummary()
{
var builder = ImmutableDictionary.CreateBuilder<ObjectKind, CharacterAnalysisObjectSummary>();
foreach (var (objectKind, entries) in LastAnalysis)
{
long totalTriangles = 0;
long texOriginalBytes = 0;
long texCompressedBytes = 0;
foreach (var entry in entries.Values)
{
totalTriangles += entry.Triangles;
if (string.Equals(entry.FileType, "tex", StringComparison.OrdinalIgnoreCase))
{
texOriginalBytes += entry.OriginalSize;
texCompressedBytes += entry.CompressedSize;
}
}
builder[objectKind] = new CharacterAnalysisObjectSummary(entries.Count, totalTriangles, texOriginalBytes, texCompressedBytes);
}
_latestSummary = new CharacterAnalysisSummary(builder.ToImmutable());
}
private void PrintAnalysis()
{
if (LastAnalysis.Count == 0) return;
@@ -232,4 +268,24 @@ public sealed class CharacterAnalyzer : MediatorSubscriberBase, IDisposable
}
});
}
}
public readonly record struct CharacterAnalysisObjectSummary(int EntryCount, long TotalTriangles, long TexOriginalBytes, long TexCompressedBytes)
{
public bool HasEntries => EntryCount > 0;
}
public sealed class CharacterAnalysisSummary
{
public static CharacterAnalysisSummary Empty { get; } =
new(ImmutableDictionary<ObjectKind, CharacterAnalysisObjectSummary>.Empty);
internal CharacterAnalysisSummary(IImmutableDictionary<ObjectKind, CharacterAnalysisObjectSummary> objects)
{
Objects = objects;
}
public IImmutableDictionary<ObjectKind, CharacterAnalysisObjectSummary> Objects { get; }
public bool HasData => Objects.Any(kvp => kvp.Value.HasEntries);
}

View File

@@ -56,7 +56,6 @@ public class CompactUi : WindowMediatorSubscriberBase
private readonly BroadcastService _broadcastService;
private List<IDrawFolder> _drawFolders;
private Dictionary<ObjectKind, Dictionary<string, CharacterAnalyzer.FileDataEntry>>? _cachedAnalysis;
private Pair? _lastAddedUser;
private string _lastAddedUserComment = string.Empty;
private Vector2 _lastPosition = Vector2.One;
@@ -382,15 +381,26 @@ public class CompactUi : WindowMediatorSubscriberBase
_uiSharedService.IconText(FontAwesomeIcon.Upload);
ImGui.SameLine(35 * ImGuiHelpers.GlobalScale);
if (currentUploads.Any())
if (currentUploads.Count > 0)
{
var totalUploads = currentUploads.Count;
int totalUploads = currentUploads.Count;
int doneUploads = 0;
long totalUploaded = 0;
long totalToUpload = 0;
var doneUploads = currentUploads.Count(c => c.IsTransferred);
var activeUploads = currentUploads.Count(c => !c.IsTransferred);
foreach (var upload in currentUploads)
{
if (upload.IsTransferred)
{
doneUploads++;
}
totalUploaded += upload.Transferred;
totalToUpload += upload.Total;
}
int activeUploads = totalUploads - doneUploads;
var uploadSlotLimit = Math.Clamp(_configService.Current.ParallelUploads, 1, 8);
var totalUploaded = currentUploads.Sum(c => c.Transferred);
var totalToUpload = currentUploads.Sum(c => c.Total);
ImGui.TextUnformatted($"{doneUploads}/{totalUploads} (slots {activeUploads}/{uploadSlotLimit})");
var uploadText = $"({UiSharedService.ByteToString(totalUploaded)}/{UiSharedService.ByteToString(totalToUpload)})";
@@ -405,17 +415,17 @@ public class CompactUi : WindowMediatorSubscriberBase
ImGui.TextUnformatted("No uploads in progress");
}
var currentDownloads = BuildCurrentDownloadSnapshot();
var downloadSummary = GetDownloadSummary();
ImGui.AlignTextToFramePadding();
_uiSharedService.IconText(FontAwesomeIcon.Download);
ImGui.SameLine(35 * ImGuiHelpers.GlobalScale);
if (currentDownloads.Any())
if (downloadSummary.HasDownloads)
{
var totalDownloads = currentDownloads.Sum(c => c.TotalFiles);
var doneDownloads = currentDownloads.Sum(c => c.TransferredFiles);
var totalDownloaded = currentDownloads.Sum(c => c.TransferredBytes);
var totalToDownload = currentDownloads.Sum(c => c.TotalBytes);
var totalDownloads = downloadSummary.TotalFiles;
var doneDownloads = downloadSummary.TransferredFiles;
var totalDownloaded = downloadSummary.TransferredBytes;
var totalToDownload = downloadSummary.TotalBytes;
ImGui.TextUnformatted($"{doneDownloads}/{totalDownloads}");
var downloadText =
@@ -433,27 +443,35 @@ public class CompactUi : WindowMediatorSubscriberBase
}
private List<FileDownloadStatus> BuildCurrentDownloadSnapshot()
private DownloadSummary GetDownloadSummary()
{
List<FileDownloadStatus> snapshot = new();
long totalBytes = 0;
long transferredBytes = 0;
int totalFiles = 0;
int transferredFiles = 0;
foreach (var kvp in _currentDownloads.ToArray())
{
var value = kvp.Value;
if (value == null || value.Count == 0)
if (kvp.Value is not { Count: > 0 } statuses)
{
continue;
try
{
snapshot.AddRange(value.Values.ToArray());
}
catch (System.ArgumentException)
foreach (var status in statuses.Values)
{
// skibidi
totalBytes += status.TotalBytes;
transferredBytes += status.TransferredBytes;
totalFiles += status.TotalFiles;
transferredFiles += status.TransferredFiles;
}
}
return snapshot;
return new DownloadSummary(totalFiles, transferredFiles, transferredBytes, totalBytes);
}
private readonly record struct DownloadSummary(int TotalFiles, int TransferredFiles, long TransferredBytes, long TotalBytes)
{
public bool HasDownloads => TotalFiles > 0 || TotalBytes > 0;
}
private void DrawUIDHeader()
@@ -480,7 +498,7 @@ public class CompactUi : WindowMediatorSubscriberBase
}
//Getting information of character and triangles threshold to show overlimit status in UID bar.
_cachedAnalysis = _characterAnalyzer.LastAnalysis.DeepClone();
var analysisSummary = _characterAnalyzer.LatestSummary;
Vector2 uidTextSize, iconSize;
using (_uiSharedService.UidFont.Push())
@@ -509,6 +527,7 @@ public class CompactUi : WindowMediatorSubscriberBase
if (ImGui.IsItemHovered())
{
ImGui.BeginTooltip();
ImGui.PushTextWrapPos(ImGui.GetFontSize() * 32f);
ImGui.PushStyleColor(ImGuiCol.Text, UIColors.Get("PairBlue"));
ImGui.Text("Lightfinder");
@@ -556,6 +575,7 @@ public class CompactUi : WindowMediatorSubscriberBase
ImGui.PopStyleColor();
}
ImGui.PopTextWrapPos();
ImGui.EndTooltip();
}
@@ -574,7 +594,7 @@ public class CompactUi : WindowMediatorSubscriberBase
var seString = SeStringUtils.BuildFormattedPlayerName(uidText, vanityTextColor, vanityGlowColor);
var cursorPos = ImGui.GetCursorScreenPos();
var fontPtr = ImGui.GetFont();
SeStringUtils.RenderSeStringWithHitbox(seString, cursorPos, fontPtr);
SeStringUtils.RenderSeStringWithHitbox(seString, cursorPos, fontPtr, "uid-header");
}
else
{
@@ -591,56 +611,40 @@ public class CompactUi : WindowMediatorSubscriberBase
UiSharedService.AttachToolTip("Click to copy");
if (_cachedAnalysis != null && _apiController.ServerState is ServerState.Connected)
if (_apiController.ServerState is ServerState.Connected && analysisSummary.HasData)
{
var firstEntry = _cachedAnalysis.FirstOrDefault();
var valueDict = firstEntry.Value;
if (valueDict != null && valueDict.Count > 0)
var objectSummary = analysisSummary.Objects.Values.FirstOrDefault(summary => summary.HasEntries);
if (objectSummary.HasEntries)
{
var groupedfiles = valueDict
.Select(v => v.Value)
.Where(v => v != null)
.GroupBy(f => f.FileType, StringComparer.Ordinal)
.OrderBy(k => k.Key, StringComparer.Ordinal)
.ToList();
var actualVramUsage = objectSummary.TexOriginalBytes;
var actualTriCount = objectSummary.TotalTriangles;
var actualTriCount = valueDict
.Select(v => v.Value)
.Where(v => v != null)
.Sum(f => f.Triangles);
var isOverVRAMUsage = _playerPerformanceConfig.Current.VRAMSizeWarningThresholdMiB * 1024 * 1024 < actualVramUsage;
var isOverTriHold = actualTriCount > (_playerPerformanceConfig.Current.TrisWarningThresholdThousands * 1000);
if (groupedfiles != null)
if ((isOverTriHold || isOverVRAMUsage) && _playerPerformanceConfig.Current.WarnOnExceedingThresholds)
{
//Checking of VRAM threshhold
var texGroup = groupedfiles.SingleOrDefault(v => string.Equals(v.Key, "tex", StringComparison.Ordinal));
var actualVramUsage = texGroup != null ? texGroup.Sum(f => f.OriginalSize) : 0L;
var isOverVRAMUsage = _playerPerformanceConfig.Current.VRAMSizeWarningThresholdMiB * 1024 * 1024 < actualVramUsage;
var isOverTriHold = actualTriCount > (_playerPerformanceConfig.Current.TrisWarningThresholdThousands * 1000);
ImGui.SameLine();
ImGui.SetCursorPosY(cursorY + 15f);
_uiSharedService.IconText(FontAwesomeIcon.ExclamationTriangle, UIColors.Get("LightlessYellow"));
if ((isOverTriHold || isOverVRAMUsage) && _playerPerformanceConfig.Current.WarnOnExceedingThresholds)
string warningMessage = "";
if (isOverTriHold)
{
ImGui.SameLine();
ImGui.SetCursorPosY(cursorY + 15f);
_uiSharedService.IconText(FontAwesomeIcon.ExclamationTriangle, UIColors.Get("LightlessYellow"));
warningMessage += $"You exceed your own triangles threshold by " +
$"{actualTriCount - _playerPerformanceConfig.Current.TrisWarningThresholdThousands * 1000} triangles.";
warningMessage += Environment.NewLine;
string warningMessage = "";
if (isOverTriHold)
{
warningMessage += $"You exceed your own triangles threshold by " +
$"{actualTriCount - _playerPerformanceConfig.Current.TrisWarningThresholdThousands * 1000} triangles.";
warningMessage += Environment.NewLine;
}
if (isOverVRAMUsage)
{
warningMessage += $"You exceed your own VRAM threshold by " +
$"{UiSharedService.ByteToString(actualVramUsage - (_playerPerformanceConfig.Current.VRAMSizeWarningThresholdMiB * 1024 * 1024))}.";
}
UiSharedService.AttachToolTip(warningMessage);
if (ImGui.IsItemClicked())
{
_lightlessMediator.Publish(new UiToggleMessage(typeof(DataAnalysisUi)));
}
}
if (isOverVRAMUsage)
{
warningMessage += $"You exceed your own VRAM threshold by " +
$"{UiSharedService.ByteToString(actualVramUsage - (_playerPerformanceConfig.Current.VRAMSizeWarningThresholdMiB * 1024 * 1024))}.";
}
UiSharedService.AttachToolTip(warningMessage);
if (ImGui.IsItemClicked())
{
_lightlessMediator.Publish(new UiToggleMessage(typeof(DataAnalysisUi)));
}
}
}
@@ -663,7 +667,7 @@ public class CompactUi : WindowMediatorSubscriberBase
var seString = SeStringUtils.BuildFormattedPlayerName(_apiController.UID, vanityTextColor, vanityGlowColor);
var cursorPos = ImGui.GetCursorScreenPos();
var fontPtr = ImGui.GetFont();
SeStringUtils.RenderSeStringWithHitbox(seString, cursorPos, fontPtr);
SeStringUtils.RenderSeStringWithHitbox(seString, cursorPos, fontPtr, "uid-footer");
}
else
{
@@ -921,4 +925,4 @@ public class CompactUi : WindowMediatorSubscriberBase
_wasOpen = IsOpen;
IsOpen = false;
}
}
}

View File

@@ -2,6 +2,7 @@
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using LightlessSync.API.Data.Enum;
using LightlessSync.API.Data.Extensions;
using LightlessSync.API.Dto.Group;
using LightlessSync.API.Dto.User;
@@ -13,6 +14,9 @@ using LightlessSync.Services.ServerConfiguration;
using LightlessSync.UI.Handlers;
using LightlessSync.Utils;
using LightlessSync.WebAPI;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Text;
namespace LightlessSync.UI.Components;
@@ -32,6 +36,8 @@ public class DrawUserPair
private readonly CharaDataManager _charaDataManager;
private float _menuWidth = -1;
private bool _wasHovered = false;
private TooltipSnapshot _tooltipSnapshot = TooltipSnapshot.Empty;
private string _cachedTooltip = string.Empty;
public DrawUserPair(string id, Pair entry, List<GroupFullInfoDto> syncedGroups,
GroupFullInfoDto? currentGroup,
@@ -190,15 +196,12 @@ public class DrawUserPair
private void DrawLeftSide()
{
string userPairText = string.Empty;
ImGui.AlignTextToFramePadding();
if (_pair.IsPaused)
{
using var _ = ImRaii.PushColor(ImGuiCol.Text, UIColors.Get("LightlessYellow"));
_uiSharedService.IconText(FontAwesomeIcon.PauseCircle);
userPairText = _pair.UserData.AliasOrUID + " is paused";
}
else if (!_pair.IsOnline)
{
@@ -207,12 +210,10 @@ public class DrawUserPair
? FontAwesomeIcon.ArrowsLeftRight
: (_pair.IndividualPairStatus == API.Data.Enum.IndividualPairStatus.Bidirectional
? FontAwesomeIcon.User : FontAwesomeIcon.Users));
userPairText = _pair.UserData.AliasOrUID + " is offline";
}
else if (_pair.IsVisible)
{
_uiSharedService.IconText(FontAwesomeIcon.Eye, UIColors.Get("LightlessBlue"));
userPairText = _pair.UserData.AliasOrUID + " is visible: " + _pair.PlayerName + Environment.NewLine + "Click to target this player";
if (ImGui.IsItemClicked())
{
_mediator.Publish(new TargetPairMessage(_pair));
@@ -223,46 +224,9 @@ public class DrawUserPair
using var _ = ImRaii.PushColor(ImGuiCol.Text, UIColors.Get("PairBlue"));
_uiSharedService.IconText(_pair.IndividualPairStatus == API.Data.Enum.IndividualPairStatus.Bidirectional
? FontAwesomeIcon.User : FontAwesomeIcon.Users);
userPairText = _pair.UserData.AliasOrUID + " is online";
}
if (_pair.IndividualPairStatus == API.Data.Enum.IndividualPairStatus.OneSided)
{
userPairText += UiSharedService.TooltipSeparator + "User has not added you back";
}
else if (_pair.IndividualPairStatus == API.Data.Enum.IndividualPairStatus.Bidirectional)
{
userPairText += UiSharedService.TooltipSeparator + "You are directly Paired";
}
if (_pair.LastAppliedDataBytes >= 0)
{
userPairText += UiSharedService.TooltipSeparator;
userPairText += ((!_pair.IsPaired) ? "(Last) " : string.Empty) + "Mods Info" + Environment.NewLine;
userPairText += "Files Size: " + UiSharedService.ByteToString(_pair.LastAppliedDataBytes, true);
if (_pair.LastAppliedApproximateVRAMBytes >= 0)
{
userPairText += Environment.NewLine + "Approx. VRAM Usage: " + UiSharedService.ByteToString(_pair.LastAppliedApproximateVRAMBytes, true);
}
if (_pair.LastAppliedDataTris >= 0)
{
userPairText += Environment.NewLine + "Approx. Triangle Count (excl. Vanilla): "
+ (_pair.LastAppliedDataTris > 1000 ? (_pair.LastAppliedDataTris / 1000d).ToString("0.0'k'") : _pair.LastAppliedDataTris);
}
}
if (_syncedGroups.Any())
{
userPairText += UiSharedService.TooltipSeparator + string.Join(Environment.NewLine,
_syncedGroups.Select(g =>
{
var groupNote = _serverConfigurationManager.GetNoteForGid(g.GID);
var groupString = string.IsNullOrEmpty(groupNote) ? g.GroupAliasOrGID : $"{groupNote} ({g.GroupAliasOrGID})";
return "Paired through " + groupString;
}));
}
UiSharedService.AttachToolTip(userPairText);
UiSharedService.AttachToolTip(GetUserTooltip());
if (_performanceConfigService.Current.ShowPerformanceIndicator
&& !_performanceConfigService.Current.UIDsToIgnore
@@ -327,6 +291,143 @@ public class DrawUserPair
_displayHandler.DrawPairText(_id, _pair, leftSide, () => rightSide - leftSide);
}
private string GetUserTooltip()
{
List<string>? groupDisplays = null;
if (_syncedGroups.Count > 0)
{
groupDisplays = new List<string>(_syncedGroups.Count);
foreach (var group in _syncedGroups)
{
var groupNote = _serverConfigurationManager.GetNoteForGid(group.GID);
groupDisplays.Add(string.IsNullOrEmpty(groupNote) ? group.GroupAliasOrGID : $"{groupNote} ({group.GroupAliasOrGID})");
}
}
var snapshot = new TooltipSnapshot(
_pair.IsPaused,
_pair.IsOnline,
_pair.IsVisible,
_pair.IndividualPairStatus,
_pair.UserData.AliasOrUID,
_pair.PlayerName ?? string.Empty,
_pair.LastAppliedDataBytes,
_pair.LastAppliedApproximateVRAMBytes,
_pair.LastAppliedDataTris,
_pair.IsPaired,
groupDisplays is null ? ImmutableArray<string>.Empty : ImmutableArray.CreateRange(groupDisplays));
if (!_tooltipSnapshot.Equals(snapshot))
{
_cachedTooltip = BuildTooltip(snapshot);
_tooltipSnapshot = snapshot;
}
return _cachedTooltip;
}
private static string BuildTooltip(in TooltipSnapshot snapshot)
{
var builder = new StringBuilder(256);
if (snapshot.IsPaused)
{
builder.Append(snapshot.AliasOrUid);
builder.Append(" is paused");
}
else if (!snapshot.IsOnline)
{
builder.Append(snapshot.AliasOrUid);
builder.Append(" is offline");
}
else if (snapshot.IsVisible)
{
builder.Append(snapshot.AliasOrUid);
builder.Append(" is visible: ");
builder.Append(snapshot.PlayerName);
builder.Append(Environment.NewLine);
builder.Append("Click to target this player");
}
else
{
builder.Append(snapshot.AliasOrUid);
builder.Append(" is online");
}
if (snapshot.PairStatus == IndividualPairStatus.OneSided)
{
builder.Append(UiSharedService.TooltipSeparator);
builder.Append("User has not added you back");
}
else if (snapshot.PairStatus == IndividualPairStatus.Bidirectional)
{
builder.Append(UiSharedService.TooltipSeparator);
builder.Append("You are directly Paired");
}
if (snapshot.LastAppliedDataBytes >= 0)
{
builder.Append(UiSharedService.TooltipSeparator);
if (!snapshot.IsPaired)
{
builder.Append("(Last) ");
}
builder.Append("Mods Info");
builder.Append(Environment.NewLine);
builder.Append("Files Size: ");
builder.Append(UiSharedService.ByteToString(snapshot.LastAppliedDataBytes, true));
if (snapshot.LastAppliedApproximateVRAMBytes >= 0)
{
builder.Append(Environment.NewLine);
builder.Append("Approx. VRAM Usage: ");
builder.Append(UiSharedService.ByteToString(snapshot.LastAppliedApproximateVRAMBytes, true));
}
if (snapshot.LastAppliedDataTris >= 0)
{
builder.Append(Environment.NewLine);
builder.Append("Approx. Triangle Count (excl. Vanilla): ");
builder.Append(snapshot.LastAppliedDataTris > 1000
? (snapshot.LastAppliedDataTris / 1000d).ToString("0.0'k'")
: snapshot.LastAppliedDataTris);
}
}
if (!snapshot.GroupDisplays.IsEmpty)
{
builder.Append(UiSharedService.TooltipSeparator);
for (int i = 0; i < snapshot.GroupDisplays.Length; i++)
{
if (i > 0)
{
builder.Append(Environment.NewLine);
}
builder.Append("Paired through ");
builder.Append(snapshot.GroupDisplays[i]);
}
}
return builder.ToString();
}
private readonly record struct TooltipSnapshot(
bool IsPaused,
bool IsOnline,
bool IsVisible,
IndividualPairStatus PairStatus,
string AliasOrUid,
string PlayerName,
long LastAppliedDataBytes,
long LastAppliedApproximateVRAMBytes,
long LastAppliedDataTris,
bool IsPaired,
ImmutableArray<string> GroupDisplays)
{
public static TooltipSnapshot Empty { get; } =
new(false, false, false, IndividualPairStatus.None, string.Empty, string.Empty, -1, -1, -1, false, ImmutableArray<string>.Empty);
}
private void DrawPairedClientMenu()
{
DrawIndividualMenu();

View File

@@ -157,7 +157,7 @@ public class IdDisplayHandler
Vector2 textSize;
using (ImRaii.PushFont(font, textIsUid))
{
SeStringUtils.RenderSeStringWithHitbox(seString, rowStart, font);
SeStringUtils.RenderSeStringWithHitbox(seString, rowStart, font, pair.UserData.UID);
itemMin = ImGui.GetItemRectMin();
itemMax = ImGui.GetItemRectMax();
//textSize = itemMax - itemMin;

View File

@@ -7,6 +7,7 @@ using Dalamud.Interface.Utility;
using Lumina.Text;
using System;
using System.Numerics;
using System.Threading;
using DalamudSeString = Dalamud.Game.Text.SeStringHandling.SeString;
using DalamudSeStringBuilder = Dalamud.Game.Text.SeStringHandling.SeStringBuilder;
using LuminaSeStringBuilder = Lumina.Text.SeStringBuilder;
@@ -15,6 +16,9 @@ namespace LightlessSync.Utils;
public static class SeStringUtils
{
private static int _seStringHitboxCounter;
private static int _iconHitboxCounter;
public static DalamudSeString BuildFormattedPlayerName(string text, Vector4? textColor, Vector4? glowColor)
{
var b = new DalamudSeStringBuilder();
@@ -119,7 +123,7 @@ public static class SeStringUtils
ImGui.Dummy(new Vector2(0f, textSize.Y));
}
public static Vector2 RenderSeStringWithHitbox(DalamudSeString seString, Vector2 position, ImFontPtr? font = null)
public static Vector2 RenderSeStringWithHitbox(DalamudSeString seString, Vector2 position, ImFontPtr? font = null, string? id = null)
{
var drawList = ImGui.GetWindowDrawList();
@@ -137,12 +141,28 @@ public static class SeStringUtils
var textSize = ImGui.CalcTextSize(seString.TextValue);
ImGui.SetCursorScreenPos(position);
ImGui.InvisibleButton($"##hitbox_{Guid.NewGuid()}", textSize);
if (id is not null)
{
ImGui.PushID(id);
}
else
{
ImGui.PushID(Interlocked.Increment(ref _seStringHitboxCounter));
}
try
{
ImGui.InvisibleButton("##hitbox", textSize);
}
finally
{
ImGui.PopID();
}
return textSize;
}
public static Vector2 RenderIconWithHitbox(int iconId, Vector2 position, ImFontPtr? font = null)
public static Vector2 RenderIconWithHitbox(int iconId, Vector2 position, ImFontPtr? font = null, string? id = null)
{
var drawList = ImGui.GetWindowDrawList();
@@ -158,7 +178,23 @@ public static class SeStringUtils
var drawResult = ImGuiHelpers.CompileSeStringWrapped(iconMacro, drawParams);
ImGui.SetCursorScreenPos(position);
ImGui.InvisibleButton($"##iconHitbox_{Guid.NewGuid()}", drawResult.Size);
if (id is not null)
{
ImGui.PushID(id);
}
else
{
ImGui.PushID(Interlocked.Increment(ref _iconHitboxCounter));
}
try
{
ImGui.InvisibleButton("##iconHitbox", drawResult.Size);
}
finally
{
ImGui.PopID();
}
return drawResult.Size;
}

View File

@@ -215,6 +215,26 @@ public partial class FileDownloadManager : DisposableMediatorSubscriberBase
await Task.Delay(retryDelay, ct).ConfigureAwait(false);
}
catch (TaskCanceledException ex) when (!ct.IsCancellationRequested)
{
response?.Dispose();
retryCount++;
Logger.LogWarning(ex, "Cancellation/timeout during download of {requestUrl}. Attempt {attempt} of {maxRetries}", requestUrl, retryCount, maxRetries);
if (retryCount >= maxRetries)
{
Logger.LogError("Max retries reached for {requestUrl} after TaskCanceledException", requestUrl);
throw;
}
await Task.Delay(retryDelay, ct).ConfigureAwait(false);
}
catch (OperationCanceledException) when (ct.IsCancellationRequested)
{
response?.Dispose();
throw;
}
catch (HttpRequestException ex)
{
response?.Dispose();