aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs827
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 */
27using System;
28using System.Collections.Generic;
29using System.Reflection;
30using log4net;
31using OMV = OpenMetaverse;
32using OpenSim.Framework;
33using OpenSim.Region.Physics.Manager;
34
35namespace OpenSim.Region.Physics.BulletSPlugin
36{
37public 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}