Skip to content

Commit

Permalink
[11529] Pack and send to client all gameobject's quaternion component…
Browse files Browse the repository at this point in the history
…s which allows place gameobjects cornerwise.

Update '.gobject turn' command, now you have to specify 3 rotations to turn gameobject: rotation angles around z, y and x axes.
Note to DB devs: use QuaternionCompressed::Unpack to extract rotations from the data that came with UPDATEFLAG_ROTATION.
  • Loading branch information
SilverIce committed May 24, 2011
1 parent a141cb5 commit 2bcbc0f
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 47 deletions.
4 changes: 2 additions & 2 deletions sql/mangos.sql
Expand Up @@ -24,7 +24,7 @@ CREATE TABLE `db_version` (
`version` varchar(120) default NULL,
`creature_ai_version` varchar(120) default NULL,
`cache_id` int(10) default '0',
`required_11523_02_mangos_mangos_string` bit(1) default NULL
`required_11529_01_mangos_command` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';

--
Expand Down Expand Up @@ -587,7 +587,7 @@ INSERT INTO `command` VALUES
('gobject move',2,'Syntax: .gobject move #goguid [#x #y #z]\r\n\r\nMove gameobject #goguid to character coordinates (or to (#x,#y,#z) coordinates if its provide).'),
('gobject near',2,'Syntax: .gobject near [#distance]\r\n\r\nOutput gameobjects at distance #distance from player. Output gameobject guids and coordinates sorted by distance from character. If #distance not provided use 10 as default value.'),
('gobject setphase',2,'Syntax: .gobject setphase #guid #phasemask\r\n\r\nGameobject with DB guid #guid phasemask changed to #phasemask with related world vision update for players. Gameobject state saved to DB and persistent.'),
('gobject turn',2,'Syntax: .gobject turn #goguid \r\n\r\nSet for gameobject #goguid orientation same as current character orientation.'),
('gobject turn',2,'Syntax: .gobject turn #goguid [#z_angle]\r\n\r\nChanges gameobject #goguid orientation (rotates gameobject around z axis). Optional parameters are (#y_angle,#x_angle) values that represents rotation angles around y and x axes.'),
('gobject target',2,'Syntax: .gobject target [#go_id|#go_name_part]\r\n\r\nLocate and show position nearest gameobject. If #go_id or #go_name_part provide then locate and show position of nearest gameobject with gameobject template id #go_id or name included #go_name_part as part.'),
('goname',1,'Syntax: .goname [$charactername]\r\n\r\nTeleport to the given character. Either specify the character name or click on the character\'s portrait, e.g. when you are in a group. Character can be offline.'),
('gps',1,'Syntax: .gps [$name|$shift-link]\r\n\r\nDisplay the position information for a selected character or creature (also if player name $name provided then for named player, or if creature/gameobject shift-link provided then pointed creature/gameobject if it loaded). Position information includes X, Y, Z, and orientation, map Id and zone Id'),
Expand Down
6 changes: 6 additions & 0 deletions sql/updates/11529_01_mangos_command.sql
@@ -0,0 +1,6 @@
ALTER TABLE db_version CHANGE COLUMN required_11523_02_mangos_mangos_string required_11529_01_mangos_command bit;

DELETE FROM command WHERE name = 'gobject turn';

INSERT INTO command (name, security, help) VALUES
('gobject turn',2,'Syntax: .gobject turn #goguid [#z_angle]\r\n\r\nChanges gameobject #goguid orientation (rotates gameobject around z axis). Optional parameters are (#y_angle,#x_angle) values that represents rotation angles around y and x axes.');
74 changes: 49 additions & 25 deletions src/game/GameObject.cpp
Expand Up @@ -38,6 +38,7 @@
#include "BattleGroundAV.h"
#include "Util.h"
#include "ScriptMgr.h"
#include <G3D/Quat.h>

GameObject::GameObject() : WorldObject(),
m_goInfo(NULL),
Expand Down Expand Up @@ -128,10 +129,7 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map *map, uint32 phaseMa

SetObjectScale(goinfo->size);

SetFloatValue(GAMEOBJECT_PARENTROTATION+0, rotation0);
SetFloatValue(GAMEOBJECT_PARENTROTATION+1, rotation1);

UpdateRotationFields(rotation2,rotation3); // GAMEOBJECT_FACING, GAMEOBJECT_ROTATION, GAMEOBJECT_PARENTROTATION+2/3
SetRotationQuat(rotation0,rotation1,rotation2,rotation3);

SetUInt32Value(GAMEOBJECT_FACTION, goinfo->faction);
SetUInt32Value(GAMEOBJECT_FLAGS, goinfo->flags);
Expand Down Expand Up @@ -1632,34 +1630,60 @@ const char* GameObject::GetNameForLocaleIdx(int32 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));

double f_rot1 = sin(GetOrientation() / 2.0f);
double f_rot2 = cos(GetOrientation() / 2.0f);

int64 i_rot1 = int64(f_rot1 / atan_pow *(f_rot2 >= 0 ? 1.0f : -1.0f));
int64 rotation = (i_rot1 << 43 >> 43) & 0x00000000001FFFFF;
QuaternionCompressed() : m_raw(0) {}
QuaternionCompressed(int64 val) : m_raw(val) {}
QuaternionCompressed(const Quat& quat) { Set(quat); }

//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;
enum{
PACK_COEFF_YZ = 1 << 20,
PACK_COEFF_X = 1 << 21,
};

//float f_rot3 = sin(0.0f / 2.0f);
//int64 i_rot3 = f_rot3 / atan(pow(2.0f, -21.0f));
//rotation |= (i_rot3 >> 42) & 0x7FFFFC0000000000;

m_rotation = rotation;
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);
}

if(rotation2==0.0f && rotation3==0.0f)
Quat Unpack() const
{
rotation2 = (float)f_rot1;
rotation3 = (float)f_rot2;
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);
MANGOS_ASSERT(w >= 0);
w = sqrt(w);

return Quat(x,y,z,w);
}

SetFloatValue(GAMEOBJECT_PARENTROTATION+2, rotation2);
SetFloatValue(GAMEOBJECT_PARENTROTATION+3, rotation3);
int64 m_raw;
};

void GameObject::SetRotationQuat(float qx, float qy, float qz, float qw)
{
Quat quat(qx, qy, qz, qw);

This comment has been minimized.

Copy link
@technoir42

technoir42 May 24, 2011

Contributor

Shouldn't quaternion be normalized?

// Temporary solution for gameobjects that has no rotation data in DB:
if (qz == 0 && qw == 0)
quat = Quat::fromAxisAngleRotation(G3D::Vector3::unitZ(), GetOrientation());

m_rotation = QuaternionCompressed(quat).m_raw;
SetFloatValue(GAMEOBJECT_PARENTROTATION+0, quat.x);
SetFloatValue(GAMEOBJECT_PARENTROTATION+1, quat.y);
SetFloatValue(GAMEOBJECT_PARENTROTATION+2, quat.z);
SetFloatValue(GAMEOBJECT_PARENTROTATION+3, quat.w);
}

void GameObject::SetRotationAngles(float z_rot, float y_rot, float x_rot)
{
Quat quat( G3D::Matrix3::fromEulerAnglesZYX(z_rot, y_rot, x_rot) );
SetRotationQuat(quat.x, quat.y, quat.z, quat.w);
}

bool GameObject::IsHostileTo(Unit const* unit) const
Expand Down
8 changes: 5 additions & 3 deletions src/game/GameObject.h
Expand Up @@ -606,7 +606,9 @@ class MANGOS_DLL_SPEC 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);
// z_rot, y_rot, x_rot - rotation angles around z, y and x axes
void SetRotationAngles(float z_rot, float y_rot, float x_rot);
int64 GetRotation() const { return m_rotation; }

// overwrite WorldObject function for proper name localization
const char* GetNameForLocaleIdx(int32 locale_idx) const;
Expand Down Expand Up @@ -721,7 +723,6 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject

GridReference<GameObject> &GetGridRef() { return m_gridRef; }

uint64 GetRotation() const { return m_rotation; }
protected:
uint32 m_spellId;
time_t m_respawnTime; // (secs) time of next respawn (or despawn if GO have owner()),
Expand All @@ -743,9 +744,10 @@ class MANGOS_DLL_SPEC GameObject : public WorldObject

GameObjectInfo const* m_goInfo;
GameObjectDisplayInfoEntry const* m_displayInfo;
uint64 m_rotation;
int64 m_rotation;
private:
void SwitchDoorOrButton(bool activate, bool alternative = false);
void SetRotationQuat(float qx, float qy, float qz, float qw);

GridReference<GameObject> m_gridRef;
};
Expand Down
18 changes: 4 additions & 14 deletions src/game/Level2.cpp
Expand Up @@ -958,23 +958,13 @@ bool ChatHandler::HandleGameObjectTurnCommand(char* args)
return false;
}

float o;
if (!ExtractOptFloat(&args, o, m_session->GetPlayer()->GetOrientation()))
return false;

Map* map = obj->GetMap();
map->Remove(obj,false);

obj->Relocate(obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ(), o);
obj->UpdateRotationFields();

map->Add(obj);
float z_rot, y_rot, x_rot;
if (!ExtractFloat(&args, z_rot) || !ExtractOptFloat(&args, y_rot, 0) || !ExtractOptFloat(&args, x_rot, 0))
return false;

obj->SetRotationAngles(z_rot, y_rot, x_rot);
obj->SaveToDB();
obj->Refresh();

PSendSysMessage(LANG_COMMAND_TURNOBJMESSAGE, obj->GetGUIDLow(), obj->GetGOInfo()->name, obj->GetGUIDLow());

return true;
}

Expand Down
2 changes: 1 addition & 1 deletion src/game/Object.cpp
Expand Up @@ -511,7 +511,7 @@ void Object::BuildMovementUpdate(ByteBuffer * data, uint16 updateFlags) const
// 0x200
if(updateFlags & UPDATEFLAG_ROTATION)
{
*data << uint64(((GameObject*)this)->GetRotation());
*data << int64(((GameObject*)this)->GetRotation());
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/shared/revision_nr.h
@@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "11528"
#define REVISION_NR "11529"
#endif // __REVISION_NR_H__
2 changes: 1 addition & 1 deletion src/shared/revision_sql.h
@@ -1,6 +1,6 @@
#ifndef __REVISION_SQL_H__
#define __REVISION_SQL_H__
#define REVISION_DB_CHARACTERS "required_11436_01_characters_character_queststatus"
#define REVISION_DB_MANGOS "required_11523_02_mangos_mangos_string"
#define REVISION_DB_MANGOS "required_11529_01_mangos_command"
#define REVISION_DB_REALMD "required_10008_01_realmd_realmd_db_version"
#endif // __REVISION_SQL_H__

21 comments on commit 2bcbc0f

@DoesntMatter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry for asking, but is there any possibility to replace UpdateRotationFields function with new functions?

e.g. for SotA patch this code is used in scripts:

GetBGObject(BG_SA_BOAT_ONE)->UpdateRotationFields(1.0f, 0.0002f);
GetBGObject(BG_SA_BOAT_TWO)->UpdateRotationFields(1.0f, 0.00001f);

maybe move SetRotationQuat function to public and replace with:

GetBGObject(BG_SA_BOAT_ONE)->SetRotationQuat(0.0f, 0.0f, 1.0f, 0.0002f);
GetBGObject(BG_SA_BOAT_TWO)->SetRotationQuat(0.0f, 0.0f, 1.0f, 0.00001f);

I know you do not support or maintainance custom patches, but still I would be happy if you can help :)

@technoir42
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use SetRotationAngles

@DoesntMatter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how to use them here :/
in UpdateRotationFields function rotation2 and rotation3 are used:

GetBGObject(BG_SA_BOAT_ONE)->UpdateRotationFields(1.0f, 0.0002f); // rotation2, rotation3

in SetRotationAngles function there are z_rot, y_rot and x_rot and I don't know the equivalent parameter :/
z_rot is rotation2? if yes, what is rotation3 and how can I use this param with SetRotationAngles function?

@SilverIce
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also you may put these parameters into Gameobject::Create as rotation0, rotation1 etc

z_rot is rotation2?

// z_rot, y_rot, x_rot - rotation angles around z, y and x axes
void SetRotationAngles(float z_rot, float y_rot, float x_rot);

'z_rot' can be called 'orientation'

@DoesntMatter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, so as one solution it is possible to add special exceptions for gameobject ids in Gameobject::Create, like this?

if (exceptions...)
    SetRotationQuat(rotation0,rotation1,1.0f,0.0002f);
else
    SetRotationQuat(rotation0,rotation1,rotation2,rotation3);

but I still do not understand how I can convert rotation2 and rotation3 parameters into SetRotationAngles function :/

@technoir42
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably
GetBGObject(BG_SA_BOAT_ONE)->SetRotationAngles(acosf(0.0002f), 0.0f, 0.0f);
GetBGObject(BG_SA_BOAT_TWO)->SetRotationAngles(acosf(0.00001f), 0.0f, 0.0f);

@DoesntMatter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you very much :)

@SilverIce
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, not SetRotationAngles(2_acosf(0.0002f), 0, 0) and SetRotationAngles(2_acosf(0.0001f), 0, 0) ?
In case your gameobjects listed in 'gameobjects' table you may just modify their rotation0 .. rotation3 fields

@DoesntMatter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again, big thanks to both of you :) I adopted that :)
but these gameobjects are spawned by script and unfortunately not in database :(

@DoesntMatter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry to bother you again, but this does not work correctly :(

would this work as a hack in GameObject::Create to fix it for first time?

if (entry ID exception)
    SetRotationQuat(rotation0,rotation1,1.0f,0.0002f);
else
    SetRotationQuat(rotation0,rotation1,rotation2,rotation3);

PS: Solved! I set rotation2 and rotation3 in BattleGround::AddObject function :)

@DoesntMatter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SilverIce:
still does not work, even if I set correct rotation2 and rotation3 :( maybe something in calculation has changed here?

@SilverIce
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you will remove this:

GetBGObject(BG_SA_BOAT_ONE)->UpdateRotationFields(1.0f, 0.0002f);
GetBGObject(BG_SA_BOAT_TWO)->UpdateRotationFields(1.0f, 0.00001f)

or use:

SetRotationQuat(GetOrientation(),0,0)
SetRotationQuat(GetOrientation(),0,0)

what happens?

@DoesntMatter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we remove this the boat moves into opposite direction then :(
it seems that orientation is ignored, because if you change orientation in script, boat spawns are always the same

where should I use this?

SetRotationQuat(GetOrientation(),0,0)

and isn't it already removed?

UpdateRotationFields(GetOrientation(),0,0)

@SilverIce
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where should I use this?

if (GameObject * obj = GetBGObject(BG_SA_BOAT_TWO))
obj->SetRotationQuat(obj->GetOrientation(),0,0)

@DoesntMatter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We used

if (GameObject * obj = GetBGObject(BG_SA_BOAT_TWO))
obj->SetRotationQuat(obj->GetOrientation(),0,0,0) // 4 parameters

and again boat moves into opposite direction then

@mosst
Copy link
Contributor

@mosst mosst commented on 2bcbc0f May 25, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DoesntMatter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confirm. after this gameobjects seem to ignore orientation sometimes :/

@SilverIce
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My code works correctly (Example: .go object 60314)
Ofc gameobject will be placed wrong in case there is some shit in DB

set gameobject rotation2 and rotation3 fields to zero and you will see

@DoesntMatter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you set rotation2 and rotation3 fields to zero they are spawned correctly yes, BUT then rotation is incorrect :(
e.g. SotA boats (move into opposite direction)

@technoir42
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assuming orientation has correct value this can be used as temporary solution (will replace both crap and good data)
UPDATE gameobject SET rotation0 = 0, rotation1 = 0, rotation2 = SIN(orientation * 0.5), rotation3 = COS(orientation * 0.5)

@DoesntMatter
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, sorry for asking, but I do not understand how this should help :/
if you see in case of SotA boats, the rotation is correct, because the boat moves to correct position with correct angle. only thing that is bugged is orientation.
besides: this does not have any effect on gameobjects spawned by scripts or core :(

Please sign in to comment.