Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 108 additions & 23 deletions src/creatures/players/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1670,6 +1670,10 @@ void Player::updatePartyTrackerAnalyzer() const {
}

void Player::sendLootStats(const std::shared_ptr<Item> &item, uint8_t count) {
// Batch loot stats to reduce I/O and allocations
batchedTrackerData.lootItems.emplace_back(item, count);

// Calculate value for metrics
uint64_t value = 0;
if (item->getID() == ITEM_GOLD_COIN || item->getID() == ITEM_PLATINUM_COIN || item->getID() == ITEM_CRYSTAL_COIN) {
if (item->getID() == ITEM_PLATINUM_COIN) {
Expand All @@ -1679,47 +1683,128 @@ void Player::sendLootStats(const std::shared_ptr<Item> &item, uint8_t count) {
} else {
value = count;
}
} else if (
const auto &npc = g_game().getNpcByName("The Lootmonger")
) {
} else if (const auto &npc = g_game().getNpcByName("The Lootmonger")) {
const auto &iType = Item::items.getItemType(item->getID());
value = iType.sellPrice * count;
}
g_metrics().addCounter("player_loot", value, { { "player", getName() } });

if (client) {
client->sendLootStats(item, count);
}
batchedTrackerData.lootValue += value;

if (m_party) {
m_party->addPlayerLoot(getPlayer(), item);
if (!trackerBatchPending) {
trackerBatchPending = true;
const auto self = static_self_cast<Player>();
trackerBatchEventId = g_dispatcher().scheduleEvent(
250, [self] {
self->flushBatchedTrackerData();
},
"Player::flushBatchedTrackerData"
);
}
}

void Player::updateSupplyTracker(const std::shared_ptr<Item> &item) {
const auto &iType = Item::items.getItemType(item->getID());
const auto value = iType.buyPrice;
g_metrics().addCounter("player_supply", value, { { "player", getName() } });

if (client) {
client->sendUpdateSupplyTracker(item);
}
batchedTrackerData.supplyItems.push_back(item);

if (m_party) {
m_party->addPlayerSupply(getPlayer(), item);
const auto &iType = Item::items.getItemType(item->getID());
batchedTrackerData.supplyValue += iType.buyPrice;

if (!trackerBatchPending) {
trackerBatchPending = true;
const auto self = static_self_cast<Player>();
trackerBatchEventId = g_dispatcher().scheduleEvent(
250, [self] {
self->flushBatchedTrackerData();
},
"Player::flushBatchedTrackerData"
);
}
}

void Player::updateImpactTracker(CombatType_t type, int32_t amount) const {
if (client) {
client->sendUpdateImpactTracker(type, amount);
const_cast<Player*>(this)->batchedTrackerData.impactData.emplace_back(type, amount);

if (!trackerBatchPending) {
const_cast<Player*>(this)->trackerBatchPending = true;
const auto self = const_cast<Player*>(this)->static_self_cast<Player>();
const_cast<Player*>(this)->trackerBatchEventId = g_dispatcher().scheduleEvent(
250, [self] {
self->flushBatchedTrackerData();
},
"Player::flushBatchedTrackerData"
);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you sum the amount, it'll create a bug with the "max-dps" and "all-time high"
But if you don’t sum it, you’ll send all of them separately so it’ll be the same, right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, sending impact events separately is the right behavior, and it’s what the code already does.

}
}

void Player::updateInputAnalyzer(CombatType_t type, int32_t amount, const std::string &target) const {
if (client) {
client->sendUpdateInputAnalyzer(type, amount, target);
const_cast<Player*>(this)->batchedTrackerData.inputData.emplace_back(type, amount, target);

if (!trackerBatchPending) {
const_cast<Player*>(this)->trackerBatchPending = true;
const auto self = const_cast<Player*>(this)->static_self_cast<Player>();
const_cast<Player*>(this)->trackerBatchEventId = g_dispatcher().scheduleEvent(
250, [self] {
self->flushBatchedTrackerData();
},
"Player::flushBatchedTrackerData"
);
}
}

void Player::flushBatchedTrackerData() {
trackerBatchPending = false;

for (const auto &[item, count] : batchedTrackerData.lootItems) {
uint64_t value = 0;
if (item) {
if (item->getID() == ITEM_GOLD_COIN || item->getID() == ITEM_PLATINUM_COIN || item->getID() == ITEM_CRYSTAL_COIN) {
if (item->getID() == ITEM_PLATINUM_COIN) {
value = static_cast<uint64_t>(count) * 100ULL;
} else if (item->getID() == ITEM_CRYSTAL_COIN) {
value = static_cast<uint64_t>(count) * 10000ULL;
} else {
value = static_cast<uint64_t>(count);
}
} else if (const auto &npc = g_game().getNpcByName("The Lootmonger")) {
const auto &iType = Item::items.getItemType(item->getID());
value = static_cast<uint64_t>(iType.sellPrice) * static_cast<uint64_t>(count);
}
}
if (value > 0) {
g_metrics().addCounter("player_loot", value, { { "player", getName() } });
}
if (client) {
client->sendLootStats(item, count);
}
if (m_party) {
m_party->addPlayerLoot(getPlayer(), item);
}
}

if (batchedTrackerData.supplyValue > 0) {
g_metrics().addCounter("player_supply", batchedTrackerData.supplyValue, { { "player", getName() } });
}

for (const auto &item : batchedTrackerData.supplyItems) {
if (client) {
client->sendUpdateSupplyTracker(item);
}
if (m_party) {
m_party->addPlayerSupply(getPlayer(), item);
}
}

for (const auto &[type, amount] : batchedTrackerData.impactData) {
if (client) {
client->sendUpdateImpactTracker(type, amount);
}
}

for (const auto &[type, amount, target] : batchedTrackerData.inputData) {
if (client) {
client->sendUpdateInputAnalyzer(type, amount, target);
}
}

batchedTrackerData = BatchedTrackerData {};
}

void Player::createLeaderTeamFinder(NetworkMessage &msg) const {
Expand Down
16 changes: 16 additions & 0 deletions src/creatures/players/player.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1491,11 +1491,11 @@
void addBestiaryKill(const std::shared_ptr<MonsterType> &mType);
void addBosstiaryKill(const std::shared_ptr<MonsterType> &mType);

phmap::flat_hash_set<uint32_t> attackedSet {};

Check warning on line 1494 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-24.04-linux-debug

when initialized here [-Wreorder]

Check warning on line 1494 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-24.04-linux-debug

when initialized here [-Wreorder]

Check warning on line 1494 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-24.04-linux-debug

when initialized here [-Wreorder]

Check warning on line 1494 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04-linux-debug

when initialized here [-Wreorder]

Check warning on line 1494 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04-linux-debug

when initialized here [-Wreorder]

Check warning on line 1494 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04-linux-debug

when initialized here [-Wreorder]

std::map<uint8_t, OpenContainer> openContainers;
std::map<uint32_t, std::shared_ptr<DepotLocker>> depotLockerMap;

Check warning on line 1497 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-24.04-linux-debug

‘uint8_t Player::DeflectCondition::chance’ [-Wreorder]

Check warning on line 1497 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-24.04-linux-debug

‘uint8_t Player::DeflectCondition::chance’ [-Wreorder]

Check warning on line 1497 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-24.04-linux-debug

‘uint8_t Player::DeflectCondition::chance’ [-Wreorder]

Check warning on line 1497 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04-linux-debug

‘uint8_t Player::DeflectCondition::chance’ [-Wreorder]

Check warning on line 1497 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04-linux-debug

‘uint8_t Player::DeflectCondition::chance’ [-Wreorder]

Check warning on line 1497 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04-linux-debug

‘uint8_t Player::DeflectCondition::chance’ [-Wreorder]
std::map<uint32_t, std::shared_ptr<DepotChest>> depotChests;

Check warning on line 1498 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-24.04-linux-debug

‘Player::DeflectCondition::condition’ will be initialized after [-Wreorder]

Check warning on line 1498 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-24.04-linux-debug

‘Player::DeflectCondition::condition’ will be initialized after [-Wreorder]

Check warning on line 1498 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-24.04-linux-debug

‘Player::DeflectCondition::condition’ will be initialized after [-Wreorder]

Check warning on line 1498 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04-linux-debug

‘Player::DeflectCondition::condition’ will be initialized after [-Wreorder]

Check warning on line 1498 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04-linux-debug

‘Player::DeflectCondition::condition’ will be initialized after [-Wreorder]

Check warning on line 1498 in src/creatures/players/player.hpp

View workflow job for this annotation

GitHub Actions / ubuntu-22.04-linux-debug

‘Player::DeflectCondition::condition’ will be initialized after [-Wreorder]
std::map<uint8_t, int64_t> moduleDelayMap;
std::map<uint32_t, int32_t> storageMap;
std::map<uint16_t, uint64_t> itemPriceMap;
Expand Down Expand Up @@ -1752,6 +1752,22 @@
uint64_t m_serene_cooldown = 0;
VirtueMonk_t m_virtue = VIRTUE_NONE;

// Batched tracker updates to reduce I/O and allocations
struct BatchedTrackerData {
uint64_t lootValue = 0;
uint64_t supplyValue = 0;
std::vector<std::pair<CombatType_t, int32_t>> impactData;
std::vector<std::tuple<CombatType_t, int32_t, std::string>> inputData;
std::vector<std::pair<std::shared_ptr<Item>, uint8_t>> lootItems;
std::vector<std::shared_ptr<Item>> supplyItems;
};

BatchedTrackerData batchedTrackerData;
uint64_t trackerBatchEventId = 0;
bool trackerBatchPending = false;

void flushBatchedTrackerData();

friend class Game;
friend class SaveManager;
friend class Npc;
Expand Down
Loading