diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp index baf93fb651a..cacb7ba54f6 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -270,18 +270,17 @@ void Creature::addEventWalk(bool firstStep) { return; } - g_dispatcher().context().tryAddEvent([ticks, self = getCreature()]() { + safeCall([this, ticks]() { // Take first step right away, but still queue the next if (ticks == 1) { - g_game().checkCreatureWalk(self->getID()); + g_game().checkCreatureWalk(getID()); } - self->eventWalk = g_dispatcher().scheduleEvent( + eventWalk = g_dispatcher().scheduleEvent( static_cast(ticks), - [creatureId = self->getID()] { g_game().checkCreatureWalk(creatureId); }, "Game::checkCreatureWalk" + [creatureId = getID()] { g_game().checkCreatureWalk(creatureId); }, "Game::checkCreatureWalk" ); - }, - "addEventWalk"); + }); } void Creature::stopEventWalk() { @@ -1082,7 +1081,7 @@ void Creature::getPathSearchParams(const std::shared_ptr &, FindPathPa void Creature::goToFollowCreature_async(std::function &&onComplete) { if (!hasAsyncTaskFlag(Pathfinder) && onComplete) { - g_dispatcher().context().addEvent(std::move(onComplete), "goToFollowCreature_async"); + g_dispatcher().addEvent(std::move(onComplete), "goToFollowCreature_async"); } setAsyncTaskFlag(Pathfinder, true); @@ -2002,3 +2001,16 @@ void Creature::sendAsyncTasks() { }, TaskGroup::WalkParallel); } + +void Creature::safeCall(std::function &&action) const { + if (g_dispatcher().context().isAsync()) { + g_dispatcher().addEvent([weak_self = std::weak_ptr(shared_from_this()), action = std::move(action)] { + if (weak_self.lock()) { + action(); + } + }, + g_dispatcher().context().getName()); + } else { + action(); + } +} diff --git a/src/creatures/creature.hpp b/src/creatures/creature.hpp index 46f628188e5..fd3c5bdce5e 100644 --- a/src/creatures/creature.hpp +++ b/src/creatures/creature.hpp @@ -848,6 +848,9 @@ class Creature : virtual public Thing, public SharedObject { virtual void onExecuteAsyncTasks() {}; + // This method maintains safety in asynchronous calls, avoiding competition between threads. + void safeCall(std::function &&action) const; + private: bool canFollowMaster() const; bool isLostSummon(); diff --git a/src/creatures/players/player.cpp b/src/creatures/players/player.cpp index dfdf467aa97..923b153a99a 100644 --- a/src/creatures/players/player.cpp +++ b/src/creatures/players/player.cpp @@ -3783,14 +3783,9 @@ void Player::addInFightTicks(bool pzlock /*= false*/) { updateImbuementTrackerStats(); - // this method can be called asynchronously. - g_dispatcher().context().tryAddEvent([self = std::weak_ptr(getPlayer())] { - if (const auto &player = self.lock()) { - const auto &condition = Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_INFIGHT, g_configManager().getNumber(PZ_LOCKED), 0); - player->addCondition(condition); - } - }, - "Player::addInFightTicks"); + safeCall([this] { + addCondition(Condition::createCondition(CONDITIONID_DEFAULT, CONDITION_INFIGHT, g_configManager().getNumber(PZ_LOCKED), 0)); + }); } void Player::setDailyReward(uint8_t reward) { diff --git a/src/game/game.cpp b/src/game/game.cpp index 49f8bf21d98..6e8a3c0eae5 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -6440,10 +6440,9 @@ void Game::addCreatureCheck(const std::shared_ptr &creature) { creature->inCheckCreaturesVector.store(true); - g_dispatcher().context().tryAddEvent([creature] { + creature->safeCall([this, creature] { checkCreatureLists[uniform_random(0, EVENT_CREATURECOUNT - 1)].emplace_back(creature); - }, - "addCreatureCheck"); + }); } void Game::removeCreatureCheck(const std::shared_ptr &creature) { diff --git a/src/game/scheduling/dispatcher.cpp b/src/game/scheduling/dispatcher.cpp index e716e9867cc..cb27cba23f1 100644 --- a/src/game/scheduling/dispatcher.cpp +++ b/src/game/scheduling/dispatcher.cpp @@ -251,22 +251,6 @@ void Dispatcher::stopEvent(uint64_t eventId) { } } -void DispatcherContext::addEvent(std::function &&f, std::string_view context) const { - g_dispatcher().addEvent(std::move(f), context); -} - -void DispatcherContext::tryAddEvent(std::function &&f, std::string_view context) const { - if (!f) { - return; - } - - if (isAsync()) { - g_dispatcher().addEvent(std::move(f), context); - } else { - f(); - } -} - bool DispatcherContext::isOn() { return OTSYS_TIME() != 0; } diff --git a/src/game/scheduling/dispatcher.hpp b/src/game/scheduling/dispatcher.hpp index 5e84d5d5fc7..d2c6819593c 100644 --- a/src/game/scheduling/dispatcher.hpp +++ b/src/game/scheduling/dispatcher.hpp @@ -55,12 +55,6 @@ struct DispatcherContext { return type; } - // postpone the event - void addEvent(std::function &&f, std::string_view context) const; - - // if the context is async, the event will be postponed, if not, it will be executed immediately. - void tryAddEvent(std::function &&f, std::string_view context) const; - private: void reset() { group = TaskGroup::ThreadPool; diff --git a/src/items/tile.cpp b/src/items/tile.cpp index f15e2bd8a94..4b7cb0fbac3 100644 --- a/src/items/tile.cpp +++ b/src/items/tile.cpp @@ -23,6 +23,7 @@ #include "lua/creature/movement.hpp" #include "map/spectators.hpp" #include "utils/tools.hpp" +#include "game/scheduling/dispatcher.hpp" auto real_nullptr_tile = std::make_shared(0xFFFF, 0xFFFF, 0xFF); const std::shared_ptr &Tile::nullptr_tile = real_nullptr_tile; @@ -1942,3 +1943,16 @@ void Tile::clearZones() { zones.erase(zone); } } + +void Tile::safeCall(std::function &&action) const { + if (g_dispatcher().context().isAsync()) { + g_dispatcher().addEvent([weak_self = std::weak_ptr(shared_from_this()), action = std::move(action)] { + if (weak_self.lock()) { + action(); + } + }, + g_dispatcher().context().getName()); + } else { + action(); + } +} diff --git a/src/items/tile.hpp b/src/items/tile.hpp index 4137b6e115d..ba3834d9914 100644 --- a/src/items/tile.hpp +++ b/src/items/tile.hpp @@ -259,6 +259,9 @@ class Tile : public Cylinder, public SharedObject { } } + // This method maintains safety in asynchronous calls, avoiding competition between threads. + void safeCall(std::function &&action) const; + private: void onAddTileItem(const std::shared_ptr &item); void onUpdateTileItem(const std::shared_ptr &oldItem, const ItemType &oldType, const std::shared_ptr &newItem, const ItemType &newType); diff --git a/src/map/mapcache.cpp b/src/map/mapcache.cpp index 01fd9da63d8..cf2f27c6ee7 100644 --- a/src/map/mapcache.cpp +++ b/src/map/mapcache.cpp @@ -146,15 +146,11 @@ std::shared_ptr MapCache::getOrCreateTileFromCache(const std::shared_ptrsetFlag(static_cast(cachedTile->flags)); - // add zone synchronously - g_dispatcher().context().tryAddEvent( - [tile, pos] { - for (const auto &zone : Zone::getZones(pos)) { - tile->addZone(zone); - } - }, - "Zone::getZones" - ); + tile->safeCall([tile, pos] { + for (const auto &zone : Zone::getZones(pos)) { + tile->addZone(zone); + } + }); floor->setTile(x, y, tile);