aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to 'OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs')
-rwxr-xr-xOpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs620
1 files changed, 620 insertions, 0 deletions
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs
new file mode 100755
index 0000000..da3fc18
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPhysObject.cs
@@ -0,0 +1,620 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OMV = OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.PhysicsModules.SharedBase;
34
35namespace OpenSim.Region.PhysicsModule.BulletS
36{
37/*
38 * Class to wrap all objects.
39 * The rest of BulletSim doesn't need to keep checking for avatars or prims
40 * unless the difference is significant.
41 *
42 * Variables in the physicsl objects are in three forms:
43 * VariableName: used by the simulator and performs taint operations, etc
44 * RawVariableName: direct reference to the BulletSim storage for the variable value
45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
46 * The last one should only be referenced in taint-time.
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}
68public abstract class BSPhysObject : PhysicsActor
69{
70 protected BSPhysObject()
71 {
72 }
73 protected BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
74 {
75 IsInitialized = false;
76
77 PhysScene = parentScene;
78 LocalID = localID;
79 PhysObjectName = name;
80 Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
81 TypeName = typeName;
82
83 // Oddity if object is destroyed and recreated very quickly it could still have the old body.
84 if (!PhysBody.HasPhysicalBody)
85 PhysBody = new BulletBody(localID);
86
87 // Clean out anything that might be in the physical actor list.
88 // Again, a workaround for destroying and recreating an object very quickly.
89 PhysicalActors.Dispose();
90
91 UserSetCenterOfMassDisplacement = null;
92
93 PrimAssetState = PrimAssetCondition.Unknown;
94
95 // Initialize variables kept in base.
96 // Beware that these cause taints to be queued whch can cause race conditions on startup.
97 GravModifier = 1.0f;
98 Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity);
99 HoverActive = false;
100
101 // Default material type. Also sets Friction, Restitution and Density.
102 SetMaterial((int)MaterialAttributes.Material.Wood);
103
104 CollisionsLastTickStep = -1;
105
106 SubscribedEventsMs = 0;
107 // Crazy values that will never be true
108 CollidingStep = BSScene.NotASimulationStep;
109 CollidingGroundStep = BSScene.NotASimulationStep;
110 CollisionAccumulation = BSScene.NotASimulationStep;
111 ColliderIsMoving = false;
112 CollisionScore = 0;
113
114 // All axis free.
115 LockedLinearAxis = LockedAxisFree;
116 LockedAngularAxis = LockedAxisFree;
117 }
118
119 // Tell the object to clean up.
120 public virtual void Destroy()
121 {
122 PhysicalActors.Enable(false);
123 PhysScene.TaintedObject(LocalID, "BSPhysObject.Destroy", delegate()
124 {
125 PhysicalActors.Dispose();
126 });
127 }
128
129 public BSScene PhysScene { get; protected set; }
130 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
131 public string PhysObjectName { get; protected set; }
132 public string TypeName { get; protected set; }
133
134 // Set to 'true' when the object is completely initialized.
135 // This mostly prevents property updates and collisions until the object is completely here.
136 public bool IsInitialized { get; protected set; }
137
138 // Set to 'true' if an object (mesh/linkset/sculpty) is not completely constructed.
139 // This test is used to prevent some updates to the object when it only partially exists.
140 // There are several reasons and object might be incomplete:
141 // Its underlying mesh/sculpty is an asset which must be fetched from the asset store
142 // It is a linkset who is being added to or removed from
143 // It is changing state (static to physical, for instance) which requires rebuilding
144 // This is a computed value based on the underlying physical object construction
145 abstract public bool IsIncomplete { get; }
146
147 // Return the object mass without calculating it or having side effects
148 public abstract float RawMass { get; }
149 // Set the raw mass but also update physical mass properties (inertia, ...)
150 // 'inWorld' true if the object has already been added to the dynamic world.
151 public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
152
153 // The gravity being applied to the object. A function of default grav, GravityModifier and Buoyancy.
154 public virtual OMV.Vector3 Gravity { get; set; }
155 // The last value calculated for the prim's inertia
156 public OMV.Vector3 Inertia { get; set; }
157
158 // Reference to the physical body (btCollisionObject) of this object
159 public BulletBody PhysBody = new BulletBody(0);
160 // Reference to the physical shape (btCollisionShape) of this object
161 public BSShape PhysShape = new BSShapeNull();
162
163 // The physical representation of the prim might require an asset fetch.
164 // The asset state is first 'Unknown' then 'Waiting' then either 'Failed' or 'Fetched'.
165 public enum PrimAssetCondition
166 {
167 Unknown, Waiting, FailedAssetFetch, FailedMeshing, Fetched
168 }
169 public PrimAssetCondition PrimAssetState { get; set; }
170 public virtual bool AssetFailed()
171 {
172 return ( (this.PrimAssetState == PrimAssetCondition.FailedAssetFetch)
173 || (this.PrimAssetState == PrimAssetCondition.FailedMeshing) );
174 }
175
176 // The objects base shape information. Null if not a prim type shape.
177 public PrimitiveBaseShape BaseShape { get; protected set; }
178
179 // When the physical properties are updated, an EntityProperty holds the update values.
180 // Keep the current and last EntityProperties to enable computation of differences
181 // between the current update and the previous values.
182 public EntityProperties CurrentEntityProperties { get; set; }
183 public EntityProperties LastEntityProperties { get; set; }
184
185 public virtual OMV.Vector3 Scale { get; set; }
186
187 // It can be confusing for an actor to know if it should move or update an object
188 // depeneding on the setting of 'selected', 'physical, ...
189 // This flag is the true test -- if true, the object is being acted on in the physical world
190 public abstract bool IsPhysicallyActive { get; }
191
192 // Detailed state of the object.
193 public abstract bool IsSolid { get; }
194 public abstract bool IsStatic { get; }
195 public abstract bool IsSelected { get; }
196 public abstract bool IsVolumeDetect { get; }
197
198 // Materialness
199 public MaterialAttributes.Material Material { get; private set; }
200 public override void SetMaterial(int material)
201 {
202 Material = (MaterialAttributes.Material)material;
203
204 // Setting the material sets the material attributes also.
205 // TODO: decide if this is necessary -- the simulator does this.
206 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
207 Friction = matAttrib.friction;
208 Restitution = matAttrib.restitution;
209 Density = matAttrib.density;
210 // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
211 }
212
213 public override float Density
214 {
215 get
216 {
217 return base.Density;
218 }
219 set
220 {
221 DetailLog("{0},BSPhysObject.Density,set,den={1}", LocalID, value);
222 base.Density = value;
223 }
224 }
225
226 // Stop all physical motion.
227 public abstract void ZeroMotion(bool inTaintTime);
228 public abstract void ZeroAngularMotion(bool inTaintTime);
229
230 // Update the physical location and motion of the object. Called with data from Bullet.
231 public abstract void UpdateProperties(EntityProperties entprop);
232
233 public virtual OMV.Vector3 RawPosition { get; set; }
234 public abstract OMV.Vector3 ForcePosition { get; set; }
235
236 public virtual OMV.Quaternion RawOrientation { get; set; }
237 public abstract OMV.Quaternion ForceOrientation { get; set; }
238
239 public virtual OMV.Vector3 RawVelocity { get; set; }
240 public abstract OMV.Vector3 ForceVelocity { get; set; }
241
242 public OMV.Vector3 RawForce { get; set; }
243 public OMV.Vector3 RawTorque { get; set; }
244 public override void AddAngularForce(OMV.Vector3 force, bool pushforce)
245 {
246 AddAngularForce(force, pushforce, false);
247 }
248 public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
249 public abstract void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
250
251 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
252
253 public abstract float ForceBuoyancy { get; set; }
254
255 public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
256
257 public override bool PIDActive
258 {
259 get { return MoveToTargetActive; }
260 set { MoveToTargetActive = value; }
261 }
262
263 public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } }
264 public override float PIDTau { set { MoveToTargetTau = value; } }
265
266 public bool MoveToTargetActive { get; set; }
267 public OMV.Vector3 MoveToTargetTarget { get; set; }
268 public float MoveToTargetTau { get; set; }
269
270 // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z
271 public override bool PIDHoverActive { set { HoverActive = value; } }
272 public override float PIDHoverHeight { set { HoverHeight = value; } }
273 public override PIDHoverType PIDHoverType { set { HoverType = value; } }
274 public override float PIDHoverTau { set { HoverTau = value; } }
275
276 public bool HoverActive { get; set; }
277 public float HoverHeight { get; set; }
278 public PIDHoverType HoverType { get; set; }
279 public float HoverTau { get; set; }
280
281 // For RotLookAt
282 public override OMV.Quaternion APIDTarget { set { return; } }
283 public override bool APIDActive { set { return; } }
284 public override float APIDStrength { set { return; } }
285 public override float APIDDamping { set { return; } }
286
287 // The current velocity forward
288 public virtual float ForwardSpeed
289 {
290 get
291 {
292 OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
293 return characterOrientedVelocity.X;
294 }
295 }
296 // The forward speed we are trying to achieve (TargetVelocity)
297 public virtual float TargetVelocitySpeed
298 {
299 get
300 {
301 OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
302 return characterOrientedVelocity.X;
303 }
304 }
305
306 // The user can optionally set the center of mass. The user's setting will override any
307 // computed center-of-mass (like in linksets).
308 // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass.
309 public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; }
310
311 public OMV.Vector3 LockedLinearAxis; // zero means locked. one means free.
312 public OMV.Vector3 LockedAngularAxis; // zero means locked. one means free.
313 public const float FreeAxis = 1f;
314 public const float LockedAxis = 0f;
315 public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free
316
317 // If an axis is locked (flagged above) then the limits of that axis are specified here.
318 // Linear axis limits are relative to the object's starting coordinates.
319 // Angular limits are limited to -PI to +PI
320 public OMV.Vector3 LockedLinearAxisLow;
321 public OMV.Vector3 LockedLinearAxisHigh;
322 public OMV.Vector3 LockedAngularAxisLow;
323 public OMV.Vector3 LockedAngularAxisHigh;
324
325 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
326 // they need waking up when parameters are changed.
327 // Called in taint-time!!
328 public void ActivateIfPhysical(bool forceIt)
329 {
330 if (PhysBody.HasPhysicalBody)
331 {
332 if (IsPhysical)
333 {
334 // Physical objects might need activating
335 PhysScene.PE.Activate(PhysBody, forceIt);
336 }
337 else
338 {
339 // Clear the collision cache since we've changed some properties.
340 PhysScene.PE.ClearCollisionProxyCache(PhysScene.World, PhysBody);
341 }
342 }
343 }
344
345 // 'actors' act on the physical object to change or constrain its motion. These can range from
346 // hovering to complex vehicle motion.
347 // May be called at non-taint time as this just adds the actor to the action list and the real
348 // work is done during the simulation step.
349 // Note that, if the actor is already in the list and we are disabling same, the actor is just left
350 // in the list disabled.
351 public delegate BSActor CreateActor();
352 public void EnableActor(bool enableActor, string actorName, CreateActor creator)
353 {
354 lock (PhysicalActors)
355 {
356 BSActor theActor;
357 if (PhysicalActors.TryGetActor(actorName, out theActor))
358 {
359 // The actor already exists so just turn it on or off
360 DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor);
361 theActor.Enabled = enableActor;
362 }
363 else
364 {
365 // The actor does not exist. If it should, create it.
366 if (enableActor)
367 {
368 DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName);
369 theActor = creator();
370 PhysicalActors.Add(actorName, theActor);
371 theActor.Enabled = true;
372 }
373 else
374 {
375 DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName);
376 }
377 }
378 }
379 }
380
381 #region Collisions
382
383 // Requested number of milliseconds between collision events. Zero means disabled.
384 protected int SubscribedEventsMs { get; set; }
385 // Given subscription, the time that a collision may be passed up
386 protected int NextCollisionOkTime { get; set; }
387 // The simulation step that last had a collision
388 protected long CollidingStep { get; set; }
389 // The simulation step that last had a collision with the ground
390 protected long CollidingGroundStep { get; set; }
391 // The simulation step that last collided with an object
392 protected long CollidingObjectStep { get; set; }
393 // The collision flags we think are set in Bullet
394 protected CollisionFlags CurrentCollisionFlags { get; set; }
395 // On a collision, check the collider and remember if the last collider was moving
396 // Used to modify the standing of avatars (avatars on stationary things stand still)
397 public bool ColliderIsMoving;
398 // 'true' if the last collider was a volume detect object
399 public bool ColliderIsVolumeDetect;
400 // Used by BSCharacter to manage standing (and not slipping)
401 public bool IsStationary;
402
403 // Count of collisions for this object
404 protected long CollisionAccumulation { get; set; }
405
406 public override bool IsColliding {
407 get { return (CollidingStep == PhysScene.SimulationStep); }
408 set {
409 if (value)
410 CollidingStep = PhysScene.SimulationStep;
411 else
412 CollidingStep = BSScene.NotASimulationStep;
413 }
414 }
415 // Complex objects (like linksets) need to know if there is a collision on any part of
416 // their shape. 'IsColliding' has an existing definition of reporting a collision on
417 // only this specific prim or component of linksets.
418 // 'HasSomeCollision' is defined as reporting if there is a collision on any part of
419 // the complex body that this prim is the root of.
420 public virtual bool HasSomeCollision
421 {
422 get { return IsColliding; }
423 set { IsColliding = value; }
424 }
425 public override bool CollidingGround {
426 get { return (CollidingGroundStep == PhysScene.SimulationStep); }
427 set
428 {
429 if (value)
430 CollidingGroundStep = PhysScene.SimulationStep;
431 else
432 CollidingGroundStep = BSScene.NotASimulationStep;
433 }
434 }
435 public override bool CollidingObj {
436 get { return (CollidingObjectStep == PhysScene.SimulationStep); }
437 set {
438 if (value)
439 CollidingObjectStep = PhysScene.SimulationStep;
440 else
441 CollidingObjectStep = BSScene.NotASimulationStep;
442 }
443 }
444
445 // The collisions that have been collected for the next collision reporting (throttled by subscription)
446 protected CollisionEventUpdate CollisionCollection = new CollisionEventUpdate();
447 // This is the collision collection last reported to the Simulator.
448 public CollisionEventUpdate CollisionsLastReported = new CollisionEventUpdate();
449 // Remember the collisions recorded in the last tick for fancy collision checking
450 // (like a BSCharacter walking up stairs).
451 public CollisionEventUpdate CollisionsLastTick = new CollisionEventUpdate();
452 private long CollisionsLastTickStep = -1;
453
454 // The simulation step is telling this object about a collision.
455 // Return 'true' if a collision was processed and should be sent up.
456 // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
457 // Called at taint time from within the Step() function
458 public delegate bool CollideCall(uint collidingWith, BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth);
459 public virtual bool Collide(uint collidingWith, BSPhysObject collidee,
460 OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
461 {
462 bool ret = false;
463
464 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
465 CollidingStep = PhysScene.SimulationStep;
466 if (collidingWith <= PhysScene.TerrainManager.HighestTerrainID)
467 {
468 CollidingGroundStep = PhysScene.SimulationStep;
469 }
470 else
471 {
472 CollidingObjectStep = PhysScene.SimulationStep;
473 }
474
475 CollisionAccumulation++;
476
477 // For movement tests, remember if we are colliding with an object that is moving.
478 ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero) : false;
479 ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false;
480
481 // Make a collection of the collisions that happened the last simulation tick.
482 // This is different than the collection created for sending up to the simulator as it is cleared every tick.
483 if (CollisionsLastTickStep != PhysScene.SimulationStep)
484 {
485 CollisionsLastTick = new CollisionEventUpdate();
486 CollisionsLastTickStep = PhysScene.SimulationStep;
487 }
488 CollisionsLastTick.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
489
490 // If someone has subscribed for collision events log the collision so it will be reported up
491 if (SubscribedEvents()) {
492 lock (PhysScene.CollisionLock)
493 {
494 CollisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
495 }
496 DetailLog("{0},{1}.Collision.AddCollider,call,with={2},point={3},normal={4},depth={5},colliderMoving={6}",
497 LocalID, TypeName, collidingWith, contactPoint, contactNormal, pentrationDepth, ColliderIsMoving);
498
499 ret = true;
500 }
501 return ret;
502 }
503
504 // Send the collected collisions into the simulator.
505 // Called at taint time from within the Step() function thus no locking problems
506 // with CollisionCollection and ObjectsWithNoMoreCollisions.
507 // Called with BSScene.CollisionLock locked to protect the collision lists.
508 // Return 'true' if there were some actual collisions passed up
509 public virtual bool SendCollisions()
510 {
511 bool ret = true;
512
513 // If no collisions this call but there were collisions last call, force the collision
514 // event to be happen right now so quick collision_end.
515 bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0);
516
517 // throttle the collisions to the number of milliseconds specified in the subscription
518 if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime))
519 {
520 NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs;
521
522 // We are called if we previously had collisions. If there are no collisions
523 // this time, send up one last empty event so OpenSim can sense collision end.
524 if (CollisionCollection.Count == 0)
525 {
526 // If I have no collisions this time, remove me from the list of objects with collisions.
527 ret = false;
528 }
529
530 DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
531 base.SendCollisionUpdate(CollisionCollection);
532
533 // Remember the collisions from this tick for some collision specific processing.
534 CollisionsLastReported = CollisionCollection;
535
536 // The CollisionCollection instance is passed around in the simulator.
537 // Make sure we don't have a handle to that one and that a new one is used for next time.
538 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
539 // a race condition is created for the other users of this instance.
540 CollisionCollection = new CollisionEventUpdate();
541 }
542 return ret;
543 }
544
545 // Subscribe for collision events.
546 // Parameter is the millisecond rate the caller wishes collision events to occur.
547 public override void SubscribeEvents(int ms) {
548 // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
549 SubscribedEventsMs = ms;
550 if (ms > 0)
551 {
552 // make sure first collision happens
553 NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
554
555 PhysScene.TaintedObject(LocalID, TypeName+".SubscribeEvents", delegate()
556 {
557 if (PhysBody.HasPhysicalBody)
558 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
559 });
560 }
561 else
562 {
563 // Subscribing for zero or less is the same as unsubscribing
564 UnSubscribeEvents();
565 }
566 }
567 public override void UnSubscribeEvents() {
568 // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
569 SubscribedEventsMs = 0;
570 PhysScene.TaintedObject(LocalID, TypeName+".UnSubscribeEvents", delegate()
571 {
572 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
573 if (PhysBody.HasPhysicalBody)
574 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
575 });
576 }
577 // Return 'true' if the simulator wants collision events
578 public override bool SubscribedEvents() {
579 return (SubscribedEventsMs > 0);
580 }
581 // Because 'CollisionScore' is called many times while sorting, it should not be recomputed
582 // each time called. So this is built to be light weight for each collision and to do
583 // all the processing when the user asks for the info.
584 public void ComputeCollisionScore()
585 {
586 // Scale the collision count by the time since the last collision.
587 // The "+1" prevents dividing by zero.
588 long timeAgo = PhysScene.SimulationStep - CollidingStep + 1;
589 CollisionScore = CollisionAccumulation / timeAgo;
590 }
591 public override float CollisionScore { get; set; }
592
593 #endregion // Collisions
594
595 #region Per Simulation Step actions
596
597 public BSActorCollection PhysicalActors = new BSActorCollection();
598
599 // When an update to the physical properties happens, this event is fired to let
600 // different actors to modify the update before it is passed around
601 public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
602 public event PreUpdatePropertyAction OnPreUpdateProperty;
603 protected void TriggerPreUpdatePropertyAction(ref EntityProperties entprop)
604 {
605 PreUpdatePropertyAction actions = OnPreUpdateProperty;
606 if (actions != null)
607 actions(ref entprop);
608 }
609
610 #endregion // Per Simulation Step actions
611
612 // High performance detailed logging routine used by the physical objects.
613 protected void DetailLog(string msg, params Object[] args)
614 {
615 if (PhysScene.PhysicsLogging.Enabled)
616 PhysScene.DetailLog(msg, args);
617 }
618
619}
620}