diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 63b70e4637..c670cca542 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -73,8 +73,12 @@ public sealed class BSCharacter : BSPhysObject // base.RawVelocity = value; } // } + // Avatars are always complete (in the physics engine sense) + public override bool IsIncomplete { get { return false; } } + public BSCharacter( uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, bool isFlying) + : base(parent_scene, localID, avName, "BSCharacter") { _physicsActorType = (int)ActorTypes.Agent; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 77f69a59cb..e7b10fe7c1 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -128,6 +128,7 @@ public abstract class BSLinkset m_children = new Dictionary(); LinksetMass = parent.RawMass; Rebuilding = false; + RebuildScheduled = false; parent.ClearDisplacement(); } @@ -297,8 +298,16 @@ public abstract class BSLinkset // Flag denoting the linkset is in the process of being rebuilt. // Used to know not the schedule a rebuild in the middle of a rebuild. + // Because of potential update calls that could want to schedule another rebuild. protected bool Rebuilding { get; set; } + // Flag saying a linkset rebuild has been scheduled. + // This is turned on when the rebuild is requested and turned off when + // the rebuild is complete. Used to limit modifications to the + // linkset parameters while the linkset is in an intermediate state. + // Protected by a "lock(this)" on the BSLinkset object + public bool RebuildScheduled { get; protected set; } + // The object is going dynamic (physical). Do any setup necessary // for a dynamic linkset. // Only the state of the passed object can be modified. The rest of the linkset diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index 6586099280..582ba5b577 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs @@ -106,13 +106,21 @@ public sealed class BSLinksetCompound : BSLinkset // When rebuilding, it is possible to set properties that would normally require a rebuild. // If already rebuilding, don't request another rebuild. // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. - if (!Rebuilding && HasAnyChildren) + lock (this) { - m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() + if (!RebuildScheduled) { - if (HasAnyChildren) - RecomputeLinksetCompound(); - }); + if (!Rebuilding && HasAnyChildren) + { + RebuildScheduled = true; + m_physicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate() + { + if (HasAnyChildren) + RecomputeLinksetCompound(); + RebuildScheduled = false; + }); + } + } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index b0a5ef181a..4384cdc36e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs @@ -212,20 +212,28 @@ public sealed class BSLinksetConstraints : BSLinkset // When rebuilding, it is possible to set properties that would normally require a rebuild. // If already rebuilding, don't request another rebuild. // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. - if (!Rebuilding && HasAnyChildren) + lock (this) { - // Queue to happen after all the other taint processing - m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() + if (!RebuildScheduled) { - if (HasAnyChildren) + if (!Rebuilding && HasAnyChildren) { - // Constraints that have not been changed are not rebuild but make sure - // the constraint of the requestor is rebuilt. - PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor); - // Rebuild the linkset and all its constraints. - RecomputeLinksetConstraints(); + RebuildScheduled = true; + // Queue to happen after all the other taint processing + m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() + { + if (HasAnyChildren) + { + // Constraints that have not been changed are not rebuild but make sure + // the constraint of the requestor is rebuilt. + PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor); + // Rebuild the linkset and all its constraints. + RecomputeLinksetConstraints(); + } + RebuildScheduled = false; + }); } - }); + } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index e4d8df8f6b..2b744a0899 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs @@ -136,6 +136,15 @@ public abstract class BSPhysObject : PhysicsActor // This mostly prevents property updates and collisions until the object is completely here. public bool IsInitialized { get; protected set; } + // Set to 'true' if an object (mesh/linkset/sculpty) is not completely constructed. + // This test is used to prevent some updates to the object when it only partially exists. + // There are several reasons and object might be incomplete: + // Its underlying mesh/sculpty is an asset which must be fetched from the asset store + // It is a linkset who is being added to or removed from + // It is changing state (static to physical, for instance) which requires rebuilding + // This is a computed value based on the underlying physical object construction + abstract public bool IsIncomplete { get; } + // Return the object mass without calculating it or having side effects public abstract float RawMass { get; } // Set the raw mass but also update physical mass properties (inertia, ...) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 27ee5ac9a8..c88a5c2a5e 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -141,6 +141,18 @@ public class BSPrim : BSPhysObject public override bool Stopped { get { return false; } } + + public override bool IsIncomplete { + get { + return ShapeRebuildScheduled; + } + } + + // 'true' if this object's shape is in need of a rebuild and a rebuild has been queued. + // The prim is still available but its underlying shape will change soon. + // This is protected by a 'lock(this)'. + public bool ShapeRebuildScheduled { get; protected set; } + public override OMV.Vector3 Size { get { return _size; } set { @@ -159,13 +171,37 @@ public class BSPrim : BSPhysObject ForceBodyShapeRebuild(false); } } + // Cause the body and shape of the prim to be rebuilt if necessary. + // If there are no changes required, this is quick and does not make changes to the prim. + // If rebuilding is necessary (like changing from static to physical), that will happen. + // The 'ShapeRebuildScheduled' tells any checker that the body/shape may change shortly. + // The return parameter is not used by anyone. public override bool ForceBodyShapeRebuild(bool inTaintTime) { - PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ForceBodyShapeRebuild", delegate() + if (inTaintTime) { + // If called in taint time, do the operation immediately _mass = CalculateMass(); // changing the shape changes the mass CreateGeomAndObject(true); - }); + } + else + { + lock (this) + { + // If a rebuild is not already in the queue + if (!ShapeRebuildScheduled) + { + // Remember that a rebuild is queued -- this is used to flag an incomplete object + ShapeRebuildScheduled = true; + PhysScene.TaintedObject(LocalID, "BSPrim.ForceBodyShapeRebuild", delegate() + { + _mass = CalculateMass(); // changing the shape changes the mass + CreateGeomAndObject(true); + ShapeRebuildScheduled = false; + }); + } + } + } return true; } public override bool Grabbed { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs index 430d645566..cdd912d78d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrimLinkable.cs @@ -54,6 +54,14 @@ public class BSPrimLinkable : BSPrimDisplaced public BSLinkset.LinksetImplementation LinksetType { get; set; } + public override bool IsIncomplete + { + get + { + return base.IsIncomplete || Linkset.RebuildScheduled ; + } + } + public BSPrimLinkable(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) : base(localID, primName, parent_scene, pos, size, rotation, pbs, pisPhysical)