mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-02-20 00:04:23 -05:00
Fix yaw conversions for online movement/entities
This commit is contained in:
@@ -9,6 +9,8 @@ namespace wowee::core::coords {
|
||||
|
||||
inline constexpr float TILE_SIZE = 533.33333f;
|
||||
inline constexpr float ZEROPOINT = 32.0f * TILE_SIZE;
|
||||
inline constexpr float PI = 3.14159265358979323846f;
|
||||
inline constexpr float TWO_PI = 6.28318530717958647692f;
|
||||
|
||||
// ---- Canonical WoW world coordinate system (per-map) ----
|
||||
// +X = North, +Y = West, +Z = Up (height)
|
||||
@@ -42,6 +44,28 @@ inline glm::vec3 canonicalToServer(const glm::vec3& canonical) {
|
||||
return glm::vec3(canonical.y, canonical.x, canonical.z);
|
||||
}
|
||||
|
||||
// Normalize angle to [-PI, PI].
|
||||
inline float normalizeAngleRad(float a) {
|
||||
while (a > PI) a -= TWO_PI;
|
||||
while (a < -PI) a += TWO_PI;
|
||||
return a;
|
||||
}
|
||||
|
||||
// Convert server/wire yaw (radians) → canonical yaw (radians).
|
||||
//
|
||||
// Under server<->canonical X/Y swap:
|
||||
// dir_s = (cos(s), sin(s))
|
||||
// dir_c = swap(dir_s) = (sin(s), cos(s)) => c = PI/2 - s
|
||||
inline float serverToCanonicalYaw(float serverYaw) {
|
||||
return normalizeAngleRad((PI * 0.5f) - serverYaw);
|
||||
}
|
||||
|
||||
// Convert canonical yaw (radians) → server/wire yaw (radians).
|
||||
// This mapping is its own inverse.
|
||||
inline float canonicalToServerYaw(float canonicalYaw) {
|
||||
return normalizeAngleRad((PI * 0.5f) - canonicalYaw);
|
||||
}
|
||||
|
||||
// Convert between canonical WoW and engine rendering coordinates (just swap X/Y).
|
||||
inline glm::vec3 canonicalToRender(const glm::vec3& wow) {
|
||||
return glm::vec3(wow.y, wow.x, wow.z);
|
||||
|
||||
@@ -685,8 +685,12 @@ void Application::update(float deltaTime) {
|
||||
|
||||
// Sync orientation: camera yaw (degrees) → WoW orientation (radians)
|
||||
float yawDeg = renderer->getCharacterYaw();
|
||||
float wowOrientation = glm::radians(yawDeg - 90.0f);
|
||||
gameHandler->setOrientation(wowOrientation);
|
||||
// Keep all game-side orientation in canonical space.
|
||||
// We historically sent serverYaw = radians(yawDeg - 90). With the new
|
||||
// canonical<->server mapping (serverYaw = PI/2 - canonicalYaw), the
|
||||
// equivalent canonical yaw is radians(180 - yawDeg).
|
||||
float canonicalYaw = core::coords::normalizeAngleRad(glm::radians(180.0f - yawDeg));
|
||||
gameHandler->setOrientation(canonicalYaw);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1794,7 +1794,7 @@ void GameHandler::handleLoginVerifyWorld(network::Packet& packet) {
|
||||
movementInfo.x = canonical.x;
|
||||
movementInfo.y = canonical.y;
|
||||
movementInfo.z = canonical.z;
|
||||
movementInfo.orientation = data.orientation;
|
||||
movementInfo.orientation = core::coords::serverToCanonicalYaw(data.orientation);
|
||||
movementInfo.flags = 0;
|
||||
movementInfo.flags2 = 0;
|
||||
movementInfo.time = 0;
|
||||
@@ -2322,23 +2322,20 @@ void GameHandler::sendMovement(Opcode opcode) {
|
||||
movementInfo.transportTime2 = movementInfo.time;
|
||||
|
||||
// ONTRANSPORT expects local orientation (player yaw relative to transport yaw).
|
||||
float transportYaw = 0.0f;
|
||||
// Keep internal yaw canonical; convert to server yaw on the wire.
|
||||
float transportYawCanonical = 0.0f;
|
||||
if (transportManager_) {
|
||||
if (auto* tr = transportManager_->getTransport(playerTransportGuid_); tr) {
|
||||
if (tr->hasServerYaw) {
|
||||
transportYaw = tr->serverYaw;
|
||||
transportYawCanonical = tr->serverYaw;
|
||||
} else {
|
||||
transportYaw = glm::eulerAngles(tr->rotation).z;
|
||||
transportYawCanonical = glm::eulerAngles(tr->rotation).z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float localTransportO = movementInfo.orientation - transportYaw;
|
||||
constexpr float kPi = 3.14159265359f;
|
||||
constexpr float kTwoPi = 6.28318530718f;
|
||||
while (localTransportO > kPi) localTransportO -= kTwoPi;
|
||||
while (localTransportO < -kPi) localTransportO += kTwoPi;
|
||||
movementInfo.transportO = localTransportO;
|
||||
movementInfo.transportO =
|
||||
core::coords::normalizeAngleRad(movementInfo.orientation - transportYawCanonical);
|
||||
} else {
|
||||
// Clear transport flag if not on transport
|
||||
movementInfo.flags &= ~static_cast<uint32_t>(MovementFlags::ONTRANSPORT);
|
||||
@@ -2357,6 +2354,9 @@ void GameHandler::sendMovement(Opcode opcode) {
|
||||
wireInfo.y = serverPos.y;
|
||||
wireInfo.z = serverPos.z;
|
||||
|
||||
// Convert canonical → server yaw for the wire
|
||||
wireInfo.orientation = core::coords::canonicalToServerYaw(wireInfo.orientation);
|
||||
|
||||
// Also convert transport local position to server coordinates if on transport
|
||||
if (isOnTransport()) {
|
||||
glm::vec3 serverTransportPos = core::coords::canonicalToServer(
|
||||
@@ -2364,6 +2364,8 @@ void GameHandler::sendMovement(Opcode opcode) {
|
||||
wireInfo.transportX = serverTransportPos.x;
|
||||
wireInfo.transportY = serverTransportPos.y;
|
||||
wireInfo.transportZ = serverTransportPos.z;
|
||||
// transportO is a local delta; server<->canonical swap negates delta yaw.
|
||||
wireInfo.transportO = core::coords::normalizeAngleRad(-wireInfo.transportO);
|
||||
}
|
||||
|
||||
// Build and send movement packet
|
||||
@@ -2520,7 +2522,8 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||
// Set position from movement block (server → canonical)
|
||||
if (block.hasMovement) {
|
||||
glm::vec3 pos = core::coords::serverToCanonical(glm::vec3(block.x, block.y, block.z));
|
||||
entity->setPosition(pos.x, pos.y, pos.z, block.orientation);
|
||||
float oCanonical = core::coords::serverToCanonicalYaw(block.orientation);
|
||||
entity->setPosition(pos.x, pos.y, pos.z, oCanonical);
|
||||
LOG_DEBUG(" Position: (", pos.x, ", ", pos.y, ", ", pos.z, ")");
|
||||
if (block.guid == playerGuid && block.runSpeed > 0.1f && block.runSpeed < 100.0f) {
|
||||
serverRunSpeed_ = block.runSpeed;
|
||||
@@ -2534,7 +2537,7 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||
playerTransportOffset_ = core::coords::serverToCanonical(serverOffset);
|
||||
if (transportManager_ && transportManager_->getTransport(playerTransportGuid_)) {
|
||||
glm::vec3 composed = transportManager_->getPlayerWorldPosition(playerTransportGuid_, playerTransportOffset_);
|
||||
entity->setPosition(composed.x, composed.y, composed.z, block.orientation);
|
||||
entity->setPosition(composed.x, composed.y, composed.z, oCanonical);
|
||||
movementInfo.x = composed.x;
|
||||
movementInfo.y = composed.y;
|
||||
movementInfo.z = composed.z;
|
||||
@@ -2556,8 +2559,9 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||
glm::vec3 localOffset = core::coords::serverToCanonical(
|
||||
glm::vec3(block.transportX, block.transportY, block.transportZ));
|
||||
const bool hasLocalOrientation = (block.updateFlags & 0x0020) != 0; // UPDATEFLAG_LIVING
|
||||
float localOriCanonical = core::coords::normalizeAngleRad(-block.transportO);
|
||||
setTransportAttachment(block.guid, block.objectType, block.transportGuid,
|
||||
localOffset, hasLocalOrientation, block.transportO);
|
||||
localOffset, hasLocalOrientation, localOriCanonical);
|
||||
if (transportManager_ && transportManager_->getTransport(block.transportGuid)) {
|
||||
glm::vec3 composed = transportManager_->getPlayerWorldPosition(block.transportGuid, localOffset);
|
||||
entity->setPosition(composed.x, composed.y, composed.z, entity->getOrientation());
|
||||
@@ -2870,7 +2874,8 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||
if (entity) {
|
||||
if (block.hasMovement) {
|
||||
glm::vec3 pos = core::coords::serverToCanonical(glm::vec3(block.x, block.y, block.z));
|
||||
entity->setPosition(pos.x, pos.y, pos.z, block.orientation);
|
||||
float oCanonical = core::coords::serverToCanonicalYaw(block.orientation);
|
||||
entity->setPosition(pos.x, pos.y, pos.z, oCanonical);
|
||||
|
||||
if (block.guid != playerGuid &&
|
||||
(entity->getType() == ObjectType::UNIT || entity->getType() == ObjectType::GAMEOBJECT)) {
|
||||
@@ -2878,8 +2883,9 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||
glm::vec3 localOffset = core::coords::serverToCanonical(
|
||||
glm::vec3(block.transportX, block.transportY, block.transportZ));
|
||||
const bool hasLocalOrientation = (block.updateFlags & 0x0020) != 0; // UPDATEFLAG_LIVING
|
||||
float localOriCanonical = core::coords::normalizeAngleRad(-block.transportO);
|
||||
setTransportAttachment(block.guid, entity->getType(), block.transportGuid,
|
||||
localOffset, hasLocalOrientation, block.transportO);
|
||||
localOffset, hasLocalOrientation, localOriCanonical);
|
||||
if (transportManager_ && transportManager_->getTransport(block.transportGuid)) {
|
||||
glm::vec3 composed = transportManager_->getPlayerWorldPosition(block.transportGuid, localOffset);
|
||||
entity->setPosition(composed.x, composed.y, composed.z, entity->getOrientation());
|
||||
@@ -3108,7 +3114,8 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||
auto entity = entityManager.getEntity(block.guid);
|
||||
if (entity) {
|
||||
glm::vec3 pos = core::coords::serverToCanonical(glm::vec3(block.x, block.y, block.z));
|
||||
entity->setPosition(pos.x, pos.y, pos.z, block.orientation);
|
||||
float oCanonical = core::coords::serverToCanonicalYaw(block.orientation);
|
||||
entity->setPosition(pos.x, pos.y, pos.z, oCanonical);
|
||||
LOG_DEBUG("Updated entity position: 0x", std::hex, block.guid, std::dec);
|
||||
|
||||
if (block.guid != playerGuid &&
|
||||
@@ -3117,8 +3124,9 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||
glm::vec3 localOffset = core::coords::serverToCanonical(
|
||||
glm::vec3(block.transportX, block.transportY, block.transportZ));
|
||||
const bool hasLocalOrientation = (block.updateFlags & 0x0020) != 0; // UPDATEFLAG_LIVING
|
||||
float localOriCanonical = core::coords::normalizeAngleRad(-block.transportO);
|
||||
setTransportAttachment(block.guid, entity->getType(), block.transportGuid,
|
||||
localOffset, hasLocalOrientation, block.transportO);
|
||||
localOffset, hasLocalOrientation, localOriCanonical);
|
||||
if (transportManager_ && transportManager_->getTransport(block.transportGuid)) {
|
||||
glm::vec3 composed = transportManager_->getPlayerWorldPosition(block.transportGuid, localOffset);
|
||||
entity->setPosition(composed.x, composed.y, composed.z, entity->getOrientation());
|
||||
@@ -3129,7 +3137,7 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||
}
|
||||
|
||||
if (block.guid == playerGuid) {
|
||||
movementInfo.orientation = block.orientation;
|
||||
movementInfo.orientation = oCanonical;
|
||||
|
||||
// Track player-on-transport state from MOVEMENT updates
|
||||
if (block.onTransport) {
|
||||
@@ -3139,7 +3147,7 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||
playerTransportOffset_ = core::coords::serverToCanonical(serverOffset);
|
||||
if (transportManager_ && transportManager_->getTransport(playerTransportGuid_)) {
|
||||
glm::vec3 composed = transportManager_->getPlayerWorldPosition(playerTransportGuid_, playerTransportOffset_);
|
||||
entity->setPosition(composed.x, composed.y, composed.z, block.orientation);
|
||||
entity->setPosition(composed.x, composed.y, composed.z, oCanonical);
|
||||
movementInfo.x = composed.x;
|
||||
movementInfo.y = composed.y;
|
||||
movementInfo.z = composed.z;
|
||||
@@ -3163,7 +3171,7 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||
// Fire transport move callback if this is a known transport
|
||||
if (transportGuids_.count(block.guid) && transportMoveCallback_) {
|
||||
serverUpdatedTransportGuids_.insert(block.guid);
|
||||
transportMoveCallback_(block.guid, pos.x, pos.y, pos.z, block.orientation);
|
||||
transportMoveCallback_(block.guid, pos.x, pos.y, pos.z, oCanonical);
|
||||
}
|
||||
// Fire move callback for non-transport gameobjects.
|
||||
if (entity->getType() == ObjectType::GAMEOBJECT &&
|
||||
@@ -5081,7 +5089,7 @@ void GameHandler::handleMonsterMove(network::Packet& packet) {
|
||||
float orientation = entity->getOrientation();
|
||||
if (data.moveType == 4) {
|
||||
// FacingAngle - server specifies exact angle
|
||||
orientation = data.facingAngle;
|
||||
orientation = core::coords::serverToCanonicalYaw(data.facingAngle);
|
||||
} else if (data.moveType == 3) {
|
||||
// FacingTarget - face toward the target entity
|
||||
auto target = entityManager.getEntity(data.facingTarget);
|
||||
@@ -5134,7 +5142,7 @@ void GameHandler::handleMonsterMoveTransport(network::Packet& packet) {
|
||||
uint8_t unk = packet.readUInt8(); // Unknown byte (usually 0)
|
||||
uint64_t transportGuid = packet.readUInt64();
|
||||
|
||||
// Transport-local coordinates
|
||||
// Transport-local coordinates (server space)
|
||||
float localX = packet.readFloat();
|
||||
float localY = packet.readFloat();
|
||||
float localZ = packet.readFloat();
|
||||
@@ -5152,9 +5160,9 @@ void GameHandler::handleMonsterMoveTransport(network::Packet& packet) {
|
||||
|
||||
if (transportManager_) {
|
||||
// Use TransportManager to compose world position from local offset
|
||||
glm::vec3 localPos(localX, localY, localZ);
|
||||
setTransportAttachment(moverGuid, entity->getType(), transportGuid, localPos, false, 0.0f);
|
||||
glm::vec3 worldPos = transportManager_->getPlayerWorldPosition(transportGuid, localPos);
|
||||
glm::vec3 localPosCanonical = core::coords::serverToCanonical(glm::vec3(localX, localY, localZ));
|
||||
setTransportAttachment(moverGuid, entity->getType(), transportGuid, localPosCanonical, false, 0.0f);
|
||||
glm::vec3 worldPos = transportManager_->getPlayerWorldPosition(transportGuid, localPosCanonical);
|
||||
|
||||
entity->setPosition(worldPos.x, worldPos.y, worldPos.z, entity->getOrientation());
|
||||
|
||||
@@ -6601,7 +6609,7 @@ void GameHandler::handleTeleportAck(network::Packet& packet) {
|
||||
movementInfo.x = canonical.x;
|
||||
movementInfo.y = canonical.y;
|
||||
movementInfo.z = canonical.z;
|
||||
movementInfo.orientation = orientation;
|
||||
movementInfo.orientation = core::coords::serverToCanonicalYaw(orientation);
|
||||
movementInfo.flags = 0;
|
||||
|
||||
// Send the ack back to the server
|
||||
@@ -6661,7 +6669,7 @@ void GameHandler::handleNewWorld(network::Packet& packet) {
|
||||
movementInfo.x = canonical.x;
|
||||
movementInfo.y = canonical.y;
|
||||
movementInfo.z = canonical.z;
|
||||
movementInfo.orientation = orientation;
|
||||
movementInfo.orientation = core::coords::serverToCanonicalYaw(orientation);
|
||||
movementInfo.flags = 0;
|
||||
movementInfo.flags2 = 0;
|
||||
resurrectPending_ = false;
|
||||
|
||||
Reference in New Issue
Block a user