Browse Source

Fixed crash if physics world was destroyed before other physics components.
Disallow to delete or create duplicates of scene-global components (Octree, PhysicsWorld, DebugRenderer) into the root node in the editor.

Lasse Öörni 14 years ago
parent
commit
f23a78eec4

+ 1 - 1
Bin/Data/Scripts/Editor/EditorNodeWindow.as

@@ -58,7 +58,7 @@ void CreateNodeWindow()
     int height = Min(ui.root.height - 60, 500);
     nodeWindow.SetSize(300, height);
     nodeWindow.SetPosition(ui.root.width - 20 - nodeWindow.width, 40);
-    nodeWindow.visible = true;
+    nodeWindow.BringToFront();
     UpdateNodeWindow();
 
     SubscribeToEvent(nodeWindow.GetChild("CloseButton", true), "Released", "HideNodeWindow");

+ 23 - 0
Bin/Data/Scripts/Editor/EditorSceneWindow.as

@@ -22,6 +22,7 @@ void CreateSceneWindow()
     int height = Min(ui.root.height - 60, 500);
     sceneWindow.SetSize(300, height);
     sceneWindow.SetPosition(20, 40);
+    sceneWindow.BringToFront();
     UpdateSceneWindow();
 
     DropDownList@ newNodeList = sceneWindow.GetChild("NewNodeList", true);
@@ -613,6 +614,10 @@ void HandleCreateComponent(StringHash eventType, VariantMap& eventData)
     if (text is null)
         return;
 
+    // If this is the root node, do not allow to create duplicate scene-global components
+    if (selectedNode is editorScene && CheckForExistingGlobalComponent(selectedNode, text.text))
+        return;
+
     // For now, make a local node's all components local
     /// \todo Allow to specify the createmode
     Component@ newComponent = selectedNode.CreateComponent(text.text, selectedNode.id < FIRST_LOCAL_ID ? REPLICATED : LOCAL);
@@ -631,6 +636,14 @@ bool CheckSceneWindowFocus()
         return false;
 }
 
+bool CheckForExistingGlobalComponent(Node@ node, const String&in typeName)
+{
+    if (typeName != "Octree" && typeName != "PhysicsWorld" && typeName != "DebugRenderer")
+        return false;
+    else
+        return node.HasComponent(typeName);
+}
+
 void SceneDelete()
 {
     if (selectedNode is null || !CheckSceneWindowFocus())
@@ -643,6 +656,11 @@ void SceneDelete()
     // Remove component
     if (selectedComponent !is null)
     {
+        // Do not allow to remove the Octree, PhysicsWorld or DebugRenderer from the root node
+        if (selectedNode is editorScene && (selectedComponent.typeName == "Octree" || selectedComponent.typeName == 
+            "PhysicsWorld" || selectedComponent.typeName == "DebugRenderer"))
+            return;
+
         uint id = selectedNode.id;
         BeginModify(id);
         selectedNode.RemoveComponent(selectedComponent);
@@ -719,6 +737,11 @@ void ScenePaste()
     if (mode == "component")
     {
         BeginModify(selectedNode.id);
+        
+        // If this is the root node, do not allow to create duplicate scene-global components
+        if (selectedNode is editorScene && CheckForExistingGlobalComponent(selectedNode, rootElem.GetAttribute("type")))
+            return;
+
         // If copied component was local, make the new local too
         Component@ newComponent = selectedNode.CreateComponent(rootElem.GetAttribute("type"), copyBufferLocal ? LOCAL :
             REPLICATED);

+ 34 - 1
Engine/Physics/PhysicsWorld.cpp

@@ -75,6 +75,7 @@ PhysicsWorld::PhysicsWorld(Context* context) :
         ++numInstances;
     }
     
+    // Create the world, the collision space, and contact joint group
     physicsWorld_ = dWorldCreate();
     space_ = dHashSpaceCreate(0);
     contactJoints_ = dJointGroupCreate(0);
@@ -90,10 +91,38 @@ PhysicsWorld::PhysicsWorld(Context* context) :
 
 PhysicsWorld::~PhysicsWorld()
 {
-    // Forcibly remove any cached geometries that still remain
+    if (scene_)
+    {
+        // Force all remaining joints, rigidbodies and collisionshapes to release themselves
+        PODVector<Node*> nodes;
+        PODVector<Joint*> joints;
+        PODVector<CollisionShape*> collisionShapes;
+        
+        scene_->GetChildrenWithComponent(nodes, Joint::GetTypeStatic(), true);
+        for (PODVector<Node*>::Iterator i = nodes.Begin(); i != nodes.End(); ++i)
+        {
+            (*i)->GetComponents<Joint>(joints);
+            for (PODVector<Joint*>::Iterator j = joints.Begin(); j != joints.End(); ++j)
+                (*j)->Clear();
+        }
+        
+        for (PODVector<RigidBody*>::Iterator i = rigidBodies_.Begin(); i != rigidBodies_.End(); ++i)
+            (*i)->ReleaseBody();
+        
+        scene_->GetChildrenWithComponent(nodes, CollisionShape::GetTypeStatic(), true);
+        for (PODVector<Node*>::Iterator i = nodes.Begin(); i != nodes.End(); ++i)
+        {
+            (*i)->GetComponents<CollisionShape>(collisionShapes);
+            for (PODVector<CollisionShape*>::Iterator j = collisionShapes.Begin(); j != collisionShapes.End(); ++j)
+                (*j)->Clear();
+        }
+    }
+    
+    // Remove any cached geometries that still remain
     triangleMeshCache_.Clear();
     heightfieldCache_.Clear();
     
+    // Destroy the global ODE objects
     if (contactJoints_)
     {
         dJointGroupDestroy(contactJoints_);
@@ -121,6 +150,7 @@ PhysicsWorld::~PhysicsWorld()
         physicsWorld_ = 0;
     }
     
+    // Finally shut down ODE if this was the last instance
     {
         MutexLock lock(GetStaticMutex());
         
@@ -482,7 +512,10 @@ void PhysicsWorld::OnNodeSet(Node* node)
 {
     // Subscribe to the scene subsystem update, which will trigger the physics simulation step
     if (node)
+    {
+        scene_ = node->GetScene();
         SubscribeToEvent(node, E_SCENESUBSYSTEMUPDATE, HANDLER(PhysicsWorld, HandleSceneSubsystemUpdate));
+    }
 }
 
 void PhysicsWorld::NearCallback(void *userData, dGeomID geomA, dGeomID geomB)

+ 2 - 0
Engine/Physics/PhysicsWorld.h

@@ -198,6 +198,8 @@ private:
     /// Handle the scene subsystem update event, step simulation here.
     void HandleSceneSubsystemUpdate(StringHash eventType, VariantMap& eventData);
     
+    /// Extra weak pointer to scene to allow for cleanup in case the world is destroyed before other components.
+    WeakPtr<Scene> scene_;
     /// ODE world ID.
     dWorldID physicsWorld_;
     /// ODE space ID.