Merge remote-tracking branch 'origin/2.0.0-crashing-bugfixes' into 2.0.0-crashing-bugfixes

# Conflicts:
#	LightlessSync/Services/DalamudUtilService.cs
#	LightlessSync/UI/DtrEntry.cs
This commit is contained in:
choco
2025-12-28 16:56:06 +01:00
18 changed files with 1038 additions and 371 deletions

View File

@@ -968,20 +968,25 @@ public class DataAnalysisUi : WindowMediatorSubscriberBase
Dictionary<ObjectKind, Dictionary<string, CharacterAnalyzer.FileDataEntry>> source)
{
var clone = new Dictionary<ObjectKind, Dictionary<string, CharacterAnalyzer.FileDataEntry>>(source.Count);
foreach (var (objectKind, entries) in source)
{
var entryClone = new Dictionary<string, CharacterAnalyzer.FileDataEntry>(entries.Count, entries.Comparer);
foreach (var (hash, entry) in entries)
{
entryClone[hash] = new CharacterAnalyzer.FileDataEntry(
hash,
entry.FileType,
entry.GamePaths.ToList(),
entry.FilePaths.ToList(),
entry.OriginalSize,
entry.CompressedSize,
entry.Triangles);
hash: hash,
fileType: entry.FileType,
gamePaths: entry.GamePaths?.ToList() ?? [],
filePaths: entry.FilePaths?.ToList() ?? [],
originalSize: entry.OriginalSize,
compressedSize: entry.CompressedSize,
triangles: entry.Triangles,
cacheEntries: entry.CacheEntries
);
}
clone[objectKind] = entryClone;
}

View File

@@ -364,21 +364,28 @@ public sealed class DtrEntry : IDisposable, IHostedService
return;
}
try
_ = Task.Run(async () =>
{
var cid = _dalamudUtilService.GetCID();
var hashedCid = cid.ToString().GetHash256();
_localHashedCid = hashedCid;
_localHashedCidFetchedAt = now;
return hashedCid;
}
catch (Exception ex)
{
if (now >= _localHashedCidNextErrorLog)
try
{
_logger.LogDebug(ex, "Failed to refresh local hashed CID for Lightfinder DTR entry.");
_localHashedCidNextErrorLog = now + _localHashedCidErrorCooldown;
var cid = _dalamudUtilService.GetCID();
var hashedCid = cid.ToString().GetHash256();
lock (_localHashedCidLock)
{
_localHashedCid = hashedCid;
_localHashedCidFetchedAt = DateTime.UtcNow;
}
}
catch (Exception ex)
{
var now = DateTime.UtcNow;
lock (_localHashedCidLock)
{
if (now >= _localHashedCidNextErrorLog)
{
_logger.LogDebug(ex, "Failed to refresh local hashed CID for Lightfinder DTR entry.");
_localHashedCidNextErrorLog = now + _localHashedCidErrorCooldown;
}
_localHashedCid = null;
_localHashedCidFetchedAt = now;

View File

@@ -37,6 +37,7 @@ public class LightFinderUI : WindowMediatorSubscriberBase
private readonly LightFinderService _broadcastService;
private readonly LightlessConfigService _configService;
private readonly LightlessProfileManager _lightlessProfileManager;
private readonly LightFinderPlateHandler _lightFinderPlateHandler;
private readonly PairUiService _pairUiService;
private readonly UiSharedService _uiSharedService;
@@ -100,7 +101,8 @@ public class LightFinderUI : WindowMediatorSubscriberBase
DalamudUtilService dalamudUtilService,
LightlessProfileManager lightlessProfileManager,
ActorObjectService actorObjectService
) : base(logger, mediator, "Lightfinder###LightlessLightfinderUI", performanceCollectorService)
,
LightFinderPlateHandler lightFinderPlateHandler) : base(logger, mediator, "Lightfinder###LightlessLightfinderUI", performanceCollectorService)
{
_broadcastService = broadcastService;
_uiSharedService = uiShared;
@@ -126,6 +128,7 @@ public class LightFinderUI : WindowMediatorSubscriberBase
Mediator.Subscribe<BroadcastStatusChangedMessage>(this, async _ => await RefreshNearbySyncshellsAsync().ConfigureAwait(false));
Mediator.Subscribe<UserLeftSyncshell>(this, async _ => await RefreshNearbySyncshellsAsync(_.gid).ConfigureAwait(false));
Mediator.Subscribe<UserJoinedSyncshell>(this, async _ => await RefreshNearbySyncshellsAsync(_.gid).ConfigureAwait(false));
_lightFinderPlateHandler = lightFinderPlateHandler;
}
#endregion
@@ -175,9 +178,9 @@ public class LightFinderUI : WindowMediatorSubscriberBase
new("Debug", LightfinderTabDebug.Debug)
};
UiSharedService.Tab("LightfinderTabs", debugTabOptions, ref _selectedTabDebug);
ImGuiHelpers.ScaledDummy(4f);
switch (_selectedTabDebug)
{
case LightfinderTabDebug.NearbySyncshells:
@@ -301,14 +304,14 @@ public class LightFinderUI : WindowMediatorSubscriberBase
var nearbySyncshellCount = _nearbySyncshells.Count;
var nearbySyncshellColor = nearbySyncshellCount > 0 ? UIColors.Get("LightlessPurple") : infoColor;
DrawStatusCell(FontAwesomeIcon.Compass, nearbySyncshellColor, nearbySyncshellCount.ToString(), "Syncshells", infoColor, scale);
// Nearby players cell (exclude self)
string? myHashedCidForCount = null;
try { myHashedCidForCount = _dalamudUtilService.GetCID().ToString().GetHash256(); } catch { }
var nearbyPlayerCount = _broadcastScannerService.CountActiveBroadcasts(myHashedCidForCount);
var nearbyPlayerColor = nearbyPlayerCount > 0 ? UIColors.Get("LightlessBlue") : infoColor;
DrawStatusCell(FontAwesomeIcon.Users, nearbyPlayerColor, nearbyPlayerCount.ToString(), "Players", infoColor, scale);
// Broadcasting syncshell cell
var isBroadcastingSyncshell = _configService.Current.SyncshellFinderEnabled && isBroadcasting;
var broadcastSyncshellColor = isBroadcastingSyncshell ? UIColors.Get("LightlessGreen") : infoColor;
@@ -318,7 +321,7 @@ public class LightFinderUI : WindowMediatorSubscriberBase
// Enable/Disable button cell - right aligned
ImGui.TableNextColumn();
float cellWidth = ImGui.GetContentRegionAvail().X;
float offsetX = cellWidth - buttonWidth;
if (offsetX > 0)
@@ -378,11 +381,11 @@ public class LightFinderUI : WindowMediatorSubscriberBase
private void UpdateItemAnimations(IEnumerable<string> visibleItemIds)
{
var deltaTime = ImGui.GetIO().DeltaTime;
_previousVisibleItems.Clear();
foreach (var id in _currentVisibleItems)
_previousVisibleItems.Add(id);
_currentVisibleItems.Clear();
foreach (var id in visibleItemIds)
_currentVisibleItems.Add(id);
@@ -392,7 +395,7 @@ public class LightFinderUI : WindowMediatorSubscriberBase
{
if (!_itemAlpha.ContainsKey(id))
_itemAlpha[id] = 0f;
_itemAlpha[id] = Math.Min(1f, _itemAlpha[id] + deltaTime * AnimationSpeed);
}
@@ -407,7 +410,7 @@ public class LightFinderUI : WindowMediatorSubscriberBase
toRemove.Add(id);
}
}
foreach (var id in toRemove)
_itemAlpha.Remove(id);
}
@@ -665,14 +668,14 @@ public class LightFinderUI : WindowMediatorSubscriberBase
ImGui.PopID();
}
private void DrawJoinButton(GroupJoinDto shell, bool fullWidth)
private void DrawJoinButton(GroupJoinDto shell, bool fullWidth)
{
const string visibleLabel = "Join";
var label = $"{visibleLabel}##{shell.Group.GID}";
var isAlreadyMember = _currentSyncshells.Exists(g => string.Equals(g.GID, shell.Group.GID, StringComparison.Ordinal));
var isRecentlyJoined = _recentlyJoined.Contains(shell.Group.GID);
var isOwnBroadcast = _configService.Current.SyncshellFinderEnabled
var isOwnBroadcast = _configService.Current.SyncshellFinderEnabled
&& _broadcastService.IsBroadcasting
&& string.Equals(_configService.Current.SelectedFinderSyncshell, shell.Group.GID, StringComparison.Ordinal);
@@ -755,7 +758,7 @@ public class LightFinderUI : WindowMediatorSubscriberBase
if (_joinDto == null || _joinInfo == null) return;
var scale = ImGuiHelpers.GlobalScale;
// if not already open
if (!ImGui.IsPopupOpen("JoinSyncshellModal"))
ImGui.OpenPopup("JoinSyncshellModal");
@@ -771,12 +774,12 @@ public class LightFinderUI : WindowMediatorSubscriberBase
ImGui.SetNextWindowSize(new Vector2(modalWidth, modalHeight));
ImGui.PushStyleVar(ImGuiStyleVar.WindowRounding, 6f * ImGuiHelpers.GlobalScale);
ImGui.PushStyleColor(ImGuiCol.Border, Vector4.Zero);
using ImRaii.Color modalBorder = ImRaii.PushColor(ImGuiCol.Border, UIColors.Get("LightlessPurple").WithAlpha(0.5f));
using ImRaii.Style rounding = ImRaii.PushStyle(ImGuiStyleVar.WindowRounding, 8f * scale);
using ImRaii.Style borderSize = ImRaii.PushStyle(ImGuiStyleVar.WindowBorderSize, 2f * scale);
using ImRaii.Style padding = ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, new Vector2(16f * scale, 16f * scale));
ImGuiWindowFlags flags = ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoScrollbar;
if (ImGui.BeginPopupModal("JoinSyncshellModal", ref _joinModalOpen, flags))
{
@@ -795,22 +798,22 @@ public class LightFinderUI : WindowMediatorSubscriberBase
ImGui.TextColored(ImGuiColors.DalamudWhite, "Permissions");
ImGuiHelpers.ScaledDummy(6f);
DrawPermissionToggleRow("Sounds", FontAwesomeIcon.VolumeUp,
_joinInfo.GroupPermissions.IsPreferDisableSounds(),
_ownPermissions.DisableGroupSounds,
v => _ownPermissions.DisableGroupSounds = v,
DrawPermissionToggleRow("Sounds", FontAwesomeIcon.VolumeUp,
_joinInfo.GroupPermissions.IsPreferDisableSounds(),
_ownPermissions.DisableGroupSounds,
v => _ownPermissions.DisableGroupSounds = v,
contentWidth);
DrawPermissionToggleRow("Animations", FontAwesomeIcon.Running,
_joinInfo.GroupPermissions.IsPreferDisableAnimations(),
_ownPermissions.DisableGroupAnimations,
v => _ownPermissions.DisableGroupAnimations = v,
DrawPermissionToggleRow("Animations", FontAwesomeIcon.Running,
_joinInfo.GroupPermissions.IsPreferDisableAnimations(),
_ownPermissions.DisableGroupAnimations,
v => _ownPermissions.DisableGroupAnimations = v,
contentWidth);
DrawPermissionToggleRow("VFX", FontAwesomeIcon.Magic,
_joinInfo.GroupPermissions.IsPreferDisableVFX(),
_ownPermissions.DisableGroupVFX,
v => _ownPermissions.DisableGroupVFX = v,
DrawPermissionToggleRow("VFX", FontAwesomeIcon.Magic,
_joinInfo.GroupPermissions.IsPreferDisableVFX(),
_ownPermissions.DisableGroupVFX,
v => _ownPermissions.DisableGroupVFX = v,
contentWidth);
ImGuiHelpers.ScaledDummy(12f);
@@ -876,13 +879,13 @@ public class LightFinderUI : WindowMediatorSubscriberBase
var scale = ImGuiHelpers.GlobalScale;
float rowHeight = 28f * scale;
bool isDifferent = current != suggested;
using (ImRaii.PushStyle(ImGuiStyleVar.FrameRounding, 4f * scale))
using (ImRaii.PushStyle(ImGuiStyleVar.ChildRounding, 4f * scale))
using (ImRaii.PushColor(ImGuiCol.ChildBg, new Vector4(0.18f, 0.15f, 0.22f, 0.6f)))
{
ImGui.BeginChild($"PermRow_{label}", new Vector2(contentWidth, rowHeight), false, ImGuiWindowFlags.NoScrollbar);
float innerPadding = 8f * scale;
ImGui.SetCursorPos(new Vector2(innerPadding, (rowHeight - ImGui.GetTextLineHeight()) * 0.5f));
@@ -890,7 +893,7 @@ public class LightFinderUI : WindowMediatorSubscriberBase
var enabledColor = UIColors.Get("LightlessGreen");
var disabledColor = UIColors.Get("DimRed");
var currentColor = !current ? enabledColor : disabledColor;
_uiSharedService.IconText(icon, currentColor);
ImGui.SameLine(0f, 6f * scale);
ImGui.TextUnformatted(label);
@@ -918,7 +921,7 @@ public class LightFinderUI : WindowMediatorSubscriberBase
float applyX = contentWidth - 26f * scale;
ImGui.SetCursorPosX(applyX);
ImGui.SetCursorPosY((rowHeight - ImGui.GetFrameHeight()) * 0.5f);
using (ImRaii.PushColor(ImGuiCol.Button, UIColors.Get("LightlessGreen").WithAlpha(0.6f)))
using (ImRaii.PushColor(ImGuiCol.ButtonHovered, UIColors.Get("LightlessGreen")))
using (ImRaii.PushColor(ImGuiCol.ButtonActive, UIColors.Get("LightlessGreenDefault")))
@@ -1034,12 +1037,12 @@ public class LightFinderUI : WindowMediatorSubscriberBase
}
private readonly record struct NearbyPlayerData(
string HashedCid,
string Name,
string? World,
nint Address,
Pair? Pair,
bool IsDirectlyPaired,
string HashedCid,
string Name,
string? World,
nint Address,
Pair? Pair,
bool IsDirectlyPaired,
List<string> SharedSyncshells);
private void DrawNearbyPlayerRow(NearbyPlayerData data)
@@ -1093,8 +1096,8 @@ public class LightFinderUI : WindowMediatorSubscriberBase
ImGui.SetCursorPosX(startX);
_uiSharedService.IconText(FontAwesomeIcon.Users, UIColors.Get("LightlessPurple"));
ImGui.SameLine(0f, 4f * ImGuiHelpers.GlobalScale);
var shellText = data.SharedSyncshells.Count == 1
? data.SharedSyncshells[0]
var shellText = data.SharedSyncshells.Count == 1
? data.SharedSyncshells[0]
: $"{data.SharedSyncshells.Count} shared shells";
ImGui.TextColored(UIColors.Get("LightlessPurple"), shellText);
if (data.SharedSyncshells.Count > 1 && ImGui.IsItemHovered())
@@ -1379,58 +1382,92 @@ public class LightFinderUI : WindowMediatorSubscriberBase
#endregion
#if DEBUG
#region Debug Tab
private void DrawDebugTab()
{
ImGui.Text("Broadcast Cache");
if (ImGui.BeginTable("##BroadcastCacheTable", 4, ImGuiTableFlags.RowBg | ImGuiTableFlags.Borders | ImGuiTableFlags.ScrollY, new Vector2(-1, 200f)))
{
ImGui.TableSetupColumn("CID", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("Broadcasting", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("Expires In", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("Syncshell GID", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableHeadersRow();
var now = DateTime.UtcNow;
foreach (var (cid, entry) in _broadcastScannerService.BroadcastCache)
#if DEBUG
if (ImGui.CollapsingHeader("LightFinder Plates", ImGuiTreeNodeFlags.DefaultOpen))
{
ImGui.TableNextRow();
var h = _lightFinderPlateHandler;
ImGui.TableNextColumn();
ImGui.TextUnformatted(cid.Truncate(12));
if (ImGui.IsItemHovered())
ImGui.SetTooltip(cid);
var enabled = h.DebugEnabled;
if (ImGui.Checkbox("Enable LightFinder debug", ref enabled))
h.DebugEnabled = enabled;
ImGui.TableNextColumn();
var colorBroadcast = entry.IsBroadcasting ? UIColors.Get("LightlessGreen") : UIColors.Get("DimRed");
ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, ImGui.GetColorU32(colorBroadcast));
ImGui.TextUnformatted(entry.IsBroadcasting.ToString());
if (h.DebugEnabled)
{
ImGui.Indent();
ImGui.TableNextColumn();
var remaining = entry.ExpiryTime - now;
var colorTtl = remaining <= TimeSpan.Zero ? UIColors.Get("DimRed")
: remaining < TimeSpan.FromSeconds(10) ? UIColors.Get("LightlessYellow")
: (Vector4?)null;
var disableOcc = h.DebugDisableOcclusion;
if (ImGui.Checkbox("Disable occlusion (force draw)", ref disableOcc))
h.DebugDisableOcclusion = disableOcc;
if (colorTtl != null)
ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, ImGui.GetColorU32(colorTtl.Value));
var drawUiRects = h.DebugDrawUiRects;
if (ImGui.Checkbox("Draw UI rects", ref drawUiRects))
h.DebugDrawUiRects = drawUiRects;
ImGui.TextUnformatted(remaining > TimeSpan.Zero ? remaining.ToString("hh\\:mm\\:ss") : "Expired");
var drawLabelRects = h.DebugDrawLabelRects;
if (ImGui.Checkbox("Draw label rects", ref drawLabelRects))
h.DebugDrawLabelRects = drawLabelRects;
ImGui.TableNextColumn();
ImGui.TextUnformatted(entry.GID ?? "-");
ImGui.Separator();
ImGui.TextUnformatted($"Labels last frame: {h.DebugLabelCountLastFrame}");
ImGui.TextUnformatted($"UI rects last frame: {h.DebugUiRectCountLastFrame}");
ImGui.TextUnformatted($"Occluded last frame: {h.DebugOccludedCountLastFrame}");
ImGui.TextUnformatted($"Last NamePlate frame: {h.DebugLastNameplateFrame}");
ImGui.Unindent();
}
}
ImGui.EndTable();
}
}
ImGui.Separator();
#endregion
ImGui.Text("Broadcast Cache");
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);
ImGui.TableSetupColumn("Expires In", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("Syncshell GID", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableHeadersRow();
var now = DateTime.UtcNow;
foreach (var (cid, entry) in _broadcastScannerService.BroadcastCache)
{
ImGui.TableNextRow();
ImGui.TableNextColumn();
ImGui.TextUnformatted(cid.Truncate(12));
if (ImGui.IsItemHovered())
ImGui.SetTooltip(cid);
ImGui.TableNextColumn();
var colorBroadcast = entry.IsBroadcasting ? UIColors.Get("LightlessGreen") : UIColors.Get("DimRed");
ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, ImGui.GetColorU32(colorBroadcast));
ImGui.TextUnformatted(entry.IsBroadcasting.ToString());
ImGui.TableNextColumn();
var remaining = entry.ExpiryTime - now;
var colorTtl = remaining <= TimeSpan.Zero ? UIColors.Get("DimRed")
: remaining < TimeSpan.FromSeconds(10) ? UIColors.Get("LightlessYellow")
: (Vector4?)null;
if (colorTtl != null)
ImGui.TableSetBgColor(ImGuiTableBgTarget.CellBg, ImGui.GetColorU32(colorTtl.Value));
ImGui.TextUnformatted(remaining > TimeSpan.Zero ? remaining.ToString("hh\\:mm\\:ss") : "Expired");
ImGui.TableNextColumn();
ImGui.TextUnformatted(entry.GID ?? "-");
}
ImGui.EndTable();
}
#endif
}
#region Data Refresh
@@ -1699,4 +1736,4 @@ public class LightFinderUI : WindowMediatorSubscriberBase
}
#endregion
}
}

View File

@@ -86,6 +86,8 @@ public class SettingsUi : WindowMediatorSubscriberBase
private bool _pairDiagnosticsEnabled;
private string? _selectedPairDebugUid = null;
private string _lightfinderIconInput = string.Empty;
private bool _showLightfinderRendererWarning = false;
private LightfinderLabelRenderer _pendingLightfinderRenderer = LightfinderLabelRenderer.Pictomancy;
private bool _lightfinderIconInputInitialized = false;
private int _lightfinderIconPresetIndex = -1;
private static readonly LightlessConfig DefaultConfig = new();
@@ -2387,7 +2389,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
var labelRenderer = _configService.Current.LightfinderLabelRenderer;
var labelRendererLabel = labelRenderer switch
{
LightfinderLabelRenderer.SignatureHook => "Native nameplate (sig hook)",
LightfinderLabelRenderer.SignatureHook => "Native Nameplate Rendering",
_ => "ImGui Overlay",
};
@@ -2397,18 +2399,25 @@ public class SettingsUi : WindowMediatorSubscriberBase
{
var optionLabel = option switch
{
LightfinderLabelRenderer.SignatureHook => "Native Nameplate (sig hook)",
LightfinderLabelRenderer.SignatureHook => "Native Nameplate Rendering",
_ => "ImGui Overlay",
};
var selected = option == labelRenderer;
if (ImGui.Selectable(optionLabel, selected))
{
_configService.Current.LightfinderLabelRenderer = option;
_configService.Save();
_nameplateService.RequestRedraw();
if (option == LightfinderLabelRenderer.SignatureHook)
{
_pendingLightfinderRenderer = option;
_showLightfinderRendererWarning = true;
}
else
{
_configService.Current.LightfinderLabelRenderer = option;
_configService.Save();
_nameplateService.RequestRedraw();
}
}
if (selected)
ImGui.SetItemDefaultFocus();
}
@@ -2416,6 +2425,34 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.EndCombo();
}
if (_showLightfinderRendererWarning)
{
ImGui.SetNextWindowSize(new Vector2(450f, 0f), ImGuiCond.Appearing);
ImGui.OpenPopup("Nameplate Warning");
}
if (ImGui.BeginPopupModal("Nameplate Warning", ref _showLightfinderRendererWarning, ImGuiWindowFlags.AlwaysAutoResize))
{
ImGui.TextColored(UIColors.Get("DimRed"), "USE AT YOUR RISK!");
ImGui.Spacing();
ImGui.TextWrapped("Writing on to the native Nameplates is known to be unstable and MAY cause crashes. DO NOT REPORT THOSE CRASHES TO DALAMUD. We will also not be supporting Nameplate crashes. You have been warned.");
ImGui.Spacing();
ImGui.TextWrapped("By accepting this warning, you understand that you are using this feature at risk of crashing.");
ImGui.Spacing();
var buttonWidth = ImGui.GetContentRegionAvail().X;
if (ImGui.Button("I Understand", new Vector2(buttonWidth, 0)))
{
_configService.Current.LightfinderLabelRenderer = _pendingLightfinderRenderer;
_configService.Save();
_nameplateService.RequestRedraw();
_showLightfinderRendererWarning = false;
ImGui.CloseCurrentPopup();
}
ImGui.EndPopup();
}
_uiShared.DrawHelpText("Choose how Lightfinder labels render: the default ImGui overlay or native nameplate nodes via signature hook.");
UiSharedService.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f);
@@ -2602,7 +2639,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
var selected = i == _lightfinderIconPresetIndex;
if (ImGui.Selectable(preview, selected))
{
_lightfinderIconInput = LightFinderPlateHandler.ToIconEditorString(optionGlyph);
_lightfinderIconInput = LightFinderPlateHandler.NormalizeIconGlyph(optionGlyph);
_lightfinderIconPresetIndex = i;
}
}
@@ -4083,7 +4120,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
private void RefreshLightfinderIconState()
{
var normalized = LightFinderPlateHandler.NormalizeIconGlyph(_configService.Current.LightfinderLabelIconGlyph);
_lightfinderIconInput = LightFinderPlateHandler.ToIconEditorString(normalized);
_lightfinderIconInput = LightFinderPlateHandler.NormalizeIconGlyph(normalized);
_lightfinderIconInputInitialized = true;
_lightfinderIconPresetIndex = -1;
@@ -4101,7 +4138,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
{
_configService.Current.LightfinderLabelIconGlyph = normalizedGlyph;
_configService.Save();
_lightfinderIconInput = LightFinderPlateHandler.ToIconEditorString(normalizedGlyph);
_lightfinderIconInput = LightFinderPlateHandler.NormalizeIconGlyph(normalizedGlyph);
_lightfinderIconPresetIndex = presetIndex;
_lightfinderIconInputInitialized = true;
}

View File

@@ -11,6 +11,7 @@ using LightlessSync.Services.ServerConfiguration;
using LightlessSync.UI.Services;
using LightlessSync.UI.Tags;
using LightlessSync.Utils;
using LightlessSync.WebAPI;
using Microsoft.Extensions.Logging;
using System.Numerics;
@@ -22,6 +23,7 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
private readonly PairUiService _pairUiService;
private readonly ServerConfigurationManager _serverManager;
private readonly ProfileTagService _profileTagService;
private readonly ApiController _apiController;
private readonly UiSharedService _uiSharedService;
private readonly UserData? _userData;
private readonly GroupData? _groupData;
@@ -60,7 +62,8 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
GroupData? groupData,
bool isLightfinderContext,
string? lightfinderCid,
PerformanceCollectorService performanceCollector)
PerformanceCollectorService performanceCollector,
ApiController apiController)
: base(logger, mediator, BuildWindowTitle(
userData,
groupData,
@@ -94,6 +97,7 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
.Apply();
IsOpen = true;
_apiController = apiController;
}
public Pair? Pair { get; }
@@ -248,19 +252,33 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
ResetBannerTexture();
_lastBannerPicture = bannerBytes;
}
string? noteText = null;
string statusLabel = _isLightfinderContext ? "Exploring" : "Offline";
var isSelfProfile = !_isLightfinderContext
&& _userData is not null
&& !string.IsNullOrEmpty(_apiController.UID)
&& string.Equals(_userData.UID, _apiController.UID, StringComparison.Ordinal);
string statusLabel = _isLightfinderContext
? "Exploring"
: isSelfProfile ? "Online" : "Offline";
string? visiblePlayerName = null;
bool directPair = false;
bool youPaused = false;
bool theyPaused = false;
List<string> syncshellLines = [];
if (!_isLightfinderContext)
{
noteText = _serverManager.GetNoteForUid(_userData!.UID);
}
if (!_isLightfinderContext && Pair != null)
{
var snapshot = _pairUiService.GetSnapshot();
noteText = _serverManager.GetNoteForUid(Pair.UserData.UID);
statusLabel = Pair.IsVisible ? "Visible" : (Pair.IsOnline ? "Online" : "Offline");
visiblePlayerName = Pair.IsVisible ? Pair.PlayerName : null;
@@ -282,11 +300,15 @@ public class StandaloneProfileUi : WindowMediatorSubscriberBase
var groupLabel = snapshot.GroupsByGid.TryGetValue(gid, out var groupInfo)
? groupInfo.GroupAliasOrGID
: gid;
var groupNote = _serverManager.GetNoteForGid(gid);
syncshellLines.Add(string.IsNullOrEmpty(groupNote) ? groupLabel : $"{groupNote} ({groupLabel})");
}
}
}
if (isSelfProfile)
statusLabel = "Online";
}
var presenceTokens = new List<PresenceToken>

View File

@@ -993,18 +993,33 @@ public sealed class ZoneChatUi : WindowMediatorSubscriberBase
{
_refocusChatInput = true;
_refocusChatInputKey = channel.Key;
var sanitized = SanitizeOutgoingDraft(draft);
var draftAtSend = draft;
var sanitized = SanitizeOutgoingDraft(draftAtSend);
if (sanitized is not null)
{
TrackPendingDraftClear(channel.Key, sanitized);
if (TrySendDraft(channel, sanitized))
draft = string.Empty;
_draftMessages[channel.Key] = draft;
_scrollToBottom = true;
_ = Task.Run(async () =>
{
_scrollToBottom = true;
}
else
{
RemovePendingDraftClear(channel.Key, sanitized);
}
try
{
var succeeded = await _zoneChatService.SendMessageAsync(channel.Descriptor, sanitized).ConfigureAwait(false);
if (!succeeded)
{
RemovePendingDraftClear(channel.Key, sanitized);
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to send chat message");
RemovePendingDraftClear(channel.Key, sanitized);
}
});
}
}
}