void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) { bool moved = true; if(!_player->IsInWorld() || _player->m_uint32Values[UNIT_FIELD_CHARMEDBY] || _player->GetPlayerStatus() == TRANSFER_PENDING || _player->GetTaxiState()) return; // spell cancel on movement, for now only fishing is added Object * t_go = _player->m_SummonedObject; if (t_go) { if (t_go->GetEntry() == GO_FISHING_BOBBER) ((GameObject*)t_go)->EndFishing(GetPlayer(),true); } /************************************************************************/ /* Clear standing state to stand. */ /************************************************************************/ if( recv_data.GetOpcode() == MSG_MOVE_START_FORWARD ) _player->SetStandState( STANDSTATE_STAND ); /************************************************************************/ /* Make sure the packet is the correct size range. */ /************************************************************************/ if(recv_data.size() > 80) { Disconnect(); return; } /************************************************************************/ /* Read Movement Data Packet */ /************************************************************************/ movement_info.init(recv_data); /************************************************************************/ /* Update player movement state */ /************************************************************************/ switch( recv_data.GetOpcode() ) { case MSG_MOVE_START_FORWARD: case MSG_MOVE_START_BACKWARD: _player->moving = true; break; case MSG_MOVE_START_STRAFE_LEFT: case MSG_MOVE_START_STRAFE_RIGHT: _player->strafing = true; break; case MSG_MOVE_JUMP: _player->jumping = true; break; case MSG_MOVE_STOP: _player->moving = false; break; case MSG_MOVE_STOP_STRAFE: _player->strafing = false; break; case MSG_MOVE_FALL_LAND: _player->jumping = false; break; default: moved = false; break; } if( moved ) { if( !_player->moving && !_player->strafing && !_player->jumping ) _player->m_isMoving = false; else _player->m_isMoving = true; } /************************************************************************/ /* Anti-Fly Hack Checks */ /************************************************************************/ if( sWorld.antihack_flight && ( recv_data.GetOpcode() == CMSG_MOVE_FLY_START_AND_END || recv_data.GetOpcode() == CMSG_FLY_PITCH_DOWN_AFTER_UP ) && !( movement_info.flags & MOVEFLAG_SWIMMING || movement_info.flags & MOVEFLAG_FALLING || movement_info.flags & MOVEFLAG_FALLING_FAR || movement_info.flags & MOVEFLAG_FREE_FALLING ) && _player->flying_aura == 0 ) { if( sWorld.no_antihack_on_gm && _player->GetSession()->HasGMPermissions() ) { // Do nothing. } else { _player->BroadcastMessage( "Flyhack detected. In case the server is wrong then make a report how to reproduce this case. You will be logged out in 5 seconds." ); sEventMgr.AddEvent( _player, &Player::_Kick, EVENT_PLAYER_KICK, 5000, 1, 0 ); } } //update the detector if( sWorld.antihack_speed && !_player->GetTaxiState() && _player->m_TransporterGUID == 0 && !_player->GetSession()->GetPermissionCount()) { // simplified: just take the fastest speed. less chance of fuckups too float speed = ( _player->flying_aura ) ? _player->m_flySpeed : ( _player->m_swimSpeed >_player-> m_runSpeed ) ? _player->m_swimSpeed : _player->m_runSpeed; _player->SDetector->AddSample( movement_info.x, movement_info.y, getMSTime(), speed ); if( _player->SDetector->IsCheatDetected() ) _player->SDetector->ReportCheater( _player ); } /************************************************************************/ /* Remove Emote State */ /************************************************************************/ if(_player->m_uint32Values[UNIT_NPC_EMOTESTATE]) _player->SetUInt32Value(UNIT_NPC_EMOTESTATE,0); /************************************************************************/ /* Make sure the co-ordinates are valid. */ /************************************************************************/ if( !((movement_info.y >= _minY) && (movement_info.y <= _maxY)) || !((movement_info.x >= _minX) && (movement_info.x <= _maxX)) ) { Disconnect(); return; } /************************************************************************/ /* Dump movement flags - Wheee! */ /************************************************************************/ #if 0 printf("=========================================================\n"); printf("Full movement flags: 0x%.8X\n", movement_info.flags); uint32 z, b; for(z = 1, b = 1; b < 32;) { if(movement_info.flags & z) printf(" Bit %u (0x%.8X or %u) is set!\n", b, z, z); z <<= 1; b+=1; } printf("=========================================================\n"); #endif /************************************************************************/ /* Orientation dumping */ /************************************************************************/ #if 0 printf("Packet: 0x%03X (%s)\n", recv_data.GetOpcode(), LookupName( recv_data.GetOpcode(), g_worldOpcodeNames ) ); printf("Orientation: %.10f\n", movement_info.orientation); #endif /************************************************************************/ /* Calculate the timestamp of the packet we have to send out */ /************************************************************************/ size_t pos = (size_t)m_MoverWoWGuid.GetNewGuidLen() + 1; uint32 mstime = mTimeStamp(); int32 move_time; if(m_clientTimeDelay == 0) m_clientTimeDelay = mstime - movement_info.time; /************************************************************************/ /* Copy into the output buffer. */ /************************************************************************/ if(_player->m_inRangePlayers.size()) { move_time = (movement_info.time - (mstime - m_clientTimeDelay)) + MOVEMENT_PACKET_TIME_DELAY + mstime; memcpy(&movement_packet[pos], recv_data.contents(), recv_data.size()); movement_packet[pos+5]=0; /************************************************************************/ /* Distribute to all inrange players. */ /************************************************************************/ for(set<Player*>::iterator itr = _player->m_inRangePlayers.begin(); itr != _player->m_inRangePlayers.end(); ++itr) { #ifdef USING_BIG_ENDIAN *(uint32*)&movement_packet[pos+5] = swap32(move_time + (*itr)->GetSession()->m_moveDelayTime); #else *(uint32*)&movement_packet[pos+5] = uint32(move_time + (*itr)->GetSession()->m_moveDelayTime); #endif #if defined(ENABLE_COMPRESSED_MOVEMENT) && defined(ENABLE_COMPRESSED_MOVEMENT_FOR_PLAYERS) if( _player->GetPositionNC().Distance2DSq((*itr)->GetPosition()) >= World::m_movementCompressThreshold ) (*itr)->AppendMovementData( recv_data.GetOpcode(), uint16(recv_data.size() + pos), movement_packet ); else (*itr)->GetSession()->OutPacket(recv_data.GetOpcode(), uint16(recv_data.size() + pos), movement_packet); #else (*itr)->GetSession()->OutPacket(recv_data.GetOpcode(), uint16(recv_data.size() + pos), movement_packet); #endif } } /************************************************************************/ /* Falling damage checks */ /************************************************************************/ if( _player->blinked ) { _player->blinked = false; _player->m_fallDisabledUntil = UNIXTIME + 5; _player->SpeedCheatDelay( 2000 ); //some say they managed to trigger system with knockback. Maybe they moved in air ? } else { if( recv_data.GetOpcode() == MSG_MOVE_FALL_LAND ) { // player has finished falling //if _player->z_axisposition contains no data then set to current position if( !_player->z_axisposition ) _player->z_axisposition = movement_info.z; // calculate distance fallen uint32 falldistance = float2int32( _player->z_axisposition - movement_info.z ); /*if player is a rogue or druid(in cat form), then apply -17 modifier to fall distance. these checks need improving, low level rogue/druid should not receive this benefit*/ if( ( _player->getClass() == ROGUE ) || ( _player->GetShapeShift() == FORM_CAT ) ) { if( falldistance > 17 ) falldistance -=17; else falldistance = 1; } //checks that player has fallen more than 12 units, otherwise no damage will be dealt //falltime check is also needed here, otherwise sudden changes in Z axis position, such as using !recall, may result in death if( _player->isAlive() && !_player->GodModeCheat && falldistance > 12 && ( UNIXTIME >= _player->m_fallDisabledUntil ) && movement_info.FallTime > 1000 ) { // 1.7% damage for each unit fallen on Z axis over 13 uint32 health_loss = float2int32( float( _player->GetUInt32Value( UNIT_FIELD_MAXHEALTH ) * ( ( falldistance ) * 0.017 ) ) ); if( health_loss >= _player->GetUInt32Value( UNIT_FIELD_HEALTH ) ) health_loss = _player->GetUInt32Value( UNIT_FIELD_HEALTH ); _player->SendEnvironmentalDamageLog( _player->GetGUID(), DAMAGE_FALL, health_loss ); _player->DealDamage( _player, health_loss, 0, 0, 0 ); //_player->RemoveStealth(); // cebernic : why again? lost stealth by AURA_INTERRUPT_ON_ANY_DAMAGE_TAKEN already. } _player->z_axisposition = 0.0f; } else //whilst player is not falling, continuosly update Z axis position. //once player lands this will be used to determine how far he fell. if( !( movement_info.flags & MOVEFLAG_FALLING ) ) _player->z_axisposition = movement_info.z; } /************************************************************************/ /* Transporter Setup */ /************************************************************************/ if(!_player->m_lockTransportVariables) { if(_player->m_TransporterGUID && !movement_info.transGuid) { /* we left the transporter we were on */ if(_player->m_CurrentTransporter) { _player->m_CurrentTransporter->RemovePlayer(_player); _player->m_CurrentTransporter = NULL; } _player->m_TransporterGUID = 0; _player->SpeedCheatReset(); } else if(movement_info.transGuid) { if(!_player->m_TransporterGUID) { /* just walked into a transport */ if(_player->IsMounted()) _player->RemoveAura(_player->m_MountSpellId); _player->m_CurrentTransporter = objmgr.GetTransporter(GUID_LOPART(movement_info.transGuid)); if(_player->m_CurrentTransporter) _player->m_CurrentTransporter->AddPlayer(_player); /* set variables */ _player->m_TransporterGUID = movement_info.transGuid; _player->m_TransporterTime = movement_info.transTime; _player->m_TransporterX = movement_info.transX; _player->m_TransporterY = movement_info.transY; _player->m_TransporterZ = movement_info.transZ; } else { /* no changes */ _player->m_TransporterTime = movement_info.transTime; _player->m_TransporterX = movement_info.transX; _player->m_TransporterY = movement_info.transY; _player->m_TransporterZ = movement_info.transZ; } } /*float x = movement_info.x - movement_info.transX; float y = movement_info.y - movement_info.transY; float z = movement_info.z - movement_info.transZ; Transporter* trans = _player->m_CurrentTransporter; if(trans) sChatHandler.SystemMessageToPlr(_player, "Client t pos: %f %f\nServer t pos: %f %f Diff: %f %f", x,y, trans->GetPositionX(), trans->GetPositionY(), trans->CalcDistance(x,y,z), trans->CalcDistance(movement_info.x, movement_info.y, movement_info.z));*/ } /************************************************************************/ /* Anti-Speed Hack Checks */ /************************************************************************/ /************************************************************************/ /* Breathing System */ /************************************************************************/ _HandleBreathing(movement_info, _player, this); /************************************************************************/ /* Remove Spells */ /************************************************************************/ _player->RemoveAurasByInterruptFlag(AURA_INTERRUPT_ON_MOVEMENT); /************************************************************************/ /* Update our position in the server. */ /************************************************************************/ if( _player->m_CurrentCharm && _player->GetMapMgr() ) { Unit *cc = _player->GetMapMgr()->GetUnit( _player->m_CurrentCharm ); if( cc ) cc->SetPosition(movement_info.x, movement_info.y, movement_info.z, movement_info.orientation); } else { if(!_player->m_CurrentTransporter) { if( !_player->SetPosition(movement_info.x, movement_info.y, movement_info.z, movement_info.orientation) ) { _player->SetUInt32Value(UNIT_FIELD_HEALTH, 0); _player->KillPlayer(); } } else { _player->SetPosition(movement_info.x, movement_info.y, movement_info.z, movement_info.orientation + movement_info.transO, false); } } }
void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ) { if(!_player->IsInWorld() || _player->m_uint32Values[UNIT_FIELD_CHARMEDBY] || _player->GetPlayerStatus() == TRANSFER_PENDING || _player->GetTaxiState()) return; // spell cancel on movement, for now only fishing is added Object * t_go = _player->m_SummonedObject; uint32 mstime_s; if (t_go) { if (t_go->GetEntry() == GO_FISHING_BOBBER) ((GameObject*)t_go)->EndFishing(GetPlayer(),true); } /************************************************************************/ /* Make sure the packet is the correct size range. */ /************************************************************************/ if(recv_data.size() > 80) { Disconnect(); return; } /************************************************************************/ /* Read Movement Data Packet */ /************************************************************************/ movement_info.init(recv_data); /************************************************************************/ /* Update player movement state */ /************************************************************************/ if( recv_data.GetOpcode() == MSG_MOVE_STOP || recv_data.GetOpcode() == MSG_MOVE_STOP_STRAFE || recv_data.GetOpcode() == MSG_MOVE_STOP_TURN || recv_data.GetOpcode() == MSG_MOVE_FALL_LAND || ( recv_data.GetOpcode() == MSG_MOVE_SET_FACING && !(movement_info.flags & MOVEFLAG_MOVING_MASK) ) ) { if( _player->m_isMoving ) { #ifdef _DEBUG // printf("MOVING: FALSE (Packet %s)\n", LookupName( recv_data.GetOpcode(), g_worldOpcodeNames ) ); #endif mstime_s = getMSTime(); _player->_SpeedhackCheck(mstime_s); _player->m_isMoving = false; _player->_startMoveTime = 0; } } else { if( !_player->m_isMoving ) { #ifdef _DEBUG // printf("MOVING: TRUE (Packet %s)\n", LookupName( recv_data.GetOpcode(), g_worldOpcodeNames ) ); #endif mstime_s = getMSTime(); _player->m_isMoving = true; _player->_startMoveTime = mstime_s; _player->_lastHeartbeatPosition = _player->GetPosition(); } } /************************************************************************/ /* Remove Emote State */ /************************************************************************/ if(_player->m_uint32Values[UNIT_NPC_EMOTESTATE]) _player->SetUInt32Value(UNIT_NPC_EMOTESTATE,0); /************************************************************************/ /* Make sure the co-ordinates are valid. */ /************************************************************************/ if( !((movement_info.y >= _minY) && (movement_info.y <= _maxY)) || !((movement_info.x >= _minX) && (movement_info.x <= _maxX)) ) { Disconnect(); return; } /************************************************************************/ /* Dump movement flags - Wheee! */ /************************************************************************/ #if 0 printf("=========================================================\n"); printf("Full movement flags: 0x%.8X\n", movement_info.flags); uint32 z, b; for(z = 1, b = 1; b < 32;) { if(movement_info.flags & z) printf(" Bit %u (0x%.8X or %u) is set!\n", b, z, z); z <<= 1; b+=1; } printf("=========================================================\n"); #endif /************************************************************************/ /* Orientation dumping */ /************************************************************************/ #if 0 printf("Packet: 0x%03X (%s)\n", recv_data.GetOpcode(), LookupName( recv_data.GetOpcode(), g_worldOpcodeNames ) ); printf("Orientation: %.10f\n", movement_info.orientation); #endif /************************************************************************/ /* Anti-Hack Checks */ /************************************************************************/ if( !(HasGMPermissions() && sWorld.no_antihack_on_gm) && !_player->m_uint32Values[UNIT_FIELD_CHARM] && !_player->_heartbeatDisable) { /************************************************************************/ /* Anti-Teleport */ /************************************************************************/ if(sWorld.antihack_teleport && _player->m_position.Distance2DSq(movement_info.x, movement_info.y) > 5625.0f && _player->m_runSpeed < 50.0f && !_player->m_TransporterGUID) { sCheatLog.writefromsession(this, "Used teleport hack {3}, speed was %f", _player->m_runSpeed); Disconnect(); return; } } /************************************************************************/ /* Calculate the timestamp of the packet we have to send out */ /************************************************************************/ size_t pos = (size_t)m_MoverWoWGuid.GetNewGuidLen() + 1; uint32 mstime = mTimeStamp(); int32 move_time; if(m_clientTimeDelay == 0) m_clientTimeDelay = mstime - movement_info.time; /************************************************************************/ /* Copy into the output buffer. */ /************************************************************************/ if(_player->m_inRangePlayers.size()) { move_time = (movement_info.time - (mstime - m_clientTimeDelay)) + MOVEMENT_PACKET_TIME_DELAY + mstime; memcpy(&movement_packet[pos], recv_data.contents(), recv_data.size()); movement_packet[pos+5]=0; /************************************************************************/ /* Distribute to all inrange players. */ /************************************************************************/ for(set<Player*>::iterator itr = _player->m_inRangePlayers.begin(); itr != _player->m_inRangePlayers.end(); ++itr) { #ifdef USING_BIG_ENDIAN *(uint32*)&movement_packet[pos+5] = swap32(move_time + (*itr)->GetSession()->m_moveDelayTime); #else *(uint32*)&movement_packet[pos+5] = uint32(move_time + (*itr)->GetSession()->m_moveDelayTime); #endif #if defined(ENABLE_COMPRESSED_MOVEMENT) && defined(ENABLE_COMPRESSED_MOVEMENT_FOR_PLAYERS) if( _player->GetPositionNC().Distance2DSq((*itr)->GetPosition()) >= World::m_movementCompressThreshold ) (*itr)->AppendMovementData( recv_data.GetOpcode(), uint16(recv_data.size() + pos), movement_packet ); else (*itr)->GetSession()->OutPacket(recv_data.GetOpcode(), uint16(recv_data.size() + pos), movement_packet); #else (*itr)->GetSession()->OutPacket(recv_data.GetOpcode(), uint16(recv_data.size() + pos), movement_packet); #endif } } /************************************************************************/ /* Falling damage checks */ /************************************************************************/ if( _player->blinked ) { _player->blinked = false; _player->m_fallDisabledUntil = UNIXTIME + 5; _player->DelaySpeedHack( 5000 ); } else { if( recv_data.GetOpcode() == MSG_MOVE_FALL_LAND ) { // player has finished falling //if _player->z_axisposition contains no data then set to current position if( !_player->z_axisposition ) _player->z_axisposition = movement_info.z; // calculate distance fallen uint32 falldistance = float2int32( _player->z_axisposition - movement_info.z ); /*if player is a rogue or druid(in cat form), then apply -17 modifier to fall distance. these checks need improving, low level rogue/druid should not receive this benefit*/ if( ( _player->getClass() == ROGUE ) || ( _player->GetShapeShift() == FORM_CAT ) ) { if( falldistance > 17 ) falldistance -=17; else falldistance = 1; } //checks that player has fallen more than 12 units, otherwise no damage will be dealt //falltime check is also needed here, otherwise sudden changes in Z axis position, such as using !recall, may result in death if( _player->isAlive() && !_player->GodModeCheat && falldistance > 12 && ( UNIXTIME >= _player->m_fallDisabledUntil ) && movement_info.FallTime > 1000 ) { // 1.7% damage for each unit fallen on Z axis over 13 uint32 health_loss = float2int32( float( _player->GetUInt32Value( UNIT_FIELD_MAXHEALTH ) * ( ( falldistance - 12 ) * 0.017 ) ) ); if( health_loss >= _player->GetUInt32Value( UNIT_FIELD_HEALTH ) ) health_loss = _player->GetUInt32Value( UNIT_FIELD_HEALTH ); _player->SendEnvironmentalDamageLog( _player->GetGUID(), DAMAGE_FALL, health_loss ); _player->DealDamage( _player, health_loss, 0, 0, 0 ); _player->RemoveStealth(); // Fall Damage will cause stealthed units to lose stealth. } _player->z_axisposition = 0.0f; } else //whilst player is not falling, continuosly update Z axis position. //once player lands this will be used to determine how far he fell. if( !( movement_info.flags & MOVEFLAG_FALLING ) ) _player->z_axisposition = movement_info.z; } /************************************************************************/ /* Transporter Setup */ /************************************************************************/ if(!_player->m_lockTransportVariables) { if(_player->m_TransporterGUID && !movement_info.transGuid) { /* we left the transporter we were on */ if(_player->m_CurrentTransporter) { _player->m_CurrentTransporter->RemovePlayer(_player); _player->m_CurrentTransporter = NULL; } _player->m_TransporterGUID = 0; _player->ResetHeartbeatCoords(); } else if(movement_info.transGuid) { if(!_player->m_TransporterGUID) { /* just walked into a transport */ if(_player->IsMounted()) _player->RemoveAura(_player->m_MountSpellId); _player->m_CurrentTransporter = objmgr.GetTransporter(GUID_LOPART(movement_info.transGuid)); if(_player->m_CurrentTransporter) _player->m_CurrentTransporter->AddPlayer(_player); /* set variables */ _player->m_TransporterGUID = movement_info.transGuid; _player->m_TransporterUnk = movement_info.transUnk; _player->m_TransporterX = movement_info.transX; _player->m_TransporterY = movement_info.transY; _player->m_TransporterZ = movement_info.transZ; } else { /* no changes */ _player->m_TransporterUnk = movement_info.transUnk; _player->m_TransporterX = movement_info.transX; _player->m_TransporterY = movement_info.transY; _player->m_TransporterZ = movement_info.transZ; } } /*float x = movement_info.x - movement_info.transX; float y = movement_info.y - movement_info.transY; float z = movement_info.z - movement_info.transZ; Transporter* trans = _player->m_CurrentTransporter; if(trans) sChatHandler.SystemMessageToPlr(_player, "Client t pos: %f %f\nServer t pos: %f %f Diff: %f %f", x,y, trans->GetPositionX(), trans->GetPositionY(), trans->CalcDistance(x,y,z), trans->CalcDistance(movement_info.x, movement_info.y, movement_info.z));*/ } /************************************************************************/ /* Anti-Speed Hack Checks */ /************************************************************************/ /************************************************************************/ /* Breathing System */ /************************************************************************/ _HandleBreathing(movement_info, _player, this); /************************************************************************/ /* Remove Spells */ /************************************************************************/ _player->RemoveAurasByInterruptFlag(AURA_INTERRUPT_ON_MOVEMENT); /************************************************************************/ /* Update our position in the server. */ /************************************************************************/ if( _player->m_CurrentCharm ) _player->m_CurrentCharm->SetPosition(movement_info.x, movement_info.y, movement_info.z, movement_info.orientation); else { if(!_player->m_CurrentTransporter) { if( !_player->SetPosition(movement_info.x, movement_info.y, movement_info.z, movement_info.orientation) ) { _player->SetUInt32Value(UNIT_FIELD_HEALTH, 0); _player->KillPlayer(); } } else { _player->SetPosition(movement_info.x, movement_info.y, movement_info.z, movement_info.orientation + movement_info.transO, false); } } }