From 178372ba8b239d523860678dd538265c1fce17a7 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Fri, 27 Oct 2023 07:48:02 -0300 Subject: [PATCH 01/10] fix: login with account name on old protocol (11.00) (#1749) Resolves #1683 --- config.lua.dist | 2 +- src/account/account.cpp | 2 +- src/account/account_repository.hpp | 2 +- src/account/account_repository_db.cpp | 7 ++++--- src/account/account_repository_db.hpp | 2 +- src/canary_server.cpp | 11 ++++++----- src/core.hpp | 7 ------- src/lib/logging/log_with_spd_log.cpp | 4 ++-- src/server/network/protocol/protocolstatus.cpp | 16 ++++++++++------ src/server/network/protocol/protocolstatus.hpp | 4 ++++ .../account/in_memory_account_repository.hpp | 2 +- tests/integration/main.cpp | 4 ++-- 12 files changed, 33 insertions(+), 30 deletions(-) diff --git a/config.lua.dist b/config.lua.dist index a78e73e63ca..5b022b17e58 100644 --- a/config.lua.dist +++ b/config.lua.dist @@ -10,7 +10,7 @@ coreDirectory = "data" -- Set log level -- It can be trace, debug, info, warning, error, critical, off (default: info). -- NOTE: Will only display logs with level higher or equal the one set. -logLevel = "debug" +logLevel = "info" -- Combat settings -- NOTE: valid values for worldType are: "pvp", "no-pvp" and "pvp-enforced" diff --git a/src/account/account.cpp b/src/account/account.cpp index 5c093f917bd..881b9491406 100644 --- a/src/account/account.cpp +++ b/src/account/account.cpp @@ -36,7 +36,7 @@ namespace account { return ERROR_NO; } - if (!m_descriptor.empty() && accountRepository.loadByEmail(m_descriptor, m_account)) { + if (!m_descriptor.empty() && accountRepository.loadByEmailOrName(getProtocolCompat(), m_descriptor, m_account)) { m_accLoaded = true; return ERROR_NO; } diff --git a/src/account/account_repository.hpp b/src/account/account_repository.hpp index daf869e249d..b883050993b 100644 --- a/src/account/account_repository.hpp +++ b/src/account/account_repository.hpp @@ -17,7 +17,7 @@ namespace account { virtual ~AccountRepository() = default; virtual bool loadByID(const uint32_t &id, AccountInfo &acc) = 0; - virtual bool loadByEmail(const std::string &email, AccountInfo &acc) = 0; + virtual bool loadByEmailOrName(bool oldProtocol, const std::string &emailOrName, AccountInfo &acc) = 0; virtual bool loadBySession(const std::string &email, AccountInfo &acc) = 0; virtual bool save(const AccountInfo &accInfo) = 0; diff --git a/src/account/account_repository_db.cpp b/src/account/account_repository_db.cpp index 601aa1ec8b1..c4a960e6244 100644 --- a/src/account/account_repository_db.cpp +++ b/src/account/account_repository_db.cpp @@ -19,8 +19,9 @@ namespace account { return load(query, acc); }; - bool AccountRepositoryDB::loadByEmail(const std::string &email, AccountInfo &acc) { - auto query = fmt::format("SELECT `id`, `type`, `premdays`, `lastday`, `creation`, `premdays_purchased`, 0 AS `expires` FROM `accounts` WHERE `email` = {}", db.escapeString(email)); + bool AccountRepositoryDB::loadByEmailOrName(bool oldProtocol, const std::string &emailOrName, AccountInfo &acc) { + auto identifier = oldProtocol ? "name" : "email"; + auto query = fmt::format("SELECT `id`, `type`, `premdays`, `lastday`, `creation`, `premdays_purchased`, 0 AS `expires` FROM `accounts` WHERE `{}` = {}", identifier, db.escapeString(emailOrName)); return load(query, acc); }; @@ -163,7 +164,7 @@ namespace account { acc.premiumLastDay = result->getNumber("lastday"); acc.sessionExpires = result->getNumber("expires"); acc.premiumDaysPurchased = result->getNumber("premdays_purchased"); - acc.creationTime = result->getNumber("creation"); + acc.creationTime = result->getNumber("creation"); setupLoyaltyInfo(acc); diff --git a/src/account/account_repository_db.hpp b/src/account/account_repository_db.hpp index 9da0486ee2b..d09f6cf7be5 100644 --- a/src/account/account_repository_db.hpp +++ b/src/account/account_repository_db.hpp @@ -21,7 +21,7 @@ namespace account { db(db), logger(logger) { } bool loadByID(const uint32_t &id, AccountInfo &acc) override; - bool loadByEmail(const std::string &email, AccountInfo &acc) override; + bool loadByEmailOrName(bool oldProtocol, const std::string &emailOrName, AccountInfo &acc) override; bool loadBySession(const std::string &esseionKey, AccountInfo &acc) override; bool save(const AccountInfo &accInfo) override; diff --git a/src/canary_server.cpp b/src/canary_server.cpp index bdb3ad2c5b1..6d833e0ce0b 100644 --- a/src/canary_server.cpp +++ b/src/canary_server.cpp @@ -26,6 +26,7 @@ #include "lua/scripts/lua_environment.hpp" #include "lua/scripts/scripts.hpp" #include "server/network/protocol/protocollogin.hpp" +#include "server/network/protocol/protocolstatus.hpp" #include "server/network/webhook/webhook.hpp" #include "io/ioprey.hpp" #include "io/io_bosstiary.hpp" @@ -50,7 +51,7 @@ CanaryServer::CanaryServer( g_dispatcher().init(); #ifdef _WIN32 - SetConsoleTitleA(STATUS_SERVER_NAME); + SetConsoleTitleA(ProtocolStatus::SERVER_NAME.c_str()); #endif } @@ -83,7 +84,7 @@ int CanaryServer::run() { if (getuid() == 0 || geteuid() == 0) { logger.warn("{} has been executed as root user, " "please consider running it as a normal user", - STATUS_SERVER_NAME); + ProtocolStatus::SERVER_NAME); } #endif @@ -181,12 +182,12 @@ void CanaryServer::setupHousesRent() { void CanaryServer::logInfos() { #if defined(GIT_RETRIEVED_STATE) && GIT_RETRIEVED_STATE - logger.debug("{} - Version [{}] dated [{}]", STATUS_SERVER_NAME, SERVER_RELEASE_VERSION, GIT_COMMIT_DATE_ISO8601); + logger.debug("{} - Version [{}] dated [{}]", ProtocolStatus::SERVER_NAME, SERVER_RELEASE_VERSION, GIT_COMMIT_DATE_ISO8601); #if GIT_IS_DIRTY logger.debug("DIRTY - NOT OFFICIAL RELEASE"); #endif #else - logger.info("{} - Version {}", STATUS_SERVER_NAME, SERVER_RELEASE_VERSION); + logger.info("{} - Version {}", ProtocolStatus::SERVER_NAME, SERVER_RELEASE_VERSION); #endif logger.debug("Compiled with {}, on {} {}, for platform {}\n", getCompiler(), __DATE__, __TIME__, getPlatform()); @@ -195,7 +196,7 @@ void CanaryServer::logInfos() { logger.debug("Linked with {} for Lua support", LUAJIT_VERSION); #endif - logger.info("A server developed by: {}", STATUS_SERVER_DEVELOPERS); + logger.info("A server developed by: {}", ProtocolStatus::SERVER_DEVELOPERS); logger.info("Visit our website for updates, support, and resources: " "https://docs.opentibiabr.com/"); } diff --git a/src/core.hpp b/src/core.hpp index 25f3f5cb1f5..f89e3adedfc 100644 --- a/src/core.hpp +++ b/src/core.hpp @@ -9,13 +9,6 @@ #pragma once -static constexpr auto STATUS_SERVER_NAME = "Canary"; -// STATUS_SERVER_VERSION is used for external display purposes, such as listings on otlist. -// This version should generally only show the major version to avoid frequent changes in otlist categories. -static constexpr auto STATUS_SERVER_VERSION = "3.0"; - -static constexpr auto STATUS_SERVER_DEVELOPERS = "OpenTibiaBR Organization"; - static constexpr auto AUTHENTICATOR_DIGITS = 6U; static constexpr auto AUTHENTICATOR_PERIOD = 30U; diff --git a/src/lib/logging/log_with_spd_log.cpp b/src/lib/logging/log_with_spd_log.cpp index d06e5e195dd..9b58317b819 100644 --- a/src/lib/logging/log_with_spd_log.cpp +++ b/src/lib/logging/log_with_spd_log.cpp @@ -12,7 +12,7 @@ #include "lib/di/container.hpp" LogWithSpdLog::LogWithSpdLog() { - setLevel("debug"); + setLevel("info"); spdlog::set_pattern("[%Y-%d-%m %H:%M:%S.%e] [%^%l%$] %v "); #ifdef DEBUG_LOG @@ -25,7 +25,7 @@ Logger &LogWithSpdLog::getInstance() { } void LogWithSpdLog::setLevel(const std::string &name) { - info("Setting log level to {}.", name); + debug("Setting log level to: {}.", name); auto level = spdlog::level::from_str(name); spdlog::set_level(level); } diff --git a/src/server/network/protocol/protocolstatus.cpp b/src/server/network/protocol/protocolstatus.cpp index 7a2a4d5bf1a..f07e5e85d18 100644 --- a/src/server/network/protocol/protocolstatus.cpp +++ b/src/server/network/protocol/protocolstatus.cpp @@ -16,6 +16,10 @@ #include "game/scheduling/dispatcher.hpp" #include "server/network/message/outputmessage.hpp" +std::string ProtocolStatus::SERVER_NAME = "Canary"; +std::string ProtocolStatus::SERVER_VERSION = "3.0"; +std::string ProtocolStatus::SERVER_DEVELOPERS = "OpenTibiaBR Organization"; + std::map ProtocolStatus::ipConnectMap; const uint64_t ProtocolStatus::start = OTSYS_TIME(); @@ -78,12 +82,12 @@ void ProtocolStatus::sendStatusString() { uint64_t uptime = (OTSYS_TIME() - ProtocolStatus::start) / 1000; serverinfo.append_attribute("uptime") = std::to_string(uptime).c_str(); serverinfo.append_attribute("ip") = g_configManager().getString(IP).c_str(); - serverinfo.append_attribute("servername") = g_configManager().getString(SERVER_NAME).c_str(); + serverinfo.append_attribute("servername") = g_configManager().getString(stringConfig_t::SERVER_NAME).c_str(); serverinfo.append_attribute("port") = std::to_string(g_configManager().getNumber(LOGIN_PORT)).c_str(); serverinfo.append_attribute("location") = g_configManager().getString(LOCATION).c_str(); serverinfo.append_attribute("url") = g_configManager().getString(URL).c_str(); - serverinfo.append_attribute("server") = STATUS_SERVER_NAME; - serverinfo.append_attribute("version") = STATUS_SERVER_VERSION; + serverinfo.append_attribute("server") = ProtocolStatus::SERVER_NAME.c_str(); + serverinfo.append_attribute("version") = ProtocolStatus::SERVER_VERSION.c_str(); serverinfo.append_attribute("client") = fmt::format("{}.{}", CLIENT_VERSION_UPPER, CLIENT_VERSION_LOWER).c_str(); pugi::xml_node owner = tsqp.append_child("owner"); @@ -150,7 +154,7 @@ void ProtocolStatus::sendInfo(uint16_t requestedInfo, const std::string &charact if (requestedInfo & REQUEST_BASIC_SERVER_INFO) { output->addByte(0x10); - output->addString(g_configManager().getString(SERVER_NAME)); + output->addString(g_configManager().getString(stringConfig_t::SERVER_NAME)); output->addString(g_configManager().getString(IP)); output->addString(std::to_string(g_configManager().getNumber(LOGIN_PORT))); } @@ -208,8 +212,8 @@ void ProtocolStatus::sendInfo(uint16_t requestedInfo, const std::string &charact if (requestedInfo & REQUEST_SERVER_SOFTWARE_INFO) { output->addByte(0x23); // server software info - output->addString(STATUS_SERVER_NAME); - output->addString(STATUS_SERVER_VERSION); + output->addString(ProtocolStatus::SERVER_NAME); + output->addString(ProtocolStatus::SERVER_VERSION); output->addString(fmt::format("{}.{}", CLIENT_VERSION_UPPER, CLIENT_VERSION_LOWER)); } send(output); diff --git a/src/server/network/protocol/protocolstatus.hpp b/src/server/network/protocol/protocolstatus.hpp index be8b35462c3..36d83f77d65 100644 --- a/src/server/network/protocol/protocolstatus.hpp +++ b/src/server/network/protocol/protocolstatus.hpp @@ -32,6 +32,10 @@ class ProtocolStatus final : public Protocol { static const uint64_t start; + static std::string SERVER_NAME; + static std::string SERVER_VERSION; + static std::string SERVER_DEVELOPERS; + private: static std::map ipConnectMap; }; diff --git a/tests/fixture/account/in_memory_account_repository.hpp b/tests/fixture/account/in_memory_account_repository.hpp index dd4e77881b1..3996b7d11a2 100644 --- a/tests/fixture/account/in_memory_account_repository.hpp +++ b/tests/fixture/account/in_memory_account_repository.hpp @@ -41,7 +41,7 @@ namespace account::tests { return false; } - bool loadByEmail(const std::string &email, AccountInfo &acc) final { + bool loadByEmailOrName(bool oldProtocol, const std::string &email, AccountInfo &acc) final { auto account = accounts.find(email); if (account == accounts.end()) { diff --git a/tests/integration/main.cpp b/tests/integration/main.cpp index 91fd28a30cd..5b4055af7b3 100644 --- a/tests/integration/main.cpp +++ b/tests/integration/main.cpp @@ -78,13 +78,13 @@ int main() { expect(eq(acc.sessionExpires, 0)); }); - test("AccountRepositoryDB::loadByEmail") = databaseTest(db, [&db] { + test("AccountRepositoryDB::loadByEmailOrName") = databaseTest(db, [&db] { InMemoryLogger logger {}; AccountRepositoryDB accRepo { db, logger }; createAccount(db); AccountInfo acc {}; - accRepo.loadByEmail("@test", acc); + accRepo.loadByEmailOrName(false, "@test", acc); assertAccountLoad(acc); expect(eq(acc.sessionExpires, 0)); }); From e54b9c7ef75ba7bcf982a1227684a8e20b2db567 Mon Sep 17 00:00:00 2001 From: Luan Colombo <94877887+luancolombo@users.noreply.github.com> Date: Mon, 30 Oct 2023 20:12:41 +0000 Subject: [PATCH 02/10] feat: The Paleworm loot and mount (#1758) Fix paleworm loot items, and add the haze mount script. --- .../quests/feaster_of_souls/the_pale_worm.lua | 2 ++ .../scripts/actions/mounts/haze_mount.lua | 25 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 data-otservbr-global/scripts/actions/mounts/haze_mount.lua diff --git a/data-otservbr-global/monster/quests/feaster_of_souls/the_pale_worm.lua b/data-otservbr-global/monster/quests/feaster_of_souls/the_pale_worm.lua index 8f1258b6e70..41bf63ad767 100644 --- a/data-otservbr-global/monster/quests/feaster_of_souls/the_pale_worm.lua +++ b/data-otservbr-global/monster/quests/feaster_of_souls/the_pale_worm.lua @@ -95,6 +95,8 @@ monster.loot = { { name = "bloody tears", chance = 1500 }, { name = "ghost chestplate", chance = 150 }, { name = "spooky hood", chance = 150 }, + { name = "pale worm's scalp", chance = 1200 }, + { name = "spectral scrap of cloth", chance = 250 }, { name = "fabulous legs", chance = 150 }, { name = "phantasmal axe", chance = 150 }, { name = "ghost backpack", chance = 150 }, diff --git a/data-otservbr-global/scripts/actions/mounts/haze_mount.lua b/data-otservbr-global/scripts/actions/mounts/haze_mount.lua new file mode 100644 index 00000000000..bd289b57df9 --- /dev/null +++ b/data-otservbr-global/scripts/actions/mounts/haze_mount.lua @@ -0,0 +1,25 @@ +local config = { + [32629] = { mountId = 162, message = "You are now versed to ride the haze!" }, +} + +local hazemount = Action() + +function hazemount.onUse(player, item, fromPosition, target, toPosition, isHotkey) + local mount = config[item.itemid] + + if not mount then + return true + end + + if not player:hasMount(mount.mountId) then + player:addMount(mount.mountId) + player:say(mount.message, TALKTYPE_MONSTER_SAY) + item:remove(1) + else + player:sendTextMessage(19, "You already have this mount") + end + return true +end + +hazemount:id(32629) +hazemount:register() From 2a3a028da7f94200353e6022dbb3184ea024ee20 Mon Sep 17 00:00:00 2001 From: Luan Santos Date: Tue, 31 Oct 2023 21:20:01 -0700 Subject: [PATCH 03/10] fix: stamina boost overflow (#1763) This is a big one, players would stop saving correctly after getting exp boosts from daily rewards totally more than max tiny int. Fixes: - Change DB column to uint16 (same as the c++ variable type) - Programatically set the max value to 12 hours (or 43,200 seconds) --- data-otservbr-global/migrations/41.lua | 10 +++++++++- data-otservbr-global/migrations/42.lua | 3 +++ schema.sql | 4 ++-- src/creatures/players/player.hpp | 5 +++++ 4 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 data-otservbr-global/migrations/42.lua diff --git a/data-otservbr-global/migrations/41.lua b/data-otservbr-global/migrations/41.lua index 86a6d8ffec1..179ac18b574 100644 --- a/data-otservbr-global/migrations/41.lua +++ b/data-otservbr-global/migrations/41.lua @@ -1,3 +1,11 @@ function onUpdateDatabase() - return false -- true = There are others migrations file | false = this is the last migration file + logger.info("Updating database to version 42 (fix xpboost types)") + + db.query([[ + ALTER TABLE `players` + MODIFY `xpboost_stamina` smallint(5) UNSIGNED DEFAULT NULL, + MODIFY `xpboost_value` tinyint(4) UNSIGNED DEFAULT NULL + ]]) + + return true end diff --git a/data-otservbr-global/migrations/42.lua b/data-otservbr-global/migrations/42.lua new file mode 100644 index 00000000000..86a6d8ffec1 --- /dev/null +++ b/data-otservbr-global/migrations/42.lua @@ -0,0 +1,3 @@ +function onUpdateDatabase() + return false -- true = There are others migrations file | false = this is the last migration file +end diff --git a/schema.sql b/schema.sql index dc58d3a71ac..3ba4e35effc 100644 --- a/schema.sql +++ b/schema.sql @@ -129,8 +129,8 @@ CREATE TABLE IF NOT EXISTS `players` ( `skill_manaleech_amount` bigint(20) UNSIGNED NOT NULL DEFAULT '0', `manashield` SMALLINT UNSIGNED NOT NULL DEFAULT '0', `max_manashield` SMALLINT UNSIGNED NOT NULL DEFAULT '0', - `xpboost_stamina` smallint(5) DEFAULT NULL, - `xpboost_value` tinyint(4) DEFAULT NULL, + `xpboost_stamina` smallint(5) UNSIGNED DEFAULT NULL, + `xpboost_value` tinyint(4) UNSIGNED DEFAULT NULL, `marriage_status` bigint(20) UNSIGNED NOT NULL DEFAULT '0', `marriage_spouse` int(11) NOT NULL DEFAULT '-1', `bonus_rerolls` bigint(21) NOT NULL DEFAULT '0', diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 791f696148c..840c257b4c1 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -1760,6 +1760,11 @@ class Player final : public Creature, public Cylinder, public Bankable { } void setExpBoostStamina(uint16_t stamina) { + // only allow stamina boosts of 12 hours or less + if (stamina > 12 * 3600) { + expBoostStamina = 12 * 3600; + return; + } expBoostStamina = stamina; } From 77d9c775c17b55613abaf22204fd0a8ac8a5cc9f Mon Sep 17 00:00:00 2001 From: Luan Santos Date: Wed, 1 Nov 2023 06:01:47 -0700 Subject: [PATCH 04/10] fix: save offline counterparty on market offer acceptance (#1764) Players were getting loaded with online = true which made it so we tried to save players asynchronously even when they were offline, causing market transactions to not always save correctly. --- src/game/game.cpp | 21 +++++++------------ .../functions/core/game/game_functions.cpp | 2 -- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/game/game.cpp b/src/game/game.cpp index b3706b7bf38..76c83737f60 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -704,6 +704,7 @@ std::shared_ptr Game::getPlayerByID(uint32_t id, bool loadTmp /* = false if (!IOLoginData::loadPlayerById(tmpPlayer, id)) { return nullptr; } + tmpPlayer->setOnline(false); return tmpPlayer; } @@ -784,6 +785,7 @@ std::shared_ptr Game::getPlayerByGUID(const uint32_t &guid, bool loadTmp if (!IOLoginData::loadPlayerById(tmpPlayer, guid)) { return nullptr; } + tmpPlayer->setOnline(false); return tmpPlayer; } @@ -8593,13 +8595,10 @@ void Game::playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16 return; } - std::shared_ptr buyerPlayer = getPlayerByGUID(offer.playerId); + std::shared_ptr buyerPlayer = getPlayerByGUID(offer.playerId, true); if (!buyerPlayer) { - buyerPlayer = std::make_shared(nullptr); - if (!IOLoginData::loadPlayerById(buyerPlayer, offer.playerId)) { - offerStatus << "Failed to load buyer player " << player->getName(); - return; - } + offerStatus << "Failed to load buyer player " << player->getName(); + return; } if (!buyerPlayer->getAccount()) { @@ -8697,14 +8696,10 @@ void Game::playerAcceptMarketOffer(uint32_t playerId, uint32_t timestamp, uint16 g_saveManager().savePlayer(buyerPlayer); } } else if (offer.type == MARKETACTION_SELL) { - std::shared_ptr sellerPlayer = getPlayerByGUID(offer.playerId); + std::shared_ptr sellerPlayer = getPlayerByGUID(offer.playerId, true); if (!sellerPlayer) { - sellerPlayer = std::make_shared(nullptr); - if (!IOLoginData::loadPlayerById(sellerPlayer, offer.playerId)) { - offerStatus << "Failed to load seller player"; - - return; - } + offerStatus << "Failed to load seller player"; + return; } if (player == sellerPlayer || player->getAccount() == sellerPlayer->getAccount()) { diff --git a/src/lua/functions/core/game/game_functions.cpp b/src/lua/functions/core/game/game_functions.cpp index 99a277490ab..cab8c599a21 100644 --- a/src/lua/functions/core/game/game_functions.cpp +++ b/src/lua/functions/core/game/game_functions.cpp @@ -630,8 +630,6 @@ int GameFunctions::luaGameGetNormalizedPlayerName(lua_State* L) { std::shared_ptr player = g_game().getPlayerByName(name, true); if (player) { pushString(L, player->getName()); - if (!player->isOnline()) { - } } else { lua_pushnil(L); } From 5b26dad8f3835d040869012fb9022068ae9ea8a1 Mon Sep 17 00:00:00 2001 From: sebbesiren <35768829+sebbesiren@users.noreply.github.com> Date: Wed, 1 Nov 2023 14:59:10 +0100 Subject: [PATCH 05/10] feat: raid addBroadcast now also announces to webhook (#1760) Added a stage to encounter to broadcast to the entire server instead of only to online players. --- data/libs/raids_lib.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/data/libs/raids_lib.lua b/data/libs/raids_lib.lua index 4f1ea9b8cdf..9b0b9d105a7 100644 --- a/data/libs/raids_lib.lua +++ b/data/libs/raids_lib.lua @@ -143,3 +143,17 @@ function Raid:getActivePlayerCount() end return count end + +--Overrides Encounter:addBroadcast +--Adds a stage that broadcasts raid information globally +--@param message string The message to send +--@return boolean True if the message stage is added successfully, false otherwise +function Raid:addBroadcast(message, type) + type = type or MESSAGE_EVENT_ADVANCE + return self:addStage({ + start = function() + self:broadcast(type, message) + Webhook.sendMessage("Incoming raid", message, WEBHOOK_COLOR_RAID) + end, + }) +end From 74ea157bd08aae53fc4bccdd298d72196210f277 Mon Sep 17 00:00:00 2001 From: Luan Santos Date: Wed, 1 Nov 2023 07:08:08 -0700 Subject: [PATCH 06/10] fix: bestiary double counting in party (#1757) This addresses two issues: - Bestiary janky implementation in Lua which causes performance issues due to its usage of onKill - Bestiary/bosstiary double counting kills when in a party and the lasthit/most damage players aren't the same Also moved concoction IDs to C++ so it can be easily used in C++ systems (such as Bestiary) --- data/libs/concoctions_lib.lua | 40 ++--- data/scripts/creatureevents/bestiary_kill.lua | 35 ----- .../scripts/creatureevents/bosstiary_kill.lua | 33 ---- src/creatures/creature.cpp | 22 +-- src/creatures/monsters/monsters.hpp | 10 +- src/creatures/players/grouping/party.hpp | 8 + src/creatures/players/player.cpp | 143 +++++++++++------- src/creatures/players/player.hpp | 14 ++ src/lua/functions/core/game/lua_enums.cpp | 25 +++ src/lua/functions/core/game/lua_enums.hpp | 1 + src/utils/utils_definitions.hpp | 23 +++ 11 files changed, 192 insertions(+), 162 deletions(-) delete mode 100644 data/scripts/creatureevents/bestiary_kill.lua delete mode 100644 data/scripts/creatureevents/bosstiary_kill.lua diff --git a/data/libs/concoctions_lib.lua b/data/libs/concoctions_lib.lua index 0d8a6e6574a..72547a8a1ab 100644 --- a/data/libs/concoctions_lib.lua +++ b/data/libs/concoctions_lib.lua @@ -12,26 +12,26 @@ ConcoctionTickType = { Concoction = {} Concoction.__index = Concoction Concoction.Ids = { - KooldownAid = 36723, - StaminaExtension = 36725, - StrikeEnhancement = 36724, - CharmUpgrade = 36726, - WealthDuplex = 36727, - BestiaryBetterment = 36728, - FireResilience = 36729, - IceResilience = 36730, - EarthResilience = 36731, - EnergyResilience = 36732, - HolyResilience = 36733, - DeathResilience = 36734, - PhysicalResilience = 36735, - FireAmplification = 36736, - IceAmplification = 36737, - EarthAmplification = 36738, - EnergyAmplification = 36739, - HolyAmplification = 36740, - DeathAmplification = 36741, - PhysicalAmplification = 36742, + KooldownAid = Concoction_KooldownAid, + StaminaExtension = Concoction_StaminaExtension, + StrikeEnhancement = Concoction_StrikeEnhancement, + CharmUpgrade = Concoction_CharmUpgrade, + WealthDuplex = Concoction_WealthDuplex, + BestiaryBetterment = Concoction_BestiaryBetterment, + FireResilience = Concoction_FireResilience, + IceResilience = Concoction_IceResilience, + EarthResilience = Concoction_EarthResilience, + EnergyResilience = Concoction_EnergyResilience, + HolyResilience = Concoction_HolyResilience, + DeathResilience = Concoction_DeathResilience, + PhysicalResilience = Concoction_PhysicalResilience, + FireAmplification = Concoction_FireAmplification, + IceAmplification = Concoction_IceAmplification, + EarthAmplification = Concoction_EarthAmplification, + EnergyAmplification = Concoction_EnergyAmplification, + HolyAmplification = Concoction_HolyAmplification, + DeathAmplification = Concoction_DeathAmplification, + PhysicalAmplification = Concoction_PhysicalAmplification, } function Concoction.find(identifier) diff --git a/data/scripts/creatureevents/bestiary_kill.lua b/data/scripts/creatureevents/bestiary_kill.lua deleted file mode 100644 index a238124eacf..00000000000 --- a/data/scripts/creatureevents/bestiary_kill.lua +++ /dev/null @@ -1,35 +0,0 @@ -local bestiaryOnKill = CreatureEvent("BestiaryOnKill") -function bestiaryOnKill.onKill(player, creature, lastHit) - if not player:isPlayer() or not creature:isMonster() or creature:hasBeenSummoned() or creature:isPlayer() then - return true - end - - local mType = MonsterType(creature:getName()) - if not mType then - logger.error("[bestiaryOnKill.onKill] monster with name {} have wrong MonsterType", creature:getName()) - return true - end - - if mType:Bestiaryrace() == 0 then - return true - end - - local bestiaryBetterment = Concoction.find(Concoction.Ids.BestiaryBetterment) - if not bestiaryBetterment then - logger.warn("[BestiaryOnKill] - Could not find BestiaryBetterment concoction.") - end - for cid, damage in pairs(creature:getDamageMap()) do - local participant = Player(cid) - if participant and participant:isPlayer() then - local bestiaryMultiplier = (configManager.getNumber(configKeys.BESTIARY_KILL_MULTIPLIER) or 1) - if bestiaryBetterment and bestiaryBetterment:active(participant) then - bestiaryMultiplier = bestiaryMultiplier * bestiaryBetterment.config.multiplier - end - participant:addBestiaryKill(creature:getName(), bestiaryMultiplier) - end - end - - return true -end - -bestiaryOnKill:register() diff --git a/data/scripts/creatureevents/bosstiary_kill.lua b/data/scripts/creatureevents/bosstiary_kill.lua deleted file mode 100644 index 2a1139cd339..00000000000 --- a/data/scripts/creatureevents/bosstiary_kill.lua +++ /dev/null @@ -1,33 +0,0 @@ -local bosstiaryOnKill = CreatureEvent("BosstiaryOnKill") -function bosstiaryOnKill.onKill(player, creature, lastHit) - if not player:isPlayer() or not creature:isMonster() or creature:hasBeenSummoned() or creature:isPlayer() then - return true - end - - local mType = MonsterType(creature:getName()) - if not mType then - logger.error("[bosstiaryOnKill.onKill] monster with name {} have wrong MonsterType", creature:getName()) - return true - end - - if mType:bossRace() == nil or mType:bossRace() == "" then - return true - end - - local bosstiaryMultiplier = (configManager.getNumber(configKeys.BOSSTIARY_KILL_MULTIPLIER) or 1) - local killBonus = (configManager.getNumber(configKeys.BOOSTED_BOSS_KILL_BONUS) or 3) - for cid, damage in pairs(creature:getDamageMap()) do - local participant = Player(cid) - if participant and participant:isPlayer() then - if creature:getName():lower() == (Game.getBoostedBoss()):lower() then - participant:addBosstiaryKill(creature:getName(), bosstiaryMultiplier * killBonus) - else - participant:addBosstiaryKill(creature:getName(), bosstiaryMultiplier) - end - end - end - - return true -end - -bosstiaryOnKill:register() diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp index 2f855c6ac15..980bab34155 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -625,14 +625,6 @@ void Creature::onCreatureMove(std::shared_ptr creature, std::shared_pt void Creature::onDeath() { bool lastHitUnjustified = false; bool mostDamageUnjustified = false; - std::shared_ptr lastHitCreature = g_game().getCreatureByID(lastHitCreatureId); - std::shared_ptr lastHitCreatureMaster; - if (lastHitCreature) { - lastHitUnjustified = lastHitCreature->onKilledCreature(static_self_cast(), true); - lastHitCreatureMaster = lastHitCreature->getMaster(); - } else { - lastHitCreatureMaster = nullptr; - } std::shared_ptr mostDamageCreature = nullptr; @@ -674,13 +666,15 @@ void Creature::onDeath() { it.first->onGainExperience(it.second, getCreature()); } + std::shared_ptr mostDamageCreatureMaster = nullptr; if (mostDamageCreature) { - if (mostDamageCreature != lastHitCreature && mostDamageCreature != lastHitCreatureMaster) { - auto mostDamageCreatureMaster = mostDamageCreature->getMaster(); - if (lastHitCreature != mostDamageCreatureMaster && (lastHitCreatureMaster == nullptr || mostDamageCreatureMaster != lastHitCreatureMaster)) { - mostDamageUnjustified = mostDamageCreature->onKilledCreature(static_self_cast(), false); - } - } + mostDamageCreatureMaster = mostDamageCreature->getMaster(); + mostDamageUnjustified = mostDamageCreature->onKilledCreature(getCreature(), false); + } + + std::shared_ptr lastHitCreature = g_game().getCreatureByID(lastHitCreatureId); + if (lastHitCreature && lastHitCreature != mostDamageCreature && lastHitCreature != mostDamageCreatureMaster) { + lastHitUnjustified = lastHitCreature->onKilledCreature(getCreature(), true); } bool droppedCorpse = dropCorpse(lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified); diff --git a/src/creatures/monsters/monsters.hpp b/src/creatures/monsters/monsters.hpp index fd911c661f9..e0cc79b88e9 100644 --- a/src/creatures/monsters/monsters.hpp +++ b/src/creatures/monsters/monsters.hpp @@ -185,15 +185,19 @@ class MonsterType { } float getHealthMultiplier() const { - return info.bosstiaryClass.empty() ? g_configManager().getFloat(RATE_MONSTER_HEALTH) : g_configManager().getFloat(RATE_BOSS_HEALTH); + return isBoss() ? g_configManager().getFloat(RATE_BOSS_HEALTH) : g_configManager().getFloat(RATE_MONSTER_HEALTH); } float getAttackMultiplier() const { - return info.bosstiaryClass.empty() ? g_configManager().getFloat(RATE_MONSTER_ATTACK) : g_configManager().getFloat(RATE_BOSS_ATTACK); + return isBoss() ? g_configManager().getFloat(RATE_BOSS_ATTACK) : g_configManager().getFloat(RATE_MONSTER_ATTACK); } float getDefenseMultiplier() const { - return info.bosstiaryClass.empty() ? g_configManager().getFloat(RATE_MONSTER_DEFENSE) : g_configManager().getFloat(RATE_BOSS_DEFENSE); + return isBoss() ? g_configManager().getFloat(RATE_BOSS_DEFENSE) : g_configManager().getFloat(RATE_MONSTER_DEFENSE); + } + + bool isBoss() const { + return !info.bosstiaryClass.empty(); } void loadLoot(const std::shared_ptr monsterType, LootBlock lootblock); diff --git a/src/creatures/players/grouping/party.hpp b/src/creatures/players/grouping/party.hpp index e7bc2c2fc55..d4c0cea0b35 100644 --- a/src/creatures/players/grouping/party.hpp +++ b/src/creatures/players/grouping/party.hpp @@ -35,6 +35,14 @@ class Party : public SharedObject { std::shared_ptr getLeader() const { return m_leader.lock(); } + std::vector> getPlayers() const { + std::vector> players; + for (auto &member : memberList) { + players.push_back(member); + } + players.push_back(getLeader()); + return players; + } std::vector> getMembers() { return memberList; } diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index 1f7f9f088b0..aba77e44c60 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -4583,75 +4583,104 @@ void Player::onTargetCreatureGainHealth(std::shared_ptr target, int32_ } } -bool Player::onKilledCreature(std::shared_ptr target, bool lastHit /* = true*/) { +bool Player::onKilledPlayer(const std::shared_ptr &target, bool lastHit) { bool unjustified = false; - - if (hasFlag(PlayerFlags_t::NotGenerateLoot)) { + if (target->getZoneType() == ZONE_PVP) { target->setDropLoot(false); - } - - Creature::onKilledCreature(target, lastHit); - - if (auto targetPlayer = target->getPlayer()) { - if (targetPlayer && targetPlayer->getZoneType() == ZONE_PVP) { - targetPlayer->setDropLoot(false); - targetPlayer->setSkillLoss(false); - } else if (!hasFlag(PlayerFlags_t::NotGainInFight) && !isPartner(targetPlayer)) { - if (!Combat::isInPvpZone(getPlayer(), targetPlayer) && hasAttacked(targetPlayer) && !targetPlayer->hasAttacked(getPlayer()) && !isGuildMate(targetPlayer) && targetPlayer != getPlayer()) { - if (targetPlayer->hasKilled(getPlayer())) { - for (auto &kill : targetPlayer->unjustifiedKills) { - if (kill.target == getGUID() && kill.unavenged) { - kill.unavenged = false; - auto it = attackedSet.find(targetPlayer->guid); - attackedSet.erase(it); - break; - } + target->setSkillLoss(false); + } else if (!hasFlag(PlayerFlags_t::NotGainInFight) && !isPartner(target)) { + if (!Combat::isInPvpZone(getPlayer(), target) && hasAttacked(target) && !target->hasAttacked(getPlayer()) && !isGuildMate(target) && target != getPlayer()) { + if (target->hasKilled(getPlayer())) { + for (auto &kill : target->unjustifiedKills) { + if (kill.target == getGUID() && kill.unavenged) { + kill.unavenged = false; + auto it = attackedSet.find(target->guid); + attackedSet.erase(it); + break; } - } else if (targetPlayer->getSkull() == SKULL_NONE && !isInWar(targetPlayer)) { - unjustified = true; - addUnjustifiedDead(targetPlayer); } - - if (lastHit && hasCondition(CONDITION_INFIGHT)) { - pzLocked = true; - std::shared_ptr condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_INFIGHT, g_configManager().getNumber(WHITE_SKULL_TIME), 0); - addCondition(condition); - } - } - } - } else if (std::shared_ptr monster = target->getMonster()) { - // Access to the monster's map damage to check if the player attacked it - for (auto [playerId, damage] : monster->getDamageMap()) { - auto damagePlayer = g_game().getPlayerByID(playerId); - if (!damagePlayer) { - continue; + } else if (target->getSkull() == SKULL_NONE && !isInWar(target)) { + unjustified = true; + addUnjustifiedDead(target); } - // If the player is not in a party and sharing exp active and enabled - // And it's not the player killing the creature, then we ignore everything else - auto damageParty = damagePlayer->getParty(); - if (static_self_cast()->getID() != damagePlayer->getID() && (!damageParty || !damageParty->isSharedExperienceActive() || !damageParty->isSharedExperienceEnabled())) { - continue; + if (lastHit && hasCondition(CONDITION_INFIGHT)) { + pzLocked = true; + std::shared_ptr condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_INFIGHT, g_configManager().getNumber(WHITE_SKULL_TIME), 0); + addCondition(condition); } + } + } + return unjustified; +} - const auto &taskSlot = damagePlayer->getTaskHuntingWithCreature(monster->getRaceId()); - if (!taskSlot || monster->isSummon()) { - continue; - } +void Player::addHuntingTaskKill(const std::shared_ptr &mType) { + const auto &taskSlot = getTaskHuntingWithCreature(mType->info.raceid); + if (!taskSlot) { + return; + } - if (const auto &option = g_ioprey().getTaskRewardOption(taskSlot)) { - taskSlot->currentKills += 1; - if ((taskSlot->upgrade && taskSlot->currentKills >= option->secondKills) || (!taskSlot->upgrade && taskSlot->currentKills >= option->firstKills)) { - taskSlot->state = PreyTaskDataState_Completed; - std::string message = "You succesfully finished your hunting task. Your reward is ready to be claimed!"; - damagePlayer->sendTextMessage(MESSAGE_STATUS, message); - } - damagePlayer->reloadTaskSlot(taskSlot->id); - } + if (const auto &option = g_ioprey().getTaskRewardOption(taskSlot)) { + taskSlot->currentKills += 1; + if ((taskSlot->upgrade && taskSlot->currentKills >= option->secondKills) || (!taskSlot->upgrade && taskSlot->currentKills >= option->firstKills)) { + taskSlot->state = PreyTaskDataState_Completed; + std::string message = "You succesfully finished your hunting task. Your reward is ready to be claimed!"; + sendTextMessage(MESSAGE_STATUS, message); } + reloadTaskSlot(taskSlot->id); } +} - return unjustified; +void Player::addBestiaryKill(const std::shared_ptr &mType) { + if (mType->isBoss()) { + return; + } + uint32_t kills = g_configManager().getNumber(BESTIARY_KILL_MULTIPLIER); + if (isConcoctionActive(Concoction_t::BestiaryBetterment)) { + kills *= 2; + } + g_iobestiary().addBestiaryKill(getPlayer(), mType, kills); +} + +void Player::addBosstiaryKill(const std::shared_ptr &mType) { + if (!mType->isBoss()) { + return; + } + uint32_t kills = g_configManager().getNumber(BOSSTIARY_KILL_MULTIPLIER); + + g_ioBosstiary().addBosstiaryKill(getPlayer(), mType, kills); +} + +bool Player::onKilledMonster(const std::shared_ptr &monster, bool lastHit) { + if (lastHit || monster->isSummon()) { + return false; + } + auto party = getParty(); + auto participants = party && party->isSharedExperienceEnabled() && party->isSharedExperienceActive() ? party->getPlayers() : std::vector> { getPlayer() }; + auto mType = monster->getMonsterType(); + for (const auto &player : participants) { + player->addHuntingTaskKill(mType); + player->addBestiaryKill(mType); + player->addBosstiaryKill(mType); + } + + return false; +} + +bool Player::onKilledCreature(std::shared_ptr target, bool lastHit /* = true*/) { + if (hasFlag(PlayerFlags_t::NotGenerateLoot)) { + target->setDropLoot(false); + } + + Creature::onKilledCreature(target, lastHit); + + if (auto targetPlayer = target->getPlayer()) { + return onKilledPlayer(targetPlayer, lastHit); + } else if (auto targetMonster = target->getMonster()) { + return onKilledMonster(targetMonster, lastHit); + } + + return false; } void Player::gainExperience(uint64_t gainExp, std::shared_ptr target) { diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 840c257b4c1..83b28e88364 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -2492,6 +2492,14 @@ class Player final : public Creature, public Cylinder, public Bankable { std::map getActiveConcoctions() const { return activeConcoctions; } + bool isConcoctionActive(Concoction_t concotion) const { + uint16_t itemId = static_cast(concotion); + if (!activeConcoctions.contains(itemId)) { + return false; + } + auto timeLeft = activeConcoctions.at(itemId); + return timeLeft > 0; + } bool checkAutoLoot() const { const bool autoLoot = g_configManager().getBoolean(AUTOLOOT) && getStorageValue(STORAGEVALUE_AUTO_LOOT) != 0; @@ -2594,6 +2602,12 @@ class Player final : public Creature, public Cylinder, public Bankable { void internalAddThing(std::shared_ptr thing) override; void internalAddThing(uint32_t index, std::shared_ptr thing) override; + void addHuntingTaskKill(const std::shared_ptr &mType); + void addBestiaryKill(const std::shared_ptr &mType); + void addBosstiaryKill(const std::shared_ptr &mType); + bool onKilledPlayer(const std::shared_ptr &target, bool lastHit); + bool onKilledMonster(const std::shared_ptr &target, bool lastHit); + phmap::flat_hash_set attackedSet; phmap::flat_hash_set VIPList; diff --git a/src/lua/functions/core/game/lua_enums.cpp b/src/lua/functions/core/game/lua_enums.cpp index fc1586f3363..f462aaae26a 100644 --- a/src/lua/functions/core/game/lua_enums.cpp +++ b/src/lua/functions/core/game/lua_enums.cpp @@ -108,6 +108,7 @@ void LuaEnums::init(lua_State* L) { initSoundEnums(L); initWheelEnums(L); initAttributeConditionSubIdEnums(L); + initConcoctionsEnum(L); } void LuaEnums::initOthersEnums(lua_State* L) { @@ -446,6 +447,30 @@ void LuaEnums::initAttributeConditionSubIdEnums(lua_State* L) { } } +void LuaEnums::initConcoctionsEnum(lua_State* L) { + std::string luaNamespace = "Concoction_"; + registerEnumNamespace(L, luaNamespace, Concoction_t::KooldownAid); + registerEnumNamespace(L, luaNamespace, Concoction_t::StaminaExtension); + registerEnumNamespace(L, luaNamespace, Concoction_t::StrikeEnhancement); + registerEnumNamespace(L, luaNamespace, Concoction_t::CharmUpgrade); + registerEnumNamespace(L, luaNamespace, Concoction_t::WealthDuplex); + registerEnumNamespace(L, luaNamespace, Concoction_t::BestiaryBetterment); + registerEnumNamespace(L, luaNamespace, Concoction_t::FireResilience); + registerEnumNamespace(L, luaNamespace, Concoction_t::IceResilience); + registerEnumNamespace(L, luaNamespace, Concoction_t::EarthResilience); + registerEnumNamespace(L, luaNamespace, Concoction_t::EnergyResilience); + registerEnumNamespace(L, luaNamespace, Concoction_t::HolyResilience); + registerEnumNamespace(L, luaNamespace, Concoction_t::DeathResilience); + registerEnumNamespace(L, luaNamespace, Concoction_t::PhysicalResilience); + registerEnumNamespace(L, luaNamespace, Concoction_t::FireAmplification); + registerEnumNamespace(L, luaNamespace, Concoction_t::IceAmplification); + registerEnumNamespace(L, luaNamespace, Concoction_t::EarthAmplification); + registerEnumNamespace(L, luaNamespace, Concoction_t::EnergyAmplification); + registerEnumNamespace(L, luaNamespace, Concoction_t::HolyAmplification); + registerEnumNamespace(L, luaNamespace, Concoction_t::DeathAmplification); + registerEnumNamespace(L, luaNamespace, Concoction_t::PhysicalAmplification); +} + void LuaEnums::initConstMeEnums(lua_State* L) { registerEnum(L, CONST_ME_NONE); registerEnum(L, CONST_ME_DRAWBLOOD); diff --git a/src/lua/functions/core/game/lua_enums.hpp b/src/lua/functions/core/game/lua_enums.hpp index 055741b3f24..448e09fb647 100644 --- a/src/lua/functions/core/game/lua_enums.hpp +++ b/src/lua/functions/core/game/lua_enums.hpp @@ -35,6 +35,7 @@ class LuaEnums final : LuaScriptInterface { static void initConditionIdEnums(lua_State* L); static void initConditionParamEnums(lua_State* L); static void initAttributeConditionSubIdEnums(lua_State* L); + static void initConcoctionsEnum(lua_State* L); static void initConstMeEnums(lua_State* L); static void initConstAniEnums(lua_State* L); static void initConstPropEnums(lua_State* L); diff --git a/src/utils/utils_definitions.hpp b/src/utils/utils_definitions.hpp index e84dcf58a64..25fce70f47a 100644 --- a/src/utils/utils_definitions.hpp +++ b/src/utils/utils_definitions.hpp @@ -762,3 +762,26 @@ enum class AttrSubId_t { BloodRageProtector, Sharpshooter, }; + +enum Concoction_t : uint16_t { + KooldownAid = 36723, + StaminaExtension = 36725, + StrikeEnhancement = 36724, + CharmUpgrade = 36726, + WealthDuplex = 36727, + BestiaryBetterment = 36728, + FireResilience = 36729, + IceResilience = 36730, + EarthResilience = 36731, + EnergyResilience = 36732, + HolyResilience = 36733, + DeathResilience = 36734, + PhysicalResilience = 36735, + FireAmplification = 36736, + IceAmplification = 36737, + EarthAmplification = 36738, + EnergyAmplification = 36739, + HolyAmplification = 36740, + DeathAmplification = 36741, + PhysicalAmplification = 36742, +}; From fe07368729668312aa8968a1b78d252a617c27dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Lu=C3=ADs=20Lucarelo=20Lamonato?= Date: Wed, 1 Nov 2023 11:13:49 -0300 Subject: [PATCH 07/10] fix: npc lokur selling wagon tickets (#1762) Added the option to buy wagon tickets from NPC Lokur. Fixes #1755 --- data-otservbr-global/npc/lokur.lua | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/data-otservbr-global/npc/lokur.lua b/data-otservbr-global/npc/lokur.lua index 6b9bbc271e0..0da622e8ba8 100644 --- a/data-otservbr-global/npc/lokur.lua +++ b/data-otservbr-global/npc/lokur.lua @@ -63,6 +63,32 @@ local function creatureSayCallback(npc, creature, type, message) return false end + if MsgContains(message, "ticket") then + if Player(creature):getStorageValue(Storage.WagonTicket) >= os.time() then + npcHandler:say("Your weekly ticket is still valid. Would be a waste of money to purchase a second one", npc, creature) + return true + end + + npcHandler:say("Do you want to purchase a weekly ticket for the ore wagons? With it you can travel freely and swiftly through Kazordoon for one week. 250 gold only. Deal?", npc, creature) + npcHandler:setTopic(playerId, 9) + elseif MsgContains(message, "yes") and npcHandler:getTopic(playerId) > 0 then + local player = Player(creature) + if npcHandler:getTopic(playerId) == 9 then + if not player:removeMoneyBank(250) then + npcHandler:say("You don't have enough money.", npc, creature) + npcHandler:setTopic(playerId, 0) + return true + end + + player:setStorageValue(Storage.WagonTicket, os.time() + 7 * 24 * 60 * 60) + npcHandler:say("Here is your stamp. It can't be transferred to another person and will last one week from now. You'll get notified upon using an ore wagon when it isn't valid anymore.", npc, creature) + end + npcHandler:setTopic(playerId, 0) + elseif MsgContains(message, "no") and npcHandler:getTopic(playerId) > 0 then + npcHandler:say("No then.", npc, creature) + npcHandler:setTopic(playerId, 0) + end + -- Parse bank npc:parseBank(message, npc, creature, npcHandler) -- Parse guild bank From 06683a6f2e3285e68491c84feee450fc91e793f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Renato=20Foot=20Guimar=C3=A3es=20Costallat?= Date: Wed, 1 Nov 2023 11:21:16 -0300 Subject: [PATCH 08/10] ci/cl: clear GitHub actions cache on PR closure (#1751) Clean GHA cache related to the PR being closed. --- .github/workflows/clean-cache.yaml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/clean-cache.yaml diff --git a/.github/workflows/clean-cache.yaml b/.github/workflows/clean-cache.yaml new file mode 100644 index 00000000000..ed298937a51 --- /dev/null +++ b/.github/workflows/clean-cache.yaml @@ -0,0 +1,30 @@ +--- +name: Cleanup caches by a branch +on: + pull_request: + types: + - closed + +jobs: + cleanup: + runs-on: ubuntu-latest + steps: + - name: Cleanup + run: | + gh extension install actions/gh-actions-cache + + echo "Fetching list of cache key" + cacheKeysForPR=$(gh actions-cache list -R "$REPO" -B "$BRANCH" -L 100 | cut -f 1 ) + + ## Setting this to not fail the workflow while deleting cache keys. + set +e + echo "Deleting caches..." + for cacheKey in $cacheKeysForPR + do + gh actions-cache delete "$cacheKey" -R "$REPO" -B "$BRANCH" --confirm + done + echo "Done" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge From 87904e3527ca13065ebe1273273cb4ecfe0f578b Mon Sep 17 00:00:00 2001 From: Renato Machado Date: Thu, 2 Nov 2023 15:37:55 -0300 Subject: [PATCH 09/10] feat: pathfinder multithreading (#1646) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This introduces multithreading capabilities to the pathfinder system, significantly improving performance for pathfinding operations. By enabling concurrent processing, the pathfinder can now handle multiple path calculations simultaneously, reducing latency and increasing efficiency in environments with high pathfinding demands. Benefits: • Enhanced pathfinding performance with parallel computation. • Reduced response times for path calculations. • Scalability in handling numerous pathfinding requests concurrently. Impact: This update is expected to bolster the responsiveness of applications that rely heavily on pathfinding, particularly in real-time scenarios or large, complex maps. With multithreading, the system's capacity to compute paths is now more robust and better equipped to maintain performance under load. --- src/creatures/combat/combat.cpp | 2 +- src/creatures/combat/condition.cpp | 6 +- src/creatures/combat/condition.hpp | 2 +- src/creatures/creature.cpp | 173 ++++++++------ src/creatures/creature.hpp | 31 ++- src/creatures/monsters/monster.cpp | 19 +- src/creatures/monsters/monster.hpp | 8 +- src/creatures/npcs/npc.cpp | 4 +- src/creatures/npcs/npc.hpp | 2 +- src/creatures/players/player.cpp | 18 +- src/creatures/players/player.hpp | 6 +- src/game/game.cpp | 84 +++---- src/game/game.hpp | 8 +- src/game/scheduling/dispatcher.cpp | 72 ++++-- src/game/scheduling/dispatcher.hpp | 14 +- src/items/items_definitions.hpp | 5 + src/items/tile.cpp | 110 +++++++-- src/items/tile.hpp | 17 +- .../creatures/creature_functions.cpp | 2 +- src/lua/functions/map/position_functions.cpp | 2 +- src/map/map.cpp | 224 +++--------------- src/map/map.hpp | 8 +- src/map/utils/astarnodes.cpp | 15 +- src/map/utils/astarnodes.hpp | 2 +- src/server/network/protocol/protocolgame.cpp | 4 +- src/utils/arraylist.hpp | 21 +- 26 files changed, 436 insertions(+), 423 deletions(-) diff --git a/src/creatures/combat/combat.cpp b/src/creatures/combat/combat.cpp index c398f07a2b2..38f2c5de217 100644 --- a/src/creatures/combat/combat.cpp +++ b/src/creatures/combat/combat.cpp @@ -898,7 +898,7 @@ void Combat::addDistanceEffect(std::shared_ptr caster, const Position void Combat::doChainEffect(const Position &origin, const Position &dest, uint8_t effect) { if (effect > 0) { - std::forward_list dirList; + stdext::arraylist dirList(128); FindPathParams fpp; fpp.minTargetDist = 0; fpp.maxTargetDist = 1; diff --git a/src/creatures/combat/condition.cpp b/src/creatures/combat/condition.cpp index f69488175bd..4cf1834e1a4 100644 --- a/src/creatures/combat/condition.cpp +++ b/src/creatures/combat/condition.cpp @@ -1929,7 +1929,7 @@ bool ConditionFeared::getFleeDirection(std::shared_ptr creature) { return false; } -bool ConditionFeared::getFleePath(std::shared_ptr creature, const Position &pos, std::forward_list &dirList) { +bool ConditionFeared::getFleePath(std::shared_ptr creature, const Position &pos, stdext::arraylist &dirList) { const std::vector walkSize { 15, 9, 3, 1 }; bool found = false; std::ptrdiff_t found_size = 0; @@ -2030,7 +2030,7 @@ bool ConditionFeared::startCondition(std::shared_ptr creature) { bool ConditionFeared::executeCondition(std::shared_ptr creature, int32_t interval) { Position currentPos = creature->getPosition(); - std::forward_list listDir; + stdext::arraylist listDir(128); g_logger().debug("[ConditionFeared::executeCondition] Executing condition, current position is {}", currentPos.toString()); @@ -2040,7 +2040,7 @@ bool ConditionFeared::executeCondition(std::shared_ptr creature, int32 } if (getFleePath(creature, currentPos, listDir)) { - g_dispatcher().addEvent(std::bind(&Game::forcePlayerAutoWalk, &g_game(), creature->getID(), listDir), "ConditionFeared::executeCondition"); + g_dispatcher().addEvent(std::bind(&Game::forcePlayerAutoWalk, &g_game(), creature->getID(), listDir.data()), "ConditionFeared::executeCondition"); g_logger().debug("[ConditionFeared::executeCondition] Walking Scheduled"); } } diff --git a/src/creatures/combat/condition.hpp b/src/creatures/combat/condition.hpp index f8228e074ca..28d637b8b87 100644 --- a/src/creatures/combat/condition.hpp +++ b/src/creatures/combat/condition.hpp @@ -333,7 +333,7 @@ class ConditionFeared final : public Condition { private: bool canWalkTo(std::shared_ptr creature, Position pos, Direction moveDirection) const; bool getFleeDirection(std::shared_ptr creature); - bool getFleePath(std::shared_ptr creature, const Position &pos, std::forward_list &dirList); + bool getFleePath(std::shared_ptr creature, const Position &pos, stdext::arraylist &dirList); bool getRandomDirection(std::shared_ptr creature, Position pos); bool isStuck(std::shared_ptr creature, Position pos) const; diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp index 980bab34155..7058753acf1 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -133,16 +133,23 @@ void Creature::onThink(uint32_t interval) { } } + auto onThink = [self = getCreature(), interval] { + // scripting event - onThink + const auto &thinkEvents = self->getCreatureEvents(CREATURE_EVENT_THINK); + for (const auto creatureEventPtr : thinkEvents) { + creatureEventPtr->executeOnThink(self->static_self_cast(), interval); + } + }; + if (isUpdatingPath) { - isUpdatingPath = false; - goToFollowCreature(); + g_dispatcher().asyncEvent([self = getCreature(), onThink = std::move(onThink)] { + self->isUpdatingPath = false; + self->goToFollowCreature_async(onThink); + }); + return; } - // scripting event - onThink - const CreatureEventList &thinkEvents = getCreatureEvents(CREATURE_EVENT_THINK); - for (const auto creatureEventPtr : thinkEvents) { - creatureEventPtr->executeOnThink(static_self_cast(), interval); - } + onThink(); } void Creature::onAttacking(uint32_t interval) { @@ -224,18 +231,20 @@ bool Creature::getNextStep(Direction &dir, uint32_t &) { return true; } -void Creature::startAutoWalk(const std::forward_list &listDir, bool ignoreConditions /* = false*/) { +void Creature::startAutoWalk(const std::vector &listDir, bool ignoreConditions /* = false*/) { + listWalkDir.clear(); + if (!ignoreConditions && (hasCondition(CONDITION_ROOTED) || hasCondition(CONDITION_FEARED))) { return; } - listWalkDir = listDir; + listWalkDir = { listDir.begin(), listDir.end() }; - size_t size = 0; - for (auto it = listDir.begin(); it != listDir.end() && size <= 1; ++it) { - size++; + if (listWalkDir.empty()) { + return; } - addEventWalk(size == 1); + + addEventWalk(listWalkDir.size() == 1); } void Creature::addEventWalk(bool firstStep) { @@ -249,20 +258,22 @@ void Creature::addEventWalk(bool firstStep) { return; } - int64_t ticks = getEventStepTicks(firstStep); + const int64_t ticks = getEventStepTicks(firstStep); if (ticks <= 0) { return; } - // Take first step right away, but still queue the next - if (ticks == 1) { - g_game().checkCreatureWalk(getID()); - } + g_dispatcher().context().tryAddEvent([ticks, self = getCreature()]() { + // Take first step right away, but still queue the next + if (ticks == 1) { + g_game().checkCreatureWalk(self->getID()); + } - eventWalk = g_dispatcher().scheduleEvent( - static_cast(ticks), std::bind(&Game::checkCreatureWalk, &g_game(), getID()), - "Creature::checkCreatureWalk" - ); + self->eventWalk = g_dispatcher().scheduleEvent( + static_cast(ticks), std::bind(&Game::checkCreatureWalk, &g_game(), self->getID()), + "Creature::checkCreatureWalk" + ); + }); } void Creature::stopEventWalk() { @@ -320,11 +331,7 @@ int32_t Creature::getWalkCache(const Position &pos) { if (std::abs(dx) <= maxWalkCacheWidth) { int32_t dy = Position::getOffsetY(pos, myPos); if (std::abs(dy) <= maxWalkCacheHeight) { - if (localMapCache[maxWalkCacheHeight + dy][maxWalkCacheWidth + dx]) { - return 1; - } else { - return 0; - } + return localMapCache[maxWalkCacheHeight + dy][maxWalkCacheWidth + dx]; } } @@ -464,7 +471,7 @@ void Creature::checkSummonMove(const Position &newPos, bool teleportSummon) { } } -void Creature::onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport) { +void Creature::onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) { if (creature == getCreature()) { lastStep = OTSYS_TIME(); lastStepCost = 1; @@ -512,7 +519,7 @@ void Creature::onCreatureMove(std::shared_ptr creature, std::shared_pt // update 0 for (int32_t x = -maxWalkCacheWidth; x <= maxWalkCacheWidth; ++x) { - std::shared_ptr cacheTile = g_game().map.getTile(static_cast(myPos.getX() + x), static_cast(myPos.getY() - maxWalkCacheHeight), myPos.z); + const auto &cacheTile = g_game().map.getTile(static_cast(myPos.getX() + x), static_cast(myPos.getY() - maxWalkCacheHeight), myPos.z); updateTileCache(cacheTile, x, -maxWalkCacheHeight); } } else if (oldPos.y < newPos.y) { // south @@ -523,7 +530,7 @@ void Creature::onCreatureMove(std::shared_ptr creature, std::shared_pt // update mapWalkHeight - 1 for (int32_t x = -maxWalkCacheWidth; x <= maxWalkCacheWidth; ++x) { - std::shared_ptr cacheTile = g_game().map.getTile(static_cast(myPos.getX() + x), static_cast(myPos.getY() + maxWalkCacheHeight), myPos.z); + const auto &cacheTile = g_game().map.getTile(static_cast(myPos.getX() + x), static_cast(myPos.getY() + maxWalkCacheHeight), myPos.z); updateTileCache(cacheTile, x, maxWalkCacheHeight); } } @@ -548,7 +555,7 @@ void Creature::onCreatureMove(std::shared_ptr creature, std::shared_pt // update mapWalkWidth - 1 for (int32_t y = -maxWalkCacheHeight; y <= maxWalkCacheHeight; ++y) { - std::shared_ptr cacheTile = g_game().map.getTile(myPos.x + maxWalkCacheWidth, static_cast(myPos.y + y), myPos.z); + const auto &cacheTile = g_game().map.getTile(myPos.x + maxWalkCacheWidth, static_cast(myPos.y + y), myPos.z); updateTileCache(cacheTile, maxWalkCacheWidth, y); } } else if (oldPos.x > newPos.x) { // west @@ -593,7 +600,7 @@ void Creature::onCreatureMove(std::shared_ptr creature, std::shared_pt } } - auto followCreature = getFollowCreature(); + const auto &followCreature = getFollowCreature(); if (followCreature && (creature == getCreature() || creature == followCreature)) { if (hasFollowPath) { isUpdatingPath = true; @@ -605,7 +612,7 @@ void Creature::onCreatureMove(std::shared_ptr creature, std::shared_pt } } - auto attackedCreature = getAttackedCreature(); + const auto &attackedCreature = getAttackedCreature(); if (attackedCreature && (creature == attackedCreature || creature == getCreature())) { if (newPos.z != oldPos.z || !canSee(attackedCreature->getPosition())) { onCreatureDisappear(attackedCreature, false); @@ -948,7 +955,7 @@ bool Creature::setAttackedCreature(std::shared_ptr creature) { return true; } -void Creature::getPathSearchParams(std::shared_ptr, FindPathParams &fpp) { +void Creature::getPathSearchParams(const std::shared_ptr &, FindPathParams &fpp) { fpp.fullPathSearch = !hasFollowPath; fpp.clearSight = true; fpp.maxSearchDist = 12; @@ -956,55 +963,64 @@ void Creature::getPathSearchParams(std::shared_ptr, FindPathParams &fp fpp.maxTargetDist = 1; } +void Creature::goToFollowCreature_async(std::function &&onComplete) { + if (pathfinderRunning.load()) { + return; + } + + pathfinderRunning.store(true); + g_dispatcher().asyncEvent([self = getCreature()] { + self->goToFollowCreature(); + self->pathfinderRunning.store(false); + }); + + if (onComplete) { + g_dispatcher().context().addEvent(std::move(onComplete)); + } +} + void Creature::goToFollowCreature() { - auto followCreature = getFollowCreature(); - if (followCreature) { - if (isSummon() && !getMonster()->isFamiliar() && !canFollowMaster()) { - hasFollowPath = false; - return; - } + const auto &followCreature = getFollowCreature(); + if (!followCreature) { + return; + } - FindPathParams fpp; - getPathSearchParams(followCreature, fpp); - std::shared_ptr monster = getMonster(); - if (monster && !monster->getMaster() && (monster->isFleeing() || fpp.maxTargetDist > 1)) { - Direction dir = DIRECTION_NONE; - - if (monster->isFleeing()) { - monster->getDistanceStep(followCreature->getPosition(), dir, true); - } else { // maxTargetDist > 1 - if (!monster->getDistanceStep(followCreature->getPosition(), dir)) { - // if we can't get anything then let the A* calculate - listWalkDir.clear(); - if (getPathTo(followCreature->getPosition(), listWalkDir, fpp)) { - hasFollowPath = true; - startAutoWalk(listWalkDir); - } else { - hasFollowPath = false; - } - return; - } - } + const auto &monster = getMonster(); - if (dir != DIRECTION_NONE) { - listWalkDir.clear(); - listWalkDir.push_front(dir); + if (isSummon() && !monster->isFamiliar() && !canFollowMaster()) { + listWalkDir.clear(); + return; + } - hasFollowPath = true; - startAutoWalk(listWalkDir); - } - } else { - listWalkDir.clear(); - if (getPathTo(followCreature->getPosition(), listWalkDir, fpp)) { - hasFollowPath = true; - startAutoWalk(listWalkDir); - } else { - hasFollowPath = false; - } + bool executeOnFollow = true; + stdext::arraylist listDir(128); + + FindPathParams fpp; + getPathSearchParams(followCreature, fpp); + + if (monster && !monster->getMaster() && (monster->isFleeing() || fpp.maxTargetDist > 1)) { + Direction dir = DIRECTION_NONE; + + if (monster->isFleeing()) { + monster->getDistanceStep(followCreature->getPosition(), dir, true); + } else if (!monster->getDistanceStep(followCreature->getPosition(), dir)) { // maxTargetDist > 1 + // if we can't get anything then let the A* calculate + executeOnFollow = false; + } else if (dir != DIRECTION_NONE) { + listDir.push_back(dir); + hasFollowPath = true; } } - onFollowCreatureComplete(followCreature); + if (listDir.empty()) { + hasFollowPath = getPathTo(getFollowCreature()->getPosition(), listDir, fpp); + } + + startAutoWalk(listDir.data()); + + if (executeOnFollow) { + onFollowCreatureComplete(getFollowCreature()); + } } bool Creature::canFollowMaster() { @@ -1248,7 +1264,6 @@ bool Creature::addCondition(std::shared_ptr condition) { std::shared_ptr prevCond = getCondition(condition->getType(), condition->getId(), condition->getSubId()); if (prevCond) { prevCond->addCondition(getCreature(), condition); - return true; } @@ -1638,11 +1653,11 @@ bool Creature::isInvisible() const { != conditions.end(); } -bool Creature::getPathTo(const Position &targetPos, std::forward_list &dirList, const FindPathParams &fpp) { +bool Creature::getPathTo(const Position &targetPos, stdext::arraylist &dirList, const FindPathParams &fpp) { return g_game().map.getPathMatching(getCreature(), dirList, FrozenPathingConditionCall(targetPos), fpp); } -bool Creature::getPathTo(const Position &targetPos, std::forward_list &dirList, int32_t minTargetDist, int32_t maxTargetDist, bool fullPathSearch /*= true*/, bool clearSight /*= true*/, int32_t maxSearchDist /*= 7*/) { +bool Creature::getPathTo(const Position &targetPos, stdext::arraylist &dirList, int32_t minTargetDist, int32_t maxTargetDist, bool fullPathSearch /*= true*/, bool clearSight /*= true*/, int32_t maxSearchDist /*= 7*/) { FindPathParams fpp; fpp.fullPathSearch = fullPathSearch; fpp.maxSearchDist = maxSearchDist; diff --git a/src/creatures/creature.hpp b/src/creatures/creature.hpp index 0195ec17c30..5e03e33d703 100644 --- a/src/creatures/creature.hpp +++ b/src/creatures/creature.hpp @@ -43,6 +43,10 @@ class FrozenPathingConditionCall { bool isInRange(const Position &startPos, const Position &testPos, const FindPathParams &fpp) const; + Position getTargetPos() const { + return targetPos; + } + private: Position targetPos; }; @@ -266,9 +270,11 @@ class Creature : virtual public Thing, public SharedObject { phmap::flat_hash_set> getZones(); // walk functions - void startAutoWalk(const std::forward_list &listDir, bool ignoreConditions = false); + void startAutoWalk(const std::vector &listDir, bool ignoreConditions = false); void addEventWalk(bool firstStep = false); void stopEventWalk(); + + void goToFollowCreature_async(std::function &&onComplete = nullptr); virtual void goToFollowCreature(); // walk events @@ -283,8 +289,12 @@ class Creature : virtual public Thing, public SharedObject { virtual bool setFollowCreature(std::shared_ptr creature); // follow events - virtual void onFollowCreature(std::shared_ptr) { } - virtual void onFollowCreatureComplete(std::shared_ptr) { } + virtual void onFollowCreature(const std::shared_ptr &) { + /* empty */ + } + virtual void onFollowCreatureComplete(const std::shared_ptr &) { + /* empty */ + } // combat functions std::shared_ptr getAttackedCreature() { @@ -446,7 +456,7 @@ class Creature : virtual public Thing, public SharedObject { * @return false */ void checkSummonMove(const Position &newPos, bool teleportSummon = false); - virtual void onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport); + virtual void onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport); virtual void onAttackedCreatureDisappear(bool) { } virtual void onFollowCreatureDisappear(bool) { } @@ -524,8 +534,8 @@ class Creature : virtual public Thing, public SharedObject { double getDamageRatio(std::shared_ptr attacker) const; - bool getPathTo(const Position &targetPos, std::forward_list &dirList, const FindPathParams &fpp); - bool getPathTo(const Position &targetPos, std::forward_list &dirList, int32_t minTargetDist, int32_t maxTargetDist, bool fullPathSearch = true, bool clearSight = true, int32_t maxSearchDist = 7); + bool getPathTo(const Position &targetPos, stdext::arraylist &dirList, const FindPathParams &fpp); + bool getPathTo(const Position &targetPos, stdext::arraylist &dirList, int32_t minTargetDist, int32_t maxTargetDist, bool fullPathSearch = true, bool clearSight = true, int32_t maxSearchDist = 7); struct CountBlock_t { int32_t total; @@ -660,7 +670,7 @@ class Creature : virtual public Thing, public SharedObject { CreatureEventList eventsList; ConditionList conditions; - std::forward_list listWalkDir; + std::deque listWalkDir; std::weak_ptr m_tile; std::weak_ptr m_attackedCreature; @@ -721,16 +731,18 @@ class Creature : virtual public Thing, public SharedObject { bool skillLoss = true; bool lootDrop = true; bool cancelNextWalk = false; - bool hasFollowPath = false; bool forceUpdateFollowPath = false; bool hiddenHealth = false; bool floorChange = false; bool canUseDefense = true; bool moveLocked = false; + bool hasFollowPath = false; int8_t charmChanceModifier = 0; uint8_t wheelOfDestinyDrainBodyDebuff = 0; + std::atomic_bool pathfinderRunning = false; + // use map here instead of phmap to keep the keys in a predictable order std::map creatureIcons = {}; @@ -756,7 +768,7 @@ class Creature : virtual public Thing, public SharedObject { virtual uint16_t getLookCorpse() const { return 0; } - virtual void getPathSearchParams(std::shared_ptr creature, FindPathParams &fpp); + virtual void getPathSearchParams(const std::shared_ptr &, FindPathParams &fpp); virtual void death(std::shared_ptr) { } virtual bool dropCorpse(std::shared_ptr lastHitCreature, std::shared_ptr mostDamageCreature, bool lastHitUnjustified, bool mostDamageUnjustified); virtual std::shared_ptr getCorpse(std::shared_ptr lastHitCreature, std::shared_ptr mostDamageCreature); @@ -769,4 +781,5 @@ class Creature : virtual public Thing, public SharedObject { bool canFollowMaster(); bool isLostSummon(); void handleLostSummon(bool teleportSummons); + void executeAsyncPathTo(bool executeOnFollow, FindPathParams &fpp, std::function &&onComplete); }; diff --git a/src/creatures/monsters/monster.cpp b/src/creatures/monsters/monster.cpp index 9bef75a5ecb..97c18e6d855 100644 --- a/src/creatures/monsters/monster.cpp +++ b/src/creatures/monsters/monster.cpp @@ -178,7 +178,7 @@ void Monster::onRemoveCreature(std::shared_ptr creature, bool isLogout } } -void Monster::onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport) { +void Monster::onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) { Creature::onCreatureMove(creature, newTile, newPos, oldTile, oldPos, teleport); if (mType->info.creatureMoveEvent != -1) { @@ -596,16 +596,17 @@ bool Monster::searchTarget(TargetSearchType_t searchType /*= TARGETSEARCH_DEFAUL return false; } -void Monster::onFollowCreatureComplete(std::shared_ptr creature) { +void Monster::onFollowCreatureComplete(const std::shared_ptr &creature) { if (!creature) { return; } + auto it = std::find(targetIDList.begin(), targetIDList.end(), creature->getID()); - if (it != targetIDList.end()) { - auto target = targetListMap[*it].lock(); - if (!target) { - return; - } + if (it == targetIDList.end()) { + return; + } + + if (const auto &target = targetListMap[*it].lock()) { targetIDList.erase(it); if (hasFollowPath) { @@ -870,7 +871,7 @@ void Monster::doAttacking(uint32_t interval) { } } -bool Monster::canUseAttack(const Position &pos, std::shared_ptr target) const { +bool Monster::canUseAttack(const Position &pos, const std::shared_ptr &target) const { if (isHostile()) { const Position &targetPos = target->getPosition(); uint32_t distance = std::max(Position::getDistanceX(pos, targetPos), Position::getDistanceY(pos, targetPos)); @@ -2066,7 +2067,7 @@ bool Monster::isImmune(CombatType_t combatType) const { return mType->info.m_damageImmunities[combatTypeToIndex(combatType)]; } -void Monster::getPathSearchParams(std::shared_ptr creature, FindPathParams &fpp) { +void Monster::getPathSearchParams(const std::shared_ptr &creature, FindPathParams &fpp) { Creature::getPathSearchParams(creature, fpp); fpp.minTargetDist = 1; diff --git a/src/creatures/monsters/monster.hpp b/src/creatures/monsters/monster.hpp index adcb0258503..e6178a4f77c 100644 --- a/src/creatures/monsters/monster.hpp +++ b/src/creatures/monsters/monster.hpp @@ -147,13 +147,13 @@ class Monster final : public Creature { void onCreatureAppear(std::shared_ptr creature, bool isLogin) override; void onRemoveCreature(std::shared_ptr creature, bool isLogout) override; - void onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport) override; + void onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) override; void onCreatureSay(std::shared_ptr creature, SpeakClasses type, const std::string &text) override; void drainHealth(std::shared_ptr attacker, int32_t damage) override; void changeHealth(int32_t healthChange, bool sendHealthChange = true) override; bool getNextStep(Direction &direction, uint32_t &flags) override; - void onFollowCreatureComplete(std::shared_ptr creature) override; + void onFollowCreatureComplete(const std::shared_ptr &creature) override; void onThink(uint32_t interval) override; @@ -407,7 +407,7 @@ class Monster final : public Creature { void onAddCondition(ConditionType_t type) override; void onEndCondition(ConditionType_t type) override; - bool canUseAttack(const Position &pos, std::shared_ptr target) const; + bool canUseAttack(const Position &pos, const std::shared_ptr &target) const; bool canUseSpell(const Position &pos, const Position &targetPos, const spellBlock_t &sb, uint32_t interval, bool &inRange, bool &resetTicks); bool getRandomStep(const Position &creaturePos, Direction &direction); bool getDanceStep(const Position &creaturePos, Direction &direction, bool keepAttack = true, bool keepDistance = true); @@ -434,7 +434,7 @@ class Monster final : public Creature { return mType->info.lookcorpse; } void dropLoot(std::shared_ptr corpse, std::shared_ptr lastHitCreature) override; - void getPathSearchParams(std::shared_ptr creature, FindPathParams &fpp) override; + void getPathSearchParams(const std::shared_ptr &creature, FindPathParams &fpp) override; bool useCacheMap() const override { return !randomStepping; } diff --git a/src/creatures/npcs/npc.cpp b/src/creatures/npcs/npc.cpp index 89eabdae28b..2df46c285cb 100644 --- a/src/creatures/npcs/npc.cpp +++ b/src/creatures/npcs/npc.cpp @@ -113,7 +113,7 @@ void Npc::onRemoveCreature(std::shared_ptr creature, bool isLogout) { shopPlayerMap.clear(); } -void Npc::onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport) { +void Npc::onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) { Creature::onCreatureMove(creature, newTile, newPos, oldTile, oldPos, teleport); // onCreatureMove(self, creature, oldPosition, newPosition) @@ -134,7 +134,7 @@ void Npc::onCreatureMove(std::shared_ptr creature, std::shared_ptrgetPlayer()) { + if (const auto &player = creature->getPlayer()) { handlePlayerMove(player, newPos); } } diff --git a/src/creatures/npcs/npc.hpp b/src/creatures/npcs/npc.hpp index 27f46cbeec6..38cd9840a17 100644 --- a/src/creatures/npcs/npc.hpp +++ b/src/creatures/npcs/npc.hpp @@ -137,7 +137,7 @@ class Npc final : public Creature { void onCreatureAppear(std::shared_ptr creature, bool isLogin) override; void onRemoveCreature(std::shared_ptr creature, bool isLogout) override; - void onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport) override; + void onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) override; void onCreatureSay(std::shared_ptr creature, SpeakClasses type, const std::string &text) override; void onThink(uint32_t interval) override; void onPlayerBuyItem(std::shared_ptr player, uint16_t itemid, uint8_t count, uint16_t amount, bool ignore, bool inBackpacks); diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index aba77e44c60..1178a666e1c 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -1830,10 +1830,10 @@ void Player::onWalk(Direction &dir) { setNextAction(OTSYS_TIME() + getStepDuration(dir)); } -void Player::onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport) { +void Player::onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) { Creature::onCreatureMove(creature, newTile, newPos, oldTile, oldPos, teleport); - auto followCreature = getFollowCreature(); + const auto &followCreature = getFollowCreature(); if (hasFollowPath && (creature == followCreature || (creature.get() == this && followCreature))) { isUpdatingPath = false; g_dispatcher().addEvent(std::bind(&Game::updateCreatureWalk, &g_game(), getID()), "Game::updateCreatureWalk"); @@ -1850,7 +1850,7 @@ void Player::onCreatureMove(std::shared_ptr creature, std::shared_ptr< } if (tradePartner && !Position::areInRange<2, 2, 0>(tradePartner->getPosition(), getPosition())) { - g_game().internalCloseTrade(static_self_cast()); + g_game().internalCloseTrade(getPlayer()); } } @@ -1873,13 +1873,13 @@ void Player::onCreatureMove(std::shared_ptr creature, std::shared_ptr< if (party) { party->updateSharedExperience(); - party->updatePlayerStatus(static_self_cast(), oldPos, newPos); + party->updatePlayerStatus(getPlayer(), oldPos, newPos); } if (teleport || oldPos.z != newPos.z) { int32_t ticks = g_configManager().getNumber(STAIRHOP_DELAY); if (ticks > 0) { - if (std::shared_ptr condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_PACIFIED, ticks, 0)) { + if (const auto &condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_PACIFIED, ticks, 0)) { addCondition(condition); } } @@ -4223,7 +4223,7 @@ void Player::goToFollowCreature() { } } -void Player::getPathSearchParams(std::shared_ptr creature, FindPathParams &fpp) { +void Player::getPathSearchParams(const std::shared_ptr &creature, FindPathParams &fpp) { Creature::getPathSearchParams(creature, fpp); fpp.fullPathSearch = true; } @@ -4287,7 +4287,7 @@ uint64_t Player::getGainedExperience(std::shared_ptr attacker) const { return 0; } -void Player::onFollowCreature(std::shared_ptr creature) { +void Player::onFollowCreature(const std::shared_ptr &creature) { if (!creature) { stopWalk(); } @@ -7558,9 +7558,9 @@ SoundEffect_t Player::getAttackSoundEffect() const { bool Player::canAutoWalk(const Position &toPosition, const std::function &function, uint32_t delay /* = 500*/) { if (!Position::areInRange<1, 1>(getPosition(), toPosition)) { // Check if can walk to the toPosition and send event to use function - std::forward_list listDir; + stdext::arraylist listDir(128); if (getPathTo(toPosition, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, &g_game(), getID(), listDir), __FUNCTION__); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, &g_game(), getID(), listDir.data()), __FUNCTION__); std::shared_ptr task = createPlayerTask(delay, function, __FUNCTION__); setNextWalkActionTask(task); diff --git a/src/creatures/players/player.hpp b/src/creatures/players/player.hpp index 83b28e88364..2a32a838c36 100644 --- a/src/creatures/players/player.hpp +++ b/src/creatures/players/player.hpp @@ -815,7 +815,7 @@ class Player final : public Creature, public Cylinder, public Bankable { void goToFollowCreature() override; // follow events - void onFollowCreature(std::shared_ptr creature) override; + void onFollowCreature(const std::shared_ptr &) override; // walk events void onWalk(Direction &dir) override; @@ -1230,7 +1230,7 @@ class Player final : public Creature, public Cylinder, public Bankable { void onCreatureAppear(std::shared_ptr creature, bool isLogin) override; void onRemoveCreature(std::shared_ptr creature, bool isLogout) override; - void onCreatureMove(std::shared_ptr creature, std::shared_ptr newTile, const Position &newPos, std::shared_ptr oldTile, const Position &oldPos, bool teleport) override; + void onCreatureMove(const std::shared_ptr &creature, const std::shared_ptr &newTile, const Position &newPos, const std::shared_ptr &oldTile, const Position &oldPos, bool teleport) override; void onAttackedCreatureDisappear(bool isLogout) override; void onFollowCreatureDisappear(bool isLogout) override; @@ -2888,7 +2888,7 @@ class Player final : public Creature, public Cylinder, public Bankable { void addConditionSuppression(const std::array &addConditions); uint16_t getLookCorpse() const override; - void getPathSearchParams(std::shared_ptr creature, FindPathParams &fpp) override; + void getPathSearchParams(const std::shared_ptr &creature, FindPathParams &fpp) override; void setDead(bool isDead) { dead = isDead; diff --git a/src/game/game.cpp b/src/game/game.cpp index 76c83737f60..417c89a8497 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -1144,9 +1144,9 @@ void Game::playerMoveCreature(std::shared_ptr player, std::shared_ptr(movingCreatureOrigPos, player->getPosition())) { // need to walk to the creature first before moving it - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(movingCreatureOrigPos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(600, std::bind(&Game::playerMoveCreatureByID, this, player->getID(), movingCreature->getID(), movingCreatureOrigPos, toTile->getPosition()), "Game::playerMoveCreatureByID"); @@ -1441,9 +1441,9 @@ void Game::playerMoveItem(std::shared_ptr player, const Position &fromPo if (!Position::areInRange<1, 1>(playerPos, mapFromPos)) { // need to walk to the item first before using it - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(item->getPosition(), listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerMoveItemByPlayerID, this, player->getID(), fromPos, itemId, fromStackPos, toPos, count), "Game::playerMoveItemByPlayerID"); player->setNextWalkActionTask(task); @@ -1498,9 +1498,9 @@ void Game::playerMoveItem(std::shared_ptr player, const Position &fromPo internalGetPosition(moveItem, itemPos, itemStackPos); } - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(walkPos, listDir, 0, 0, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerMoveItemByPlayerID, this, player->getID(), itemPos, itemId, itemStackPos, toPos, count), "Game::playerMoveItemByPlayerID"); player->setNextWalkActionTask(task); @@ -3020,7 +3020,7 @@ void Game::playerMove(uint32_t playerId, Direction direction) { player->setNextWalkActionTask(nullptr); player->cancelPush(); - player->startAutoWalk(std::forward_list { direction }, false); + player->startAutoWalk(std::vector { direction }, false); } void Game::forcePlayerMove(uint32_t playerId, Direction direction) { @@ -3033,7 +3033,7 @@ void Game::forcePlayerMove(uint32_t playerId, Direction direction) { player->setNextWalkActionTask(nullptr); player->cancelPush(); - player->startAutoWalk(std::forward_list { direction }, true); + player->startAutoWalk(std::vector { direction }, true); } bool Game::playerBroadcastMessage(std::shared_ptr player, const std::string &text) const { @@ -3198,7 +3198,7 @@ void Game::playerReceivePingBack(uint32_t playerId) { player->sendPingBack(); } -void Game::playerAutoWalk(uint32_t playerId, const std::forward_list &listDir) { +void Game::playerAutoWalk(uint32_t playerId, const std::vector &listDir) { std::shared_ptr player = getPlayerByID(playerId); if (!player) { return; @@ -3209,7 +3209,7 @@ void Game::playerAutoWalk(uint32_t playerId, const std::forward_list player->startAutoWalk(listDir, false); } -void Game::forcePlayerAutoWalk(uint32_t playerId, const std::forward_list &listDir) { +void Game::forcePlayerAutoWalk(uint32_t playerId, const std::vector &listDir) { std::shared_ptr player = getPlayerByID(playerId); if (!player) { return; @@ -3298,9 +3298,9 @@ void Game::playerUseItemEx(uint32_t playerId, const Position &fromPos, uint8_t f internalGetPosition(moveItem, itemPos, itemStackPos); } - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(walkToPos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerUseItemEx, this, playerId, itemPos, itemStackPos, fromItemId, toPos, toStackPos, toItemId), "Game::playerUseItemEx"); if (it.isRune() || it.type == ITEM_TYPE_POTION) { @@ -3403,9 +3403,9 @@ void Game::playerUseItem(uint32_t playerId, const Position &pos, uint8_t stackPo ReturnValue ret = g_actions().canUse(player, pos); if (ret != RETURNVALUE_NOERROR) { if (ret == RETURNVALUE_TOOFARAWAY) { - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerUseItem, this, playerId, pos, stackPos, index, itemId), "Game::playerUseItem"); if (it.isRune() || it.type == ITEM_TYPE_POTION) { @@ -3537,9 +3537,9 @@ void Game::playerUseWithCreature(uint32_t playerId, const Position &fromPos, uin internalGetPosition(moveItem, itemPos, itemStackPos); } - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(walkToPos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerUseWithCreature, this, playerId, itemPos, itemStackPos, creatureId, itemId), "Game::playerUseWithCreature"); if (it.isRune() || it.type == ITEM_TYPE_POTION) { @@ -3676,9 +3676,9 @@ void Game::playerRotateItem(uint32_t playerId, const Position &pos, uint8_t stac } if (pos.x != 0xFFFF && !Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerRotateItem, this, playerId, pos, stackPos, itemId), "Game::playerRotateItem"); player->setNextWalkActionTask(task); @@ -3717,9 +3717,9 @@ void Game::playerConfigureShowOffSocket(uint32_t playerId, const Position &pos, bool isPodiumOfRenown = itemId == ITEM_PODIUM_OF_RENOWN1 || itemId == ITEM_PODIUM_OF_RENOWN2; if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, false)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task; if (isPodiumOfRenown) { task = createPlayerTask(400, std::bind_front(&Player::sendPodiumWindow, player, item, pos, itemId, stackPos), "Game::playerConfigureShowOffSocket"); @@ -3764,9 +3764,9 @@ void Game::playerSetShowOffSocket(uint32_t playerId, Outfit_t &outfit, const Pos } if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, false)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerBrowseField, this, playerId, pos), "Game::playerBrowseField"); player->setNextWalkActionTask(task); } else { @@ -3893,9 +3893,9 @@ void Game::playerWrapableItem(uint32_t playerId, const Position &pos, uint8_t st } if (pos.x != 0xFFFF && !Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerWrapableItem, this, playerId, pos, stackPos, itemId), "Game::playerWrapableItem"); player->setNextWalkActionTask(task); @@ -4063,9 +4063,9 @@ void Game::playerBrowseField(uint32_t playerId, const Position &pos) { } if (!Position::areInRange<1, 1>(playerPos, pos)) { - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerBrowseField, this, playerId, pos), "Game::playerBrowseField"); player->setNextWalkActionTask(task); } else { @@ -4313,9 +4313,9 @@ void Game::playerRequestTrade(uint32_t playerId, const Position &pos, uint8_t st } if (!Position::areInRange<1, 1>(tradeItemPosition, playerPosition)) { - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind(&Game::playerRequestTrade, this, playerId, pos, stackPos, tradePlayerId, itemId), "Game::playerRequestTrade"); player->setNextWalkActionTask(task); @@ -4862,9 +4862,9 @@ void Game::playerQuickLoot(uint32_t playerId, const Position &pos, uint16_t item if (!autoLoot && pos.x != 0xffff) { if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { // need to walk to the corpse first before looting it - std::forward_list listDir; + stdext::arraylist listDir(128); if (player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(0, std::bind(&Game::playerQuickLoot, this, player->getID(), pos, itemId, stackPos, defaultItem, lootAllCorpses, autoLoot), "Game::playerQuickLoot"); player->setNextWalkActionTask(task); } else { @@ -5747,7 +5747,7 @@ bool Game::internalCreatureSay(std::shared_ptr creature, SpeakClasses } void Game::checkCreatureWalk(uint32_t creatureId) { - std::shared_ptr creature = getCreatureByID(creatureId); + const auto &creature = getCreatureByID(creatureId); if (creature && creature->getHealth() > 0) { creature->onCreatureWalk(); cleanup(); @@ -5755,20 +5755,20 @@ void Game::checkCreatureWalk(uint32_t creatureId) { } void Game::updateCreatureWalk(uint32_t creatureId) { - std::shared_ptr creature = getCreatureByID(creatureId); + const auto &creature = getCreatureByID(creatureId); if (creature && creature->getHealth() > 0) { - creature->goToFollowCreature(); + creature->goToFollowCreature_async(); } } void Game::checkCreatureAttack(uint32_t creatureId) { - std::shared_ptr creature = getCreatureByID(creatureId); + const auto &creature = getCreatureByID(creatureId); if (creature && creature->getHealth() > 0) { creature->onAttacking(0); } } -void Game::addCreatureCheck(std::shared_ptr creature) { +void Game::addCreatureCheck(const std::shared_ptr &creature) { creature->creatureCheck = true; if (creature->inCheckCreaturesVector) { @@ -5777,10 +5777,10 @@ void Game::addCreatureCheck(std::shared_ptr creature) { } creature->inCheckCreaturesVector = true; - checkCreatureLists[uniform_random(0, EVENT_CREATURECOUNT - 1)].push_back(creature); + checkCreatureLists[uniform_random(0, EVENT_CREATURECOUNT - 1)].emplace_back(creature); } -void Game::removeCreatureCheck(std::shared_ptr creature) { +void Game::removeCreatureCheck(const std::shared_ptr &creature) { if (creature->inCheckCreaturesVector) { creature->creatureCheck = false; } @@ -5792,7 +5792,7 @@ void Game::checkCreatures() { auto &checkCreatureList = checkCreatureLists[index]; size_t it = 0, end = checkCreatureList.size(); while (it < end) { - std::shared_ptr creature = checkCreatureList[it]; + const auto &creature = checkCreatureList[it]; if (creature && creature->creatureCheck) { if (creature->getHealth() > 0) { creature->onThink(EVENT_CREATURE_THINK_INTERVAL); @@ -8995,9 +8995,9 @@ void Game::playerSetMonsterPodium(uint32_t playerId, uint32_t monsterRaceId, con } if (!Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - if (std::forward_list listDir; + if (stdext::arraylist listDir(128); player->getPathTo(pos, listDir, 0, 1, true, false)) { - g_dispatcher().addEvent(std::bind_front(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind_front(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind_front(&Game::playerBrowseField, this, playerId, pos), "Game::playerBrowseField"); player->setNextWalkActionTask(task); } else { @@ -9086,9 +9086,9 @@ void Game::playerRotatePodium(uint32_t playerId, const Position &pos, uint8_t st } if (pos.x != 0xFFFF && !Position::areInRange<1, 1, 0>(pos, player->getPosition())) { - if (std::forward_list listDir; + if (stdext::arraylist listDir(128); player->getPathTo(pos, listDir, 0, 1, true, true)) { - g_dispatcher().addEvent(std::bind_front(&Game::playerAutoWalk, this, player->getID(), listDir), "Game::playerAutoWalk"); + g_dispatcher().addEvent(std::bind_front(&Game::playerAutoWalk, this, player->getID(), listDir.data()), "Game::playerAutoWalk"); std::shared_ptr task = createPlayerTask(400, std::bind_front(&Game::playerRotatePodium, this, playerId, pos, stackPos, itemId), "Game::playerRotatePodium"); player->setNextWalkActionTask(task); diff --git a/src/game/game.hpp b/src/game/game.hpp index a5c7cd116c0..2b30a31d2f4 100644 --- a/src/game/game.hpp +++ b/src/game/game.hpp @@ -168,8 +168,8 @@ class Game { bool removeCreature(std::shared_ptr creature, bool isLogout = true); void executeDeath(uint32_t creatureId); - void addCreatureCheck(std::shared_ptr creature); - static void removeCreatureCheck(std::shared_ptr creature); + void addCreatureCheck(const std::shared_ptr &creature); + static void removeCreatureCheck(const std::shared_ptr &creature); size_t getPlayersOnline() const { return players.size(); @@ -320,8 +320,8 @@ class Game { void playerCloseNpcChannel(uint32_t playerId); void playerReceivePing(uint32_t playerId); void playerReceivePingBack(uint32_t playerId); - void playerAutoWalk(uint32_t playerId, const std::forward_list &listDir); - void forcePlayerAutoWalk(uint32_t playerId, const std::forward_list &listDir); + void playerAutoWalk(uint32_t playerId, const std::vector &listDir); + void forcePlayerAutoWalk(uint32_t playerId, const std::vector &listDir); void playerStopAutoWalk(uint32_t playerId); void playerUseItemEx(uint32_t playerId, const Position &fromPos, uint8_t fromStackPos, uint16_t fromItemId, const Position &toPos, uint8_t toStackPos, uint16_t toItemId); void playerUseItem(uint32_t playerId, const Position &pos, uint8_t stackPos, uint8_t index, uint16_t itemId); diff --git a/src/game/scheduling/dispatcher.cpp b/src/game/scheduling/dispatcher.cpp index 1bb7512f11d..a24ef770466 100644 --- a/src/game/scheduling/dispatcher.cpp +++ b/src/game/scheduling/dispatcher.cpp @@ -14,7 +14,6 @@ #include "lib/di/container.hpp" #include "utils/tools.hpp" -constexpr static auto ASYNC_TIME_OUT = std::chrono::seconds(15); thread_local DispatcherContext Dispatcher::dispacherContext; Dispatcher &Dispatcher::getInstance() { @@ -30,7 +29,7 @@ void Dispatcher::init() { while (!threadPool.getIoContext().stopped()) { updateClock(); - executeEvents(asyncLock); + executeEvents(); executeScheduledEvents(); mergeEvents(); @@ -56,12 +55,12 @@ void Dispatcher::executeSerialEvents(std::vector &tasks) { dispacherContext.reset(); } -void Dispatcher::executeParallelEvents(std::vector &tasks, const uint8_t groupId, std::unique_lock &asyncLock) { - const size_t totalTaskSize = tasks.size(); - std::atomic_uint_fast64_t executedTasks = 0; +void Dispatcher::executeParallelEvents(std::vector &tasks, const uint8_t groupId) { + std::atomic_uint_fast64_t totalTaskSize = tasks.size(); + std::atomic_bool isTasksCompleted = false; for (const auto &task : tasks) { - threadPool.addLoad([this, &task, &executedTasks, groupId, totalTaskSize] { + threadPool.addLoad([groupId, &task, &isTasksCompleted, &totalTaskSize] { dispacherContext.type = DispatcherType::AsyncEvent; dispacherContext.group = static_cast(groupId); dispacherContext.taskName = task.getContext(); @@ -70,21 +69,21 @@ void Dispatcher::executeParallelEvents(std::vector &tasks, const uint8_t g dispacherContext.reset(); - executedTasks.fetch_add(1); - if (executedTasks.load() >= totalTaskSize) { - signalAsync.notify_one(); + totalTaskSize.fetch_sub(1); + if (totalTaskSize.load() == 0) { + isTasksCompleted.store(true); + isTasksCompleted.notify_one(); } }); } - if (signalAsync.wait_for(asyncLock, ASYNC_TIME_OUT) == std::cv_status::timeout) { - g_logger().warn("A timeout occurred when executing the async dispatch in the context({}). Executed Tasks: {}/{}.", groupId, executedTasks.load(), totalTaskSize); - } + isTasksCompleted.wait(false); + tasks.clear(); } -void Dispatcher::executeEvents(std::unique_lock &asyncLock) { - for (uint_fast8_t groupId = 0; groupId < static_cast(TaskGroup::Last); ++groupId) { +void Dispatcher::executeEvents(const TaskGroup startGroup) { + for (uint_fast8_t groupId = static_cast(startGroup); groupId < static_cast(TaskGroup::Last); ++groupId) { auto &tasks = m_tasks[groupId]; if (tasks.empty()) { return; @@ -92,9 +91,9 @@ void Dispatcher::executeEvents(std::unique_lock &asyncLock) { if (groupId == static_cast(TaskGroup::Serial)) { executeSerialEvents(tasks); - mergeEvents(); // merge request, as there may be async event requests + mergeAsyncEvents(); } else { - executeParallelEvents(tasks, groupId, asyncLock); + executeParallelEvents(tasks, groupId); } } } @@ -128,18 +127,37 @@ void Dispatcher::executeScheduledEvents() { } dispacherContext.reset(); + + mergeAsyncEvents(); // merge async events requested by scheduled events + executeEvents(TaskGroup::GenericParallel); // execute async events requested by scheduled events } -// Merge thread events with main dispatch events -void Dispatcher::mergeEvents() { +// Merge only async thread events with main dispatch events +void Dispatcher::mergeAsyncEvents() { + constexpr uint8_t start = static_cast(TaskGroup::GenericParallel); + constexpr uint8_t end = static_cast(TaskGroup::Last); + for (const auto &thread : threads) { std::scoped_lock lock(thread->mutex); - for (uint_fast8_t i = 0; i < static_cast(TaskGroup::Last); ++i) { + for (uint_fast8_t i = start; i < end; ++i) { if (!thread->tasks[i].empty()) { m_tasks[i].insert(m_tasks[i].end(), make_move_iterator(thread->tasks[i].begin()), make_move_iterator(thread->tasks[i].end())); thread->tasks[i].clear(); } } + } +} + +// Merge thread events with main dispatch events +void Dispatcher::mergeEvents() { + constexpr uint8_t serial = static_cast(TaskGroup::Serial); + + for (const auto &thread : threads) { + std::scoped_lock lock(thread->mutex); + if (!thread->tasks[serial].empty()) { + m_tasks[serial].insert(m_tasks[serial].end(), make_move_iterator(thread->tasks[serial].begin()), make_move_iterator(thread->tasks[serial].end())); + thread->tasks[serial].clear(); + } if (!thread->scheduledTasks.empty()) { scheduledTasks.insert(make_move_iterator(thread->scheduledTasks.begin()), make_move_iterator(thread->scheduledTasks.end())); @@ -196,3 +214,19 @@ void Dispatcher::stopEvent(uint64_t eventId) { scheduledTasksRef.erase(it); } } + +void DispatcherContext::addEvent(std::function &&f) const { + g_dispatcher().addEvent(std::move(f), taskName); +} + +void DispatcherContext::tryAddEvent(std::function &&f) const { + if (!f) { + return; + } + + if (isAsync()) { + g_dispatcher().addEvent(std::move(f), taskName); + } else { + f(); + } +} diff --git a/src/game/scheduling/dispatcher.hpp b/src/game/scheduling/dispatcher.hpp index 73ba38ed224..9d0a5c51750 100644 --- a/src/game/scheduling/dispatcher.hpp +++ b/src/game/scheduling/dispatcher.hpp @@ -55,6 +55,12 @@ struct DispatcherContext { return type; } + // postpone the event + void addEvent(std::function &&f) const; + + // if the context is async, the event will be postponed, if not, it will be executed immediately. + void tryAddEvent(std::function &&f) const; + private: void reset() { group = TaskGroup::ThreadPool; @@ -143,15 +149,16 @@ class Dispatcher { void init(); void shutdown() { - signalAsync.notify_all(); + signalSchedule.notify_all(); } + inline void mergeAsyncEvents(); inline void mergeEvents(); - inline void executeEvents(std::unique_lock &asyncLock); + inline void executeEvents(const TaskGroup startGroup = TaskGroup::Serial); inline void executeScheduledEvents(); inline void executeSerialEvents(std::vector &tasks); - inline void executeParallelEvents(std::vector &tasks, const uint8_t groupId, std::unique_lock &asyncLock); + inline void executeParallelEvents(std::vector &tasks, const uint8_t groupId); inline std::chrono::nanoseconds timeUntilNextScheduledTask() const; inline void checkPendingTasks() { @@ -174,7 +181,6 @@ class Dispatcher { uint_fast64_t dispatcherCycle = 0; ThreadPool &threadPool; - std::condition_variable signalAsync; std::condition_variable signalSchedule; std::atomic_bool hasPendingTasks = false; std::mutex dummyMutex; // This is only used for signaling the condition variable and not as an actual lock. diff --git a/src/items/items_definitions.hpp b/src/items/items_definitions.hpp index 8b54fa679b5..c6326acd28b 100644 --- a/src/items/items_definitions.hpp +++ b/src/items/items_definitions.hpp @@ -431,6 +431,11 @@ enum TileFlags_t : uint32_t { TILESTATE_IMMOVABLENOFIELDBLOCKPATH = 1 << 21, TILESTATE_NOFIELDBLOCKPATH = 1 << 22, TILESTATE_SUPPORTS_HANGABLE = 1 << 23, + TILESTATE_MOVEABLE = 1 << 24, + TILESTATE_ISHORIZONTAL = 1 << 25, + TILESTATE_ISVERTICAL = 1 << 26, + TILESTATE_BLOCKPROJECTILE = 1 << 27, + TILESTATE_HASHEIGHT = 1 << 28, TILESTATE_FLOORCHANGE = TILESTATE_FLOORCHANGE_DOWN | TILESTATE_FLOORCHANGE_NORTH | TILESTATE_FLOORCHANGE_SOUTH | TILESTATE_FLOORCHANGE_EAST | TILESTATE_FLOORCHANGE_WEST | TILESTATE_FLOORCHANGE_SOUTH_ALT | TILESTATE_FLOORCHANGE_EAST_ALT, }; diff --git a/src/items/tile.cpp b/src/items/tile.cpp index 92beb20d52f..44631406fda 100644 --- a/src/items/tile.cpp +++ b/src/items/tile.cpp @@ -26,18 +26,34 @@ auto real_nullptr_tile = std::make_shared(0xFFFF, 0xFFFF, 0xFF); const std::shared_ptr &Tile::nullptr_tile = real_nullptr_tile; bool Tile::hasProperty(ItemProperty prop) const { - if (ground && ground->hasProperty(prop)) { - return true; - } - - if (const TileItemVector* items = getItemList()) { - for (auto &item : *items) { - if (item->hasProperty(prop)) { - return true; - } - } + switch (prop) { + case CONST_PROP_BLOCKSOLID: + return hasFlag(TILESTATE_BLOCKSOLID); + case CONST_PROP_HASHEIGHT: + return hasFlag(TILESTATE_HASHEIGHT); + case CONST_PROP_BLOCKPROJECTILE: + return hasFlag(TILESTATE_BLOCKPROJECTILE); + case CONST_PROP_BLOCKPATH: + return hasFlag(TILESTATE_BLOCKPATH); + case CONST_PROP_ISVERTICAL: + return hasFlag(TILESTATE_ISVERTICAL); + case CONST_PROP_ISHORIZONTAL: + return hasFlag(TILESTATE_ISHORIZONTAL); + case CONST_PROP_MOVEABLE: + return hasFlag(TILESTATE_MOVEABLE); + case CONST_PROP_IMMOVABLEBLOCKSOLID: + return hasFlag(TILESTATE_IMMOVABLEBLOCKSOLID); + case CONST_PROP_IMMOVABLEBLOCKPATH: + return hasFlag(TILESTATE_IMMOVABLEBLOCKPATH); + case CONST_PROP_IMMOVABLENOFIELDBLOCKPATH: + return hasFlag(TILESTATE_IMMOVABLENOFIELDBLOCKPATH); + case CONST_PROP_NOFIELDBLOCKPATH: + return hasFlag(TILESTATE_NOFIELDBLOCKPATH); + case CONST_PROP_SUPPORTHANGABLE: + return hasFlag(TILESTATE_SUPPORTS_HANGABLE); + default: + return false; } - return false; } bool Tile::hasProperty(std::shared_ptr exclude, ItemProperty prop) const { @@ -943,6 +959,7 @@ void Tile::addThing(int32_t, std::shared_ptr thing) { if (creature) { Spectators::clearCache(); creature->setParent(static_self_cast()); + CreatureVector* creatures = makeCreatures(); creatures->insert(creatures->begin(), creature); } else { @@ -1530,6 +1547,7 @@ void Tile::internalAddThing(uint32_t, std::shared_ptr thing) { std::shared_ptr creature = thing->getCreature(); if (creature) { Spectators::clearCache(); + CreatureVector* creatures = makeCreatures(); creatures->insert(creatures->begin(), creature); } else { @@ -1574,14 +1592,14 @@ void Tile::internalAddThing(uint32_t, std::shared_ptr thing) { } } -void Tile::updateTileFlags(std::shared_ptr item) { +void Tile::updateTileFlags(const std::shared_ptr &item) { resetTileFlags(item); setTileFlags(item); } -void Tile::setTileFlags(std::shared_ptr item) { +void Tile::setTileFlags(const std::shared_ptr &item) { if (!hasFlag(TILESTATE_FLOORCHANGE)) { - const ItemType &it = Item::items[item->getID()]; + const auto &it = Item::items[item->getID()]; if (it.floorChange != 0) { setFlag(it.floorChange); } @@ -1603,6 +1621,10 @@ void Tile::setTileFlags(std::shared_ptr item) { setFlag(TILESTATE_IMMOVABLENOFIELDBLOCKPATH); } + if (item->hasProperty(CONST_PROP_SUPPORTHANGABLE)) { + setFlag(TILESTATE_SUPPORTS_HANGABLE); + } + if (item->getTeleport()) { setFlag(TILESTATE_TELEPORT); } @@ -1627,9 +1649,34 @@ void Tile::setTileFlags(std::shared_ptr item) { setFlag(TILESTATE_BED); } - std::shared_ptr container = item->getContainer(); - if (container && container->getDepotLocker()) { - setFlag(TILESTATE_DEPOT); + if (item->hasProperty(CONST_PROP_IMMOVABLEBLOCKPATH)) { + setFlag(TILESTATE_IMMOVABLEBLOCKPATH); + } + + if (item->hasProperty(CONST_PROP_MOVEABLE)) { + setFlag(TILESTATE_MOVEABLE); + } + + if (item->hasProperty(CONST_PROP_ISHORIZONTAL)) { + setFlag(TILESTATE_ISHORIZONTAL); + } + + if (item->hasProperty(CONST_PROP_ISVERTICAL)) { + setFlag(TILESTATE_ISVERTICAL); + } + + if (item->hasProperty(CONST_PROP_BLOCKPROJECTILE)) { + setFlag(TILESTATE_BLOCKPROJECTILE); + } + + if (item->hasProperty(CONST_PROP_HASHEIGHT)) { + setFlag(TILESTATE_HASHEIGHT); + } + + if (const auto &container = item->getContainer()) { + if (container->getDepotLocker()) { + setFlag(TILESTATE_DEPOT); + } } if (item->hasProperty(CONST_PROP_SUPPORTHANGABLE)) { @@ -1637,7 +1684,7 @@ void Tile::setTileFlags(std::shared_ptr item) { } } -void Tile::resetTileFlags(std::shared_ptr item) { +void Tile::resetTileFlags(const std::shared_ptr &item) { const ItemType &it = Item::items[item->getID()]; if (it.floorChange != 0) { resetFlag(TILESTATE_FLOORCHANGE); @@ -1667,6 +1714,26 @@ void Tile::resetTileFlags(std::shared_ptr item) { resetFlag(TILESTATE_IMMOVABLENOFIELDBLOCKPATH); } + if (item->hasProperty(CONST_PROP_MOVEABLE) && !hasProperty(item, CONST_PROP_MOVEABLE)) { + resetFlag(TILESTATE_MOVEABLE); + } + + if (item->hasProperty(CONST_PROP_ISHORIZONTAL) && !hasProperty(item, CONST_PROP_ISHORIZONTAL)) { + resetFlag(TILESTATE_ISHORIZONTAL); + } + + if (item->hasProperty(CONST_PROP_ISVERTICAL) && !hasProperty(item, CONST_PROP_ISVERTICAL)) { + resetFlag(TILESTATE_ISVERTICAL); + } + + if (item->hasProperty(CONST_PROP_BLOCKPROJECTILE) && !hasProperty(item, CONST_PROP_BLOCKPROJECTILE)) { + resetFlag(TILESTATE_BLOCKPROJECTILE); + } + + if (item->hasProperty(CONST_PROP_HASHEIGHT) && !hasProperty(item, CONST_PROP_HASHEIGHT)) { + resetFlag(TILESTATE_HASHEIGHT); + } + if (item->getTeleport()) { resetFlag(TILESTATE_TELEPORT); } @@ -1687,9 +1754,10 @@ void Tile::resetTileFlags(std::shared_ptr item) { resetFlag(TILESTATE_BED); } - std::shared_ptr container = item->getContainer(); - if (container && container->getDepotLocker()) { - resetFlag(TILESTATE_DEPOT); + if (const auto &container = item->getContainer()) { + if (container->getDepotLocker()) { + resetFlag(TILESTATE_DEPOT); + } } if (item->hasProperty(CONST_PROP_SUPPORTHANGABLE)) { diff --git a/src/items/tile.hpp b/src/items/tile.hpp index de5dd4f0e43..c5471756159 100644 --- a/src/items/tile.hpp +++ b/src/items/tile.hpp @@ -140,6 +140,7 @@ class Tile : public Cylinder, public SharedObject { std::shared_ptr getTopCreature() const; std::shared_ptr getBottomCreature() const; std::shared_ptr getTopVisibleCreature(std::shared_ptr creature) const; + std::shared_ptr getBottomVisibleCreature(std::shared_ptr creature) const; std::shared_ptr getTopTopItem() const; std::shared_ptr getTopDownItem() const; @@ -210,7 +211,7 @@ class Tile : public Cylinder, public SharedObject { void addThing(std::shared_ptr thing) override final; void addThing(int32_t index, std::shared_ptr thing) override; - void updateTileFlags(std::shared_ptr item); + void updateTileFlags(const std::shared_ptr &item); void updateThing(std::shared_ptr thing, uint16_t itemId, uint32_t count) override final; void replaceThing(uint32_t index, std::shared_ptr thing) override final; @@ -244,8 +245,14 @@ class Tile : public Cylinder, public SharedObject { std::shared_ptr getGround() const { return ground; } - void setGround(std::shared_ptr item) { - ground = item; + void setGround(const std::shared_ptr &item) { + if (ground) { + resetTileFlags(ground); + } + + if (ground = item) { + setTileFlags(item); + } } private: @@ -254,8 +261,8 @@ class Tile : public Cylinder, public SharedObject { void onRemoveTileItem(const CreatureVector &spectators, const std::vector &oldStackPosVector, std::shared_ptr item); void onUpdateTile(const CreatureVector &spectators); - void setTileFlags(std::shared_ptr item); - void resetTileFlags(std::shared_ptr item); + void setTileFlags(const std::shared_ptr &item); + void resetTileFlags(const std::shared_ptr &item); bool hasHarmfulField() const; ReturnValue checkNpcCanWalkIntoTile() const; diff --git a/src/lua/functions/creatures/creature_functions.cpp b/src/lua/functions/creatures/creature_functions.cpp index 14d86f1e291..c5221a9c3ad 100644 --- a/src/lua/functions/creatures/creature_functions.cpp +++ b/src/lua/functions/creatures/creature_functions.cpp @@ -911,7 +911,7 @@ int CreatureFunctions::luaCreatureGetPathTo(lua_State* L) { fpp.clearSight = getBoolean(L, 6, fpp.clearSight); fpp.maxSearchDist = getNumber(L, 7, fpp.maxSearchDist); - std::forward_list dirList; + stdext::arraylist dirList(128); if (creature->getPathTo(position, dirList, fpp)) { lua_newtable(L); diff --git a/src/lua/functions/map/position_functions.cpp b/src/lua/functions/map/position_functions.cpp index 5cee3f2d847..3e5582a1cd2 100644 --- a/src/lua/functions/map/position_functions.cpp +++ b/src/lua/functions/map/position_functions.cpp @@ -97,7 +97,7 @@ int PositionFunctions::luaPositionGetPathTo(lua_State* L) { fpp.clearSight = getBoolean(L, 6, fpp.clearSight); fpp.maxSearchDist = getNumber(L, 7, fpp.maxSearchDist); - std::forward_list dirList; + stdext::arraylist dirList(128); if (g_game().map.getPathMatching(pos, dirList, FrozenPathingConditionCall(position), fpp)) { lua_newtable(L); diff --git a/src/map/map.cpp b/src/map/map.cpp index 53f7c98db38..72e867551be 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -17,6 +17,7 @@ #include "game/zones/zone.hpp" #include "io/iomap.hpp" #include "io/iomapserialize.hpp" +#include "game/scheduling/dispatcher.hpp" #include "map/spectators.hpp" void Map::load(const std::string &identifier, const Position &pos) { @@ -484,30 +485,39 @@ bool Map::isSightClear(const Position &fromPos, const Position &toPos, bool floo } std::shared_ptr Map::canWalkTo(const std::shared_ptr &creature, const Position &pos) { - int32_t walkCache = creature->getWalkCache(pos); + if (!creature || creature->isRemoved()) { + return nullptr; + } + + const int32_t walkCache = creature->getWalkCache(pos); + if (walkCache == 0) { return nullptr; - } else if (walkCache == 1) { + } + + if (walkCache == 1) { return getTile(pos.x, pos.y, pos.z); } // used for non-cached tiles - std::shared_ptr tile = getTile(pos.x, pos.y, pos.z); + const auto &tile = getTile(pos.x, pos.y, pos.z); if (creature->getTile() != tile) { if (!tile || tile->queryAdd(0, creature, 1, FLAG_PATHFINDING | FLAG_IGNOREFIELDDAMAGE) != RETURNVALUE_NOERROR) { return nullptr; } } + return tile; } -bool Map::getPathMatching(const std::shared_ptr &creature, std::forward_list &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { - Position pos = creature->getPosition(); - Position endPos; - - AStarNodes nodes(pos.x, pos.y); +bool Map::getPathMatching(const std::shared_ptr &creature, stdext::arraylist &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { + return getPathMatching(creature, creature->getPosition(), dirList, pathCondition, fpp); +} - int32_t bestMatch = 0; +bool Map::getPathMatching(const std::shared_ptr &creature, const Position &startPos, stdext::arraylist &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { + static int_fast32_t allNeighbors[8][2] = { + { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 } + }; static int_fast32_t dirNeighbors[8][5][2] = { { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 1, 1 }, { -1, 1 } }, @@ -519,186 +529,14 @@ bool Map::getPathMatching(const std::shared_ptr &creature, std::forwar { { 0, 1 }, { 1, 0 }, { 1, -1 }, { 1, 1 }, { -1, 1 } }, { { -1, 0 }, { 0, 1 }, { -1, -1 }, { 1, 1 }, { -1, 1 } } }; - static int_fast32_t allNeighbors[8][2] = { - { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 } - }; - const Position startPos = pos; - - AStarNode* found = nullptr; - while (fpp.maxSearchDist != 0 || nodes.getClosedNodes() < 100) { - AStarNode* n = nodes.getBestNode(); - if (!n) { - if (found) { - break; - } - return false; - } - - const int_fast32_t x = n->x; - const int_fast32_t y = n->y; - pos.x = x; - pos.y = y; - if (pathCondition(startPos, pos, fpp, bestMatch)) { - found = n; - endPos = pos; - if (bestMatch == 0) { - break; - } - } - - uint_fast32_t dirCount; - int_fast32_t* neighbors; - if (n->parent) { - const int_fast32_t offset_x = n->parent->x - x; - const int_fast32_t offset_y = n->parent->y - y; - if (offset_y == 0) { - if (offset_x == -1) { - neighbors = *dirNeighbors[DIRECTION_WEST]; - } else { - neighbors = *dirNeighbors[DIRECTION_EAST]; - } - } else if (!fpp.allowDiagonal || offset_x == 0) { - if (offset_y == -1) { - neighbors = *dirNeighbors[DIRECTION_NORTH]; - } else { - neighbors = *dirNeighbors[DIRECTION_SOUTH]; - } - } else if (offset_y == -1) { - if (offset_x == -1) { - neighbors = *dirNeighbors[DIRECTION_NORTHWEST]; - } else { - neighbors = *dirNeighbors[DIRECTION_NORTHEAST]; - } - } else if (offset_x == -1) { - neighbors = *dirNeighbors[DIRECTION_SOUTHWEST]; - } else { - neighbors = *dirNeighbors[DIRECTION_SOUTHEAST]; - } - dirCount = fpp.allowDiagonal ? 5 : 3; - } else { - dirCount = 8; - neighbors = *allNeighbors; - } - - const int_fast32_t f = n->f; - for (uint_fast32_t i = 0; i < dirCount; ++i) { - pos.x = x + *neighbors++; - pos.y = y + *neighbors++; - - if (fpp.maxSearchDist != 0 && (Position::getDistanceX(startPos, pos) > fpp.maxSearchDist || Position::getDistanceY(startPos, pos) > fpp.maxSearchDist)) { - continue; - } - - if (fpp.keepDistance && !pathCondition.isInRange(startPos, pos, fpp)) { - continue; - } - - std::shared_ptr tile; - AStarNode* neighborNode = nodes.getNodeByPosition(pos.x, pos.y); - if (neighborNode) { - tile = getTile(pos.x, pos.y, pos.z); - } else { - tile = canWalkTo(creature, pos); - if (!tile) { - continue; - } - } - - // The cost (g) for this neighbor - const int_fast32_t cost = AStarNodes::getMapWalkCost(n, pos); - const int_fast32_t extraCost = AStarNodes::getTileWalkCost(creature, tile); - const int_fast32_t newf = f + cost + extraCost; - - if (neighborNode) { - if (neighborNode->f <= newf) { - // The node on the closed/open list is cheaper than this one - continue; - } - - neighborNode->f = newf; - neighborNode->parent = n; - nodes.openNode(neighborNode); - } else { - // Does not exist in the open/closed list, create a std::make_shared - neighborNode = nodes.createOpenNode(n, pos.x, pos.y, newf); - if (!neighborNode) { - if (found) { - break; - } - return false; - } - } - } - - nodes.closeNode(n); - } - - if (!found) { - return false; - } - - int_fast32_t prevx = endPos.x; - int_fast32_t prevy = endPos.y; - - found = found->parent; - while (found) { - pos.x = found->x; - pos.y = found->y; - - int_fast32_t dx = pos.getX() - prevx; - int_fast32_t dy = pos.getY() - prevy; - - prevx = pos.x; - prevy = pos.y; - - if (dx == 1 && dy == 1) { - dirList.push_front(DIRECTION_NORTHWEST); - } else if (dx == -1 && dy == 1) { - dirList.push_front(DIRECTION_NORTHEAST); - } else if (dx == 1 && dy == -1) { - dirList.push_front(DIRECTION_SOUTHWEST); - } else if (dx == -1 && dy == -1) { - dirList.push_front(DIRECTION_SOUTHEAST); - } else if (dx == 1) { - dirList.push_front(DIRECTION_WEST); - } else if (dx == -1) { - dirList.push_front(DIRECTION_EAST); - } else if (dy == 1) { - dirList.push_front(DIRECTION_NORTH); - } else if (dy == -1) { - dirList.push_front(DIRECTION_SOUTH); - } - - found = found->parent; - } - return true; -} - -bool Map::getPathMatching(const Position &start, std::forward_list &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { - Position pos = start; + Position pos = startPos; Position endPos; AStarNodes nodes(pos.x, pos.y); int32_t bestMatch = 0; - static int_fast32_t dirNeighbors[8][5][2] = { - { { -1, 0 }, { 0, 1 }, { 1, 0 }, { 1, 1 }, { -1, 1 } }, - { { -1, 0 }, { 0, 1 }, { 0, -1 }, { -1, -1 }, { -1, 1 } }, - { { -1, 0 }, { 1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 } }, - { { 0, 1 }, { 1, 0 }, { 0, -1 }, { 1, -1 }, { 1, 1 } }, - { { 1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 }, { 1, 1 } }, - { { -1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 }, { -1, 1 } }, - { { 0, 1 }, { 1, 0 }, { 1, -1 }, { 1, 1 }, { -1, 1 } }, - { { -1, 0 }, { 0, 1 }, { -1, -1 }, { 1, 1 }, { -1, 1 } } - }; - static int_fast32_t allNeighbors[8][2] = { - { -1, 0 }, { 0, 1 }, { 1, 0 }, { 0, -1 }, { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 } - }; - - const Position startPos = pos; - AStarNode* found = nullptr; while (fpp.maxSearchDist != 0 || nodes.getClosedNodes() < 100) { AStarNode* n = nodes.getBestNode(); @@ -768,20 +606,18 @@ bool Map::getPathMatching(const Position &start, std::forward_list &d continue; } - std::shared_ptr tile; AStarNode* neighborNode = nodes.getNodeByPosition(pos.x, pos.y); - if (neighborNode) { - tile = getTile(pos.x, pos.y, pos.z); - } else { - tile = getTile(pos.x, pos.y, pos.z); - if (!tile || tile->hasFlag(TILESTATE_BLOCKSOLID)) { - continue; - } + + const bool withoutCreature = creature == nullptr; + const auto &tile = neighborNode || withoutCreature ? getTile(pos.x, pos.y, pos.z) : canWalkTo(creature, pos); + + if (!tile || !neighborNode && withoutCreature && tile->hasFlag(TILESTATE_BLOCKSOLID)) { + continue; } // The cost (g) for this neighbor - const int_fast32_t cost = AStarNodes::getMapWalkCost(n, pos, true); - const int_fast32_t extraCost = 0; + const int_fast32_t cost = AStarNodes::getMapWalkCost(n, pos, withoutCreature); + const int_fast32_t extraCost = AStarNodes::getTileWalkCost(creature, tile); const int_fast32_t newf = f + cost + extraCost; if (neighborNode) { @@ -820,8 +656,8 @@ bool Map::getPathMatching(const Position &start, std::forward_list &d pos.x = found->x; pos.y = found->y; - int_fast32_t dx = pos.getX() - prevx; - int_fast32_t dy = pos.getY() - prevy; + const int_fast32_t dx = pos.getX() - prevx; + const int_fast32_t dy = pos.getY() - prevy; prevx = pos.x; prevy = pos.y; diff --git a/src/map/map.hpp b/src/map/map.hpp index ac0211c7daf..d5ca9b2af14 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -123,9 +123,11 @@ class Map : protected MapCache { std::shared_ptr canWalkTo(const std::shared_ptr &creature, const Position &pos); - bool getPathMatching(const std::shared_ptr &creature, std::forward_list &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp); + bool getPathMatching(const std::shared_ptr &creature, stdext::arraylist &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp); - bool getPathMatching(const Position &startPos, std::forward_list &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp); + bool getPathMatching(const Position &startPos, stdext::arraylist &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp) { + return getPathMatching(nullptr, startPos, dirList, pathCondition, fpp); + } std::map waypoints; @@ -145,6 +147,8 @@ class Map : protected MapCache { Houses housesCustomMaps[50]; private: + bool getPathMatching(const std::shared_ptr &creature, const Position &startPos, stdext::arraylist &dirList, const FrozenPathingConditionCall &pathCondition, const FindPathParams &fpp); + /** * Set a single tile. */ diff --git a/src/map/utils/astarnodes.cpp b/src/map/utils/astarnodes.cpp index 36265dd7f12..e4cccd4e694 100644 --- a/src/map/utils/astarnodes.cpp +++ b/src/map/utils/astarnodes.cpp @@ -104,23 +104,28 @@ int_fast32_t AStarNodes::getMapWalkCost(AStarNode* node, const Position &neighbo return MAP_NORMALWALKCOST; } -int_fast32_t AStarNodes::getTileWalkCost(const std::shared_ptr &creature, std::shared_ptr tile) { +int_fast32_t AStarNodes::getTileWalkCost(const std::shared_ptr &creature, const std::shared_ptr &tile) { + if (!creature || !tile) { + return 0; + } + int_fast32_t cost = 0; if (tile->getTopVisibleCreature(creature) != nullptr) { // destroy creature cost cost += MAP_NORMALWALKCOST * 3; } - if (std::shared_ptr field = tile->getFieldItem()) { - CombatType_t combatType = field->getCombatType(); - std::shared_ptr monster = creature->getMonster(); + if (const auto &field = tile->getFieldItem()) { + const CombatType_t combatType = field->getCombatType(); + const auto &monster = creature->getMonster(); + if (!creature->isImmune(combatType) && !creature->hasCondition(Combat::DamageToConditionType(combatType)) && (monster && !monster->canWalkOnFieldType(combatType))) { cost += MAP_NORMALWALKCOST * 18; } /** * Make player try to avoid magic fields, when calculating pathing */ - std::shared_ptr player = creature->getPlayer(); + const auto &player = creature->getPlayer(); if (player && !field->isBlocking() && field->getDamage() != 0) { cost += MAP_NORMALWALKCOST * 18; } diff --git a/src/map/utils/astarnodes.hpp b/src/map/utils/astarnodes.hpp index eba694de218..26f33cdfcc4 100644 --- a/src/map/utils/astarnodes.hpp +++ b/src/map/utils/astarnodes.hpp @@ -31,7 +31,7 @@ class AStarNodes { AStarNode* getNodeByPosition(uint32_t x, uint32_t y); static int_fast32_t getMapWalkCost(AStarNode* node, const Position &neighborPos, bool preferDiagonal = false); - static int_fast32_t getTileWalkCost(const std::shared_ptr &creature, std::shared_ptr tile); + static int_fast32_t getTileWalkCost(const std::shared_ptr &creature, const std::shared_ptr &tile); private: static constexpr int32_t MAX_NODES = 512; diff --git a/src/server/network/protocol/protocolgame.cpp b/src/server/network/protocol/protocolgame.cpp index 6da9e94180e..e81933610a8 100644 --- a/src/server/network/protocol/protocolgame.cpp +++ b/src/server/network/protocol/protocolgame.cpp @@ -1555,7 +1555,7 @@ void ProtocolGame::parseAutoWalk(NetworkMessage &msg) { msg.skipBytes(numdirs); - std::forward_list path; + stdext::arraylist path; for (uint8_t i = 0; i < numdirs; ++i) { uint8_t rawdir = msg.getPreviousByte(); switch (rawdir) { @@ -1592,7 +1592,7 @@ void ProtocolGame::parseAutoWalk(NetworkMessage &msg) { return; } - addGameTask(&Game::playerAutoWalk, player->getID(), path); + addGameTask(&Game::playerAutoWalk, player->getID(), path.data()); } void ProtocolGame::parseSetOutfit(NetworkMessage &msg) { diff --git a/src/utils/arraylist.hpp b/src/utils/arraylist.hpp index ea803ab8cf0..94e05e2eb76 100644 --- a/src/utils/arraylist.hpp +++ b/src/utils/arraylist.hpp @@ -21,6 +21,25 @@ namespace stdext { template class arraylist { public: + arraylist() = default; + + explicit arraylist(size_t reserveSize) { + reserve(reserveSize); + } + + explicit arraylist(std::initializer_list _Ilist) { + backContainer.assign(_Ilist); + } + + arraylist &operator=(std::initializer_list _Ilist) { + backContainer.assign(_Ilist); + return *this; + } + + void assign(std::initializer_list _Ilist) { + backContainer.assign(_Ilist); + } + bool contains(const T &v) { update(); return std::ranges::find(backContainer, v) != backContainer.end(); @@ -128,7 +147,7 @@ namespace stdext { const auto &data() noexcept { update(); - return backContainer.data(); + return backContainer; } T &operator[](const size_t i) { From 57b4593b4029e9208bb0c5bcc3c0c9ec4d7236b2 Mon Sep 17 00:00:00 2001 From: Renato Machado Date: Thu, 2 Nov 2023 16:16:08 -0300 Subject: [PATCH 10/10] improve: use modern implementations to manage threads (#1756) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This updates the thread management constructs within the codebase. It shifts from using std::lock_guard to std::scoped_lock for managing mutexes, providing a more modern and safer scope-based locking mechanism. Additionally, it replaces std::condition_variable with std::atomic::wait, leveraging the more efficient and scalable waiting and notification system provided by atomics. Benefits: • std::scoped_lock is more flexible than std::lock_guard, allowing for handling multiple mutexes without the risk of deadlock. • std::atomic::wait introduces potential performance gains by utilizing a more lightweight synchronization mechanism compared to traditional condition variables. Impact: • These improvements are expected to enhance the safety and efficiency of concurrent operations. They modernize the codebase, aligning it with current best practices for C++ concurrency. --- src/canary_server.cpp | 16 +++++++--------- src/canary_server.hpp | 15 +++++++-------- src/creatures/players/management/ban.cpp | 2 +- src/game/game.cpp | 2 +- src/kv/kv.cpp | 4 ++-- src/lib/di/shared.hpp | 8 ++++---- src/server/network/connection/connection.cpp | 14 +++++++------- 7 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/canary_server.cpp b/src/canary_server.cpp index 6d833e0ce0b..7facada14d5 100644 --- a/src/canary_server.cpp +++ b/src/canary_server.cpp @@ -40,8 +40,7 @@ CanaryServer::CanaryServer( ) : logger(logger), rsa(rsa), - serviceManager(serviceManager), - loaderUniqueLock(loaderLock) { + serviceManager(serviceManager) { logInfos(); toggleForceCloseButton(); g_game().setGameState(GAME_STATE_STARTUP); @@ -93,10 +92,9 @@ int CanaryServer::run() { g_webhook().sendMessage("Server is now online", "Server has successfully started.", WEBHOOK_COLOR_ONLINE); - loaderDone = true; - loaderSignal.notify_all(); + loaderStatus = LoaderStatus::LOADED; } catch (FailedToInitializeCanary &err) { - loadFailed = true; + loaderStatus = LoaderStatus::FAILED; logger.error(err.what()); logger.error("The program will close after pressing the enter key..."); @@ -104,16 +102,16 @@ int CanaryServer::run() { if (isatty(STDIN_FILENO)) { getchar(); } - - loaderSignal.notify_all(); } + + loaderStatus.notify_one(); }, "CanaryServer::run" ); - loaderSignal.wait(loaderUniqueLock, [this] { return loaderDone || loadFailed; }); + loaderStatus.wait(LoaderStatus::LOADING); - if (loadFailed || !serviceManager.is_running()) { + if (loaderStatus == LoaderStatus::FAILED || !serviceManager.is_running()) { logger.error("No services running. The server is NOT online!"); shutdown(); return EXIT_FAILURE; diff --git a/src/canary_server.hpp b/src/canary_server.hpp index 6d75f64dc16..d9374309c4a 100644 --- a/src/canary_server.hpp +++ b/src/canary_server.hpp @@ -40,18 +40,17 @@ class CanaryServer { int run(); private: + enum class LoaderStatus : uint8_t { + LOADING, + LOADED, + FAILED + }; + RSA &rsa; Logger &logger; ServiceManager &serviceManager; - std::mutex loaderLock; - std::condition_variable loaderSignal; - std::condition_variable mapSignal; - std::unique_lock loaderUniqueLock; - std::string threadFailMsg; - - bool loaderDone = false; - bool loadFailed = false; + std::atomic loaderStatus = LoaderStatus::LOADING; void logInfos(); static void toggleForceCloseButton(); diff --git a/src/creatures/players/management/ban.cpp b/src/creatures/players/management/ban.cpp index 0c08fdc6f1e..3315836ebea 100644 --- a/src/creatures/players/management/ban.cpp +++ b/src/creatures/players/management/ban.cpp @@ -15,7 +15,7 @@ #include "utils/tools.hpp" bool Ban::acceptConnection(uint32_t clientIP) { - std::lock_guard lockClass(lock); + std::scoped_lock lockClass(lock); uint64_t currentTime = OTSYS_TIME(); diff --git a/src/game/game.cpp b/src/game/game.cpp index 417c89a8497..a01ac60bff8 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -9864,7 +9864,7 @@ void Game::playerRewardChestCollect(uint32_t playerId, const Position &pos, uint reward->setParent(playerRewardChest); } - std::lock_guard lock(player->quickLootMutex); + std::scoped_lock lock(player->quickLootMutex); ReturnValue returnValue = collectRewardChestItems(player, maxMoveItems); if (returnValue != RETURNVALUE_NOERROR) { diff --git a/src/kv/kv.cpp b/src/kv/kv.cpp index e5dbc974b76..0e2f4b2f836 100644 --- a/src/kv/kv.cpp +++ b/src/kv/kv.cpp @@ -27,7 +27,7 @@ void KVStore::set(const std::string &key, const std::initializer_list KVStore::get(const std::string &key, bool forceLoad /*= false */) { logger.debug("KVStore::get({})", key); - std::lock_guard lock(mutex_); + std::scoped_lock lock(mutex_); if (forceLoad || !store_.contains(key)) { auto value = load(key); if (value) { diff --git a/src/lib/di/shared.hpp b/src/lib/di/shared.hpp index e206cbd4b4c..c1e2f0c6743 100644 --- a/src/lib/di/shared.hpp +++ b/src/lib/di/shared.hpp @@ -29,9 +29,9 @@ namespace extension { #if !defined(BOOST_DI_NOT_THREAD_SAFE) //<> explicit scope(scope &&other) noexcept : - scope(std::move(other), std::lock_guard(other.mutex_)) { } + scope(std::move(other), std::scoped_lock(other.mutex_)) { } //<> - scope(scope &&other, const std::lock_guard &) noexcept : + scope(scope &&other, const std::scoped_lock &) noexcept : object_(std::move(other.object_)) { } #endif @@ -49,7 +49,7 @@ namespace extension { wrappers::shared create(const TProvider &provider) & { if (!object_) { #if !defined(BOOST_DI_NOT_THREAD_SAFE) - std::lock_guard lock(mutex_); + std::scoped_lock lock(mutex_); if (!object_) #endif object_ = std::shared_ptr { provider.get() }; @@ -65,7 +65,7 @@ namespace extension { auto &object = provider.cfg().template data(); if (!object) { #if !defined(BOOST_DI_NOT_THREAD_SAFE) - std::lock_guard lock(mutex_); + std::scoped_lock lock(mutex_); if (!object) #endif object = std::shared_ptr { provider.get() }; diff --git a/src/server/network/connection/connection.cpp b/src/server/network/connection/connection.cpp index 8e637c053ee..d2937756cf0 100644 --- a/src/server/network/connection/connection.cpp +++ b/src/server/network/connection/connection.cpp @@ -53,7 +53,7 @@ void Connection::close(bool force) { // any thread ConnectionManager::getInstance().releaseConnection(shared_from_this()); - std::lock_guard lockClass(connectionLock); + std::scoped_lock lockClass(connectionLock); ip = 0; if (connectionState == CONNECTION_STATE_CLOSED) { return; @@ -114,7 +114,7 @@ void Connection::accept(bool toggleParseHeader /* = true */) { } void Connection::parseProxyIdentification(const std::error_code &error) { - std::lock_guard lockClass(connectionLock); + std::scoped_lock lockClass(connectionLock); readTimer.cancel(); if (error) { @@ -167,7 +167,7 @@ void Connection::parseProxyIdentification(const std::error_code &error) { } void Connection::parseHeader(const std::error_code &error) { - std::lock_guard lockClass(connectionLock); + std::scoped_lock lockClass(connectionLock); readTimer.cancel(); if (error) { @@ -209,7 +209,7 @@ void Connection::parseHeader(const std::error_code &error) { } void Connection::parsePacket(const std::error_code &error) { - std::lock_guard lockClass(connectionLock); + std::scoped_lock lockClass(connectionLock); readTimer.cancel(); if (error) { @@ -275,7 +275,7 @@ void Connection::parsePacket(const std::error_code &error) { } void Connection::resumeWork() { - std::lock_guard lockClass(connectionLock); + std::scoped_lock lockClass(connectionLock); try { // Wait to the next packet @@ -287,7 +287,7 @@ void Connection::resumeWork() { } void Connection::send(const OutputMessage_ptr &outputMessage) { - std::lock_guard lockClass(connectionLock); + std::scoped_lock lockClass(connectionLock); if (connectionState == CONNECTION_STATE_CLOSED) { return; } @@ -324,7 +324,7 @@ uint32_t Connection::getIP() { return ip; } - std::lock_guard lockClass(connectionLock); + std::scoped_lock lockClass(connectionLock); // IP-address is expressed in network byte order std::error_code error;