Fix Deeprun Tram: visual movement, direction, and player riding

- Fix NULL renderer pointers by moving TransportManager connection after
  initializeRenderers for WMO-only maps
- Fix tram direction by negating DBC TransportAnimation X/Y local offsets
  before serverToCanonical conversion
- Implement client-side M2 transport boarding via proximity detection
  (server doesn't send transport attachment for trams)
- Use position-delta approach: player keeps normal movement while
  transport's frame-to-frame motion is applied on top
- Prevent server movement packets from clearing client-side M2 transport
  state (isClientM2Transport guard)
- Fix getPlayerWorldPosition for M2 transports: simple canonical addition
  instead of render-space matrix multiplication
This commit is contained in:
Kelsi 2026-03-06 23:01:11 -08:00
parent e001aaa2b6
commit f4c115ade9
5 changed files with 233 additions and 70 deletions

View file

@ -4936,10 +4936,17 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
LOG_INFO("Player on transport: 0x", std::hex, playerTransportGuid_, std::dec,
" offset=(", playerTransportOffset_.x, ", ", playerTransportOffset_.y, ", ", playerTransportOffset_.z, ")");
} else {
if (playerTransportGuid_ != 0) {
LOG_INFO("Player left transport");
// Don't clear client-side M2 transport boarding (trams) —
// the server doesn't know about client-detected transport attachment.
bool isClientM2Transport = false;
if (playerTransportGuid_ != 0 && transportManager_) {
auto* tr = transportManager_->getTransport(playerTransportGuid_);
isClientM2Transport = (tr && tr->isM2);
}
if (playerTransportGuid_ != 0 && !isClientM2Transport) {
LOG_INFO("Player left transport");
clearPlayerTransport();
}
clearPlayerTransport();
}
}
@ -5173,9 +5180,13 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
queryGameObjectInfo(itEntry->second, block.guid);
}
// Detect transport GameObjects via UPDATEFLAG_TRANSPORT (0x0002)
LOG_WARNING("GameObject CREATE: guid=0x", std::hex, block.guid, std::dec,
" entry=", go->getEntry(), " displayId=", go->getDisplayId(),
" updateFlags=0x", std::hex, block.updateFlags, std::dec,
" pos=(", go->getX(), ", ", go->getY(), ", ", go->getZ(), ")");
if (block.updateFlags & 0x0002) {
transportGuids_.insert(block.guid);
LOG_INFO("Detected transport GameObject: 0x", std::hex, block.guid, std::dec,
LOG_WARNING("Detected transport GameObject: 0x", std::hex, block.guid, std::dec,
" entry=", go->getEntry(),
" displayId=", go->getDisplayId(),
" pos=(", go->getX(), ", ", go->getY(), ", ", go->getZ(), ")");
@ -5691,7 +5702,13 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
movementInfo.x = pos.x;
movementInfo.y = pos.y;
movementInfo.z = pos.z;
if (playerTransportGuid_ != 0) {
// Don't clear client-side M2 transport boarding
bool isClientM2Transport = false;
if (playerTransportGuid_ != 0 && transportManager_) {
auto* tr = transportManager_->getTransport(playerTransportGuid_);
isClientM2Transport = (tr && tr->isM2);
}
if (playerTransportGuid_ != 0 && !isClientM2Transport) {
LOG_INFO("Player left transport (MOVEMENT)");
clearPlayerTransport();
}