Merge pull request 'Fixed many issues with lightfinder, added back icon support' (#102) from lightfinder-changes-picto into 2.0.1
Reviewed-on: #102
This commit was merged in pull request #102.
This commit is contained in:
@@ -4,6 +4,7 @@ using Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
|||||||
using Dalamud.Game.ClientState.Objects.Enums;
|
using Dalamud.Game.ClientState.Objects.Enums;
|
||||||
using Dalamud.Game.Text;
|
using Dalamud.Game.Text;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
|
using Dalamud.Interface.Utility;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using FFXIVClientStructs.FFXIV.Client.System.Framework;
|
using FFXIVClientStructs.FFXIV.Client.System.Framework;
|
||||||
@@ -16,12 +17,13 @@ using LightlessSync.UI;
|
|||||||
using LightlessSync.UI.Services;
|
using LightlessSync.UI.Services;
|
||||||
using LightlessSync.Utils;
|
using LightlessSync.Utils;
|
||||||
using LightlessSync.UtilsEnum.Enum;
|
using LightlessSync.UtilsEnum.Enum;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Pictomancy;
|
using Pictomancy;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using Task = System.Threading.Tasks.Task;
|
using Task = System.Threading.Tasks.Task;
|
||||||
|
|
||||||
namespace LightlessSync.Services.LightFinder;
|
namespace LightlessSync.Services.LightFinder;
|
||||||
@@ -48,9 +50,19 @@ public unsafe class LightFinderPlateHandler : IHostedService, IMediatorSubscribe
|
|||||||
|
|
||||||
private const string DefaultLabelText = "LightFinder";
|
private const string DefaultLabelText = "LightFinder";
|
||||||
private const SeIconChar DefaultIcon = SeIconChar.Hyadelyn;
|
private const SeIconChar DefaultIcon = SeIconChar.Hyadelyn;
|
||||||
private static readonly string DefaultIconGlyph = SeIconCharExtensions.ToIconString(DefaultIcon);
|
private static readonly string _defaultIconGlyph = SeIconCharExtensions.ToIconString(DefaultIcon);
|
||||||
private static readonly Vector2 DefaultPivot = new(0.5f, 1f);
|
private static readonly Vector2 _defaultPivot = new(0.5f, 1f);
|
||||||
|
private uint _lastNamePlateDrawFrame;
|
||||||
|
|
||||||
|
private const ImGuiWindowFlags _overlayFlags =
|
||||||
|
ImGuiWindowFlags.NoDecoration |
|
||||||
|
ImGuiWindowFlags.NoBackground |
|
||||||
|
ImGuiWindowFlags.NoMove |
|
||||||
|
ImGuiWindowFlags.NoSavedSettings |
|
||||||
|
ImGuiWindowFlags.NoNav |
|
||||||
|
ImGuiWindowFlags.NoInputs;
|
||||||
|
|
||||||
|
private readonly List<RectF> _uiRects = new(128);
|
||||||
private ImmutableHashSet<string> _activeBroadcastingCids = [];
|
private ImmutableHashSet<string> _activeBroadcastingCids = [];
|
||||||
|
|
||||||
public LightFinderPlateHandler(
|
public LightFinderPlateHandler(
|
||||||
@@ -145,6 +157,10 @@ public unsafe class LightFinderPlateHandler : IHostedService, IMediatorSubscribe
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fw = Framework.Instance();
|
||||||
|
if (fw != null)
|
||||||
|
_lastNamePlateDrawFrame = fw->FrameCounter;
|
||||||
|
|
||||||
var pNameplateAddon = (AddonNamePlate*)args.Addon.Address;
|
var pNameplateAddon = (AddonNamePlate*)args.Addon.Address;
|
||||||
|
|
||||||
if (_mpNameplateAddon != pNameplateAddon)
|
if (_mpNameplateAddon != pNameplateAddon)
|
||||||
@@ -175,6 +191,12 @@ public unsafe class LightFinderPlateHandler : IHostedService, IMediatorSubscribe
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!IsNamePlateAddonVisible())
|
||||||
|
{
|
||||||
|
ClearLabelBuffer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var framework = Framework.Instance();
|
var framework = Framework.Instance();
|
||||||
if (framework == null)
|
if (framework == null)
|
||||||
{
|
{
|
||||||
@@ -215,6 +237,7 @@ public unsafe class LightFinderPlateHandler : IHostedService, IMediatorSubscribe
|
|||||||
|
|
||||||
for (int i = 0; i < safeCount; ++i)
|
for (int i = 0; i < safeCount; ++i)
|
||||||
{
|
{
|
||||||
|
|
||||||
var objectInfoPtr = vec[i];
|
var objectInfoPtr = vec[i];
|
||||||
if (objectInfoPtr == null)
|
if (objectInfoPtr == null)
|
||||||
continue;
|
continue;
|
||||||
@@ -261,12 +284,11 @@ public unsafe class LightFinderPlateHandler : IHostedService, IMediatorSubscribe
|
|||||||
|
|
||||||
root->Component->UldManager.UpdateDrawNodeList();
|
root->Component->UldManager.UpdateDrawNodeList();
|
||||||
|
|
||||||
bool isVisible =
|
bool isNameplateVisible =
|
||||||
(marker != null && marker->AtkResNode.IsVisible()) ||
|
nameContainer->IsVisible() &&
|
||||||
(nameContainer->IsVisible() && nameText->AtkResNode.IsVisible()) ||
|
nameText->AtkResNode.IsVisible();
|
||||||
currentConfig.LightfinderLabelShowHidden;
|
|
||||||
|
|
||||||
if (!isVisible)
|
if (!currentConfig.LightfinderLabelShowHidden && !isNameplateVisible)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var scaleMultiplier = System.Math.Clamp(currentConfig.LightfinderLabelScale, 0.5f, 2.0f);
|
var scaleMultiplier = System.Math.Clamp(currentConfig.LightfinderLabelScale, 0.5f, 2.0f);
|
||||||
@@ -332,65 +354,84 @@ public unsafe class LightFinderPlateHandler : IHostedService, IMediatorSubscribe
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var res = nameContainer;
|
||||||
|
|
||||||
|
var worldScaleX = GetWorldScaleX(res);
|
||||||
|
if (worldScaleX <= 0f) worldScaleX = 1f;
|
||||||
|
|
||||||
|
var worldScaleY = GetWorldScaleY(res);
|
||||||
|
if (worldScaleY <= 0f) worldScaleY = 1f;
|
||||||
|
|
||||||
|
positionY += currentConfig.LightfinderLabelOffsetY;
|
||||||
|
var positionYScreen = positionY * worldScaleY;
|
||||||
|
|
||||||
float finalX;
|
float finalX;
|
||||||
if (currentConfig.LightfinderAutoAlign)
|
if (currentConfig.LightfinderAutoAlign)
|
||||||
{
|
{
|
||||||
var measuredWidth = System.Math.Max(1, textWidth > 0 ? textWidth : nodeWidth);
|
var measuredWidth = Math.Max(1, textWidth > 0 ? textWidth : nodeWidth);
|
||||||
var measuredWidthF = (float)measuredWidth;
|
var measuredWidthF = (float)measuredWidth;
|
||||||
var alignmentType = currentConfig.LabelAlignment;
|
|
||||||
|
|
||||||
var containerScale = nameContainer->ScaleX;
|
var containerWidthLocal = res->Width > 0 ? res->Width : measuredWidthF;
|
||||||
if (containerScale <= 0f)
|
var containerWidthScreen = containerWidthLocal * worldScaleX;
|
||||||
containerScale = 1f;
|
|
||||||
var containerWidthRaw = (float)nameContainer->Width;
|
|
||||||
if (containerWidthRaw <= 0f)
|
|
||||||
containerWidthRaw = measuredWidthF;
|
|
||||||
var containerWidth = containerWidthRaw * containerScale;
|
|
||||||
if (containerWidth <= 0f)
|
|
||||||
containerWidth = measuredWidthF;
|
|
||||||
|
|
||||||
var containerLeft = nameContainer->ScreenX;
|
var containerLeft = res->ScreenX;
|
||||||
var containerRight = containerLeft + containerWidth;
|
var containerRight = containerLeft + containerWidthScreen;
|
||||||
var containerCenter = containerLeft + (containerWidth * 0.5f);
|
var containerCenter = containerLeft + (containerWidthScreen * 0.5f);
|
||||||
|
|
||||||
var iconMargin = currentConfig.LightfinderLabelUseIcon
|
var iconMargin = currentConfig.LightfinderLabelUseIcon
|
||||||
? System.Math.Min(containerWidth * 0.1f, 14f * containerScale)
|
? MathF.Min(containerWidthScreen * 0.1f, 14f * worldScaleX)
|
||||||
: 0f;
|
: 0f;
|
||||||
|
|
||||||
switch (alignmentType)
|
var offsetXScreen = currentConfig.LightfinderLabelOffsetX * worldScaleX;
|
||||||
|
|
||||||
|
switch (currentConfig.LabelAlignment)
|
||||||
{
|
{
|
||||||
case LabelAlignment.Left:
|
case LabelAlignment.Left:
|
||||||
finalX = containerLeft + iconMargin;
|
finalX = containerLeft + iconMargin + offsetXScreen;
|
||||||
alignment = AlignmentType.BottomLeft;
|
alignment = AlignmentType.BottomLeft;
|
||||||
break;
|
break;
|
||||||
case LabelAlignment.Right:
|
case LabelAlignment.Right:
|
||||||
finalX = containerRight - iconMargin;
|
finalX = containerRight - iconMargin + offsetXScreen;
|
||||||
alignment = AlignmentType.BottomRight;
|
alignment = AlignmentType.BottomRight;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
finalX = containerCenter;
|
finalX = containerCenter + offsetXScreen;
|
||||||
alignment = AlignmentType.Bottom;
|
alignment = AlignmentType.Bottom;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
finalX += currentConfig.LightfinderLabelOffsetX;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var cachedTextOffset = _buffers.TextOffsets[nameplateIndex];
|
var cachedTextOffset = _buffers.TextOffsets[nameplateIndex];
|
||||||
var hasCachedOffset = cachedTextOffset != int.MinValue;
|
var hasCachedOffset = cachedTextOffset != int.MinValue;
|
||||||
var baseOffsetX = (!currentConfig.LightfinderLabelUseIcon && hasValidOffset && hasCachedOffset) ? cachedTextOffset : 0;
|
var baseOffsetXLocal = (!currentConfig.LightfinderLabelUseIcon && hasValidOffset && hasCachedOffset)
|
||||||
finalX = nameContainer->ScreenX + baseOffsetX + 58 + currentConfig.LightfinderLabelOffsetX;
|
? cachedTextOffset
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
finalX =
|
||||||
|
res->ScreenX
|
||||||
|
+ (baseOffsetXLocal * worldScaleX)
|
||||||
|
+ (58f * worldScaleX)
|
||||||
|
+ (currentConfig.LightfinderLabelOffsetX * worldScaleX);
|
||||||
|
|
||||||
alignment = AlignmentType.Bottom;
|
alignment = AlignmentType.Bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
positionY += currentConfig.LightfinderLabelOffsetY;
|
alignment = (AlignmentType)Math.Clamp((int)alignment, 0, 8);
|
||||||
alignment = (AlignmentType)System.Math.Clamp((int)alignment, 0, 8);
|
|
||||||
|
var finalPosition = new Vector2(finalX, res->ScreenY + positionYScreen);
|
||||||
|
var dpiScale = ImGui.GetIO().DisplayFramebufferScale.X; // often same for Y
|
||||||
|
var fw = Framework.Instance();
|
||||||
|
float dt = fw->RealFrameDeltaTime;
|
||||||
|
|
||||||
|
//smoothing..
|
||||||
|
finalPosition = SnapToPixels(finalPosition, dpiScale);
|
||||||
|
finalPosition = SmoothPosition(nameplateIndex, finalPosition, dt);
|
||||||
|
finalPosition = SnapToPixels(finalPosition, dpiScale);
|
||||||
|
|
||||||
var finalPosition = new Vector2(finalX, nameContainer->ScreenY + positionY);
|
|
||||||
var pivot = (currentConfig.LightfinderAutoAlign || currentConfig.LightfinderLabelUseIcon)
|
var pivot = (currentConfig.LightfinderAutoAlign || currentConfig.LightfinderLabelUseIcon)
|
||||||
? AlignmentToPivot(alignment)
|
? AlignmentToPivot(alignment)
|
||||||
: DefaultPivot;
|
: _defaultPivot;
|
||||||
var textColorPacked = PackColor(labelColor);
|
var textColorPacked = PackColor(labelColor);
|
||||||
var edgeColorPacked = PackColor(edgeColor);
|
var edgeColorPacked = PackColor(edgeColor);
|
||||||
|
|
||||||
@@ -423,6 +464,23 @@ public unsafe class LightFinderPlateHandler : IHostedService, IMediatorSubscribe
|
|||||||
if (!_mEnabled)
|
if (!_mEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
var fw = Framework.Instance();
|
||||||
|
if (fw == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var frame = fw->FrameCounter;
|
||||||
|
|
||||||
|
if (_lastNamePlateDrawFrame == 0 || (frame - _lastNamePlateDrawFrame) > 1)
|
||||||
|
{
|
||||||
|
ClearLabelBuffer();
|
||||||
|
Array.Clear(_buffers.HasSmoothed, 0, _buffers.HasSmoothed.Length);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsNamePlateAddonVisible())
|
||||||
|
return;
|
||||||
|
|
||||||
int copyCount;
|
int copyCount;
|
||||||
lock (_labelLock)
|
lock (_labelLock)
|
||||||
{
|
{
|
||||||
@@ -433,21 +491,78 @@ public unsafe class LightFinderPlateHandler : IHostedService, IMediatorSubscribe
|
|||||||
Array.Copy(_buffers.LabelRender, _buffers.LabelCopy, copyCount);
|
Array.Copy(_buffers.LabelRender, _buffers.LabelCopy, copyCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var uiModule = fw != null ? fw->GetUIModule() : null;
|
||||||
|
|
||||||
|
if (uiModule != null)
|
||||||
|
{
|
||||||
|
var rapture = uiModule->GetRaptureAtkModule();
|
||||||
|
if (rapture != null)
|
||||||
|
RefreshUiRects(&rapture->RaptureAtkUnitManager);
|
||||||
|
else
|
||||||
|
_uiRects.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_uiRects.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
var vp = ImGui.GetMainViewport();
|
||||||
|
var vpPos = vp.Pos;
|
||||||
|
|
||||||
|
ImGuiHelpers.ForceNextWindowMainViewport();
|
||||||
|
|
||||||
|
ImGui.SetNextWindowPos(vp.Pos);
|
||||||
|
ImGui.SetNextWindowSize(vp.Size);
|
||||||
|
|
||||||
|
ImGui.PushStyleVar(ImGuiStyleVar.WindowRounding, 0);
|
||||||
|
ImGui.PushStyleVar(ImGuiStyleVar.WindowBorderSize, 0);
|
||||||
|
|
||||||
|
ImGui.Begin("##LightFinderOverlay", _overlayFlags);
|
||||||
|
|
||||||
|
ImGui.PopStyleVar(2);
|
||||||
|
|
||||||
using var drawList = PictoService.Draw();
|
using var drawList = PictoService.Draw();
|
||||||
if (drawList == null)
|
if (drawList == null)
|
||||||
|
{
|
||||||
|
ImGui.End();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < copyCount; ++i)
|
for (int i = 0; i < copyCount; ++i)
|
||||||
{
|
{
|
||||||
ref var info = ref _buffers.LabelCopy[i];
|
ref var info = ref _buffers.LabelCopy[i];
|
||||||
|
|
||||||
|
var drawPos = info.ScreenPosition + vpPos;
|
||||||
var font = default(ImFontPtr);
|
var font = default(ImFontPtr);
|
||||||
if (info.UseIcon)
|
if (info.UseIcon)
|
||||||
{
|
{
|
||||||
var ioFonts = ImGui.GetIO().Fonts;
|
var ioFonts = ImGui.GetIO().Fonts;
|
||||||
font = ioFonts.Fonts.Size > 1 ? new ImFontPtr(ioFonts.Fonts[1]) : ImGui.GetFont();
|
font = ioFonts.Fonts.Size > 1 ? new ImFontPtr(ioFonts.Fonts[1]) : ImGui.GetFont();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
font = ImGui.GetFont();
|
||||||
|
}
|
||||||
|
|
||||||
drawList.AddScreenText(info.ScreenPosition, info.Text, info.TextColor, info.FontSize, info.Pivot, info.EdgeColor, font);
|
if (!font.IsNull)
|
||||||
|
ImGui.PushFont(font);
|
||||||
|
|
||||||
|
var baseSize = ImGui.CalcTextSize(info.Text);
|
||||||
|
var baseFontSize = ImGui.GetFontSize();
|
||||||
|
|
||||||
|
if (!font.IsNull)
|
||||||
|
ImGui.PopFont();
|
||||||
|
|
||||||
|
var scale = baseFontSize > 0 ? (info.FontSize / baseFontSize) : 1f;
|
||||||
|
var size = baseSize * scale;
|
||||||
|
|
||||||
|
var topLeft = info.ScreenPosition - new Vector2(size.X * info.Pivot.X, size.Y * info.Pivot.Y);
|
||||||
|
var labelRect = new RectF(topLeft.X, topLeft.Y, topLeft.X + size.X, topLeft.Y + size.Y);
|
||||||
|
|
||||||
|
if (IsOccludedByAnyUi(labelRect))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
drawList.AddScreenText(drawPos, info.Text, info.TextColor, info.FontSize, info.Pivot, info.EdgeColor, font);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,7 +575,7 @@ public unsafe class LightFinderPlateHandler : IHostedService, IMediatorSubscribe
|
|||||||
AlignmentType.Top => new Vector2(0.5f, 0f),
|
AlignmentType.Top => new Vector2(0.5f, 0f),
|
||||||
AlignmentType.Left => new Vector2(0f, 0.5f),
|
AlignmentType.Left => new Vector2(0f, 0.5f),
|
||||||
AlignmentType.Right => new Vector2(1f, 0.5f),
|
AlignmentType.Right => new Vector2(1f, 0.5f),
|
||||||
_ => DefaultPivot
|
_ => _defaultPivot
|
||||||
};
|
};
|
||||||
|
|
||||||
private static uint PackColor(Vector4 color)
|
private static uint PackColor(Vector4 color)
|
||||||
@@ -554,10 +669,132 @@ public unsafe class LightFinderPlateHandler : IHostedService, IMediatorSubscribe
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Vector2 SnapToPixels(Vector2 p, float dpiScale)
|
||||||
|
{
|
||||||
|
// snap to pixel grid
|
||||||
|
var x = MathF.Round(p.X * dpiScale) / dpiScale;
|
||||||
|
var y = MathF.Round(p.Y * dpiScale) / dpiScale;
|
||||||
|
return new Vector2(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector2 SmoothPosition(int idx, Vector2 target, float dt, float responsiveness = 24f)
|
||||||
|
{
|
||||||
|
// exponential smoothing
|
||||||
|
if (!_buffers.HasSmoothed[idx])
|
||||||
|
{
|
||||||
|
_buffers.HasSmoothed[idx] = true;
|
||||||
|
_buffers.SmoothedPos[idx] = target;
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cur = _buffers.SmoothedPos[idx];
|
||||||
|
|
||||||
|
// compute smoothing factor
|
||||||
|
var a = 1f - MathF.Exp(-responsiveness * dt);
|
||||||
|
|
||||||
|
if (Vector2.DistanceSquared(cur, target) < 0.25f)
|
||||||
|
return cur;
|
||||||
|
|
||||||
|
cur = Vector2.Lerp(cur, target, a);
|
||||||
|
_buffers.SmoothedPos[idx] = cur;
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryGetAddonRect(AtkUnitBase* addon, Vector2 screen, out RectF rect)
|
||||||
|
{
|
||||||
|
// validate addon visibility and size
|
||||||
|
rect = default;
|
||||||
|
if (addon == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var root = addon->RootNode;
|
||||||
|
if (root == null || !root->IsVisible())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
float w = root->Width;
|
||||||
|
float h = root->Height;
|
||||||
|
|
||||||
|
if (w <= 0 || h <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// apply scale
|
||||||
|
var sx = root->ScaleX; if (sx <= 0f) sx = 1f;
|
||||||
|
var sy = root->ScaleY; if (sy <= 0f) sy = 1f;
|
||||||
|
|
||||||
|
w *= sx;
|
||||||
|
h *= sy;
|
||||||
|
|
||||||
|
if (w < 4f || h < 4f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// compute screen rect
|
||||||
|
float l = root->ScreenX;
|
||||||
|
float t = root->ScreenY;
|
||||||
|
float r = l + w;
|
||||||
|
float b = t + h;
|
||||||
|
|
||||||
|
// cull too large or out-of-bounds rects
|
||||||
|
if (w >= screen.X * 0.98f && h >= screen.Y * 0.98f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (l < -screen.X || t < -screen.Y || r > screen.X * 2f || b > screen.Y * 2f)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
rect = new RectF(l, t, r, b);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshUiRects(RaptureAtkUnitManager* unitMgr)
|
||||||
|
{
|
||||||
|
_uiRects.Clear();
|
||||||
|
if (unitMgr == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var screen = ImGui.GetIO().DisplaySize;
|
||||||
|
|
||||||
|
ref var list = ref unitMgr->AllLoadedUnitsList;
|
||||||
|
var count = (int)list.Count;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var addon = list.Entries[i].Value;
|
||||||
|
if (addon == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (_mpNameplateAddon != null && addon == (AtkUnitBase*)_mpNameplateAddon)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (TryGetAddonRect(addon, screen, out var r))
|
||||||
|
_uiRects.Add(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsOccludedByAnyUi(RectF labelRect)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _uiRects.Count; i++)
|
||||||
|
{
|
||||||
|
if (_uiRects[i].Intersects(labelRect))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float GetWorldScaleX(AtkResNode* n)
|
||||||
|
{
|
||||||
|
var t = n->Transform;
|
||||||
|
return MathF.Sqrt(t.M11 * t.M11 + t.M12 * t.M12);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float GetWorldScaleY(AtkResNode* n)
|
||||||
|
{
|
||||||
|
var t = n->Transform;
|
||||||
|
return MathF.Sqrt(t.M21 * t.M21 + t.M22 * t.M22);
|
||||||
|
}
|
||||||
|
|
||||||
internal static string NormalizeIconGlyph(string? rawInput)
|
internal static string NormalizeIconGlyph(string? rawInput)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(rawInput))
|
if (string.IsNullOrWhiteSpace(rawInput))
|
||||||
return DefaultIconGlyph;
|
return _defaultIconGlyph;
|
||||||
|
|
||||||
var trimmed = rawInput.Trim();
|
var trimmed = rawInput.Trim();
|
||||||
|
|
||||||
@@ -575,7 +812,15 @@ public unsafe class LightFinderPlateHandler : IHostedService, IMediatorSubscribe
|
|||||||
if (enumerator.MoveNext())
|
if (enumerator.MoveNext())
|
||||||
return enumerator.Current.ToString();
|
return enumerator.Current.ToString();
|
||||||
|
|
||||||
return DefaultIconGlyph;
|
return _defaultIconGlyph;
|
||||||
|
}
|
||||||
|
private bool IsNamePlateAddonVisible()
|
||||||
|
{
|
||||||
|
if (_mpNameplateAddon == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var root = _mpNameplateAddon->AtkUnitBase.RootNode;
|
||||||
|
return root != null && root->IsVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string ToIconEditorString(string? rawInput)
|
internal static string ToIconEditorString(string? rawInput)
|
||||||
@@ -584,7 +829,7 @@ public unsafe class LightFinderPlateHandler : IHostedService, IMediatorSubscribe
|
|||||||
var runeEnumerator = normalized.EnumerateRunes();
|
var runeEnumerator = normalized.EnumerateRunes();
|
||||||
return runeEnumerator.MoveNext()
|
return runeEnumerator.MoveNext()
|
||||||
? runeEnumerator.Current.Value.ToString("X4", CultureInfo.InvariantCulture)
|
? runeEnumerator.Current.Value.ToString("X4", CultureInfo.InvariantCulture)
|
||||||
: DefaultIconGlyph;
|
: _defaultIconGlyph;
|
||||||
}
|
}
|
||||||
private readonly struct NameplateLabelInfo
|
private readonly struct NameplateLabelInfo
|
||||||
{
|
{
|
||||||
@@ -650,6 +895,9 @@ public unsafe class LightFinderPlateHandler : IHostedService, IMediatorSubscribe
|
|||||||
{
|
{
|
||||||
_buffers.Clear();
|
_buffers.Clear();
|
||||||
ClearLabelBuffer();
|
ClearLabelBuffer();
|
||||||
|
|
||||||
|
Array.Clear(_buffers.HasSmoothed, 0, _buffers.HasSmoothed.Length);
|
||||||
|
Array.Clear(_buffers.SmoothedPos, 0, _buffers.SmoothedPos.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class NameplateBuffers
|
private sealed class NameplateBuffers
|
||||||
@@ -668,6 +916,10 @@ public unsafe class LightFinderPlateHandler : IHostedService, IMediatorSubscribe
|
|||||||
public NameplateLabelInfo[] LabelRender { get; } = new NameplateLabelInfo[AddonNamePlate.NumNamePlateObjects];
|
public NameplateLabelInfo[] LabelRender { get; } = new NameplateLabelInfo[AddonNamePlate.NumNamePlateObjects];
|
||||||
public NameplateLabelInfo[] LabelCopy { get; } = new NameplateLabelInfo[AddonNamePlate.NumNamePlateObjects];
|
public NameplateLabelInfo[] LabelCopy { get; } = new NameplateLabelInfo[AddonNamePlate.NumNamePlateObjects];
|
||||||
|
|
||||||
|
public Vector2[] SmoothedPos = new Vector2[AddonNamePlate.NumNamePlateObjects];
|
||||||
|
|
||||||
|
public bool[] HasSmoothed = new bool[AddonNamePlate.NumNamePlateObjects];
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
System.Array.Clear(TextWidths, 0, TextWidths.Length);
|
System.Array.Clear(TextWidths, 0, TextWidths.Length);
|
||||||
@@ -689,4 +941,13 @@ public unsafe class LightFinderPlateHandler : IHostedService, IMediatorSubscribe
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
|
private readonly struct RectF
|
||||||
|
{
|
||||||
|
public readonly float L, T, R, B;
|
||||||
|
public RectF(float l, float t, float r, float b) { L = l; T = t; R = r; B = b; }
|
||||||
|
|
||||||
|
public bool Intersects(in RectF o) =>
|
||||||
|
!(R <= o.L || o.R <= L || B <= o.T || o.B <= T);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user