diff --git a/.gitea/workflows/lightless-tag-and-release.yml b/.gitea/workflows/lightless-tag-and-release.yml index 5c39934..d5b7266 100644 --- a/.gitea/workflows/lightless-tag-and-release.yml +++ b/.gitea/workflows/lightless-tag-and-release.yml @@ -41,9 +41,9 @@ jobs: - name: Get version id: package_version - uses: KageKirin/get-csproj-version@v0 - with: - file: LightlessSync/LightlessSync.csproj + run: | + version=$(grep -oPm1 "(?<=)[^<]+" LightlessSync/LightlessSync.csproj) + echo "version=$version" >> $GITHUB_OUTPUT - name: Display version run: | diff --git a/LightlessSync/LightlessConfiguration/Configurations/LightlessConfig.cs b/LightlessSync/LightlessConfiguration/Configurations/LightlessConfig.cs index c7359e9..1a4f6ae 100644 --- a/LightlessSync/LightlessConfiguration/Configurations/LightlessConfig.cs +++ b/LightlessSync/LightlessConfiguration/Configurations/LightlessConfig.cs @@ -81,7 +81,7 @@ public class LightlessConfig : ILightlessConfiguration public bool LightfinderLabelUseIcon { get; set; } = false; public bool LightfinderLabelShowOwn { get; set; } = true; public bool LightfinderLabelShowPaired { get; set; } = true; - public string LightfinderLabelIconGlyph { get; set; } = SeIconCharExtensions.ToIconString(SeIconChar.LinkMarker); + public string LightfinderLabelIconGlyph { get; set; } = SeIconCharExtensions.ToIconString(SeIconChar.Hyadelyn); public float LightfinderLabelScale { get; set; } = 1.0f; public bool LightfinderAutoAlign { get; set; } = true; public LabelAlignment LabelAlignment { get; set; } = LabelAlignment.Left; diff --git a/LightlessSync/Services/NameplateHandler.cs b/LightlessSync/Services/NameplateHandler.cs index 969c494..74edabc 100644 --- a/LightlessSync/Services/NameplateHandler.cs +++ b/LightlessSync/Services/NameplateHandler.cs @@ -6,7 +6,6 @@ using FFXIVClientStructs.FFXIV.Client.System.Framework; using FFXIVClientStructs.FFXIV.Client.UI; using FFXIVClientStructs.FFXIV.Component.GUI; using LightlessSync.LightlessConfiguration; -using LightlessSync.LightlessConfiguration.Configurations; using LightlessSync.PlayerData.Pairs; using LightlessSync.Services.Mediator; using LightlessSync.UI; @@ -43,8 +42,9 @@ public unsafe class NameplateHandler : IMediatorSubscriber private readonly int[] _cachedNameplateTextOffsets = new int[AddonNamePlate.NumNamePlateObjects]; internal const uint mNameplateNodeIDBase = 0x7D99D500; - private const string DefaultLabelText = "Lightfinder"; - private const SeIconChar DefaultIcon = SeIconChar.LinkMarker; + private const string DefaultLabelText = "LightFinder"; + private const SeIconChar DefaultIcon = SeIconChar.Hyadelyn; + private const int ContainerOffsetX = 50; private static readonly string DefaultIconGlyph = SeIconCharExtensions.ToIconString(DefaultIcon); private volatile HashSet _activeBroadcastingCids = []; @@ -266,11 +266,20 @@ public unsafe class NameplateHandler : IMediatorSubscriber var scaleMultiplier = System.Math.Clamp(config.LightfinderLabelScale, 0.5f, 2.0f); var baseScale = config.LightfinderLabelUseIcon ? 1.0f : 0.5f; var effectiveScale = baseScale * scaleMultiplier; - var nodeWidth = (int)System.Math.Round(AtkNodeHelpers.DefaultTextNodeWidth * effectiveScale); - var nodeHeight = (int)System.Math.Round(AtkNodeHelpers.DefaultTextNodeHeight * effectiveScale); + var labelContent = config.LightfinderLabelUseIcon + ? NormalizeIconGlyph(config.LightfinderLabelIconGlyph) + : DefaultLabelText; - int positionX = 58; - AlignmentType alignment = AlignmentType.Bottom; + pNode->FontType = config.LightfinderLabelUseIcon ? FontType.Axis : FontType.MiedingerMed; + pNode->AtkResNode.SetScale(effectiveScale, effectiveScale); + var nodeWidth = (int)pNode->AtkResNode.GetWidth(); + if (nodeWidth <= 0) + nodeWidth = (int)System.Math.Round(AtkNodeHelpers.DefaultTextNodeWidth * effectiveScale); + var nodeHeight = (int)System.Math.Round(AtkNodeHelpers.DefaultTextNodeHeight * effectiveScale); + var baseFontSize = config.LightfinderLabelUseIcon ? 36f : 24f; + var computedFontSize = (int)System.Math.Round(baseFontSize * scaleMultiplier); + pNode->FontSize = (byte)System.Math.Clamp(computedFontSize, 1, 255); + AlignmentType alignment; var textScaleY = nameText->AtkResNode.ScaleY; if (textScaleY <= 0f) @@ -322,21 +331,15 @@ public unsafe class NameplateHandler : IMediatorSubscriber var positionY = blockTop - verticalPadding - nodeHeight; var textWidth = System.Math.Abs((int)nameplateObject.TextW); - if (textWidth > 0) - { - _cachedNameplateTextWidths[nameplateIndex] = textWidth; - } - else - { - textWidth = _cachedNameplateTextWidths[nameplateIndex]; - } - if (textWidth <= 0) { textWidth = GetScaledTextWidth(nameText); if (textWidth <= 0) textWidth = nodeWidth; + } + if (textWidth > 0) + { _cachedNameplateTextWidths[nameplateIndex] = textWidth; } @@ -355,37 +358,67 @@ public unsafe class NameplateHandler : IMediatorSubscriber { hasValidOffset = false; } + int positionX; if (config.LightfinderAutoAlign && nameContainer != null && hasValidOffset) { + var nameplateWidth = (int)nameContainer->Width; + + if (!config.LightfinderLabelUseIcon) + { + pNode->TextFlags &= ~TextFlags.AutoAdjustNodeSize; + pNode->AtkResNode.Width = 0; + pNode->SetText(labelContent); + + nodeWidth = (int)pNode->AtkResNode.GetWidth(); + if (nodeWidth <= 0) + nodeWidth = (int)System.Math.Round(AtkNodeHelpers.DefaultTextNodeWidth * effectiveScale); + + if (nodeWidth > nameplateWidth) + nodeWidth = nameplateWidth; + + pNode->AtkResNode.Width = (ushort)nodeWidth; + } + else + { + pNode->TextFlags |= TextFlags.AutoAdjustNodeSize; + pNode->AtkResNode.Width = 0; + pNode->SetText(labelContent); + nodeWidth = (int)pNode->AtkResNode.GetWidth(); + } + + int leftPos = nameplateWidth / 8; + int rightPos = nameplateWidth - nodeWidth - (nameplateWidth / 8); + int centrePos = (nameplateWidth - nodeWidth) / 2; + int staticMargin = 24; + int calcMargin = (int)(nameplateWidth * 0.08f); + switch (config.LabelAlignment) { case LabelAlignment.Left: - positionX = textOffset; + positionX = config.LightfinderLabelUseIcon ? leftPos + staticMargin : leftPos; alignment = AlignmentType.BottomLeft; break; case LabelAlignment.Right: - positionX = textOffset + textWidth - nodeWidth; + positionX = config.LightfinderLabelUseIcon ? rightPos - staticMargin : nameplateWidth - nodeWidth + calcMargin; alignment = AlignmentType.BottomRight; break; default: - positionX = textOffset + textWidth / 2 - nodeWidth / 2; + positionX = config.LightfinderLabelUseIcon ? centrePos : centrePos + calcMargin; alignment = AlignmentType.Bottom; break; } } else { + positionX = 58 + config.LightfinderLabelOffsetX; alignment = AlignmentType.Bottom; } - positionX += config.LightfinderLabelOffsetX; positionY += config.LightfinderLabelOffsetY; alignment = (AlignmentType)System.Math.Clamp((int)alignment, 0, 8); - pNode->AtkResNode.SetPositionShort((short)System.Math.Clamp(positionX, short.MinValue, short.MaxValue), (short)System.Math.Clamp(positionY, short.MinValue, short.MaxValue)); pNode->AtkResNode.SetUseDepthBasedPriority(true); - pNode->AtkResNode.SetScale(effectiveScale, effectiveScale); pNode->AtkResNode.Color.A = 255; @@ -399,24 +432,25 @@ public unsafe class NameplateHandler : IMediatorSubscriber pNode->EdgeColor.B = (byte)(edgeColor.Z * 255); pNode->EdgeColor.A = (byte)(edgeColor.W * 255); - var baseFontSize = config.LightfinderLabelUseIcon ? 36f : 24f; - var computedFontSize = (int)System.Math.Round(baseFontSize * scaleMultiplier); - pNode->FontSize = (byte)System.Math.Clamp(computedFontSize, 1, 255); - pNode->AlignmentType = alignment; + + if(!config.LightfinderLabelUseIcon) + { + pNode->AlignmentType = AlignmentType.Bottom; + } + else + { + pNode->AlignmentType = alignment; + } + pNode->AtkResNode.SetPositionShort( + (short)System.Math.Clamp(positionX, short.MinValue, short.MaxValue), + (short)System.Math.Clamp(positionY, short.MinValue, short.MaxValue) + ); var computedLineSpacing = (int)System.Math.Round(24 * scaleMultiplier); pNode->LineSpacing = (byte)System.Math.Clamp(computedLineSpacing, 0, byte.MaxValue); pNode->CharSpacing = 1; - pNode->TextFlags = config.LightfinderLabelUseIcon ? TextFlags.Edge | TextFlags.Glare | TextFlags.AutoAdjustNodeSize - : TextFlags.Edge | TextFlags.Glare; - - var labelContent = config.LightfinderLabelUseIcon - ? NormalizeIconGlyph(config.LightfinderLabelIconGlyph) - : DefaultLabelText; - - pNode->FontType = config.LightfinderLabelUseIcon ? FontType.Axis : FontType.MiedingerMed; - pNode->SetText(labelContent); + : TextFlags.Edge | TextFlags.Glare; } } @@ -552,4 +586,12 @@ public unsafe class NameplateHandler : IMediatorSubscriber FlagRefresh(); } + + public void ClearNameplateCaches() + { + System.Array.Clear(_cachedNameplateTextWidths, 0, _cachedNameplateTextWidths.Length); + System.Array.Clear(_cachedNameplateTextHeights, 0, _cachedNameplateTextHeights.Length); + System.Array.Clear(_cachedNameplateContainerHeights, 0, _cachedNameplateContainerHeights.Length); + System.Array.Fill(_cachedNameplateTextOffsets, int.MinValue); + } } diff --git a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs index f90d7a2..25d9796 100644 --- a/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs +++ b/LightlessSync/Services/ServerConfiguration/ServerConfigurationManager.cs @@ -504,7 +504,7 @@ public class ServerConfigurationManager internal void RenameTag(Dictionary> tags, HashSet storage, string oldName, string newName) { - if (newName.Length > _maxCharactersFolder) + if (newName.Length < _maxCharactersFolder) { storage.Remove(oldName); storage.Add(newName); diff --git a/LightlessSync/UI/SettingsUi.cs b/LightlessSync/UI/SettingsUi.cs index c54e912..f8249ac 100644 --- a/LightlessSync/UI/SettingsUi.cs +++ b/LightlessSync/UI/SettingsUi.cs @@ -1074,41 +1074,82 @@ public class SettingsUi : WindowMediatorSubscriberBase if (_uiShared.MediumTreeNode("Lightfinder", UIColors.Get("LightlessPurple"))) { + var autoAlign = _configService.Current.LightfinderAutoAlign; var offsetX = (int)_configService.Current.LightfinderLabelOffsetX; + var offsetY = (int)_configService.Current.LightfinderLabelOffsetY; + var labelScale = _configService.Current.LightfinderLabelScale; + + ImGui.TextUnformatted("Alignment"); + ImGui.BeginDisabled(autoAlign); if (ImGui.SliderInt("Label Offset X", ref offsetX, -200, 200)) { _configService.Current.LightfinderLabelOffsetX = (short)offsetX; _configService.Save(); + _nameplateHandler.ClearNameplateCaches(); _nameplateHandler.FlagRefresh(); _nameplateService.RequestRedraw(); } - _uiShared.DrawHelpText("Moves the Lightfinder label horizontally on player nameplates."); + if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) + { + _configService.Current.LightfinderLabelOffsetX = 0; + _configService.Save(); + _nameplateHandler.ClearNameplateCaches(); + _nameplateHandler.FlagRefresh(); + _nameplateService.RequestRedraw(); + } + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Right click to reset to default."); + ImGui.EndDisabled(); + _uiShared.DrawHelpText("Moves the Lightfinder label horizontally on player nameplates.\nUnavailable when automatic alignment is enabled."); + - var offsetY = (int)_configService.Current.LightfinderLabelOffsetY; if (ImGui.SliderInt("Label Offset Y", ref offsetY, -200, 200)) { _configService.Current.LightfinderLabelOffsetY = (short)offsetY; _configService.Save(); + _nameplateHandler.ClearNameplateCaches(); _nameplateHandler.FlagRefresh(); _nameplateService.RequestRedraw(); } + if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) + { + _configService.Current.LightfinderLabelOffsetY = 0; + _configService.Save(); + _nameplateHandler.ClearNameplateCaches(); + _nameplateHandler.FlagRefresh(); + _nameplateService.RequestRedraw(); + } + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Right click to reset to default."); _uiShared.DrawHelpText("Moves the Lightfinder label vertically on player nameplates."); - var labelScale = _configService.Current.LightfinderLabelScale; if (ImGui.SliderFloat("Label Size", ref labelScale, 0.5f, 2.0f, "%.2fx")) { _configService.Current.LightfinderLabelScale = labelScale; _configService.Save(); + _nameplateHandler.ClearNameplateCaches(); _nameplateHandler.FlagRefresh(); _nameplateService.RequestRedraw(); } + if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) + { + _configService.Current.LightfinderLabelScale = 1.0f; + _configService.Save(); + _nameplateHandler.ClearNameplateCaches(); + _nameplateHandler.FlagRefresh(); + _nameplateService.RequestRedraw(); + } + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Right click to reset to default."); _uiShared.DrawHelpText("Adjusts the Lightfinder label size for both text and icon modes."); - var autoAlign = _configService.Current.LightfinderAutoAlign; + ImGui.Dummy(new Vector2(8)); + if (ImGui.Checkbox("Automatically align with nameplate", ref autoAlign)) { _configService.Current.LightfinderAutoAlign = autoAlign; _configService.Save(); + _nameplateHandler.ClearNameplateCaches(); _nameplateHandler.FlagRefresh(); _nameplateService.RequestRedraw(); } @@ -1152,31 +1193,40 @@ public class SettingsUi : WindowMediatorSubscriberBase } + _uiShared.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f); + + ImGui.TextUnformatted("Visibility"); var showOwn = _configService.Current.LightfinderLabelShowOwn; - if (ImGui.Checkbox("Show your own Lightfinder indicator", ref showOwn)) + if (ImGui.Checkbox("Show your own Lightfinder label", ref showOwn)) { _configService.Current.LightfinderLabelShowOwn = showOwn; _configService.Save(); + _nameplateHandler.ClearNameplateCaches(); _nameplateHandler.FlagRefresh(); _nameplateService.RequestRedraw(); } - _uiShared.DrawHelpText("Toggles your own Lightfinder indicator."); + _uiShared.DrawHelpText("Toggles your own Lightfinder label."); var showPaired = _configService.Current.LightfinderLabelShowPaired; - if (ImGui.Checkbox("Show paired player(s) Lightfinder indicator", ref showPaired)) + if (ImGui.Checkbox("Show paired player(s) Lightfinder label", ref showPaired)) { _configService.Current.LightfinderLabelShowPaired = showPaired; _configService.Save(); + _nameplateHandler.ClearNameplateCaches(); _nameplateHandler.FlagRefresh(); _nameplateService.RequestRedraw(); } - _uiShared.DrawHelpText("Toggles paired player(s) Lightfinder indicator."); + _uiShared.DrawHelpText("Toggles paired player(s) Lightfinder label."); + _uiShared.ColoredSeparator(UIColors.Get("LightlessPurpleDefault"), 1.5f); + + ImGui.TextUnformatted("Label"); var useIcon = _configService.Current.LightfinderLabelUseIcon; if (ImGui.Checkbox("Show icon instead of text", ref useIcon)) { _configService.Current.LightfinderLabelUseIcon = useIcon; _configService.Save(); + _nameplateHandler.ClearNameplateCaches(); _nameplateHandler.FlagRefresh(); _nameplateService.RequestRedraw();