aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs354
1 files changed, 331 insertions, 23 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index f6a890e..f953c1e 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.
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
61 LastAssetBuildFailed = false; 89 LastAssetBuildFailed = false;
62 90
91 // Default material type. Also sets Friction, Restitution and Density.
92 SetMaterial((int)MaterialAttributes.Material.Wood);
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
@@ -92,6 +139,7 @@ public abstract class BSPhysObject : PhysicsActor
92 139
93 // The objects base shape information. Null if not a prim type shape. 140 // The objects base shape information. Null if not a prim type shape.
94 public PrimitiveBaseShape BaseShape { get; protected set; } 141 public PrimitiveBaseShape BaseShape { get; protected set; }
142
95 // Some types of objects have preferred physical representations. 143 // Some types of objects have preferred physical representations.
96 // Returns SHAPE_UNKNOWN if there is no preference. 144 // Returns SHAPE_UNKNOWN if there is no preference.
97 public virtual BSPhysicsShapeType PreferredPhysicalShape 145 public virtual BSPhysicsShapeType PreferredPhysicalShape
@@ -105,29 +153,46 @@ public abstract class BSPhysObject : PhysicsActor
105 public EntityProperties CurrentEntityProperties { get; set; } 153 public EntityProperties CurrentEntityProperties { get; set; }
106 public EntityProperties LastEntityProperties { get; set; } 154 public EntityProperties LastEntityProperties { get; set; }
107 155
108 public abstract OMV.Vector3 Scale { get; set; } 156 public virtual OMV.Vector3 Scale { get; set; }
157
158 // It can be confusing for an actor to know if it should move or update an object
159 // depeneding on the setting of 'selected', 'physical, ...
160 // This flag is the true test -- if true, the object is being acted on in the physical world
161 public abstract bool IsPhysicallyActive { get; }
162
163 // Detailed state of the object.
109 public abstract bool IsSolid { get; } 164 public abstract bool IsSolid { get; }
110 public abstract bool IsStatic { get; } 165 public abstract bool IsStatic { get; }
166 public abstract bool IsSelected { get; }
167
168 // Materialness
169 public MaterialAttributes.Material Material { get; private set; }
170 public override void SetMaterial(int material)
171 {
172 Material = (MaterialAttributes.Material)material;
173
174 // Setting the material sets the material attributes also.
175 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
176 Friction = matAttrib.friction;
177 Restitution = matAttrib.restitution;
178 Density = matAttrib.density / BSParam.DensityScaleFactor;
179 DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
180 }
111 181
112 // Stop all physical motion. 182 // Stop all physical motion.
113 public abstract void ZeroMotion(bool inTaintTime); 183 public abstract void ZeroMotion(bool inTaintTime);
114 public abstract void ZeroAngularMotion(bool inTaintTime); 184 public abstract void ZeroAngularMotion(bool inTaintTime);
115 185
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. 186 // Update the physical location and motion of the object. Called with data from Bullet.
120 public abstract void UpdateProperties(EntityProperties entprop); 187 public abstract void UpdateProperties(EntityProperties entprop);
121 188
122 // Tell the object to clean up.
123 public abstract void Destroy();
124
125 public abstract OMV.Vector3 RawPosition { get; set; } 189 public abstract OMV.Vector3 RawPosition { get; set; }
126 public abstract OMV.Vector3 ForcePosition { get; set; } 190 public abstract OMV.Vector3 ForcePosition { get; set; }
127 191
128 public abstract OMV.Quaternion RawOrientation { get; set; } 192 public abstract OMV.Quaternion RawOrientation { get; set; }
129 public abstract OMV.Quaternion ForceOrientation { get; set; } 193 public abstract OMV.Quaternion ForceOrientation { get; set; }
130 194
195 public abstract OMV.Vector3 RawVelocity { get; set; }
131 public abstract OMV.Vector3 ForceVelocity { get; set; } 196 public abstract OMV.Vector3 ForceVelocity { get; set; }
132 197
133 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } 198 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
@@ -136,6 +201,32 @@ public abstract class BSPhysObject : PhysicsActor
136 201
137 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } 202 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
138 203
204 // The current velocity forward
205 public virtual float ForwardSpeed
206 {
207 get
208 {
209 OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
210 return characterOrientedVelocity.X;
211 }
212 }
213 // The forward speed we are trying to achieve (TargetVelocity)
214 public virtual float TargetVelocitySpeed
215 {
216 get
217 {
218 OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
219 return characterOrientedVelocity.X;
220 }
221 }
222
223 // The user can optionally set the center of mass. The user's setting will override any
224 // computed center-of-mass (like in linksets).
225 public OMV.Vector3? UserSetCenterOfMass { get; set; }
226
227 public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free.
228 public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free
229
139 #region Collisions 230 #region Collisions
140 231
141 // Requested number of milliseconds between collision events. Zero means disabled. 232 // Requested number of milliseconds between collision events. Zero means disabled.
@@ -146,38 +237,82 @@ public abstract class BSPhysObject : PhysicsActor
146 protected long CollidingStep { get; set; } 237 protected long CollidingStep { get; set; }
147 // The simulation step that last had a collision with the ground 238 // The simulation step that last had a collision with the ground
148 protected long CollidingGroundStep { get; set; } 239 protected long CollidingGroundStep { get; set; }
240 // The simulation step that last collided with an object
241 protected long CollidingObjectStep { get; set; }
149 // The collision flags we think are set in Bullet 242 // The collision flags we think are set in Bullet
150 protected CollisionFlags CurrentCollisionFlags { get; set; } 243 protected CollisionFlags CurrentCollisionFlags { get; set; }
244 // On a collision, check the collider and remember if the last collider was moving
245 // Used to modify the standing of avatars (avatars on stationary things stand still)
246 protected bool ColliderIsMoving;
247
248 // Count of collisions for this object
249 protected long CollisionAccumulation { get; set; }
250
251 public override bool IsColliding {
252 get { return (CollidingStep == PhysicsScene.SimulationStep); }
253 set {
254 if (value)
255 CollidingStep = PhysicsScene.SimulationStep;
256 else
257 CollidingStep = 0;
258 }
259 }
260 public override bool CollidingGround {
261 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
262 set
263 {
264 if (value)
265 CollidingGroundStep = PhysicsScene.SimulationStep;
266 else
267 CollidingGroundStep = 0;
268 }
269 }
270 public override bool CollidingObj {
271 get { return (CollidingObjectStep == PhysicsScene.SimulationStep); }
272 set {
273 if (value)
274 CollidingObjectStep = PhysicsScene.SimulationStep;
275 else
276 CollidingObjectStep = 0;
277 }
278 }
151 279
152 // The collisions that have been collected this tick 280 // The collisions that have been collected this tick
153 protected CollisionEventUpdate CollisionCollection; 281 protected CollisionEventUpdate CollisionCollection;
282 // Remember collisions from last tick for fancy collision based actions
283 // (like a BSCharacter walking up stairs).
284 protected CollisionEventUpdate CollisionsLastTick;
154 285
155 // The simulation step is telling this object about a collision. 286 // The simulation step is telling this object about a collision.
156 // Return 'true' if a collision was processed and should be sent up. 287 // Return 'true' if a collision was processed and should be sent up.
288 // 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 289 // Called at taint time from within the Step() function
158 public virtual bool Collide(uint collidingWith, BSPhysObject collidee, 290 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
159 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) 291 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
160 { 292 {
161 bool ret = false; 293 bool ret = false;
162 294
163 // The following lines make IsColliding() and IsCollidingGround() work 295 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
164 CollidingStep = PhysicsScene.SimulationStep; 296 CollidingStep = PhysicsScene.SimulationStep;
165 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) 297 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
166 { 298 {
167 CollidingGroundStep = PhysicsScene.SimulationStep; 299 CollidingGroundStep = PhysicsScene.SimulationStep;
168 } 300 }
169 301 else
170 // prims in the same linkset cannot collide with each other
171 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
172 { 302 {
173 return ret; 303 CollidingObjectStep = PhysicsScene.SimulationStep;
174 } 304 }
175 305
176 // if someone has subscribed for collision events.... 306 CollisionAccumulation++;
307
308 // For movement tests, remember if we are colliding with an object that is moving.
309 ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false;
310
311 // If someone has subscribed for collision events log the collision so it will be reported up
177 if (SubscribedEvents()) { 312 if (SubscribedEvents()) {
178 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); 313 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
179 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5}", 314 DetailLog("{0},{1}.Collison.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}",
180 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth); 315 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving);
181 316
182 ret = true; 317 ret = true;
183 } 318 }
@@ -191,8 +326,9 @@ public abstract class BSPhysObject : PhysicsActor
191 public virtual bool SendCollisions() 326 public virtual bool SendCollisions()
192 { 327 {
193 bool ret = true; 328 bool ret = true;
329
194 // If the 'no collision' call, force it to happen right now so quick collision_end 330 // If the 'no collision' call, force it to happen right now so quick collision_end
195 bool force = CollisionCollection.Count == 0; 331 bool force = (CollisionCollection.Count == 0 && CollisionsLastTick.Count != 0);
196 332
197 // throttle the collisions to the number of milliseconds specified in the subscription 333 // throttle the collisions to the number of milliseconds specified in the subscription
198 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) 334 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
@@ -207,11 +343,16 @@ public abstract class BSPhysObject : PhysicsActor
207 ret = false; 343 ret = false;
208 } 344 }
209 345
210 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); 346 DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
211 base.SendCollisionUpdate(CollisionCollection); 347 base.SendCollisionUpdate(CollisionCollection);
212 348
213 // The collisionCollection structure is passed around in the simulator. 349 // Remember the collisions from this tick for some collision specific processing.
350 CollisionsLastTick = CollisionCollection;
351
352 // 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. 353 // Make sure we don't have a handle to that one and that a new one is used for next time.
354 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
355 // a race condition is created for the other users of this instance.
215 CollisionCollection = new CollisionEventUpdate(); 356 CollisionCollection = new CollisionEventUpdate();
216 } 357 }
217 return ret; 358 return ret;
@@ -229,7 +370,8 @@ public abstract class BSPhysObject : PhysicsActor
229 370
230 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() 371 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
231 { 372 {
232 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 373 if (PhysBody.HasPhysicalBody)
374 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
233 }); 375 });
234 } 376 }
235 else 377 else
@@ -243,21 +385,187 @@ public abstract class BSPhysObject : PhysicsActor
243 SubscribedEventsMs = 0; 385 SubscribedEventsMs = 0;
244 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 386 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
245 { 387 {
246 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 388 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
389 if (PhysBody.HasPhysicalBody)
390 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
247 }); 391 });
248 } 392 }
249 // Return 'true' if the simulator wants collision events 393 // Return 'true' if the simulator wants collision events
250 public override bool SubscribedEvents() { 394 public override bool SubscribedEvents() {
251 return (SubscribedEventsMs > 0); 395 return (SubscribedEventsMs > 0);
252 } 396 }
397 // Because 'CollisionScore' is called many times while sorting, it should not be recomputed
398 // each time called. So this is built to be light weight for each collision and to do
399 // all the processing when the user asks for the info.
400 public void ComputeCollisionScore()
401 {
402 // Scale the collision count by the time since the last collision.
403 // The "+1" prevents dividing by zero.
404 long timeAgo = PhysicsScene.SimulationStep - CollidingStep + 1;
405 CollisionScore = CollisionAccumulation / timeAgo;
406 }
407 public override float CollisionScore { get; set; }
253 408
254 #endregion // Collisions 409 #endregion // Collisions
255 410
411 #region Per Simulation Step actions
412 // There are some actions that must be performed for a physical object before each simulation step.
413 // These actions are optional so, rather than scanning all the physical objects and asking them
414 // if they have anything to do, a physical object registers for an event call before the step is performed.
415 // This bookkeeping makes it easy to add, remove and clean up after all these registrations.
416 private Dictionary<string, BSScene.PreStepAction> RegisteredPrestepActions = new Dictionary<string, BSScene.PreStepAction>();
417 private Dictionary<string, BSScene.PostStepAction> RegisteredPoststepActions = new Dictionary<string, BSScene.PostStepAction>();
418 protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
419 {
420 string identifier = op + "-" + id.ToString();
421
422 lock (RegisteredPrestepActions)
423 {
424 // Clean out any existing action
425 UnRegisterPreStepAction(op, id);
426 RegisteredPrestepActions[identifier] = actn;
427 PhysicsScene.BeforeStep += actn;
428 }
429 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
430 }
431
432 // Unregister a pre step action. Safe to call if the action has not been registered.
433 // Returns 'true' if an action was actually removed
434 protected bool UnRegisterPreStepAction(string op, uint id)
435 {
436 string identifier = op + "-" + id.ToString();
437 bool removed = false;
438 lock (RegisteredPrestepActions)
439 {
440 if (RegisteredPrestepActions.ContainsKey(identifier))
441 {
442 PhysicsScene.BeforeStep -= RegisteredPrestepActions[identifier];
443 RegisteredPrestepActions.Remove(identifier);
444 removed = true;
445 }
446 }
447 DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
448 return removed;
449 }
450
451 protected void UnRegisterAllPreStepActions()
452 {
453 lock (RegisteredPrestepActions)
454 {
455 foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredPrestepActions)
456 {
457 PhysicsScene.BeforeStep -= kvp.Value;
458 }
459 RegisteredPrestepActions.Clear();
460 }
461 DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
462 }
463
464 protected void RegisterPostStepAction(string op, uint id, BSScene.PostStepAction actn)
465 {
466 string identifier = op + "-" + id.ToString();
467
468 lock (RegisteredPoststepActions)
469 {
470 // Clean out any existing action
471 UnRegisterPostStepAction(op, id);
472 RegisteredPoststepActions[identifier] = actn;
473 PhysicsScene.AfterStep += actn;
474 }
475 DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier);
476 }
477
478 // Unregister a pre step action. Safe to call if the action has not been registered.
479 // Returns 'true' if an action was actually removed.
480 protected bool UnRegisterPostStepAction(string op, uint id)
481 {
482 string identifier = op + "-" + id.ToString();
483 bool removed = false;
484 lock (RegisteredPoststepActions)
485 {
486 if (RegisteredPoststepActions.ContainsKey(identifier))
487 {
488 PhysicsScene.AfterStep -= RegisteredPoststepActions[identifier];
489 RegisteredPoststepActions.Remove(identifier);
490 removed = true;
491 }
492 }
493 DetailLog("{0},BSPhysObject.UnRegisterPostStepAction,id={1},removed={2}", LocalID, identifier, removed);
494 return removed;
495 }
496
497 protected void UnRegisterAllPostStepActions()
498 {
499 lock (RegisteredPoststepActions)
500 {
501 foreach (KeyValuePair<string, BSScene.PostStepAction> kvp in RegisteredPoststepActions)
502 {
503 PhysicsScene.AfterStep -= kvp.Value;
504 }
505 RegisteredPoststepActions.Clear();
506 }
507 DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID);
508 }
509
510 // When an update to the physical properties happens, this event is fired to let
511 // different actors to modify the update before it is passed around
512 public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
513 public event PreUpdatePropertyAction OnPreUpdateProperty;
514 protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop)
515 {
516 PreUpdatePropertyAction actions = OnPreUpdateProperty;
517 if (actions != null)
518 actions(ref entprop);
519 }
520
521 private Dictionary<string, PreUpdatePropertyAction> RegisteredPreUpdatePropertyActions = new Dictionary<string, PreUpdatePropertyAction>();
522 public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn)
523 {
524 lock (RegisteredPreUpdatePropertyActions)
525 {
526 // Clean out any existing action
527 UnRegisterPreUpdatePropertyAction(identifier);
528 RegisteredPreUpdatePropertyActions[identifier] = actn;
529 OnPreUpdateProperty += actn;
530 }
531 DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier);
532 }
533 public bool UnRegisterPreUpdatePropertyAction(string identifier)
534 {
535 bool removed = false;
536 lock (RegisteredPreUpdatePropertyActions)
537 {
538 if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier))
539 {
540 OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier];
541 RegisteredPreUpdatePropertyActions.Remove(identifier);
542 removed = true;
543 }
544 }
545 DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed);
546 return removed;
547 }
548 public void UnRegisterAllPreUpdatePropertyActions()
549 {
550 lock (RegisteredPreUpdatePropertyActions)
551 {
552 foreach (KeyValuePair<string, PreUpdatePropertyAction> kvp in RegisteredPreUpdatePropertyActions)
553 {
554 OnPreUpdateProperty -= kvp.Value;
555 }
556 RegisteredPreUpdatePropertyActions.Clear();
557 }
558 DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID);
559 }
560
561 #endregion // Per Simulation Step actions
562
256 // High performance detailed logging routine used by the physical objects. 563 // High performance detailed logging routine used by the physical objects.
257 protected void DetailLog(string msg, params Object[] args) 564 protected void DetailLog(string msg, params Object[] args)
258 { 565 {
259 if (PhysicsScene.PhysicsLogging.Enabled) 566 if (PhysicsScene.PhysicsLogging.Enabled)
260 PhysicsScene.DetailLog(msg, args); 567 PhysicsScene.DetailLog(msg, args);
261 } 568 }
569
262} 570}
263} 571}