OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
BSCharacter.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyrightD
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 using System;
28 using System.Collections.Generic;
29 using System.Reflection;
30 using log4net;
31 using OMV = OpenMetaverse;
32 using OpenSim.Framework;
33 using OpenSim.Region.PhysicsModules.SharedBase;
34 
35 namespace OpenSim.Region.PhysicsModule.BulletS
36 {
37 public sealed class BSCharacter : BSPhysObject
38 {
39  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40  private static readonly string LogHeader = "[BULLETS CHAR]";
41 
42  // private bool _stopped;
43  private bool _grabbed;
44  private bool _selected;
45  private float _mass;
46  private float _avatarVolume;
47  private float _collisionScore;
48  private OMV.Vector3 _acceleration;
49  private int _physicsActorType;
50  private bool _isPhysical;
51  private bool _flying;
52  private bool _setAlwaysRun;
53  private bool _throttleUpdates;
54  private bool _floatOnWater;
55  private OMV.Vector3 _rotationalVelocity;
56  private bool _kinematic;
57  private float _buoyancy;
58 
59  private OMV.Vector3 _size;
60  private float _footOffset;
61 
62  private BSActorAvatarMove m_moveActor;
63  private const string AvatarMoveActorName = "BSCharacter.AvatarMove";
64 
65  private OMV.Vector3 _PIDTarget;
66  private float _PIDTau;
67 
68 // public override OMV.Vector3 RawVelocity
69 // { get { return base.RawVelocity; }
70 // set {
71 // if (value != base.RawVelocity)
72 // Util.PrintCallStack();
73 // Console.WriteLine("Set rawvel to {0}", value);
74 // base.RawVelocity = value; }
75 // }
76 
77  // Avatars are always complete (in the physics engine sense)
78  public override bool IsIncomplete { get { return false; } }
79 
80  public BSCharacter(
81  uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, float footOffset, bool isFlying)
82 
83  : base(parent_scene, localID, avName, "BSCharacter")
84  {
85  _physicsActorType = (int)ActorTypes.Agent;
86  RawPosition = pos;
87 
88  _flying = isFlying;
89  RawOrientation = OMV.Quaternion.Identity;
90  RawVelocity = vel;
91  _buoyancy = ComputeBuoyancyFromFlying(isFlying);
92  Friction = BSParam.AvatarStandingFriction;
93  Density = BSParam.AvatarDensity;
94  _isPhysical = true;
95 
96  // Adjustments for zero X and Y made in Size()
97  // This also computes avatar scale, volume, and mass
98  SetAvatarSize(size, footOffset, true /* initializing */);
99 
100  DetailLog(
101  "{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6},vel={7}",
102  LocalID, Size, Scale, Density, _avatarVolume, RawMass, pos, vel);
103 
104  // do actual creation in taint time
105  PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate()
106  {
107  DetailLog("{0},BSCharacter.create,taint", LocalID);
108 
109  // New body and shape into PhysBody and PhysShape
110  PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this);
111 
112  // The avatar's movement is controlled by this motor that speeds up and slows down
113  // the avatar seeking to reach the motor's target speed.
114  // This motor runs as a prestep action for the avatar so it will keep the avatar
115  // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
116  m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName);
117  PhysicalActors.Add(AvatarMoveActorName, m_moveActor);
118 
119  SetPhysicalProperties();
120 
121  IsInitialized = true;
122  });
123  return;
124  }
125 
126  // called when this character is being destroyed and the resources should be released
127  public override void Destroy()
128  {
129  IsInitialized = false;
130 
131  base.Destroy();
132 
133  DetailLog("{0},BSCharacter.Destroy", LocalID);
134  PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate()
135  {
136  PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
137  PhysBody.Clear();
138  PhysShape.Dereference(PhysScene);
139  PhysShape = new BSShapeNull();
140  });
141  }
142 
143  private void SetPhysicalProperties()
144  {
145  PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
146 
147  ForcePosition = RawPosition;
148 
149  // Set the velocity
150  if (m_moveActor != null)
151  m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false);
152 
153  ForceVelocity = RawVelocity;
154  TargetVelocity = RawVelocity;
155 
156  // This will enable or disable the flying buoyancy of the avatar.
157  // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
158  Flying = _flying;
159 
160  PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
161  PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin);
162  PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
163  PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
164  if (BSParam.CcdMotionThreshold > 0f)
165  {
166  PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
167  PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
168  }
169 
170  UpdatePhysicalMassProperties(RawMass, false);
171 
172  // Make so capsule does not fall over
173  PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
174 
175  // The avatar mover sets some parameters.
176  PhysicalActors.Refresh();
177 
178  PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
179 
180  PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
181 
182  // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
183  PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
184  PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
185 
186  // Do this after the object has been added to the world
187  if (BSParam.AvatarToAvatarCollisionsByDefault)
188  PhysBody.collisionType = CollisionType.Avatar;
189  else
190  PhysBody.collisionType = CollisionType.PhantomToOthersAvatar;
191 
192  PhysBody.ApplyCollisionMask(PhysScene);
193  }
194 
195  public override void RequestPhysicsterseUpdate()
196  {
197  base.RequestPhysicsterseUpdate();
198  }
199 
200  // No one calls this method so I don't know what it could possibly mean
201  public override bool Stopped { get { return false; } }
202 
203  public override OMV.Vector3 Size {
204  get
205  {
206  return _size;
207  }
208 
209  set {
210  setAvatarSize(value, _footOffset);
211  }
212  }
213 
214  // OpenSim 0.9 introduces a common avatar size computation
215  public override void setAvatarSize(OMV.Vector3 size, float feetOffset)
216  {
217  SetAvatarSize(size, feetOffset, false /* initializing */);
218  }
219 
220  // Internal version that, if initializing, doesn't do all the updating of the physics engine
221  public void SetAvatarSize(OMV.Vector3 size, float feetOffset, bool initializing)
222  {
223  OMV.Vector3 newSize = size;
224  if (newSize.IsFinite())
225  {
226  // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
227  // replace with the default values.
228  if (newSize.X == 0f) newSize.X = BSParam.AvatarCapsuleDepth;
229  if (newSize.Y == 0f) newSize.Y = BSParam.AvatarCapsuleWidth;
230 
231  if (newSize.X < 0.01f) newSize.X = 0.01f;
232  if (newSize.Y < 0.01f) newSize.Y = 0.01f;
233  if (newSize.Z < 0.01f) newSize.Z = BSParam.AvatarCapsuleHeight;
234  }
235  else
236  {
237  newSize = new OMV.Vector3(BSParam.AvatarCapsuleDepth, BSParam.AvatarCapsuleWidth, BSParam.AvatarCapsuleHeight);
238  }
239 
240  // This is how much the avatar size is changing. Positive means getting bigger.
241  // The avatar altitude must be adjusted for this change.
242  float heightChange = newSize.Z - Size.Z;
243 
244  _size = newSize;
245 
246  Scale = ComputeAvatarScale(Size);
247  ComputeAvatarVolumeAndMass();
248  DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
249  LocalID, _size, Scale, Density, _avatarVolume, RawMass);
250 
251  PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate()
252  {
253  if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape)
254  {
255  PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
256  UpdatePhysicalMassProperties(RawMass, true);
257 
258  // Adjust the avatar's position to account for the increase/decrease in size
259  ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f);
260 
261  // Make sure this change appears as a property update event
262  PhysScene.PE.PushUpdate(PhysBody);
263  }
264  });
265  }
266 
267  public override PrimitiveBaseShape Shape
268  {
269  set { BaseShape = value; }
270  }
271 
272  public override bool Grabbed {
273  set { _grabbed = value; }
274  }
275  public override bool Selected {
276  set { _selected = value; }
277  }
278  public override bool IsSelected
279  {
280  get { return _selected; }
281  }
282  public override void CrossingFailure() { return; }
283  public override void link(PhysicsActor obj) { return; }
284  public override void delink() { return; }
285 
286  // Set motion values to zero.
287  // Do it to the properties so the values get set in the physics engine.
288  // Push the setting of the values to the viewer.
289  // Called at taint time!
290  public override void ZeroMotion(bool inTaintTime)
291  {
292  RawVelocity = OMV.Vector3.Zero;
293  _acceleration = OMV.Vector3.Zero;
294  _rotationalVelocity = OMV.Vector3.Zero;
295 
296  // Zero some other properties directly into the physics engine
297  PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
298  {
299  if (PhysBody.HasPhysicalBody)
300  PhysScene.PE.ClearAllForces(PhysBody);
301  });
302  }
303 
304  public override void ZeroAngularMotion(bool inTaintTime)
305  {
306  _rotationalVelocity = OMV.Vector3.Zero;
307 
308  PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
309  {
310  if (PhysBody.HasPhysicalBody)
311  {
312  PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
313  PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
314  // The next also get rid of applied linear force but the linear velocity is untouched.
315  PhysScene.PE.ClearForces(PhysBody);
316  }
317  });
318  }
319 
320 
321  public override void LockAngularMotion(byte axislocks) { return; }
322 
323  public override OMV.Vector3 Position {
324  get {
325  // Don't refetch the position because this function is called a zillion times
326  // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
327  return RawPosition;
328  }
329  set {
330  RawPosition = value;
331 
332  PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate()
333  {
334  DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
335  PositionSanityCheck();
336  ForcePosition = RawPosition;
337  });
338  }
339  }
340  public override OMV.Vector3 ForcePosition {
341  get {
342  RawPosition = PhysScene.PE.GetPosition(PhysBody);
343  return RawPosition;
344  }
345  set {
346  RawPosition = value;
347  if (PhysBody.HasPhysicalBody)
348  {
349  PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
350  }
351  }
352  }
353 
354 
355  // Check that the current position is sane and, if not, modify the position to make it so.
356  // Check for being below terrain or on water.
357  // Returns 'true' of the position was made sane by some action.
358  private bool PositionSanityCheck()
359  {
360  bool ret = false;
361 
362  // TODO: check for out of bounds
363  if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
364  {
365  // The character is out of the known/simulated area.
366  // Force the avatar position to be within known. ScenePresence will use the position
367  // plus the velocity to decide if the avatar is moving out of the region.
368  RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
369  DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
370  return true;
371  }
372 
373  // If below the ground, move the avatar up
374  float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
375  if (Position.Z < terrainHeight)
376  {
377  DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
378  RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters);
379  ret = true;
380  }
381  if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
382  {
383  float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
384  if (Position.Z < waterHeight)
385  {
386  RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight);
387  ret = true;
388  }
389  }
390 
391  return ret;
392  }
393 
394  // A version of the sanity check that also makes sure a new position value is
395  // pushed back to the physics engine. This routine would be used by anyone
396  // who is not already pushing the value.
397  private bool PositionSanityCheck(bool inTaintTime)
398  {
399  bool ret = false;
400  if (PositionSanityCheck())
401  {
402  // The new position value must be pushed into the physics engine but we can't
403  // just assign to "Position" because of potential call loops.
404  PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate()
405  {
406  DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
407  ForcePosition = RawPosition;
408  });
409  ret = true;
410  }
411  return ret;
412  }
413 
414  public override float Mass { get { return _mass; } }
415 
416  // used when we only want this prim's mass and not the linkset thing
417  public override float RawMass {
418  get {return _mass; }
419  }
420  public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
421  {
422  OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
423  PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia);
424  }
425 
426  public override OMV.Vector3 Force {
427  get { return RawForce; }
428  set {
429  RawForce = value;
430  // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
431  PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate()
432  {
433  DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce);
434  if (PhysBody.HasPhysicalBody)
435  PhysScene.PE.SetObjectForce(PhysBody, RawForce);
436  });
437  }
438  }
439 
440  // Avatars don't do vehicles
441  public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } }
442  public override void VehicleFloatParam(int param, float value) { }
443  public override void VehicleVectorParam(int param, OMV.Vector3 value) {}
444  public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { }
445  public override void VehicleFlags(int param, bool remove) { }
446 
447  // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
448  public override void SetVolumeDetect(int param) { return; }
449  public override bool IsVolumeDetect { get { return false; } }
450 
451  public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
452  public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
453 
454  // Sets the target in the motor. This starts the changing of the avatar's velocity.
455  public override OMV.Vector3 TargetVelocity
456  {
457  get
458  {
459  return base.m_targetVelocity;
460  }
461  set
462  {
463  DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
464  m_targetVelocity = value;
465  OMV.Vector3 targetVel = value;
466  if (_setAlwaysRun && !_flying)
467  targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 1f);
468 
469  if (m_moveActor != null)
470  m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */);
471  }
472  }
473  // Directly setting velocity means this is what the user really wants now.
474  public override OMV.Vector3 Velocity {
475  get { return RawVelocity; }
476  set {
477  RawVelocity = value;
478  OMV.Vector3 vel = RawVelocity;
479 
480  DetailLog("{0}: set Velocity = {1}", LocalID, value);
481 
482  PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate()
483  {
484  if (m_moveActor != null)
485  m_moveActor.SetVelocityAndTarget(vel, vel, true /* inTaintTime */);
486 
487  DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, vel);
488  ForceVelocity = vel;
489  });
490  }
491  }
492 
493  public override OMV.Vector3 ForceVelocity {
494  get { return RawVelocity; }
495  set {
496  PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity");
497 // Util.PrintCallStack();
498  DetailLog("{0}: set ForceVelocity = {1}", LocalID, value);
499 
500  RawVelocity = value;
501  PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
502  PhysScene.PE.Activate(PhysBody, true);
503  }
504  }
505 
506  public override OMV.Vector3 Torque {
507  get { return RawTorque; }
508  set { RawTorque = value;
509  }
510  }
511 
512  public override float CollisionScore {
513  get { return _collisionScore; }
514  set { _collisionScore = value;
515  }
516  }
517  public override OMV.Vector3 Acceleration {
518  get { return _acceleration; }
519  set { _acceleration = value; }
520  }
521  public override OMV.Quaternion Orientation {
522  get { return RawOrientation; }
523  set {
524  // Orientation is set zillions of times when an avatar is walking. It's like
525  // the viewer doesn't trust us.
526  if (RawOrientation != value)
527  {
528  RawOrientation = value;
529  PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate()
530  {
531  // Bullet assumes we know what we are doing when forcing orientation
532  // so it lets us go against all the rules and just compensates for them later.
533  // This forces rotation to be only around the Z axis and doesn't change any of the other axis.
534  // This keeps us from flipping the capsule over which the veiwer does not understand.
535  float oRoll, oPitch, oYaw;
536  RawOrientation.GetEulerAngles(out oRoll, out oPitch, out oYaw);
537  OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw);
538  // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}",
539  // LocalID, RawOrientation, OMV.Vector3.UnitX * RawOrientation,
540  // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation);
541  ForceOrientation = trimmedOrientation;
542  });
543  }
544  }
545  }
546  // Go directly to Bullet to get/set the value.
547  public override OMV.Quaternion ForceOrientation
548  {
549  get
550  {
551  RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
552  return RawOrientation;
553  }
554  set
555  {
556  RawOrientation = value;
557  if (PhysBody.HasPhysicalBody)
558  {
559  // RawPosition = PhysicsScene.PE.GetPosition(BSBody);
560  PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
561  }
562  }
563  }
564  public override int PhysicsActorType {
565  get { return _physicsActorType; }
566  set { _physicsActorType = value;
567  }
568  }
569  public override bool IsPhysical {
570  get { return _isPhysical; }
571  set { _isPhysical = value;
572  }
573  }
574  public override bool IsSolid {
575  get { return true; }
576  }
577  public override bool IsStatic {
578  get { return false; }
579  }
580  public override bool IsPhysicallyActive {
581  get { return true; }
582  }
583  public override bool Flying {
584  get { return _flying; }
585  set {
586  _flying = value;
587 
588  // simulate flying by changing the effect of gravity
589  Buoyancy = ComputeBuoyancyFromFlying(_flying);
590  }
591  }
592  // Flying is implimented by changing the avatar's buoyancy.
593  // Would this be done better with a vehicle type?
594  private float ComputeBuoyancyFromFlying(bool ifFlying) {
595  return ifFlying ? 1f : 0f;
596  }
597  public override bool
599  get { return _setAlwaysRun; }
600  set { _setAlwaysRun = value; }
601  }
602  public override bool ThrottleUpdates {
603  get { return _throttleUpdates; }
604  set { _throttleUpdates = value; }
605  }
606  public override bool FloatOnWater {
607  set {
608  _floatOnWater = value;
609  PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate()
610  {
611  if (PhysBody.HasPhysicalBody)
612  {
613  if (_floatOnWater)
614  CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
615  else
616  CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
617  }
618  });
619  }
620  }
621  public override OMV.Vector3 RotationalVelocity {
622  get { return _rotationalVelocity; }
623  set { _rotationalVelocity = value; }
624  }
625  public override OMV.Vector3 ForceRotationalVelocity {
626  get { return _rotationalVelocity; }
627  set { _rotationalVelocity = value; }
628  }
629  public override bool Kinematic {
630  get { return _kinematic; }
631  set { _kinematic = value; }
632  }
633  // neg=fall quickly, 0=1g, 1=0g, pos=float up
634  public override float Buoyancy {
635  get { return _buoyancy; }
636  set { _buoyancy = value;
637  PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate()
638  {
639  DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
640  ForceBuoyancy = _buoyancy;
641  });
642  }
643  }
644  public override float ForceBuoyancy {
645  get { return _buoyancy; }
646  set {
647  PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
648 
649  _buoyancy = value;
650  DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
651  // Buoyancy is faked by changing the gravity applied to the object
652  float grav = BSParam.Gravity * (1f - _buoyancy);
653  Gravity = new OMV.Vector3(0f, 0f, grav);
654  if (PhysBody.HasPhysicalBody)
655  PhysScene.PE.SetGravity(PhysBody, Gravity);
656  }
657  }
658 
659  // Used for MoveTo
660  public override OMV.Vector3 PIDTarget {
661  set { _PIDTarget = value; }
662  }
663 
664  public override bool PIDActive { get; set; }
665 
666  public override float PIDTau {
667  set { _PIDTau = value; }
668  }
669 
670  public override void AddForce(OMV.Vector3 force, bool pushforce)
671  {
672  // Since this force is being applied in only one step, make this a force per second.
673  OMV.Vector3 addForce = force;
674 
675  // The interaction of this force with the simulator rate and collision occurance is tricky.
676  // ODE multiplies the force by 100
677  // ubODE multiplies the force by 5.3
678  // BulletSim, after much in-world testing, thinks it gets a similar effect by multiplying mass*0.315f
679  // This number could be a feature of friction or timing, but it seems to move avatars the same as ubODE
680  addForce *= Mass * BSParam.AvatarAddForcePushFactor;
681 
682  DetailLog("{0},BSCharacter.addForce,call,force={1},addForce={2},push={3},mass={4}", LocalID, force, addForce, pushforce, Mass);
683  AddForce(false, addForce);
684  }
685 
686  public override void AddForce(bool inTaintTime, OMV.Vector3 force) {
687  if (force.IsFinite())
688  {
689  OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
690  // DetailLog("{0},BSCharacter.addForce,call,force={1},push={2},inTaint={3}", LocalID, addForce, pushforce, inTaintTime);
691 
692  PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate()
693  {
694  // Bullet adds this central force to the total force for this tick
695  // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
696  if (PhysBody.HasPhysicalBody)
697  {
698  // Bullet adds this central force to the total force for this tick.
699  // Deep down in Bullet:
700  // linearVelocity += totalForce / mass * timeStep;
701  PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
702  PhysScene.PE.Activate(PhysBody, true);
703  }
704  if (m_moveActor != null)
705  {
706  m_moveActor.SuppressStationayCheckUntilLowVelocity();
707  }
708  });
709  }
710  else
711  {
712  m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID);
713  return;
714  }
715  }
716 
717  public override void AddAngularForce(bool inTaintTime, OMV.Vector3 force) {
718  }
719  public override void SetMomentum(OMV.Vector3 momentum) {
720  }
721 
722  // The avatar's physical shape (whether capsule or cube) is unit sized. BulletSim sets
723  // the scale of that unit shape to create the avatars full size.
724  private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
725  {
726  OMV.Vector3 newScale = size;
727 
728  if (BSParam.AvatarUseBefore09SizeComputation)
729  {
730 
731  // Bullet's capsule total height is the "passed height + radius * 2";
732  // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1)
733  // The number we pass in for 'scaling' is the multiplier to get that base
734  // shape to be the size desired.
735  // So, when creating the scale for the avatar height, we take the passed height
736  // (size.Z) and remove the caps.
737  // An oddity of the Bullet capsule implementation is that it presumes the Y
738  // dimension is the radius of the capsule. Even though some of the code allows
739  // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
740 
741  // Scale is multiplier of radius with one of "0.5"
742 
743  float heightAdjust = BSParam.AvatarHeightMidFudge;
744  if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f)
745  {
746  const float AVATAR_LOW = 1.1f;
747  const float AVATAR_MID = 1.775f; // 1.87f
748  const float AVATAR_HI = 2.45f;
749  // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m.
750  float midHeightOffset = size.Z - AVATAR_MID;
751  if (midHeightOffset < 0f)
752  {
753  // Small avatar. Add the adjustment based on the distance from midheight
754  heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge;
755  }
756  else
757  {
758  // Large avatar. Add the adjustment based on the distance from midheight
759  heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge;
760  }
761  }
762  if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule)
763  {
764  newScale.X = size.X / 2f;
765  newScale.Y = size.Y / 2f;
766  // The total scale height is the central cylindar plus the caps on the two ends.
767  newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f;
768  }
769  else
770  {
771  newScale.Z = size.Z + heightAdjust;
772  }
773  // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale);
774 
775  // If smaller than the endcaps, just fake like we're almost that small
776  if (newScale.Z < 0)
777  newScale.Z = 0.1f;
778 
779  DetailLog("{0},BSCharacter.ComputeAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}",
780  LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale);
781  }
782  else
783  {
784  newScale.Z = size.Z + _footOffset;
785  DetailLog("{0},BSCharacter.ComputeAvatarScale,using newScale={1}, footOffset={2}", LocalID, newScale, _footOffset);
786  }
787 
788  return newScale;
789  }
790 
791  // set _avatarVolume and _mass based on capsule size, _density and Scale
792  private void ComputeAvatarVolumeAndMass()
793  {
794  if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule)
795  {
796  _avatarVolume = (float)(
797  Math.PI
798  * Size.X / 2f
799  * Size.Y / 2f // the area of capsule cylinder
800  * Size.Z // times height of capsule cylinder
801  + 1.33333333f
802  * Math.PI
803  * Size.X / 2f
804  * Math.Min(Size.X, Size.Y) / 2
805  * Size.Y / 2f // plus the volume of the capsule end caps
806  );
807  }
808  else
809  {
810  _avatarVolume = Size.X * Size.Y * Size.Z;
811  }
812  _mass = Density * BSParam.DensityScaleFactor * _avatarVolume;
813  }
814 
815  // The physics engine says that properties have updated. Update same and inform
816  // the world that things have changed.
817  public override void UpdateProperties(EntityProperties entprop)
818  {
819  // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
820  TriggerPreUpdatePropertyAction(ref entprop);
821 
822  RawPosition = entprop.Position;
823  RawOrientation = entprop.Rotation;
824 
825  // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
826  // and will send agent updates to the clients if velocity changes by more than
827  // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
828  // extra updates.
829  //
830  // XXX: Contrary to the above comment, setting an update threshold here above 0.4 actually introduces jitter to
831  // avatar movement rather than removes it. The larger the threshold, the bigger the jitter.
832  // This is most noticeable in level flight and can be seen with
833  // the "show updates" option in a viewer. With an update threshold, the RawVelocity cycles between a lower
834  // bound and an upper bound, where the difference between the two is enough to trigger a large delta v update
835  // and subsequently trigger an update in ScenePresence.SendTerseUpdateToAllClients(). The cause of this cycle (feedback?)
836  // has not yet been identified.
837  //
838  // If there is a threshold below 0.4 or no threshold check at all (as in ODE), then RawVelocity stays constant and extra
839  // updates are not triggered in ScenePresence.SendTerseUpdateToAllClients().
840 // if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f))
841  RawVelocity = entprop.Velocity;
842 
843  _acceleration = entprop.Acceleration;
844  _rotationalVelocity = entprop.RotationalVelocity;
845 
846  // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
847  if (PositionSanityCheck(true))
848  {
849  DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition);
850  entprop.Position = RawPosition;
851  }
852 
853  // remember the current and last set values
854  LastEntityProperties = CurrentEntityProperties;
855  CurrentEntityProperties = entprop;
856 
857  // Tell the linkset about value changes
858  // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
859 
860  // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
861  // PhysScene.PostUpdate(this);
862 
863  DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
864  LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity);
865  }
866 }
867 }
OpenMetaverse OMV
override void UpdateProperties(EntityProperties entprop)
Definition: BSCharacter.cs:817
delegate void SetAlwaysRun(IClientAPI remoteClient, bool SetAlwaysRun)
override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
Definition: BSCharacter.cs:420
override void AddForce(OMV.Vector3 force, bool pushforce)
Definition: BSCharacter.cs:670
override void VehicleFloatParam(int param, float value)
Definition: BSCharacter.cs:442
override void setAvatarSize(OMV.Vector3 size, float feetOffset)
Definition: BSCharacter.cs:215
override void AddForce(bool inTaintTime, OMV.Vector3 force)
Definition: BSCharacter.cs:686
OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion rotation
Definition: ICM_Api.cs:32
override void SetVolumeDetect(int param)
Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more ...
Definition: BSCharacter.cs:448
BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, float footOffset, bool isFlying)
Definition: BSCharacter.cs:80
override void ZeroAngularMotion(bool inTaintTime)
Definition: BSCharacter.cs:304
override void ZeroMotion(bool inTaintTime)
Definition: BSCharacter.cs:290
override void LockAngularMotion(byte axislocks)
Definition: BSCharacter.cs:321
override void SetMomentum(OMV.Vector3 momentum)
Definition: BSCharacter.cs:719
override void VehicleFlags(int param, bool remove)
Definition: BSCharacter.cs:445
override void AddAngularForce(bool inTaintTime, OMV.Vector3 force)
Definition: BSCharacter.cs:717
override void link(PhysicsActor obj)
Definition: BSCharacter.cs:283
void SetAvatarSize(OMV.Vector3 size, float feetOffset, bool initializing)
Definition: BSCharacter.cs:221
override void VehicleVectorParam(int param, OMV.Vector3 value)
Definition: BSCharacter.cs:443
override void VehicleRotationParam(int param, OMV.Quaternion rotation)
Definition: BSCharacter.cs:444