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;