- Logging System is asyncronous to improve performance.
- Each msg and Logger has a Log Type and Log Level assigned. Each msg is assigned the Logger of same Log Type or "root" Logger is selected if there is no Logger configured for the given Log Type
- Loggers have a list of Appenders to send the msg to. The Msg in the Logger is not sent to Appenders if the msg LogLevel is lower than Logger LogLevel.
- There are three (at the moment) types of Appenders: Console, File or DB (this is WIP, not working ATM). Msg is not written to the resource if msg LogLevel is lower than Appender LogLevel.
- Appender and Console Log levels can be changed while server is active with command '.set loglevel (a/l) name level'
Explanation of use with Sample config:
Appender.Console.Type=1 (1 = Console)
Appender.Console.Level=2 (2 = Debug)
Appender.Server.Type=2 (2 = File)
Appender.Server.Level=3 (3 = Info)
Appender.Server.File=Server.log
Appender.SQL.Type=2 (2 = File)
Appender.SQL.Level=1 (1 = Trace)
Appender.SQL.File=sql.log
Appenders=Console Server (NOTE: SQL has not been included here... that will make core ignore the config for "SQL" as it's not in this list)
Logger.root.Type=0 (0 = Default - if it's not created by config, server will create it with LogLevel = DISABLED)
Logger.root.Level=5 (5 = Error)
Logger.root.Appenders=Console
Logger.SQL.Type=26 (26 = SQL)
Logger.SQL.Level=3 (2 = Debug)
Logger.SQL.Appenders=Console Server SQL
Logger.SomeRandomName.Type=24 (24 = Guild)
Logger.SomeRandomName.Level=5 (5 = Error)
Loggers=root SQL SomeRandomName
* At loading Appender SQL will be ignored, as it's not present on "Appenders"
* sLog->outDebug(LOG_FILTER_GUILD, "Some log msg related to Guilds")
- Msg is sent to Logger of Type LOG_FILTER_GUILD (24). Logger with name SomeRandomName is found but it's LogLevel = 5 and Msg LogLevel=2... Msg is not logged
* sLog->outError(LOG_FILTER_GUILD, "Some error log msg related to Guilds")
- Msg is sent to Logger of Type LOG_FILTER_GUILD (24). Logger with name SomeRandomeName is found with proper LogLevel but Logger does not have any Appenders assigned to that logger... Msg is not logged
* sLog->outDebug(LOG_FILTER_SQL, "Some msg related to SQLs")
- Msg is sent to Logger SQL (matches type), as it matches LogLevel the msg is sent to Appenders Console, Server and SQL
- Appender Console has lower Log Level: Msg is logged to Console
- Appender Server has higher Log Level: Msg is not logged to file
- Appender SQL has lower Log Level: Msg is logged to file sql.log
* sLog->outDebug(LOG_FILTER_BATTLEGROUND, "Some msg related to Battelgrounds")
- Msg is sent to Logger root (Type 0) as no Logger was found with Type LOG_FILTER_BATTLEGROUND (13). As Logger has higher LogLevel msg is not sent to any appender
* sLog->outError(LOG_FILTER_BATTLEGROUND, "Some error msg related to Battelgrounds")
- Msg is sent to Logger root (Type 0) as no Logger was found with Type LOG_FILTER_BATTLEGROUND (13). Msg has lower LogLevel and is sent to Appender Console
- Appender Console has lower LogLevel: Msg is logged to Console
597 lines
22 KiB
C++
Executable File
597 lines
22 KiB
C++
Executable File
/*
|
|
* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
|
|
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2 of the License, or (at your
|
|
* option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "Common.h"
|
|
#include "WorldPacket.h"
|
|
#include "WorldSession.h"
|
|
#include "Opcodes.h"
|
|
#include "Log.h"
|
|
#include "Corpse.h"
|
|
#include "Player.h"
|
|
#include "SpellAuras.h"
|
|
#include "MapManager.h"
|
|
#include "Transport.h"
|
|
#include "Battleground.h"
|
|
#include "WaypointMovementGenerator.h"
|
|
#include "InstanceSaveMgr.h"
|
|
#include "ObjectMgr.h"
|
|
|
|
void WorldSession::HandleMoveWorldportAckOpcode(WorldPacket & /*recv_data*/)
|
|
{
|
|
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: got MSG_MOVE_WORLDPORT_ACK.");
|
|
HandleMoveWorldportAckOpcode();
|
|
}
|
|
|
|
void WorldSession::HandleMoveWorldportAckOpcode()
|
|
{
|
|
// ignore unexpected far teleports
|
|
if (!GetPlayer()->IsBeingTeleportedFar())
|
|
return;
|
|
|
|
GetPlayer()->SetSemaphoreTeleportFar(false);
|
|
|
|
// get the teleport destination
|
|
WorldLocation const loc = GetPlayer()->GetTeleportDest();
|
|
|
|
// possible errors in the coordinate validity check
|
|
if (!MapManager::IsValidMapCoord(loc))
|
|
{
|
|
LogoutPlayer(false);
|
|
return;
|
|
}
|
|
|
|
// get the destination map entry, not the current one, this will fix homebind and reset greeting
|
|
MapEntry const* mEntry = sMapStore.LookupEntry(loc.GetMapId());
|
|
InstanceTemplate const* mInstance = sObjectMgr->GetInstanceTemplate(loc.GetMapId());
|
|
|
|
// reset instance validity, except if going to an instance inside an instance
|
|
if (GetPlayer()->m_InstanceValid == false && !mInstance)
|
|
GetPlayer()->m_InstanceValid = true;
|
|
|
|
Map* oldMap = GetPlayer()->GetMap();
|
|
if (GetPlayer()->IsInWorld())
|
|
{
|
|
sLog->outError(LOG_FILTER_NETWORKIO, "Player (Name %s) is still in world when teleported from map %u to new map %u", GetPlayer()->GetName(), oldMap->GetId(), loc.GetMapId());
|
|
oldMap->RemovePlayerFromMap(GetPlayer(), false);
|
|
}
|
|
|
|
// relocate the player to the teleport destination
|
|
Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), GetPlayer());
|
|
// the CanEnter checks are done in TeleporTo but conditions may change
|
|
// while the player is in transit, for example the map may get full
|
|
if (!newMap || !newMap->CanEnter(GetPlayer()))
|
|
{
|
|
sLog->outError(LOG_FILTER_NETWORKIO, "Map %d could not be created for player %d, porting player to homebind", loc.GetMapId(), GetPlayer()->GetGUIDLow());
|
|
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
|
|
return;
|
|
}
|
|
else
|
|
GetPlayer()->Relocate(&loc);
|
|
|
|
GetPlayer()->ResetMap();
|
|
GetPlayer()->SetMap(newMap);
|
|
|
|
GetPlayer()->SendInitialPacketsBeforeAddToMap();
|
|
if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer()))
|
|
{
|
|
sLog->outError(LOG_FILTER_NETWORKIO, "WORLD: failed to teleport player %s (%d) to map %d because of unknown reason!", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.GetMapId());
|
|
GetPlayer()->ResetMap();
|
|
GetPlayer()->SetMap(oldMap);
|
|
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
|
|
return;
|
|
}
|
|
|
|
// battleground state prepare (in case join to BG), at relogin/tele player not invited
|
|
// only add to bg group and object, if the player was invited (else he entered through command)
|
|
if (_player->InBattleground())
|
|
{
|
|
// cleanup setting if outdated
|
|
if (!mEntry->IsBattlegroundOrArena())
|
|
{
|
|
// We're not in BG
|
|
_player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE);
|
|
// reset destination bg team
|
|
_player->SetBGTeam(0);
|
|
}
|
|
// join to bg case
|
|
else if (Battleground* bg = _player->GetBattleground())
|
|
{
|
|
if (_player->IsInvitedForBattlegroundInstance(_player->GetBattlegroundId()))
|
|
bg->AddPlayer(_player);
|
|
}
|
|
}
|
|
|
|
GetPlayer()->SendInitialPacketsAfterAddToMap();
|
|
|
|
// flight fast teleport case
|
|
if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE)
|
|
{
|
|
if (!_player->InBattleground())
|
|
{
|
|
// short preparations to continue flight
|
|
FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top());
|
|
flight->Initialize(*GetPlayer());
|
|
return;
|
|
}
|
|
|
|
// battleground state prepare, stop flight
|
|
GetPlayer()->GetMotionMaster()->MovementExpired();
|
|
GetPlayer()->CleanupAfterTaxiFlight();
|
|
}
|
|
|
|
// resurrect character at enter into instance where his corpse exist after add to map
|
|
Corpse* corpse = GetPlayer()->GetCorpse();
|
|
if (corpse && corpse->GetType() != CORPSE_BONES && corpse->GetMapId() == GetPlayer()->GetMapId())
|
|
{
|
|
if (mEntry->IsDungeon())
|
|
{
|
|
GetPlayer()->ResurrectPlayer(0.5f, false);
|
|
GetPlayer()->SpawnCorpseBones();
|
|
}
|
|
}
|
|
|
|
bool allowMount = !mEntry->IsDungeon() || mEntry->IsBattlegroundOrArena();
|
|
if (mInstance)
|
|
{
|
|
Difficulty diff = GetPlayer()->GetDifficulty(mEntry->IsRaid());
|
|
if (MapDifficulty const* mapDiff = GetMapDifficultyData(mEntry->MapID, diff))
|
|
{
|
|
if (mapDiff->resetTime)
|
|
{
|
|
if (time_t timeReset = sInstanceSaveMgr->GetResetTimeFor(mEntry->MapID, diff))
|
|
{
|
|
uint32 timeleft = uint32(timeReset - time(NULL));
|
|
GetPlayer()->SendInstanceResetWarning(mEntry->MapID, diff, timeleft);
|
|
}
|
|
}
|
|
}
|
|
allowMount = mInstance->AllowMount;
|
|
}
|
|
|
|
// mount allow check
|
|
if (!allowMount)
|
|
_player->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
|
|
// update zone immediately, otherwise leave channel will cause crash in mtmap
|
|
uint32 newzone, newarea;
|
|
GetPlayer()->GetZoneAndAreaId(newzone, newarea);
|
|
GetPlayer()->UpdateZone(newzone, newarea);
|
|
|
|
// honorless target
|
|
if (GetPlayer()->pvpInfo.inHostileArea)
|
|
GetPlayer()->CastSpell(GetPlayer(), 2479, true);
|
|
|
|
// in friendly area
|
|
else if (GetPlayer()->IsPvP() && !GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP))
|
|
GetPlayer()->UpdatePvP(false, false);
|
|
|
|
// resummon pet
|
|
GetPlayer()->ResummonPetTemporaryUnSummonedIfAny();
|
|
|
|
//lets process all delayed operations on successful teleport
|
|
GetPlayer()->ProcessDelayedOperations();
|
|
}
|
|
|
|
void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data)
|
|
{
|
|
sLog->outDebug(LOG_FILTER_NETWORKIO, "MSG_MOVE_TELEPORT_ACK");
|
|
uint64 guid;
|
|
|
|
recv_data.readPackGUID(guid);
|
|
|
|
uint32 flags, time;
|
|
recv_data >> flags >> time;
|
|
sLog->outDebug(LOG_FILTER_NETWORKIO, "Guid " UI64FMTD, guid);
|
|
sLog->outDebug(LOG_FILTER_NETWORKIO, "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(false);
|
|
|
|
uint32 old_zone = plMover->GetZoneId();
|
|
|
|
WorldLocation const& dest = plMover->GetTeleportDest();
|
|
|
|
plMover->UpdatePosition(dest, true);
|
|
|
|
uint32 newzone, newarea;
|
|
plMover->GetZoneAndAreaId(newzone, newarea);
|
|
plMover->UpdateZone(newzone, newarea);
|
|
|
|
// new zone
|
|
if (old_zone != newzone)
|
|
{
|
|
// honorless target
|
|
if (plMover->pvpInfo.inHostileArea)
|
|
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();
|
|
}
|
|
|
|
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.t_pos.GetPositionX() > 50 || movementInfo.t_pos.GetPositionY() > 50 || movementInfo.t_pos.GetPositionZ() > 50)
|
|
{
|
|
recvData.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()))
|
|
{
|
|
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.t_guid)
|
|
{
|
|
plrMover->m_transport = *iter;
|
|
(*iter)->AddPassenger(plrMover);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (plrMover->GetTransport()->GetGUID() != movementInfo.t_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.t_guid)
|
|
{
|
|
foundNewTransport = true;
|
|
plrMover->m_transport = *iter;
|
|
(*iter)->AddPassenger(plrMover);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!foundNewTransport)
|
|
{
|
|
plrMover->m_transport = NULL;
|
|
movementInfo.t_pos.Relocate(0.0f, 0.0f, 0.0f, 0.0f);
|
|
movementInfo.t_time = 0;
|
|
movementInfo.t_seat = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 (plrMover && plrMover->GetTransport()) // if we were on a transport, leave
|
|
{
|
|
plrMover->m_transport->RemovePassenger(plrMover);
|
|
plrMover->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 && 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);
|
|
|
|
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::HandleForceSpeedChangeAck(WorldPacket &recv_data)
|
|
{
|
|
uint32 opcode = recv_data.GetOpcode();
|
|
sLog->outDebug(LOG_FILTER_NETWORKIO, "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.rfinish(); // 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(LOG_FILTER_NETWORKIO, "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(LOG_FILTER_NETWORKIO, "%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->outDebug(LOG_FILTER_GENERAL, "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::HandleSetActiveMoverOpcode(WorldPacket &recv_data)
|
|
{
|
|
sLog->outDebug(LOG_FILTER_NETWORKIO, "WORLD: Recvd CMSG_SET_ACTIVE_MOVER");
|
|
|
|
uint64 guid;
|
|
recv_data >> guid;
|
|
|
|
if (GetPlayer()->IsInWorld())
|
|
{
|
|
if (_player->m_mover->GetGUID() != guid)
|
|
sLog->outError(LOG_FILTER_NETWORKIO, "HandleSetActiveMoverOpcode: incorrect mover guid: mover is " UI64FMTD " (%s - Entry: %u) and should be " UI64FMTD, guid, GetLogNameForGuid(guid), GUID_ENPART(guid), _player->m_mover->GetGUID());
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
mi.guid = old_mover_guid;
|
|
|
|
_player->m_movementInfo = mi;
|
|
}
|
|
|
|
void WorldSession::HandleMountSpecialAnimOpcode(WorldPacket& /*recv_data*/)
|
|
{
|
|
WorldPacket data(SMSG_MOUNTSPECIAL_ANIM, 8);
|
|
data << uint64(GetPlayer()->GetGUID());
|
|
|
|
GetPlayer()->SendMessageToSet(&data, false);
|
|
}
|
|
|
|
void WorldSession::HandleMoveKnockBackAck(WorldPacket & recv_data)
|
|
{
|
|
sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_MOVE_KNOCK_BACK_ACK");
|
|
|
|
uint64 guid;
|
|
recv_data.readPackGUID(guid);
|
|
|
|
if (_player->m_mover->GetGUID() != guid)
|
|
return;
|
|
|
|
recv_data.read_skip<uint32>(); // unk
|
|
|
|
MovementInfo movementInfo;
|
|
ReadMovementInfo(recv_data, &movementInfo);
|
|
|
|
_player->m_movementInfo = movementInfo;
|
|
|
|
WorldPacket data(MSG_MOVE_KNOCK_BACK, 66);
|
|
data.appendPackGUID(guid);
|
|
_player->BuildMovementPacket(&data);
|
|
|
|
// knockback specific info
|
|
data << movementInfo.j_sinAngle;
|
|
data << movementInfo.j_cosAngle;
|
|
data << movementInfo.j_xyspeed;
|
|
data << movementInfo.j_zspeed;
|
|
|
|
_player->SendMessageToSet(&data, false);
|
|
}
|
|
|
|
void WorldSession::HandleMoveHoverAck(WorldPacket& recv_data)
|
|
{
|
|
sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_MOVE_HOVER_ACK");
|
|
|
|
uint64 guid; // guid - unused
|
|
recv_data.readPackGUID(guid);
|
|
|
|
recv_data.read_skip<uint32>(); // unk
|
|
|
|
MovementInfo movementInfo;
|
|
ReadMovementInfo(recv_data, &movementInfo);
|
|
|
|
recv_data.read_skip<uint32>(); // unk2
|
|
}
|
|
|
|
void WorldSession::HandleMoveWaterWalkAck(WorldPacket& recv_data)
|
|
{
|
|
sLog->outDebug(LOG_FILTER_NETWORKIO, "CMSG_MOVE_WATER_WALK_ACK");
|
|
|
|
uint64 guid; // guid - unused
|
|
recv_data.readPackGUID(guid);
|
|
|
|
recv_data.read_skip<uint32>(); // unk
|
|
|
|
MovementInfo movementInfo;
|
|
ReadMovementInfo(recv_data, &movementInfo);
|
|
|
|
recv_data.read_skip<uint32>(); // unk2
|
|
}
|
|
|
|
void WorldSession::HandleSummonResponseOpcode(WorldPacket& recv_data)
|
|
{
|
|
if (!_player->isAlive() || _player->isInCombat())
|
|
return;
|
|
|
|
uint64 summoner_guid;
|
|
bool agree;
|
|
recv_data >> summoner_guid;
|
|
recv_data >> agree;
|
|
|
|
_player->SummonIfPossible(agree);
|
|
}
|