PvP hotbar fix: load saved PvE on zone leave then use live bars; Show Action ID in tooltips
- On leaving PvP, LoadSavedHotbar for all 10 bars (via TryRestorePvEHotbarsAfterLeavePvP in Framework update) and re-apply for ~2s so live Hotbars show PvE - GetSlotData always reads from live StandardHotbars so combo updates (e.g. Pictomancer) and icons work normally - Misc: Show Action ID option in Misc -> Tooltips; hotbar/party cooldown tooltips pass TooltipIdKind for Action vs Status IDs Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -89,9 +89,48 @@ namespace HSUI.Helpers
|
||||
return p;
|
||||
}
|
||||
|
||||
/// <summary>Track PvP state so we can restore PvE bars when leaving PvP (game sometimes leaves PvP data in StandardHotbars).</summary>
|
||||
private static bool _pvpHotbarsActiveLastFrame;
|
||||
private static bool _clientStatePvPLastFrame;
|
||||
/// <summary>After leaving PvP, keep re-applying PvE load for this many frames in case the game overwrites.</summary>
|
||||
private static int _restorePvEFramesLeft;
|
||||
|
||||
/// <summary>
|
||||
/// Call once per frame (e.g. from Framework Update). When we detect leaving PvP, loads saved PvE hotbars into the live bars
|
||||
/// and keeps re-applying for a short window so PvE actions are not overwritten by stale PvP state.
|
||||
/// </summary>
|
||||
public static unsafe void TryRestorePvEHotbarsAfterLeavePvP()
|
||||
{
|
||||
var module = RaptureHotbarModule.Instance();
|
||||
if (module == null || !module->ModuleReady)
|
||||
return;
|
||||
|
||||
bool pvpActive = module->PvPHotbarsActive;
|
||||
bool clientPvP = Plugin.ClientState.IsPvP;
|
||||
|
||||
if (!pvpActive && !clientPvP)
|
||||
{
|
||||
bool justLeftPvP = _pvpHotbarsActiveLastFrame || _clientStatePvPLastFrame;
|
||||
if (justLeftPvP)
|
||||
_restorePvEFramesLeft = 120; // ~2s at 60fps
|
||||
|
||||
if (_restorePvEFramesLeft > 0)
|
||||
{
|
||||
uint classJobId = (uint)(module->ActiveHotbarClassJobId & 0x7F);
|
||||
for (uint barId = 0; barId < 10; barId++)
|
||||
module->LoadSavedHotbar(classJobId, barId);
|
||||
_restorePvEFramesLeft--;
|
||||
}
|
||||
}
|
||||
|
||||
_pvpHotbarsActiveLastFrame = pvpActive;
|
||||
_clientStatePvPLastFrame = clientPvP;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads hotbar slot data from RaptureHotbarModule. Returns up to slotCount slots.
|
||||
/// hotbarIndex 1-10 maps to StandardHotbars 0-9.
|
||||
/// Always reads from live Hotbars; when leaving PvP, TryRestorePvEHotbarsAfterLeavePvP loads saved PvE into live so we then show PvE.
|
||||
/// </summary>
|
||||
public unsafe List<SlotInfo> GetSlotData(int hotbarIndex, int slotCount)
|
||||
{
|
||||
@@ -100,11 +139,11 @@ namespace HSUI.Helpers
|
||||
if (module == null || !module->ModuleReady)
|
||||
return list;
|
||||
|
||||
var hotbars = module->StandardHotbars;
|
||||
int barIdx = Math.Clamp(hotbarIndex, 1, 10) - 1;
|
||||
int count = Math.Clamp(slotCount, 1, 12);
|
||||
|
||||
var hotbars = module->StandardHotbars;
|
||||
ref var bar = ref hotbars[barIdx];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var slot = bar.GetHotbarSlot((uint)i);
|
||||
@@ -116,7 +155,6 @@ namespace HSUI.Helpers
|
||||
continue;
|
||||
}
|
||||
|
||||
// GearSet with id 0 is valid (first gearset); the game's IsEmpty (CommandId == 0) would wrongly treat it as empty.
|
||||
bool isEmpty = slot->IsEmpty && slot->CommandType != RaptureHotbarModule.HotbarSlotType.GearSet;
|
||||
if (isEmpty)
|
||||
{
|
||||
@@ -124,7 +162,6 @@ namespace HSUI.Helpers
|
||||
continue;
|
||||
}
|
||||
|
||||
// Use CommandType/CommandId for GearSet so we handle gearset 0 and slots not yet synced to Apparent*.
|
||||
var slotType = slot->CommandType == RaptureHotbarModule.HotbarSlotType.GearSet
|
||||
? RaptureHotbarModule.HotbarSlotType.GearSet
|
||||
: slot->ApparentSlotType;
|
||||
@@ -132,13 +169,11 @@ namespace HSUI.Helpers
|
||||
? slot->CommandId
|
||||
: slot->ApparentActionId;
|
||||
|
||||
// For GearSet slots, refresh IconId from the gearset (e.g. job icon from first equipment slot).
|
||||
if (slotType == RaptureHotbarModule.HotbarSlotType.GearSet)
|
||||
slot->LoadIconId();
|
||||
|
||||
bool usable = slot->IsSlotUsable(slotType, actionId);
|
||||
uint iconId = slot->IconId;
|
||||
// GearSet 0 or just-dropped: game may not have synced Apparent* so IconId can be 0; resolve for display.
|
||||
if (slotType == RaptureHotbarModule.HotbarSlotType.GearSet && iconId == 0)
|
||||
{
|
||||
int resolved = slot->GetIconIdForSlot(slotType, actionId);
|
||||
@@ -148,8 +183,6 @@ namespace HSUI.Helpers
|
||||
|
||||
(int pct, int secsLeft) = GetSlotCooldown(slot);
|
||||
(int currentCharges, int maxCharges) = GetSlotCharges(slotType, actionId);
|
||||
// For charge-based actions, don't grey out the icon until all charges are spent.
|
||||
// Use both the slot's recast-charge count and ActionManager so we catch all cases.
|
||||
uint apparentCharges = slotType == RaptureHotbarModule.HotbarSlotType.Action ? slot->GetApparentIconRecastCharges() : 0;
|
||||
if (maxCharges > 1 && (apparentCharges > 0 || currentCharges > 0))
|
||||
usable = true;
|
||||
|
||||
Reference in New Issue
Block a user