2007-12-11 01:26:06 +00:00
/ *
2008-03-18 05:16:43 +00:00
* Copyright ( c ) Contributors , http : //opensimulator.org/
* See CONTRIBUTORS . TXT for a full list of copyright holders .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
* * Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* * Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
2009-06-01 06:37:14 +00:00
* * Neither the name of the OpenSimulator Project nor the
2008-03-18 05:16:43 +00:00
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ` ` AS IS ' ' AND ANY
* EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
* ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
* LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* /
2007-12-11 01:26:06 +00:00
2007-12-04 04:59:27 +00:00
using System ;
2009-06-25 07:39:48 +00:00
using System.Collections.Generic ;
2008-12-10 23:46:20 +00:00
using System.Reflection ;
2008-09-06 07:52:41 +00:00
using OpenMetaverse ;
2007-12-04 04:59:27 +00:00
using Ode.NET ;
using OpenSim.Framework ;
using OpenSim.Region.Physics.Manager ;
2010-12-09 01:19:06 +00:00
using OpenSim.Region.CoreModules.RegionSync.RegionSyncModule ;
2008-12-10 23:46:20 +00:00
using log4net ;
2007-12-04 04:59:27 +00:00
namespace OpenSim.Region.Physics.OdePlugin
{
2008-01-13 07:14:54 +00:00
/// <summary>
2008-02-14 00:44:21 +00:00
/// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves.
2008-01-13 07:14:54 +00:00
/// </summary>
2008-05-16 01:22:11 +00:00
2008-01-13 07:14:54 +00:00
public enum dParam : int
{
LowStop = 0 ,
HiStop = 1 ,
Vel = 2 ,
FMax = 3 ,
FudgeFactor = 4 ,
Bounce = 5 ,
CFM = 6 ,
2009-07-15 10:09:37 +00:00
StopERP = 7 ,
2008-01-13 07:14:54 +00:00
StopCFM = 8 ,
LoStop2 = 256 ,
HiStop2 = 257 ,
2009-04-19 08:12:10 +00:00
Vel2 = 258 ,
FMax2 = 259 ,
2009-07-15 10:09:37 +00:00
StopERP2 = 7 + 256 ,
StopCFM2 = 8 + 256 ,
2008-01-13 07:14:54 +00:00
LoStop3 = 512 ,
2009-04-19 08:12:10 +00:00
HiStop3 = 513 ,
Vel3 = 514 ,
2009-07-15 10:09:37 +00:00
FMax3 = 515 ,
StopERP3 = 7 + 512 ,
StopCFM3 = 8 + 512
2008-01-13 07:14:54 +00:00
}
2007-12-04 04:59:27 +00:00
public class OdeCharacter : PhysicsActor
{
2009-02-08 17:25:02 +00:00
private static readonly ILog m_log = LogManager . GetLogger ( MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
2009-10-26 06:16:12 +00:00
private Vector3 _position ;
2009-02-08 17:25:02 +00:00
private d . Vector3 _zeroPosition ;
// private d.Matrix3 m_StandUpRotation;
private bool _zeroFlag = false ;
private bool m_lastUpdateSent = false ;
2009-10-26 06:16:12 +00:00
private Vector3 _velocity ;
private Vector3 _target_velocity ;
private Vector3 _acceleration ;
private Vector3 m_rotationalVelocity ;
2009-02-08 17:25:02 +00:00
private float m_mass = 80f ;
2008-05-15 23:11:31 +00:00
public float m_density = 60f ;
2009-02-08 17:25:02 +00:00
private bool m_pidControllerActive = true ;
2008-05-15 23:11:31 +00:00
public float PID_D = 800.0f ;
public float PID_P = 900.0f ;
2009-02-08 17:25:02 +00:00
//private static float POSTURE_SERVO = 10000.0f;
2008-05-15 23:11:31 +00:00
public float CAPSULE_RADIUS = 0.37f ;
2008-01-18 02:26:43 +00:00
public float CAPSULE_LENGTH = 2.140599f ;
2008-05-15 23:11:31 +00:00
public float m_tensor = 3800000f ;
public float heightFudgeFactor = 0.52f ;
public float walkDivisor = 1.3f ;
public float runDivisor = 0.8f ;
2009-02-08 17:25:02 +00:00
private bool flying = false ;
private bool m_iscolliding = false ;
private bool m_iscollidingGround = false ;
private bool m_wascolliding = false ;
private bool m_wascollidingGround = false ;
private bool m_iscollidingObj = false ;
private bool m_alwaysRun = false ;
private bool m_hackSentFall = false ;
private bool m_hackSentFly = false ;
2009-10-10 07:53:53 +00:00
private int m_requestedUpdateFrequency = 0 ;
2009-10-26 06:16:12 +00:00
private Vector3 m_taintPosition = Vector3 . Zero ;
2008-02-23 11:42:55 +00:00
public uint m_localID = 0 ;
2008-03-14 05:22:52 +00:00
public bool m_returnCollisions = false ;
2008-12-10 23:46:20 +00:00
// taints and their non-tainted counterparts
public bool m_isPhysical = false ; // the current physical status
public bool m_tainted_isPhysical = false ; // set when the physical status is tainted (false=not existing in physics engine, true=existing)
2009-03-07 07:17:43 +00:00
public float MinimumGroundFlightOffset = 3f ;
2009-02-08 17:25:02 +00:00
private float m_tainted_CAPSULE_LENGTH ; // set when the capsule length changes.
2009-09-18 02:26:52 +00:00
private float m_tiltMagnitudeWhenProjectedOnXYPlane = 0.1131371f ; // used to introduce a fixed tilt because a straight-up capsule falls through terrain, probably a bug in terrain collider
2008-02-23 11:42:55 +00:00
2009-03-07 07:17:43 +00:00
2009-02-08 17:25:02 +00:00
private float m_buoyancy = 0f ;
2008-03-10 05:23:43 +00:00
2009-02-08 17:25:02 +00:00
// private CollisionLocker ode;
2008-01-23 23:57:54 +00:00
2009-02-08 17:25:02 +00:00
private string m_name = String . Empty ;
2007-12-04 04:59:27 +00:00
2009-02-08 17:25:02 +00:00
private bool [ ] m_colliderarr = new bool [ 11 ] ;
private bool [ ] m_colliderGroundarr = new bool [ 11 ] ;
2007-12-04 04:59:27 +00:00
2008-02-23 11:42:55 +00:00
// Default we're a Character
2009-02-08 17:25:02 +00:00
private CollisionCategories m_collisionCategories = ( CollisionCategories . Character ) ;
2008-02-23 11:42:55 +00:00
// Default, Collide with Other Geometries, spaces, bodies and characters.
2009-02-08 17:25:02 +00:00
private CollisionCategories m_collisionFlags = ( CollisionCategories . Geom
2008-02-23 11:42:55 +00:00
| CollisionCategories . Space
| CollisionCategories . Body
2008-05-16 01:22:11 +00:00
| CollisionCategories . Character
2008-02-23 11:42:55 +00:00
| CollisionCategories . Land ) ;
2008-12-10 23:46:20 +00:00
public IntPtr Body = IntPtr . Zero ;
2009-02-08 17:25:02 +00:00
private OdeScene _parent_scene ;
2008-12-10 23:46:20 +00:00
public IntPtr Shell = IntPtr . Zero ;
public IntPtr Amotor = IntPtr . Zero ;
2007-12-04 04:59:27 +00:00
public d . Mass ShellMass ;
public bool collidelock = false ;
2008-05-03 04:33:17 +00:00
public int m_eventsubscription = 0 ;
2009-02-08 17:25:02 +00:00
private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate ( ) ;
2008-05-03 04:33:17 +00:00
2009-10-18 23:48:44 +00:00
// unique UUID of this character object
public UUID m_uuid ;
public bool bad = false ;
2009-10-26 06:16:12 +00:00
public OdeCharacter ( String avName , OdeScene parent_scene , Vector3 pos , CollisionLocker dode , Vector3 size , float pid_d , float pid_p , float capsule_radius , float tensor , float density , float height_fudge_factor , float walk_divisor , float rundivisor )
2007-12-04 04:59:27 +00:00
{
2009-10-18 23:48:44 +00:00
m_uuid = UUID . Random ( ) ;
2009-10-26 06:16:12 +00:00
if ( pos . IsFinite ( ) )
2009-04-07 16:41:07 +00:00
{
2009-10-26 06:16:12 +00:00
if ( pos . Z > 9999999f )
2009-04-14 01:57:35 +00:00
{
pos . Z = parent_scene . GetTerrainHeightAtXY ( 127 , 127 ) + 5 ;
}
2009-10-26 06:16:12 +00:00
if ( pos . Z < - 90000f )
2009-04-14 01:57:35 +00:00
{
pos . Z = parent_scene . GetTerrainHeightAtXY ( 127 , 127 ) + 5 ;
}
2009-04-07 16:41:07 +00:00
_position = pos ;
m_taintPosition . X = pos . X ;
m_taintPosition . Y = pos . Y ;
m_taintPosition . Z = pos . Z ;
}
else
{
2009-10-26 06:16:12 +00:00
_position = new Vector3 ( ( ( float ) _parent_scene . WorldExtents . X * 0.5f ) , ( ( float ) _parent_scene . WorldExtents . Y * 0.5f ) , parent_scene . GetTerrainHeightAtXY ( 128f , 128f ) + 10f ) ;
2009-04-07 16:41:07 +00:00
m_taintPosition . X = _position . X ;
m_taintPosition . Y = _position . Y ;
m_taintPosition . Z = _position . Z ;
m_log . Warn ( "[PHYSICS]: Got NaN Position on Character Create" ) ;
}
2007-12-04 04:59:27 +00:00
_parent_scene = parent_scene ;
2008-01-26 17:38:30 +00:00
2008-05-15 23:11:31 +00:00
PID_D = pid_d ;
PID_P = pid_p ;
CAPSULE_RADIUS = capsule_radius ;
m_tensor = tensor ;
m_density = density ;
heightFudgeFactor = height_fudge_factor ;
walkDivisor = walk_divisor ;
runDivisor = rundivisor ;
2008-06-27 17:25:03 +00:00
// m_StandUpRotation =
// new d.Matrix3(0.5f, 0.7071068f, 0.5f, -0.7071068f, 0f, 0.7071068f, 0.5f, -0.7071068f,
// 0.5f);
2007-12-26 04:23:36 +00:00
2007-12-04 04:59:27 +00:00
for ( int i = 0 ; i < 11 ; i + + )
{
m_colliderarr [ i ] = false ;
}
2008-11-10 01:28:37 +00:00
CAPSULE_LENGTH = ( size . Z * 1.15f ) - CAPSULE_RADIUS * 2.0f ;
//m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString());
2008-12-10 23:46:20 +00:00
m_tainted_CAPSULE_LENGTH = CAPSULE_LENGTH ;
m_isPhysical = false ; // current status: no ODE information exists
m_tainted_isPhysical = true ; // new tainted status: need to create ODE information
2007-12-04 04:59:27 +00:00
2009-01-31 16:49:32 +00:00
_parent_scene . AddPhysicsActorTaint ( this ) ;
2007-12-04 04:59:27 +00:00
m_name = avName ;
}
2007-12-27 21:41:48 +00:00
2010-12-09 01:19:06 +00:00
public override void RequestPhysicsterseUpdate ( )
{
2010-12-14 23:31:00 +00:00
if ( PhysEngineToSceneConnectorModule . IsPhysEngineActorS )
2010-12-09 01:19:06 +00:00
{
2010-12-15 23:05:40 +00:00
// m_log.DebugFormat("[ODE CHARACTER]: Sending terse update for {0}", LocalID);
if ( this . lastValues . Changed ( this ) )
{
PhysEngineToSceneConnectorModule . RouteUpdate ( this ) ;
}
2010-12-09 01:19:06 +00:00
}
else
{
base . RequestPhysicsterseUpdate ( ) ;
}
}
2007-12-04 04:59:27 +00:00
public override int PhysicsActorType
{
2007-12-27 21:41:48 +00:00
get { return ( int ) ActorTypes . Agent ; }
2007-12-04 04:59:27 +00:00
set { return ; }
}
2007-12-27 21:41:48 +00:00
2008-01-13 07:14:54 +00:00
/// <summary>
/// If this is set, the avatar will move faster
/// </summary>
2007-12-04 04:59:27 +00:00
public override bool SetAlwaysRun
{
get { return m_alwaysRun ; }
set { m_alwaysRun = value ; }
}
2007-12-27 21:41:48 +00:00
2008-02-23 11:42:55 +00:00
public override uint LocalID
{
set { m_localID = value ; }
2010-12-14 23:31:00 +00:00
get { return m_localID ; }
2008-02-23 11:42:55 +00:00
}
2008-01-29 15:10:18 +00:00
public override bool Grabbed
{
set { return ; }
}
public override bool Selected
{
set { return ; }
}
2008-03-10 05:23:43 +00:00
public override float Buoyancy
{
get { return m_buoyancy ; }
set { m_buoyancy = value ; }
}
2008-01-29 15:10:18 +00:00
2008-03-10 05:56:58 +00:00
public override bool FloatOnWater
{
set { return ; }
}
2007-12-04 04:59:27 +00:00
public override bool IsPhysical
{
get { return false ; }
set { return ; }
}
2007-12-27 21:41:48 +00:00
2007-12-04 04:59:27 +00:00
public override bool ThrottleUpdates
{
get { return false ; }
set { return ; }
}
2007-12-27 21:41:48 +00:00
2007-12-04 04:59:27 +00:00
public override bool Flying
{
get { return flying ; }
set { flying = value ; }
}
2007-12-27 21:41:48 +00:00
2008-01-13 07:14:54 +00:00
/// <summary>
/// Returns if the avatar is colliding in general.
/// This includes the ground and objects and avatar.
/// </summary>
2007-12-04 04:59:27 +00:00
public override bool IsColliding
{
get { return m_iscolliding ; }
set
{
int i ;
int truecount = 0 ;
int falsecount = 0 ;
if ( m_colliderarr . Length > = 10 )
{
for ( i = 0 ; i < 10 ; i + + )
{
m_colliderarr [ i ] = m_colliderarr [ i + 1 ] ;
}
}
m_colliderarr [ 10 ] = value ;
for ( i = 0 ; i < 11 ; i + + )
{
if ( m_colliderarr [ i ] )
{
truecount + + ;
}
else
{
falsecount + + ;
}
}
// Equal truecounts and false counts means we're colliding with something.
2007-12-27 21:41:48 +00:00
if ( falsecount > 1.2 * truecount )
2007-12-04 04:59:27 +00:00
{
m_iscolliding = false ;
}
else
{
m_iscolliding = true ;
}
if ( m_wascolliding ! = m_iscolliding )
{
2009-07-16 04:50:49 +00:00
//base.SendCollisionUpdate(new CollisionEventUpdate());
2007-12-04 04:59:27 +00:00
}
m_wascolliding = m_iscolliding ;
}
}
2007-12-27 21:41:48 +00:00
2008-01-13 07:14:54 +00:00
/// <summary>
/// Returns if an avatar is colliding with the ground
/// </summary>
2007-12-04 04:59:27 +00:00
public override bool CollidingGround
{
get { return m_iscollidingGround ; }
set
{
2008-01-13 07:14:54 +00:00
// Collisions against the ground are not really reliable
// So, to get a consistant value we have to average the current result over time
// Currently we use 1 second = 10 calls to this.
2007-12-04 04:59:27 +00:00
int i ;
int truecount = 0 ;
int falsecount = 0 ;
if ( m_colliderGroundarr . Length > = 10 )
{
for ( i = 0 ; i < 10 ; i + + )
{
m_colliderGroundarr [ i ] = m_colliderGroundarr [ i + 1 ] ;
}
}
m_colliderGroundarr [ 10 ] = value ;
for ( i = 0 ; i < 11 ; i + + )
{
if ( m_colliderGroundarr [ i ] )
{
truecount + + ;
}
else
{
falsecount + + ;
}
}
// Equal truecounts and false counts means we're colliding with something.
2007-12-27 21:41:48 +00:00
if ( falsecount > 1.2 * truecount )
2007-12-04 04:59:27 +00:00
{
m_iscollidingGround = false ;
}
else
{
m_iscollidingGround = true ;
}
if ( m_wascollidingGround ! = m_iscollidingGround )
{
2009-07-16 04:50:49 +00:00
//base.SendCollisionUpdate(new CollisionEventUpdate());
2007-12-04 04:59:27 +00:00
}
m_wascollidingGround = m_iscollidingGround ;
}
}
2007-12-27 21:41:48 +00:00
2008-01-13 07:14:54 +00:00
/// <summary>
/// Returns if the avatar is colliding with an object
/// </summary>
2007-12-04 04:59:27 +00:00
public override bool CollidingObj
{
2007-12-15 05:08:08 +00:00
get { return m_iscollidingObj ; }
2007-12-27 21:41:48 +00:00
set
{
2007-12-15 05:08:08 +00:00
m_iscollidingObj = value ;
if ( value )
m_pidControllerActive = false ;
else
m_pidControllerActive = true ;
}
2007-12-04 04:59:27 +00:00
}
2007-12-27 21:41:48 +00:00
2008-01-13 07:14:54 +00:00
/// <summary>
2008-05-16 01:22:11 +00:00
/// turn the PID controller on or off.
2008-01-13 07:14:54 +00:00
/// The PID Controller will turn on all by itself in many situations
/// </summary>
/// <param name="status"></param>
2007-12-26 17:16:47 +00:00
public void SetPidStatus ( bool status )
{
m_pidControllerActive = status ;
}
2007-12-27 21:41:48 +00:00
2008-02-17 10:41:08 +00:00
public override bool Stopped
{
get { return _zeroFlag ; }
}
2008-01-13 07:14:54 +00:00
/// <summary>
/// This 'puts' an avatar somewhere in the physics space.
2008-05-16 01:22:11 +00:00
/// Not really a good choice unless you 'know' it's a good
2008-01-13 07:14:54 +00:00
/// spot otherwise you're likely to orbit the avatar.
/// </summary>
2009-10-26 06:16:12 +00:00
public override Vector3 Position
2007-12-04 04:59:27 +00:00
{
get { return _position ; }
set
{
2009-01-31 16:49:32 +00:00
if ( Body = = IntPtr . Zero | | Shell = = IntPtr . Zero )
2009-04-07 16:13:17 +00:00
{
2009-10-26 06:16:12 +00:00
if ( value . IsFinite ( ) )
2009-04-07 16:13:17 +00:00
{
2009-10-26 06:16:12 +00:00
if ( value . Z > 9999999f )
2009-04-14 01:57:35 +00:00
{
value . Z = _parent_scene . GetTerrainHeightAtXY ( 127 , 127 ) + 5 ;
}
2009-10-26 06:16:12 +00:00
if ( value . Z < - 90000f )
2009-04-14 01:57:35 +00:00
{
value . Z = _parent_scene . GetTerrainHeightAtXY ( 127 , 127 ) + 5 ;
}
2009-04-07 16:13:17 +00:00
_position . X = value . X ;
_position . Y = value . Y ;
_position . Z = value . Z ;
m_taintPosition . X = value . X ;
m_taintPosition . Y = value . Y ;
m_taintPosition . Z = value . Z ;
_parent_scene . AddPhysicsActorTaint ( this ) ;
}
else
{
m_log . Warn ( "[PHYSICS]: Got a NaN Position from Scene on a Character" ) ;
}
}
2007-12-04 04:59:27 +00:00
}
}
2007-12-27 21:41:48 +00:00
2009-10-26 06:16:12 +00:00
public override Vector3 RotationalVelocity
2007-12-04 04:59:27 +00:00
{
get { return m_rotationalVelocity ; }
set { m_rotationalVelocity = value ; }
}
2007-12-27 21:41:48 +00:00
2008-01-13 07:14:54 +00:00
/// <summary>
/// This property sets the height of the avatar only. We use the height to make sure the avatar stands up straight
/// and use it to offset landings properly
/// </summary>
2009-10-26 06:16:12 +00:00
public override Vector3 Size
2007-12-04 04:59:27 +00:00
{
2009-10-26 06:16:12 +00:00
get { return new Vector3 ( CAPSULE_RADIUS * 2 , CAPSULE_RADIUS * 2 , CAPSULE_LENGTH ) ; }
2007-12-04 04:59:27 +00:00
set
{
2009-10-26 06:16:12 +00:00
if ( value . IsFinite ( ) )
2009-04-07 16:13:17 +00:00
{
m_pidControllerActive = true ;
2009-10-26 06:16:12 +00:00
Vector3 SetSize = value ;
2009-04-07 16:13:17 +00:00
m_tainted_CAPSULE_LENGTH = ( SetSize . Z * 1.15f ) - CAPSULE_RADIUS * 2.0f ;
2008-02-13 08:37:50 +00:00
//m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString());
2008-01-30 07:09:58 +00:00
2009-10-26 06:16:12 +00:00
Velocity = Vector3 . Zero ;
2009-04-07 16:13:17 +00:00
_parent_scene . AddPhysicsActorTaint ( this ) ;
}
else
{
m_log . Warn ( "[PHYSICS]: Got a NaN Size from Scene on a Character" ) ;
}
2007-12-04 04:59:27 +00:00
}
}
2009-09-18 02:26:52 +00:00
2009-10-26 06:16:12 +00:00
private void AlignAvatarTiltWithCurrentDirectionOfMovement ( Vector3 movementVector )
2009-09-18 02:26:52 +00:00
{
movementVector . Z = 0f ;
float magnitude = ( float ) Math . Sqrt ( ( double ) ( movementVector . X * movementVector . X + movementVector . Y * movementVector . Y ) ) ;
if ( magnitude < 0.1f ) return ;
// normalize the velocity vector
float invMagnitude = 1.0f / magnitude ;
movementVector . X * = invMagnitude ;
movementVector . Y * = invMagnitude ;
// if we change the capsule heading too often, the capsule can fall down
// therefore we snap movement vector to just 1 of 4 predefined directions (ne, nw, se, sw),
// meaning only 4 possible capsule tilt orientations
if ( movementVector . X > 0 )
{
// east
if ( movementVector . Y > 0 )
{
// northeast
movementVector . X = ( float ) Math . Sqrt ( 2.0 ) ;
movementVector . Y = ( float ) Math . Sqrt ( 2.0 ) ;
}
else
{
// southeast
movementVector . X = ( float ) Math . Sqrt ( 2.0 ) ;
movementVector . Y = - ( float ) Math . Sqrt ( 2.0 ) ;
}
}
else
{
// west
if ( movementVector . Y > 0 )
{
// northwest
movementVector . X = - ( float ) Math . Sqrt ( 2.0 ) ;
movementVector . Y = ( float ) Math . Sqrt ( 2.0 ) ;
}
else
{
// southwest
movementVector . X = - ( float ) Math . Sqrt ( 2.0 ) ;
movementVector . Y = - ( float ) Math . Sqrt ( 2.0 ) ;
}
}
// movementVector.Z is zero
// calculate tilt components based on desired amount of tilt and current (snapped) heading.
// the "-" sign is to force the tilt to be OPPOSITE the direction of movement.
float xTiltComponent = - movementVector . X * m_tiltMagnitudeWhenProjectedOnXYPlane ;
float yTiltComponent = - movementVector . Y * m_tiltMagnitudeWhenProjectedOnXYPlane ;
//m_log.Debug("[PHYSICS] changing avatar tilt");
d . JointSetAMotorParam ( Amotor , ( int ) dParam . LowStop , xTiltComponent ) ;
d . JointSetAMotorParam ( Amotor , ( int ) dParam . HiStop , xTiltComponent ) ; // must be same as lowstop, else a different, spurious tilt is introduced
d . JointSetAMotorParam ( Amotor , ( int ) dParam . LoStop2 , yTiltComponent ) ;
d . JointSetAMotorParam ( Amotor , ( int ) dParam . HiStop2 , yTiltComponent ) ; // same as lowstop
d . JointSetAMotorParam ( Amotor , ( int ) dParam . LoStop3 , 0f ) ;
d . JointSetAMotorParam ( Amotor , ( int ) dParam . HiStop3 , 0f ) ; // same as lowstop
}
2008-01-13 07:14:54 +00:00
/// <summary>
/// This creates the Avatar's physical Surrogate at the position supplied
/// </summary>
/// <param name="npositionX"></param>
/// <param name="npositionY"></param>
/// <param name="npositionZ"></param>
2008-12-10 23:46:20 +00:00
// WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access
// to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only
// place that is safe to call this routine AvatarGeomAndBodyCreation.
2009-02-08 17:25:02 +00:00
private void AvatarGeomAndBodyCreation ( float npositionX , float npositionY , float npositionZ , float tensor )
2008-01-13 07:14:54 +00:00
{
2008-12-14 07:29:40 +00:00
//CAPSULE_LENGTH = -5;
//CAPSULE_RADIUS = -5;
2008-01-13 07:14:54 +00:00
int dAMotorEuler = 1 ;
2008-01-30 07:09:58 +00:00
_parent_scene . waitForSpaceUnlock ( _parent_scene . space ) ;
2008-12-14 07:29:40 +00:00
if ( CAPSULE_LENGTH < = 0 )
{
m_log . Warn ( "[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!" ) ;
CAPSULE_LENGTH = 0.01f ;
}
if ( CAPSULE_RADIUS < = 0 )
{
m_log . Warn ( "[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!" ) ;
CAPSULE_RADIUS = 0.01f ;
}
2008-01-13 07:14:54 +00:00
Shell = d . CreateCapsule ( _parent_scene . space , CAPSULE_RADIUS , CAPSULE_LENGTH ) ;
2008-05-16 01:22:11 +00:00
2008-02-23 11:42:55 +00:00
d . GeomSetCategoryBits ( Shell , ( int ) m_collisionCategories ) ;
d . GeomSetCollideBits ( Shell , ( int ) m_collisionFlags ) ;
2008-01-13 07:14:54 +00:00
d . MassSetCapsuleTotal ( out ShellMass , m_mass , 2 , CAPSULE_RADIUS , CAPSULE_LENGTH ) ;
Body = d . BodyCreate ( _parent_scene . world ) ;
d . BodySetPosition ( Body , npositionX , npositionY , npositionZ ) ;
2009-01-31 16:49:32 +00:00
_position . X = npositionX ;
_position . Y = npositionY ;
_position . Z = npositionZ ;
m_taintPosition . X = npositionX ;
m_taintPosition . Y = npositionY ;
m_taintPosition . Z = npositionZ ;
2008-01-13 07:14:54 +00:00
d . BodySetMass ( Body , ref ShellMass ) ;
2008-01-18 21:38:47 +00:00
d . Matrix3 m_caprot ;
2008-01-13 07:14:54 +00:00
// 90 Stand up on the cap of the capped cyllinder
2009-07-08 01:41:05 +00:00
if ( _parent_scene . IsAvCapsuleTilted )
{
d . RFromAxisAndAngle ( out m_caprot , 1 , 0 , 1 , ( float ) ( Math . PI / 2 ) ) ;
}
else
{
d . RFromAxisAndAngle ( out m_caprot , 0 , 0 , 1 , ( float ) ( Math . PI / 2 ) ) ;
}
2008-01-13 07:14:54 +00:00
2008-01-23 23:57:54 +00:00
d . GeomSetRotation ( Shell , ref m_caprot ) ;
d . BodySetRotation ( Body , ref m_caprot ) ;
2008-01-13 07:14:54 +00:00
d . GeomSetBody ( Shell , Body ) ;
2008-05-16 01:22:11 +00:00
// The purpose of the AMotor here is to keep the avatar's physical
2008-01-13 07:14:54 +00:00
// surrogate from rotating while moving
2008-01-23 23:57:54 +00:00
Amotor = d . JointCreateAMotor ( _parent_scene . world , IntPtr . Zero ) ;
d . JointAttach ( Amotor , Body , IntPtr . Zero ) ;
d . JointSetAMotorMode ( Amotor , dAMotorEuler ) ;
d . JointSetAMotorNumAxes ( Amotor , 3 ) ;
d . JointSetAMotorAxis ( Amotor , 0 , 0 , 1 , 0 , 0 ) ;
d . JointSetAMotorAxis ( Amotor , 1 , 0 , 0 , 1 , 0 ) ;
d . JointSetAMotorAxis ( Amotor , 2 , 0 , 0 , 0 , 1 ) ;
d . JointSetAMotorAngle ( Amotor , 0 , 0 ) ;
d . JointSetAMotorAngle ( Amotor , 1 , 0 ) ;
d . JointSetAMotorAngle ( Amotor , 2 , 0 ) ;
2008-05-16 01:22:11 +00:00
2008-01-13 07:14:54 +00:00
// These lowstops and high stops are effectively (no wiggle room)
2009-07-08 01:41:05 +00:00
if ( _parent_scene . IsAvCapsuleTilted )
{
d . JointSetAMotorParam ( Amotor , ( int ) dParam . LowStop , - 0.000000000001f ) ;
d . JointSetAMotorParam ( Amotor , ( int ) dParam . LoStop3 , - 0.000000000001f ) ;
d . JointSetAMotorParam ( Amotor , ( int ) dParam . LoStop2 , - 0.000000000001f ) ;
d . JointSetAMotorParam ( Amotor , ( int ) dParam . HiStop , 0.000000000001f ) ;
d . JointSetAMotorParam ( Amotor , ( int ) dParam . HiStop3 , 0.000000000001f ) ;
d . JointSetAMotorParam ( Amotor , ( int ) dParam . HiStop2 , 0.000000000001f ) ;
}
else
{
2009-07-15 10:09:37 +00:00
#region Documentation of capsule motor LowStop and HighStop parameters
// Intentionally introduce some tilt into the capsule by setting
// the motor stops to small epsilon values. This small tilt prevents
// the capsule from falling into the terrain; a straight-up capsule
// (with -0..0 motor stops) falls into the terrain for reasons yet
// to be comprehended in their entirety.
# endregion
2009-10-26 06:16:12 +00:00
AlignAvatarTiltWithCurrentDirectionOfMovement ( Vector3 . Zero ) ;
2009-07-15 10:09:37 +00:00
d . JointSetAMotorParam ( Amotor , ( int ) dParam . LowStop , 0.08f ) ;
d . JointSetAMotorParam ( Amotor , ( int ) dParam . LoStop3 , - 0f ) ;
d . JointSetAMotorParam ( Amotor , ( int ) dParam . LoStop2 , 0.08f ) ;
d . JointSetAMotorParam ( Amotor , ( int ) dParam . HiStop , 0.08f ) ; // must be same as lowstop, else a different, spurious tilt is introduced
d . JointSetAMotorParam ( Amotor , ( int ) dParam . HiStop3 , 0f ) ; // same as lowstop
d . JointSetAMotorParam ( Amotor , ( int ) dParam . HiStop2 , 0.08f ) ; // same as lowstop
2009-07-08 01:41:05 +00:00
}
2008-01-13 07:14:54 +00:00
2008-05-16 01:22:11 +00:00
// Fudge factor is 1f by default, we're setting it to 0. We don't want it to Fudge or the
2008-01-13 07:14:54 +00:00
// capped cyllinder will fall over
2008-01-23 23:57:54 +00:00
d . JointSetAMotorParam ( Amotor , ( int ) dParam . FudgeFactor , 0f ) ;
d . JointSetAMotorParam ( Amotor , ( int ) dParam . FMax , tensor ) ;
2008-05-16 01:22:11 +00:00
2008-01-18 21:38:47 +00:00
//d.Matrix3 bodyrotation = d.BodyGetRotation(Body);
//d.QfromR(
//d.Matrix3 checkrotation = new d.Matrix3(0.7071068,0.5, -0.7071068,
2008-05-16 01:22:11 +00:00
/ /
2008-02-05 19:44:27 +00:00
//m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22);
2008-01-18 21:38:47 +00:00
//standupStraight();
2008-01-13 07:14:54 +00:00
}
2007-12-27 21:41:48 +00:00
2008-05-16 01:22:11 +00:00
/ /
2008-01-13 07:14:54 +00:00
/// <summary>
/// Uses the capped cyllinder volume formula to calculate the avatar's mass.
/// This may be used in calculations in the scene/scenepresence
/// </summary>
2007-12-19 22:42:06 +00:00
public override float Mass
{
2007-12-27 21:41:48 +00:00
get
{
float AVvolume = ( float ) ( Math . PI * Math . Pow ( CAPSULE_RADIUS , 2 ) * CAPSULE_LENGTH ) ;
return m_density * AVvolume ;
2007-12-19 22:42:06 +00:00
}
}
2008-03-02 09:31:39 +00:00
public override void link ( PhysicsActor obj )
{
}
2007-12-19 22:42:06 +00:00
2008-03-02 09:31:39 +00:00
public override void delink ( )
{
}
2008-01-18 02:26:43 +00:00
2009-10-26 06:16:12 +00:00
public override void LockAngularMotion ( Vector3 axis )
2008-04-23 15:32:19 +00:00
{
}
2008-05-16 01:22:11 +00:00
// This code is very useful. Written by DanX0r. We're just not using it right now.
2008-04-23 15:32:19 +00:00
// Commented out to prevent a warning.
/ /
2009-02-08 17:25:02 +00:00
// private void standupStraight()
2008-03-25 03:49:08 +00:00
// {
// // The purpose of this routine here is to quickly stabilize the Body while it's popped up in the air.
2008-05-16 01:22:11 +00:00
// // The amotor needs a few seconds to stabilize so without it, the avatar shoots up sky high when you
2008-03-25 03:49:08 +00:00
// // change appearance and when you enter the simulator
// // After this routine is done, the amotor stabilizes much quicker
// d.Vector3 feet;
// d.Vector3 head;
// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, -1.0f, out feet);
// d.BodyGetRelPointPos(Body, 0.0f, 0.0f, 1.0f, out head);
// float posture = head.Z - feet.Z;
// // restoring force proportional to lack of posture:
// float servo = (2.5f - posture) * POSTURE_SERVO;
// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, servo, 0.0f, 0.0f, 1.0f);
// d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, -servo, 0.0f, 0.0f, -1.0f);
// //d.Matrix3 bodyrotation = d.BodyGetRotation(Body);
// //m_log.Info("[PHYSICSAV]: Rotation: " + bodyrotation.M00 + " : " + bodyrotation.M01 + " : " + bodyrotation.M02 + " : " + bodyrotation.M10 + " : " + bodyrotation.M11 + " : " + bodyrotation.M12 + " : " + bodyrotation.M20 + " : " + bodyrotation.M21 + " : " + bodyrotation.M22);
// }
2008-01-18 02:26:43 +00:00
2009-10-26 06:16:12 +00:00
public override Vector3 Force
2007-12-19 22:42:06 +00:00
{
2009-10-26 06:16:12 +00:00
get { return _target_velocity ; }
2008-07-24 07:45:58 +00:00
set { return ; }
2007-12-19 22:42:06 +00:00
}
2008-09-28 22:38:59 +00:00
public override int VehicleType
{
get { return 0 ; }
set { return ; }
}
2008-09-28 20:20:32 +00:00
public override void VehicleFloatParam ( int param , float value )
2008-09-28 18:36:30 +00:00
{
2008-09-28 20:20:32 +00:00
}
2009-10-26 06:16:12 +00:00
public override void VehicleVectorParam ( int param , Vector3 value )
2008-09-28 20:20:32 +00:00
{
2008-09-28 18:36:30 +00:00
}
2008-09-28 21:53:56 +00:00
public override void VehicleRotationParam ( int param , Quaternion rotation )
{
}
2010-02-14 21:41:57 +00:00
public override void VehicleFlags ( int param , bool remove )
{
}
2008-12-09 11:11:16 +00:00
public override void SetVolumeDetect ( int param )
{
}
2008-09-28 21:53:56 +00:00
2009-10-26 06:16:12 +00:00
public override Vector3 CenterOfMass
2007-12-19 22:42:06 +00:00
{
2009-10-26 06:16:12 +00:00
get { return Vector3 . Zero ; }
2007-12-19 22:42:06 +00:00
}
2009-10-26 06:16:12 +00:00
public override Vector3 GeometricCenter
2007-12-19 22:42:06 +00:00
{
2009-10-26 06:16:12 +00:00
get { return Vector3 . Zero ; }
2007-12-19 22:42:06 +00:00
}
2007-12-04 04:59:27 +00:00
public override PrimitiveBaseShape Shape
{
2007-12-27 21:41:48 +00:00
set { return ; }
2007-12-04 04:59:27 +00:00
}
2009-10-26 06:16:12 +00:00
public override Vector3 Velocity
2007-12-04 04:59:27 +00:00
{
2008-02-15 21:35:52 +00:00
get {
2009-10-26 06:16:12 +00:00
// There's a problem with Vector3.Zero! Don't Use it Here!
2008-02-15 21:35:52 +00:00
if ( _zeroFlag )
2009-10-26 06:16:12 +00:00
return Vector3 . Zero ;
2008-02-15 21:35:52 +00:00
m_lastUpdateSent = false ;
2008-05-16 01:22:11 +00:00
return _velocity ;
2008-02-15 21:35:52 +00:00
}
2007-12-27 21:41:48 +00:00
set
{
2009-10-26 06:16:12 +00:00
if ( value . IsFinite ( ) )
2009-04-07 16:13:17 +00:00
{
m_pidControllerActive = true ;
_target_velocity = value ;
}
else
{
m_log . Warn ( "[PHYSICS]: Got a NaN velocity from Scene in a Character" ) ;
}
2007-12-27 21:41:48 +00:00
}
2007-12-04 04:59:27 +00:00
}
2009-10-26 06:16:12 +00:00
public override Vector3 Torque
2008-12-14 14:30:28 +00:00
{
2009-10-26 06:16:12 +00:00
get { return Vector3 . Zero ; }
2008-12-14 14:30:28 +00:00
set { return ; }
}
2008-02-13 07:50:15 +00:00
public override float CollisionScore
{
get { return 0f ; }
2008-05-25 11:22:05 +00:00
set { }
2008-02-13 07:50:15 +00:00
}
2007-12-04 04:59:27 +00:00
public override bool Kinematic
{
get { return false ; }
set { }
}
public override Quaternion Orientation
{
get { return Quaternion . Identity ; }
2008-01-18 02:26:43 +00:00
set {
//Matrix3 or = Orientation.ToRotationMatrix();
//d.Matrix3 ord = new d.Matrix3(or.m00, or.m10, or.m20, or.m01, or.m11, or.m21, or.m02, or.m12, or.m22);
//d.BodySetRotation(Body, ref ord);
}
2007-12-04 04:59:27 +00:00
}
2009-10-26 06:16:12 +00:00
public override Vector3 Acceleration
2007-12-04 04:59:27 +00:00
{
get { return _acceleration ; }
}
2009-10-26 06:16:12 +00:00
public void SetAcceleration ( Vector3 accel )
2007-12-04 04:59:27 +00:00
{
2007-12-15 05:08:08 +00:00
m_pidControllerActive = true ;
2007-12-04 04:59:27 +00:00
_acceleration = accel ;
}
2008-01-13 07:14:54 +00:00
/// <summary>
2008-05-16 01:22:11 +00:00
/// Adds the force supplied to the Target Velocity
2008-01-13 07:14:54 +00:00
/// The PID controller takes this target velocity and tries to make it a reality
/// </summary>
/// <param name="force"></param>
2009-10-26 06:16:12 +00:00
public override void AddForce ( Vector3 force , bool pushforce )
2007-12-04 04:59:27 +00:00
{
2009-10-26 06:16:12 +00:00
if ( force . IsFinite ( ) )
2008-05-06 00:23:19 +00:00
{
2009-04-07 16:13:17 +00:00
if ( pushforce )
{
m_pidControllerActive = false ;
force * = 100f ;
doForce ( force ) ;
2009-07-16 19:09:03 +00:00
// If uncommented, things get pushed off world
/ /
// m_log.Debug("Push!");
// _target_velocity.X += force.X;
// _target_velocity.Y += force.Y;
// _target_velocity.Z += force.Z;
2009-04-07 16:13:17 +00:00
}
else
{
m_pidControllerActive = true ;
_target_velocity . X + = force . X ;
_target_velocity . Y + = force . Y ;
_target_velocity . Z + = force . Z ;
}
2008-05-06 00:23:19 +00:00
}
2008-05-16 01:22:11 +00:00
else
2008-05-06 00:23:19 +00:00
{
2009-04-07 16:13:17 +00:00
m_log . Warn ( "[PHYSICS]: Got a NaN force applied to a Character" ) ;
2008-05-06 00:23:19 +00:00
}
2007-12-04 04:59:27 +00:00
//m_lastUpdateSent = false;
}
2007-12-27 21:41:48 +00:00
2009-10-26 06:16:12 +00:00
public override void AddAngularForce ( Vector3 force , bool pushforce )
2008-12-14 14:30:28 +00:00
{
}
2008-01-13 07:14:54 +00:00
/// <summary>
/// After all of the forces add up with 'add force' we apply them with doForce
/// </summary>
/// <param name="force"></param>
2009-10-26 06:16:12 +00:00
public void doForce ( Vector3 force )
2007-12-04 04:59:27 +00:00
{
if ( ! collidelock )
{
d . BodyAddForce ( Body , force . X , force . Y , force . Z ) ;
2008-01-18 21:38:47 +00:00
//d.BodySetRotation(Body, ref m_StandUpRotation);
2008-01-23 23:57:54 +00:00
//standupStraight();
2008-05-16 01:22:11 +00:00
2007-12-04 04:59:27 +00:00
}
}
2007-12-27 21:41:48 +00:00
2009-10-26 06:16:12 +00:00
public override void SetMomentum ( Vector3 momentum )
2007-12-04 04:59:27 +00:00
{
}
2008-01-13 07:14:54 +00:00
/// <summary>
/// Called from Simulate
/// This is the avatar's movement control + PID Controller
/// </summary>
/// <param name="timeStep"></param>
2009-06-25 07:39:48 +00:00
public void Move ( float timeStep , List < OdeCharacter > defects )
2007-12-04 04:59:27 +00:00
{
// no lock; for now it's only called from within Simulate()
2008-01-13 07:14:54 +00:00
2008-05-16 01:22:11 +00:00
// If the PID Controller isn't active then we set our force
2008-01-13 07:14:54 +00:00
// calculating base velocity to the current position
2008-05-16 01:22:11 +00:00
2009-01-31 16:49:32 +00:00
if ( Body = = IntPtr . Zero )
return ;
2008-01-27 03:18:10 +00:00
2007-12-15 05:08:08 +00:00
if ( m_pidControllerActive = = false )
{
_zeroPosition = d . BodyGetPosition ( Body ) ;
}
//PidStatus = true;
2008-05-16 01:22:11 +00:00
2009-04-14 01:57:35 +00:00
d . Vector3 localpos = d . BodyGetPosition ( Body ) ;
2009-10-26 06:16:12 +00:00
Vector3 localPos = new Vector3 ( localpos . X , localpos . Y , localpos . Z ) ;
2009-06-25 07:39:48 +00:00
2010-04-30 15:13:02 +00:00
if ( ! localPos . IsFinite ( ) | | localpos . X < 0.0 | | localpos . X > 256.0 | | localpos . Y < 0.0 | | localpos . Y > 256.0 | | localpos . Z < 0.0 )
2009-04-14 01:57:35 +00:00
{
2010-04-30 15:13:02 +00:00
m_log . Warn ( "[PHYSICS]: Avatar Position is non-finite or out of bounds!" ) ;
2009-06-25 07:39:48 +00:00
defects . Add ( this ) ;
// _parent_scene.RemoveCharacter(this);
2009-04-14 01:57:35 +00:00
// destroy avatar capsule and related ODE data
if ( Amotor ! = IntPtr . Zero )
{
// Kill the Amotor
d . JointDestroy ( Amotor ) ;
Amotor = IntPtr . Zero ;
}
2009-06-25 07:39:48 +00:00
2009-04-14 01:57:35 +00:00
//kill the Geometry
_parent_scene . waitForSpaceUnlock ( _parent_scene . space ) ;
if ( Body ! = IntPtr . Zero )
{
//kill the body
d . BodyDestroy ( Body ) ;
Body = IntPtr . Zero ;
}
if ( Shell ! = IntPtr . Zero )
{
d . GeomDestroy ( Shell ) ;
_parent_scene . geom_name_map . Remove ( Shell ) ;
Shell = IntPtr . Zero ;
}
return ;
}
2009-10-26 06:16:12 +00:00
Vector3 vec = Vector3 . Zero ;
2007-12-04 04:59:27 +00:00
d . Vector3 vel = d . BodyGetLinearVel ( Body ) ;
2009-09-18 02:26:52 +00:00
2007-12-04 04:59:27 +00:00
float movementdivisor = 1f ;
if ( ! m_alwaysRun )
{
2008-05-15 23:11:31 +00:00
movementdivisor = walkDivisor ;
2007-12-04 04:59:27 +00:00
}
else
{
2008-05-15 23:11:31 +00:00
movementdivisor = runDivisor ;
2007-12-04 04:59:27 +00:00
}
// if velocity is zero, use position control; otherwise, velocity control
if ( _target_velocity . X = = 0.0f & & _target_velocity . Y = = 0.0f & & _target_velocity . Z = = 0.0f & & m_iscolliding )
{
// keep track of where we stopped. No more slippin' & slidin'
if ( ! _zeroFlag )
{
_zeroFlag = true ;
_zeroPosition = d . BodyGetPosition ( Body ) ;
}
2007-12-15 05:08:08 +00:00
if ( m_pidControllerActive )
2007-12-04 04:59:27 +00:00
{
2008-01-13 07:14:54 +00:00
// We only want to deactivate the PID Controller if we think we want to have our surrogate
// react to the physics scene by moving it's position.
// Avatar to Avatar collisions
// Prim to avatar collisions
2007-12-15 05:08:08 +00:00
d . Vector3 pos = d . BodyGetPosition ( Body ) ;
2008-01-28 03:25:02 +00:00
vec . X = ( _target_velocity . X - vel . X ) * ( PID_D ) + ( _zeroPosition . X - pos . X ) * ( PID_P * 2 ) ;
vec . Y = ( _target_velocity . Y - vel . Y ) * ( PID_D ) + ( _zeroPosition . Y - pos . Y ) * ( PID_P * 2 ) ;
2007-12-15 05:08:08 +00:00
if ( flying )
{
2008-01-27 03:18:10 +00:00
vec . Z = ( _target_velocity . Z - vel . Z ) * ( PID_D ) + ( _zeroPosition . Z - pos . Z ) * PID_P ;
2007-12-15 05:08:08 +00:00
}
2007-12-04 04:59:27 +00:00
}
2007-12-15 05:08:08 +00:00
//PidStatus = true;
2007-12-04 04:59:27 +00:00
}
else
{
2007-12-15 05:08:08 +00:00
m_pidControllerActive = true ;
2007-12-04 04:59:27 +00:00
_zeroFlag = false ;
2008-01-28 03:25:02 +00:00
if ( m_iscolliding & & ! flying )
{
2008-04-06 06:42:54 +00:00
// We're standing on something
2008-01-28 03:25:02 +00:00
vec . X = ( ( _target_velocity . X / movementdivisor ) - vel . X ) * ( PID_D ) ;
vec . Y = ( ( _target_velocity . Y / movementdivisor ) - vel . Y ) * ( PID_D ) ;
}
else if ( m_iscolliding & & flying )
2007-12-04 04:59:27 +00:00
{
2008-01-13 07:14:54 +00:00
// We're flying and colliding with something
2008-01-28 03:25:02 +00:00
vec . X = ( ( _target_velocity . X / movementdivisor ) - vel . X ) * ( PID_D / 16 ) ;
vec . Y = ( ( _target_velocity . Y / movementdivisor ) - vel . Y ) * ( PID_D / 16 ) ;
2007-12-04 04:59:27 +00:00
}
2008-01-28 03:25:02 +00:00
else if ( ! m_iscolliding & & flying )
{
2008-04-06 06:42:54 +00:00
// we're in mid air suspended
2008-01-28 03:25:02 +00:00
vec . X = ( ( _target_velocity . X / movementdivisor ) - vel . X ) * ( PID_D / 6 ) ;
vec . Y = ( ( _target_velocity . Y / movementdivisor ) - vel . Y ) * ( PID_D / 6 ) ;
}
2007-12-04 04:59:27 +00:00
if ( m_iscolliding & & ! flying & & _target_velocity . Z > 0.0f )
{
2008-01-13 07:14:54 +00:00
// We're colliding with something and we're not flying but we're moving
// This means we're walking or running.
2007-12-04 04:59:27 +00:00
d . Vector3 pos = d . BodyGetPosition ( Body ) ;
2007-12-27 21:41:48 +00:00
vec . Z = ( _target_velocity . Z - vel . Z ) * PID_D + ( _zeroPosition . Z - pos . Z ) * PID_P ;
2007-12-04 04:59:27 +00:00
if ( _target_velocity . X > 0 )
{
2007-12-27 21:41:48 +00:00
vec . X = ( ( _target_velocity . X - vel . X ) / 1.2f ) * PID_D ;
2007-12-04 04:59:27 +00:00
}
if ( _target_velocity . Y > 0 )
{
2007-12-27 21:41:48 +00:00
vec . Y = ( ( _target_velocity . Y - vel . Y ) / 1.2f ) * PID_D ;
2007-12-04 04:59:27 +00:00
}
}
else if ( ! m_iscolliding & & ! flying )
{
2008-01-13 07:14:54 +00:00
// we're not colliding and we're not flying so that means we're falling!
// m_iscolliding includes collisions with the ground.
2008-06-27 17:25:03 +00:00
// d.Vector3 pos = d.BodyGetPosition(Body);
2007-12-04 04:59:27 +00:00
if ( _target_velocity . X > 0 )
{
2007-12-27 21:41:48 +00:00
vec . X = ( ( _target_velocity . X - vel . X ) / 1.2f ) * PID_D ;
2007-12-04 04:59:27 +00:00
}
if ( _target_velocity . Y > 0 )
{
2007-12-27 21:41:48 +00:00
vec . Y = ( ( _target_velocity . Y - vel . Y ) / 1.2f ) * PID_D ;
2007-12-04 04:59:27 +00:00
}
}
if ( flying )
{
2008-01-27 03:18:10 +00:00
vec . Z = ( _target_velocity . Z - vel . Z ) * ( PID_D ) ;
2007-12-04 04:59:27 +00:00
}
}
if ( flying )
{
2008-05-15 06:35:01 +00:00
vec . Z + = ( ( - 1 * _parent_scene . gravityz ) * m_mass ) ;
2007-12-04 04:59:27 +00:00
2009-02-12 07:58:10 +00:00
//Added for auto fly height. Kitto Flora
2009-03-07 07:17:43 +00:00
//d.Vector3 pos = d.BodyGetPosition(Body);
float target_altitude = _parent_scene . GetTerrainHeightAtXY ( _position . X , _position . Y ) + MinimumGroundFlightOffset ;
if ( _position . Z < target_altitude )
2009-02-12 07:58:10 +00:00
{
2009-03-07 07:17:43 +00:00
vec . Z + = ( target_altitude - _position . Z ) * PID_P * 5.0f ;
2009-02-12 07:58:10 +00:00
}
// end add Kitto Flora
}
2009-10-26 06:16:12 +00:00
if ( vec . IsFinite ( ) )
2009-04-07 16:13:17 +00:00
{
doForce ( vec ) ;
2009-09-18 02:26:52 +00:00
if ( ! _zeroFlag )
{
2009-10-26 06:16:12 +00:00
AlignAvatarTiltWithCurrentDirectionOfMovement ( vec ) ;
2009-09-18 02:26:52 +00:00
}
2009-04-07 16:13:17 +00:00
}
else
{
m_log . Warn ( "[PHYSICS]: Got a NaN force vector in Move()" ) ;
2009-04-14 01:57:35 +00:00
m_log . Warn ( "[PHYSICS]: Avatar Position is non-finite!" ) ;
2009-06-25 07:39:48 +00:00
defects . Add ( this ) ;
// _parent_scene.RemoveCharacter(this);
2009-04-14 01:57:35 +00:00
// destroy avatar capsule and related ODE data
if ( Amotor ! = IntPtr . Zero )
{
// Kill the Amotor
d . JointDestroy ( Amotor ) ;
Amotor = IntPtr . Zero ;
}
//kill the Geometry
_parent_scene . waitForSpaceUnlock ( _parent_scene . space ) ;
if ( Body ! = IntPtr . Zero )
{
//kill the body
d . BodyDestroy ( Body ) ;
Body = IntPtr . Zero ;
}
if ( Shell ! = IntPtr . Zero )
{
d . GeomDestroy ( Shell ) ;
_parent_scene . geom_name_map . Remove ( Shell ) ;
Shell = IntPtr . Zero ;
}
2009-04-07 16:13:17 +00:00
}
2007-12-04 04:59:27 +00:00
}
2008-01-13 07:14:54 +00:00
/// <summary>
/// Updates the reported position and velocity. This essentially sends the data up to ScenePresence.
/// </summary>
2007-12-04 04:59:27 +00:00
public void UpdatePositionAndVelocity ( )
{
// no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
2009-10-16 07:32:30 +00:00
d . Vector3 vec ;
try
{
vec = d . BodyGetPosition ( Body ) ;
}
catch ( NullReferenceException )
{
2009-10-18 23:48:44 +00:00
bad = true ;
2009-10-16 18:30:55 +00:00
_parent_scene . BadCharacter ( this ) ;
2009-10-16 07:40:44 +00:00
vec = new d . Vector3 ( _position . X , _position . Y , _position . Z ) ;
base . RaiseOutOfBounds ( _position ) ; // Tells ScenePresence that there's a problem!
2009-10-18 23:48:44 +00:00
m_log . WarnFormat ( "[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}" , m_name , m_uuid ) ;
2009-10-16 07:32:30 +00:00
}
2007-12-04 04:59:27 +00:00
// kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!)
if ( vec . X < 0.0f ) vec . X = 0.0f ;
if ( vec . Y < 0.0f ) vec . Y = 0.0f ;
2009-08-18 15:05:07 +00:00
if ( vec . X > ( int ) _parent_scene . WorldExtents . X - 0.05f ) vec . X = ( int ) _parent_scene . WorldExtents . X - 0.05f ;
if ( vec . Y > ( int ) _parent_scene . WorldExtents . Y - 0.05f ) vec . Y = ( int ) _parent_scene . WorldExtents . Y - 0.05f ;
2007-12-04 04:59:27 +00:00
_position . X = vec . X ;
_position . Y = vec . Y ;
_position . Z = vec . Z ;
2008-01-13 07:14:54 +00:00
// Did we move last? = zeroflag
// This helps keep us from sliding all over
2007-12-04 04:59:27 +00:00
if ( _zeroFlag )
{
_velocity . X = 0.0f ;
_velocity . Y = 0.0f ;
_velocity . Z = 0.0f ;
2008-05-16 01:22:11 +00:00
2008-01-13 07:14:54 +00:00
// Did we send out the 'stopped' message?
2007-12-04 04:59:27 +00:00
if ( ! m_lastUpdateSent )
{
m_lastUpdateSent = true ;
2010-12-14 23:31:00 +00:00
// base.RequestPhysicsterseUpdate();
2008-05-16 01:22:11 +00:00
2007-12-04 04:59:27 +00:00
}
}
else
{
m_lastUpdateSent = false ;
2009-10-16 07:32:30 +00:00
try
{
vec = d . BodyGetLinearVel ( Body ) ;
}
catch ( NullReferenceException )
{
vec . X = _velocity . X ;
vec . Y = _velocity . Y ;
vec . Z = _velocity . Z ;
}
2007-12-04 04:59:27 +00:00
_velocity . X = ( vec . X ) ;
_velocity . Y = ( vec . Y ) ;
_velocity . Z = ( vec . Z ) ;
2008-05-16 01:22:11 +00:00
2007-12-04 04:59:27 +00:00
if ( _velocity . Z < - 6 & & ! m_hackSentFall )
{
m_hackSentFall = true ;
2007-12-15 05:08:08 +00:00
m_pidControllerActive = false ;
2007-12-04 04:59:27 +00:00
}
else if ( flying & & ! m_hackSentFly )
{
//m_hackSentFly = true;
//base.SendCollisionUpdate(new CollisionEventUpdate());
}
else
{
m_hackSentFly = false ;
m_hackSentFall = false ;
}
}
2010-12-14 23:31:00 +00:00
if ( ! m_lastUpdateSent )
{
this . RequestPhysicsterseUpdate ( ) ;
}
2007-12-04 04:59:27 +00:00
}
2008-01-13 07:14:54 +00:00
/// <summary>
/// Cleanup the things we use in the scene.
/// </summary>
2007-12-04 04:59:27 +00:00
public void Destroy ( )
{
2009-01-31 16:49:32 +00:00
m_tainted_isPhysical = false ;
_parent_scene . AddPhysicsActorTaint ( this ) ;
2007-12-04 04:59:27 +00:00
}
2008-03-18 05:16:43 +00:00
2008-02-13 23:14:41 +00:00
public override void CrossingFailure ( )
{
}
2009-03-06 23:01:35 +00:00
2009-10-26 06:16:12 +00:00
public override Vector3 PIDTarget { set { return ; } }
2008-03-25 03:36:31 +00:00
public override bool PIDActive { set { return ; } }
public override float PIDTau { set { return ; } }
2009-03-06 23:01:35 +00:00
public override float PIDHoverHeight { set { return ; } }
public override bool PIDHoverActive { set { return ; } }
public override PIDHoverType PIDHoverType { set { return ; } }
public override float PIDHoverTau { set { return ; } }
2009-12-22 00:26:12 +00:00
public override Quaternion APIDTarget { set { return ; } }
public override bool APIDActive { set { return ; } }
public override float APIDStrength { set { return ; } }
public override float APIDDamping { set { return ; } }
2009-03-06 23:01:35 +00:00
2008-05-03 04:33:17 +00:00
public override void SubscribeEvents ( int ms )
{
2009-10-10 07:53:53 +00:00
m_requestedUpdateFrequency = ms ;
2008-05-03 04:33:17 +00:00
m_eventsubscription = ms ;
2008-05-03 15:39:40 +00:00
_parent_scene . addCollisionEventReporting ( this ) ;
2008-05-03 04:33:17 +00:00
}
public override void UnSubscribeEvents ( )
{
2008-05-03 15:39:40 +00:00
_parent_scene . remCollisionEventReporting ( this ) ;
2009-10-10 07:53:53 +00:00
m_requestedUpdateFrequency = 0 ;
2008-05-03 04:33:17 +00:00
m_eventsubscription = 0 ;
}
2009-10-29 08:46:58 +00:00
public void AddCollisionEvent ( uint CollidedWith , ContactPoint contact )
2008-05-03 04:33:17 +00:00
{
if ( m_eventsubscription > 0 )
2009-10-10 07:53:53 +00:00
{
2009-10-29 08:46:58 +00:00
CollisionEventsThisFrame . addCollider ( CollidedWith , contact ) ;
2009-10-10 07:53:53 +00:00
}
2008-05-03 04:33:17 +00:00
}
public void SendCollisions ( )
{
2009-10-10 07:53:53 +00:00
if ( m_eventsubscription > m_requestedUpdateFrequency )
2008-05-03 04:33:17 +00:00
{
2009-12-05 18:01:21 +00:00
if ( CollisionEventsThisFrame ! = null )
{
base . SendCollisionUpdate ( CollisionEventsThisFrame ) ;
}
2008-05-03 04:33:17 +00:00
CollisionEventsThisFrame = new CollisionEventUpdate ( ) ;
2009-10-10 07:53:53 +00:00
m_eventsubscription = 0 ;
2008-05-03 04:33:17 +00:00
}
}
public override bool SubscribedEvents ( )
{
if ( m_eventsubscription > 0 )
return true ;
return false ;
}
2008-12-10 23:46:20 +00:00
public void ProcessTaints ( float timestep )
{
if ( m_tainted_isPhysical ! = m_isPhysical )
{
if ( m_tainted_isPhysical )
{
// Create avatar capsule and related ODE data
if ( ! ( Shell = = IntPtr . Zero & & Body = = IntPtr . Zero & & Amotor = = IntPtr . Zero ) )
{
m_log . Warn ( "[PHYSICS]: re-creating the following avatar ODE data, even though it already exists - "
+ ( Shell ! = IntPtr . Zero ? "Shell " : "" )
+ ( Body ! = IntPtr . Zero ? "Body " : "" )
2009-06-10 04:28:56 +00:00
+ ( Amotor ! = IntPtr . Zero ? "Amotor " : "" ) ) ;
2008-12-10 23:46:20 +00:00
}
AvatarGeomAndBodyCreation ( _position . X , _position . Y , _position . Z , m_tensor ) ;
2009-03-30 14:10:24 +00:00
2008-12-10 23:46:20 +00:00
_parent_scene . geom_name_map [ Shell ] = m_name ;
_parent_scene . actor_name_map [ Shell ] = ( PhysicsActor ) this ;
2009-03-30 14:10:24 +00:00
_parent_scene . AddCharacter ( this ) ;
2008-12-10 23:46:20 +00:00
}
else
{
2009-03-30 14:10:24 +00:00
_parent_scene . RemoveCharacter ( this ) ;
2008-12-10 23:46:20 +00:00
// destroy avatar capsule and related ODE data
2009-04-14 01:57:35 +00:00
if ( Amotor ! = IntPtr . Zero )
{
// Kill the Amotor
d . JointDestroy ( Amotor ) ;
Amotor = IntPtr . Zero ;
}
2008-12-10 23:46:20 +00:00
//kill the Geometry
_parent_scene . waitForSpaceUnlock ( _parent_scene . space ) ;
2009-04-14 01:57:35 +00:00
if ( Body ! = IntPtr . Zero )
{
//kill the body
d . BodyDestroy ( Body ) ;
Body = IntPtr . Zero ;
}
if ( Shell ! = IntPtr . Zero )
{
d . GeomDestroy ( Shell ) ;
_parent_scene . geom_name_map . Remove ( Shell ) ;
Shell = IntPtr . Zero ;
}
2008-12-10 23:46:20 +00:00
}
m_isPhysical = m_tainted_isPhysical ;
}
if ( m_tainted_CAPSULE_LENGTH ! = CAPSULE_LENGTH )
{
if ( Shell ! = IntPtr . Zero & & Body ! = IntPtr . Zero & & Amotor ! = IntPtr . Zero )
{
m_pidControllerActive = true ;
// no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate()
d . JointDestroy ( Amotor ) ;
float prevCapsule = CAPSULE_LENGTH ;
CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH ;
//m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString());
d . BodyDestroy ( Body ) ;
d . GeomDestroy ( Shell ) ;
AvatarGeomAndBodyCreation ( _position . X , _position . Y ,
_position . Z + ( Math . Abs ( CAPSULE_LENGTH - prevCapsule ) * 2 ) , m_tensor ) ;
2009-10-26 06:16:12 +00:00
Velocity = Vector3 . Zero ;
2008-12-10 23:46:20 +00:00
_parent_scene . geom_name_map [ Shell ] = m_name ;
_parent_scene . actor_name_map [ Shell ] = ( PhysicsActor ) this ;
}
else
{
m_log . Warn ( "[PHYSICS]: trying to change capsule size, but the following ODE data is missing - "
+ ( Shell = = IntPtr . Zero ? "Shell " : "" )
+ ( Body = = IntPtr . Zero ? "Body " : "" )
2009-06-10 04:28:56 +00:00
+ ( Amotor = = IntPtr . Zero ? "Amotor " : "" ) ) ;
2008-12-10 23:46:20 +00:00
}
}
2009-01-31 16:49:32 +00:00
2009-10-26 06:16:12 +00:00
if ( ! m_taintPosition . ApproxEquals ( _position , 0.05f ) )
2009-01-31 16:49:32 +00:00
{
if ( Body ! = IntPtr . Zero )
{
d . BodySetPosition ( Body , m_taintPosition . X , m_taintPosition . Y , m_taintPosition . Z ) ;
_position . X = m_taintPosition . X ;
_position . Y = m_taintPosition . Y ;
_position . Z = m_taintPosition . Z ;
}
}
2010-12-14 23:31:00 +00:00
Console . WriteLine ( "ODECharacter: ProcessTaints: doing update" ) ;
this . RequestPhysicsterseUpdate ( ) ;
2008-12-10 23:46:20 +00:00
}
2009-10-10 07:53:53 +00:00
internal void AddCollisionFrameTime ( int p )
{
2009-10-10 08:01:36 +00:00
// protect it from overflow crashing
if ( m_eventsubscription + p > = int . MaxValue )
m_eventsubscription = 0 ;
2009-10-10 07:53:53 +00:00
m_eventsubscription + = p ;
}
2007-12-04 04:59:27 +00:00
}
2008-01-25 16:36:00 +00:00
}