From 4dbf27089a32e0ef8a2f3fa1a174cf888034ee79 Mon Sep 17 00:00:00 2001 From: Bernardo Lopes Date: Mon, 20 Mar 2023 10:46:03 -0300 Subject: [PATCH 1/3] Create framework for YesHealMe (AU NoTankYou). --- Dalamud/Fools/FoolsManager.cs | 10 +++ Dalamud/Fools/Helper/YesHealMe/HudHelper.cs | 41 ++++++++++++ .../Fools/Helper/YesHealMe/PartyListAddon.cs | 67 +++++++++++++++++++ .../Helper/YesHealMe/PartyListAddonData.cs | 37 ++++++++++ Dalamud/Fools/Plugins/YesHealMePlugin.cs | 32 +++++++++ 5 files changed, 187 insertions(+) create mode 100644 Dalamud/Fools/Helper/YesHealMe/HudHelper.cs create mode 100644 Dalamud/Fools/Helper/YesHealMe/PartyListAddon.cs create mode 100644 Dalamud/Fools/Helper/YesHealMe/PartyListAddonData.cs create mode 100644 Dalamud/Fools/Plugins/YesHealMePlugin.cs diff --git a/Dalamud/Fools/FoolsManager.cs b/Dalamud/Fools/FoolsManager.cs index b85c2ee24..a8fa3d624 100644 --- a/Dalamud/Fools/FoolsManager.cs +++ b/Dalamud/Fools/FoolsManager.cs @@ -135,6 +135,16 @@ internal class FoolsManager : IDisposable, IServiceType RealAuthor = "Chirp", Type = typeof(GoodVibesPlugin), }, + new() + { + Name = "YesHealMe", + InternalName = "YesHealMePlugin", + Description = "The only warning you need.", + Author = "MidoriKami", + RealAuthor = "Berna", + Type = typeof(YesHealMePlugin), + }, + }; } diff --git a/Dalamud/Fools/Helper/YesHealMe/HudHelper.cs b/Dalamud/Fools/Helper/YesHealMe/HudHelper.cs new file mode 100644 index 000000000..6de258c6e --- /dev/null +++ b/Dalamud/Fools/Helper/YesHealMe/HudHelper.cs @@ -0,0 +1,41 @@ +using Dalamud; +using Dalamud.Game.ClientState.Objects; +using Dalamud.Game.ClientState.Objects.SubKinds; +using FFXIVClientStructs.FFXIV.Client.UI.Agent; + +namespace NoTankYou.Utilities; + +public static unsafe class HudHelper +{ + private static AgentHUD* AgentHud => AgentModule.Instance()->GetAgentHUD(); + + public static PlayerCharacter? GetPlayerCharacter(int index) + { + // Sorta temporary, waiting for ClientStructs to merge a fixed size array for this element + var partyMemberList = AgentHud->PartyMemberList; + var targetOffset = index * sizeof(HudPartyMember); + var targetAddress = partyMemberList + targetOffset; + var hudData = (HudPartyMember*) targetAddress; + + var targetPlayer = hudData->ObjectId; + + return GetPlayer(targetPlayer); + } + + public static PlayerCharacter? GetAllianceMember(int index) + { + var targetPlayer = AgentHud->RaidMemberIds[index]; + + return GetPlayer(targetPlayer); + } + + private static PlayerCharacter? GetPlayer(uint objectId) + { + var result = Service.Get().SearchById(objectId); + + if (result?.GetType() == typeof(PlayerCharacter)) + return result as PlayerCharacter; + + return null; + } +} diff --git a/Dalamud/Fools/Helper/YesHealMe/PartyListAddon.cs b/Dalamud/Fools/Helper/YesHealMe/PartyListAddon.cs new file mode 100644 index 000000000..a2b106b40 --- /dev/null +++ b/Dalamud/Fools/Helper/YesHealMe/PartyListAddon.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Dalamud; +using Dalamud.Game; +using Dalamud.Game.Gui; +using FFXIVClientStructs.FFXIV.Client.UI; +using NoTankYou.DataModels; +using NoTankYou.Utilities; + +namespace NoTankYou.System; + +public unsafe class PartyListAddon : IEnumerable, IDisposable +{ + public record PartyFramePositionInfo(Vector2 Position, Vector2 Size, Vector2 Scale); + public IEnumerator GetEnumerator() => addonData.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + private static AddonPartyList* PartyList => (AddonPartyList*) Service.Get()?.GetAddonByName("_PartyList"); + public static bool DataAvailable => PartyList != null && PartyList->AtkUnitBase.RootNode != null; + + private readonly List addonData = new(); + + public PartyListAddon() + { + Service.Get().Update += OnFrameworkUpdate; + } + + public void Dispose() + { + Service.Get().Update -= OnFrameworkUpdate; + } + + private void OnFrameworkUpdate(Framework framework) + { + addonData.Clear(); + if (!DataAvailable) return; + if (PartyList->MemberCount <= 0) return; + + foreach (var index in Enumerable.Range(0, PartyList->MemberCount)) + { + var playerCharacter = HudHelper.GetPlayerCharacter(index); + var userInterface = PartyList->PartyMember[index]; + + addonData.Add(new PartyListAddonData + { + PlayerCharacter = playerCharacter, + UserInterface = userInterface, + }); + } + } + + public static PartyFramePositionInfo GetPositionInfo() + { + // Resource Node (id 9) contains a weird offset for the actual list elements + var rootNode = PartyList->AtkUnitBase.RootNode; + var addonBasePosition = new Vector2(rootNode->X, rootNode->Y); + var scale = new Vector2(rootNode->ScaleX, rootNode->ScaleY); + + var partyListNode = PartyList->AtkUnitBase.GetNodeById(9); + var partyListPositionOffset = new Vector2(partyListNode->X, partyListNode->Y) * scale; + var partyListSize = new Vector2(partyListNode->Width, partyListNode->Height); + + return new PartyFramePositionInfo(addonBasePosition + partyListPositionOffset, partyListSize * scale, scale); + } +} diff --git a/Dalamud/Fools/Helper/YesHealMe/PartyListAddonData.cs b/Dalamud/Fools/Helper/YesHealMe/PartyListAddonData.cs new file mode 100644 index 000000000..b9989ab0b --- /dev/null +++ b/Dalamud/Fools/Helper/YesHealMe/PartyListAddonData.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using Dalamud.Game.ClientState.Objects.SubKinds; +using FFXIVClientStructs.FFXIV.Client.UI; + +namespace NoTankYou.DataModels; + +public readonly unsafe struct PartyListAddonData +{ + private static readonly Dictionary TimeSinceLastTargetable = new(); + + public AddonPartyList.PartyListMemberStruct UserInterface { get; init; } + public PlayerCharacter? PlayerCharacter { get; init; } + + private bool Targetable => UserInterface.PartyMemberComponent->OwnerNode->AtkResNode.Color.A != 0x99; + + public bool IsTargetable() + { + if (PlayerCharacter is null) return false; + + TimeSinceLastTargetable.TryAdd(PlayerCharacter.ObjectId, Stopwatch.StartNew()); + var stopwatch = TimeSinceLastTargetable[PlayerCharacter.ObjectId]; + + if (Targetable) + { + // Returns true if the party member has been targetable for 2second or more + return stopwatch.Elapsed >= TimeSpan.FromSeconds(2); + } + else + { + // Returns false, and continually resets the stopwatch + stopwatch.Restart(); + return false; + } + } +} \ No newline at end of file diff --git a/Dalamud/Fools/Plugins/YesHealMePlugin.cs b/Dalamud/Fools/Plugins/YesHealMePlugin.cs new file mode 100644 index 000000000..5b416b0a6 --- /dev/null +++ b/Dalamud/Fools/Plugins/YesHealMePlugin.cs @@ -0,0 +1,32 @@ +using System.Linq; +using Dalamud.Logging; +using NoTankYou.System; + +namespace Dalamud.Fools.Plugins; + +public class YesHealMePlugin: IFoolsPlugin +{ + private PartyListAddon partyListAddon; + + public YesHealMePlugin() + { + partyListAddon = new PartyListAddon(); + } + + public void DrawUi() + { + foreach (var partyMember in this.partyListAddon.Select(pla => pla.PlayerCharacter).Where(pc => pc is not null)) + { + if (partyMember.CurrentHp < partyMember.MaxHp) + { + // Do things here + } + } + } + + + public void Dispose() + { + this.partyListAddon.Dispose(); + } +} From dd2b842723f88082449c76362c157b34841770db Mon Sep 17 00:00:00 2001 From: Bernardo Lopes Date: Mon, 20 Mar 2023 11:12:12 -0300 Subject: [PATCH 2/3] Change DailyLifeDuty description. --- Dalamud/Fools/FoolsManager.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Dalamud/Fools/FoolsManager.cs b/Dalamud/Fools/FoolsManager.cs index a8fa3d624..d81d1dbe6 100644 --- a/Dalamud/Fools/FoolsManager.cs +++ b/Dalamud/Fools/FoolsManager.cs @@ -85,7 +85,7 @@ internal class FoolsManager : IDisposable, IServiceType { Name = "DailyLifeDuty", InternalName = "DailyLifeDutyPlugin", - Description = "Easily Track Daily and Weekly tasks... in real life", + Description = "We were just informed there are these things called \"chores\" outside the game. No worries, though, we can track them!", Author = "MidoriKami", RealAuthor = "Berna", Type = typeof(DailyLifeDutyPlugin), @@ -144,7 +144,6 @@ internal class FoolsManager : IDisposable, IServiceType RealAuthor = "Berna", Type = typeof(YesHealMePlugin), }, - }; } From b91ce2c46fb10591d5e58cbf5f1c993322dbaa3b Mon Sep 17 00:00:00 2001 From: Bernardo Lopes Date: Mon, 20 Mar 2023 11:15:13 -0300 Subject: [PATCH 3/3] [Fools-YesHealMePlugin] Finished implementation. --- Dalamud/Fools/FoolsManager.cs | 2 +- Dalamud/Fools/Helper/YesHealMe/Colors.cs | 31 ++++++ .../Fools/Helper/YesHealMe/DrawUtilities.cs | 99 +++++++++++++++++++ Dalamud/Fools/Helper/YesHealMe/FontManager.cs | 20 ++++ Dalamud/Fools/Helper/YesHealMe/IconCache.cs | 70 +++++++++++++ Dalamud/Fools/Plugins/YesHealMePlugin.cs | 35 ++++--- .../Fools/Plugins/YesHealMePluginWindow.cs | 97 ++++++++++++++++++ 7 files changed, 335 insertions(+), 19 deletions(-) create mode 100644 Dalamud/Fools/Helper/YesHealMe/Colors.cs create mode 100644 Dalamud/Fools/Helper/YesHealMe/DrawUtilities.cs create mode 100644 Dalamud/Fools/Helper/YesHealMe/FontManager.cs create mode 100644 Dalamud/Fools/Helper/YesHealMe/IconCache.cs create mode 100644 Dalamud/Fools/Plugins/YesHealMePluginWindow.cs diff --git a/Dalamud/Fools/FoolsManager.cs b/Dalamud/Fools/FoolsManager.cs index d81d1dbe6..761dd0c08 100644 --- a/Dalamud/Fools/FoolsManager.cs +++ b/Dalamud/Fools/FoolsManager.cs @@ -139,7 +139,7 @@ internal class FoolsManager : IDisposable, IServiceType { Name = "YesHealMe", InternalName = "YesHealMePlugin", - Description = "The only warning you need.", + Description = "As the saying goes: it's the first missing HP that matters. And the second. And the third...", Author = "MidoriKami", RealAuthor = "Berna", Type = typeof(YesHealMePlugin), diff --git a/Dalamud/Fools/Helper/YesHealMe/Colors.cs b/Dalamud/Fools/Helper/YesHealMe/Colors.cs new file mode 100644 index 000000000..9828fe54b --- /dev/null +++ b/Dalamud/Fools/Helper/YesHealMe/Colors.cs @@ -0,0 +1,31 @@ +using System.Numerics; +using ImGuiNET; + +namespace Dalamud.Fools.Helper.YesHealMe; + +public static class Colors +{ + public static Vector4 Purple = new(176 / 255.0f, 38 / 255.0f, 236 / 255.0f, 1.0f); + public static Vector4 Blue = new(37 / 255.0f, 168 / 255.0f, 1.0f, 1.0f); + public static Vector4 ForestGreen = new(0.133f, 0.545f, 0.1333f, 1.0f); + public static Vector4 White = new(1.0f, 1.0f, 1.0f,1.0f); + public static Vector4 Red = new(1.0f, 0.0f, 0.0f, 1.0f); + public static Vector4 Green = new(0.0f, 1.0f, 0.0f, 1.0f); + public static Vector4 Black = new(0.0f, 0.0f, 0.0f, 1.0f); + public static Vector4 HealerGreen = new(33 / 255f, 193 / 255f, 0, 1.0f); + public static Vector4 DPSRed = new(210/255f, 42/255f, 43/255f, 1.0f); + public static Vector4 SoftRed = new(0.8f, 0.2f, 0.2f, 1.0f); + public static Vector4 Grey = new(0.6f, 0.6f, 0.6f, 1.0f); + public static Vector4 LightGrey = new(220/250.0f, 220/250.0f, 220/250f, 1.0f); + public static Vector4 Orange = new(1.0f, 165.0f / 255.0f, 0.0f, 1.0f); + public static Vector4 SoftGreen = new(0.2f, 0.8f, 0.2f, 1.0f); + public static Vector4 FatePink = new(0.58f, 0.388f, 0.827f, 0.33f); + public static Vector4 FateDarkPink = new(0.58f, 0.388f, 0.827f, 1.0f); + public static Vector4 MapTextBrown = new(0.655f, 0.396f, 0.149f, 1.0f); + public static Vector4 BabyBlue = new(0.537f, 0.812f, 0.941f, 1.0f); +} + +public static class ColorExtensions +{ + public static uint ToU32(this Vector4 color) => ImGui.GetColorU32(color); +} diff --git a/Dalamud/Fools/Helper/YesHealMe/DrawUtilities.cs b/Dalamud/Fools/Helper/YesHealMe/DrawUtilities.cs new file mode 100644 index 000000000..38bc401ad --- /dev/null +++ b/Dalamud/Fools/Helper/YesHealMe/DrawUtilities.cs @@ -0,0 +1,99 @@ +using System; +using System.Numerics; +using ImGuiNET; +using KamiLib.Caching; + +namespace Dalamud.Fools.Helper.YesHealMe; + +internal static class DrawUtilities +{ + public static void TextOutlined(FontManager fontManager, Vector2 startingPosition, string text, float scale, Vector4 color) + { + startingPosition = startingPosition.Ceil(); + + var outlineThickness = (int)MathF.Ceiling(1 * scale); + + for (var x = -outlineThickness; x <= outlineThickness; ++x) + { + for (var y = -outlineThickness; y <= outlineThickness; ++y) + { + if (x == 0 && y == 0) + { + continue; + } + + DrawText(fontManager, startingPosition + new Vector2(x, y), text, Colors.Black, scale); + } + } + + DrawText(fontManager, startingPosition, text, color, scale); + } + + public static void DrawIconWithName(FontManager fontManager, Vector2 drawPosition, uint iconID, string name, float iconScale, float textScale, bool drawText = true) + { + if (!fontManager.GameFont.Available) return; + + var icon = IconCache.Instance.GetIcon(iconID); + if (icon != null) + { + var drawList = ImGui.GetBackgroundDrawList(); + + var imagePadding = new Vector2(20.0f, 10.0f) * iconScale; + var imageSize = new Vector2(50.0f, 50.0f) * iconScale; + + drawPosition += imagePadding; + + drawList.AddImage(icon.ImGuiHandle, drawPosition, drawPosition + imageSize); + + if (drawText) + { + drawPosition.X += imageSize.X / 2.0f; + drawPosition.Y += imageSize.Y + 2.0f * iconScale; + + var textSize = CalculateTextSize(fontManager, name, textScale / 2.75f); + var textOffset = new Vector2(0.0f, 5.0f) * iconScale; + + drawPosition.X -= textSize.X / 2.0f; + + TextOutlined(fontManager, drawPosition + textOffset, name, textScale / 2.75f, Colors.White); + } + } + } + + public static Vector2 CalculateTextSize(FontManager fontManager, string text, float scale) + { + if(!fontManager.GameFont.Available) return Vector2.Zero; + + var fontSize = fontManager.GameFont.ImFont.FontSize; + var textSize = ImGui.CalcTextSize(text); + var fontScalar = 62.0f / textSize.Y; + + var textWidth = textSize.X * fontScalar; + + return new Vector2(textWidth, fontSize) * scale; + } + + private static void DrawText(FontManager fontManager, Vector2 drawPosition, string text, Vector4 color, float scale, bool debug = false) + { + if (!fontManager.GameFont.Available) return; + var font = fontManager.GameFont.ImFont; + + var drawList = ImGui.GetBackgroundDrawList(); + var stringSize = CalculateTextSize(fontManager, text, scale); + + if (debug) + { + drawList.AddRect(drawPosition, drawPosition + stringSize, ImGui.GetColorU32(Colors.Green)); + } + + drawList.AddText(font, font.FontSize * scale, drawPosition, ImGui.GetColorU32(color), text); + } +} + +public static class VectorExtensions +{ + public static Vector2 Ceil(this Vector2 data) + { + return new Vector2(MathF.Ceiling(data.X), MathF.Ceiling(data.Y)); + } +} diff --git a/Dalamud/Fools/Helper/YesHealMe/FontManager.cs b/Dalamud/Fools/Helper/YesHealMe/FontManager.cs new file mode 100644 index 000000000..d7ea88fd0 --- /dev/null +++ b/Dalamud/Fools/Helper/YesHealMe/FontManager.cs @@ -0,0 +1,20 @@ +using System; +using Dalamud.Interface; +using Dalamud.Interface.GameFonts; + +namespace Dalamud.Fools.Helper.YesHealMe; + +public class FontManager : IDisposable +{ + public GameFontHandle GameFont { get; } + + public FontManager(UiBuilder uiBuilder) + { + this.GameFont = uiBuilder.GetGameFontHandle( new GameFontStyle( GameFontFamily.Axis, 52.0f ) ); + } + + public void Dispose() + { + this.GameFont.Dispose(); + } +} diff --git a/Dalamud/Fools/Helper/YesHealMe/IconCache.cs b/Dalamud/Fools/Helper/YesHealMe/IconCache.cs new file mode 100644 index 000000000..0a64d030e --- /dev/null +++ b/Dalamud/Fools/Helper/YesHealMe/IconCache.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Dalamud; +using Dalamud.Data; +using Dalamud.Logging; +using Dalamud.Utility; +using ImGuiScene; + +namespace KamiLib.Caching; + +public class IconCache : IDisposable +{ + private readonly Dictionary iconTextures = new(); + + private const string IconFilePath = "ui/icon/{0:D3}000/{1:D6}_hr1.tex"; + + private static IconCache? _instance; + public static IconCache Instance => _instance ??= new IconCache(); + + public static void Cleanup() + { + _instance?.Dispose(); + } + + public void Dispose() + { + foreach (var texture in iconTextures.Values) + { + texture?.Dispose(); + } + + iconTextures.Clear(); + } + + private void LoadIconTexture(uint iconId) + { + Task.Run(() => + { + try + { + var path = IconFilePath.Format(iconId / 1000, iconId); + var tex = Service.Get().GetImGuiTexture(path); + + if (tex is not null && tex.ImGuiHandle != nint.Zero) + { + iconTextures[iconId] = tex; + } + else + { + tex?.Dispose(); + } + } + catch (Exception ex) + { + PluginLog.LogError($"Failed loading texture for icon {iconId} - {ex.Message}"); + } + }); + } + + public TextureWrap? GetIcon(uint iconId) + { + if (iconTextures.TryGetValue(iconId, out var value)) return value; + + iconTextures.Add(iconId, null); + LoadIconTexture(iconId); + + return iconTextures[iconId]; + } +} diff --git a/Dalamud/Fools/Plugins/YesHealMePlugin.cs b/Dalamud/Fools/Plugins/YesHealMePlugin.cs index 5b416b0a6..b33d24e0e 100644 --- a/Dalamud/Fools/Plugins/YesHealMePlugin.cs +++ b/Dalamud/Fools/Plugins/YesHealMePlugin.cs @@ -1,32 +1,31 @@ -using System.Linq; -using Dalamud.Logging; +using Dalamud.Fools.Helper.YesHealMe; +using Dalamud.Interface; using NoTankYou.System; namespace Dalamud.Fools.Plugins; -public class YesHealMePlugin: IFoolsPlugin +public class YesHealMePlugin : IFoolsPlugin { - private PartyListAddon partyListAddon; + private readonly FontManager fontManager; + private readonly PartyListAddon partyListAddon = new(); + private int iconId = 1; public YesHealMePlugin() { - partyListAddon = new PartyListAddon(); + const string nameSpace = "fools+YesHealMe"; + var uiBuilder = new UiBuilder(nameSpace); + this.fontManager = new FontManager(uiBuilder); + } + + /// + public void Dispose() + { + this.fontManager.Dispose(); + this.partyListAddon.Dispose(); } public void DrawUi() { - foreach (var partyMember in this.partyListAddon.Select(pla => pla.PlayerCharacter).Where(pc => pc is not null)) - { - if (partyMember.CurrentHp < partyMember.MaxHp) - { - // Do things here - } - } - } - - - public void Dispose() - { - this.partyListAddon.Dispose(); + YesHealMePluginWindow.Draw(this.partyListAddon, this.fontManager, ref this.iconId); } } diff --git a/Dalamud/Fools/Plugins/YesHealMePluginWindow.cs b/Dalamud/Fools/Plugins/YesHealMePluginWindow.cs new file mode 100644 index 000000000..36dfc2a44 --- /dev/null +++ b/Dalamud/Fools/Plugins/YesHealMePluginWindow.cs @@ -0,0 +1,97 @@ +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Dalamud.Data; +using Dalamud.Fools.Helper.YesHealMe; +using Dalamud.Game.ClientState; +using Dalamud.Game.ClientState.Objects.SubKinds; +using Dalamud.Game.Text.SeStringHandling; +using Dalamud.Game.Text.SeStringHandling.Payloads; +using Dalamud.Interface.Components; +using Dalamud.Interface.Internal; +using ImGuiNET; +using NoTankYou.System; + +namespace Dalamud.Fools.Plugins; + +public static class YesHealMePluginWindow +{ + private const string WindowName = "##foolsYesHealMeBanner"; + private const string WarningText = "HEAL ME"; + private const int Length = 300; + private const int SectionHeight = 100; + private const float Scale = 1f; + private static readonly Vector2 Position = new(200, 200); + private static readonly Vector2 Size = new(Length, SectionHeight); + + private static IEnumerable Characters(PartyListAddon partyListAddon) + { + return partyListAddon.Any() ? partyListAddon.Select(pla => pla.PlayerCharacter) : new[] { Service.Get().LocalPlayer }; + } + + private static List HurtingCharacters(IEnumerable characters) + { + return characters + .Where(pc => pc.CurrentHp < pc.MaxHp || + Service.Get() + .IsDevMenuOpen) + .ToList(); + } + + public static void Draw(PartyListAddon partyListAddon, FontManager fontManager, ref int iconId) + { + ImGui.SetNextWindowPos(Position, ImGuiCond.FirstUseEver); + ImGui.SetNextWindowSize(Size); + ImGui.SetNextWindowSizeConstraints(Size, Size); + ImGui.Begin(WindowName, ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoBackground); + var playersDrawn = 0; + var hurtingCharacters = HurtingCharacters(Characters(partyListAddon)); + if (hurtingCharacters.Count > 0) + { + var windowPos = ImGui.GetCursorScreenPos(); + foreach (var hurtingCharacter in hurtingCharacters) + { + var position = windowPos + new Vector2(0, playersDrawn * SectionHeight); + var healMeTextSize = DrawUtilities.CalculateTextSize(fontManager, WarningText, Scale); + var healMePosition = position with + { + X = position.X + healMeTextSize.X, + }; + DrawHealMeText(fontManager, position); + DrawPlayerName(fontManager, hurtingCharacter, healMePosition); + DrawIcon(fontManager, healMePosition); + playersDrawn += 1; + } + } + + ImGui.End(); + } + + private static void DrawIcon(FontManager fontManager, Vector2 healMePosition) + { + DrawUtilities.DrawIconWithName(fontManager, healMePosition, 62582, "pls? owo", 1, 1); + } + + private static void DrawHealMeText(FontManager fontManager, Vector2 position) + { + // HEAL ME text + DrawUtilities.TextOutlined(fontManager, position, WarningText, 1, Colors.White); + } + + private static void DrawPlayerName( + FontManager fontManager, PlayerCharacter hurtingCharacter, Vector2 healMePosition) + { + var textSize = DrawUtilities.CalculateTextSize(fontManager, hurtingCharacter.Name.TextValue, Scale); + var namePosition = new Vector2 + { + X = healMePosition.X - textSize.X / 2.0f, + Y = healMePosition.Y + textSize.Y, + }; + DrawUtilities.TextOutlined( + fontManager, + namePosition, + hurtingCharacter.Name.TextValue, + Scale / 2f, + Colors.White); + } +}