Code:
[StructLayout(LayoutKind.Sequential, Size = 0x30)]
private struct SpellCooldownEntry
{
public uint Unk;
public IntPtr Next;
public uint SpellId;
public uint ItemId;
public uint StartTime;
public uint TimeOffset;
public uint SpellCategoryId;
public uint CategoryCooldownTimeStart;
public uint CooldownDuration;
public uint HasCooldown; // Check low byte
public uint GCDStartTime;
public uint StartRecoveryCategoryId;
public uint GCDLeft;
public override string ToString()
{
return
string.Format(
"Unk: {0}, Next: {1}, SpellId: {2}, ItemId: {3}, StartTime: {4}, TimeOffset: {5}, SpellCategoryId: {6}, CategoryCooldownTimeStart: {7}, CooldownDuration: {8}, HasCooldown: {9}, GcdStartTime: {10}, StartRecoveryCategoryId: {11}, GcdLeft: {12}",
Unk,
Next,
SpellId,
ItemId,
StartTime,
TimeOffset,
SpellCategoryId,
CategoryCooldownTimeStart,
CooldownDuration,
HasCooldown,
GCDStartTime,
StartRecoveryCategoryId,
GCDLeft);
}
}
Then something like this:
Code:
public static TimeSpan GetSpellCooldownTimeLeft(int spellId)
{
// We need to do this, because the WoW client is often off by 1-4 seconds. The actual val from perf counter is accurate.
long currentTime = (long)WoWClient.PerformanceCounter();
//Get first list object
var current = Memory.Read<IntPtr>(Offsets.Statics.LocalPlayerSpellsOnCooldown + 0x8);
while (current != (IntPtr)0 && ((uint)current & 1) == 0)
{
var entry = Memory.Read<SpellCooldownEntry>(current);
// Spell ID doesn't match
if (entry.SpellId != spellId)
{
current = entry.Next;
continue;
}
//Spell on gcd?
if ((entry.StartTime + entry.TimeOffset + entry.CooldownDuration) > currentTime)
{
return Utilities.PerformanceCounterToDateTime(entry.StartTime + entry.TimeOffset).AddMilliseconds(entry.CooldownDuration) -
Utilities.PerformanceCounterToDateTime((ulong)currentTime);
}
//Get next list object
current = entry.Next;
}
return TimeSpan.Zero;
}