From 14ebaae275aae61b2fab8c4da056d23058804a9e Mon Sep 17 00:00:00 2001 From: blinkysc <37940565+blinkysc@users.noreply.github.com> Date: Tue, 3 Feb 2026 11:26:50 -0600 Subject: [PATCH] fix(Core/GameObject): Use quaternion rotation directly instead of orientation hackfix (#24602) Co-authored-by: blinkysc Co-authored-by: zergtmn --- .../rev_1770075577120661993.sql | 6 +++ .../rev_1770127062954420379.sql | 5 ++ .../game/Entities/GameObject/GameObject.cpp | 46 ++++++------------- .../game/Entities/GameObject/GameObjectData.h | 14 ++++++ src/server/game/Globals/ObjectMgr.cpp | 15 ++++-- 5 files changed, 51 insertions(+), 35 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1770075577120661993.sql create mode 100644 data/sql/updates/pending_db_world/rev_1770127062954420379.sql diff --git a/data/sql/updates/pending_db_world/rev_1770075577120661993.sql b/data/sql/updates/pending_db_world/rev_1770075577120661993.sql new file mode 100644 index 000000000..0a9e9b7d3 --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1770075577120661993.sql @@ -0,0 +1,6 @@ +-- Add parent rotation columns to gameobject_addon table for transport rotation support +ALTER TABLE `gameobject_addon` + ADD COLUMN `parent_rotation0` FLOAT NOT NULL DEFAULT 0 AFTER `guid`, + ADD COLUMN `parent_rotation1` FLOAT NOT NULL DEFAULT 0 AFTER `parent_rotation0`, + ADD COLUMN `parent_rotation2` FLOAT NOT NULL DEFAULT 0 AFTER `parent_rotation1`, + ADD COLUMN `parent_rotation3` FLOAT NOT NULL DEFAULT 1 AFTER `parent_rotation2`; diff --git a/data/sql/updates/pending_db_world/rev_1770127062954420379.sql b/data/sql/updates/pending_db_world/rev_1770127062954420379.sql new file mode 100644 index 000000000..86b77b06e --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1770127062954420379.sql @@ -0,0 +1,5 @@ +-- DB/Gameobject: Update "Dangerous!" sign with sniffed values +-- Closes https://github.com/azerothcore/azerothcore-wotlk/issues/16834 +DELETE FROM `gameobject` WHERE `guid` = 17154 AND `id` = 2008; +INSERT INTO `gameobject` (`guid`, `id`, `map`, `zoneId`, `areaId`, `spawnMask`, `phaseMask`, `position_x`, `position_y`, `position_z`, `orientation`, `rotation0`, `rotation1`, `rotation2`, `rotation3`, `spawntimesecs`, `animprogress`, `state`, `VerifiedBuild`) VALUES +(17154, 2008, 0, 267, 272, 1, 1, -19.4826393127441406, -935.3038330078125, 58.09708786010742187, 2.65289926528930664, -0.04655265808105468, 0.011606216430664062, 0.969178199768066406, 0.241643846035003662, 120, 255, 1, 42328); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index aa07590f6..d093eb4a1 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -38,6 +38,11 @@ #include #include +bool QuaternionData::IsUnit() const +{ + return fabs(x * x + y * y + z * z + w * w - 1.0f) < 1e-5f; +} + GameObject::GameObject() : WorldObject(), MovableMapObject(), m_model(nullptr), m_goValue(), m_AI(nullptr) { @@ -293,35 +298,14 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u return false; } - GameObjectAddon const* addon = sObjectMgr->GetGameObjectAddon(GetSpawnId()); + SetLocalRotation(rotation); - // hackfix for the hackfix down below - switch (goinfo->entry) - { - // excluded ids from the hackfix below - // used switch since there should be more - case 181233: // maexxna portal effect - case 181575: // maexxna portal - case 20992: // theramore black shield - case 21042: // theramore guard badge - SetLocalRotation(rotation); - break; - default: - // xinef: hackfix - but make it possible to use original WorldRotation (using special gameobject addon data) - // pussywizard: temporarily calculate WorldRotation from orientation, do so until values in db are correct - if (addon && addon->invisibilityType == INVISIBILITY_GENERAL && addon->InvisibilityValue == 0) - { - SetLocalRotation(rotation); - } - else - { - SetLocalRotationAngles(NormalizeOrientation(GetOrientation()), 0.0f, 0.0f); - } - break; - } + GameObjectAddon const* gameObjectAddon = sObjectMgr->GetGameObjectAddon(GetSpawnId()); + QuaternionData parentRotation; + if (gameObjectAddon) + parentRotation = gameObjectAddon->ParentRotation; - // pussywizard: no PathRotation for normal gameobjects - SetTransportPathRotation(0.0f, 0.0f, 0.0f, 1.0f); + SetTransportPathRotation(parentRotation.x, parentRotation.y, parentRotation.z, parentRotation.w); SetObjectScale(goinfo->size); @@ -403,12 +387,12 @@ bool GameObject::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, u break; } - if (addon) + if (gameObjectAddon) { - if (addon->InvisibilityValue) + if (gameObjectAddon->InvisibilityValue) { - m_invisibility.AddFlag(addon->invisibilityType); - m_invisibility.AddValue(addon->invisibilityType, addon->InvisibilityValue); + m_invisibility.AddFlag(gameObjectAddon->invisibilityType); + m_invisibility.AddValue(gameObjectAddon->invisibilityType, gameObjectAddon->InvisibilityValue); } } diff --git a/src/server/game/Entities/GameObject/GameObjectData.h b/src/server/game/Entities/GameObject/GameObjectData.h index 7615dbbbe..eafe70a9d 100644 --- a/src/server/game/Entities/GameObject/GameObjectData.h +++ b/src/server/game/Entities/GameObject/GameObjectData.h @@ -678,9 +678,23 @@ struct GameObjectLocale std::vector CastBarCaption; }; +struct AC_GAME_API QuaternionData +{ + float x; + float y; + float z; + float w; + + QuaternionData() : x(0.0f), y(0.0f), z(0.0f), w(1.0f) { } + QuaternionData(float X, float Y, float Z, float W) : x(X), y(Y), z(Z), w(W) { } + + [[nodiscard]] bool IsUnit() const; +}; + // `gameobject_addon` table struct GameObjectAddon { + QuaternionData ParentRotation; InvisibilityType invisibilityType; uint32 InvisibilityValue; }; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 175bdd7c2..977d5436d 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -1355,8 +1355,8 @@ void ObjectMgr::LoadGameObjectAddons() { uint32 oldMSTime = getMSTime(); - // 0 1 2 - QueryResult result = WorldDatabase.Query("SELECT guid, invisibilityType, invisibilityValue FROM gameobject_addon"); + // 0 1 2 3 4 5 6 + QueryResult result = WorldDatabase.Query("SELECT guid, parent_rotation0, parent_rotation1, parent_rotation2, parent_rotation3, invisibilityType, invisibilityValue FROM gameobject_addon"); if (!result) { @@ -1380,8 +1380,9 @@ void ObjectMgr::LoadGameObjectAddons() } GameObjectAddon& gameObjectAddon = _gameObjectAddonStore[guid]; - gameObjectAddon.invisibilityType = InvisibilityType(fields[1].Get()); - gameObjectAddon.InvisibilityValue = fields[2].Get(); + gameObjectAddon.ParentRotation = QuaternionData(fields[1].Get(), fields[2].Get(), fields[3].Get(), fields[4].Get()); + gameObjectAddon.invisibilityType = InvisibilityType(fields[5].Get()); + gameObjectAddon.InvisibilityValue = fields[6].Get(); if (gameObjectAddon.invisibilityType >= TOTAL_INVISIBILITY_TYPES) { @@ -1396,6 +1397,12 @@ void ObjectMgr::LoadGameObjectAddons() gameObjectAddon.InvisibilityValue = 1; } + if (!gameObjectAddon.ParentRotation.IsUnit()) + { + LOG_ERROR("sql.sql", "GameObject (GUID: {}) has invalid parent rotation in `gameobject_addon`, set to default", guid); + gameObjectAddon.ParentRotation = QuaternionData(); + } + ++count; } while (result->NextRow());