fix(DB/Gameobject): Recalculate quaternion rotation values from orientation (#24617)

This commit is contained in:
blinkysc
2026-02-06 14:41:08 -06:00
committed by GitHub
parent 653136e311
commit 9b63cde7cb
8 changed files with 105 additions and 41 deletions

View File

@@ -840,7 +840,8 @@ GameObject* Battlefield::SpawnGameObject(uint32 entry, float x, float y, float z
// Create gameobject
GameObject* go = sObjectMgr->IsGameObjectStaticTransport(entry) ? new StaticTransport() : new GameObject();
if (!go->Create(map->GenerateLowGuid<HighGuid::GameObject>(), entry, map, PHASEMASK_NORMAL, x, y, z, o, G3D::Quat(), 100, GO_STATE_READY))
G3D::Quat rotation = G3D::Quat::fromAxisAngleRotation(G3D::Vector3::unitZ(), o);
if (!go->Create(map->GenerateLowGuid<HighGuid::GameObject>(), entry, map, PHASEMASK_NORMAL, x, y, z, o, rotation, 100, GO_STATE_READY))
{
LOG_ERROR("sql.sql", "Battlefield::SpawnGameObject: Gameobject template {} not found in database! Battlefield not created!", entry);
LOG_ERROR("bg.battlefield", "Battlefield::SpawnGameObject: Cannot create gameobject template {}! Battlefield not created!", entry);

View File

@@ -298,7 +298,7 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u
return false;
}
SetLocalRotation(rotation);
SetWorldRotation(rotation);
GameObjectAddon const* gameObjectAddon = sObjectMgr->GetGameObjectAddon(GetSpawnId());
QuaternionData parentRotation;
@@ -1038,7 +1038,7 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask, bool
data.posY = GetPositionY();
data.posZ = GetPositionZ();
data.orientation = GetOrientation();
data.rotation = m_localRotation;
data.rotation = WorldRotation;
data.spawntimesecs = m_spawnedByDefault ? m_respawnDelayTime : -(int32)m_respawnDelayTime;
data.animprogress = GetGoAnimProgress();
data.go_state = GetGoState();
@@ -1064,10 +1064,10 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask, bool
stmt->SetData(index++, GetPositionY());
stmt->SetData(index++, GetPositionZ());
stmt->SetData(index++, GetOrientation());
stmt->SetData(index++, m_localRotation.x);
stmt->SetData(index++, m_localRotation.y);
stmt->SetData(index++, m_localRotation.z);
stmt->SetData(index++, m_localRotation.w);
stmt->SetData(index++, WorldRotation.x);
stmt->SetData(index++, WorldRotation.y);
stmt->SetData(index++, WorldRotation.z);
stmt->SetData(index++, WorldRotation.w);
stmt->SetData(index++, int32(m_respawnDelayTime));
stmt->SetData(index++, GetGoAnimProgress());
stmt->SetData(index++, uint8(GetGoState()));
@@ -2199,24 +2199,18 @@ void GameObject::UpdatePackedRotation()
static const int32 PACK_X = PACK_YZ << 1;
static const int32 PACK_YZ_MASK = (PACK_YZ << 1) - 1;
static const int32 PACK_X_MASK = (PACK_X << 1) - 1;
int8 w_sign = (m_localRotation.w >= 0.f ? 1 : -1);
int64 x = int32(m_localRotation.x * PACK_X) * w_sign & PACK_X_MASK;
int64 y = int32(m_localRotation.y * PACK_YZ) * w_sign & PACK_YZ_MASK;
int64 z = int32(m_localRotation.z * PACK_YZ) * w_sign & PACK_YZ_MASK;
int8 w_sign = (WorldRotation.w >= 0.f ? 1 : -1);
int64 x = int32(WorldRotation.x * PACK_X) * w_sign & PACK_X_MASK;
int64 y = int32(WorldRotation.y * PACK_YZ) * w_sign & PACK_YZ_MASK;
int64 z = int32(WorldRotation.z * PACK_YZ) * w_sign & PACK_YZ_MASK;
m_packedRotation = z | (y << 21) | (x << 42);
}
void GameObject::SetLocalRotation(G3D::Quat const& rot)
void GameObject::SetWorldRotation(G3D::Quat const& rot)
{
G3D::Quat rotation;
// Temporary solution for gameobjects that have no rotation data in DB:
if (G3D::fuzzyEq(rot.z, 0.f) && G3D::fuzzyEq(rot.w, 0.f))
rotation = G3D::Quat::fromAxisAngleRotation(G3D::Vector3::unitZ(), GetOrientation());
else
rotation = rot;
G3D::Quat rotation = rot;
rotation.unitize();
m_localRotation = rotation;
WorldRotation = rotation;
UpdatePackedRotation();
}
@@ -2228,26 +2222,26 @@ void GameObject::SetTransportPathRotation(float qx, float qy, float qz, float qw
SetFloatValue(GAMEOBJECT_PARENTROTATION + 3, qw);
}
void GameObject::SetLocalRotationAngles(float z_rot, float y_rot, float x_rot)
void GameObject::SetWorldRotationAngles(float z_rot, float y_rot, float x_rot)
{
SetLocalRotation(G3D::Quat(G3D::Matrix3::fromEulerAnglesZYX(z_rot, y_rot, x_rot)));
SetWorldRotation(G3D::Quat(G3D::Matrix3::fromEulerAnglesZYX(z_rot, y_rot, x_rot)));
}
G3D::Quat GameObject::GetWorldRotation() const
G3D::Quat GameObject::GetFinalWorldRotation() const
{
G3D::Quat localRotation = GetLocalRotation();
G3D::Quat worldRotation = GetWorldRotation();
if (Transport* transport = GetTransport())
{
G3D::Quat worldRotation = transport->GetWorldRotation();
G3D::Quat transportRotation = transport->GetWorldRotation();
G3D::Quat transportRotationQuat(transportRotation.x, transportRotation.y, transportRotation.z, transportRotation.w);
G3D::Quat worldRotationQuat(worldRotation.x, worldRotation.y, worldRotation.z, worldRotation.w);
G3D::Quat localRotationQuat(localRotation.x, localRotation.y, localRotation.z, localRotation.w);
G3D::Quat resultRotation = localRotationQuat * worldRotationQuat;
G3D::Quat resultRotation = worldRotationQuat * transportRotationQuat;
return G3D::Quat(resultRotation.x, resultRotation.y, resultRotation.z, resultRotation.w);
}
return localRotation;
return worldRotation;
}
void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= nullptr*/, uint32 spellId /*= 0*/)
@@ -2967,10 +2961,10 @@ bool GameObject::IsAtInteractDistance(Position const& pos, float radius) const
float maxY = displayInfo->maxY * scale + radius;
float maxZ = displayInfo->maxZ * scale + radius;
G3D::Quat worldRotation = GetWorldRotation();
G3D::Quat worldRotationQuat(worldRotation.x, worldRotation.y, worldRotation.z, worldRotation.w);
G3D::Quat finalRotation = GetFinalWorldRotation();
G3D::Quat finalRotationQuat(finalRotation.x, finalRotation.y, finalRotation.z, finalRotation.w);
return G3D::CoordinateFrame {{worldRotationQuat}, {GetPositionX(), GetPositionY(), GetPositionZ()}}.toWorldSpace(G3D::Box {{minX, minY, minZ}, {maxX, maxY, maxZ}}).contains({pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()});
return G3D::CoordinateFrame {{finalRotationQuat}, {GetPositionX(), GetPositionY(), GetPositionZ()}}.toWorldSpace(G3D::Box {{minX, minY, minZ}, {maxX, maxY, maxZ}}).contains({pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()});
}
return GetExactDist(&pos) <= radius;

View File

@@ -144,12 +144,12 @@ public:
[[nodiscard]] ObjectGuid::LowType GetSpawnId() const { return m_spawnId; }
// z_rot, y_rot, x_rot - rotation angles around z, y and x axes
void SetLocalRotationAngles(float z_rot, float y_rot, float x_rot);
void SetLocalRotation(G3D::Quat const& rot);
void SetWorldRotationAngles(float z_rot, float y_rot, float x_rot);
void SetWorldRotation(G3D::Quat const& rot);
void SetTransportPathRotation(float qx, float qy, float qz, float qw);
[[nodiscard]] G3D::Quat const& GetLocalRotation() const { return m_localRotation; }
[[nodiscard]] int64 GetPackedLocalRotation() const { return m_packedRotation; }
[[nodiscard]] G3D::Quat GetWorldRotation() const;
[[nodiscard]] G3D::Quat const& GetWorldRotation() const { return WorldRotation; }
[[nodiscard]] int64 GetPackedWorldRotation() const { return m_packedRotation; }
[[nodiscard]] G3D::Quat GetFinalWorldRotation() const;
// overwrite WorldObject function for proper name localization
[[nodiscard]] std::string const& GetNameForLocaleIdx(LocaleConstant locale_idx) const override;
@@ -394,7 +394,7 @@ protected:
bool m_allowModifyDestructibleBuilding;
int64 m_packedRotation;
G3D::Quat m_localRotation;
G3D::Quat WorldRotation;
Position m_stationaryPosition;
ObjectGuid m_lootRecipient;

View File

@@ -479,7 +479,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const
// 0x200
if (flags & UPDATEFLAG_ROTATION)
{
*data << int64(ToGameObject()->GetPackedLocalRotation());
*data << int64(ToGameObject()->GetPackedWorldRotation());
}
}

View File

@@ -99,7 +99,7 @@ bool MotionTransport::CreateMoTrans(ObjectGuid::LowType guidlow, uint32 entry, u
SetName(goinfo->name);
// pussywizard: no WorldRotation for MotionTransports
SetLocalRotation(G3D::Quat());
SetWorldRotation(G3D::Quat());
// pussywizard: no PathRotation for MotionTransports
SetTransportPathRotation(0.0f, 0.0f, 0.0f, 1.0f);
@@ -768,7 +768,7 @@ bool StaticTransport::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* m
// pussywizard: temporarily calculate WorldRotation from orientation, do so until values in db are correct
//SetWorldRotation( /*for StaticTransport we need 2 rotation Quats in db for World- and Path- Rotation*/ );
SetLocalRotationAngles(NormalizeOrientation(GetOrientation()), 0.0f, 0.0f);
SetWorldRotationAngles(NormalizeOrientation(GetOrientation()), 0.0f, 0.0f);
// pussywizard: PathRotation for StaticTransport (only StaticTransports have PathRotation)
SetTransportPathRotation(rotation.x, rotation.y, rotation.z, rotation.w);

View File

@@ -332,7 +332,7 @@ public:
Map* map = object->GetMap();
object->Relocate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), *oz);
object->SetLocalRotationAngles(*oz, oy.value_or(0.0f), ox.value_or(0.0f));
object->SetWorldRotationAngles(*oz, oy.value_or(0.0f), ox.value_or(0.0f));
object->SaveToDB();
// Generate a completely new spawn with new guid