void WorldSession::HandleGrantLevel(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: CMSG_GRANT_LEVEL"); uint64 guid; recvData.readPackGUID(guid); Player* target = ObjectAccessor::GetObjectInWorld(guid, _player); // check cheating uint8 levels = _player->GetGrantableLevels(); uint8 error = 0; if (!target) error = ERR_REFER_A_FRIEND_NO_TARGET; else if (levels == 0) error = ERR_REFER_A_FRIEND_INSUFFICIENT_GRANTABLE_LEVELS; else if (GetRecruiterId() != target->GetSession()->GetAccountId()) error = ERR_REFER_A_FRIEND_NOT_REFERRED_BY; else if (target->GetTeamId() != _player->GetTeamId()) error = ERR_REFER_A_FRIEND_DIFFERENT_FACTION; else if (target->getLevel() >= _player->getLevel()) error = ERR_REFER_A_FRIEND_TARGET_TOO_HIGH; else if (target->getLevel() >= sWorld->getIntConfig(CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL)) error = ERR_REFER_A_FRIEND_GRANT_LEVEL_MAX_I; else if (target->GetGroup() != _player->GetGroup()) error = ERR_REFER_A_FRIEND_NOT_IN_GROUP; if (error) { WorldPacket data(SMSG_REFER_A_FRIEND_FAILURE, 24); data << uint32(error); if (error == ERR_REFER_A_FRIEND_NOT_IN_GROUP) data << target->GetName(); SendPacket(&data); return; } WorldPacket data2(SMSG_PROPOSE_LEVEL_GRANT, 8); data2.append(_player->GetPackGUID()); target->GetSession()->SendPacket(&data2); }
void WorldSession::HandleMoveNotActiveMover(WorldPacket &recv_data) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_MOVE_NOT_ACTIVE_MOVER"); uint64 old_mover_guid; recv_data.readPackGUID(old_mover_guid); MovementInfo mi; ReadMovementInfo(recv_data, &mi); if (mi.Violated) { recv_data.rfinish(); return; } mi.guid = old_mover_guid; _player->m_movementInfo = mi; }
void WorldSession::HandleMoveNotActiveMover(WorldPacket &recvData) { ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_MOVE_NOT_ACTIVE_MOVER"); uint64 old_mover_guid; recvData.readPackGUID(old_mover_guid); // pussywizard: typical check for incomming movement packets if (!_player->m_mover || !_player->m_mover->IsInWorld() || _player->m_mover->IsDuringRemoveFromWorld() || old_mover_guid != _player->m_mover->GetGUID()) { recvData.rfinish(); // prevent warnings spam return; } MovementInfo mi; mi.guid = old_mover_guid; ReadMovementInfo(recvData, &mi); _player->m_mover->m_movementInfo = mi; }
void WorldSession::HandleMoveNotActiveMover(WorldPacket &recv_data) { sLog.outDebug("WORLD: Recvd CMSG_MOVE_NOT_ACTIVE_MOVER"); uint64 old_mover_guid; recv_data.readPackGUID(old_mover_guid); /*if (_player->m_mover->GetGUID() == old_mover_guid) { sLog.outError("HandleMoveNotActiveMover: incorrect mover guid: mover is " I64FMT " and should be " I64FMT " instead of " I64FMT, _player->m_mover->GetGUID(), _player->GetGUID(), old_mover_guid); recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; }*/ MovementInfo mi; mi.guid = old_mover_guid; ReadMovementInfo(recv_data, &mi); //ReadMovementInfo(recv_data, &_player->m_mover->m_movementInfo); _player->m_movementInfo = mi; }
void WorldSession::HandleAcceptGrantLevel(WorldPacket& recv_data) { sLog->outDebug("WORLD: CMSG_ACCEPT_LEVEL_GRANT"); uint64 guid; recv_data.readPackGUID(guid); Player *other = sObjectAccessor->GetObjectInWorld(guid, _player); if (!(other && other->GetSession())) return; if (GetAccountId() != other->GetSession()->GetRecruiterId()) return; if (other->GetGrantableLevels()) other->SetGrantableLevels(other->GetGrantableLevels() - 1); else return; _player->GiveLevel(_player->getLevel() + 1); }
void WorldSession::HandleCalendarAddEvent(WorldPacket& recvData) { uint64 guid = _player->GetGUID(); std::string title; std::string description; uint8 type; bool repeatable; uint32 maxInvites; int32 dungeonId; uint32 eventPackedTime; uint32 unkPackedTime; uint32 flags; uint64 inviteId = 0; uint64 invitee = 0; uint8 status; uint8 rank; recvData >> title >> description >> type >> repeatable >> maxInvites; recvData >> dungeonId; recvData.ReadPackedTime(eventPackedTime); recvData.ReadPackedTime(unkPackedTime); recvData >> flags; if (!(flags & CALENDAR_FLAG_WITHOUT_INVITES)) { uint32 inviteCount; recvData >> inviteCount; recvData.readPackGUID(invitee); recvData >> status >> rank; if (inviteCount != 1 || invitee != guid) { sLog->outError(LOG_FILTER_NETWORKIO, "HandleCalendarAddEvent: [" UI64FMTD "]: More than one invite (%d) or Invitee [" UI64FMTD "] differs", guid, inviteCount, invitee); return; } inviteId = sCalendarMgr->GetFreeInviteId(); }
void WorldSession::HandleMoveKnockBackAck(WorldPacket & recvData) { #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_MOVE_KNOCK_BACK_ACK"); #endif uint64 guid; recvData.readPackGUID(guid); // pussywizard: typical check for incomming movement packets if (!_player->m_mover || !_player->m_mover->IsInWorld() || _player->m_mover->IsDuringRemoveFromWorld() || guid != _player->m_mover->GetGUID()) { recvData.rfinish(); // prevent warnings spam return; } recvData.read_skip<uint32>(); // unk MovementInfo movementInfo; movementInfo.guid = guid; ReadMovementInfo(recvData, &movementInfo); _player->m_mover->m_movementInfo = movementInfo; WorldPacket data(MSG_MOVE_KNOCK_BACK, 66); data.appendPackGUID(guid); _player->m_mover->BuildMovementPacket(&data); // knockback specific info data << movementInfo.jump.sinAngle; data << movementInfo.jump.cosAngle; data << movementInfo.jump.xyspeed; data << movementInfo.jump.zspeed; _player->SendMessageToSet(&data, false); }
void WorldSession::HandleCalendarEventRemoveInvite(WorldPacket& recvData) { uint64 guid = _player->GetGUID(); uint64 invitee; uint64 eventId; uint64 ownerInviteId; // isn't it sender's inviteId? uint64 inviteId; recvData.readPackGUID(invitee); recvData >> inviteId >> ownerInviteId >> eventId; if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(eventId)) { if (calendarEvent->GetCreatorGUID() == invitee) { sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_DELETE_CREATOR_FAILED); return; } sCalendarMgr->RemoveInvite(inviteId, eventId, guid); } else sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_NO_INVITE); }
void WorldSession::HandleDismissControlledVehicle(WorldPacket &recvData) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_DISMISS_CONTROLLED_VEHICLE"); uint64 vehicleGUID = _player->GetCharmGUID(); if (!vehicleGUID) // something wrong here... { recvData.rfinish(); // prevent warnings spam return; } uint64 guid; recvData.readPackGUID(guid); MovementInfo mi; mi.guid = guid; ReadMovementInfo(recvData, &mi); _player->m_movementInfo = mi; _player->ExitVehicle(); }
void WorldSession::HandleMoveKnockBackAck( WorldPacket & recv_data ) { sLog.outDebug("CMSG_MOVE_KNOCK_BACK_ACK"); uint64 guid; // guid - unused if(!recv_data.readPackGUID(guid)) return; recv_data.read_skip<uint32>(); // unk MovementInfo movementInfo; uint32 unk1,unk2,unk3; recv_data >> unk1 >> unk2 >> unk3; ReadMovementInfo(recv_data, &movementInfo); //Save movement flags _player->m_movementInfo.SetMovementFlags(MovementFlags(movementInfo.flags)); //recv_data.read_skip<uint64>(); // guid //recv_data.read_skip<uint32>(); // unk //MovementInfo movementInfo; //ReadMovementInfo(recv_data, &movementInfo); }
void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) { uint16 opcode = recvData.GetOpcode(); Unit* mover = _player->m_mover; ASSERT(mover != NULL); // there must always be a mover Player* plrMover = mover->ToPlayer(); // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if (plrMover && plrMover->IsBeingTeleported()) { recvData.rfinish(); // prevent warnings spam return; } /* extract packet */ uint64 guid; recvData.readPackGUID(guid); MovementInfo movementInfo; movementInfo.guid = guid; ReadMovementInfo(recvData, &movementInfo); recvData.rfinish(); // prevent warnings spam // prevent tampered movement data if (guid != mover->GetGUID()) return; if (!movementInfo.pos.IsPositionValid()) { recvData.rfinish(); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) { // transports size limited // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) if (movementInfo.transport.pos.GetPositionX() > 50 || movementInfo.transport.pos.GetPositionY() > 50 || movementInfo.transport.pos.GetPositionZ() > 50) { recvData.rfinish(); // prevent warnings spam return; } if (!Trinity::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.transport.pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.transport.pos.GetPositionY(), movementInfo.pos.GetPositionZ() + movementInfo.transport.pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.transport.pos.GetOrientation())) { recvData.rfinish(); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plrMover) { if (!plrMover->GetTransport()) { // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just dismount 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.transport.guid) { plrMover->m_transport = *iter; (*iter)->AddPassenger(plrMover); break; } } } else if (plrMover->GetTransport()->GetGUID() != movementInfo.transport.guid) { bool foundNewTransport = false; plrMover->m_transport->RemovePassenger(plrMover); for (MapManager::TransportSet::const_iterator iter = sMapMgr->m_Transports.begin(); iter != sMapMgr->m_Transports.end(); ++iter) { if ((*iter)->GetGUID() == movementInfo.transport.guid) { foundNewTransport = true; plrMover->m_transport = *iter; (*iter)->AddPassenger(plrMover); break; } } if (!foundNewTransport) { plrMover->m_transport = NULL; movementInfo.transport.Reset(); } } } if (!mover->GetTransport() && !mover->GetVehicle()) { GameObject* go = mover->GetMap()->GetGameObject(movementInfo.transport.guid); if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; } } else if (plrMover && plrMover->GetTransport()) // if we were on a transport, leave { plrMover->m_transport->RemovePassenger(plrMover); plrMover->m_transport = NULL; movementInfo.transport.Reset(); } // 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 && plrMover && !plrMover->IsInFlight()) plrMover->HandleFall(movementInfo); if (plrMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plrMover->IsInWater()) { // now client not include swimming flag in case jumping under water plrMover->SetInWater(!plrMover->IsInWater() || plrMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ())); } if (plrMover) sAnticheatMgr->StartHackDetection(plrMover, movementInfo, opcode); /*----------------------*/ /* process position-change */ WorldPacket data(opcode, recvData.size()); movementInfo.time = getMSTime(); movementInfo.guid = mover->GetGUID(); WriteMovementInfo(&data, &movementInfo); mover->SendMessageToSet(&data, _player); mover->m_movementInfo = movementInfo; // this is almost never true (not sure why it is sometimes, but it is), normally use mover->IsVehicle() if (mover->GetVehicle()) { mover->SetOrientation(movementInfo.pos.GetOrientation()); return; } mover->UpdatePosition(movementInfo.pos); if (plrMover) // nothing is charmed, or player charmed { plrMover->UpdateFallInformationIfNeed(movementInfo, opcode); if (movementInfo.pos.GetPositionZ() < -500.0f) { if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(_player))) { // 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 (plrMover->IsAlive()) { plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // player can be alive if GM/etc // change the death state to CORPSE to prevent the death timer from // starting in the next player update if (!plrMover->IsAlive()) plrMover->KillPlayer(); } } } } }
void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket& recvData) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE"); Unit* vehicle_base = GetPlayer()->GetVehicleBase(); if (!vehicle_base) { recvData.rfinish(); // prevent warnings spam return; } VehicleSeatEntry const* seat = GetPlayer()->GetVehicle()->GetSeatForPassenger(GetPlayer()); if (!seat->CanSwitchFromSeat()) { recvData.rfinish(); // prevent warnings spam sLog->outError(LOG_FILTER_NETWORKIO, "HandleChangeSeatsOnControlledVehicle, Opcode: %u, Player %u tried to switch seats but current seatflags %u don't permit that.", recvData.GetOpcode(), GetPlayer()->GetGUIDLow(), seat->m_flags); return; } switch (recvData.GetOpcode()) { case CMSG_REQUEST_VEHICLE_PREV_SEAT: GetPlayer()->ChangeSeat(-1, false); break; case CMSG_REQUEST_VEHICLE_NEXT_SEAT: GetPlayer()->ChangeSeat(-1, true); break; /*case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: { uint64 guid; // current vehicle guid recvData.readPackGUID(guid); MovementInfo movementInfo; ReadMovementInfo(recvData, &movementInfo); vehicle_base->m_movementInfo = movementInfo; uint64 accessory; // accessory guid recvData.readPackGUID(accessory); int8 seatId; recvData >> seatId; if (vehicle_base->GetGUID() != guid) return; if (!accessory) GetPlayer()->ChangeSeat(-1, seatId > 0); // prev/next else if (Unit* vehUnit = Unit::GetUnit(*GetPlayer(), accessory)) { if (Vehicle* vehicle = vehUnit->GetVehicleKit()) if (vehicle->HasEmptySeat(seatId)) vehUnit->HandleSpellClick(GetPlayer(), seatId); } break; }*/ case CMSG_REQUEST_VEHICLE_SWITCH_SEAT: { uint64 guid; // current vehicle guid recvData.readPackGUID(guid); int8 seatId; recvData >> seatId; if (vehicle_base->GetGUID() == guid) GetPlayer()->ChangeSeat(seatId); else if (Unit* vehUnit = Unit::GetUnit(*GetPlayer(), guid)) if (Vehicle* vehicle = vehUnit->GetVehicleKit()) if (vehicle->HasEmptySeat(seatId)) vehUnit->HandleSpellClick(GetPlayer(), seatId); break; } default: break; } }
void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) { uint32 spellId; uint8 cast_count, unk_flags; recvPacket >> cast_count; recvPacket >> spellId; recvPacket >> unk_flags; // flags (if 0x02 - some additional data are received) // ignore for remote control state (for player case) Unit* mover = _player->m_mover; if (mover != _player && mover->GetTypeId() == TYPEID_PLAYER) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet return; } sLog.outDebug("WORLD: got cast spell packet, spellId - %u, cast_count: %u, unk_flags %u, data length = %i", spellId, cast_count, unk_flags, (uint32)recvPacket.size()); SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId ); if (!spellInfo) { sLog.outError("WORLD: unknown spell id %u", spellId); recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet return; } if (mover->GetTypeId() == TYPEID_PLAYER) { // not have spell in spellbook or spell passive and not casted by client if (!((Player*)mover)->HasActiveSpell (spellId) || IsPassiveSpell(spellId) ) { //cheater? kick? ban? recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet return; } } else { // not have spell in spellbook or spell passive and not casted by client if (!((Creature*)mover)->HasSpell(spellId) || IsPassiveSpell(spellId) ) { //cheater? kick? ban? recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet return; } } // Client is resending autoshot cast opcode when other spell is casted during shoot rotation // Skip it to prevent "interrupt" message if (IsAutoRepeatRangedSpell(spellInfo) && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL) && _player->GetCurrentSpell(CURRENT_AUTOREPEAT_SPELL)->m_spellInfo == spellInfo) return; // can't use our own spells when we're in possession of another unit, if (_player->isPossessing()) return; // client provided targets SpellCastTargets targets; if (!targets.read(&recvPacket,mover)) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet return; } // some spell cast packet including more data (for projectiles?) if (unk_flags & 0x02) { //recvPacket.read_skip<float>(); // unk1, coords? //recvPacket.read_skip<float>(); // unk1, coords? uint8 unk1; recvPacket >> unk1; // >> 1 or 0 if (unk1) { recvPacket.read_skip<uint32>(); // >> MSG_MOVE_STOP uint64 guid; // guid - unused if (!recvPacket.readPackGUID(guid)) return; MovementInfo movementInfo; ReadMovementInfo(recvPacket, &movementInfo); } }
void WorldSession::HandleCastSpellOpcode(WorldPacket& recvPacket) { uint32 spellId; uint8 cast_count, unk_flags; recvPacket >> cast_count; recvPacket >> spellId; recvPacket >> unk_flags; // flags (if 0x02 - some additional data are received) // ignore for remote control state (for player case) Unit* mover = _player->m_mover; if(mover != _player && mover->GetTypeId()==TYPEID_PLAYER) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet return; } // vehicle spells are handled by CMSG_PET_CAST_SPELL, // but player is still able to cast own spells if(_player->GetCharmGUID() && _player->GetCharmGUID() == _player->GetVehicleGUID()) mover = _player; sLog.outDebug("WORLD: got cast spell packet, spellId - %u, cast_count: %u, unk_flags %u, data length = %i", spellId, cast_count, unk_flags, (uint32)recvPacket.size()); SpellEntry const *spellInfo = sSpellStore.LookupEntry(spellId ); if(!spellInfo) { sLog.outError("WORLD: unknown spell id %u", spellId); recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet return; } //remove invisibility on casted hack if(spellId != 32612) if(mover->HasAura(32612)) mover->RemoveAurasDueToSpell(32612); if(mover->GetTypeId()==TYPEID_PLAYER) { // not have spell in spellbook or spell passive and not casted by client if (!((Player*)mover)->HasActiveSpell (spellId) || IsPassiveSpell(spellId) ) { //cheater? kick? ban? recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet return; } } else { // not have spell in spellbook or spell passive and not casted by client if (!((Creature*)mover)->HasSpell(spellId) || IsPassiveSpell(spellId) ) { //cheater? kick? ban? recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet return; } } // client provided targets SpellCastTargets targets; if(!targets.read(&recvPacket,mover)) { recvPacket.rpos(recvPacket.wpos()); // prevent spam at ignore packet return; } // some spell cast packet including more data (for projectiles?) if (unk_flags & 0x02) { recvPacket.read_skip<float>(); // unk1, coords? recvPacket.read_skip<float>(); // unk1, coords? uint8 unk1; recvPacket >> unk1; // >> 1 or 0 if(unk1) { recvPacket.read_skip<uint32>(); // >> MSG_MOVE_STOP uint64 guid; // guid - unused if(!recvPacket.readPackGUID(guid)) return; MovementInfo movementInfo; ReadMovementInfo(recvPacket, &movementInfo); } }
void WorldSession::HandleMovementOpcodes(WorldPacket & recv_data) { uint16 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; ASSERT(mover != NULL); // there must always be a 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; recv_data.readPackGUID(guid); MovementInfo movementInfo; movementInfo.guid = guid; ReadMovementInfo(recv_data, &movementInfo); /*----------------*/ /* if (recv_data.size() != recv_data.rpos()) { sLog.outError("MovementHandler: player %s (guid %d, account %u) sent a packet (opcode %u) that is " SIZEFMTD " bytes larger than it should be. Kicked as cheater.", _player->GetName(), _player->GetGUIDLow(), _player->GetSession()->GetAccountId(), recv_data.GetOpcode(), recv_data.size() - recv_data.rpos()); KickPlayer();*/ recv_data.rpos(recv_data.wpos()); // prevent warnings spam /* return; }*/ if (!movementInfo.pos.IsPositionValid()) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) { // 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_pos.GetPositionX() > 50 || movementInfo.t_pos.GetPositionY() > 50 || movementInfo.t_pos.GetPositionZ() > 50) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } if (!Trinity::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.t_pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.t_pos.GetPositionY(), movementInfo.pos.GetPositionZ() + movementInfo.t_pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.t_pos.GetOrientation())) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plMover && !plMover->GetTransport()) { // 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; } } } if (!mover->GetTransport() && !mover->GetVehicle()) { GameObject *go = mover->GetMap()->GetGameObject(movementInfo.t_guid); if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; } } else if (plMover && plMover->GetTransport()) // if we were on a transport, leave { plMover->m_transport->RemovePassenger(plMover); plMover->m_transport = NULL; movementInfo.t_pos.Relocate(0.0f, 0.0f, 0.0f, 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.flags & MOVEMENTFLAG_SWIMMING) != 0) != plMover->IsInWater()) { // now client not include swimming flag in case jumping under water plMover->SetInWater(!plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ())); } /*----------------------*/ /* process position-change */ WorldPacket data(opcode, recv_data.size()); movementInfo.time = getMSTime(); movementInfo.guid = mover->GetGUID(); WriteMovementInfo(&data, &movementInfo); mover->SendMessageToSet(&data, _player); mover->m_movementInfo = movementInfo; // this is almost never true (not sure why it is sometimes, but it is), normally use mover->IsVehicle() if (mover->GetVehicle()) { mover->SetOrientation(movementInfo.pos.GetOrientation()); return; } mover->SetPosition(movementInfo.pos); if (plMover) // nothing is charmed, or player charmed { plMover->UpdateFallInformationIfNeed(movementInfo, opcode); if (movementInfo.pos.GetPositionZ() < -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->canFly()) { bool flying = mover->IsFlying(); if (flying != ((mover->GetByteValue(UNIT_FIELD_BYTES_1, 3) & 0x02) ? true : false)) mover->SetFlying(flying); } }*/ //sLog.outString("Receive Movement Packet %s:", opcodeTable[recv_data.GetOpcode()]); //mover->OutMovementInfo(); }
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()); } } }
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); /*----------------*/ 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)) { // 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) { // 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) ); } /*----------------------*/ /* 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->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); plMover->m_movementInfo = movementInfo; 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); } }
void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recv_data) { sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Received CMSG_MOVE_SPLINE_DONE"); uint64 guid; // used only for proper packet read recv_data.readPackGUID(guid); MovementInfo movementInfo; // used only for proper packet read ReadMovementInfo(recv_data, &movementInfo); recv_data.read_skip<uint32>(); // unk // in taxi flight packet received in 2 case: // 1) end taxi path in far (multi-node) flight // 2) switch from one map to other in case multim-map taxi path // we need process only (1) uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination(); if (!curDest) return; TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest); // far teleport case if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId()) { if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) { // short preparations to continue flight FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); flight->SetCurrentNodeAfterTeleport(); TaxiPathNodeEntry const& node = flight->GetPath()[flight->GetCurrentNode()]; flight->SkipCurrentNode(); GetPlayer()->TeleportTo(curDestNode->map_id,node.x,node.y,node.z,GetPlayer()->GetOrientation()); } return; } uint32 destinationnode = GetPlayer()->m_taxi.NextTaxiDestination(); if (destinationnode > 0) // if more destinations to go { // current source node for next destination uint32 sourcenode = GetPlayer()->m_taxi.GetTaxiSource(); // Add to taximask middle hubs in taxicheat mode (to prevent having player with disabled taxicheat and not having back flight path) if (GetPlayer()->isTaxiCheater()) { if (GetPlayer()->m_taxi.SetTaximaskNode(sourcenode)) { WorldPacket data(SMSG_NEW_TAXI_PATH, 0); _player->GetSession()->SendPacket(&data); } } sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Taxi has to go from %u to %u", sourcenode, destinationnode); uint32 mountDisplayId = sObjectMgr->GetTaxiMountDisplayId(sourcenode, GetPlayer()->GetTeam()); uint32 path, cost; sObjectMgr->GetTaxiPath(sourcenode, destinationnode, path, cost); if (path && mountDisplayId) SendDoFlight(mountDisplayId, path, 1); // skip start fly node else GetPlayer()->m_taxi.ClearTaxiDestinations(); // clear problematic path and next return; } else GetPlayer()->m_taxi.ClearTaxiDestinations(); // not destinations, clear source node GetPlayer()->CleanupAfterTaxiFlight(); GetPlayer()->SetFallInformation(0, GetPlayer()->GetPositionZ()); if (GetPlayer()->pvpInfo.inHostileArea) GetPlayer()->CastSpell(GetPlayer(), 2479, true); }
void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket &recv_data) { sLog->outDebug("WORLD: Recvd CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE"); recv_data.hexlike(); Unit* vehicle_base = GetPlayer()->GetVehicleBase(); if (!vehicle_base) return; switch (recv_data.GetOpcodeEnum()) { case CMSG_REQUEST_VEHICLE_PREV_SEAT: GetPlayer()->ChangeSeat(-1, false); break; case CMSG_REQUEST_VEHICLE_NEXT_SEAT: GetPlayer()->ChangeSeat(-1, true); break; case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: { uint64 guid; // current vehicle guid recv_data.readPackGUID(guid); ReadMovementInfo(recv_data, &vehicle_base->m_movementInfo); uint64 accessory; // accessory guid recv_data.readPackGUID(accessory); int8 seatId; recv_data >> seatId; if (vehicle_base->GetGUID() != guid) return; if (!accessory) GetPlayer()->ChangeSeat(-1, seatId > 0); // prev/next else if (Unit *vehUnit = Unit::GetUnit(*GetPlayer(), accessory)) { if (Vehicle *vehicle = vehUnit->GetVehicleKit()) if (vehicle->HasEmptySeat(seatId)) GetPlayer()->EnterVehicle(vehUnit, seatId); } } break; case CMSG_REQUEST_VEHICLE_SWITCH_SEAT: { uint64 guid; // current vehicle guid recv_data.readPackGUID(guid); int8 seatId; recv_data >> seatId; if (vehicle_base->GetGUID() == guid) GetPlayer()->ChangeSeat(seatId); else if (Unit *vehUnit = Unit::GetUnit(*GetPlayer(), guid)) if (Vehicle *vehicle = vehUnit->GetVehicleKit()) if (vehicle->HasEmptySeat(seatId)) GetPlayer()->EnterVehicle(vehUnit, seatId); } break; default: break; } }
void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) { uint16 opcode = recvData.GetOpcode(); Unit* mover = _player->m_mover; ASSERT(mover != NULL); // there must always be a mover Player* plrMover = mover->ToPlayer(); // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if (plrMover && plrMover->IsBeingTeleported()) { recvData.rfinish(); // prevent warnings spam return; } /* extract packet */ uint64 guid; recvData.readPackGUID(guid); MovementInfo movementInfo; movementInfo.guid = guid; ReadMovementInfo(recvData, &movementInfo); recvData.rfinish(); // prevent warnings spam // prevent tampered movement data if (guid != mover->GetGUID()) return; if (!movementInfo.pos.IsPositionValid()) { recvData.rfinish(); // prevent warnings spam return; } // Tempfix for Drink Exploit (Thx jetwanx) if (mover->IsSitState() && movementInfo.GetMovementFlags() & (MOVEMENTFLAG_MASK_MOVING | MOVEMENTFLAG_MASK_TURNING)) mover->SetStandState(UNIT_STAND_STATE_STAND); /* handle special cases */ if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) { // transports size limited // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) if (movementInfo.transport.pos.GetPositionX() > 50 || movementInfo.transport.pos.GetPositionY() > 50 || movementInfo.transport.pos.GetPositionZ() > 50) { recvData.rfinish(); // prevent warnings spam return; } if (!Trinity::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.transport.pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.transport.pos.GetPositionY(), movementInfo.pos.GetPositionZ() + movementInfo.transport.pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.transport.pos.GetOrientation())) { recvData.rfinish(); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plrMover) { if (!plrMover->GetTransport()) { // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just dismount 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.transport.guid) { plrMover->m_transport = *iter; (*iter)->AddPassenger(plrMover); break; } } } else if (plrMover->GetTransport()->GetGUID() != movementInfo.transport.guid) { bool foundNewTransport = false; plrMover->m_transport->RemovePassenger(plrMover); for (MapManager::TransportSet::const_iterator iter = sMapMgr->m_Transports.begin(); iter != sMapMgr->m_Transports.end(); ++iter) { if ((*iter)->GetGUID() == movementInfo.transport.guid) { foundNewTransport = true; plrMover->m_transport = *iter; (*iter)->AddPassenger(plrMover); break; } } if (!foundNewTransport) { plrMover->m_transport = NULL; movementInfo.transport.Reset(); } } } if (!mover->GetTransport() && !mover->GetVehicle()) { GameObject* go = mover->GetMap()->GetGameObject(movementInfo.transport.guid); if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; } } else if (plrMover && plrMover->GetTransport()) // if we were on a transport, leave { plrMover->m_transport->RemovePassenger(plrMover); plrMover->m_transport = NULL; movementInfo.transport.Reset(); } // 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 && plrMover && !plrMover->IsInFlight()) plrMover->HandleFall(movementInfo); if (plrMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plrMover->IsInWater()) { // now client not include swimming flag in case jumping under water plrMover->SetInWater(!plrMover->IsInWater() || plrMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ())); } /*----------------------*/ /* process position-change */ WorldPacket data(opcode, recvData.size()); movementInfo.time = getMSTime(); movementInfo.guid = mover->GetGUID(); WriteMovementInfo(&data, &movementInfo); mover->SendMessageToSet(&data, _player); mover->m_movementInfo = movementInfo; // this is almost never true (not sure why it is sometimes, but it is), normally use mover->IsVehicle() if (mover->GetVehicle()) { mover->SetOrientation(movementInfo.pos.GetOrientation()); return; } mover->UpdatePosition(movementInfo.pos); if (plrMover) // nothing is charmed, or player charmed { plrMover->UpdateFallInformationIfNeed(movementInfo, opcode); float underMapValueZ; switch (plrMover->GetMapId()) { case 617: underMapValueZ = 3.0f; break; // Dalaran Sewers case 618: underMapValueZ = 28.0f; break; // Ring of Valor case 562: underMapValueZ = -10.0f; break; // Blade Edge Arena case 559: underMapValueZ = -18.0f; break; // Nagrand arena case 572: underMapValueZ = 28.0f; break; // Lordearon case 571: underMapValueZ = -400.0f; break; // Northrend default: underMapValueZ = -500.0f; break; } if (movementInfo.pos.GetPositionZ() < underMapValueZ) { if (underMapValueZ != -500) // For Custom Arena Zone { // Hackfix for ArenaUnderZ -> Teleport WHY TRINITY BREAK IT! if (plrMover->GetMapId() == 572) // Lordaeron Arena plrMover->TeleportTo(572, 1286.14868f, 1667.32f, 41.0f, 1.6f); // if (plrMover->GetMapId() == 559) // Nagrand Arena plrMover->TeleportTo(559, 4052.79868f, 2926.32f, 16.0f, 1.6f); if (plrMover->GetMapId() == 562) // Blade Edge arena 6237.797363 261.146088 2 0.7 plrMover->TeleportTo(562, 6237.79768f, 261.142f, 2.0f, 4.0f); if (plrMover->GetMapId() == 617) // Dalaran Arena 1292.31384 790.40667 8 plrMover->TeleportTo(617, 1292.34868f, 790.40f, 8.5f, 1.6f); } else if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(_player))) { // 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 (plrMover->IsAlive()) { plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // player can be alive if GM/etc // change the death state to CORPSE to prevent the death timer from // starting in the next player update if (!plrMover->IsAlive()) plrMover->KillPlayer(); } } } } }
void WorldSession::HandleMoveTeleportAck(WorldPacket& recvData) { ;//sLog->outDebug(LOG_FILTER_NETWORKIO, "MSG_MOVE_TELEPORT_ACK"); uint64 guid; recvData.readPackGUID(guid); uint32 flags, time; recvData >> flags >> time; // unused ;//sLog->outStaticDebug("Guid " UI64FMTD, guid); ;//sLog->outStaticDebug("Flags %u, time %u", flags, time/IN_MILLISECONDS); Player* plMover = _player->m_mover->ToPlayer(); if (!plMover || !plMover->IsBeingTeleportedNear()) return; if (guid != plMover->GetGUID()) return; plMover->SetSemaphoreTeleportNear(0); uint32 old_zone = plMover->GetZoneId(); WorldLocation const& dest = plMover->GetTeleportDest(); Position oldPos(*plMover); plMover->UpdatePosition(dest, true); // xinef: teleport pets if they are not unsummoned if (Pet* pet = plMover->GetPet()) { if (!pet->IsWithinDist3d(plMover, plMover->GetMap()->GetVisibilityRange()-5.0f)) pet->NearTeleportTo(plMover->GetPositionX(), plMover->GetPositionY(), plMover->GetPositionZ(), pet->GetOrientation()); } if (oldPos.GetExactDist2d(plMover) > 100.0f) { uint32 newzone, newarea; plMover->GetZoneAndAreaId(newzone, newarea, true); plMover->UpdateZone(newzone, newarea); // new zone if (old_zone != newzone) { // honorless target if (plMover->pvpInfo.IsHostile) plMover->CastSpell(plMover, 2479, true); // in friendly area else if (plMover->IsPvP() && !plMover->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP)) plMover->UpdatePvP(false, false); } } // resummon pet GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); //lets process all delayed operations on successful teleport GetPlayer()->ProcessDelayedOperations(); plMover->GetMotionMaster()->ReinitializeMovement(); // pussywizard: client forgets about losing control, resend it if (plMover->HasUnitState(UNIT_STATE_FLEEING|UNIT_STATE_CONFUSED) || plMover->IsCharmed()) // only in such cases SetClientControl(self, false) is sent plMover->SetClientControl(plMover, false, true); }
void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recv_data) { sLog.outDebug("WORLD: Received CMSG_MOVE_SPLINE_DONE"); uint64 guid; // used only for proper packet read if (!recv_data.readPackGUID(guid)) return; // movement anticheat code const Unit *mover = _player->m_mover; const Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; if (!plMover) return; // end movement anticheat MovementInfo movementInfo; // used only for proper packet read ReadMovementInfo(recv_data, &movementInfo); recv_data.read_skip<uint32>(); // unk // in taxi flight packet received in 2 case: // 1) end taxi path in far (multi-node) flight // 2) switch from one map to other in case multim-map taxi path // we need process only (1) uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination(); if (!curDest) { // movement anticheat code GetPlayer()->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); GetPlayer()->m_movementInfo = movementInfo; GetPlayer()->SetUnitMovementFlags(movementInfo.flags); // calc time deltas int32 cClientTimeDelta = 0; if (GetPlayer()->m_anti_LastClientTime != 0) { cClientTimeDelta = movementInfo.time - GetPlayer()->m_anti_LastClientTime; GetPlayer()->m_anti_DeltaClientTime += cClientTimeDelta; GetPlayer()->m_anti_LastClientTime = movementInfo.time; } else GetPlayer()->m_anti_LastClientTime = movementInfo.time; const uint64 cServerTime = getMSTime(); uint32 cServerTimeDelta = 0; if (GetPlayer()->m_anti_LastServerTime != 0) { cServerTimeDelta = cServerTime - GetPlayer()->m_anti_LastServerTime; GetPlayer()->m_anti_DeltaServerTime += cServerTimeDelta; GetPlayer()->m_anti_LastServerTime = cServerTime; } else GetPlayer()->m_anti_LastServerTime = cServerTime; // end movement anticheat return; } // movment anticheat const uint32 curloc = objmgr.GetNearestTaxiNode(movementInfo.x,movementInfo.y,movementInfo.z,GetPlayer()->GetMapId(),GetPlayer()->GetTeam(), curDest); // end movement anticheat // sLog.outBasic("AC2-%s > | xyzo: %f,%f,%fo(%f) flags[%X] | curloc: %d | destloc: %d ", // GetPlayer()->GetName(), movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o, // movementInfo.flags, curloc, curDest); TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest); if (curDestNode && curDestNode->map_id == GetPlayer()->GetMapId()) while (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) GetPlayer()->GetMotionMaster()->MovementExpired(false); // movement anticheat code GetPlayer()->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o); GetPlayer()->m_movementInfo = movementInfo; GetPlayer()->SetUnitMovementFlags(movementInfo.flags); // calc time deltas int32 cClientTimeDelta = 0; if (GetPlayer()->m_anti_LastClientTime != 0) { cClientTimeDelta = movementInfo.time - GetPlayer()->m_anti_LastClientTime; GetPlayer()->m_anti_DeltaClientTime += cClientTimeDelta; GetPlayer()->m_anti_LastClientTime = movementInfo.time; } else GetPlayer()->m_anti_LastClientTime = movementInfo.time; const uint64 cServerTime = getMSTime(); uint32 cServerTimeDelta = 0; if (GetPlayer()->m_anti_LastServerTime != 0) { cServerTimeDelta = cServerTime - GetPlayer()->m_anti_LastServerTime; GetPlayer()->m_anti_DeltaServerTime += cServerTimeDelta; GetPlayer()->m_anti_LastServerTime = cServerTime; } else GetPlayer()->m_anti_LastServerTime = cServerTime; // end movement anticheat // far teleport case if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId()) { if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) { // short preparations to continue flight FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); flight->SetCurrentNodeAfterTeleport(); Path::PathNode const& node = flight->GetPath()[flight->GetCurrentNode()]; flight->SkipCurrentNode(); GetPlayer()->TeleportTo(curDestNode->map_id,node.x,node.y,node.z,GetPlayer()->GetOrientation()); } return; } // movement anticheat fix - disallow unmount from taxi if (curloc != curDest) { // current source node for next destination uint32 sourcenode = GetPlayer()->m_taxi.GetTaxiSource(); uint16 MountId = objmgr.GetTaxiMountDisplayId(sourcenode, GetPlayer()->GetTeam()); uint32 path, cost; objmgr.GetTaxiPath(sourcenode, curDest, path, cost); if (path && MountId) SendDoFlight(MountId, path, 1); // skip start fly node else GetPlayer()->m_taxi.ClearTaxiDestinations(); // clear problematic path and next return; } // end movement anticheat uint32 destinationnode = GetPlayer()->m_taxi.NextTaxiDestination(); if (destinationnode > 0) // if more destinations to go { // current source node for next destination uint32 sourcenode = GetPlayer()->m_taxi.GetTaxiSource(); // Add to taximask middle hubs in taxicheat mode (to prevent having player with disabled taxicheat and not having back flight path) if (GetPlayer()->isTaxiCheater()) { if (GetPlayer()->m_taxi.SetTaximaskNode(sourcenode)) { WorldPacket data(SMSG_NEW_TAXI_PATH, 0); _player->GetSession()->SendPacket(&data); } } sLog.outDebug("WORLD: Taxi has to go from %u to %u", sourcenode, destinationnode); uint32 mountDisplayId = objmgr.GetTaxiMountDisplayId(sourcenode, GetPlayer()->GetTeam()); uint32 path, cost; objmgr.GetTaxiPath(sourcenode, destinationnode, path, cost); if (path && mountDisplayId) SendDoFlight(mountDisplayId, path, 1); // skip start fly node else GetPlayer()->m_taxi.ClearTaxiDestinations(); // clear problematic path and next return; } GetPlayer()->CleanupAfterTaxiFlight(); GetPlayer()->SetFallInformation(0, GetPlayer()->GetPositionZ()); if (GetPlayer()->pvpInfo.inHostileArea) GetPlayer()->CastSpell(GetPlayer(), 2479, true); }
void WorldSession::HandleCalendarAddEvent(WorldPacket& recvData) { uint64 guid = _player->GetGUID(); std::string title; std::string description; uint8 type; uint8 repeatable; uint32 maxInvites; int32 dungeonId; uint32 eventPackedTime; uint32 unkPackedTime; uint32 flags; recvData >> title >> description >> type >> repeatable >> maxInvites >> dungeonId; recvData.ReadPackedTime(eventPackedTime); recvData.ReadPackedTime(unkPackedTime); recvData >> flags; CalendarEvent calendarEvent(sCalendarMgr->GetFreeEventId(), guid, 0, CalendarEventType(type), dungeonId, time_t(eventPackedTime), flags, time_t(unkPackedTime), title, description); if (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement()) if (Player* creator = ObjectAccessor::FindPlayer(guid)) calendarEvent.SetGuildId(creator->GetGuildId()); if (calendarEvent.IsGuildAnnouncement()) { // 946684800 is 01/01/2000 00:00:00 - default response time CalendarInvite invite(0, calendarEvent.GetEventId(), 0, guid, 946684800, CALENDAR_STATUS_NOT_SIGNED_UP, CALENDAR_RANK_PLAYER, ""); // WARNING: By passing pointer to a local variable, the underlying method(s) must NOT perform any kind // of storage of the pointer as it will lead to memory corruption sCalendarMgr->AddInvite(&calendarEvent, &invite); } else { uint32 inviteCount; recvData >> inviteCount; SQLTransaction trans; if (inviteCount > 1) trans = CharacterDatabase.BeginTransaction(); // client limits the amount of players to be invited to 100 const uint32 MaxPlayerInvites = 100; for (uint32 i = 0; i < inviteCount && i < MaxPlayerInvites; ++i) { uint64 invitee = 0; uint8 status = 0; uint8 rank = 0; recvData.readPackGUID(invitee); recvData >> status >> rank; // 946684800 is 01/01/2000 00:00:00 - default response time CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), calendarEvent.GetEventId(), invitee, guid, 946684800, CalendarInviteStatus(status), CalendarModerationRank(rank), ""); sCalendarMgr->AddInvite(&calendarEvent, invite, trans); } if (inviteCount > 1) CharacterDatabase.CommitTransaction(trans); } sCalendarMgr->AddEvent(new CalendarEvent(calendarEvent, calendarEvent.GetEventId()), CALENDAR_SENDTYPE_ADD); }
void WorldSession::HandleMovementOpcodes(WorldPacket & recvData) { uint16 opcode = recvData.GetOpcode(); Unit* mover = _player->m_mover; ASSERT(mover != NULL); // there must always be a mover Player* plrMover = mover->ToPlayer(); // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if (plrMover && plrMover->IsBeingTeleported()) { recvData.rfinish(); // prevent warnings spam return; } /* extract packet */ uint64 guid; recvData.readPackGUID(guid); MovementInfo movementInfo; movementInfo.guid = guid; ReadMovementInfo(recvData, &movementInfo); recvData.rfinish(); // prevent warnings spam // pussywizard: typical check for incomming movement packets if (!mover || !mover->IsInWorld() || mover->IsDuringRemoveFromWorld() || guid != mover->GetGUID()) return; if (!movementInfo.pos.IsPositionValid()) { recvData.rfinish(); // prevent warnings spam return; } if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) { // T_POS ON VEHICLES! if (mover->GetVehicle()) movementInfo.transport.pos = mover->m_movementInfo.transport.pos; // transports size limited // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) if (movementInfo.transport.pos.GetPositionX() > 75.0f || movementInfo.transport.pos.GetPositionY() > 75.0f || movementInfo.transport.pos.GetPositionZ() > 75.0f || movementInfo.transport.pos.GetPositionX() < -75.0f || movementInfo.transport.pos.GetPositionY() < -75.0f || movementInfo.transport.pos.GetPositionZ() < -75.0f) { recvData.rfinish(); // prevent warnings spam return; } if (!Trinity::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.transport.pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.transport.pos.GetPositionY(), movementInfo.pos.GetPositionZ() + movementInfo.transport.pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.transport.pos.GetOrientation())) { recvData.rfinish(); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plrMover) { if (!plrMover->GetTransport()) { if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid)) { plrMover->m_transport = transport; transport->AddPassenger(plrMover); } } else if (plrMover->GetTransport()->GetGUID() != movementInfo.transport.guid) { bool foundNewTransport = false; plrMover->m_transport->RemovePassenger(plrMover); if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid)) { foundNewTransport = true; plrMover->m_transport = transport; transport->AddPassenger(plrMover); } if (!foundNewTransport) { plrMover->m_transport = NULL; movementInfo.transport.Reset(); } } } if (!mover->GetTransport() && !mover->GetVehicle()) movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; } else if (plrMover && plrMover->GetTransport()) // if we were on a transport, leave { plrMover->m_transport->RemovePassenger(plrMover); plrMover->m_transport = NULL; movementInfo.transport.Reset(); } if (plrMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plrMover->IsInWater()) { // now client not include swimming flag in case jumping under water plrMover->SetInWater(!plrMover->IsInWater() || plrMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ())); } // Dont allow to turn on walking if charming other player if (mover->GetGUID() != _player->GetGUID()) movementInfo.flags &= ~MOVEMENTFLAG_WALKING; uint32 mstime = World::GetGameTimeMS(); /*----------------------*/ if(m_clientTimeDelay == 0) m_clientTimeDelay = mstime > movementInfo.time ? std::min(mstime - movementInfo.time, (uint32)100) : 0; // Xinef: do not allow to move with UNIT_FLAG_DISABLE_MOVE if (mover->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE)) { // Xinef: skip moving packets if (movementInfo.HasMovementFlag(MOVEMENTFLAG_MASK_MOVING)) return; movementInfo.pos.Relocate(mover->GetPositionX(), mover->GetPositionY(), mover->GetPositionZ()); if (mover->GetTypeId() == TYPEID_UNIT) { movementInfo.transport.guid = mover->m_movementInfo.transport.guid; movementInfo.transport.pos.Relocate(mover->m_movementInfo.transport.pos.GetPositionX(), mover->m_movementInfo.transport.pos.GetPositionY(), mover->m_movementInfo.transport.pos.GetPositionZ()); movementInfo.transport.seat = mover->m_movementInfo.transport.seat; } } /* process position-change */ WorldPacket data(opcode, recvData.size()); //movementInfo.time = movementInfo.time + m_clientTimeDelay + MOVEMENT_PACKET_TIME_DELAY; movementInfo.time = mstime; // pussywizard: set to time of relocation (server time), constant addition may smoothen movement clientside, but client sees target on different position than the real serverside position movementInfo.guid = mover->GetGUID(); WriteMovementInfo(&data, &movementInfo); mover->SendMessageToSet(&data, _player); mover->m_movementInfo = movementInfo; // this is almost never true (pussywizard: only one packet when entering vehicle), normally use mover->IsVehicle() if (mover->GetVehicle()) { mover->SetOrientation(movementInfo.pos.GetOrientation()); mover->UpdatePosition(movementInfo.pos); return; } // pussywizard: previously always mover->UpdatePosition(movementInfo.pos); if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT && mover->GetTransport()) { float x, y, z, o; movementInfo.transport.pos.GetPosition(x, y, z, o); mover->GetTransport()->CalculatePassengerPosition(x, y, z, &o); mover->UpdatePosition(x, y, z, o); } else mover->UpdatePosition(movementInfo.pos); // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map). // Xinef: moved it here, previously StopMoving function called when player died relocated him to last saved coordinates (which were in air) if (opcode == MSG_MOVE_FALL_LAND && plrMover && !plrMover->IsInFlight() && (!plrMover->GetTransport() || plrMover->GetTransport()->IsStaticTransport())) plrMover->HandleFall(movementInfo); // Xinef: interrupt parachutes upon falling or landing in water if (opcode == MSG_MOVE_FALL_LAND || opcode == MSG_MOVE_START_SWIM) mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_LANDING); // Parachutes if (plrMover) // nothing is charmed, or player charmed { if (plrMover->IsSitState() && (movementInfo.flags & (MOVEMENTFLAG_MASK_MOVING | MOVEMENTFLAG_MASK_TURNING))) plrMover->SetStandState(UNIT_STAND_STATE_STAND); plrMover->UpdateFallInformationIfNeed(movementInfo, opcode); if (movementInfo.pos.GetPositionZ() < -500.0f) if (!plrMover->GetBattleground() || !plrMover->GetBattleground()->HandlePlayerUnderMap(_player)) { if (plrMover->IsAlive()) { plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // player can be alive if GM if (plrMover->IsAlive()) plrMover->KillPlayer(); } plrMover->StopMovingOnCurrentPos(); // pussywizard: moving corpse can't release spirit } } }
void WorldSession::HandleMovementOpcodes(WorldPacket & recv_data) { uint16 opcode = recv_data.GetOpcode(); recv_data.hexlike(); Unit *mover = _player->m_mover; ASSERT(mover != NULL); // there must always be a 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; recv_data.readPackGUID(guid); MovementInfo movementInfo; movementInfo.guid = guid; ReadMovementInfo(recv_data, &movementInfo); recv_data.rpos(recv_data.wpos()); // prevent warnings spam // prevent tampered movement data if (guid != mover->GetGUID()) return; if (!movementInfo.pos.IsPositionValid()) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) { // 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_pos.GetPositionX() > 50 || movementInfo.t_pos.GetPositionY() > 50 || movementInfo.t_pos.GetPositionZ() > 50) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } if (!Trinity::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.t_pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.t_pos.GetPositionY(), movementInfo.pos.GetPositionZ() + movementInfo.t_pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.t_pos.GetOrientation())) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plMover && !plMover->GetTransport()) { // 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; } } } if (!mover->GetTransport() && !mover->GetVehicle()) { GameObject *go = mover->GetMap()->GetGameObject(movementInfo.t_guid); if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; } } else if (plMover && plMover->GetTransport()) // if we were on a transport, leave { plMover->m_transport->RemovePassenger(plMover); plMover->m_transport = NULL; movementInfo.t_pos.Relocate(0.0f, 0.0f, 0.0f, 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.flags & MOVEMENTFLAG_SWIMMING) != 0) != plMover->IsInWater()) { // now client not include swimming flag in case jumping under water plMover->SetInWater(!plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ())); } /*----------------------*/ // ANTICHEAT CHECKS if (sWorld.getBoolConfig(CONFIG_ANTICHEAT_ENABLE)) { /*********************/ /* Exceptions: In Flight On Transport Being Teleported Can't free move Is GameMaster **********************/ // preventing escape from JAIL! MUAHAHHAHA if (plMover && plMover->GetAreaId() == 876 && !plMover->isGameMaster()) { if (plMover->GetBaseMap()->GetAreaId(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ()) != 876) { plMover->TeleportTo(1,16226.5f,16403.6f,-64.5f,3.2f); return; } } if (plMover && !plMover->isInFlight() && !plMover->GetTransport() && !plMover->IsBeingTeleported() && plMover->CanFreeMove() && !plMover->isGameMaster()) { // speed hack detection called! plMover->SpeedHackDetection(plMover->GetLastPacket(), movementInfo,opcode, plMover->GetLastSpeedRate()); if (plMover->isAlive()) plMover->WalkOnWaterHackDetection(plMover->GetLastPacket(),movementInfo); // fly hack detection called! plMover->FlyHackDetection(plMover->GetLastPacket(),movementInfo); } // save packet time for next control. if (plMover) { uint8 uiMoveType = 0; if (plMover->IsFlying()) uiMoveType = MOVE_FLIGHT; else if (plMover->IsUnderWater()) uiMoveType = MOVE_SWIM; else uiMoveType = MOVE_RUN; plMover->SaveLastPacket(movementInfo); plMover->SetLastSpeedRate(plMover->GetSpeedRate(UnitMoveType(uiMoveType)));//plMover->GetSpeed(UnitMoveType(uiMoveType)));//Rate(UnitMoveType(uiMoveType))); plMover->SetLastOpcode(opcode); } } /* process position-change */ WorldPacket data(opcode, recv_data.size()); movementInfo.time = getMSTime(); movementInfo.guid = mover->GetGUID(); WriteMovementInfo(&data, &movementInfo); mover->SendMessageToSet(&data, _player); mover->m_movementInfo = movementInfo; // this is almost never true (not sure why it is sometimes, but it is), normally use mover->IsVehicle() if (mover->GetVehicle()) { mover->SetOrientation(movementInfo.pos.GetOrientation()); return; } mover->SetPosition(movementInfo.pos); if (plMover) // nothing is charmed, or player charmed { plMover->UpdateFallInformationIfNeed(movementInfo, opcode); if (movementInfo.pos.GetPositionZ() < -500.0f) { if (!(plMover->InBattleground() && plMover->GetBattleground() && plMover->GetBattleground()->HandlePlayerUnderMap(_player))) { // 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(); } } } }
void WorldSession::HandleForceSpeedChangeAck(WorldPacket &recv_data) { Opcodes opcode = recv_data.GetOpcodeEnum(); sLog->outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); /* extract packet */ uint64 guid; uint32 unk1; float newspeed; recv_data.readPackGUID(guid); // now can skip not our packet if (_player->GetGUID() != guid) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } // continue parse packet recv_data >> unk1; // counter or moveEvent MovementInfo movementInfo; movementInfo.guid = guid; ReadMovementInfo(recv_data, &movementInfo); recv_data >> newspeed; /*----------------*/ // client ACK send one packet for mounted/run case and need skip all except last from its // in other cases anti-cheat check can be fail in false case UnitMoveType move_type; UnitMoveType force_move_type; static char const* move_type_name[MAX_MOVE_TYPE] = { "Walk", "Run", "RunBack", "Swim", "SwimBack", "TurnRate", "Flight", "FlightBack", "PitchRate" }; switch(opcode) { case CMSG_FORCE_WALK_SPEED_CHANGE_ACK: move_type = MOVE_WALK; force_move_type = MOVE_WALK; break; case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: move_type = MOVE_RUN; force_move_type = MOVE_RUN; break; case CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK: move_type = MOVE_RUN_BACK; force_move_type = MOVE_RUN_BACK; break; case CMSG_FORCE_SWIM_SPEED_CHANGE_ACK: move_type = MOVE_SWIM; force_move_type = MOVE_SWIM; break; case CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK: move_type = MOVE_SWIM_BACK; force_move_type = MOVE_SWIM_BACK; break; case CMSG_FORCE_TURN_RATE_CHANGE_ACK: move_type = MOVE_TURN_RATE; force_move_type = MOVE_TURN_RATE; break; case CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT; force_move_type = MOVE_FLIGHT; break; case CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT_BACK; force_move_type = MOVE_FLIGHT_BACK; break; case CMSG_FORCE_PITCH_RATE_CHANGE_ACK: move_type = MOVE_PITCH_RATE; force_move_type = MOVE_PITCH_RATE; break; default: sLog->outError("WorldSession::HandleForceSpeedChangeAck: Unknown move type opcode: %u", opcode); return; } // skip all forced speed changes except last and unexpected // in run/mounted case used one ACK and it must be skipped.m_forced_speed_changes[MOVE_RUN} store both. if (_player->m_forced_speed_changes[force_move_type] > 0) { --_player->m_forced_speed_changes[force_move_type]; if (_player->m_forced_speed_changes[force_move_type] > 0) return; } if (!_player->GetTransport() && fabs(_player->GetSpeed(move_type) - newspeed) > 0.01f) { if (_player->GetSpeed(move_type) > newspeed) // must be greater - just correct { sLog->outError("%sSpeedChange player %s is NOT correct (must be %f instead %f), force set to correct value", move_type_name[move_type], _player->GetName(), _player->GetSpeed(move_type), newspeed); _player->SetSpeed(move_type, _player->GetSpeedRate(move_type), true); } else // must be lesser - cheating { sLog->outBasic("Player %s from account id %u kicked for incorrect speed (must be %f instead %f)", _player->GetName(), _player->GetSession()->GetAccountId(), _player->GetSpeed(move_type), newspeed); _player->GetSession()->KickPlayer(); } } }
void WorldSession::HandleCalendarAddEvent(WorldPacket& recvData) { uint64 guid = _player->GetGUID(); std::string title; std::string description; uint8 type; uint8 repeatable; uint32 maxInvites; int32 dungeonId; uint32 eventPackedTime; uint32 unkPackedTime; uint32 flags; recvData >> title >> description >> type >> repeatable >> maxInvites >> dungeonId; recvData.ReadPackedTime(eventPackedTime); recvData.ReadPackedTime(unkPackedTime); recvData >> flags; // prevent events in the past // To Do: properly handle timezones and remove the "- time_t(86400L)" hack if (time_t(eventPackedTime) < (time(NULL) - time_t(86400L))) { recvData.rfinish(); return; } CalendarEvent* calendarEvent = new CalendarEvent(sCalendarMgr->GetFreeEventId(), guid, 0, CalendarEventType(type), dungeonId, time_t(eventPackedTime), flags, time_t(unkPackedTime), title, description); if (calendarEvent->IsGuildEvent() || calendarEvent->IsGuildAnnouncement()) if (Player* creator = ObjectAccessor::FindPlayer(guid)) calendarEvent->SetGuildId(creator->GetGuildId()); if (calendarEvent->IsGuildAnnouncement()) { // 946684800 is 01/01/2000 00:00:00 - default response time CalendarInvite invite(0, calendarEvent->GetEventId(), 0, guid, 946684800, CALENDAR_STATUS_NOT_SIGNED_UP, CALENDAR_RANK_PLAYER, ""); // WARNING: By passing pointer to a local variable, the underlying method(s) must NOT perform any kind // of storage of the pointer as it will lead to memory corruption sCalendarMgr->AddInvite(calendarEvent, &invite); } else { // client limits the amount of players to be invited to 100 const uint32 MaxPlayerInvites = 100; uint32 inviteCount; uint64 invitee[MaxPlayerInvites]; uint8 status[MaxPlayerInvites]; uint8 rank[MaxPlayerInvites]; memset(invitee, 0, sizeof(invitee)); memset(status, 0, sizeof(status)); memset(rank, 0, sizeof(rank)); try { recvData >> inviteCount; for (uint32 i = 0; i < inviteCount && i < MaxPlayerInvites; ++i) { recvData.readPackGUID(invitee[i]); recvData >> status[i] >> rank[i]; } } catch (ByteBufferException const&) { delete calendarEvent; calendarEvent = NULL; throw; } SQLTransaction trans; if (inviteCount > 1) trans = CharacterDatabase.BeginTransaction(); for (uint32 i = 0; i < inviteCount && i < MaxPlayerInvites; ++i) { // 946684800 is 01/01/2000 00:00:00 - default response time CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), calendarEvent->GetEventId(), invitee[i], guid, 946684800, CalendarInviteStatus(status[i]), CalendarModerationRank(rank[i]), ""); sCalendarMgr->AddInvite(calendarEvent, invite, trans); } if (inviteCount > 1) CharacterDatabase.CommitTransaction(trans); } sCalendarMgr->AddEvent(calendarEvent, CALENDAR_SENDTYPE_ADD); }
void WorldSession::HandleChangeSeatsOnControlledVehicle(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE"); Unit* vehicle_base = GetPlayer()->GetVehicleBase(); if (!vehicle_base) { recvData.rfinish(); // prevent warnings spam return; } VehicleSeatEntry const* seat = GetPlayer()->GetVehicle()->GetSeatForPassenger(GetPlayer()); if (!seat->CanSwitchFromSeat()) { recvData.rfinish(); // prevent warnings spam TC_LOG_ERROR("network", "HandleChangeSeatsOnControlledVehicle, Opcode: %u, Player %u tried to switch seats but current seatflags %u don't permit that.", recvData.GetOpcode(), GetPlayer()->GetGUIDLow(), seat->m_flags); return; } switch (recvData.GetOpcode()) { case CMSG_REQUEST_VEHICLE_PREV_SEAT: GetPlayer()->ChangeSeat(-1, false); break; case CMSG_REQUEST_VEHICLE_NEXT_SEAT: GetPlayer()->ChangeSeat(-1, true); break; case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: { static MovementStatusElements const accessoryGuid[] = { MSEExtraInt8, MSEHasGuidByte2, MSEHasGuidByte1, MSEHasGuidByte7, MSEHasGuidByte5, MSEHasGuidByte3, MSEHasGuidByte6, MSEHasGuidByte4, MSEHasGuidByte0, MSEGuidByte5, MSEGuidByte4, MSEGuidByte7, MSEGuidByte1, MSEGuidByte3, MSEGuidByte2, MSEGuidByte6, MSEGuidByte0, }; Movement::ExtraMovementStatusElement extra(accessoryGuid); MovementInfo movementInfo; GetPlayer()->ReadMovementInfo(recvData, &movementInfo, &extra); vehicle_base->m_movementInfo = movementInfo; uint64 accessory = extra.Data.guid; int8 seatId = extra.Data.byteData; if (vehicle_base->GetGUID() != movementInfo.guid) return; if (!accessory) GetPlayer()->ChangeSeat(-1, seatId > 0); // prev/next else if (Unit* vehUnit = Unit::GetUnit(*GetPlayer(), accessory)) { if (Vehicle* vehicle = vehUnit->GetVehicleKit()) if (vehicle->HasEmptySeat(seatId)) vehUnit->HandleSpellClick(GetPlayer(), seatId); } break; } case CMSG_REQUEST_VEHICLE_SWITCH_SEAT: { uint64 guid; // current vehicle guid recvData.readPackGUID(guid); int8 seatId; recvData >> seatId; if (vehicle_base->GetGUID() == guid) GetPlayer()->ChangeSeat(seatId); else if (Unit* vehUnit = Unit::GetUnit(*GetPlayer(), guid)) if (Vehicle* vehicle = vehUnit->GetVehicleKit()) if (vehicle->HasEmptySeat(seatId)) vehUnit->HandleSpellClick(GetPlayer(), seatId); break; } default: break; } }
void WorldSession::HandleMovementOpcodes(WorldPacket & recv_data) { uint32 opcode = recv_data.GetOpcode(); Unit* mover = _player->m_mover; ASSERT(mover != NULL); // there must always be a 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.rfinish(); // prevent warnings spam return; } /* extract packet */ uint64 guid; recv_data.readPackGUID(guid); MovementInfo movementInfo; movementInfo.guid = guid; ReadMovementInfo(recv_data, &movementInfo); recv_data.rfinish(); // prevent warnings spam // prevent tampered movement data if (guid != mover->GetGUID()) return; if (!movementInfo.pos.IsPositionValid()) { recv_data.rfinish(); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) { // 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_pos.GetPositionX() > 50 || movementInfo.t_pos.GetPositionY() > 50 || movementInfo.t_pos.GetPositionZ() > 50) { recv_data.rfinish(); // prevent warnings spam return; } if (!Trinity::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.t_pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.t_pos.GetPositionY(), movementInfo.pos.GetPositionZ() + movementInfo.t_pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.t_pos.GetOrientation())) { recv_data.rfinish(); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plMover && !plMover->GetTransport()) { // 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; } } } if (!mover->GetTransport() && !mover->GetVehicle()) { GameObject* go = mover->GetMap()->GetGameObject(movementInfo.t_guid); if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT) movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT; } } else if (plMover && plMover->GetTransport()) // if we were on a transport, leave { plMover->m_transport->RemovePassenger(plMover); plMover->m_transport = NULL; movementInfo.t_pos.Relocate(0.0f, 0.0f, 0.0f, 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.flags & MOVEMENTFLAG_SWIMMING) != 0) != plMover->IsInWater()) { // now client not include swimming flag in case jumping under water plMover->SetInWater(!plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ())); } /*----------------------*/ /* process position-change */ WorldPacket data(opcode, recv_data.size()); movementInfo.time = getMSTime(); movementInfo.guid = mover->GetGUID(); WriteMovementInfo(&data, &movementInfo); mover->SendMessageToSet(&data, _player); mover->m_movementInfo = movementInfo; // this is almost never true (not sure why it is sometimes, but it is), normally use mover->IsVehicle() if (mover->GetVehicle()) { mover->SetOrientation(movementInfo.pos.GetOrientation()); return; } mover->UpdatePosition(movementInfo.pos); if (plMover) // nothing is charmed, or player charmed { if (plMover->GetEmoteState() != 0 && opcode == MSG_MOVE_START_FORWARD && opcode != MSG_MOVE_SET_FACING && opcode != MSG_MOVE_START_TURN_LEFT && opcode != MSG_MOVE_START_TURN_RIGHT && opcode != MSG_MOVE_STOP_TURN) plMover->SetEmoteState(0); plMover->UpdateFallInformationIfNeed(movementInfo, opcode); float underMapValue = -500.0f; switch (plMover->GetMapId()) { case 617: underMapValue = 3.0f; break; // Dalaran Sewers case 618: underMapValue = 25.0f; break; // Ring of Valor case 572: underMapValue = 30.0f; break; // Ruins of Lordearon case 562: underMapValue = 0.0f; break; // Blade's Edge Arena case 559: underMapValue = 9.0f; break; // Nagrand Arena } if (movementInfo.pos.GetPositionZ() < underMapValue) { if (!(plMover->InBattleground() && plMover->GetBattleground() && plMover->GetBattleground()->HandlePlayerUnderMap(_player))) { // 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()); // player can be alive if GM/etc // change the death state to CORPSE to prevent the death timer from // starting in the next player update if (!plMover->isAlive()) plMover->KillPlayer(); } } } } }