fix(Core/Movement): rework root protocol with ack in mind (#23147)

This commit is contained in:
killerwife
2025-10-11 18:49:43 +02:00
committed by GitHub
parent bc89aa561c
commit 31b11d0d11
10 changed files with 86 additions and 143 deletions

View File

@@ -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

View File

@@ -448,8 +448,6 @@ typedef std::list<Item*> ItemDurationList;
enum PlayerMovementType
{
MOVE_ROOT = 1,
MOVE_UNROOT = 2,
MOVE_WATER_WALK = 3,
MOVE_LAND_WALK = 4
};

View File

@@ -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();
}
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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();

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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 );

View File

@@ -628,7 +628,6 @@ public: // opcodes handlers
void HandlePlayedTime(WorldPackets::Character::PlayedTimeClient& packet);
// new
void HandleMoveUnRootAck(WorldPacket& recvPacket);
void HandleMoveRootAck(WorldPacket& recvPacket);
// new inspect