فهرست منبع

Explicitly mark changed nodes to avoid going through the whole scene in PrepareNetworkUpdate().

Lasse Öörni 13 سال پیش
والد
کامیت
91f6f87472

+ 1 - 1
Bin/Data/Scripts/TestSceneOld.as

@@ -233,7 +233,7 @@ void InitScene()
         light.shadowNearFarRatio = 0.01;
         light.shadowNearFarRatio = 0.01;
 
 
         // Store the original rotation as a node property
         // Store the original rotation as a node property
-        newNode.vars["rotation"] = Variant(newNode.rotation);
+        newNode.vars["rotation"] = newNode.rotation;
 
 
         lights.Push(newNode);
         lights.Push(newNode);
     }
     }

+ 2 - 0
Docs/Reference.dox

@@ -1153,6 +1153,8 @@ There are some things to watch out for:
 
 
 - Networked attributes can either be in delta update or latest data mode. Delta updates are small incremental changes and must be applied in order, which may cause increased latency if there is a stall in network message delivery eg. due to packet loss. High volume data such as position, rotation and velocities are transmitted as latest data, which does not need ordering, instead this mode simply discards any old data received out of order. Note that node and component creation (when initial attributes need to be sent) and removal can also be considered as delta updates and are therefore applied in order.
 - Networked attributes can either be in delta update or latest data mode. Delta updates are small incremental changes and must be applied in order, which may cause increased latency if there is a stall in network message delivery eg. due to packet loss. High volume data such as position, rotation and velocities are transmitted as latest data, which does not need ordering, instead this mode simply discards any old data received out of order. Note that node and component creation (when initial attributes need to be sent) and removal can also be considered as delta updates and are therefore applied in order.
 
 
+- To avoid going through the whole scene when sending network updates, nodes and components explicitly mark themselves for update when necessary. When writing your own replicated C++ components, call \ref Component::MarkNetworkUpdate "MarkNetworkUpdate()" in member functions that modify any networked attribute.
+
 - The server update logic orders replication messages so that parent nodes are created and updated before their children. Remote events are queued and only sent after the replication update to ensure that if they target a newly created node, it will already exist on the receiving end. However, it is also possible to specify unordered transmission for a remote event, in which case that guarantee does not hold.
 - The server update logic orders replication messages so that parent nodes are created and updated before their children. Remote events are queued and only sent after the replication update to ensure that if they target a newly created node, it will already exist on the receiving end. However, it is also possible to specify unordered transmission for a remote event, in which case that guarantee does not hold.
 
 
 - Nodes have the concept of the \ref Node::SetOwner "owner connection" (for example the player that is controlling a specific game object), which can be set in server code. This property is not replicated to the client. Messages or remote events can be used instead to tell the players what object they control.
 - Nodes have the concept of the \ref Node::SetOwner "owner connection" (for example the player that is controlling a specific game object), which can be set in server code. This property is not replicated to the client. Messages or remote events can be used instead to tell the players what object they control.

+ 38 - 16
Docs/ScriptAPI.dox

@@ -1187,6 +1187,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 
 
 Properties:<br>
 Properties:<br>
 - ShortStringHash type (readonly)
 - ShortStringHash type (readonly)
@@ -1276,10 +1277,10 @@ Properties:<br>
 - Component@[] components (readonly)
 - Component@[] components (readonly)
 - String& name
 - String& name
 - Node@ parent
 - Node@ parent
+- VariantMap& vars (readonly)
 - Scene@ scene (readonly)
 - Scene@ scene (readonly)
 - Connection@ owner
 - Connection@ owner
 - ScriptObject@ scriptObject (readonly)
 - ScriptObject@ scriptObject (readonly)
-- VariantMap vars
 
 
 
 
 SmoothedTransform
 SmoothedTransform
@@ -1293,6 +1294,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void Update(float, float)
 - void Update(float, float)
 
 
 Properties:<br>
 Properties:<br>
@@ -1401,6 +1403,7 @@ Properties:<br>
 - Component@[] components (readonly)
 - Component@[] components (readonly)
 - String& name
 - String& name
 - Node@ parent
 - Node@ parent
+- VariantMap& vars (readonly)
 - bool active
 - bool active
 - float smoothingConstant
 - float smoothingConstant
 - float snapThreshold
 - float snapThreshold
@@ -1412,7 +1415,6 @@ Properties:<br>
 - DebugRenderer@ debugRenderer (readonly)
 - DebugRenderer@ debugRenderer (readonly)
 - Octree@ octree (readonly)
 - Octree@ octree (readonly)
 - PhysicsWorld@ physicsWorld (readonly)
 - PhysicsWorld@ physicsWorld (readonly)
-- VariantMap vars
 
 
 
 
 Camera
 Camera
@@ -1426,6 +1428,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void SetOrthoSize(const Vector2&)
 - void SetOrthoSize(const Vector2&)
 - Frustum GetSplitFrustum(float, float)
 - Frustum GetSplitFrustum(float, float)
 - Ray GetScreenRay(float, float)
 - Ray GetScreenRay(float, float)
@@ -1738,6 +1741,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void AddLine(const Vector3&, const Vector3&, const Color&, bool arg3 = true)
 - void AddLine(const Vector3&, const Vector3&, const Color&, bool arg3 = true)
 - void AddNode(Node@, bool arg1 = true)
 - void AddNode(Node@, bool arg1 = true)
 - void AddBoundingBox(const BoundingBox&, const Color&, bool arg2 = true)
 - void AddBoundingBox(const BoundingBox&, const Color&, bool arg2 = true)
@@ -1767,6 +1771,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void DrawDebugGeometry(DebugRenderer@, bool)
 - void DrawDebugGeometry(DebugRenderer@, bool)
 
 
 Properties:<br>
 Properties:<br>
@@ -1831,6 +1836,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void DrawDebugGeometry(DebugRenderer@, bool)
 - void DrawDebugGeometry(DebugRenderer@, bool)
 
 
 Properties:<br>
 Properties:<br>
@@ -1886,6 +1892,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void DrawDebugGeometry(DebugRenderer@, bool)
 - void DrawDebugGeometry(DebugRenderer@, bool)
 
 
 Properties:<br>
 Properties:<br>
@@ -1933,6 +1940,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void DrawDebugGeometry(DebugRenderer@, bool)
 - void DrawDebugGeometry(DebugRenderer@, bool)
 
 
 Properties:<br>
 Properties:<br>
@@ -1976,6 +1984,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void DrawDebugGeometry(DebugRenderer@, bool)
 - void DrawDebugGeometry(DebugRenderer@, bool)
 
 
 Properties:<br>
 Properties:<br>
@@ -2036,6 +2045,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void DrawDebugGeometry(DebugRenderer@, bool)
 - void DrawDebugGeometry(DebugRenderer@, bool)
 - AnimationState@ AddAnimationState(Animation@)
 - AnimationState@ AddAnimationState(Animation@)
 - void RemoveAnimationState(Animation@)
 - void RemoveAnimationState(Animation@)
@@ -2096,6 +2106,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - bool Play(const String&, uint8, bool, float arg3 = 0.0f)
 - bool Play(const String&, uint8, bool, float arg3 = 0.0f)
 - bool PlayExclusive(const String&, uint8, bool, float arg3 = 0.0f)
 - bool PlayExclusive(const String&, uint8, bool, float arg3 = 0.0f)
 - void Stop(const String&, float arg1 = 0.0f)
 - void Stop(const String&, float arg1 = 0.0f)
@@ -2155,6 +2166,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void DrawDebugGeometry(DebugRenderer@, bool)
 - void DrawDebugGeometry(DebugRenderer@, bool)
 - void Updated()
 - void Updated()
 
 
@@ -2201,6 +2213,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void SetActive(bool, bool)
 - void SetActive(bool, bool)
 
 
 Properties:<br>
 Properties:<br>
@@ -2242,6 +2255,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void Resize(const BoundingBox&, uint)
 - void Resize(const BoundingBox&, uint)
 - void DrawDebugGeometry(bool) const
 - void DrawDebugGeometry(bool) const
 - void AddManualDrawable(Drawable@)
 - void AddManualDrawable(Drawable@)
@@ -2388,6 +2402,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void Play(Sound@)
 - void Play(Sound@)
 - void Play(Sound@, float)
 - void Play(Sound@, float)
 - void Play(Sound@, float, float)
 - void Play(Sound@, float, float)
@@ -2424,6 +2439,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void Play(Sound@)
 - void Play(Sound@)
 - void Play(Sound@, float)
 - void Play(Sound@, float)
 - void Play(Sound@, float, float)
 - void Play(Sound@, float, float)
@@ -2564,7 +2580,7 @@ Properties:<br>
 - IntVector2 screenPosition (readonly)
 - IntVector2 screenPosition (readonly)
 - float derivedOpacity (readonly)
 - float derivedOpacity (readonly)
 - IntRect combinedScreenRect (readonly)
 - IntRect combinedScreenRect (readonly)
-- VariantMap vars
+- VariantMap& vars (readonly)
 
 
 
 
 BorderImage
 BorderImage
@@ -2644,11 +2660,11 @@ Properties:<br>
 - IntVector2 screenPosition (readonly)
 - IntVector2 screenPosition (readonly)
 - float derivedOpacity (readonly)
 - float derivedOpacity (readonly)
 - IntRect combinedScreenRect (readonly)
 - IntRect combinedScreenRect (readonly)
+- VariantMap& vars (readonly)
 - Texture@ texture
 - Texture@ texture
 - IntRect& imageRect
 - IntRect& imageRect
 - IntRect& border
 - IntRect& border
 - IntVector2& hoverOffset
 - IntVector2& hoverOffset
-- VariantMap vars
 
 
 
 
 Button
 Button
@@ -2731,6 +2747,7 @@ Properties:<br>
 - IntVector2 screenPosition (readonly)
 - IntVector2 screenPosition (readonly)
 - float derivedOpacity (readonly)
 - float derivedOpacity (readonly)
 - IntRect combinedScreenRect (readonly)
 - IntRect combinedScreenRect (readonly)
+- VariantMap& vars (readonly)
 - Texture@ texture
 - Texture@ texture
 - IntRect& imageRect
 - IntRect& imageRect
 - IntRect& border
 - IntRect& border
@@ -2739,7 +2756,6 @@ Properties:<br>
 - IntVector2& labelOffset
 - IntVector2& labelOffset
 - float repeatDelay
 - float repeatDelay
 - float repeatRate
 - float repeatRate
-- VariantMap vars
 
 
 
 
 CheckBox
 CheckBox
@@ -2820,13 +2836,13 @@ Properties:<br>
 - IntVector2 screenPosition (readonly)
 - IntVector2 screenPosition (readonly)
 - float derivedOpacity (readonly)
 - float derivedOpacity (readonly)
 - IntRect combinedScreenRect (readonly)
 - IntRect combinedScreenRect (readonly)
+- VariantMap& vars (readonly)
 - Texture@ texture
 - Texture@ texture
 - IntRect& imageRect
 - IntRect& imageRect
 - IntRect& border
 - IntRect& border
 - IntVector2& hoverOffset
 - IntVector2& hoverOffset
 - bool checked
 - bool checked
 - IntVector2& checkedOffset
 - IntVector2& checkedOffset
-- VariantMap vars
 
 
 
 
 Cursor
 Cursor
@@ -2907,12 +2923,12 @@ Properties:<br>
 - IntVector2 screenPosition (readonly)
 - IntVector2 screenPosition (readonly)
 - float derivedOpacity (readonly)
 - float derivedOpacity (readonly)
 - IntRect combinedScreenRect (readonly)
 - IntRect combinedScreenRect (readonly)
+- VariantMap& vars (readonly)
 - Texture@ texture
 - Texture@ texture
 - IntRect& imageRect
 - IntRect& imageRect
 - IntRect& border
 - IntRect& border
 - IntVector2& hoverOffset
 - IntVector2& hoverOffset
 - CursorShape shape
 - CursorShape shape
-- VariantMap vars
 
 
 
 
 Slider
 Slider
@@ -2993,6 +3009,7 @@ Properties:<br>
 - IntVector2 screenPosition (readonly)
 - IntVector2 screenPosition (readonly)
 - float derivedOpacity (readonly)
 - float derivedOpacity (readonly)
 - IntRect combinedScreenRect (readonly)
 - IntRect combinedScreenRect (readonly)
+- VariantMap& vars (readonly)
 - Texture@ texture
 - Texture@ texture
 - IntRect& imageRect
 - IntRect& imageRect
 - IntRect& border
 - IntRect& border
@@ -3001,7 +3018,6 @@ Properties:<br>
 - float range
 - float range
 - float value
 - float value
 - BorderImage@ knob (readonly)
 - BorderImage@ knob (readonly)
-- VariantMap vars
 
 
 
 
 ScrollBar
 ScrollBar
@@ -3082,6 +3098,7 @@ Properties:<br>
 - IntVector2 screenPosition (readonly)
 - IntVector2 screenPosition (readonly)
 - float derivedOpacity (readonly)
 - float derivedOpacity (readonly)
 - IntRect combinedScreenRect (readonly)
 - IntRect combinedScreenRect (readonly)
+- VariantMap& vars (readonly)
 - Orientation orientation
 - Orientation orientation
 - float range
 - float range
 - float value
 - float value
@@ -3091,7 +3108,6 @@ Properties:<br>
 - Button@ backButton (readonly)
 - Button@ backButton (readonly)
 - Button@ forwardButton (readonly)
 - Button@ forwardButton (readonly)
 - Slider@ slider (readonly)
 - Slider@ slider (readonly)
-- VariantMap vars
 
 
 
 
 ScrollView
 ScrollView
@@ -3171,6 +3187,7 @@ Properties:<br>
 - IntVector2 screenPosition (readonly)
 - IntVector2 screenPosition (readonly)
 - float derivedOpacity (readonly)
 - float derivedOpacity (readonly)
 - IntRect combinedScreenRect (readonly)
 - IntRect combinedScreenRect (readonly)
+- VariantMap& vars (readonly)
 - UIElement@ contentElement
 - UIElement@ contentElement
 - IntVector2& viewPosition
 - IntVector2& viewPosition
 - float scrollStep
 - float scrollStep
@@ -3178,7 +3195,6 @@ Properties:<br>
 - ScrollBar@ horizontalScrollBar (readonly)
 - ScrollBar@ horizontalScrollBar (readonly)
 - ScrollBar@ verticalScrollBar (readonly)
 - ScrollBar@ verticalScrollBar (readonly)
 - BorderImage@ scrollPanel (readonly)
 - BorderImage@ scrollPanel (readonly)
-- VariantMap vars
 
 
 
 
 ListView
 ListView
@@ -3273,6 +3289,7 @@ Properties:<br>
 - IntVector2 screenPosition (readonly)
 - IntVector2 screenPosition (readonly)
 - float derivedOpacity (readonly)
 - float derivedOpacity (readonly)
 - IntRect combinedScreenRect (readonly)
 - IntRect combinedScreenRect (readonly)
+- VariantMap& vars (readonly)
 - IntVector2& viewPosition
 - IntVector2& viewPosition
 - UIElement@ contentElement (readonly)
 - UIElement@ contentElement (readonly)
 - ScrollBar@ horizontalScrollBar (readonly)
 - ScrollBar@ horizontalScrollBar (readonly)
@@ -3291,7 +3308,6 @@ Properties:<br>
 - bool hierarchyMode
 - bool hierarchyMode
 - bool clearSelectionOnDefocus
 - bool clearSelectionOnDefocus
 - float floatClickInterval
 - float floatClickInterval
-- VariantMap vars
 
 
 
 
 Text
 Text
@@ -3373,6 +3389,7 @@ Properties:<br>
 - IntVector2 screenPosition (readonly)
 - IntVector2 screenPosition (readonly)
 - float derivedOpacity (readonly)
 - float derivedOpacity (readonly)
 - IntRect combinedScreenRect (readonly)
 - IntRect combinedScreenRect (readonly)
+- VariantMap& vars (readonly)
 - Font@ font (readonly)
 - Font@ font (readonly)
 - int fontSize (readonly)
 - int fontSize (readonly)
 - String& text
 - String& text
@@ -3385,7 +3402,6 @@ Properties:<br>
 - Color& hoverColor
 - Color& hoverColor
 - uint numRows (readonly)
 - uint numRows (readonly)
 - int rowHeight (readonly)
 - int rowHeight (readonly)
-- VariantMap vars
 
 
 
 
 LineEdit
 LineEdit
@@ -3465,6 +3481,7 @@ Properties:<br>
 - IntVector2 screenPosition (readonly)
 - IntVector2 screenPosition (readonly)
 - float derivedOpacity (readonly)
 - float derivedOpacity (readonly)
 - IntRect combinedScreenRect (readonly)
 - IntRect combinedScreenRect (readonly)
+- VariantMap& vars (readonly)
 - Texture@ texture
 - Texture@ texture
 - IntRect& imageRect
 - IntRect& imageRect
 - IntRect& border
 - IntRect& border
@@ -3479,7 +3496,6 @@ Properties:<br>
 - bool textCopyable
 - bool textCopyable
 - Text@ textElement (readonly)
 - Text@ textElement (readonly)
 - BorderImage@ cursor (readonly)
 - BorderImage@ cursor (readonly)
-- VariantMap vars
 
 
 
 
 Menu
 Menu
@@ -3564,6 +3580,7 @@ Properties:<br>
 - IntVector2 screenPosition (readonly)
 - IntVector2 screenPosition (readonly)
 - float derivedOpacity (readonly)
 - float derivedOpacity (readonly)
 - IntRect combinedScreenRect (readonly)
 - IntRect combinedScreenRect (readonly)
+- VariantMap& vars (readonly)
 - Texture@ texture
 - Texture@ texture
 - IntRect& imageRect
 - IntRect& imageRect
 - IntRect& border
 - IntRect& border
@@ -3577,7 +3594,6 @@ Properties:<br>
 - bool showPopup
 - bool showPopup
 - int acceleratorKey (readonly)
 - int acceleratorKey (readonly)
 - int acceleratorQualifiers (readonly)
 - int acceleratorQualifiers (readonly)
-- VariantMap vars
 
 
 
 
 DropDownList
 DropDownList
@@ -3668,6 +3684,7 @@ Properties:<br>
 - IntVector2 screenPosition (readonly)
 - IntVector2 screenPosition (readonly)
 - float derivedOpacity (readonly)
 - float derivedOpacity (readonly)
 - IntRect combinedScreenRect (readonly)
 - IntRect combinedScreenRect (readonly)
+- VariantMap& vars (readonly)
 - Texture@ texture
 - Texture@ texture
 - IntRect& imageRect
 - IntRect& imageRect
 - IntRect& border
 - IntRect& border
@@ -3686,7 +3703,6 @@ Properties:<br>
 - UIElement@ selectedItem (readonly)
 - UIElement@ selectedItem (readonly)
 - ListView@ listView (readonly)
 - ListView@ listView (readonly)
 - UIElement@ placeholder (readonly)
 - UIElement@ placeholder (readonly)
-- VariantMap vars
 
 
 
 
 Window
 Window
@@ -3766,6 +3782,7 @@ Properties:<br>
 - IntVector2 screenPosition (readonly)
 - IntVector2 screenPosition (readonly)
 - float derivedOpacity (readonly)
 - float derivedOpacity (readonly)
 - IntRect combinedScreenRect (readonly)
 - IntRect combinedScreenRect (readonly)
+- VariantMap& vars (readonly)
 - Texture@ texture
 - Texture@ texture
 - IntRect& imageRect
 - IntRect& imageRect
 - IntRect& border
 - IntRect& border
@@ -3773,7 +3790,6 @@ Properties:<br>
 - bool movable
 - bool movable
 - bool resizable
 - bool resizable
 - IntRect& resizeBorder
 - IntRect& resizeBorder
-- VariantMap vars
 
 
 
 
 FileSelector
 FileSelector
@@ -3848,6 +3864,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 
 
 Properties:<br>
 Properties:<br>
 - ShortStringHash type (readonly)
 - ShortStringHash type (readonly)
@@ -3928,6 +3945,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void SetSphere(float, const Vector3& arg1 = Vector3 ( ), const Quaternion& arg2 = Quaternion ( ))
 - void SetSphere(float, const Vector3& arg1 = Vector3 ( ), const Quaternion& arg2 = Quaternion ( ))
 - void SetBox(const Vector3&, const Vector3& arg1 = Vector3 ( ), const Quaternion& arg2 = Quaternion ( ))
 - void SetBox(const Vector3&, const Vector3& arg1 = Vector3 ( ), const Quaternion& arg2 = Quaternion ( ))
 - void SetCylinder(float, float, const Vector3& arg2 = Vector3 ( ), const Quaternion& arg3 = Quaternion ( ))
 - void SetCylinder(float, float, const Vector3& arg2 = Vector3 ( ), const Quaternion& arg3 = Quaternion ( ))
@@ -3966,6 +3984,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void SetTransform(const Vector3&, const Quaternion&)
 - void SetTransform(const Vector3&, const Quaternion&)
 - void SetCollisionLayerAndMask(uint, uint)
 - void SetCollisionLayerAndMask(uint, uint)
 - void ApplyForce(const Vector3&)
 - void ApplyForce(const Vector3&)
@@ -4021,6 +4040,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void Clear()
 - void Clear()
 - void DrawDebugGeometry(DebugRenderer@, bool)
 - void DrawDebugGeometry(DebugRenderer@, bool)
 
 
@@ -4059,6 +4079,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - void Update(float)
 - void Update(float)
 - void UpdateCollisions()
 - void UpdateCollisions()
 - PhysicsRaycastResult[]@ Raycast(const Ray&, float arg1 = M_INFINITY, uint arg2 = 0xffff)
 - PhysicsRaycastResult[]@ Raycast(const Ray&, float arg1 = M_INFINITY, uint arg2 = 0xffff)
@@ -4108,6 +4129,7 @@ Methods:<br>
 - bool SetAttribute(const String&, const Variant&)
 - bool SetAttribute(const String&, const Variant&)
 - Variant GetAttribute(const String&)
 - Variant GetAttribute(const String&)
 - void Remove()
 - void Remove()
+- void MarkNetworkUpdate() const
 - bool CreateObject(ScriptFile@, const String&)
 - bool CreateObject(ScriptFile@, const String&)
 - bool Execute(const String&, const Variant[]@)
 - bool Execute(const String&, const Variant[]@)
 - bool Execute(const String&)
 - bool Execute(const String&)

+ 9 - 0
Engine/Audio/SoundSource.cpp

@@ -161,6 +161,8 @@ void SoundSource::Play(Sound* sound)
     }
     }
     else
     else
         PlayLockless(sound);
         PlayLockless(sound);
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 void SoundSource::Play(Sound* sound, float frequency)
 void SoundSource::Play(Sound* sound, float frequency)
@@ -199,6 +201,8 @@ void SoundSource::Stop()
     // Free the compressed sound decoder now if any
     // Free the compressed sound decoder now if any
     FreeDecoder();
     FreeDecoder();
     sound_.Reset();
     sound_.Reset();
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 void SoundSource::SetSoundType(SoundType type)
 void SoundSource::SetSoundType(SoundType type)
@@ -207,26 +211,31 @@ void SoundSource::SetSoundType(SoundType type)
         return;
         return;
     
     
     soundType_ = type;
     soundType_ = type;
+    MarkNetworkUpdate();
 }
 }
 
 
 void SoundSource::SetFrequency(float frequency)
 void SoundSource::SetFrequency(float frequency)
 {
 {
     frequency_ = Clamp(frequency, 0.0f, 535232.0f);
     frequency_ = Clamp(frequency, 0.0f, 535232.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void SoundSource::SetGain(float gain)
 void SoundSource::SetGain(float gain)
 {
 {
     gain_ = Max(gain, 0.0f);
     gain_ = Max(gain, 0.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void SoundSource::SetAttenuation(float attenuation)
 void SoundSource::SetAttenuation(float attenuation)
 {
 {
     attenuation_ = Clamp(attenuation, 0.0f, 1.0f);
     attenuation_ = Clamp(attenuation, 0.0f, 1.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void SoundSource::SetPanning(float panning)
 void SoundSource::SetPanning(float panning)
 {
 {
     panning_ = Clamp(panning, -1.0f, 1.0f);
     panning_ = Clamp(panning, -1.0f, 1.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void SoundSource::SetAutoRemove(bool enable)
 void SoundSource::SetAutoRemove(bool enable)

+ 4 - 0
Engine/Audio/SoundSource3D.cpp

@@ -68,21 +68,25 @@ void SoundSource3D::SetDistanceAttenuation(float nearDistance, float farDistance
     nearDistance_ = Max(nearDistance, 0.0f);
     nearDistance_ = Max(nearDistance, 0.0f);
     farDistance_ = Max(farDistance, 0.0f);
     farDistance_ = Max(farDistance, 0.0f);
     rolloffFactor_ = Max(rolloffFactor, MIN_ROLLOFF);
     rolloffFactor_ = Max(rolloffFactor, MIN_ROLLOFF);
+    MarkNetworkUpdate();
 }
 }
 
 
 void SoundSource3D::SetFarDistance(float distance)
 void SoundSource3D::SetFarDistance(float distance)
 {
 {
     farDistance_ = Max(distance, 0.0f);
     farDistance_ = Max(distance, 0.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void SoundSource3D::SetNearDistance(float distance)
 void SoundSource3D::SetNearDistance(float distance)
 {
 {
     nearDistance_ = Max(distance, 0.0f);
     nearDistance_ = Max(distance, 0.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void SoundSource3D::SetRolloffFactor(float factor)
 void SoundSource3D::SetRolloffFactor(float factor)
 {
 {
     rolloffFactor_ = Max(factor, MIN_ROLLOFF);
     rolloffFactor_ = Max(factor, MIN_ROLLOFF);
+    MarkNetworkUpdate();
 }
 }
 
 
 void SoundSource3D::CalculateAttenuation()
 void SoundSource3D::CalculateAttenuation()

+ 15 - 2
Engine/Engine/APITemplates.h

@@ -372,6 +372,7 @@ template <class T> void RegisterComponent(asIScriptEngine* engine, const char* c
     RegisterSerializable<T>(engine, className);
     RegisterSerializable<T>(engine, className);
     RegisterSubclass<Component, T>(engine, "Component", className);
     RegisterSubclass<Component, T>(engine, "Component", className);
     engine->RegisterObjectMethod(className, "void Remove()", asMETHODPR(T, Remove, (), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void Remove()", asMETHODPR(T, Remove, (), void), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "void MarkNetworkUpdate() const", asMETHODPR(T, MarkNetworkUpdate, (), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "uint get_id()", asMETHODPR(T, GetID, () const, unsigned), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "uint get_id()", asMETHODPR(T, GetID, () const, unsigned), asCALL_THISCALL);
     if (nodeRegistered)
     if (nodeRegistered)
         engine->RegisterObjectMethod(className, "Node@+ get_node() const", asMETHODPR(T, GetNode, () const, Node*), asCALL_THISCALL);
         engine->RegisterObjectMethod(className, "Node@+ get_node() const", asMETHODPR(T, GetNode, () const, Node*), asCALL_THISCALL);
@@ -488,6 +489,13 @@ static CScriptArray* NodeGetChildrenWithClassName(const String& className, bool
     return VectorToHandleArray<Node>(result, "Array<Node@>");
     return VectorToHandleArray<Node>(result, "Array<Node@>");
 }
 }
 
 
+static VariantMap& NodeGetVars(Node* ptr)
+{
+    // Assume that the vars will be modified and queue a network update attribute check
+    ptr->MarkNetworkUpdate();
+    return const_cast<VariantMap&>(ptr->GetVars());
+}
+
 /// Template function for registering a class derived from Node.
 /// Template function for registering a class derived from Node.
 template <class T> void RegisterNode(asIScriptEngine* engine, const char* className)
 template <class T> void RegisterNode(asIScriptEngine* engine, const char* className)
 {
 {
@@ -558,7 +566,7 @@ template <class T> void RegisterNode(asIScriptEngine* engine, const char* classN
     engine->RegisterObjectMethod(className, "const String& get_name() const", asMETHOD(T, GetName), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "const String& get_name() const", asMETHOD(T, GetName), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void set_parent(Node@+)", asMETHOD(T, SetParent), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void set_parent(Node@+)", asMETHOD(T, SetParent), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "Node@+ get_parent() const", asMETHOD(T, GetParent), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "Node@+ get_parent() const", asMETHOD(T, GetParent), asCALL_THISCALL);
-    engine->RegisterObjectProperty(className, "VariantMap vars", offsetof(T, vars_));
+    engine->RegisterObjectMethod(className, "VariantMap& get_vars()", asFUNCTION(NodeGetVars), asCALL_CDECL_OBJLAST);
 }
 }
 
 
 static bool ResourceLoad(File* file, XMLFile* ptr)
 static bool ResourceLoad(File* file, XMLFile* ptr)
@@ -708,6 +716,11 @@ static unsigned UIElementGetNumChildrenRecursive(UIElement* ptr)
     return ptr->GetNumChildren(true);
     return ptr->GetNumChildren(true);
 }
 }
 
 
+static VariantMap& UIElementGetVars(UIElement* ptr)
+{
+    return const_cast<VariantMap&>(ptr->GetVars());
+}
+
 /// Template function for registering a class derived from UIElement.
 /// Template function for registering a class derived from UIElement.
 template <class T> void RegisterUIElement(asIScriptEngine* engine, const char* className)
 template <class T> void RegisterUIElement(asIScriptEngine* engine, const char* className)
 {
 {
@@ -816,7 +829,7 @@ template <class T> void RegisterUIElement(asIScriptEngine* engine, const char* c
     engine->RegisterObjectMethod(className, "IntVector2 get_screenPosition()", asMETHOD(T, GetScreenPosition), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "IntVector2 get_screenPosition()", asMETHOD(T, GetScreenPosition), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "float get_derivedOpacity()", asMETHOD(T, GetDerivedOpacity), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "float get_derivedOpacity()", asMETHOD(T, GetDerivedOpacity), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "IntRect get_combinedScreenRect()", asMETHOD(T, GetCombinedScreenRect), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "IntRect get_combinedScreenRect()", asMETHOD(T, GetCombinedScreenRect), asCALL_THISCALL);
-    engine->RegisterObjectProperty(className, "VariantMap vars", offsetof(T, vars_));
+    engine->RegisterObjectMethod(className, "VariantMap& get_vars()", asFUNCTION(UIElementGetVars), asCALL_CDECL_OBJLAST);
 }
 }
 
 
 /// Template function for registering a class derived from BorderImage.
 /// Template function for registering a class derived from BorderImage.

+ 12 - 3
Engine/Graphics/AnimatedModel.cpp

@@ -89,6 +89,7 @@ void AnimatedModel::RegisterObject(Context* context)
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Animation LOD Bias", GetAnimationLodBias, SetAnimationLodBias, float, 1.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Animation LOD Bias", GetAnimationLodBias, SetAnimationLodBias, float, 1.0f, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Invisible Anim LOD Factor", GetInvisibleLodFactor, SetInvisibleLodFactor, float, 0.0f, AM_DEFAULT);
     COPY_BASE_ATTRIBUTES(AnimatedModel, Drawable);
     COPY_BASE_ATTRIBUTES(AnimatedModel, Drawable);
     ATTRIBUTE(AnimatedModel, VAR_INT, "Ray/Occl. LOD Level", softwareLodLevel_, M_MAX_UNSIGNED, AM_DEFAULT);
     ATTRIBUTE(AnimatedModel, VAR_INT, "Ray/Occl. LOD Level", softwareLodLevel_, M_MAX_UNSIGNED, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_VARIANTVECTOR, "Bone Animation Enabled", GetBonesEnabledAttr, SetBonesEnabledAttr, VariantVector, VariantVector(), AM_FILE | AM_NOEDIT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_VARIANTVECTOR, "Bone Animation Enabled", GetBonesEnabledAttr, SetBonesEnabledAttr, VariantVector, VariantVector(), AM_FILE | AM_NOEDIT);
@@ -338,6 +339,8 @@ void AnimatedModel::SetModel(Model* model, bool createBones)
     // Copy bounding box & skeleton
     // Copy bounding box & skeleton
     SetBoundingBox(model->GetBoundingBox());
     SetBoundingBox(model->GetBoundingBox());
     SetSkeleton(model->GetSkeleton(), createBones);
     SetSkeleton(model->GetSkeleton(), createBones);
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 AnimationState* AnimatedModel::AddAnimationState(Animation* animation)
 AnimationState* AnimatedModel::AddAnimationState(Animation* animation)
@@ -410,6 +413,7 @@ void AnimatedModel::RemoveAllAnimationStates()
 void AnimatedModel::SetAnimationLodBias(float bias)
 void AnimatedModel::SetAnimationLodBias(float bias)
 {
 {
     animationLodBias_ = Max(bias, 0.0f);
     animationLodBias_ = Max(bias, 0.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void AnimatedModel::SetInvisibleLodFactor(float factor)
 void AnimatedModel::SetInvisibleLodFactor(float factor)
@@ -418,7 +422,9 @@ void AnimatedModel::SetInvisibleLodFactor(float factor)
         factor = 0.0f;
         factor = 0.0f;
     else if (factor != 0.0f && factor < 1.0f)
     else if (factor != 0.0f && factor < 1.0f)
         factor = 1.0f;
         factor = 1.0f;
+    
     invisibleLodFactor_ = factor;
     invisibleLodFactor_ = factor;
+    MarkNetworkUpdate();
 }
 }
 
 
 void AnimatedModel::SetMorphWeight(unsigned index, float weight)
 void AnimatedModel::SetMorphWeight(unsigned index, float weight)
@@ -431,7 +437,6 @@ void AnimatedModel::SetMorphWeight(unsigned index, float weight)
     if (weight != morphs_[index].weight_)
     if (weight != morphs_[index].weight_)
     {
     {
         morphs_[index].weight_ = weight;
         morphs_[index].weight_ = weight;
-        MarkMorphsDirty();
         
         
         // For a master model, set the same morph weight on non-master models
         // For a master model, set the same morph weight on non-master models
         if (isMaster_)
         if (isMaster_)
@@ -443,6 +448,9 @@ void AnimatedModel::SetMorphWeight(unsigned index, float weight)
             for (unsigned i = 1; i < models.Size(); ++i)
             for (unsigned i = 1; i < models.Size(); ++i)
                 models[i]->SetMorphWeight(morphs_[index].nameHash_, weight);
                 models[i]->SetMorphWeight(morphs_[index].nameHash_, weight);
         }
         }
+        
+        MarkMorphsDirty();
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -475,8 +483,6 @@ void AnimatedModel::ResetMorphWeights()
     for (Vector<ModelMorph>::Iterator i = morphs_.Begin(); i != morphs_.End(); ++i)
     for (Vector<ModelMorph>::Iterator i = morphs_.Begin(); i != morphs_.End(); ++i)
         i->weight_ = 0.0f;
         i->weight_ = 0.0f;
     
     
-    MarkMorphsDirty();
-
     // For a master model, reset weights on non-master models
     // For a master model, reset weights on non-master models
     if (isMaster_)
     if (isMaster_)
     {
     {
@@ -487,6 +493,9 @@ void AnimatedModel::ResetMorphWeights()
         for (unsigned i = 1; i < models.Size(); ++i)
         for (unsigned i = 1; i < models.Size(); ++i)
             models[i]->ResetMorphWeights();
             models[i]->ResetMorphWeights();
     }
     }
+    
+    MarkMorphsDirty();
+    MarkNetworkUpdate();
 }
 }
 
 
 float AnimatedModel::GetMorphWeight(unsigned index) const
 float AnimatedModel::GetMorphWeight(unsigned index) const

+ 18 - 1
Engine/Graphics/AnimationController.cpp

@@ -127,6 +127,7 @@ void AnimationController::Update(float timeStep)
             if (state)
             if (state)
                 model->RemoveAnimationState(state);
                 model->RemoveAnimationState(state);
             i = animations_.Erase(i);
             i = animations_.Erase(i);
+            MarkNetworkUpdate();
         }
         }
         else
         else
             ++i;
             ++i;
@@ -166,6 +167,7 @@ bool AnimationController::Play(const String& name, unsigned char layer, bool loo
     animations_[index].targetWeight_ = 1.0f;
     animations_[index].targetWeight_ = 1.0f;
     animations_[index].fadeTime_ = fadeInTime;
     animations_[index].fadeTime_ = fadeInTime;
     
     
+    MarkNetworkUpdate();
     return true;
     return true;
 }
 }
 
 
@@ -188,6 +190,7 @@ bool AnimationController::Stop(const String& name, float fadeOutTime)
     {
     {
         animations_[index].targetWeight_ = 0.0f;
         animations_[index].targetWeight_ = 0.0f;
         animations_[index].fadeTime_ = fadeOutTime;
         animations_[index].fadeTime_ = fadeOutTime;
+        MarkNetworkUpdate();
     }
     }
     
     
     return index != M_MAX_UNSIGNED || state != 0;
     return index != M_MAX_UNSIGNED || state != 0;
@@ -208,6 +211,8 @@ void AnimationController::StopLayer(unsigned char layer, float fadeOutTime)
             i->fadeTime_ = fadeOutTime;
             i->fadeTime_ = fadeOutTime;
         }
         }
     }
     }
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 void AnimationController::StopAll(float fadeOutTime)
 void AnimationController::StopAll(float fadeOutTime)
@@ -221,6 +226,8 @@ void AnimationController::StopAll(float fadeOutTime)
         i->targetWeight_ = 0.0f;
         i->targetWeight_ = 0.0f;
         i->fadeTime_ = fadeOutTime;
         i->fadeTime_ = fadeOutTime;
     }
     }
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 bool AnimationController::Fade(const String& name, float targetWeight, float fadeTime)
 bool AnimationController::Fade(const String& name, float targetWeight, float fadeTime)
@@ -233,6 +240,7 @@ bool AnimationController::Fade(const String& name, float targetWeight, float fad
     
     
     animations_[index].targetWeight_ = Clamp(targetWeight, 0.0f, 1.0f);
     animations_[index].targetWeight_ = Clamp(targetWeight, 0.0f, 1.0f);
     animations_[index].fadeTime_ = fadeTime;
     animations_[index].fadeTime_ = fadeTime;
+    MarkNetworkUpdate();
     return true;
     return true;
 }
 }
 
 
@@ -260,6 +268,8 @@ bool AnimationController::FadeOthers(const String& name, float targetWeight, flo
             }
             }
         }
         }
     }
     }
+    
+    MarkNetworkUpdate();
     return true;
     return true;
 }
 }
 
 
@@ -270,6 +280,7 @@ bool AnimationController::SetLayer(const String& name, unsigned char layer)
         return false;
         return false;
     
     
     state->SetLayer(layer);
     state->SetLayer(layer);
+    MarkNetworkUpdate();
     return true;
     return true;
 }
 }
 
 
@@ -282,6 +293,7 @@ bool AnimationController::SetStartBone(const String& name, const String& startBo
     AnimatedModel* model = GetComponent<AnimatedModel>();
     AnimatedModel* model = GetComponent<AnimatedModel>();
     Bone* bone = model->GetSkeleton().GetBone(startBoneName);
     Bone* bone = model->GetSkeleton().GetBone(startBoneName);
     state->SetStartBone(bone);
     state->SetStartBone(bone);
+    MarkNetworkUpdate();
     return true;
     return true;
 }
 }
 
 
@@ -299,6 +311,7 @@ bool AnimationController::SetTime(const String& name, float time)
     animations_[index].setTime_ = (unsigned short)(time / state->GetLength() * 65535.0f);
     animations_[index].setTime_ = (unsigned short)(time / state->GetLength() * 65535.0f);
     animations_[index].setTimeTtl_ = COMMAND_STAY_TIME;
     animations_[index].setTimeTtl_ = COMMAND_STAY_TIME;
     ++animations_[index].setTimeRev_;
     ++animations_[index].setTimeRev_;
+    MarkNetworkUpdate();
     return true;
     return true;
 }
 }
 
 
@@ -311,6 +324,7 @@ bool AnimationController::SetSpeed(const String& name, float speed)
         return false;
         return false;
     
     
     animations_[index].speed_ = speed;
     animations_[index].speed_ = speed;
+    MarkNetworkUpdate();
     return true;
     return true;
 }
 }
 
 
@@ -328,6 +342,7 @@ bool AnimationController::SetWeight(const String& name, float weight)
     animations_[index].setWeight_ = (unsigned char)(weight * 255.0f);
     animations_[index].setWeight_ = (unsigned char)(weight * 255.0f);
     animations_[index].setWeightTtl_ = COMMAND_STAY_TIME;
     animations_[index].setWeightTtl_ = COMMAND_STAY_TIME;
     ++animations_[index].setWeightRev_;
     ++animations_[index].setWeightRev_;
+    MarkNetworkUpdate();
     return true;
     return true;
 }
 }
 
 
@@ -338,6 +353,7 @@ bool AnimationController::SetLooped(const String& name, bool enable)
         return false;
         return false;
     
     
     state->SetLooped(enable);
     state->SetLooped(enable);
+    MarkNetworkUpdate();
     return true;
     return true;
 }
 }
 
 
@@ -350,6 +366,7 @@ bool AnimationController::SetAutoFade(const String& name, float fadeOutTime)
         return false;
         return false;
     
     
     animations_[index].autoFadeTime_ = Max(fadeOutTime, 0.0f);
     animations_[index].autoFadeTime_ = Max(fadeOutTime, 0.0f);
+    MarkNetworkUpdate();
     return true;
     return true;
 }
 }
 
 
@@ -506,7 +523,7 @@ void AnimationController::SetNetAnimationsAttr(const PODVector<unsigned char>& v
         StringHash animHash = buf.ReadStringHash();
         StringHash animHash = buf.ReadStringHash();
         processedAnimations.Insert(animHash);
         processedAnimations.Insert(animHash);
         
         
-       // Check if the animation state exists. If not, add new
+        // Check if the animation state exists. If not, add new
         AnimationState* state = model->GetAnimationState(animHash);
         AnimationState* state = model->GetAnimationState(animHash);
         if (!state)
         if (!state)
         {
         {

+ 7 - 0
Engine/Graphics/BillboardSet.cpp

@@ -164,6 +164,7 @@ void BillboardSet::GetBatch(Batch& batch, const FrameInfo& frame, unsigned batch
 void BillboardSet::SetMaterial(Material* material)
 void BillboardSet::SetMaterial(Material* material)
 {
 {
     material_ = material;
     material_ = material;
+    MarkNetworkUpdate();
 }
 }
 
 
 void BillboardSet::SetNumBillboards(unsigned num)
 void BillboardSet::SetNumBillboards(unsigned num)
@@ -185,34 +186,40 @@ void BillboardSet::SetNumBillboards(unsigned num)
     
     
     bufferSizeDirty_ = true;
     bufferSizeDirty_ = true;
     MarkPositionsDirty();
     MarkPositionsDirty();
+    MarkNetworkUpdate();
 }
 }
 
 
 void BillboardSet::SetRelative(bool enable)
 void BillboardSet::SetRelative(bool enable)
 {
 {
     relative_ = enable;
     relative_ = enable;
     MarkPositionsDirty();
     MarkPositionsDirty();
+    MarkNetworkUpdate();
 }
 }
 
 
 void BillboardSet::SetScaled(bool enable)
 void BillboardSet::SetScaled(bool enable)
 {
 {
     scaled_ = enable;
     scaled_ = enable;
     MarkPositionsDirty();
     MarkPositionsDirty();
+    MarkNetworkUpdate();
 }
 }
 
 
 void BillboardSet::SetSorted(bool enable)
 void BillboardSet::SetSorted(bool enable)
 {
 {
     sorted_ = enable;
     sorted_ = enable;
     MarkPositionsDirty();
     MarkPositionsDirty();
+    MarkNetworkUpdate();
 }
 }
 
 
 void BillboardSet::SetAnimationLodBias(float bias)
 void BillboardSet::SetAnimationLodBias(float bias)
 {
 {
     animationLodBias_ = Max(bias, 0.0f);
     animationLodBias_ = Max(bias, 0.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void BillboardSet::Updated()
 void BillboardSet::Updated()
 {
 {
     MarkPositionsDirty();
     MarkPositionsDirty();
+    MarkNetworkUpdate();
 }
 }
 
 
 Billboard* BillboardSet::GetBillboard(unsigned index)
 Billboard* BillboardSet::GetBillboard(unsigned index)

+ 14 - 0
Engine/Graphics/Camera.cpp

@@ -89,6 +89,7 @@ void Camera::SetNearClip(float nearClip)
     nearClip_ = Max(nearClip, M_MIN_NEARCLIP);
     nearClip_ = Max(nearClip, M_MIN_NEARCLIP);
     frustumDirty_ = true;
     frustumDirty_ = true;
     projectionDirty_ = true;
     projectionDirty_ = true;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Camera::SetFarClip(float farClip)
 void Camera::SetFarClip(float farClip)
@@ -96,6 +97,7 @@ void Camera::SetFarClip(float farClip)
     farClip_ = Max(farClip, M_MIN_NEARCLIP);
     farClip_ = Max(farClip, M_MIN_NEARCLIP);
     frustumDirty_ = true;
     frustumDirty_ = true;
     projectionDirty_ = true;
     projectionDirty_ = true;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Camera::SetFov(float fov)
 void Camera::SetFov(float fov)
@@ -103,6 +105,7 @@ void Camera::SetFov(float fov)
     fov_ = Clamp(fov, 0.0f, M_MAX_FOV);
     fov_ = Clamp(fov, 0.0f, M_MAX_FOV);
     frustumDirty_ = true;
     frustumDirty_ = true;
     projectionDirty_ = true;
     projectionDirty_ = true;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Camera::SetOrthoSize(float orthoSize)
 void Camera::SetOrthoSize(float orthoSize)
@@ -111,6 +114,7 @@ void Camera::SetOrthoSize(float orthoSize)
     aspectRatio_ = 1.0f;
     aspectRatio_ = 1.0f;
     frustumDirty_ = true;
     frustumDirty_ = true;
     projectionDirty_ = true;
     projectionDirty_ = true;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Camera::SetOrthoSize(const Vector2& orthoSize)
 void Camera::SetOrthoSize(const Vector2& orthoSize)
@@ -119,6 +123,7 @@ void Camera::SetOrthoSize(const Vector2& orthoSize)
     aspectRatio_ = orthoSize.x_ / orthoSize.y_;
     aspectRatio_ = orthoSize.x_ / orthoSize.y_;
     frustumDirty_ = true;
     frustumDirty_ = true;
     projectionDirty_ = true;
     projectionDirty_ = true;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Camera::SetAspectRatio(float aspectRatio)
 void Camera::SetAspectRatio(float aspectRatio)
@@ -126,6 +131,7 @@ void Camera::SetAspectRatio(float aspectRatio)
     aspectRatio_ = aspectRatio;
     aspectRatio_ = aspectRatio;
     frustumDirty_ = true;
     frustumDirty_ = true;
     projectionDirty_ = true;
     projectionDirty_ = true;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Camera::SetZoom(float zoom)
 void Camera::SetZoom(float zoom)
@@ -133,21 +139,25 @@ void Camera::SetZoom(float zoom)
     zoom_ = Max(zoom, M_EPSILON);
     zoom_ = Max(zoom, M_EPSILON);
     frustumDirty_ = true;
     frustumDirty_ = true;
     projectionDirty_ = true;
     projectionDirty_ = true;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Camera::SetLodBias(float bias)
 void Camera::SetLodBias(float bias)
 {
 {
     lodBias_ = Max(bias, M_EPSILON);
     lodBias_ = Max(bias, M_EPSILON);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Camera::SetViewMask(unsigned mask)
 void Camera::SetViewMask(unsigned mask)
 {
 {
     viewMask_ = mask;
     viewMask_ = mask;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Camera::SetViewOverrideFlags(unsigned flags)
 void Camera::SetViewOverrideFlags(unsigned flags)
 {
 {
     viewOverrideFlags_ = flags;
     viewOverrideFlags_ = flags;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Camera::SetOrthographic(bool enable)
 void Camera::SetOrthographic(bool enable)
@@ -155,23 +165,27 @@ void Camera::SetOrthographic(bool enable)
     orthographic_ = enable;
     orthographic_ = enable;
     frustumDirty_ = true;
     frustumDirty_ = true;
     projectionDirty_ = true;
     projectionDirty_ = true;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Camera::SetAutoAspectRatio(bool enable)
 void Camera::SetAutoAspectRatio(bool enable)
 {
 {
     autoAspectRatio_ = enable;
     autoAspectRatio_ = enable;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Camera::SetProjectionOffset(const Vector2& offset)
 void Camera::SetProjectionOffset(const Vector2& offset)
 {
 {
     projectionOffset_ = offset;
     projectionOffset_ = offset;
     projectionDirty_ = true;
     projectionDirty_ = true;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Camera::SetFlipVertical(bool enable)
 void Camera::SetFlipVertical(bool enable)
 {
 {
     flipVertical_ = enable;
     flipVertical_ = enable;
     projectionDirty_ = true;
     projectionDirty_ = true;
+    MarkNetworkUpdate();
 }
 }
 
 
 float Camera::GetNearClip() const
 float Camera::GetNearClip() const

+ 12 - 0
Engine/Graphics/Drawable.cpp

@@ -115,31 +115,37 @@ void Drawable::DrawDebugGeometry(DebugRenderer* debug, bool depthTest)
 void Drawable::SetDrawDistance(float distance)
 void Drawable::SetDrawDistance(float distance)
 {
 {
     drawDistance_ = distance;
     drawDistance_ = distance;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Drawable::SetShadowDistance(float distance)
 void Drawable::SetShadowDistance(float distance)
 {
 {
     shadowDistance_ = distance;
     shadowDistance_ = distance;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Drawable::SetLodBias(float bias)
 void Drawable::SetLodBias(float bias)
 {
 {
     lodBias_ = Max(bias, M_EPSILON);
     lodBias_ = Max(bias, M_EPSILON);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Drawable::SetViewMask(unsigned mask)
 void Drawable::SetViewMask(unsigned mask)
 {
 {
     viewMask_ = mask;
     viewMask_ = mask;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Drawable::SetLightMask(unsigned mask)
 void Drawable::SetLightMask(unsigned mask)
 {
 {
     lightMask_ = mask;
     lightMask_ = mask;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Drawable::SetShadowMask(unsigned mask)
 void Drawable::SetShadowMask(unsigned mask)
 {
 {
     shadowMask_ = mask;
     shadowMask_ = mask;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Drawable::SetZoneMask(unsigned mask)
 void Drawable::SetZoneMask(unsigned mask)
@@ -147,26 +153,31 @@ void Drawable::SetZoneMask(unsigned mask)
     zoneMask_ = mask;
     zoneMask_ = mask;
     // Mark dirty to reset cached zone
     // Mark dirty to reset cached zone
     OnMarkedDirty(node_);
     OnMarkedDirty(node_);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Drawable::SetMaxLights(unsigned num)
 void Drawable::SetMaxLights(unsigned num)
 {
 {
     maxLights_ = num;
     maxLights_ = num;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Drawable::SetVisible(bool enable)
 void Drawable::SetVisible(bool enable)
 {
 {
     visible_ = enable;
     visible_ = enable;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Drawable::SetCastShadows(bool enable)
 void Drawable::SetCastShadows(bool enable)
 {
 {
     castShadows_ = enable;
     castShadows_ = enable;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Drawable::SetOccluder(bool enable)
 void Drawable::SetOccluder(bool enable)
 {
 {
     occluder_ = enable;
     occluder_ = enable;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Drawable::SetOccludee(bool enable)
 void Drawable::SetOccludee(bool enable)
@@ -177,6 +188,7 @@ void Drawable::SetOccludee(bool enable)
         // Reinsert to octree to make sure octant occlusion does not erroneously hide this drawable
         // Reinsert to octree to make sure octant occlusion does not erroneously hide this drawable
         if (octant_ && !reinsertionQueued_)
         if (octant_ && !reinsertionQueued_)
             octant_->GetRoot()->QueueReinsertion(this);
             octant_->GetRoot()->QueueReinsertion(this);
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 

+ 18 - 2
Engine/Graphics/Light.cpp

@@ -142,7 +142,7 @@ void Light::RegisterObject(Context* context)
 
 
 void Light::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 void Light::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 {
 {
-    Serializable::OnSetAttribute(attr, src);
+    Component::OnSetAttribute(attr, src);
     
     
     // Validate the bias, cascade & focus parameters
     // Validate the bias, cascade & focus parameters
     switch (attr.offset_)
     switch (attr.offset_)
@@ -266,11 +266,13 @@ void Light::SetLightType(LightType type)
 {
 {
     lightType_ = type;
     lightType_ = type;
     OnMarkedDirty(node_);
     OnMarkedDirty(node_);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetPerVertex(bool enable)
 void Light::SetPerVertex(bool enable)
 {
 {
     perVertex_ = enable;
     perVertex_ = enable;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetColor(const Color& color)
 void Light::SetColor(const Color& color)
@@ -278,82 +280,97 @@ void Light::SetColor(const Color& color)
     // Clamp RGB values to positive, as negative values behave erratically depending on whether the pass uses
     // Clamp RGB values to positive, as negative values behave erratically depending on whether the pass uses
     // replace or additive blend mode
     // replace or additive blend mode
     color_ = Color(Max(color.r_, 0.0f), Max(color.g_, 0.0f), Max(color.b_, 0.0f), 1.0f);
     color_ = Color(Max(color.r_, 0.0f), Max(color.g_, 0.0f), Max(color.b_, 0.0f), 1.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetRange(float range)
 void Light::SetRange(float range)
 {
 {
     range_ = Max(range, 0.0f);
     range_ = Max(range, 0.0f);
     OnMarkedDirty(node_);
     OnMarkedDirty(node_);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetFov(float fov)
 void Light::SetFov(float fov)
 {
 {
     fov_ = Clamp(fov, 0.0f, M_MAX_FOV);
     fov_ = Clamp(fov, 0.0f, M_MAX_FOV);
     OnMarkedDirty(node_);
     OnMarkedDirty(node_);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetAspectRatio(float aspectRatio)
 void Light::SetAspectRatio(float aspectRatio)
 {
 {
     aspectRatio_ = Max(aspectRatio, M_EPSILON);
     aspectRatio_ = Max(aspectRatio, M_EPSILON);
     OnMarkedDirty(node_);
     OnMarkedDirty(node_);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetShadowNearFarRatio(float nearFarRatio)
 void Light::SetShadowNearFarRatio(float nearFarRatio)
 {
 {
     shadowNearFarRatio_ = Clamp(nearFarRatio, 0.0f, 0.5f);
     shadowNearFarRatio_ = Clamp(nearFarRatio, 0.0f, 0.5f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetSpecularIntensity(float intensity)
 void Light::SetSpecularIntensity(float intensity)
 {
 {
     specularIntensity_ = Max(intensity, 0.0f);
     specularIntensity_ = Max(intensity, 0.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetFadeDistance(float distance)
 void Light::SetFadeDistance(float distance)
 {
 {
     fadeDistance_ = Max(distance, 0.0f);
     fadeDistance_ = Max(distance, 0.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetShadowBias(const BiasParameters& parameters)
 void Light::SetShadowBias(const BiasParameters& parameters)
 {
 {
     shadowBias_ = parameters;
     shadowBias_ = parameters;
     shadowBias_.Validate();
     shadowBias_.Validate();
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetShadowCascade(const CascadeParameters& parameters)
 void Light::SetShadowCascade(const CascadeParameters& parameters)
 {
 {
     shadowCascade_ = parameters;
     shadowCascade_ = parameters;
     shadowCascade_.Validate();
     shadowCascade_.Validate();
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetShadowFocus(const FocusParameters& parameters)
 void Light::SetShadowFocus(const FocusParameters& parameters)
 {
 {
     shadowFocus_ = parameters;
     shadowFocus_ = parameters;
     shadowFocus_.Validate();
     shadowFocus_.Validate();
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetShadowFadeDistance(float distance)
 void Light::SetShadowFadeDistance(float distance)
 {
 {
     shadowFadeDistance_ = Max(distance, 0.0f);
     shadowFadeDistance_ = Max(distance, 0.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetShadowIntensity(float intensity)
 void Light::SetShadowIntensity(float intensity)
 {
 {
     shadowIntensity_ = Clamp(intensity, 0.0f, 1.0f);
     shadowIntensity_ = Clamp(intensity, 0.0f, 1.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetShadowResolution(float resolution)
 void Light::SetShadowResolution(float resolution)
 {
 {
     shadowResolution_ = Clamp(resolution, 0.125f, 1.0f);
     shadowResolution_ = Clamp(resolution, 0.125f, 1.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetRampTexture(Texture* texture)
 void Light::SetRampTexture(Texture* texture)
 {
 {
     rampTexture_ = texture;
     rampTexture_ = texture;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Light::SetShapeTexture(Texture* texture)
 void Light::SetShapeTexture(Texture* texture)
 {
 {
     shapeTexture_ = texture;
     shapeTexture_ = texture;
+    MarkNetworkUpdate();
 }
 }
 
 
 Frustum Light::GetFrustum() const
 Frustum Light::GetFrustum() const
@@ -365,7 +382,6 @@ Frustum Light::GetFrustum() const
     return ret;
     return ret;
 }
 }
 
 
-
 Matrix3x4 Light::GetDirLightTransform(Camera* camera, bool getNearQuad)
 Matrix3x4 Light::GetDirLightTransform(Camera* camera, bool getNearQuad)
 {
 {
     if (!camera)
     if (!camera)

+ 1 - 1
Engine/Graphics/Octree.cpp

@@ -382,7 +382,7 @@ void Octree::RegisterObject(Context* context)
 void Octree::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 void Octree::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 {
 {
     // If any of the (size) attributes change, resize the octree
     // If any of the (size) attributes change, resize the octree
-    Serializable::OnSetAttribute(attr, src);
+    Component::OnSetAttribute(attr, src);
     Resize(worldBoundingBox_, numLevels_);
     Resize(worldBoundingBox_, numLevels_);
 }
 }
 
 

+ 2 - 0
Engine/Graphics/ParticleEmitter.cpp

@@ -347,6 +347,7 @@ bool ParticleEmitter::LoadParameters(XMLFile* file)
         textureAnimation_ = animations;
         textureAnimation_ = animations;
     }
     }
     
     
+    MarkNetworkUpdate();
     return true;
     return true;
 }
 }
 
 
@@ -356,6 +357,7 @@ void ParticleEmitter::SetActive(bool enable, bool resetPeriod)
     {
     {
         active_ = enable;
         active_ = enable;
         periodTimer_ = 0.0f;
         periodTimer_ = 0.0f;
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 

+ 5 - 0
Engine/Graphics/StaticModel.cpp

@@ -274,12 +274,15 @@ void StaticModel::SetModel(Model* model)
     
     
     SetBoundingBox(model->GetBoundingBox());
     SetBoundingBox(model->GetBoundingBox());
     ResetLodLevels();
     ResetLodLevels();
+    MarkNetworkUpdate();
 }
 }
 
 
 void StaticModel::SetMaterial(Material* material)
 void StaticModel::SetMaterial(Material* material)
 {
 {
     for (unsigned i = 0; i < materials_.Size(); ++i)
     for (unsigned i = 0; i < materials_.Size(); ++i)
         materials_[i] = material;
         materials_[i] = material;
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 bool StaticModel::SetMaterial(unsigned index, Material* material)
 bool StaticModel::SetMaterial(unsigned index, Material* material)
@@ -291,12 +294,14 @@ bool StaticModel::SetMaterial(unsigned index, Material* material)
     }
     }
     
     
     materials_[index] = material;
     materials_[index] = material;
+    MarkNetworkUpdate();
     return true;
     return true;
 }
 }
 
 
 void StaticModel::SetSoftwareLodLevel(unsigned level)
 void StaticModel::SetSoftwareLodLevel(unsigned level)
 {
 {
     softwareLodLevel_ = level;
     softwareLodLevel_ = level;
+    MarkNetworkUpdate();
 }
 }
 
 
 Material* StaticModel::GetMaterial(unsigned index) const
 Material* StaticModel::GetMaterial(unsigned index) const

+ 8 - 8
Engine/Graphics/View.cpp

@@ -790,8 +790,8 @@ void View::GetBatches()
                     ShadowBatchQueue& shadowQueue = lightQueue.shadowSplits_[j];
                     ShadowBatchQueue& shadowQueue = lightQueue.shadowSplits_[j];
                     Camera* shadowCamera = split.shadowCamera_;
                     Camera* shadowCamera = split.shadowCamera_;
                     shadowQueue.shadowCamera_ = shadowCamera;
                     shadowQueue.shadowCamera_ = shadowCamera;
-                    shadowQueue.nearSplit_ = split.shadowNearSplit_;
-                    shadowQueue.farSplit_ = split.shadowFarSplit_;
+                    shadowQueue.nearSplit_ = split.nearSplit_;
+                    shadowQueue.farSplit_ = split.farSplit_;
                     
                     
                     // Setup the shadow split viewport and finalize shadow camera parameters
                     // Setup the shadow split viewport and finalize shadow camera parameters
                     shadowQueue.shadowViewport_ = GetShadowMapViewport(light, j, lightQueue.shadowMap_);
                     shadowQueue.shadowViewport_ = GetShadowMapViewport(light, j, lightQueue.shadowMap_);
@@ -1853,9 +1853,9 @@ void View::ProcessShadowSplit(LightQueryResult& query, unsigned splitIndex, unsi
     // For directional light check that the split is inside the visible scene: if not, can skip the split
     // For directional light check that the split is inside the visible scene: if not, can skip the split
     if (type == LIGHT_DIRECTIONAL)
     if (type == LIGHT_DIRECTIONAL)
     {
     {
-        if (sceneViewBox_.min_.z_ > split.shadowFarSplit_)
+        if (sceneViewBox_.min_.z_ > split.farSplit_)
             return;
             return;
-        if (sceneViewBox_.max_.z_ < split.shadowNearSplit_)
+        if (sceneViewBox_.max_.z_ < split.nearSplit_)
             return;
             return;
     }
     }
     
     
@@ -1892,8 +1892,8 @@ void View::ProcessShadowCasters(LightQueryResult& query, const PODVector<Drawabl
     if (type != LIGHT_DIRECTIONAL)
     if (type != LIGHT_DIRECTIONAL)
         lightViewFrustum = sceneFrustum_.Transformed(lightView);
         lightViewFrustum = sceneFrustum_.Transformed(lightView);
     else
     else
-        lightViewFrustum = camera_->GetSplitFrustum(Max(sceneViewBox_.min_.z_, split.shadowNearSplit_),
-            Min(sceneViewBox_.max_.z_, split.shadowFarSplit_)).Transformed(lightView);
+        lightViewFrustum = camera_->GetSplitFrustum(Max(sceneViewBox_.min_.z_, split.nearSplit_),
+            Min(sceneViewBox_.max_.z_, split.farSplit_)).Transformed(lightView);
     
     
     BoundingBox lightViewFrustumBox(lightViewFrustum);
     BoundingBox lightViewFrustumBox(lightViewFrustum);
      
      
@@ -2055,8 +2055,8 @@ void View::SetupShadowCameras(LightQueryResult& query)
             ShadowQueryResult& split = query.shadowSplits_[i];
             ShadowQueryResult& split = query.shadowSplits_[i];
             Camera* shadowCamera = renderer_->GetShadowCamera();
             Camera* shadowCamera = renderer_->GetShadowCamera();
             split.shadowCamera_ = shadowCamera;
             split.shadowCamera_ = shadowCamera;
-            split.shadowNearSplit_ = nearSplit;
-            split.shadowFarSplit_ = farSplit;
+            split.nearSplit_ = nearSplit;
+            split.farSplit_ = farSplit;
             SetupDirLightShadowCamera(shadowCamera, light, nearSplit, farSplit);
             SetupDirLightShadowCamera(shadowCamera, light, nearSplit, farSplit);
             
             
             nearSplit = farSplit;
             nearSplit = farSplit;

+ 2 - 2
Engine/Graphics/View.h

@@ -61,9 +61,9 @@ struct ShadowQueryResult
     /// Combined bounding box of the shadow casters in light view or projection space.
     /// Combined bounding box of the shadow casters in light view or projection space.
     BoundingBox shadowCasterBox_;
     BoundingBox shadowCasterBox_;
     /// Directional light shadow near split distance.
     /// Directional light shadow near split distance.
-    float shadowNearSplit_;
+    float nearSplit_;
     /// Directional light shadow far split distance.
     /// Directional light shadow far split distance.
-    float shadowFarSplit_;
+    float farSplit_;
 };
 };
 
 
 /// Intermediate light processing result.
 /// Intermediate light processing result.

+ 9 - 1
Engine/Graphics/Zone.cpp

@@ -78,7 +78,7 @@ void Zone::RegisterObject(Context* context)
 
 
 void Zone::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 void Zone::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 {
 {
-    Serializable::OnSetAttribute(attr, src);
+    Component::OnSetAttribute(attr, src);
     
     
     // If bounding box, override mode, visibility or priority changes, dirty the drawable as applicable
     // If bounding box, override mode, visibility or priority changes, dirty the drawable as applicable
     switch (attr.offset_)
     switch (attr.offset_)
@@ -102,16 +102,19 @@ void Zone::SetBoundingBox(const BoundingBox& box)
 {
 {
     boundingBox_ = box;
     boundingBox_ = box;
     OnMarkedDirty(node_);
     OnMarkedDirty(node_);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Zone::SetAmbientColor(const Color& color)
 void Zone::SetAmbientColor(const Color& color)
 {
 {
     ambientColor_ = Color(color, 1.0f);
     ambientColor_ = Color(color, 1.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Zone::SetFogColor(const Color& color)
 void Zone::SetFogColor(const Color& color)
 {
 {
     fogColor_ = Color(color, 1.0f);
     fogColor_ = Color(color, 1.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void Zone::SetFogStart(float start)
 void Zone::SetFogStart(float start)
@@ -120,6 +123,7 @@ void Zone::SetFogStart(float start)
         start = 0.0f;
         start = 0.0f;
     
     
     fogStart_ = start;
     fogStart_ = start;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Zone::SetFogEnd(float end)
 void Zone::SetFogEnd(float end)
@@ -128,21 +132,25 @@ void Zone::SetFogEnd(float end)
         end = 0.0f;
         end = 0.0f;
     
     
     fogEnd_ = end;
     fogEnd_ = end;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Zone::SetPriority(int priority)
 void Zone::SetPriority(int priority)
 {
 {
     priority_ = priority;
     priority_ = priority;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Zone::SetOverride(bool enable)
 void Zone::SetOverride(bool enable)
 {
 {
     override_ = enable;
     override_ = enable;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Zone::SetAmbientGradient(bool enable)
 void Zone::SetAmbientGradient(bool enable)
 {
 {
     ambientGradient_ = enable;
     ambientGradient_ = enable;
+    MarkNetworkUpdate();
 }
 }
 
 
 const Color& Zone::GetAmbientStartColor()
 const Color& Zone::GetAmbientStartColor()

+ 5 - 8
Engine/Network/Connection.cpp

@@ -496,13 +496,12 @@ void Connection::ProcessSceneUpdate(int msgID, MemoryBuffer& msg)
             
             
             // Read initial user variables
             // Read initial user variables
             unsigned numVars = msg.ReadVLE();
             unsigned numVars = msg.ReadVLE();
-            VariantMap& vars = node->GetVars();
+            const VariantMap& vars = node->GetVars();
             while (numVars)
             while (numVars)
             {
             {
-                --numVars;
-                
                 ShortStringHash key = msg.ReadShortStringHash();
                 ShortStringHash key = msg.ReadShortStringHash();
-                vars[key] = msg.ReadVariant();
+                node->SetVar(key, msg.ReadVariant());
+                --numVars;
             }
             }
             
             
             // Read components
             // Read components
@@ -547,13 +546,11 @@ void Connection::ProcessSceneUpdate(int msgID, MemoryBuffer& msg)
                 // ApplyAttributes() is deliberately skipped, as Node has no attributes that require late applying.
                 // ApplyAttributes() is deliberately skipped, as Node has no attributes that require late applying.
                 // Furthermore it would propagate to components and child nodes, which is not desired in this case
                 // Furthermore it would propagate to components and child nodes, which is not desired in this case
                 unsigned changedVars = msg.ReadVLE();
                 unsigned changedVars = msg.ReadVLE();
-                VariantMap& vars = node->GetVars();
                 while (changedVars)
                 while (changedVars)
                 {
                 {
-                    --changedVars;
-                    
                     ShortStringHash key = msg.ReadShortStringHash();
                     ShortStringHash key = msg.ReadShortStringHash();
-                    vars[key] = msg.ReadVariant();
+                    node->SetVar(key, msg.ReadVariant());
+                    --changedVars;
                 }
                 }
             }
             }
             else
             else

+ 4 - 0
Engine/Network/NetworkPriority.cpp

@@ -60,21 +60,25 @@ void NetworkPriority::RegisterObject(Context* context)
 void NetworkPriority::SetBasePriority(float priority)
 void NetworkPriority::SetBasePriority(float priority)
 {
 {
     basePriority_ = Max(priority, 0.0f);
     basePriority_ = Max(priority, 0.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void NetworkPriority::SetDistanceFactor(float factor)
 void NetworkPriority::SetDistanceFactor(float factor)
 {
 {
     distanceFactor_ = Max(factor, 0.0f);
     distanceFactor_ = Max(factor, 0.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void NetworkPriority::SetMinPriority(float priority)
 void NetworkPriority::SetMinPriority(float priority)
 {
 {
     minPriority_ = Max(priority, 0.0f);
     minPriority_ = Max(priority, 0.0f);
+    MarkNetworkUpdate();
 }
 }
 
 
 void NetworkPriority::SetAlwaysUpdateOwner(bool enable)
 void NetworkPriority::SetAlwaysUpdateOwner(bool enable)
 {
 {
     alwaysUpdateOwner_ = enable;
     alwaysUpdateOwner_ = enable;
+    MarkNetworkUpdate();
 }
 }
 
 
 bool NetworkPriority::CheckUpdate(float distance, float& accumulator)
 bool NetworkPriority::CheckUpdate(float distance, float& accumulator)

+ 17 - 1
Engine/Physics/CollisionShape.cpp

@@ -236,7 +236,7 @@ void CollisionShape::RegisterObject(Context* context)
 
 
 void CollisionShape::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 void CollisionShape::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 {
 {
-    Serializable::OnSetAttribute(attr, src);
+    Component::OnSetAttribute(attr, src);
     dirty_ = true;
     dirty_ = true;
 }
 }
 
 
@@ -260,6 +260,7 @@ void CollisionShape::SetBox(const Vector3& size, const Vector3& position, const
     
     
     UpdateShape();
     UpdateShape();
     NotifyRigidBody();
     NotifyRigidBody();
+    MarkNetworkUpdate();
 }
 }
 
 
 void CollisionShape::SetSphere(float diameter, const Vector3& position, const Quaternion& rotation)
 void CollisionShape::SetSphere(float diameter, const Vector3& position, const Quaternion& rotation)
@@ -272,6 +273,7 @@ void CollisionShape::SetSphere(float diameter, const Vector3& position, const Qu
     
     
     UpdateShape();
     UpdateShape();
     NotifyRigidBody();
     NotifyRigidBody();
+    MarkNetworkUpdate();
 }
 }
 
 
 void CollisionShape::SetCylinder(float diameter, float height, const Vector3& position, const Quaternion& rotation)
 void CollisionShape::SetCylinder(float diameter, float height, const Vector3& position, const Quaternion& rotation)
@@ -284,6 +286,7 @@ void CollisionShape::SetCylinder(float diameter, float height, const Vector3& po
     
     
     UpdateShape();
     UpdateShape();
     NotifyRigidBody();
     NotifyRigidBody();
+    MarkNetworkUpdate();
 }
 }
 
 
 void CollisionShape::SetCapsule(float diameter, float height, const Vector3& position, const Quaternion& rotation)
 void CollisionShape::SetCapsule(float diameter, float height, const Vector3& position, const Quaternion& rotation)
@@ -296,6 +299,7 @@ void CollisionShape::SetCapsule(float diameter, float height, const Vector3& pos
     
     
     UpdateShape();
     UpdateShape();
     NotifyRigidBody();
     NotifyRigidBody();
+    MarkNetworkUpdate();
 }
 }
 
 
 void CollisionShape::SetCone(float diameter, float height, const Vector3& position, const Quaternion& rotation)
 void CollisionShape::SetCone(float diameter, float height, const Vector3& position, const Quaternion& rotation)
@@ -308,6 +312,7 @@ void CollisionShape::SetCone(float diameter, float height, const Vector3& positi
     
     
     UpdateShape();
     UpdateShape();
     NotifyRigidBody();
     NotifyRigidBody();
+    MarkNetworkUpdate();
 }
 }
 
 
 void CollisionShape::SetTriangleMesh(Model* model, unsigned lodLevel, const Vector3& scale, const Vector3& position, const Quaternion& rotation)
 void CollisionShape::SetTriangleMesh(Model* model, unsigned lodLevel, const Vector3& scale, const Vector3& position, const Quaternion& rotation)
@@ -327,6 +332,7 @@ void CollisionShape::SetTriangleMesh(Model* model, unsigned lodLevel, const Vect
     
     
     UpdateShape();
     UpdateShape();
     NotifyRigidBody();
     NotifyRigidBody();
+    MarkNetworkUpdate();
 }
 }
 
 
 void CollisionShape::SetConvexHull(Model* model, unsigned lodLevel, const Vector3& scale, const Vector3& position, const Quaternion& rotation)
 void CollisionShape::SetConvexHull(Model* model, unsigned lodLevel, const Vector3& scale, const Vector3& position, const Quaternion& rotation)
@@ -346,6 +352,7 @@ void CollisionShape::SetConvexHull(Model* model, unsigned lodLevel, const Vector
     
     
     UpdateShape();
     UpdateShape();
     NotifyRigidBody();
     NotifyRigidBody();
+    MarkNetworkUpdate();
 }
 }
 
 
 void CollisionShape::SetShapeType(ShapeType type)
 void CollisionShape::SetShapeType(ShapeType type)
@@ -355,6 +362,7 @@ void CollisionShape::SetShapeType(ShapeType type)
         shapeType_ = type;
         shapeType_ = type;
         UpdateShape();
         UpdateShape();
         NotifyRigidBody();
         NotifyRigidBody();
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -365,6 +373,7 @@ void CollisionShape::SetSize(const Vector3& size)
         size_ = size;
         size_ = size;
         UpdateShape();
         UpdateShape();
         NotifyRigidBody();
         NotifyRigidBody();
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -374,6 +383,7 @@ void CollisionShape::SetPosition(const Vector3& position)
     {
     {
         position_ = position;
         position_ = position;
         NotifyRigidBody();
         NotifyRigidBody();
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -383,6 +393,7 @@ void CollisionShape::SetRotation(const Quaternion& rotation)
     {
     {
         rotation_ = rotation;
         rotation_ = rotation;
         NotifyRigidBody();
         NotifyRigidBody();
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -393,6 +404,7 @@ void CollisionShape::SetTransform(const Vector3& position, const Quaternion& rot
         position_ = position;
         position_ = position;
         rotation_ = rotation;
         rotation_ = rotation;
         NotifyRigidBody();
         NotifyRigidBody();
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -405,6 +417,7 @@ void CollisionShape::SetMargin(float margin)
         if (shape_)
         if (shape_)
             shape_->setMargin(margin);
             shape_->setMargin(margin);
         margin_ = margin;
         margin_ = margin;
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -418,6 +431,7 @@ void CollisionShape::SetModel(Model* model)
             UpdateShape();
             UpdateShape();
             NotifyRigidBody();
             NotifyRigidBody();
         }
         }
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -431,6 +445,7 @@ void CollisionShape::SetLodLevel(unsigned lodLevel)
             UpdateShape();
             UpdateShape();
             NotifyRigidBody();
             NotifyRigidBody();
         }
         }
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -483,6 +498,7 @@ void CollisionShape::SetModelAttr(ResourceRef value)
     ResourceCache* cache = GetSubsystem<ResourceCache>();
     ResourceCache* cache = GetSubsystem<ResourceCache>();
     model_ = cache->GetResource<Model>(value.id_);
     model_ = cache->GetResource<Model>(value.id_);
     dirty_ = true;
     dirty_ = true;
+    MarkNetworkUpdate();
 }
 }
 
 
 ResourceRef CollisionShape::GetModelAttr() const
 ResourceRef CollisionShape::GetModelAttr() const

+ 1 - 1
Engine/Physics/Joint.cpp

@@ -72,7 +72,7 @@ void Joint::RegisterObject(Context* context)
 
 
 void Joint::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 void Joint::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 {
 {
-    Serializable::OnSetAttribute(attr, src);
+    Component::OnSetAttribute(attr, src);
     
     
     // Change of the joint type or connected body requires the joint to be recreated
     // Change of the joint type or connected body requires the joint to be recreated
     if (attr.offset_ == offsetof(Joint, type_) || attr.offset_ == offsetof(Joint, otherBodyNodeID_))
     if (attr.offset_ == offsetof(Joint, type_) || attr.offset_ == offsetof(Joint, otherBodyNodeID_))

+ 50 - 1
Engine/Physics/RigidBody.cpp

@@ -119,7 +119,7 @@ void RigidBody::RegisterObject(Context* context)
 
 
 void RigidBody::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 void RigidBody::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
 {
 {
-    Serializable::OnSetAttribute(attr, src);
+    Component::OnSetAttribute(attr, src);
     dirty_ = true;
     dirty_ = true;
 }
 }
 
 
@@ -163,6 +163,8 @@ void RigidBody::setWorldTransform(const btTransform &worldTrans)
         delayed.worldRotation_ = newWorldRotation;
         delayed.worldRotation_ = newWorldRotation;
         physicsWorld_->AddDelayedWorldTransform(delayed);
         physicsWorld_->AddDelayedWorldTransform(delayed);
     }
     }
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 void RigidBody::SetMass(float mass)
 void RigidBody::SetMass(float mass)
@@ -173,6 +175,7 @@ void RigidBody::SetMass(float mass)
     {
     {
         mass_ = mass;
         mass_ = mass;
         AddBodyToWorld();
         AddBodyToWorld();
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -187,6 +190,8 @@ void RigidBody::SetPosition(Vector3 position)
         btTransform interpTrans = body_->getInterpolationWorldTransform();
         btTransform interpTrans = body_->getInterpolationWorldTransform();
         interpTrans.setOrigin(worldTrans.getOrigin());
         interpTrans.setOrigin(worldTrans.getOrigin());
         body_->setInterpolationWorldTransform(interpTrans);
         body_->setInterpolationWorldTransform(interpTrans);
+        
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -201,6 +206,8 @@ void RigidBody::SetRotation(Quaternion rotation)
         btTransform interpTrans = body_->getInterpolationWorldTransform();
         btTransform interpTrans = body_->getInterpolationWorldTransform();
         interpTrans.setRotation(worldTrans.getRotation());
         interpTrans.setRotation(worldTrans.getRotation());
         body_->setInterpolationWorldTransform(interpTrans);
         body_->setInterpolationWorldTransform(interpTrans);
+        
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -217,6 +224,8 @@ void RigidBody::SetTransform(const Vector3& position, const Quaternion& rotation
         interpTrans.setOrigin(worldTrans.getOrigin());
         interpTrans.setOrigin(worldTrans.getOrigin());
         interpTrans.setRotation(worldTrans.getRotation());
         interpTrans.setRotation(worldTrans.getRotation());
         body_->setInterpolationWorldTransform(interpTrans);
         body_->setInterpolationWorldTransform(interpTrans);
+        
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -227,25 +236,35 @@ void RigidBody::SetLinearVelocity(Vector3 velocity)
         body_->setLinearVelocity(ToBtVector3(velocity));
         body_->setLinearVelocity(ToBtVector3(velocity));
         if (velocity != Vector3::ZERO)
         if (velocity != Vector3::ZERO)
             Activate();
             Activate();
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
 void RigidBody::SetLinearFactor(Vector3 factor)
 void RigidBody::SetLinearFactor(Vector3 factor)
 {
 {
     if (body_)
     if (body_)
+    {
         body_->setLinearFactor(ToBtVector3(factor));
         body_->setLinearFactor(ToBtVector3(factor));
+        MarkNetworkUpdate();
+    }
 }
 }
 
 
 void RigidBody::SetLinearRestThreshold(float threshold)
 void RigidBody::SetLinearRestThreshold(float threshold)
 {
 {
     if (body_)
     if (body_)
+    {
         body_->setSleepingThresholds(threshold, body_->getAngularSleepingThreshold());
         body_->setSleepingThresholds(threshold, body_->getAngularSleepingThreshold());
+        MarkNetworkUpdate();
+    }
 }
 }
 
 
 void RigidBody::SetLinearDamping(float damping)
 void RigidBody::SetLinearDamping(float damping)
 {
 {
     if (body_)
     if (body_)
+    {
         body_->setDamping(damping, body_->getAngularDamping());
         body_->setDamping(damping, body_->getAngularDamping());
+        MarkNetworkUpdate();
+    }
 }
 }
 
 
 void RigidBody::SetAngularVelocity(Vector3 velocity)
 void RigidBody::SetAngularVelocity(Vector3 velocity)
@@ -255,51 +274,73 @@ void RigidBody::SetAngularVelocity(Vector3 velocity)
         body_->setAngularVelocity(ToBtVector3(velocity));
         body_->setAngularVelocity(ToBtVector3(velocity));
         if (velocity != Vector3::ZERO)
         if (velocity != Vector3::ZERO)
             Activate();
             Activate();
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
 void RigidBody::SetAngularFactor(Vector3 factor)
 void RigidBody::SetAngularFactor(Vector3 factor)
 {
 {
     if (body_)
     if (body_)
+    {
         body_->setAngularFactor(ToBtVector3(factor));
         body_->setAngularFactor(ToBtVector3(factor));
+        MarkNetworkUpdate();
+    }
 }
 }
 
 
 void RigidBody::SetAngularRestThreshold(float threshold)
 void RigidBody::SetAngularRestThreshold(float threshold)
 {
 {
     if (body_)
     if (body_)
+    {
         body_->setSleepingThresholds(body_->getLinearSleepingThreshold(), threshold);
         body_->setSleepingThresholds(body_->getLinearSleepingThreshold(), threshold);
+        MarkNetworkUpdate();
+    }
 }
 }
 
 
 void RigidBody::SetAngularDamping(float damping)
 void RigidBody::SetAngularDamping(float damping)
 {
 {
     if (body_)
     if (body_)
+    {
         body_->setDamping(body_->getLinearDamping(), damping);
         body_->setDamping(body_->getLinearDamping(), damping);
+        MarkNetworkUpdate();
+    }
 }
 }
 
 
 void RigidBody::SetFriction(float friction)
 void RigidBody::SetFriction(float friction)
 {
 {
     if (body_)
     if (body_)
+    {
         body_->setFriction(friction);
         body_->setFriction(friction);
+        MarkNetworkUpdate();
+    }
 }
 }
 
 
 void RigidBody::SetRestitution(float restitution)
 void RigidBody::SetRestitution(float restitution)
 {
 {
     if (body_)
     if (body_)
+    {
         body_->setRestitution(restitution);
         body_->setRestitution(restitution);
+        MarkNetworkUpdate();
+    }
 }
 }
 
 
 void RigidBody::SetCcdRadius(float radius)
 void RigidBody::SetCcdRadius(float radius)
 {
 {
     radius = Max(radius, 0.0f);
     radius = Max(radius, 0.0f);
     if (body_)
     if (body_)
+    {
         body_->setCcdSweptSphereRadius(radius);
         body_->setCcdSweptSphereRadius(radius);
+        MarkNetworkUpdate();
+    }
 }
 }
 
 
 void RigidBody::SetCcdMotionThreshold(float threshold)
 void RigidBody::SetCcdMotionThreshold(float threshold)
 {
 {
     threshold = Max(threshold, 0.0f);
     threshold = Max(threshold, 0.0f);
     if (body_)
     if (body_)
+    {
         body_->setCcdMotionThreshold(threshold);
         body_->setCcdMotionThreshold(threshold);
+        MarkNetworkUpdate();
+    }
 }
 }
 
 
 void RigidBody::SetUseGravity(bool enable)
 void RigidBody::SetUseGravity(bool enable)
@@ -319,6 +360,8 @@ void RigidBody::SetUseGravity(bool enable)
             body_->setGravity(world->getGravity());
             body_->setGravity(world->getGravity());
         else
         else
             body_->setGravity(btVector3(0.0f, 0.0f, 0.0f));
             body_->setGravity(btVector3(0.0f, 0.0f, 0.0f));
+        
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -328,6 +371,7 @@ void RigidBody::SetKinematic(bool enable)
     {
     {
         kinematic_ = enable;
         kinematic_ = enable;
         AddBodyToWorld();
         AddBodyToWorld();
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -337,6 +381,7 @@ void RigidBody::SetPhantom(bool enable)
     {
     {
         phantom_ = enable;
         phantom_ = enable;
         AddBodyToWorld();
         AddBodyToWorld();
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -346,6 +391,7 @@ void RigidBody::SetCollisionLayer(unsigned layer)
     {
     {
         collisionLayer_ = layer;
         collisionLayer_ = layer;
         AddBodyToWorld();
         AddBodyToWorld();
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -355,6 +401,7 @@ void RigidBody::SetCollisionMask(unsigned mask)
     {
     {
         collisionMask_ = mask;
         collisionMask_ = mask;
         AddBodyToWorld();
         AddBodyToWorld();
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
@@ -365,12 +412,14 @@ void RigidBody::SetCollisionLayerAndMask(unsigned layer, unsigned mask)
         collisionLayer_ = layer;
         collisionLayer_ = layer;
         collisionMask_ = mask;
         collisionMask_ = mask;
         AddBodyToWorld();
         AddBodyToWorld();
+        MarkNetworkUpdate();
     }
     }
 }
 }
 
 
 void RigidBody::SetCollisionEventMode(CollisionEventMode mode)
 void RigidBody::SetCollisionEventMode(CollisionEventMode mode)
 {
 {
     collisionEventMode_ = mode;
     collisionEventMode_ = mode;
+    MarkNetworkUpdate();
 }
 }
 
 
 void RigidBody::ApplyForce(const Vector3& force)
 void RigidBody::ApplyForce(const Vector3& force)

+ 13 - 1
Engine/Scene/Component.cpp

@@ -24,8 +24,8 @@
 #include "Precompiled.h"
 #include "Precompiled.h"
 #include "Component.h"
 #include "Component.h"
 #include "Context.h"
 #include "Context.h"
-#include "Node.h"
 #include "ReplicationState.h"
 #include "ReplicationState.h"
+#include "Scene.h"
 #include "XMLElement.h"
 #include "XMLElement.h"
 
 
 #include "DebugNew.h"
 #include "DebugNew.h"
@@ -43,6 +43,12 @@ Component::~Component()
 {
 {
 }
 }
 
 
+void Component::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
+{
+    Serializable::OnSetAttribute(attr, src);
+    MarkNetworkUpdate();
+}
+
 bool Component::Save(Serializer& dest)
 bool Component::Save(Serializer& dest)
 {
 {
     // Write type and ID
     // Write type and ID
@@ -141,6 +147,12 @@ void Component::CleanupConnection(Connection* connection)
     }
     }
 }
 }
 
 
+void Component::MarkNetworkUpdate()
+{
+    if (id_ < FIRST_LOCAL_ID && node_)
+        node_->MarkNetworkUpdate();
+}
+
 void Component::SetID(unsigned id)
 void Component::SetID(unsigned id)
 {
 {
     id_ = id;
     id_ = id;

+ 4 - 0
Engine/Scene/Component.h

@@ -45,6 +45,8 @@ public:
     /// Destruct.
     /// Destruct.
     virtual ~Component();
     virtual ~Component();
     
     
+    /// Handle attribute write access.
+    virtual void OnSetAttribute(const AttributeInfo& attr, const Variant& src);
     /// Save as binary data. Return true if successful.
     /// Save as binary data. Return true if successful.
     virtual bool Save(Serializer& dest);
     virtual bool Save(Serializer& dest);
     /// Save as XML data. Return true if successful.
     /// Save as XML data. Return true if successful.
@@ -84,6 +86,8 @@ public:
     void PrepareNetworkUpdate();
     void PrepareNetworkUpdate();
     /// Clean up all references to a network connection that is about to be removed.
     /// Clean up all references to a network connection that is about to be removed.
     void CleanupConnection(Connection* connection);
     void CleanupConnection(Connection* connection);
+    /// Mark for attribute check on the next network update.
+    void MarkNetworkUpdate();
     
     
 protected:
 protected:
     /// Handle scene node being assigned at creation.
     /// Handle scene node being assigned at creation.

+ 76 - 11
Engine/Scene/Node.cpp

@@ -50,7 +50,8 @@ Node::Node(Context* context) :
     scale_(Vector3::ONE),
     scale_(Vector3::ONE),
     worldTransform_(Matrix3x4::IDENTITY),
     worldTransform_(Matrix3x4::IDENTITY),
     rotateCount_(0),
     rotateCount_(0),
-    dirty_(false)
+    dirty_(false),
+    networkUpdate_(false)
 {
 {
 }
 }
 
 
@@ -98,6 +99,12 @@ void Node::OnEvent(Object* sender, bool broadcast, StringHash eventType, Variant
         Object::OnEvent(sender, broadcast, eventType, eventData);
         Object::OnEvent(sender, broadcast, eventType, eventData);
 }
 }
 
 
+void Node::OnSetAttribute(const AttributeInfo& attr, const Variant& src)
+{
+    Serializable::OnSetAttribute(attr, src);
+    MarkNetworkUpdate();
+}
+
 bool Node::Load(Deserializer& source)
 bool Node::Load(Deserializer& source)
 {
 {
     SceneResolver resolver;
     SceneResolver resolver;
@@ -230,6 +237,8 @@ void Node::SetName(const String& name)
 {
 {
     name_ = name;
     name_ = name;
     nameHash_ = StringHash(name);
     nameHash_ = StringHash(name);
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 void Node::SetPosition(const Vector3& position)
 void Node::SetPosition(const Vector3& position)
@@ -237,15 +246,18 @@ void Node::SetPosition(const Vector3& position)
     position_ = position;
     position_ = position;
     if (!dirty_)
     if (!dirty_)
         MarkDirty();
         MarkDirty();
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 void Node::SetRotation(const Quaternion& rotation)
 void Node::SetRotation(const Quaternion& rotation)
 {
 {
     rotation_ = rotation;
     rotation_ = rotation;
+    rotateCount_ = 0;
     if (!dirty_)
     if (!dirty_)
         MarkDirty();
         MarkDirty();
     
     
-    rotateCount_ = 0;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Node::SetDirection(const Vector3& direction)
 void Node::SetDirection(const Vector3& direction)
@@ -258,6 +270,8 @@ void Node::SetScale(float scale)
     scale_ = Vector3(scale, scale, scale).Abs();
     scale_ = Vector3(scale, scale, scale).Abs();
     if (!dirty_)
     if (!dirty_)
         MarkDirty();
         MarkDirty();
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 void Node::SetScale(const Vector3& scale)
 void Node::SetScale(const Vector3& scale)
@@ -265,38 +279,43 @@ void Node::SetScale(const Vector3& scale)
     scale_ = scale.Abs();
     scale_ = scale.Abs();
     if (!dirty_)
     if (!dirty_)
         MarkDirty();
         MarkDirty();
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 void Node::SetTransform(const Vector3& position, const Quaternion& rotation)
 void Node::SetTransform(const Vector3& position, const Quaternion& rotation)
 {
 {
     position_ = position;
     position_ = position;
     rotation_ = rotation;
     rotation_ = rotation;
+    rotateCount_ = 0;
     if (!dirty_)
     if (!dirty_)
         MarkDirty();
         MarkDirty();
     
     
-    rotateCount_ = 0;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Node::SetTransform(const Vector3& position, const Quaternion& rotation, float scale)
 void Node::SetTransform(const Vector3& position, const Quaternion& rotation, float scale)
 {
 {
     position_ = position;
     position_ = position;
     rotation_ = rotation;
     rotation_ = rotation;
+    rotateCount_ = 0;
     scale_ = Vector3(scale, scale, scale);
     scale_ = Vector3(scale, scale, scale);
     if (!dirty_)
     if (!dirty_)
         MarkDirty();
         MarkDirty();
     
     
-    rotateCount_ = 0;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Node::SetTransform(const Vector3& position, const Quaternion& rotation, const Vector3& scale)
 void Node::SetTransform(const Vector3& position, const Quaternion& rotation, const Vector3& scale)
 {
 {
     position_ = position;
     position_ = position;
     rotation_ = rotation;
     rotation_ = rotation;
+    rotateCount_ = 0;
     scale_ = scale;
     scale_ = scale;
     if (!dirty_)
     if (!dirty_)
         MarkDirty();
         MarkDirty();
     
     
-    rotateCount_ = 0;
+    MarkNetworkUpdate();
 }
 }
 
 
 void Node::SetWorldPosition(const Vector3& position)
 void Node::SetWorldPosition(const Vector3& position)
@@ -370,6 +389,8 @@ void Node::Translate(const Vector3& delta)
     position_ += delta;
     position_ += delta;
     if (!dirty_)
     if (!dirty_)
         MarkDirty();
         MarkDirty();
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 void Node::TranslateRelative(const Vector3& delta)
 void Node::TranslateRelative(const Vector3& delta)
@@ -377,6 +398,8 @@ void Node::TranslateRelative(const Vector3& delta)
     position_ += rotation_ * delta;
     position_ += rotation_ * delta;
     if (!dirty_)
     if (!dirty_)
         MarkDirty();
         MarkDirty();
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 void Node::Rotate(const Quaternion& delta, bool fixedAxis)
 void Node::Rotate(const Quaternion& delta, bool fixedAxis)
@@ -395,6 +418,8 @@ void Node::Rotate(const Quaternion& delta, bool fixedAxis)
     
     
     if (!dirty_)
     if (!dirty_)
         MarkDirty();
         MarkDirty();
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 void Node::Yaw(float angle, bool fixedAxis)
 void Node::Yaw(float angle, bool fixedAxis)
@@ -434,6 +459,8 @@ void Node::Scale(float scale)
     scale_ *= scale;
     scale_ *= scale;
     if (!dirty_)
     if (!dirty_)
         MarkDirty();
         MarkDirty();
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 void Node::Scale(const Vector3& scale)
 void Node::Scale(const Vector3& scale)
@@ -441,6 +468,8 @@ void Node::Scale(const Vector3& scale)
     scale_ *= scale;
     scale_ *= scale;
     if (!dirty_)
     if (!dirty_)
         MarkDirty();
         MarkDirty();
+    
+    MarkNetworkUpdate();
 }
 }
 
 
 void Node::SetOwner(Connection* owner)
 void Node::SetOwner(Connection* owner)
@@ -502,6 +531,7 @@ void Node::AddChild(Node* node)
     
     
     node->parent_ = this;
     node->parent_ = this;
     node->MarkDirty();
     node->MarkDirty();
+    node->MarkNetworkUpdate();
 }
 }
 
 
 void Node::RemoveChild(Node* node)
 void Node::RemoveChild(Node* node)
@@ -622,6 +652,12 @@ void Node::SetParent(Node* parent)
     }
     }
 }
 }
 
 
+void Node::SetVar(ShortStringHash key, const Variant& value)
+{
+    vars_[key] = value;
+    MarkNetworkUpdate();
+}
+
 void Node::AddListener(Component* component)
 void Node::AddListener(Component* component)
 {
 {
     if (!component)
     if (!component)
@@ -775,6 +811,15 @@ bool Node::HasComponent(ShortStringHash type) const
     return false;
     return false;
 }
 }
 
 
+const Variant& Node::GetVar(ShortStringHash key) const
+{
+    VariantMap::ConstIterator i = vars_.Find(key);
+    if (i != vars_.End())
+        return i->second_;
+    else
+        return Variant::EMPTY;
+}
+
 Component* Node::GetComponent(ShortStringHash type) const
 Component* Node::GetComponent(ShortStringHash type) const
 {
 {
     for (Vector<SharedPtr<Component> >::ConstIterator i = components_.Begin(); i != components_.End(); ++i)
     for (Vector<SharedPtr<Component> >::ConstIterator i = components_.Begin(); i != components_.End(); ++i)
@@ -787,7 +832,7 @@ Component* Node::GetComponent(ShortStringHash type) const
 
 
 void Node::PrepareNetworkUpdate()
 void Node::PrepareNetworkUpdate()
 {
 {
-    // Process dependencies first
+    // Update dependency nodes list first
     dependencyNodes_.Clear();
     dependencyNodes_.Clear();
     
     
     // Add the parent node, but if it is local, traverse to the first non-local node
     // Add the parent node, but if it is local, traverse to the first non-local node
@@ -800,10 +845,18 @@ void Node::PrepareNetworkUpdate()
             dependencyNodes_.Push(current);
             dependencyNodes_.Push(current);
     }
     }
     
     
-    // Then let the components add their dependencies
+    // Let the components add their dependencies, and check their attributes at the same time
     for (Vector<SharedPtr<Component> >::ConstIterator i = components_.Begin(); i != components_.End(); ++i)
     for (Vector<SharedPtr<Component> >::ConstIterator i = components_.Begin(); i != components_.End(); ++i)
-        (*i)->GetDependencyNodes(dependencyNodes_);
+    {
+        Component* component = *i;
+        if (component->GetID() < FIRST_LOCAL_ID)
+        {
+            component->GetDependencyNodes(dependencyNodes_);
+            component->PrepareNetworkUpdate();
+        }
+    }
     
     
+    // Then check for node attribute changes
     const Vector<AttributeInfo>* attributes = GetNetworkAttributes();
     const Vector<AttributeInfo>* attributes = GetNetworkAttributes();
     if (attributes)
     if (attributes)
     {
     {
@@ -846,7 +899,7 @@ void Node::PrepareNetworkUpdate()
         }
         }
     }
     }
     
     
-    // Check for user var changes
+    // Finally check for user var changes
     for (VariantMap::ConstIterator i = vars_.Begin(); i != vars_.End(); ++i)
     for (VariantMap::ConstIterator i = vars_.Begin(); i != vars_.End(); ++i)
     {
     {
         VariantMap::ConstIterator j = previousVars_.Find(i->first_);
         VariantMap::ConstIterator j = previousVars_.Find(i->first_);
@@ -867,6 +920,8 @@ void Node::PrepareNetworkUpdate()
             }
             }
         }
         }
     }
     }
+    
+    networkUpdate_ = false;
 }
 }
 
 
 void Node::CleanupConnection(Connection* connection)
 void Node::CleanupConnection(Connection* connection)
@@ -881,11 +936,19 @@ void Node::CleanupConnection(Connection* connection)
     }
     }
 }
 }
 
 
+void Node::MarkNetworkUpdate()
+{
+    if (id_ < FIRST_LOCAL_ID && !networkUpdate_ && scene_)
+    {
+        scene_->MarkNetworkUpdate(this);
+        networkUpdate_ = true;
+    }
+}
+
 void Node::MarkReplicationDirty()
 void Node::MarkReplicationDirty()
 {
 {
     for (PODVector<NodeReplicationState*>::Iterator j = replicationStates_.Begin(); j != replicationStates_.End(); ++j)
     for (PODVector<NodeReplicationState*>::Iterator j = replicationStates_.Begin(); j != replicationStates_.End(); ++j)
     {
     {
-        // Add component's parent node to the dirty set if not added yet
         if (!(*j)->markedDirty_)
         if (!(*j)->markedDirty_)
         {
         {
             (*j)->markedDirty_ = true;
             (*j)->markedDirty_ = true;
@@ -1113,7 +1176,8 @@ Component* Node::CreateComponent(ShortStringHash type, unsigned id, CreateMode m
     newComponent->SetNode(this);
     newComponent->SetNode(this);
     newComponent->OnMarkedDirty(this);
     newComponent->OnMarkedDirty(this);
     
     
-    // Mark node dirty in all replication states
+    // Check attributes of the new component on next network update, and mark node dirty in all replication states
+    MarkNetworkUpdate();
     MarkReplicationDirty();
     MarkReplicationDirty();
     
     
     return newComponent;
     return newComponent;
@@ -1155,6 +1219,7 @@ void Node::RemoveChild(Vector<SharedPtr<Node> >::Iterator i)
 {
 {
     (*i)->parent_ = 0;
     (*i)->parent_ = 0;
     (*i)->MarkDirty();
     (*i)->MarkDirty();
+    (*i)->MarkNetworkUpdate();
     children_.Erase(i);
     children_.Erase(i);
 }
 }
 
 

+ 14 - 5
Engine/Scene/Node.h

@@ -58,6 +58,8 @@ public:
     
     
     /// Handle event. Targeted events will be forwarded to all components.
     /// Handle event. Targeted events will be forwarded to all components.
     virtual void OnEvent(Object* sender, bool broadcast, StringHash eventType, VariantMap& eventData);
     virtual void OnEvent(Object* sender, bool broadcast, StringHash eventType, VariantMap& eventData);
+    /// Handle attribute write access.
+    virtual void OnSetAttribute(const AttributeInfo& attr, const Variant& src);
     /// Load from binary data. Return true if successful.
     /// Load from binary data. Return true if successful.
     virtual bool Load(Deserializer& source);
     virtual bool Load(Deserializer& source);
     /// Load from XML data. Return true if successful.
     /// Load from XML data. Return true if successful.
@@ -151,6 +153,8 @@ public:
     void Remove();
     void Remove();
     /// %Set parent scene node. Retains the world transform.
     /// %Set parent scene node. Retains the world transform.
     void SetParent(Node* parent);
     void SetParent(Node* parent);
+    /// %Set a user variable.
+    void SetVar(ShortStringHash key, const Variant& value);
     /// Add listener component that is notified of node being dirtied. Can either be in the same node or another.
     /// Add listener component that is notified of node being dirtied. Can either be in the same node or another.
     void AddListener(Component* component);
     void AddListener(Component* component);
     /// Remove listener component.
     /// Remove listener component.
@@ -266,8 +270,10 @@ public:
     bool HasComponent(ShortStringHash type) const;
     bool HasComponent(ShortStringHash type) const;
     /// Return listener components.
     /// Return listener components.
     const Vector<WeakPtr<Component> > GetListeners() const { return listeners_; }
     const Vector<WeakPtr<Component> > GetListeners() const { return listeners_; }
-    /// Return user variables.
-    VariantMap& GetVars() { return vars_; }
+    /// Return a user variable.
+    const Variant& GetVar(ShortStringHash key) const;
+    /// Return all user variables.
+    const VariantMap& GetVars() const { return vars_; }
     /// Return first component derived from class.
     /// Return first component derived from class.
     template <class T> T* GetDerivedComponent() const;
     template <class T> T* GetDerivedComponent() const;
     /// Return components derived from class.
     /// Return components derived from class.
@@ -307,18 +313,19 @@ public:
     void PrepareNetworkUpdate();
     void PrepareNetworkUpdate();
     /// Clean up all references to a network connection that is about to be removed.
     /// Clean up all references to a network connection that is about to be removed.
     void CleanupConnection(Connection* connection);
     void CleanupConnection(Connection* connection);
+    /// Mark for attribute check on the next network update.
+    void MarkNetworkUpdate();
     /// Mark node dirty in scene replication states.
     /// Mark node dirty in scene replication states.
     void MarkReplicationDirty();
     void MarkReplicationDirty();
     
     
-    /// User variables.
-    VariantMap vars_;
-    
 protected:
 protected:
     /// Create a component with specific ID.
     /// Create a component with specific ID.
     Component* CreateComponent(ShortStringHash type, unsigned id, CreateMode mode);
     Component* CreateComponent(ShortStringHash type, unsigned id, CreateMode mode);
     /// Create a child node with specific ID.
     /// Create a child node with specific ID.
     Node* CreateChild(unsigned id, CreateMode mode);
     Node* CreateChild(unsigned id, CreateMode mode);
     
     
+    /// User variables.
+    VariantMap vars_;
     /// Per-user network replication states.
     /// Per-user network replication states.
     PODVector<NodeReplicationState*> replicationStates_;
     PODVector<NodeReplicationState*> replicationStates_;
     
     
@@ -370,6 +377,8 @@ private:
     unsigned char rotateCount_;
     unsigned char rotateCount_;
     /// World transform needs update flag.
     /// World transform needs update flag.
     mutable bool dirty_;
     mutable bool dirty_;
+    /// Network update queued flag.
+    bool networkUpdate_;
 };
 };
 
 
 template <class T> T* Node::CreateComponent(CreateMode mode) { return static_cast<T*>(CreateComponent(T::GetTypeStatic(), mode)); }
 template <class T> T* Node::CreateComponent(CreateMode mode) { return static_cast<T*>(CreateComponent(T::GetTypeStatic(), mode)); }

+ 24 - 9
Engine/Scene/Scene.cpp

@@ -612,6 +612,8 @@ void Scene::NodeAdded(Node* node)
         }
         }
         
         
         replicatedNodes_[id] = node;
         replicatedNodes_[id] = node;
+        
+        MarkNetworkUpdate(node);
         MarkReplicationDirty(node);
         MarkReplicationDirty(node);
     }
     }
     else
     else
@@ -709,13 +711,14 @@ String Scene::GetVarNamesAttr() const
 
 
 void Scene::PrepareNetworkUpdate()
 void Scene::PrepareNetworkUpdate()
 {
 {
-    Node::PrepareNetworkUpdate();
-    
-    for (HashMap<unsigned, Node*>::Iterator i = replicatedNodes_.Begin(); i != replicatedNodes_.End(); ++i)
-        i->second_->PrepareNetworkUpdate();
+    for (HashSet<unsigned>::Iterator i = networkUpdateNodes_.Begin(); i != networkUpdateNodes_.End(); ++i)
+    {
+        Node* node = GetNode(*i);
+        if (node)
+            node->PrepareNetworkUpdate();
+    }
     
     
-    for (HashMap<unsigned, Component*>::Iterator i = replicatedComponents_.Begin(); i != replicatedComponents_.End(); ++i)
-        i->second_->PrepareNetworkUpdate();
+    networkUpdateNodes_.Clear();
 }
 }
 
 
 void Scene::CleanupConnection(Connection* connection)
 void Scene::CleanupConnection(Connection* connection)
@@ -729,12 +732,24 @@ void Scene::CleanupConnection(Connection* connection)
         i->second_->CleanupConnection(connection);
         i->second_->CleanupConnection(connection);
 }
 }
 
 
+void Scene::MarkNetworkUpdate(Node* node)
+{
+    if (node)
+    {
+        unsigned id = node->GetID();
+        if (id < FIRST_LOCAL_ID)
+            networkUpdateNodes_.Insert(id);
+    }
+}
+
 void Scene::MarkReplicationDirty(Node* node)
 void Scene::MarkReplicationDirty(Node* node)
 {
 {
     unsigned id = node->GetID();
     unsigned id = node->GetID();
-    
-    for (PODVector<NodeReplicationState*>::Iterator i = replicationStates_.Begin(); i != replicationStates_.End(); ++i)
-        (*i)->sceneState_->dirtyNodes_.Insert(id);
+    if (id < FIRST_LOCAL_ID)
+    {
+        for (PODVector<NodeReplicationState*>::Iterator i = replicationStates_.Begin(); i != replicationStates_.End(); ++i)
+            (*i)->sceneState_->dirtyNodes_.Insert(id);
+    }
 }
 }
 
 
 void Scene::HandleUpdate(StringHash eventType, VariantMap& eventData)
 void Scene::HandleUpdate(StringHash eventType, VariantMap& eventData)

+ 4 - 0
Engine/Scene/Scene.h

@@ -164,6 +164,8 @@ public:
     void PrepareNetworkUpdate();
     void PrepareNetworkUpdate();
     /// Clean up all references to a network connection that is about to be removed.
     /// Clean up all references to a network connection that is about to be removed.
     void CleanupConnection(Connection* connection);
     void CleanupConnection(Connection* connection);
+    /// Mark a node for attribute check on the next network update.
+    void MarkNetworkUpdate(Node* node);
     /// Mark a node dirty in scene replication states. The node does not need to have own replication state yet.
     /// Mark a node dirty in scene replication states. The node does not need to have own replication state yet.
     void MarkReplicationDirty(Node* node);
     void MarkReplicationDirty(Node* node);
     
     
@@ -195,6 +197,8 @@ private:
     Vector<SharedPtr<PackageFile> > requiredPackageFiles_;
     Vector<SharedPtr<PackageFile> > requiredPackageFiles_;
     /// Registered node user variable reverse mappings.
     /// Registered node user variable reverse mappings.
     HashMap<ShortStringHash, String> varNames_;
     HashMap<ShortStringHash, String> varNames_;
+    /// Node IDs to check for attribute changes on the next network update.
+    HashSet<unsigned> networkUpdateNodes_;
     /// Delayed dirty notification queue for components.
     /// Delayed dirty notification queue for components.
     PODVector<Component*> delayedDirtyComponents_;
     PODVector<Component*> delayedDirtyComponents_;
     /// Mutex for the delayed dirty notification queue.
     /// Mutex for the delayed dirty notification queue.

+ 4 - 0
Engine/Script/ScriptInstance.cpp

@@ -120,6 +120,7 @@ void ScriptInstance::SetScriptFile(ScriptFile* scriptFile)
     scriptFile_ = scriptFile;
     scriptFile_ = scriptFile;
     
     
     CreateObject();
     CreateObject();
+    MarkNetworkUpdate();
 }
 }
 
 
 void ScriptInstance::SetClassName(const String& className)
 void ScriptInstance::SetClassName(const String& className)
@@ -130,11 +131,13 @@ void ScriptInstance::SetClassName(const String& className)
     ReleaseObject();
     ReleaseObject();
     className_ = className;
     className_ = className;
     CreateObject();
     CreateObject();
+    MarkNetworkUpdate();
 }
 }
 
 
 void ScriptInstance::SetActive(bool active)
 void ScriptInstance::SetActive(bool active)
 {
 {
     active_ = active;
     active_ = active;
+    MarkNetworkUpdate();
 }
 }
 
 
 void ScriptInstance::SetFixedUpdateFps(int fps)
 void ScriptInstance::SetFixedUpdateFps(int fps)
@@ -143,6 +146,7 @@ void ScriptInstance::SetFixedUpdateFps(int fps)
     fixedUpdateInterval_ = fixedUpdateFps_ ? (1.0f / fixedUpdateFps_) : 0.0f;
     fixedUpdateInterval_ = fixedUpdateFps_ ? (1.0f / fixedUpdateFps_) : 0.0f;
     fixedUpdateAcc_ = 0.0f;
     fixedUpdateAcc_ = 0.0f;
     fixedPostUpdateAcc_ = 0.0f;
     fixedPostUpdateAcc_ = 0.0f;
+    MarkNetworkUpdate();
 }
 }
 
 
 bool ScriptInstance::Execute(const String& declaration, const VariantVector& parameters)
 bool ScriptInstance::Execute(const String& declaration, const VariantVector& parameters)

+ 2 - 2
Engine/UI/ListView.cpp

@@ -46,7 +46,7 @@ int GetItemIndent(UIElement* item)
 {
 {
     if (!item)
     if (!item)
         return 0;
         return 0;
-    return item->vars_[indentHash].GetInt();
+    return item->GetVar(indentHash).GetInt();
 }
 }
 
 
 OBJECTTYPESTATIC(ListView);
 OBJECTTYPESTATIC(ListView);
@@ -97,7 +97,7 @@ void ListView::SetStyle(const XMLElement& element)
                 UIElement* item = root->GetChild(itemElem.GetAttribute("name"), true);
                 UIElement* item = root->GetChild(itemElem.GetAttribute("name"), true);
                 AddItem(item);
                 AddItem(item);
                 if (itemElem.HasAttribute("indent"))
                 if (itemElem.HasAttribute("indent"))
-                    item->vars_[indentHash] = itemElem.GetInt("indent");
+                    item->SetVar(indentHash, itemElem.GetInt("indent"));
                 itemElem = itemElem.GetNext("listitem");
                 itemElem = itemElem.GetNext("listitem");
             }
             }
         }
         }

+ 3 - 3
Engine/UI/Menu.cpp

@@ -121,7 +121,7 @@ void Menu::ShowPopup(bool enable)
             root->AddChild(popup_);
             root->AddChild(popup_);
         popup_->SetPosition(GetScreenPosition() + popupOffset_);
         popup_->SetPosition(GetScreenPosition() + popupOffset_);
         popup_->SetVisible(true);
         popup_->SetVisible(true);
-        popup_->vars_[originHash] = (void*)this;
+        popup_->SetVar(originHash, (void*)this);
         popup_->BringToFront();
         popup_->BringToFront();
     }
     }
     else
     else
@@ -136,7 +136,7 @@ void Menu::ShowPopup(bool enable)
                 menu->ShowPopup(false);
                 menu->ShowPopup(false);
         }
         }
         
         
-        popup_->vars_[originHash].Clear();
+        popup_->SetVar(originHash, Variant());
         popup_->SetVisible(false);
         popup_->SetVisible(false);
         popup_->Remove();
         popup_->Remove();
     }
     }
@@ -212,7 +212,7 @@ void Menu::HandleFocusChanged(StringHash eventType, VariantMap& eventData)
         if (element == this || element == popup_)
         if (element == this || element == popup_)
             return;
             return;
         if (element->GetParent() == root)
         if (element->GetParent() == root)
-            element = static_cast<UIElement*>(element->vars_[originHash].GetPtr());
+            element = static_cast<UIElement*>(element->GetVar(originHash).GetPtr());
         else
         else
             element = element->GetParent();
             element = element->GetParent();
     }
     }

+ 14 - 0
Engine/UI/UIElement.cpp

@@ -847,6 +847,11 @@ void UIElement::SetParent(UIElement* parent)
         parent->AddChild(this);
         parent->AddChild(this);
 }
 }
 
 
+void UIElement::SetVar(ShortStringHash key, const Variant& value)
+{
+    vars_[key] = value;
+}
+
 IntVector2 UIElement::GetScreenPosition()
 IntVector2 UIElement::GetScreenPosition()
 {
 {
     if (positionDirty_)
     if (positionDirty_)
@@ -1001,6 +1006,15 @@ unsigned UIElement::GetUIntColor()
     return uintColor_;
     return uintColor_;
 }
 }
 
 
+const Variant& UIElement::GetVar(ShortStringHash key) const
+{
+    VariantMap::ConstIterator i = vars_.Find(key);
+    if (i != vars_.End())
+        return i->second_;
+    else
+        return Variant::EMPTY;
+}
+
 IntVector2 UIElement::ScreenToElement(const IntVector2& screenPosition)
 IntVector2 UIElement::ScreenToElement(const IntVector2& screenPosition)
 {
 {
     return screenPosition - GetScreenPosition();
     return screenPosition - GetScreenPosition();

+ 8 - 5
Engine/UI/UIElement.h

@@ -247,6 +247,8 @@ public:
     void Remove();
     void Remove();
     /// %Set parent element. Same as parent->AddChild(this).
     /// %Set parent element. Same as parent->AddChild(this).
     void SetParent(UIElement* parent);
     void SetParent(UIElement* parent);
+    /// %Set a user variable.
+    void SetVar(ShortStringHash key, const Variant& value);
     
     
     /// Return name.
     /// Return name.
     const String& GetName() const { return name_; }
     const String& GetName() const { return name_; }
@@ -334,8 +336,10 @@ public:
     UIElement* GetRoot() const;
     UIElement* GetRoot() const;
     /// Return precalculated 32-bit color. Only valid when no gradient.
     /// Return precalculated 32-bit color. Only valid when no gradient.
     unsigned GetUIntColor();
     unsigned GetUIntColor();
-    /// Return user variables.
-    VariantMap& GetVars() { return vars_; }
+    /// Return a user variable.
+    const Variant& GetVar(ShortStringHash key) const;
+    /// Return all user variables.
+    const VariantMap& GetVars() const { return vars_; }
     
     
     /// Convert screen coordinates to element coordinates.
     /// Convert screen coordinates to element coordinates.
     IntVector2 ScreenToElement(const IntVector2& screenPosition);
     IntVector2 ScreenToElement(const IntVector2& screenPosition);
@@ -362,9 +366,6 @@ public:
     void GetBatchesWithOffset(IntVector2& offset, PODVector<UIBatch>& batches, PODVector<UIQuad>& quads, IntRect
     void GetBatchesWithOffset(IntVector2& offset, PODVector<UIBatch>& batches, PODVector<UIQuad>& quads, IntRect
         currentScissor);
         currentScissor);
     
     
-    /// User variables.
-    VariantMap vars_;
-    
 protected:
 protected:
     /// Mark screen position as needing an update.
     /// Mark screen position as needing an update.
     void MarkDirty();
     void MarkDirty();
@@ -379,6 +380,8 @@ protected:
     IntRect clipBorder_;
     IntRect clipBorder_;
     /// Colors.
     /// Colors.
     Color color_[MAX_UIELEMENT_CORNERS];
     Color color_[MAX_UIELEMENT_CORNERS];
+    /// User variables.
+    VariantMap vars_;
     /// Priority.
     /// Priority.
     int priority_;
     int priority_;
     /// Bring to front when focused flag.
     /// Bring to front when focused flag.