Transports - phase 2. Implementing the GameObject rotation quaternions.
- As long as we send the correct rotation quaternion to the client, the GAMEOBJECT_FACING must be set to 0 - GameObjectModel internal rotation matrices now take into account the rotation quaternion
This commit is contained in:
parent
350feb5889
commit
e803c57c9f
@ -58,7 +58,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include "Formulas.h"
|
#include "Formulas.h"
|
||||||
|
#include "G3D/Quat.h" // for turning GO's
|
||||||
#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
|
#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
|
||||||
#include "MoveMap.h" // for mmap manager
|
#include "MoveMap.h" // for mmap manager
|
||||||
#include "PathFinder.h" // for mmap commands
|
#include "PathFinder.h" // for mmap commands
|
||||||
@ -947,11 +947,27 @@ bool ChatHandler::HandleGameObjectTurnCommand(char* args)
|
|||||||
if (!ExtractOptFloat(&args, o, m_session->GetPlayer()->GetOrientation()))
|
if (!ExtractOptFloat(&args, o, m_session->GetPlayer()->GetOrientation()))
|
||||||
{ return false; }
|
{ return false; }
|
||||||
|
|
||||||
Map* map = obj->GetMap();
|
// ok, let's rotate the GO around Z axis
|
||||||
map->Remove(obj, false);
|
// we first get the original rotation quaternion
|
||||||
|
// then we'll create a rotation quat describing the rotation around Z
|
||||||
|
G3D::Quat original_rot;
|
||||||
|
obj->GetQuaternion(original_rot);
|
||||||
|
|
||||||
obj->Relocate(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), o);
|
// the rotation amount around Z-axis
|
||||||
obj->UpdateRotationFields();
|
float deltaO = o - obj->GetOrientationFromQuat(original_rot);
|
||||||
|
|
||||||
|
// multiplying 2 quaternions gives the final rotation
|
||||||
|
// quaternion multiplication is not commutative!
|
||||||
|
G3D::Quat final_rot = G3D::Quat(0.0f, 0.0f, sin(deltaO/2), cos(deltaO/2)) * original_rot;
|
||||||
|
|
||||||
|
// quaternion multiplication gives a non-unit quat
|
||||||
|
final_rot.unitize();
|
||||||
|
|
||||||
|
Map* map = obj->GetMap();
|
||||||
|
map->Remove(obj, false); //mandatory to remove GO model from m_dyn_tree
|
||||||
|
|
||||||
|
obj->SetQuaternion(final_rot); // this will update internal model rotation matrices
|
||||||
|
obj->Relocate(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), obj->GetOrientationFromQuat(final_rot));
|
||||||
|
|
||||||
map->Add(obj);
|
map->Add(obj);
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "GameObject.h"
|
#include "GameObject.h"
|
||||||
|
#include "G3D/Quat.h"
|
||||||
#include "QuestDef.h"
|
#include "QuestDef.h"
|
||||||
#include "ObjectMgr.h"
|
#include "ObjectMgr.h"
|
||||||
#include "PoolManager.h"
|
#include "PoolManager.h"
|
||||||
@ -145,10 +146,32 @@ void GameObject::CleanupsBeforeDelete()
|
|||||||
WorldObject::CleanupsBeforeDelete();
|
WorldObject::CleanupsBeforeDelete();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, float x, float y, float z, float ang, float rotation0, float rotation1, float rotation2, float rotation3, uint32 animprogress, GOState go_state)
|
bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, float x, float y, float z, float ang, float r0, float r1, float r2, float r3, uint32 animprogress, GOState go_state)
|
||||||
{
|
{
|
||||||
MANGOS_ASSERT(map);
|
if (!map)
|
||||||
Relocate(x, y, z, ang);
|
{ return false; }
|
||||||
|
|
||||||
|
GameObjectInfo const* goinfo = ObjectMgr::GetGameObjectInfo(name_id);
|
||||||
|
if (!goinfo)
|
||||||
|
{
|
||||||
|
sLog.outErrorDb("Gameobject (GUID: %u) not created: Entry %u does not exist in `gameobject_template`", guidlow, name_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object::_Create(guidlow, goinfo->id, HIGHGUID_GAMEOBJECT);
|
||||||
|
|
||||||
|
// let's make sure we don't send the client invalid quaternion
|
||||||
|
if (r0 == 0.0f && r1 == 0.0f && r2 == 0.0f)
|
||||||
|
{
|
||||||
|
r2 = sin(ang/2);
|
||||||
|
r3 = cos(ang/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
G3D::Quat q(r0, r1, r2, r3);
|
||||||
|
q.unitize();
|
||||||
|
|
||||||
|
float o = GetOrientationFromQuat(q);
|
||||||
|
Relocate(x, y, z, o);
|
||||||
SetMap(map);
|
SetMap(map);
|
||||||
|
|
||||||
if (!IsPositionValid())
|
if (!IsPositionValid())
|
||||||
@ -157,14 +180,7 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, float x, float
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameObjectInfo const* goinfo = ObjectMgr::GetGameObjectInfo(name_id);
|
SetQuaternion(q);
|
||||||
if (!goinfo)
|
|
||||||
{
|
|
||||||
sLog.outErrorDb("Gameobject (GUID: %u) not created: Entry %u does not exist in `gameobject_template`. Map: %u (X: %f Y: %f Z: %f) ang: %f rotation0: %f rotation1: %f rotation2: %f rotation3: %f", guidlow, name_id, map->GetId(), x, y, z, ang, rotation0, rotation1, rotation2, rotation3);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object::_Create(guidlow, goinfo->id, HIGHGUID_GAMEOBJECT);
|
|
||||||
|
|
||||||
m_goInfo = goinfo;
|
m_goInfo = goinfo;
|
||||||
|
|
||||||
@ -180,11 +196,6 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, float x, float
|
|||||||
SetFloatValue(GAMEOBJECT_POS_Y, y);
|
SetFloatValue(GAMEOBJECT_POS_Y, y);
|
||||||
SetFloatValue(GAMEOBJECT_POS_Z, z);
|
SetFloatValue(GAMEOBJECT_POS_Z, z);
|
||||||
|
|
||||||
SetFloatValue(GAMEOBJECT_ROTATION + 0, rotation0);
|
|
||||||
SetFloatValue(GAMEOBJECT_ROTATION + 1, rotation1);
|
|
||||||
|
|
||||||
UpdateRotationFields(rotation2, rotation3); // GAMEOBJECT_FACING, GAMEOBJECT_ROTATION+2/3
|
|
||||||
|
|
||||||
SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction);
|
SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction);
|
||||||
SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags);
|
SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags);
|
||||||
|
|
||||||
@ -1673,18 +1684,30 @@ const char* GameObject::GetNameForLocaleIdx(int32 loc_idx) const
|
|||||||
return GetName();
|
return GetName();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameObject::UpdateRotationFields(float rotation2 /*=0.0f*/, float rotation3 /*=0.0f*/)
|
void GameObject::SetQuaternion(G3D::Quat const& q)
|
||||||
{
|
{
|
||||||
SetFloatValue(GAMEOBJECT_FACING, GetOrientation());
|
SetFloatValue(GAMEOBJECT_ROTATION + 0, q.x);
|
||||||
|
SetFloatValue(GAMEOBJECT_ROTATION + 1, q.y);
|
||||||
|
SetFloatValue(GAMEOBJECT_ROTATION + 2, q.z);
|
||||||
|
SetFloatValue(GAMEOBJECT_ROTATION + 3, q.w);
|
||||||
|
|
||||||
if (rotation2 == 0.0f && rotation3 == 0.0f)
|
if (m_model)
|
||||||
{
|
{ m_model->UpdateRotation(q); }
|
||||||
rotation2 = sin(GetOrientation() / 2);
|
|
||||||
rotation3 = cos(GetOrientation() / 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetFloatValue(GAMEOBJECT_ROTATION + 2, rotation2);
|
void GameObject::GetQuaternion(G3D::Quat& q) const
|
||||||
SetFloatValue(GAMEOBJECT_ROTATION + 3, rotation3);
|
{
|
||||||
|
q.x = GetFloatValue(GAMEOBJECT_ROTATION + 0);
|
||||||
|
q.y = GetFloatValue(GAMEOBJECT_ROTATION + 1);
|
||||||
|
q.z = GetFloatValue(GAMEOBJECT_ROTATION + 2);
|
||||||
|
q.w = GetFloatValue(GAMEOBJECT_ROTATION + 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
float GameObject::GetOrientationFromQuat(G3D::Quat const& q)
|
||||||
|
{
|
||||||
|
double t1 = +2.0f * (q.w * q.z + q.x * q.y);
|
||||||
|
double t2 = +1.0f - 2.0f * (q.y * q.y + q.z * q.z);
|
||||||
|
return MapManager::NormalizeOrientation(std::atan2(t1, t2));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameObject::IsHostileTo(Unit const* unit) const
|
bool GameObject::IsHostileTo(Unit const* unit) const
|
||||||
|
@ -491,16 +491,16 @@ enum GOState
|
|||||||
// from `gameobject`
|
// from `gameobject`
|
||||||
struct GameObjectData
|
struct GameObjectData
|
||||||
{
|
{
|
||||||
uint32 id; // entry in gamobject_template
|
uint32 id; // entry in gameobject_template
|
||||||
uint32 mapid;
|
uint32 mapid;
|
||||||
float posX;
|
float posX;
|
||||||
float posY;
|
float posY;
|
||||||
float posZ;
|
float posZ;
|
||||||
float orientation;
|
float orientation;
|
||||||
float rotation0;
|
float rotation0; // i component of rotation quaternion
|
||||||
float rotation1;
|
float rotation1; // j
|
||||||
float rotation2;
|
float rotation2; // k
|
||||||
float rotation3;
|
float rotation3; // w
|
||||||
int32 spawntimesecs;
|
int32 spawntimesecs;
|
||||||
uint32 animprogress;
|
uint32 animprogress;
|
||||||
GOState go_state;
|
GOState go_state;
|
||||||
@ -538,6 +538,12 @@ enum CapturePointSliderValue
|
|||||||
|
|
||||||
class Unit;
|
class Unit;
|
||||||
class GameObjectModel;
|
class GameObjectModel;
|
||||||
|
|
||||||
|
namespace G3D
|
||||||
|
{
|
||||||
|
class Quat;
|
||||||
|
};
|
||||||
|
|
||||||
struct GameObjectDisplayInfoEntry;
|
struct GameObjectDisplayInfoEntry;
|
||||||
|
|
||||||
// 5 sec for bobber catch
|
// 5 sec for bobber catch
|
||||||
@ -565,7 +571,12 @@ class GameObject : public WorldObject
|
|||||||
|
|
||||||
bool HasStaticDBSpawnData() const; // listed in `gameobject` table and have fixed in DB guid
|
bool HasStaticDBSpawnData() const; // listed in `gameobject` table and have fixed in DB guid
|
||||||
|
|
||||||
void UpdateRotationFields(float rotation2 = 0.0f, float rotation3 = 0.0f);
|
// rotation methods
|
||||||
|
void GetQuaternion(G3D::Quat& q) const;
|
||||||
|
void SetQuaternion(G3D::Quat const& q);
|
||||||
|
float GetOrientationFromQuat(G3D::Quat const& q);
|
||||||
|
|
||||||
|
void SetDisplayId(uint32 model_id);
|
||||||
|
|
||||||
// overwrite WorldObject function for proper name localization
|
// overwrite WorldObject function for proper name localization
|
||||||
const char* GetNameForLocaleIdx(int32 locale_idx) const override;
|
const char* GetNameForLocaleIdx(int32 locale_idx) const override;
|
||||||
@ -636,7 +647,7 @@ class GameObject : public WorldObject
|
|||||||
uint32 GetGoAnimProgress() const { return GetUInt32Value(GAMEOBJECT_ANIMPROGRESS); }
|
uint32 GetGoAnimProgress() const { return GetUInt32Value(GAMEOBJECT_ANIMPROGRESS); }
|
||||||
void SetGoAnimProgress(uint32 animprogress) { SetUInt32Value(GAMEOBJECT_ANIMPROGRESS, animprogress); }
|
void SetGoAnimProgress(uint32 animprogress) { SetUInt32Value(GAMEOBJECT_ANIMPROGRESS, animprogress); }
|
||||||
uint32 GetDisplayId() const { return GetUInt32Value(GAMEOBJECT_DISPLAYID); }
|
uint32 GetDisplayId() const { return GetUInt32Value(GAMEOBJECT_DISPLAYID); }
|
||||||
void SetDisplayId(uint32 modelId);
|
void SetDisplayIdx(uint32 modelId);
|
||||||
|
|
||||||
float GetObjectBoundingRadius() const override; // overwrite WorldObject version
|
float GetObjectBoundingRadius() const override; // overwrite WorldObject version
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "GameObjectModel.h"
|
#include "GameObjectModel.h"
|
||||||
#include "DBCStores.h"
|
#include "DBCStores.h"
|
||||||
#include "Creature.h"
|
#include "Creature.h"
|
||||||
|
#include "G3D/Quat.h"
|
||||||
|
|
||||||
struct GameobjectModelData
|
struct GameobjectModelData
|
||||||
{
|
{
|
||||||
@ -107,9 +108,9 @@ bool GameObjectModel::initialize(const GameObject* const pGo, const GameObjectDi
|
|||||||
if (it == model_list.end())
|
if (it == model_list.end())
|
||||||
{ return false; }
|
{ return false; }
|
||||||
|
|
||||||
G3D::AABox mdl_box(it->second.bound);
|
iModelBound = it->second.bound;
|
||||||
// ignore models with no bounds
|
// ignore models with no bounds
|
||||||
if (mdl_box == G3D::AABox::zero())
|
if (iModelBound == G3D::AABox::zero())
|
||||||
{
|
{
|
||||||
sLog.outDebug("Model %s has zero bounds, loading skipped", it->second.name.c_str());
|
sLog.outDebug("Model %s has zero bounds, loading skipped", it->second.name.c_str());
|
||||||
return false;
|
return false;
|
||||||
@ -126,18 +127,30 @@ bool GameObjectModel::initialize(const GameObject* const pGo, const GameObjectDi
|
|||||||
iScale = pGo->GetObjectScale();
|
iScale = pGo->GetObjectScale();
|
||||||
iInvScale = 1.f / iScale;
|
iInvScale = 1.f / iScale;
|
||||||
|
|
||||||
iRot = G3D::Matrix3::fromEulerAnglesZYX(pGo->GetOrientation(), 0, 0);
|
G3D::Quat q;
|
||||||
|
pGo->GetQuaternion(q);
|
||||||
|
UpdateRotation(q);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameObjectModel::UpdateRotation(G3D::Quat const& q)
|
||||||
|
{
|
||||||
|
q.toRotationMatrix(iRot);
|
||||||
|
|
||||||
iInvRot = iRot.inverse();
|
iInvRot = iRot.inverse();
|
||||||
|
|
||||||
|
G3D::AABox mdl_box(iModelBound);
|
||||||
|
|
||||||
// transform bounding box:
|
// transform bounding box:
|
||||||
mdl_box = AABox(mdl_box.low() * iScale, mdl_box.high() * iScale);
|
mdl_box = AABox(mdl_box.low() * iScale, mdl_box.high() * iScale);
|
||||||
AABox rotated_bounds;
|
|
||||||
|
G3D::AABox rotated_bounds;
|
||||||
|
|
||||||
for (int i = 0; i < 8; ++i)
|
for (int i = 0; i < 8; ++i)
|
||||||
{ rotated_bounds.merge(iRot * mdl_box.corner(i)); }
|
{ rotated_bounds.merge(iRot * mdl_box.corner(i)); }
|
||||||
|
|
||||||
iBound = rotated_bounds + iPos;
|
iBound = rotated_bounds + iPos;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GameObjectModel* GameObjectModel::Create(const GameObject* const pGo)
|
GameObjectModel* GameObjectModel::Create(const GameObject* const pGo)
|
||||||
|
@ -40,6 +40,11 @@ namespace VMAP
|
|||||||
class WorldModel;
|
class WorldModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace G3D
|
||||||
|
{
|
||||||
|
class Quat;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief
|
* @brief
|
||||||
*
|
*
|
||||||
@ -51,6 +56,7 @@ class GameObjectModel
|
|||||||
|
|
||||||
std::string iName;
|
std::string iName;
|
||||||
G3D::AABox iBound;
|
G3D::AABox iBound;
|
||||||
|
G3D::AABox iModelBound;
|
||||||
G3D::Vector3 iPos;
|
G3D::Vector3 iPos;
|
||||||
G3D::Matrix3 iRot;
|
G3D::Matrix3 iRot;
|
||||||
float iScale;
|
float iScale;
|
||||||
@ -71,6 +77,7 @@ class GameObjectModel
|
|||||||
~GameObjectModel();
|
~GameObjectModel();
|
||||||
|
|
||||||
const G3D::Vector3& GetPosition() const { return iPos;}
|
const G3D::Vector3& GetPosition() const { return iPos;}
|
||||||
|
void UpdateRotation(G3D::Quat const& q);
|
||||||
const GameObject* GetOwner() const { return iOwner; }
|
const GameObject* GetOwner() const { return iOwner; }
|
||||||
|
|
||||||
void SetCollidable(bool enabled) { isCollidable = enabled; }
|
void SetCollidable(bool enabled) { isCollidable = enabled; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user