/// Heartbeat for the World void WorldRunnable::run() { uint32 realCurrTime = 0; uint32 realPrevTime = getMSTime(); uint32 prevSleepTime = 0; // used for balanced full tick time length near WORLD_SLEEP_CONST sScriptMgr->OnStartup(); ///- While we have not World::m_stopEvent, update the world while (!World::IsStopped()) { ++World::m_worldLoopCounter; realCurrTime = getMSTime(); uint32 diff = getMSTimeDiff(realPrevTime,realCurrTime); sWorld->Update( diff ); realPrevTime = realCurrTime; // diff (D0) include time of previous sleep (d0) + tick time (t0) // we want that next d1 + t1 == WORLD_SLEEP_CONST // we can't know next t1 and then can use (t0 + d1) == WORLD_SLEEP_CONST requirement // d1 = WORLD_SLEEP_CONST - t0 = WORLD_SLEEP_CONST - (D0 - d0) = WORLD_SLEEP_CONST + d0 - D0 if (diff <= WORLD_SLEEP_CONST+prevSleepTime) { prevSleepTime = WORLD_SLEEP_CONST+prevSleepTime-diff; ACE_Based::Thread::Sleep(prevSleepTime); } else prevSleepTime = 0; #ifdef _WIN32 if (m_ServiceStatus == 0) World::StopNow(SHUTDOWN_EXIT_CODE); while (m_ServiceStatus == 2) Sleep(1000); #endif } sScriptMgr->OnShutdown(); sWorld->KickAll(); // save and kick all players sWorld->UpdateSessions( 1 ); // real players unload required UpdateSessions call // unload battleground templates before different singletons destroyed sBattlegroundMgr->DeleteAllBattlegrounds(); sWorldSocketMgr->StopNetwork(); sObjectAccessor->UnloadAll(); // unload 'i_player2corpse' storage and remove from world sMapMgr->UnloadAll(); // unload all grids (including locked in memory) }
uint32 WorldTimer::tick() { // save previous world tick time m_iPrevTime = m_iTime; // get the new one and don't forget to persist current system time in m_SystemTickTime m_iTime = WorldTimer::getMSTime_internal(true); // return tick diff return getMSTimeDiff(m_iPrevTime, m_iTime); }
void SetData(uint32 id, uint32 value) { if (id == 1337) { if (lastShatterMSTime) if (getMSTimeDiff(lastShatterMSTime, World::GetGameTimeMS()) <= 5000) bShattered = true; lastShatterMSTime = World::GetGameTimeMS(); } }
/// Heartbeat for the World void WorldRunnable::run() { ///- Init new SQL thread for the world database WorldDatabase.ThreadStart(); // let thread do safe mySQL requests (one connection call enough) sWorld.InitResultQueue(); uint32 realCurrTime = 0; uint32 realPrevTime = getMSTime(); uint32 prevSleepTime = 0; // used for balanced full tick time length near WORLD_SLEEP_CONST ///- While we have not World::m_stopEvent, update the world while (!World::IsStopped()) { ++World::m_worldLoopCounter; realCurrTime = getMSTime(); uint32 diff = getMSTimeDiff(realPrevTime,realCurrTime); sWorld.Update( diff ); realPrevTime = realCurrTime; // diff (D0) include time of previous sleep (d0) + tick time (t0) // we want that next d1 + t1 == WORLD_SLEEP_CONST // we can't know next t1 and then can use (t0 + d1) == WORLD_SLEEP_CONST requirement // d1 = WORLD_SLEEP_CONST - t0 = WORLD_SLEEP_CONST - (D0 - d0) = WORLD_SLEEP_CONST + d0 - D0 if (diff <= WORLD_SLEEP_CONST+prevSleepTime) { prevSleepTime = WORLD_SLEEP_CONST+prevSleepTime-diff; ACE_Based::Thread::Sleep(prevSleepTime); } else prevSleepTime = 0; #ifdef _WIN32 if (m_ServiceStatus == 0) World::StopNow(SHUTDOWN_EXIT_CODE); while (m_ServiceStatus == 2) Sleep(1000); #endif } sWorld.KickAll(); // save and kick all players sWorld.UpdateSessions( 1 ); // real players unload required UpdateSessions call // unload battleground templates before different singletons destroyed sBattleGroundMgr.DeleteAllBattleGrounds(); sWorldSocketMgr->StopNetwork(); sMapMgr.UnloadAll(); // unload all grids (including locked in memory) ///- End the database thread WorldDatabase.ThreadEnd(); // free mySQL thread resources }
bool MySQLConnection::_Query(PreparedStatement* stmt, MYSQL_RES **pResult, uint64* pRowCount, uint32* pFieldCount) { if (!m_Mysql) return false; uint32 index = stmt->m_index; MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index); ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query m_mStmt->m_stmt = stmt; // Cross reference them for debug output stmt->BindParameters(m_mStmt); MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT(); MYSQL_BIND* msql_BIND = m_mStmt->GetBind(); uint32 _s = getMSTime(); if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) { uint32 lErrno = mysql_errno(m_Mysql); TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString().c_str(), lErrno, mysql_stmt_error(msql_STMT)); if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) return _Query(stmt, pResult, pRowCount, pFieldCount); // Try again m_mStmt->ClearParameters(); return false; } if (mysql_stmt_execute(msql_STMT)) { uint32 lErrno = mysql_errno(m_Mysql); TC_LOG_ERROR("sql.sql", "SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString().c_str(), lErrno, mysql_stmt_error(msql_STMT)); if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) return _Query(stmt, pResult, pRowCount, pFieldCount); // Try again m_mStmt->ClearParameters(); return false; } TC_LOG_DEBUG("sql.sql", "[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString().c_str()); m_mStmt->ClearParameters(); *pResult = mysql_stmt_result_metadata(msql_STMT); *pRowCount = mysql_stmt_num_rows(msql_STMT); *pFieldCount = mysql_stmt_field_count(msql_STMT); return true; }
bool MySQLConnection::Execute(PreparedStatement* stmt) { if (!m_Mysql) return false; uint32 index = stmt->m_index; { MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index); ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query m_mStmt->m_stmt = stmt; // Cross reference them for debug output stmt->m_stmt = m_mStmt; // TODO: Cleaner way stmt->BindParameters(); MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT(); MYSQL_BIND* msql_BIND = m_mStmt->GetBind(); uint32 _s = 0; if (sLog->GetSQLDriverQueryLogging()) _s = getMSTime(); if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) { uint32 lErrno = mysql_errno(m_Mysql); sLog->outSQLDriver("SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT)); if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) return Execute(stmt); // Try again m_mStmt->ClearParameters(); return false; } if (mysql_stmt_execute(msql_STMT)) { uint32 lErrno = mysql_errno(m_Mysql); sLog->outSQLDriver("SQL(p): %s\n [ERROR]: [%u] %s", m_mStmt->getQueryString(m_queries[index].first).c_str(), lErrno, mysql_stmt_error(msql_STMT)); if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) return Execute(stmt); // Try again m_mStmt->ClearParameters(); return false; } if (sLog->GetSQLDriverQueryLogging()) sLog->outSQLDriver("[%u ms] SQL(p): %s", getMSTimeDiff(_s, getMSTime()), m_mStmt->getQueryString(m_queries[index].first).c_str()); m_mStmt->ClearParameters(); return true; } }
void AnticheatMgr::SpeedHackDetection(Player* player,MovementInfo movementInfo) { // Ignorar spell 56640 if (player->HasAura(56640)) return; if ((sWorld->getIntConfig(CONFIG_ANTICHEAT_DETECTIONS_ENABLED) & SPEED_HACK_DETECTION) == 0) return; uint32 key = player->GetGUIDLow(); // We also must check the map because the movementFlag can be modified by the client. // If we just check the flag, they could always add that flag and always skip the speed hacking detection. // 369 == DEEPRUN TRAM && 607 == SoTA // if (m_Players[key].GetLastMovementInfo().HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && player->GetMapId() == 369 || player->GetMapId() == 607) // Para dejarlo como estaba borrar el de abajo y descomentar el anterior if (m_Players[key].GetLastMovementInfo().HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT)) return; uint32 distance2D = (uint32)movementInfo.pos.GetExactDist2d(&m_Players[key].GetLastMovementInfo().pos); uint8 moveType = 0; // we need to know HOW is the player moving // TO-DO: Should we check the incoming movement flags? if (player->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING)) moveType = MOVE_SWIM; else if (player->IsFlying()) moveType = MOVE_FLIGHT; else if (player->HasUnitMovementFlag(MOVEMENTFLAG_WALKING)) moveType = MOVE_WALK; else moveType = MOVE_RUN; // how many yards the player can do in one sec. uint32 speedRate = (uint32)(player->GetSpeed(UnitMoveType(moveType)) + movementInfo.j_xyspeed); // how long the player took to move to here. uint32 timeDiff = getMSTimeDiff(m_Players[key].GetLastMovementInfo().time,movementInfo.time); if (!timeDiff) timeDiff = 1; // this is the distance doable by the player in 1 sec, using the time done to move to this point. uint32 clientSpeedRate = distance2D * 1000 / timeDiff; // we did the (uint32) cast to accept a margin of tolerance if (clientSpeedRate > speedRate) { BuildReport(player,SPEED_HACK_REPORT); sLog->outError("AnticheatMgr:: Speed-Hack detected player GUID (low) %u",player->GetGUIDLow()); } }
QueryResult* DatabaseMysql::Query(const char *sql) { if (!mMysql) return 0; MYSQL_RES *result = 0; uint64 rowCount = 0; uint32 fieldCount = 0; { // guarded block for thread-safe mySQL request ZThread::Guard<ZThread::FastMutex> query_connection_guard(mMutex); #ifdef MANGOS_DEBUG uint32 _s = getMSTime(); #endif if(mysql_query(mMysql, sql)) { sLog.outErrorDb( "SQL: %s", sql ); sLog.outErrorDb("query ERROR: %s", mysql_error(mMysql)); return NULL; } else { #ifdef MANGOS_DEBUG sLog.outDebug("[%u ms] SQL: %s", getMSTimeDiff(_s,getMSTime()), sql ); #endif } result = mysql_store_result(mMysql); rowCount = mysql_affected_rows(mMysql); fieldCount = mysql_field_count(mMysql); // end guarded block } if (!result ) return NULL; if (!rowCount) { mysql_free_result(result); return NULL; } QueryResultMysql *queryResult = new QueryResultMysql(result, rowCount, fieldCount); queryResult->NextRow(); return queryResult; }
void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recv_data*/) { // empty opcode sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Battleground status"); WorldPacket data; // we must update all queues here Battleground* bg = NULL; for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) { BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(i); if (!bgQueueTypeId) continue; BattlegroundTypeId bgTypeId = BattlegroundMgr::BGTemplateId(bgQueueTypeId); //we are sending update to player about queue - he can be invited there! //get GroupQueueInfo for queue status BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; GroupQueueInfo ginfo; if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) continue; if (ginfo.IsInvitedToBGInstanceGUID) { bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); if (!bg) continue; uint32 remainingTime = getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime); // send status invited to Battleground sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0); SendPacket(&data); } else { bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) continue; // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); if (!bracketEntry) continue; uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, bracketEntry->GetBracketId()); // send status in Battleground Queue sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, getMSTime())); SendPacket(&data); } } }
bool MySQLConnection::Execute(PreparedStatement* stmt) { if (!m_Mysql) return false; uint32 index = stmt->m_index; { // guarded block for thread-safe mySQL request ACE_Guard<ACE_Thread_Mutex> query_connection_guard(m_Mutex); MySQLPreparedStatement* m_mStmt = GetPreparedStatement(index); ASSERT(m_mStmt); // Can only be null if preparation failed, server side error or bad query m_mStmt->m_stmt = stmt; // Cross reference them for debug output stmt->m_stmt = m_mStmt; // TODO: Cleaner way stmt->BindParameters(); MYSQL_STMT* msql_STMT = m_mStmt->GetSTMT(); MYSQL_BIND* msql_BIND = m_mStmt->GetBind(); #ifdef SQLQUERY_LOG uint32 _s = getMSTime(); #endif if (mysql_stmt_bind_param(msql_STMT, msql_BIND)) { sLog.outSQLDriver("[ERROR]: PreparedStatement (id: %u) error binding params: %s", index, mysql_stmt_error(msql_STMT)); m_mStmt->ClearParameters(); return false; } if (mysql_stmt_execute(msql_STMT)) { sLog.outSQLDriver("[ERROR]: PreparedStatement (id: %u) error executing: %s", index, mysql_stmt_error(msql_STMT)); m_mStmt->ClearParameters(); return false; } else { #ifdef SQLQUERY_LOG sLog.outSQLDriver("[%u ms] Prepared SQL: %u", getMSTimeDiff(_s, getMSTime()), index); #endif m_mStmt->ClearParameters(); return true; } } }
void run(void) { if(!_delaytime) return; sLog.outString("Starting up anti-freeze thread (%u seconds max stuck time)...",_delaytime/1000); m_loops = 0; w_loops = 0; m_lastchange = 0; w_lastchange = 0; while(!World::IsStopped()) { ACE_Based::Thread::Sleep(1000); uint32 curtime = getMSTime(); //DEBUG_LOG("anti-freeze: time=%u, counters=[%u; %u]",curtime,Master::m_masterLoopCounter,World::m_worldLoopCounter); // There is no Master anymore // TODO: clear the rest of the code // // normal work // if(m_loops != Master::m_masterLoopCounter) // { // m_lastchange = curtime; // m_loops = Master::m_masterLoopCounter; // } // // possible freeze // else if(getMSTimeDiff(m_lastchange,curtime) > _delaytime) // { // sLog.outError("Main/Sockets Thread hangs, kicking out server!"); // *((uint32 volatile*)NULL) = 0; // bang crash // } // normal work if(w_loops != World::m_worldLoopCounter) { w_lastchange = curtime; w_loops = World::m_worldLoopCounter; } // possible freeze else if(getMSTimeDiff(w_lastchange,curtime) > _delaytime) { sLog.outError("World Thread hangs, kicking out server!"); *((uint32 volatile*)NULL) = 0; // bang crash } } sLog.outString("Anti-freeze thread exiting without problems."); }
bool MySQLConnection::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount) { if (!m_Mysql) return false; { uint32 _s = 0; if (sLog->GetSQLDriverQueryLogging()) _s = getMSTime(); if (mysql_query(m_Mysql, sql)) { uint32 lErrno = mysql_errno(m_Mysql); sLog->outSQLDriver("SQL: %s", sql); sLog->outSQLDriver("ERROR: [%u] %s", lErrno, mysql_error(m_Mysql)); if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) return _Query(sql, pResult, pFields, pRowCount, pFieldCount); // We try again return false; } else if (sLog->GetSQLDriverQueryLogging()) { sLog->outSQLDriver("[%u ms] SQL: %s", getMSTimeDiff(_s,getMSTime()), sql); } *pResult = mysql_store_result(m_Mysql); *pRowCount = mysql_affected_rows(m_Mysql); *pFieldCount = mysql_field_count(m_Mysql); } if (!*pResult ) return false; if (!*pRowCount) { mysql_free_result(*pResult); return false; } *pFields = mysql_fetch_fields(*pResult); return true; }
bool MySQLConnection::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount) { if (!m_Mysql) return false; { uint32 _s = getMSTime(); if (mysql_query(m_Mysql, sql)) { uint32 lErrno = mysql_errno(m_Mysql); sLog->outInfo(LOG_FILTER_SQL, "SQL: %s", sql); sLog->outError(LOG_FILTER_SQL, "[%u] %s", lErrno, mysql_error(m_Mysql)); if (lErrno == ER_BAD_FIELD_ERROR || lErrno == ER_NO_SUCH_TABLE || lErrno == ER_PARSE_ERROR) sLog->outError(LOG_FILTER_SQL, "TrinityCore TRANSFERT ERROR %u : query : %s", lErrno, sql); if (_HandleMySQLErrno(lErrno)) // If it returns true, an error was handled successfully (i.e. reconnection) return _Query(sql, pResult, pFields, pRowCount, pFieldCount); // We try again return false; } else sLog->outDebug(LOG_FILTER_SQL, "[%u ms] SQL: %s", getMSTimeDiff(_s, getMSTime()), sql); *pResult = mysql_store_result(m_Mysql); *pRowCount = mysql_affected_rows(m_Mysql); *pFieldCount = mysql_field_count(m_Mysql); } if (!*pResult ) return false; if (!*pRowCount) { mysql_free_result(*pResult); return false; } *pFields = mysql_fetch_fields(*pResult); return true; }
void AnticheatMgr::SpeedHackDetection(Player* player,MovementInfo movementInfo) { uint32 key = player->GetGUIDLow(); // We also must check the map because the movementFlag can be modified by the client. // If we just check the flag, they could always add that flag and always skip the speed hacking detection. // 369 == DEEPRUN TRAM if (m_Players[key].GetLastMovementInfo().HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT) || m_Players[key].GetLastMovementInfo().HasMovementFlag(MOVEMENTFLAG_FALLING) || player->GetMapId() == 369) return; uint32 distance2D = (uint32)movementInfo.pos.GetExactDist2d(&m_Players[key].GetLastMovementInfo().pos); uint8 moveType = 0; // we need to know HOW is the player moving // TO-DO: Should we check the incoming movement flags? if (player->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING)) moveType = MOVE_SWIM; else if (player->IsFlying()) moveType = MOVE_FLIGHT; else if (player->HasUnitMovementFlag(MOVEMENTFLAG_WALKING)) moveType = MOVE_WALK; else moveType = MOVE_RUN; // how many yards the player can do in one sec. uint32 speedRate = (uint32)(player->GetSpeed(UnitMoveType(moveType)) + movementInfo.jump.xyspeed); // how long the player took to move to here. uint32 timeDiff = getMSTimeDiff(m_Players[key].GetLastMovementInfo().time,movementInfo.time); if (!timeDiff) timeDiff = 1; // this is the distance doable by the player in 1 sec, using the time done to move to this point. uint32 clientSpeedRate = distance2D * 1000 / timeDiff; // we did the (uint32) cast to accept a margin of tolerance if (clientSpeedRate > speedRate) { Report(player, SPEED_HACK); } }
bool DatabaseMysql::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount) { if (!mMysql) return 0; { // guarded block for thread-safe mySQL request ACE_Guard<ACE_Thread_Mutex> query_connection_guard(mMutex); #ifdef MANGOS_DEBUG uint32 _s = getMSTime(); #endif if(mysql_query(mMysql, sql)) { sLog.outErrorDb( "SQL: %s", sql ); sLog.outErrorDb("query ERROR: %s", mysql_error(mMysql)); return false; } else { #ifdef MANGOS_DEBUG sLog.outDebug("[%u ms] SQL: %s", getMSTimeDiff(_s,getMSTime()), sql ); #endif } *pResult = mysql_store_result(mMysql); *pRowCount = mysql_affected_rows(mMysql); *pFieldCount = mysql_field_count(mMysql); // end guarded block } if (!*pResult ) return false; if (!*pRowCount) { mysql_free_result(*pResult); return false; } *pFields = mysql_fetch_fields(*pResult); return true; }
static bool HandleMmapTestArea(ChatHandler* handler, const char* args) { float radius = 40.0f; handler->ExtractFloat((char**)&args, radius); CellPair pair(Strawberry::ComputeCellPair(handler->GetSession()->GetPlayer()->GetPositionX(), handler->GetSession()->GetPlayer()->GetPositionY())); Cell cell(pair); cell.SetNoCreate(); std::list<Creature*> creatureList; Creature* const creature = handler->getSelectedCreature(); Strawberry::AnyUnitInObjectRangeCheck go_check(handler->GetSession()->GetPlayer(), radius); Strawberry::CreatureListSearcher<Strawberry::AnyUnitInObjectRangeCheck> go_search(creature, creatureList, go_check); TypeContainerVisitor<Strawberry::CreatureListSearcher<Strawberry::AnyUnitInObjectRangeCheck>, GridTypeMapContainer> go_visit(go_search); // Get Creatures cell.Visit(pair, go_visit, *(handler->GetSession()->GetPlayer()->GetMap()), *(handler->GetSession()->GetPlayer()), radius); if (!creatureList.empty()) { handler->PSendSysMessage("Found %i Creatures.", creatureList.size()); uint32 paths = 0; uint32 uStartTime = getMSTime(); float gx,gy,gz; handler->GetSession()->GetPlayer()->GetPosition(gx,gy,gz); for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr) { PathFinder((*itr), gx, gy, gz); ++paths; } uint32 uPathLoadTime = getMSTimeDiff(uStartTime, getMSTime()); handler->PSendSysMessage("Generated %i paths in %i ms", paths, uPathLoadTime); } else handler->PSendSysMessage("No creatures in %f yard range.", radius); return true; }
void Unit::Update() { WorldObject::Update(); m_motionMaster.Update(); // update movement if the unit is moving if (IsMoving()) { const uint32_t msNow = getMSTime(); // update position using movement vector uint32_t msDiff = getMSTimeDiff(m_lastMovementUpdate, msNow); if (msDiff >= 1) { float coef = (float)msDiff; float newX; float newY; //m_position.x += coef * m_moveVector.x; newX = m_position.x + coef * m_moveVector.x; if (newX < 0.0f) newX = 0.0f; MapField* mf = GetMap()->GetField(newX, m_position.y); if (!mf || !CanMoveOn((MapFieldType)mf->type, mf->flags)) newX = m_position.x; newY = m_position.y + coef * m_moveVector.y; if (newY < 0.0f) newY = 0.0f; mf = GetMap()->GetField(newX, newY); if (!mf || !CanMoveOn((MapFieldType)mf->type, mf->flags)) newY = m_position.y; RelocateWithinMap(newX, newY); m_lastMovementUpdate = msNow; } } }
static bool HandleMmapTestArea(ChatHandler* handler, const char* args) { float radius = 40.0f; WorldObject* object = handler->GetSession()->GetPlayer(); CellCoord pair(Trinity::ComputeCellCoord(object->GetPositionX(), object->GetPositionY()) ); Cell cell(pair); cell.SetNoCreate(); std::list<Creature*> creatureList; Trinity::AnyUnitInObjectRangeCheck go_check(object, radius); Trinity::CreatureListSearcher<Trinity::AnyUnitInObjectRangeCheck> go_search(object, creatureList, go_check); TypeContainerVisitor<Trinity::CreatureListSearcher<Trinity::AnyUnitInObjectRangeCheck>, GridTypeMapContainer> go_visit(go_search); // Get Creatures cell.Visit(pair, go_visit, *(object->GetMap()), *object, radius); if (!creatureList.empty()) { handler->PSendSysMessage("Found %i Creatures.", creatureList.size()); uint32 paths = 0; uint32 uStartTime = getMSTime(); float gx, gy, gz; object->GetPosition(gx, gy, gz); for (std::list<Creature*>::iterator itr = creatureList.begin(); itr != creatureList.end(); ++itr) { PathGenerator path(*itr); path.CalculatePath(gx, gy, gz); ++paths; } uint32 uPathLoadTime = getMSTimeDiff(uStartTime, getMSTime()); handler->PSendSysMessage("Generated %i paths in %i ms", paths, uPathLoadTime); } else handler->PSendSysMessage("No creatures in %f yard range.", radius); return true; }
bool MySQLConnection::_Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount) { if (!m_Mysql) return false; { // guarded block for thread-safe mySQL request ACE_Guard<ACE_Thread_Mutex> query_connection_guard(m_Mutex); #ifdef SQLQUERY_LOG uint32 _s = getMSTime(); #endif if (mysql_query(m_Mysql, sql)) { sLog.outSQLDriver("SQL: %s", sql); sLog.outSQLDriver("query ERROR: %s", mysql_error(m_Mysql)); return false; } else { #ifdef SQLQUERY_LOG sLog.outSQLDriver("[%u ms] SQL: %s", getMSTimeDiff(_s,getMSTime()), sql); #endif } *pResult = mysql_store_result(m_Mysql); *pRowCount = mysql_affected_rows(m_Mysql); *pFieldCount = mysql_field_count(m_Mysql); } if (!*pResult ) return false; if (!*pRowCount) { mysql_free_result(*pResult); return false; } *pFields = mysql_fetch_fields(*pResult); return true; }
bool MySQLConnection::Execute(const char* sql) { if (!mMysql) return false; { uint32 _s = getMSTime(); if(mysql_query(mMysql, sql)) { sLog.outErrorDb("SQL: %s", sql); sLog.outErrorDb("SQL ERROR: %s", mysql_error(mMysql)); return false; } else { DEBUG_FILTER_LOG(LOG_FILTER_SQL_TEXT, "[%u ms] SQL: %s", getMSTimeDiff(_s,getMSTime()), sql ); } // end guarded block } return true; }
uint32 GetData(uint32 type) const override { switch (type) { case DATA_MOVEMENT_FINISHED: return _myMovementFinished ? 1 : 0; case DATA_DEATH_TIME: return _timeDied; case DATA_HORSEMEN_IS_TIMED_KILL: { uint32 minTime = 0, maxTime = 0; for (Horseman boss : horsemen) if (Creature* cBoss = getHorsemanHandle(boss)) { uint32 deathTime = cBoss->AI()->GetData(DATA_DEATH_TIME); if (!deathTime) { TC_LOG_WARN("scripts", "FourHorsemenAI: Checking for achievement credit but horseman %s is reporting not dead", cBoss->GetName().c_str()); return 0; } if (!minTime || deathTime < minTime) minTime = deathTime; if (!maxTime || deathTime > maxTime) maxTime = deathTime; } else { TC_LOG_WARN("scripts", "FourHorsemenAI: Checking for achievement credit but horseman with id %u is not present", uint32(boss)); return 0; } return (getMSTimeDiff(minTime, maxTime) <= 15 * IN_MILLISECONDS) ? 1 : 0; } default: return 0; } }
void run() { if (!_delayTime) return; sLog->outString("Starting up anti-freeze thread (%u seconds max stuck time)...", _delayTime/1000); while (!World::IsStopped()) { uint32 curtime = getMSTime(); if (_loops != World::m_worldLoopCounter) { _lastChange = curtime; _loops = World::m_worldLoopCounter; } else if (getMSTimeDiff(_lastChange, curtime) > _delayTime) { sLog->outString("World Thread hangs, kicking out server!"); ASSERT(false); } ACE_Based::Thread::Sleep(1000); } sLog->outString("Anti-freeze thread exiting without problems."); }
void LfgGroup::SendLfgQueueStatus() { Player *plr; for(member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) { plr = sObjectMgr.GetPlayer(citr->guid); if (!plr || !plr->GetSession()) continue; uint8 role = plr->m_lookingForGroup.roles; WorldPacket data(SMSG_LFG_QUEUE_STATUS, 31); data << uint32(GetDungeonInfo(IsFromRnd(citr->guid))->ID); // Dungeon data << uint32(sLfgMgr.GetAvgWaitTime(GetDungeonInfo(true)->ID, LFG_WAIT_TIME_AVG, role)); // Average Wait time data << uint32(sLfgMgr.GetAvgWaitTime(GetDungeonInfo(true)->ID, LFG_WAIT_TIME, role)); // Wait Time data << uint32(sLfgMgr.GetAvgWaitTime(GetDungeonInfo(true)->ID, LFG_WAIT_TIME_TANK, role));// Wait Tanks data << uint32(sLfgMgr.GetAvgWaitTime(GetDungeonInfo(true)->ID, LFG_WAIT_TIME_HEAL, role));// Wait Healers data << uint32(sLfgMgr.GetAvgWaitTime(GetDungeonInfo(true)->ID, LFG_WAIT_TIME_DPS, role)); // Wait Dps data << uint8(m_tank ? 0 : 1); // Tanks needed data << uint8(m_heal ? 0 : 1); // Healers needed data << uint8(LFG_DPS_COUNT - dps.size()); // Dps needed data << uint32(getMSTimeDiff(plr->m_lookingForGroup.joinTime, getMSTime())/1000); // Player wait time in queue plr->GetSession()->SendPacket(&data); } }
void WorldSession::HandleBattlefieldStatusOpcode(WorldPacket & /*recv_data*/) { // empty opcode sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Battleground status"); WorldPacket data; // we must update all queues here Battleground *bg = NULL; for (uint8 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; ++i) { BattlegroundQueueTypeId bgQueueTypeId = _player->GetBattlegroundQueueTypeId(i); if (!bgQueueTypeId) continue; BattlegroundTypeId bgTypeId = BattlegroundMgr::BGTemplateId(bgQueueTypeId); uint8 arenaType = BattlegroundMgr::BGArenaType(bgQueueTypeId); if (bgTypeId == _player->GetBattlegroundTypeId()) { bg = _player->GetBattleground(); //i cannot check any variable from player class because player class doesn't know if player is in 2v2 / 3v3 or 5v5 arena //so i must use bg pointer to get that information if (bg && bg->GetArenaType() == arenaType) { // this line is checked, i only don't know if GetStartTime is changing itself after bg end! // send status in Battleground sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_IN_PROGRESS, bg->GetEndTime(), bg->GetStartTime(), arenaType); SendPacket(&data); continue; } } //we are sending update to player about queue - he can be invited there! //get GroupQueueInfo for queue status BattlegroundQueue& bgQueue = sBattlegroundMgr->m_BattlegroundQueues[bgQueueTypeId]; GroupQueueInfo ginfo; if (!bgQueue.GetPlayerGroupInfoData(_player->GetGUID(), &ginfo)) continue; if (ginfo.IsInvitedToBGInstanceGUID) { bg = sBattlegroundMgr->GetBattleground(ginfo.IsInvitedToBGInstanceGUID, bgTypeId); if (!bg) continue; uint32 remainingTime = getMSTimeDiff(getMSTime(), ginfo.RemoveInviteTime); // send status invited to Battleground sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_JOIN, remainingTime, 0, arenaType); SendPacket(&data); } else { bg = sBattlegroundMgr->GetBattlegroundTemplate(bgTypeId); if (!bg) continue; // expected bracket entry PvPDifficultyEntry const* bracketEntry = GetBattlegroundBracketByLevel(bg->GetMapId(), _player->getLevel()); if (!bracketEntry) continue; uint32 avgTime = bgQueue.GetAverageQueueWaitTime(&ginfo, bracketEntry->GetBracketId()); // send status in Battleground Queue sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, i, STATUS_WAIT_QUEUE, avgTime, getMSTimeDiff(ginfo.JoinTime, getMSTime()), arenaType); SendPacket(&data); } } }
void AnticheatMgr::BuildReport(Player* player,uint8 reportType) { uint32 key = player->GetGUIDLow(); if (MustCheckTempReports(reportType)) { uint32 actualTime = getMSTime(); if (!m_Players[key].GetTempReportsTimer(reportType)) m_Players[key].SetTempReportsTimer(actualTime,reportType); if (getMSTimeDiff(m_Players[key].GetTempReportsTimer(reportType),actualTime) < 3000) { m_Players[key].SetTempReports(m_Players[key].GetTempReports(reportType)+1,reportType); if (m_Players[key].GetTempReports(reportType) < 3) return; } else { m_Players[key].SetTempReportsTimer(actualTime,reportType); m_Players[key].SetTempReports(1,reportType); return; } } // generating creationTime for average calculation if (!m_Players[key].GetTotalReports()) m_Players[key].SetCreationTime(getMSTime()); // increasing total_reports m_Players[key].SetTotalReports(m_Players[key].GetTotalReports()+1); // increasing specific cheat report m_Players[key].SetTypeReports(reportType,m_Players[key].GetTypeReports(reportType)+1); // diff time for average calculation uint32 diffTime = getMSTimeDiff(m_Players[key].GetCreationTime(),getMSTime()) / IN_MILLISECONDS; if (diffTime > 0) { // Average == Reports per second float average = float(m_Players[key].GetTotalReports()) / float(diffTime); m_Players[key].SetAverage(average); } if (sWorld->getIntConfig(CONFIG_ANTICHEAT_MAX_REPORTS_FOR_DAILY_REPORT) < m_Players[key].GetTotalReports()) { if (!m_Players[key].GetDailyReportState()) { CharacterDatabase.PExecute("REPLACE INTO daily_players_reports (guid,average,total_reports,speed_reports,fly_reports,jump_reports,waterwalk_reports,teleportplane_reports,climb_reports,creation_time) VALUES (%u,%f,%u,%u,%u,%u,%u,%u,%u,%u);",player->GetGUIDLow(),m_Players[player->GetGUIDLow()].GetAverage(),m_Players[player->GetGUIDLow()].GetTotalReports(), m_Players[player->GetGUIDLow()].GetTypeReports(SPEED_HACK_REPORT),m_Players[player->GetGUIDLow()].GetTypeReports(FLY_HACK_REPORT),m_Players[player->GetGUIDLow()].GetTypeReports(JUMP_HACK_REPORT),m_Players[player->GetGUIDLow()].GetTypeReports(WALK_WATER_HACK_REPORT),m_Players[player->GetGUIDLow()].GetTypeReports(TELEPORT_PLANE_HACK_REPORT),m_Players[player->GetGUIDLow()].GetTypeReports(CLIMB_HACK_REPORT),m_Players[player->GetGUIDLow()].GetCreationTime()); m_Players[key].SetDailyReportState(true); } } if (m_Players[key].GetTotalReports() > sWorld->getIntConfig(CONFIG_ANTICHEAT_REPORTS_INGAME_NOTIFICATION)) { // display warning at the center of the screen, hacky way? std::string str = ""; if (sWorld->getBoolConfig(CONFIG_BAN_PLAYER)) //Make anticheat active. { if (m_Players[key].GetAverage() > 0.5f) { str = "Possible cheater found: " + std::string(player->GetName()); sWorld->BanCharacter(player->GetName(), "48h", str, "Anticheat"); sWorld->SendWorldText(LANG_BAN_CHEATER, player->GetName().c_str()); } } else { str = "|cFFFFFC00[AC]|cFF00FFFF[|cFF60FF00" + std::string(player->GetName().c_str()) + "|cFF00FFFF] Возможно читер!"; WorldPacket data(SMSG_NOTIFICATION, (str.size()+1)); data << str; sWorld->SendGlobalGMMessage(&data); } } }
void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) { uint32 opcode = recv_data.GetOpcode(); DEBUG_LOG("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); recv_data.hexlike(); Unit *mover = _player->GetMover(); Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if(plMover && plMover->IsBeingTeleported()) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* extract packet */ ObjectGuid guid; MovementInfo movementInfo; recv_data >> guid.ReadAsPacked(); recv_data >> movementInfo; /*----------------*/ if (!VerifyMovementInfo(movementInfo, guid)) return; // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). if (opcode == MSG_MOVE_FALL_LAND && plMover && !plMover->IsTaxiFlying()) plMover->HandleFall(movementInfo); // ---- anti-cheat features -->>> uint32 Anti_TeleTimeDiff=plMover ? time(NULL) - plMover->Anti__GetLastTeleTime() : time(NULL); static const uint32 Anti_TeleTimeIgnoreDiff=sWorld.GetMvAnticheatIgnoreAfterTeleport(); if (plMover && (plMover->m_transport == 0) && sWorld.GetMvAnticheatEnable() && GetPlayer()->GetSession()->GetSecurity() <= sWorld.GetMvAnticheatGmLevel() && GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType()!=FLIGHT_MOTION_TYPE && Anti_TeleTimeDiff>Anti_TeleTimeIgnoreDiff) { const uint32 CurTime=getMSTime(); if (getMSTimeDiff(GetPlayer()->m_anti_lastalarmtime,CurTime) > sWorld.GetMvAnticheatAlarmPeriod()) { GetPlayer()->m_anti_alarmcount = 0; } /* I really don't care about movement-type yet (todo) UnitMoveType move_type; if (movementInfo.flags & MOVEMENTFLAG_FLYING) move_type = MOVE_FLY; else if (movementInfo.flags & MOVEMENTFLAG_SWIMMING) move_type = MOVE_SWIM; else if (movementInfo.flags & MOVEMENTFLAG_WALK_MODE) move_type = MOVE_WALK; else move_type = MOVE_RUN;*/ float delta_x = GetPlayer()->GetPositionX() - movementInfo.GetPos()->x; float delta_y = GetPlayer()->GetPositionY() - movementInfo.GetPos()->y; float delta_z = GetPlayer()->GetPositionZ() - movementInfo.GetPos()->z; float delta = sqrt(delta_x * delta_x + delta_y * delta_y); // Len of movement-vector via Pythagoras (a^2+b^2=Len^2) float tg_z = 0.0f; //tangens float delta_t = getMSTimeDiff(GetPlayer()->m_anti_lastmovetime,CurTime); GetPlayer()->m_anti_lastmovetime = CurTime; GetPlayer()->m_anti_MovedLen += delta; if (delta_t > 15000.0f) { delta_t = 15000.0f; } // Tangens of walking angel if (!(movementInfo.GetMovementFlags() & (MOVEFLAG_FLYING | MOVEFLAG_SWIMMING))) { tg_z = ((delta !=0.0f) && (delta_z > 0.0f)) ? (atan((delta_z*delta_z) / delta) * 180.0f / M_PI) : 0.0f; } //antiOFF fall-damage, MOVEMENTFLAG_UNK4 seted by client if player try movement when falling and unset in this case the MOVEMENTFLAG_FALLING flag. if ((!GetPlayer()->CanFly() && GetPlayer()->m_anti_BeginFallZ == INVALID_HEIGHT) && (movementInfo.GetMovementFlags() & (MOVEFLAG_FALLING | MOVEFLAG_FALLINGFAR)) != 0) { GetPlayer()->m_anti_BeginFallZ=(float)(movementInfo.GetPos()->z); } if (GetPlayer()->m_anti_NextLenCheck <= CurTime) { // Check every 500ms is a lot more advisable then 1000ms, because normal movment packet arrives every 500ms uint32 OldNextLenCheck=GetPlayer()->m_anti_NextLenCheck; float delta_xyt=GetPlayer()->m_anti_MovedLen/(float)(getMSTimeDiff(OldNextLenCheck-500,CurTime)); GetPlayer()->m_anti_NextLenCheck = CurTime+500; GetPlayer()->m_anti_MovedLen = 0.0f; static const float MaxDeltaXYT = sWorld.GetMvAnticheatMaxXYT(); if (delta_xyt > MaxDeltaXYT && delta<=100.0f && GetPlayer()->GetZoneId() != 2257) { if (sWorld.GetMvAnticheatSpeedCheck()) Anti__CheatOccurred(CurTime,"Speed hack",delta_xyt,LookupOpcodeName(opcode), (float)(GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType()), (float)(getMSTimeDiff(OldNextLenCheck-500,CurTime))); } } if (delta > 100.0f && GetPlayer()->GetZoneId() != 2257) { if (sWorld.GetMvAnticheatTeleportCheck()) Anti__ReportCheat("Tele hack",delta,LookupOpcodeName(opcode)); } // Check for waterwalking . Fix new way of checking for waterwalking by Darky88 if (movementInfo.HasMovementFlag(MOVEFLAG_WATERWALKING) && !(GetPlayer()->HasAuraType(SPELL_AURA_WATER_WALK) || GetPlayer()->HasAuraType(SPELL_AURA_GHOST))) { if(sWorld.GetMvAnticheatWaterCheck()) Anti__CheatOccurred(CurTime,"Water walking",0.0f,NULL,0.0f,(uint32)(movementInfo.GetMovementFlags())); } // Check for walking upwards a mountain while not beeing able to do that, New check by Darky88 if ((delta_z < -2.3f) && (tg_z > 2.37f)) { if (sWorld.GetMvAnticheatMountainCheck()) Anti__CheatOccurred(CurTime,"Mountain hack",tg_z,NULL,delta,delta_z); } static const float DIFF_OVERGROUND = 10.0f; float Anti__GroundZ = GetPlayer()->GetTerrain()->GetHeight(GetPlayer()->GetPositionX(),GetPlayer()->GetPositionY(),MAX_HEIGHT); float Anti__FloorZ = GetPlayer()->GetTerrain()->GetHeight(GetPlayer()->GetPositionX(),GetPlayer()->GetPositionY(),GetPlayer()->GetPositionZ()); float Anti__MapZ = ((Anti__FloorZ <= (INVALID_HEIGHT+5.0f)) ? Anti__GroundZ : Anti__FloorZ) + DIFF_OVERGROUND; if (!GetPlayer()->CanFly() && !GetPlayer()->GetTerrain()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z-7.0f) && Anti__MapZ < GetPlayer()->GetPositionZ() && Anti__MapZ > (INVALID_HEIGHT+DIFF_OVERGROUND + 5.0f)) { static const float DIFF_AIRJUMP=25.0f; // 25 is realy high, but to many false positives... // Air-Jump-Detection definitively needs a better way to be detected... if ((movementInfo.GetMovementFlags() & (MOVEFLAG_CAN_FLY | MOVEFLAG_FLYING | MOVEFLAG_ROOT)) != 0) // Fly Hack { // Fix Aura 55164 if (!GetPlayer()->HasAura(55164) || !GetPlayer()->HasAuraType(SPELL_AURA_FEATHER_FALL)) if (sWorld.GetMvAnticheatFlyCheck()) Anti__CheatOccurred(CurTime,"Fly hack", ((uint8)(GetPlayer()->HasAuraType(SPELL_AURA_FLY))) + ((uint8)(GetPlayer()->HasAuraType(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED))*2), NULL,GetPlayer()->GetPositionZ()-Anti__MapZ); } // Need a better way to do that - currently a lot of fake alarms else if ((Anti__MapZ+DIFF_AIRJUMP < GetPlayer()->GetPositionZ() && (movementInfo.GetMovementFlags() & (MOVEFLAG_FALLINGFAR | MOVEFLAG_PENDINGSTOP))==0) || (Anti__MapZ < GetPlayer()->GetPositionZ() && opcode==MSG_MOVE_JUMP) && !GetPlayer()->HasAuraType(SPELL_AURA_FEATHER_FALL)) { if (sWorld.GetMvAnticheatJumpCheck()) Anti__CheatOccurred(CurTime,"Possible Air Jump Hack",0.0f,LookupOpcodeName(opcode),0.0f,movementInfo.GetMovementFlags()); } } /*if(Anti__FloorZ < -199900.0f && Anti__GroundZ >= -199900.0f && GetPlayer()->GetPositionZ()+5.0f < Anti__GroundZ) { Anti__CheatOccurred(CurTime,"Teleport2Plane hack", GetPlayer()->GetPositionZ(),NULL,Anti__GroundZ); }*/ //Teleport To Plane checks if (movementInfo.GetPos()->z < 0.0001f && movementInfo.GetPos()->z > -0.0001f && (!movementInfo.HasMovementFlag(MovementFlags(MOVEFLAG_SWIMMING | MOVEFLAG_CAN_FLY | MOVEFLAG_FLYING)))) { if(sWorld.GetMvAnticheatTeleport2PlaneCheck()) { // Prevent using TeleportToPlan. Map *map = GetPlayer()->GetMap(); if (map) { float plane_z = map->GetTerrain()->GetHeight(movementInfo.GetPos()->x, movementInfo.GetPos()->y, MAX_HEIGHT) - movementInfo.GetPos()->z; plane_z = (plane_z < -500.0f) ? 0 : plane_z; //check holes in heigth map if(plane_z > 0.1f || plane_z < -0.1f) { if(sWorld.GetMvAnticheatTeleport2PlaneCheck()) Anti__CheatOccurred(CurTime,"Teleport2Plane hack",GetPlayer()->GetPositionZ(),NULL,plane_z); } } } } } // <<---- anti-cheat features /* process position-change */ HandleMoverRelocation(movementInfo); if (plMover) plMover->UpdateFallInformationIfNeed(movementInfo, opcode); // after move info set if (opcode == MSG_MOVE_SET_WALK_MODE || opcode == MSG_MOVE_SET_RUN_MODE) mover->UpdateWalkMode(mover, false); WorldPacket data(opcode, recv_data.size()); data << mover->GetPackGUID(); // write guid movementInfo.Write(data); // write data mover->SendMessageToSetExcept(&data, _player); }
void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) { uint32 opcode = recv_data.GetOpcode(); DEBUG_LOG("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); recv_data.hexlike(); Unit *mover = _player->GetMover(); Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if (plMover && plMover->IsBeingTeleported()) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* extract packet */ ObjectGuid guid; MovementInfo movementInfo; recv_data >> guid.ReadAsPacked(); recv_data >> movementInfo; /*----------------*/ if (!Diamond::IsValidMapCoord(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o)) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.HasMovementFlag(MOVEFLAG_ONTRANSPORT)) { // transports size limited // (also received at zeppelin/lift leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) if ( movementInfo.GetTransportPos()->x > 50 || movementInfo.GetTransportPos()->y > 50 || movementInfo.GetTransportPos()->z > 100 ) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } if ( !Diamond::IsValidMapCoord(movementInfo.GetPos()->x + movementInfo.GetTransportPos()->x, movementInfo.GetPos()->y + movementInfo.GetTransportPos()->y, movementInfo.GetPos()->z + movementInfo.GetTransportPos()->z, movementInfo.GetPos()->o + movementInfo.GetTransportPos()->o) ) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plMover && !plMover->m_transport) { float trans_rad = movementInfo.GetTransportPos()->x*movementInfo.GetTransportPos()->x + movementInfo.GetTransportPos()->y*movementInfo.GetTransportPos()->y + movementInfo.GetTransportPos()->z*movementInfo.GetTransportPos()->z; if (trans_rad > 3600.0f) // transport radius = 60 yards //cheater with on_transport_flag { return; } // elevators also cause the client to send MOVEFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list for (MapManager::TransportSet::const_iterator iter = sMapMgr.m_Transports.begin(); iter != sMapMgr.m_Transports.end(); ++iter) { if ((*iter)->GetObjectGuid() == movementInfo.GetTransportGuid()) { plMover->m_transport = (*iter); (*iter)->AddPassenger(plMover); if (plMover->GetVehicleKit()) plMover->GetVehicleKit()->RemoveAllPassengers(); break; } } } } else if (plMover && plMover->m_transport) // if we were on a transport, leave { plMover->m_transport->RemovePassenger(plMover); plMover->m_transport = NULL; movementInfo.ClearTransportData(); } // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). if (opcode == MSG_MOVE_FALL_LAND && plMover && !plMover->IsTaxiFlying()) plMover->HandleFall(movementInfo); if (plMover && (movementInfo.HasMovementFlag(MOVEFLAG_SWIMMING) != plMover->IsInWater())) { // now client not include swimming flag in case jumping under water plMover->SetInWater( !plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z) ); if (plMover->GetBaseMap()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z-7.0f)) { plMover->m_anti_BeginFallZ=INVALID_HEIGHT; } } // ---- anti-cheat features -->>> uint32 Anti_TeleTimeDiff=plMover ? time(NULL) - plMover->Anti__GetLastTeleTime() : time(NULL); static const uint32 Anti_TeleTimeIgnoreDiff=sWorld.GetMvAnticheatIgnoreAfterTeleport(); if (plMover && (plMover->m_transport == 0) && sWorld.GetMvAnticheatEnable() && GetPlayer()->GetSession()->GetSecurity() <= sWorld.GetMvAnticheatGmLevel() && GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType()!=FLIGHT_MOTION_TYPE && Anti_TeleTimeDiff>Anti_TeleTimeIgnoreDiff) { const uint32 CurTime=getMSTime(); if (getMSTimeDiff(GetPlayer()->m_anti_lastalarmtime,CurTime) > sWorld.GetMvAnticheatAlarmPeriod()) { GetPlayer()->m_anti_alarmcount = 0; } /* I really don't care about movement-type yet (todo) UnitMoveType move_type; if (movementInfo.flags & MOVEMENTFLAG_FLYING) move_type = MOVE_FLY; else if (movementInfo.flags & MOVEMENTFLAG_SWIMMING) move_type = MOVE_SWIM; else if (movementInfo.flags & MOVEMENTFLAG_WALK_MODE) move_type = MOVE_WALK; else move_type = MOVE_RUN;*/ float delta_x = GetPlayer()->GetPositionX() - movementInfo.GetPos()->x; float delta_y = GetPlayer()->GetPositionY() - movementInfo.GetPos()->y; float delta_z = GetPlayer()->GetPositionZ() - movementInfo.GetPos()->z; float delta = sqrt(delta_x * delta_x + delta_y * delta_y); // Len of movement-vector via Pythagoras (a^2+b^2=Len^2) float tg_z = 0.0f; //tangens float delta_t = getMSTimeDiff(GetPlayer()->m_anti_lastmovetime,CurTime); GetPlayer()->m_anti_lastmovetime = CurTime; GetPlayer()->m_anti_MovedLen += delta; if (delta_t > 15000.0f) { delta_t = 15000.0f; } // Tangens of walking angel if (!(movementInfo.GetMovementFlags() & (MOVEFLAG_FLYING | MOVEFLAG_SWIMMING))) { tg_z = ((delta !=0.0f) && (delta_z > 0.0f)) ? (atan((delta_z*delta_z) / delta) * 180.0f / M_PI) : 0.0f; } //antiOFF fall-damage, MOVEMENTFLAG_UNK4 seted by client if player try movement when falling and unset in this case the MOVEMENTFLAG_FALLING flag. if ((!GetPlayer()->CanFly() && GetPlayer()->m_anti_BeginFallZ == INVALID_HEIGHT) && (movementInfo.GetMovementFlags() & (MOVEFLAG_FALLING | MOVEFLAG_FALLINGFAR)) != 0) { GetPlayer()->m_anti_BeginFallZ=(float)(movementInfo.GetPos()->z); } if (GetPlayer()->m_anti_NextLenCheck <= CurTime) { // Check every 500ms is a lot more advisable then 1000ms, because normal movment packet arrives every 500ms uint32 OldNextLenCheck=GetPlayer()->m_anti_NextLenCheck; float delta_xyt=GetPlayer()->m_anti_MovedLen/(float)(getMSTimeDiff(OldNextLenCheck-500,CurTime)); GetPlayer()->m_anti_NextLenCheck = CurTime+500; GetPlayer()->m_anti_MovedLen = 0.0f; static const float MaxDeltaXYT = sWorld.GetMvAnticheatMaxXYT(); if (delta_xyt > MaxDeltaXYT && delta<=100.0f && GetPlayer()->GetZoneId() != 2257) { if (sWorld.GetMvAnticheatSpeedCheck()) Anti__CheatOccurred(CurTime,"Speed hack",delta_xyt,LookupOpcodeName(opcode), (float)(GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType()), (float)(getMSTimeDiff(OldNextLenCheck-500,CurTime))); } } if (delta > 100.0f && GetPlayer()->GetZoneId() != 2257) { if (sWorld.GetMvAnticheatTeleportCheck()) Anti__ReportCheat("Tele hack",delta,LookupOpcodeName(opcode)); } // Check for waterwalking . Fix new way of checking for waterwalking by Darky88 if (movementInfo.HasMovementFlag(MOVEFLAG_WATERWALKING) && !(GetPlayer()->HasAuraType(SPELL_AURA_WATER_WALK) || GetPlayer()->HasAuraType(SPELL_AURA_GHOST))) { if (sWorld.GetMvAnticheatWaterCheck()) Anti__CheatOccurred(CurTime,"Water walking",0.0f,NULL,0.0f,(uint32)(movementInfo.GetMovementFlags())); } // Check for walking upwards a mountain while not beeing able to do that, New check by Darky88 if ((delta_z < -2.3f) && (tg_z > 2.37f)) { if (sWorld.GetMvAnticheatMountainCheck()) Anti__CheatOccurred(CurTime,"Mountain hack",tg_z,NULL,delta,delta_z); } static const float DIFF_OVERGROUND = 10.0f; float Anti__GroundZ = GetPlayer()->GetMap()->GetHeight(GetPlayer()->GetPositionX(),GetPlayer()->GetPositionY(),MAX_HEIGHT); float Anti__FloorZ = GetPlayer()->GetMap()->GetHeight(GetPlayer()->GetPositionX(),GetPlayer()->GetPositionY(),GetPlayer()->GetPositionZ()); float Anti__MapZ = ((Anti__FloorZ <= (INVALID_HEIGHT+5.0f)) ? Anti__GroundZ : Anti__FloorZ) + DIFF_OVERGROUND; if (!GetPlayer()->CanFly() && !GetPlayer()->GetBaseMap()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z-7.0f) && Anti__MapZ < GetPlayer()->GetPositionZ() && Anti__MapZ > (INVALID_HEIGHT+DIFF_OVERGROUND + 5.0f)) { static const float DIFF_AIRJUMP=25.0f; // 25 is realy high, but to many false positives... // Air-Jump-Detection definitively needs a better way to be detected... if ((movementInfo.GetMovementFlags() & (MOVEFLAG_CAN_FLY | MOVEFLAG_FLYING | MOVEFLAG_ROOT)) != 0) // Fly Hack { // Fix Aura 55164 if (!GetPlayer()->HasAura(55164) || !GetPlayer()->HasAuraType(SPELL_AURA_FEATHER_FALL)) if (sWorld.GetMvAnticheatFlyCheck()) Anti__CheatOccurred(CurTime,"Fly hack", ((uint8)(GetPlayer()->HasAuraType(SPELL_AURA_FLY))) + ((uint8)(GetPlayer()->HasAuraType(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED))*2), NULL,GetPlayer()->GetPositionZ()-Anti__MapZ); } // Need a better way to do that - currently a lot of fake alarms else if ((Anti__MapZ+DIFF_AIRJUMP < GetPlayer()->GetPositionZ() && (movementInfo.GetMovementFlags() & (MOVEFLAG_FALLINGFAR | MOVEFLAG_PENDINGSTOP))==0) || (Anti__MapZ < GetPlayer()->GetPositionZ() && opcode==MSG_MOVE_JUMP) && !GetPlayer()->HasAuraType(SPELL_AURA_FEATHER_FALL)) { if (sWorld.GetMvAnticheatJumpCheck()) Anti__CheatOccurred(CurTime,"Possible Air Jump Hack",0.0f,LookupOpcodeName(opcode),0.0f,movementInfo.GetMovementFlags()); } } /*if (Anti__FloorZ < -199900.0f && Anti__GroundZ >= -199900.0f && GetPlayer()->GetPositionZ()+5.0f < Anti__GroundZ) { Anti__CheatOccurred(CurTime,"Teleport2Plane hack", GetPlayer()->GetPositionZ(),NULL,Anti__GroundZ); }*/ //Teleport To Plane checks if (movementInfo.GetPos()->z < 0.0001f && movementInfo.GetPos()->z > -0.0001f && (!movementInfo.HasMovementFlag(MovementFlags(MOVEFLAG_SWIMMING | MOVEFLAG_CAN_FLY | MOVEFLAG_FLYING)))) { if (sWorld.GetMvAnticheatTeleport2PlaneCheck()) { // Prevent using TeleportToPlan. Map *map = GetPlayer()->GetMap(); if (map) { float plane_z = map->GetHeight(movementInfo.GetPos()->x, movementInfo.GetPos()->y, MAX_HEIGHT) - movementInfo.GetPos()->z; plane_z = (plane_z < -500.0f) ? 0 : plane_z; //check holes in heigth map if (plane_z > 0.1f || plane_z < -0.1f) { if (sWorld.GetMvAnticheatTeleport2PlaneCheck()) Anti__CheatOccurred(CurTime,"Teleport2Plane hack",GetPlayer()->GetPositionZ(),NULL,plane_z); } } } } } // <<---- anti-cheat features /* process position-change */ movementInfo.UpdateTime(getMSTime()); WorldPacket data(opcode, recv_data.size()); data.appendPackGUID(mover->GetGUID()); // write guid movementInfo.Write(data); // write data mover->SendMessageToSetExcept(&data, _player); mover->m_movementInfo = movementInfo; mover->SetPosition(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o); if (plMover) // nothing is charmed, or player charmed { plMover->UpdateFallInformationIfNeed(movementInfo, opcode); // after move info set if ((opcode == MSG_MOVE_SET_WALK_MODE || opcode == MSG_MOVE_SET_RUN_MODE)) plMover->UpdateWalkMode(plMover, false); if (plMover->isMovingOrTurning()) plMover->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); if (movementInfo.GetPos()->z < -500.0f) { if (plMover->InBattleGround() && plMover->GetBattleGround() && plMover->GetBattleGround()->HandlePlayerUnderMap(_player)) { // do nothing, the handle already did if returned true } else { // NOTE: this is actually called many times while falling // even after the player has been teleported away // TODO: discard movement packets after the player is rooted if (plMover->isAlive()) { plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, plMover->GetMaxHealth()); // pl can be alive if GM/etc if (!plMover->isAlive()) { // change the death state to CORPSE to prevent the death timer from // starting in the next player update plMover->KillPlayer(); plMover->BuildPlayerRepop(); } } // cancel the death timer here if started plMover->RepopAtGraveyard(); } } } }
/// Update the WorldSession (triggered by World update) bool WorldSession::Update(uint32 diff, PacketFilter& updater) { /// Update Timeout timer. UpdateTimeOutTime(diff); ///- Before we process anything: /// If necessary, kick the player from the character select screen if (IsConnectionIdle()) m_Socket->CloseSocket(); ///- Retrieve packets from the receive queue and call the appropriate handlers /// not process packets if socket already closed WorldPacket* packet = NULL; //! Delete packet after processing by default bool deletePacket = true; //! To prevent infinite loop WorldPacket* firstDelayedPacket = NULL; //! If _recvQueue.peek() == firstDelayedPacket it means that in this Update call, we've processed all //! *properly timed* packets, and we're now at the part of the queue where we find //! delayed packets that were re-enqueued due to improper timing. To prevent an infinite //! loop caused by re-enqueueing the same packets over and over again, we stop updating this session //! and continue updating others. The re-enqueued packets will be handled in the next Update call for this session. //uint32 processedPackets = 0; uint32 msTime = getMSTime(); uint32 currentMSTime = msTime; //bool output = false; std::list<std::pair<uint32, uint32> > processedOpcodes; while (m_Socket && !m_Socket->IsClosed() && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater)) { sLog->outDebug(LOG_FILTER_NETWORKIO, "SESSION: IN opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); if (packet->GetOpcode() >= NUM_MSG_TYPES) { sLog->outError("SESSION: received non-existed opcode %s (0x%.4X)", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); sScriptMgr->OnUnknownPacketReceive(m_Socket, WorldPacket(*packet)); } else { OpcodeHandler &opHandle = opcodeTable[packet->GetOpcode()]; try { switch (opHandle.status) { case STATUS_LOGGEDIN: if (!_player) { // skip STATUS_LOGGEDIN opcode unexpected errors if player logout sometime ago - this can be network lag delayed packets //! If player didn't log out a while ago, it means packets are being sent while the server does not recognize //! the client to be in world yet. We will re-add the packets to the bottom of the queue and process them later. if (!m_playerRecentlyLogout) { //! Prevent infinite loop if (!firstDelayedPacket) firstDelayedPacket = packet; //! Because checking a bool is faster than reallocating memory deletePacket = false; QueuePacket(packet); //! Log sLog->outDebug(LOG_FILTER_NETWORKIO, "Re-enqueueing packet with opcode %s (0x%.4X) with with status STATUS_LOGGEDIN. " "Player is currently not in world yet.", opHandle.name, packet->GetOpcode()); } } else if (_player->IsInWorld()) { sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); if (sLog->IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); } // lag can cause STATUS_LOGGEDIN opcodes to arrive after the player started a transfer break; case STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT: if (!_player && !m_playerRecentlyLogout && !m_playerLogout) // There's a short delay between _player = null and m_playerRecentlyLogout = true during logout LogUnexpectedOpcode(packet, "STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT", "the player has not logged in yet and not recently logout"); else { // not expected _player or must checked in packet handler sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); if (sLog->IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); } break; case STATUS_TRANSFER: if (!_player) LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player has not logged in yet"); else if (_player->IsInWorld()) LogUnexpectedOpcode(packet, "STATUS_TRANSFER", "the player is still in world"); else { sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); if (sLog->IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); } break; case STATUS_AUTHED: // prevent cheating with skip queue wait if (m_inQueue) { LogUnexpectedOpcode(packet, "STATUS_AUTHED", "the player not pass queue yet"); break; } // some auth opcodes can be recieved before STATUS_LOGGEDIN_OR_RECENTLY_LOGGOUT opcodes // however when we recieve CMSG_CHAR_ENUM we are surely no longer during the logout process. if (packet->GetOpcode() == CMSG_CHAR_ENUM) m_playerRecentlyLogout = false; sScriptMgr->OnPacketReceive(m_Socket, WorldPacket(*packet)); (this->*opHandle.handler)(*packet); if (sLog->IsOutDebug() && packet->rpos() < packet->wpos()) LogUnprocessedTail(packet); break; case STATUS_NEVER: sLog->outDebug(LOG_FILTER_NETWORKIO, "SESSION (account: %u, guidlow: %u, char: %s): received not allowed opcode %s (0x%.4X)", GetAccountId(), m_GUIDLow, _player ? _player->GetName() : "<none>", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); break; case STATUS_UNHANDLED: sLog->outDebug(LOG_FILTER_NETWORKIO, "SESSION (account: %u, guidlow: %u, char: %s): received not handled opcode %s (0x%.4X)", GetAccountId(), m_GUIDLow, _player ? _player->GetName() : "<none>", LookupOpcodeName(packet->GetOpcode()), packet->GetOpcode()); break; } } catch (ByteBufferException &) { sLog->outError("WorldSession::Update ByteBufferException occured while parsing a packet (opcode: %u) from client %s, accountid=%i. Skipped packet.", packet->GetOpcode(), GetRemoteAddress().c_str(), GetAccountId()); if (sLog->IsOutDebug()) { sLog->outDebug(LOG_FILTER_NETWORKIO, "Dumping error causing packet:"); packet->hexlike(); } } } uint32 temporary = getMSTime(); processedOpcodes.push_back(std::pair<uint32, uint32>(packet->GetOpcode(), getMSTimeDiff(currentMSTime, temporary))); if (deletePacket) delete packet; deletePacket = true; /*#define MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE 50 processedPackets++; //process only a max amout of packets in 1 Update() call. //Any leftover will be processed in next update if (processedPackets > MAX_PROCESSED_PACKETS_IN_SAME_WORLDSESSION_UPDATE) { output = true; break; } #define MAX_PROCESS_MSTIME_IN_SAME_WORLDSESSION_UPDATE 5 currentMSTime = getMSTime(); if (getUSTimeDiff(msTime, currentMSTime) > MAX_PROCESS_MSTIME_IN_SAME_WORLDSESSION_UPDATE) { output = true; break; }*/ } /*if (output) { std::stringstream ss; ss << "Session: " << GetAccountId() << " Player: " << GetPlayerName(); std::list<std::pair<uint32, uint32> >::iterator itr = processedOpcodes.begin(); for (; itr != processedOpcodes.end(); ++itr) ss << " " << itr->first << "-" << itr->second << "ms"; sLog->outPerformance(ss.str().c_str()); }*/ ProcessQueryCallbacks(); if (_newNode) { if (Player *player = GetPlayer()) { if (player->IsSaveCommited()) { WorldPacket data(NODE_MISC_DATA); data << uint32(CL_DEF_TRANSFER_TO_NODE); data << _newNode; SendPacket(&data); _newNode = 0; } } } //check if we are safe to proceed with logout //logout procedure should happen only in World::UpdateSessions() method!!! if (updater.ProcessLogout()) { time_t currTime = time(NULL); ///- If necessary, log the player out if (ShouldLogOut(currTime) && !m_playerLoading) LogoutPlayer(true); ///- Cleanup socket pointer if need if (m_Socket && m_Socket->IsClosed()) { expireTime -= expireTime > diff ? diff : expireTime; if (expireTime < diff || forceExit) { m_Socket->RemoveReference(); m_Socket = NULL; } } if (!m_Socket) return false; //Will remove this session from the world session map } return true; }
/// Heartbeat for the World void WorldRunnable::run() { ///- Init MySQL threads or connections bool needInit = true; if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_WORLDDB) & MYSQL_BUNDLE_RA)) { WorldDatabase.Init_MySQL_Connection(); needInit = false; } if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_LOGINDB) & MYSQL_BUNDLE_RA)) { LoginDatabase.Init_MySQL_Connection(); needInit = false; } if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_CHARDB) & MYSQL_BUNDLE_RA)) { CharacterDatabase.Init_MySQL_Connection(); needInit = false; } if (needInit) MySQL::Thread_Init(); uint32 realCurrTime = 0; uint32 realPrevTime = getMSTime(); uint32 prevSleepTime = 0; // used for balanced full tick time length near WORLD_SLEEP_CONST sScriptMgr.OnStartup(); ///- While we have not World::m_stopEvent, update the world while (!World::IsStopped()) { ++World::m_worldLoopCounter; realCurrTime = getMSTime(); uint32 diff = getMSTimeDiff(realPrevTime,realCurrTime); sWorld.Update( diff ); realPrevTime = realCurrTime; // diff (D0) include time of previous sleep (d0) + tick time (t0) // we want that next d1 + t1 == WORLD_SLEEP_CONST // we can't know next t1 and then can use (t0 + d1) == WORLD_SLEEP_CONST requirement // d1 = WORLD_SLEEP_CONST - t0 = WORLD_SLEEP_CONST - (D0 - d0) = WORLD_SLEEP_CONST + d0 - D0 if (diff <= WORLD_SLEEP_CONST+prevSleepTime) { prevSleepTime = WORLD_SLEEP_CONST+prevSleepTime-diff; ACE_Based::Thread::Sleep(prevSleepTime); } else prevSleepTime = 0; #ifdef _WIN32 if (m_ServiceStatus == 0) World::StopNow(SHUTDOWN_EXIT_CODE); while (m_ServiceStatus == 2) Sleep(1000); #endif } sScriptMgr.OnShutdown(); sWorld.KickAll(); // save and kick all players sWorld.UpdateSessions( 1 ); // real players unload required UpdateSessions call // unload battleground templates before different singletons destroyed sBattlegroundMgr.DeleteAllBattlegrounds(); sWorldSocketMgr->StopNetwork(); sMapMgr.UnloadAll(); // unload all grids (including locked in memory) ///- Free MySQL thread resources and deallocate lingering connections if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_WORLDDB) & MYSQL_BUNDLE_RA)) WorldDatabase.End_MySQL_Connection(); if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_LOGINDB) & MYSQL_BUNDLE_RA)) LoginDatabase.End_MySQL_Connection(); if (!(sWorld.getConfig(CONFIG_MYSQL_BUNDLE_CHARDB) & MYSQL_BUNDLE_RA)) CharacterDatabase.End_MySQL_Connection(); if (needInit) MySQL::Thread_End(); }
void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) { uint32 opcode = recv_data.GetOpcode(); sLog.outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); recv_data.hexlike(); Unit *mover = _player->m_mover; Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if(plMover && plMover->IsBeingTeleported()) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* extract packet */ uint64 guid; if(!recv_data.readPackGUID(guid)) return; MovementInfo movementInfo; movementInfo.guid = guid; ReadMovementInfo(recv_data, &movementInfo); /*----------------*/ if(!(movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) && _player->GetVehicleGUID()) { if(mover->GetGUID() == _player->GetGUID()) { return; } } // we sent a movement packet with MOVEMENTFLAG_ONTRANSPORT and we are on vehicle // this can be moving on vehicle or entering another transport (eg. boat) if((movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) && _player->GetVehicleGUID()) { // we are controlling that vehicle if(mover->GetGUID() == _player->GetVehicleGUID()) { // we sent movement packet, related to movement ON vehicle, // but not WITH vehicle, so mover = player if(_player->GetVehicleGUID() == movementInfo.t_guid) { // this is required to avoid client crash, otherwise it will result // in moving with vehicle on the same vehicle and that = crash mover = _player; plMover = _player; } } if(_player->GetVehicleGUID() == movementInfo.t_guid) { _player->m_SeatData.OffsetX = movementInfo.t_x; _player->m_SeatData.OffsetY = movementInfo.t_y; _player->m_SeatData.OffsetZ = movementInfo.t_z; _player->m_SeatData.Orientation = movementInfo.t_o; } } recv_data.rpos(recv_data.wpos()); // prevent warnings spam if (!MaNGOS::IsValidMapCoord(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o)) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && !mover->GetVehicleGUID()) { // transports size limited // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) if( movementInfo.t_x > 50 || movementInfo.t_y > 50 || movementInfo.t_z > 50 ) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } if( !MaNGOS::IsValidMapCoord(movementInfo.x+movementInfo.t_x, movementInfo.y + movementInfo.t_y, movementInfo.z + movementInfo.t_z, movementInfo.o + movementInfo.t_o) ) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plMover && !plMover->m_transport) { float trans_rad = movementInfo.t_x*movementInfo.t_x + movementInfo.t_y*movementInfo.t_y + movementInfo.t_z*movementInfo.t_z; if (trans_rad > 3600.0f) // transport radius = 60 yards //cheater with on_transport_flag { return; } // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list for (MapManager::TransportSet::const_iterator iter = sMapMgr.m_Transports.begin(); iter != sMapMgr.m_Transports.end(); ++iter) { if ((*iter)->GetGUID() == movementInfo.t_guid) { plMover->m_transport = (*iter); (*iter)->AddPassenger(plMover); break; } } } } else if (plMover && plMover->m_transport) // if we were on a transport, leave { plMover->m_transport->RemovePassenger(plMover); plMover->m_transport = NULL; movementInfo.t_x = 0.0f; movementInfo.t_y = 0.0f; movementInfo.t_z = 0.0f; movementInfo.t_o = 0.0f; movementInfo.t_time = 0; movementInfo.t_seat = -1; } // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). if (opcode == MSG_MOVE_FALL_LAND && plMover && !plMover->isInFlight()) plMover->HandleFall(movementInfo); if (plMover && (movementInfo.HasMovementFlag(MOVEMENTFLAG_SWIMMING) != plMover->IsInWater())) { // now client not include swimming flag in case jumping under water plMover->SetInWater( !plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.x, movementInfo.y, movementInfo.z) ); if(plMover->GetBaseMap()->IsUnderWater(movementInfo.x, movementInfo.y, movementInfo.z-7.0f)) { plMover->m_anti_BeginFallZ=INVALID_HEIGHT; } } if (movementInfo.HasMovementFlag(MOVEMENTFLAG_SWIMMING)) { if(mover->GetTypeId() == TYPEID_UNIT) { if(((Creature*)mover)->isVehicle() && !((Creature*)mover)->canSwim()) { // NOTE : we should enter evade mode here, but... ((Vehicle*)mover)->SetSpawnDuration(1); } } } // ---- anti-cheat features -->>> uint32 Anti_TeleTimeDiff=plMover ? time(NULL) - plMover->Anti__GetLastTeleTime() : time(NULL); static const uint32 Anti_TeleTimeIgnoreDiff=sWorld.GetMvAnticheatIgnoreAfterTeleport(); if (plMover && (plMover->m_transport == 0) && sWorld.GetMvAnticheatEnable() && GetPlayer()->GetSession()->GetSecurity() <= sWorld.GetMvAnticheatGmLevel() && GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType()!=FLIGHT_MOTION_TYPE && Anti_TeleTimeDiff>Anti_TeleTimeIgnoreDiff) { const uint32 CurTime=getMSTime(); if(getMSTimeDiff(GetPlayer()->m_anti_lastalarmtime,CurTime) > sWorld.GetMvAnticheatAlarmPeriod()) { GetPlayer()->m_anti_alarmcount = 0; } /* I really don't care about movement-type yet (todo) UnitMoveType move_type; if (movementInfo.flags & MOVEMENTFLAG_FLYING) move_type = MOVE_FLY; else if (movementInfo.flags & MOVEMENTFLAG_SWIMMING) move_type = MOVE_SWIM; else if (movementInfo.flags & MOVEMENTFLAG_WALK_MODE) move_type = MOVE_WALK; else move_type = MOVE_RUN;*/ float delta_x = GetPlayer()->GetPositionX() - movementInfo.x; float delta_y = GetPlayer()->GetPositionY() - movementInfo.y; float delta_z = GetPlayer()->GetPositionZ() - movementInfo.z; float delta = sqrt(delta_x * delta_x + delta_y * delta_y); // Len of movement-vector via Pythagoras (a^2+b^2=Len^2) float tg_z = 0.0f; //tangens float delta_t = getMSTimeDiff(GetPlayer()->m_anti_lastmovetime,CurTime); GetPlayer()->m_anti_lastmovetime = CurTime; GetPlayer()->m_anti_MovedLen += delta; if(delta_t > 15000.0f) { delta_t = 15000.0f; } // Tangens of walking angel /*if (!(movementInfo.flags & (MOVEMENTFLAG_FLYING | MOVEMENTFLAG_SWIMMING))) { //Mount hack detection currently disabled tg_z = ((delta !=0.0f) && (delta_z > 0.0f)) ? (atan((delta_z*delta_z) / delta) * 180.0f / M_PI) : 0.0f; }*/ //antiOFF fall-damage, MOVEMENTFLAG_UNK4 seted by client if player try movement when falling and unset in this case the MOVEMENTFLAG_FALLING flag. if((GetPlayer()->m_anti_BeginFallZ == INVALID_HEIGHT) && (movementInfo.flags & (MOVEMENTFLAG_FALLING | MOVEMENTFLAG_UNK4)) != 0) { GetPlayer()->m_anti_BeginFallZ=(float)(movementInfo.z); } if(GetPlayer()->m_anti_NextLenCheck <= CurTime) { // Check every 500ms is a lot more advisable then 1000ms, because normal movment packet arrives every 500ms uint32 OldNextLenCheck=GetPlayer()->m_anti_NextLenCheck; float delta_xyt=GetPlayer()->m_anti_MovedLen/(float)(getMSTimeDiff(OldNextLenCheck-500,CurTime)); GetPlayer()->m_anti_NextLenCheck = CurTime+500; GetPlayer()->m_anti_MovedLen = 0.0f; static const float MaxDeltaXYT = sWorld.GetMvAnticheatMaxXYT(); #ifdef __ANTI_DEBUG__ SendAreaTriggerMessage("XYT: %f ; Flags: %s",delta_xyt,FlagsToStr(movementInfo.flags).c_str()); #endif //__ANTI_DEBUG__ if(delta_xyt > MaxDeltaXYT && delta<=100.0f && GetPlayer()->GetZoneId() != 2257) { Anti__CheatOccurred(CurTime,"Speed hack",delta_xyt,LookupOpcodeName(opcode), (float)(GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType()), (float)(getMSTimeDiff(OldNextLenCheck-500,CurTime)),&movementInfo); } } if(delta > 100.0f && GetPlayer()->GetZoneId() != 2257) { Anti__ReportCheat("Tele hack",delta,LookupOpcodeName(opcode)); } // Check for waterwalking if(((movementInfo.flags & MOVEMENTFLAG_WATERWALKING) != 0) && ((movementInfo.flags ^ MOVEMENTFLAG_WATERWALKING) != 0) && // Client sometimes set waterwalk where it shouldn't do that... ((movementInfo.flags & MOVEMENTFLAG_JUMPING) == 0) && GetPlayer()->GetBaseMap()->IsUnderWater(movementInfo.x, movementInfo.y, movementInfo.z-6.0f) && !(GetPlayer()->HasAuraType(SPELL_AURA_WATER_WALK) || GetPlayer()->HasAuraType(SPELL_AURA_GHOST))) { Anti__CheatOccurred(CurTime,"Water walking",0.0f,NULL,0.0f,(uint32)(movementInfo.flags)); } // Check for walking upwards a mountain while not beeing able to do that /*if ((tg_z > 85.0f)) { Anti__CheatOccurred(CurTime,"Mount hack",tg_z,NULL,delta,delta_z); } */ static const float DIFF_OVERGROUND = 10.0f; float Anti__GroundZ = GetPlayer()->GetMap()->GetHeight(GetPlayer()->GetPositionX(),GetPlayer()->GetPositionY(),MAX_HEIGHT); float Anti__FloorZ = GetPlayer()->GetMap()->GetHeight(GetPlayer()->GetPositionX(),GetPlayer()->GetPositionY(),GetPlayer()->GetPositionZ()); float Anti__MapZ = ((Anti__FloorZ <= (INVALID_HEIGHT+5.0f)) ? Anti__GroundZ : Anti__FloorZ) + DIFF_OVERGROUND; if(!GetPlayer()->CanFly() && !GetPlayer()->GetBaseMap()->IsUnderWater(movementInfo.x, movementInfo.y, movementInfo.z-7.0f) && Anti__MapZ < GetPlayer()->GetPositionZ() && Anti__MapZ > (INVALID_HEIGHT+DIFF_OVERGROUND + 5.0f)) { static const float DIFF_AIRJUMP=25.0f; // 25 is realy high, but to many false positives... // Air-Jump-Detection definitively needs a better way to be detected... if((movementInfo.flags & (MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_FLYING | MOVEMENTFLAG_FLYING2)) != 0) // Fly Hack { Anti__CheatOccurred(CurTime,"Fly hack", ((uint8)(GetPlayer()->HasAuraType(SPELL_AURA_FLY))) + ((uint8)(GetPlayer()->HasAuraType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED))*2), NULL,GetPlayer()->GetPositionZ()-Anti__MapZ); } /* Need a better way to do that - currently a lot of fake alarms else if((Anti__MapZ+DIFF_AIRJUMP < GetPlayer()->GetPositionZ() && (movementInfo.flags & (MOVEMENTFLAG_FALLING | MOVEMENTFLAG_UNK4))==0) || (Anti__MapZ < GetPlayer()->GetPositionZ() && opcode==MSG_MOVE_JUMP)) { Anti__CheatOccurred(CurTime,"Possible Air Jump Hack", 0.0f,LookupOpcodeName(opcode),0.0f,movementInfo.flags,&movementInfo); }*/ } /* if(Anti__FloorZ < -199900.0f && Anti__GroundZ >= -199900.0f && GetPlayer()->GetPositionZ()+5.0f < Anti__GroundZ) { Anti__CheatOccurred(CurTime,"Teleport2Plane hack", GetPlayer()->GetPositionZ(),NULL,Anti__GroundZ); }*/ } // <<---- anti-cheat features /* process position-change */ WorldPacket data(opcode, recv_data.size()); movementInfo.time = getMSTime(); movementInfo.guid = mover->GetGUID(); WriteMovementInfo(&data, &movementInfo); GetPlayer()->SendMessageToSet(&data, false); if(plMover) // nothing is charmed, or player charmed { plMover->m_movementInfo = movementInfo; plMover->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); plMover->UpdateFallInformationIfNeed(movementInfo, opcode); if(plMover->isMovingOrTurning()) plMover->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); if(movementInfo.z < -500.0f) { if(plMover->InBattleGround() && plMover->GetBattleGround() && plMover->GetBattleGround()->HandlePlayerUnderMap(_player)) { // do nothing, the handle already did if returned true } else { // NOTE: this is actually called many times while falling // even after the player has been teleported away // TODO: discard movement packets after the player is rooted if(plMover->isAlive()) { plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // pl can be alive if GM/etc if(!plMover->isAlive()) { // change the death state to CORPSE to prevent the death timer from // starting in the next player update plMover->KillPlayer(); plMover->BuildPlayerRepop(); } } // cancel the death timer here if started plMover->RepopAtGraveyard(); } } } else // creature charmed { if(mover->IsInWorld()) { mover->GetMap()->CreatureRelocation((Creature*)mover, movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); if(((Creature*)mover)->isVehicle()) ((Vehicle*)mover)->RellocatePassengers(mover->GetMap()); } } }