diff --git a/sql/updates/world/2012_01_15_01_world_gameobject_addon.sql b/sql/updates/world/2012_01_15_01_world_gameobject_addon.sql new file mode 100644 index 0000000000000..5227673e19116 --- /dev/null +++ b/sql/updates/world/2012_01_15_01_world_gameobject_addon.sql @@ -0,0 +1,9 @@ +DROP TABLE IF EXISTS `gameobject_addon`; +CREATE TABLE `gameobject_addon` ( + `guid` int(10) unsigned NOT NULL default '0', + `path_rotation0` float NOT NULL default '0', + `path_rotation1` float NOT NULL default '0', + `path_rotation2` float NOT NULL default '0', + `path_rotation3` float NOT NULL default '1', + PRIMARY KEY (`guid`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Gameobject System'; \ No newline at end of file diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 6a75869511658..cb5ff9e70242d 100755 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -1420,7 +1420,7 @@ bool Battleground::AddObject(uint32 type, uint32 entry, float x, float y, float // So we must create it specific for this instance GameObject* go = new GameObject; if (!go->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), entry, GetBgMap(), - PHASEMASK_NORMAL, x, y, z, o, rotation0, rotation1, rotation2, rotation3, 100, GO_STATE_READY)) + PHASEMASK_NORMAL, x, y, z, o, QuaternionData(rotation0, rotation1, rotation2, rotation3))) { sLog->outErrorDb("Battleground::AddObject: cannot create gameobject (entry: %u) for BG (map: %u, instance id: %u)!", entry, m_MapId, m_InstanceID); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp index 5ee1a7bcc5820..42478cd1b1bdc 100755 --- a/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundSA.cpp @@ -114,8 +114,8 @@ bool BattlegroundSA::ResetObjs() } // MAD props for Kiper for discovering those values - 4 hours of his work. - GetBGObject(BG_SA_BOAT_ONE)->UpdateRotationFields(1.0f, 0.0002f); - GetBGObject(BG_SA_BOAT_TWO)->UpdateRotationFields(1.0f, 0.00001f); + GetBGObject(BG_SA_BOAT_ONE)->SetWorldRotationAngles(1.0f, 0.0002f, 0.0f); + GetBGObject(BG_SA_BOAT_TWO)->SetWorldRotationAngles(1.0f, 0.00001f, 0.0f); SpawnBGObject(BG_SA_BOAT_ONE, RESPAWN_IMMEDIATELY); SpawnBGObject(BG_SA_BOAT_TWO, RESPAWN_IMMEDIATELY); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index fd094938da877..e7c740e7c2919 100755 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -16,6 +16,8 @@ * with this program. If not, see . */ +#include + #include "GameObjectAI.h" #include "ObjectMgr.h" #include "GroupMgr.h" @@ -50,7 +52,7 @@ GameObject::GameObject() : WorldObject(false), m_goValue(new GameObjectValue), m m_goData = NULL; m_DBTableGuid = 0; - m_rotation = 0; + m_packedRotation = 0; m_groupLootTimer = 0; lootingGroupLowGUID = 0; @@ -145,7 +147,7 @@ void GameObject::RemoveFromWorld() } } -bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 artKit) +bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, QuaternionData rotation, uint8 animprogress, GOState go_state, uint32 artKit) { ASSERT(map); SetMap(map); @@ -184,16 +186,21 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa return false; } - SetFloatValue(GAMEOBJECT_PARENTROTATION+0, rotation0); - SetFloatValue(GAMEOBJECT_PARENTROTATION+1, rotation1); - - UpdateRotationFields(rotation2, rotation3); // GAMEOBJECT_FACING, GAMEOBJECT_ROTATION, GAMEOBJECT_PARENTROTATION+2/3 + SetWorldRotation(rotation.x, rotation.y, rotation.z, rotation.w); + // For most of gameobjects is (0, 0, 0, 1) quaternion, only some transports has not standart rotation + if (GameObjectDataAddon const* addon = sObjectMgr->GetGameObjectAddonTemplate(guidlow)) + SetTransportPathRotation(addon->path_rotation); + else + SetTransportPathRotation(QuaternionData(0,0,0,1)); SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size); SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction); SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags); + if (goinfo->type == GAMEOBJECT_TYPE_TRANSPORT) + SetFlag(GAMEOBJECT_FLAGS, (GO_FLAG_TRANSPORT | GO_FLAG_NODESPAWN)); + SetEntry(goinfo->entry); // set name for logs usage, doesn't affect anything ingame @@ -294,7 +301,6 @@ void GameObject::Update(uint32 diff) if (caster && caster->GetTypeId() == TYPEID_PLAYER) { SetGoState(GO_STATE_ACTIVE); - SetUInt32Value(GAMEOBJECT_FLAGS, GO_FLAG_NODESPAWN); UpdateData udata; WorldPacket packet; @@ -659,10 +665,10 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) data.posY = GetPositionY(); data.posZ = GetPositionZ(); data.orientation = GetOrientation(); - data.rotation0 = GetFloatValue(GAMEOBJECT_PARENTROTATION+0); - data.rotation1 = GetFloatValue(GAMEOBJECT_PARENTROTATION+1); - data.rotation2 = GetFloatValue(GAMEOBJECT_PARENTROTATION+2); - data.rotation3 = GetFloatValue(GAMEOBJECT_PARENTROTATION+3); + data.rotation.x = m_worldRotation.x; + data.rotation.y = m_worldRotation.y; + data.rotation.z = m_worldRotation.z; + data.rotation.w = m_worldRotation.w; data.spawntimesecs = m_spawnedByDefault ? m_respawnDelayTime : -(int32)m_respawnDelayTime; data.animprogress = GetGoAnimProgress(); data.go_state = GetGoState(); @@ -681,10 +687,10 @@ void GameObject::SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask) << GetPositionY() << ',' << GetPositionZ() << ',' << GetOrientation() << ',' - << GetFloatValue(GAMEOBJECT_PARENTROTATION) << ',' - << GetFloatValue(GAMEOBJECT_PARENTROTATION+1) << ',' - << GetFloatValue(GAMEOBJECT_PARENTROTATION+2) << ',' - << GetFloatValue(GAMEOBJECT_PARENTROTATION+3) << ',' + << m_worldRotation.x << ',' + << m_worldRotation.y << ',' + << m_worldRotation.z << ',' + << m_worldRotation.w << ',' << m_respawnDelayTime << ',' << uint32(GetGoAnimProgress()) << ',' << uint32(GetGoState()) << ')'; @@ -713,19 +719,14 @@ bool GameObject::LoadGameObjectFromDB(uint32 guid, Map* map, bool addToMap) float z = data->posZ; float ang = data->orientation; - float rotation0 = data->rotation0; - float rotation1 = data->rotation1; - float rotation2 = data->rotation2; - float rotation3 = data->rotation3; - - uint32 animprogress = data->animprogress; + uint8 animprogress = data->animprogress; GOState go_state = data->go_state; uint32 artKit = data->artKit; m_DBTableGuid = guid; if (map->GetInstanceId() != 0) guid = sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT); - if (!Create(guid, entry, map, phaseMask, x, y, z, ang, rotation0, rotation1, rotation2, rotation3, animprogress, go_state, artKit)) + if (!Create(guid, entry, map, phaseMask, x, y, z, ang, data->rotation, animprogress, go_state, artKit)) return false; if (data->spawntimesecs >= 0) @@ -1691,34 +1692,70 @@ const char* GameObject::GetNameForLocaleIdx(LocaleConstant loc_idx) const return GetName(); } -void GameObject::UpdateRotationFields(float rotation2 /*=0.0f*/, float rotation3 /*=0.0f*/) +using G3D::Quat; +struct QuaternionCompressed { - static double const atan_pow = atan(pow(2.0f, -20.0f)); + QuaternionCompressed() : m_raw(0) {} + QuaternionCompressed(int64 val) : m_raw(val) {} + QuaternionCompressed(const Quat& quat) { Set(quat); } - double f_rot1 = sin(GetOrientation() / 2.0f); - double f_rot2 = cos(GetOrientation() / 2.0f); + enum + { + PACK_COEFF_YZ = 1 << 20, + PACK_COEFF_X = 1 << 21, + }; - int64 i_rot1 = int64(f_rot1 / atan_pow *(f_rot2 >= 0 ? 1.0f : -1.0f)); - int64 rotation = (i_rot1 << 43 >> 43) & 0x00000000001FFFFF; + void Set(const Quat& quat) + { + int8 w_sign = (quat.w >= 0 ? 1 : -1); + int64 X = int32(quat.x * PACK_COEFF_X) * w_sign & ((1 << 22) - 1); + int64 Y = int32(quat.y * PACK_COEFF_YZ) * w_sign & ((1 << 21) - 1); + int64 Z = int32(quat.z * PACK_COEFF_YZ) * w_sign & ((1 << 21) - 1); + m_raw = Z | (Y << 21) | (X << 42); + } - //float f_rot2 = sin(0.0f / 2.0f); - //int64 i_rot2 = f_rot2 / atan(pow(2.0f, -20.0f)); - //rotation |= (((i_rot2 << 22) >> 32) >> 11) & 0x000003FFFFE00000; + Quat Unpack() const + { + double x = (double)(m_raw >> 42) / (double)PACK_COEFF_X; + double y = (double)(m_raw << 22 >> 43) / (double)PACK_COEFF_YZ; + double z = (double)(m_raw << 43 >> 43) / (double)PACK_COEFF_YZ; + double w = 1 - (x * x + y * y + z * z); + ASSERT(w >= 0); + w = sqrt(w); + + return Quat(x,y,z,w); + } - //float f_rot3 = sin(0.0f / 2.0f); - //int64 i_rot3 = f_rot3 / atan(pow(2.0f, -21.0f)); - //rotation |= (i_rot3 >> 42) & 0x7FFFFC0000000000; + int64 m_raw; +}; - m_rotation = rotation; +void GameObject::SetWorldRotation(float qx, float qy, float qz, float qw) +{ + Quat rotation(qx, qy, qz, qw); + // Temporary solution for gameobjects that has no rotation data in DB: + if (qz == 0.f && qw == 0.f) + rotation = Quat::fromAxisAngleRotation(G3D::Vector3::unitZ(), GetOrientation()); + + rotation.unitize(); + m_packedRotation = QuaternionCompressed(rotation).m_raw; + m_worldRotation.x = rotation.x; + m_worldRotation.y = rotation.y; + m_worldRotation.z = rotation.z; + m_worldRotation.w = rotation.w; +} - if (rotation2 == 0.0f && rotation3 == 0.0f) - { - rotation2 = (float)f_rot1; - rotation3 = (float)f_rot2; - } +void GameObject::SetTransportPathRotation(QuaternionData rotation) +{ + SetFloatValue(GAMEOBJECT_PARENTROTATION + 0, rotation.x); + SetFloatValue(GAMEOBJECT_PARENTROTATION + 1, rotation.y); + SetFloatValue(GAMEOBJECT_PARENTROTATION + 2, rotation.z); + SetFloatValue(GAMEOBJECT_PARENTROTATION + 3, rotation.w); +} - SetFloatValue(GAMEOBJECT_PARENTROTATION+2, rotation2); - SetFloatValue(GAMEOBJECT_PARENTROTATION+3, rotation3); +void GameObject::SetWorldRotationAngles(float z_rot, float y_rot, float x_rot) +{ + Quat quat( G3D::Matrix3::fromEulerAnglesZYX(z_rot, y_rot, x_rot) ); + SetWorldRotation(quat.x, quat.y, quat.z, quat.w); } void GameObject::ModifyHealth(int32 change, Unit* attackerOrHealer /*= NULL*/, uint32 spellId /*= 0*/) diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index 9298c5affee9f..bbdf56c36effd 100755 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -573,6 +573,16 @@ enum GOState #define MAX_GO_STATE 3 +struct QuaternionData +{ + float x, y, z, w; + + QuaternionData() : x(0.f), y(0.f), z(0.f), w(0.f) {} + QuaternionData(float X, float Y, float Z, float W) : x(X), y(Y), z(Z), w(W) {} + + bool isUnit() const { return fabs(x*x + y*y + z*z + w*w - 1.f) < 1e-5;} +}; + // from `gameobject` struct GameObjectData { @@ -584,10 +594,7 @@ struct GameObjectData float posY; float posZ; float orientation; - float rotation0; - float rotation1; - float rotation2; - float rotation3; + QuaternionData rotation; int32 spawntimesecs; uint32 animprogress; GOState go_state; @@ -596,6 +603,15 @@ struct GameObjectData bool dbData; }; +// from `gameobject_addon` +struct GameObjectDataAddon +{ + uint32 guid; + QuaternionData path_rotation; +}; + +typedef UNORDERED_MAP GameObjectAddonContainer; + // For containers: [GO_NOT_READY]->GO_READY (close)->GO_ACTIVATED (open) ->GO_JUST_DEACTIVATED->GO_READY -> ... // For bobber: GO_NOT_READY ->GO_READY (close)->GO_ACTIVATED (open) ->GO_JUST_DEACTIVATED-> // For door(closed):[GO_NOT_READY]->GO_READY (close)->GO_ACTIVATED (open) ->GO_JUST_DEACTIVATED->GO_READY(close) -> ... @@ -613,6 +629,8 @@ class Unit; // 5 sec for bobber catch #define FISHING_BOBBER_READY_TIME 5 +#define GO_ANIMPROGRESS_DEFAULT 0xFF + class GameObject : public WorldObject, public GridObject { public: @@ -623,7 +641,8 @@ class GameObject : public WorldObject, public GridObject void RemoveFromWorld(); void CleanupsBeforeDelete(bool finalCleanup = true); - bool Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state, uint32 artKit = 0); + bool Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, + QuaternionData rotation = QuaternionData(), uint8 animprogress = GO_ANIMPROGRESS_DEFAULT, GOState go_state = GO_STATE_READY, uint32 artKit = 0); void Update(uint32 p_time); static GameObject* GetGameObject(WorldObject& object, uint64 guid); GameObjectTemplate const* GetGOInfo() const { return m_goInfo; } @@ -635,7 +654,11 @@ class GameObject : public WorldObject, public GridObject uint32 GetDBTableGUIDLow() const { return m_DBTableGuid; } - void UpdateRotationFields(float rotation2 = 0.0f, float rotation3 = 0.0f); + // z_rot, y_rot, x_rot - rotation angles around z, y and x axes + void SetWorldRotationAngles(float z_rot, float y_rot, float x_rot); + void SetWorldRotation(float qx, float qy, float qz, float qw); + void SetTransportPathRotation(QuaternionData rotation); // transforms(rotates) transport's path + int64 GetPackedWorldRotation() const { return m_packedRotation; } void Say(int32 textId, uint32 language, uint64 TargetGuid) { MonsterSay(textId, language, TargetGuid); } void Yell(int32 textId, uint32 language, uint64 TargetGuid) { MonsterYell(textId, language, TargetGuid); } @@ -784,7 +807,6 @@ class GameObject : public WorldObject, public GridObject void EventInform(uint32 eventId); - uint64 GetRotation() const { return m_rotation; } virtual uint32 GetScriptId() const { return GetGOInfo()->ScriptId; } GameObjectAI* AI() const { return m_AI; } @@ -812,7 +834,8 @@ class GameObject : public WorldObject, public GridObject GameObjectData const* m_goData; GameObjectValue * const m_goValue; - uint64 m_rotation; + int64 m_packedRotation; + QuaternionData m_worldRotation; uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable private: diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 5c034f1a42a40..8a1308594902e 100755 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -427,7 +427,7 @@ void Object::_BuildMovementUpdate(ByteBuffer * data, uint16 flags) const // 0x200 if (flags & UPDATEFLAG_ROTATION) { - *data << int64(((GameObject*)this)->GetRotation()); + *data << int64(((GameObject*)this)->GetPackedWorldRotation()); } } @@ -2360,7 +2360,7 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float } Map* map = GetMap(); GameObject* go = new GameObject(); - if (!go->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), entry, map, GetPhaseMask(), x, y, z, ang, rotation0, rotation1, rotation2, rotation3, 100, GO_STATE_READY)) + if (!go->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), entry, map, GetPhaseMask(), x, y, z, ang, QuaternionData(rotation0, rotation1, rotation2, rotation3))) { delete go; return NULL; diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 67d1636c7e2ec..1d01269d90858 100755 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -190,7 +190,7 @@ Transport::~Transport() m_passengers.clear(); } -bool Transport::Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags) +bool Transport::Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint8 animprogress, uint16 dynamicHighValue) { Relocate(x, y, z, ang); // instance id and phaseMask isn't set to values different from std. @@ -217,8 +217,7 @@ bool Transport::Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, floa SetFloatValue(OBJECT_FIELD_SCALE_X, goinfo->size); SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction); - //SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags); - SetUInt32Value(GAMEOBJECT_FLAGS, MAKE_PAIR32(0x28, 0x64)); + SetUInt32Value(GAMEOBJECT_FLAGS, (GO_FLAG_TRANSPORT | GO_FLAG_NODESPAWN)); SetUInt32Value(GAMEOBJECT_LEVEL, m_period); SetEntry(goinfo->entry); @@ -226,10 +225,12 @@ bool Transport::Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, floa SetGoState(GO_STATE_READY); SetGoType(GameobjectTypes(goinfo->type)); - + SetGoArtKit(0); SetGoAnimProgress(animprogress); - if (dynflags) - SetUInt32Value(GAMEOBJECT_DYNAMIC, MAKE_PAIR32(0, dynflags)); + + // low part always 0, dynamicHighValue is some kind of progression (not implemented) + SetUInt16Value(GAMEOBJECT_DYNAMIC, 0, 0); + SetUInt16Value(GAMEOBJECT_DYNAMIC, 1, dynamicHighValue); SetName(goinfo->name); diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h index 518dcf6359d74..e66a108dfed00 100755 --- a/src/server/game/Entities/Transport/Transport.h +++ b/src/server/game/Entities/Transport/Transport.h @@ -31,7 +31,7 @@ class Transport : public GameObject Transport(uint32 period, uint32 script); ~Transport(); - bool Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress, uint32 dynflags); + bool Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint8 animprogress, uint16 dynamicHighValue); bool GenerateWaypoints(uint32 pathid, std::set &mapids); void Update(uint32 p_time); bool AddPassenger(Player* passenger); diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 086dd610ee2ed..68a558caa9757 100755 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -1589,7 +1589,7 @@ void ObjectMgr::RemoveCreatureFromGrid(uint32 guid, CreatureData const* data) } } -uint32 ObjectMgr::AddGOData(uint32 entry, uint32 mapId, float x, float y, float z, float o, uint32 spawntimedelay, float rotation0, float rotation1, float rotation2, float rotation3) +uint32 ObjectMgr::AddGOData(uint32 entry, uint32 mapId, float x, float y, float z, float o, uint32 spawntimedelay, QuaternionData rotation) { GameObjectTemplate const* goinfo = GetGameObjectTemplate(entry); if (!goinfo) @@ -1607,10 +1607,10 @@ uint32 ObjectMgr::AddGOData(uint32 entry, uint32 mapId, float x, float y, float data.posY = y; data.posZ = z; data.orientation = o; - data.rotation0 = rotation0; - data.rotation1 = rotation1; - data.rotation2 = rotation2; - data.rotation3 = rotation3; + data.rotation.x = rotation.x; + data.rotation.y = rotation.y; + data.rotation.z = rotation.z; + data.rotation.w = rotation.w; data.spawntimesecs = spawntimedelay; data.animprogress = 100; data.spawnMask = 1; @@ -1794,10 +1794,10 @@ void ObjectMgr::LoadGameobjects() data.posY = fields[ 4].GetFloat(); data.posZ = fields[ 5].GetFloat(); data.orientation = fields[ 6].GetFloat(); - data.rotation0 = fields[ 7].GetFloat(); - data.rotation1 = fields[ 8].GetFloat(); - data.rotation2 = fields[ 9].GetFloat(); - data.rotation3 = fields[10].GetFloat(); + data.rotation.x = fields[ 7].GetFloat(); + data.rotation.y = fields[ 8].GetFloat(); + data.rotation.z = fields[ 9].GetFloat(); + data.rotation.w = fields[10].GetFloat(); data.spawntimesecs = fields[11].GetInt32(); MapEntry const* mapEntry = sMapStore.LookupEntry(data.mapid); @@ -1832,15 +1832,27 @@ void ObjectMgr::LoadGameobjects() int16 gameEvent = fields[16].GetInt16(); uint32 PoolId = fields[17].GetUInt32(); - if (data.rotation2 < -1.0f || data.rotation2 > 1.0f) + if (data.rotation.x < -1.0f || data.rotation.x > 1.0f) { - sLog->outErrorDb("Table `gameobject` has gameobject (GUID: %u Entry: %u) with invalid rotation2 (%f) value, skip", guid, data.id, data.rotation2); + sLog->outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid rotation0 (%f) value, skip", guid, data.id, data.rotation.x); continue; } - if (data.rotation3 < -1.0f || data.rotation3 > 1.0f) + if (data.rotation.y < -1.0f || data.rotation.y > 1.0f) { - sLog->outErrorDb("Table `gameobject` has gameobject (GUID: %u Entry: %u) with invalid rotation3 (%f) value, skip", guid, data.id, data.rotation3); + sLog->outErrorDb("Table `gameobject` have gameobject (GUID: %u Entry: %u) with invalid rotation1 (%f) value, skip", guid, data.id, data.rotation.y); + continue; + } + + if (data.rotation.z < -1.0f || data.rotation.z > 1.0f) + { + sLog->outErrorDb("Table `gameobject` has gameobject (GUID: %u Entry: %u) with invalid rotation2 (%f) value, skip", guid, data.id, data.rotation.z); + continue; + } + + if (data.rotation.w < -1.0f || data.rotation.w > 1.0f) + { + sLog->outErrorDb("Table `gameobject` has gameobject (GUID: %u Entry: %u) with invalid rotation3 (%f) value, skip", guid, data.id, data.rotation.w); continue; } @@ -1866,6 +1878,66 @@ void ObjectMgr::LoadGameobjects() sLog->outString(); } +void ObjectMgr::LoadGameObjectAddon() +{ + uint32 oldMSTime = getMSTime(); + + // 0 1 2 3 4 + QueryResult result = WorldDatabase.Query("SELECT guid, path_rotation0, path_rotation1, path_rotation2, path_rotation3, FROM gameobject_addon"); + + if (!result) + { + sLog->outErrorDb(">> Loaded 0 gameobjects addon definitions. DB table `gameobject_addon` is empty."); + sLog->outString(); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + uint32 guid = fields[0].GetUInt32(); + + if (mGameObjectDataMap.find(guid) == mGameObjectDataMap.end()) + { + sLog->outErrorDb("Gameobject (GUID: %u) does not exist but has a record in `gameobject_addon`", guid); + continue; + } + + GameObjectDataAddon const* addon = GetGameObjectAddonTemplate(guid); + if (!addon) + return; + + GameObjectDataAddon& gameObjectAddon = GameObjectAddonStore[guid]; + + gameObjectAddon.path_rotation.x = fields[1].GetFloat(); + gameObjectAddon.path_rotation.y = fields[2].GetFloat(); + gameObjectAddon.path_rotation.z = fields[3].GetFloat(); + gameObjectAddon.path_rotation.w = fields[4].GetFloat(); + + if (!gameObjectAddon.path_rotation.isUnit()) + { + sLog->outErrorDb("Gameobject (GUID: %u) has invalid path rotation", guid); + const_cast(addon)->path_rotation = QuaternionData(0.f, 0.f, 0.f, 1.f); + } + ++count; + } + while (result->NextRow()); + + sLog->outString(">> Loaded %lu gameobject addons in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); + sLog->outString(); +} + +GameObjectDataAddon const* ObjectMgr::GetGameObjectAddonTemplate(uint32 lowguid) +{ + GameObjectAddonContainer::const_iterator itr = GameObjectAddonStore.find(lowguid); + if (itr != GameObjectAddonStore.end()) + return &(itr->second); + + return NULL; +} + void ObjectMgr::AddGameobjectToGrid(uint32 guid, GameObjectData const* data) { uint8 mask = data->spawnMask; diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 126cca59ef0af..ab8b127d3d24e 100755 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -627,6 +627,9 @@ class ObjectMgr void LoadGameObjectTemplate(); void AddGameobjectInfo(GameObjectTemplate* goinfo); + GameObjectDataAddon const* GetGameObjectAddonTemplate(uint32 lowguid); + GameObjectAddonContainer const* GetGameObjectAddonTemplate() { return &GameObjectAddonStore; } + CreatureTemplate const* GetCreatureTemplate(uint32 entry); CreatureTemplateContainer const* GetCreatureTemplates() { return &CreatureTemplateStore; } CreatureModelInfo const* GetCreatureModelInfo(uint32 modelId); @@ -866,6 +869,7 @@ class ObjectMgr void LoadEquipmentTemplates(); void LoadGameObjectLocales(); void LoadGameobjects(); + void LoadGameObjectAddon(); void LoadGameobjectRespawnTimes(); void LoadItemTemplates(); void LoadItemLocales(); @@ -1098,7 +1102,7 @@ class ObjectMgr void RemoveCreatureFromGrid(uint32 guid, CreatureData const* data); void AddGameobjectToGrid(uint32 guid, GameObjectData const* data); void RemoveGameobjectFromGrid(uint32 guid, GameObjectData const* data); - uint32 AddGOData(uint32 entry, uint32 map, float x, float y, float z, float o, uint32 spawntimedelay = 0, float rotation0 = 0, float rotation1 = 0, float rotation2 = 0, float rotation3 = 0); + uint32 AddGOData(uint32 entry, uint32 map, float x, float y, float z, float o, uint32 spawntimedelay = 0, QuaternionData rotation = QuaternionData()); uint32 AddCreData(uint32 entry, uint32 team, uint32 map, float x, float y, float z, float o, uint32 spawntimedelay = 0); bool MoveCreData(uint32 guid, uint32 map, Position pos); @@ -1314,6 +1318,7 @@ class ObjectMgr CreatureAddonContainer CreatureAddonStore; CreatureAddonContainer CreatureTemplateAddonStore; EquipmentInfoContainer EquipmentInfoStore; + GameObjectAddonContainer GameObjectAddonStore; LinkedRespawnMap mLinkedRespawnMap; CreatureLocaleMap mCreatureLocaleMap; GameObjectDataMap mGameObjectDataMap; diff --git a/src/server/game/OutdoorPvP/OutdoorPvP.cpp b/src/server/game/OutdoorPvP/OutdoorPvP.cpp index 9f6ec54734269..e5ef6ba200063 100755 --- a/src/server/game/OutdoorPvP/OutdoorPvP.cpp +++ b/src/server/game/OutdoorPvP/OutdoorPvP.cpp @@ -95,7 +95,7 @@ void OPvPCapturePoint::AddCre(uint32 type, uint32 guid, uint32 entry) bool OPvPCapturePoint::AddObject(uint32 type, uint32 entry, uint32 map, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3) { - if (uint32 guid = sObjectMgr->AddGOData(entry, map, x, y, z, o, 0, rotation0, rotation1, rotation2, rotation3)) + if (uint32 guid = sObjectMgr->AddGOData(entry, map, x, y, z, o, 0, QuaternionData(rotation0, rotation1, rotation2, rotation3))) { AddGO(type, guid, entry); return true; @@ -127,7 +127,7 @@ bool OPvPCapturePoint::SetCapturePointData(uint32 entry, uint32 map, float x, fl return false; } - m_capturePointGUID = sObjectMgr->AddGOData(entry, map, x, y, z, o, 0, rotation0, rotation1, rotation2, rotation3); + m_capturePointGUID = sObjectMgr->AddGOData(entry, map, x, y, z, o, 0, QuaternionData(rotation0, rotation1, rotation2, rotation3)); if (!m_capturePointGUID) return false; diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index eaf5f4e1d317a..b2ec0bb0284a0 100755 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -4353,7 +4353,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) Map* map = target->GetMap(); if (!pGameObj->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), gameobject_id, map, - m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) + m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), QuaternionData(0.0f, 0.0f, 0.0f, 0.0f))) { delete pGameObj; return; @@ -4404,7 +4404,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) { GameObject* linkedGO = new GameObject; if (linkedGO->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, map, - m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) + m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), QuaternionData(0.0f, 0.0f, 0.0f, 0.0f))) { linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); linkedGO->SetSpellId(m_spellInfo->Id); @@ -5576,7 +5576,7 @@ void Spell::EffectDuel(SpellEffIndex effIndex) m_caster->GetPositionX()+(unitTarget->GetPositionX()-m_caster->GetPositionX())/2, m_caster->GetPositionY()+(unitTarget->GetPositionY()-m_caster->GetPositionY())/2, m_caster->GetPositionZ(), - m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) + m_caster->GetOrientation(), QuaternionData(0.0f, 0.0f, 0.0f, 0.0f))) { delete pGameObj; return; @@ -5930,7 +5930,7 @@ void Spell::EffectSummonObject(SpellEffIndex effIndex) Map* map = m_caster->GetMap(); if (!pGameObj->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), go_id, map, - m_caster->GetPhaseMask(), x, y, z, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) + m_caster->GetPhaseMask(), x, y, z, m_caster->GetOrientation(), QuaternionData(0.0f, 0.0f, 0.0f, 0.0f))) { delete pGameObj; return; @@ -6588,7 +6588,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) GameObject* pGameObj = new GameObject; if (!pGameObj->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), name_id, cMap, - m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) + m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), QuaternionData(0.0f, 0.0f, 0.0f, 0.0f))) { delete pGameObj; return; @@ -6654,7 +6654,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) { GameObject* linkedGO = new GameObject; if (linkedGO->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), linkedEntry, cMap, - m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) + m_caster->GetPhaseMask(), fx, fy, fz, m_caster->GetOrientation(), QuaternionData(0.0f, 0.0f, 0.0f, 0.0f))) { linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); //linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 426a93fda57c2..83285285d7ad6 100755 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1398,6 +1398,9 @@ void World::SetInitialWorldSettings() sLog->outString("Loading Gameobject Data..."); sObjectMgr->LoadGameobjects(); + sLog->outString("Loading Gameobject Addon Data..." ); + sObjectMgr->LoadGameObjectAddon(); + sLog->outString("Loading Gameobject Respawn Data..."); // must be after PackInstances() sObjectMgr->LoadGameobjectRespawnTimes(); diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp index 2fb6c3f0d10f2..d1ff969ddbf81 100644 --- a/src/server/scripts/Commands/cs_gobject.cpp +++ b/src/server/scripts/Commands/cs_gobject.cpp @@ -149,7 +149,7 @@ class gobject_commandscript : public CommandScript GameObject* object = new GameObject; uint32 guidLow = sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT); - if (!object->Create(guidLow, objectInfo->entry, map, player->GetPhaseMaskForSpawn(), x, y, z, o, 0.0f, 0.0f, 0.0f, 0.0f, 0, GO_STATE_READY)) + if (!object->Create(guidLow, objectInfo->entry, map, player->GetPhaseMaskForSpawn(), x, y, z, o, QuaternionData(0.0f, 0.0f, 0.0f, 0.0f))) { delete object; return false; @@ -413,7 +413,7 @@ class gobject_commandscript : public CommandScript } object->Relocate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), o); - object->UpdateRotationFields(); + //object->UpdateRotationFields(); object->DestroyForNearbyPlayers(); object->UpdateObjectVisibility(); diff --git a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp index fcb54985357a3..ba02f021c7611 100644 --- a/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp +++ b/src/server/scripts/Northrend/Nexus/EyeOfEternity/instance_eye_of_eternity.cpp @@ -93,7 +93,7 @@ class instance_eye_of_eternity : public InstanceMapScript GameObject* go = new GameObject; if (!go->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), entry, instance, PHASEMASK_NORMAL, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), - 0, 0, 0, 0, 120, GO_STATE_READY)) + QuaternionData(0, 0, 0, 0))) { delete go; return; diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp index a69dd3ed874ad..e5f09ae4339c1 100755 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp @@ -163,7 +163,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player* player, uint32 spellId) return true; } - if (!go->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), SI_SILITHYST_MOUND, map, player->GetPhaseMask(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), 0, 0, 0, 0, 100, GO_STATE_READY)) + if (!go->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), SI_SILITHYST_MOUND, map, player->GetPhaseMask(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), QuaternionData(0, 0, 0, 0))) { delete go; return true; @@ -197,7 +197,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player* player, uint32 spellId) return true; } - if (!go->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), SI_SILITHYST_MOUND, map, player->GetPhaseMask(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), 0, 0, 0, 0, 100, GO_STATE_READY)) + if (!go->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), SI_SILITHYST_MOUND, map, player->GetPhaseMask(), player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation(), QuaternionData(0, 0, 0, 0))) { delete go; return true;