OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
ODECharacter.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 copyright
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 
28 using System;
29 using System.Collections.Generic;
30 using System.Reflection;
31 using OpenMetaverse;
32 using OpenSim.Framework;
33 using OpenSim.Region.PhysicsModules.SharedBase;
34 using log4net;
35 
36 namespace OpenSim.Region.PhysicsModule.ODE
37 {
41  public enum dParam : int
42  {
43  LowStop = 0,
44  HiStop = 1,
45  Vel = 2,
46  FMax = 3,
47  FudgeFactor = 4,
48  Bounce = 5,
49  CFM = 6,
50  StopERP = 7,
51  StopCFM = 8,
52  LoStop2 = 256,
53  HiStop2 = 257,
54  Vel2 = 258,
55  FMax2 = 259,
56  StopERP2 = 7 + 256,
57  StopCFM2 = 8 + 256,
58  LoStop3 = 512,
59  HiStop3 = 513,
60  Vel3 = 514,
61  FMax3 = 515,
62  StopERP3 = 7 + 512,
63  StopCFM3 = 8 + 512
64  }
65 
66  public class OdeCharacter : PhysicsActor
67  {
68  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
69 
70  private Vector3 _position;
71  private d.Vector3 _zeroPosition;
72  private bool _zeroFlag = false;
73  private bool m_lastUpdateSent = false;
74  private Vector3 _velocity;
75  private Vector3 m_taintTargetVelocity;
76  private Vector3 _target_velocity;
77  private Vector3 _acceleration;
78  private Vector3 m_rotationalVelocity;
79  private float m_mass = 80f;
80  private float m_density = 60f;
81  private bool m_pidControllerActive = true;
82  private float PID_D = 800.0f;
83  private float PID_P = 900.0f;
84  //private static float POSTURE_SERVO = 10000.0f;
85  private float CAPSULE_RADIUS = 0.37f;
86  private float CAPSULE_LENGTH = 2.140599f;
87  private float m_tensor = 3800000f;
88 // private float heightFudgeFactor = 0.52f;
89  private float walkDivisor = 1.3f;
90  private float runDivisor = 0.8f;
91  private bool flying = false;
92  private bool m_iscolliding = false;
93  private bool m_iscollidingGround = false;
94  private bool m_wascolliding = false;
95  private bool m_wascollidingGround = false;
96  private bool m_iscollidingObj = false;
97  private bool m_alwaysRun = false;
98  private bool m_hackSentFall = false;
99  private bool m_hackSentFly = false;
100  private int m_requestedUpdateFrequency = 0;
101  private Vector3 m_taintPosition;
102  internal bool m_avatarplanted = false;
107  private Vector3 m_taintForce;
108 
109  // taints and their non-tainted counterparts
110  private bool m_isPhysical = false; // the current physical status
111  private bool m_tainted_isPhysical = false; // set when the physical status is tainted (false=not existing in physics engine, true=existing)
112  internal float MinimumGroundFlightOffset = 3f;
113 
114  private float m_tainted_CAPSULE_LENGTH; // set when the capsule length changes.
115 
119  private float m_tiltBaseMovement = (float)Math.Sqrt(2);
120 
124  private float m_tiltMagnitudeWhenProjectedOnXYPlane = 0.1131371f;
125 
126  private float m_buoyancy = 0f;
127 
128  // private CollisionLocker ode;
129  private bool[] m_colliderarr = new bool[11];
130  private bool[] m_colliderGroundarr = new bool[11];
131 
132  // Default we're a Character
133  private CollisionCategories m_collisionCategories = (CollisionCategories.Character);
134 
135  // Default, Collide with Other Geometries, spaces, bodies and characters.
136  private CollisionCategories m_collisionFlags = (CollisionCategories.Geom
137  | CollisionCategories.Space
138  | CollisionCategories.Body
139  | CollisionCategories.Character
140  | CollisionCategories.Land);
144  internal IntPtr Body { get; private set; }
145 
146  private OdeScene _parent_scene;
147 
151  internal IntPtr Shell { get; private set; }
152 
153  private IntPtr Amotor = IntPtr.Zero;
154  private d.Mass ShellMass;
155 
156  private int m_eventsubscription = 0;
157  private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate();
158 
159  // unique UUID of this character object
160  internal UUID m_uuid { get; private set; }
161  internal bool bad = false;
162 
180  public OdeCharacter(
181  String avName, OdeScene parent_scene, Vector3 pos, Vector3 vel, Vector3 size, float pid_d, float pid_p,
182  float capsule_radius, float tensor, float density,
183  float walk_divisor, float rundivisor)
184  {
185  m_uuid = UUID.Random();
186 
187  if (pos.IsFinite())
188  {
189  if (pos.Z > 9999999f)
190  {
191  pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
192  }
193  if (pos.Z < -90000f)
194  {
195  pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
196  }
197 
198  _position = pos;
199  m_taintPosition = pos;
200  }
201  else
202  {
203  _position
204  = new Vector3(
205  (float)_parent_scene.WorldExtents.X * 0.5f,
206  (float)_parent_scene.WorldExtents.Y * 0.5f,
207  parent_scene.GetTerrainHeightAtXY(128f, 128f) + 10f);
208  m_taintPosition = _position;
209 
210  m_log.WarnFormat("[ODE CHARACTER]: Got NaN Position on Character Create for {0}", avName);
211  }
212 
213  _velocity = vel;
214  m_taintTargetVelocity = vel;
215 
216  _parent_scene = parent_scene;
217 
218  PID_D = pid_d;
219  PID_P = pid_p;
220  CAPSULE_RADIUS = capsule_radius;
221  m_tensor = tensor;
222  m_density = density;
223 // heightFudgeFactor = height_fudge_factor;
224  walkDivisor = walk_divisor;
225  runDivisor = rundivisor;
226 
227  // m_StandUpRotation =
228  // new d.Matrix3(0.5f, 0.7071068f, 0.5f, -0.7071068f, 0f, 0.7071068f, 0.5f, -0.7071068f,
229  // 0.5f);
230 
231  // We can set taint and actual to be the same here, since the entire character will be set up when the
232  // m_tainted_isPhysical is processed.
233  SetTaintedCapsuleLength(size);
234  CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH;
235 
236  m_isPhysical = false; // current status: no ODE information exists
237  m_tainted_isPhysical = true; // new tainted status: need to create ODE information
238 
239  _parent_scene.AddPhysicsActorTaint(this);
240 
241  Name = avName;
242  }
243 
244  public override int PhysicsActorType
245  {
246  get { return (int) ActorTypes.Agent; }
247  set { return; }
248  }
249 
253  public override bool SetAlwaysRun
254  {
255  get { return m_alwaysRun; }
256  set { m_alwaysRun = value; }
257  }
258 
259  public override bool Grabbed
260  {
261  set { return; }
262  }
263 
264  public override bool Selected
265  {
266  set { return; }
267  }
268 
269  public override float Buoyancy
270  {
271  get { return m_buoyancy; }
272  set { m_buoyancy = value; }
273  }
274 
275  public override bool FloatOnWater
276  {
277  set { return; }
278  }
279 
280  public override bool IsPhysical
281  {
282  get { return m_isPhysical; }
283  set { return; }
284  }
285 
286  public override bool ThrottleUpdates
287  {
288  get { return false; }
289  set { return; }
290  }
291 
292  public override bool Flying
293  {
294  get { return flying; }
295  set
296  {
297  flying = value;
298 // m_log.DebugFormat("[ODE CHARACTER]: Set OdeCharacter Flying to {0}", flying);
299  }
300  }
301 
306  public override bool IsColliding
307  {
308  get { return m_iscolliding; }
309  set
310  {
311  int i;
312  int truecount = 0;
313  int falsecount = 0;
314 
315  if (m_colliderarr.Length >= 10)
316  {
317  for (i = 0; i < 10; i++)
318  {
319  m_colliderarr[i] = m_colliderarr[i + 1];
320  }
321  }
322  m_colliderarr[10] = value;
323 
324  for (i = 0; i < 11; i++)
325  {
326  if (m_colliderarr[i])
327  {
328  truecount++;
329  }
330  else
331  {
332  falsecount++;
333  }
334  }
335 
336  // Equal truecounts and false counts means we're colliding with something.
337 
338  if (falsecount > 1.2*truecount)
339  {
340  m_iscolliding = false;
341  }
342  else
343  {
344  m_iscolliding = true;
345  }
346 
347  if (m_wascolliding != m_iscolliding)
348  {
349  //base.SendCollisionUpdate(new CollisionEventUpdate());
350  }
351 
352  m_wascolliding = m_iscolliding;
353  }
354  }
355 
359  public override bool CollidingGround
360  {
361  get { return m_iscollidingGround; }
362  set
363  {
364  // Collisions against the ground are not really reliable
365  // So, to get a consistant value we have to average the current result over time
366  // Currently we use 1 second = 10 calls to this.
367  int i;
368  int truecount = 0;
369  int falsecount = 0;
370 
371  if (m_colliderGroundarr.Length >= 10)
372  {
373  for (i = 0; i < 10; i++)
374  {
375  m_colliderGroundarr[i] = m_colliderGroundarr[i + 1];
376  }
377  }
378  m_colliderGroundarr[10] = value;
379 
380  for (i = 0; i < 11; i++)
381  {
382  if (m_colliderGroundarr[i])
383  {
384  truecount++;
385  }
386  else
387  {
388  falsecount++;
389  }
390  }
391 
392  // Equal truecounts and false counts means we're colliding with something.
393 
394  if (falsecount > 1.2*truecount)
395  {
396  m_iscollidingGround = false;
397  }
398  else
399  {
400  m_iscollidingGround = true;
401  }
402  if (m_wascollidingGround != m_iscollidingGround)
403  {
404  //base.SendCollisionUpdate(new CollisionEventUpdate());
405  }
406  m_wascollidingGround = m_iscollidingGround;
407  }
408  }
409 
413  public override bool CollidingObj
414  {
415  get { return m_iscollidingObj; }
416  set
417  {
418  m_iscollidingObj = value;
419  if (value && !m_avatarplanted)
420  m_pidControllerActive = false;
421  else
422  m_pidControllerActive = true;
423  }
424  }
425 
431  public void SetPidStatus(bool status)
432  {
433  m_pidControllerActive = status;
434  }
435 
436  public override bool Stopped
437  {
438  get { return _zeroFlag; }
439  }
440 
446  public override Vector3 Position
447  {
448  get { return _position; }
449  set
450  {
451  if (Body == IntPtr.Zero || Shell == IntPtr.Zero)
452  {
453  if (value.IsFinite())
454  {
455  if (value.Z > 9999999f)
456  {
457  value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
458  }
459  if (value.Z < -90000f)
460  {
461  value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
462  }
463 
464  m_taintPosition = value;
465  _parent_scene.AddPhysicsActorTaint(this);
466  }
467  else
468  {
469  m_log.WarnFormat("[ODE CHARACTER]: Got a NaN Position from Scene on character {0}", Name);
470  }
471  }
472  }
473  }
474 
475  public override Vector3 RotationalVelocity
476  {
477  get { return m_rotationalVelocity; }
478  set { m_rotationalVelocity = value; }
479  }
480 
485  public override Vector3 Size
486  {
487  get { return new Vector3(CAPSULE_RADIUS * 2, CAPSULE_RADIUS * 2, CAPSULE_LENGTH); }
488  set
489  {
490  SetTaintedCapsuleLength(value);
491 
492  // If we reset velocity here, then an avatar stalls when it crosses a border for the first time
493  // (as the height of the new root agent is set).
494 // Velocity = Vector3.Zero;
495 
496  _parent_scene.AddPhysicsActorTaint(this);
497  }
498  }
499 
500  private void SetTaintedCapsuleLength(Vector3 size)
501  {
502  if (size.IsFinite())
503  {
504  m_pidControllerActive = true;
505 
506  m_tainted_CAPSULE_LENGTH = size.Z - CAPSULE_RADIUS * 2.0f;
507 
508  // m_log.InfoFormat("[ODE CHARACTER]: Size = {0}, Capsule Length = {1} (Capsule Radius = {2})",
509  // size, m_tainted_CAPSULE_LENGTH, CAPSULE_RADIUS);
510  }
511  else
512  {
513  m_log.WarnFormat("[ODE CHARACTER]: Got a NaN Size for {0} in {1}", Name, _parent_scene.PhysicsSceneName);
514  }
515  }
516 
517  private void AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3 movementVector)
518  {
519  movementVector.Z = 0f;
520  float magnitude = (float)Math.Sqrt((double)(movementVector.X * movementVector.X + movementVector.Y * movementVector.Y));
521  if (magnitude < 0.1f) return;
522 
523  // normalize the velocity vector
524  float invMagnitude = 1.0f / magnitude;
525  movementVector.X *= invMagnitude;
526  movementVector.Y *= invMagnitude;
527 
528  // if we change the capsule heading too often, the capsule can fall down
529  // therefore we snap movement vector to just 1 of 4 predefined directions (ne, nw, se, sw),
530  // meaning only 4 possible capsule tilt orientations
531  if (movementVector.X > 0)
532  {
533  // east
534  if (movementVector.Y > 0)
535  {
536  // northeast
537  movementVector.X = m_tiltBaseMovement;
538  movementVector.Y = m_tiltBaseMovement;
539  }
540  else
541  {
542  // southeast
543  movementVector.X = m_tiltBaseMovement;
544  movementVector.Y = -m_tiltBaseMovement;
545  }
546  }
547  else
548  {
549  // west
550  if (movementVector.Y > 0)
551  {
552  // northwest
553  movementVector.X = -m_tiltBaseMovement;
554  movementVector.Y = m_tiltBaseMovement;
555  }
556  else
557  {
558  // southwest
559  movementVector.X = -m_tiltBaseMovement;
560  movementVector.Y = -m_tiltBaseMovement;
561  }
562  }
563 
564  // movementVector.Z is zero
565 
566  // calculate tilt components based on desired amount of tilt and current (snapped) heading.
567  // the "-" sign is to force the tilt to be OPPOSITE the direction of movement.
568  float xTiltComponent = -movementVector.X * m_tiltMagnitudeWhenProjectedOnXYPlane;
569  float yTiltComponent = -movementVector.Y * m_tiltMagnitudeWhenProjectedOnXYPlane;
570 
571  //m_log.Debug("[ODE CHARACTER]: changing avatar tilt");
572  d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, xTiltComponent);
573  d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, xTiltComponent); // must be same as lowstop, else a different, spurious tilt is introduced
574  d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, yTiltComponent);
575  d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, yTiltComponent); // same as lowstop
576  d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, 0f);
577  d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop
578  }
579 
584  public override float Mass
585  {
586  get
587  {
588  float AVvolume = (float)(Math.PI * Math.Pow(CAPSULE_RADIUS, 2) * CAPSULE_LENGTH);
589  return m_density * AVvolume;
590  }
591  }
592 
593  public override void link(PhysicsActor obj) {}
594 
595  public override void delink() {}
596 
597  public override void LockAngularMotion(byte axislocks) {}
598 
599 // This code is very useful. Written by DanX0r. We're just not using it right now.
600 // Commented out to prevent a warning.
601 //
602 // private void standupStraight()
603 // {
604 // // The purpose of this routine here is to quickly stabilize the Body while it's popped up in the air.
605 // // The amotor needs a few seconds to stabilize so without it, the avatar shoots up sky high when you
606 // // change appearance and when you enter the simulator
607 // // After this routine is done, the amotor stabilizes much quicker
608 // d.Vector3 feet;
609 // d.Vector3 head;
610 // d.BodyGetRelPointPos(Body, 0.0f, 0.0f, -1.0f, out feet);
611 // d.BodyGetRelPointPos(Body, 0.0f, 0.0f, 1.0f, out head);
612 // float posture = head.Z - feet.Z;
613 
614 // // restoring force proportional to lack of posture:
615 // float servo = (2.5f - posture) * POSTURE_SERVO;
616 // d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, servo, 0.0f, 0.0f, 1.0f);
617 // d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, -servo, 0.0f, 0.0f, -1.0f);
618 // //d.Matrix3 bodyrotation = d.BodyGetRotation(Body);
619 // //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyFArotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22);
620 // }
621 
622  public override Vector3 Force
623  {
624  get { return _target_velocity; }
625  set { return; }
626  }
627 
628  public override int VehicleType
629  {
630  get { return 0; }
631  set { return; }
632  }
633 
634  public override void VehicleFloatParam(int param, float value)
635  {
636  }
637 
638  public override void VehicleVectorParam(int param, Vector3 value)
639  {
640  }
641 
642  public override void VehicleRotationParam(int param, Quaternion rotation)
643  {
644  }
645 
646  public override void VehicleFlags(int param, bool remove)
647  {
648  }
649 
650  public override void SetVolumeDetect(int param)
651  {
652  }
653 
654  public override Vector3 CenterOfMass
655  {
656  get { return Vector3.Zero; }
657  }
658 
659  public override Vector3 GeometricCenter
660  {
661  get { return Vector3.Zero; }
662  }
663 
664  public override PrimitiveBaseShape Shape
665  {
666  set { return; }
667  }
668 
669  public override Vector3 TargetVelocity
670  {
671  get
672  {
673  return m_taintTargetVelocity;
674  }
675 
676  set
677  {
678  Velocity = value;
679  }
680  }
681 
682 
683  public override Vector3 Velocity
684  {
685  get
686  {
687  // There's a problem with Vector3.Zero! Don't Use it Here!
688  if (_zeroFlag)
689  return Vector3.Zero;
690  m_lastUpdateSent = false;
691  return _velocity;
692  }
693 
694  set
695  {
696  if (value.IsFinite())
697  {
698  m_pidControllerActive = true;
699  m_taintTargetVelocity = value;
700  _parent_scene.AddPhysicsActorTaint(this);
701  }
702  else
703  {
704  m_log.WarnFormat("[ODE CHARACTER]: Got a NaN velocity from Scene for {0}", Name);
705  }
706 
707 // m_log.DebugFormat("[PHYSICS]: Set target velocity of {0}", m_taintTargetVelocity);
708  }
709  }
710 
711  public override Vector3 Torque
712  {
713  get { return Vector3.Zero; }
714  set { return; }
715  }
716 
717  public override float CollisionScore
718  {
719  get { return 0f; }
720  set { }
721  }
722 
723  public override bool Kinematic
724  {
725  get { return false; }
726  set { }
727  }
728 
729  public override Quaternion Orientation
730  {
731  get { return Quaternion.Identity; }
732  set {
733  //Matrix3 or = Orientation.ToRotationMatrix();
734  //d.Matrix3 ord = new d.Matrix3(or.m00, or.m10, or.m20, or.m01, or.m11, or.m21, or.m02, or.m12, or.m22);
735  //d.BodySetRotation(Body, ref ord);
736  }
737  }
738 
739  public override Vector3 Acceleration
740  {
741  get { return _acceleration; }
742  set { _acceleration = value; }
743  }
744 
750  public override void AddForce(Vector3 force, bool pushforce)
751  {
752  if (force.IsFinite())
753  {
754  if (pushforce)
755  {
756  m_pidControllerActive = false;
757  force *= 100f;
758  m_taintForce += force;
759  _parent_scene.AddPhysicsActorTaint(this);
760 
761  // If uncommented, things get pushed off world
762  //
763  // m_log.Debug("Push!");
764  // m_taintTargetVelocity.X += force.X;
765  // m_taintTargetVelocity.Y += force.Y;
766  // m_taintTargetVelocity.Z += force.Z;
767  }
768  else
769  {
770  m_pidControllerActive = true;
771  m_taintTargetVelocity += force;
772  }
773  }
774  else
775  {
776  m_log.WarnFormat("[ODE CHARACTER]: Got a NaN force applied to {0}", Name);
777  }
778  //m_lastUpdateSent = false;
779  }
780 
781  public override void AddAngularForce(Vector3 force, bool pushforce)
782  {
783  }
784 
785  public override void SetMomentum(Vector3 momentum)
786  {
787  }
788 
796  internal void Move(List<OdeCharacter> defects)
797  {
798  // no lock; for now it's only called from within Simulate()
799 
800  // If the PID Controller isn't active then we set our force
801  // calculating base velocity to the current position
802 
803  if (Body == IntPtr.Zero)
804  return;
805 
806  if (m_pidControllerActive == false)
807  {
808  _zeroPosition = d.BodyGetPosition(Body);
809  }
810  //PidStatus = true;
811 
812  d.Vector3 localpos = d.BodyGetPosition(Body);
813  Vector3 localPos = new Vector3(localpos.X, localpos.Y, localpos.Z);
814 
815  if (!localPos.IsFinite())
816  {
817  m_log.WarnFormat(
818  "[ODE CHARACTER]: Avatar position of {0} for {1} is non-finite! Removing from physics scene.",
819  localPos, Name);
820 
821  defects.Add(this);
822 
823  return;
824  }
825 
826  Vector3 vec = Vector3.Zero;
827  d.Vector3 vel = d.BodyGetLinearVel(Body);
828 
829 // m_log.DebugFormat(
830 // "[ODE CHARACTER]: Current velocity in Move() is <{0},{1},{2}>, target {3} for {4}",
831 // vel.X, vel.Y, vel.Z, _target_velocity, Name);
832 
833  float movementdivisor = 1f;
834 
835  if (!m_alwaysRun)
836  {
837  movementdivisor = walkDivisor;
838  }
839  else
840  {
841  movementdivisor = runDivisor;
842  }
843 
844  // if velocity is zero, use position control; otherwise, velocity control
845  if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f && m_iscolliding)
846  {
847  // keep track of where we stopped. No more slippin' & slidin'
848  if (!_zeroFlag)
849  {
850  _zeroFlag = true;
851  _zeroPosition = d.BodyGetPosition(Body);
852  }
853 
854  if (m_pidControllerActive)
855  {
856  // We only want to deactivate the PID Controller if we think we want to have our surrogate
857  // react to the physics scene by moving it's position.
858  // Avatar to Avatar collisions
859  // Prim to avatar collisions
860 
861  d.Vector3 pos = d.BodyGetPosition(Body);
862  vec.X = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2);
863  vec.Y = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y)* (PID_P * 2);
864  if (flying)
865  {
866  vec.Z = (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P;
867  }
868  }
869  //PidStatus = true;
870  }
871  else
872  {
873  m_pidControllerActive = true;
874  _zeroFlag = false;
875  if (m_iscolliding && !flying)
876  {
877  // We're standing on something
878  vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D);
879  vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D);
880  }
881  else if (m_iscolliding && flying)
882  {
883  // We're flying and colliding with something
884  vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 16);
885  vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 16);
886  }
887  else if (!m_iscolliding && flying)
888  {
889  // we're in mid air suspended
890  vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 6);
891  vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 6);
892 
893 // m_log.DebugFormat(
894 // "[ODE CHARACTER]: !m_iscolliding && flying, vec {0}, _target_velocity {1}, movementdivisor {2}, vel {3}",
895 // vec, _target_velocity, movementdivisor, vel);
896  }
897 
898  if (flying)
899  {
900  // This also acts as anti-gravity so that we hover when flying rather than fall.
901  vec.Z = (_target_velocity.Z - vel.Z) * (PID_D);
902  }
903  else
904  {
905  if (m_iscolliding && _target_velocity.Z > 0.0f)
906  {
907  // We're colliding with something and we're not flying but we're moving
908  // This means we're walking or running.
909  d.Vector3 pos = d.BodyGetPosition(Body);
910  vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P;
911  vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D;
912  vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D;
913  }
914  else if (!m_iscolliding)
915  {
916  // we're not colliding and we're not flying so that means we're falling!
917  // m_iscolliding includes collisions with the ground.
918  vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D;
919  vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D;
920  }
921  }
922  }
923 
924  if (flying)
925  {
926  // Anti-gravity so that we hover when flying rather than fall.
927  vec.Z += ((-1 * _parent_scene.gravityz) * m_mass);
928 
929  //Added for auto fly height. Kitto Flora
930  //d.Vector3 pos = d.BodyGetPosition(Body);
931  float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset;
932 
933  if (_position.Z < target_altitude)
934  {
935  vec.Z += (target_altitude - _position.Z) * PID_P * 5.0f;
936  }
937  // end add Kitto Flora
938  }
939 
940  if (vec.IsFinite())
941  {
942  // Apply the total force acting on this avatar
943  d.BodyAddForce(Body, vec.X, vec.Y, vec.Z);
944 
945  if (!_zeroFlag)
946  AlignAvatarTiltWithCurrentDirectionOfMovement(vec);
947  }
948  else
949  {
950  m_log.WarnFormat(
951  "[ODE CHARACTER]: Got a NaN force vector {0} in Move() for {1}. Removing character from physics scene.",
952  vec, Name);
953 
954  defects.Add(this);
955 
956  return;
957  }
958 
959  d.Vector3 newVel = d.BodyGetLinearVel(Body);
960  if (newVel.X >= 256 || newVel.X <= 256 || newVel.Y >= 256 || newVel.Y <= 256 || newVel.Z >= 256 || newVel.Z <= 256)
961  {
962 // m_log.DebugFormat(
963 // "[ODE CHARACTER]: Limiting falling velocity from {0} to {1} for {2}", newVel.Z, -9.8, Name);
964 
965  newVel.X = Util.Clamp<float>(newVel.X, -255f, 255f);
966  newVel.Y = Util.Clamp<float>(newVel.Y, -255f, 255f);
967 
968  if (!flying)
969  newVel.Z
970  = Util.Clamp<float>(
971  newVel.Z, -_parent_scene.AvatarTerminalVelocity, _parent_scene.AvatarTerminalVelocity);
972  else
973  newVel.Z = Util.Clamp<float>(newVel.Z, -255f, 255f);
974 
975  d.BodySetLinearVel(Body, newVel.X, newVel.Y, newVel.Z);
976  }
977  }
978 
985  internal void UpdatePositionAndVelocity(List<OdeCharacter> defects)
986  {
987  // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
988  d.Vector3 newPos;
989  try
990  {
991  newPos = d.BodyGetPosition(Body);
992  }
993  catch (NullReferenceException)
994  {
995  bad = true;
996  defects.Add(this);
997  newPos = new d.Vector3(_position.X, _position.Y, _position.Z);
998  base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem!
999  m_log.WarnFormat("[ODE CHARACTER]: Avatar Null reference for Avatar {0}, physical actor {1}", Name, m_uuid);
1000 
1001  return;
1002  }
1003 
1004  // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!)
1005  if (newPos.X < 0.0f) newPos.X = 0.0f;
1006  if (newPos.Y < 0.0f) newPos.Y = 0.0f;
1007  if (newPos.X > (int)_parent_scene.WorldExtents.X - 0.05f) newPos.X = (int)_parent_scene.WorldExtents.X - 0.05f;
1008  if (newPos.Y > (int)_parent_scene.WorldExtents.Y - 0.05f) newPos.Y = (int)_parent_scene.WorldExtents.Y - 0.05f;
1009 
1010  _position.X = newPos.X;
1011  _position.Y = newPos.Y;
1012  _position.Z = newPos.Z;
1013 
1014  // I think we need to update the taintPosition too -- Diva 12/24/10
1015  m_taintPosition = _position;
1016 
1017  // Did we move last? = zeroflag
1018  // This helps keep us from sliding all over
1019 
1020  if (_zeroFlag)
1021  {
1022  _velocity = Vector3.Zero;
1023 
1024  // Did we send out the 'stopped' message?
1025  if (!m_lastUpdateSent)
1026  {
1027  m_lastUpdateSent = true;
1028  //base.RequestPhysicsterseUpdate();
1029  }
1030  }
1031  else
1032  {
1033  m_lastUpdateSent = false;
1034  d.Vector3 newVelocity;
1035 
1036  try
1037  {
1038  newVelocity = d.BodyGetLinearVel(Body);
1039  }
1040  catch (NullReferenceException)
1041  {
1042  newVelocity.X = _velocity.X;
1043  newVelocity.Y = _velocity.Y;
1044  newVelocity.Z = _velocity.Z;
1045  }
1046 
1047  _velocity.X = newVelocity.X;
1048  _velocity.Y = newVelocity.Y;
1049  _velocity.Z = newVelocity.Z;
1050 
1051  if (_velocity.Z < -6 && !m_hackSentFall)
1052  {
1053  m_hackSentFall = true;
1054  m_pidControllerActive = false;
1055  }
1056  else if (flying && !m_hackSentFly)
1057  {
1058  //m_hackSentFly = true;
1059  //base.SendCollisionUpdate(new CollisionEventUpdate());
1060  }
1061  else
1062  {
1063  m_hackSentFly = false;
1064  m_hackSentFall = false;
1065  }
1066  }
1067  }
1068 
1081  private void CreateOdeStructures(float npositionX, float npositionY, float npositionZ, float tensor)
1082  {
1083  if (!(Shell == IntPtr.Zero && Body == IntPtr.Zero && Amotor == IntPtr.Zero))
1084  {
1085  m_log.ErrorFormat(
1086  "[ODE CHARACTER]: Creating ODE structures for {0} even though some already exist. Shell = {1}, Body = {2}, Amotor = {3}",
1087  Name, Shell, Body, Amotor);
1088  }
1089 
1090  int dAMotorEuler = 1;
1091 // _parent_scene.waitForSpaceUnlock(_parent_scene.space);
1092  if (CAPSULE_LENGTH <= 0)
1093  {
1094  m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!");
1095  CAPSULE_LENGTH = 0.01f;
1096  }
1097 
1098  if (CAPSULE_RADIUS <= 0)
1099  {
1100  m_log.Warn("[ODE CHARACTER]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!");
1101  CAPSULE_RADIUS = 0.01f;
1102  }
1103 
1104 // lock (OdeScene.UniversalColliderSyncObject)
1105  Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH);
1106 
1107  d.GeomSetCategoryBits(Shell, (uint)m_collisionCategories);
1108  d.GeomSetCollideBits(Shell, (uint)m_collisionFlags);
1109 
1110  d.MassSetCapsuleTotal(out ShellMass, m_mass, 2, CAPSULE_RADIUS, CAPSULE_LENGTH);
1111  Body = d.BodyCreate(_parent_scene.world);
1112  d.BodySetPosition(Body, npositionX, npositionY, npositionZ);
1113 
1114  _position.X = npositionX;
1115  _position.Y = npositionY;
1116  _position.Z = npositionZ;
1117 
1118  m_taintPosition = _position;
1119 
1120  d.BodySetMass(Body, ref ShellMass);
1121  d.Matrix3 m_caprot;
1122  // 90 Stand up on the cap of the capped cyllinder
1123  if (_parent_scene.IsAvCapsuleTilted)
1124  {
1125  d.RFromAxisAndAngle(out m_caprot, 1, 0, 1, (float)(Math.PI / 2));
1126  }
1127  else
1128  {
1129  d.RFromAxisAndAngle(out m_caprot, 0, 0, 1, (float)(Math.PI / 2));
1130  }
1131 
1132  d.GeomSetRotation(Shell, ref m_caprot);
1133  d.BodySetRotation(Body, ref m_caprot);
1134 
1135  d.GeomSetBody(Shell, Body);
1136 
1137  // The purpose of the AMotor here is to keep the avatar's physical
1138  // surrogate from rotating while moving
1139  Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
1140  d.JointAttach(Amotor, Body, IntPtr.Zero);
1141  d.JointSetAMotorMode(Amotor, dAMotorEuler);
1142  d.JointSetAMotorNumAxes(Amotor, 3);
1143  d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0);
1144  d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0);
1145  d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1);
1146  d.JointSetAMotorAngle(Amotor, 0, 0);
1147  d.JointSetAMotorAngle(Amotor, 1, 0);
1148  d.JointSetAMotorAngle(Amotor, 2, 0);
1149 
1150  // These lowstops and high stops are effectively (no wiggle room)
1151  if (_parent_scene.IsAvCapsuleTilted)
1152  {
1153  d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0.000000000001f);
1154  d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0.000000000001f);
1155  d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0.000000000001f);
1156  d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.000000000001f);
1157  d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0.000000000001f);
1158  d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.000000000001f);
1159  }
1160  else
1161  {
1162  #region Documentation of capsule motor LowStop and HighStop parameters
1163  // Intentionally introduce some tilt into the capsule by setting
1164  // the motor stops to small epsilon values. This small tilt prevents
1165  // the capsule from falling into the terrain; a straight-up capsule
1166  // (with -0..0 motor stops) falls into the terrain for reasons yet
1167  // to be comprehended in their entirety.
1168  #endregion
1169  AlignAvatarTiltWithCurrentDirectionOfMovement(Vector3.Zero);
1170  d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, 0.08f);
1171  d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0f);
1172  d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, 0.08f);
1173  d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.08f); // must be same as lowstop, else a different, spurious tilt is introduced
1174  d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0f); // same as lowstop
1175  d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.08f); // same as lowstop
1176  }
1177 
1178  // Fudge factor is 1f by default, we're setting it to 0. We don't want it to Fudge or the
1179  // capped cyllinder will fall over
1180  d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f);
1181  d.JointSetAMotorParam(Amotor, (int)dParam.FMax, tensor);
1182 
1183  //d.Matrix3 bodyrotation = d.BodyGetRotation(Body);
1184  //d.QfromR(
1185  //d.Matrix3 checkrotation = new d.Matrix3(0.7071068,0.5, -0.7071068,
1186  //
1187  //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22);
1188  //standupStraight();
1189 
1190  _parent_scene.geom_name_map[Shell] = Name;
1191  _parent_scene.actor_name_map[Shell] = this;
1192  }
1193 
1197  internal void Destroy()
1198  {
1199  m_tainted_isPhysical = false;
1200  _parent_scene.AddPhysicsActorTaint(this);
1201  }
1202 
1206  internal void DestroyOdeStructures()
1207  {
1208  // Create avatar capsule and related ODE data
1209  if (Shell == IntPtr.Zero || Body == IntPtr.Zero || Amotor == IntPtr.Zero)
1210  {
1211  m_log.ErrorFormat(
1212  "[ODE CHARACTER]: Destroying ODE structures for {0} even though some are already null. Shell = {1}, Body = {2}, Amotor = {3}",
1213  Name, Shell, Body, Amotor);
1214  }
1215 
1216  // destroy avatar capsule and related ODE data
1217  if (Amotor != IntPtr.Zero)
1218  {
1219  // Kill the Amotor
1220  d.JointDestroy(Amotor);
1221  Amotor = IntPtr.Zero;
1222  }
1223 
1224  //kill the Geometry
1225 // _parent_scene.waitForSpaceUnlock(_parent_scene.space);
1226 
1227  if (Body != IntPtr.Zero)
1228  {
1229  //kill the body
1230  d.BodyDestroy(Body);
1231  Body = IntPtr.Zero;
1232  }
1233 
1234  if (Shell != IntPtr.Zero)
1235  {
1236 // lock (OdeScene.UniversalColliderSyncObject)
1237  d.GeomDestroy(Shell);
1238 
1239  _parent_scene.geom_name_map.Remove(Shell);
1240  _parent_scene.actor_name_map.Remove(Shell);
1241 
1242  Shell = IntPtr.Zero;
1243  }
1244  }
1245 
1246  public override void CrossingFailure()
1247  {
1248  }
1249 
1250  public override Vector3 PIDTarget { set { return; } }
1251  public override bool PIDActive
1252  {
1253  get { return false; }
1254  set { return; }
1255  }
1256  public override float PIDTau { set { return; } }
1257 
1258  public override float PIDHoverHeight { set { return; } }
1259  public override bool PIDHoverActive {get {return false;} set { return; } }
1260  public override PIDHoverType PIDHoverType { set { return; } }
1261  public override float PIDHoverTau { set { return; } }
1262 
1263  public override Quaternion APIDTarget{ set { return; } }
1264 
1265  public override bool APIDActive{ set { return; } }
1266 
1267  public override float APIDStrength{ set { return; } }
1268 
1269  public override float APIDDamping{ set { return; } }
1270 
1271  public override void SubscribeEvents(int ms)
1272  {
1273  m_requestedUpdateFrequency = ms;
1274  m_eventsubscription = ms;
1275 
1276  // Don't clear collision event reporting here. This is called directly from scene code and so can lead
1277  // to a race condition with the simulate loop
1278 
1279  _parent_scene.AddCollisionEventReporting(this);
1280  }
1281 
1282  public override void UnSubscribeEvents()
1283  {
1284  _parent_scene.RemoveCollisionEventReporting(this);
1285 
1286  // Don't clear collision event reporting here. This is called directly from scene code and so can lead
1287  // to a race condition with the simulate loop
1288 
1289  m_requestedUpdateFrequency = 0;
1290  m_eventsubscription = 0;
1291  }
1292 
1293  public override void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
1294  {
1295  if (m_eventsubscription > 0)
1296  {
1297 // m_log.DebugFormat(
1298 // "[PHYSICS]: Adding collision event for {0}, collidedWith {1}, contact {2}", "", CollidedWith, contact);
1299 
1300  CollisionEventsThisFrame.AddCollider(CollidedWith, contact);
1301  }
1302  }
1303 
1304  internal void SendCollisions()
1305  {
1306  if (m_eventsubscription > m_requestedUpdateFrequency)
1307  {
1308  base.SendCollisionUpdate(CollisionEventsThisFrame);
1309 
1310  CollisionEventsThisFrame.Clear();
1311  m_eventsubscription = 0;
1312  }
1313  }
1314 
1315  public override bool SubscribedEvents()
1316  {
1317  if (m_eventsubscription > 0)
1318  return true;
1319  return false;
1320  }
1321 
1322  internal void ProcessTaints()
1323  {
1324  if (m_taintPosition != _position)
1325  {
1326  if (Body != IntPtr.Zero)
1327  {
1328  d.BodySetPosition(Body, m_taintPosition.X, m_taintPosition.Y, m_taintPosition.Z);
1329  _position = m_taintPosition;
1330  }
1331  }
1332 
1333  if (m_taintForce != Vector3.Zero)
1334  {
1335  if (Body != IntPtr.Zero)
1336  {
1337  // FIXME: This is not a good solution since it's subject to a race condition if a force is another
1338  // thread sets a new force while we're in this loop (since it could be obliterated by
1339  // m_taintForce = Vector3.Zero. Need to lock ProcessTaints() when we set a new tainted force.
1340  d.BodyAddForce(Body, m_taintForce.X, m_taintForce.Y, m_taintForce.Z);
1341  }
1342 
1343  m_taintForce = Vector3.Zero;
1344  }
1345 
1346  if (m_taintTargetVelocity != _target_velocity)
1347  _target_velocity = m_taintTargetVelocity;
1348 
1349  if (m_tainted_isPhysical != m_isPhysical)
1350  {
1351  if (m_tainted_isPhysical)
1352  {
1353  CreateOdeStructures(_position.X, _position.Y, _position.Z, m_tensor);
1354  _parent_scene.AddCharacter(this);
1355  }
1356  else
1357  {
1358  _parent_scene.RemoveCharacter(this);
1359  DestroyOdeStructures();
1360  }
1361 
1362  m_isPhysical = m_tainted_isPhysical;
1363  }
1364 
1365  if (m_tainted_CAPSULE_LENGTH != CAPSULE_LENGTH)
1366  {
1367  if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero)
1368  {
1369 // m_log.DebugFormat(
1370 // "[ODE CHARACTER]: Changing capsule size from {0} to {1} for {2}",
1371 // CAPSULE_LENGTH, m_tainted_CAPSULE_LENGTH, Name);
1372 
1373  m_pidControllerActive = true;
1374 
1375  // no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate()
1376  DestroyOdeStructures();
1377 
1378  float prevCapsule = CAPSULE_LENGTH;
1379  CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH;
1380 
1381  CreateOdeStructures(
1382  _position.X,
1383  _position.Y,
1384  _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule) * 2), m_tensor);
1385 
1386  // As with Size, we reset velocity. However, this isn't strictly necessary since it doesn't
1387  // appear to stall initial region crossings when done here. Being done for consistency.
1388 // Velocity = Vector3.Zero;
1389  }
1390  else
1391  {
1392  m_log.Warn("[ODE CHARACTER]: trying to change capsule size for " + Name + ", but the following ODE data is missing - "
1393  + (Shell==IntPtr.Zero ? "Shell ":"")
1394  + (Body==IntPtr.Zero ? "Body ":"")
1395  + (Amotor==IntPtr.Zero ? "Amotor ":""));
1396  }
1397  }
1398  }
1399 
1400  internal void AddCollisionFrameTime(int p)
1401  {
1402  // protect it from overflow crashing
1403  if (m_eventsubscription + p >= int.MaxValue)
1404  m_eventsubscription = 0;
1405  m_eventsubscription += p;
1406  }
1407  }
1408 }
override void VehicleFlags(int param, bool remove)
override void AddAngularForce(Vector3 force, bool pushforce)
dParam
Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ours...
Definition: ODECharacter.cs:41
delegate void SetAlwaysRun(IClientAPI remoteClient, bool SetAlwaysRun)
void SetPidStatus(bool status)
turn the PID controller on or off. The PID Controller will turn on all by itself in many situations ...
override void AddForce(Vector3 force, bool pushforce)
Adds the force supplied to the Target Velocity The PID controller takes this target velocity and trie...
OdeCharacter(String avName, OdeScene parent_scene, Vector3 pos, Vector3 vel, Vector3 size, float pid_d, float pid_p, float capsule_radius, float tensor, float density, float walk_divisor, float rundivisor)
ODE Avatar.
Used to pass collision information to OnCollisionUpdate listeners.
OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion rotation
Definition: ICM_Api.cs:32
override void VehicleRotationParam(int param, Quaternion rotation)
dParam
Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ours...
Definition: ODECharacter.cs:46
override void VehicleFloatParam(int param, float value)
override void SetVolumeDetect(int param)
Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more ...
override void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
override void VehicleVectorParam(int param, Vector3 value)
override void LockAngularMotion(byte axislocks)
override void SetMomentum(Vector3 momentum)
override void link(PhysicsActor obj)