Browse Source

Added Abs() to Vector2, Vector3 and Vector4.
Compressed rotation and angular velocity to half size in network replication.

Lasse Öörni 14 years ago
parent
commit
13d449d9cc

+ 2 - 0
Engine/Math/Vector2.h

@@ -170,6 +170,8 @@ public:
     float DotProduct(const Vector2& rhs) const { return x_ * rhs.x_ + y_ * rhs.y_; }
     float DotProduct(const Vector2& rhs) const { return x_ * rhs.x_ + y_ * rhs.y_; }
     /// Calculate absolute dot product
     /// Calculate absolute dot product
     float AbsDotProduct(const Vector2& rhs) const { return fabsf(x_ * rhs.x_) + fabsf(y_ * rhs.y_); }
     float AbsDotProduct(const Vector2& rhs) const { return fabsf(x_ * rhs.x_) + fabsf(y_ * rhs.y_); }
+    /// Return absolute vector
+    Vector2 Abs() const { return Vector2(fabsf(x_), fabsf(y_)); }
     /// Linear interpolation with another vector
     /// Linear interpolation with another vector
     Vector2 Lerp(const Vector2& rhs, float t) const { return *this * (1.0f - t) + rhs * t; }
     Vector2 Lerp(const Vector2& rhs, float t) const { return *this * (1.0f - t) + rhs * t; }
     
     

+ 2 - 0
Engine/Math/Vector3.h

@@ -201,6 +201,8 @@ public:
         );
         );
     }
     }
     
     
+    /// Return absolute vector
+    Vector3 Abs() const { return Vector3(fabsf(x_), fabsf(y_), fabsf(z_)); }
     /// Linear interpolation with another vector
     /// Linear interpolation with another vector
     Vector3 Lerp(const Vector3& rhs, float t) const { return *this * (1.0f - t) + rhs * t; }
     Vector3 Lerp(const Vector3& rhs, float t) const { return *this * (1.0f - t) + rhs * t; }
     
     

+ 2 - 0
Engine/Math/Vector4.h

@@ -170,6 +170,8 @@ public:
     float DotProduct(const Vector4& rhs) const { return x_ * rhs.x_ + y_ * rhs.y_ + z_ * rhs.z_ + w_ * rhs.w_; }
     float DotProduct(const Vector4& rhs) const { return x_ * rhs.x_ + y_ * rhs.y_ + z_ * rhs.z_ + w_ * rhs.w_; }
     /// Calculate absolute dot product
     /// Calculate absolute dot product
     float AbsDotProduct(const Vector4& rhs) const { return fabsf(x_ * rhs.x_) + fabsf(y_ * rhs.y_) + fabsf(z_ * rhs.z_) + fabsf(w_ * rhs.w_); }
     float AbsDotProduct(const Vector4& rhs) const { return fabsf(x_ * rhs.x_) + fabsf(y_ * rhs.y_) + fabsf(z_ * rhs.z_) + fabsf(w_ * rhs.w_); }
+    /// Return absolute vector
+    Vector4 Abs() const { return Vector4(fabsf(x_), fabsf(y_), fabsf(z_), fabsf(w_)); }
     /// Linear interpolation with another vector
     /// Linear interpolation with another vector
     Vector4 Lerp(const Vector4& rhs, float t) const { return *this * (1.0f - t) + rhs * t; }
     Vector4 Lerp(const Vector4& rhs, float t) const { return *this * (1.0f - t) + rhs * t; }
     
     

+ 2 - 2
Engine/Physics/Joint.cpp

@@ -65,8 +65,8 @@ void Joint::RegisterObject(Context* context)
     ENUM_ATTRIBUTE(Joint, "Joint Type", type_, typeNames, JOINT_NONE, AM_DEFAULT);
     ENUM_ATTRIBUTE(Joint, "Joint Type", type_, typeNames, JOINT_NONE, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Joint, VAR_INT, "Body A", GetBodyAAttr, SetBodyAAttr, int, 0, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Joint, VAR_INT, "Body A", GetBodyAAttr, SetBodyAAttr, int, 0, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Joint, VAR_INT, "Body B", GetBodyBAttr, SetBodyBAttr, int, 0, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(Joint, VAR_INT, "Body B", GetBodyBAttr, SetBodyBAttr, int, 0, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(Joint, VAR_VECTOR3, "Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(Joint, VAR_VECTOR3, "Axis", GetAxis, SetAxis, Vector3, Vector3::ZERO, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(Joint, VAR_VECTOR3, "Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_DEFAULT | AM_LATESTDATA);
+    ACCESSOR_ATTRIBUTE(Joint, VAR_VECTOR3, "Axis", GetAxis, SetAxis, Vector3, Vector3::ZERO, AM_DEFAULT | AM_LATESTDATA);
 }
 }
 
 
 void Joint::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 void Joint::OnSetAttribute(const AttributeInfo& attr, const Variant& src)

+ 14 - 8
Engine/Physics/PhysicsWorld.cpp

@@ -42,8 +42,8 @@
 #include "DebugNew.h"
 #include "DebugNew.h"
 
 
 static const int DEFAULT_FPS = 60;
 static const int DEFAULT_FPS = 60;
-static const int DEFAULT_MAXCONTACTS = 20;
-static const float DEFAULT_BOUNCETHRESHOLD = 0.1f;
+static const int DEFAULT_MAX_CONTACTS = 20;
+static const float DEFAULT_BOUNCE_THRESHOLD = 0.1f;
 
 
 static unsigned numInstances = 0;
 static unsigned numInstances = 0;
 
 
@@ -61,8 +61,8 @@ PhysicsWorld::PhysicsWorld(Context* context) :
     rayGeometry_(0),
     rayGeometry_(0),
     contactJoints_(0),
     contactJoints_(0),
     fps_(DEFAULT_FPS),
     fps_(DEFAULT_FPS),
-    maxContacts_(DEFAULT_MAXCONTACTS),
-    bounceThreshold_(DEFAULT_BOUNCETHRESHOLD),
+    maxContacts_(DEFAULT_MAX_CONTACTS),
+    bounceThreshold_(DEFAULT_BOUNCE_THRESHOLD),
     timeAcc_(0.0f),
     timeAcc_(0.0f),
     randomSeed_(0)
     randomSeed_(0)
 {
 {
@@ -134,10 +134,11 @@ void PhysicsWorld::RegisterObject(Context* context)
     context->RegisterFactory<PhysicsWorld>();
     context->RegisterFactory<PhysicsWorld>();
     
     
     ATTRIBUTE(PhysicsWorld, VAR_INT, "Physics FPS", fps_, DEFAULT_FPS, AM_DEFAULT);
     ATTRIBUTE(PhysicsWorld, VAR_INT, "Physics FPS", fps_, DEFAULT_FPS, AM_DEFAULT);
-    ATTRIBUTE(PhysicsWorld, VAR_INT, "Max Contacts", maxContacts_, DEFAULT_MAXCONTACTS, AM_DEFAULT);
-    ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Bounce Threshold", bounceThreshold_, DEFAULT_BOUNCETHRESHOLD, AM_DEFAULT);
-    ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Time Accumulator", timeAcc_, 0.0f, AM_DEFAULT);
-    ATTRIBUTE(PhysicsWorld, VAR_INT, "Random Seed", randomSeed_, 0, AM_DEFAULT);
+    ATTRIBUTE(PhysicsWorld, VAR_INT, "Max Contacts", maxContacts_, DEFAULT_MAX_CONTACTS, AM_DEFAULT);
+    ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Bounce Threshold", bounceThreshold_, DEFAULT_BOUNCE_THRESHOLD, AM_DEFAULT);
+    ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Max Network Angular Velocity", maxNetworkAngularVelocity_, DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY, AM_DEFAULT);
+    ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Time Accumulator", timeAcc_, 0.0f, AM_FILE | AM_NOEDIT);
+    ATTRIBUTE(PhysicsWorld, VAR_INT, "Random Seed", randomSeed_, 0, AM_FILE | AM_NOEDIT);
     ACCESSOR_ATTRIBUTE(PhysicsWorld, VAR_VECTOR3, "Gravity", GetGravity, SetGravity, Vector3, Vector3::ZERO, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(PhysicsWorld, VAR_VECTOR3, "Gravity", GetGravity, SetGravity, Vector3, Vector3::ZERO, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Linear Rest Threshold", GetLinearRestThreshold, SetLinearRestThreshold, float, 0.01f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Linear Rest Threshold", GetLinearRestThreshold, SetLinearRestThreshold, float, 0.01f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Linear Damping Threshold", GetLinearDampingThreshold, SetLinearDampingThreshold, float, 0.01f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(PhysicsWorld, VAR_FLOAT, "Linear Damping Threshold", GetLinearDampingThreshold, SetLinearDampingThreshold, float, 0.01f, AM_DEFAULT);
@@ -262,6 +263,11 @@ void PhysicsWorld::SetBounceThreshold(float threshold)
     bounceThreshold_ = Max(threshold, 0.0f);
     bounceThreshold_ = Max(threshold, 0.0f);
 }
 }
 
 
+void PhysicsWorld::SetMaxNetworkAngularVelocity(float velocity)
+{
+    maxNetworkAngularVelocity_ = Clamp(velocity, 1.0f, 32767.0f);
+}
+
 void PhysicsWorld::SetERP(float erp)
 void PhysicsWorld::SetERP(float erp)
 {
 {
     dWorldSetERP(physicsWorld_, erp);
     dWorldSetERP(physicsWorld_, erp);

+ 7 - 1
Engine/Physics/PhysicsWorld.h

@@ -84,7 +84,7 @@ struct PhysicsCollisionInfo
     PODVector<PhysicsContactInfo> contacts_;
     PODVector<PhysicsContactInfo> contacts_;
 };
 };
 
 
-static const float PHYSICS_MIN_TIMESTEP = 0.001f;
+static const float DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY = 100.0f;
 
 
 /// A physics simulation world
 /// A physics simulation world
 class PhysicsWorld : public Component
 class PhysicsWorld : public Component
@@ -121,6 +121,8 @@ public:
     void SetAngularDampingScale(float scale);
     void SetAngularDampingScale(float scale);
     /// Set collision bounce velocity threshold (apply bounce if above)
     /// Set collision bounce velocity threshold (apply bounce if above)
     void SetBounceThreshold(float threshold);
     void SetBounceThreshold(float threshold);
+    /// Set maximum angular velocity for network replication
+    void SetMaxNetworkAngularVelocity(float velocity);
     /// Set simulation ERP parameter
     /// Set simulation ERP parameter
     void SetERP(float erp);
     void SetERP(float erp);
     /// Set simulation CFM parameter
     /// Set simulation CFM parameter
@@ -157,6 +159,8 @@ public:
     float GetAngularDampingScale() const;
     float GetAngularDampingScale() const;
     /// Return collision bounce velocity threshold
     /// Return collision bounce velocity threshold
     float GetBounceThreshold() const { return bounceThreshold_; }
     float GetBounceThreshold() const { return bounceThreshold_; }
+    /// Return maximum angular velocity for network replication
+    float GetMaxNetworkAngularVelocity() const { return maxNetworkAngularVelocity_; }
     /// Return simulation ERP parameter
     /// Return simulation ERP parameter
     float GetERP() const;
     float GetERP() const;
     /// Return simulation CFM parameter
     /// Return simulation CFM parameter
@@ -208,6 +212,8 @@ private:
     unsigned maxContacts_;
     unsigned maxContacts_;
     /// Collision bounce velocity threshold
     /// Collision bounce velocity threshold
     float bounceThreshold_;
     float bounceThreshold_;
+    /// Maximum angular velocity for network replication
+    float maxNetworkAngularVelocity_;
     /// Simulation step time accumulator
     /// Simulation step time accumulator
     float timeAcc_;
     float timeAcc_;
     /// Simulation random seed
     /// Simulation random seed

+ 22 - 3
Engine/Physics/RigidBody.cpp

@@ -25,6 +25,7 @@
 #include "CollisionShape.h"
 #include "CollisionShape.h"
 #include "Context.h"
 #include "Context.h"
 #include "Log.h"
 #include "Log.h"
+#include "MemoryBuffer.h"
 #include "PhysicsWorld.h"
 #include "PhysicsWorld.h"
 #include "ResourceCache.h"
 #include "ResourceCache.h"
 #include "ResourceEvents.h"
 #include "ResourceEvents.h"
@@ -68,18 +69,19 @@ void RigidBody::RegisterObject(Context* context)
     context->RegisterFactory<RigidBody>();
     context->RegisterFactory<RigidBody>();
     
     
     ATTRIBUTE(RigidBody, VAR_FLOAT, "Mass", mass_, DEFAULT_MASS, AM_DEFAULT);
     ATTRIBUTE(RigidBody, VAR_FLOAT, "Mass", mass_, DEFAULT_MASS, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(RigidBody, VAR_VECTOR3, "Physics Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_FILE);
-    ACCESSOR_ATTRIBUTE(RigidBody, VAR_QUATERNION, "Physics Rotation", GetRotation, SetRotation, Quaternion, Quaternion::IDENTITY, AM_FILE);
+    ACCESSOR_ATTRIBUTE(RigidBody, VAR_VECTOR3, "Physics Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_FILE | AM_NOEDIT);
+    ACCESSOR_ATTRIBUTE(RigidBody, VAR_QUATERNION, "Physics Rotation", GetRotation, SetRotation, Quaternion, Quaternion::IDENTITY, AM_FILE | AM_NOEDIT);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_VECTOR3, "Linear Velocity", GetLinearVelocity, SetLinearVelocity, Vector3, Vector3::ZERO, AM_DEFAULT | AM_LATESTDATA);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_VECTOR3, "Linear Velocity", GetLinearVelocity, SetLinearVelocity, Vector3, Vector3::ZERO, AM_DEFAULT | AM_LATESTDATA);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Linear Rest Threshold", GetLinearRestThreshold, SetLinearRestThreshold, float, 0.01f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Linear Rest Threshold", GetLinearRestThreshold, SetLinearRestThreshold, float, 0.01f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Linear Damping Threshold", GetLinearDampingThreshold, SetLinearDampingThreshold, float, 0.01f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Linear Damping Threshold", GetLinearDampingThreshold, SetLinearDampingThreshold, float, 0.01f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Linear Damping Scale", GetLinearDampingScale, SetLinearDampingScale, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Linear Damping Scale", GetLinearDampingScale, SetLinearDampingScale, float, 0.0f, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(RigidBody, VAR_VECTOR3, "Angular Velocity", GetAngularVelocity, SetAngularVelocity, Vector3, Vector3::ZERO, AM_DEFAULT | AM_LATESTDATA);
+    ACCESSOR_ATTRIBUTE(RigidBody, VAR_VECTOR3, "Angular Velocity", GetAngularVelocity, SetAngularVelocity, Vector3, Vector3::ZERO, AM_FILE);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Rest Threshold", GetAngularRestThreshold, SetAngularRestThreshold, float, 0.01f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Rest Threshold", GetAngularRestThreshold, SetAngularRestThreshold, float, 0.01f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Damping Threshold", GetAngularDampingThreshold, SetAngularDampingThreshold, float, 0.01f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Damping Threshold", GetAngularDampingThreshold, SetAngularDampingThreshold, float, 0.01f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Damping Scale", GetAngularDampingScale, SetAngularDampingScale, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Damping Scale", GetAngularDampingScale, SetAngularDampingScale, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Max Velocity", GetAngularMaxVelocity, SetAngularMaxVelocity, float, M_INFINITY, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_FLOAT, "Angular Max Velocity", GetAngularMaxVelocity, SetAngularMaxVelocity, float, M_INFINITY, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_BOOL, "Is Active", IsActive, SetActive, bool, true, AM_FILE);
     ACCESSOR_ATTRIBUTE(RigidBody, VAR_BOOL, "Is Active", IsActive, SetActive, bool, true, AM_FILE);
+    REF_ACCESSOR_ATTRIBUTE(RigidBody, VAR_BUFFER, "Network Angular Velocity", GetNetAngularVelocityAttr, SetNetAngularVelocityAttr, PODVector<unsigned char>, PODVector<unsigned char>(), AM_NET | AM_LATESTDATA | AM_NOEDIT);
 }
 }
 
 
 void RigidBody::SetMass(float mass)
 void RigidBody::SetMass(float mass)
@@ -333,6 +335,23 @@ bool RigidBody::IsActive() const
         return false;
         return false;
 }
 }
 
 
+void RigidBody::SetNetAngularVelocityAttr(const PODVector<unsigned char>& value)
+{
+    float maxVelocity = physicsWorld_ ? physicsWorld_->GetMaxNetworkAngularVelocity() : DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY;
+    
+    MemoryBuffer buf(value);
+    SetAngularVelocity(buf.ReadPackedVector3(maxVelocity));
+}
+
+const PODVector<unsigned char>& RigidBody::GetNetAngularVelocityAttr() const
+{
+    float maxVelocity = physicsWorld_ ? physicsWorld_->GetMaxNetworkAngularVelocity() : DEFAULT_MAX_NETWORK_ANGULAR_VELOCITY;
+    
+    attrBuffer_.Clear();
+    attrBuffer_.WritePackedVector3(GetAngularVelocity(), maxVelocity);
+    return attrBuffer_.GetBuffer();
+}
+
 void RigidBody::OnMarkedDirty(Node* node)
 void RigidBody::OnMarkedDirty(Node* node)
 {
 {
     // Clear the dirty flag by querying world position; this way we are sure to get the dirty notification immediately
     // Clear the dirty flag by querying world position; this way we are sure to get the dirty notification immediately

+ 6 - 0
Engine/Physics/RigidBody.h

@@ -114,6 +114,10 @@ public:
     
     
     /// Recalculate mass
     /// Recalculate mass
     void UpdateMass();
     void UpdateMass();
+    /// Set network angular velocity attribute
+    void SetNetAngularVelocityAttr(const PODVector<unsigned char>& value);
+    /// Return network angular velocity attribute
+    const PODVector<unsigned char>& GetNetAngularVelocityAttr() const;
     
     
 protected:
 protected:
     /// Handle node being assigned
     /// Handle node being assigned
@@ -141,6 +145,8 @@ private:
     Vector3 previousPosition_;
     Vector3 previousPosition_;
     /// Previous rotation for rendering interpolation
     /// Previous rotation for rendering interpolation
     Quaternion previousRotation_;
     Quaternion previousRotation_;
+    /// Attribute buffer for network replication
+    mutable VectorBuffer attrBuffer_;
     /// Poststep flag
     /// Poststep flag
     bool inPostStep_;
     bool inPostStep_;
 };
 };

+ 25 - 11
Engine/Scene/Node.cpp

@@ -67,10 +67,11 @@ void Node::RegisterObject(Context* context)
     
     
     REF_ACCESSOR_ATTRIBUTE(Node, VAR_STRING, "Name", GetName, SetName, String, String(), AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(Node, VAR_STRING, "Name", GetName, SetName, String, String(), AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(Node, VAR_VECTOR3, "Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_DEFAULT | AM_LATESTDATA);
     REF_ACCESSOR_ATTRIBUTE(Node, VAR_VECTOR3, "Position", GetPosition, SetPosition, Vector3, Vector3::ZERO, AM_DEFAULT | AM_LATESTDATA);
-    REF_ACCESSOR_ATTRIBUTE(Node, VAR_QUATERNION, "Rotation", GetRotation, SetRotation, Quaternion, Quaternion::IDENTITY, AM_DEFAULT | AM_LATESTDATA);
+    REF_ACCESSOR_ATTRIBUTE(Node, VAR_QUATERNION, "Rotation", GetRotation, SetRotation, Quaternion, Quaternion::IDENTITY, AM_FILE);
     REF_ACCESSOR_ATTRIBUTE(Node, VAR_VECTOR3, "Scale", GetScale, SetScale, Vector3, Vector3::UNITY, AM_DEFAULT);
     REF_ACCESSOR_ATTRIBUTE(Node, VAR_VECTOR3, "Scale", GetScale, SetScale, Vector3, Vector3::UNITY, AM_DEFAULT);
-    REF_ACCESSOR_ATTRIBUTE(Node, VAR_BUFFER, "Parent Node", GetParentAttr, SetParentAttr, PODVector<unsigned char>, PODVector<unsigned char>(), AM_NET | AM_NOEDIT);
-    ATTRIBUTE(Node, VAR_VARIANTMAP, "Variables", vars_, VariantMap(), AM_FILE);
+    ATTRIBUTE(Node, VAR_VARIANTMAP, "Variables", vars_, VariantMap(), AM_FILE); // Network replication of vars uses custom data
+    REF_ACCESSOR_ATTRIBUTE(Node, VAR_BUFFER, "Network Rotation", GetNetRotationAttr, SetNetRotationAttr, PODVector<unsigned char>, PODVector<unsigned char>(), AM_NET | AM_LATESTDATA | AM_NOEDIT);
+    REF_ACCESSOR_ATTRIBUTE(Node, VAR_BUFFER, "Network Parent Node", GetNetParentAttr, SetNetParentAttr, PODVector<unsigned char>, PODVector<unsigned char>(), AM_NET | AM_NOEDIT);
 }
 }
 
 
 void Node::OnEvent(Object* sender, bool broadcast, StringHash eventType, VariantMap& eventData)
 void Node::OnEvent(Object* sender, bool broadcast, StringHash eventType, VariantMap& eventData)
@@ -620,7 +621,13 @@ void Node::SetOwner(Connection* owner)
     owner_ = owner;
     owner_ = owner;
 }
 }
 
 
-void Node::SetParentAttr(const PODVector<unsigned char>& value)
+void Node::SetNetRotationAttr(const PODVector<unsigned char>& value)
+{
+    MemoryBuffer buf(value);
+    SetRotation(buf.ReadPackedQuaternion());
+}
+
+void Node::SetNetParentAttr(const PODVector<unsigned char>& value)
 {
 {
     Scene* scene = GetScene();
     Scene* scene = GetScene();
     if (!scene)
     if (!scene)
@@ -641,15 +648,22 @@ void Node::SetParentAttr(const PODVector<unsigned char>& value)
     }
     }
 }
 }
 
 
-const PODVector<unsigned char>& Node::GetParentAttr() const
+const PODVector<unsigned char>& Node::GetNetRotationAttr() const
+{
+    attrBuffer_.Clear();
+    attrBuffer_.WritePackedQuaternion(rotation_);
+    return attrBuffer_.GetBuffer();
+}
+
+const PODVector<unsigned char>& Node::GetNetParentAttr() const
 {
 {
-    parentAttr_.Clear();
+    attrBuffer_.Clear();
     Scene* scene = GetScene();
     Scene* scene = GetScene();
     if (scene && parent_)
     if (scene && parent_)
     {
     {
         unsigned parentID = parent_->GetID();
         unsigned parentID = parent_->GetID();
         if (parentID < FIRST_LOCAL_ID)
         if (parentID < FIRST_LOCAL_ID)
-            parentAttr_.WriteVLE(parentID);
+            attrBuffer_.WriteVLE(parentID);
         else
         else
         {
         {
             // Parent is local: traverse hierarchy to find a non-local base node
             // Parent is local: traverse hierarchy to find a non-local base node
@@ -658,14 +672,14 @@ const PODVector<unsigned char>& Node::GetParentAttr() const
             while (current->GetID() >= FIRST_LOCAL_ID)
             while (current->GetID() >= FIRST_LOCAL_ID)
                 current = current->GetParent();
                 current = current->GetParent();
             
             
-            parentAttr_.WriteVLE(current->GetID());
-            parentAttr_.WriteStringHash(parent_->GetNameHash());
+            attrBuffer_.WriteVLE(current->GetID());
+            attrBuffer_.WriteStringHash(parent_->GetNameHash());
         }
         }
     }
     }
     else
     else
-        parentAttr_.WriteVLE(0);
+        attrBuffer_.WriteVLE(0);
     
     
-    return parentAttr_.GetBuffer();
+    return attrBuffer_.GetBuffer();
 }
 }
 
 
 bool Node::Load(Deserializer& source, bool readChildren)
 bool Node::Load(Deserializer& source, bool readChildren)

+ 10 - 7
Engine/Scene/Node.h

@@ -243,11 +243,14 @@ public:
     void SetScene(Scene* scene);
     void SetScene(Scene* scene);
     /// Set owner connection for multiplayer
     /// Set owner connection for multiplayer
     void SetOwner(Connection* owner);
     void SetOwner(Connection* owner);
-    
-    /// Set parent attribute (network only)
-    void SetParentAttr(const PODVector<unsigned char>& value);
-    /// Return parent attribute (network only)
-    const PODVector<unsigned char>& GetParentAttr() const;
+    /// Set network rotation attribute
+    void SetNetRotationAttr(const PODVector<unsigned char>& value);
+    /// Set network parent attribute
+    void SetNetParentAttr(const PODVector<unsigned char>& value);
+    /// Return network rotation attribute
+    const PODVector<unsigned char>& GetNetRotationAttr() const;
+    /// Return network parent attribute
+    const PODVector<unsigned char>& GetNetParentAttr() const;
     
     
     /// User variables
     /// User variables
     VariantMap vars_;
     VariantMap vars_;
@@ -298,8 +301,8 @@ private:
     Vector<SharedPtr<Component> > components_;
     Vector<SharedPtr<Component> > components_;
     /// Node listeners
     /// Node listeners
     Vector<WeakPtr<Component> > listeners_;
     Vector<WeakPtr<Component> > listeners_;
-    /// Parent attribute buffer for network replication
-    mutable VectorBuffer parentAttr_;
+    /// Attribute buffer for network replication
+    mutable VectorBuffer attrBuffer_;
     /// Consecutive rotation count for rotation renormalization
     /// Consecutive rotation count for rotation renormalization
     unsigned char rotateCount_;
     unsigned char rotateCount_;
     /// World transform needs update flag
     /// World transform needs update flag