OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
BSPhysObject.cs
Go to the documentation of this file.
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  */
27 using System;
28 using System.Collections.Generic;
29 using System.Text;
30 
31 using OMV = OpenMetaverse;
32 using OpenSim.Framework;
33 using OpenSim.Region.PhysicsModules.SharedBase;
34 
35 namespace 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.
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,
67 }
68 public 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  {
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  // RawForce is a constant force applied to object (see Force { set; } )
243  public OMV.Vector3 RawForce { get; set; }
244  public OMV.Vector3 RawTorque { get; set; }
245 
246  public override void AddAngularForce(OMV.Vector3 force, bool pushforce)
247  {
248  AddAngularForce(false, force);
249  }
250  public abstract void AddAngularForce(bool inTaintTime, OMV.Vector3 force);
251  public abstract void AddForce(bool inTaintTime, OMV.Vector3 force);
252 
253  public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
254 
255  public abstract float ForceBuoyancy { get; set; }
256 
257  public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
258 
259  public override bool PIDActive
260  {
261  get { return MoveToTargetActive; }
262  set { MoveToTargetActive = value; }
263  }
264 
265  public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } }
266  public override float PIDTau { set { MoveToTargetTau = value; } }
267 
268  public bool MoveToTargetActive { get; set; }
269  public OMV.Vector3 MoveToTargetTarget { get; set; }
270  public float MoveToTargetTau { get; set; }
271 
272  // Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z
273  public override bool PIDHoverActive {get {return HoverActive;} set { HoverActive = value; } }
274  public override float PIDHoverHeight { set { HoverHeight = value; } }
275  public override PIDHoverType PIDHoverType { set { HoverType = value; } }
276  public override float PIDHoverTau { set { HoverTau = value; } }
277 
278  public bool HoverActive { get; set; }
279  public float HoverHeight { get; set; }
280  public PIDHoverType HoverType { get; set; }
281  public float HoverTau { get; set; }
282 
283  // For RotLookAt
284  public override OMV.Quaternion APIDTarget { set { return; } }
285  public override bool APIDActive { set { return; } }
286  public override float APIDStrength { set { return; } }
287  public override float APIDDamping { set { return; } }
288 
289  // The current velocity forward
290  public virtual float ForwardSpeed
291  {
292  get
293  {
294  OMV.Vector3 characterOrientedVelocity = RawVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
295  return characterOrientedVelocity.X;
296  }
297  }
298  // The forward speed we are trying to achieve (TargetVelocity)
299  public virtual float TargetVelocitySpeed
300  {
301  get
302  {
303  OMV.Vector3 characterOrientedVelocity = TargetVelocity * OMV.Quaternion.Inverse(OMV.Quaternion.Normalize(RawOrientation));
304  return characterOrientedVelocity.X;
305  }
306  }
307 
308  // The user can optionally set the center of mass. The user's setting will override any
309  // computed center-of-mass (like in linksets).
310  // Note this is a displacement from the root's coordinates. Zero means use the root prim as center-of-mass.
311  public OMV.Vector3? UserSetCenterOfMassDisplacement { get; set; }
312 
313  public OMV.Vector3 LockedLinearAxis; // zero means locked. one means free.
314  public OMV.Vector3 LockedAngularAxis; // zero means locked. one means free.
315  public const float FreeAxis = 1f;
316  public const float LockedAxis = 0f;
317  public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(FreeAxis, FreeAxis, FreeAxis); // All axis are free
318 
319  // If an axis is locked (flagged above) then the limits of that axis are specified here.
320  // Linear axis limits are relative to the object's starting coordinates.
321  // Angular limits are limited to -PI to +PI
322  public OMV.Vector3 LockedLinearAxisLow;
323  public OMV.Vector3 LockedLinearAxisHigh;
324  public OMV.Vector3 LockedAngularAxisLow;
325  public OMV.Vector3 LockedAngularAxisHigh;
326 
327  // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
328  // they need waking up when parameters are changed.
329  // Called in taint-time!!
330  public void ActivateIfPhysical(bool forceIt)
331  {
332  if (PhysBody.HasPhysicalBody)
333  {
334  if (IsPhysical)
335  {
336  // Physical objects might need activating
337  PhysScene.PE.Activate(PhysBody, forceIt);
338  }
339  else
340  {
341  // Clear the collision cache since we've changed some properties.
342  PhysScene.PE.ClearCollisionProxyCache(PhysScene.World, PhysBody);
343  }
344  }
345  }
346 
347  // 'actors' act on the physical object to change or constrain its motion. These can range from
348  // hovering to complex vehicle motion.
349  // May be called at non-taint time as this just adds the actor to the action list and the real
350  // work is done during the simulation step.
351  // Note that, if the actor is already in the list and we are disabling same, the actor is just left
352  // in the list disabled.
353  public delegate BSActor CreateActor();
354  public void EnableActor(bool enableActor, string actorName, CreateActor creator)
355  {
356  lock (PhysicalActors)
357  {
358  BSActor theActor;
359  if (PhysicalActors.TryGetActor(actorName, out theActor))
360  {
361  // The actor already exists so just turn it on or off
362  DetailLog("{0},BSPhysObject.EnableActor,enablingExistingActor,name={1},enable={2}", LocalID, actorName, enableActor);
363  theActor.Enabled = enableActor;
364  }
365  else
366  {
367  // The actor does not exist. If it should, create it.
368  if (enableActor)
369  {
370  DetailLog("{0},BSPhysObject.EnableActor,creatingActor,name={1}", LocalID, actorName);
371  theActor = creator();
372  PhysicalActors.Add(actorName, theActor);
373  theActor.Enabled = true;
374  }
375  else
376  {
377  DetailLog("{0},BSPhysObject.EnableActor,notCreatingActorSinceNotEnabled,name={1}", LocalID, actorName);
378  }
379  }
380  }
381  }
382 
383  #region Collisions
384 
385  // Requested number of milliseconds between collision events. Zero means disabled.
386  protected int SubscribedEventsMs { get; set; }
387  // Given subscription, the time that a collision may be passed up
388  protected int NextCollisionOkTime { get; set; }
389  // The simulation step that last had a collision
390  protected long CollidingStep { get; set; }
391  // The simulation step that last had a collision with the ground
392  protected long CollidingGroundStep { get; set; }
393  // The simulation step that last collided with an object
394  protected long CollidingObjectStep { get; set; }
395  // The collision flags we think are set in Bullet
396  protected CollisionFlags CurrentCollisionFlags { get; set; }
397  // On a collision, check the collider and remember if the last collider was moving
398  // Used to modify the standing of avatars (avatars on stationary things stand still)
399  public bool ColliderIsMoving;
400  // 'true' if the last collider was a volume detect object
402  // Used by BSCharacter to manage standing (and not slipping)
403  public bool IsStationary;
404 
405  // Count of collisions for this object
406  protected long CollisionAccumulation { get; set; }
407 
408  public override bool IsColliding {
409  get { return (CollidingStep == PhysScene.SimulationStep); }
410  set {
411  if (value)
412  CollidingStep = PhysScene.SimulationStep;
413  else
414  CollidingStep = BSScene.NotASimulationStep;
415  }
416  }
417  // Complex objects (like linksets) need to know if there is a collision on any part of
418  // their shape. 'IsColliding' has an existing definition of reporting a collision on
419  // only this specific prim or component of linksets.
420  // 'HasSomeCollision' is defined as reporting if there is a collision on any part of
421  // the complex body that this prim is the root of.
422  public virtual bool HasSomeCollision
423  {
424  get { return IsColliding; }
425  set { IsColliding = value; }
426  }
427  public override bool CollidingGround {
428  get { return (CollidingGroundStep == PhysScene.SimulationStep); }
429  set
430  {
431  if (value)
432  CollidingGroundStep = PhysScene.SimulationStep;
433  else
434  CollidingGroundStep = BSScene.NotASimulationStep;
435  }
436  }
437  public override bool CollidingObj {
438  get { return (CollidingObjectStep == PhysScene.SimulationStep); }
439  set {
440  if (value)
441  CollidingObjectStep = PhysScene.SimulationStep;
442  else
443  CollidingObjectStep = BSScene.NotASimulationStep;
444  }
445  }
446 
447  // The collisions that have been collected for the next collision reporting (throttled by subscription)
448  protected CollisionEventUpdate CollisionCollection = new CollisionEventUpdate();
449  // This is the collision collection last reported to the Simulator.
450  public CollisionEventUpdate CollisionsLastReported = new CollisionEventUpdate();
451  // Remember the collisions recorded in the last tick for fancy collision checking
452  // (like a BSCharacter walking up stairs).
453  public CollisionEventUpdate CollisionsLastTick = new CollisionEventUpdate();
454  private long CollisionsLastTickStep = -1;
455 
456  // The simulation step is telling this object about a collision.
457  // I'm the 'collider', the thing I'm colliding with is the 'collidee'.
458  // Return 'true' if a collision was processed and should be sent up.
459  // Return 'false' if this object is not enabled/subscribed/appropriate for or has already seen this collision.
460  // Called at taint time from within the Step() function
461  public virtual bool Collide(BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
462  {
463  bool ret = false;
464 
465  // if 'collidee' is null, that means it is terrain
466  uint collideeLocalID = (collidee == null) ? BSScene.TERRAIN_ID : collidee.LocalID;
467  // All terrain goes by the TERRAIN_ID id when passed up as a collision
468  if (collideeLocalID <= PhysScene.TerrainManager.HighestTerrainID) {
469  collideeLocalID = BSScene.TERRAIN_ID;
470  }
471 
472  // The following lines make IsColliding(), CollidingGround() and CollidingObj work
473  CollidingStep = PhysScene.SimulationStep;
474  if (collideeLocalID == BSScene.TERRAIN_ID)
475  {
476  CollidingGroundStep = PhysScene.SimulationStep;
477  }
478  else
479  {
480  CollidingObjectStep = PhysScene.SimulationStep;
481  }
482 
483  CollisionAccumulation++;
484 
485  // For movement tests, if the collider is me, remember if we are colliding with an object that is moving.
486  // Here the 'collider'/'collidee' thing gets messed up. In the larger context, when something is checking
487  // if the thing it is colliding with is moving, for instance, it asks if the its collider is moving.
488  ColliderIsMoving = collidee != null ? (collidee.RawVelocity != OMV.Vector3.Zero || collidee.RotationalVelocity != OMV.Vector3.Zero) : false;
489  ColliderIsVolumeDetect = collidee != null ? (collidee.IsVolumeDetect) : false;
490 
491 
492  // Make a collection of the collisions that happened the last simulation tick.
493  // This is different than the collection created for sending up to the simulator as it is cleared every tick.
494  if (CollisionsLastTickStep != PhysScene.SimulationStep)
495  {
496  CollisionsLastTick = new CollisionEventUpdate();
497  CollisionsLastTickStep = PhysScene.SimulationStep;
498  }
499  CollisionsLastTick.AddCollider(collideeLocalID, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
500 
501  // If someone has subscribed for collision events log the collision so it will be reported up
502  if (SubscribedEvents()) {
503  ContactPoint newContact = new ContactPoint(contactPoint, contactNormal, pentrationDepth);
504 
505  // Collision sound requires a velocity to know it should happen. This is a lot of computation for a little used feature.
506  OMV.Vector3 relvel = OMV.Vector3.Zero;
507  if (IsPhysical)
508  relvel = RawVelocity;
509  if (collidee != null && collidee.IsPhysical)
510  relvel -= collidee.RawVelocity;
511  newContact.RelativeSpeed = OMV.Vector3.Dot(relvel, contactNormal);
512  // DetailLog("{0},{1}.Collision.AddCollider,vel={2},contee.vel={3},relvel={4},relspeed={5}",
513  // LocalID, TypeName, RawVelocity, (collidee == null ? OMV.Vector3.Zero : collidee.RawVelocity), relvel, newContact.RelativeSpeed);
514 
515  lock (PhysScene.CollisionLock)
516  {
517  CollisionCollection.AddCollider(collideeLocalID, newContact);
518  }
519  DetailLog("{0},{1}.Collision.AddCollider,call,with={2},point={3},normal={4},depth={5},speed={6},colliderMoving={7}",
520  LocalID, TypeName, collideeLocalID, contactPoint, contactNormal, pentrationDepth,
521  newContact.RelativeSpeed, ColliderIsMoving);
522 
523  ret = true;
524  }
525  return ret;
526  }
527 
528  // Send the collected collisions into the simulator.
529  // Called at taint time from within the Step() function thus no locking problems
530  // with CollisionCollection and ObjectsWithNoMoreCollisions.
531  // Called with BSScene.CollisionLock locked to protect the collision lists.
532  // Return 'true' if there were some actual collisions passed up
533  public virtual bool SendCollisions()
534  {
535  bool ret = true;
536 
537  // If no collisions this call but there were collisions last call, force the collision
538  // event to be happen right now so quick collision_end.
539  bool force = (CollisionCollection.Count == 0 && CollisionsLastReported.Count != 0);
540 
541  // throttle the collisions to the number of milliseconds specified in the subscription
542  if (force || (PhysScene.SimulationNowTime >= NextCollisionOkTime))
543  {
544  NextCollisionOkTime = PhysScene.SimulationNowTime + SubscribedEventsMs;
545 
546  // We are called if we previously had collisions. If there are no collisions
547  // this time, send up one last empty event so OpenSim can sense collision end.
548  if (CollisionCollection.Count == 0)
549  {
550  // If I have no collisions this time, remove me from the list of objects with collisions.
551  ret = false;
552  }
553 
554  DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
555  base.SendCollisionUpdate(CollisionCollection);
556 
557  // Remember the collisions from this tick for some collision specific processing.
558  CollisionsLastReported = CollisionCollection;
559 
560  // The CollisionCollection instance is passed around in the simulator.
561  // Make sure we don't have a handle to that one and that a new one is used for next time.
562  // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
563  // a race condition is created for the other users of this instance.
564  CollisionCollection = new CollisionEventUpdate();
565  }
566  return ret;
567  }
568 
569  // Subscribe for collision events.
570  // Parameter is the millisecond rate the caller wishes collision events to occur.
571  public override void SubscribeEvents(int ms) {
572  // DetailLog("{0},{1}.SubscribeEvents,subscribing,ms={2}", LocalID, TypeName, ms);
573  SubscribedEventsMs = ms;
574  if (ms > 0)
575  {
576  // make sure first collision happens
577  NextCollisionOkTime = Util.EnvironmentTickCountSubtract(SubscribedEventsMs);
578 
579  PhysScene.TaintedObject(LocalID, TypeName+".SubscribeEvents", delegate()
580  {
581  if (PhysBody.HasPhysicalBody)
582  {
583  CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
584  DetailLog("{0},{1}.SubscribeEvents,setting collision. ms={2}, collisionFlags={3:x}",
585  LocalID, TypeName, ms, CurrentCollisionFlags);
586  }
587  });
588  }
589  else
590  {
591  // Subscribing for zero or less is the same as unsubscribing
592  UnSubscribeEvents();
593  }
594  }
595  public override void UnSubscribeEvents() {
596  // DetailLog("{0},{1}.UnSubscribeEvents,unsubscribing", LocalID, TypeName);
597  SubscribedEventsMs = 0;
598  PhysScene.TaintedObject(LocalID, TypeName+".UnSubscribeEvents", delegate()
599  {
600  // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
601  if (PhysBody.HasPhysicalBody)
602  CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
603  });
604  }
605  // Return 'true' if the simulator wants collision events
606  public override bool SubscribedEvents() {
607  return (SubscribedEventsMs > 0);
608  }
609  // Because 'CollisionScore' is called many times while sorting, it should not be recomputed
610  // each time called. So this is built to be light weight for each collision and to do
611  // all the processing when the user asks for the info.
612  public void ComputeCollisionScore()
613  {
614  // Scale the collision count by the time since the last collision.
615  // The "+1" prevents dividing by zero.
616  long timeAgo = PhysScene.SimulationStep - CollidingStep + 1;
617  CollisionScore = CollisionAccumulation / timeAgo;
618  }
619  public override float CollisionScore { get; set; }
620 
621  #endregion // Collisions
622 
623  #region Per Simulation Step actions
624 
625  public BSActorCollection PhysicalActors = new BSActorCollection();
626 
627  // When an update to the physical properties happens, this event is fired to let
628  // different actors to modify the update before it is passed around
629  public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
630  public event PreUpdatePropertyAction OnPreUpdateProperty;
632  {
633  PreUpdatePropertyAction actions = OnPreUpdateProperty;
634  if (actions != null)
635  actions(ref entprop);
636  }
637 
638  #endregion // Per Simulation Step actions
639 
640  // High performance detailed logging routine used by the physical objects.
641  protected void DetailLog(string msg, params Object[] args)
642  {
643  if (PhysScene.PhysicsLogging.Enabled)
644  PhysScene.DetailLog(msg, args);
645  }
646 
647 }
648 }
OpenMetaverse OMV
void DetailLog(string msg, params Object[] args)
override void AddAngularForce(OMV.Vector3 force, bool pushforce)
Each physical object can have 'actors' who are pushing the object around. This can be used for hover...
Definition: BSActors.cs:118
void TriggerPreUpdatePropertyAction(ref EntityProperties entprop)
Used to pass collision information to OnCollisionUpdate listeners.
void EnableActor(bool enableActor, string actorName, CreateActor creator)
Unthrottled packets
virtual bool ForceBodyShapeRebuild(bool inTaintTime)
virtual bool Collide(BSPhysObject collidee, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
Material
Material type for a primitive
Definition: OdeScene.cs:79
BSPhysObject(BSScene parentScene, uint localID, string name, string typeName)
Definition: BSPhysObject.cs:73