mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 08:03:50 +00:00
fix(combatlog): dedupe duplicate spellsteal aura logs
This commit is contained in:
parent
3edf280e06
commit
91dc45d19e
2 changed files with 82 additions and 25 deletions
|
|
@ -2369,6 +2369,7 @@ private:
|
||||||
|
|
||||||
void addCombatText(CombatTextEntry::Type type, int32_t amount, uint32_t spellId, bool isPlayerSource, uint8_t powerType = 0,
|
void addCombatText(CombatTextEntry::Type type, int32_t amount, uint32_t spellId, bool isPlayerSource, uint8_t powerType = 0,
|
||||||
uint64_t srcGuid = 0, uint64_t dstGuid = 0);
|
uint64_t srcGuid = 0, uint64_t dstGuid = 0);
|
||||||
|
bool shouldLogSpellstealAura(uint64_t casterGuid, uint64_t victimGuid, uint32_t spellId);
|
||||||
void addSystemChatMessage(const std::string& message);
|
void addSystemChatMessage(const std::string& message);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2575,7 +2576,15 @@ private:
|
||||||
std::unordered_set<uint64_t> hostileAttackers_;
|
std::unordered_set<uint64_t> hostileAttackers_;
|
||||||
std::vector<CombatTextEntry> combatText;
|
std::vector<CombatTextEntry> combatText;
|
||||||
static constexpr size_t MAX_COMBAT_LOG = 500;
|
static constexpr size_t MAX_COMBAT_LOG = 500;
|
||||||
|
struct RecentSpellstealLogEntry {
|
||||||
|
uint64_t casterGuid = 0;
|
||||||
|
uint64_t victimGuid = 0;
|
||||||
|
uint32_t spellId = 0;
|
||||||
|
std::chrono::steady_clock::time_point timestamp{};
|
||||||
|
};
|
||||||
|
static constexpr size_t MAX_RECENT_SPELLSTEAL_LOGS = 32;
|
||||||
std::deque<CombatLogEntry> combatLog_;
|
std::deque<CombatLogEntry> combatLog_;
|
||||||
|
std::deque<RecentSpellstealLogEntry> recentSpellstealLogs_;
|
||||||
std::deque<std::string> areaTriggerMsgs_;
|
std::deque<std::string> areaTriggerMsgs_;
|
||||||
// unitGuid → sorted threat list (descending by threat value)
|
// unitGuid → sorted threat list (descending by threat value)
|
||||||
std::unordered_map<uint64_t, std::vector<ThreatEntry>> threatLists_;
|
std::unordered_map<uint64_t, std::vector<ThreatEntry>> threatLists_;
|
||||||
|
|
|
||||||
|
|
@ -6164,43 +6164,56 @@ void GameHandler::handlePacket(network::Packet& packet) {
|
||||||
// multi-aura packets down to the first entry only.
|
// multi-aura packets down to the first entry only.
|
||||||
std::vector<uint32_t> dispelledIds;
|
std::vector<uint32_t> dispelledIds;
|
||||||
dispelledIds.reserve(count);
|
dispelledIds.reserve(count);
|
||||||
std::string firstSpellName;
|
|
||||||
for (uint32_t i = 0; i < count && packet.getSize() - packet.getReadPos() >= 5; ++i) {
|
for (uint32_t i = 0; i < count && packet.getSize() - packet.getReadPos() >= 5; ++i) {
|
||||||
uint32_t dispelledId = packet.readUInt32();
|
uint32_t dispelledId = packet.readUInt32();
|
||||||
/*uint8_t isPositive =*/ packet.readUInt8();
|
/*uint8_t isPositive =*/ packet.readUInt8();
|
||||||
if (dispelledId != 0) {
|
if (dispelledId != 0) {
|
||||||
dispelledIds.push_back(dispelledId);
|
dispelledIds.push_back(dispelledId);
|
||||||
}
|
}
|
||||||
if (i == 0) {
|
|
||||||
const std::string& nm = getSpellName(dispelledId);
|
|
||||||
firstSpellName = nm.empty() ? ("spell " + std::to_string(dispelledId)) : nm;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Show system message if player was victim or caster
|
// Show system message if player was victim or caster
|
||||||
if (victimGuid == playerGuid || casterGuid == playerGuid) {
|
if (victimGuid == playerGuid || casterGuid == playerGuid) {
|
||||||
if (!firstSpellName.empty()) {
|
std::vector<uint32_t> loggedIds;
|
||||||
|
if (isStolen) {
|
||||||
|
loggedIds.reserve(dispelledIds.size());
|
||||||
|
for (uint32_t dispelledId : dispelledIds) {
|
||||||
|
if (shouldLogSpellstealAura(casterGuid, victimGuid, dispelledId))
|
||||||
|
loggedIds.push_back(dispelledId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
loggedIds = dispelledIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t displaySpellId = !loggedIds.empty() ? loggedIds.front() : 0;
|
||||||
|
const std::string displaySpellName = displaySpellId != 0
|
||||||
|
? [&]() {
|
||||||
|
const std::string& nm = getSpellName(displaySpellId);
|
||||||
|
return nm.empty() ? ("spell " + std::to_string(displaySpellId)) : nm;
|
||||||
|
}()
|
||||||
|
: std::string{};
|
||||||
|
if (!displaySpellName.empty()) {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
if (isStolen) {
|
if (isStolen) {
|
||||||
if (victimGuid == playerGuid && casterGuid != playerGuid)
|
if (victimGuid == playerGuid && casterGuid != playerGuid)
|
||||||
std::snprintf(buf, sizeof(buf), "%s was stolen.", firstSpellName.c_str());
|
std::snprintf(buf, sizeof(buf), "%s was stolen.", displaySpellName.c_str());
|
||||||
else if (casterGuid == playerGuid)
|
else if (casterGuid == playerGuid)
|
||||||
std::snprintf(buf, sizeof(buf), "You steal %s.", firstSpellName.c_str());
|
std::snprintf(buf, sizeof(buf), "You steal %s.", displaySpellName.c_str());
|
||||||
else
|
else
|
||||||
std::snprintf(buf, sizeof(buf), "%s was stolen.", firstSpellName.c_str());
|
std::snprintf(buf, sizeof(buf), "%s was stolen.", displaySpellName.c_str());
|
||||||
} else {
|
} else {
|
||||||
if (victimGuid == playerGuid && casterGuid != playerGuid)
|
if (victimGuid == playerGuid && casterGuid != playerGuid)
|
||||||
std::snprintf(buf, sizeof(buf), "%s was dispelled.", firstSpellName.c_str());
|
std::snprintf(buf, sizeof(buf), "%s was dispelled.", displaySpellName.c_str());
|
||||||
else if (casterGuid == playerGuid)
|
else if (casterGuid == playerGuid)
|
||||||
std::snprintf(buf, sizeof(buf), "You dispel %s.", firstSpellName.c_str());
|
std::snprintf(buf, sizeof(buf), "You dispel %s.", displaySpellName.c_str());
|
||||||
else
|
else
|
||||||
std::snprintf(buf, sizeof(buf), "%s was dispelled.", firstSpellName.c_str());
|
std::snprintf(buf, sizeof(buf), "%s was dispelled.", displaySpellName.c_str());
|
||||||
}
|
}
|
||||||
addSystemChatMessage(buf);
|
addSystemChatMessage(buf);
|
||||||
}
|
}
|
||||||
// Preserve stolen auras as spellsteal events so the log wording stays accurate.
|
// Preserve stolen auras as spellsteal events so the log wording stays accurate.
|
||||||
if (!dispelledIds.empty()) {
|
if (!loggedIds.empty()) {
|
||||||
bool isPlayerCaster = (casterGuid == playerGuid);
|
bool isPlayerCaster = (casterGuid == playerGuid);
|
||||||
for (uint32_t dispelledId : dispelledIds) {
|
for (uint32_t dispelledId : loggedIds) {
|
||||||
addCombatText(isStolen ? CombatTextEntry::STEAL : CombatTextEntry::DISPEL,
|
addCombatText(isStolen ? CombatTextEntry::STEAL : CombatTextEntry::DISPEL,
|
||||||
0, dispelledId, isPlayerCaster, 0,
|
0, dispelledId, isPlayerCaster, 0,
|
||||||
casterGuid, victimGuid);
|
casterGuid, victimGuid);
|
||||||
|
|
@ -6236,31 +6249,41 @@ void GameHandler::handlePacket(network::Packet& packet) {
|
||||||
// Preserve every stolen aura in the combat log instead of only the first.
|
// Preserve every stolen aura in the combat log instead of only the first.
|
||||||
std::vector<uint32_t> stolenIds;
|
std::vector<uint32_t> stolenIds;
|
||||||
stolenIds.reserve(stealCount);
|
stolenIds.reserve(stealCount);
|
||||||
std::string stolenName;
|
|
||||||
for (uint32_t i = 0; i < stealCount && packet.getSize() - packet.getReadPos() >= 5; ++i) {
|
for (uint32_t i = 0; i < stealCount && packet.getSize() - packet.getReadPos() >= 5; ++i) {
|
||||||
uint32_t stolenId = packet.readUInt32();
|
uint32_t stolenId = packet.readUInt32();
|
||||||
/*uint8_t isPos =*/ packet.readUInt8();
|
/*uint8_t isPos =*/ packet.readUInt8();
|
||||||
if (stolenId != 0) {
|
if (stolenId != 0) {
|
||||||
stolenIds.push_back(stolenId);
|
stolenIds.push_back(stolenId);
|
||||||
}
|
}
|
||||||
if (i == 0) {
|
|
||||||
const std::string& nm = getSpellName(stolenId);
|
|
||||||
stolenName = nm.empty() ? ("spell " + std::to_string(stolenId)) : nm;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (stealCaster == playerGuid || stealVictim == playerGuid) {
|
if (stealCaster == playerGuid || stealVictim == playerGuid) {
|
||||||
if (!stolenName.empty()) {
|
std::vector<uint32_t> loggedIds;
|
||||||
|
loggedIds.reserve(stolenIds.size());
|
||||||
|
for (uint32_t stolenId : stolenIds) {
|
||||||
|
if (shouldLogSpellstealAura(stealCaster, stealVictim, stolenId))
|
||||||
|
loggedIds.push_back(stolenId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t displaySpellId = !loggedIds.empty() ? loggedIds.front() : 0;
|
||||||
|
const std::string displaySpellName = displaySpellId != 0
|
||||||
|
? [&]() {
|
||||||
|
const std::string& nm = getSpellName(displaySpellId);
|
||||||
|
return nm.empty() ? ("spell " + std::to_string(displaySpellId)) : nm;
|
||||||
|
}()
|
||||||
|
: std::string{};
|
||||||
|
if (!displaySpellName.empty()) {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
if (stealCaster == playerGuid)
|
if (stealCaster == playerGuid)
|
||||||
std::snprintf(buf, sizeof(buf), "You stole %s.", stolenName.c_str());
|
std::snprintf(buf, sizeof(buf), "You stole %s.", displaySpellName.c_str());
|
||||||
else
|
else
|
||||||
std::snprintf(buf, sizeof(buf), "%s was stolen.", stolenName.c_str());
|
std::snprintf(buf, sizeof(buf), "%s was stolen.", displaySpellName.c_str());
|
||||||
addSystemChatMessage(buf);
|
addSystemChatMessage(buf);
|
||||||
}
|
}
|
||||||
// Preserve spellsteal as a distinct event so the UI wording stays accurate.
|
// Some servers emit both SPELLDISPELLOG(isStolen=1) and SPELLSTEALLOG
|
||||||
if (!stolenIds.empty()) {
|
// for the same aura. Keep the first event and suppress the duplicate.
|
||||||
|
if (!loggedIds.empty()) {
|
||||||
bool isPlayerCaster = (stealCaster == playerGuid);
|
bool isPlayerCaster = (stealCaster == playerGuid);
|
||||||
for (uint32_t stolenId : stolenIds) {
|
for (uint32_t stolenId : loggedIds) {
|
||||||
addCombatText(CombatTextEntry::STEAL, 0, stolenId, isPlayerCaster, 0,
|
addCombatText(CombatTextEntry::STEAL, 0, stolenId, isPlayerCaster, 0,
|
||||||
stealCaster, stealVictim);
|
stealCaster, stealVictim);
|
||||||
}
|
}
|
||||||
|
|
@ -14080,6 +14103,31 @@ void GameHandler::addCombatText(CombatTextEntry::Type type, int32_t amount, uint
|
||||||
combatLog_.push_back(std::move(log));
|
combatLog_.push_back(std::move(log));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GameHandler::shouldLogSpellstealAura(uint64_t casterGuid, uint64_t victimGuid, uint32_t spellId) {
|
||||||
|
if (spellId == 0) return false;
|
||||||
|
|
||||||
|
const auto now = std::chrono::steady_clock::now();
|
||||||
|
constexpr auto kRecentWindow = std::chrono::seconds(1);
|
||||||
|
while (!recentSpellstealLogs_.empty() &&
|
||||||
|
now - recentSpellstealLogs_.front().timestamp > kRecentWindow) {
|
||||||
|
recentSpellstealLogs_.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = recentSpellstealLogs_.begin(); it != recentSpellstealLogs_.end(); ++it) {
|
||||||
|
if (it->casterGuid == casterGuid &&
|
||||||
|
it->victimGuid == victimGuid &&
|
||||||
|
it->spellId == spellId) {
|
||||||
|
recentSpellstealLogs_.erase(it);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recentSpellstealLogs_.size() >= MAX_RECENT_SPELLSTEAL_LOGS)
|
||||||
|
recentSpellstealLogs_.pop_front();
|
||||||
|
recentSpellstealLogs_.push_back({casterGuid, victimGuid, spellId, now});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void GameHandler::updateCombatText(float deltaTime) {
|
void GameHandler::updateCombatText(float deltaTime) {
|
||||||
for (auto& entry : combatText) {
|
for (auto& entry : combatText) {
|
||||||
entry.age += deltaTime;
|
entry.age += deltaTime;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue