Release 1.0.5.0: World Object Tooltip (hover tooltip, detach option), version bump, pluginmaster

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-02-01 01:22:58 -05:00
parent d30f42d4c8
commit 048f6451c8
6 changed files with 161 additions and 10 deletions
+145
View File
@@ -1,3 +1,5 @@
using Dalamud.Game.ClientState.Objects.SubKinds;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using HSUI.Config;
@@ -6,6 +8,7 @@ using HSUI.Interface.GeneralElements;
using Dalamud.Bindings.ImGui;
using System;
using System.Numerics;
using System.Text;
namespace HSUI.Helpers
{
@@ -124,6 +127,109 @@ namespace HSUI.Helpers
Plugin.Logger.Information($"[HSUI Tooltip DBG] ShowTooltip: title='{title}' textLen={text?.Length ?? 0} textPreview='{(text != null && text.Length > 80 ? text[..80] + "..." : text ?? "")}' pos=({_position.X:F0},{_position.Y:F0})");
}
private WorldObjectTooltipConfig? _worldTooltipConfig;
/// <summary>
/// Shows a tooltip for the game object the mouse is hovering over in the 3D world.
/// Call this each frame before Draw().
/// </summary>
public void ShowWorldObjectTooltip()
{
try
{
_worldTooltipConfig ??= ConfigurationManager.Instance.GetConfigObject<WorldObjectTooltipConfig>();
if (_worldTooltipConfig == null || !_worldTooltipConfig.Enabled)
return;
}
catch (Exception ex)
{
// Config not ready yet or not found - silently skip
if (_config.DebugTooltips)
Plugin.Logger.Warning($"[HSUI Tooltip] WorldObjectTooltipConfig not available: {ex.Message}");
return;
}
IGameObject? mouseOverTarget = Plugin.TargetManager.MouseOverTarget;
if (mouseOverTarget == null)
return;
// Don't show tooltip for ourselves
if (mouseOverTarget.GameObjectId == Plugin.ObjectTable.LocalPlayer?.GameObjectId)
return;
string name = mouseOverTarget.Name.ToString();
if (string.IsNullOrEmpty(name))
name = "Unknown";
var sb = new StringBuilder();
// Free Company tag for players
if (_worldTooltipConfig.ShowTitle && mouseOverTarget is IPlayerCharacter player)
{
string fcTag = player.CompanyTag.ToString();
if (!string.IsNullOrEmpty(fcTag))
sb.AppendLine($"«{fcTag}»");
}
// Level
if (_worldTooltipConfig.ShowLevel && mouseOverTarget is ICharacter charLevel)
{
byte level = charLevel.Level;
if (level > 0)
sb.AppendLine($"Level {level}");
}
// Job (for players)
if (_worldTooltipConfig.ShowJob && mouseOverTarget is IPlayerCharacter playerJob)
{
uint jobId = playerJob.ClassJob.RowId;
if (jobId > 0 && JobsHelper.JobNames.TryGetValue(jobId, out string? jobName))
sb.AppendLine($"Job: {jobName}");
}
// HP
if (_worldTooltipConfig.ShowHP && mouseOverTarget is ICharacter charHp)
{
uint currentHp = charHp.CurrentHp;
uint maxHp = charHp.MaxHp;
if (maxHp > 0)
{
float pct = (float)currentHp / maxHp * 100f;
sb.AppendLine($"HP: {currentHp:N0} / {maxHp:N0} ({pct:F0}%)");
}
}
// Distance
if (_worldTooltipConfig.ShowDistance)
{
var localPlayer = Plugin.ObjectTable.LocalPlayer;
if (localPlayer != null)
{
float dist = Vector3.Distance(localPlayer.Position, mouseOverTarget.Position);
sb.AppendLine($"Distance: {dist:F1}y");
}
}
// Object ID (debug)
if (_worldTooltipConfig.ShowObjectId)
{
sb.AppendLine($"ID: {mouseOverTarget.GameObjectId}");
}
string body = sb.ToString().TrimEnd('\r', '\n');
if (string.IsNullOrEmpty(body))
body = "(No info)";
if (_worldTooltipConfig.DetachFromCursor)
{
ShowTooltip(body, _worldTooltipConfig.Position, name);
}
else
{
ShowTooltipOnCursor(body, name);
}
}
public void RemoveTooltip()
{
_dataIsValid = false;
@@ -305,4 +411,43 @@ namespace HSUI.Helpers
Thickness = thickness;
}
}
[Section("Misc")]
[SubSection("World Tooltip", 0)]
public class WorldObjectTooltipConfig : PluginConfigObject
{
public new static WorldObjectTooltipConfig DefaultConfig() { return new WorldObjectTooltipConfig(); }
[Checkbox("Detach from Cursor", spacing = true)]
[Order(1)]
public bool DetachFromCursor = false;
[DragFloat2("Position (when detached)", min = -4000f, max = 4000f)]
[Order(2, collapseWith = nameof(DetachFromCursor))]
public Vector2 Position = new Vector2(100, 100);
[Checkbox("Show Level", spacing = true)]
[Order(5)]
public bool ShowLevel = true;
[Checkbox("Show HP")]
[Order(10)]
public bool ShowHP = true;
[Checkbox("Show Job (Players)")]
[Order(15)]
public bool ShowJob = true;
[Checkbox("Show FC Tag (Players)")]
[Order(20)]
public bool ShowTitle = false;
[Checkbox("Show Distance")]
[Order(25)]
public bool ShowDistance = true;
[Checkbox("Show Object ID")]
[Order(30)]
public bool ShowObjectId = false;
}
}