mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-02 15:53:51 +00:00
Stabilize taxi/state sync and creature spawn handling
This commit is contained in:
parent
38cef8d9c6
commit
40b50454ce
18 changed files with 818 additions and 127 deletions
|
|
@ -160,6 +160,7 @@ void GameHandler::update(float deltaTime) {
|
|||
// Send periodic heartbeat if in world
|
||||
if (state == WorldState::IN_WORLD) {
|
||||
timeSinceLastPing += deltaTime;
|
||||
timeSinceLastMoveHeartbeat_ += deltaTime;
|
||||
|
||||
if (timeSinceLastPing >= pingInterval) {
|
||||
if (socket) {
|
||||
|
|
@ -168,6 +169,11 @@ void GameHandler::update(float deltaTime) {
|
|||
timeSinceLastPing = 0.0f;
|
||||
}
|
||||
|
||||
if (timeSinceLastMoveHeartbeat_ >= moveHeartbeatInterval_) {
|
||||
sendMovement(Opcode::CMSG_MOVE_HEARTBEAT);
|
||||
timeSinceLastMoveHeartbeat_ = 0.0f;
|
||||
}
|
||||
|
||||
// Update cast timer (Phase 3)
|
||||
if (casting && castTimeRemaining > 0.0f) {
|
||||
castTimeRemaining -= deltaTime;
|
||||
|
|
@ -203,6 +209,9 @@ void GameHandler::update(float deltaTime) {
|
|||
if (taxiLandingCooldown_ > 0.0f) {
|
||||
taxiLandingCooldown_ -= deltaTime;
|
||||
}
|
||||
if (taxiStartGrace_ > 0.0f) {
|
||||
taxiStartGrace_ -= deltaTime;
|
||||
}
|
||||
|
||||
// Taxi logic timing
|
||||
auto taxiStart = std::chrono::high_resolution_clock::now();
|
||||
|
|
@ -215,7 +224,8 @@ void GameHandler::update(float deltaTime) {
|
|||
if (unit &&
|
||||
(unit->getUnitFlags() & 0x00000100) == 0 &&
|
||||
!taxiClientActive_ &&
|
||||
!taxiActivatePending_) {
|
||||
!taxiActivatePending_ &&
|
||||
taxiStartGrace_ <= 0.0f) {
|
||||
onTaxiFlight_ = false;
|
||||
taxiLandingCooldown_ = 2.0f; // 2 second cooldown to prevent re-entering
|
||||
if (taxiMountActive_ && mountCallback_) {
|
||||
|
|
@ -247,7 +257,7 @@ void GameHandler::update(float deltaTime) {
|
|||
serverStillTaxi = (playerUnit->getUnitFlags() & 0x00000100) != 0;
|
||||
}
|
||||
|
||||
if (serverStillTaxi || taxiClientActive_ || taxiActivatePending_) {
|
||||
if (taxiStartGrace_ > 0.0f || serverStillTaxi || taxiClientActive_ || taxiActivatePending_) {
|
||||
onTaxiFlight_ = true;
|
||||
} else {
|
||||
if (mountCallback_) mountCallback_(0);
|
||||
|
|
@ -264,6 +274,25 @@ void GameHandler::update(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
// Keep non-taxi mount state server-authoritative.
|
||||
// Some server paths don't emit explicit mount field updates in lockstep
|
||||
// with local visual state changes, so reconcile continuously.
|
||||
if (!onTaxiFlight_ && !taxiMountActive_) {
|
||||
auto playerEntity = entityManager.getEntity(playerGuid);
|
||||
auto playerUnit = std::dynamic_pointer_cast<Unit>(playerEntity);
|
||||
if (playerUnit) {
|
||||
uint32_t serverMountDisplayId = playerUnit->getMountDisplayId();
|
||||
if (serverMountDisplayId != currentMountDisplayId_) {
|
||||
LOG_INFO("Mount reconcile: server=", serverMountDisplayId,
|
||||
" local=", currentMountDisplayId_);
|
||||
currentMountDisplayId_ = serverMountDisplayId;
|
||||
if (mountCallback_) {
|
||||
mountCallback_(serverMountDisplayId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (taxiRecoverPending_ && state == WorldState::IN_WORLD) {
|
||||
auto playerEntity = entityManager.getEntity(playerGuid);
|
||||
if (playerEntity) {
|
||||
|
|
@ -408,7 +437,7 @@ void GameHandler::update(float deltaTime) {
|
|||
|
||||
// Log profiling every 60 frames
|
||||
if (++profileCounter >= 60) {
|
||||
LOG_INFO("UPDATE PROFILE (60 frames): socket=", socketTime / 60.0f, "ms taxi=", taxiTime / 60.0f,
|
||||
LOG_DEBUG("UPDATE PROFILE (60 frames): socket=", socketTime / 60.0f, "ms taxi=", taxiTime / 60.0f,
|
||||
"ms distance=", distanceCheckTime / 60.0f, "ms entity=", entityUpdateTime / 60.0f,
|
||||
"ms TOTAL=", totalTime / 60.0f, "ms");
|
||||
profileCounter = 0;
|
||||
|
|
@ -1603,6 +1632,20 @@ void GameHandler::handleLoginVerifyWorld(network::Packet& packet) {
|
|||
movementInfo.flags = 0;
|
||||
movementInfo.flags2 = 0;
|
||||
movementInfo.time = 0;
|
||||
resurrectPending_ = false;
|
||||
resurrectRequestPending_ = false;
|
||||
onTaxiFlight_ = false;
|
||||
taxiMountActive_ = false;
|
||||
taxiActivatePending_ = false;
|
||||
taxiClientActive_ = false;
|
||||
taxiClientPath_.clear();
|
||||
taxiRecoverPending_ = false;
|
||||
taxiStartGrace_ = 0.0f;
|
||||
currentMountDisplayId_ = 0;
|
||||
taxiMountDisplayId_ = 0;
|
||||
if (mountCallback_) {
|
||||
mountCallback_(0);
|
||||
}
|
||||
|
||||
// Send CMSG_SET_ACTIVE_MOVER (required by some servers)
|
||||
if (playerGuid != 0 && socket) {
|
||||
|
|
@ -1705,9 +1748,17 @@ void GameHandler::sendMovement(Opcode opcode) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Block manual movement while taxi is active/mounted, but still allow heartbeat packets.
|
||||
if ((onTaxiFlight_ || taxiMountActive_) && opcode != Opcode::CMSG_MOVE_HEARTBEAT) return;
|
||||
if (resurrectPending_) return;
|
||||
// Block manual movement while taxi is active/mounted, but always allow
|
||||
// stop/heartbeat opcodes so stuck states can be recovered.
|
||||
bool taxiAllowed =
|
||||
(opcode == Opcode::CMSG_MOVE_HEARTBEAT) ||
|
||||
(opcode == Opcode::CMSG_MOVE_STOP) ||
|
||||
(opcode == Opcode::CMSG_MOVE_STOP_STRAFE) ||
|
||||
(opcode == Opcode::CMSG_MOVE_STOP_TURN) ||
|
||||
(opcode == Opcode::CMSG_MOVE_STOP_SWIM) ||
|
||||
(opcode == Opcode::CMSG_MOVE_FALL_LAND);
|
||||
if ((onTaxiFlight_ || taxiMountActive_) && !taxiAllowed) return;
|
||||
if (resurrectPending_ && !taxiAllowed) return;
|
||||
|
||||
// Use real millisecond timestamp (server validates for anti-cheat)
|
||||
static auto startTime = std::chrono::steady_clock::now();
|
||||
|
|
@ -1817,6 +1868,45 @@ void GameHandler::sendMovement(Opcode opcode) {
|
|||
socket->send(packet);
|
||||
}
|
||||
|
||||
void GameHandler::forceClearTaxiAndMovementState() {
|
||||
taxiActivatePending_ = false;
|
||||
taxiActivateTimer_ = 0.0f;
|
||||
taxiClientActive_ = false;
|
||||
taxiClientPath_.clear();
|
||||
taxiRecoverPending_ = false;
|
||||
taxiStartGrace_ = 0.0f;
|
||||
onTaxiFlight_ = false;
|
||||
|
||||
if (taxiMountActive_ && mountCallback_) {
|
||||
mountCallback_(0);
|
||||
}
|
||||
taxiMountActive_ = false;
|
||||
taxiMountDisplayId_ = 0;
|
||||
currentMountDisplayId_ = 0;
|
||||
resurrectPending_ = false;
|
||||
resurrectRequestPending_ = false;
|
||||
playerDead_ = false;
|
||||
releasedSpirit_ = false;
|
||||
repopPending_ = false;
|
||||
pendingSpiritHealerGuid_ = 0;
|
||||
resurrectCasterGuid_ = 0;
|
||||
|
||||
movementInfo.flags = 0;
|
||||
movementInfo.flags2 = 0;
|
||||
movementInfo.transportGuid = 0;
|
||||
clearPlayerTransport();
|
||||
|
||||
if (socket && state == WorldState::IN_WORLD) {
|
||||
sendMovement(Opcode::CMSG_MOVE_STOP);
|
||||
sendMovement(Opcode::CMSG_MOVE_STOP_STRAFE);
|
||||
sendMovement(Opcode::CMSG_MOVE_STOP_TURN);
|
||||
sendMovement(Opcode::CMSG_MOVE_STOP_SWIM);
|
||||
sendMovement(Opcode::CMSG_MOVE_HEARTBEAT);
|
||||
}
|
||||
|
||||
LOG_INFO("Force-cleared taxi/movement state");
|
||||
}
|
||||
|
||||
void GameHandler::setPosition(float x, float y, float z) {
|
||||
movementInfo.x = x;
|
||||
movementInfo.y = y;
|
||||
|
|
@ -2001,6 +2091,7 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
|||
constexpr uint32_t UNIT_FLAG_TAXI_FLIGHT = 0x00000100;
|
||||
if ((unit->getUnitFlags() & UNIT_FLAG_TAXI_FLIGHT) != 0 && !onTaxiFlight_ && taxiLandingCooldown_ <= 0.0f) {
|
||||
onTaxiFlight_ = true;
|
||||
taxiStartGrace_ = std::max(taxiStartGrace_, 2.0f);
|
||||
applyTaxiMountForCurrentNode();
|
||||
}
|
||||
}
|
||||
|
|
@ -2559,6 +2650,15 @@ void GameHandler::handleDestroyObject(network::Packet& packet) {
|
|||
LOG_INFO("Ignoring destroy for transport entity: 0x", std::hex, data.guid, std::dec);
|
||||
return;
|
||||
}
|
||||
// Mirror out-of-range handling: invoke render-layer despawn callbacks before entity removal.
|
||||
auto entity = entityManager.getEntity(data.guid);
|
||||
if (entity) {
|
||||
if (entity->getType() == ObjectType::UNIT && creatureDespawnCallback_) {
|
||||
creatureDespawnCallback_(data.guid);
|
||||
} else if (entity->getType() == ObjectType::GAMEOBJECT && gameObjectDespawnCallback_) {
|
||||
gameObjectDespawnCallback_(data.guid);
|
||||
}
|
||||
}
|
||||
entityManager.removeEntity(data.guid);
|
||||
LOG_INFO("Destroyed entity: 0x", std::hex, data.guid, std::dec,
|
||||
" (", (data.isDeath ? "death" : "despawn"), ")");
|
||||
|
|
@ -4114,7 +4214,20 @@ void GameHandler::handleAttackStop(network::Packet& packet) {
|
|||
}
|
||||
|
||||
void GameHandler::dismount() {
|
||||
if (!isMounted() || !socket) return;
|
||||
if (!socket) return;
|
||||
if (!isMounted()) {
|
||||
// Local/server desync guard: clear visual mount even when server says unmounted.
|
||||
if (mountCallback_) {
|
||||
mountCallback_(0);
|
||||
}
|
||||
currentMountDisplayId_ = 0;
|
||||
taxiMountActive_ = false;
|
||||
taxiMountDisplayId_ = 0;
|
||||
onTaxiFlight_ = false;
|
||||
taxiActivatePending_ = false;
|
||||
taxiClientActive_ = false;
|
||||
LOG_INFO("Dismount desync recovery: force-cleared local mount state");
|
||||
}
|
||||
network::Packet pkt(static_cast<uint16_t>(Opcode::CMSG_CANCEL_MOUNT_AURA));
|
||||
socket->send(pkt);
|
||||
LOG_INFO("Sent CMSG_CANCEL_MOUNT_AURA");
|
||||
|
|
@ -4144,20 +4257,27 @@ void GameHandler::handleForceRunSpeedChange(network::Packet& packet) {
|
|||
|
||||
if (guid != playerGuid) return;
|
||||
|
||||
// Always ACK the speed change to prevent server stall
|
||||
// Always ACK the speed change to prevent server stall.
|
||||
// Packet format mirrors movement packets: packed guid + counter + movement info + new speed.
|
||||
if (socket) {
|
||||
network::Packet ack(static_cast<uint16_t>(Opcode::CMSG_FORCE_RUN_SPEED_CHANGE_ACK));
|
||||
ack.writeUInt64(playerGuid);
|
||||
MovementPacket::writePackedGuid(ack, playerGuid);
|
||||
ack.writeUInt32(counter);
|
||||
// MovementInfo (minimal — no flags set means no optional fields)
|
||||
ack.writeUInt32(0); // moveFlags
|
||||
ack.writeUInt16(0); // moveFlags2
|
||||
ack.writeUInt32(movementTime);
|
||||
ack.writeFloat(movementInfo.x);
|
||||
ack.writeFloat(movementInfo.y);
|
||||
ack.writeFloat(movementInfo.z);
|
||||
ack.writeFloat(movementInfo.orientation);
|
||||
ack.writeUInt32(0); // fallTime
|
||||
|
||||
MovementInfo wire = movementInfo;
|
||||
glm::vec3 serverPos = core::coords::canonicalToServer(glm::vec3(wire.x, wire.y, wire.z));
|
||||
wire.x = serverPos.x;
|
||||
wire.y = serverPos.y;
|
||||
wire.z = serverPos.z;
|
||||
if (wire.hasFlag(MovementFlags::ONTRANSPORT)) {
|
||||
glm::vec3 serverTransport =
|
||||
core::coords::canonicalToServer(glm::vec3(wire.transportX, wire.transportY, wire.transportZ));
|
||||
wire.transportX = serverTransport.x;
|
||||
wire.transportY = serverTransport.y;
|
||||
wire.transportZ = serverTransport.z;
|
||||
}
|
||||
MovementPacket::writeMovementPayload(ack, wire);
|
||||
|
||||
ack.writeFloat(newSpeed);
|
||||
socket->send(ack);
|
||||
}
|
||||
|
|
@ -5899,6 +6019,21 @@ void GameHandler::handleNewWorld(network::Packet& packet) {
|
|||
movementInfo.z = canonical.z;
|
||||
movementInfo.orientation = orientation;
|
||||
movementInfo.flags = 0;
|
||||
movementInfo.flags2 = 0;
|
||||
resurrectPending_ = false;
|
||||
resurrectRequestPending_ = false;
|
||||
onTaxiFlight_ = false;
|
||||
taxiMountActive_ = false;
|
||||
taxiActivatePending_ = false;
|
||||
taxiClientActive_ = false;
|
||||
taxiClientPath_.clear();
|
||||
taxiRecoverPending_ = false;
|
||||
taxiStartGrace_ = 0.0f;
|
||||
currentMountDisplayId_ = 0;
|
||||
taxiMountDisplayId_ = 0;
|
||||
if (mountCallback_) {
|
||||
mountCallback_(0);
|
||||
}
|
||||
|
||||
// Clear world state for the new map
|
||||
entityManager.clear();
|
||||
|
|
@ -6359,6 +6494,13 @@ void GameHandler::handleActivateTaxiReply(network::Packet& packet) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Guard against stray/mis-mapped packets being treated as taxi replies.
|
||||
// Only honor taxi replies when a taxi flow is actually active.
|
||||
if (!taxiActivatePending_ && !taxiWindowOpen_ && !onTaxiFlight_) {
|
||||
LOG_DEBUG("Ignoring stray taxi reply: result=", data.result);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.result == 0) {
|
||||
// Some cores can emit duplicate success replies (e.g. basic + express activate).
|
||||
// Ignore repeats once taxi is already active and no activation is pending.
|
||||
|
|
@ -6366,6 +6508,7 @@ void GameHandler::handleActivateTaxiReply(network::Packet& packet) {
|
|||
return;
|
||||
}
|
||||
onTaxiFlight_ = true;
|
||||
taxiStartGrace_ = std::max(taxiStartGrace_, 2.0f);
|
||||
taxiWindowOpen_ = false;
|
||||
taxiActivatePending_ = false;
|
||||
taxiActivateTimer_ = 0.0f;
|
||||
|
|
@ -6391,6 +6534,12 @@ void GameHandler::handleActivateTaxiReply(network::Packet& packet) {
|
|||
void GameHandler::closeTaxi() {
|
||||
taxiWindowOpen_ = false;
|
||||
|
||||
// Closing the taxi UI must not cancel an active/pending flight.
|
||||
// The window can auto-close due distance checks while takeoff begins.
|
||||
if (taxiActivatePending_ || onTaxiFlight_ || taxiClientActive_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we optimistically mounted during node selection, dismount now
|
||||
if (taxiMountActive_ && mountCallback_) {
|
||||
mountCallback_(0); // Dismount
|
||||
|
|
@ -6444,6 +6593,11 @@ uint32_t GameHandler::getTaxiCostTo(uint32_t destNodeId) const {
|
|||
void GameHandler::activateTaxi(uint32_t destNodeId) {
|
||||
if (!socket || state != WorldState::IN_WORLD) return;
|
||||
|
||||
// One-shot taxi activation until server replies or timeout.
|
||||
if (taxiActivatePending_ || onTaxiFlight_) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t startNode = currentTaxiData_.nearestNode;
|
||||
if (startNode == 0 || destNodeId == 0 || startNode == destNodeId) return;
|
||||
|
||||
|
|
@ -6514,13 +6668,14 @@ void GameHandler::activateTaxi(uint32_t destNodeId) {
|
|||
auto basicPkt = ActivateTaxiPacket::build(taxiNpcGuid_, startNode, destNodeId);
|
||||
socket->send(basicPkt);
|
||||
|
||||
// Others accept express with a full node path + cost.
|
||||
auto pkt = ActivateTaxiExpressPacket::build(taxiNpcGuid_, totalCost, path);
|
||||
socket->send(pkt);
|
||||
// AzerothCore in this setup rejects/misparses CMSG_ACTIVATETAXIEXPRESS (0x312),
|
||||
// so keep taxi activation on the basic packet only.
|
||||
|
||||
// Optimistically start taxi visuals; server will correct if it denies.
|
||||
taxiWindowOpen_ = false;
|
||||
taxiActivatePending_ = true;
|
||||
taxiActivateTimer_ = 0.0f;
|
||||
taxiStartGrace_ = 2.0f;
|
||||
if (!onTaxiFlight_) {
|
||||
onTaxiFlight_ = true;
|
||||
applyTaxiMountForCurrentNode();
|
||||
|
|
|
|||
|
|
@ -371,7 +371,7 @@ void TransportManager::updateTransportMovement(ActiveTransport& transport, float
|
|||
if (debugFrameCount++ % 120 == 0) {
|
||||
// Log canonical position AND render position to check coordinate conversion
|
||||
glm::vec3 renderPos = core::coords::canonicalToRender(transport.position);
|
||||
LOG_INFO("Transport 0x", std::hex, transport.guid, std::dec,
|
||||
LOG_DEBUG("Transport 0x", std::hex, transport.guid, std::dec,
|
||||
" pathTime=", pathTimeMs, "ms / ", path.durationMs, "ms",
|
||||
" canonicalPos=(", transport.position.x, ", ", transport.position.y, ", ", transport.position.z, ")",
|
||||
" renderPos=(", renderPos.x, ", ", renderPos.y, ", ", renderPos.z, ")",
|
||||
|
|
|
|||
|
|
@ -523,23 +523,12 @@ bool PongParser::parse(network::Packet& packet, PongData& data) {
|
|||
return true;
|
||||
}
|
||||
|
||||
network::Packet MovementPacket::build(Opcode opcode, const MovementInfo& info, uint64_t playerGuid) {
|
||||
network::Packet packet(static_cast<uint16_t>(opcode));
|
||||
|
||||
// Movement packet format (WoW 3.3.5a):
|
||||
// packed GUID
|
||||
// uint32 flags
|
||||
// uint16 flags2
|
||||
// uint32 time
|
||||
// float x, y, z
|
||||
// float orientation
|
||||
|
||||
// Write packed GUID
|
||||
void MovementPacket::writePackedGuid(network::Packet& packet, uint64_t guid) {
|
||||
uint8_t mask = 0;
|
||||
uint8_t guidBytes[8];
|
||||
int guidByteCount = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint8_t byte = static_cast<uint8_t>((playerGuid >> (i * 8)) & 0xFF);
|
||||
uint8_t byte = static_cast<uint8_t>((guid >> (i * 8)) & 0xFF);
|
||||
if (byte != 0) {
|
||||
mask |= (1 << i);
|
||||
guidBytes[guidByteCount++] = byte;
|
||||
|
|
@ -549,6 +538,15 @@ network::Packet MovementPacket::build(Opcode opcode, const MovementInfo& info, u
|
|||
for (int i = 0; i < guidByteCount; i++) {
|
||||
packet.writeUInt8(guidBytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void MovementPacket::writeMovementPayload(network::Packet& packet, const MovementInfo& info) {
|
||||
// Movement packet format (WoW 3.3.5a) payload:
|
||||
// uint32 flags
|
||||
// uint16 flags2
|
||||
// uint32 time
|
||||
// float x, y, z
|
||||
// float orientation
|
||||
|
||||
// Write movement flags
|
||||
packet.writeUInt32(info.flags);
|
||||
|
|
@ -617,6 +615,15 @@ network::Packet MovementPacket::build(Opcode opcode, const MovementInfo& info, u
|
|||
packet.writeBytes(reinterpret_cast<const uint8_t*>(&info.jumpCosAngle), sizeof(float));
|
||||
packet.writeBytes(reinterpret_cast<const uint8_t*>(&info.jumpXYSpeed), sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
network::Packet MovementPacket::build(Opcode opcode, const MovementInfo& info, uint64_t playerGuid) {
|
||||
network::Packet packet(static_cast<uint16_t>(opcode));
|
||||
|
||||
// Movement packet format (WoW 3.3.5a):
|
||||
// packed GUID + movement payload
|
||||
writePackedGuid(packet, playerGuid);
|
||||
writeMovementPayload(packet, info);
|
||||
|
||||
// Detailed hex dump for debugging
|
||||
static int mvLog = 5;
|
||||
|
|
@ -828,16 +835,27 @@ bool UpdateObjectParser::parseMovementBlock(network::Packet& packet, UpdateBlock
|
|||
block.z = packet.readFloat();
|
||||
block.onTransport = (transportGuid != 0);
|
||||
block.transportGuid = transportGuid;
|
||||
block.transportX = packet.readFloat();
|
||||
block.transportY = packet.readFloat();
|
||||
block.transportZ = packet.readFloat();
|
||||
float tx = packet.readFloat();
|
||||
float ty = packet.readFloat();
|
||||
float tz = packet.readFloat();
|
||||
if (block.onTransport) {
|
||||
block.transportX = tx;
|
||||
block.transportY = ty;
|
||||
block.transportZ = tz;
|
||||
} else {
|
||||
block.transportX = 0.0f;
|
||||
block.transportY = 0.0f;
|
||||
block.transportZ = 0.0f;
|
||||
}
|
||||
block.orientation = packet.readFloat();
|
||||
/*float corpseOrientation =*/ packet.readFloat();
|
||||
block.hasMovement = true;
|
||||
|
||||
LOG_INFO(" TRANSPORT POSITION UPDATE: guid=0x", std::hex, transportGuid, std::dec,
|
||||
" pos=(", block.x, ", ", block.y, ", ", block.z, "), o=", block.orientation,
|
||||
" offset=(", block.transportX, ", ", block.transportY, ", ", block.transportZ, ")");
|
||||
if (block.onTransport) {
|
||||
LOG_INFO(" TRANSPORT POSITION UPDATE: guid=0x", std::hex, transportGuid, std::dec,
|
||||
" pos=(", block.x, ", ", block.y, ", ", block.z, "), o=", block.orientation,
|
||||
" offset=(", block.transportX, ", ", block.transportY, ", ", block.transportZ, ")");
|
||||
}
|
||||
}
|
||||
else if (updateFlags & UPDATEFLAG_STATIONARY_POSITION) {
|
||||
// Simple stationary position (4 floats)
|
||||
|
|
@ -895,9 +913,9 @@ bool UpdateObjectParser::parseUpdateFields(network::Packet& packet, UpdateBlock&
|
|||
}
|
||||
|
||||
uint32_t fieldsCapacity = blockCount * 32;
|
||||
LOG_INFO(" UPDATE MASK PARSE:");
|
||||
LOG_INFO(" maskBlockCount = ", (int)blockCount);
|
||||
LOG_INFO(" fieldsCapacity (blocks * 32) = ", fieldsCapacity);
|
||||
LOG_DEBUG(" UPDATE MASK PARSE:");
|
||||
LOG_DEBUG(" maskBlockCount = ", (int)blockCount);
|
||||
LOG_DEBUG(" fieldsCapacity (blocks * 32) = ", fieldsCapacity);
|
||||
|
||||
// Read update mask
|
||||
std::vector<uint32_t> updateMask(blockCount);
|
||||
|
|
@ -932,11 +950,11 @@ bool UpdateObjectParser::parseUpdateFields(network::Packet& packet, UpdateBlock&
|
|||
size_t bytesUsed = endPos - startPos;
|
||||
size_t bytesRemaining = packet.getSize() - endPos;
|
||||
|
||||
LOG_INFO(" highestSetBitIndex = ", highestSetBit);
|
||||
LOG_INFO(" valuesReadCount = ", valuesReadCount);
|
||||
LOG_INFO(" bytesUsedForFields = ", bytesUsed);
|
||||
LOG_INFO(" bytesRemainingInPacket = ", bytesRemaining);
|
||||
LOG_INFO(" Parsed ", block.fields.size(), " fields");
|
||||
LOG_DEBUG(" highestSetBitIndex = ", highestSetBit);
|
||||
LOG_DEBUG(" valuesReadCount = ", valuesReadCount);
|
||||
LOG_DEBUG(" bytesUsedForFields = ", bytesUsed);
|
||||
LOG_DEBUG(" bytesRemainingInPacket = ", bytesRemaining);
|
||||
LOG_DEBUG(" Parsed ", block.fields.size(), " fields");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1009,9 +1027,9 @@ bool UpdateObjectParser::parse(network::Packet& packet, UpdateObjectData& data)
|
|||
// Read block count
|
||||
data.blockCount = packet.readUInt32();
|
||||
|
||||
LOG_INFO("SMSG_UPDATE_OBJECT:");
|
||||
LOG_INFO(" objectCount = ", data.blockCount);
|
||||
LOG_INFO(" packetSize = ", packet.getSize());
|
||||
LOG_DEBUG("SMSG_UPDATE_OBJECT:");
|
||||
LOG_DEBUG(" objectCount = ", data.blockCount);
|
||||
LOG_DEBUG(" packetSize = ", packet.getSize());
|
||||
|
||||
// Check for out-of-range objects first
|
||||
if (packet.getReadPos() + 1 <= packet.getSize()) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue