From 87825b0abee76c28dcffdaa2c532779b813b6d14 Mon Sep 17 00:00:00 2001
From: Robert Adams
Date: Fri, 5 Oct 2012 15:33:17 -0700
Subject: BulletSim: Fix crash when linking large physical linksets. Properly
 remove and restore linkage constraints when upgrading     a prim's mesh to a
 hull. Lots more debug logging. Definitions and use of Bullet structure
 dumping. Centralize detail logging so a Flush() can be added for debugging.

---
 .../Region/Physics/BulletSPlugin/BSConstraint.cs   |  13 +-
 OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs |   2 +-
 OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs  | 137 ++++++++++-----------
 .../Region/Physics/BulletSPlugin/BSPhysObject.cs   |   3 +-
 OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs     |   9 +-
 OpenSim/Region/Physics/BulletSPlugin/BSScene.cs    |  11 +-
 .../Physics/BulletSPlugin/BSShapeCollection.cs     |  45 ++++---
 .../Region/Physics/BulletSPlugin/BulletSimAPI.cs   |  14 ++-
 8 files changed, 132 insertions(+), 102 deletions(-)

(limited to 'OpenSim/Region')

diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index 63a4127..a20be3a 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -49,9 +49,16 @@ public abstract class BSConstraint : IDisposable
         if (m_enabled)
         {
             m_enabled = false;
-            bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
-            m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success);
-            m_constraint.ptr = System.IntPtr.Zero;
+            if (m_constraint.ptr != IntPtr.Zero)
+            {
+                bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr);
+                m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
+                                    BSScene.DetailLogZero, 
+                                    m_body1.ID, m_body1.ptr.ToString("X"),
+                                    m_body2.ID, m_body2.ptr.ToString("X"),
+                                    success);
+                m_constraint.ptr = System.IntPtr.Zero;
+            }
         }
     }
 
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 4ba2f62..3fb2253 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -862,7 +862,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
         private void VDetailLog(string msg, params Object[] args)
         {
             if (Prim.PhysicsScene.VehicleLoggingEnabled)
-                Prim.PhysicsScene.PhysicsLogging.Write(msg, args);
+                Prim.PhysicsScene.DetailLog(msg, args);
         }
     }
 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 3e82642..20db4de 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -52,8 +52,8 @@ public class BSLinkset
     //    the physical 'taint' children separately.
     // After taint processing and before the simulation step, these
     //    two lists must be the same.
-    private List<BSPhysObject> m_children;
-    private List<BSPhysObject> m_taintChildren;
+    private HashSet<BSPhysObject> m_children;
+    private HashSet<BSPhysObject> m_taintChildren;
 
     // We lock the diddling of linkset classes to prevent any badness.
     // This locks the modification of the instances of this class. Changes
@@ -90,8 +90,8 @@ public class BSLinkset
             m_nextLinksetID = 1;
         PhysicsScene = scene;
         LinksetRoot = parent;
-        m_children = new List<BSPhysObject>();
-        m_taintChildren = new List<BSPhysObject>();
+        m_children = new HashSet<BSPhysObject>();
+        m_taintChildren = new HashSet<BSPhysObject>();
         m_mass = parent.MassRaw;
     }
 
@@ -197,6 +197,8 @@ public class BSLinkset
             PhysicsScene.TaintedObject("BSLinkSet.Refresh", delegate()
             {
                 RecomputeLinksetConstraintVariables();
+                DetailLog("{0},BSLinkset.Refresh,complete,rBody={1}", 
+                                LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
             });
         }
     }
@@ -215,13 +217,10 @@ public class BSLinkset
             if (IsRoot(child))
             {
                 // If the one with the dependency is root, must undo all children
-                DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},numChild={2}",
-                                                child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
-                foreach (BSPhysObject bpo in m_taintChildren)
-                {
-                    PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
-                    ret = true;
-                }
+                DetailLog("{0},BSLinkset.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
+                                                child.LocalID, LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"));
+
+                ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot);
             }
             else
             {
@@ -229,12 +228,9 @@ public class BSLinkset
                                                 child.LocalID,
                                                 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
                                                 child.LocalID, child.BSBody.ptr.ToString("X"));
-                // Remove the dependency on the body of this one 
-                if (m_taintChildren.Contains(child))
-                {
-                    PhysicallyUnlinkAChildFromRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
-                    ret = true;
-                }
+                // ret = PhysicallyUnlinkAChildFromRoot(LinksetRoot, child);
+                // Despite the function name, this removes any link to the specified object.
+                ret = PhysicallyUnlinkAllChildrenFromRoot(child);
             }
         }
         return ret;
@@ -254,7 +250,7 @@ public class BSLinkset
                                                 child.LocalID, LinksetRoot.LocalID, m_taintChildren.Count);
                 foreach (BSPhysObject bpo in m_taintChildren)
                 {
-                    PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, bpo, bpo.BSBody);
+                    PhysicallyLinkAChildToRoot(LinksetRoot, bpo);
                 }
             }
             else
@@ -263,7 +259,7 @@ public class BSLinkset
                                                 LinksetRoot.LocalID,
                                                 LinksetRoot.LocalID, LinksetRoot.BSBody.ptr.ToString("X"),
                                                 child.LocalID, child.BSBody.ptr.ToString("X"));
-                PhysicallyLinkAChildToRoot(LinksetRoot, LinksetRoot.BSBody, child, child.BSBody);
+                PhysicallyLinkAChildToRoot(LinksetRoot, child);
             }
         }
     }
@@ -330,22 +326,22 @@ public class BSLinkset
         {
             m_children.Add(child);
 
-            BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
+            BSPhysObject rootx = LinksetRoot; // capture the root as of now
             BSPhysObject childx = child;
 
-            DetailLog("{0},AddChildToLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 
-                            rootx.LocalID,
-                            rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
-                            childx.LocalID, childx.BSBody.ptr.ToString("X"));
+            DetailLog("{0},AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
 
             PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
             {
-                DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID);
-                // build the physical binding between me and the child
-                m_taintChildren.Add(childx);
-
+                DetailLog("{0},AddChildToLinkset,taint,rID={1},rBody={2},cID={3},cBody={4}", 
+                                rootx.LocalID,
+                                rootx.LocalID, rootx.BSBody.ptr.ToString("X"),
+                                childx.LocalID, childx.BSBody.ptr.ToString("X"));
                 // Since this is taint-time, the body and shape could have changed for the child
-                PhysicallyLinkAChildToRoot(rootx, rootx.BSBody, childx, childx.BSBody);
+                rootx.ForcePosition = rootx.Position;   // DEBUG
+                childx.ForcePosition = childx.Position;   // DEBUG
+                PhysicallyLinkAChildToRoot(rootx, childx);
+                m_taintChildren.Add(child);
             });
         }
         return;
@@ -378,10 +374,8 @@ public class BSLinkset
 
             PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
             {
-                if (m_taintChildren.Contains(childx))
-                    m_taintChildren.Remove(childx);
-
-                PhysicallyUnlinkAChildFromRoot(rootx, rootx.BSBody, childx, childx.BSBody);
+                m_taintChildren.Remove(child);
+                PhysicallyUnlinkAChildFromRoot(rootx, childx);
                 RecomputeLinksetConstraintVariables();
             });
 
@@ -396,8 +390,7 @@ public class BSLinkset
 
     // Create a constraint between me (root of linkset) and the passed prim (the child).
     // Called at taint time!
-    private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody,
-                                    BSPhysObject childPrim, BulletBody childBody)
+    private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
     {
         // Zero motion for children so they don't interpolate
         childPrim.ZeroMotion();
@@ -409,33 +402,17 @@ public class BSLinkset
         // real world coordinate of midpoint between the two objects
         OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2);
 
-        DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
+        DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
                                         rootPrim.LocalID,
-                                        rootPrim.LocalID, rootBody.ptr.ToString("X"),
-                                        childPrim.LocalID, childBody.ptr.ToString("X"),
+                                        rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
+                                        childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"),
                                         rootPrim.Position, childPrim.Position, midPoint);
 
         // create a constraint that allows no freedom of movement between the two objects
         // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
 
-        // There is great subtlty in these paramters. Notice the check for a ptr of zero.
-        // We pass the BulletBody structure into the taint in order to capture the pointer
-        //     of the body at the time of constraint creation. This doesn't work for the very first
-        //     construction because there is no body yet. The body
-        //     is constructed later at taint time. Thus we use the body address at time of the
-        //     taint creation but, if it is zero, use what's in the prim at the moment.
-        //     There is a possible race condition since shape can change without a taint call
-        //     (like changing to a mesh that is already constructed). The fix for that would be
-        //     to only change BSShape at taint time thus syncronizing these operations at
-        //     the cost of efficiency and lag.
         BS6DofConstraint constrain = new BS6DofConstraint(
-                        PhysicsScene.World,
-                        rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody,
-                        childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody,
-                        midPoint,
-                        true,
-                        true
-                        );
+                            PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, midPoint, true, true );
 
         /* NOTE: below is an attempt to build constraint with full frame computation, etc.
          *     Using the midpoint is easier since it lets the Bullet code manipulate the transforms
@@ -452,7 +429,7 @@ public class BSLinkset
 
         // create a constraint that allows no freedom of movement between the two objects
         // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
-        DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
+        DetailLog("{0},BSLinkset.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
         BS6DofConstraint constrain = new BS6DofConstraint(
                         PhysicsScene.World, rootPrim.Body, childPrim.Body,
                         OMV.Vector3.Zero,
@@ -486,39 +463,44 @@ public class BSLinkset
         {
             constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
         }
-
-        RecomputeLinksetConstraintVariables();
     }
 
     // Remove linkage between myself and a particular child
     // The root and child bodies are passed in because we need to remove the constraint between
     //      the bodies that were at unlink time.
     // Called at taint time!
-    private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BulletBody rootBody,
-                                                    BSPhysObject childPrim, BulletBody childBody)
+    private bool PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim)
     {
-        DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
+        bool ret = false;
+        DetailLog("{0},BSLinkset.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
                             rootPrim.LocalID,
-                            rootPrim.LocalID, rootBody.ptr.ToString("X"),
-                            childPrim.LocalID, childBody.ptr.ToString("X"));
+                            rootPrim.LocalID, rootPrim.BSBody.ptr.ToString("X"),
+                            childPrim.LocalID, childPrim.BSBody.ptr.ToString("X"));
 
         // Find the constraint for this link and get rid of it from the overall collection and from my list
-        PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootBody, childBody);
+        if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody))
+        {
+            // Make the child refresh its location
+            BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
+            ret = true;
+        }
 
-        // Make the child refresh its location
-        BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
+        return ret;
     }
 
-    /*
     // Remove linkage between myself and any possible children I might have.
     // Called at taint time!
-    private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
+    private bool PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
     {
-        DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
+        DetailLog("{0},BSLinkset.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
+        bool ret = false;
 
-        PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody);
+        if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody))
+        {
+            ret = true;
+        }
+        return ret;
     }
-     */
 
     // Call each of the constraints that make up this linkset and recompute the
     //    various transforms and variables. Used when objects are added or removed
@@ -550,11 +532,17 @@ public class BSLinkset
         {
             // If this is a multiple object linkset, set everybody's center of mass to the set's center of mass
             OMV.Vector3 centerOfMass = ComputeLinksetCenterOfMass();
-            BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity);
+            BulletSimAPI.SetCenterOfMassByPosRot2(LinksetRoot.BSBody.ptr, 
+                                centerOfMass, OMV.Quaternion.Identity);
+            DetailLog("{0},BSLinkset.RecomputeLinksetConstraintVariables,setCenterOfMass,COM={1},rBody={2}",
+                                LinksetRoot.LocalID, centerOfMass, LinksetRoot.BSBody.ptr.ToString("X"));
             foreach (BSPhysObject child in m_taintChildren)
             {
-                BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, centerOfMass, OMV.Quaternion.Identity);
+                BulletSimAPI.SetCenterOfMassByPosRot2(child.BSBody.ptr, 
+                                centerOfMass, OMV.Quaternion.Identity);
             }
+
+            // BulletSimAPI.DumpAllInfo2(PhysicsScene.World.ptr);  // DEBUG DEBUG DEBUG
         }
         return;
     }
@@ -563,7 +551,8 @@ public class BSLinkset
     // Invoke the detailed logger and output something if it's enabled.
     private void DetailLog(string msg, params Object[] args)
     {
-        PhysicsScene.PhysicsLogging.Write(msg, args);
+        if (PhysicsScene.PhysicsLogging.Enabled)
+            PhysicsScene.DetailLog(msg, args);
     }
 
 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index 1ac8c59..0665292 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -207,7 +207,8 @@ public abstract class BSPhysObject : PhysicsActor
     // High performance detailed logging routine used by the physical objects.
     protected void DetailLog(string msg, params Object[] args)
     {
-        PhysicsScene.PhysicsLogging.Write(msg, args);
+        if (PhysicsScene.PhysicsLogging.Enabled)
+            PhysicsScene.DetailLog(msg, args);
     }
 }
 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index f7b68ba..98a18a1 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -196,7 +196,7 @@ public sealed class BSPrim : BSPhysObject
             _isSelected = value;
             PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
             {
-                // DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
+                DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
                 SetObjectDynamic(false);
             });
         }
@@ -620,8 +620,10 @@ public sealed class BSPrim : BSPhysObject
             BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
             // There can be special things needed for implementing linksets
             Linkset.MakeStatic(this);
-            // The activation state is 'disabled' so Bullet will not try to act on it
-            BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION);
+            // The activation state is 'disabled' so Bullet will not try to act on it.
+            // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION);
+            // Start it out sleeping and physical actions could wake it up.
+            BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
 
             BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
             BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
@@ -1204,6 +1206,7 @@ public sealed class BSPrim : BSPhysObject
         {
             // Called if the current prim body is about to be destroyed.
             // Remove all the physical dependencies on the old body.
+            // (Maybe someday make the changing of BSShape an event handled by BSLinkset.)
             needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
         });
 
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index aaed7de..eed915d 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -254,7 +254,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
 
         // The bounding box for the simulated world. The origin is 0,0,0 unless we're
         //    a child in a mega-region.
-        // Turns out that Bullet really doesn't care about the extents of the simulated
+        // Bullet actually doesn't care about the extents of the simulated
         //    area. It tracks active objects no matter where they are.
         Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
 
@@ -331,7 +331,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
     // Called directly from unmanaged code so don't do much
     private void BulletLoggerPhysLog(string msg)
     {
-        PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg);
+        DetailLog("[BULLETS UNMANAGED]:" + msg);
     }
 
     public override void Dispose()
@@ -494,8 +494,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
         m_simulationStep++;
         int numSubSteps = 0;
 
-        // Sometimes needed for debugging to find out what happened before the step
-        // PhysicsLogging.Flush();
+        // DEBUG
+        DetailLog("{0},BSScene.Simulate,beforeStep,ntaimts={1},step={2}", DetailLogZero, numTaints, m_simulationStep);
 
         try
         {
@@ -715,6 +715,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
             {
                 try
                 {
+                    DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
                     tcbe.callback();
                 }
                 catch (Exception e)
@@ -1270,6 +1271,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters
     public void DetailLog(string msg, params Object[] args)
     {
         PhysicsLogging.Write(msg, args);
+        // Add the Flush() if debugging crashes to get all the messages written out.
+        PhysicsLogging.Flush();         // DEBUG DEBUG DEBUG
     }
     // used to fill in the LocalID when there isn't one
     public const string DetailLogZero = "0000000000";
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 399a133..283b601 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -136,7 +136,21 @@ public class BSShapeCollection : IDisposable
                 // New entry
                 bodyDesc.ptr = body.ptr;
                 bodyDesc.referenceCount = 1;
-                DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={1}", body.ID, body, bodyDesc.referenceCount);
+                DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,ref={2}",
+                                    body.ID, body, bodyDesc.referenceCount);
+                BSScene.TaintCallback createOperation = delegate()
+                {
+                    if (!BulletSimAPI.IsInWorld2(body.ptr))
+                    {
+                        BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr);
+                        DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", 
+                                        body.ID, body);
+                    }
+                };
+                if (atTaintTime)
+                    createOperation();
+                else
+                    PhysicsScene.TaintedObject("BSShapeCollection.ReferenceBody", createOperation);
             }
             bodyDesc.lastReferenced = System.DateTime.Now;
             Bodies[body.ID] = bodyDesc;
@@ -160,21 +174,22 @@ public class BSShapeCollection : IDisposable
                 Bodies[body.ID] = bodyDesc;
                 DetailLog("{0},BSShapeCollection.DereferenceBody,ref={1}", body.ID, bodyDesc.referenceCount);
 
-                // If body is no longer being used, free it -- bodies are never shared.
+                // If body is no longer being used, free it -- bodies can never be shared.
                 if (bodyDesc.referenceCount == 0)
                 {
                     Bodies.Remove(body.ID);
                     BSScene.TaintCallback removeOperation = delegate()
                     {
-                        DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}",
-                                                    body.ID, body.ptr.ToString("X"));
+                        DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody. ptr={1}, inTaintTime={2}",
+                                                    body.ID, body.ptr.ToString("X"), inTaintTime);
                         // If the caller needs to know the old body is going away, pass the event up.
                         if (bodyCallback != null) bodyCallback(body);
 
-                        // Zero any reference to the shape so it is not freed when the body is deleted.
-                        BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
                         // It may have already been removed from the world in which case the next is a NOOP.
                         BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr);
+
+                        // Zero any reference to the shape so it is not freed when the body is deleted.
+                        BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero);
                         BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr);
                     };
                     // If already in taint-time, do the operations now. Otherwise queue for later.
@@ -208,7 +223,7 @@ public class BSShapeCollection : IDisposable
                 {
                     // There is an existing instance of this mesh.
                     meshDesc.referenceCount++;
-                    DetailLog("{0},BSShapeColliction.ReferenceShape,existingMesh,key={1},cnt={2}",
+                    DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
                                 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
                 }
                 else
@@ -217,7 +232,7 @@ public class BSShapeCollection : IDisposable
                     meshDesc.ptr = shape.ptr;
                     // We keep a reference to the underlying IMesh data so a hull can be built
                     meshDesc.referenceCount = 1;
-                    DetailLog("{0},BSShapeColliction.ReferenceShape,newMesh,key={1},cnt={2}",
+                    DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
                                 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
                     ret = true;
                 }
@@ -230,7 +245,7 @@ public class BSShapeCollection : IDisposable
                 {
                     // There is an existing instance of this hull.
                     hullDesc.referenceCount++;
-                    DetailLog("{0},BSShapeColliction.ReferenceShape,existingHull,key={1},cnt={2}",
+                    DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
                                 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
                 }
                 else
@@ -238,7 +253,7 @@ public class BSShapeCollection : IDisposable
                     // This is a new reference to a hull
                     hullDesc.ptr = shape.ptr;
                     hullDesc.referenceCount = 1;
-                    DetailLog("{0},BSShapeColliction.ReferenceShape,newHull,key={1},cnt={2}",
+                    DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
                                 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
                     ret = true;
 
@@ -525,7 +540,7 @@ public class BSShapeCollection : IDisposable
         DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}",
                         prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
 
-        // Remove usage of the previous shape. Also removes reference to underlying mesh if it is a hull.
+        // Remove usage of the previous shape.
         DereferenceShape(prim.BSShape, true, shapeCallback);
 
         newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
@@ -659,6 +674,7 @@ public class BSShapeCollection : IDisposable
         if (pbs.SculptEntry)
             lod = PhysicsScene.SculptLOD;
 
+        // Mega prims usually get more detail because one can interact with shape approximations at this size.
         float maxAxis = Math.Max(shapeData.Size.X, Math.Max(shapeData.Size.Y, shapeData.Size.Z));
         if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
             lod = PhysicsScene.MeshMegaPrimLOD;
@@ -709,13 +725,13 @@ public class BSShapeCollection : IDisposable
             {
                 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr,
                                         shapeData.ID, shapeData.Position, shapeData.Rotation);
-                // DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
+                DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
             }
             else
             {
                 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr,
                                         shapeData.ID, shapeData.Position, shapeData.Rotation);
-                // DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
+                DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
             }
             aBody = new BulletBody(shapeData.ID, bodyPtr);
 
@@ -731,7 +747,8 @@ public class BSShapeCollection : IDisposable
 
     private void DetailLog(string msg, params Object[] args)
     {
-        PhysicsScene.PhysicsLogging.Write(msg, args);
+        if (PhysicsScene.PhysicsLogging.Enabled)
+            PhysicsScene.DetailLog(msg, args);
     }
 }
 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index a43880d..bb4d399 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -192,8 +192,9 @@ public struct ShapeData
 		SHAPE_SPHERE    = 5,
 		SHAPE_MESH      = 6,
 		SHAPE_HULL      = 7,
-		SHAPE_GROUNDPLANE  = 8,
-		SHAPE_TERRAIN   = 9,
+        // following defined by BulletSim
+		SHAPE_GROUNDPLANE  = 20,
+		SHAPE_TERRAIN   = 21,
     };
     public uint ID;
     public PhysicsShapeType Type;
@@ -1108,6 +1109,15 @@ public static extern float GetMargin2(IntPtr shape);
 public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
 
 [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void DumpAllInfo2(IntPtr sim);
+
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
 public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
 
 [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
-- 
cgit v1.1