fix(Core/GameObject): Handle zero quaternion rotation for dynamically spawned gameobjects (#24662)

Co-authored-by: blinkysc <blinkysc@users.noreply.github.com>
Co-authored-by: zergtmn <zergtmn@users.noreply.github.com>
This commit is contained in:
blinkysc
2026-02-09 20:07:23 -06:00
committed by GitHub
parent d914d61acb
commit 54d145499e
5 changed files with 67 additions and 4 deletions

View File

@@ -2209,6 +2209,10 @@ void GameObject::UpdatePackedRotation()
void GameObject::SetWorldRotation(G3D::Quat const& rot)
{
G3D::Quat rotation = rot;
// If the quaternion is zero (e.g. dynamically spawned GOs with no rotation),
// fall back to computing rotation from orientation to avoid NaN from unitize()
if (G3D::fuzzyEq(rotation.magnitude(), 0.0f))
rotation = G3D::Quat::fromAxisAngleRotation(G3D::Vector3::unitZ(), GetOrientation());
rotation.unitize();
WorldRotation = rotation;
UpdatePackedRotation();

View File

@@ -766,11 +766,13 @@ bool StaticTransport::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* m
return false;
}
// 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*/ );
SetWorldRotationAngles(NormalizeOrientation(GetOrientation()), 0.0f, 0.0f);
// pussywizard: PathRotation for StaticTransport (only StaticTransports have PathRotation)
SetTransportPathRotation(rotation.x, rotation.y, rotation.z, rotation.w);
// Prefer gameobject_addon parent_rotation for path rotation, fall back to gameobject.rotation
if (GameObjectAddon const* addon = sObjectMgr->GetGameObjectAddon(GetSpawnId()))
SetTransportPathRotation(addon->ParentRotation.x, addon->ParentRotation.y, addon->ParentRotation.z, addon->ParentRotation.w);
else
SetTransportPathRotation(rotation.x, rotation.y, rotation.z, rotation.w);
SetObjectScale(goinfo->size);

View File

@@ -2888,6 +2888,13 @@ void ObjectMgr::LoadGameobjects()
continue;
}
if (fabs(data.rotation.x * data.rotation.x + data.rotation.y * data.rotation.y +
data.rotation.z * data.rotation.z + data.rotation.w * data.rotation.w - 1.0f) >= 1e-5f)
{
LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: {} Entry: {}) with invalid rotation quaternion (non-unit), defaulting to orientation on Z axis only", guid, data.id);
data.rotation = G3D::Quat(G3D::Matrix3::fromEulerAnglesZYX(data.orientation, 0.0f, 0.0f));
}
if (!MapMgr::IsValidMapCoord(data.mapid, data.posX, data.posY, data.posZ, data.orientation))
{
LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: {} Entry: {}) with invalid coordinates, skip", guid, data.id);
@@ -3028,6 +3035,13 @@ GameObjectData const* ObjectMgr::LoadGameObjectDataFromDB(ObjectGuid::LowType sp
return nullptr;
}
if (fabs(goData.rotation.x * goData.rotation.x + goData.rotation.y * goData.rotation.y +
goData.rotation.z * goData.rotation.z + goData.rotation.w * goData.rotation.w - 1.0f) >= 1e-5f)
{
LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: {} Entry: {}) with invalid rotation quaternion (non-unit), defaulting to orientation on Z axis only", spawnId, entry);
goData.rotation = G3D::Quat(G3D::Matrix3::fromEulerAnglesZYX(goData.orientation, 0.0f, 0.0f));
}
if (!MapMgr::IsValidMapCoord(goData.mapid, goData.posX, goData.posY, goData.posZ, goData.orientation))
{
LOG_ERROR("sql.sql", "Table `gameobject` has gameobject (GUID: {} Entry: {}) with invalid coordinates, skipped.", spawnId, entry);