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 <typeinfo>
|
||||
#include "Formulas.h"
|
||||
|
||||
#include "G3D/Quat.h" // for turning GO's
|
||||
#include "TargetedMovementGenerator.h" // for HandleNpcUnFollowCommand
|
||||
#include "MoveMap.h" // for mmap manager
|
||||
#include "PathFinder.h" // for mmap commands
|
||||
@ -947,11 +947,27 @@ bool ChatHandler::HandleGameObjectTurnCommand(char* args)
|
||||
if (!ExtractOptFloat(&args, o, m_session->GetPlayer()->GetOrientation()))
|
||||
{ return false; }
|
||||
|
||||
Map* map = obj->GetMap();
|
||||
map->Remove(obj, false);
|
||||
// ok, let's rotate the GO around Z axis
|
||||
// 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);
|
||||
obj->UpdateRotationFields();
|
||||
// the rotation amount around Z-axis
|
||||
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);
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "GameObject.h"
|
||||
#include "G3D/Quat.h"
|
||||
#include "QuestDef.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "PoolManager.h"
|
||||
@ -145,10 +146,32 @@ void GameObject::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);
|
||||
Relocate(x, y, z, ang);
|
||||
if (!map)
|
||||
{ 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);
|
||||
|
||||
if (!IsPositionValid())
|
||||
@ -157,14 +180,7 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, float x, float
|
||||
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`. 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);
|
||||
SetQuaternion(q);
|
||||
|
||||
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_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_FLAGS, goinfo->flags);
|
||||
|
||||
@ -1673,18 +1684,30 @@ const char* GameObject::GetNameForLocaleIdx(int32 loc_idx) const
|
||||
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)
|
||||
{
|
||||
rotation2 = sin(GetOrientation() / 2);
|
||||
rotation3 = cos(GetOrientation() / 2);
|
||||
if (m_model)
|
||||
{ m_model->UpdateRotation(q); }
|
||||
}
|
||||
|
||||
SetFloatValue(GAMEOBJECT_ROTATION + 2, rotation2);
|
||||
SetFloatValue(GAMEOBJECT_ROTATION + 3, rotation3);
|
||||
void GameObject::GetQuaternion(G3D::Quat& q) const
|
||||
{
|
||||
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
|
||||
|
@ -491,16 +491,16 @@ enum GOState
|
||||
// from `gameobject`
|
||||
struct GameObjectData
|
||||
{
|
||||
uint32 id; // entry in gamobject_template
|
||||
uint32 id; // entry in gameobject_template
|
||||
uint32 mapid;
|
||||
float posX;
|
||||
float posY;
|
||||
float posZ;
|
||||
float orientation;
|
||||
float rotation0;
|
||||
float rotation1;
|
||||
float rotation2;
|
||||
float rotation3;
|
||||
float rotation0; // i component of rotation quaternion
|
||||
float rotation1; // j
|
||||
float rotation2; // k
|
||||
float rotation3; // w
|
||||
int32 spawntimesecs;
|
||||
uint32 animprogress;
|
||||
GOState go_state;
|
||||
@ -538,6 +538,12 @@ enum CapturePointSliderValue
|
||||
|
||||
class Unit;
|
||||
class GameObjectModel;
|
||||
|
||||
namespace G3D
|
||||
{
|
||||
class Quat;
|
||||
};
|
||||
|
||||
struct GameObjectDisplayInfoEntry;
|
||||
|
||||
// 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
|
||||
|
||||
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
|
||||
const char* GetNameForLocaleIdx(int32 locale_idx) const override;
|
||||
@ -636,7 +647,7 @@ class GameObject : public WorldObject
|
||||
uint32 GetGoAnimProgress() const { return GetUInt32Value(GAMEOBJECT_ANIMPROGRESS); }
|
||||
void SetGoAnimProgress(uint32 animprogress) { SetUInt32Value(GAMEOBJECT_ANIMPROGRESS, animprogress); }
|
||||
uint32 GetDisplayId() const { return GetUInt32Value(GAMEOBJECT_DISPLAYID); }
|
||||
void SetDisplayId(uint32 modelId);
|
||||
void SetDisplayIdx(uint32 modelId);
|
||||
|
||||
float GetObjectBoundingRadius() const override; // overwrite WorldObject version
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "GameObjectModel.h"
|
||||
#include "DBCStores.h"
|
||||
#include "Creature.h"
|
||||
#include "G3D/Quat.h"
|
||||
|
||||
struct GameobjectModelData
|
||||
{
|
||||
@ -107,9 +108,9 @@ bool GameObjectModel::initialize(const GameObject* const pGo, const GameObjectDi
|
||||
if (it == model_list.end())
|
||||
{ return false; }
|
||||
|
||||
G3D::AABox mdl_box(it->second.bound);
|
||||
iModelBound = it->second.bound;
|
||||
// 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());
|
||||
return false;
|
||||
@ -126,18 +127,30 @@ bool GameObjectModel::initialize(const GameObject* const pGo, const GameObjectDi
|
||||
iScale = pGo->GetObjectScale();
|
||||
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();
|
||||
|
||||
G3D::AABox mdl_box(iModelBound);
|
||||
|
||||
// transform bounding box:
|
||||
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)
|
||||
{ rotated_bounds.merge(iRot * mdl_box.corner(i)); }
|
||||
|
||||
iBound = rotated_bounds + iPos;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GameObjectModel* GameObjectModel::Create(const GameObject* const pGo)
|
||||
|
@ -40,6 +40,11 @@ namespace VMAP
|
||||
class WorldModel;
|
||||
}
|
||||
|
||||
namespace G3D
|
||||
{
|
||||
class Quat;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
@ -51,6 +56,7 @@ class GameObjectModel
|
||||
|
||||
std::string iName;
|
||||
G3D::AABox iBound;
|
||||
G3D::AABox iModelBound;
|
||||
G3D::Vector3 iPos;
|
||||
G3D::Matrix3 iRot;
|
||||
float iScale;
|
||||
@ -71,6 +77,7 @@ class GameObjectModel
|
||||
~GameObjectModel();
|
||||
|
||||
const G3D::Vector3& GetPosition() const { return iPos;}
|
||||
void UpdateRotation(G3D::Quat const& q);
|
||||
const GameObject* GetOwner() const { return iOwner; }
|
||||
|
||||
void SetCollidable(bool enabled) { isCollidable = enabled; }
|
||||
|
Loading…
x
Reference in New Issue
Block a user