Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge branch 'bulletsim7'

  • Loading branch information...
commit 3ecd39068cf756fc9de2f8f30bc2a703be90d7dc 2 parents 3a55d5b + 0c7ce4f
Robert Adams authored August 10, 2012
80  OpenSim/Region/Physics/BulletSPlugin/BS6DofConstraint.cs
... ...
@@ -0,0 +1,80 @@
  1
+/*
  2
+ * Copyright (c) Contributors, http://opensimulator.org/
  3
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4
+ *
  5
+ * Redistribution and use in source and binary forms, with or without
  6
+ * modification, are permitted provided that the following conditions are met:
  7
+ *     * Redistributions of source code must retain the above copyright
  8
+ *       notice, this list of conditions and the following disclaimer.
  9
+ *     * Redistributions in binary form must reproduce the above copyrightD
  10
+ *       notice, this list of conditions and the following disclaimer in the
  11
+ *       documentation and/or other materials provided with the distribution.
  12
+ *     * Neither the name of the OpenSimulator Project nor the
  13
+ *       names of its contributors may be used to endorse or promote products
  14
+ *       derived from this software without specific prior written permission.
  15
+ *
  16
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26
+ */
  27
+using System;
  28
+using System.Collections.Generic;
  29
+using System.Text;
  30
+using OpenMetaverse;
  31
+
  32
+namespace OpenSim.Region.Physics.BulletSPlugin
  33
+{
  34
+
  35
+public class BS6DofConstraint : BSConstraint
  36
+{
  37
+    // Create a btGeneric6DofConstraint
  38
+    public BS6DofConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
  39
+                    Vector3 frame1, Quaternion frame1rot,
  40
+                    Vector3 frame2, Quaternion frame2rot )
  41
+    {
  42
+        m_world = world;
  43
+        m_body1 = obj1;
  44
+        m_body2 = obj2;
  45
+        m_constraint = new BulletConstraint(
  46
+                            BulletSimAPI.Create6DofConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr,
  47
+                                frame1, frame1rot,
  48
+                                frame2, frame2rot,
  49
+                                true /*useLinearReferenceFrameA*/, true /*disableCollisionsBetweenLinkedBodies*/));
  50
+        m_enabled = true;
  51
+    }
  52
+
  53
+    public bool SetCFMAndERP(float cfm, float erp)
  54
+    {
  55
+        bool ret = true;
  56
+        BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
  57
+        BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
  58
+        BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
  59
+        return ret;
  60
+    }
  61
+
  62
+    public bool UseFrameOffset(bool useOffset)
  63
+    {
  64
+        bool ret = false;
  65
+        float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
  66
+        if (m_enabled)
  67
+            ret = BulletSimAPI.UseFrameOffset2(m_constraint.Ptr, onOff);
  68
+        return ret;
  69
+    }
  70
+
  71
+    public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce)
  72
+    {
  73
+        bool ret = false;
  74
+        float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
  75
+        if (m_enabled)
  76
+            ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.Ptr, onOff, targetVelocity, maxMotorForce);
  77
+        return ret;
  78
+    }
  79
+}
  80
+}
86  OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -122,7 +122,7 @@ public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 po
122 122
         shapeData.Restitution = _scene.Params.avatarRestitution;
123 123
 
124 124
         // do actual create at taint time
125  
-        _scene.TaintedObject(delegate()
  125
+        _scene.TaintedObject("BSCharacter.create", delegate()
126 126
         {
127 127
             BulletSimAPI.CreateObject(parent_scene.WorldID, shapeData);
128 128
 
@@ -138,7 +138,7 @@ public BSCharacter(uint localID, String avName, BSScene parent_scene, Vector3 po
138 138
     public void Destroy()
139 139
     {
140 140
         // DetailLog("{0},Destroy", LocalID);
141  
-        _scene.TaintedObject(delegate()
  141
+        _scene.TaintedObject("BSCharacter.destroy", delegate()
142 142
         {
143 143
             BulletSimAPI.DestroyObject(_scene.WorldID, _localID);
144 144
         });
@@ -169,7 +169,7 @@ public override void RequestPhysicsterseUpdate()
169 169
 
170 170
             ComputeAvatarVolumeAndMass();
171 171
 
172  
-            _scene.TaintedObject(delegate()
  172
+            _scene.TaintedObject("BSCharacter.setSize", delegate()
173 173
             {
174 174
                 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, LocalID, _scale, _mass, true);
175 175
             });
@@ -205,13 +205,37 @@ public override void RequestPhysicsterseUpdate()
205 205
         } 
206 206
         set {
207 207
             _position = value;
208  
-            _scene.TaintedObject(delegate()
  208
+            PositionSanityCheck();
  209
+
  210
+            _scene.TaintedObject("BSCharacter.setPosition", delegate()
209 211
             {
210 212
                 DetailLog("{0},SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
211 213
                 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
212 214
             });
213 215
         } 
214 216
     }
  217
+
  218
+    // Check that the current position is sane and, if not, modify the position to make it so.
  219
+    // Check for being below terrain and being out of bounds.
  220
+    // Returns 'true' of the position was made sane by some action.
  221
+    private bool PositionSanityCheck()
  222
+    {
  223
+        bool ret = false;
  224
+        
  225
+        // If below the ground, move the avatar up
  226
+        float terrainHeight = Scene.GetTerrainHeightAtXYZ(_position);
  227
+        if (_position.Z < terrainHeight)
  228
+        {
  229
+            DetailLog("{0},PositionAdjustUnderGround,call,pos={1},orient={2}", LocalID, _position, _orientation);
  230
+            _position.Z = terrainHeight + 2.0f;
  231
+            ret = true;
  232
+        }
  233
+
  234
+        // TODO: check for out of bounds
  235
+
  236
+        return ret;
  237
+    }
  238
+
215 239
     public override float Mass { 
216 240
         get { 
217 241
             return _mass; 
@@ -222,9 +246,9 @@ public override void RequestPhysicsterseUpdate()
222 246
         set {
223 247
             _force = value;
224 248
             // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
225  
-            Scene.TaintedObject(delegate()
  249
+            Scene.TaintedObject("BSCharacter.SetForce", delegate()
226 250
             {
227  
-                DetailLog("{0},setForce,taint,force={1}", LocalID, _force);
  251
+                DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
228 252
                 BulletSimAPI.SetObjectForce(Scene.WorldID, LocalID, _force);
229 253
             });
230 254
         } 
@@ -249,9 +273,9 @@ public override void RequestPhysicsterseUpdate()
249 273
         set {
250 274
             _velocity = value;
251 275
             // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
252  
-            _scene.TaintedObject(delegate()
  276
+            _scene.TaintedObject("BSCharacter.setVelocity", delegate()
253 277
             {
254  
-                DetailLog("{0},setVelocity,taint,vel={1}", LocalID, _velocity);
  278
+                DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
255 279
                 BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity);
256 280
             });
257 281
         } 
@@ -275,7 +299,7 @@ public override void RequestPhysicsterseUpdate()
275 299
         set {
276 300
             _orientation = value;
277 301
             // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
278  
-            _scene.TaintedObject(delegate()
  302
+            _scene.TaintedObject("BSCharacter.setOrientation", delegate()
279 303
             {
280 304
                 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
281 305
                 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
@@ -342,7 +366,7 @@ public override bool
342 366
     public override float Buoyancy { 
343 367
         get { return _buoyancy; } 
344 368
         set { _buoyancy = value; 
345  
-            _scene.TaintedObject(delegate()
  369
+            _scene.TaintedObject("BSCharacter.setBuoyancy", delegate()
346 370
             {
347 371
                 DetailLog("{0},setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
348 372
                 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy);
@@ -389,7 +413,7 @@ public override bool
389 413
             _force.Y += force.Y;
390 414
             _force.Z += force.Z;
391 415
             // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
392  
-            _scene.TaintedObject(delegate()
  416
+            _scene.TaintedObject("BSCharacter.AddForce", delegate()
393 417
             {
394 418
                 DetailLog("{0},setAddForce,taint,addedForce={1}", LocalID, _force);
395 419
                 BulletSimAPI.AddObjectForce2(Body.Ptr, _force);
@@ -415,7 +439,7 @@ public override bool
415 439
             // make sure first collision happens
416 440
             _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
417 441
 
418  
-            Scene.TaintedObject(delegate()
  442
+            Scene.TaintedObject("BSCharacter.SubscribeEvents", delegate()
419 443
             {
420 444
                 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
421 445
             });
@@ -425,7 +449,7 @@ public override bool
425 449
     public override void UnSubscribeEvents() { 
426 450
         _subscribedEventsMs = 0;
427 451
         // Avatars get all their collision events
428  
-        // Scene.TaintedObject(delegate()
  452
+        // Scene.TaintedObject("BSCharacter.UnSubscribeEvents", delegate()
429 453
         // {
430 454
         //     BulletSimAPI.RemoveFromCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
431 455
         // });
@@ -456,43 +480,17 @@ private void ComputeAvatarVolumeAndMass()
456 480
     // the world that things have changed.
457 481
     public void UpdateProperties(EntityProperties entprop)
458 482
     {
459  
-        /*
460  
-        bool changed = false;
461  
-        // we assign to the local variables so the normal set action does not happen
462  
-        if (_position != entprop.Position) {
463  
-            _position = entprop.Position;
464  
-            changed = true;
465  
-        }
466  
-        if (_orientation != entprop.Rotation) {
467  
-            _orientation = entprop.Rotation;
468  
-            changed = true;
469  
-        }
470  
-        if (_velocity != entprop.Velocity) {
471  
-            _velocity = entprop.Velocity;
472  
-            changed = true;
473  
-        }
474  
-        if (_acceleration != entprop.Acceleration) {
475  
-            _acceleration = entprop.Acceleration;
476  
-            changed = true;
477  
-        }
478  
-        if (_rotationalVelocity != entprop.RotationalVelocity) {
479  
-            _rotationalVelocity = entprop.RotationalVelocity;
480  
-            changed = true;
481  
-        }
482  
-        if (changed) {
483  
-            // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
484  
-            // Avatar movement is not done by generating this event. There is code in the heartbeat
485  
-            //   loop that updates avatars.
486  
-            // base.RequestPhysicsterseUpdate();
487  
-        }
488  
-        */
489 483
         _position = entprop.Position;
490 484
         _orientation = entprop.Rotation;
491 485
         _velocity = entprop.Velocity;
492 486
         _acceleration = entprop.Acceleration;
493 487
         _rotationalVelocity = entprop.RotationalVelocity;
494  
-        // Avatars don't report theirr changes the usual way. Changes are checked for in the heartbeat loop.
  488
+        // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
495 489
         // base.RequestPhysicsterseUpdate();
  490
+
  491
+        DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
  492
+                LocalID, entprop.Position, entprop.Rotation, entprop.Velocity, 
  493
+                entprop.Acceleration, entprop.RotationalVelocity);
496 494
     }
497 495
 
498 496
     // Called by the scene when a collision with this object is reported
64  OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -32,35 +32,26 @@
32 32
 namespace OpenSim.Region.Physics.BulletSPlugin
33 33
 {
34 34
 
35  
-public class BSConstraint : IDisposable
  35
+public abstract class BSConstraint : IDisposable
36 36
 {
37  
-    private BulletSim m_world;
38  
-    private BulletBody m_body1;
39  
-    private BulletBody m_body2;
40  
-    private BulletConstraint m_constraint;
41  
-    private bool m_enabled = false;
  37
+    protected BulletSim m_world;
  38
+    protected BulletBody m_body1;
  39
+    protected BulletBody m_body2;
  40
+    protected BulletConstraint m_constraint;
  41
+    protected bool m_enabled = false;
42 42
 
43  
-    public BSConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
44  
-                    Vector3 frame1, Quaternion frame1rot,
45  
-                    Vector3 frame2, Quaternion frame2rot
46  
-        )
  43
+    public BSConstraint()
47 44
     {
48  
-        m_world = world;
49  
-        m_body1 = obj1;
50  
-        m_body2 = obj2;
51  
-        m_constraint = new BulletConstraint(BulletSimAPI.CreateConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr,
52  
-                            frame1, frame1rot,
53  
-                            frame2, frame2rot,
54  
-                            true /*useLinearReferenceFrameA*/, true /*disableCollisionsBetweenLinkedBodies*/));
55  
-        m_enabled = true;
56 45
     }
57 46
 
58  
-    public void Dispose()
  47
+    public virtual void Dispose()
59 48
     {
60 49
         if (m_enabled)
61 50
         {
62 51
             // BulletSimAPI.RemoveConstraint(m_world.ID, m_body1.ID, m_body2.ID);
63  
-            BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr);
  52
+            bool success = BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr);
  53
+            m_world.scene.DetailLog("{0},BSConstraint.Dispose,taint,body1={1},body2={2},success={3}", BSScene.DetailLogZero, m_body1.ID, m_body2.ID, success);
  54
+            m_constraint.Ptr = System.IntPtr.Zero;
64 55
             m_enabled = false;
65 56
         }
66 57
     }
@@ -68,7 +59,7 @@ public void Dispose()
68 59
     public BulletBody Body1 { get { return m_body1; } }
69 60
     public BulletBody Body2 { get { return m_body2; } }
70 61
 
71  
-    public bool SetLinearLimits(Vector3 low, Vector3 high)
  62
+    public virtual bool SetLinearLimits(Vector3 low, Vector3 high)
72 63
     {
73 64
         bool ret = false;
74 65
         if (m_enabled)
@@ -76,7 +67,7 @@ public bool SetLinearLimits(Vector3 low, Vector3 high)
76 67
         return ret;
77 68
     }
78 69
 
79  
-    public bool SetAngularLimits(Vector3 low, Vector3 high)
  70
+    public virtual bool SetAngularLimits(Vector3 low, Vector3 high)
80 71
     {
81 72
         bool ret = false;
82 73
         if (m_enabled)
@@ -84,34 +75,7 @@ public bool SetAngularLimits(Vector3 low, Vector3 high)
84 75
         return ret;
85 76
     }
86 77
 
87  
-    public bool SetCFMAndERP(float cfm, float erp)
88  
-    {
89  
-        bool ret = true;
90  
-        BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
91  
-        BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
92  
-        BulletSimAPI.SetConstraintParam2(m_constraint.Ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
93  
-        return ret;
94  
-    }
95  
-
96  
-    public bool UseFrameOffset(bool useOffset)
97  
-    {
98  
-        bool ret = false;
99  
-        float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
100  
-        if (m_enabled)
101  
-            ret = BulletSimAPI.UseFrameOffset2(m_constraint.Ptr, onOff);
102  
-        return ret;
103  
-    }
104  
-
105  
-    public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce)
106  
-    {
107  
-        bool ret = false;
108  
-        float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
109  
-        if (m_enabled)
110  
-            ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.Ptr, onOff, targetVelocity, maxMotorForce);
111  
-        return ret;
112  
-    }
113  
-
114  
-    public bool CalculateTransforms()
  78
+    public virtual bool CalculateTransforms()
115 79
     {
116 80
         bool ret = false;
117 81
         if (m_enabled)
18  OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
@@ -63,21 +63,13 @@ public void Clear()
63 63
         m_constraints.Clear();
64 64
     }
65 65
 
66  
-    public BSConstraint CreateConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
67  
-                    Vector3 frame1, Quaternion frame1rot,
68  
-                    Vector3 frame2, Quaternion frame2rot)
69  
-    {
70  
-        BSConstraint constrain = new BSConstraint(world, obj1, obj2, frame1, frame1rot, frame2, frame2rot);
71  
-
72  
-        this.AddConstraint(constrain);
73  
-        return constrain;
74  
-    }
75  
-
76 66
     public bool AddConstraint(BSConstraint cons)
77 67
     {
78 68
         // There is only one constraint between any bodies. Remove any old just to make sure.
79 69
         RemoveAndDestroyConstraint(cons.Body1, cons.Body2);
80 70
 
  71
+        m_world.scene.DetailLog("{0},BSConstraintCollection.AddConstraint,call,body1={1},body2={2}", BSScene.DetailLogZero, cons.Body1.ID, cons.Body2.ID);
  72
+
81 73
         m_constraints.Add(cons);
82 74
 
83 75
         return true;
@@ -118,6 +110,7 @@ public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2)
118 110
 
119 111
         if (this.TryGetConstraint(body1, body2, out constrain))
120 112
         {
  113
+            m_world.scene.DetailLog("{0},BSConstraintCollection.RemoveAndDestroyConstraint,taint,body1={1},body2={2}", BSScene.DetailLogZero, body1.ID, body2.ID);
121 114
             // remove the constraint from our collection
122 115
             m_constraints.Remove(constrain);
123 116
             // tell the engine that all its structures need to be freed
@@ -158,10 +151,11 @@ public bool RemoveAndDestroyConstraint(BulletBody body1)
158 151
 
159 152
     public bool RecalculateAllConstraints()
160 153
     {
161  
-        foreach (BSConstraint constrain in m_constraints)
  154
+        ForEachConstraint(delegate(BSConstraint constrain)
162 155
         {
163 156
             constrain.CalculateTransforms();
164  
-        }
  157
+            return false;
  158
+        });
165 159
         return true;
166 160
     }
167 161
 
114  OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -40,6 +40,7 @@ public class BSLinkset
40 40
     public BSPrim Root { get { return m_linksetRoot; } }
41 41
 
42 42
     private BSScene m_scene;
  43
+    public BSScene Scene { get { return m_scene; } }
43 44
 
44 45
     private List<BSPrim> m_children;
45 46
 
@@ -80,14 +81,14 @@ public BSLinkset(BSScene scene, BSPrim parent)
80 81
 
81 82
     // Link to a linkset where the child knows the parent.
82 83
     // Parent changing should not happen so do some sanity checking.
83  
-    // We return the parent's linkset so the child can track it's membership.
84  
-    public BSLinkset AddMeToLinkset(BSPrim child, BSPrim parent)
  84
+    // We return the parent's linkset so the child can track its membership.
  85
+    public BSLinkset AddMeToLinkset(BSPrim child)
85 86
     {
86 87
         lock (m_linksetActivityLock)
87 88
         {
88  
-            parent.Linkset.AddChildToLinkset(child);
  89
+            AddChildToLinkset(child);
89 90
         }
90  
-        return parent.Linkset;
  91
+        return this;
91 92
     }
92 93
 
93 94
     public BSLinkset RemoveMeFromLinkset(BSPrim child)
@@ -101,7 +102,7 @@ public BSLinkset RemoveMeFromLinkset(BSPrim child)
101 102
                 {
102 103
                     // Note that we don't do a foreach because the remove routine
103 104
                     //    takes it out of the list.
104  
-                    RemoveChildFromLinkset(m_children[0]);
  105
+                    RemoveChildFromOtherLinkset(m_children[0]);
105 106
                 }
106 107
                 m_children.Clear(); // just to make sure
107 108
             }
@@ -113,9 +114,10 @@ public BSLinkset RemoveMeFromLinkset(BSPrim child)
113 114
         }
114 115
 
115 116
         // The child is down to a linkset of just itself
116  
-        return new BSLinkset(m_scene, child);
  117
+        return new BSLinkset(Scene, child);
117 118
     }
118 119
 
  120
+    /* DEPRECATED: this is really bad in that it trys to unlink other prims.
119 121
     // An existing linkset had one of its members rebuilt or something.
120 122
     // Go through the linkset and rebuild the pointers to the bodies of the linkset members.
121 123
     public BSLinkset RefreshLinkset(BSPrim requestor)
@@ -124,6 +126,7 @@ public BSLinkset RefreshLinkset(BSPrim requestor)
124 126
 
125 127
         lock (m_linksetActivityLock)
126 128
         {
  129
+            // The body pointer is refetched in case anything has moved.
127 130
             System.IntPtr aPtr = BulletSimAPI.GetBodyHandle2(m_scene.World.Ptr, m_linksetRoot.LocalID);
128 131
             if (aPtr == System.IntPtr.Zero)
129 132
             {
@@ -155,13 +158,14 @@ public BSLinkset RefreshLinkset(BSPrim requestor)
155 158
                 }
156 159
                 foreach (BSPrim bsp in toRemove)
157 160
                 {
158  
-                    RemoveChildFromLinkset(bsp);
  161
+                    RemoveChildFromOtherLinkset(bsp);
159 162
                 }
160 163
             }
161 164
         }
162 165
 
163 166
         return ret;
164 167
     }
  168
+     */
165 169
 
166 170
 
167 171
     // Return 'true' if the passed object is the root object of this linkset
@@ -170,6 +174,8 @@ public bool IsRoot(BSPrim requestor)
170 174
         return (requestor.LocalID == m_linksetRoot.LocalID);
171 175
     }
172 176
 
  177
+    public int NumberOfChildren { get { return m_children.Count; } }
  178
+
173 179
     // Return 'true' if this linkset has any children (more than the root member)
174 180
     public bool HasAnyChildren { get { return (m_children.Count > 0); } }
175 181
 
@@ -208,7 +214,8 @@ private OMV.Vector3 ComputeLinksetCenterOfMass()
208 214
             com += bp.Position * bp.MassRaw;
209 215
             totalMass += bp.MassRaw;
210 216
         }
211  
-        com /= totalMass;
  217
+        if (totalMass != 0f)
  218
+            com /= totalMass;
212 219
 
213 220
         return com;
214 221
     }
@@ -221,51 +228,54 @@ private OMV.Vector3 ComputeLinksetGeometricCenter()
221 228
         {
222 229
             com += bp.Position * bp.MassRaw;
223 230
         }
224  
-        com /= m_children.Count + 1;
  231
+        com /= (m_children.Count + 1);
225 232
 
226 233
         return com;
227 234
     }
228 235
 
229 236
     // I am the root of a linkset and a new child is being added
230  
-    public void AddChildToLinkset(BSPrim pchild)
  237
+    // Called while LinkActivity is locked.
  238
+    public void AddChildToLinkset(BSPrim child)
231 239
     {
232  
-        BSPrim child = pchild;
233 240
         if (!HasChild(child))
234 241
         {
235 242
             m_children.Add(child);
236 243
 
237  
-            m_scene.TaintedObject(delegate()
  244
+            BSPrim root = Root; // capture the root as of now
  245
+            m_scene.TaintedObject("AddChildToLinkset", delegate()
238 246
             {
239 247
                 DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, m_linksetRoot.LocalID);
240  
-                DetailLog("{0},AddChildToLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID);
241  
-                PhysicallyLinkAChildToRoot(pchild);     // build the physical binding between me and the child
  248
+                DetailLog("{0},AddChildToLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID);
  249
+                PhysicallyLinkAChildToRoot(root, child);     // build the physical binding between me and the child
242 250
             });
243 251
         }
244 252
         return;
245 253
     }
246 254
 
  255
+    // Forcefully removing a child from a linkset.
  256
+    // This is not being called by the child so we have to make sure the child doesn't think
  257
+    //    it's still connected to the linkset.
  258
+    // Normal OpenSimulator operation will never do this because other SceneObjectPart information
  259
+    //    has to be updated also (like pointer to prim's parent).
  260
+    public void RemoveChildFromOtherLinkset(BSPrim pchild)
  261
+    {
  262
+        pchild.Linkset = new BSLinkset(m_scene, pchild);
  263
+        RemoveChildFromLinkset(pchild);
  264
+    }
  265
+
247 266
     // I am the root of a linkset and one of my children is being removed.
248 267
     // Safe to call even if the child is not really in my linkset.
249  
-    public void RemoveChildFromLinkset(BSPrim pchild)
  268
+    public void RemoveChildFromLinkset(BSPrim child)
250 269
     {
251  
-        BSPrim child = pchild;
252  
-
253 270
         if (m_children.Remove(child))
254 271
         {
255  
-            m_scene.TaintedObject(delegate()
  272
+            BSPrim root = Root; // capture the root as of now
  273
+            m_scene.TaintedObject("RemoveChildFromLinkset", delegate()
256 274
             {
257 275
                 DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID);
258  
-                DetailLog("{0},RemoveChildFromLinkset,child={1}", m_linksetRoot.LocalID, pchild.LocalID);
  276
+                DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", m_linksetRoot.LocalID, child.LocalID);
259 277
 
260  
-                if (m_children.Count == 0)
261  
-                {
262  
-                    // if the linkset is empty, make sure all linkages have been removed
263  
-                    PhysicallyUnlinkAllChildrenFromRoot();
264  
-                }
265  
-                else
266  
-                {
267  
-                    PhysicallyUnlinkAChildFromRoot(pchild);
268  
-                }
  278
+                PhysicallyUnlinkAChildFromRoot(root, child);
269 279
             });
270 280
         }
271 281
         else
@@ -278,14 +288,14 @@ public void RemoveChildFromLinkset(BSPrim pchild)
278 288
 
279 289
     // Create a constraint between me (root of linkset) and the passed prim (the child).
280 290
     // Called at taint time!
281  
-    private void PhysicallyLinkAChildToRoot(BSPrim childPrim)
  291
+    private void PhysicallyLinkAChildToRoot(BSPrim rootPrim, BSPrim childPrim)
282 292
     {
283 293
         // Zero motion for children so they don't interpolate
284 294
         childPrim.ZeroMotion();
285 295
 
286 296
         // relative position normalized to the root prim
287  
-        OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(m_linksetRoot.Orientation);
288  
-        OMV.Vector3 childRelativePosition = (childPrim.Position - m_linksetRoot.Position) * invThisOrientation;
  297
+        OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation);
  298
+        OMV.Vector3 childRelativePosition = (childPrim.Position - rootPrim.Position) * invThisOrientation;
289 299
 
290 300
         // relative rotation of the child to the parent
291 301
         OMV.Quaternion childRelativeRotation = invThisOrientation * childPrim.Orientation;
@@ -293,16 +303,17 @@ private void PhysicallyLinkAChildToRoot(BSPrim childPrim)
293 303
         // create a constraint that allows no freedom of movement between the two objects
294 304
         // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
295 305
         // DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID);
296  
-        DetailLog("{0},LinkAChildToMe,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID);
297  
-        BSConstraint constrain = m_scene.Constraints.CreateConstraint(
298  
-                        m_scene.World, m_linksetRoot.Body, childPrim.Body,
299  
-                        // childRelativePosition,
300  
-                        // childRelativeRotation,
301  
-                        OMV.Vector3.Zero,
302  
-                        OMV.Quaternion.Identity,
  306
+        DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
  307
+        BS6DofConstraint constrain = new BS6DofConstraint(
  308
+                        m_scene.World, rootPrim.Body, childPrim.Body,
  309
+                        childRelativePosition,
  310
+                        childRelativeRotation,
303 311
                         OMV.Vector3.Zero,
304  
-                        OMV.Quaternion.Identity
  312
+                        -childRelativeRotation
305 313
                         );
  314
+        m_scene.Constraints.AddConstraint(constrain);
  315
+
  316
+        // zero linear and angular limits makes the objects unable to move in relation to each other
306 317
         constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
307 318
         constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
308 319
 
@@ -317,29 +328,32 @@ private void PhysicallyLinkAChildToRoot(BSPrim childPrim)
317 328
 
318 329
     // Remove linkage between myself and a particular child
319 330
     // Called at taint time!
320  
-    private void PhysicallyUnlinkAChildFromRoot(BSPrim childPrim)
  331
+    private void PhysicallyUnlinkAChildFromRoot(BSPrim rootPrim, BSPrim childPrim)
321 332
     {
322  
-        DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}", 
323  
-                    LogHeader, m_linksetRoot.LocalID, childPrim.LocalID);
324  
-        DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", m_linksetRoot.LocalID, m_linksetRoot.LocalID, childPrim.LocalID);
325  
-        // BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, childPrim.LocalID);
326  
-        m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body, childPrim.Body);
  333
+        // DebugLog("{0}: PhysicallyUnlinkAChildFromRoot: RemoveConstraint between root prim {1} and child prim {2}", 
  334
+        //             LogHeader, rootPrim.LocalID, childPrim.LocalID);
  335
+        DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID);
  336
+
  337
+        m_scene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body, childPrim.Body);
  338
+        // Make the child refresh its location
  339
+        BulletSimAPI.PushUpdate2(childPrim.Body.Ptr);
327 340
     }
328 341
 
329 342
     // Remove linkage between myself and any possible children I might have
330 343
     // Called at taint time!
331  
-    private void PhysicallyUnlinkAllChildrenFromRoot()
  344
+    private void PhysicallyUnlinkAllChildrenFromRoot(BSPrim rootPrim)
332 345
     {
333 346
         // DebugLog("{0}: PhysicallyUnlinkAllChildren:", LogHeader);
334  
-        DetailLog("{0},PhysicallyUnlinkAllChildren,taint", m_linksetRoot.LocalID);
335  
-        m_scene.Constraints.RemoveAndDestroyConstraint(m_linksetRoot.Body);
336  
-        // BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID);
  347
+        DetailLog("{0},PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID);
  348
+
  349
+        m_scene.Constraints.RemoveAndDestroyConstraint(rootPrim.Body);
337 350
     }
338 351
 
339 352
     // Invoke the detailed logger and output something if it's enabled.
340 353
     private void DebugLog(string msg, params Object[] args)
341 354
     {
342  
-        m_scene.Logger.DebugFormat(msg, args);
  355
+        if (m_scene.ShouldDebugLog)
  356
+            m_scene.Logger.DebugFormat(msg, args);
343 357
     }
344 358
 
345 359
     // Invoke the detailed logger and output something if it's enabled.
167  OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -42,7 +42,7 @@ public sealed class BSPrim : PhysicsActor
42 42
     private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 43
     private static readonly string LogHeader = "[BULLETS PRIM]";
44 44
 
45  
-    private void DebugLog(string mm, params Object[] xx) { if (_scene.shouldDebugLog) m_log.DebugFormat(mm, xx); }
  45
+    private void DebugLog(string mm, params Object[] xx) { if (_scene.ShouldDebugLog) m_log.DebugFormat(mm, xx); }
46 46
 
47 47
     private IMesh _mesh;
48 48
     private PrimitiveBaseShape _pbs;
@@ -138,14 +138,15 @@ public BSLinkset Linkset
138 138
         _isPhysical = pisPhysical;
139 139
         _isVolumeDetect = false;
140 140
         _subscribedEventsMs = 0;
141  
-        _friction = _scene.Params.defaultFriction; // TODO: compute based on object material
142  
-        _density = _scene.Params.defaultDensity; // TODO: compute based on object material
  141
+        _friction = _scene.Params.defaultFriction;  // TODO: compute based on object material
  142
+        _density = _scene.Params.defaultDensity;    // TODO: compute based on object material
143 143
         _restitution = _scene.Params.defaultRestitution;
144 144
         _linkset = new BSLinkset(_scene, this);     // a linkset of one
145  
-        _vehicle = new BSDynamics(this);    // add vehicleness
  145
+        _vehicle = new BSDynamics(this);            // add vehicleness
146 146
         _mass = CalculateMass();
147 147
         // do the actual object creation at taint time
148  
-        _scene.TaintedObject(delegate()
  148
+        DetailLog("{0},BSPrim.constructor,call", LocalID);
  149
+        _scene.TaintedObject("BSPrim.create", delegate()
149 150
         {
150 151
             RecreateGeomAndObject();
151 152
 
@@ -160,17 +161,22 @@ public BSLinkset Linkset
160 161
     public void Destroy()
161 162
     {
162 163
         // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
163  
-        // DetailLog("{0},Destroy", LocalID);
  164
+
  165
+        // Undo any links between me and any other object
  166
+        BSPrim parentBefore = _linkset.Root;
  167
+        int childrenBefore = _linkset.NumberOfChildren;
  168
+
  169
+        _linkset = _linkset.RemoveMeFromLinkset(this);
  170
+
  171
+        DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
  172
+            LocalID, parentBefore.LocalID, childrenBefore, _linkset.Root.LocalID, _linkset.NumberOfChildren);
164 173
 
165 174
         // Undo any vehicle properties
166  
-        _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE);
167  
-        _scene.RemoveVehiclePrim(this);     // just to make sure
  175
+        this.VehicleType = (int)Vehicle.TYPE_NONE;
168 176
 
169  
-        _scene.TaintedObject(delegate()
  177
+        _scene.TaintedObject("BSPrim.destroy", delegate()
170 178
         {
171  
-            // Undo any links between me and any other object
172  
-            _linkset = _linkset.RemoveMeFromLinkset(this);
173  
-
  179
+            DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
174 180
             // everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
175 181
             BulletSimAPI.DestroyObject(_scene.WorldID, LocalID);
176 182
         });
@@ -183,11 +189,11 @@ public void Destroy()
183 189
         get { return _size; } 
184 190
         set {
185 191
             _size = value;
186  
-            _scene.TaintedObject(delegate()
  192
+            _scene.TaintedObject("BSPrim.setSize", delegate()
187 193
             {
188 194
                 _mass = CalculateMass();   // changing size changes the mass
189 195
                 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, (IsPhysical ? _mass : 0f), IsPhysical);
190  
-                // DetailLog("{0}: setSize: size={1}, mass={2}, physical={3}", LocalID, _size, _mass, IsPhysical);
  196
+                // DetailLog("{0}: BSPrim.setSize: size={1}, mass={2}, physical={3}", LocalID, _size, _mass, IsPhysical);
191 197
                 RecreateGeomAndObject();
192 198
             });
193 199
         } 
@@ -195,7 +201,7 @@ public void Destroy()
195 201
     public override PrimitiveBaseShape Shape { 
196 202
         set {
197 203
             _pbs = value;
198  
-            _scene.TaintedObject(delegate()
  204
+            _scene.TaintedObject("BSPrim.setShape", delegate()
199 205
             {
200 206
                 _mass = CalculateMass();   // changing the shape changes the mass
201 207
                 RecreateGeomAndObject();
@@ -213,7 +219,7 @@ public void Destroy()
213 219
     public override bool Selected { 
214 220
         set {
215 221
             _isSelected = value;
216  
-            _scene.TaintedObject(delegate()
  222
+            _scene.TaintedObject("BSPrim.setSelected", delegate()
217 223
             {
218 224
                 SetObjectDynamic();
219 225
             });
@@ -224,10 +230,17 @@ public void Destroy()
224 230
     // link me to the specified parent
225 231
     public override void link(PhysicsActor obj) {
226 232
         BSPrim parent = obj as BSPrim;
227  
-        DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID);
228  
-        DetailLog("{0},link,parent={1}", LocalID, obj.LocalID);
  233
+        if (parent != null)
  234
+        {
  235
+            DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, parent.LocalID);
  236
+            BSPrim parentBefore = _linkset.Root;
  237
+            int childrenBefore = _linkset.NumberOfChildren;
229 238
 
230  
-        _linkset = _linkset.AddMeToLinkset(this, parent);
  239
+            _linkset = parent.Linkset.AddMeToLinkset(this);
  240
+
  241
+            DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}", 
  242
+                LocalID, parentBefore.LocalID, childrenBefore, _linkset.Root.LocalID, _linkset.NumberOfChildren);
  243
+        }
231 244
         return; 
232 245
     }
233 246
 
@@ -237,9 +250,14 @@ public void Destroy()
237 250
         // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
238 251
         DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID, 
239 252
                             _linkset.Root._avName+"/"+_linkset.Root.LocalID.ToString());
240  
-        DetailLog("{0},delink,parent={1}", LocalID, _linkset.Root.LocalID.ToString());
241 253
 
242  
-        _linkset.RemoveMeFromLinkset(this);
  254
+        BSPrim parentBefore = _linkset.Root;
  255
+        int childrenBefore = _linkset.NumberOfChildren;
  256
+        
  257
+        _linkset = _linkset.RemoveMeFromLinkset(this);
  258
+
  259
+        DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ", 
  260
+            LocalID, parentBefore.LocalID, childrenBefore, _linkset.Root.LocalID, _linkset.NumberOfChildren);
243 261
         return; 
244 262
     }
245 263
 
@@ -262,7 +280,7 @@ public void ZeroMotion()
262 280
 
263 281
     public override void LockAngularMotion(OMV.Vector3 axis)
264 282
     { 
265  
-        DetailLog("{0},LockAngularMotion,call,axis={1}", LocalID, axis);
  283
+        DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
266 284
         return;
267 285
     }
268 286
 
@@ -279,9 +297,9 @@ public override void LockAngularMotion(OMV.Vector3 axis)
279 297
         set {
280 298
             _position = value;
281 299
             // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
282  
-            _scene.TaintedObject(delegate()
  300
+            _scene.TaintedObject("BSPrim.setPosition", delegate()
283 301
             {
284  
-                DetailLog("{0},SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
  302
+                DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
285 303
                 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
286 304
             });
287 305
         } 
@@ -316,9 +334,9 @@ public override OMV.Vector3 GeometricCenter
316 334
         get { return _force; } 
317 335
         set {
318 336
             _force = value;
319  
-            _scene.TaintedObject(delegate()
  337
+            _scene.TaintedObject("BSPrim.setForce", delegate()
320 338
             {
321  
-                DetailLog("{0},setForce,taint,force={1}", LocalID, _force);
  339
+                DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
322 340
                 // BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
323 341
                 BulletSimAPI.SetObjectForce2(Body.Ptr, _force);
324 342
             });
@@ -331,53 +349,41 @@ public override OMV.Vector3 GeometricCenter
331 349
         } 
332 350
         set {
333 351
             Vehicle type = (Vehicle)value;
334  
-            _scene.TaintedObject(delegate()
  352
+            BSPrim vehiclePrim = this;
  353
+            _scene.TaintedObject("setVehicleType", delegate()
335 354
             {
336  
-                DetailLog("{0},SetVehicleType,taint,type={1}", LocalID, type);
  355
+                // Done at taint time so we're sure the physics engine is not using the variables
  356
+                // Vehicle code changes the parameters for this vehicle type.
337 357
                 _vehicle.ProcessTypeChange(type);
338  
-                if (type == Vehicle.TYPE_NONE)
339  
-                {
340  
-                    _scene.RemoveVehiclePrim(this);
341  
-                }
342  
-                else
343  
-                {
344  
-                    _scene.TaintedObject(delegate()
345  
-                    {
346  
-                        // Tell the physics engine to clear state
347  
-                        BulletSimAPI.ClearForces2(this.Body.Ptr);
348  
-                    });
349  
-
350  
-                    // make it so the scene will call us each tick to do vehicle things
351  
-                    _scene.AddVehiclePrim(this);
352  
-                }
353  
-                return;
  358
+                // Tell the scene about the vehicle so it will get processing each frame.
  359
+                _scene.VehicleInSceneTypeChanged(this, type);
354 360
             });
355 361
         } 
356 362
     }
357 363
     public override void VehicleFloatParam(int param, float value) 
358 364
     {
359  
-        _scene.TaintedObject(delegate()
  365
+        _scene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
360 366
         {
361 367
             _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
362 368
         });
363 369
     }
364 370
     public override void VehicleVectorParam(int param, OMV.Vector3 value) 
365 371
     {
366  
-        _scene.TaintedObject(delegate()
  372
+        _scene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
367 373
         {
368 374
             _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
369 375
         });
370 376
     }
371 377
     public override void VehicleRotationParam(int param, OMV.Quaternion rotation) 
372 378
     {
373  
-        _scene.TaintedObject(delegate()
  379
+        _scene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
374 380
         {
375 381
             _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
376 382
         });
377 383
     }
378 384
     public override void VehicleFlags(int param, bool remove) 
379 385
     {
380  
-        _scene.TaintedObject(delegate()
  386
+        _scene.TaintedObject("BSPrim.VehicleFlags", delegate()
381 387
         {
382 388
             _vehicle.ProcessVehicleFlags(param, remove);
383 389
         });
@@ -395,7 +401,7 @@ public void StepVehicle(float timeStep)
395 401
     public override void SetVolumeDetect(int param) {
396 402
         bool newValue = (param != 0);
397 403
         _isVolumeDetect = newValue;
398  
-        _scene.TaintedObject(delegate()
  404
+        _scene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
399 405
         {
400 406
             SetObjectDynamic();
401 407
         });
@@ -406,9 +412,9 @@ public void StepVehicle(float timeStep)
406 412
         get { return _velocity; } 
407 413
         set {
408 414
             _velocity = value;
409  
-            _scene.TaintedObject(delegate()
  415
+            _scene.TaintedObject("BSPrim.setVelocity", delegate()
410 416
             {
411  
-                DetailLog("{0},SetVelocity,taint,vel={1}", LocalID, _velocity);
  417
+                DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
412 418
                 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity);
413 419
             });
414 420
         } 
@@ -416,7 +422,7 @@ public void StepVehicle(float timeStep)
416 422
     public override OMV.Vector3 Torque { 
417 423
         get { return _torque; } 
418 424
         set { _torque = value; 
419  
-            DetailLog("{0},SetTorque,call,torque={1}", LocalID, _torque);
  425
+            DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
420 426
         } 
421 427
     }
422 428
     public override float CollisionScore { 
@@ -440,10 +446,10 @@ public void StepVehicle(float timeStep)
440 446
         set {
441 447
             _orientation = value;
442 448
             // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
443  
-            _scene.TaintedObject(delegate()
  449
+            _scene.TaintedObject("BSPrim.setOrientation", delegate()
444 450
             {
445 451
                 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
446  
-                DetailLog("{0},setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
  452
+                DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
447 453
                 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
448 454
             });
449 455
         } 
@@ -457,7 +463,7 @@ public void StepVehicle(float timeStep)
457 463
         get { return _isPhysical; } 
458 464
         set {
459 465
             _isPhysical = value;
460  
-            _scene.TaintedObject(delegate()
  466
+            _scene.TaintedObject("BSPrim.setIsPhysical", delegate()
461 467
             {
462 468
                 SetObjectDynamic();
463 469
             });
@@ -478,7 +484,6 @@ private bool IsSolid
478 484
 
479 485
     // Make gravity work if the object is physical and not selected
480 486
     // No locking here because only called when it is safe
481  
-    // Only called at taint time so it is save to call into Bullet.
482 487
     private void SetObjectDynamic()
483 488
     {
484 489
         // RA: remove this for the moment.
@@ -490,8 +495,10 @@ private void SetObjectDynamic()
490 495
         // Bullet wants static objects to have a mass of zero
491 496
         float mass = IsStatic ? 0f : _mass;
492 497
 
493  
-        DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, mass);
494 498
         BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), mass);
  499
+
  500
+        CollisionFlags cf = BulletSimAPI.GetCollisionFlags2(Body.Ptr);
  501
+        DetailLog("{0},BSPrim.SetObjectDynamic,taint,static={1},solid={2},mass={3}, cf={4}", LocalID, IsStatic, IsSolid, mass, cf);
495 502
     }
496 503
 
497 504
     // prims don't fly
@@ -546,9 +553,9 @@ private void SetObjectDynamic()
546 553
         set {
547 554
             _rotationalVelocity = value;
548 555
             // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
549  
-            _scene.TaintedObject(delegate()
  556
+            _scene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
550 557
             {
551  
-                DetailLog("{0},SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
  558
+                DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
552 559
                 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity);
553 560
             });
554 561
         } 
@@ -563,9 +570,9 @@ private void SetObjectDynamic()
563 570
         get { return _buoyancy; } 
564 571
         set {
565 572
             _buoyancy = value;
566  
-            _scene.TaintedObject(delegate()
  573
+            _scene.TaintedObject("BSPrim.setBuoyancy", delegate()
567 574
             {
568  
-                DetailLog("{0},SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
  575
+                DetailLog("{0},BSPrim.SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
569 576
                 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
570 577
             });
571 578
         } 
@@ -617,7 +624,7 @@ private void SetObjectDynamic()
617 624
             m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
618 625
             return;
619 626
         }
620  
-        _scene.TaintedObject(delegate()
  627
+        _scene.TaintedObject("BSPrim.AddForce", delegate()
621 628
         {
622 629
             OMV.Vector3 fSum = OMV.Vector3.Zero;
623 630
             lock (m_accumulatedForces)
@@ -628,17 +635,17 @@ private void SetObjectDynamic()
628 635
                 }
629 636
                 m_accumulatedForces.Clear();
630 637
             }
631  
-            DetailLog("{0},AddObjectForce,taint,force={1}", LocalID, _force);
  638
+            DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, _force);
632 639
             BulletSimAPI.AddObjectForce2(Body.Ptr, fSum);
633 640
         });
634 641
     }
635 642
 
636 643
     public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 
637  
-        DetailLog("{0},AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce);
  644
+        DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce);
638 645
         // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
639 646
     }
640 647
     public override void SetMomentum(OMV.Vector3 momentum) { 
641  
-        DetailLog("{0},SetMomentum,call,mom={1}", LocalID, momentum);
  648
+        DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
642 649
     }
643 650
     public override void SubscribeEvents(int ms) { 
644 651
         _subscribedEventsMs = ms;
@@ -647,7 +654,7 @@ private void SetObjectDynamic()
647 654
             // make sure first collision happens
648 655
             _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs;
649 656
 
650  
-            Scene.TaintedObject(delegate()
  657
+            Scene.TaintedObject("BSPrim.SubscribeEvents", delegate()
651 658
             {
652 659
                 BulletSimAPI.AddToCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
653 660
             });
@@ -655,7 +662,7 @@ private void SetObjectDynamic()
655 662
     }
656 663
     public override void UnSubscribeEvents() { 
657 664
         _subscribedEventsMs = 0;
658  
-        Scene.TaintedObject(delegate()
  665
+        Scene.TaintedObject("BSPrim.UnSubscribeEvents", delegate()
659 666
         {
660 667
             BulletSimAPI.RemoveFromCollisionFlags2(Body.Ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
661 668
         });
@@ -982,7 +989,7 @@ private bool CreateGeom(bool forceRebuild)
982 989
                     // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size);
983 990
                     if (forceRebuild || (_shapeType != ShapeData.PhysicsShapeType.SHAPE_SPHERE))
984 991
                     {
985  
-                        DetailLog("{0},CreateGeom,sphere", LocalID);
  992
+                        DetailLog("{0},BSPrim.CreateGeom,sphere (force={1}", LocalID, forceRebuild);
986