diff options
| author | Vincent-Michael <Vincent_Michael@gmx.de> | 2014-07-27 12:09:32 +0200 |
|---|---|---|
| committer | Vincent-Michael <Vincent_Michael@gmx.de> | 2014-07-27 12:09:32 +0200 |
| commit | 55eafa247d91e24bd59a369daa05b05d20334791 (patch) | |
| tree | d9cd3bfe6c7d63860916e8c1fdab28a009a33bb5 /src/server/game | |
| parent | 7a93e93c9f2afcef80034399ae6754abd1f77152 (diff) | |
| parent | 6699d969f3114b60109288caebee7b5d7d86b61e (diff) | |
Merge branch 'master' of github.com:TrinityCore/TrinityCore into 4.3.4
Conflicts:
src/server/authserver/Server/AuthSession.cpp
src/server/game/Server/WorldSocket.cpp
src/server/game/Server/WorldSocket.h
Diffstat (limited to 'src/server/game')
| -rw-r--r-- | src/server/game/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/server/game/Globals/ObjectAccessor.h | 4 | ||||
| -rwxr-xr-x | src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp | 19 | ||||
| -rw-r--r-- | src/server/game/Movement/Waypoints/WaypointManager.cpp | 20 | ||||
| -rw-r--r-- | src/server/game/Movement/Waypoints/WaypointManager.h | 12 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSession.cpp | 2 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSocket.cpp | 233 | ||||
| -rw-r--r-- | src/server/game/Server/WorldSocket.h | 29 | ||||
| -rw-r--r-- | src/server/game/World/World.cpp | 3 |
9 files changed, 151 insertions, 172 deletions
diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index 8e4ae9b5498..abb415e0f64 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -123,6 +123,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference ${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic ${CMAKE_SOURCE_DIR}/src/server/shared/Logging + ${CMAKE_SOURCE_DIR}/src/server/shared/Networking ${CMAKE_SOURCE_DIR}/src/server/shared/Packets ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h index d2331f14690..f466d8bd328 100644 --- a/src/server/game/Globals/ObjectAccessor.h +++ b/src/server/game/Globals/ObjectAccessor.h @@ -51,7 +51,7 @@ class HashMapHolder static void Insert(T* o) { - boost::shared_lock<boost::shared_mutex> lock(_lock); + boost::unique_lock<boost::shared_mutex> lock(_lock); _objectMap[o->GetGUID()] = o; } @@ -59,12 +59,14 @@ class HashMapHolder static void Remove(T* o) { boost::unique_lock<boost::shared_mutex> lock(_lock); + _objectMap.erase(o->GetGUID()); } static T* Find(uint64 guid) { boost::shared_lock<boost::shared_mutex> lock(_lock); + typename MapType::iterator itr = _objectMap.find(guid); return (itr != _objectMap.end()) ? itr->second : NULL; } diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp index aee8c497247..8cde9876ca1 100755 --- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp +++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp @@ -161,13 +161,28 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature) if (node->orientation && node->delay) init.SetFacing(node->orientation); - init.SetWalk(!node->run); + switch (node->move_type) + { + case WAYPOINT_MOVE_TYPE_LAND: + init.SetAnimation(Movement::ToGround); + break; + case WAYPOINT_MOVE_TYPE_TAKEOFF: + init.SetAnimation(Movement::ToFly); + break; + case WAYPOINT_MOVE_TYPE_RUN: + init.SetWalk(false); + break; + case WAYPOINT_MOVE_TYPE_WALK: + init.SetWalk(true); + break; + } + init.Launch(); //Call for creature group update if (creature->GetFormation() && creature->GetFormation()->getLeader() == creature) { - creature->SetWalk(!node->run); + creature->SetWalk(node->move_type != WAYPOINT_MOVE_TYPE_RUN); creature->GetFormation()->LeaderMoveTo(formationDest.x, formationDest.y, formationDest.z); } diff --git a/src/server/game/Movement/Waypoints/WaypointManager.cpp b/src/server/game/Movement/Waypoints/WaypointManager.cpp index f7cb147a148..2820c5dee17 100644 --- a/src/server/game/Movement/Waypoints/WaypointManager.cpp +++ b/src/server/game/Movement/Waypoints/WaypointManager.cpp @@ -42,7 +42,7 @@ void WaypointMgr::Load() uint32 oldMSTime = getMSTime(); // 0 1 2 3 4 5 6 7 8 9 - QueryResult result = WorldDatabase.Query("SELECT id, point, position_x, position_y, position_z, orientation, move_flag, delay, action, action_chance FROM waypoint_data ORDER BY id, point"); + QueryResult result = WorldDatabase.Query("SELECT id, point, position_x, position_y, position_z, orientation, move_type, delay, action, action_chance FROM waypoint_data ORDER BY id, point"); if (!result) { @@ -73,7 +73,14 @@ void WaypointMgr::Load() wp->y = y; wp->z = z; wp->orientation = o; - wp->run = fields[6].GetBool(); + wp->move_type = fields[6].GetUInt32(); + + if (wp->move_type >= WAYPOINT_MOVE_TYPE_MAX) + { + TC_LOG_ERROR("sql.sql", "Waypoint %u in waypoint_data has invalid move_type, ignoring", wp->id); + continue; + } + wp->delay = fields[7].GetUInt32(); wp->event_id = fields[8].GetUInt32(); wp->event_chance = fields[9].GetInt16(); @@ -126,7 +133,14 @@ void WaypointMgr::ReloadPath(uint32 id) wp->y = y; wp->z = z; wp->orientation = o; - wp->run = fields[5].GetBool(); + wp->move_type = fields[5].GetUInt32(); + + if (wp->move_type >= WAYPOINT_MOVE_TYPE_MAX) + { + TC_LOG_ERROR("sql.sql", "Waypoint %u in waypoint_data has invalid move_type, ignoring", wp->id); + continue; + } + wp->delay = fields[6].GetUInt32(); wp->event_id = fields[7].GetUInt32(); wp->event_chance = fields[8].GetUInt8(); diff --git a/src/server/game/Movement/Waypoints/WaypointManager.h b/src/server/game/Movement/Waypoints/WaypointManager.h index 385f4809729..8e5dd1f64c7 100644 --- a/src/server/game/Movement/Waypoints/WaypointManager.h +++ b/src/server/game/Movement/Waypoints/WaypointManager.h @@ -21,13 +21,23 @@ #include <vector> +enum WaypointMoveType +{ + WAYPOINT_MOVE_TYPE_WALK, + WAYPOINT_MOVE_TYPE_RUN, + WAYPOINT_MOVE_TYPE_LAND, + WAYPOINT_MOVE_TYPE_TAKEOFF, + + WAYPOINT_MOVE_TYPE_MAX +}; + struct WaypointData { uint32 id; float x, y, z, orientation; uint32 delay; uint32 event_id; - bool run; + uint32 move_type; uint8 event_chance; }; diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index cabb0ef0494..46411b35522 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -134,7 +134,7 @@ WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr if (sock) { - m_Address = sock->GetRemoteIpAddress(); + m_Address = sock->GetRemoteIpAddress().to_string(); ResetTimeOutTime(); LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = %u;", GetAccountId()); // One-time query } diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 7dad289d1e9..48c12f84870 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -16,8 +16,6 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <boost/asio/write.hpp> -#include <boost/asio/read_until.hpp> #include <memory> #include "WorldSocket.h" #include "ServerPktHeader.h" @@ -29,10 +27,9 @@ #include "BattlenetAccountMgr.h" using boost::asio::ip::tcp; -using boost::asio::streambuf; WorldSocket::WorldSocket(tcp::socket&& socket) - : _socket(std::move(socket)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr) + : Socket(std::move(socket), sizeof(ClientPktHeader)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr) { } @@ -63,135 +60,119 @@ void WorldSocket::HandleSendAuthSession() AsyncWrite(packet); } -void WorldSocket::AsyncReadHeader() +void WorldSocket::ReadHeaderHandler(boost::system::error_code error, size_t transferedBytes) { - auto self(shared_from_this()); - _socket.async_read_some(boost::asio::buffer(_readBuffer, sizeof(ClientPktHeader)), [this, self](boost::system::error_code error, size_t transferedBytes) + if (!error && transferedBytes == sizeof(ClientPktHeader)) { - if (!error && transferedBytes == sizeof(ClientPktHeader)) - { - ClientPktHeader* header = (ClientPktHeader*)&_readBuffer; - - if (_worldSession) - _authCrypt.DecryptRecv((uint8*)header, sizeof(ClientPktHeader)); + _authCrypt.DecryptRecv(GetReadBuffer(), sizeof(ClientPktHeader)); - EndianConvertReverse(header->size); - EndianConvert(header->cmd); + ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetReadBuffer()); + EndianConvertReverse(header->size); + EndianConvert(header->cmd); - AsyncReadData(header->size - sizeof(header->cmd)); - } - else - { - // _socket.is_open() till returns true even after calling close() - CloseSocket(); - } - }); + AsyncReadData(header->size - sizeof(header->cmd), sizeof(ClientPktHeader)); + } + else + CloseSocket(); } -void WorldSocket::AsyncReadData(size_t dataSize) +void WorldSocket::ReadDataHandler(boost::system::error_code error, size_t transferedBytes) { - auto self(shared_from_this()); - _socket.async_read_some(boost::asio::buffer(&_readBuffer[sizeof(ClientPktHeader)], dataSize), [this, dataSize, self](boost::system::error_code error, size_t transferedBytes) - { - if (!error && transferedBytes == dataSize) - { - ClientPktHeader* header = (ClientPktHeader*)&_readBuffer; + ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(GetReadBuffer()); - header->size -= sizeof(header->cmd); + if (!error && transferedBytes == (header->size - sizeof(header->cmd))) + { + header->size -= sizeof(header->cmd); - Opcodes opcode = PacketFilter::DropHighBytes(Opcodes(header->cmd)); + Opcodes opcode = PacketFilter::DropHighBytes(Opcodes(header->cmd)); - std::string opcodeName = GetOpcodeNameForLogging(opcode); + std::string opcodeName = GetOpcodeNameForLogging(opcode); - WorldPacket packet(opcode, header->size); + WorldPacket packet(opcode, header->size); - if (header->size > 0) - { - packet.resize(header->size); + if (header->size > 0) + { + packet.resize(header->size); - std::memcpy(packet.contents(), &_readBuffer[sizeof(ClientPktHeader)], header->size); - } + std::memcpy(packet.contents(), &(GetReadBuffer()[sizeof(ClientPktHeader)]), header->size); + } - if (sPacketLog->CanLogPacket()) - sPacketLog->LogPacket(packet, CLIENT_TO_SERVER); + if (sPacketLog->CanLogPacket()) + sPacketLog->LogPacket(packet, CLIENT_TO_SERVER); - TC_LOG_TRACE("network.opcode", "C->S: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress()).c_str(), GetOpcodeNameForLogging(opcode).c_str()); + TC_LOG_TRACE("network.opcode", "C->S: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(opcode).c_str()); - switch (opcode) - { - case CMSG_PING: - HandlePing(packet); - break; - case CMSG_AUTH_SESSION: - if (_worldSession) - { - TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from %s", _worldSession->GetPlayerInfo().c_str()); - break; - } - - sScriptMgr->OnPacketReceive(shared_from_this(), packet); - HandleAuthSession(packet); - break; - case CMSG_KEEP_ALIVE: - TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); - sScriptMgr->OnPacketReceive(shared_from_this(), packet); - break; - case CMSG_LOG_DISCONNECT: - packet.rfinish(); // contains uint32 disconnectReason; - TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); - sScriptMgr->OnPacketReceive(shared_from_this(), packet); - return; - // not an opcode, client sends string "WORLD OF WARCRAFT CONNECTION - CLIENT TO SERVER" without opcode - // first 4 bytes become the opcode (2 dropped) - case MSG_VERIFY_CONNECTIVITY: + switch (opcode) + { + case CMSG_PING: + HandlePing(packet); + break; + case CMSG_AUTH_SESSION: + if (_worldSession) { - TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); - sScriptMgr->OnPacketReceive(shared_from_this(), packet); - std::string str; - packet >> str; - if (str != "D OF WARCRAFT CONNECTION - CLIENT TO SERVER") - { - _socket.close(); - break; - } - - HandleSendAuthSession(); + TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from %s", _worldSession->GetPlayerInfo().c_str()); break; } - case CMSG_ENABLE_NAGLE: + + sScriptMgr->OnPacketReceive(shared_from_this(), packet); + HandleAuthSession(packet); + break; + case CMSG_KEEP_ALIVE: + TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); + sScriptMgr->OnPacketReceive(shared_from_this(), packet); + break; + case CMSG_LOG_DISCONNECT: + packet.rfinish(); // contains uint32 disconnectReason; + TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); + sScriptMgr->OnPacketReceive(shared_from_this(), packet); + return; + // not an opcode, client sends string "WORLD OF WARCRAFT CONNECTION - CLIENT TO SERVER" without opcode + // first 4 bytes become the opcode (2 dropped) + case MSG_VERIFY_CONNECTIVITY: + { + TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); + sScriptMgr->OnPacketReceive(shared_from_this(), packet); + std::string str; + packet >> str; + if (str != "D OF WARCRAFT CONNECTION - CLIENT TO SERVER") { - TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); - sScriptMgr->OnPacketReceive(shared_from_this(), packet); - if (_worldSession) - _worldSession->HandleEnableNagleAlgorithm(); + CloseSocket(); break; } - default: + + HandleSendAuthSession(); + break; + } + case CMSG_ENABLE_NAGLE: + { + TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); + sScriptMgr->OnPacketReceive(shared_from_this(), packet); + if (_worldSession) + _worldSession->HandleEnableNagleAlgorithm(); + break; + } + default: + { + if (!_worldSession) { - if (!_worldSession) - { - TC_LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = %u", uint32(opcode)); - break; - } - - // Our Idle timer will reset on any non PING opcodes. - // Catches people idling on the login screen and any lingering ingame connections. - _worldSession->ResetTimeOutTime(); - - // Copy the packet to the heap before enqueuing - _worldSession->QueuePacket(new WorldPacket(packet)); + TC_LOG_ERROR("network.opcode", "ProcessIncoming: Client not authed opcode = %u", uint32(opcode)); break; } - } - AsyncReadHeader(); - } - else - { - // _socket.is_open() till returns true even after calling close() - CloseSocket(); + // Our Idle timer will reset on any non PING opcodes. + // Catches people idling on the login screen and any lingering ingame connections. + _worldSession->ResetTimeOutTime(); + + // Copy the packet to the heap before enqueuing + _worldSession->QueuePacket(new WorldPacket(packet)); + break; + } } - }); + + AsyncReadHeader(); + } + else + CloseSocket(); } void WorldSocket::AsyncWrite(WorldPacket const& packet) @@ -207,7 +188,7 @@ void WorldSocket::AsyncWrite(WorldPacket const& packet) pkt = &buff; } - TC_LOG_TRACE("network.opcode", "S->C: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress()).c_str(), GetOpcodeNameForLogging(pkt->GetOpcode()).c_str()); + TC_LOG_TRACE("network.opcode", "S->C: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(pkt->GetOpcode()).c_str()); ServerPktHeader header(pkt->size() + 2, pkt->GetOpcode()); @@ -228,25 +209,6 @@ void WorldSocket::AsyncWrite(WorldPacket const& packet) AsyncWrite(_writeQueue.front()); } -void WorldSocket::AsyncWrite(std::vector<uint8> const& data) -{ - auto self(shared_from_this()); - boost::asio::async_write(_socket, boost::asio::buffer(data), [this, self](boost::system::error_code error, std::size_t /*length*/) - { - if (!error) - { - std::lock_guard<std::mutex> deleteGuard(_writeLock); - - _writeQueue.pop(); - - if (!_writeQueue.empty()) - AsyncWrite(_writeQueue.front()); - } - else - CloseSocket(); - }); -} - void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) { uint8 digest[20]; @@ -306,7 +268,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) if (sWorld->IsClosed()) { SendAuthResponseError(AUTH_REJECT); - TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteIpAddress().c_str()); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: World closed, denying client (%s).", GetRemoteIpAddress().to_string().c_str()); return; } @@ -347,7 +309,7 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) expansion = world_expansion; // For hook purposes, we get Remoteaddress at this point. - std::string address = GetRemoteIpAddress(); + std::string address = GetRemoteIpAddress().to_string(); // As we don't know if attempted login process by ip works, we update last_attempt_ip right away stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_ATTEMPT_IP); @@ -550,7 +512,7 @@ void WorldSocket::HandlePing(WorldPacket& recvPacket) if (_worldSession && !_worldSession->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_OVERSPEED_PING)) { TC_LOG_ERROR("network", "WorldSocket::HandlePing: %s kicked for over-speed pings (address: %s)", - _worldSession->GetPlayerInfo().c_str(), GetRemoteIpAddress().c_str()); + _worldSession->GetPlayerInfo().c_str(), GetRemoteIpAddress().to_string().c_str()); CloseSocket(); return; @@ -568,8 +530,7 @@ void WorldSocket::HandlePing(WorldPacket& recvPacket) } else { - TC_LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = %s", - GetRemoteIpAddress().c_str()); + TC_LOG_ERROR("network", "WorldSocket::HandlePing: peer sent CMSG_PING, but is not authenticated or got recently kicked, address = %s", GetRemoteIpAddress().to_string().c_str()); CloseSocket(); return; @@ -579,13 +540,3 @@ void WorldSocket::HandlePing(WorldPacket& recvPacket) packet << ping; return AsyncWrite(packet); } - -void WorldSocket::CloseSocket() -{ - boost::system::error_code socketError; - _socket.close(socketError); - if (socketError) - TC_LOG_DEBUG("network", "WorldSocket::CloseSocket: Player '%s' (%s) errored when closing socket: %i (%s)", - _worldSession ? _worldSession->GetPlayerInfo().c_str() : "unknown", GetRemoteIpAddress().c_str(), - socketError.value(), socketError.message().c_str()); -} diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 085ee98b00d..ca50b46efb0 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -21,14 +21,12 @@ #include "Common.h" #include "WorldPacketCrypt.h" +#include "Socket.h" #include "Util.h" #include "WorldPacket.h" #include "WorldSession.h" -#include <memory> #include <chrono> -#include <mutex> #include <boost/asio/ip/tcp.hpp> -#include <boost/asio/streambuf.hpp> using boost::asio::ip::tcp; @@ -42,7 +40,7 @@ struct ClientPktHeader #pragma pack(pop) -class WorldSocket : public std::enable_shared_from_this<WorldSocket> +class WorldSocket : public Socket<WorldSocket> { public: WorldSocket(tcp::socket&& socket); @@ -50,15 +48,14 @@ public: WorldSocket(WorldSocket const& right) = delete; WorldSocket& operator=(WorldSocket const& right) = delete; - void Start(); - - std::string GetRemoteIpAddress() const { return _socket.remote_endpoint().address().to_string(); }; - uint16 GetRemotePort() const { return _socket.remote_endpoint().port(); } - - void CloseSocket(); - bool IsOpen() const { return _socket.is_open(); } + void Start() override; void AsyncWrite(WorldPacket const& packet); + using Socket<WorldSocket>::AsyncWrite; + +protected: + void ReadHeaderHandler(boost::system::error_code error, size_t transferedBytes) override; + void ReadDataHandler(boost::system::error_code error, size_t transferedBytes) override; private: void HandleSendAuthSession(); @@ -67,16 +64,6 @@ private: void HandlePing(WorldPacket& recvPacket); - void AsyncReadHeader(); - void AsyncReadData(size_t dataSize); - void AsyncWrite(std::vector<uint8> const& data); - - tcp::socket _socket; - - char _readBuffer[4096]; - std::mutex _writeLock; - std::queue<std::vector<uint8> > _writeQueue; - uint32 _authSeed; WorldPacketCrypt _authCrypt; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index e5dc9ba1a4c..14591db9eb6 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2778,8 +2778,7 @@ void World::UpdateRealmCharCount(uint32 accountId) { PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_COUNT); stmt->setUInt32(0, accountId); - PreparedQueryResultFuture result = CharacterDatabase.AsyncQuery(stmt); - m_realmCharCallbacks.push_back(std::move(result)); + m_realmCharCallbacks.push_back(CharacterDatabase.AsyncQuery(stmt)); } void World::_UpdateRealmCharCount(PreparedQueryResult resultCharCount) |
