aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs527
1 files changed, 184 insertions, 343 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 25be416..fc18960 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -43,15 +43,10 @@ public sealed class BSCharacter : BSPhysObject
43 private OMV.Vector3 _size; 43 private OMV.Vector3 _size;
44 private bool _grabbed; 44 private bool _grabbed;
45 private bool _selected; 45 private bool _selected;
46 private OMV.Vector3 _position;
47 private float _mass; 46 private float _mass;
48 private float _avatarVolume; 47 private float _avatarVolume;
49 private OMV.Vector3 _force;
50 private OMV.Vector3 _velocity;
51 private OMV.Vector3 _torque;
52 private float _collisionScore; 48 private float _collisionScore;
53 private OMV.Vector3 _acceleration; 49 private OMV.Vector3 _acceleration;
54 private OMV.Quaternion _orientation;
55 private int _physicsActorType; 50 private int _physicsActorType;
56 private bool _isPhysical; 51 private bool _isPhysical;
57 private bool _flying; 52 private bool _flying;
@@ -61,31 +56,26 @@ public sealed class BSCharacter : BSPhysObject
61 private OMV.Vector3 _rotationalVelocity; 56 private OMV.Vector3 _rotationalVelocity;
62 private bool _kinematic; 57 private bool _kinematic;
63 private float _buoyancy; 58 private float _buoyancy;
64 private bool _isStationaryStanding; // true is standing on a stationary object
65 59
66 private BSVMotor _velocityMotor; 60 private BSActorAvatarMove m_moveActor;
61 private const string AvatarMoveActorName = "BSCharacter.AvatarMove";
67 62
68 private OMV.Vector3 _PIDTarget; 63 private OMV.Vector3 _PIDTarget;
69 private bool _usePID; 64 private bool _usePID;
70 private float _PIDTau; 65 private float _PIDTau;
71 private bool _useHoverPID;
72 private float _PIDHoverHeight;
73 private PIDHoverType _PIDHoverType;
74 private float _PIDHoverTao;
75 66
76 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) 67 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
77 : base(parent_scene, localID, avName, "BSCharacter") 68 : base(parent_scene, localID, avName, "BSCharacter")
78 { 69 {
79 _physicsActorType = (int)ActorTypes.Agent; 70 _physicsActorType = (int)ActorTypes.Agent;
80 _position = pos; 71 RawPosition = pos;
81 72
82 _flying = isFlying; 73 _flying = isFlying;
83 _orientation = OMV.Quaternion.Identity; 74 RawOrientation = OMV.Quaternion.Identity;
84 _velocity = OMV.Vector3.Zero; 75 RawVelocity = OMV.Vector3.Zero;
85 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 76 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
86 Friction = BSParam.AvatarStandingFriction; 77 Friction = BSParam.AvatarStandingFriction;
87 Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; 78 Density = BSParam.AvatarDensity;
88 _isStationaryStanding = false;
89 79
90 // Old versions of ScenePresence passed only the height. If width and/or depth are zero, 80 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
91 // replace with the default values. 81 // replace with the default values.
@@ -99,19 +89,26 @@ public sealed class BSCharacter : BSPhysObject
99 // set _avatarVolume and _mass based on capsule size, _density and Scale 89 // set _avatarVolume and _mass based on capsule size, _density and Scale
100 ComputeAvatarVolumeAndMass(); 90 ComputeAvatarVolumeAndMass();
101 91
102 SetupMovementMotor(); 92 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6}",
103 93 LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos);
104 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
105 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
106 94
107 // do actual creation in taint time 95 // do actual creation in taint time
108 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 96 PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate()
109 { 97 {
110 DetailLog("{0},BSCharacter.create,taint", LocalID); 98 DetailLog("{0},BSCharacter.create,taint", LocalID);
111 // New body and shape into PhysBody and PhysShape 99 // New body and shape into PhysBody and PhysShape
112 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); 100 PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this);
101
102 // The avatar's movement is controlled by this motor that speeds up and slows down
103 // the avatar seeking to reach the motor's target speed.
104 // This motor runs as a prestep action for the avatar so it will keep the avatar
105 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
106 m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName);
107 PhysicalActors.Add(AvatarMoveActorName, m_moveActor);
113 108
114 SetPhysicalProperties(); 109 SetPhysicalProperties();
110
111 IsInitialized = true;
115 }); 112 });
116 return; 113 return;
117 } 114 }
@@ -119,219 +116,68 @@ public sealed class BSCharacter : BSPhysObject
119 // called when this character is being destroyed and the resources should be released 116 // called when this character is being destroyed and the resources should be released
120 public override void Destroy() 117 public override void Destroy()
121 { 118 {
119 IsInitialized = false;
120
122 base.Destroy(); 121 base.Destroy();
123 122
124 DetailLog("{0},BSCharacter.Destroy", LocalID); 123 DetailLog("{0},BSCharacter.Destroy", LocalID);
125 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 124 PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate()
126 { 125 {
127 PhysicsScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); 126 PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
128 PhysBody.Clear(); 127 PhysBody.Clear();
129 PhysicsScene.Shapes.DereferenceShape(PhysShape, null /* bodyCallback */); 128 PhysShape.Dereference(PhysScene);
130 PhysShape.Clear(); 129 PhysShape = new BSShapeNull();
131 }); 130 });
132 } 131 }
133 132
134 private void SetPhysicalProperties() 133 private void SetPhysicalProperties()
135 { 134 {
136 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 135 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
137 136
138 ZeroMotion(true); 137 ZeroMotion(true);
139 ForcePosition = _position; 138 ForcePosition = RawPosition;
140 139
141 // Set the velocity 140 // Set the velocity
142 _velocityMotor.Reset(); 141 if (m_moveActor != null)
143 _velocityMotor.SetTarget(_velocity); 142 m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false);
144 _velocityMotor.SetCurrent(_velocity); 143
145 ForceVelocity = _velocity; 144 ForceVelocity = RawVelocity;
146 145
147 // This will enable or disable the flying buoyancy of the avatar. 146 // This will enable or disable the flying buoyancy of the avatar.
148 // Needs to be reset especially when an avatar is recreated after crossing a region boundry. 147 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
149 Flying = _flying; 148 Flying = _flying;
150 149
151 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); 150 PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
152 PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); 151 PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin);
153 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 152 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
154 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 153 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
155 if (BSParam.CcdMotionThreshold > 0f) 154 if (BSParam.CcdMotionThreshold > 0f)
156 { 155 {
157 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 156 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
158 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 157 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
159 } 158 }
160 159
161 UpdatePhysicalMassProperties(RawMass, false); 160 UpdatePhysicalMassProperties(RawMass, false);
162 161
163 // Make so capsule does not fall over 162 // Make so capsule does not fall over
164 PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); 163 PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
164
165 // The avatar mover sets some parameters.
166 PhysicalActors.Refresh();
165 167
166 PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); 168 PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
167 169
168 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); 170 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
169 171
170 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); 172 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
171 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); 173 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
172 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); 174 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
173 175
174 // Do this after the object has been added to the world 176 // Do this after the object has been added to the world
175 PhysBody.collisionType = CollisionType.Avatar; 177 PhysBody.collisionType = CollisionType.Avatar;
176 PhysBody.ApplyCollisionMask(PhysicsScene); 178 PhysBody.ApplyCollisionMask(PhysScene);
177 }
178
179 // The avatar's movement is controlled by this motor that speeds up and slows down
180 // the avatar seeking to reach the motor's target speed.
181 // This motor runs as a prestep action for the avatar so it will keep the avatar
182 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
183 private void SetupMovementMotor()
184 {
185 // Infinite decay and timescale values so motor only changes current to target values.
186 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
187 0.2f, // time scale
188 BSMotor.Infinite, // decay time scale
189 BSMotor.InfiniteVector, // friction timescale
190 1f // efficiency
191 );
192 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
193
194 RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
195 {
196 // TODO: Decide if the step parameters should be changed depending on the avatar's
197 // state (flying, colliding, ...). There is code in ODE to do this.
198
199 // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
200 // specified for the avatar is the one that should be used. For falling, if the avatar
201 // is not flying and is not colliding then it is presumed to be falling and the Z
202 // component is not fooled with (thus allowing gravity to do its thing).
203 // When the avatar is standing, though, the user has specified a velocity of zero and
204 // the avatar should be standing. But if the avatar is pushed by something in the world
205 // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
206 // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
207 // errors can creap in and the avatar will slowly float off in some direction.
208 // So, the problem is that, when an avatar is standing, we cannot tell creaping error
209 // from real pushing.
210 // The code below uses whether the collider is static or moving to decide whether to zero motion.
211
212 _velocityMotor.Step(timeStep);
213 _isStationaryStanding = false;
214
215 // If we're not supposed to be moving, make sure things are zero.
216 if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero)
217 {
218 // The avatar shouldn't be moving
219 _velocityMotor.Zero();
220
221 if (IsColliding)
222 {
223 // If we are colliding with a stationary object, presume we're standing and don't move around
224 if (!ColliderIsMoving)
225 {
226 DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", LocalID);
227 _isStationaryStanding = true;
228 ZeroMotion(true /* inTaintTime */);
229 }
230
231 // Standing has more friction on the ground
232 if (Friction != BSParam.AvatarStandingFriction)
233 {
234 Friction = BSParam.AvatarStandingFriction;
235 PhysicsScene.PE.SetFriction(PhysBody, Friction);
236 }
237 }
238 else
239 {
240 if (Flying)
241 {
242 // Flying and not collising and velocity nearly zero.
243 ZeroMotion(true /* inTaintTime */);
244 }
245 }
246
247 DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding);
248 }
249 else
250 {
251 // Supposed to be moving.
252 OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue;
253
254 if (Friction != BSParam.AvatarFriction)
255 {
256 // Probably starting up walking. Set friction to moving friction.
257 Friction = BSParam.AvatarFriction;
258 PhysicsScene.PE.SetFriction(PhysBody, Friction);
259 }
260
261 // If falling, we keep the world's downward vector no matter what the other axis specify.
262 // The check for _velocity.Z < 0 makes jumping work (temporary upward force).
263 if (!Flying && !IsColliding)
264 {
265 if (_velocity.Z < 0)
266 stepVelocity.Z = _velocity.Z;
267 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
268 }
269
270 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
271 OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass;
272
273 // Should we check for move force being small and forcing velocity to zero?
274
275 // Add special movement force to allow avatars to walk up stepped surfaces.
276 moveForce += WalkUpStairs();
277
278 DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
279 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce);
280 }
281 });
282 } 179 }
283 180
284 // Decide if the character is colliding with a low object and compute a force to pop the
285 // avatar up so it can walk up and over the low objects.
286 private OMV.Vector3 WalkUpStairs()
287 {
288 OMV.Vector3 ret = OMV.Vector3.Zero;
289
290 // This test is done if moving forward, not flying and is colliding with something.
291 // DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}",
292 // LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count);
293 if (IsColliding && !Flying && TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */)
294 {
295 // The range near the character's feet where we will consider stairs
296 float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f;
297 float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
298
299 // Look for a collision point that is near the character's feet and is oriented the same as the charactor is
300 foreach (KeyValuePair<uint, ContactPoint> kvp in CollisionsLastTick.m_objCollisionList)
301 {
302 // Don't care about collisions with the terrain
303 if (kvp.Key > PhysicsScene.TerrainManager.HighestTerrainID)
304 {
305 OMV.Vector3 touchPosition = kvp.Value.Position;
306 // DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
307 // LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
308 if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
309 {
310 // This contact is within the 'near the feet' range.
311 // The normal should be our contact point to the object so it is pointing away
312 // thus the difference between our facing orientation and the normal should be small.
313 OMV.Vector3 directionFacing = OMV.Vector3.UnitX * RawOrientation;
314 OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
315 float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
316 if (diff < BSParam.AvatarStepApproachFactor)
317 {
318 // Found the stairs contact point. Push up a little to raise the character.
319 float upForce = (touchPosition.Z - nearFeetHeightMin) * Mass * BSParam.AvatarStepForceFactor;
320 ret = new OMV.Vector3(0f, 0f, upForce);
321
322 // Also move the avatar up for the new height
323 OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f);
324 ForcePosition = RawPosition + displacement;
325 }
326 DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}",
327 LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret);
328 }
329 }
330 }
331 }
332
333 return ret;
334 }
335 181
336 public override void RequestPhysicsterseUpdate() 182 public override void RequestPhysicsterseUpdate()
337 { 183 {
@@ -348,6 +194,10 @@ public sealed class BSCharacter : BSPhysObject
348 } 194 }
349 195
350 set { 196 set {
197 // This is how much the avatar size is changing. Positive means getting bigger.
198 // The avatar altitude must be adjusted for this change.
199 float heightChange = value.Z - _size.Z;
200
351 _size = value; 201 _size = value;
352 // Old versions of ScenePresence passed only the height. If width and/or depth are zero, 202 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
353 // replace with the default values. 203 // replace with the default values.
@@ -359,14 +209,18 @@ public sealed class BSCharacter : BSPhysObject
359 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 209 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
360 LocalID, _size, Scale, Density, _avatarVolume, RawMass); 210 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
361 211
362 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 212 PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate()
363 { 213 {
364 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) 214 if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape)
365 { 215 {
366 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 216 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
367 UpdatePhysicalMassProperties(RawMass, true); 217 UpdatePhysicalMassProperties(RawMass, true);
218
219 // Adjust the avatar's position to account for the increase/decrease in size
220 ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f);
221
368 // Make sure this change appears as a property update event 222 // Make sure this change appears as a property update event
369 PhysicsScene.PE.PushUpdate(PhysBody); 223 PhysScene.PE.PushUpdate(PhysBody);
370 } 224 }
371 }); 225 });
372 226
@@ -377,11 +231,6 @@ public sealed class BSCharacter : BSPhysObject
377 { 231 {
378 set { BaseShape = value; } 232 set { BaseShape = value; }
379 } 233 }
380 // I want the physics engine to make an avatar capsule
381 public override BSPhysicsShapeType PreferredPhysicalShape
382 {
383 get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
384 }
385 234
386 public override bool Grabbed { 235 public override bool Grabbed {
387 set { _grabbed = value; } 236 set { _grabbed = value; }
@@ -403,29 +252,29 @@ public sealed class BSCharacter : BSPhysObject
403 // Called at taint time! 252 // Called at taint time!
404 public override void ZeroMotion(bool inTaintTime) 253 public override void ZeroMotion(bool inTaintTime)
405 { 254 {
406 _velocity = OMV.Vector3.Zero; 255 RawVelocity = OMV.Vector3.Zero;
407 _acceleration = OMV.Vector3.Zero; 256 _acceleration = OMV.Vector3.Zero;
408 _rotationalVelocity = OMV.Vector3.Zero; 257 _rotationalVelocity = OMV.Vector3.Zero;
409 258
410 // Zero some other properties directly into the physics engine 259 // Zero some other properties directly into the physics engine
411 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 260 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
412 { 261 {
413 if (PhysBody.HasPhysicalBody) 262 if (PhysBody.HasPhysicalBody)
414 PhysicsScene.PE.ClearAllForces(PhysBody); 263 PhysScene.PE.ClearAllForces(PhysBody);
415 }); 264 });
416 } 265 }
417 public override void ZeroAngularMotion(bool inTaintTime) 266 public override void ZeroAngularMotion(bool inTaintTime)
418 { 267 {
419 _rotationalVelocity = OMV.Vector3.Zero; 268 _rotationalVelocity = OMV.Vector3.Zero;
420 269
421 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 270 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
422 { 271 {
423 if (PhysBody.HasPhysicalBody) 272 if (PhysBody.HasPhysicalBody)
424 { 273 {
425 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); 274 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
426 PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); 275 PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
427 // The next also get rid of applied linear force but the linear velocity is untouched. 276 // The next also get rid of applied linear force but the linear velocity is untouched.
428 PhysicsScene.PE.ClearForces(PhysBody); 277 PhysScene.PE.ClearForces(PhysBody);
429 } 278 }
430 }); 279 });
431 } 280 }
@@ -433,38 +282,33 @@ public sealed class BSCharacter : BSPhysObject
433 282
434 public override void LockAngularMotion(OMV.Vector3 axis) { return; } 283 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
435 284
436 public override OMV.Vector3 RawPosition
437 {
438 get { return _position; }
439 set { _position = value; }
440 }
441 public override OMV.Vector3 Position { 285 public override OMV.Vector3 Position {
442 get { 286 get {
443 // Don't refetch the position because this function is called a zillion times 287 // Don't refetch the position because this function is called a zillion times
444 // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); 288 // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
445 return _position; 289 return RawPosition;
446 } 290 }
447 set { 291 set {
448 _position = value; 292 RawPosition = value;
449 293
450 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 294 PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate()
451 { 295 {
452 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 296 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
453 PositionSanityCheck(); 297 PositionSanityCheck();
454 ForcePosition = _position; 298 ForcePosition = RawPosition;
455 }); 299 });
456 } 300 }
457 } 301 }
458 public override OMV.Vector3 ForcePosition { 302 public override OMV.Vector3 ForcePosition {
459 get { 303 get {
460 _position = PhysicsScene.PE.GetPosition(PhysBody); 304 RawPosition = PhysScene.PE.GetPosition(PhysBody);
461 return _position; 305 return RawPosition;
462 } 306 }
463 set { 307 set {
464 _position = value; 308 RawPosition = value;
465 if (PhysBody.HasPhysicalBody) 309 if (PhysBody.HasPhysicalBody)
466 { 310 {
467 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 311 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
468 } 312 }
469 } 313 }
470 } 314 }
@@ -478,30 +322,30 @@ public sealed class BSCharacter : BSPhysObject
478 bool ret = false; 322 bool ret = false;
479 323
480 // TODO: check for out of bounds 324 // TODO: check for out of bounds
481 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) 325 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
482 { 326 {
483 // The character is out of the known/simulated area. 327 // The character is out of the known/simulated area.
484 // Force the avatar position to be within known. ScenePresence will use the position 328 // Force the avatar position to be within known. ScenePresence will use the position
485 // plus the velocity to decide if the avatar is moving out of the region. 329 // plus the velocity to decide if the avatar is moving out of the region.
486 RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); 330 RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
487 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); 331 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
488 return true; 332 return true;
489 } 333 }
490 334
491 // If below the ground, move the avatar up 335 // If below the ground, move the avatar up
492 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); 336 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
493 if (Position.Z < terrainHeight) 337 if (Position.Z < terrainHeight)
494 { 338 {
495 DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight); 339 DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
496 _position.Z = terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters; 340 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters);
497 ret = true; 341 ret = true;
498 } 342 }
499 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 343 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
500 { 344 {
501 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); 345 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
502 if (Position.Z < waterHeight) 346 if (Position.Z < waterHeight)
503 { 347 {
504 _position.Z = waterHeight; 348 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight);
505 ret = true; 349 ret = true;
506 } 350 }
507 } 351 }
@@ -519,10 +363,10 @@ public sealed class BSCharacter : BSPhysObject
519 { 363 {
520 // The new position value must be pushed into the physics engine but we can't 364 // The new position value must be pushed into the physics engine but we can't
521 // just assign to "Position" because of potential call loops. 365 // just assign to "Position" because of potential call loops.
522 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() 366 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate()
523 { 367 {
524 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 368 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
525 ForcePosition = _position; 369 ForcePosition = RawPosition;
526 }); 370 });
527 ret = true; 371 ret = true;
528 } 372 }
@@ -532,25 +376,25 @@ public sealed class BSCharacter : BSPhysObject
532 public override float Mass { get { return _mass; } } 376 public override float Mass { get { return _mass; } }
533 377
534 // used when we only want this prim's mass and not the linkset thing 378 // used when we only want this prim's mass and not the linkset thing
535 public override float RawMass { 379 public override float RawMass {
536 get {return _mass; } 380 get {return _mass; }
537 } 381 }
538 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) 382 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
539 { 383 {
540 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); 384 OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
541 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); 385 PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia);
542 } 386 }
543 387
544 public override OMV.Vector3 Force { 388 public override OMV.Vector3 Force {
545 get { return _force; } 389 get { return RawForce; }
546 set { 390 set {
547 _force = value; 391 RawForce = value;
548 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); 392 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
549 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 393 PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate()
550 { 394 {
551 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 395 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce);
552 if (PhysBody.HasPhysicalBody) 396 if (PhysBody.HasPhysicalBody)
553 PhysicsScene.PE.SetObjectForce(PhysBody, _force); 397 PhysScene.PE.SetObjectForce(PhysBody, RawForce);
554 }); 398 });
555 } 399 }
556 } 400 }
@@ -564,6 +408,7 @@ public sealed class BSCharacter : BSPhysObject
564 408
565 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 409 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
566 public override void SetVolumeDetect(int param) { return; } 410 public override void SetVolumeDetect(int param) { return; }
411 public override bool IsVolumeDetect { get { return false; } }
567 412
568 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } 413 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
569 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } 414 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
@@ -573,61 +418,49 @@ public sealed class BSCharacter : BSPhysObject
573 { 418 {
574 get 419 get
575 { 420 {
576 return m_targetVelocity; 421 return base.m_targetVelocity;
577 } 422 }
578 set 423 set
579 { 424 {
580 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); 425 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
581 m_targetVelocity = value; 426 m_targetVelocity = value;
582 OMV.Vector3 targetVel = value; 427 OMV.Vector3 targetVel = value;
583 if (_setAlwaysRun) 428 if (_setAlwaysRun && !_flying)
584 targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); 429 targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f);
585 430
586 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() 431 if (m_moveActor != null)
587 { 432 m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */);
588 _velocityMotor.Reset();
589 _velocityMotor.SetTarget(targetVel);
590 _velocityMotor.SetCurrent(_velocity);
591 _velocityMotor.Enabled = true;
592 });
593 } 433 }
594 } 434 }
595 public override OMV.Vector3 RawVelocity
596 {
597 get { return _velocity; }
598 set { _velocity = value; }
599 }
600 // Directly setting velocity means this is what the user really wants now. 435 // Directly setting velocity means this is what the user really wants now.
601 public override OMV.Vector3 Velocity { 436 public override OMV.Vector3 Velocity {
602 get { return _velocity; } 437 get { return RawVelocity; }
603 set { 438 set {
604 _velocity = value; 439 RawVelocity = value;
605 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 440 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity);
606 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() 441 PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate()
607 { 442 {
608 _velocityMotor.Reset(); 443 if (m_moveActor != null)
609 _velocityMotor.SetCurrent(_velocity); 444 m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */);
610 _velocityMotor.SetTarget(_velocity);
611 _velocityMotor.Enabled = false;
612 445
613 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 446 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, RawVelocity);
614 ForceVelocity = _velocity; 447 ForceVelocity = RawVelocity;
615 }); 448 });
616 } 449 }
617 } 450 }
618 public override OMV.Vector3 ForceVelocity { 451 public override OMV.Vector3 ForceVelocity {
619 get { return _velocity; } 452 get { return RawVelocity; }
620 set { 453 set {
621 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); 454 PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity");
622 455
623 _velocity = value; 456 RawVelocity = value;
624 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); 457 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
625 PhysicsScene.PE.Activate(PhysBody, true); 458 PhysScene.PE.Activate(PhysBody, true);
626 } 459 }
627 } 460 }
628 public override OMV.Vector3 Torque { 461 public override OMV.Vector3 Torque {
629 get { return _torque; } 462 get { return RawTorque; }
630 set { _torque = value; 463 set { RawTorque = value;
631 } 464 }
632 } 465 }
633 public override float CollisionScore { 466 public override float CollisionScore {
@@ -639,22 +472,27 @@ public sealed class BSCharacter : BSPhysObject
639 get { return _acceleration; } 472 get { return _acceleration; }
640 set { _acceleration = value; } 473 set { _acceleration = value; }
641 } 474 }
642 public override OMV.Quaternion RawOrientation
643 {
644 get { return _orientation; }
645 set { _orientation = value; }
646 }
647 public override OMV.Quaternion Orientation { 475 public override OMV.Quaternion Orientation {
648 get { return _orientation; } 476 get { return RawOrientation; }
649 set { 477 set {
650 // Orientation is set zillions of times when an avatar is walking. It's like 478 // Orientation is set zillions of times when an avatar is walking. It's like
651 // the viewer doesn't trust us. 479 // the viewer doesn't trust us.
652 if (_orientation != value) 480 if (RawOrientation != value)
653 { 481 {
654 _orientation = value; 482 RawOrientation = value;
655 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 483 PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate()
656 { 484 {
657 ForceOrientation = _orientation; 485 // Bullet assumes we know what we are doing when forcing orientation
486 // so it lets us go against all the rules and just compensates for them later.
487 // This forces rotation to be only around the Z axis and doesn't change any of the other axis.
488 // This keeps us from flipping the capsule over which the veiwer does not understand.
489 float oRoll, oPitch, oYaw;
490 RawOrientation.GetEulerAngles(out oRoll, out oPitch, out oYaw);
491 OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw);
492 // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}",
493 // LocalID, RawOrientation, OMV.Vector3.UnitX * RawOrientation,
494 // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation);
495 ForceOrientation = trimmedOrientation;
658 }); 496 });
659 } 497 }
660 } 498 }
@@ -664,16 +502,16 @@ public sealed class BSCharacter : BSPhysObject
664 { 502 {
665 get 503 get
666 { 504 {
667 _orientation = PhysicsScene.PE.GetOrientation(PhysBody); 505 RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
668 return _orientation; 506 return RawOrientation;
669 } 507 }
670 set 508 set
671 { 509 {
672 _orientation = value; 510 RawOrientation = value;
673 if (PhysBody.HasPhysicalBody) 511 if (PhysBody.HasPhysicalBody)
674 { 512 {
675 // _position = PhysicsScene.PE.GetPosition(BSBody); 513 // RawPosition = PhysicsScene.PE.GetPosition(BSBody);
676 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 514 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
677 } 515 }
678 } 516 }
679 } 517 }
@@ -722,14 +560,14 @@ public sealed class BSCharacter : BSPhysObject
722 public override bool FloatOnWater { 560 public override bool FloatOnWater {
723 set { 561 set {
724 _floatOnWater = value; 562 _floatOnWater = value;
725 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 563 PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate()
726 { 564 {
727 if (PhysBody.HasPhysicalBody) 565 if (PhysBody.HasPhysicalBody)
728 { 566 {
729 if (_floatOnWater) 567 if (_floatOnWater)
730 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 568 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
731 else 569 else
732 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 570 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
733 } 571 }
734 }); 572 });
735 } 573 }
@@ -750,7 +588,7 @@ public sealed class BSCharacter : BSPhysObject
750 public override float Buoyancy { 588 public override float Buoyancy {
751 get { return _buoyancy; } 589 get { return _buoyancy; }
752 set { _buoyancy = value; 590 set { _buoyancy = value;
753 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() 591 PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate()
754 { 592 {
755 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 593 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
756 ForceBuoyancy = _buoyancy; 594 ForceBuoyancy = _buoyancy;
@@ -759,8 +597,8 @@ public sealed class BSCharacter : BSPhysObject
759 } 597 }
760 public override float ForceBuoyancy { 598 public override float ForceBuoyancy {
761 get { return _buoyancy; } 599 get { return _buoyancy; }
762 set { 600 set {
763 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); 601 PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
764 602
765 _buoyancy = value; 603 _buoyancy = value;
766 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 604 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
@@ -768,7 +606,7 @@ public sealed class BSCharacter : BSPhysObject
768 float grav = BSParam.Gravity * (1f - _buoyancy); 606 float grav = BSParam.Gravity * (1f - _buoyancy);
769 Gravity = new OMV.Vector3(0f, 0f, grav); 607 Gravity = new OMV.Vector3(0f, 0f, grav);
770 if (PhysBody.HasPhysicalBody) 608 if (PhysBody.HasPhysicalBody)
771 PhysicsScene.PE.SetGravity(PhysBody, Gravity); 609 PhysScene.PE.SetGravity(PhysBody, Gravity);
772 } 610 }
773 } 611 }
774 612
@@ -783,46 +621,25 @@ public sealed class BSCharacter : BSPhysObject
783 set { _PIDTau = value; } 621 set { _PIDTau = value; }
784 } 622 }
785 623
786 // Used for llSetHoverHeight and maybe vehicle height
787 // Hover Height will override MoveTo target's Z
788 public override bool PIDHoverActive {
789 set { _useHoverPID = value; }
790 }
791 public override float PIDHoverHeight {
792 set { _PIDHoverHeight = value; }
793 }
794 public override PIDHoverType PIDHoverType {
795 set { _PIDHoverType = value; }
796 }
797 public override float PIDHoverTau {
798 set { _PIDHoverTao = value; }
799 }
800
801 // For RotLookAt
802 public override OMV.Quaternion APIDTarget { set { return; } }
803 public override bool APIDActive { set { return; } }
804 public override float APIDStrength { set { return; } }
805 public override float APIDDamping { set { return; } }
806
807 public override void AddForce(OMV.Vector3 force, bool pushforce) 624 public override void AddForce(OMV.Vector3 force, bool pushforce)
808 { 625 {
809 // Since this force is being applied in only one step, make this a force per second. 626 // Since this force is being applied in only one step, make this a force per second.
810 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; 627 OMV.Vector3 addForce = force / PhysScene.LastTimeStep;
811 AddForce(addForce, pushforce, false); 628 AddForce(addForce, pushforce, false);
812 } 629 }
813 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 630 public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
814 if (force.IsFinite()) 631 if (force.IsFinite())
815 { 632 {
816 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); 633 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
817 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); 634 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
818 635
819 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() 636 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate()
820 { 637 {
821 // Bullet adds this central force to the total force for this tick 638 // Bullet adds this central force to the total force for this tick
822 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); 639 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
823 if (PhysBody.HasPhysicalBody) 640 if (PhysBody.HasPhysicalBody)
824 { 641 {
825 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); 642 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
826 } 643 }
827 }); 644 });
828 } 645 }
@@ -833,7 +650,7 @@ public sealed class BSCharacter : BSPhysObject
833 } 650 }
834 } 651 }
835 652
836 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 653 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
837 } 654 }
838 public override void SetMomentum(OMV.Vector3 momentum) { 655 public override void SetMomentum(OMV.Vector3 momentum) {
839 } 656 }
@@ -841,14 +658,14 @@ public sealed class BSCharacter : BSPhysObject
841 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) 658 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
842 { 659 {
843 OMV.Vector3 newScale; 660 OMV.Vector3 newScale;
844 661
845 // Bullet's capsule total height is the "passed height + radius * 2"; 662 // Bullet's capsule total height is the "passed height + radius * 2";
846 // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) 663 // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1)
847 // The number we pass in for 'scaling' is the multiplier to get that base 664 // The number we pass in for 'scaling' is the multiplier to get that base
848 // shape to be the size desired. 665 // shape to be the size desired.
849 // So, when creating the scale for the avatar height, we take the passed height 666 // So, when creating the scale for the avatar height, we take the passed height
850 // (size.Z) and remove the caps. 667 // (size.Z) and remove the caps.
851 // Another oddity of the Bullet capsule implementation is that it presumes the Y 668 // An oddity of the Bullet capsule implementation is that it presumes the Y
852 // dimension is the radius of the capsule. Even though some of the code allows 669 // dimension is the radius of the capsule. Even though some of the code allows
853 // for a asymmetrical capsule, other parts of the code presume it is cylindrical. 670 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
854 671
@@ -856,12 +673,36 @@ public sealed class BSCharacter : BSPhysObject
856 newScale.X = size.X / 2f; 673 newScale.X = size.X / 2f;
857 newScale.Y = size.Y / 2f; 674 newScale.Y = size.Y / 2f;
858 675
676 float heightAdjust = BSParam.AvatarHeightMidFudge;
677 if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f)
678 {
679 const float AVATAR_LOW = 1.1f;
680 const float AVATAR_MID = 1.775f; // 1.87f
681 const float AVATAR_HI = 2.45f;
682 // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m.
683 float midHeightOffset = size.Z - AVATAR_MID;
684 if (midHeightOffset < 0f)
685 {
686 // Small avatar. Add the adjustment based on the distance from midheight
687 heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge;
688 }
689 else
690 {
691 // Large avatar. Add the adjustment based on the distance from midheight
692 heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge;
693 }
694 }
859 // The total scale height is the central cylindar plus the caps on the two ends. 695 // The total scale height is the central cylindar plus the caps on the two ends.
860 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f; 696 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f;
697 // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale);
698
861 // If smaller than the endcaps, just fake like we're almost that small 699 // If smaller than the endcaps, just fake like we're almost that small
862 if (newScale.Z < 0) 700 if (newScale.Z < 0)
863 newScale.Z = 0.1f; 701 newScale.Z = 0.1f;
864 702
703 DetailLog("{0},BSCharacter.ComputerAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}",
704 LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale);
705
865 return newScale; 706 return newScale;
866 } 707 }
867 708
@@ -886,18 +727,18 @@ public sealed class BSCharacter : BSPhysObject
886 // the world that things have changed. 727 // the world that things have changed.
887 public override void UpdateProperties(EntityProperties entprop) 728 public override void UpdateProperties(EntityProperties entprop)
888 { 729 {
889 // Don't change position if standing on a stationary object. 730 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
890 if (!_isStationaryStanding) 731 TriggerPreUpdatePropertyAction(ref entprop);
891 _position = entprop.Position;
892 732
893 _orientation = entprop.Rotation; 733 RawPosition = entprop.Position;
734 RawOrientation = entprop.Rotation;
894 735
895 // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar 736 // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
896 // and will send agent updates to the clients if velocity changes by more than 737 // and will send agent updates to the clients if velocity changes by more than
897 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many 738 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
898 // extra updates. 739 // extra updates.
899 if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f)) 740 if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f))
900 _velocity = entprop.Velocity; 741 RawVelocity = entprop.Velocity;
901 742
902 _acceleration = entprop.Acceleration; 743 _acceleration = entprop.Acceleration;
903 _rotationalVelocity = entprop.RotationalVelocity; 744 _rotationalVelocity = entprop.RotationalVelocity;
@@ -905,8 +746,8 @@ public sealed class BSCharacter : BSPhysObject
905 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 746 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
906 if (PositionSanityCheck(true)) 747 if (PositionSanityCheck(true))
907 { 748 {
908 DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position); 749 DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition);
909 entprop.Position = _position; 750 entprop.Position = RawPosition;
910 } 751 }
911 752
912 // remember the current and last set values 753 // remember the current and last set values
@@ -917,10 +758,10 @@ public sealed class BSCharacter : BSPhysObject
917 // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); 758 // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
918 759
919 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 760 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
920 // base.RequestPhysicsterseUpdate(); 761 // PhysScene.PostUpdate(this);
921 762
922 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 763 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
923 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 764 LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity);
924 } 765 }
925} 766}
926} 767}