Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: highscore client pages #1735

Merged
merged 5 commits into from
Oct 24, 2023
Merged
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
4 changes: 2 additions & 2 deletions src/creatures/players/player.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1605,9 +1605,9 @@ class Player final : public Creature, public Cylinder, public Bankable {
client->sendHighscoresNoData();
}
}
void sendHighscores(const std::vector<HighscoreCharacter> &characters, uint8_t categoryId, uint32_t vocationId, uint16_t page, uint16_t pages) {
void sendHighscores(const std::vector<HighscoreCharacter> &characters, uint8_t categoryId, uint32_t vocationId, uint16_t page, uint16_t pages, uint32_t updateTimer) {
if (client) {
client->sendHighscores(characters, categoryId, vocationId, page, pages);
client->sendHighscores(characters, categoryId, vocationId, page, pages, updateTimer);
}
}
void addAsyncOngoingTask(uint64_t flags) {
Expand Down
53 changes: 25 additions & 28 deletions src/game/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7968,14 +7968,18 @@ void Game::processHighscoreResults(DBResult_ptr result, uint32_t playerID, uint8
pages /= entriesPerPage;

std::ostringstream cacheKeyStream;
cacheKeyStream << "Highscore_" << static_cast<int>(category) << "_" << static_cast<int>(vocation) << "_" << static_cast<int>(entriesPerPage);
cacheKeyStream << "Highscore_" << static_cast<int>(category) << "_" << static_cast<int>(vocation) << "_" << static_cast<int>(entriesPerPage) << "_" << page;
std::string cacheKey = cacheKeyStream.str();

auto it = highscoreCache.find(cacheKey);
auto now = std::chrono::steady_clock::now();
auto now = std::chrono::system_clock::now();
if (it != highscoreCache.end() && (now - it->second.timestamp < HIGHSCORE_CACHE_EXPIRATION_TIME)) {
auto &cacheEntry = it->second;
player->sendHighscores(cacheEntry.characters, category, vocation, page, static_cast<uint16_t>(pages));
auto cachedTime = it->second.timestamp;
auto durationSinceEpoch = cachedTime.time_since_epoch();
auto secondsSinceEpoch = std::chrono::duration_cast<std::chrono::seconds>(durationSinceEpoch).count();
auto updateTimer = static_cast<uint32_t>(secondsSinceEpoch);
player->sendHighscores(cacheEntry.characters, category, vocation, cacheEntry.page, static_cast<uint16_t>(cacheEntry.entriesPerPage), updateTimer);
} else {
std::vector<HighscoreCharacter> characters;
characters.reserve(result->countResults());
Expand All @@ -7992,39 +7996,30 @@ void Game::processHighscoreResults(DBResult_ptr result, uint32_t playerID, uint8
} while (result->next());
}

player->sendHighscores(characters, category, vocation, page, static_cast<uint16_t>(pages));
highscoreCache[cacheKey] = { characters, now };
player->sendHighscores(characters, category, vocation, page, static_cast<uint16_t>(pages), getTimeNow());
highscoreCache[cacheKey] = { characters, page, pages, now };
}
}

std::string Game::getCachedQueryHighscore(const std::string &key) {
auto it = queryCache.find(key);
if (it != queryCache.end()) {
auto now = std::chrono::steady_clock::now();
if (now - it->second.timestamp < CACHE_EXPIRATION_TIME) {
return it->second.query;
}
}
return "";
}

void Game::cacheQueryHighscore(const std::string &key, const std::string &query) {
auto now = std::chrono::steady_clock::now();
queryCache[key] = { query, now };
void Game::cacheQueryHighscore(const std::string &key, const std::string &query, uint32_t page, uint8_t entriesPerPage) {
QueryHighscoreCacheEntry queryEntry { query, page, entriesPerPage, std::chrono::steady_clock::now() };
queryCache[key] = queryEntry;
}

std::string Game::generateHighscoreOrGetCachedQueryForEntries(const std::string &categoryName, uint32_t page, uint8_t entriesPerPage, uint32_t vocation) {
std::ostringstream cacheKeyStream;
cacheKeyStream << "Entries_" << categoryName << "_" << page << "_" << static_cast<int>(entriesPerPage) << "_" << vocation;
std::string cacheKey = cacheKeyStream.str();

std::string cachedQuery = getCachedQueryHighscore(cacheKey);
if (!cachedQuery.empty()) {
return cachedQuery;
if (queryCache.find(cacheKey) != queryCache.end()) {
const QueryHighscoreCacheEntry &cachedEntry = queryCache[cacheKey];
if (cachedEntry.page == page) {
return cachedEntry.query;
}
}

std::string newQuery = generateHighscoreQueryForEntries(categoryName, page, entriesPerPage, vocation);
cacheQueryHighscore(cacheKey, newQuery);
cacheQueryHighscore(cacheKey, newQuery, page, entriesPerPage);

return newQuery;
}
Expand All @@ -8034,13 +8029,15 @@ std::string Game::generateHighscoreOrGetCachedQueryForOurRank(const std::string
cacheKeyStream << "OurRank_" << categoryName << "_" << static_cast<int>(entriesPerPage) << "_" << playerGUID << "_" << vocation;
std::string cacheKey = cacheKeyStream.str();

std::string cachedQuery = getCachedQueryHighscore(cacheKey);
if (!cachedQuery.empty()) {
return cachedQuery;
if (queryCache.find(cacheKey) != queryCache.end()) {
const QueryHighscoreCacheEntry &cachedEntry = queryCache[cacheKey];
if (cachedEntry.page == entriesPerPage) {
return cachedEntry.query;
}
}

std::string newQuery = generateHighscoreQueryForOurRank(categoryName, entriesPerPage, playerGUID, vocation);
cacheQueryHighscore(cacheKey, newQuery);
cacheQueryHighscore(cacheKey, newQuery, entriesPerPage, entriesPerPage);

return newQuery;
}
Expand Down Expand Up @@ -8092,7 +8089,7 @@ void Game::playerHighscores(std::shared_ptr<Player> player, HighscoreType_t type

uint32_t playerID = player->getID();
std::function<void(DBResult_ptr, bool)> callback = [this, playerID, category, vocation, entriesPerPage](DBResult_ptr result, bool) {
processHighscoreResults(result, playerID, category, vocation, entriesPerPage);
processHighscoreResults(std::move(result), playerID, category, vocation, entriesPerPage);
};

g_databaseTasks().store(query, callback);
Expand Down
9 changes: 6 additions & 3 deletions src/game/game.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,16 @@ static constexpr std::chrono::minutes HIGHSCORE_CACHE_EXPIRATION_TIME { 10 }; //

struct QueryHighscoreCacheEntry {
std::string query;
uint32_t page;
uint8_t entriesPerPage;
std::chrono::time_point<std::chrono::steady_clock> timestamp;
};

struct HighscoreCacheEntry {
std::vector<HighscoreCharacter> characters;
std::chrono::time_point<std::chrono::steady_clock> timestamp;
uint32_t page;
uint32_t entriesPerPage;
std::chrono::time_point<std::chrono::system_clock> timestamp;
};

class Game {
Expand Down Expand Up @@ -900,10 +904,9 @@ class Game {
// Variable members (m_)
std::unique_ptr<IOWheel> m_IOWheel;

void cacheQueryHighscore(const std::string &key, const std::string &query);
void cacheQueryHighscore(const std::string &key, const std::string &query, uint32_t page, uint8_t entriesPerPage);
void processHighscoreResults(DBResult_ptr result, uint32_t playerID, uint8_t category, uint32_t vocation, uint8_t entriesPerPage);

std::string getCachedQueryHighscore(const std::string &key);
std::string generateVocationConditionHighscore(uint32_t vocation);
std::string generateHighscoreQueryForEntries(const std::string &categoryName, uint32_t page, uint8_t entriesPerPage, uint32_t vocation);
std::string generateHighscoreQueryForOurRank(const std::string &categoryName, uint8_t entriesPerPage, uint32_t playerGUID, uint32_t vocation);
Expand Down
5 changes: 2 additions & 3 deletions src/server/network/protocol/protocolgame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2066,7 +2066,7 @@ void ProtocolGame::sendHighscoresNoData() {
writeToOutputBuffer(msg);
}

void ProtocolGame::sendHighscores(const std::vector<HighscoreCharacter> &characters, uint8_t categoryId, uint32_t vocationId, uint16_t page, uint16_t pages) {
void ProtocolGame::sendHighscores(const std::vector<HighscoreCharacter> &characters, uint8_t categoryId, uint32_t vocationId, uint16_t page, uint16_t pages, uint32_t updateTimer) {
if (oldProtocol) {
return;
}
Expand Down Expand Up @@ -2145,8 +2145,7 @@ void ProtocolGame::sendHighscores(const std::vector<HighscoreCharacter> &charact
msg.addByte(0xFF); // ??
msg.addByte(0); // ??
msg.addByte(1); // ??
msg.add<uint32_t>(time(nullptr)); // Last Update

msg.add<uint32_t>(updateTimer); // Last Update
msg.setBufferPosition(vocationPosition);
msg.addByte(vocations);
writeToOutputBuffer(msg);
Expand Down
2 changes: 1 addition & 1 deletion src/server/network/protocol/protocolgame.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class ProtocolGame final : public Protocol {
void parseHighscores(NetworkMessage &msg);
void parseTaskHuntingAction(NetworkMessage &msg);
void sendHighscoresNoData();
void sendHighscores(const std::vector<HighscoreCharacter> &characters, uint8_t categoryId, uint32_t vocationId, uint16_t page, uint16_t pages);
void sendHighscores(const std::vector<HighscoreCharacter> &characters, uint8_t categoryId, uint32_t vocationId, uint16_t page, uint16_t pages, uint32_t updateTimer);

void parseGreet(NetworkMessage &msg);
void parseBugReport(NetworkMessage &msg);
Expand Down
Loading