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
+108 -29
View File
@@ -2,37 +2,86 @@ 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
{ {
Hotbar1 = 0xC48D3605, // _ActionBar_a // Hotbars
Hotbar2 = 0xFB7B6E1E, // _ActionBar01_a Hotbar1 = 0xC48D3605, // _ActionBar_a
Hotbar3 = 0xF93DD047, // _ActionBar02_a Hotbar2 = 0xFB7B6E1E, // _ActionBar01_a
Hotbar4 = 0xF8FFBA70, // _ActionBar03_a Hotbar3 = 0xF93DD047, // _ActionBar02_a
Hotbar5 = 0xFDB0ACF5, // _ActionBar04_a Hotbar4 = 0xF8FFBA70, // _ActionBar03_a
Hotbar6 = 0xFC72C6C2, // _ActionBar05_a Hotbar5 = 0xFDB0ACF5, // _ActionBar04_a
Hotbar7 = 0xFE34789B, // _ActionBar06_a Hotbar6 = 0xFC72C6C2, // _ActionBar05_a
Hotbar8 = 0xFFF612AC, // _ActionBar07_a Hotbar7 = 0xFE34789B, // _ActionBar06_a
Hotbar9 = 0xF4AA5591, // _ActionBar08_a Hotbar8 = 0xFFF612AC, // _ActionBar07_a
Hotbar10 = 0xF5683FA6, // _ActionBar09_a Hotbar9 = 0xF4AA5591, // _ActionBar08_a
PetHotbar = 0xD8D188FF, // _ActionBarEx_a Hotbar10 = 0xF5683FA6, // _ActionBar09_a
CrossHotbar = 0xBA81E8D1, // _ActionCross_a PetHotbar = 0xD8D188FF, // _ActionBarEx_a
LeftWCrossHotbar = 0x6665735D, // _ActionDoubleCrossL_a CrossHotbar = 0xBA81E8D1, // _ActionCross_a
RightWCrossHotbar = 0x70DDFD27, // _ActionDoubleCrossR_a LeftWCrossHotbar = 0x6665735D,
ParameterBar = 0x9818E23E, // _ParameterWidget - player HP/MP RightWCrossHotbar = 0x70DDFD27,
TargetBar = 0x9139E9FD, // target info
FocusTargetBar = 0xC28E7D1F, // Player & target
ProgressBar = 0xECB1E391, // cast bar ParameterBar = 0x981EC49E, // _ParameterWidget_a (player HP/MP)
ExperienceBar = 0x21E32D4E, ProgressBar = 0xECB29811, // _CastBar_a
LimitGauge = 0xC7A40A8A, TargetBar = 0x913EC97D, // _TargetInfo_a
StatusEffects = 0x4A5B6A16, // player buffs/debuffs TargetInfoHp = 0xBD128377, // _TargetInfoMainTarget_a
StatusInfoEnhancements = 0x1F320624, TargetInfoProgressBar = 0xCB54A2EF, // _TargetInfoCastBar_a
StatusInfoEnfeeblements = 0x1E7A7A83, TargetInfoStatus = 0x076F596B, // _TargetInfoBuffDebuff_a
TargetInfoHp = 0xBD411F17, FocusTargetBar = 0xC292F05F, // _FocusTargetInfo_a
TargetInfoProgressBar = 0xCB5BCCCF,
TargetInfoStatus = 0x070F4E6B, // Party & lists
PartyList = 0x3D3B34F9, PartyList = 0x3D425039, // _PartyList_a
EnemyList = 0xB8C30AC5, AllianceList1 = 0x2943729A,
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"
} }
] ]