diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 6cefb184e9e..791f696148c 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -1605,9 +1605,9 @@ class Player final : public Creature, public Cylinder, public Bankable { client->sendHighscoresNoData(); } } - void sendHighscores(const std::vector &characters, uint8_t categoryId, uint32_t vocationId, uint16_t page, uint16_t pages) { + void sendHighscores(const std::vector &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) { diff --git a/src/game/game.cpp b/src/game/game.cpp index 046de46a20f..b3706b7bf38 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -7968,14 +7968,18 @@ void Game::processHighscoreResults(DBResult_ptr result, uint32_t playerID, uint8 pages /= entriesPerPage; std::ostringstream cacheKeyStream; - cacheKeyStream << "Highscore_" << static_cast(category) << "_" << static_cast(vocation) << "_" << static_cast(entriesPerPage); + cacheKeyStream << "Highscore_" << static_cast(category) << "_" << static_cast(vocation) << "_" << static_cast(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(pages)); + auto cachedTime = it->second.timestamp; + auto durationSinceEpoch = cachedTime.time_since_epoch(); + auto secondsSinceEpoch = std::chrono::duration_cast(durationSinceEpoch).count(); + auto updateTimer = static_cast(secondsSinceEpoch); + player->sendHighscores(cacheEntry.characters, category, vocation, cacheEntry.page, static_cast(cacheEntry.entriesPerPage), updateTimer); } else { std::vector characters; characters.reserve(result->countResults()); @@ -7992,25 +7996,14 @@ void Game::processHighscoreResults(DBResult_ptr result, uint32_t playerID, uint8 } while (result->next()); } - player->sendHighscores(characters, category, vocation, page, static_cast(pages)); - highscoreCache[cacheKey] = { characters, now }; + player->sendHighscores(characters, category, vocation, page, static_cast(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) { @@ -8018,13 +8011,15 @@ std::string Game::generateHighscoreOrGetCachedQueryForEntries(const std::string cacheKeyStream << "Entries_" << categoryName << "_" << page << "_" << static_cast(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; } @@ -8034,13 +8029,15 @@ std::string Game::generateHighscoreOrGetCachedQueryForOurRank(const std::string cacheKeyStream << "OurRank_" << categoryName << "_" << static_cast(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; } @@ -8092,7 +8089,7 @@ void Game::playerHighscores(std::shared_ptr player, HighscoreType_t type uint32_t playerID = player->getID(); std::function 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); diff --git a/src/game/game.hpp b/src/game/game.hpp index e84cb4a513b..a5c7cd116c0 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -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 timestamp; }; struct HighscoreCacheEntry { std::vector characters; - std::chrono::time_point timestamp; + uint32_t page; + uint32_t entriesPerPage; + std::chrono::time_point timestamp; }; class Game { @@ -900,10 +904,9 @@ class Game { // Variable members (m_) std::unique_ptr 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); diff --git a/src/map/house/house.cpp b/src/map/house/house.cpp index e1225aa9370..8bb26bcfb6b 100644 --- a/src/map/house/house.cpp +++ b/src/map/house/house.cpp @@ -502,7 +502,20 @@ bool House::executeTransfer(std::shared_ptr item, std::shared } void AccessList::parseList(const std::string &list) { - std::string validList = validateNameHouse(list); + std::regex regexValidChars("[^a-zA-Z' \n*!@#]+"); + std::string validList = std::regex_replace(list, regexValidChars, ""); + + // Remove empty lines + std::istringstream iss(validList); + std::ostringstream oss; + std::string line; + while (std::getline(iss, line)) { + if (!line.empty()) { + oss << line << '\n'; + } + } + validList = oss.str(); + playerList.clear(); guildRankList.clear(); allowEveryone = false; diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 53aedeb1c88..a2466038c99 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -2066,7 +2066,7 @@ void ProtocolGame::sendHighscoresNoData() { writeToOutputBuffer(msg); } -void ProtocolGame::sendHighscores(const std::vector &characters, uint8_t categoryId, uint32_t vocationId, uint16_t page, uint16_t pages) { +void ProtocolGame::sendHighscores(const std::vector &characters, uint8_t categoryId, uint32_t vocationId, uint16_t page, uint16_t pages, uint32_t updateTimer) { if (oldProtocol) { return; } @@ -2145,8 +2145,7 @@ void ProtocolGame::sendHighscores(const std::vector &charact msg.addByte(0xFF); // ?? msg.addByte(0); // ?? msg.addByte(1); // ?? - msg.add(time(nullptr)); // Last Update - + msg.add(updateTimer); // Last Update msg.setBufferPosition(vocationPosition); msg.addByte(vocations); writeToOutputBuffer(msg); diff --git a/src/server/network/protocol/protocolgame.hpp b/src/server/network/protocol/protocolgame.hpp index df7a9f53a35..2295c1036ea 100644 --- a/src/server/network/protocol/protocolgame.hpp +++ b/src/server/network/protocol/protocolgame.hpp @@ -132,7 +132,7 @@ class ProtocolGame final : public Protocol { void parseHighscores(NetworkMessage &msg); void parseTaskHuntingAction(NetworkMessage &msg); void sendHighscoresNoData(); - void sendHighscores(const std::vector &characters, uint8_t categoryId, uint32_t vocationId, uint16_t page, uint16_t pages); + void sendHighscores(const std::vector &characters, uint8_t categoryId, uint32_t vocationId, uint16_t page, uint16_t pages, uint32_t updateTimer); void parseGreet(NetworkMessage &msg); void parseBugReport(NetworkMessage &msg); diff --git a/src/utils/tools.cpp b/src/utils/tools.cpp index f5a8597eb9c..ea927bc5189 100644 --- a/src/utils/tools.cpp +++ b/src/utils/tools.cpp @@ -1511,17 +1511,6 @@ void consoleHandlerExit() { return; } -std::string validateNameHouse(const std::string &list) { - std::string result; - for (char c : list) { - if (isalpha(c) || c == ' ' || c == '\'' || c == '!' || c == '\n' - || c == '?' || c == '#' || c == '@' || c == '*') { - result += c; - } - } - return result; -} - NameEval_t validateName(const std::string &name) { StringVector prohibitedWords = { "owner", "gamemaster", "hoster", "admin", "staff", "tibia", "account", "god", "anal", "ass", "fuck", "sex", "hitler", "pussy", "dick", "rape", "cm", "gm", "tutor", "counsellor", "god" }; StringVector toks; diff --git a/src/utils/tools.hpp b/src/utils/tools.hpp index fd6b41d1f3c..14e9fd39416 100644 --- a/src/utils/tools.hpp +++ b/src/utils/tools.hpp @@ -126,7 +126,6 @@ const char* getReturnMessage(ReturnValue value); void sleep_for(uint64_t ms); void capitalizeWords(std::string &source); void consoleHandlerExit(); -std::string validateNameHouse(const std::string &name); NameEval_t validateName(const std::string &name); bool isCaskItem(uint16_t itemId);