diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs | 814 |
1 files changed, 814 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs new file mode 100644 index 0000000..d91c47f --- /dev/null +++ b/OpenSim/Region/Physics/BulletSNPlugin/BSCharacter.cs | |||
@@ -0,0 +1,814 @@ | |||
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.BulletSNPlugin | ||
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 OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar | ||
70 | private float _currentFriction; // the friction currently being used (changed by setVelocity). | ||
71 | |||
72 | private BSVMotor _velocityMotor; | ||
73 | |||
74 | private OMV.Vector3 _PIDTarget; | ||
75 | private bool _usePID; | ||
76 | private float _PIDTau; | ||
77 | private bool _useHoverPID; | ||
78 | private float _PIDHoverHeight; | ||
79 | private PIDHoverType _PIDHoverType; | ||
80 | private float _PIDHoverTao; | ||
81 | |||
82 | public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) | ||
83 | : base(parent_scene, localID, avName, "BSCharacter") | ||
84 | { | ||
85 | _physicsActorType = (int)ActorTypes.Agent; | ||
86 | _position = pos; | ||
87 | |||
88 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||
89 | // replace with the default values. | ||
90 | _size = size; | ||
91 | if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; | ||
92 | if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; | ||
93 | |||
94 | // A motor to control the acceleration and deceleration of the avatar movement. | ||
95 | // _velocityMotor = new BSVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f); | ||
96 | // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f); | ||
97 | // Infinite decay and timescale values so motor only changes current to target values. | ||
98 | _velocityMotor = new BSVMotor("BSCharacter.Velocity", | ||
99 | 0.2f, // time scale | ||
100 | BSMotor.Infinite, // decay time scale | ||
101 | BSMotor.InfiniteVector, // friction timescale | ||
102 | 1f // efficiency | ||
103 | ); | ||
104 | _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages. | ||
105 | |||
106 | _flying = isFlying; | ||
107 | _orientation = OMV.Quaternion.Identity; | ||
108 | _velocity = OMV.Vector3.Zero; | ||
109 | _appliedVelocity = OMV.Vector3.Zero; | ||
110 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); | ||
111 | _currentFriction = BSParam.AvatarStandingFriction; | ||
112 | _avatarDensity = BSParam.AvatarDensity; | ||
113 | |||
114 | // The dimensions of the avatar capsule are kept in the scale. | ||
115 | // Physics creates a unit capsule which is scaled by the physics engine. | ||
116 | ComputeAvatarScale(_size); | ||
117 | // set _avatarVolume and _mass based on capsule size, _density and Scale | ||
118 | ComputeAvatarVolumeAndMass(); | ||
119 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | ||
120 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | ||
121 | |||
122 | // do actual creation in taint time | ||
123 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | ||
124 | { | ||
125 | DetailLog("{0},BSCharacter.create,taint", LocalID); | ||
126 | // New body and shape into PhysBody and PhysShape | ||
127 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); | ||
128 | |||
129 | SetPhysicalProperties(); | ||
130 | }); | ||
131 | return; | ||
132 | } | ||
133 | |||
134 | // called when this character is being destroyed and the resources should be released | ||
135 | public override void Destroy() | ||
136 | { | ||
137 | base.Destroy(); | ||
138 | |||
139 | DetailLog("{0},BSCharacter.Destroy", LocalID); | ||
140 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | ||
141 | { | ||
142 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | ||
143 | PhysBody.Clear(); | ||
144 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | ||
145 | PhysShape.Clear(); | ||
146 | }); | ||
147 | } | ||
148 | |||
149 | private void SetPhysicalProperties() | ||
150 | { | ||
151 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); | ||
152 | |||
153 | ZeroMotion(true); | ||
154 | ForcePosition = _position; | ||
155 | // Set the velocity and compute the proper friction | ||
156 | ForceVelocity = _velocity; | ||
157 | // Setting the current and target in the motor will cause it to start computing any deceleration. | ||
158 | _velocityMotor.Reset(); | ||
159 | _velocityMotor.SetCurrent(_velocity); | ||
160 | _velocityMotor.SetTarget(_velocity); | ||
161 | _velocityMotor.Enabled = false; | ||
162 | |||
163 | // This will enable or disable the flying buoyancy of the avatar. | ||
164 | // Needs to be reset especially when an avatar is recreated after crossing a region boundry. | ||
165 | Flying = _flying; | ||
166 | |||
167 | BulletSimAPI.SetRestitution2(PhysBody.ptr, BSParam.AvatarRestitution); | ||
168 | BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); | ||
169 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); | ||
170 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold); | ||
171 | if (BSParam.CcdMotionThreshold > 0f) | ||
172 | { | ||
173 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold); | ||
174 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius); | ||
175 | } | ||
176 | |||
177 | UpdatePhysicalMassProperties(RawMass, false); | ||
178 | |||
179 | // Make so capsule does not fall over | ||
180 | BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero); | ||
181 | |||
182 | BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); | ||
183 | |||
184 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr, _position, _orientation); | ||
185 | |||
186 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); | ||
187 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION); | ||
188 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | ||
189 | |||
190 | // Do this after the object has been added to the world | ||
191 | PhysBody.collisionType = CollisionType.Avatar; | ||
192 | PhysBody.ApplyCollisionMask(); | ||
193 | } | ||
194 | |||
195 | public override void RequestPhysicsterseUpdate() | ||
196 | { | ||
197 | base.RequestPhysicsterseUpdate(); | ||
198 | } | ||
199 | // No one calls this method so I don't know what it could possibly mean | ||
200 | public override bool Stopped { get { return false; } } | ||
201 | |||
202 | public override OMV.Vector3 Size { | ||
203 | get | ||
204 | { | ||
205 | // Avatar capsule size is kept in the scale parameter. | ||
206 | return _size; | ||
207 | } | ||
208 | |||
209 | set { | ||
210 | // When an avatar's size is set, only the height is changed. | ||
211 | _size = value; | ||
212 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||
213 | // replace with the default values. | ||
214 | if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; | ||
215 | if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; | ||
216 | |||
217 | ComputeAvatarScale(_size); | ||
218 | ComputeAvatarVolumeAndMass(); | ||
219 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", | ||
220 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | ||
221 | |||
222 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | ||
223 | { | ||
224 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) | ||
225 | { | ||
226 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); | ||
227 | UpdatePhysicalMassProperties(RawMass, true); | ||
228 | // Make sure this change appears as a property update event | ||
229 | BulletSimAPI.PushUpdate2(PhysBody.ptr); | ||
230 | } | ||
231 | }); | ||
232 | |||
233 | } | ||
234 | } | ||
235 | |||
236 | public override PrimitiveBaseShape Shape | ||
237 | { | ||
238 | set { BaseShape = value; } | ||
239 | } | ||
240 | // I want the physics engine to make an avatar capsule | ||
241 | public override BSPhysicsShapeType PreferredPhysicalShape | ||
242 | { | ||
243 | get {return BSPhysicsShapeType.SHAPE_CAPSULE; } | ||
244 | } | ||
245 | |||
246 | public override bool Grabbed { | ||
247 | set { _grabbed = value; } | ||
248 | } | ||
249 | public override bool Selected { | ||
250 | set { _selected = value; } | ||
251 | } | ||
252 | public override void CrossingFailure() { return; } | ||
253 | public override void link(PhysicsActor obj) { return; } | ||
254 | public override void delink() { return; } | ||
255 | |||
256 | // Set motion values to zero. | ||
257 | // Do it to the properties so the values get set in the physics engine. | ||
258 | // Push the setting of the values to the viewer. | ||
259 | // Called at taint time! | ||
260 | public override void ZeroMotion(bool inTaintTime) | ||
261 | { | ||
262 | _velocity = OMV.Vector3.Zero; | ||
263 | _acceleration = OMV.Vector3.Zero; | ||
264 | _rotationalVelocity = OMV.Vector3.Zero; | ||
265 | |||
266 | // Zero some other properties directly into the physics engine | ||
267 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | ||
268 | { | ||
269 | if (PhysBody.HasPhysicalBody) | ||
270 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | ||
271 | }); | ||
272 | } | ||
273 | public override void ZeroAngularMotion(bool inTaintTime) | ||
274 | { | ||
275 | _rotationalVelocity = OMV.Vector3.Zero; | ||
276 | |||
277 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | ||
278 | { | ||
279 | if (PhysBody.HasPhysicalBody) | ||
280 | { | ||
281 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | ||
282 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | ||
283 | // The next also get rid of applied linear force but the linear velocity is untouched. | ||
284 | BulletSimAPI.ClearForces2(PhysBody.ptr); | ||
285 | } | ||
286 | }); | ||
287 | } | ||
288 | |||
289 | |||
290 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } | ||
291 | |||
292 | public override OMV.Vector3 RawPosition | ||
293 | { | ||
294 | get { return _position; } | ||
295 | set { _position = value; } | ||
296 | } | ||
297 | public override OMV.Vector3 Position { | ||
298 | get { | ||
299 | // Don't refetch the position because this function is called a zillion times | ||
300 | // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); | ||
301 | return _position; | ||
302 | } | ||
303 | set { | ||
304 | _position = value; | ||
305 | PositionSanityCheck(); | ||
306 | |||
307 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() | ||
308 | { | ||
309 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
310 | if (PhysBody.HasPhysicalBody) | ||
311 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
312 | }); | ||
313 | } | ||
314 | } | ||
315 | public override OMV.Vector3 ForcePosition { | ||
316 | get { | ||
317 | _position = BulletSimAPI.GetPosition2(PhysBody.ptr); | ||
318 | return _position; | ||
319 | } | ||
320 | set { | ||
321 | _position = value; | ||
322 | PositionSanityCheck(); | ||
323 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
324 | } | ||
325 | } | ||
326 | |||
327 | |||
328 | // Check that the current position is sane and, if not, modify the position to make it so. | ||
329 | // Check for being below terrain or on water. | ||
330 | // Returns 'true' of the position was made sane by some action. | ||
331 | private bool PositionSanityCheck() | ||
332 | { | ||
333 | bool ret = false; | ||
334 | |||
335 | // TODO: check for out of bounds | ||
336 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) | ||
337 | { | ||
338 | // The character is out of the known/simulated area. | ||
339 | // Upper levels of code will handle the transition to other areas so, for | ||
340 | // the time, we just ignore the position. | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | // If below the ground, move the avatar up | ||
345 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | ||
346 | if (Position.Z < terrainHeight) | ||
347 | { | ||
348 | DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | ||
349 | _position.Z = terrainHeight + 2.0f; | ||
350 | ret = true; | ||
351 | } | ||
352 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | ||
353 | { | ||
354 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); | ||
355 | if (Position.Z < waterHeight) | ||
356 | { | ||
357 | _position.Z = waterHeight; | ||
358 | ret = true; | ||
359 | } | ||
360 | } | ||
361 | |||
362 | return ret; | ||
363 | } | ||
364 | |||
365 | // A version of the sanity check that also makes sure a new position value is | ||
366 | // pushed back to the physics engine. This routine would be used by anyone | ||
367 | // who is not already pushing the value. | ||
368 | private bool PositionSanityCheck(bool inTaintTime) | ||
369 | { | ||
370 | bool ret = false; | ||
371 | if (PositionSanityCheck()) | ||
372 | { | ||
373 | // The new position value must be pushed into the physics engine but we can't | ||
374 | // just assign to "Position" because of potential call loops. | ||
375 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() | ||
376 | { | ||
377 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
378 | if (PhysBody.HasPhysicalBody) | ||
379 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
380 | }); | ||
381 | ret = true; | ||
382 | } | ||
383 | return ret; | ||
384 | } | ||
385 | |||
386 | public override float Mass { get { return _mass; } } | ||
387 | |||
388 | // used when we only want this prim's mass and not the linkset thing | ||
389 | public override float RawMass { | ||
390 | get {return _mass; } | ||
391 | } | ||
392 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) | ||
393 | { | ||
394 | OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); | ||
395 | BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); | ||
396 | } | ||
397 | |||
398 | public override OMV.Vector3 Force { | ||
399 | get { return _force; } | ||
400 | set { | ||
401 | _force = value; | ||
402 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); | ||
403 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | ||
404 | { | ||
405 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | ||
406 | if (PhysBody.HasPhysicalBody) | ||
407 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | ||
408 | }); | ||
409 | } | ||
410 | } | ||
411 | |||
412 | public bool TouchingGround() | ||
413 | { | ||
414 | bool ret = BulletSimAPI.RayCastGround(PhysicsScene.World.ptr,_position,_size.Z * 0.55f, PhysBody.ptr); | ||
415 | return ret; | ||
416 | } | ||
417 | // Avatars don't do vehicles | ||
418 | public override int VehicleType { get { return (int)Vehicle.TYPE_NONE; } set { return; } } | ||
419 | public override void VehicleFloatParam(int param, float value) { } | ||
420 | public override void VehicleVectorParam(int param, OMV.Vector3 value) {} | ||
421 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) { } | ||
422 | public override void VehicleFlags(int param, bool remove) { } | ||
423 | |||
424 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | ||
425 | public override void SetVolumeDetect(int param) { return; } | ||
426 | |||
427 | public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } | ||
428 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } | ||
429 | |||
430 | // Sets the target in the motor. This starts the changing of the avatar's velocity. | ||
431 | public override OMV.Vector3 TargetVelocity | ||
432 | { | ||
433 | get | ||
434 | { | ||
435 | return _velocityMotor.TargetValue; | ||
436 | } | ||
437 | set | ||
438 | { | ||
439 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); | ||
440 | |||
441 | if (!_flying) | ||
442 | if ((value.Z >= 0.0001f) || (value.Z <= -0.0001f) || _velocity.Z < -0.0001f) | ||
443 | if (!TouchingGround()) | ||
444 | value.Z = _velocity.Z; | ||
445 | if (_setAlwaysRun) | ||
446 | value *= 1.3f; | ||
447 | |||
448 | OMV.Vector3 targetVel = value; | ||
449 | |||
450 | PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() | ||
451 | { | ||
452 | |||
453 | _velocityMotor.Reset(); | ||
454 | _velocityMotor.SetTarget(targetVel); | ||
455 | _velocityMotor.SetCurrent(_velocity); | ||
456 | _velocityMotor.Enabled = true; | ||
457 | |||
458 | // Make sure a property update happens next step so the motor gets incorporated. | ||
459 | BulletSimAPI.PushUpdate2(PhysBody.ptr); | ||
460 | }); | ||
461 | } | ||
462 | } | ||
463 | // Directly setting velocity means this is what the user really wants now. | ||
464 | public override OMV.Vector3 Velocity { | ||
465 | get { return _velocity; } | ||
466 | set { | ||
467 | _velocity = value; | ||
468 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); | ||
469 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() | ||
470 | { | ||
471 | _velocityMotor.Reset(); | ||
472 | _velocityMotor.SetCurrent(_velocity); | ||
473 | _velocityMotor.SetTarget(_velocity); | ||
474 | // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar. | ||
475 | _velocityMotor.Enabled = false; | ||
476 | |||
477 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); | ||
478 | ForceVelocity = _velocity; | ||
479 | }); | ||
480 | } | ||
481 | } | ||
482 | public override OMV.Vector3 ForceVelocity { | ||
483 | get { return _velocity; } | ||
484 | set { | ||
485 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); | ||
486 | |||
487 | _velocity = value; | ||
488 | // Depending on whether the avatar is moving or not, change the friction | ||
489 | // to keep the avatar from slipping around | ||
490 | if (_velocity.Length() == 0) | ||
491 | { | ||
492 | if (_currentFriction != BSParam.AvatarStandingFriction) | ||
493 | { | ||
494 | _currentFriction = BSParam.AvatarStandingFriction; | ||
495 | if (PhysBody.HasPhysicalBody) | ||
496 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | ||
497 | } | ||
498 | } | ||
499 | else | ||
500 | { | ||
501 | if (_currentFriction != BSParam.AvatarFriction) | ||
502 | { | ||
503 | _currentFriction = BSParam.AvatarFriction; | ||
504 | if (PhysBody.HasPhysicalBody) | ||
505 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | ||
506 | } | ||
507 | } | ||
508 | // Remember the set velocity so we can suppress the reduction by friction, ... | ||
509 | _appliedVelocity = value; | ||
510 | |||
511 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | ||
512 | BulletSimAPI.Activate2(PhysBody.ptr, true); | ||
513 | } | ||
514 | } | ||
515 | public override OMV.Vector3 Torque { | ||
516 | get { return _torque; } | ||
517 | set { _torque = value; | ||
518 | } | ||
519 | } | ||
520 | public override float CollisionScore { | ||
521 | get { return _collisionScore; } | ||
522 | set { _collisionScore = value; | ||
523 | } | ||
524 | } | ||
525 | public override OMV.Vector3 Acceleration { | ||
526 | get { return _acceleration; } | ||
527 | set { _acceleration = value; } | ||
528 | } | ||
529 | public override OMV.Quaternion RawOrientation | ||
530 | { | ||
531 | get { return _orientation; } | ||
532 | set { _orientation = value; } | ||
533 | } | ||
534 | public override OMV.Quaternion Orientation { | ||
535 | get { return _orientation; } | ||
536 | set { | ||
537 | _orientation = value; | ||
538 | // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); | ||
539 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() | ||
540 | { | ||
541 | if (PhysBody.HasPhysicalBody) | ||
542 | { | ||
543 | // _position = BulletSimAPI.GetPosition2(BSBody.ptr); | ||
544 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
545 | } | ||
546 | }); | ||
547 | } | ||
548 | } | ||
549 | // Go directly to Bullet to get/set the value. | ||
550 | public override OMV.Quaternion ForceOrientation | ||
551 | { | ||
552 | get | ||
553 | { | ||
554 | _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); | ||
555 | return _orientation; | ||
556 | } | ||
557 | set | ||
558 | { | ||
559 | _orientation = value; | ||
560 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
561 | } | ||
562 | } | ||
563 | public override int PhysicsActorType { | ||
564 | get { return _physicsActorType; } | ||
565 | set { _physicsActorType = value; | ||
566 | } | ||
567 | } | ||
568 | public override bool IsPhysical { | ||
569 | get { return _isPhysical; } | ||
570 | set { _isPhysical = value; | ||
571 | } | ||
572 | } | ||
573 | public override bool IsSolid { | ||
574 | get { return true; } | ||
575 | } | ||
576 | public override bool IsStatic { | ||
577 | get { return false; } | ||
578 | } | ||
579 | public override bool Flying { | ||
580 | get { return _flying; } | ||
581 | set { | ||
582 | _flying = value; | ||
583 | |||
584 | // simulate flying by changing the effect of gravity | ||
585 | Buoyancy = ComputeBuoyancyFromFlying(_flying); | ||
586 | } | ||
587 | } | ||
588 | // Flying is implimented by changing the avatar's buoyancy. | ||
589 | // Would this be done better with a vehicle type? | ||
590 | private float ComputeBuoyancyFromFlying(bool ifFlying) { | ||
591 | return ifFlying ? 1f : 0f; | ||
592 | } | ||
593 | public override bool | ||
594 | SetAlwaysRun { | ||
595 | get { return _setAlwaysRun; } | ||
596 | set { _setAlwaysRun = value; } | ||
597 | } | ||
598 | public override bool ThrottleUpdates { | ||
599 | get { return _throttleUpdates; } | ||
600 | set { _throttleUpdates = value; } | ||
601 | } | ||
602 | public override bool IsColliding { | ||
603 | get { return (CollidingStep == PhysicsScene.SimulationStep); } | ||
604 | set { _isColliding = value; } | ||
605 | } | ||
606 | public override bool CollidingGround { | ||
607 | get { return (CollidingGroundStep == PhysicsScene.SimulationStep); } | ||
608 | set { CollidingGround = value; } | ||
609 | } | ||
610 | public override bool CollidingObj { | ||
611 | get { return _collidingObj; } | ||
612 | set { _collidingObj = value; } | ||
613 | } | ||
614 | public override bool FloatOnWater { | ||
615 | set { | ||
616 | _floatOnWater = value; | ||
617 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() | ||
618 | { | ||
619 | if (PhysBody.HasPhysicalBody) | ||
620 | { | ||
621 | if (_floatOnWater) | ||
622 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | ||
623 | else | ||
624 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | ||
625 | } | ||
626 | }); | ||
627 | } | ||
628 | } | ||
629 | public override OMV.Vector3 RotationalVelocity { | ||
630 | get { return _rotationalVelocity; } | ||
631 | set { _rotationalVelocity = value; } | ||
632 | } | ||
633 | public override OMV.Vector3 ForceRotationalVelocity { | ||
634 | get { return _rotationalVelocity; } | ||
635 | set { _rotationalVelocity = value; } | ||
636 | } | ||
637 | public override bool Kinematic { | ||
638 | get { return _kinematic; } | ||
639 | set { _kinematic = value; } | ||
640 | } | ||
641 | // neg=fall quickly, 0=1g, 1=0g, pos=float up | ||
642 | public override float Buoyancy { | ||
643 | get { return _buoyancy; } | ||
644 | set { _buoyancy = value; | ||
645 | PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() | ||
646 | { | ||
647 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | ||
648 | ForceBuoyancy = _buoyancy; | ||
649 | }); | ||
650 | } | ||
651 | } | ||
652 | public override float ForceBuoyancy { | ||
653 | get { return _buoyancy; } | ||
654 | set { | ||
655 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); | ||
656 | |||
657 | _buoyancy = value; | ||
658 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | ||
659 | // Buoyancy is faked by changing the gravity applied to the object | ||
660 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | ||
661 | if (PhysBody.HasPhysicalBody) | ||
662 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | ||
663 | } | ||
664 | } | ||
665 | |||
666 | // Used for MoveTo | ||
667 | public override OMV.Vector3 PIDTarget { | ||
668 | set { _PIDTarget = value; } | ||
669 | } | ||
670 | public override bool PIDActive { | ||
671 | set { _usePID = value; } | ||
672 | } | ||
673 | public override float PIDTau { | ||
674 | set { _PIDTau = value; } | ||
675 | } | ||
676 | |||
677 | // Used for llSetHoverHeight and maybe vehicle height | ||
678 | // Hover Height will override MoveTo target's Z | ||
679 | public override bool PIDHoverActive { | ||
680 | set { _useHoverPID = value; } | ||
681 | } | ||
682 | public override float PIDHoverHeight { | ||
683 | set { _PIDHoverHeight = value; } | ||
684 | } | ||
685 | public override PIDHoverType PIDHoverType { | ||
686 | set { _PIDHoverType = value; } | ||
687 | } | ||
688 | public override float PIDHoverTau { | ||
689 | set { _PIDHoverTao = value; } | ||
690 | } | ||
691 | |||
692 | // For RotLookAt | ||
693 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
694 | public override bool APIDActive { set { return; } } | ||
695 | public override float APIDStrength { set { return; } } | ||
696 | public override float APIDDamping { set { return; } } | ||
697 | |||
698 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | ||
699 | if (force.IsFinite()) | ||
700 | { | ||
701 | _force.X += force.X; | ||
702 | _force.Y += force.Y; | ||
703 | _force.Z += force.Z; | ||
704 | // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); | ||
705 | PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() | ||
706 | { | ||
707 | DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); | ||
708 | if (PhysBody.HasPhysicalBody) | ||
709 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | ||
710 | }); | ||
711 | } | ||
712 | else | ||
713 | { | ||
714 | m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader); | ||
715 | } | ||
716 | //m_lastUpdateSent = false; | ||
717 | } | ||
718 | |||
719 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | ||
720 | } | ||
721 | public override void SetMomentum(OMV.Vector3 momentum) { | ||
722 | } | ||
723 | |||
724 | private void ComputeAvatarScale(OMV.Vector3 size) | ||
725 | { | ||
726 | OMV.Vector3 newScale = size; | ||
727 | // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; | ||
728 | // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; | ||
729 | |||
730 | // From the total height, remove the capsule half spheres that are at each end | ||
731 | // The 1.15f came from ODE. Not sure what this factors in. | ||
732 | // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y); | ||
733 | |||
734 | // The total scale height is the central cylindar plus the caps on the two ends. | ||
735 | newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f); | ||
736 | |||
737 | // Convert diameters to radii and height to half height -- the way Bullet expects it. | ||
738 | Scale = newScale / 2f; | ||
739 | } | ||
740 | |||
741 | // set _avatarVolume and _mass based on capsule size, _density and Scale | ||
742 | private void ComputeAvatarVolumeAndMass() | ||
743 | { | ||
744 | _avatarVolume = (float)( | ||
745 | Math.PI | ||
746 | * Scale.X | ||
747 | * Scale.Y // the area of capsule cylinder | ||
748 | * Scale.Z // times height of capsule cylinder | ||
749 | + 1.33333333f | ||
750 | * Math.PI | ||
751 | * Scale.X | ||
752 | * Math.Min(Scale.X, Scale.Y) | ||
753 | * Scale.Y // plus the volume of the capsule end caps | ||
754 | ); | ||
755 | _mass = _avatarDensity * _avatarVolume; | ||
756 | } | ||
757 | |||
758 | // The physics engine says that properties have updated. Update same and inform | ||
759 | // the world that things have changed. | ||
760 | public override void UpdateProperties(EntityProperties entprop) | ||
761 | { | ||
762 | _position = entprop.Position; | ||
763 | _orientation = entprop.Rotation; | ||
764 | _velocity = entprop.Velocity; | ||
765 | _acceleration = entprop.Acceleration; | ||
766 | _rotationalVelocity = entprop.RotationalVelocity; | ||
767 | |||
768 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. | ||
769 | PositionSanityCheck(true); | ||
770 | |||
771 | if (_velocityMotor.Enabled) | ||
772 | { | ||
773 | // TODO: Decide if the step parameters should be changed depending on the avatar's | ||
774 | // state (flying, colliding, ...). | ||
775 | |||
776 | OMV.Vector3 stepVelocity = _velocityMotor.Step(PhysicsScene.LastTimeStep); | ||
777 | |||
778 | // If falling, we keep the world's downward vector no matter what the other axis specify. | ||
779 | if (!Flying && !IsColliding) | ||
780 | { | ||
781 | stepVelocity.Z = entprop.Velocity.Z; | ||
782 | DetailLog("{0},BSCharacter.UpdateProperties,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity); | ||
783 | } | ||
784 | |||
785 | // If the user has said stop and we've stopped applying velocity correction, | ||
786 | // the motor can be turned off. Set the velocity to zero so the zero motion is sent to the viewer. | ||
787 | if (_velocityMotor.TargetValue.ApproxEquals(OMV.Vector3.Zero, 0.01f) && _velocityMotor.ErrorIsZero) | ||
788 | { | ||
789 | ZeroMotion(true); | ||
790 | stepVelocity = OMV.Vector3.Zero; | ||
791 | _velocityMotor.Enabled = false; | ||
792 | DetailLog("{0},BSCharacter.UpdateProperties,taint,disableVelocityMotor,m={1}", LocalID, _velocityMotor); | ||
793 | } | ||
794 | |||
795 | _velocity = stepVelocity; | ||
796 | entprop.Velocity = _velocity; | ||
797 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | ||
798 | } | ||
799 | |||
800 | // remember the current and last set values | ||
801 | LastEntityProperties = CurrentEntityProperties; | ||
802 | CurrentEntityProperties = entprop; | ||
803 | |||
804 | // Tell the linkset about value changes | ||
805 | Linkset.UpdateProperties(this, true); | ||
806 | |||
807 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. | ||
808 | // base.RequestPhysicsterseUpdate(); | ||
809 | |||
810 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
811 | LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | ||
812 | } | ||
813 | } | ||
814 | } | ||