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
+109 -30
View File
@@ -2,37 +2,86 @@ using System;
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
{
Hotbar1 = 0xC48D3605, // _ActionBar_a
Hotbar2 = 0xFB7B6E1E, // _ActionBar01_a
Hotbar3 = 0xF93DD047, // _ActionBar02_a
Hotbar4 = 0xF8FFBA70, // _ActionBar03_a
Hotbar5 = 0xFDB0ACF5, // _ActionBar04_a
Hotbar6 = 0xFC72C6C2, // _ActionBar05_a
Hotbar7 = 0xFE34789B, // _ActionBar06_a
Hotbar8 = 0xFFF612AC, // _ActionBar07_a
Hotbar9 = 0xF4AA5591, // _ActionBar08_a
Hotbar10 = 0xF5683FA6, // _ActionBar09_a
PetHotbar = 0xD8D188FF, // _ActionBarEx_a
CrossHotbar = 0xBA81E8D1, // _ActionCross_a
LeftWCrossHotbar = 0x6665735D, // _ActionDoubleCrossL_a
RightWCrossHotbar = 0x70DDFD27, // _ActionDoubleCrossR_a
ParameterBar = 0x9818E23E, // _ParameterWidget - player HP/MP
TargetBar = 0x9139E9FD, // target info
FocusTargetBar = 0xC28E7D1F,
ProgressBar = 0xECB1E391, // cast bar
ExperienceBar = 0x21E32D4E,
LimitGauge = 0xC7A40A8A,
StatusEffects = 0x4A5B6A16, // player buffs/debuffs
StatusInfoEnhancements = 0x1F320624,
StatusInfoEnfeeblements = 0x1E7A7A83,
TargetInfoHp = 0xBD411F17,
TargetInfoProgressBar = 0xCB5BCCCF,
TargetInfoStatus = 0x070F4E6B,
PartyList = 0x3D3B34F9,
EnemyList = 0xB8C30AC5,
// Hotbars
Hotbar1 = 0xC48D3605, // _ActionBar_a
Hotbar2 = 0xFB7B6E1E, // _ActionBar01_a
Hotbar3 = 0xF93DD047, // _ActionBar02_a
Hotbar4 = 0xF8FFBA70, // _ActionBar03_a
Hotbar5 = 0xFDB0ACF5, // _ActionBar04_a
Hotbar6 = 0xFC72C6C2, // _ActionBar05_a
Hotbar7 = 0xFE34789B, // _ActionBar06_a
Hotbar8 = 0xFFF612AC, // _ActionBar07_a
Hotbar9 = 0xF4AA5591, // _ActionBar08_a
Hotbar10 = 0xF5683FA6, // _ActionBar09_a
PetHotbar = 0xD8D188FF, // _ActionBarEx_a
CrossHotbar = 0xBA81E8D1, // _ActionCross_a
LeftWCrossHotbar = 0x6665735D,
RightWCrossHotbar = 0x70DDFD27,
// Player & target
ParameterBar = 0x981EC49E, // _ParameterWidget_a (player HP/MP)
ProgressBar = 0xECB29811, // _CastBar_a
TargetBar = 0x913EC97D, // _TargetInfo_a
TargetInfoHp = 0xBD128377, // _TargetInfoMainTarget_a
TargetInfoProgressBar = 0xCB54A2EF, // _TargetInfoCastBar_a
TargetInfoStatus = 0x076F596B, // _TargetInfoBuffDebuff_a
FocusTargetBar = 0xC292F05F, // _FocusTargetInfo_a
// Party & lists
PartyList = 0x3D425039, // _PartyList_a
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
@@ -55,4 +104,34 @@ public static class ElementKindHelper
_ => 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>
<AssemblyName>HSUI</AssemblyName>
<AssemblyVersion>1.0.2.3</AssemblyVersion>
<FileVersion>1.0.2.3</FileVersion>
<InformationalVersion>1.0.2.3</InformationalVersion>
<AssemblyVersion>1.0.2.4</AssemblyVersion>
<FileVersion>1.0.2.4</FileVersion>
<InformationalVersion>1.0.2.4</InformationalVersion>
</PropertyGroup>
<PropertyGroup>
+1 -1
View File
@@ -2,7 +2,7 @@
"Author": "Knack117",
"Name": "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.",
"ApplicableVersion": "any",
"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.Objects.SubKinds;
using HSUI.Config;
using HSUI.Enums;
using HSUI.Helpers;
using HSUI.Interface.EnemyList;
using HSUI.Interface.GeneralElements;
@@ -194,70 +195,66 @@ namespace HSUI.Interface
}
var hashesToHide = new List<uint>();
void AddHashes(params string[] addonNames)
void AddElements(params ElementKind[] elements)
{
foreach (var name in addonNames)
{
var h = HudLayoutHashHelper.GetHash(name);
if (h != 0)
hashesToHide.Add(h);
}
foreach (var e in elements)
hashesToHide.Add((uint)e);
}
// Use ElementKind hashes (HUD Layout config) — the proper way per DelvUI. Source: HUDManager ElementKind.cs
var hotbarsConfig = ConfigurationManager.Instance?.GetConfigObject<HotbarsConfig>();
if (hotbarsConfig?.Enabled == true)
if (hotbarsConfig?.Enabled == true && AnyHotbarEnabled())
{
AddHashes("_ActionBar", "_ActionBar01", "_ActionBar02", "_ActionBar03", "_ActionBar04",
"_ActionBar05", "_ActionBar06", "_ActionBar07", "_ActionBar08", "_ActionBar09", "_ActionCross");
AddElements(ElementKind.Hotbar1, ElementKind.Hotbar2, ElementKind.Hotbar3, ElementKind.Hotbar4, ElementKind.Hotbar5,
ElementKind.Hotbar6, ElementKind.Hotbar7, ElementKind.Hotbar8, ElementKind.Hotbar9, ElementKind.Hotbar10, ElementKind.CrossHotbar);
}
var playerUnitFrame = ConfigurationManager.Instance?.GetConfigObject<PlayerUnitFrameConfig>();
if (playerUnitFrame?.Enabled == true)
AddHashes("_ParameterWidget");
AddElements(ElementKind.ParameterBar);
var targetUnitFrame = ConfigurationManager.Instance?.GetConfigObject<TargetUnitFrameConfig>();
if (targetUnitFrame?.Enabled == true)
AddHashes("_TargetInfo", "_TargetInfoMainTarget", "_TargetInfoCastBar", "_TargetInfoBuffDebuff");
AddElements(ElementKind.TargetBar, ElementKind.TargetInfoHp, ElementKind.TargetInfoProgressBar, ElementKind.TargetInfoStatus);
var focusUnitFrame = ConfigurationManager.Instance?.GetConfigObject<FocusTargetUnitFrameConfig>();
if (focusUnitFrame?.Enabled == true)
AddHashes("_FocusTargetInfo");
AddElements(ElementKind.FocusTargetBar);
var playerCastbar = ConfigurationManager.Instance?.GetConfigObject<PlayerCastbarConfig>();
if (playerCastbar?.Enabled == true)
AddHashes("_CastBar");
AddElements(ElementKind.ProgressBar);
var expBar = ConfigurationManager.Instance?.GetConfigObject<ExperienceBarConfig>();
if (expBar?.Enabled == true)
AddHashes("_Exp");
AddElements(ElementKind.ExperienceBar);
var limitBreak = ConfigurationManager.Instance?.GetConfigObject<LimitBreakConfig>();
if (limitBreak?.Enabled == true)
AddHashes("_LimitBreak");
AddElements(ElementKind.LimitGauge);
var playerBuffs = ConfigurationManager.Instance?.GetConfigObject<PlayerBuffsListConfig>();
var playerDebuffs = ConfigurationManager.Instance?.GetConfigObject<PlayerDebuffsListConfig>();
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>();
if (partyFrames?.Enabled == true)
AddHashes("_PartyList");
AddElements(ElementKind.PartyList);
var enemyList = ConfigurationManager.Instance?.GetConfigObject<EnemyListConfig>();
if (enemyList?.Enabled == true)
AddHashes("_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");
AddElements(ElementKind.EnemyList);
// NamePlate is not in HUD Layout config; use UpdateDefaultNameplates (IsVisible) for that
if (IsCurrentJobHudEnabled())
{
foreach (var name in GetCurrentJobGaugeAddonNames())
AddHashes(name);
var player = Plugin.ObjectTable.LocalPlayer;
if (player != null)
{
foreach (var ek in ElementKindHelper.GetJobGaugeElementKinds(player.ClassJob.RowId))
hashesToHide.Add((uint)ek);
}
}
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
- **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",
"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.",
"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",
"AssemblyVersion": "1.0.2.3",
"AssemblyVersion": "1.0.2.4",
"RepoUrl": "https://github.com/Knack117/HSUI",
"ApplicableVersion": "any",
"Tags": ["UI", "HUD", "Unit Frames", "Nameplates", "Party Frames", "Hotbars"],
@@ -14,10 +14,10 @@
"DalamudApiLevel": 14,
"IconUrl": "https://raw.githubusercontent.com/Knack117/HSUI/main/Media/Images/icon.png",
"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,
"IsTestingExclusive": false,
"DownloadLinkTesting": "https://github.com/Knack117/HSUI/releases/download/v1.0.2.3/latest.zip",
"DownloadLinkUpdate": "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.4/latest.zip"
}
]