diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 522 |
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 | } |