aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs)572
1 files changed, 279 insertions, 293 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs
index 103d8fc..83fc3a6 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/PhysicsModules/BulletS/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 *
@@ -30,9 +30,9 @@ using System.Reflection;
30using log4net; 30using log4net;
31using OMV = OpenMetaverse; 31using OMV = OpenMetaverse;
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager; 33using OpenSim.Region.PhysicsModules.SharedBase;
34 34
35namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.PhysicsModule.BulletS
36{ 36{
37public sealed class BSCharacter : BSPhysObject 37public sealed class BSCharacter : BSPhysObject
38{ 38{
@@ -43,53 +43,52 @@ 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 _avatarDensity;
49 private float _avatarVolume; 47 private float _avatarVolume;
50 private OMV.Vector3 _force;
51 private OMV.Vector3 _velocity;
52 private OMV.Vector3 _torque;
53 private float _collisionScore; 48 private float _collisionScore;
54 private OMV.Vector3 _acceleration; 49 private OMV.Vector3 _acceleration;
55 private OMV.Quaternion _orientation;
56 private int _physicsActorType; 50 private int _physicsActorType;
57 private bool _isPhysical; 51 private bool _isPhysical;
58 private bool _flying; 52 private bool _flying;
59 private bool _setAlwaysRun; 53 private bool _setAlwaysRun;
60 private bool _throttleUpdates; 54 private bool _throttleUpdates;
61 private bool _isColliding;
62 private bool _collidingObj;
63 private bool _floatOnWater; 55 private bool _floatOnWater;
64 private OMV.Vector3 _rotationalVelocity; 56 private OMV.Vector3 _rotationalVelocity;
65 private bool _kinematic; 57 private bool _kinematic;
66 private float _buoyancy; 58 private float _buoyancy;
67 59
68 // The friction and velocity of the avatar is modified depending on whether walking or not. 60 private BSActorAvatarMove m_moveActor;
69 private float _currentFriction; // the friction currently being used (changed by setVelocity). 61 private const string AvatarMoveActorName = "BSCharacter.AvatarMove";
70
71 private BSVMotor _velocityMotor;
72 62
73 private OMV.Vector3 _PIDTarget; 63 private OMV.Vector3 _PIDTarget;
74 private bool _usePID;
75 private float _PIDTau; 64 private float _PIDTau;
76 private bool _useHoverPID;
77 private float _PIDHoverHeight;
78 private PIDHoverType _PIDHoverType;
79 private float _PIDHoverTao;
80 65
81 public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) 66// public override OMV.Vector3 RawVelocity
67// { get { return base.RawVelocity; }
68// set {
69// if (value != base.RawVelocity)
70// Util.PrintCallStack();
71// Console.WriteLine("Set rawvel to {0}", value);
72// base.RawVelocity = value; }
73// }
74
75 // Avatars are always complete (in the physics engine sense)
76 public override bool IsIncomplete { get { return false; } }
77
78 public BSCharacter(
79 uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, bool isFlying)
80
82 : base(parent_scene, localID, avName, "BSCharacter") 81 : base(parent_scene, localID, avName, "BSCharacter")
83 { 82 {
84 _physicsActorType = (int)ActorTypes.Agent; 83 _physicsActorType = (int)ActorTypes.Agent;
85 _position = pos; 84 RawPosition = pos;
86 85
87 _flying = isFlying; 86 _flying = isFlying;
88 _orientation = OMV.Quaternion.Identity; 87 RawOrientation = OMV.Quaternion.Identity;
89 _velocity = OMV.Vector3.Zero; 88 RawVelocity = vel;
90 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 89 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
91 _currentFriction = BSParam.AvatarStandingFriction; 90 Friction = BSParam.AvatarStandingFriction;
92 _avatarDensity = BSParam.AvatarDensity; 91 Density = BSParam.AvatarDensity;
93 92
94 // Old versions of ScenePresence passed only the height. If width and/or depth are zero, 93 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
95 // replace with the default values. 94 // replace with the default values.
@@ -103,19 +102,28 @@ public sealed class BSCharacter : BSPhysObject
103 // set _avatarVolume and _mass based on capsule size, _density and Scale 102 // set _avatarVolume and _mass based on capsule size, _density and Scale
104 ComputeAvatarVolumeAndMass(); 103 ComputeAvatarVolumeAndMass();
105 104
106 SetupMovementMotor(); 105 DetailLog(
107 106 "{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6},vel={7}",
108 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 107 LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos, vel);
109 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
110 108
111 // do actual creation in taint time 109 // do actual creation in taint time
112 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 110 PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate()
113 { 111 {
114 DetailLog("{0},BSCharacter.create,taint", LocalID); 112 DetailLog("{0},BSCharacter.create,taint", LocalID);
113
115 // New body and shape into PhysBody and PhysShape 114 // New body and shape into PhysBody and PhysShape
116 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); 115 PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this);
116
117 // The avatar's movement is controlled by this motor that speeds up and slows down
118 // the avatar seeking to reach the motor's target speed.
119 // This motor runs as a prestep action for the avatar so it will keep the avatar
120 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
121 m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName);
122 PhysicalActors.Add(AvatarMoveActorName, m_moveActor);
117 123
118 SetPhysicalProperties(); 124 SetPhysicalProperties();
125
126 IsInitialized = true;
119 }); 127 });
120 return; 128 return;
121 } 129 }
@@ -123,122 +131,77 @@ public sealed class BSCharacter : BSPhysObject
123 // called when this character is being destroyed and the resources should be released 131 // called when this character is being destroyed and the resources should be released
124 public override void Destroy() 132 public override void Destroy()
125 { 133 {
134 IsInitialized = false;
135
126 base.Destroy(); 136 base.Destroy();
127 137
128 DetailLog("{0},BSCharacter.Destroy", LocalID); 138 DetailLog("{0},BSCharacter.Destroy", LocalID);
129 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 139 PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate()
130 { 140 {
131 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 141 PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */);
132 PhysBody.Clear(); 142 PhysBody.Clear();
133 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 143 PhysShape.Dereference(PhysScene);
134 PhysShape.Clear(); 144 PhysShape = new BSShapeNull();
135 }); 145 });
136 } 146 }
137 147
138 private void SetPhysicalProperties() 148 private void SetPhysicalProperties()
139 { 149 {
140 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); 150 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
151
152 ForcePosition = RawPosition;
141 153
142 ZeroMotion(true); 154 // Set the velocity
143 ForcePosition = _position; 155 if (m_moveActor != null)
156 m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false);
144 157
145 // Set the velocity and compute the proper friction 158 ForceVelocity = RawVelocity;
146 _velocityMotor.Reset(); 159 TargetVelocity = RawVelocity;
147 _velocityMotor.SetTarget(_velocity);
148 _velocityMotor.SetCurrent(_velocity);
149 ForceVelocity = _velocity;
150 160
151 // This will enable or disable the flying buoyancy of the avatar. 161 // This will enable or disable the flying buoyancy of the avatar.
152 // Needs to be reset especially when an avatar is recreated after crossing a region boundry. 162 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
153 Flying = _flying; 163 Flying = _flying;
154 164
155 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); 165 PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
156 PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); 166 PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin);
157 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 167 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
158 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); 168 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
159 if (BSParam.CcdMotionThreshold > 0f) 169 if (BSParam.CcdMotionThreshold > 0f)
160 { 170 {
161 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); 171 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
162 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); 172 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
163 } 173 }
164 174
165 UpdatePhysicalMassProperties(RawMass, false); 175 UpdatePhysicalMassProperties(RawMass, false);
166 176
167 // Make so capsule does not fall over 177 // Make so capsule does not fall over
168 PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); 178 PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
169 179
170 PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); 180 // The avatar mover sets some parameters.
181 PhysicalActors.Refresh();
171 182
172 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); 183 PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
184
185 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
173 186
174 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); 187 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
175 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); 188 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
176 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); 189 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
177 190
178 // Do this after the object has been added to the world 191 // Do this after the object has been added to the world
179 PhysBody.collisionType = CollisionType.Avatar; 192 if (BSParam.AvatarToAvatarCollisionsByDefault)
180 PhysBody.ApplyCollisionMask(PhysicsScene); 193 PhysBody.collisionType = CollisionType.Avatar;
181 } 194 else
182 195 PhysBody.collisionType = CollisionType.PhantomToOthersAvatar;
183 // The avatar's movement is controlled by this motor that speeds up and slows down
184 // the avatar seeking to reach the motor's target speed.
185 // This motor runs as a prestep action for the avatar so it will keep the avatar
186 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
187 private void SetupMovementMotor()
188 {
189
190 // Someday, use a PID motor for asymmetric speed up and slow down
191 // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
192
193 // Infinite decay and timescale values so motor only changes current to target values.
194 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
195 0.2f, // time scale
196 BSMotor.Infinite, // decay time scale
197 BSMotor.InfiniteVector, // friction timescale
198 1f // efficiency
199 );
200 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
201
202 RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
203 {
204 // TODO: Decide if the step parameters should be changed depending on the avatar's
205 // state (flying, colliding, ...). There is code in ODE to do this.
206
207 OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep);
208
209 // If falling, we keep the world's downward vector no matter what the other axis specify.
210 if (!Flying && !IsColliding)
211 {
212 stepVelocity.Z = _velocity.Z;
213 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
214 }
215
216 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
217 OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass / PhysicsScene.LastTimeStep;
218 196
219 /* 197 PhysBody.ApplyCollisionMask(PhysScene);
220 // If moveForce is very small, zero things so we don't keep sending microscopic updates to the user
221 float moveForceMagnitudeSquared = moveForce.LengthSquared();
222 if (moveForceMagnitudeSquared < 0.0001)
223 {
224 DetailLog("{0},BSCharacter.MoveMotor,zeroMovement,stepVel={1},vel={2},mass={3},magSq={4},moveForce={5}",
225 LocalID, stepVelocity, _velocity, Mass, moveForceMagnitudeSquared, moveForce);
226 ForceVelocity = OMV.Vector3.Zero;
227 }
228 else
229 {
230 AddForce(moveForce, false, true);
231 }
232 */
233 // DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
234 AddForce(moveForce, false, true);
235 });
236 } 198 }
237 199
238 public override void RequestPhysicsterseUpdate() 200 public override void RequestPhysicsterseUpdate()
239 { 201 {
240 base.RequestPhysicsterseUpdate(); 202 base.RequestPhysicsterseUpdate();
241 } 203 }
204
242 // No one calls this method so I don't know what it could possibly mean 205 // No one calls this method so I don't know what it could possibly mean
243 public override bool Stopped { get { return false; } } 206 public override bool Stopped { get { return false; } }
244 207
@@ -250,6 +213,10 @@ public sealed class BSCharacter : BSPhysObject
250 } 213 }
251 214
252 set { 215 set {
216 // This is how much the avatar size is changing. Positive means getting bigger.
217 // The avatar altitude must be adjusted for this change.
218 float heightChange = value.Z - _size.Z;
219
253 _size = value; 220 _size = value;
254 // Old versions of ScenePresence passed only the height. If width and/or depth are zero, 221 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
255 // replace with the default values. 222 // replace with the default values.
@@ -259,16 +226,20 @@ public sealed class BSCharacter : BSPhysObject
259 Scale = ComputeAvatarScale(_size); 226 Scale = ComputeAvatarScale(_size);
260 ComputeAvatarVolumeAndMass(); 227 ComputeAvatarVolumeAndMass();
261 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 228 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
262 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 229 LocalID, _size, Scale, Density, _avatarVolume, RawMass);
263 230
264 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 231 PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate()
265 { 232 {
266 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) 233 if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape)
267 { 234 {
268 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); 235 PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale);
269 UpdatePhysicalMassProperties(RawMass, true); 236 UpdatePhysicalMassProperties(RawMass, true);
237
238 // Adjust the avatar's position to account for the increase/decrease in size
239 ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f);
240
270 // Make sure this change appears as a property update event 241 // Make sure this change appears as a property update event
271 PhysicsScene.PE.PushUpdate(PhysBody); 242 PhysScene.PE.PushUpdate(PhysBody);
272 } 243 }
273 }); 244 });
274 245
@@ -279,11 +250,6 @@ public sealed class BSCharacter : BSPhysObject
279 { 250 {
280 set { BaseShape = value; } 251 set { BaseShape = value; }
281 } 252 }
282 // I want the physics engine to make an avatar capsule
283 public override BSPhysicsShapeType PreferredPhysicalShape
284 {
285 get {return BSPhysicsShapeType.SHAPE_CAPSULE; }
286 }
287 253
288 public override bool Grabbed { 254 public override bool Grabbed {
289 set { _grabbed = value; } 255 set { _grabbed = value; }
@@ -291,6 +257,10 @@ public sealed class BSCharacter : BSPhysObject
291 public override bool Selected { 257 public override bool Selected {
292 set { _selected = value; } 258 set { _selected = value; }
293 } 259 }
260 public override bool IsSelected
261 {
262 get { return _selected; }
263 }
294 public override void CrossingFailure() { return; } 264 public override void CrossingFailure() { return; }
295 public override void link(PhysicsActor obj) { return; } 265 public override void link(PhysicsActor obj) { return; }
296 public override void delink() { return; } 266 public override void delink() { return; }
@@ -301,29 +271,30 @@ public sealed class BSCharacter : BSPhysObject
301 // Called at taint time! 271 // Called at taint time!
302 public override void ZeroMotion(bool inTaintTime) 272 public override void ZeroMotion(bool inTaintTime)
303 { 273 {
304 _velocity = OMV.Vector3.Zero; 274 RawVelocity = OMV.Vector3.Zero;
305 _acceleration = OMV.Vector3.Zero; 275 _acceleration = OMV.Vector3.Zero;
306 _rotationalVelocity = OMV.Vector3.Zero; 276 _rotationalVelocity = OMV.Vector3.Zero;
307 277
308 // Zero some other properties directly into the physics engine 278 // Zero some other properties directly into the physics engine
309 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 279 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
310 { 280 {
311 if (PhysBody.HasPhysicalBody) 281 if (PhysBody.HasPhysicalBody)
312 PhysicsScene.PE.ClearAllForces(PhysBody); 282 PhysScene.PE.ClearAllForces(PhysBody);
313 }); 283 });
314 } 284 }
285
315 public override void ZeroAngularMotion(bool inTaintTime) 286 public override void ZeroAngularMotion(bool inTaintTime)
316 { 287 {
317 _rotationalVelocity = OMV.Vector3.Zero; 288 _rotationalVelocity = OMV.Vector3.Zero;
318 289
319 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 290 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate()
320 { 291 {
321 if (PhysBody.HasPhysicalBody) 292 if (PhysBody.HasPhysicalBody)
322 { 293 {
323 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); 294 PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
324 PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); 295 PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
325 // The next also get rid of applied linear force but the linear velocity is untouched. 296 // The next also get rid of applied linear force but the linear velocity is untouched.
326 PhysicsScene.PE.ClearForces(PhysBody); 297 PhysScene.PE.ClearForces(PhysBody);
327 } 298 }
328 }); 299 });
329 } 300 }
@@ -331,38 +302,34 @@ public sealed class BSCharacter : BSPhysObject
331 302
332 public override void LockAngularMotion(OMV.Vector3 axis) { return; } 303 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
333 304
334 public override OMV.Vector3 RawPosition
335 {
336 get { return _position; }
337 set { _position = value; }
338 }
339 public override OMV.Vector3 Position { 305 public override OMV.Vector3 Position {
340 get { 306 get {
341 // Don't refetch the position because this function is called a zillion times 307 // Don't refetch the position because this function is called a zillion times
342 // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); 308 // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
343 return _position; 309 return RawPosition;
344 } 310 }
345 set { 311 set {
346 _position = value; 312 RawPosition = value;
347 PositionSanityCheck();
348 313
349 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 314 PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate()
350 { 315 {
351 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 316 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
352 if (PhysBody.HasPhysicalBody) 317 PositionSanityCheck();
353 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 318 ForcePosition = RawPosition;
354 }); 319 });
355 } 320 }
356 } 321 }
357 public override OMV.Vector3 ForcePosition { 322 public override OMV.Vector3 ForcePosition {
358 get { 323 get {
359 _position = PhysicsScene.PE.GetPosition(PhysBody); 324 RawPosition = PhysScene.PE.GetPosition(PhysBody);
360 return _position; 325 return RawPosition;
361 } 326 }
362 set { 327 set {
363 _position = value; 328 RawPosition = value;
364 PositionSanityCheck(); 329 if (PhysBody.HasPhysicalBody)
365 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 330 {
331 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
332 }
366 } 333 }
367 } 334 }
368 335
@@ -375,28 +342,30 @@ public sealed class BSCharacter : BSPhysObject
375 bool ret = false; 342 bool ret = false;
376 343
377 // TODO: check for out of bounds 344 // TODO: check for out of bounds
378 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) 345 if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
379 { 346 {
380 // The character is out of the known/simulated area. 347 // The character is out of the known/simulated area.
381 // Upper levels of code will handle the transition to other areas so, for 348 // Force the avatar position to be within known. ScenePresence will use the position
382 // the time, we just ignore the position. 349 // plus the velocity to decide if the avatar is moving out of the region.
383 return ret; 350 RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
351 DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
352 return true;
384 } 353 }
385 354
386 // If below the ground, move the avatar up 355 // If below the ground, move the avatar up
387 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 356 float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
388 if (Position.Z < terrainHeight) 357 if (Position.Z < terrainHeight)
389 { 358 {
390 DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 359 DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
391 _position.Z = terrainHeight + 2.0f; 360 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters);
392 ret = true; 361 ret = true;
393 } 362 }
394 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 363 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
395 { 364 {
396 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); 365 float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
397 if (Position.Z < waterHeight) 366 if (Position.Z < waterHeight)
398 { 367 {
399 _position.Z = waterHeight; 368 RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight);
400 ret = true; 369 ret = true;
401 } 370 }
402 } 371 }
@@ -414,11 +383,10 @@ public sealed class BSCharacter : BSPhysObject
414 { 383 {
415 // The new position value must be pushed into the physics engine but we can't 384 // The new position value must be pushed into the physics engine but we can't
416 // just assign to "Position" because of potential call loops. 385 // just assign to "Position" because of potential call loops.
417 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() 386 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate()
418 { 387 {
419 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 388 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
420 if (PhysBody.HasPhysicalBody) 389 ForcePosition = RawPosition;
421 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
422 }); 390 });
423 ret = true; 391 ret = true;
424 } 392 }
@@ -428,25 +396,25 @@ public sealed class BSCharacter : BSPhysObject
428 public override float Mass { get { return _mass; } } 396 public override float Mass { get { return _mass; } }
429 397
430 // used when we only want this prim's mass and not the linkset thing 398 // used when we only want this prim's mass and not the linkset thing
431 public override float RawMass { 399 public override float RawMass {
432 get {return _mass; } 400 get {return _mass; }
433 } 401 }
434 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) 402 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
435 { 403 {
436 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); 404 OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
437 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); 405 PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia);
438 } 406 }
439 407
440 public override OMV.Vector3 Force { 408 public override OMV.Vector3 Force {
441 get { return _force; } 409 get { return RawForce; }
442 set { 410 set {
443 _force = value; 411 RawForce = value;
444 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); 412 // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
445 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 413 PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate()
446 { 414 {
447 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 415 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce);
448 if (PhysBody.HasPhysicalBody) 416 if (PhysBody.HasPhysicalBody)
449 PhysicsScene.PE.SetObjectForce(PhysBody, _force); 417 PhysScene.PE.SetObjectForce(PhysBody, RawForce);
450 }); 418 });
451 } 419 }
452 } 420 }
@@ -460,6 +428,7 @@ public sealed class BSCharacter : BSPhysObject
460 428
461 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 429 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
462 public override void SetVolumeDetect(int param) { return; } 430 public override void SetVolumeDetect(int param) { return; }
431 public override bool IsVolumeDetect { get { return false; } }
463 432
464 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } 433 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
465 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } 434 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
@@ -469,79 +438,59 @@ public sealed class BSCharacter : BSPhysObject
469 { 438 {
470 get 439 get
471 { 440 {
472 return _velocityMotor.TargetValue; 441 return base.m_targetVelocity;
473 } 442 }
474 set 443 set
475 { 444 {
476 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); 445 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
446 m_targetVelocity = value;
477 OMV.Vector3 targetVel = value; 447 OMV.Vector3 targetVel = value;
478 if (_setAlwaysRun) 448 if (_setAlwaysRun && !_flying)
479 targetVel *= BSParam.AvatarAlwaysRunFactor; 449 targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 1f);
480 450
481 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() 451 if (m_moveActor != null)
482 { 452 m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */);
483 _velocityMotor.Reset();
484 _velocityMotor.SetTarget(targetVel);
485 _velocityMotor.SetCurrent(_velocity);
486 _velocityMotor.Enabled = true;
487 });
488 } 453 }
489 } 454 }
490 // Directly setting velocity means this is what the user really wants now. 455 // Directly setting velocity means this is what the user really wants now.
491 public override OMV.Vector3 Velocity { 456 public override OMV.Vector3 Velocity {
492 get { return _velocity; } 457 get { return RawVelocity; }
493 set { 458 set {
494 _velocity = value; 459 RawVelocity = value;
495 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 460 OMV.Vector3 vel = RawVelocity;
496 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() 461
462 DetailLog("{0}: set Velocity = {1}", LocalID, value);
463
464 PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate()
497 { 465 {
498 _velocityMotor.Reset(); 466 if (m_moveActor != null)
499 _velocityMotor.SetCurrent(_velocity); 467 m_moveActor.SetVelocityAndTarget(vel, vel, true /* inTaintTime */);
500 _velocityMotor.SetTarget(_velocity); 468
501 // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar. 469 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, vel);
502 _velocityMotor.Enabled = false; 470 ForceVelocity = vel;
503
504 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
505 ForceVelocity = _velocity;
506 }); 471 });
507 } 472 }
508 } 473 }
474
509 public override OMV.Vector3 ForceVelocity { 475 public override OMV.Vector3 ForceVelocity {
510 get { return _velocity; } 476 get { return RawVelocity; }
511 set { 477 set {
512 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); 478 PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity");
479// Util.PrintCallStack();
480 DetailLog("{0}: set ForceVelocity = {1}", LocalID, value);
513 481
514 _velocity = value; 482 RawVelocity = value;
515 // Depending on whether the avatar is moving or not, change the friction 483 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
516 // to keep the avatar from slipping around 484 PhysScene.PE.Activate(PhysBody, true);
517 if (_velocity.Length() == 0)
518 {
519 if (_currentFriction != BSParam.AvatarStandingFriction)
520 {
521 _currentFriction = BSParam.AvatarStandingFriction;
522 if (PhysBody.HasPhysicalBody)
523 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
524 }
525 }
526 else
527 {
528 if (_currentFriction != BSParam.AvatarFriction)
529 {
530 _currentFriction = BSParam.AvatarFriction;
531 if (PhysBody.HasPhysicalBody)
532 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
533 }
534 }
535
536 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
537 PhysicsScene.PE.Activate(PhysBody, true);
538 } 485 }
539 } 486 }
487
540 public override OMV.Vector3 Torque { 488 public override OMV.Vector3 Torque {
541 get { return _torque; } 489 get { return RawTorque; }
542 set { _torque = value; 490 set { RawTorque = value;
543 } 491 }
544 } 492 }
493
545 public override float CollisionScore { 494 public override float CollisionScore {
546 get { return _collisionScore; } 495 get { return _collisionScore; }
547 set { _collisionScore = value; 496 set { _collisionScore = value;
@@ -551,22 +500,27 @@ public sealed class BSCharacter : BSPhysObject
551 get { return _acceleration; } 500 get { return _acceleration; }
552 set { _acceleration = value; } 501 set { _acceleration = value; }
553 } 502 }
554 public override OMV.Quaternion RawOrientation
555 {
556 get { return _orientation; }
557 set { _orientation = value; }
558 }
559 public override OMV.Quaternion Orientation { 503 public override OMV.Quaternion Orientation {
560 get { return _orientation; } 504 get { return RawOrientation; }
561 set { 505 set {
562 // Orientation is set zillions of times when an avatar is walking. It's like 506 // Orientation is set zillions of times when an avatar is walking. It's like
563 // the viewer doesn't trust us. 507 // the viewer doesn't trust us.
564 if (_orientation != value) 508 if (RawOrientation != value)
565 { 509 {
566 _orientation = value; 510 RawOrientation = value;
567 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 511 PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate()
568 { 512 {
569 ForceOrientation = _orientation; 513 // Bullet assumes we know what we are doing when forcing orientation
514 // so it lets us go against all the rules and just compensates for them later.
515 // This forces rotation to be only around the Z axis and doesn't change any of the other axis.
516 // This keeps us from flipping the capsule over which the veiwer does not understand.
517 float oRoll, oPitch, oYaw;
518 RawOrientation.GetEulerAngles(out oRoll, out oPitch, out oYaw);
519 OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw);
520 // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}",
521 // LocalID, RawOrientation, OMV.Vector3.UnitX * RawOrientation,
522 // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation);
523 ForceOrientation = trimmedOrientation;
570 }); 524 });
571 } 525 }
572 } 526 }
@@ -576,16 +530,16 @@ public sealed class BSCharacter : BSPhysObject
576 { 530 {
577 get 531 get
578 { 532 {
579 _orientation = PhysicsScene.PE.GetOrientation(PhysBody); 533 RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
580 return _orientation; 534 return RawOrientation;
581 } 535 }
582 set 536 set
583 { 537 {
584 _orientation = value; 538 RawOrientation = value;
585 if (PhysBody.HasPhysicalBody) 539 if (PhysBody.HasPhysicalBody)
586 { 540 {
587 // _position = PhysicsScene.PE.GetPosition(BSBody); 541 // RawPosition = PhysicsScene.PE.GetPosition(BSBody);
588 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); 542 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
589 } 543 }
590 } 544 }
591 } 545 }
@@ -605,6 +559,9 @@ public sealed class BSCharacter : BSPhysObject
605 public override bool IsStatic { 559 public override bool IsStatic {
606 get { return false; } 560 get { return false; }
607 } 561 }
562 public override bool IsPhysicallyActive {
563 get { return true; }
564 }
608 public override bool Flying { 565 public override bool Flying {
609 get { return _flying; } 566 get { return _flying; }
610 set { 567 set {
@@ -631,14 +588,14 @@ public sealed class BSCharacter : BSPhysObject
631 public override bool FloatOnWater { 588 public override bool FloatOnWater {
632 set { 589 set {
633 _floatOnWater = value; 590 _floatOnWater = value;
634 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 591 PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate()
635 { 592 {
636 if (PhysBody.HasPhysicalBody) 593 if (PhysBody.HasPhysicalBody)
637 { 594 {
638 if (_floatOnWater) 595 if (_floatOnWater)
639 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 596 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
640 else 597 else
641 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); 598 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
642 } 599 }
643 }); 600 });
644 } 601 }
@@ -659,7 +616,7 @@ public sealed class BSCharacter : BSPhysObject
659 public override float Buoyancy { 616 public override float Buoyancy {
660 get { return _buoyancy; } 617 get { return _buoyancy; }
661 set { _buoyancy = value; 618 set { _buoyancy = value;
662 PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() 619 PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate()
663 { 620 {
664 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 621 DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
665 ForceBuoyancy = _buoyancy; 622 ForceBuoyancy = _buoyancy;
@@ -668,15 +625,16 @@ public sealed class BSCharacter : BSPhysObject
668 } 625 }
669 public override float ForceBuoyancy { 626 public override float ForceBuoyancy {
670 get { return _buoyancy; } 627 get { return _buoyancy; }
671 set { 628 set {
672 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); 629 PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
673 630
674 _buoyancy = value; 631 _buoyancy = value;
675 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 632 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
676 // Buoyancy is faked by changing the gravity applied to the object 633 // Buoyancy is faked by changing the gravity applied to the object
677 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 634 float grav = BSParam.Gravity * (1f - _buoyancy);
635 Gravity = new OMV.Vector3(0f, 0f, grav);
678 if (PhysBody.HasPhysicalBody) 636 if (PhysBody.HasPhysicalBody)
679 PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav)); 637 PhysScene.PE.SetGravity(PhysBody, Gravity);
680 } 638 }
681 } 639 }
682 640
@@ -684,60 +642,32 @@ public sealed class BSCharacter : BSPhysObject
684 public override OMV.Vector3 PIDTarget { 642 public override OMV.Vector3 PIDTarget {
685 set { _PIDTarget = value; } 643 set { _PIDTarget = value; }
686 } 644 }
687 public override bool PIDActive { 645
688 set { _usePID = value; } 646 public override bool PIDActive { get; set; }
689 } 647
690 public override float PIDTau { 648 public override float PIDTau {
691 set { _PIDTau = value; } 649 set { _PIDTau = value; }
692 } 650 }
693 651
694 // Used for llSetHoverHeight and maybe vehicle height
695 // Hover Height will override MoveTo target's Z
696 public override bool PIDHoverActive {
697 set { _useHoverPID = value; }
698 }
699 public override float PIDHoverHeight {
700 set { _PIDHoverHeight = value; }
701 }
702 public override PIDHoverType PIDHoverType {
703 set { _PIDHoverType = value; }
704 }
705 public override float PIDHoverTau {
706 set { _PIDHoverTao = value; }
707 }
708
709 // For RotLookAt
710 public override OMV.Quaternion APIDTarget { set { return; } }
711 public override bool APIDActive { set { return; } }
712 public override float APIDStrength { set { return; } }
713 public override float APIDDamping { set { return; } }
714
715 public override void AddForce(OMV.Vector3 force, bool pushforce) 652 public override void AddForce(OMV.Vector3 force, bool pushforce)
716 { 653 {
717 // Since this force is being applied in only one step, make this a force per second. 654 // Since this force is being applied in only one step, make this a force per second.
718 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; 655 OMV.Vector3 addForce = force / PhysScene.LastTimeStep;
719 AddForce(addForce, pushforce, false); 656 AddForce(addForce, pushforce, false);
720 } 657 }
721 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 658 public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
722 if (force.IsFinite()) 659 if (force.IsFinite())
723 { 660 {
724 float magnitude = force.Length(); 661 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
725 if (magnitude > BSParam.MaxAddForceMagnitude)
726 {
727 // Force has a limit
728 force = force / magnitude * BSParam.MaxAddForceMagnitude;
729 }
730
731 OMV.Vector3 addForce = force;
732 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); 662 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
733 663
734 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() 664 PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate()
735 { 665 {
736 // Bullet adds this central force to the total force for this tick 666 // Bullet adds this central force to the total force for this tick
737 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); 667 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
738 if (PhysBody.HasPhysicalBody) 668 if (PhysBody.HasPhysicalBody)
739 { 669 {
740 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); 670 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
741 } 671 }
742 }); 672 });
743 } 673 }
@@ -748,35 +678,66 @@ public sealed class BSCharacter : BSPhysObject
748 } 678 }
749 } 679 }
750 680
751 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 681 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
752 } 682 }
753 public override void SetMomentum(OMV.Vector3 momentum) { 683 public override void SetMomentum(OMV.Vector3 momentum) {
754 } 684 }
755 685
756 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) 686 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
757 { 687 {
758 OMV.Vector3 newScale; 688 OMV.Vector3 newScale = size;
759 689
760 // Bullet's capsule total height is the "passed height + radius * 2"; 690 // Bullet's capsule total height is the "passed height + radius * 2";
761 // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) 691 // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1)
762 // The number we pass in for 'scaling' is the multiplier to get that base 692 // The number we pass in for 'scaling' is the multiplier to get that base
763 // shape to be the size desired. 693 // shape to be the size desired.
764 // So, when creating the scale for the avatar height, we take the passed height 694 // So, when creating the scale for the avatar height, we take the passed height
765 // (size.Z) and remove the caps. 695 // (size.Z) and remove the caps.
766 // Another oddity of the Bullet capsule implementation is that it presumes the Y 696 // An oddity of the Bullet capsule implementation is that it presumes the Y
767 // dimension is the radius of the capsule. Even though some of the code allows 697 // dimension is the radius of the capsule. Even though some of the code allows
768 // for a asymmetrical capsule, other parts of the code presume it is cylindrical. 698 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
769 699
770 // Scale is multiplier of radius with one of "0.5" 700 // Scale is multiplier of radius with one of "0.5"
771 newScale.X = size.X / 2f;
772 newScale.Y = size.Y / 2f;
773 701
774 // The total scale height is the central cylindar plus the caps on the two ends. 702 float heightAdjust = BSParam.AvatarHeightMidFudge;
775 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f; 703 if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f)
704 {
705 const float AVATAR_LOW = 1.1f;
706 const float AVATAR_MID = 1.775f; // 1.87f
707 const float AVATAR_HI = 2.45f;
708 // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m.
709 float midHeightOffset = size.Z - AVATAR_MID;
710 if (midHeightOffset < 0f)
711 {
712 // Small avatar. Add the adjustment based on the distance from midheight
713 heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge;
714 }
715 else
716 {
717 // Large avatar. Add the adjustment based on the distance from midheight
718 heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge;
719 }
720 }
721 if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule)
722 {
723 newScale.X = size.X / 2f;
724 newScale.Y = size.Y / 2f;
725 // The total scale height is the central cylindar plus the caps on the two ends.
726 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f;
727 }
728 else
729 {
730 newScale.Z = size.Z + heightAdjust;
731 }
732 // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale);
733
776 // If smaller than the endcaps, just fake like we're almost that small 734 // If smaller than the endcaps, just fake like we're almost that small
777 if (newScale.Z < 0) 735 if (newScale.Z < 0)
778 newScale.Z = 0.1f; 736 newScale.Z = 0.1f;
779 737
738 DetailLog("{0},BSCharacter.ComputerAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}",
739 LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale);
740
780 return newScale; 741 return newScale;
781 } 742 }
782 743
@@ -794,34 +755,59 @@ public sealed class BSCharacter : BSPhysObject
794 * Math.Min(Size.X, Size.Y) / 2 755 * Math.Min(Size.X, Size.Y) / 2
795 * Size.Y / 2f // plus the volume of the capsule end caps 756 * Size.Y / 2f // plus the volume of the capsule end caps
796 ); 757 );
797 _mass = _avatarDensity * _avatarVolume; 758 _mass = Density * BSParam.DensityScaleFactor * _avatarVolume;
798 } 759 }
799 760
800 // The physics engine says that properties have updated. Update same and inform 761 // The physics engine says that properties have updated. Update same and inform
801 // the world that things have changed. 762 // the world that things have changed.
802 public override void UpdateProperties(EntityProperties entprop) 763 public override void UpdateProperties(EntityProperties entprop)
803 { 764 {
804 _position = entprop.Position; 765 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
805 _orientation = entprop.Rotation; 766 TriggerPreUpdatePropertyAction(ref entprop);
806 _velocity = entprop.Velocity; 767
768 RawPosition = entprop.Position;
769 RawOrientation = entprop.Rotation;
770
771 // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar
772 // and will send agent updates to the clients if velocity changes by more than
773 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
774 // extra updates.
775 //
776 // XXX: Contrary to the above comment, setting an update threshold here above 0.4 actually introduces jitter to
777 // avatar movement rather than removes it. The larger the threshold, the bigger the jitter.
778 // This is most noticeable in level flight and can be seen with
779 // the "show updates" option in a viewer. With an update threshold, the RawVelocity cycles between a lower
780 // bound and an upper bound, where the difference between the two is enough to trigger a large delta v update
781 // and subsequently trigger an update in ScenePresence.SendTerseUpdateToAllClients(). The cause of this cycle (feedback?)
782 // has not yet been identified.
783 //
784 // If there is a threshold below 0.4 or no threshold check at all (as in ODE), then RawVelocity stays constant and extra
785 // updates are not triggered in ScenePresence.SendTerseUpdateToAllClients().
786// if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f))
787 RawVelocity = entprop.Velocity;
788
807 _acceleration = entprop.Acceleration; 789 _acceleration = entprop.Acceleration;
808 _rotationalVelocity = entprop.RotationalVelocity; 790 _rotationalVelocity = entprop.RotationalVelocity;
809 791
810 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 792 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
811 PositionSanityCheck(true); 793 if (PositionSanityCheck(true))
794 {
795 DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition);
796 entprop.Position = RawPosition;
797 }
812 798
813 // remember the current and last set values 799 // remember the current and last set values
814 LastEntityProperties = CurrentEntityProperties; 800 LastEntityProperties = CurrentEntityProperties;
815 CurrentEntityProperties = entprop; 801 CurrentEntityProperties = entprop;
816 802
817 // Tell the linkset about value changes 803 // Tell the linkset about value changes
818 Linkset.UpdateProperties(this, true); 804 // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
819 805
820 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 806 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
821 // base.RequestPhysicsterseUpdate(); 807 // PhysScene.PostUpdate(this);
822 808
823 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 809 DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
824 LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); 810 LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity);
825 } 811 }
826} 812}
827} 813}