Browse Source

Further optimization of network updates. Use a HashMap to store replicated and local nodes and components separately. Query depended on scene nodes only once per network frame, not per user. Cache the network attribute infos to Serializable.
Fixed incorrect transform snapping in networked NinjaSnowWar.
Allow to execute arbitrary AngelScript from the NinjaSnowWar headless server console.
Added maximum block time to Profiler.

Lasse Öörni 13 years ago
parent
commit
c710fb4ef6

+ 166 - 166
Bin/Data/Scenes/NinjaSnowWar.xml

@@ -1,166 +1,166 @@
-<?xml version="1.0"?>
-<scene id="1">
-	<attribute name="Name" value="NinjaSnowWar" />
-	<attribute name="Position" value="0 0 0" />
-	<attribute name="Rotation" value="1 0 0 0" />
-	<attribute name="Scale" value="1 1 1" />
-	<attribute name="Smoothing Constant" value="50" />
-	<attribute name="Snap Threshold" value="1" />
-	<attribute name="Next Replicated Node ID" value="2" />
-	<attribute name="Next Replicated Component ID" value="1" />
-	<attribute name="Next Local Node ID" value="16777220" />
-	<attribute name="Next Local Component ID" value="16777223" />
-	<attribute name="Variables" />
-	<attribute name="Variable Names" value="" />
-	<component type="Octree" id="16777216">
-		<attribute name="Bounding Box Min" value="-20000 -20000 -20000" />
-		<attribute name="Bounding Box Max" value="20000 20000 20000" />
-		<attribute name="Number of Levels" value="7" />
-	</component>
-	<component type="PhysicsWorld" id="16777217">
-		<attribute name="Gravity" value="0 -981 0" />
-		<attribute name="Physics FPS" value="100" />
-		<attribute name="Net Max Angular Vel." value="100" />
-		<attribute name="Interpolation" value="true" />
-	</component>
-	<component type="DebugRenderer" id="16777218" />
-	<node id="16777216">
-		<attribute name="Name" value="Zone" />
-		<attribute name="Position" value="0 0 0" />
-		<attribute name="Rotation" value="1 0 0 0" />
-		<attribute name="Scale" value="1 1 1" />
-		<attribute name="Variables" />
-		<component type="Zone" id="4">
-			<attribute name="Bounding Box Min" value="-100000 -100000 -100000" />
-			<attribute name="Bounding Box Max" value="100000 100000 100000" />
-			<attribute name="Ambient Color" value="0.2 0.2 0.7 1" />
-			<attribute name="Fog Color" value="0.2 0.2 0.7 1" />
-			<attribute name="Fog Start" value="5000" />
-			<attribute name="Fog End" value="15000" />
-			<attribute name="Is Visible" value="true" />
-			<attribute name="Override Mode" value="false" />
-			<attribute name="Ambient Gradient" value="false" />
-			<attribute name="Priority" value="0" />
-			<attribute name="Light Mask" value="-1" />
-			<attribute name="Shadow Mask" value="-1" />
-			<attribute name="Zone Mask" value="-1" />
-		</component>
-	</node>
-	<node id="16777217">
-		<attribute name="Name" value="GlobalLight" />
-		<attribute name="Position" value="0 0 0" />
-		<attribute name="Rotation" value="0.888074 0.325058 -0.325058 0" />
-		<attribute name="Scale" value="1 1 1" />
-		<attribute name="Variables" />
-		<component type="Light" id="16777219">
-			<attribute name="Light Type" value="Directional" />
-			<attribute name="Color" value="1 1 1 1" />
-			<attribute name="Specular Intensity" value="0" />
-			<attribute name="Range" value="10" />
-			<attribute name="Spot FOV" value="30" />
-			<attribute name="Spot Aspect Ratio" value="1" />
-			<attribute name="Attenuation Texture" value="Texture2D;" />
-			<attribute name="Light Shape Texture" value="Texture2D;" />
-			<attribute name="Is Visible" value="true" />
-			<attribute name="Can Be Occluded" value="true" />
-			<attribute name="Cast Shadows" value="true" />
-			<attribute name="Per Vertex" value="false" />
-			<attribute name="Draw Distance" value="0" />
-			<attribute name="Fade Distance" value="0" />
-			<attribute name="Shadow Distance" value="0" />
-			<attribute name="Shadow Fade Distance" value="0" />
-			<attribute name="Shadow Intensity" value="0" />
-			<attribute name="Shadow Resolution" value="1" />
-			<attribute name="Focus To Scene" value="true" />
-			<attribute name="Non-uniform View" value="true" />
-			<attribute name="Auto-Reduce Size" value="true" />
-			<attribute name="CSM Splits" value="1000 2000 5000 0" />
-			<attribute name="CSM Fade Start" value="0.8" />
-			<attribute name="View Size Quantize" value="25" />
-			<attribute name="View Size Minimum" value="500" />
-			<attribute name="Depth Constant Bias" value="0.00025" />
-			<attribute name="Depth Slope Bias" value="0.001" />
-			<attribute name="Near/Farclip Ratio" value="0.002" />
-			<attribute name="View Mask" value="-1" />
-			<attribute name="Light Mask" value="-1" />
-		</component>
-	</node>
-	<node id="16777218">
-		<attribute name="Name" value="Static" />
-		<attribute name="Position" value="0 0 0" />
-		<attribute name="Rotation" value="1 0 0 0" />
-		<attribute name="Scale" value="1 1 1" />
-		<attribute name="Variables" />
-		<component type="StaticModel" id="16777220">
-			<attribute name="Model" value="Model;Models/Level.mdl" />
-			<attribute name="Material" value="Material;Materials/Snow.xml" />
-			<attribute name="Is Visible" value="true" />
-			<attribute name="Is Occluder" value="false" />
-			<attribute name="Can Be Occluded" value="true" />
-			<attribute name="Cast Shadows" value="false" />
-			<attribute name="Draw Distance" value="0" />
-			<attribute name="Shadow Distance" value="0" />
-			<attribute name="LOD Bias" value="1" />
-			<attribute name="Max Lights" value="0" />
-			<attribute name="View Mask" value="-1" />
-			<attribute name="Light Mask" value="-1" />
-			<attribute name="Shadow Mask" value="-1" />
-			<attribute name="Zone Mask" value="-1" />
-			<attribute name="Ray/Occl. LOD Level" value="-1" />
-		</component>
-		<component type="CollisionShape" id="16777221">
-			<attribute name="Shape Type" value="TriangleMesh" />
-			<attribute name="Size" value="1 1 1" />
-			<attribute name="Offset Position" value="0 0 0" />
-			<attribute name="Offset Rotation" value="1 0 0 0" />
-			<attribute name="Collision Margin" value="1" />
-			<attribute name="Model" value="Model;Models/Level.mdl" />
-			<attribute name="LOD Level" value="0" />
-		</component>
-		<component type="RigidBody" id="16777223">
-			<attribute name="Physics Position" value="0 0 0" />
-			<attribute name="Physics Rotation" value="1 0 0 0" />
-			<attribute name="Mass" value="0" />
-			<attribute name="Friction" value="0.5" />
-			<attribute name="Restitution" value="0" />
-			<attribute name="Linear Velocity" value="0 0 0" />
-			<attribute name="Angular Velocity" value="0 0 0" />
-			<attribute name="Linear Factor" value="1 1 1" />
-			<attribute name="Angular Factor" value="1 1 1" />
-			<attribute name="Linear Damping" value="0" />
-			<attribute name="Angular Damping" value="0" />
-			<attribute name="Linear Rest Threshold" value="0.8" />
-			<attribute name="Angular Rest Threshold" value="1" />
-			<attribute name="Collision Layer" value="2" />
-			<attribute name="Collision Mask" value="3" />
-			<attribute name="Collision Event Mode" value="When Active" />
-			<attribute name="Use Gravity" value="true" />
-			<attribute name="Is Kinematic" value="false" />
-			<attribute name="Is Phantom" value="false" />
-		</component>
-	</node>
-	<node id="16777219">
-		<attribute name="Name" value="Sky" />
-		<attribute name="Position" value="0 3000 0" />
-		<attribute name="Rotation" value="1 0 0 0" />
-		<attribute name="Scale" value="30000 1 30000" />
-		<attribute name="Variables" />
-		<component type="Skybox" id="16777222">
-			<attribute name="Model" value="Model;Models/CloudPlane.mdl" />
-			<attribute name="Material" value="Material;Materials/CloudPlane.xml" />
-			<attribute name="Is Visible" value="true" />
-			<attribute name="Is Occluder" value="false" />
-			<attribute name="Can Be Occluded" value="true" />
-			<attribute name="Cast Shadows" value="false" />
-			<attribute name="Draw Distance" value="0" />
-			<attribute name="Shadow Distance" value="0" />
-			<attribute name="LOD Bias" value="1" />
-			<attribute name="Max Lights" value="0" />
-			<attribute name="View Mask" value="-1" />
-			<attribute name="Light Mask" value="-1" />
-			<attribute name="Shadow Mask" value="-1" />
-			<attribute name="Zone Mask" value="-1" />
-			<attribute name="Ray/Occl. LOD Level" value="-1" />
-		</component>
-	</node>
-</scene>
+<?xml version="1.0"?>
+<scene id="1">
+	<attribute name="Name" value="NinjaSnowWar" />
+	<attribute name="Position" value="0 0 0" />
+	<attribute name="Rotation" value="1 0 0 0" />
+	<attribute name="Scale" value="1 1 1" />
+	<attribute name="Smoothing Constant" value="50" />
+	<attribute name="Snap Threshold" value="100" />
+	<attribute name="Next Replicated Node ID" value="2" />
+	<attribute name="Next Replicated Component ID" value="1" />
+	<attribute name="Next Local Node ID" value="16777220" />
+	<attribute name="Next Local Component ID" value="16777223" />
+	<attribute name="Variables" />
+	<attribute name="Variable Names" value="" />
+	<component type="Octree" id="16777216">
+		<attribute name="Bounding Box Min" value="-20000 -20000 -20000" />
+		<attribute name="Bounding Box Max" value="20000 20000 20000" />
+		<attribute name="Number of Levels" value="7" />
+	</component>
+	<component type="PhysicsWorld" id="16777217">
+		<attribute name="Gravity" value="0 -981 0" />
+		<attribute name="Physics FPS" value="100" />
+		<attribute name="Net Max Angular Vel." value="100" />
+		<attribute name="Interpolation" value="true" />
+	</component>
+	<component type="DebugRenderer" id="16777218" />
+	<node id="16777216">
+		<attribute name="Name" value="Zone" />
+		<attribute name="Position" value="0 0 0" />
+		<attribute name="Rotation" value="1 0 0 0" />
+		<attribute name="Scale" value="1 1 1" />
+		<attribute name="Variables" />
+		<component type="Zone" id="4">
+			<attribute name="Bounding Box Min" value="-100000 -100000 -100000" />
+			<attribute name="Bounding Box Max" value="100000 100000 100000" />
+			<attribute name="Ambient Color" value="0.2 0.2 0.7 1" />
+			<attribute name="Fog Color" value="0.2 0.2 0.7 1" />
+			<attribute name="Fog Start" value="5000" />
+			<attribute name="Fog End" value="15000" />
+			<attribute name="Is Visible" value="true" />
+			<attribute name="Override Mode" value="false" />
+			<attribute name="Ambient Gradient" value="false" />
+			<attribute name="Priority" value="0" />
+			<attribute name="Light Mask" value="-1" />
+			<attribute name="Shadow Mask" value="-1" />
+			<attribute name="Zone Mask" value="-1" />
+		</component>
+	</node>
+	<node id="16777217">
+		<attribute name="Name" value="GlobalLight" />
+		<attribute name="Position" value="0 0 0" />
+		<attribute name="Rotation" value="0.888074 0.325058 -0.325058 0" />
+		<attribute name="Scale" value="1 1 1" />
+		<attribute name="Variables" />
+		<component type="Light" id="16777219">
+			<attribute name="Light Type" value="Directional" />
+			<attribute name="Color" value="1 1 1 1" />
+			<attribute name="Specular Intensity" value="0" />
+			<attribute name="Range" value="10" />
+			<attribute name="Spot FOV" value="30" />
+			<attribute name="Spot Aspect Ratio" value="1" />
+			<attribute name="Attenuation Texture" value="Texture2D;" />
+			<attribute name="Light Shape Texture" value="Texture2D;" />
+			<attribute name="Is Visible" value="true" />
+			<attribute name="Can Be Occluded" value="true" />
+			<attribute name="Cast Shadows" value="true" />
+			<attribute name="Per Vertex" value="false" />
+			<attribute name="Draw Distance" value="0" />
+			<attribute name="Fade Distance" value="0" />
+			<attribute name="Shadow Distance" value="0" />
+			<attribute name="Shadow Fade Distance" value="0" />
+			<attribute name="Shadow Intensity" value="0" />
+			<attribute name="Shadow Resolution" value="1" />
+			<attribute name="Focus To Scene" value="true" />
+			<attribute name="Non-uniform View" value="true" />
+			<attribute name="Auto-Reduce Size" value="true" />
+			<attribute name="CSM Splits" value="1000 2000 5000 0" />
+			<attribute name="CSM Fade Start" value="0.8" />
+			<attribute name="View Size Quantize" value="25" />
+			<attribute name="View Size Minimum" value="500" />
+			<attribute name="Depth Constant Bias" value="0.00025" />
+			<attribute name="Depth Slope Bias" value="0.001" />
+			<attribute name="Near/Farclip Ratio" value="0.002" />
+			<attribute name="View Mask" value="-1" />
+			<attribute name="Light Mask" value="-1" />
+		</component>
+	</node>
+	<node id="16777218">
+		<attribute name="Name" value="Static" />
+		<attribute name="Position" value="0 0 0" />
+		<attribute name="Rotation" value="1 0 0 0" />
+		<attribute name="Scale" value="1 1 1" />
+		<attribute name="Variables" />
+		<component type="StaticModel" id="16777220">
+			<attribute name="Model" value="Model;Models/Level.mdl" />
+			<attribute name="Material" value="Material;Materials/Snow.xml" />
+			<attribute name="Is Visible" value="true" />
+			<attribute name="Is Occluder" value="false" />
+			<attribute name="Can Be Occluded" value="true" />
+			<attribute name="Cast Shadows" value="false" />
+			<attribute name="Draw Distance" value="0" />
+			<attribute name="Shadow Distance" value="0" />
+			<attribute name="LOD Bias" value="1" />
+			<attribute name="Max Lights" value="0" />
+			<attribute name="View Mask" value="-1" />
+			<attribute name="Light Mask" value="-1" />
+			<attribute name="Shadow Mask" value="-1" />
+			<attribute name="Zone Mask" value="-1" />
+			<attribute name="Ray/Occl. LOD Level" value="-1" />
+		</component>
+		<component type="CollisionShape" id="16777221">
+			<attribute name="Shape Type" value="TriangleMesh" />
+			<attribute name="Size" value="1 1 1" />
+			<attribute name="Offset Position" value="0 0 0" />
+			<attribute name="Offset Rotation" value="1 0 0 0" />
+			<attribute name="Collision Margin" value="1" />
+			<attribute name="Model" value="Model;Models/Level.mdl" />
+			<attribute name="LOD Level" value="0" />
+		</component>
+		<component type="RigidBody" id="16777223">
+			<attribute name="Physics Position" value="0 0 0" />
+			<attribute name="Physics Rotation" value="1 0 0 0" />
+			<attribute name="Mass" value="0" />
+			<attribute name="Friction" value="0.5" />
+			<attribute name="Restitution" value="0" />
+			<attribute name="Linear Velocity" value="0 0 0" />
+			<attribute name="Angular Velocity" value="0 0 0" />
+			<attribute name="Linear Factor" value="1 1 1" />
+			<attribute name="Angular Factor" value="1 1 1" />
+			<attribute name="Linear Damping" value="0" />
+			<attribute name="Angular Damping" value="0" />
+			<attribute name="Linear Rest Threshold" value="0.8" />
+			<attribute name="Angular Rest Threshold" value="1" />
+			<attribute name="Collision Layer" value="2" />
+			<attribute name="Collision Mask" value="3" />
+			<attribute name="Collision Event Mode" value="When Active" />
+			<attribute name="Use Gravity" value="true" />
+			<attribute name="Is Kinematic" value="false" />
+			<attribute name="Is Phantom" value="false" />
+		</component>
+	</node>
+	<node id="16777219">
+		<attribute name="Name" value="Sky" />
+		<attribute name="Position" value="0 3000 0" />
+		<attribute name="Rotation" value="1 0 0 0" />
+		<attribute name="Scale" value="30000 1 30000" />
+		<attribute name="Variables" />
+		<component type="Skybox" id="16777222">
+			<attribute name="Model" value="Model;Models/CloudPlane.mdl" />
+			<attribute name="Material" value="Material;Materials/CloudPlane.xml" />
+			<attribute name="Is Visible" value="true" />
+			<attribute name="Is Occluder" value="false" />
+			<attribute name="Can Be Occluded" value="true" />
+			<attribute name="Cast Shadows" value="false" />
+			<attribute name="Draw Distance" value="0" />
+			<attribute name="Shadow Distance" value="0" />
+			<attribute name="LOD Bias" value="1" />
+			<attribute name="Max Lights" value="0" />
+			<attribute name="View Mask" value="-1" />
+			<attribute name="Light Mask" value="-1" />
+			<attribute name="Shadow Mask" value="-1" />
+			<attribute name="Zone Mask" value="-1" />
+			<attribute name="Ray/Occl. LOD Level" value="-1" />
+		</component>
+	</node>
+</scene>

+ 3 - 6
Bin/Data/Scripts/NinjaSnowWar.as

@@ -117,9 +117,6 @@ void InitScene()
 {
     gameScene = Scene("NinjaSnowWar");
 
-    // Set network snap threshold higher, as the world unit is centimeter
-    gameScene.snapThreshold = 100.0;
-
     // Enable access to this script file & scene from the console
     script.defaultScene = gameScene;
     script.defaultScriptFile = scriptFile;
@@ -376,9 +373,9 @@ void HandleUpdate(StringHash eventType, VariantMap& eventData)
     
     if (engine.headless)
     {
-        String command = GetConsoleInput().ToLower();
-        if (command == "shutdown" || command == "exit" || command == "quit")
-            engine.Exit();
+        String command = GetConsoleInput();
+        if (command.length > 0)
+            script.Execute(command);
     }
 }
 

+ 17 - 13
Engine/Core/Profiler.h

@@ -33,6 +33,7 @@ public:
     ProfilerBlock(ProfilerBlock* parent, const char* name) :
         name_(name),
         time_(0),
+        maxTime_(0),
         count_(0),
         parent_(parent),
         lastSearchName_(0),
@@ -56,17 +57,20 @@ public:
         }
     }
     
-    /// Begin timing. Call count can also be specified if known to reduce overhead.
-    void Begin(unsigned count = 1)
+    /// Begin timing.
+    void Begin()
     {
         timer_.Reset();
-        count_ += count;
+        ++count_;
     }
     
     /// End timing.
     void End()
     {
-        time_ += timer_.GetUSec(false);
+        long long time = timer_.GetUSec(false);
+        if (time > maxTime_)
+            maxTime_ = time;
+        time_ += time;
     }
     
     /// End profiling frame and update accumulation period and total values.
@@ -122,6 +126,8 @@ public:
     /// Return name of block.
     const char* GetName() const { return name_; }
     
+    /// Return maximum time of a single call.
+    long long GetMaxTime() const { return maxTime_; }
     /// Return accumulated time during last frame.
     long long GetFrameTime() const { return frameTime_; }
     /// Return number of calls during last frame.
@@ -146,9 +152,10 @@ private:
     HiresTimer timer_;
     /// Time on current frame.
     long long time_;
+    /// Maximum time on a block.
+    long long maxTime_;
     /// Calls on current frame.
     unsigned count_;
-
     /// Parent block.
     ProfilerBlock* parent_;
     /// Last queried child block name (optimization.)
@@ -157,7 +164,6 @@ private:
     ProfilerBlock* lastSearchBlock_;
     /// Child blocks.
     PODVector<ProfilerBlock*> children_;
-    
     /// Time on the previous frame.
     long long frameTime_;
     /// Calls on the previous frame.
@@ -183,11 +189,11 @@ public:
     /// Destruct.
     virtual ~Profiler();
     
-    /// Begin timing a profiling block. Call count can also be specified if known to reduce overhead.
-    void BeginBlock(const char* name, unsigned count = 1)
+    /// Begin timing a profiling block.
+    void BeginBlock(const char* name)
     {
         current_ = current_->GetChild(name);
-        current_->Begin(count);
+        current_->Begin();
     }
     
     /// End timing the current profiling block.
@@ -231,11 +237,11 @@ class AutoProfileBlock
 {
 public:
     /// Construct. Begin a profiling block with the specified name and optional call count.
-    AutoProfileBlock(Profiler* profiler, const char* name, unsigned count = 1) :
+    AutoProfileBlock(Profiler* profiler, const char* name) :
         profiler_(profiler)
     {
         if (profiler_)
-            profiler_->BeginBlock(name, count);
+            profiler_->BeginBlock(name);
     }
     
     /// Destruct. End the profiling block.
@@ -252,8 +258,6 @@ private:
 
 #ifdef ENABLE_PROFILING
 #define PROFILE(name) AutoProfileBlock profile_ ## name (GetSubsystem<Profiler>(), #name)
-#define PROFILE_MULTIPLE(name, count) AutoProfileBlock profile_ ## name (GetSubsystem<Profiler>(), #name, count)
 #else
 #define PROFILE(name)
-#define PROFILE_MULTIPLE(name, count)
 #endif

+ 2 - 5
Engine/Core/Variant.cpp

@@ -117,13 +117,10 @@ bool Variant::operator == (const Variant& rhs) const
         return *(reinterpret_cast<const Vector3*>(&value_)) == *(reinterpret_cast<const Vector3*>(&rhs.value_));
         
     case VAR_VECTOR4:
-        return *(reinterpret_cast<const Vector4*>(&value_)) == *(reinterpret_cast<const Vector4*>(&rhs.value_));
-        
     case VAR_QUATERNION:
-        return *(reinterpret_cast<const Quaternion*>(&value_)) == *(reinterpret_cast<const Quaternion*>(&rhs.value_));
-        
     case VAR_COLOR:
-        return *(reinterpret_cast<const Color*>(&value_)) == *(reinterpret_cast<const Color*>(&rhs.value_));
+        // Hack: use the Vector4 compare for all these classes, as they have the same memory structure
+        return *(reinterpret_cast<const Vector4*>(&value_)) == *(reinterpret_cast<const Vector4*>(&rhs.value_));
         
     case VAR_STRING:
         return *(reinterpret_cast<const String*>(&value_)) == *(reinterpret_cast<const String*>(&rhs.value_));

+ 1 - 1
Engine/Graphics/View.cpp

@@ -664,7 +664,7 @@ void View::GetBatches()
     
     // Process lit geometries and shadow casters for each light
     {
-        PROFILE_MULTIPLE(ProcessLights, lights_.Size());
+        PROFILE(ProcessLights);
         
         lightQueryResults_.Resize(lights_.Size());
         

+ 4 - 5
Engine/Network/Connection.cpp

@@ -222,7 +222,7 @@ void Connection::SendServerUpdate(unsigned frameNumber)
     
     PROFILE(SendServerUpdate);
     
-    const Map<unsigned, Node*>& nodes = scene_->GetAllNodes();
+    const HashMap<unsigned, Node*>& nodes = scene_->GetReplicatedNodes();
     
     // Check for new or changed nodes
     // Start from the root node (scene) so that the scene-wide components get sent first
@@ -230,7 +230,7 @@ void Connection::SendServerUpdate(unsigned frameNumber)
     ProcessNode(frameNumber, scene_);
     
     // Then go through the rest of the nodes
-    for (Map<unsigned, Node*>::ConstIterator i = nodes.Begin(); i != nodes.End() && i->first_ < FIRST_LOCAL_ID; ++i)
+    for (HashMap<unsigned, Node*>::ConstIterator i = nodes.Begin(); i != nodes.End() && i->first_ < FIRST_LOCAL_ID; ++i)
         ProcessNode(frameNumber, i->second_);
     
     // Check for removed nodes
@@ -1011,8 +1011,7 @@ void Connection::ProcessNode(unsigned frameNumber, Node* node)
     processedNodes_.Insert(node);
     
     // Process depended upon nodes first
-    PODVector<Node*> dependencyNodes;
-    node->GetDependencyNodes(dependencyNodes);
+    const PODVector<Node*>& dependencyNodes = node->GetDependencyNodes(frameNumber);
     for (PODVector<Node*>::ConstIterator i = dependencyNodes.Begin(); i != dependencyNodes.End(); ++i)
         ProcessNode(frameNumber, *i);
     
@@ -1072,7 +1071,7 @@ void Connection::ProcessExistingNode(unsigned frameNumber, Node* node, NodeRepli
 {
     nodeState.frameNumber_ = frameNumber;
     
-    // Check from the interest management priority component, if exists, whether should update
+    // Check from the interest management component, if exists, whether should update
     NetworkPriority* priority = node->GetComponent<NetworkPriority>();
     if (priority && (!priority->GetAlwaysUpdateOwner() || node->GetOwner() != this))
     {

+ 1 - 1
Engine/Physics/PhysicsWorld.cpp

@@ -351,7 +351,7 @@ void PhysicsWorld::PreStep(float timeStep)
 #ifdef ENABLE_PROFILING
     Profiler* profiler = GetSubsystem<Profiler>();
     if (profiler)
-        profiler->BeginBlock("StepSimulation", 1);
+        profiler->BeginBlock("StepSimulation");
 #endif
 }
 

+ 21 - 10
Engine/Scene/Node.cpp

@@ -48,6 +48,7 @@ Node::Node(Context* context) :
     rotation_(Quaternion::IDENTITY),
     scale_(Vector3::ONE),
     worldTransform_(Matrix3x4::IDENTITY),
+    dependencyFrameNumber_(0),
     rotateCount_(0),
     dirty_(false)
 {
@@ -770,20 +771,30 @@ Component* Node::GetComponent(ShortStringHash type) const
     return 0;
 }
 
-void Node::GetDependencyNodes(PODVector<Node*>& dest) const
+const PODVector<Node*>& Node::GetDependencyNodes(unsigned frameNumber) const
 {
-    // Add the parent node, but if it is local, traverse to the first non-local node
-    if (parent_ && parent_ != scene_)
+    if (frameNumber != dependencyFrameNumber_)
     {
-        Node* current = parent_;
-        while (current->id_ >= FIRST_LOCAL_ID)
-            current = current->parent_;
-        dest.Push(current);
+        dependencyNodes_.Clear();
+        
+        // Add the parent node, but if it is local, traverse to the first non-local node
+        if (parent_ && parent_ != scene_)
+        {
+            Node* current = parent_;
+            while (current->id_ >= FIRST_LOCAL_ID)
+                current = current->parent_;
+            if (current && current != scene_)
+                dependencyNodes_.Push(current);
+        }
+        
+        // Then let the components add their dependencies
+        for (Vector<SharedPtr<Component> >::ConstIterator i = components_.Begin(); i != components_.End(); ++i)
+            (*i)->GetDependencyNodes(dependencyNodes_);
+        
+        dependencyFrameNumber_ = frameNumber;
     }
     
-    // Then let the components add their dependencies
-    for (Vector<SharedPtr<Component> >::ConstIterator i = components_.Begin(); i != components_.End(); ++i)
-        (*i)->GetDependencyNodes(dest);
+    return dependencyNodes_;
 }
 
 void Node::SetID(unsigned id)

+ 6 - 2
Engine/Scene/Node.h

@@ -266,7 +266,7 @@ public:
     /// Return user variables.
     VariantMap& GetVars() { return vars_; }
     /// Return the depended on nodes to order network updates.
-    void GetDependencyNodes(PODVector<Node*>& dest) const;
+    const PODVector<Node*>& GetDependencyNodes(unsigned frameNumber) const;
     /// Return first component derived from class.
     template <class T> T* GetDerivedComponent() const;
     /// Return components derived from class.
@@ -348,8 +348,12 @@ private:
     Vector<SharedPtr<Component> > components_;
     /// Node listeners.
     Vector<WeakPtr<Component> > listeners_;
-    /// Attribute buffer for network replication.
+    /// Nodes this node depends on for network updates.
+    mutable PODVector<Node*> dependencyNodes_;
+    /// Attribute buffer for network updates.
     mutable VectorBuffer attrBuffer_;
+    /// Dependency nodes update framenumber.
+    mutable unsigned dependencyFrameNumber_;
     /// Consecutive rotation count for rotation renormalization.
     unsigned char rotateCount_;
     /// World transform needs update flag.

+ 98 - 30
Engine/Scene/Scene.cpp

@@ -66,7 +66,12 @@ Scene::Scene(Context* context) :
 Scene::~Scene()
 {
     // Remove scene reference and owner from all nodes that still exist
-    for (Map<unsigned, Node*>::Iterator i = allNodes_.Begin(); i != allNodes_.End(); ++i)
+    for (HashMap<unsigned, Node*>::Iterator i = replicatedNodes_.Begin(); i != replicatedNodes_.End(); ++i)
+    {
+        i->second_->SetScene(0);
+        i->second_->SetOwner(0);
+    }
+    for (HashMap<unsigned, Node*>::Iterator i = localNodes_.Begin(); i != localNodes_.End(); ++i)
     {
         i->second_->SetScene(0);
         i->second_->SetOwner(0);
@@ -379,7 +384,12 @@ void Scene::ClearRequiredPackageFiles()
 
 void Scene::ResetOwner(Connection* owner)
 {
-    for (Map<unsigned, Node*>::Iterator i = allNodes_.Begin(); i != allNodes_.End(); ++i)
+    for (HashMap<unsigned, Node*>::Iterator i = replicatedNodes_.Begin(); i != replicatedNodes_.End(); ++i)
+    {
+        if (i->second_->GetOwner() == owner)
+            i->second_->SetOwner(0);
+    }
+    for (HashMap<unsigned, Node*>::Iterator i = localNodes_.Begin(); i != localNodes_.End(); ++i)
     {
         if (i->second_->GetOwner() == owner)
             i->second_->SetOwner(0);
@@ -403,20 +413,42 @@ void Scene::UnregisterAllVars()
 
 Node* Scene::GetNode(unsigned id) const
 {
-    Map<unsigned, Node*>::ConstIterator i = allNodes_.Find(id);
-    if (i != allNodes_.End())
-        return i->second_;
+    if (id < FIRST_LOCAL_ID)
+    {
+        HashMap<unsigned, Node*>::ConstIterator i = replicatedNodes_.Find(id);
+        if (i != replicatedNodes_.End())
+            return i->second_;
+        else
+            return 0;
+    }
     else
-        return 0;
+    {
+        HashMap<unsigned, Node*>::ConstIterator i = localNodes_.Find(id);
+        if (i != localNodes_.End())
+            return i->second_;
+        else
+            return 0;
+    }
 }
 
 Component* Scene::GetComponent(unsigned id) const
 {
-    Map<unsigned, Component*>::ConstIterator i = allComponents_.Find(id);
-    if (i != allComponents_.End())
-        return i->second_;
+    if (id < FIRST_LOCAL_ID)
+    {
+        HashMap<unsigned, Component*>::ConstIterator i = replicatedComponents_.Find(id);
+        if (i != replicatedComponents_.End())
+            return i->second_;
+        else
+            return 0;
+    }
     else
-        return 0;
+    {
+        HashMap<unsigned, Component*>::ConstIterator i = localComponents_.Find(id);
+        if (i != localComponents_.End())
+            return i->second_;
+        else
+            return 0;
+    }
 }
 
 float Scene::GetAsyncProgress() const
@@ -429,7 +461,7 @@ float Scene::GetAsyncProgress() const
 
 const String& Scene::GetVarName(ShortStringHash hash) const
 {
-    Map<ShortStringHash, String>::ConstIterator i = varNames_.Find(hash);
+    HashMap<ShortStringHash, String>::ConstIterator i = varNames_.Find(hash);
     return i != varNames_.End() ? i->second_ : emptyVarName;
 }
 
@@ -510,7 +542,7 @@ unsigned Scene::GetFreeNodeID(CreateMode mode)
     {
         for (;;)
         {
-            if (!allNodes_.Contains(replicatedNodeID_))
+            if (!replicatedNodes_.Contains(replicatedNodeID_))
                 return replicatedNodeID_;
             
             if (replicatedNodeID_ != LAST_REPLICATED_ID)
@@ -523,7 +555,7 @@ unsigned Scene::GetFreeNodeID(CreateMode mode)
     {
         for (;;)
         {
-            if (!allNodes_.Contains(localNodeID_))
+            if (!localNodes_.Contains(localNodeID_))
                 return localNodeID_;
             
             if (localNodeID_ != LAST_LOCAL_ID)
@@ -540,7 +572,7 @@ unsigned Scene::GetFreeComponentID(CreateMode mode)
     {
         for (;;)
         {
-            if (!allComponents_.Contains(replicatedComponentID_))
+            if (!replicatedComponents_.Contains(replicatedComponentID_))
                 return replicatedComponentID_;
             
             if (replicatedComponentID_ != LAST_REPLICATED_ID)
@@ -553,7 +585,7 @@ unsigned Scene::GetFreeComponentID(CreateMode mode)
     {
         for (;;)
         {
-            if (!allComponents_.Contains(localComponentID_))
+            if (!localComponents_.Contains(localComponentID_))
                 return localComponentID_;
             
             if (localComponentID_ != LAST_LOCAL_ID)
@@ -573,15 +605,30 @@ void Scene::NodeAdded(Node* node)
     
     // If we already have an existing node with the same ID, must remove the scene reference from it
     unsigned id = node->GetID();
-    Map<unsigned, Node*>::Iterator i = allNodes_.Find(id);
-    if (i != allNodes_.End() && i->second_ != node)
+    if (id < FIRST_LOCAL_ID)
     {
-        LOGWARNING("Overwriting node with ID " + String(id));
-        i->second_->SetScene(0);
-        i->second_->SetOwner(0);
+        HashMap<unsigned, Node*>::Iterator i = replicatedNodes_.Find(id);
+        if (i != replicatedNodes_.End() && i->second_ != node)
+        {
+            LOGWARNING("Overwriting node with ID " + String(id));
+            i->second_->SetScene(0);
+            i->second_->SetOwner(0);
+        }
+        
+        replicatedNodes_[id] = node;
+    }
+    else
+    {
+        HashMap<unsigned, Node*>::Iterator i = localNodes_.Find(id);
+        if (i != localNodes_.End() && i->second_ != node)
+        {
+            LOGWARNING("Overwriting node with ID " + String(id));
+            i->second_->SetScene(0);
+            i->second_->SetOwner(0);
+        }
+        
+        localNodes_[id] = node;
     }
-    
-    allNodes_[id] = node;
 }
 
 void Scene::NodeRemoved(Node* node)
@@ -589,7 +636,12 @@ void Scene::NodeRemoved(Node* node)
     if (!node || node->GetScene() != this)
         return;
     
-    allNodes_.Erase(node->GetID());
+    unsigned id = node->GetID();
+    if (id < FIRST_LOCAL_ID)
+        replicatedNodes_.Erase(id);
+    else
+        localNodes_.Erase(id);
+    
     node->SetID(0);
     node->SetScene(0);
 }
@@ -600,11 +652,22 @@ void Scene::ComponentAdded(Component* component)
         return;
     
     unsigned id = component->GetID();
-    Map<unsigned, Component*>::Iterator i = allComponents_.Find(id);
-    if (i != allComponents_.End() && i->second_ != component)
-        LOGWARNING("Overwriting component with ID " + String(id));
-    
-    allComponents_[id] = component;
+    if (id < FIRST_LOCAL_ID)
+    {
+        HashMap<unsigned, Component*>::Iterator i = replicatedComponents_.Find(id);
+        if (i != replicatedComponents_.End() && i->second_ != component)
+            LOGWARNING("Overwriting component with ID " + String(id));
+        
+        replicatedComponents_[id] = component;
+    }
+    else
+    {
+        HashMap<unsigned, Component*>::Iterator i = localComponents_.Find(id);
+        if (i != localComponents_.End() && i->second_ != component)
+            LOGWARNING("Overwriting component with ID " + String(id));
+        
+        localComponents_[id] = component;
+    }
 }
 
 void Scene::ComponentRemoved(Component* component)
@@ -612,7 +675,12 @@ void Scene::ComponentRemoved(Component* component)
     if (!component)
         return;
     
-    allComponents_.Erase(component->GetID());
+    unsigned id = component->GetID();
+    if (id < FIRST_LOCAL_ID)
+        replicatedComponents_.Erase(id);
+    else
+        localComponents_.Erase(id);
+    
     component->SetID(0);
 }
 
@@ -629,7 +697,7 @@ String Scene::GetVarNamesAttr() const
 {
     String ret;
     
-    for (Map<ShortStringHash, String>::ConstIterator i = varNames_.Begin(); i != varNames_.End(); ++i)
+    for (HashMap<ShortStringHash, String>::ConstIterator i = varNames_.Begin(); i != varNames_.End(); ++i)
     {
         if (i != varNames_.Begin())
             ret += ';';

+ 12 - 10
Engine/Scene/Scene.h

@@ -131,11 +131,9 @@ public:
     float GetSnapThreshold() const { return snapThreshold_; }
     /// Return required package files.
     const Vector<SharedPtr<PackageFile> >& GetRequiredPackageFiles() const { return requiredPackageFiles_; }
-    /// Return all nodes.
-    const Map<unsigned, Node*>& GetAllNodes() const { return allNodes_; }
-    /// Return all components.
-    const Map<unsigned, Component*>& GetAllComponents() const { return allComponents_; }
-    /// Return a node var name, or empty if not registered.
+    /// Return all replicated scene nodes.
+    const HashMap<unsigned, Node*>& GetReplicatedNodes() const { return replicatedNodes_; }
+    /// Return a node user variable name, or empty if not registered.
     const String& GetVarName(ShortStringHash hash) const;
     
     /// Update scene. Called by HandleUpdate.
@@ -175,10 +173,14 @@ private:
     /// Finish loading. Sets the scene filename and checksum.
     void FinishLoading(Deserializer* source);
     
-    /// Map of scene nodes by ID.
-    Map<unsigned, Node*> allNodes_;
-    /// Map of components by ID.
-    Map<unsigned, Component*> allComponents_;
+    /// Replicated scene nodes by ID.
+    HashMap<unsigned, Node*> replicatedNodes_;
+    /// Local scene nodes by ID.
+    HashMap<unsigned, Node*> localNodes_;
+    /// Replicated components by ID.
+    HashMap<unsigned, Component*> replicatedComponents_;
+    /// Local components by ID.
+    HashMap<unsigned, Component*> localComponents_;
     /// Asynchronous loading progress.
     AsyncProgress asyncProgress_;
     /// Node and component ID resolver for asynchronous loading.
@@ -188,7 +190,7 @@ private:
     /// Required package files for networking.
     Vector<SharedPtr<PackageFile> > requiredPackageFiles_;
     /// Registered node user variable reverse mappings.
-    Map<ShortStringHash, String> varNames_;
+    HashMap<ShortStringHash, String> varNames_;
     /// Delayed dirty notification queue for components.
     PODVector<Component*> delayedDirtyComponents_;
     /// Mutex for the delayed dirty notification queue.

+ 25 - 29
Engine/Scene/Serializable.cpp

@@ -36,6 +36,7 @@ OBJECTTYPESTATIC(Serializable);
 Serializable::Serializable(Context* context) :
     Object(context),
     serverFrameNumber_(0),
+    networkAttributes_(0),
     loading_(false)
 {
 }
@@ -423,19 +424,20 @@ bool Serializable::SetAttribute(const String& name, const Variant& value)
 void Serializable::WriteInitialDeltaUpdate(unsigned frameNumber, Serializer& dest, PODVector<unsigned char>& deltaUpdateBits,
     Vector<Variant>& replicationState)
 {
-    const Vector<AttributeInfo>* attributes = GetNetworkAttributes();
-    if (!attributes)
+    networkAttributes_ = GetNetworkAttributes();
+    if (!networkAttributes_)
         return;
-    unsigned numAttributes = attributes->Size();
+    
+    unsigned numAttributes = networkAttributes_->Size();
     
     // Get current attribute values if necessary
-    if (frameNumber != serverFrameNumber_ || serverAttributes_.Empty())
+    if (frameNumber != serverFrameNumber_ || currentState_.Empty())
     {
-        serverAttributes_.Resize(numAttributes);
+        currentState_.Resize(numAttributes);
         for (unsigned i = 0; i < numAttributes; ++i)
         {
-            const AttributeInfo& attr = attributes->At(i);
-            OnGetAttribute(attr, serverAttributes_[i]);
+            const AttributeInfo& attr = networkAttributes_->At(i);
+            OnGetAttribute(attr, currentState_[i]);
         }
         serverFrameNumber_ = frameNumber;
     }
@@ -448,8 +450,8 @@ void Serializable::WriteInitialDeltaUpdate(unsigned frameNumber, Serializer& des
     // Copy attributes to replication state and compare against defaults
     for (unsigned i = 0; i < numAttributes; ++i)
     {
-        const AttributeInfo& attr = attributes->At(i);
-        replicationState[i] = serverAttributes_[i];
+        const AttributeInfo& attr = networkAttributes_->At(i);
+        replicationState[i] = currentState_[i];
         if (replicationState[i] != attr.defaultValue_)
             deltaUpdateBits[i >> 3] |= (1 << (i & 7));
     }
@@ -470,24 +472,18 @@ void Serializable::PrepareUpdates(unsigned frameNumber, PODVector<unsigned char>
     deltaUpdate = false;
     latestData = false;
     
-    const Vector<AttributeInfo>* attributes = GetNetworkAttributes();
-    if (!attributes)
+    if (!networkAttributes_ || currentState_.Empty())
         return;
-    unsigned numAttributes = attributes->Size();
     
-    if (numAttributes && serverAttributes_.Empty())
-    {
-        LOGWARNING("PrepareUpdates called without calling WriteInitialDeltaUpdate first");
-        serverAttributes_.Resize(numAttributes);
-    }
+    unsigned numAttributes = networkAttributes_->Size();
     
     // Get current attribute values if necessary
     if (frameNumber != serverFrameNumber_)
     {
         for (unsigned i = 0; i < numAttributes; ++i)
         {
-            const AttributeInfo& attr = attributes->At(i);
-            OnGetAttribute(attr, serverAttributes_[i]);
+            const AttributeInfo& attr = networkAttributes_->At(i);
+            OnGetAttribute(attr, currentState_[i]);
         }
         serverFrameNumber_ = frameNumber;
     }
@@ -498,10 +494,10 @@ void Serializable::PrepareUpdates(unsigned frameNumber, PODVector<unsigned char>
     
     for (unsigned i = 0; i < numAttributes; ++i)
     {
-        if (serverAttributes_[i] != replicationState[i])
+        if (currentState_[i] != replicationState[i])
         {
-            const AttributeInfo& attr = attributes->At(i);
-            replicationState[i] = serverAttributes_[i];
+            const AttributeInfo& attr = networkAttributes_->At(i);
+            replicationState[i] = currentState_[i];
             if (attr.mode_ & AM_LATESTDATA)
                 latestData = true;
             else
@@ -515,10 +511,10 @@ void Serializable::PrepareUpdates(unsigned frameNumber, PODVector<unsigned char>
 
 void Serializable::WriteDeltaUpdate(Serializer& dest, PODVector<unsigned char>& deltaUpdateBits, Vector<Variant>& replicationState)
 {
-    const Vector<AttributeInfo>* attributes = GetNetworkAttributes();
-    if (!attributes)
+    if (!networkAttributes_)
         return;
-    unsigned numAttributes = attributes->Size();
+    
+    unsigned numAttributes = networkAttributes_->Size();
     
     // First write the change bitfield, then attribute data for changed attributes
     dest.Write(&deltaUpdateBits[0], deltaUpdateBits.Size());
@@ -532,14 +528,14 @@ void Serializable::WriteDeltaUpdate(Serializer& dest, PODVector<unsigned char>&
 
 void Serializable::WriteLatestDataUpdate(Serializer& dest, Vector<Variant>& replicationState)
 {
-    const Vector<AttributeInfo>* attributes = GetNetworkAttributes();
-    if (!attributes)
+    if (!networkAttributes_)
         return;
-    unsigned numAttributes = attributes->Size();
+    
+    unsigned numAttributes = networkAttributes_->Size();
     
     for (unsigned i = 0; i < numAttributes; ++i)
     {
-        if (attributes->At(i).mode_ & AM_LATESTDATA)
+        if (networkAttributes_->At(i).mode_ & AM_LATESTDATA)
             dest.WriteVariantData(replicationState[i]);
     }
 }

+ 4 - 2
Engine/Scene/Serializable.h

@@ -91,8 +91,10 @@ public:
     bool IsLoading() const { return loading_; }
     
 private:
-    /// Server-side attributes for sending updates. Only updated once per network frame, not per user.
-    Vector<Variant> serverAttributes_;
+    /// Current attributes for sending network updates. Updated only once per network frame, not per user.
+    Vector<Variant> currentState_;
+    /// Cached network attribute infos.
+    mutable const Vector<AttributeInfo>* networkAttributes_;
     /// Last server frame number.
     unsigned serverFrameNumber_;
     /// Is loading flag.