diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 33e0ebe5d..d310563ce 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -4431,12 +4431,6 @@ void Player::SetMovement(PlayerMovementType pType) const PackedGuid& guid = GetPackGUID(); switch (pType) { - case MOVE_ROOT: - data.Initialize(SMSG_FORCE_MOVE_ROOT, guid.size() + 4); - break; - case MOVE_UNROOT: - data.Initialize(SMSG_FORCE_MOVE_UNROOT, guid.size() + 4); - break; case MOVE_WATER_WALK: data.Initialize(SMSG_MOVE_WATER_WALK, guid.size() + 4); break; @@ -4490,10 +4484,10 @@ void Player::BuildPlayerRepop() SetHealth(1); // convert player body to ghost SetMovement(MOVE_WATER_WALK); SetWaterWalking(true); - if (!GetSession()->isLogingOut()) - { - SetMovement(MOVE_UNROOT); - } + + if (!IsImmobilizedState()) + SendMoveRoot(false); + RemoveUnitFlag(UNIT_FLAG_SKINNABLE); // BG - remove insignia related int32 corpseReclaimDelay = CalculateCorpseReclaimDelay(); if (corpseReclaimDelay >= 0) @@ -4530,7 +4524,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) setDeathState(DeathState::Alive); SetMovement(MOVE_LAND_WALK); - SetMovement(MOVE_UNROOT); + SendMoveRoot(false); SetWaterWalking(false); m_deathTimer = 0; @@ -4594,7 +4588,7 @@ void Player::KillPlayer() if (IsFlying() && !GetTransport()) GetMotionMaster()->MoveFall(); - SetMovement(MOVE_ROOT); + SendMoveRoot(true); StopMirrorTimers(); //disable timers(bars) @@ -11703,9 +11697,6 @@ void Player::SendInitialPacketsAfterAddToMap() GetZoneAndAreaId(newzone, newarea); UpdateZone(newzone, newarea); // also call SendInitWorldStates(); - if (HasStunAura()) - SetMovement(MOVE_ROOT); - WorldPacket setCompoundState(SMSG_MULTIPLE_MOVES, 100); setCompoundState << uint32(0); // size placeholder diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 74c89cc96..0e03f58d1 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -448,8 +448,6 @@ typedef std::list ItemDurationList; enum PlayerMovementType { - MOVE_ROOT = 1, - MOVE_UNROOT = 2, MOVE_WATER_WALK = 3, MOVE_LAND_WALK = 4 }; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 4a26367b5..eb1a3f06b 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -18293,73 +18293,65 @@ void Unit::SetStunned(bool apply) } } -void Unit::SetRooted(bool apply, bool isStun) +void Unit::SetRooted(bool apply, bool stun, bool logout) { + const uint32 state = (stun ? (logout ? UNIT_STATE_LOGOUT_TIMER : UNIT_STATE_STUNNED) : UNIT_STATE_ROOT); + if (apply) { - // MOVEMENTFLAG_ROOT cannot be used in conjunction with MOVEMENTFLAG_MASK_MOVING (tested 3.3.5a) - // this will freeze clients. That's why we remove MOVEMENTFLAG_MASK_MOVING before - // setting MOVEMENTFLAG_ROOT - RemoveUnitMovementFlag(MOVEMENTFLAG_MASK_MOVING); + AddUnitState(state); - if (IsFalling()) - { - AddUnitMovementFlag(MOVEMENTFLAG_PENDING_ROOT); - } - else - { - AddUnitMovementFlag(MOVEMENTFLAG_ROOT); - } - - // Creature specific - if (!IsPlayer()) - { - if (isStun && movespline->Finalized()) - { - StopMovingOnCurrentPos(); - } - else - { - StopMoving(); - } - } - - if (m_movedByPlayer) - { - WorldPacket data(SMSG_FORCE_MOVE_ROOT, GetPackGUID().size() + 4); - data << GetPackGUID(); - data << m_movedByPlayer->ToPlayer()->GetSession()->GetOrderCounter(); // movement counter - m_movedByPlayer->ToPlayer()->SendDirectMessage(&data); - m_movedByPlayer->ToPlayer()->GetSession()->IncrementOrderCounter(); - } - else - { - WorldPacket data(SMSG_SPLINE_MOVE_ROOT, GetPackGUID().size()); - data << GetPackGUID(); - SendMessageToSet(&data, true); - } + SendMoveRoot(true); } else { - RemoveUnitMovementFlag(MOVEMENTFLAG_ROOT | MOVEMENTFLAG_PENDING_ROOT); + ClearUnitState(state); - if (!HasUnitState(UNIT_STATE_STUNNED)) // prevent moving if it also has stun effect + // Prevent giving ability to move if more immobilizers are active + if (!IsImmobilizedState()) + SendMoveRoot(false); + } +} + +void Unit::SendMoveRoot(bool apply) +{ + const Player* client = GetClientControlling(); + + // Apply flags in-place when unit currently is not controlled by a player + if (!client) + { + if (apply) { - if (m_movedByPlayer) - { - WorldPacket data(SMSG_FORCE_MOVE_UNROOT, GetPackGUID().size() + 4); - data << GetPackGUID(); - data << m_movedByPlayer->ToPlayer()->GetSession()->GetOrderCounter(); // movement counter - m_movedByPlayer->ToPlayer()->SendDirectMessage(&data); - m_movedByPlayer->ToPlayer()->GetSession()->IncrementOrderCounter(); - } - else - { - WorldPacket data(SMSG_SPLINE_MOVE_UNROOT, GetPackGUID().size()); - data << GetPackGUID(); - SendMessageToSet(&data, true); - } + m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_MASK_MOVING_FLY); + m_movementInfo.AddMovementFlag(MOVEMENTFLAG_ROOT); + if (!client) + StopMoving(); } + else + m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ROOT); + } + + if (!IsInWorld()) + return; + + const PackedGuid& guid = GetPackGUID(); + // Wrath+ spline root: when unit is currently not controlled by a player + if (!client) + { + WorldPacket data(apply ? SMSG_SPLINE_MOVE_ROOT : SMSG_SPLINE_MOVE_UNROOT, guid.size()); + data << guid; + SendMessageToSet(&data, true); + } + // Wrath+ force root: when unit is controlled by a player + else + { + auto const counter = client->GetSession()->GetOrderCounter(); + + WorldPacket data(apply ? SMSG_FORCE_MOVE_ROOT : SMSG_FORCE_MOVE_UNROOT, guid.size() + 4); + data << guid; + data << counter; + client->GetSession()->SendPacket(&data); + client->GetSession()->IncrementOrderCounter(); } } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 726addd94..290282510 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -2066,7 +2066,8 @@ protected: void SetFeared(bool apply, Unit* fearedBy = nullptr, bool isFear = false); void SetConfused(bool apply); void SetStunned(bool apply); - void SetRooted(bool apply, bool isStun = false); + void SetRooted(bool apply, bool stun = false, bool logout = false); + void SendMoveRoot(bool state); //----------- Protected variables ----------// UnitAI* i_AI; diff --git a/src/server/game/Entities/Unit/UnitDefines.h b/src/server/game/Entities/Unit/UnitDefines.h index 1875a96aa..72d19e7eb 100644 --- a/src/server/game/Entities/Unit/UnitDefines.h +++ b/src/server/game/Entities/Unit/UnitDefines.h @@ -197,7 +197,9 @@ enum UnitState UNIT_STATE_IGNORE_PATHFINDING = 0x10000000, // do not use pathfinding in any MovementGenerator UNIT_STATE_NO_ENVIRONMENT_UPD = 0x20000000, - UNIT_STATE_NO_COMBAT_MOVEMENT = 0x40000000, // serverside only - should not be changed outside the core and should be placed at the end + // serverside region + UNIT_STATE_NO_COMBAT_MOVEMENT = 0x40000000, // should not be changed outside the core and should be placed at the end + UNIT_STATE_LOGOUT_TIMER = 0x80000000, // Unit is logging out UNIT_STATE_ALL_STATE_SUPPORTED = UNIT_STATE_DIED | UNIT_STATE_MELEE_ATTACKING | UNIT_STATE_STUNNED | UNIT_STATE_ROAMING | UNIT_STATE_CHASE | UNIT_STATE_FLEEING | UNIT_STATE_IN_FLIGHT | UNIT_STATE_FOLLOW | UNIT_STATE_ROOT | UNIT_STATE_CONFUSED diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index e18b7365e..ac7ab2783 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -1164,8 +1164,11 @@ void WorldSession::HandlePlayerLoginToCharInWorld(Player* pCurrChar) SendPacket(&data); // Xinef: fix possible problem with flag UNIT_FLAG_STUNNED added during logout - if (!pCurrChar->HasUnitState(UNIT_STATE_STUNNED)) + if (pCurrChar->HasUnitState(UNIT_STATE_LOGOUT_TIMER)) + { + pCurrChar->SetRooted(false, true, true); pCurrChar->RemoveUnitFlag(UNIT_FLAG_STUNNED); + } pCurrChar->SendInitialPacketsBeforeAddToMap(); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index bb2651c02..03c91c298 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -468,7 +468,7 @@ void WorldSession::HandleLogoutRequestOpcode(WorldPackets::Character::LogoutRequ GetPlayer()->SetStandState(UNIT_STAND_STATE_SIT); } - GetPlayer()->SetRooted(true); + GetPlayer()->SetRooted(true, true, true); GetPlayer()->SetUnitFlag(UNIT_FLAG_STUNNED); } @@ -492,7 +492,7 @@ void WorldSession::HandleLogoutCancelOpcode(WorldPackets::Character::LogoutCance // not remove flags if can't free move - its not set in Logout request code. if (GetPlayer()->CanFreeMove()) { - GetPlayer()->SetRooted(false); + GetPlayer()->SetRooted(false, true, true); GetPlayer()->SetStandState(UNIT_STAND_STATE_STAND); GetPlayer()->RemoveUnitFlag(UNIT_FLAG_STUNNED); diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index c738365b5..6bf1b899b 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -967,79 +967,36 @@ void WorldSession::ComputeNewClockDelta() void WorldSession::HandleMoveRootAck(WorldPacket& recvData) { + LOG_DEBUG("network", "WORLD: {}", GetOpcodeNameForLogging((Opcodes)recvData.GetOpcode())); + ObjectGuid guid; - recvData >> guid.ReadAsPacked(); - - Unit* mover = _player->m_mover; - if (!mover || guid != mover->GetGUID()) - { - recvData.rfinish(); // prevent warnings spam - return; - } - - uint32 movementCounter; - recvData >> movementCounter; - + uint32 counter; MovementInfo movementInfo; - movementInfo.guid = guid; + recvData >> guid.ReadAsPacked(); + recvData >> counter; ReadMovementInfo(recvData, &movementInfo); - /* process position-change */ - int64 movementTime = (int64) movementInfo.time + _timeSyncClockDelta; - if (_timeSyncClockDelta == 0 || movementTime < 0 || movementTime > 0xFFFFFFFF) - { - LOG_INFO("misc", "The computed movement time using clockDelta is erronous. Using fallback instead"); - movementInfo.time = getMSTime(); - } - else - { - movementInfo.time = (uint32)movementTime; - } - - movementInfo.guid = mover->GetGUID(); - mover->m_movementInfo = movementInfo; - mover->UpdatePosition(movementInfo.pos); - -} - -void WorldSession::HandleMoveUnRootAck(WorldPacket& recvData) -{ - ObjectGuid guid; - recvData >> guid.ReadAsPacked(); - Unit* mover = _player->m_mover; - if (!mover || guid != mover->GetGUID()) - { - recvData.rfinish(); // prevent warnings spam + + if (mover->GetGUID() != guid) return; - } - uint32 movementCounter; - recvData >> movementCounter; - - MovementInfo movementInfo; - movementInfo.guid = guid; - ReadMovementInfo(recvData, &movementInfo); - - /* process position-change */ - int64 movementTime = (int64) movementInfo.time + _timeSyncClockDelta; - if (_timeSyncClockDelta == 0 || movementTime < 0 || movementTime > 0xFFFFFFFF) + if (recvData.GetOpcode() == CMSG_FORCE_MOVE_UNROOT_ACK) // unroot case { - LOG_INFO("misc", "The computed movement time using clockDelta is erronous. Using fallback instead"); - movementInfo.time = getMSTime(); + if (!mover->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_ROOT)) + return; } - else + else // root case { - movementInfo.time = (uint32)movementTime; + if (mover->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_ROOT)) + return; } - if (G3D::fuzzyEq(movementInfo.fallTime, 0.f)) - { - movementInfo.RemoveMovementFlag(MOVEMENTFLAG_FALLING); - } - - movementInfo.guid = mover->GetGUID(); - mover->m_movementInfo = movementInfo; - mover->UpdatePosition(movementInfo.pos); + if (!ProcessMovementInfo(movementInfo, mover, _player, recvData)) + return; + WorldPacket data(recvData.GetOpcode() == CMSG_FORCE_MOVE_UNROOT_ACK ? MSG_MOVE_UNROOT : MSG_MOVE_ROOT); + data << guid.WriteAsPacked(); + WriteMovementInfo(&data, &movementInfo); + mover->SendMessageToSet(&data, _player); } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 11b0a9005..cbb576580 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -363,7 +363,7 @@ void OpcodeTable::Initialize() /*0x0E8*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_MOVE_ROOT, STATUS_NEVER); /*0x0E9*/ DEFINE_HANDLER(CMSG_FORCE_MOVE_ROOT_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveRootAck ); /*0x0EA*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_MOVE_UNROOT, STATUS_NEVER); - /*0x0EB*/ DEFINE_HANDLER(CMSG_FORCE_MOVE_UNROOT_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveUnRootAck ); + /*0x0EB*/ DEFINE_HANDLER(CMSG_FORCE_MOVE_UNROOT_ACK, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMoveRootAck ); /*0x0EC*/ DEFINE_HANDLER(MSG_MOVE_ROOT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); /*0x0ED*/ DEFINE_HANDLER(MSG_MOVE_UNROOT, STATUS_NEVER, PROCESS_INPLACE, &WorldSession::Handle_NULL ); /*0x0EE*/ DEFINE_HANDLER(MSG_MOVE_HEARTBEAT, STATUS_LOGGEDIN, PROCESS_THREADSAFE, &WorldSession::HandleMovementOpcodes ); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 33ccaaa4f..c4f9ce9fe 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -628,7 +628,6 @@ public: // opcodes handlers void HandlePlayedTime(WorldPackets::Character::PlayedTimeClient& packet); // new - void HandleMoveUnRootAck(WorldPacket& recvPacket); void HandleMoveRootAck(WorldPacket& recvPacket); // new inspect