Owner-authorized source migration: 31 helper-only translation units were merged into their callers or existing inline headers; both build manifests updated. Includes the preserved source payload, Lua configuration matching wowdecomp, and exact malloca expansion without diagnostic pragmas. 449 native units compiled locally and 449 staged units compiled by the pinned server toolchain. No previously byte-matched function regressed. Compiler mapping diagnostics remain recorded as needs_cleanup, not accepted or peer-confirmed. Existing independent review records are preserved. README.md is intentionally unchanged.
193 lines
6.2 KiB
C++
193 lines
6.2 KiB
C++
#include "UI/Shortcuts/ShortcutCooldowns.h"
|
|
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
#include <windows.h>
|
|
#include <timeapi.h>
|
|
|
|
namespace {
|
|
// OFFSET: 0x00E1DCA0
|
|
// FUNCTION: fn_23875
|
|
bool IsFirstRange(unsigned id) {
|
|
return id - 8000u <= 60;
|
|
}
|
|
|
|
// OFFSET: 0x00E1DD20
|
|
// FUNCTION: fn_23878
|
|
bool IsOtherRange(unsigned id) {
|
|
return id - 8200u <= 41 || id - 8400u <= 57;
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00D42070
|
|
// FUNCTION: fn_21827
|
|
void ShortcutCooldowns::LoadSnapshot(
|
|
const void* packet, const std::list<ShortcutCooldownIcon>& mainIcons, const std::list<ShortcutCooldownIcon>& alternateIcons, int replayMode,
|
|
const std::uint32_t& serverTick
|
|
) {
|
|
this->records.clear();
|
|
const auto* bytes = static_cast<const unsigned char*>(packet);
|
|
std::int16_t size;
|
|
std::memcpy(&size, bytes + 2, sizeof(size));
|
|
const int count = (size - 2) / 10;
|
|
|
|
for (int index = 0; index < count; ++index) {
|
|
const unsigned char* source = bytes + 4 + index * 10;
|
|
std::uint16_t id;
|
|
std::uint32_t duration;
|
|
std::uint32_t remaining;
|
|
std::memcpy(&id, source, sizeof(id));
|
|
std::memcpy(&duration, source + 2, sizeof(duration));
|
|
std::memcpy(&remaining, source + 6, sizeof(remaining));
|
|
const std::uint32_t now = replayMode == 1 ? serverTick : timeGetTime();
|
|
ShortcutCooldownRecord value{id, now + remaining, duration, {}, {}};
|
|
|
|
for (const ShortcutCooldownIcon& icon : mainIcons) {
|
|
if (icon.id == id) {
|
|
value.main.emplace_back(icon.slot, icon.x, icon.y, duration, now, duration - remaining, 0);
|
|
}
|
|
}
|
|
|
|
for (const ShortcutCooldownIcon& icon : alternateIcons) {
|
|
if (icon.id == id) {
|
|
value.alternate.emplace_back(icon.slot, icon.x, icon.y, duration, now, duration - remaining, 0);
|
|
}
|
|
}
|
|
|
|
this->records.push_back(value);
|
|
}
|
|
}
|
|
|
|
// OFFSET: 0x00D41990
|
|
// FUNCTION: fn_21826
|
|
void ShortcutCooldowns::ApplyStart(
|
|
const void* packet, const std::list<ShortcutCooldownIcon>& mainIcons, const std::list<ShortcutCooldownIcon>& alternateIcons, int replayMode,
|
|
const std::uint32_t& serverTick
|
|
) {
|
|
const auto* bytes = static_cast<const unsigned char*>(packet);
|
|
std::uint16_t id;
|
|
std::uint32_t duration;
|
|
std::memcpy(&id, bytes + 2, sizeof(id));
|
|
std::memcpy(&duration, bytes + 4, sizeof(duration));
|
|
const std::uint32_t now = replayMode == 1 ? serverTick : timeGetTime();
|
|
ShortcutCooldownRecord value{id, now + duration, duration, {}, {}};
|
|
const auto find = [&]() {
|
|
return std::find_if(this->records.begin(), this->records.end(), [&](const ShortcutCooldownRecord& record) { return record.id == id; });
|
|
};
|
|
|
|
for (const ShortcutCooldownIcon& icon : mainIcons) {
|
|
if (icon.id != id) {
|
|
continue;
|
|
}
|
|
|
|
const auto entry = find();
|
|
if (entry == this->records.end()) {
|
|
value.main.emplace_back(icon.slot, icon.x, icon.y, duration, now, 0, 0);
|
|
this->records.push_back(value);
|
|
} else {
|
|
const auto slot = std::find_if(entry->main.begin(), entry->main.end(), [&](const CooldownState& state) { return state.slot == icon.slot; });
|
|
if (slot == entry->main.end()) {
|
|
entry->main.emplace_back(icon.slot, icon.x, icon.y, duration, now, 0, 0);
|
|
} else {
|
|
this->records.erase(entry);
|
|
|
|
value.main.emplace_back(icon.slot, icon.x, icon.y, duration, now, 0, 0);
|
|
this->records.push_back(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const ShortcutCooldownIcon& icon : alternateIcons) {
|
|
if (icon.id == id && find() == this->records.end()) {
|
|
value.alternate.emplace_back(icon.slot, icon.x, icon.y, duration, now, 0, 0);
|
|
this->records.push_back(value);
|
|
}
|
|
}
|
|
}
|
|
|
|
// INLINED
|
|
bool ShortcutCooldowns::RotateRows(int amount, int bank, int& rotation0, int& rotation1, const CooldownClock& clock) {
|
|
const int rows = amount < 4 ? amount : amount % 4;
|
|
if (rows <= 0) {
|
|
return false;
|
|
}
|
|
|
|
if (bank == 0 || bank == 1) {
|
|
int& rotation = bank == 0 ? rotation0 : rotation1;
|
|
rotation += rows;
|
|
if (rotation >= 4) {
|
|
rotation -= 4;
|
|
}
|
|
}
|
|
|
|
const std::uint32_t now = clock.Now();
|
|
|
|
for (auto entry = this->records.begin(); entry != this->records.end();) {
|
|
if (entry->end <= now) {
|
|
entry = this->records.erase(entry);
|
|
continue;
|
|
}
|
|
|
|
for (CooldownState& state : entry->main) {
|
|
state.slot -= 9 * rows;
|
|
state.y -= 33 * rows;
|
|
if (state.slot < 0) {
|
|
state.slot += 36;
|
|
state.y += 132;
|
|
}
|
|
}
|
|
|
|
++entry;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// INLINED
|
|
void ShortcutCooldowns::PaintMain(
|
|
const std::list<ShortcutCooldownIcon>& icons, int rows, int x, int y, CooldownDrawing& drawing, const CooldownClock& clock, RenderCommandPool& pool,
|
|
CRenderSystemBase& system
|
|
) {
|
|
const int limit = rows * 33 + 4;
|
|
this->Paint(icons, &ShortcutCooldownRecord::main, limit, x, y, drawing, clock, pool, system);
|
|
}
|
|
|
|
// INLINED
|
|
void ShortcutCooldowns::PaintAlternate(
|
|
const std::list<ShortcutCooldownIcon>& icons, int x, int y, CooldownDrawing& drawing, const CooldownClock& clock, RenderCommandPool& pool,
|
|
CRenderSystemBase& system
|
|
) {
|
|
this->Paint(icons, &ShortcutCooldownRecord::alternate, 0, x, y, drawing, clock, pool, system);
|
|
}
|
|
|
|
// INLINED
|
|
void ShortcutCooldowns::Paint(
|
|
const std::list<ShortcutCooldownIcon>& icons, std::list<CooldownState> ShortcutCooldownRecord::* values, int limit, int x, int y, CooldownDrawing& drawing,
|
|
const CooldownClock& clock, RenderCommandPool& pool, CRenderSystemBase& system
|
|
) {
|
|
const std::uint32_t now = clock.Now();
|
|
|
|
for (auto entry = this->records.begin(); entry != this->records.end();) {
|
|
if (entry->end <= now) {
|
|
entry = this->records.erase(entry);
|
|
continue;
|
|
}
|
|
|
|
std::list<CooldownState>& states = (*entry).*values;
|
|
|
|
for (const ShortcutCooldownIcon& icon : icons) {
|
|
if (entry->id == icon.id || (entry->id == 577 && !IsFirstRange(icon.id)) || (entry->id == 9999 && (IsFirstRange(icon.id) || IsOtherRange(icon.id)))) {
|
|
const auto previous = std::find_if(states.begin(), states.end(), [&](const CooldownState& state) { return state.slot == icon.slot; });
|
|
if (previous == states.end()) {
|
|
states.emplace_back(icon.slot, icon.x, icon.y, entry->duration, entry->end - entry->duration, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (CooldownState& state : states) {
|
|
drawing.Draw(0, 0, 12, 12, state, limit, x, y, clock, pool, system);
|
|
}
|
|
|
|
++entry;
|
|
}
|
|
}
|