Browse Source

Added possibility to clear scene of only replicated or local content. Do not clear local content from a client scene when joining a server. This makes the startup of the SceneReplication sample faster, as the static scene is not replicated.
Exposed missing Node::RemoveAllComponents() to script.

Lasse Öörni 12 years ago
parent
commit
3b32acf27f

+ 2 - 3
Source/Engine/Network/Connection.cpp

@@ -1380,11 +1380,10 @@ void Connection::OnPackagesReady()
     
     if (sceneFileName_.Empty())
     {
-        /// \todo Should not clear local nodes
-        scene_->Clear();
+        // If the scene filename is empty, just clear the scene of all existing replicated content, and send the loaded reply
+        scene_->Clear(true, false);
         sceneLoaded_ = true;
         
-        // If filename is empty, can send the scene loaded reply immediately
         msg_.Clear();
         msg_.WriteUInt(scene_->GetChecksum());
         SendMessage(MSG_SCENELOADED, true, true, msg_);

+ 58 - 8
Source/Engine/Scene/Node.cpp

@@ -577,8 +577,37 @@ void Node::RemoveChild(Node* node)
 
 void Node::RemoveAllChildren()
 {
-    while (children_.Size())
-        RemoveChild(--children_.End());
+    RemoveChildren(true, true, true);
+}
+
+void Node::RemoveChildren(bool removeReplicated, bool removeLocal, bool recursive)
+{
+    unsigned numRemoved = 0;
+    
+    for (unsigned i = 0; i < children_.Size();)
+    {
+        bool remove = false;
+        Node* childNode = children_[i];
+        
+        if (recursive)
+            childNode->RemoveChildren(removeReplicated, removeLocal, true);
+        if (childNode->GetID() < FIRST_LOCAL_ID && removeReplicated)
+            remove = true;
+        else if (childNode->GetID() >= FIRST_LOCAL_ID && removeLocal)
+            remove = true;
+        
+        if (remove)
+        {
+            RemoveChild(children_.Begin() + i);
+            ++numRemoved;
+        }
+        else
+            ++i;
+    }
+    
+    // Mark node dirty in all replication states
+    if (numRemoved)
+        MarkReplicationDirty();
 }
 
 Component* Node::CreateComponent(ShortStringHash type, CreateMode mode, unsigned id)
@@ -636,14 +665,35 @@ void Node::RemoveComponent(ShortStringHash type)
 
 void Node::RemoveAllComponents()
 {
-    if (components_.Empty())
-        return;
-
-    while (components_.Size())
-        RemoveComponent(--components_.End());
+    RemoveComponents(true, true);
+}
 
+void Node::RemoveComponents(bool removeReplicated, bool removeLocal)
+{
+    unsigned numRemoved = 0;
+    
+    for (unsigned i = 0; i < components_.Size();)
+    {
+        bool remove = false;
+        Component* component = components_[i];
+        
+        if (component->GetID() < FIRST_LOCAL_ID && removeReplicated)
+            remove = true;
+        else if (component->GetID() >= FIRST_LOCAL_ID && removeLocal)
+            remove = true;
+        
+        if (remove)
+        {
+            RemoveComponent(components_.Begin() + i);
+            ++numRemoved;
+        }
+        else
+            ++i;
+    }
+    
     // Mark node dirty in all replication states
-    MarkReplicationDirty();
+    if (numRemoved)
+        MarkReplicationDirty();
 }
 
 Node* Node::Clone(CreateMode mode)

+ 4 - 0
Source/Engine/Scene/Node.h

@@ -145,6 +145,8 @@ public:
     void RemoveChild(Node* node);
     /// Remove all child scene nodes.
     void RemoveAllChildren();
+    /// Remove child scene nodes that match criteria.
+    void RemoveChildren(bool removeReplicated, bool removeLocal, bool recursive);
     /// Create a component to this node (with specified ID if provided).
     Component* CreateComponent(ShortStringHash type, CreateMode mode = REPLICATED, unsigned id = 0);
     /// Create a component to this node if it does not exist already.
@@ -155,6 +157,8 @@ public:
     void RemoveComponent(ShortStringHash type);
     /// Remove all components from this node.
     void RemoveAllComponents();
+    /// Remove components that match criteria.
+    void RemoveComponents(bool removeReplicated, bool removeLocal);
     /// Clone scene node, components and child nodes. Return the clone.
     Node* Clone(CreateMode mode = REPLICATED);
     /// Remove from the parent node. If no other shared pointer references exist, causes immediate deletion.

+ 25 - 11
Source/Engine/Scene/Scene.cpp

@@ -375,19 +375,33 @@ Node* Scene::InstantiateXML(Deserializer& source, const Vector3& position, const
     return InstantiateXML(xml->GetRoot(), position, rotation, mode);
 }
 
-void Scene::Clear()
+void Scene::Clear(bool clearReplicated, bool clearLocal)
 {
     StopAsyncLoading();
-    RemoveAllChildren();
-    RemoveAllComponents();
-    UnregisterAllVars();
-    SetName(String::EMPTY);
-    fileName_.Clear();
-    checksum_ = 0;
-    replicatedNodeID_ = FIRST_REPLICATED_ID;
-    replicatedComponentID_ = FIRST_REPLICATED_ID;
-    localNodeID_ = FIRST_LOCAL_ID;
-    localComponentID_ = FIRST_LOCAL_ID;
+    
+    RemoveChildren(clearReplicated, clearLocal, true);
+    RemoveComponents(clearReplicated, clearLocal);
+    
+    // Only clear name etc. if clearing completely
+    if (clearReplicated && clearLocal)
+    {
+        UnregisterAllVars();
+        SetName(String::EMPTY);
+        fileName_.Clear();
+        checksum_ = 0;
+    }
+    
+    // Reset ID generators
+    if (clearReplicated)
+    {
+        replicatedNodeID_ = FIRST_REPLICATED_ID;
+        replicatedComponentID_ = FIRST_REPLICATED_ID;
+    }
+    if (clearLocal)
+    {
+        localNodeID_ = FIRST_LOCAL_ID;
+        localComponentID_ = FIRST_LOCAL_ID;
+    }
 }
 
 void Scene::SetUpdateEnabled(bool enable)

+ 2 - 2
Source/Engine/Scene/Scene.h

@@ -95,8 +95,8 @@ public:
     Node* InstantiateXML(const XMLElement& source, const Vector3& position, const Quaternion& rotation, CreateMode mode = REPLICATED);
     /// Instantiate scene content from XML data. Return root node if successful.
     Node* InstantiateXML(Deserializer& source, const Vector3& position, const Quaternion& rotation, CreateMode mode = REPLICATED);
-    /// Clear scene completely of nodes and components.
-    void Clear();
+    /// Clear scene completely of either replicated, local or all nodes and components.
+    void Clear(bool clearReplicated = true, bool clearLocal = true);
     /// Enable or disable scene update.
     void SetUpdateEnabled(bool enable);
     /// Set update time scale. 1.0 = real time (default.)

+ 3 - 0
Source/Engine/Script/APITemplates.h

@@ -553,11 +553,14 @@ template <class T> void RegisterNode(asIScriptEngine* engine, const char* classN
     engine->RegisterObjectMethod(className, "void AddChild(Node@+)", asMETHOD(T, AddChild), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void RemoveChild(Node@+)", asMETHODPR(T, RemoveChild, (Node*), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void RemoveAllChildren()", asMETHOD(T, RemoveAllChildren), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "void RemoveChildren(bool, bool, bool)", asMETHOD(T, RemoveChildren), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void Remove()", asMETHOD(T, Remove), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "Component@+ CreateComponent(const String&in, CreateMode mode = REPLICATED, uint id = 0)", asFUNCTION(NodeCreateComponent), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "Component@+ GetOrCreateComponent(const String&in, CreateMode mode = REPLICATED, uint id = 0)", asFUNCTION(NodeGetOrCreateComponent), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "void RemoveComponent(Component@+)", asMETHODPR(T, RemoveComponent, (Component*), void), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "void RemoveComponent(const String&in)", asFUNCTION(NodeRemoveComponent), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod(className, "void RemoveAllComponents()", asMETHOD(T, RemoveAllComponents), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "void RemoveComponents(bool, bool)", asMETHOD(T, RemoveComponents), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildren(bool recursive = false) const", asFUNCTION(NodeGetChildren), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildrenWithComponent(const String&in, bool recursive = false) const", asFUNCTION(NodeGetChildrenWithComponent), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod(className, "Array<Node@>@ GetChildrenWithScript(bool recursive = false) const", asFUNCTION(NodeGetChildrenWithScript), asCALL_CDECL_OBJLAST);

+ 1 - 1
Source/Engine/Script/SceneAPI.cpp

@@ -188,7 +188,7 @@ static void RegisterScene(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Scene", "Node@+ InstantiateXML(File@+, const Vector3&in, const Quaternion&in, CreateMode mode = REPLICATED)", asFUNCTION(SceneInstantiateXML), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Scene", "Node@+ InstantiateXML(XMLFile@+, const Vector3&in, const Quaternion&in, CreateMode mode = REPLICATED)", asFUNCTION(SceneInstantiateXMLFile), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Scene", "Node@+ InstantiateXML(const XMLElement&in, const Vector3&in, const Quaternion&in, CreateMode mode = REPLICATED)", asMETHODPR(Scene, InstantiateXML, (const XMLElement&, const Vector3&, const Quaternion&, CreateMode), Node*), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Scene", "void Clear()", asMETHOD(Scene, Clear), asCALL_THISCALL);
+    engine->RegisterObjectMethod("Scene", "void Clear(bool clearReplicated = true, bool clearLocal = true)", asMETHOD(Scene, Clear), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void AddRequiredPackageFile(PackageFile@+)", asMETHOD(Scene, AddRequiredPackageFile), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void ClearRequiredPackageFiles()", asMETHOD(Scene, ClearRequiredPackageFiles), asCALL_THISCALL);
     engine->RegisterObjectMethod("Scene", "void RegisterVar(const String&in)", asMETHOD(Scene, RegisterVar), asCALL_THISCALL);

+ 2 - 0
Source/Extras/LuaScript/pkgs/Scene/Node.pkg

@@ -72,11 +72,13 @@ class Node : public Serializable
     void AddChild(Node* node);
     void RemoveChild(Node* node);
     void RemoveAllChildren();
+    void RemoveChildren(bool removeReplicated, bool removeLocal, bool recursive);
     void RemoveComponent(Component* component);
     void RemoveComponent(ShortStringHash type);
     void RemoveComponent(const char* type);
     
     void RemoveAllComponents();
+    void RemoveComponents(bool removeReplicated, bool removeLocal);
     
     Node* Clone(CreateMode mode = REPLICATED);
     

+ 1 - 1
Source/Extras/LuaScript/pkgs/Scene/Scene.pkg

@@ -15,7 +15,7 @@ class Scene : public Node
     bool LoadAsync(File* file);
     bool LoadAsyncXML(File* file);
     void StopAsyncLoading();
-    void Clear();
+    void Clear(bool clearReplicated = true, bool clearLocal = true);
     void SetUpdateEnabled(bool enable);
     void SetTimeScale(float scale);
     void SetElapsedTime(float time);

+ 51 - 50
Source/Samples/17_SceneReplication/SceneReplication.cpp

@@ -100,9 +100,52 @@ void SceneReplication::CreateScene()
 {
     scene_ = new Scene(context_);
     
-    // Create the camera. Limit far clip distance to match the fog. Camera is created outside the scene so that network
-    // replication will not affect it (the scene will be cleared when connecting as a client)
-    cameraNode_ = new Node(context_);
+    // Create scene content on the server only
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    
+    // Create octree and physics world with default settings. Create them as local so that they are not needlessly replicated
+    // when a client connects
+    scene_->CreateComponent<Octree>(LOCAL);
+    scene_->CreateComponent<PhysicsWorld>(LOCAL);
+    
+    // All static scene content and the camera are also created as local, so that they are unaffected by scene replication and are
+    // not removed from the client upon connection. Create a Zone component first for ambient lighting & fog control.
+    Node* zoneNode = scene_->CreateChild("Zone", LOCAL);
+    Zone* zone = zoneNode->CreateComponent<Zone>();
+    zone->SetBoundingBox(BoundingBox(-1000.0f, 1000.0f));
+    zone->SetAmbientColor(Color(0.1f, 0.1f, 0.1f));
+    zone->SetFogStart(100.0f);
+    zone->SetFogEnd(300.0f);
+    
+    // Create a directional light without shadows
+    Node* lightNode = scene_->CreateChild("DirectionalLight", LOCAL);
+    lightNode->SetDirection(Vector3(0.5f, -1.0f, 0.5f));
+    Light* light = lightNode->CreateComponent<Light>();
+    light->SetLightType(LIGHT_DIRECTIONAL);
+    light->SetColor(Color(0.2f, 0.2f, 0.2f));
+    light->SetSpecularIntensity(1.0f);
+    
+    // Create a "floor" consisting of several tiles. Make the tiles physical but leave small cracks between them
+    for (int y = -20; y <= 20; ++y)
+    {
+        for (int x = -20; x <= 20; ++x)
+        {
+            Node* floorNode = scene_->CreateChild("FloorTile", LOCAL);
+            floorNode->SetPosition(Vector3(x * 20.2f, -0.5f, y * 20.2f));
+            floorNode->SetScale(Vector3(20.0f, 1.0f, 20.0f));
+            StaticModel* floorObject = floorNode->CreateComponent<StaticModel>();
+            floorObject->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
+            floorObject->SetMaterial(cache->GetResource<Material>("Materials/Stone.xml"));
+            
+            RigidBody* body = floorNode->CreateComponent<RigidBody>();
+            body->SetFriction(1.0f);
+            CollisionShape* shape = floorNode->CreateComponent<CollisionShape>();
+            shape->SetBox(Vector3::ONE);
+        }
+    }
+    
+    // Create the camera. Limit far clip distance to match the fog
+    cameraNode_ = scene_->CreateChild("Camera", LOCAL);
     Camera* camera = cameraNode_->CreateComponent<Camera>();
     camera->SetFarClip(300.0f);
     
@@ -224,7 +267,7 @@ Node* SceneReplication::CreateControllableObject()
 {
     ResourceCache* cache = GetSubsystem<ResourceCache>();
     
-    // Create the scene node & visual representation
+    // Create the scene node & visual representation. This will be a replicated object
     Node* ballNode = scene_->CreateChild("Ball");
     ballNode->SetPosition(Vector3(Random(40.0f) - 20.0f, 5.0f, Random(40.0f) - 20.0f));
     ballNode->SetScale(0.5f);
@@ -389,21 +432,21 @@ void SceneReplication::HandleDisconnect(StringHash eventType, VariantMap& eventD
 {
     Network* network = GetSubsystem<Network>();
     Connection* serverConnection = network->GetServerConnection();
-    // If we were connected to server, disconnect
+    // If we were connected to server, disconnect. Or if we were running a server, stop it. In both cases clear the
+    // scene of all replicated content, but let the local nodes & components (the static world + camera) stay
     if (serverConnection)
     {
         serverConnection->Disconnect();
-        scene_->Clear();
+        scene_->Clear(true, false);
         clientObjectID_ = 0;
     }
     // Or if we were running a server, stop it
     else if (network->IsServerRunning())
     {
         network->StopServer();
-        scene_->Clear();
+        scene_->Clear(true, false);
     }
     
-    
     UpdateButtons();
 }
 
@@ -412,48 +455,6 @@ void SceneReplication::HandleStartServer(StringHash eventType, VariantMap& event
     Network* network = GetSubsystem<Network>();
     network->StartServer(SERVER_PORT);
     
-    // Create scene content on the server only
-    ResourceCache* cache = GetSubsystem<ResourceCache>();
-    
-    // Create octree and physics world with default settings
-    scene_->CreateComponent<Octree>();
-    scene_->CreateComponent<PhysicsWorld>();
-    
-    // Create a Zone component for ambient lighting & fog control
-    Node* zoneNode = scene_->CreateChild("Zone");
-    Zone* zone = zoneNode->CreateComponent<Zone>();
-    zone->SetBoundingBox(BoundingBox(-1000.0f, 1000.0f));
-    zone->SetAmbientColor(Color(0.1f, 0.1f, 0.1f));
-    zone->SetFogStart(100.0f);
-    zone->SetFogEnd(300.0f);
-    
-    // Create a directional light without shadows
-    Node* lightNode = scene_->CreateChild("DirectionalLight");
-    lightNode->SetDirection(Vector3(0.5f, -1.0f, 0.5f));
-    Light* light = lightNode->CreateComponent<Light>();
-    light->SetLightType(LIGHT_DIRECTIONAL);
-    light->SetColor(Color(0.2f, 0.2f, 0.2f));
-    light->SetSpecularIntensity(1.0f);
-    
-    // Create a "floor" consisting of several tiles. Make the tiles physical but leave small cracks between them
-    for (int y = -20; y <= 20; ++y)
-    {
-        for (int x = -20; x <= 20; ++x)
-        {
-            Node* floorNode = scene_->CreateChild("FloorTile");
-            floorNode->SetPosition(Vector3(x * 20.2f, -0.5f, y * 20.2f));
-            floorNode->SetScale(Vector3(20.0f, 1.0f, 20.0f));
-            StaticModel* floorObject = floorNode->CreateComponent<StaticModel>();
-            floorObject->SetModel(cache->GetResource<Model>("Models/Box.mdl"));
-            floorObject->SetMaterial(cache->GetResource<Material>("Materials/Stone.xml"));
-            
-            RigidBody* body = floorNode->CreateComponent<RigidBody>();
-            body->SetFriction(1.0f);
-            CollisionShape* shape = floorNode->CreateComponent<CollisionShape>();
-            shape->SetBox(Vector3::ONE);
-        }
-    }
-    
     UpdateButtons();
 }