diff options
Diffstat (limited to '')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | 366 |
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. | ||
59 | public 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 | } | ||
48 | public abstract class BSPhysObject : PhysicsActor | 68 | public 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 | } |