aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs366
1 files changed, 339 insertions, 27 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index f6a890e..6bb88c7 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -45,6 +45,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin
45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. 45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
46 * The last two (and certainly the last one) should be referenced only in taint-time. 46 * The last two (and certainly the last one) should be referenced only in taint-time.
47 */ 47 */
48
49/*
50 * As of 20121221, the following are the call sequences (going down) for different script physical functions:
51 * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce
52 * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce
53 * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse
54 * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v
55 * BS.ApplyCentralForce BS.ApplyTorque
56 */
57
58// Flags used to denote which properties updates when making UpdateProperties calls to linksets, etc.
59public enum UpdatedProperties : uint
60{
61 Position = 1 << 0,
62 Orientation = 1 << 1,
63 Velocity = 1 << 2,
64 Acceleration = 1 << 3,
65 RotationalVelocity = 1 << 4,
66 EntPropUpdates = Position | Orientation | Velocity | Acceleration | RotationalVelocity,
67}
48public abstract class BSPhysObject : PhysicsActor 68public abstract class BSPhysObject : PhysicsActor
49{ 69{
50 protected BSPhysObject() 70 protected BSPhysObject()
@@ -55,15 +75,40 @@ public abstract class BSPhysObject : PhysicsActor
55 PhysicsScene = parentScene; 75 PhysicsScene = parentScene;
56 LocalID = localID; 76 LocalID = localID;
57 PhysObjectName = name; 77 PhysObjectName = name;
78 Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
58 TypeName = typeName; 79 TypeName = typeName;
59 80
60 Linkset = BSLinkset.Factory(PhysicsScene, this); 81 // Initialize variables kept in base.
61 LastAssetBuildFailed = false; 82 GravModifier = 1.0f;
83 Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity);
84
85 // We don't have any physical representation yet.
86 PhysBody = new BulletBody(localID);
87 PhysShape = new BulletShape();
88
89 PrimAssetState = PrimAssetCondition.Unknown;
90
91 // Default material type. Also sets Friction, Restitution and Density.
92 SetMaterial((int)MaterialAttributes.Material.Wood);
62 93
63 CollisionCollection = new CollisionEventUpdate(); 94 CollisionCollection = new CollisionEventUpdate();
95 CollisionsLastTick = CollisionCollection;
64 SubscribedEventsMs = 0; 96 SubscribedEventsMs = 0;
65 CollidingStep = 0; 97 CollidingStep = 0;
66 CollidingGroundStep = 0; 98 CollidingGroundStep = 0;
99 CollisionAccumulation = 0;
100 ColliderIsMoving = false;
101 CollisionScore = 0;
102
103 // All axis free.
104 LockedAxis = LockedAxisFree;
105 }
106
107 // Tell the object to clean up.
108 public virtual void Destroy()
109 {
110 UnRegisterAllPreStepActions();
111 UnRegisterAllPostStepActions();
67 } 112 }
68 113
69 public BSScene PhysicsScene { get; protected set; } 114 public BSScene PhysicsScene { get; protected set; }
@@ -71,13 +116,15 @@ public abstract class BSPhysObject : PhysicsActor
71 public string PhysObjectName { get; protected set; } 116 public string PhysObjectName { get; protected set; }
72 public string TypeName { get; protected set; } 117 public string TypeName { get; protected set; }
73 118
74 public BSLinkset Linkset { get; set; }
75 119
76 // Return the object mass without calculating it or having side effects 120 // Return the object mass without calculating it or having side effects
77 public abstract float RawMass { get; } 121 public abstract float RawMass { get; }
78 // Set the raw mass but also update physical mass properties (inertia, ...) 122 // Set the raw mass but also update physical mass properties (inertia, ...)
79 public abstract void UpdatePhysicalMassProperties(float mass); 123 // 'inWorld' true if the object has already been added to the dynamic world.
124 public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
80 125
126 // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy.
127 public virtual OMV.Vector3 Gravity { get; set; }
81 // The last value calculated for the prim's inertia 128 // The last value calculated for the prim's inertia
82 public OMV.Vector3 Inertia { get; set; } 129 public OMV.Vector3 Inertia { get; set; }
83 130
@@ -86,12 +133,17 @@ public abstract class BSPhysObject : PhysicsActor
86 // Reference to the physical shape (btCollisionShape) of this object 133 // Reference to the physical shape (btCollisionShape) of this object
87 public BulletShape PhysShape; 134 public BulletShape PhysShape;
88 135
89 // 'true' if the mesh's underlying asset failed to build. 136 // The physical representation of the prim might require an asset fetch.
90 // This will keep us from looping after the first time the build failed. 137 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
91 public bool LastAssetBuildFailed { get; set; } 138 public enum PrimAssetCondition
139 {
140 Unknown, Waiting, Failed, Fetched
141 }
142 public PrimAssetCondition PrimAssetState { get; set; }
92 143
93 // The objects base shape information. Null if not a prim type shape. 144 // The objects base shape information. Null if not a prim type shape.
94 public PrimitiveBaseShape BaseShape { get; protected set; } 145 public PrimitiveBaseShape BaseShape { get; protected set; }
146
95 // Some types of objects have preferred physical representations. 147 // Some types of objects have preferred physical representations.
96 // Returns SHAPE_UNKNOWN if there is no preference. 148 // Returns SHAPE_UNKNOWN if there is no preference.
97 public virtual BSPhysicsShapeType PreferredPhysicalShape 149 public virtual BSPhysicsShapeType PreferredPhysicalShape
@@ -105,29 +157,46 @@ public abstract class BSPhysObject : PhysicsActor
105 public EntityProperties CurrentEntityProperties { get; set; } 157 public EntityProperties CurrentEntityProperties { get; set; }
106 public EntityProperties LastEntityProperties { get; set; } 158 public EntityProperties LastEntityProperties { get; set; }
107 159
108 public abstract OMV.Vector3 Scale { get; set; } 160 public virtual OMV.Vector3 Scale { get; set; }
161
162 // It can be confusing for an actor to know if it should move or update an object
163 // depeneding on the setting of 'selected', 'physical, ...
164 // This flag is the true test -- if true, the object is being acted on in the physical world
165 public abstract bool IsPhysicallyActive { get; }
166
167 // Detailed state of the object.
109 public abstract bool IsSolid { get; } 168 public abstract bool IsSolid { get; }
110 public abstract bool IsStatic { get; } 169 public abstract bool IsStatic { get; }
170 public abstract bool IsSelected { get; }
171
172 // Materialness
173 public MaterialAttributes.Material Material { get; private set; }
174 public override void SetMaterial(int material)
175 {
176 Material = (MaterialAttributes.Material)material;
177
178 // Setting the material sets the material attributes also.
179 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
180 Friction = matAttrib.friction;
181 Restitution = matAttrib.restitution;
182 Density = matAttrib.density / BSParam.DensityScaleFactor;
183 DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
184 }
111 185
112 // Stop all physical motion. 186 // Stop all physical motion.
113 public abstract void ZeroMotion(bool inTaintTime); 187 public abstract void ZeroMotion(bool inTaintTime);
114 public abstract void ZeroAngularMotion(bool inTaintTime); 188 public abstract void ZeroAngularMotion(bool inTaintTime);
115 189
116 // Step the vehicle simulation for this object. A NOOP if the vehicle was not configured.
117 public virtual void StepVehicle(float timeStep) { }
118
119 // Update the physical location and motion of the object. Called with data from Bullet. 190 // Update the physical location and motion of the object. Called with data from Bullet.
120 public abstract void UpdateProperties(EntityProperties entprop); 191 public abstract void UpdateProperties(EntityProperties entprop);
121 192
122 // Tell the object to clean up.
123 public abstract void Destroy();
124
125 public abstract OMV.Vector3 RawPosition { get; set; } 193 public abstract OMV.Vector3 RawPosition { get; set; }
126 public abstract OMV.Vector3 ForcePosition { get; set; } 194 public abstract OMV.Vector3 ForcePosition { get; set; }
127 195
128 public abstract OMV.Quaternion RawOrientation { get; set; } 196 public abstract OMV.Quaternion RawOrientation { get; set; }
129 public abstract OMV.Quaternion ForceOrientation { get; set; } 197 public abstract OMV.Quaternion ForceOrientation { get; set; }
130 198
199 public abstract OMV.Vector3 RawVelocity { get; set; }
131 public abstract OMV.Vector3 ForceVelocity { get; set; } 200 public abstract OMV.Vector3 ForceVelocity { get; set; }
132 201
133 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } 202 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
@@ -136,6 +205,32 @@ public abstract class BSPhysObject : PhysicsActor
136 205
137 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } 206 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
138 207
208 // The current velocity forward
209 public virtual float ForwardSpeed
210 {
211 get
212 {
213 OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
214 return characterOrientedVelocity.X;
215 }
216 }
217 // The forward speed we are trying to achieve (TargetVelocity)
218 public virtual float TargetVelocitySpeed
219 {
220 get
221 {
222 OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
223 return characterOrientedVelocity.X;
224 }
225 }
226
227 // The user can optionally set the center of mass. The user's setting will override any
228 // computed center-of-mass (like in linksets).
229 public OMV.Vector3? UserSetCenterOfMass { get; set; }
230
231 public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free.
232 public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free
233
139 #region Collisions 234 #region Collisions
140 235
141 // Requested number of milliseconds between collision events. Zero means disabled. 236 // Requested number of milliseconds between collision events. Zero means disabled.
@@ -146,38 +241,82 @@ public abstract class BSPhysObject : PhysicsActor
146 protected long CollidingStep { get; set; } 241 protected long CollidingStep { get; set; }
147 // The simulation step that last had a collision with the ground 242 // The simulation step that last had a collision with the ground
148 protected long CollidingGroundStep { get; set; } 243 protected long CollidingGroundStep { get; set; }
244 // The simulation step that last collided with an object
245 protected long CollidingObjectStep { get; set; }
149 // The collision flags we think are set in Bullet 246 // The collision flags we think are set in Bullet
150 protected CollisionFlags CurrentCollisionFlags { get; set; } 247 protected CollisionFlags CurrentCollisionFlags { get; set; }
248 // On a collision, check the collider and remember if the last collider was moving
249 // Used to modify the standing of avatars (avatars on stationary things stand still)
250 protected bool ColliderIsMoving;
251
252 // Count of collisions for this object
253 protected long CollisionAccumulation { get; set; }
254
255 public override bool IsColliding {
256 get { return (CollidingStep == PhysicsScene.SimulationStep); }
257 set {
258 if (value)
259 CollidingStep = PhysicsScene.SimulationStep;
260 else
261 CollidingStep = 0;
262 }
263 }
264 public override bool CollidingGround {
265 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
266 set
267 {
268 if (value)
269 CollidingGroundStep = PhysicsScene.SimulationStep;
270 else
271 CollidingGroundStep = 0;
272 }
273 }
274 public override bool CollidingObj {
275 get { return (CollidingObjectStep == PhysicsScene.SimulationStep); }
276 set {
277 if (value)
278 CollidingObjectStep = PhysicsScene.SimulationStep;
279 else
280 CollidingObjectStep = 0;
281 }
282 }
151 283
152 // The collisions that have been collected this tick 284 // The collisions that have been collected this tick
153 protected CollisionEventUpdate CollisionCollection; 285 protected CollisionEventUpdate CollisionCollection;
286 // Remember collisions from last tick for fancy collision based actions
287 // (like a BSCharacter walking up stairs).
288 protected CollisionEventUpdate CollisionsLastTick;
154 289
155 // The simulation step is telling this object about a collision. 290 // The simulation step is telling this object about a collision.
156 // Return 'true' if a collision was processed and should be sent up. 291 // Return 'true' if a collision was processed and should be sent up.
292 // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
157 // Called at taint time from within the Step() function 293 // Called at taint time from within the Step() function
158 public virtual bool Collide(uint collidingWith, BSPhysObject collidee, 294 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
159 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) 295 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
160 { 296 {
161 bool ret = false; 297 bool ret = false;
162 298
163 // The following lines make IsColliding() and IsCollidingGround() work 299 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
164 CollidingStep = PhysicsScene.SimulationStep; 300 CollidingStep = PhysicsScene.SimulationStep;
165 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) 301 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
166 { 302 {
167 CollidingGroundStep = PhysicsScene.SimulationStep; 303 CollidingGroundStep = PhysicsScene.SimulationStep;
168 } 304 }
169 305 else
170 // prims in the same linkset cannot collide with each other
171 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
172 { 306 {
173 return ret; 307 CollidingObjectStep = PhysicsScene.SimulationStep;
174 } 308 }
175 309
176 // if someone has subscribed for collision events.... 310 CollisionAccumulation++;
311
312 // For movement tests, remember if we are colliding with an object that is moving.
313 ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false;
314
315 // If someone has subscribed for collision events log the collision so it will be reported up
177 if (SubscribedEvents()) { 316 if (SubscribedEvents()) {
178 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); 317 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
179 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}", 318 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}",
180 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth); 319 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving);
181 320
182 ret = true; 321 ret = true;
183 } 322 }
@@ -191,8 +330,9 @@ public abstract class BSPhysObject : PhysicsActor
191 public virtual bool SendCollisions() 330 public virtual bool SendCollisions()
192 { 331 {
193 bool ret = true; 332 bool ret = true;
333
194 // If the 'no collision' call, force it to happen right now so quick collision_end 334 // If the 'no collision' call, force it to happen right now so quick collision_end
195 bool force = CollisionCollection.Count == 0; 335 bool force = (CollisionCollection.Count == 0 && CollisionsLastTick.Count != 0);
196 336
197 // throttle the collisions to the number of milliseconds specified in the subscription 337 // throttle the collisions to the number of milliseconds specified in the subscription
198 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) 338 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
@@ -207,11 +347,16 @@ public abstract class BSPhysObject : PhysicsActor
207 ret = false; 347 ret = false;
208 } 348 }
209 349
210 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); 350 DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
211 base.SendCollisionUpdate(CollisionCollection); 351 base.SendCollisionUpdate(CollisionCollection);
212 352
213 // The collisionCollection structure is passed around in the simulator. 353 // Remember the collisions from this tick for some collision specific processing.
354 CollisionsLastTick = CollisionCollection;
355
356 // The CollisionCollection instance is passed around in the simulator.
214 // Make sure we don't have a handle to that one and that a new one is used for next time. 357 // Make sure we don't have a handle to that one and that a new one is used for next time.
358 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
359 // a race condition is created for the other users of this instance.
215 CollisionCollection = new CollisionEventUpdate(); 360 CollisionCollection = new CollisionEventUpdate();
216 } 361 }
217 return ret; 362 return ret;
@@ -229,7 +374,8 @@ public abstract class BSPhysObject : PhysicsActor
229 374
230 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() 375 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
231 { 376 {
232 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 377 if (PhysBody.HasPhysicalBody)
378 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
233 }); 379 });
234 } 380 }
235 else 381 else
@@ -243,21 +389,187 @@ public abstract class BSPhysObject : PhysicsActor
243 SubscribedEventsMs = 0; 389 SubscribedEventsMs = 0;
244 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 390 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
245 { 391 {
246 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 392 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
393 if (PhysBody.HasPhysicalBody)
394 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
247 }); 395 });
248 } 396 }
249 // Return 'true' if the simulator wants collision events 397 // Return 'true' if the simulator wants collision events
250 public override bool SubscribedEvents() { 398 public override bool SubscribedEvents() {
251 return (SubscribedEventsMs > 0); 399 return (SubscribedEventsMs > 0);
252 } 400 }
401 // Because 'CollisionScore' is called many times while sorting, it should not be recomputed
402 // each time called. So this is built to be light weight for each collision and to do
403 // all the processing when the user asks for the info.
404 public void ComputeCollisionScore()
405 {
406 // Scale the collision count by the time since the last collision.
407 // The "+1" prevents dividing by zero.
408 long timeAgo = PhysicsScene.SimulationStep - CollidingStep + 1;
409 CollisionScore = CollisionAccumulation / timeAgo;
410 }
411 public override float CollisionScore { get; set; }
253 412
254 #endregion // Collisions 413 #endregion // Collisions
255 414
415 #region Per Simulation Step actions
416 // There are some actions that must be performed for a physical object before each simulation step.
417 // These actions are optional so, rather than scanning all the physical objects and asking them
418 // if they have anything to do, a physical object registers for an event call before the step is performed.
419 // This bookkeeping makes it easy to add, remove and clean up after all these registrations.
420 private Dictionary<string, BSScene.PreStepAction> RegisteredPrestepActions = new Dictionary<string, BSScene.PreStepAction>();
421 private Dictionary<string, BSScene.PostStepAction> RegisteredPoststepActions = new Dictionary<string, BSScene.PostStepAction>();
422 protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
423 {
424 string identifier = op + "-" + id.ToString();
425
426 lock (RegisteredPrestepActions)
427 {
428 // Clean out any existing action
429 UnRegisterPreStepAction(op, id);
430 RegisteredPrestepActions[identifier] = actn;
431 PhysicsScene.BeforeStep += actn;
432 }
433 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
434 }
435
436 // Unregister a pre step action. Safe to call if the action has not been registered.
437 // Returns 'true' if an action was actually removed
438 protected bool UnRegisterPreStepAction(string op, uint id)
439 {
440 string identifier = op + "-" + id.ToString();
441 bool removed = false;
442 lock (RegisteredPrestepActions)
443 {
444 if (RegisteredPrestepActions.ContainsKey(identifier))
445 {
446 PhysicsScene.BeforeStep -= RegisteredPrestepActions[identifier];
447 RegisteredPrestepActions.Remove(identifier);
448 removed = true;
449 }
450 }
451 DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
452 return removed;
453 }
454
455 protected void UnRegisterAllPreStepActions()
456 {
457 lock (RegisteredPrestepActions)
458 {
459 foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredPrestepActions)
460 {
461 PhysicsScene.BeforeStep -= kvp.Value;
462 }
463 RegisteredPrestepActions.Clear();
464 }
465 DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
466 }
467
468 protected void RegisterPostStepAction(string op, uint id, BSScene.PostStepAction actn)
469 {
470 string identifier = op + "-" + id.ToString();
471
472 lock (RegisteredPoststepActions)
473 {
474 // Clean out any existing action
475 UnRegisterPostStepAction(op, id);
476 RegisteredPoststepActions[identifier] = actn;
477 PhysicsScene.AfterStep += actn;
478 }
479 DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier);
480 }
481
482 // Unregister a pre step action. Safe to call if the action has not been registered.
483 // Returns 'true' if an action was actually removed.
484 protected bool UnRegisterPostStepAction(string op, uint id)
485 {
486 string identifier = op + "-" + id.ToString();
487 bool removed = false;
488 lock (RegisteredPoststepActions)
489 {
490 if (RegisteredPoststepActions.ContainsKey(identifier))
491 {
492 PhysicsScene.AfterStep -= RegisteredPoststepActions[identifier];
493 RegisteredPoststepActions.Remove(identifier);
494 removed = true;
495 }
496 }
497 DetailLog("{0},BSPhysObject.UnRegisterPostStepAction,id={1},removed={2}", LocalID, identifier, removed);
498 return removed;
499 }
500
501 protected void UnRegisterAllPostStepActions()
502 {
503 lock (RegisteredPoststepActions)
504 {
505 foreach (KeyValuePair<string, BSScene.PostStepAction> kvp in RegisteredPoststepActions)
506 {
507 PhysicsScene.AfterStep -= kvp.Value;
508 }
509 RegisteredPoststepActions.Clear();
510 }
511 DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID);
512 }
513
514 // When an update to the physical properties happens, this event is fired to let
515 // different actors to modify the update before it is passed around
516 public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
517 public event PreUpdatePropertyAction OnPreUpdateProperty;
518 protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop)
519 {
520 PreUpdatePropertyAction actions = OnPreUpdateProperty;
521 if (actions != null)
522 actions(ref entprop);
523 }
524
525 private Dictionary<string, PreUpdatePropertyAction> RegisteredPreUpdatePropertyActions = new Dictionary<string, PreUpdatePropertyAction>();
526 public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn)
527 {
528 lock (RegisteredPreUpdatePropertyActions)
529 {
530 // Clean out any existing action
531 UnRegisterPreUpdatePropertyAction(identifier);
532 RegisteredPreUpdatePropertyActions[identifier] = actn;
533 OnPreUpdateProperty += actn;
534 }
535 DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier);
536 }
537 public bool UnRegisterPreUpdatePropertyAction(string identifier)
538 {
539 bool removed = false;
540 lock (RegisteredPreUpdatePropertyActions)
541 {
542 if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier))
543 {
544 OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier];
545 RegisteredPreUpdatePropertyActions.Remove(identifier);
546 removed = true;
547 }
548 }
549 DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed);
550 return removed;
551 }
552 public void UnRegisterAllPreUpdatePropertyActions()
553 {
554 lock (RegisteredPreUpdatePropertyActions)
555 {
556 foreach (KeyValuePair<string, PreUpdatePropertyAction> kvp in RegisteredPreUpdatePropertyActions)
557 {
558 OnPreUpdateProperty -= kvp.Value;
559 }
560 RegisteredPreUpdatePropertyActions.Clear();
561 }
562 DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID);
563 }
564
565 #endregion // Per Simulation Step actions
566
256 // High performance detailed logging routine used by the physical objects. 567 // High performance detailed logging routine used by the physical objects.
257 protected void DetailLog(string msg, params Object[] args) 568 protected void DetailLog(string msg, params Object[] args)
258 { 569 {
259 if (PhysicsScene.PhysicsLogging.Enabled) 570 if (PhysicsScene.PhysicsLogging.Enabled)
260 PhysicsScene.DetailLog(msg, args); 571 PhysicsScene.DetailLog(msg, args);
261 } 572 }
573
262} 574}
263} 575}