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