Browse Source

Initial work to separate Component's association with its owner node and scene (OnNodeSet() and OnSceneSet()). This should allow components to work properly when moved from one scene to another, or when created initially outside a scene, and be removed from rendering & physics when removed from the scene, even if the node's refcount keeps it alive after the removal.

Lasse Öörni 10 years ago
parent
commit
52b739e2a4

+ 5 - 7
Source/Urho3D/Graphics/AnimationController.cpp

@@ -757,14 +757,12 @@ VariantVector AnimationController::GetNodeAnimationStatesAttr() const
     return ret;
     return ret;
 }
 }
 
 
-void AnimationController::OnNodeSet(Node* node)
+void AnimationController::OnSceneSet(Scene* scene)
 {
 {
-    if (node)
-    {
-        Scene* scene = GetScene();
-        if (scene && IsEnabledEffective())
-            SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(AnimationController, HandleScenePostUpdate));
-    }
+    if (scene && IsEnabledEffective())
+        SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(AnimationController, HandleScenePostUpdate));
+    else if (!scene)
+        UnsubscribeFromEvent(E_SCENEPOSTUPDATE);
 }
 }
 
 
 AnimationState* AnimationController::AddAnimationState(Animation* animation)
 AnimationState* AnimationController::AddAnimationState(Animation* animation)

+ 2 - 2
Source/Urho3D/Graphics/AnimationController.h

@@ -174,8 +174,8 @@ public:
     VariantVector GetNodeAnimationStatesAttr() const;
     VariantVector GetNodeAnimationStatesAttr() const;
 
 
 protected:
 protected:
-    /// Handle node being assigned.
-    virtual void OnNodeSet(Node* node);
+    /// Handle scene being assigned.
+    virtual void OnSceneSet(Scene* scene);
 
 
 private:
 private:
     /// Add an animation state either to AnimatedModel or as a node animation.
     /// Add an animation state either to AnimatedModel or as a node animation.

+ 6 - 3
Source/Urho3D/Graphics/Drawable.cpp

@@ -359,10 +359,13 @@ void Drawable::LimitVertexLights(bool removeConvertedLights)
 void Drawable::OnNodeSet(Node* node)
 void Drawable::OnNodeSet(Node* node)
 {
 {
     if (node)
     if (node)
-    {
-        AddToOctree();
         node->AddListener(this);
         node->AddListener(this);
-    }
+}
+
+void Drawable::OnSceneSet(Scene* scene)
+{
+    if (scene)
+        AddToOctree();
     else
     else
         RemoveFromOctree();
         RemoveFromOctree();
 }
 }

+ 2 - 0
Source/Urho3D/Graphics/Drawable.h

@@ -257,6 +257,8 @@ public:
 protected:
 protected:
     /// Handle node being assigned.
     /// Handle node being assigned.
     virtual void OnNodeSet(Node* node);
     virtual void OnNodeSet(Node* node);
+    /// Handle scene being assigned.
+    virtual void OnSceneSet(Scene* scene);
     /// Handle node transform being dirtied.
     /// Handle node transform being dirtied.
     virtual void OnMarkedDirty(Node* node);
     virtual void OnMarkedDirty(Node* node);
     /// Recalculate the world-space bounding box.
     /// Recalculate the world-space bounding box.

+ 6 - 8
Source/Urho3D/Graphics/ParticleEmitter.cpp

@@ -408,16 +408,14 @@ VariantVector ParticleEmitter::GetParticleBillboardsAttr() const
     return ret;
     return ret;
 }
 }
 
 
-void ParticleEmitter::OnNodeSet(Node* node)
+void ParticleEmitter::OnSceneSet(Scene* scene)
 {
 {
-    BillboardSet::OnNodeSet(node);
+    BillboardSet::OnSceneSet(scene);
 
 
-    if (node)
-    {
-        Scene* scene = GetScene();
-        if (scene && IsEnabledEffective())
-            SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(ParticleEmitter, HandleScenePostUpdate));
-    }
+    if (scene && IsEnabledEffective())
+        SubscribeToEvent(scene, E_SCENEPOSTUPDATE, HANDLER(ParticleEmitter, HandleScenePostUpdate));
+    else if (!scene)
+         UnsubscribeFromEvent(E_SCENEPOSTUPDATE);
 }
 }
 
 
 bool ParticleEmitter::EmitNewParticle()
 bool ParticleEmitter::EmitNewParticle()

+ 2 - 2
Source/Urho3D/Graphics/ParticleEmitter.h

@@ -106,8 +106,8 @@ public:
     VariantVector GetParticleBillboardsAttr() const;
     VariantVector GetParticleBillboardsAttr() const;
 
 
 protected:
 protected:
-    /// Handle node being assigned.
-    virtual void OnNodeSet(Node* node);
+    /// Handle scene being assigned.
+    virtual void OnSceneSet(Scene* scene);
 
 
     /// Create a new particle. Return true if there was room.
     /// Create a new particle. Return true if there was room.
     bool EmitNewParticle();
     bool EmitNewParticle();

+ 10 - 10
Source/Urho3D/Navigation/CrowdAgent.cpp

@@ -107,17 +107,17 @@ void CrowdAgent::RegisterObject(Context* context)
 void CrowdAgent::OnNodeSet(Node* node)
 void CrowdAgent::OnNodeSet(Node* node)
 {
 {
     if (node)
     if (node)
-    {
-        Scene* scene = GetScene();
-        if (scene)
-        {
-            if (scene == node)
-                LOGERROR(GetTypeName() + " should not be created to the root scene node");
-            crowdManager_ = scene->GetOrCreateComponent<DetourCrowdManager>();
-            AddAgentToCrowd();
-        }
-
         node->AddListener(this);
         node->AddListener(this);
+}
+
+void CrowdAgent::OnSceneSet(Scene* scene)
+{
+    if (scene)
+    {
+        if (scene == node_)
+            LOGERROR(GetTypeName() + " should not be created to the root scene node");
+        crowdManager_ = scene->GetOrCreateComponent<DetourCrowdManager>();
+        AddAgentToCrowd();
     }
     }
     else
     else
         RemoveAgentFromCrowd();
         RemoveAgentFromCrowd();

+ 2 - 0
Source/Urho3D/Navigation/CrowdAgent.h

@@ -133,6 +133,8 @@ protected:
     virtual void OnCrowdAgentReposition(const Vector3& newPos, const Vector3& newVel);
     virtual void OnCrowdAgentReposition(const Vector3& newPos, const Vector3& newVel);
     /// Handle node being assigned.
     /// Handle node being assigned.
     virtual void OnNodeSet(Node* node);
     virtual void OnNodeSet(Node* node);
+    /// Handle node being assigned.
+    virtual void OnSceneSet(Scene* scene);
     /// \todo Handle node transform being dirtied.
     /// \todo Handle node transform being dirtied.
     virtual void OnMarkedDirty(Node* node);
     virtual void OnMarkedDirty(Node* node);
     /// Get internal Detour crowd agent.
     /// Get internal Detour crowd agent.

+ 14 - 6
Source/Urho3D/Navigation/DetourCrowdManager.cpp

@@ -78,7 +78,7 @@ void DetourCrowdManager::RegisterObject(Context* context)
 
 
 void DetourCrowdManager::SetNavigationMesh(NavigationMesh* navMesh)
 void DetourCrowdManager::SetNavigationMesh(NavigationMesh* navMesh)
 {
 {
-    navigationMesh_ = WeakPtr<NavigationMesh>(navMesh);
+    navigationMesh_ = navMesh;
     if (navigationMesh_ && !navigationMesh_->navMeshQuery_)
     if (navigationMesh_ && !navigationMesh_->navMeshQuery_)
         navigationMesh_->InitializeQuery();
         navigationMesh_->InitializeQuery();
     CreateCrowd();
     CreateCrowd();
@@ -514,23 +514,31 @@ void DetourCrowdManager::HandleNavMeshFullRebuild(StringHash eventType, VariantM
     }
     }
 }
 }
 
 
-void DetourCrowdManager::OnNodeSet(Node* node)
+void DetourCrowdManager::OnSceneSet(Scene* scene)
 {
 {
     // Subscribe to the scene subsystem update, which will trigger the crowd update step, and grab a reference
     // Subscribe to the scene subsystem update, which will trigger the crowd update step, and grab a reference
     // to the scene's NavigationMesh
     // to the scene's NavigationMesh
-    if (node)
+    if (scene)
     {
     {
-        SubscribeToEvent(node, E_SCENESUBSYSTEMUPDATE, HANDLER(DetourCrowdManager, HandleSceneSubsystemUpdate));
-        SubscribeToEvent(node, E_NAVIGATION_MESH_REBUILT, HANDLER(DetourCrowdManager, HandleNavMeshFullRebuild));
-
+        SubscribeToEvent(scene, E_SCENESUBSYSTEMUPDATE, HANDLER(DetourCrowdManager, HandleSceneSubsystemUpdate));
         NavigationMesh* mesh = GetScene()->GetComponent<NavigationMesh>();
         NavigationMesh* mesh = GetScene()->GetComponent<NavigationMesh>();
         if (!mesh)
         if (!mesh)
             mesh = GetScene()->GetComponent<DynamicNavigationMesh>();
             mesh = GetScene()->GetComponent<DynamicNavigationMesh>();
         if (mesh)
         if (mesh)
+        {
+            SubscribeToEvent(mesh, E_NAVIGATION_MESH_REBUILT, HANDLER(DetourCrowdManager, HandleNavMeshFullRebuild));
             SetNavigationMesh(mesh);
             SetNavigationMesh(mesh);
+        }
         else
         else
             LOGERROR("DetourCrowdManager requires an existing navigation mesh");
             LOGERROR("DetourCrowdManager requires an existing navigation mesh");
     }
     }
+    else
+    {
+        UnsubscribeFromEvent(E_SCENESUBSYSTEMUPDATE);
+        UnsubscribeFromEvent(E_NAVIGATION_MESH_REBUILT);
+        navigationMesh_.Reset();
+    }
+
 }
 }
 
 
 }
 }

+ 2 - 2
Source/Urho3D/Navigation/DetourCrowdManager.h

@@ -116,8 +116,8 @@ protected:
 protected:
 protected:
     /// Update the crowd simulation.
     /// Update the crowd simulation.
     void Update(float delta);
     void Update(float delta);
-    /// Handle node being assigned.
-    virtual void OnNodeSet(Node* node);
+    /// Handle scene being assigned.
+    virtual void OnSceneSet(Scene* scene);
     /// Get the detour crowd agent.
     /// Get the detour crowd agent.
     const dtCrowdAgent* GetCrowdAgent(int agent);
     const dtCrowdAgent* GetCrowdAgent(int agent);
     /// Get the internal detour crowd component.
     /// Get the internal detour crowd component.

+ 4 - 4
Source/Urho3D/Navigation/Obstacle.cpp

@@ -85,17 +85,17 @@ void Obstacle::SetRadius(float newRadius)
     MarkNetworkUpdate();
     MarkNetworkUpdate();
 }
 }
 
 
-void Obstacle::OnNodeSet(Node* node)
+void Obstacle::OnSceneSet(Scene* scene)
 {
 {
-    if (node)
+    if (scene)
     {
     {
-        if (GetScene() == node)
+        if (scene == node_)
         {
         {
             LOGWARNING(GetTypeName() + " should not be created to the root scene node");
             LOGWARNING(GetTypeName() + " should not be created to the root scene node");
             return;
             return;
         }
         }
         if (!ownerMesh_)
         if (!ownerMesh_)
-            ownerMesh_ = GetScene()->GetComponent<DynamicNavigationMesh>();
+            ownerMesh_ = scene->GetComponent<DynamicNavigationMesh>();
         if (ownerMesh_)
         if (ownerMesh_)
             ownerMesh_->AddObstacle(this);
             ownerMesh_->AddObstacle(this);
     }
     }

+ 2 - 2
Source/Urho3D/Navigation/Obstacle.h

@@ -66,8 +66,8 @@ public:
     void DrawDebugGeometry(bool depthTest);
     void DrawDebugGeometry(bool depthTest);
 
 
 protected:
 protected:
-    /// Handle node being assigned, identify our DynamicNavigationMesh.
-    virtual void OnNodeSet(Node* node);
+    /// Handle scene being assigned, identify our DynamicNavigationMesh.
+    virtual void OnSceneSet(Scene* scene);
 
 
 private:
 private:
     /// Radius of this obstacle.
     /// Radius of this obstacle.

+ 19 - 12
Source/Urho3D/Physics/CollisionShape.cpp

@@ -914,18 +914,6 @@ void CollisionShape::OnNodeSet(Node* node)
 {
 {
     if (node)
     if (node)
     {
     {
-        Scene* scene = GetScene();
-        if (scene)
-        {
-            if (scene == node)
-                LOGWARNING(GetTypeName() + " should not be created to the root scene node");
-
-            physicsWorld_ = scene->GetOrCreateComponent<PhysicsWorld>();
-            physicsWorld_->AddCollisionShape(this);
-        }
-        else
-            LOGERROR("Node is detached from scene, can not create collision shape");
-
         node->AddListener(this);
         node->AddListener(this);
         cachedWorldScale_ = node->GetWorldScale();
         cachedWorldScale_ = node->GetWorldScale();
 
 
@@ -934,6 +922,25 @@ void CollisionShape::OnNodeSet(Node* node)
     }
     }
 }
 }
 
 
+void CollisionShape::OnSceneSet(Scene* scene)
+{
+    if (scene)
+    {
+        if (scene == node_)
+            LOGWARNING(GetTypeName() + " should not be created to the root scene node");
+
+        physicsWorld_ = scene->GetOrCreateComponent<PhysicsWorld>();
+        physicsWorld_->AddCollisionShape(this);
+    }
+    else
+    {
+        ReleaseShape();
+
+        if (physicsWorld_)
+            physicsWorld_->RemoveCollisionShape(this);
+    }
+}
+
 void CollisionShape::OnMarkedDirty(Node* node)
 void CollisionShape::OnMarkedDirty(Node* node)
 {
 {
     Vector3 newWorldScale = node_->GetWorldScale();
     Vector3 newWorldScale = node_->GetWorldScale();

+ 2 - 0
Source/Urho3D/Physics/CollisionShape.h

@@ -221,6 +221,8 @@ public:
 protected:
 protected:
     /// Handle node being assigned.
     /// Handle node being assigned.
     virtual void OnNodeSet(Node* node);
     virtual void OnNodeSet(Node* node);
+    /// Handle scene being assigned.
+    virtual void OnSceneSet(Scene* scene);
     /// Handle node transform being dirtied.
     /// Handle node transform being dirtied.
     virtual void OnMarkedDirty(Node* node);
     virtual void OnMarkedDirty(Node* node);
 
 

+ 19 - 12
Source/Urho3D/Physics/Constraint.cpp

@@ -441,23 +441,30 @@ void Constraint::OnNodeSet(Node* node)
 {
 {
     if (node)
     if (node)
     {
     {
-        Scene* scene = GetScene();
-        if (scene)
-        {
-            if (scene == node)
-                LOGWARNING(GetTypeName() + " should not be created to the root scene node");
-
-            physicsWorld_ = scene->GetOrCreateComponent<PhysicsWorld>();
-            physicsWorld_->AddConstraint(this);
-        }
-        else
-            LOGERROR("Node is detached from scene, can not create constraint");
-
         node->AddListener(this);
         node->AddListener(this);
         cachedWorldScale_ = node->GetWorldScale();
         cachedWorldScale_ = node->GetWorldScale();
     }
     }
 }
 }
 
 
+void Constraint::OnSceneSet(Scene* scene)
+{
+    if (scene)
+    {
+        if (scene == node_)
+            LOGWARNING(GetTypeName() + " should not be created to the root scene node");
+
+        physicsWorld_ = scene->GetOrCreateComponent<PhysicsWorld>();
+        physicsWorld_->AddConstraint(this);
+    }
+    else
+    {
+        ReleaseConstraint();
+
+        if (physicsWorld_)
+            physicsWorld_->RemoveConstraint(this);
+    }
+}
+
 void Constraint::OnMarkedDirty(Node* node)
 void Constraint::OnMarkedDirty(Node* node)
 {
 {
     /// \todo This does not catch the connected body node's scale changing
     /// \todo This does not catch the connected body node's scale changing

+ 2 - 0
Source/Urho3D/Physics/Constraint.h

@@ -136,6 +136,8 @@ public:
 protected:
 protected:
     /// Handle node being assigned.
     /// Handle node being assigned.
     virtual void OnNodeSet(Node* node);
     virtual void OnNodeSet(Node* node);
+    /// Handle scene being assigned.
+    virtual void OnSceneSet(Scene* scene);
     /// Handle node transform being dirtied.
     /// Handle node transform being dirtied.
     virtual void OnMarkedDirty(Node* node);
     virtual void OnMarkedDirty(Node* node);
     
     

+ 5 - 3
Source/Urho3D/Physics/PhysicsWorld.cpp

@@ -653,14 +653,16 @@ void PhysicsWorld::CleanupGeometryCache()
     }
     }
 }
 }
 
 
-void PhysicsWorld::OnNodeSet(Node* node)
+void PhysicsWorld::OnSceneSet(Scene* scene)
 {
 {
     // Subscribe to the scene subsystem update, which will trigger the physics simulation step
     // Subscribe to the scene subsystem update, which will trigger the physics simulation step
-    if (node)
+    if (scene)
     {
     {
         scene_ = GetScene();
         scene_ = GetScene();
-        SubscribeToEvent(node, E_SCENESUBSYSTEMUPDATE, HANDLER(PhysicsWorld, HandleSceneSubsystemUpdate));
+        SubscribeToEvent(scene_, E_SCENESUBSYSTEMUPDATE, HANDLER(PhysicsWorld, HandleSceneSubsystemUpdate));
     }
     }
+    else
+        UnsubscribeFromEvent(E_SCENESUBSYSTEMUPDATE);
 }
 }
 
 
 void PhysicsWorld::HandleSceneSubsystemUpdate(StringHash eventType, VariantMap& eventData)
 void PhysicsWorld::HandleSceneSubsystemUpdate(StringHash eventType, VariantMap& eventData)

+ 2 - 2
Source/Urho3D/Physics/PhysicsWorld.h

@@ -217,8 +217,8 @@ public:
     bool IsApplyingTransforms() const { return applyingTransforms_; }
     bool IsApplyingTransforms() const { return applyingTransforms_; }
 
 
 protected:
 protected:
-    /// Handle node being assigned.
-    virtual void OnNodeSet(Node* node);
+    /// Handle scene being assigned.
+    virtual void OnSceneSet(Scene* scene);
 
 
 private:
 private:
     /// Handle the scene subsystem update event, step simulation here.
     /// Handle the scene subsystem update event, step simulation here.

+ 17 - 12
Source/Urho3D/Physics/RigidBody.cpp

@@ -909,22 +909,27 @@ void RigidBody::OnMarkedDirty(Node* node)
 void RigidBody::OnNodeSet(Node* node)
 void RigidBody::OnNodeSet(Node* node)
 {
 {
     if (node)
     if (node)
+        node->AddListener(this);
+}
+
+void RigidBody::OnSceneSet(Scene* scene)
+{
+    if (scene)
     {
     {
-        Scene* scene = GetScene();
-        if (scene)
-        {
-            if (scene == node)
-                LOGWARNING(GetTypeName() + " should not be created to the root scene node");
+        if (scene == node_)
+            LOGWARNING(GetTypeName() + " should not be created to the root scene node");
 
 
-            physicsWorld_ = scene->GetOrCreateComponent<PhysicsWorld>();
-            physicsWorld_->AddRigidBody(this);
+        physicsWorld_ = scene->GetOrCreateComponent<PhysicsWorld>();
+        physicsWorld_->AddRigidBody(this);
 
 
-            AddBodyToWorld();
-        }
-        else
-            LOGERROR("Node is detached from scene, can not create rigid body");
+        AddBodyToWorld();
+    }
+    else
+    {
+        ReleaseBody();
 
 
-        node->AddListener(this);
+        if (physicsWorld_)
+            physicsWorld_->RemoveRigidBody(this);
     }
     }
 }
 }
 
 

+ 2 - 0
Source/Urho3D/Physics/RigidBody.h

@@ -234,6 +234,8 @@ public:
 protected:
 protected:
     /// Handle node being assigned.
     /// Handle node being assigned.
     virtual void OnNodeSet(Node* node);
     virtual void OnNodeSet(Node* node);
+    /// Handle scene being assigned.
+    virtual void OnSceneSet(Scene* scene);
     /// Handle node transform being dirtied.
     /// Handle node transform being dirtied.
     virtual void OnMarkedDirty(Node* node);
     virtual void OnMarkedDirty(Node* node);
 
 

+ 4 - 0
Source/Urho3D/Scene/Component.cpp

@@ -216,6 +216,10 @@ void Component::OnNodeSet(Node* node)
 {
 {
 }
 }
 
 
+void Component::OnSceneSet(Scene* scene)
+{
+}
+
 void Component::OnMarkedDirty(Node* node)
 void Component::OnMarkedDirty(Node* node)
 {
 {
 }
 }

+ 2 - 0
Source/Urho3D/Scene/Component.h

@@ -99,6 +99,8 @@ protected:
     virtual void OnAttributeAnimationRemoved();
     virtual void OnAttributeAnimationRemoved();
     /// Handle scene node being assigned at creation.
     /// Handle scene node being assigned at creation.
     virtual void OnNodeSet(Node* node);
     virtual void OnNodeSet(Node* node);
+    /// Handle scene being assigned. This may happen several times during the component's lifetime. Scene-wide subsystems and events are subscribed to here.
+    virtual void OnSceneSet(Scene* scene);
     /// Handle scene node transform dirtied.
     /// Handle scene node transform dirtied.
     virtual void OnMarkedDirty(Node* node);
     virtual void OnMarkedDirty(Node* node);
     /// Handle scene node enabled status changing.
     /// Handle scene node enabled status changing.

+ 15 - 7
Source/Urho3D/Scene/LogicComponent.cpp

@@ -78,9 +78,7 @@ void LogicComponent::OnNodeSet(Node* node)
 {
 {
     if (node)
     if (node)
     {
     {
-        // We have been attached to a node. Set initial update event subscription state
-        UpdateEventSubscription();
-        // Then execute the user-defined start function
+        // Execute the user-defined start function
         Start();
         Start();
     }
     }
     else
     else
@@ -90,12 +88,22 @@ void LogicComponent::OnNodeSet(Node* node)
     }
     }
 }
 }
 
 
+void LogicComponent::OnSceneSet(Scene* scene)
+{
+    if (scene)
+        UpdateEventSubscription();
+    else
+    {
+        UnsubscribeFromEvent(E_SCENEUPDATE);
+        UnsubscribeFromEvent(E_SCENEPOSTUPDATE);
+        UnsubscribeFromEvent(E_PHYSICSPRESTEP);
+        UnsubscribeFromEvent(E_PHYSICSPOSTSTEP);
+        currentEventMask_ = 0;
+    }
+}
+
 void LogicComponent::UpdateEventSubscription()
 void LogicComponent::UpdateEventSubscription()
 {
 {
-    // If scene node is not assigned yet, no need to update subscription
-    if (!node_)
-        return;
-    
     Scene* scene = GetScene();
     Scene* scene = GetScene();
     if (!scene)
     if (!scene)
     {
     {

+ 2 - 0
Source/Urho3D/Scene/LogicComponent.h

@@ -74,6 +74,8 @@ class URHO3D_API LogicComponent : public Component
 protected:
 protected:
     /// Handle scene node being assigned at creation.
     /// Handle scene node being assigned at creation.
     virtual void OnNodeSet(Node* node);
     virtual void OnNodeSet(Node* node);
+    /// Handle scene being assigned.
+    virtual void OnSceneSet(Scene* scene);
     
     
 private:
 private:
     /// Subscribe/unsubscribe to update events based on current enabled state and update event mask.
     /// Subscribe/unsubscribe to update events based on current enabled state and update event mask.

+ 5 - 5
Source/Urho3D/Scene/Node.cpp

@@ -1419,6 +1419,11 @@ void Node::AddComponent(Component* component, unsigned id, CreateMode mode)
 
 
     components_.Push(SharedPtr<Component>(component));
     components_.Push(SharedPtr<Component>(component));
 
 
+    if (component->GetNode())
+        LOGWARNING("Component " + component->GetTypeName() + " already belongs to a node!");
+
+    component->SetNode(this);
+
     // If zero ID specified, or the ID is already taken, let the scene assign
     // If zero ID specified, or the ID is already taken, let the scene assign
     if (scene_)
     if (scene_)
     {
     {
@@ -1430,10 +1435,6 @@ void Node::AddComponent(Component* component, unsigned id, CreateMode mode)
     else
     else
         component->SetID(id);
         component->SetID(id);
 
 
-    if(component->GetNode())
-        LOGWARNING("Component " + component->GetTypeName() + " already belongs to a node!");
-
-    component->SetNode(this);
     component->OnMarkedDirty(this);
     component->OnMarkedDirty(this);
 
 
     // Check attributes of the new component on next network update, and 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
@@ -1698,7 +1699,6 @@ void Node::RemoveChild(Vector<SharedPtr<Node> >::Iterator i)
     child->parent_ = 0;
     child->parent_ = 0;
     child->MarkDirty();
     child->MarkDirty();
     child->MarkNetworkUpdate();
     child->MarkNetworkUpdate();
-    // Remove the child from the scene already at this point, in case it is not destroyed immediately
     if (scene_)
     if (scene_)
         scene_->NodeRemoved(child);
         scene_->NodeRemoved(child);
 
 

+ 3 - 0
Source/Urho3D/Scene/Scene.cpp

@@ -844,6 +844,8 @@ void Scene::ComponentAdded(Component* component)
 
 
         localComponents_[id] = component;
         localComponents_[id] = component;
     }
     }
+
+    component->OnSceneSet(this);
 }
 }
 
 
 void Scene::ComponentRemoved(Component* component)
 void Scene::ComponentRemoved(Component* component)
@@ -858,6 +860,7 @@ void Scene::ComponentRemoved(Component* component)
         localComponents_.Erase(id);
         localComponents_.Erase(id);
 
 
     component->SetID(0);
     component->SetID(0);
+    component->OnSceneSet(0);
 }
 }
 
 
 void Scene::SetVarNamesAttr(const String& value)
 void Scene::SetVarNamesAttr(const String& value)