using Dalamud.Bindings.ImGui; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Interface; using Dalamud.Interface.ImGuiSeStringRenderer; using Dalamud.Interface.Utility; using System.Numerics; namespace LightlessSync.Utils; public static class SeStringUtils { public static SeString BuildFormattedPlayerName(string text, Vector4? textColor, Vector4? glowColor) { var b = new SeStringBuilder(); if (glowColor is Vector4 glow) b.Add(new GlowPayload(glow)); if (textColor is Vector4 color) b.Add(new ColorPayload(color)); b.AddText(text ?? string.Empty); if (textColor is not null) b.Add(new ColorEndPayload()); if (glowColor is not null) b.Add(new GlowEndPayload()); return b.Build(); } public static SeString BuildPlain(string text) { var b = new SeStringBuilder(); b.AddText(text ?? string.Empty); return b.Build(); } public static void RenderSeString(SeString seString, Vector2 position, ImFontPtr? font = null, ImDrawListPtr? drawList = null) { drawList ??= ImGui.GetWindowDrawList(); var drawParams = new SeStringDrawParams { Font = font ?? UiBuilder.MonoFont, Color = 0xFFFFFFFF, WrapWidth = float.MaxValue, TargetDrawList = drawList }; ImGui.SetCursorScreenPos(position); ImGuiHelpers.SeStringWrapped(seString.Encode(), drawParams); } public static Vector2 RenderSeStringWithHitbox(SeString seString, Vector2 position, ImFontPtr? font = null) { var drawList = ImGui.GetWindowDrawList(); var drawParams = new SeStringDrawParams { Font = font ?? UiBuilder.MonoFont, Color = 0xFFFFFFFF, WrapWidth = float.MaxValue, TargetDrawList = drawList }; ImGui.SetCursorScreenPos(position); ImGuiHelpers.SeStringWrapped(seString.Encode(), drawParams); var textSize = ImGui.CalcTextSize(seString.TextValue); ImGui.SetCursorScreenPos(position); ImGui.InvisibleButton($"##hitbox_{Guid.NewGuid()}", textSize); return textSize; } public static Vector2 RenderIconWithHitbox(int iconId, Vector2 position, ImFontPtr? font = null) { var drawList = ImGui.GetWindowDrawList(); var drawParams = new SeStringDrawParams { Font = font ?? UiBuilder.MonoFont, Color = 0xFFFFFFFF, WrapWidth = float.MaxValue, TargetDrawList = drawList }; var iconMacro = $""; var drawResult = ImGuiHelpers.CompileSeStringWrapped(iconMacro, drawParams); ImGui.SetCursorScreenPos(position); ImGui.InvisibleButton($"##iconHitbox_{Guid.NewGuid()}", drawResult.Size); return drawResult.Size; } #region Internal Payloads private abstract class AbstractColorPayload : Payload { protected byte Red { get; init; } protected byte Green { get; init; } protected byte Blue { get; init; } protected override byte[] EncodeImpl() { return new byte[] { 0x02, ChunkType, 0x05, 0xF6, Red, Green, Blue, 0x03 }; } protected override void DecodeImpl(BinaryReader reader, long endOfStream) { } public override PayloadType Type => PayloadType.Unknown; protected abstract byte ChunkType { get; } } private abstract class AbstractColorEndPayload : Payload { protected override byte[] EncodeImpl() { return new byte[] { 0x02, ChunkType, 0x02, 0xEC, 0x03 }; } protected override void DecodeImpl(BinaryReader reader, long endOfStream) { } public override PayloadType Type => PayloadType.Unknown; protected abstract byte ChunkType { get; } } private class ColorPayload : AbstractColorPayload { protected override byte ChunkType => 0x13; public ColorPayload(Vector3 color) { Red = Math.Max((byte)1, (byte)(color.X * 255f)); Green = Math.Max((byte)1, (byte)(color.Y * 255f)); Blue = Math.Max((byte)1, (byte)(color.Z * 255f)); } public ColorPayload(Vector4 color) : this(new Vector3(color.X, color.Y, color.Z)) { } } private class ColorEndPayload : AbstractColorEndPayload { protected override byte ChunkType => 0x13; } private class GlowPayload : AbstractColorPayload { protected override byte ChunkType => 0x14; public GlowPayload(Vector3 color) { Red = Math.Max((byte)1, (byte)(color.X * 255f)); Green = Math.Max((byte)1, (byte)(color.Y * 255f)); Blue = Math.Max((byte)1, (byte)(color.Z * 255f)); } public GlowPayload(Vector4 color) : this(new Vector3(color.X, color.Y, color.Z)) { } } private class GlowEndPayload : AbstractColorEndPayload { protected override byte ChunkType => 0x14; } #endregion }