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