aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs')
-rw-r--r--OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs1474
1 files changed, 1474 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs
new file mode 100644
index 0000000..9c1b87b
--- /dev/null
+++ b/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs
@@ -0,0 +1,1474 @@
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 copyright
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
28
29// Revision by Ubit 2011/12
30
31using System;
32using System.Collections.Generic;
33using System.Reflection;
34using OpenMetaverse;
35using OdeAPI;
36using OpenSim.Framework;
37using OpenSim.Region.Physics.Manager;
38using log4net;
39
40namespace OpenSim.Region.Physics.OdePlugin
41{
42 /// <summary>
43 /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves.
44 /// </summary>
45
46 public enum dParam : int
47 {
48 LowStop = 0,
49 HiStop = 1,
50 Vel = 2,
51 FMax = 3,
52 FudgeFactor = 4,
53 Bounce = 5,
54 CFM = 6,
55 StopERP = 7,
56 StopCFM = 8,
57 LoStop2 = 256,
58 HiStop2 = 257,
59 Vel2 = 258,
60 FMax2 = 259,
61 StopERP2 = 7 + 256,
62 StopCFM2 = 8 + 256,
63 LoStop3 = 512,
64 HiStop3 = 513,
65 Vel3 = 514,
66 FMax3 = 515,
67 StopERP3 = 7 + 512,
68 StopCFM3 = 8 + 512
69 }
70
71 public class OdeCharacter : PhysicsActor
72 {
73 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
74
75 private Vector3 _position;
76 private Vector3 _zeroPosition;
77 private bool _zeroFlag = false;
78 private Vector3 _velocity;
79 private Vector3 _target_velocity;
80 private Vector3 _acceleration;
81 private Vector3 m_rotationalVelocity;
82 private float m_mass = 80f;
83 public float m_density = 60f;
84 private bool m_pidControllerActive = true;
85 public float PID_D = 800.0f;
86 public float PID_P = 900.0f;
87 //private static float POSTURE_SERVO = 10000.0f;
88 public float CAPSULE_RADIUS = 0.37f;
89 public float CAPSULE_LENGTH = 2.140599f;
90 public float walkDivisor = 1.3f;
91 public float runDivisor = 0.8f;
92 private bool flying = false;
93 private bool m_iscolliding = false;
94 private bool m_iscollidingGround = false;
95 private bool m_iscollidingObj = false;
96 private bool m_alwaysRun = false;
97 private int m_requestedUpdateFrequency = 0;
98 public uint m_localID = 0;
99 public bool m_returnCollisions = false;
100 // taints and their non-tainted counterparts
101 public bool m_isPhysical = false; // the current physical status
102 public float MinimumGroundFlightOffset = 3f;
103
104 private float m_buoyancy = 0f;
105
106 // private CollisionLocker ode;
107
108 private string m_name = String.Empty;
109 // other filter control
110 int m_colliderfilter = 0;
111 // int m_colliderGroundfilter = 0;
112 int m_colliderObjectfilter = 0;
113
114 // Default we're a Character
115 private CollisionCategories m_collisionCategories = (CollisionCategories.Character);
116
117 // Default, Collide with Other Geometries, spaces, bodies and characters.
118 private CollisionCategories m_collisionFlags = (CollisionCategories.Character
119 | CollisionCategories.Geom
120 | CollisionCategories.VolumeDtc
121 );
122 // we do land collisions not ode | CollisionCategories.Land);
123 public IntPtr Body = IntPtr.Zero;
124 private OdeScene _parent_scene;
125 public IntPtr Shell = IntPtr.Zero;
126 public IntPtr Amotor = IntPtr.Zero;
127 public d.Mass ShellMass;
128// public bool collidelock = false;
129
130 private bool m_haseventsubscription = false;
131 public int m_eventsubscription = 0;
132 private CollisionEventUpdate CollisionEventsThisFrame = new CollisionEventUpdate();
133
134 // unique UUID of this character object
135 public UUID m_uuid;
136 public bool bad = false;
137
138 float mu;
139
140 public OdeCharacter(String avName, OdeScene parent_scene, Vector3 pos, Vector3 size, float pid_d, float pid_p, float capsule_radius, float density, float walk_divisor, float rundivisor)
141 {
142 m_uuid = UUID.Random();
143
144 if (pos.IsFinite())
145 {
146 if (pos.Z > 99999f)
147 {
148 pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
149 }
150 if (pos.Z < -100f) // shouldn't this be 0 ?
151 {
152 pos.Z = parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
153 }
154 _position = pos;
155 }
156 else
157 {
158 _position = new Vector3(((float)_parent_scene.WorldExtents.X * 0.5f), ((float)_parent_scene.WorldExtents.Y * 0.5f), parent_scene.GetTerrainHeightAtXY(128f, 128f) + 10f);
159 m_log.Warn("[PHYSICS]: Got NaN Position on Character Create");
160 }
161
162 _parent_scene = parent_scene;
163
164 PID_D = pid_d;
165 PID_P = pid_p;
166 CAPSULE_RADIUS = capsule_radius;
167 m_density = density;
168 m_mass = 80f; // sure we have a default
169
170 mu = parent_scene.AvatarFriction;
171
172 walkDivisor = walk_divisor;
173 runDivisor = rundivisor;
174
175 CAPSULE_LENGTH = size.Z * 1.15f - CAPSULE_RADIUS * 2.0f;
176 //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString());
177
178 m_isPhysical = false; // current status: no ODE information exists
179
180 m_name = avName;
181
182 AddChange(changes.Add, null);
183 }
184
185 public override int PhysicsActorType
186 {
187 get { return (int)ActorTypes.Agent; }
188 set { return; }
189 }
190
191 public override void getContactData(ref ContactData cdata)
192 {
193 cdata.mu = mu;
194 cdata.bounce = 0;
195 cdata.softcolide = false;
196 }
197
198 public override bool Building { get; set; }
199
200 /// <summary>
201 /// If this is set, the avatar will move faster
202 /// </summary>
203 public override bool SetAlwaysRun
204 {
205 get { return m_alwaysRun; }
206 set { m_alwaysRun = value; }
207 }
208
209 public override uint LocalID
210 {
211 set { m_localID = value; }
212 }
213
214 public override bool Grabbed
215 {
216 set { return; }
217 }
218
219 public override bool Selected
220 {
221 set { return; }
222 }
223
224 public override float Buoyancy
225 {
226 get { return m_buoyancy; }
227 set { m_buoyancy = value; }
228 }
229
230 public override bool FloatOnWater
231 {
232 set { return; }
233 }
234
235 public override bool IsPhysical
236 {
237 get { return false; }
238 set { return; }
239 }
240
241 public override bool ThrottleUpdates
242 {
243 get { return false; }
244 set { return; }
245 }
246
247 public override bool Flying
248 {
249 get { return flying; }
250 set
251 {
252 flying = value;
253 // m_log.DebugFormat("[PHYSICS]: Set OdeCharacter Flying to {0}", flying);
254 }
255 }
256
257 /// <summary>
258 /// Returns if the avatar is colliding in general.
259 /// This includes the ground and objects and avatar.
260 /// </summary>
261 public override bool IsColliding
262 {
263 get { return (m_iscolliding || m_iscollidingGround); }
264 set
265 {
266 if (value)
267 {
268 m_colliderfilter += 2;
269 if (m_colliderfilter > 2)
270 m_colliderfilter = 2;
271 }
272 else
273 {
274 m_colliderfilter--;
275 if (m_colliderfilter < 0)
276 m_colliderfilter = 0;
277 }
278
279 if (m_colliderfilter == 0)
280 m_iscolliding = false;
281 else
282 {
283// SetPidStatus(false);
284 m_pidControllerActive = true;
285 m_iscolliding = true;
286 }
287 }
288 }
289
290 /// <summary>
291 /// Returns if an avatar is colliding with the ground
292 /// </summary>
293 public override bool CollidingGround
294 {
295 get { return m_iscollidingGround; }
296 set
297 {
298 /* we now control this
299 if (value)
300 {
301 m_colliderGroundfilter += 2;
302 if (m_colliderGroundfilter > 2)
303 m_colliderGroundfilter = 2;
304 }
305 else
306 {
307 m_colliderGroundfilter--;
308 if (m_colliderGroundfilter < 0)
309 m_colliderGroundfilter = 0;
310 }
311
312 if (m_colliderGroundfilter == 0)
313 m_iscollidingGround = false;
314 else
315 m_iscollidingGround = true;
316 */
317 }
318
319 }
320
321 /// <summary>
322 /// Returns if the avatar is colliding with an object
323 /// </summary>
324 public override bool CollidingObj
325 {
326 get { return m_iscollidingObj; }
327 set
328 {
329 // Ubit filter this also
330 if (value)
331 {
332 m_colliderObjectfilter += 2;
333 if (m_colliderObjectfilter > 2)
334 m_colliderObjectfilter = 2;
335 }
336 else
337 {
338 m_colliderObjectfilter--;
339 if (m_colliderObjectfilter < 0)
340 m_colliderObjectfilter = 0;
341 }
342
343 if (m_colliderObjectfilter == 0)
344 m_iscollidingObj = false;
345 else
346 m_iscollidingObj = true;
347
348 // m_iscollidingObj = value;
349/*
350 if (m_iscollidingObj)
351 m_pidControllerActive = false;
352 else
353 m_pidControllerActive = true;
354 */
355 }
356 }
357
358 /// <summary>
359 /// turn the PID controller on or off.
360 /// The PID Controller will turn on all by itself in many situations
361 /// </summary>
362 /// <param name="status"></param>
363 public void SetPidStatus(bool status)
364 {
365 m_pidControllerActive = status;
366 }
367
368 public override bool Stopped
369 {
370 get { return _zeroFlag; }
371 }
372
373 /// <summary>
374 /// This 'puts' an avatar somewhere in the physics space.
375 /// Not really a good choice unless you 'know' it's a good
376 /// spot otherwise you're likely to orbit the avatar.
377 /// </summary>
378 public override Vector3 Position
379 {
380 get { return _position; }
381 set
382 {
383 if (Body == IntPtr.Zero || Shell == IntPtr.Zero)
384 {
385 if (value.IsFinite())
386 {
387 if (value.Z > 9999999f)
388 {
389 value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
390 }
391 if (value.Z < -100f)
392 {
393 value.Z = _parent_scene.GetTerrainHeightAtXY(127, 127) + 5;
394 }
395 AddChange(changes.Position, value);
396 }
397 else
398 {
399 m_log.Warn("[PHYSICS]: Got a NaN Position from Scene on a Character");
400 }
401 }
402 }
403 }
404
405 public override Vector3 RotationalVelocity
406 {
407 get { return m_rotationalVelocity; }
408 set { m_rotationalVelocity = value; }
409 }
410
411 /// <summary>
412 /// This property sets the height of the avatar only. We use the height to make sure the avatar stands up straight
413 /// and use it to offset landings properly
414 /// </summary>
415 public override Vector3 Size
416 {
417 get {
418 float d = CAPSULE_RADIUS * 2;
419 return new Vector3(d, d, (CAPSULE_LENGTH +d)/1.15f); }
420 set
421 {
422 if (value.IsFinite())
423 {
424 AddChange(changes.Size, value);
425 }
426 else
427 {
428 m_log.Warn("[PHYSICS]: Got a NaN Size from Scene on a Character");
429 }
430 }
431 }
432
433 /// <summary>
434 /// This creates the Avatar's physical Surrogate at the position supplied
435 /// </summary>
436 /// <param name="npositionX"></param>
437 /// <param name="npositionY"></param>
438 /// <param name="npositionZ"></param>
439
440 //
441 /// <summary>
442 /// Uses the capped cyllinder volume formula to calculate the avatar's mass.
443 /// This may be used in calculations in the scene/scenepresence
444 /// </summary>
445 public override float Mass
446 {
447 get
448 {
449 float AVvolume = (float)(Math.PI * CAPSULE_RADIUS * CAPSULE_RADIUS * (1.3333333333f * CAPSULE_RADIUS + CAPSULE_LENGTH));
450 return m_density * AVvolume;
451 }
452 }
453 public override void link(PhysicsActor obj)
454 {
455
456 }
457
458 public override void delink()
459 {
460
461 }
462
463 public override void LockAngularMotion(Vector3 axis)
464 {
465
466 }
467
468
469 public override Vector3 Force
470 {
471 get { return _target_velocity; }
472 set { return; }
473 }
474
475 public override int VehicleType
476 {
477 get { return 0; }
478 set { return; }
479 }
480
481 public override void VehicleFloatParam(int param, float value)
482 {
483
484 }
485
486 public override void VehicleVectorParam(int param, Vector3 value)
487 {
488
489 }
490
491 public override void VehicleRotationParam(int param, Quaternion rotation)
492 {
493
494 }
495
496 public override void VehicleFlags(int param, bool remove)
497 {
498
499 }
500
501 public override void SetVolumeDetect(int param)
502 {
503
504 }
505
506 public override Vector3 CenterOfMass
507 {
508 get
509 {
510 Vector3 pos = _position;
511 return pos;
512 }
513 }
514
515 public override Vector3 GeometricCenter
516 {
517 get
518 {
519 Vector3 pos = _position;
520 return pos;
521 }
522 }
523
524 //UBit mess
525 /* for later use
526 public override Vector3 PrimOOBsize
527 {
528 get
529 {
530 Vector3 s=Size;
531 s.X *=0.5f;
532 s.Y *=0.5f;
533 s.Z *=0.5f;
534 return s;
535 }
536 }
537
538 public override Vector3 PrimOOBoffset
539 {
540 get
541 {
542 return Vector3.Zero;
543 }
544 }
545 */
546
547 public override PrimitiveBaseShape Shape
548 {
549 set { return; }
550 }
551
552 public override Vector3 Velocity
553 {
554 get
555 {
556 return _velocity;
557 }
558 set
559 {
560 if (value.IsFinite())
561 {
562 AddChange(changes.Velocity, value);
563 }
564 else
565 {
566 m_log.Warn("[PHYSICS]: Got a NaN velocity from Scene in a Character");
567 }
568 }
569 }
570
571 public override Vector3 Torque
572 {
573 get { return Vector3.Zero; }
574 set { return; }
575 }
576
577 public override float CollisionScore
578 {
579 get { return 0f; }
580 set { }
581 }
582
583 public override bool Kinematic
584 {
585 get { return false; }
586 set { }
587 }
588
589 public override Quaternion Orientation
590 {
591 get { return Quaternion.Identity; }
592 set
593 {
594 }
595 }
596
597 public override Vector3 Acceleration
598 {
599 get { return _acceleration; }
600 set { }
601 }
602
603 public void SetAcceleration(Vector3 accel)
604 {
605 m_pidControllerActive = true;
606 _acceleration = accel;
607 }
608
609 /// <summary>
610 /// Adds the force supplied to the Target Velocity
611 /// The PID controller takes this target velocity and tries to make it a reality
612 /// </summary>
613 /// <param name="force"></param>
614 public override void AddForce(Vector3 force, bool pushforce)
615 {
616 if (force.IsFinite())
617 {
618 if (pushforce)
619 {
620 AddChange(changes.Force, force * m_density / _parent_scene.ODE_STEPSIZE / 28f);
621 }
622 else
623 {
624 AddChange(changes.Velocity, force);
625 }
626 }
627 else
628 {
629 m_log.Warn("[PHYSICS]: Got a NaN force applied to a Character");
630 }
631 //m_lastUpdateSent = false;
632 }
633
634 public override void AddAngularForce(Vector3 force, bool pushforce)
635 {
636
637 }
638
639 public override void SetMomentum(Vector3 momentum)
640 {
641 if (momentum.IsFinite())
642 AddChange(changes.Momentum, momentum);
643 }
644
645
646 // WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access
647 // to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only
648 // place that is safe to call this routine AvatarGeomAndBodyCreation.
649 private void AvatarGeomAndBodyCreation(float npositionX, float npositionY, float npositionZ)
650 {
651 _parent_scene.waitForSpaceUnlock(_parent_scene.ActiveSpace);
652 if (CAPSULE_LENGTH <= 0)
653 {
654 m_log.Warn("[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!");
655 CAPSULE_LENGTH = 0.01f;
656
657 }
658
659 if (CAPSULE_RADIUS <= 0)
660 {
661 m_log.Warn("[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!");
662 CAPSULE_RADIUS = 0.01f;
663
664 }
665 Shell = d.CreateCapsule(_parent_scene.ActiveSpace, CAPSULE_RADIUS, CAPSULE_LENGTH);
666
667 d.GeomSetCategoryBits(Shell, (uint)m_collisionCategories);
668 d.GeomSetCollideBits(Shell, (uint)m_collisionFlags);
669
670 d.MassSetCapsule(out ShellMass, m_density, 3, CAPSULE_RADIUS, CAPSULE_LENGTH);
671
672 m_mass = ShellMass.mass; // update mass
673
674 // rescale PID parameters
675 PID_D = _parent_scene.avPIDD;
676 PID_P = _parent_scene.avPIDP;
677
678 // rescale PID parameters so that this aren't affected by mass
679 // and so don't get unstable for some masses
680 // also scale by ode time step so you don't need to refix them
681
682 PID_D /= 50 * 80; //scale to original mass of around 80 and 50 ODE fps
683 PID_D *= m_mass / _parent_scene.ODE_STEPSIZE;
684 PID_P /= 50 * 80;
685 PID_P *= m_mass / _parent_scene.ODE_STEPSIZE;
686
687 Body = d.BodyCreate(_parent_scene.world);
688
689 d.BodySetAutoDisableFlag(Body, false);
690 d.BodySetPosition(Body, npositionX, npositionY, npositionZ);
691
692 _position.X = npositionX;
693 _position.Y = npositionY;
694 _position.Z = npositionZ;
695
696 d.BodySetMass(Body, ref ShellMass);
697 d.GeomSetBody(Shell, Body);
698
699 // The purpose of the AMotor here is to keep the avatar's physical
700 // surrogate from rotating while moving
701 Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero);
702 d.JointAttach(Amotor, Body, IntPtr.Zero);
703
704 d.JointSetAMotorMode(Amotor, 0);
705 d.JointSetAMotorNumAxes(Amotor, 3);
706 d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0);
707 d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0);
708 d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1);
709
710 d.JointSetAMotorAngle(Amotor, 0, 0);
711 d.JointSetAMotorAngle(Amotor, 1, 0);
712 d.JointSetAMotorAngle(Amotor, 2, 0);
713
714 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM, 0f); // make it HARD
715 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM2, 0f);
716 d.JointSetAMotorParam(Amotor, (int)dParam.StopCFM3, 0f);
717 d.JointSetAMotorParam(Amotor, (int)dParam.StopERP, 0.8f);
718 d.JointSetAMotorParam(Amotor, (int)dParam.StopERP2, 0.8f);
719 d.JointSetAMotorParam(Amotor, (int)dParam.StopERP3, 0.8f);
720
721 // These lowstops and high stops are effectively (no wiggle room)
722 d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -1e-5f);
723 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 1e-5f);
724 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -1e-5f);
725 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 1e-5f);
726 d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -1e-5f);
727 d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 1e-5f);
728
729 d.JointSetAMotorParam(Amotor, (int)d.JointParam.Vel, 0);
730 d.JointSetAMotorParam(Amotor, (int)d.JointParam.Vel2, 0);
731 d.JointSetAMotorParam(Amotor, (int)d.JointParam.Vel3, 0);
732
733 d.JointSetAMotorParam(Amotor, (int)dParam.FMax, 5e6f);
734 d.JointSetAMotorParam(Amotor, (int)dParam.FMax2, 5e6f);
735 d.JointSetAMotorParam(Amotor, (int)dParam.FMax3, 5e6f);
736 }
737
738 /// <summary>
739 /// Destroys the avatar body and geom
740
741 private void AvatarGeomAndBodyDestroy()
742 {
743 // Kill the Amotor
744 if (Amotor != IntPtr.Zero)
745 {
746 d.JointDestroy(Amotor);
747 Amotor = IntPtr.Zero;
748 }
749
750 if (Body != IntPtr.Zero)
751 {
752 //kill the body
753 d.BodyDestroy(Body);
754 Body = IntPtr.Zero;
755 }
756
757 //kill the Geometry
758 if (Shell != IntPtr.Zero)
759 {
760 _parent_scene.geom_name_map.Remove(Shell);
761 _parent_scene.waitForSpaceUnlock(_parent_scene.ActiveSpace);
762 d.GeomDestroy(Shell);
763 Shell = IntPtr.Zero;
764 }
765 }
766
767 /// <summary>
768 /// Called from Simulate
769 /// This is the avatar's movement control + PID Controller
770 /// </summary>
771 /// <param name="timeStep"></param>
772 public void Move(float timeStep, List<OdeCharacter> defects)
773 {
774 // no lock; for now it's only called from within Simulate()
775
776 // If the PID Controller isn't active then we set our force
777 // calculating base velocity to the current position
778
779 if (Body == IntPtr.Zero)
780 return;
781
782 d.Vector3 dtmp;
783 d.BodyCopyPosition(Body, out dtmp);
784 Vector3 localpos = new Vector3(dtmp.X, dtmp.Y, dtmp.Z);
785
786 // the Amotor still lets avatar rotation to drift during colisions
787 // so force it back to identity
788
789 d.Quaternion qtmp;
790 qtmp.W = 1;
791 qtmp.X = 0;
792 qtmp.Y = 0;
793 qtmp.Z = 0;
794 d.BodySetQuaternion(Body, ref qtmp);
795
796 if (m_pidControllerActive == false)
797 {
798 _zeroPosition = localpos;
799 }
800 //PidStatus = true;
801
802
803 if (!localpos.IsFinite())
804 {
805
806 m_log.Warn("[PHYSICS]: Avatar Position is non-finite!");
807 defects.Add(this);
808 // _parent_scene.RemoveCharacter(this);
809
810 // destroy avatar capsule and related ODE data
811 AvatarGeomAndBodyDestroy();
812
813 return;
814 }
815
816 Vector3 vec = Vector3.Zero;
817 dtmp = d.BodyGetLinearVel(Body);
818 Vector3 vel = new Vector3(dtmp.X, dtmp.Y, dtmp.Z);
819
820 float movementdivisor = 1f;
821 //Ubit change divisions into multiplications below
822 if (!m_alwaysRun)
823 {
824 movementdivisor = 1 / walkDivisor;
825 }
826 else
827 {
828 movementdivisor = 1 / runDivisor;
829 }
830
831 // colide with land
832
833 d.AABB aabb;
834 d.GeomGetAABB(Shell, out aabb);
835 float chrminZ = aabb.MinZ;
836
837 Vector3 posch = localpos;
838
839 float ftmp;
840
841 if (flying)
842 {
843 ftmp = timeStep;
844 posch.X += vel.X * ftmp;
845 posch.Y += vel.Y * ftmp;
846 }
847
848 float terrainheight = _parent_scene.GetTerrainHeightAtXY(posch.X, posch.Y);
849 if (chrminZ < terrainheight)
850 {
851 float depth = terrainheight - chrminZ;
852 if (!flying)
853 {
854 vec.Z = -vel.Z * PID_D * 1.5f + depth * PID_P * 50;
855 }
856 else
857 vec.Z = depth * PID_P * 50;
858
859 /*
860 Vector3 vtmp;
861 vtmp.X = _target_velocity.X * timeStep;
862 vtmp.Y = _target_velocity.Y * timeStep;
863 // fake and avoid squares
864 float k = (Math.Abs(vtmp.X) + Math.Abs(vtmp.Y));
865 if (k > 0)
866 {
867 posch.X += vtmp.X;
868 posch.Y += vtmp.Y;
869 terrainheight -= _parent_scene.GetTerrainHeightAtXY(posch.X, posch.Y);
870 k = 1 + Math.Abs(terrainheight) / k;
871 movementdivisor /= k;
872
873 if (k < 1)
874 k = 1;
875 }
876 */
877
878
879 if (depth < 0.1f)
880 {
881 m_iscolliding = true;
882 m_colliderfilter = 2;
883 m_iscollidingGround = true;
884
885 ContactPoint contact = new ContactPoint();
886 contact.PenetrationDepth = depth;
887 contact.Position.X = localpos.X;
888 contact.Position.Y = localpos.Y;
889 contact.Position.Z = chrminZ;
890 contact.SurfaceNormal.X = 0f;
891 contact.SurfaceNormal.Y = 0f;
892 contact.SurfaceNormal.Z = -1f;
893 AddCollisionEvent(0, contact);
894
895 vec.Z *= 0.5f;
896 }
897
898 else
899 m_iscollidingGround = false;
900 }
901 else
902 m_iscollidingGround = false;
903
904
905 // if velocity is zero, use position control; otherwise, velocity control
906 if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f
907 && m_iscolliding)
908 {
909 // keep track of where we stopped. No more slippin' & slidin'
910 if (!_zeroFlag)
911 {
912 _zeroFlag = true;
913 _zeroPosition = localpos;
914 }
915 if (m_pidControllerActive)
916 {
917 // We only want to deactivate the PID Controller if we think we want to have our surrogate
918 // react to the physics scene by moving it's position.
919 // Avatar to Avatar collisions
920 // Prim to avatar collisions
921
922 vec.X = -vel.X * PID_D + (_zeroPosition.X - localpos.X) * (PID_P * 2);
923 vec.Y = -vel.Y * PID_D + (_zeroPosition.Y - localpos.Y) * (PID_P * 2);
924 if (flying)
925 {
926 vec.Z += -vel.Z * PID_D + (_zeroPosition.Z - localpos.Z) * PID_P;
927 }
928 }
929 //PidStatus = true;
930 }
931 else
932 {
933 m_pidControllerActive = true;
934 _zeroFlag = false;
935
936 if (m_iscolliding)
937 {
938 if (!flying)
939 {
940 if (_target_velocity.Z > 0.0f)
941 {
942 // We're colliding with something and we're not flying but we're moving
943 // This means we're walking or running. JUMPING
944 vec.Z += (_target_velocity.Z - vel.Z) * PID_D * 1.2f;// +(_zeroPosition.Z - localpos.Z) * PID_P;
945 }
946 // We're standing on something
947 vec.X = ((_target_velocity.X * movementdivisor) - vel.X) * (PID_D);
948 vec.Y = ((_target_velocity.Y * movementdivisor) - vel.Y) * (PID_D);
949 }
950 else
951 {
952 // We're flying and colliding with something
953 vec.X = ((_target_velocity.X * movementdivisor) - vel.X) * (PID_D * 0.0625f);
954 vec.Y = ((_target_velocity.Y * movementdivisor) - vel.Y) * (PID_D * 0.0625f);
955 vec.Z += (_target_velocity.Z - vel.Z) * (PID_D);
956 }
957 }
958 else // ie not colliding
959 {
960 if (flying) //(!m_iscolliding && flying)
961 {
962 // we're in mid air suspended
963 vec.X = ((_target_velocity.X * movementdivisor) - vel.X) * (PID_D * 1.667f);
964 vec.Y = ((_target_velocity.Y * movementdivisor) - vel.Y) * (PID_D * 1.667f);
965 vec.Z += (_target_velocity.Z - vel.Z) * (PID_D);
966 }
967
968 else
969 {
970 // we're not colliding and we're not flying so that means we're falling!
971 // m_iscolliding includes collisions with the ground.
972
973 // d.Vector3 pos = d.BodyGetPosition(Body);
974 vec.X = (_target_velocity.X - vel.X) * PID_D * 0.833f;
975 vec.Y = (_target_velocity.Y - vel.Y) * PID_D * 0.833f;
976 }
977 }
978 }
979
980 if (flying)
981 {
982 vec.Z -= _parent_scene.gravityz * m_mass;
983
984 //Added for auto fly height. Kitto Flora
985 float target_altitude = _parent_scene.GetTerrainHeightAtXY(localpos.X, localpos.Y) + MinimumGroundFlightOffset;
986
987 if (localpos.Z < target_altitude)
988 {
989 vec.Z += (target_altitude - localpos.Z) * PID_P * 5.0f;
990 }
991 // end add Kitto Flora
992 }
993
994 if (vel.X * vel.X + vel.Y * vel.Y + vel.Z * vel.Z > 2500.0f) // 50m/s apply breaks
995 {
996 float breakfactor = 0.16f * m_mass; // will give aprox 60m/s terminal velocity at free fall
997 vec.X -= breakfactor * vel.X;
998 vec.Y -= breakfactor * vel.Y;
999 vec.Z -= breakfactor * vel.Z;
1000 }
1001
1002 if (vec.IsFinite())
1003 {
1004 if (vec.X != 0 || vec.Y !=0 || vec.Z !=0)
1005 d.BodyAddForce(Body, vec.X, vec.Y, vec.Z);
1006 }
1007 else
1008 {
1009 m_log.Warn("[PHYSICS]: Got a NaN force vector in Move()");
1010 m_log.Warn("[PHYSICS]: Avatar Position is non-finite!");
1011 defects.Add(this);
1012 // _parent_scene.RemoveCharacter(this);
1013 // destroy avatar capsule and related ODE data
1014 AvatarGeomAndBodyDestroy();
1015 }
1016 }
1017
1018 /// <summary>
1019 /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence.
1020 /// </summary>
1021 public void UpdatePositionAndVelocity()
1022 {
1023 // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit!
1024 if (Body == IntPtr.Zero)
1025 return;
1026
1027 d.Vector3 vec;
1028 try
1029 {
1030 d.BodyCopyPosition(Body, out vec);
1031 }
1032 catch (NullReferenceException)
1033 {
1034 bad = true;
1035 _parent_scene.BadCharacter(this);
1036 vec = new d.Vector3(_position.X, _position.Y, _position.Z);
1037 base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem!
1038 m_log.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}", m_name, m_uuid);
1039 }
1040
1041 _position.X = vec.X;
1042 _position.Y = vec.Y;
1043 _position.Z = vec.Z;
1044
1045 bool fixbody = false;
1046
1047 if (_position.X < 0.0f)
1048 {
1049 fixbody = true;
1050 _position.X = 0.1f;
1051 }
1052 else if (_position.X > (int)_parent_scene.WorldExtents.X - 0.1f)
1053 {
1054 fixbody = true;
1055 _position.X = (int)_parent_scene.WorldExtents.X - 0.1f;
1056 }
1057
1058 if (_position.Y < 0.0f)
1059 {
1060 fixbody = true;
1061 _position.Y = 0.1f;
1062 }
1063 else if (_position.Y > (int)_parent_scene.WorldExtents.Y - 0.1)
1064 {
1065 fixbody = true;
1066 _position.Y = (int)_parent_scene.WorldExtents.Y - 0.1f;
1067 }
1068
1069 if (fixbody)
1070 d.BodySetPosition(Body, _position.X, _position.Y, _position.Z);
1071
1072 // Did we move last? = zeroflag
1073 // This helps keep us from sliding all over
1074/*
1075 if (_zeroFlag)
1076 {
1077 _velocity.X = 0.0f;
1078 _velocity.Y = 0.0f;
1079 _velocity.Z = 0.0f;
1080
1081 // Did we send out the 'stopped' message?
1082 if (!m_lastUpdateSent)
1083 {
1084 m_lastUpdateSent = true;
1085 base.RequestPhysicsterseUpdate();
1086 }
1087 }
1088 else
1089 {
1090 m_lastUpdateSent = false;
1091 */
1092 try
1093 {
1094 vec = d.BodyGetLinearVel(Body);
1095 }
1096 catch (NullReferenceException)
1097 {
1098 vec.X = _velocity.X;
1099 vec.Y = _velocity.Y;
1100 vec.Z = _velocity.Z;
1101 }
1102 _velocity.X = (vec.X);
1103 _velocity.Y = (vec.Y);
1104 _velocity.Z = (vec.Z);
1105 // }
1106 }
1107
1108 /// <summary>
1109 /// Cleanup the things we use in the scene.
1110 /// </summary>
1111 public void Destroy()
1112 {
1113 AddChange(changes.Remove, null);
1114 }
1115
1116 public override void CrossingFailure()
1117 {
1118 }
1119
1120 public override Vector3 PIDTarget { set { return; } }
1121 public override bool PIDActive { set { return; } }
1122 public override float PIDTau { set { return; } }
1123
1124 public override float PIDHoverHeight { set { return; } }
1125 public override bool PIDHoverActive { set { return; } }
1126 public override PIDHoverType PIDHoverType { set { return; } }
1127 public override float PIDHoverTau { set { return; } }
1128
1129 public override Quaternion APIDTarget { set { return; } }
1130
1131 public override bool APIDActive { set { return; } }
1132
1133 public override float APIDStrength { set { return; } }
1134
1135 public override float APIDDamping { set { return; } }
1136
1137
1138 public override void SubscribeEvents(int ms)
1139 {
1140 m_requestedUpdateFrequency = ms;
1141 m_eventsubscription = ms;
1142 _parent_scene.AddCollisionEventReporting(this);
1143 m_haseventsubscription = true;
1144 }
1145
1146 public override void UnSubscribeEvents()
1147 {
1148 m_haseventsubscription = false;
1149 _parent_scene.RemoveCollisionEventReporting(this);
1150 m_requestedUpdateFrequency = 0;
1151 m_eventsubscription = 0;
1152 }
1153
1154 public void AddCollisionEvent(uint CollidedWith, ContactPoint contact)
1155 {
1156 if (m_haseventsubscription)
1157 {
1158 // m_log.DebugFormat(
1159 // "[PHYSICS]: Adding collision event for {0}, collidedWith {1}, contact {2}", "", CollidedWith, contact);
1160
1161 CollisionEventsThisFrame.AddCollider(CollidedWith, contact);
1162 }
1163 }
1164
1165 public void SendCollisions()
1166 {
1167 if (m_haseventsubscription && m_eventsubscription > m_requestedUpdateFrequency)
1168 {
1169 if (CollisionEventsThisFrame != null)
1170 {
1171 base.SendCollisionUpdate(CollisionEventsThisFrame);
1172 }
1173 CollisionEventsThisFrame = new CollisionEventUpdate();
1174 m_eventsubscription = 0;
1175 }
1176 }
1177
1178 public override bool SubscribedEvents()
1179 {
1180 return m_haseventsubscription;
1181 }
1182
1183 private void changePhysicsStatus(bool NewStatus)
1184 {
1185 if (NewStatus != m_isPhysical)
1186 {
1187 if (NewStatus)
1188 {
1189 // Create avatar capsule and related ODE data
1190 if ((Shell != IntPtr.Zero))
1191 {
1192 // a lost shell ?
1193 m_log.Warn("[PHYSICS]: re-creating the following avatar ODE data, even though it already exists - "
1194 + (Shell != IntPtr.Zero ? "Shell " : "")
1195 + (Body != IntPtr.Zero ? "Body " : "")
1196 + (Amotor != IntPtr.Zero ? "Amotor " : ""));
1197 AvatarGeomAndBodyDestroy();
1198 }
1199
1200 AvatarGeomAndBodyCreation(_position.X, _position.Y, _position.Z);
1201 _parent_scene.geom_name_map[Shell] = m_name;
1202 _parent_scene.actor_name_map[Shell] = (PhysicsActor)this;
1203 _parent_scene.AddCharacter(this);
1204 }
1205 else
1206 {
1207 _parent_scene.RemoveCharacter(this);
1208 // destroy avatar capsule and related ODE data
1209 AvatarGeomAndBodyDestroy();
1210 }
1211
1212 m_isPhysical = NewStatus;
1213 }
1214 }
1215
1216 private void changeAdd()
1217 {
1218 changePhysicsStatus(true);
1219 }
1220
1221 private void changeRemove()
1222 {
1223 changePhysicsStatus(false);
1224 }
1225
1226 private void changeShape(PrimitiveBaseShape arg)
1227 {
1228 }
1229
1230 private void changeSize(Vector3 Size)
1231 {
1232 if (Size.IsFinite())
1233 {
1234 float caplen = Size.Z;
1235
1236 caplen = caplen * 1.15f - CAPSULE_RADIUS * 2.0f;
1237
1238 if (caplen != CAPSULE_LENGTH)
1239 {
1240 if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero)
1241 {
1242 AvatarGeomAndBodyDestroy();
1243
1244 float prevCapsule = CAPSULE_LENGTH;
1245 CAPSULE_LENGTH = caplen;
1246
1247 AvatarGeomAndBodyCreation(_position.X, _position.Y,
1248 _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule) * 2));
1249
1250 Velocity = Vector3.Zero;
1251
1252 _parent_scene.geom_name_map[Shell] = m_name;
1253 _parent_scene.actor_name_map[Shell] = (PhysicsActor)this;
1254 }
1255 else
1256 {
1257 m_log.Warn("[PHYSICS]: trying to change capsule size, but the following ODE data is missing - "
1258 + (Shell == IntPtr.Zero ? "Shell " : "")
1259 + (Body == IntPtr.Zero ? "Body " : "")
1260 + (Amotor == IntPtr.Zero ? "Amotor " : ""));
1261 }
1262 }
1263
1264 m_pidControllerActive = true;
1265 }
1266 else
1267 {
1268 m_log.Warn("[PHYSICS]: Got a NaN Size from Scene on a Character");
1269 }
1270 }
1271
1272 private void changePosition( Vector3 newPos)
1273 {
1274 if (Body != IntPtr.Zero)
1275 d.BodySetPosition(Body, newPos.X, newPos.Y, newPos.Z);
1276 _position = newPos;
1277 }
1278
1279 private void changeOrientation(Quaternion newOri)
1280 {
1281 }
1282
1283 private void changeVelocity(Vector3 newVel)
1284 {
1285 m_pidControllerActive = true;
1286 _target_velocity = newVel;
1287 }
1288
1289 private void changeSetTorque(Vector3 newTorque)
1290 {
1291 }
1292
1293 private void changeAddForce(Vector3 newForce)
1294 {
1295 }
1296
1297 private void changeAddAngularForce(Vector3 arg)
1298 {
1299 }
1300
1301 private void changeAngularLock(Vector3 arg)
1302 {
1303 }
1304
1305 private void changeFloatOnWater(bool arg)
1306 {
1307 }
1308
1309 private void changeVolumedetetion(bool arg)
1310 {
1311 }
1312
1313 private void changeSelectedStatus(bool arg)
1314 {
1315 }
1316
1317 private void changeDisable(bool arg)
1318 {
1319 }
1320
1321 private void changeBuilding(bool arg)
1322 {
1323 }
1324
1325 private void changeForce(Vector3 newForce)
1326 {
1327 m_pidControllerActive = false;
1328 if (Body != IntPtr.Zero)
1329 {
1330 if (newForce.X != 0f || newForce.Y != 0f || newForce.Z != 0)
1331 d.BodyAddForce(Body, newForce.X, newForce.Y, newForce.Z);
1332 }
1333 }
1334
1335 // for now momentum is actually velocity
1336 private void changeMomentum(Vector3 newmomentum)
1337 {
1338 _velocity = newmomentum;
1339 _target_velocity = newmomentum;
1340 m_pidControllerActive = true;
1341 if (Body != IntPtr.Zero)
1342 d.BodySetLinearVel(Body, newmomentum.X, newmomentum.Y, newmomentum.Z);
1343 }
1344
1345 private void donullchange()
1346 {
1347 }
1348
1349 public bool DoAChange(changes what, object arg)
1350 {
1351 if (Shell == IntPtr.Zero && what != changes.Add && what != changes.Remove)
1352 {
1353 return false;
1354 }
1355
1356 // nasty switch
1357 switch (what)
1358 {
1359 case changes.Add:
1360 changeAdd();
1361 break;
1362 case changes.Remove:
1363 changeRemove();
1364 break;
1365
1366 case changes.Position:
1367 changePosition((Vector3)arg);
1368 break;
1369
1370 case changes.Orientation:
1371 changeOrientation((Quaternion)arg);
1372 break;
1373
1374 case changes.PosOffset:
1375 donullchange();
1376 break;
1377
1378 case changes.OriOffset:
1379 donullchange();
1380 break;
1381
1382 case changes.Velocity:
1383 changeVelocity((Vector3)arg);
1384 break;
1385
1386 // case changes.Acceleration:
1387 // changeacceleration((Vector3)arg);
1388 // break;
1389 // case changes.AngVelocity:
1390 // changeangvelocity((Vector3)arg);
1391 // break;
1392
1393 case changes.Force:
1394 changeForce((Vector3)arg);
1395 break;
1396
1397 case changes.Torque:
1398 changeSetTorque((Vector3)arg);
1399 break;
1400
1401 case changes.AddForce:
1402 changeAddForce((Vector3)arg);
1403 break;
1404
1405 case changes.AddAngForce:
1406 changeAddAngularForce((Vector3)arg);
1407 break;
1408
1409 case changes.AngLock:
1410 changeAngularLock((Vector3)arg);
1411 break;
1412
1413 case changes.Size:
1414 changeSize((Vector3)arg);
1415 break;
1416
1417 case changes.Momentum:
1418 changeMomentum((Vector3)arg);
1419 break;
1420/* not in use for now
1421 case changes.Shape:
1422 changeShape((PrimitiveBaseShape)arg);
1423 break;
1424
1425 case changes.CollidesWater:
1426 changeFloatOnWater((bool)arg);
1427 break;
1428
1429 case changes.VolumeDtc:
1430 changeVolumedetetion((bool)arg);
1431 break;
1432
1433 case changes.Physical:
1434 changePhysicsStatus((bool)arg);
1435 break;
1436
1437 case changes.Selected:
1438 changeSelectedStatus((bool)arg);
1439 break;
1440
1441 case changes.disabled:
1442 changeDisable((bool)arg);
1443 break;
1444
1445 case changes.building:
1446 changeBuilding((bool)arg);
1447 break;
1448*/
1449 case changes.Null:
1450 donullchange();
1451 break;
1452
1453 default:
1454 donullchange();
1455 break;
1456 }
1457 return false;
1458 }
1459
1460 public void AddChange(changes what, object arg)
1461 {
1462 _parent_scene.AddChange((PhysicsActor)this, what, arg);
1463 }
1464
1465
1466 internal void AddCollisionFrameTime(int p)
1467 {
1468 // protect it from overflow crashing
1469 if (m_eventsubscription + p >= int.MaxValue)
1470 m_eventsubscription = 0;
1471 m_eventsubscription += p;
1472 }
1473 }
1474}