diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 827 |
1 files changed, 0 insertions, 827 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs deleted file mode 100644 index 103d8fc..0000000 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ /dev/null | |||
@@ -1,827 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Reflection; | ||
30 | using log4net; | ||
31 | using OMV = OpenMetaverse; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Physics.Manager; | ||
34 | |||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
36 | { | ||
37 | public sealed class BSCharacter : BSPhysObject | ||
38 | { | ||
39 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
40 | private static readonly string LogHeader = "[BULLETS CHAR]"; | ||
41 | |||
42 | // private bool _stopped; | ||
43 | private OMV.Vector3 _size; | ||
44 | private bool _grabbed; | ||
45 | private bool _selected; | ||
46 | private OMV.Vector3 _position; | ||
47 | private float _mass; | ||
48 | private float _avatarDensity; | ||
49 | private float _avatarVolume; | ||
50 | private OMV.Vector3 _force; | ||
51 | private OMV.Vector3 _velocity; | ||
52 | private OMV.Vector3 _torque; | ||
53 | private float _collisionScore; | ||
54 | private OMV.Vector3 _acceleration; | ||
55 | private OMV.Quaternion _orientation; | ||
56 | private int _physicsActorType; | ||
57 | private bool _isPhysical; | ||
58 | private bool _flying; | ||
59 | private bool _setAlwaysRun; | ||
60 | private bool _throttleUpdates; | ||
61 | private bool _isColliding; | ||
62 | private bool _collidingObj; | ||
63 | private bool _floatOnWater; | ||
64 | private OMV.Vector3 _rotationalVelocity; | ||
65 | private bool _kinematic; | ||
66 | private float _buoyancy; | ||
67 | |||
68 | // The friction and velocity of the avatar is modified depending on whether walking or not. | ||
69 | private float _currentFriction; // the friction currently being used (changed by setVelocity). | ||
70 | |||
71 | private BSVMotor _velocityMotor; | ||
72 | |||
73 | private OMV.Vector3 _PIDTarget; | ||
74 | private bool _usePID; | ||
75 | private float _PIDTau; | ||
76 | private bool _useHoverPID; | ||
77 | private float _PIDHoverHeight; | ||
78 | private PIDHoverType _PIDHoverType; | ||
79 | private float _PIDHoverTao; | ||
80 | |||
81 | public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) | ||
82 | : base(parent_scene, localID, avName, "BSCharacter") | ||
83 | { | ||
84 | _physicsActorType = (int)ActorTypes.Agent; | ||
85 | _position = pos; | ||
86 | |||
87 | _flying = isFlying; | ||
88 | _orientation = OMV.Quaternion.Identity; | ||
89 | _velocity = OMV.Vector3.Zero; | ||
90 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); | ||
91 | _currentFriction = BSParam.AvatarStandingFriction; | ||
92 | _avatarDensity = BSParam.AvatarDensity; | ||
93 | |||
94 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||
95 | // replace with the default values. | ||
96 | _size = size; | ||
97 | if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; | ||
98 | if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; | ||
99 | |||
100 | // The dimensions of the physical capsule are kept in the scale. | ||
101 | // Physics creates a unit capsule which is scaled by the physics engine. | ||
102 | Scale = ComputeAvatarScale(_size); | ||
103 | // set _avatarVolume and _mass based on capsule size, _density and Scale | ||
104 | ComputeAvatarVolumeAndMass(); | ||
105 | |||
106 | SetupMovementMotor(); | ||
107 | |||
108 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | ||
109 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | ||
110 | |||
111 | // do actual creation in taint time | ||
112 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | ||
113 | { | ||
114 | DetailLog("{0},BSCharacter.create,taint", LocalID); | ||
115 | // New body and shape into PhysBody and PhysShape | ||
116 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); | ||
117 | |||
118 | SetPhysicalProperties(); | ||
119 | }); | ||
120 | return; | ||
121 | } | ||
122 | |||
123 | // called when this character is being destroyed and the resources should be released | ||
124 | public override void Destroy() | ||
125 | { | ||
126 | base.Destroy(); | ||
127 | |||
128 | DetailLog("{0},BSCharacter.Destroy", LocalID); | ||
129 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | ||
130 | { | ||
131 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | ||
132 | PhysBody.Clear(); | ||
133 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | ||
134 | PhysShape.Clear(); | ||
135 | }); | ||
136 | } | ||
137 | |||
138 | private void SetPhysicalProperties() | ||
139 | { | ||
140 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); | ||
141 | |||
142 | ZeroMotion(true); | ||
143 | ForcePosition = _position; | ||
144 | |||
145 | // Set the velocity and compute the proper friction | ||
146 | _velocityMotor.Reset(); | ||
147 | _velocityMotor.SetTarget(_velocity); | ||
148 | _velocityMotor.SetCurrent(_velocity); | ||
149 | ForceVelocity = _velocity; | ||
150 | |||
151 | // This will enable or disable the flying buoyancy of the avatar. | ||
152 | // Needs to be reset especially when an avatar is recreated after crossing a region boundry. | ||
153 | Flying = _flying; | ||
154 | |||
155 | PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); | ||
156 | PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); | ||
157 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); | ||
158 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | ||
159 | if (BSParam.CcdMotionThreshold > 0f) | ||
160 | { | ||
161 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | ||
162 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | ||
163 | } | ||
164 | |||
165 | UpdatePhysicalMassProperties(RawMass, false); | ||
166 | |||
167 | // Make so capsule does not fall over | ||
168 | PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); | ||
169 | |||
170 | PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); | ||
171 | |||
172 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); | ||
173 | |||
174 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); | ||
175 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); | ||
176 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); | ||
177 | |||
178 | // Do this after the object has been added to the world | ||
179 | PhysBody.collisionType = CollisionType.Avatar; | ||
180 | PhysBody.ApplyCollisionMask(PhysicsScene); | ||
181 | } | ||
182 | |||
183 | // The avatar's movement is controlled by this motor that speeds up and slows down | ||
184 | // the avatar seeking to reach the motor's target speed. | ||
185 | // This motor runs as a prestep action for the avatar so it will keep the avatar | ||
186 | // standing as well as moving. Destruction of the avatar will destroy the pre-step action. | ||
187 | private void SetupMovementMotor() | ||
188 | { | ||
189 | |||
190 | // Someday, use a PID motor for asymmetric speed up and slow down | ||
191 | // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f); | ||
192 | |||
193 | // Infinite decay and timescale values so motor only changes current to target values. | ||
194 | _velocityMotor = new BSVMotor("BSCharacter.Velocity", | ||
195 | 0.2f, // time scale | ||
196 | BSMotor.Infinite, // decay time scale | ||
197 | BSMotor.InfiniteVector, // friction timescale | ||
198 | 1f // efficiency | ||
199 | ); | ||
200 | // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
201 | |||
202 | RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep) | ||
203 | { | ||
204 | // TODO: Decide if the step parameters should be changed depending on the avatar's | ||
205 | // state (flying, colliding, ...). There is code in ODE to do this. | ||
206 | |||
207 | OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep); | ||
208 | |||
209 | // If falling, we keep the world's downward vector no matter what the other axis specify. | ||
210 | if (!Flying && !IsColliding) | ||
211 | { | ||
212 | stepVelocity.Z = _velocity.Z; | ||
213 | // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); | ||
214 | } | ||
215 | |||
216 | // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. | ||
217 | OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass / PhysicsScene.LastTimeStep; | ||
218 | |||
219 | /* | ||
220 | // If moveForce is very small, zero things so we don't keep sending microscopic updates to the user | ||
221 | float moveForceMagnitudeSquared = moveForce.LengthSquared(); | ||
222 | if (moveForceMagnitudeSquared < 0.0001) | ||
223 | { | ||
224 | DetailLog("{0},BSCharacter.MoveMotor,zeroMovement,stepVel={1},vel={2},mass={3},magSq={4},moveForce={5}", | ||
225 | LocalID, stepVelocity, _velocity, Mass, moveForceMagnitudeSquared, moveForce); | ||
226 | ForceVelocity = OMV.Vector3.Zero; | ||
227 | } | ||
228 | else | ||
229 | { | ||
230 | AddForce(moveForce, false, true); | ||
231 | } | ||
232 | */ | ||
233 | // DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce); | ||
234 | AddForce(moveForce, false, true); | ||
235 | }); | ||
236 | } | ||
237 | |||
238 | public override void RequestPhysicsterseUpdate() | ||
239 | { | ||
240 | base.RequestPhysicsterseUpdate(); | ||
241 | } | ||
242 | // No one calls this method so I don't know what it could possibly mean | ||
243 | public override bool Stopped { get { return false; } } | ||
244 | |||
245 | public override OMV.Vector3 Size { | ||
246 | get | ||
247 | { | ||
248 | // Avatar capsule size is kept in the scale parameter. | ||
249 | return _size; | ||
250 | } | ||
251 | |||
252 | set { | ||
253 | _size = value; | ||
254 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||
255 | // replace with the default values. | ||
256 | if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; | ||
257 | if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; | ||
258 | |||
259 | Scale = ComputeAvatarScale(_size); | ||
260 | ComputeAvatarVolumeAndMass(); | ||
261 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", | ||
262 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | ||
263 | |||
264 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | ||
265 | { | ||
266 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) | ||
267 | { | ||
268 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); | ||
269 | UpdatePhysicalMassProperties(RawMass, true); | ||
270 | // Make sure this change appears as a property update event | ||
271 | PhysicsScene.PE.PushUpdate(PhysBody); | ||
272 | } | ||
273 | }); | ||
274 | |||
275 | } | ||
276 | } | ||
277 | |||
278 | public override PrimitiveBaseShape Shape | ||
279 | { | ||
280 | set { BaseShape = value; } | ||
281 | } | ||
282 | // I want the physics engine to make an avatar capsule | ||
283 | public override BSPhysicsShapeType PreferredPhysicalShape | ||
284 | { | ||
285 | get {return BSPhysicsShapeType.SHAPE_CAPSULE; } | ||
286 | } | ||
287 | |||
288 | public override bool Grabbed { | ||
289 | set { _grabbed = value; } | ||
290 | } | ||
291 | public override bool Selected { | ||
292 | set { _selected = value; } | ||
293 | } | ||
294 | public override void CrossingFailure() { return; } | ||
295 | public override void link(PhysicsActor obj) { return; } | ||
296 | public override void delink() { return; } | ||
297 | |||
298 | // Set motion values to zero. | ||
299 | // Do it to the properties so the values get set in the physics engine. | ||
300 | // Push the setting of the values to the viewer. | ||
301 | // Called at taint time! | ||
302 | public override void ZeroMotion(bool inTaintTime) | ||
303 | { | ||
304 | _velocity = OMV.Vector3.Zero; | ||
305 | _acceleration = OMV.Vector3.Zero; | ||
306 | _rotationalVelocity = OMV.Vector3.Zero; | ||
307 | |||
308 | // Zero some other properties directly into the physics engine | ||
309 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | ||
310 | { | ||
311 | if (PhysBody.HasPhysicalBody) | ||
312 | PhysicsScene.PE.ClearAllForces(PhysBody); | ||
313 | }); | ||
314 | } | ||
315 | public override void ZeroAngularMotion(bool inTaintTime) | ||
316 | { | ||
317 | _rotationalVelocity = OMV.Vector3.Zero; | ||
318 | |||
319 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | ||
320 | { | ||
321 | if (PhysBody.HasPhysicalBody) | ||
322 | { | ||
323 | PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); | ||
324 | PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); | ||
325 | // The next also get rid of applied linear force but the linear velocity is untouched. | ||
326 | PhysicsScene.PE.ClearForces(PhysBody); | ||
327 | } | ||
328 | }); | ||
329 | } | ||
330 | |||
331 | |||
332 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } | ||
333 | |||
334 | public override OMV.Vector3 RawPosition | ||
335 | { | ||
336 | get { return _position; } | ||
337 | set { _position = value; } | ||
338 | } | ||
339 | public override OMV.Vector3 Position { | ||
340 | get { | ||
341 | // Don't refetch the position because this function is called a zillion times | ||
342 | // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); | ||
343 | return _position; | ||
344 | } | ||
345 | set { | ||
346 | _position = value; | ||
347 | PositionSanityCheck(); | ||
348 | |||
349 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() | ||
350 | { | ||
351 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
352 | if (PhysBody.HasPhysicalBody) | ||
353 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
354 | }); | ||
355 | } | ||
356 | } | ||
357 | public override OMV.Vector3 ForcePosition { | ||
358 | get { | ||
359 | _position = PhysicsScene.PE.GetPosition(PhysBody); | ||
360 | return _position; | ||
361 | } | ||
362 | set { | ||
363 | _position = value; | ||
364 | PositionSanityCheck(); | ||
365 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
366 | } | ||
367 | } | ||
368 | |||
369 | |||
370 | // Check that the current position is sane and, if not, modify the position to make it so. | ||
371 | // Check for being below terrain or on water. | ||
372 | // Returns 'true' of the position was made sane by some action. | ||
373 | private bool PositionSanityCheck() | ||
374 | { | ||
375 | bool ret = false; | ||
376 | |||
377 | // TODO: check for out of bounds | ||
378 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) | ||
379 | { | ||
380 | // The character is out of the known/simulated area. | ||
381 | // Upper levels of code will handle the transition to other areas so, for | ||
382 | // the time, we just ignore the position. | ||
383 | return ret; | ||
384 | } | ||
385 | |||
386 | // If below the ground, move the avatar up | ||
387 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | ||
388 | if (Position.Z < terrainHeight) | ||
389 | { | ||
390 | DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | ||
391 | _position.Z = terrainHeight + 2.0f; | ||
392 | ret = true; | ||
393 | } | ||
394 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | ||
395 | { | ||
396 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); | ||
397 | if (Position.Z < waterHeight) | ||
398 | { | ||
399 | _position.Z = waterHeight; | ||
400 | ret = true; | ||
401 | } | ||
402 | } | ||
403 | |||
404 | return ret; | ||
405 | } | ||
406 | |||
407 | // A version of the sanity check that also makes sure a new position value is | ||
408 | // pushed back to the physics engine. This routine would be used by anyone | ||
409 | // who is not already pushing the value. | ||
410 | private bool PositionSanityCheck(bool inTaintTime) | ||
411 | { | ||
412 | bool ret = false; | ||
413 | if (PositionSanityCheck()) | ||
414 | { | ||
415 | // The new position value must be pushed into the physics engine but we can't | ||
416 | // just assign to "Position" because of potential call loops. | ||
417 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() | ||
418 | { | ||
419 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
420 | if (PhysBody.HasPhysicalBody) | ||
421 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
422 | }); | ||
423 | ret = true; | ||
424 | } | ||
425 | return ret; | ||
426 | } | ||
427 | |||
428 | public override float Mass { get { return _mass; } } | ||
429 | |||
430 | // used when we only want this prim's mass and not the linkset thing | ||
431 | public override float RawMass { | ||
432 | get {return _mass; } | ||
433 | } | ||
434 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) | ||
435 | { | ||
436 | OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); | ||
437 | PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); | ||
438 | } | ||
439 | |||
440 | public override OMV.Vector3 Force { | ||
441 | get { return _force; } | ||
442 | set { | ||
443 | _force = value; | ||
444 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); | ||
445 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | ||
446 | { | ||
447 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | ||
448 | if (PhysBody.HasPhysicalBody) | ||
449 | PhysicsScene.PE.SetObjectForce(PhysBody, _force); | ||
450 | }); | ||
451 | } | ||
452 | } | ||
453 | |||
454 | // Avatars don't do vehicles | ||
455 | public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } } | ||
456 | public override void VehicleFloatParam(int param, float value) { } | ||
457 | public override void VehicleVectorParam(int param, OMV.Vector3 value) {} | ||
458 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } | ||
459 | public override void VehicleFlags(int param, bool remove) { } | ||
460 | |||
461 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | ||
462 | public override void SetVolumeDetect(int param) { return; } | ||
463 | |||
464 | public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } | ||
465 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } | ||
466 | |||
467 | // Sets the target in the motor. This starts the changing of the avatar's velocity. | ||
468 | public override OMV.Vector3 TargetVelocity | ||
469 | { | ||
470 | get | ||
471 | { | ||
472 | return _velocityMotor.TargetValue; | ||
473 | } | ||
474 | set | ||
475 | { | ||
476 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); | ||
477 | OMV.Vector3 targetVel = value; | ||
478 | if (_setAlwaysRun) | ||
479 | targetVel *= BSParam.AvatarAlwaysRunFactor; | ||
480 | |||
481 | PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() | ||
482 | { | ||
483 | _velocityMotor.Reset(); | ||
484 | _velocityMotor.SetTarget(targetVel); | ||
485 | _velocityMotor.SetCurrent(_velocity); | ||
486 | _velocityMotor.Enabled = true; | ||
487 | }); | ||
488 | } | ||
489 | } | ||
490 | // Directly setting velocity means this is what the user really wants now. | ||
491 | public override OMV.Vector3 Velocity { | ||
492 | get { return _velocity; } | ||
493 | set { | ||
494 | _velocity = value; | ||
495 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); | ||
496 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() | ||
497 | { | ||
498 | _velocityMotor.Reset(); | ||
499 | _velocityMotor.SetCurrent(_velocity); | ||
500 | _velocityMotor.SetTarget(_velocity); | ||
501 | // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar. | ||
502 | _velocityMotor.Enabled = false; | ||
503 | |||
504 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); | ||
505 | ForceVelocity = _velocity; | ||
506 | }); | ||
507 | } | ||
508 | } | ||
509 | public override OMV.Vector3 ForceVelocity { | ||
510 | get { return _velocity; } | ||
511 | set { | ||
512 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); | ||
513 | |||
514 | _velocity = value; | ||
515 | // Depending on whether the avatar is moving or not, change the friction | ||
516 | // to keep the avatar from slipping around | ||
517 | if (_velocity.Length() == 0) | ||
518 | { | ||
519 | if (_currentFriction != BSParam.AvatarStandingFriction) | ||
520 | { | ||
521 | _currentFriction = BSParam.AvatarStandingFriction; | ||
522 | if (PhysBody.HasPhysicalBody) | ||
523 | PhysicsScene.PE.SetFriction(PhysBody, _currentFriction); | ||
524 | } | ||
525 | } | ||
526 | else | ||
527 | { | ||
528 | if (_currentFriction != BSParam.AvatarFriction) | ||
529 | { | ||
530 | _currentFriction = BSParam.AvatarFriction; | ||
531 | if (PhysBody.HasPhysicalBody) | ||
532 | PhysicsScene.PE.SetFriction(PhysBody, _currentFriction); | ||
533 | } | ||
534 | } | ||
535 | |||
536 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); | ||
537 | PhysicsScene.PE.Activate(PhysBody, true); | ||
538 | } | ||
539 | } | ||
540 | public override OMV.Vector3 Torque { | ||
541 | get { return _torque; } | ||
542 | set { _torque = value; | ||
543 | } | ||
544 | } | ||
545 | public override float CollisionScore { | ||
546 | get { return _collisionScore; } | ||
547 | set { _collisionScore = value; | ||
548 | } | ||
549 | } | ||
550 | public override OMV.Vector3 Acceleration { | ||
551 | get { return _acceleration; } | ||
552 | set { _acceleration = value; } | ||
553 | } | ||
554 | public override OMV.Quaternion RawOrientation | ||
555 | { | ||
556 | get { return _orientation; } | ||
557 | set { _orientation = value; } | ||
558 | } | ||
559 | public override OMV.Quaternion Orientation { | ||
560 | get { return _orientation; } | ||
561 | set { | ||
562 | // Orientation is set zillions of times when an avatar is walking. It's like | ||
563 | // the viewer doesn't trust us. | ||
564 | if (_orientation != value) | ||
565 | { | ||
566 | _orientation = value; | ||
567 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() | ||
568 | { | ||
569 | ForceOrientation = _orientation; | ||
570 | }); | ||
571 | } | ||
572 | } | ||
573 | } | ||
574 | // Go directly to Bullet to get/set the value. | ||
575 | public override OMV.Quaternion ForceOrientation | ||
576 | { | ||
577 | get | ||
578 | { | ||
579 | _orientation = PhysicsScene.PE.GetOrientation(PhysBody); | ||
580 | return _orientation; | ||
581 | } | ||
582 | set | ||
583 | { | ||
584 | _orientation = value; | ||
585 | if (PhysBody.HasPhysicalBody) | ||
586 | { | ||
587 | // _position = PhysicsScene.PE.GetPosition(BSBody); | ||
588 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
589 | } | ||
590 | } | ||
591 | } | ||
592 | public override int PhysicsActorType { | ||
593 | get { return _physicsActorType; } | ||
594 | set { _physicsActorType = value; | ||
595 | } | ||
596 | } | ||
597 | public override bool IsPhysical { | ||
598 | get { return _isPhysical; } | ||
599 | set { _isPhysical = value; | ||
600 | } | ||
601 | } | ||
602 | public override bool IsSolid { | ||
603 | get { return true; } | ||
604 | } | ||
605 | public override bool IsStatic { | ||
606 | get { return false; } | ||
607 | } | ||
608 | public override bool Flying { | ||
609 | get { return _flying; } | ||
610 | set { | ||
611 | _flying = value; | ||
612 | |||
613 | // simulate flying by changing the effect of gravity | ||
614 | Buoyancy = ComputeBuoyancyFromFlying(_flying); | ||
615 | } | ||
616 | } | ||
617 | // Flying is implimented by changing the avatar's buoyancy. | ||
618 | // Would this be done better with a vehicle type? | ||
619 | private float ComputeBuoyancyFromFlying(bool ifFlying) { | ||
620 | return ifFlying ? 1f : 0f; | ||
621 | } | ||
622 | public override bool | ||
623 | SetAlwaysRun { | ||
624 | get { return _setAlwaysRun; } | ||
625 | set { _setAlwaysRun = value; } | ||
626 | } | ||
627 | public override bool ThrottleUpdates { | ||
628 | get { return _throttleUpdates; } | ||
629 | set { _throttleUpdates = value; } | ||
630 | } | ||
631 | public override bool FloatOnWater { | ||
632 | set { | ||
633 | _floatOnWater = value; | ||
634 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() | ||
635 | { | ||
636 | if (PhysBody.HasPhysicalBody) | ||
637 | { | ||
638 | if (_floatOnWater) | ||
639 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | ||
640 | else | ||
641 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | ||
642 | } | ||
643 | }); | ||
644 | } | ||
645 | } | ||
646 | public override OMV.Vector3 RotationalVelocity { | ||
647 | get { return _rotationalVelocity; } | ||
648 | set { _rotationalVelocity = value; } | ||
649 | } | ||
650 | public override OMV.Vector3 ForceRotationalVelocity { | ||
651 | get { return _rotationalVelocity; } | ||
652 | set { _rotationalVelocity = value; } | ||
653 | } | ||
654 | public override bool Kinematic { | ||
655 | get { return _kinematic; } | ||
656 | set { _kinematic = value; } | ||
657 | } | ||
658 | // neg=fall quickly, 0=1g, 1=0g, pos=float up | ||
659 | public override float Buoyancy { | ||
660 | get { return _buoyancy; } | ||
661 | set { _buoyancy = value; | ||
662 | PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() | ||
663 | { | ||
664 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | ||
665 | ForceBuoyancy = _buoyancy; | ||
666 | }); | ||
667 | } | ||
668 | } | ||
669 | public override float ForceBuoyancy { | ||
670 | get { return _buoyancy; } | ||
671 | set { | ||
672 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); | ||
673 | |||
674 | _buoyancy = value; | ||
675 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | ||
676 | // Buoyancy is faked by changing the gravity applied to the object | ||
677 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | ||
678 | if (PhysBody.HasPhysicalBody) | ||
679 | PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav)); | ||
680 | } | ||
681 | } | ||
682 | |||
683 | // Used for MoveTo | ||
684 | public override OMV.Vector3 PIDTarget { | ||
685 | set { _PIDTarget = value; } | ||
686 | } | ||
687 | public override bool PIDActive { | ||
688 | set { _usePID = value; } | ||
689 | } | ||
690 | public override float PIDTau { | ||
691 | set { _PIDTau = value; } | ||
692 | } | ||
693 | |||
694 | // Used for llSetHoverHeight and maybe vehicle height | ||
695 | // Hover Height will override MoveTo target's Z | ||
696 | public override bool PIDHoverActive { | ||
697 | set { _useHoverPID = value; } | ||
698 | } | ||
699 | public override float PIDHoverHeight { | ||
700 | set { _PIDHoverHeight = value; } | ||
701 | } | ||
702 | public override PIDHoverType PIDHoverType { | ||
703 | set { _PIDHoverType = value; } | ||
704 | } | ||
705 | public override float PIDHoverTau { | ||
706 | set { _PIDHoverTao = value; } | ||
707 | } | ||
708 | |||
709 | // For RotLookAt | ||
710 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
711 | public override bool APIDActive { set { return; } } | ||
712 | public override float APIDStrength { set { return; } } | ||
713 | public override float APIDDamping { set { return; } } | ||
714 | |||
715 | public override void AddForce(OMV.Vector3 force, bool pushforce) | ||
716 | { | ||
717 | // Since this force is being applied in only one step, make this a force per second. | ||
718 | OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; | ||
719 | AddForce(addForce, pushforce, false); | ||
720 | } | ||
721 | private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | ||
722 | if (force.IsFinite()) | ||
723 | { | ||
724 | float magnitude = force.Length(); | ||
725 | if (magnitude > BSParam.MaxAddForceMagnitude) | ||
726 | { | ||
727 | // Force has a limit | ||
728 | force = force / magnitude * BSParam.MaxAddForceMagnitude; | ||
729 | } | ||
730 | |||
731 | OMV.Vector3 addForce = force; | ||
732 | // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); | ||
733 | |||
734 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() | ||
735 | { | ||
736 | // Bullet adds this central force to the total force for this tick | ||
737 | // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); | ||
738 | if (PhysBody.HasPhysicalBody) | ||
739 | { | ||
740 | PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); | ||
741 | } | ||
742 | }); | ||
743 | } | ||
744 | else | ||
745 | { | ||
746 | m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID); | ||
747 | return; | ||
748 | } | ||
749 | } | ||
750 | |||
751 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | ||
752 | } | ||
753 | public override void SetMomentum(OMV.Vector3 momentum) { | ||
754 | } | ||
755 | |||
756 | private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) | ||
757 | { | ||
758 | OMV.Vector3 newScale; | ||
759 | |||
760 | // Bullet's capsule total height is the "passed height + radius * 2"; | ||
761 | // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) | ||
762 | // The number we pass in for 'scaling' is the multiplier to get that base | ||
763 | // shape to be the size desired. | ||
764 | // So, when creating the scale for the avatar height, we take the passed height | ||
765 | // (size.Z) and remove the caps. | ||
766 | // Another oddity of the Bullet capsule implementation is that it presumes the Y | ||
767 | // dimension is the radius of the capsule. Even though some of the code allows | ||
768 | // for a asymmetrical capsule, other parts of the code presume it is cylindrical. | ||
769 | |||
770 | // Scale is multiplier of radius with one of "0.5" | ||
771 | newScale.X = size.X / 2f; | ||
772 | newScale.Y = size.Y / 2f; | ||
773 | |||
774 | // The total scale height is the central cylindar plus the caps on the two ends. | ||
775 | newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f; | ||
776 | // If smaller than the endcaps, just fake like we're almost that small | ||
777 | if (newScale.Z < 0) | ||
778 | newScale.Z = 0.1f; | ||
779 | |||
780 | return newScale; | ||
781 | } | ||
782 | |||
783 | // set _avatarVolume and _mass based on capsule size, _density and Scale | ||
784 | private void ComputeAvatarVolumeAndMass() | ||
785 | { | ||
786 | _avatarVolume = (float)( | ||
787 | Math.PI | ||
788 | * Size.X / 2f | ||
789 | * Size.Y / 2f // the area of capsule cylinder | ||
790 | * Size.Z // times height of capsule cylinder | ||
791 | + 1.33333333f | ||
792 | * Math.PI | ||
793 | * Size.X / 2f | ||
794 | * Math.Min(Size.X, Size.Y) / 2 | ||
795 | * Size.Y / 2f // plus the volume of the capsule end caps | ||
796 | ); | ||
797 | _mass = _avatarDensity * _avatarVolume; | ||
798 | } | ||
799 | |||
800 | // The physics engine says that properties have updated. Update same and inform | ||
801 | // the world that things have changed. | ||
802 | public override void UpdateProperties(EntityProperties entprop) | ||
803 | { | ||
804 | _position = entprop.Position; | ||
805 | _orientation = entprop.Rotation; | ||
806 | _velocity = entprop.Velocity; | ||
807 | _acceleration = entprop.Acceleration; | ||
808 | _rotationalVelocity = entprop.RotationalVelocity; | ||
809 | |||
810 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. | ||
811 | PositionSanityCheck(true); | ||
812 | |||
813 | // remember the current and last set values | ||
814 | LastEntityProperties = CurrentEntityProperties; | ||
815 | CurrentEntityProperties = entprop; | ||
816 | |||
817 | // Tell the linkset about value changes | ||
818 | Linkset.UpdateProperties(this, true); | ||
819 | |||
820 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. | ||
821 | // base.RequestPhysicsterseUpdate(); | ||
822 | |||
823 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
824 | LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | ||
825 | } | ||
826 | } | ||
827 | } | ||