v1.0.2.4: HUD Layout - use proper AddonConfig with ElementKind hashes from HUDManager

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-01-31 11:14:24 -05:00
parent 5c559b73c6
commit 891eb59877
6 changed files with 145 additions and 66 deletions
+96 -17
View File
@@ -2,9 +2,13 @@ using System;
namespace HSUI.Enums; namespace HSUI.Enums;
// Hashes from HUD layout (AddonNameHash). Sources: HSUI, HUDManager plugin /// <summary>
/// HUD layout AddonNameHash values. Uses CRC32 of "AddonName_a".
/// Source: https://github.com/zacharied/FFXIV-Plugin-HudManager/blob/testing/HUDManager/Structs/ElementKind.cs
/// </summary>
public enum ElementKind : uint public enum ElementKind : uint
{ {
// Hotbars
Hotbar1 = 0xC48D3605, // _ActionBar_a Hotbar1 = 0xC48D3605, // _ActionBar_a
Hotbar2 = 0xFB7B6E1E, // _ActionBar01_a Hotbar2 = 0xFB7B6E1E, // _ActionBar01_a
Hotbar3 = 0xF93DD047, // _ActionBar02_a Hotbar3 = 0xF93DD047, // _ActionBar02_a
@@ -17,22 +21,67 @@ public enum ElementKind : uint
Hotbar10 = 0xF5683FA6, // _ActionBar09_a Hotbar10 = 0xF5683FA6, // _ActionBar09_a
PetHotbar = 0xD8D188FF, // _ActionBarEx_a PetHotbar = 0xD8D188FF, // _ActionBarEx_a
CrossHotbar = 0xBA81E8D1, // _ActionCross_a CrossHotbar = 0xBA81E8D1, // _ActionCross_a
LeftWCrossHotbar = 0x6665735D, // _ActionDoubleCrossL_a LeftWCrossHotbar = 0x6665735D,
RightWCrossHotbar = 0x70DDFD27, // _ActionDoubleCrossR_a RightWCrossHotbar = 0x70DDFD27,
ParameterBar = 0x9818E23E, // _ParameterWidget - player HP/MP
TargetBar = 0x9139E9FD, // target info // Player & target
FocusTargetBar = 0xC28E7D1F, ParameterBar = 0x981EC49E, // _ParameterWidget_a (player HP/MP)
ProgressBar = 0xECB1E391, // cast bar ProgressBar = 0xECB29811, // _CastBar_a
ExperienceBar = 0x21E32D4E, TargetBar = 0x913EC97D, // _TargetInfo_a
LimitGauge = 0xC7A40A8A, TargetInfoHp = 0xBD128377, // _TargetInfoMainTarget_a
StatusEffects = 0x4A5B6A16, // player buffs/debuffs TargetInfoProgressBar = 0xCB54A2EF, // _TargetInfoCastBar_a
StatusInfoEnhancements = 0x1F320624, TargetInfoStatus = 0x076F596B, // _TargetInfoBuffDebuff_a
StatusInfoEnfeeblements = 0x1E7A7A83, FocusTargetBar = 0xC292F05F, // _FocusTargetInfo_a
TargetInfoHp = 0xBD411F17,
TargetInfoProgressBar = 0xCB5BCCCF, // Party & lists
TargetInfoStatus = 0x070F4E6B, PartyList = 0x3D425039, // _PartyList_a
PartyList = 0x3D3B34F9, AllianceList1 = 0x2943729A,
EnemyList = 0xB8C30AC5, AllianceList2 = 0x2B05CCC3,
EnemyList = 0xB8BD6685, // _EnemyList_a
// Misc HUD
ExperienceBar = 0x21E53CCE, // _Exp_a
LimitGauge = 0xC79F450A, // _LimitBreak_a
StatusEffects = 0x4A569616, // _Status_a
StatusInfoEnhancements = 0x1F4230B4, // _StatusCustom0_a
StatusInfoEnfeeblements = 0x1E805A83, // _StatusCustom1_a
StatusInfoOther = 0x1CC6E4DA, // _StatusCustom2_a
StatusInfoConditionalEnhancements = 0x1D048EED, // _StatusCustom3_a
// Job gauges (PLD, WAR, DRK, GNB, WHM, SCH, AST, SGE, MNK, DRG, NIN, SAM, RPR, VPR, BRD, MCH, DNC, BLM, SMN, RDM, PCT)
OathGauge = 0xEFBAFE40, // JobHudPLD0
BeastGauge = 0x7F5D020A, // JobHudWAR0
BloodGauge = 0xF04E8778, // JobHudDRK0
DarksideGauge = 0xF18CED4F, // JobHudDRK1
PowderGauge = 0xAEC2C0DF, // JobHudGNB0
HealingGauge = 0x7A3727B2, // JobHudWHM0
AetherflowGaugeSch = 0xCADD58CB, // JobHudACN0
FaerieGauge = 0xA1A8A487, // JobHudSCH0
ArcanaGauge = 0x959978B2, // JobHudAST0
EukrasiaGauge = 0x11D01C49, // JobHudGFF0 (SGE)
AddersgallGauge = 0x1012767E, // JobHudGFF1 (SGE)
MastersGauge = 0x7251AC33, // JobHudMNK0
ChakraGauge = 0x7393C604, // JobHudMNK1
DragonGauge = 0xBA9838C0, // JobHudDRG0
NinkiGauge = 0x713BF2BF, // JobHudNIN0
Kazematoi = 0x6CD4313E, // JobHudNIN1v70 (NIN)
KenkiGauge = 0xECB607D5, // JobHudSAM0
SenGauge = 0xED746DE2, // JobHudSAM1
SoulGauge = 0xA2D9B660, // JobHudRRP0 (RPR)
DeathGauge = 0xA31BDC57, // JobHudRRP1 (RPR)
Vipersight = 0xB7694B56, // JobHudRDB0 (VIP)
SerpentOfferingsGauge = 0xB6AB2161, // JobHudRDB1 (VIP)
SongGauge = 0x7E747433, // JobHudBRD0
HeatGauge = 0x9874C76C, // JobHudMCH0
StepGauge = 0x90EAD514, // JobHudDNC0
FourfoldFeathers = 0x9128BF23, // JobHudDNC1
ElementalGauge = 0xDCAC125A, // JobHudBLM0
AstralGauge = 0xDD6E786D, // JobHudBLM1
AetherflowGaugeSmn = 0x3BF3453A, // JobHudSMN0
TranceGauge = 0x3A312F0D, // JobHudSMN1
BalanceGauge = 0xEF0A5B00, // JobHudRDM0
Canvases = 0x7A6A6A42, // JobHudRPM0 (PCT)
PaletteGauge = 0x7BA80075, // JobHudRPM1 (PCT)
} }
public static class ElementKindHelper public static class ElementKindHelper
@@ -55,4 +104,34 @@ public static class ElementKindHelper
_ => throw new ArgumentOutOfRangeException(nameof(hotBarId)) _ => throw new ArgumentOutOfRangeException(nameof(hotBarId))
}; };
} }
/// <summary>Returns ElementKind hashes for the current job's gauges (0-4 gauges per job).</summary>
public static ElementKind[] GetJobGaugeElementKinds(uint jobId)
{
return jobId switch
{
19 => new[] { ElementKind.OathGauge }, // PLD
21 => new[] { ElementKind.MastersGauge, ElementKind.ChakraGauge }, // MNK
22 => new[] { ElementKind.BeastGauge }, // WAR
23 => new[] { ElementKind.DragonGauge }, // DRG
24 => new[] { ElementKind.SongGauge }, // BRD
25 => new[] { ElementKind.HealingGauge }, // WHM
27 => new[] { ElementKind.ElementalGauge, ElementKind.AstralGauge }, // BLM
28 => new[] { ElementKind.AetherflowGaugeSmn, ElementKind.TranceGauge }, // SMN
29 => new[] { ElementKind.AetherflowGaugeSch, ElementKind.FaerieGauge }, // SCH
30 => new[] { ElementKind.NinkiGauge, ElementKind.Kazematoi }, // NIN
31 => new[] { ElementKind.HeatGauge }, // MCH
32 => new[] { ElementKind.BloodGauge, ElementKind.DarksideGauge }, // DRK
33 => new[] { ElementKind.ArcanaGauge }, // AST
34 => new[] { ElementKind.KenkiGauge, ElementKind.SenGauge }, // SAM
35 => new[] { ElementKind.BalanceGauge }, // RDM
37 => new[] { ElementKind.PowderGauge }, // GNB
38 => new[] { ElementKind.StepGauge, ElementKind.FourfoldFeathers }, // DNC
39 => new[] { ElementKind.SoulGauge, ElementKind.DeathGauge }, // RPR
40 => new[] { ElementKind.EukrasiaGauge, ElementKind.AddersgallGauge }, // SGE
41 => new[] { ElementKind.Vipersight, ElementKind.SerpentOfferingsGauge },// VPR
42 => new[] { ElementKind.Canvases, ElementKind.PaletteGauge }, // PCT
_ => Array.Empty<ElementKind>()
};
}
} }
+3 -3
View File
@@ -9,9 +9,9 @@
<PropertyGroup> <PropertyGroup>
<AssemblyName>HSUI</AssemblyName> <AssemblyName>HSUI</AssemblyName>
<AssemblyVersion>1.0.2.3</AssemblyVersion> <AssemblyVersion>1.0.2.4</AssemblyVersion>
<FileVersion>1.0.2.3</FileVersion> <FileVersion>1.0.2.4</FileVersion>
<InformationalVersion>1.0.2.3</InformationalVersion> <InformationalVersion>1.0.2.4</InformationalVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
+1 -1
View File
@@ -2,7 +2,7 @@
"Author": "Knack117", "Author": "Knack117",
"Name": "HSUI", "Name": "HSUI",
"InternalName": "HSUI", "InternalName": "HSUI",
"AssemblyVersion": "1.0.2.3", "AssemblyVersion": "1.0.2.4",
"Description": "HSUI provides a highly configurable HUD replacement for FFXIV, recreated from DelvUI using KamiToolKit, FFXIVClientStructs, and Dalamud. Features unit frames, castbars, job gauges, nameplates, party frames, status effects, enemy list, configurable hotbars with drag-and-drop, and profiles.", "Description": "HSUI provides a highly configurable HUD replacement for FFXIV, recreated from DelvUI using KamiToolKit, FFXIVClientStructs, and Dalamud. Features unit frames, castbars, job gauges, nameplates, party frames, status effects, enemy list, configurable hotbars with drag-and-drop, and profiles.",
"ApplicableVersion": "any", "ApplicableVersion": "any",
"RepoUrl": "https://github.com/Knack117/HSUI", "RepoUrl": "https://github.com/Knack117/HSUI",
+24 -27
View File
@@ -2,6 +2,7 @@ using Dalamud.Game.Addon.Lifecycle;
using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.ClientState.Objects.SubKinds; using Dalamud.Game.ClientState.Objects.SubKinds;
using HSUI.Config; using HSUI.Config;
using HSUI.Enums;
using HSUI.Helpers; using HSUI.Helpers;
using HSUI.Interface.EnemyList; using HSUI.Interface.EnemyList;
using HSUI.Interface.GeneralElements; using HSUI.Interface.GeneralElements;
@@ -194,70 +195,66 @@ namespace HSUI.Interface
} }
var hashesToHide = new List<uint>(); var hashesToHide = new List<uint>();
void AddHashes(params string[] addonNames) void AddElements(params ElementKind[] elements)
{ {
foreach (var name in addonNames) foreach (var e in elements)
{ hashesToHide.Add((uint)e);
var h = HudLayoutHashHelper.GetHash(name);
if (h != 0)
hashesToHide.Add(h);
}
} }
// Use ElementKind hashes (HUD Layout config) — the proper way per DelvUI. Source: HUDManager ElementKind.cs
var hotbarsConfig = ConfigurationManager.Instance?.GetConfigObject<HotbarsConfig>(); var hotbarsConfig = ConfigurationManager.Instance?.GetConfigObject<HotbarsConfig>();
if (hotbarsConfig?.Enabled == true) if (hotbarsConfig?.Enabled == true && AnyHotbarEnabled())
{ {
AddHashes("_ActionBar", "_ActionBar01", "_ActionBar02", "_ActionBar03", "_ActionBar04", AddElements(ElementKind.Hotbar1, ElementKind.Hotbar2, ElementKind.Hotbar3, ElementKind.Hotbar4, ElementKind.Hotbar5,
"_ActionBar05", "_ActionBar06", "_ActionBar07", "_ActionBar08", "_ActionBar09", "_ActionCross"); ElementKind.Hotbar6, ElementKind.Hotbar7, ElementKind.Hotbar8, ElementKind.Hotbar9, ElementKind.Hotbar10, ElementKind.CrossHotbar);
} }
var playerUnitFrame = ConfigurationManager.Instance?.GetConfigObject<PlayerUnitFrameConfig>(); var playerUnitFrame = ConfigurationManager.Instance?.GetConfigObject<PlayerUnitFrameConfig>();
if (playerUnitFrame?.Enabled == true) if (playerUnitFrame?.Enabled == true)
AddHashes("_ParameterWidget"); AddElements(ElementKind.ParameterBar);
var targetUnitFrame = ConfigurationManager.Instance?.GetConfigObject<TargetUnitFrameConfig>(); var targetUnitFrame = ConfigurationManager.Instance?.GetConfigObject<TargetUnitFrameConfig>();
if (targetUnitFrame?.Enabled == true) if (targetUnitFrame?.Enabled == true)
AddHashes("_TargetInfo", "_TargetInfoMainTarget", "_TargetInfoCastBar", "_TargetInfoBuffDebuff"); AddElements(ElementKind.TargetBar, ElementKind.TargetInfoHp, ElementKind.TargetInfoProgressBar, ElementKind.TargetInfoStatus);
var focusUnitFrame = ConfigurationManager.Instance?.GetConfigObject<FocusTargetUnitFrameConfig>(); var focusUnitFrame = ConfigurationManager.Instance?.GetConfigObject<FocusTargetUnitFrameConfig>();
if (focusUnitFrame?.Enabled == true) if (focusUnitFrame?.Enabled == true)
AddHashes("_FocusTargetInfo"); AddElements(ElementKind.FocusTargetBar);
var playerCastbar = ConfigurationManager.Instance?.GetConfigObject<PlayerCastbarConfig>(); var playerCastbar = ConfigurationManager.Instance?.GetConfigObject<PlayerCastbarConfig>();
if (playerCastbar?.Enabled == true) if (playerCastbar?.Enabled == true)
AddHashes("_CastBar"); AddElements(ElementKind.ProgressBar);
var expBar = ConfigurationManager.Instance?.GetConfigObject<ExperienceBarConfig>(); var expBar = ConfigurationManager.Instance?.GetConfigObject<ExperienceBarConfig>();
if (expBar?.Enabled == true) if (expBar?.Enabled == true)
AddHashes("_Exp"); AddElements(ElementKind.ExperienceBar);
var limitBreak = ConfigurationManager.Instance?.GetConfigObject<LimitBreakConfig>(); var limitBreak = ConfigurationManager.Instance?.GetConfigObject<LimitBreakConfig>();
if (limitBreak?.Enabled == true) if (limitBreak?.Enabled == true)
AddHashes("_LimitBreak"); AddElements(ElementKind.LimitGauge);
var playerBuffs = ConfigurationManager.Instance?.GetConfigObject<PlayerBuffsListConfig>(); var playerBuffs = ConfigurationManager.Instance?.GetConfigObject<PlayerBuffsListConfig>();
var playerDebuffs = ConfigurationManager.Instance?.GetConfigObject<PlayerDebuffsListConfig>(); var playerDebuffs = ConfigurationManager.Instance?.GetConfigObject<PlayerDebuffsListConfig>();
if (playerBuffs?.Enabled == true || playerDebuffs?.Enabled == true) if (playerBuffs?.Enabled == true || playerDebuffs?.Enabled == true)
AddHashes("_Status", "_StatusCustom0", "_StatusCustom1", "_StatusCustom2", "_StatusCustom3"); AddElements(ElementKind.StatusEffects, ElementKind.StatusInfoEnhancements, ElementKind.StatusInfoEnfeeblements, ElementKind.StatusInfoOther, ElementKind.StatusInfoConditionalEnhancements);
var partyFrames = ConfigurationManager.Instance?.GetConfigObject<PartyFramesConfig>(); var partyFrames = ConfigurationManager.Instance?.GetConfigObject<PartyFramesConfig>();
if (partyFrames?.Enabled == true) if (partyFrames?.Enabled == true)
AddHashes("_PartyList"); AddElements(ElementKind.PartyList);
var enemyList = ConfigurationManager.Instance?.GetConfigObject<EnemyListConfig>(); var enemyList = ConfigurationManager.Instance?.GetConfigObject<EnemyListConfig>();
if (enemyList?.Enabled == true) if (enemyList?.Enabled == true)
AddHashes("_EnemyList"); AddElements(ElementKind.EnemyList);
// Hide NamePlate when HSUI nameplates are enabled. We read icon IDs from the addon (still updated when hidden)
// and draw our own quest icons (! ? above NPCs) via NPC nameplate IconConfig.
var nameplatesConfig = ConfigurationManager.Instance?.GetConfigObject<NameplatesGeneralConfig>();
if (nameplatesConfig?.Enabled == true)
AddHashes("NamePlate");
// NamePlate is not in HUD Layout config; use UpdateDefaultNameplates (IsVisible) for that
if (IsCurrentJobHudEnabled()) if (IsCurrentJobHudEnabled())
{ {
foreach (var name in GetCurrentJobGaugeAddonNames()) var player = Plugin.ObjectTable.LocalPlayer;
AddHashes(name); if (player != null)
{
foreach (var ek in ElementKindHelper.GetJobGaugeElementKinds(player.ClassJob.RowId))
hashesToHide.Add((uint)ek);
}
} }
SetGameHudElementsHidden(hashesToHide.ToArray(), false); SetGameHudElementsHidden(hashesToHide.ToArray(), false);
+3
View File
@@ -1,3 +1,6 @@
# 1.0.2.4
- **HUD Layout**: Switched to proper HUD Layout config (AddonConfig) instead of memory reads. Uses authoritative ElementKind hashes from HUDManager for hiding default elements. Job gauges now use layout hashes.
# 1.0.2.3 # 1.0.2.3
- **Hotbars**: Keypress flash indicator — slots flash when you press their keybind (or click). Toggle in Hotbars → per-hotbar "Show Keypress Flash". - **Hotbars**: Keypress flash indicator — slots flash when you press their keybind (or click). Toggle in Hotbars → per-hotbar "Show Keypress Flash".
+5 -5
View File
@@ -4,9 +4,9 @@
"Name": "HSUI", "Name": "HSUI",
"Punchline": "A modern HUD replacement built for customization.", "Punchline": "A modern HUD replacement built for customization.",
"Description": "HSUI provides a highly configurable HUD replacement for FFXIV, recreated from DelvUI using KamiToolKit, FFXIVClientStructs, and Dalamud. Features unit frames, castbars, job gauges, nameplates, party frames, status effects, enemy list, configurable hotbars with drag-and-drop, and profiles.", "Description": "HSUI provides a highly configurable HUD replacement for FFXIV, recreated from DelvUI using KamiToolKit, FFXIVClientStructs, and Dalamud. Features unit frames, castbars, job gauges, nameplates, party frames, status effects, enemy list, configurable hotbars with drag-and-drop, and profiles.",
"Changelog": "Hotbars: Keypress flash indicator when pressing slot keybinds. Toggle per hotbar.", "Changelog": "HUD Layout: Use proper HUD config instead of memory reads. ElementKind hashes from HUDManager for hiding default elements.",
"InternalName": "HSUI", "InternalName": "HSUI",
"AssemblyVersion": "1.0.2.3", "AssemblyVersion": "1.0.2.4",
"RepoUrl": "https://github.com/Knack117/HSUI", "RepoUrl": "https://github.com/Knack117/HSUI",
"ApplicableVersion": "any", "ApplicableVersion": "any",
"Tags": ["UI", "HUD", "Unit Frames", "Nameplates", "Party Frames", "Hotbars"], "Tags": ["UI", "HUD", "Unit Frames", "Nameplates", "Party Frames", "Hotbars"],
@@ -14,10 +14,10 @@
"DalamudApiLevel": 14, "DalamudApiLevel": 14,
"IconUrl": "https://raw.githubusercontent.com/Knack117/HSUI/main/Media/Images/icon.png", "IconUrl": "https://raw.githubusercontent.com/Knack117/HSUI/main/Media/Images/icon.png",
"ImageUrls": [], "ImageUrls": [],
"DownloadLinkInstall": "https://github.com/Knack117/HSUI/releases/download/v1.0.2.3/latest.zip", "DownloadLinkInstall": "https://github.com/Knack117/HSUI/releases/download/v1.0.2.4/latest.zip",
"IsHide": false, "IsHide": false,
"IsTestingExclusive": false, "IsTestingExclusive": false,
"DownloadLinkTesting": "https://github.com/Knack117/HSUI/releases/download/v1.0.2.3/latest.zip", "DownloadLinkTesting": "https://github.com/Knack117/HSUI/releases/download/v1.0.2.4/latest.zip",
"DownloadLinkUpdate": "https://github.com/Knack117/HSUI/releases/download/v1.0.2.3/latest.zip" "DownloadLinkUpdate": "https://github.com/Knack117/HSUI/releases/download/v1.0.2.4/latest.zip"
} }
] ]