opensim-development – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 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 using System;
29 using System.Xml;
30 using System.Collections.Generic;
31 using System.Reflection;
32 using System.Threading;
33 using System.Timers;
34 using Timer = System.Timers.Timer;
35 using OpenMetaverse;
36 using log4net;
37 using Nini.Config;
38 using OpenSim.Framework;
39 using OpenSim.Framework.Client;
40 using OpenSim.Region.Framework.Interfaces;
41 using OpenSim.Region.Framework.Scenes.Animation;
42 using OpenSim.Region.Framework.Scenes.Types;
43 using OpenSim.Region.Physics.Manager;
44 using GridRegion = OpenSim.Services.Interfaces.GridRegion;
45 using OpenSim.Services.Interfaces;
46 using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags;
47  
48 namespace OpenSim.Region.Framework.Scenes
49 {
50 [Flags]
51 enum ScriptControlled : uint
52 {
53 CONTROL_ZERO = 0,
54 CONTROL_FWD = 1,
55 CONTROL_BACK = 2,
56 CONTROL_LEFT = 4,
57 CONTROL_RIGHT = 8,
58 CONTROL_UP = 16,
59 CONTROL_DOWN = 32,
60 CONTROL_ROT_LEFT = 256,
61 CONTROL_ROT_RIGHT = 512,
62 CONTROL_LBUTTON = 268435456,
63 CONTROL_ML_LBUTTON = 1073741824
64 }
65  
66 struct ScriptControllers
67 {
68 public UUID objectID;
69 public UUID itemID;
70 public ScriptControlled ignoreControls;
71 public ScriptControlled eventControls;
72 }
73  
74 public delegate void SendCoarseLocationsMethod(UUID scene, ScenePresence presence, List<Vector3> coarseLocations, List<UUID> avatarUUIDs);
75  
76 public class ScenePresence : EntityBase, IScenePresence
77 {
78 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
79 private static readonly String LogHeader = "[SCENE PRESENCE]";
80  
81 // ~ScenePresence()
82 // {
83 // m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name);
84 // }
85  
86 public void TriggerScenePresenceUpdated()
87 {
88 if (m_scene != null)
89 m_scene.EventManager.TriggerScenePresenceUpdated(this);
90 }
91  
92 public PresenceType PresenceType { get; private set; }
93  
94 private ScenePresenceStateMachine m_stateMachine;
95  
96 /// <summary>
97 /// The current state of this presence. Governs only the existence lifecycle. See ScenePresenceStateMachine
98 /// for more details.
99 /// </summary>
100 public ScenePresenceState LifecycleState
101 {
102 get
103 {
104 return m_stateMachine.GetState();
105 }
106  
107 set
108 {
109 m_stateMachine.SetState(value);
110 }
111 }
112  
113 /// <summary>
114 /// This exists to prevent race conditions between two CompleteMovement threads if the simulator is slow and
115 /// the viewer fires these in quick succession.
116 /// </summary>
117 /// <remarks>
118 /// TODO: The child -> agent transition should be folded into LifecycleState and the CompleteMovement
119 /// regulation done there.
120 /// </remarks>
121 private object m_completeMovementLock = new object();
122  
123 // private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes();
124 private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags));
125 private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f);
126  
127 /// <summary>
128 /// Experimentally determined "fudge factor" to make sit-target positions
129 /// the same as in SecondLife. Fudge factor was tested for 36 different
130 /// test cases including prims of type box, sphere, cylinder, and torus,
131 /// with varying parameters for sit target location, prim size, prim
132 /// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis
133 /// issue #1716
134 /// </summary>
135 public static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.4f);
136  
137 /// <summary>
138 /// Movement updates for agents in neighboring regions are sent directly to clients.
139 /// This value only affects how often agent positions are sent to neighbor regions
140 /// for things such as distance-based update prioritization
141 /// </summary>
142 public static readonly float SIGNIFICANT_MOVEMENT = 2.0f;
143  
144 public UUID currentParcelUUID = UUID.Zero;
145  
146 /// <value>
147 /// The animator for this avatar
148 /// </value>
149 public ScenePresenceAnimator Animator { get; private set; }
150  
151 /// <summary>
152 /// Attachments recorded on this avatar.
153 /// </summary>
154 /// <remarks>
155 /// TODO: For some reason, we effectively have a list both here and in Appearance. Need to work out if this is
156 /// necessary.
157 /// </remarks>
158 private List<SceneObjectGroup> m_attachments = new List<SceneObjectGroup>();
159  
160 public Object AttachmentsSyncLock { get; private set; }
161  
162 private Dictionary<UUID, ScriptControllers> scriptedcontrols = new Dictionary<UUID, ScriptControllers>();
163 private ScriptControlled IgnoredControls = ScriptControlled.CONTROL_ZERO;
164 private ScriptControlled LastCommands = ScriptControlled.CONTROL_ZERO;
165 private bool MouseDown = false;
166 // private SceneObjectGroup proxyObjectGroup;
167 //private SceneObjectPart proxyObjectPart = null;
168 public Vector3 lastKnownAllowedPosition;
169 public bool sentMessageAboutRestrictedParcelFlyingDown;
170 public Vector4 CollisionPlane = Vector4.UnitW;
171  
172 private Vector3 m_lastPosition;
173 private Quaternion m_lastRotation;
174 private Vector3 m_lastVelocity;
175 private Vector3 m_lastSize = new Vector3(0.45f,0.6f,1.9f);
176  
177 private bool m_followCamAuto = false;
178  
179  
180 private Vector3? m_forceToApply;
181 private int m_userFlags;
182 public int UserFlags
183 {
184 get { return m_userFlags; }
185 }
186  
187 // Flying
188 public bool Flying
189 {
190 get { return PhysicsActor != null && PhysicsActor.Flying; }
191 set { PhysicsActor.Flying = value; }
192 }
193  
194 // add for fly velocity control
195 private bool FlyingOld {get; set;}
196 public bool WasFlying
197 {
198 get; private set;
199 }
200  
201 public bool IsColliding
202 {
203 get { return PhysicsActor != null && PhysicsActor.IsColliding; }
204 // We would expect setting IsColliding to be private but it's used by a hack in Scene
205 set { PhysicsActor.IsColliding = value; }
206 }
207  
208 // private int m_lastColCount = -1; //KF: Look for Collision chnages
209 // private int m_updateCount = 0; //KF: Update Anims for a while
210 // private static readonly int UPDATE_COUNT = 10; // how many frames to update for
211 private List<uint> m_lastColliders = new List<uint>();
212  
213 private TeleportFlags m_teleportFlags;
214 public TeleportFlags TeleportFlags
215 {
216 get { return m_teleportFlags; }
217 set { m_teleportFlags = value; }
218 }
219  
220 private uint m_requestedSitTargetID;
221 private UUID m_requestedSitTargetUUID;
222  
223 /// <summary>
224 /// Are we sitting on the ground?
225 /// </summary>
226 public bool SitGround { get; private set; }
227  
228 private SendCoarseLocationsMethod m_sendCoarseLocationsMethod;
229  
230 //private Vector3 m_requestedSitOffset = new Vector3();
231  
232 private Vector3 m_LastFinitePos;
233  
234 private float m_sitAvatarHeight = 2.0f;
235  
236 private Vector3 m_lastChildAgentUpdatePosition;
237 // private Vector3 m_lastChildAgentUpdateCamPosition;
238  
239 private const int LAND_VELOCITYMAG_MAX = 12;
240  
241 private const float FLY_ROLL_MAX_RADIANS = 1.1f;
242  
243 private const float FLY_ROLL_RADIANS_PER_UPDATE = 0.06f;
244 private const float FLY_ROLL_RESET_RADIANS_PER_UPDATE = 0.02f;
245  
246 private float m_health = 100f;
247  
248 protected ulong crossingFromRegion;
249  
250 private readonly Vector3[] Dir_Vectors = new Vector3[11];
251  
252 protected Timer m_reprioritization_timer;
253 protected bool m_reprioritizing;
254 protected bool m_reprioritization_called;
255  
256 private Quaternion m_headrotation = Quaternion.Identity;
257  
258 //PauPaw:Proper PID Controler for autopilot************
259 public bool MovingToTarget { get; private set; }
260 public Vector3 MoveToPositionTarget { get; private set; }
261  
262 /// <summary>
263 /// Controls whether an avatar automatically moving to a target will land when it gets there (if flying).
264 /// </summary>
265 public bool LandAtTarget { get; private set; }
266  
267 private int m_movementUpdateCount;
268 private const int NumMovementsBetweenRayCast = 5;
269  
270 private bool CameraConstraintActive;
271 //private int m_moveToPositionStateStatus;
272 //*****************************************************
273  
274 private bool m_collisionEventFlag = false;
275 private object m_collisionEventLock = new Object();
276  
277 private int m_movementAnimationUpdateCounter = 0;
278  
279 public Vector3 PrevSitOffset { get; set; }
280  
281 protected AvatarAppearance m_appearance;
282  
283 public AvatarAppearance Appearance
284 {
285 get { return m_appearance; }
286 set
287 {
288 m_appearance = value;
289 // m_log.DebugFormat("[SCENE PRESENCE]: Set appearance for {0} to {1}", Name, value);
290 }
291 }
292  
293 /// <summary>
294 /// Copy of the script states while the agent is in transit. This state may
295 /// need to be placed back in case of transfer fail.
296 /// </summary>
297 public List<string> InTransitScriptStates
298 {
299 get { return m_InTransitScriptStates; }
300 private set { m_InTransitScriptStates = value; }
301 }
302 private List<string> m_InTransitScriptStates = new List<string>();
303  
304 /// <summary>
305 /// Implemented Control Flags
306 /// </summary>
307 private enum Dir_ControlFlags
308 {
309 DIR_CONTROL_FLAG_FORWARD = AgentManager.ControlFlags.AGENT_CONTROL_AT_POS,
310 DIR_CONTROL_FLAG_BACK = AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG,
311 DIR_CONTROL_FLAG_LEFT = AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS,
312 DIR_CONTROL_FLAG_RIGHT = AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG,
313 DIR_CONTROL_FLAG_UP = AgentManager.ControlFlags.AGENT_CONTROL_UP_POS,
314 DIR_CONTROL_FLAG_DOWN = AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG,
315 DIR_CONTROL_FLAG_FORWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS,
316 DIR_CONTROL_FLAG_BACKWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG,
317 DIR_CONTROL_FLAG_LEFT_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS,
318 DIR_CONTROL_FLAG_RIGHT_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG,
319 DIR_CONTROL_FLAG_DOWN_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG
320 }
321  
322 /// <summary>
323 /// Position at which a significant movement was made
324 /// </summary>
325 private Vector3 posLastSignificantMove;
326  
327 #region For teleports and crossings callbacks
328  
329 /// <summary>
330 /// In the V1 teleport protocol, the destination simulator sends ReleaseAgent to this address.
331 /// </summary>
332 private string m_callbackURI;
333  
334 /// <summary>
335 /// Records the region from which this presence originated, if not from login.
336 /// </summary>
337 /// <remarks>
338 /// Also acts as a signal in the teleport V2 process to release UpdateAgent after a viewer has triggered
339 /// CompleteMovement and made the previous child agent a root agent.
340 /// </remarks>
341 private UUID m_originRegionID;
342  
343 /// <summary>
344 /// This object is used as a lock before accessing m_originRegionID to make sure that every thread is seeing
345 /// the very latest value and not using some cached version. Cannot make m_originRegionID itself volatite as
346 /// it is a value type.
347 /// </summary>
348 private object m_originRegionIDAccessLock = new object();
349  
350 /// <summary>
351 /// Used by the entity transfer module to signal when the presence should not be closed because a subsequent
352 /// teleport is reusing the connection.
353 /// </summary>
354 /// <remarks>May be refactored or move somewhere else soon.</remarks>
355 public bool DoNotCloseAfterTeleport { get; set; }
356  
357 #endregion
358  
359 /// <value>
360 /// Script engines present in the scene
361 /// </value>
362 private IScriptModule[] m_scriptEngines;
363  
364 #region Properties
365  
366 /// <summary>
367 /// Physical scene representation of this Avatar.
368 /// </summary>
369 public PhysicsActor PhysicsActor { get; private set; }
370  
371 /// <summary>
372 /// Record user movement inputs.
373 /// </summary>
374 public uint MovementFlag { get; private set; }
375  
376 /// <summary>
377 /// Is the agent stop control flag currently active?
378 /// </summary>
379 public bool AgentControlStopActive { get; private set; }
380  
381 private bool m_invulnerable = true;
382  
383 public bool Invulnerable
384 {
385 set { m_invulnerable = value; }
386 get { return m_invulnerable; }
387 }
388  
389 private int m_userLevel;
390  
391 public int UserLevel
392 {
393 get { return m_userLevel; }
394 private set { m_userLevel = value; }
395 }
396  
397 private int m_godLevel;
398  
399 public int GodLevel
400 {
401 get { return m_godLevel; }
402 private set { m_godLevel = value; }
403 }
404  
405 private ulong m_rootRegionHandle;
406  
407 public ulong RegionHandle
408 {
409 get { return m_rootRegionHandle; }
410 private set { m_rootRegionHandle = value; }
411 }
412  
413 #region Client Camera
414  
415 /// <summary>
416 /// Position of agent's camera in world (region cordinates)
417 /// </summary>
418 protected Vector3 m_lastCameraPosition;
419  
420 private Vector4 m_lastCameraCollisionPlane = new Vector4(0f, 0f, 0f, 1);
421 private bool m_doingCamRayCast = false;
422  
423 public Vector3 CameraPosition { get; set; }
424  
425 public Quaternion CameraRotation
426 {
427 get { return Util.Axes2Rot(CameraAtAxis, CameraLeftAxis, CameraUpAxis); }
428 }
429  
430 // Use these three vectors to figure out what the agent is looking at
431 // Convert it to a Matrix and/or Quaternion
432 //
433 public Vector3 CameraAtAxis { get; set; }
434 public Vector3 CameraLeftAxis { get; set; }
435 public Vector3 CameraUpAxis { get; set; }
436  
437 public Vector3 Lookat
438 {
439 get
440 {
441 Vector3 a = new Vector3(CameraAtAxis.X, CameraAtAxis.Y, 0);
442  
443 if (a == Vector3.Zero)
444 return a;
445  
446 return Util.GetNormalizedVector(a);
447 }
448 }
449 #endregion
450  
451 public string Firstname { get; private set; }
452 public string Lastname { get; private set; }
453  
454 public string Grouptitle { get; set; }
455  
456 // Agent's Draw distance.
457 public float DrawDistance { get; set; }
458  
459 public bool AllowMovement { get; set; }
460  
461 private bool m_setAlwaysRun;
462  
463 public bool SetAlwaysRun
464 {
465 get
466 {
467 if (PhysicsActor != null)
468 {
469 return PhysicsActor.SetAlwaysRun;
470 }
471 else
472 {
473 return m_setAlwaysRun;
474 }
475 }
476 set
477 {
478 m_setAlwaysRun = value;
479 if (PhysicsActor != null)
480 {
481 PhysicsActor.SetAlwaysRun = value;
482 }
483 }
484 }
485  
486 public byte State { get; set; }
487  
488 private AgentManager.ControlFlags m_AgentControlFlags;
489  
490 public uint AgentControlFlags
491 {
492 get { return (uint)m_AgentControlFlags; }
493 set { m_AgentControlFlags = (AgentManager.ControlFlags)value; }
494 }
495  
496 public IClientAPI ControllingClient { get; set; }
497  
498 public IClientCore ClientView
499 {
500 get { return (IClientCore)ControllingClient; }
501 }
502  
503 public UUID COF { get; set; }
504  
505 // public Vector3 ParentPosition { get; set; }
506  
507 /// <summary>
508 /// Position of this avatar relative to the region the avatar is in
509 /// </summary>
510 public override Vector3 AbsolutePosition
511 {
512 get
513 {
514 if (PhysicsActor != null)
515 {
516 m_pos = PhysicsActor.Position;
517  
518 // m_log.DebugFormat(
519 // "[SCENE PRESENCE]: Set position of {0} in {1} to {2} via getting AbsolutePosition!",
520 // Name, Scene.Name, m_pos);
521 }
522 else
523 {
524 // m_log.DebugFormat("[SCENE PRESENCE]: Fetching abs pos where PhysicsActor == null and parent part {0} for {1}", Name, Scene.Name);
525 // Obtain the correct position of a seated avatar.
526 // In addition to providing the correct position while
527 // the avatar is seated, this value will also
528 // be used as the location to unsit to.
529 //
530 // If ParentID is not 0, assume we are a seated avatar
531 // and we should return the position based on the sittarget
532 // offset and rotation of the prim we are seated on.
533 //
534 // Generally, m_pos will contain the position of the avatar
535 // in the sim unless the avatar is on a sit target. While
536 // on a sit target, m_pos will contain the desired offset
537 // without the parent rotation applied.
538 SceneObjectPart sitPart = ParentPart;
539  
540 if (sitPart != null)
541 return sitPart.AbsolutePosition + (m_pos * sitPart.GetWorldRotation());
542 }
543  
544 return m_pos;
545 }
546 set
547 {
548 // m_log.DebugFormat("[SCENE PRESENCE]: Setting position of {0} to {1} in {2}", Name, value, Scene.Name);
549 // Util.PrintCallStack();
550  
551 if (PhysicsActor != null)
552 {
553 try
554 {
555 PhysicsActor.Position = value;
556 }
557 catch (Exception e)
558 {
559 m_log.Error("[SCENE PRESENCE]: ABSOLUTE POSITION " + e.Message);
560 }
561 }
562  
563 // Don't update while sitting. The PhysicsActor above is null whilst sitting.
564 if (ParentID == 0)
565 m_pos = value;
566  
567 //m_log.DebugFormat(
568 // "[ENTITY BASE]: In {0} set AbsolutePosition of {1} to {2}",
569 // Scene.RegionInfo.RegionName, Name, m_pos);
570 TriggerScenePresenceUpdated();
571 }
572 }
573  
574 /// <summary>
575 /// If sitting, returns the offset position from the prim the avatar is sitting on.
576 /// Otherwise, returns absolute position in the scene.
577 /// </summary>
578 public Vector3 OffsetPosition
579 {
580 get { return m_pos; }
581 // Don't remove setter. It's not currently used in core but
582 // upcoming Avination code needs it.
583 set
584 {
585 // There is no offset position when not seated
586 if (ParentID == 0)
587 return;
588  
589 m_pos = value;
590 TriggerScenePresenceUpdated();
591 }
592 }
593  
594 /// <summary>
595 /// Current velocity of the avatar.
596 /// </summary>
597 public override Vector3 Velocity
598 {
599 get
600 {
601 if (PhysicsActor != null)
602 {
603 m_velocity = PhysicsActor.Velocity;
604  
605 // m_log.DebugFormat(
606 // "[SCENE PRESENCE]: Set velocity {0} for {1} in {2} via getting Velocity!",
607 // m_velocity, Name, Scene.RegionInfo.RegionName);
608 }
609  
610 return m_velocity;
611 }
612 set
613 {
614 if (PhysicsActor != null)
615 {
616 try
617 {
618 PhysicsActor.TargetVelocity = value;
619 }
620 catch (Exception e)
621 {
622 m_log.Error("[SCENE PRESENCE]: VELOCITY " + e.Message);
623 }
624 }
625  
626 m_velocity = value;
627  
628 // m_log.DebugFormat(
629 // "[SCENE PRESENCE]: In {0} set velocity of {1} to {2}",
630 // Scene.RegionInfo.RegionName, Name, m_velocity);
631 }
632 }
633 /*
634 public override Vector3 AngularVelocity
635 {
636 get
637 {
638 if (PhysicsActor != null)
639 {
640 m_rotationalvelocity = PhysicsActor.RotationalVelocity;
641  
642 // m_log.DebugFormat(
643 // "[SCENE PRESENCE]: Set velocity {0} for {1} in {2} via getting Velocity!",
644 // m_velocity, Name, Scene.RegionInfo.RegionName);
645 }
646  
647 return m_rotationalvelocity;
648 }
649 }
650 */
651 private Quaternion m_bodyRot = Quaternion.Identity;
652  
653 /// <summary>
654 /// The rotation of the avatar.
655 /// </summary>
656 /// <remarks>
657 /// If the avatar is not sitting, this is with respect to the world
658 /// If the avatar is sitting, this is a with respect to the part that it's sitting upon (a local rotation).
659 /// If you always want the world rotation, use GetWorldRotation()
660 /// </remarks>
661 public Quaternion Rotation
662 {
663 get
664 {
665 return m_bodyRot;
666 }
667  
668 set
669 {
670 m_bodyRot = value;
671  
672 if (PhysicsActor != null)
673 {
674 try
675 {
676 PhysicsActor.Orientation = m_bodyRot;
677 }
678 catch (Exception e)
679 {
680 m_log.Error("[SCENE PRESENCE]: Orientation " + e.Message);
681 }
682 }
683 // m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot);
684 }
685 }
686  
687 // Used for limited viewer 'fake' user rotations.
688 private Vector3 m_AngularVelocity = Vector3.Zero;
689  
690 public Vector3 AngularVelocity
691 {
692 get { return m_AngularVelocity; }
693 }
694  
695 public bool IsChildAgent { get; set; }
696 public bool IsLoggingIn { get; set; }
697  
698 /// <summary>
699 /// If the avatar is sitting, the local ID of the prim that it's sitting on. If not sitting then zero.
700 /// </summary>
701 public uint ParentID { get; set; }
702  
703 public UUID ParentUUID
704 {
705 get { return m_parentUUID; }
706 set { m_parentUUID = value; }
707 }
708 private UUID m_parentUUID = UUID.Zero;
709  
710 /// <summary>
711 /// Are we sitting on an object?
712 /// </summary>
713 /// <remarks>A more readable way of testing presence sit status than ParentID == 0</remarks>
714 public bool IsSatOnObject { get { return ParentID != 0; } }
715  
716 /// <summary>
717 /// If the avatar is sitting, the prim that it's sitting on. If not sitting then null.
718 /// </summary>
719 /// <remarks>
720 /// If you use this property then you must take a reference since another thread could set it to null.
721 /// </remarks>
722 public SceneObjectPart ParentPart { get; set; }
723  
724 public float Health
725 {
726 get { return m_health; }
727 set { m_health = value; }
728 }
729  
730 /// <summary>
731 /// Gets the world rotation of this presence.
732 /// </summary>
733 /// <remarks>
734 /// Unlike Rotation, this returns the world rotation no matter whether the avatar is sitting on a prim or not.
735 /// </remarks>
736 /// <returns></returns>
737 public Quaternion GetWorldRotation()
738 {
739 if (IsSatOnObject)
740 {
741 SceneObjectPart sitPart = ParentPart;
742  
743 if (sitPart != null)
744 return sitPart.GetWorldRotation() * Rotation;
745 }
746  
747 return Rotation;
748 }
749  
750 public void AdjustKnownSeeds()
751 {
752 Dictionary<ulong, string> seeds;
753  
754 if (Scene.CapsModule != null)
755 seeds = Scene.CapsModule.GetChildrenSeeds(UUID);
756 else
757 seeds = new Dictionary<ulong, string>();
758  
759 List<ulong> old = new List<ulong>();
760 foreach (ulong handle in seeds.Keys)
761 {
762 uint x, y;
763 Util.RegionHandleToRegionLoc(handle, out x, out y);
764  
765 if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY))
766 {
767 old.Add(handle);
768 }
769 }
770 DropOldNeighbours(old);
771  
772 if (Scene.CapsModule != null)
773 Scene.CapsModule.SetChildrenSeed(UUID, seeds);
774  
775 KnownRegions = seeds;
776 //m_log.Debug(" ++++++++++AFTER+++++++++++++ ");
777 //DumpKnownRegions();
778 }
779  
780 public void DumpKnownRegions()
781 {
782 m_log.Info("================ KnownRegions "+Scene.RegionInfo.RegionName+" ================");
783 foreach (KeyValuePair<ulong, string> kvp in KnownRegions)
784 {
785 uint x, y;
786 Util.RegionHandleToRegionLoc(kvp.Key, out x, out y);
787 m_log.Info(" >> "+x+", "+y+": "+kvp.Value);
788 }
789 }
790  
791 private bool m_mouseLook;
792 private bool m_leftButtonDown;
793  
794 private bool m_inTransit;
795  
796 /// <summary>
797 /// This signals whether the presence is in transit between neighbouring regions.
798 /// </summary>
799 /// <remarks>
800 /// It is not set when the presence is teleporting or logging in/out directly to a region.
801 /// </remarks>
802 public bool IsInTransit
803 {
804 get { return m_inTransit; }
805 set {
806 if(value)
807 {
808 if (Flying)
809 m_AgentControlFlags |= AgentManager.ControlFlags.AGENT_CONTROL_FLY;
810 else
811 m_AgentControlFlags &= ~AgentManager.ControlFlags.AGENT_CONTROL_FLY;
812 }
813 m_inTransit = value;
814 }
815 }
816  
817 private float m_speedModifier = 1.0f;
818  
819 public float SpeedModifier
820 {
821 get { return m_speedModifier; }
822 set { m_speedModifier = value; }
823 }
824  
825 /// <summary>
826 /// Modifier for agent movement if we get an AGENT_CONTROL_STOP whilst walking or running
827 /// </summary>
828 /// <remarks>
829 /// AGENT_CONTRL_STOP comes about if user holds down space key on viewers.
830 /// </remarks>
831 private float AgentControlStopSlowWhilstMoving = 0.5f;
832  
833 private bool m_forceFly;
834  
835 public bool ForceFly
836 {
837 get { return m_forceFly; }
838 set { m_forceFly = value; }
839 }
840  
841 private bool m_flyDisabled;
842  
843 public bool FlyDisabled
844 {
845 get { return m_flyDisabled; }
846 set { m_flyDisabled = value; }
847 }
848  
849 public string Viewer
850 {
851 get { return m_scene.AuthenticateHandler.GetAgentCircuitData(ControllingClient.CircuitCode).Viewer; }
852 }
853  
854 #endregion
855  
856 #region Constructor(s)
857  
858 public ScenePresence(
859 IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type)
860 {
861 AttachmentsSyncLock = new Object();
862 AllowMovement = true;
863 IsChildAgent = true;
864 IsLoggingIn = false;
865 m_sendCoarseLocationsMethod = SendCoarseLocationsDefault;
866 Animator = new ScenePresenceAnimator(this);
867 PresenceType = type;
868 DrawDistance = world.DefaultDrawDistance;
869 RegionHandle = world.RegionInfo.RegionHandle;
870 ControllingClient = client;
871 Firstname = ControllingClient.FirstName;
872 Lastname = ControllingClient.LastName;
873 m_name = String.Format("{0} {1}", Firstname, Lastname);
874 m_scene = world;
875 m_uuid = client.AgentId;
876 LocalId = m_scene.AllocateLocalId();
877  
878 UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, m_uuid);
879 if (account != null)
880 m_userFlags = account.UserFlags;
881 else
882 m_userFlags = 0;
883  
884 if (account != null)
885 UserLevel = account.UserLevel;
886  
887 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
888 if (gm != null)
889 Grouptitle = gm.GetGroupTitle(m_uuid);
890  
891 m_scriptEngines = m_scene.RequestModuleInterfaces<IScriptModule>();
892  
893 AbsolutePosition = posLastSignificantMove = CameraPosition =
894 m_lastCameraPosition = ControllingClient.StartPos;
895  
896 m_reprioritization_timer = new Timer(world.ReprioritizationInterval);
897 m_reprioritization_timer.Elapsed += new ElapsedEventHandler(Reprioritize);
898 m_reprioritization_timer.AutoReset = false;
899  
900 AdjustKnownSeeds();
901  
902 RegisterToEvents();
903 SetDirectionVectors();
904  
905 Appearance = appearance;
906  
907 m_stateMachine = new ScenePresenceStateMachine(this);
908 }
909  
910 private void RegionHeartbeatEnd(Scene scene)
911 {
912 if (IsChildAgent)
913 return;
914  
915 m_movementAnimationUpdateCounter ++;
916 if (m_movementAnimationUpdateCounter >= 2)
917 {
918 m_movementAnimationUpdateCounter = 0;
919 if (Animator != null)
920 {
921 // If the parentID == 0 we are not sitting
922 // if !SitGournd then we are not sitting on the ground
923 // Fairly straightforward, now here comes the twist
924 // if ParentUUID is NOT UUID.Zero, we are looking to
925 // be sat on an object that isn't there yet. Should
926 // be treated as if sat.
927 if(ParentID == 0 && !SitGround && ParentUUID == UUID.Zero) // skip it if sitting
928 Animator.UpdateMovementAnimations();
929 }
930 else
931 {
932 m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd;
933 }
934 }
935 }
936  
937 public void RegisterToEvents()
938 {
939 ControllingClient.OnCompleteMovementToRegion += CompleteMovement;
940 ControllingClient.OnAgentUpdate += HandleAgentUpdate;
941 ControllingClient.OnAgentCameraUpdate += HandleAgentCamerasUpdate;
942 ControllingClient.OnAgentRequestSit += HandleAgentRequestSit;
943 ControllingClient.OnAgentSit += HandleAgentSit;
944 ControllingClient.OnSetAlwaysRun += HandleSetAlwaysRun;
945 ControllingClient.OnStartAnim += HandleStartAnim;
946 ControllingClient.OnStopAnim += HandleStopAnim;
947 ControllingClient.OnForceReleaseControls += HandleForceReleaseControls;
948 ControllingClient.OnAutoPilotGo += MoveToTarget;
949  
950 // ControllingClient.OnChildAgentStatus += new StatusChange(this.ChildStatusChange);
951 // ControllingClient.OnStopMovement += new GenericCall2(this.StopMovement);
952 }
953  
954 private void SetDirectionVectors()
955 {
956 Dir_Vectors[0] = Vector3.UnitX; //FORWARD
957 Dir_Vectors[1] = -Vector3.UnitX; //BACK
958 Dir_Vectors[2] = Vector3.UnitY; //LEFT
959 Dir_Vectors[3] = -Vector3.UnitY; //RIGHT
960 Dir_Vectors[4] = Vector3.UnitZ; //UP
961 Dir_Vectors[5] = -Vector3.UnitZ; //DOWN
962 Dir_Vectors[6] = new Vector3(0.5f, 0f, 0f); //FORWARD_NUDGE
963 Dir_Vectors[7] = new Vector3(-0.5f, 0f, 0f); //BACK_NUDGE
964 Dir_Vectors[8] = new Vector3(0f, 0.5f, 0f); //LEFT_NUDGE
965 Dir_Vectors[9] = new Vector3(0f, -0.5f, 0f); //RIGHT_NUDGE
966 Dir_Vectors[10] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge
967 }
968  
969 private Vector3[] GetWalkDirectionVectors()
970 {
971 Vector3[] vector = new Vector3[11];
972 vector[0] = new Vector3(CameraUpAxis.Z, 0f, -CameraAtAxis.Z); //FORWARD
973 vector[1] = new Vector3(-CameraUpAxis.Z, 0f, CameraAtAxis.Z); //BACK
974 vector[2] = Vector3.UnitY; //LEFT
975 vector[3] = -Vector3.UnitY; //RIGHT
976 vector[4] = new Vector3(CameraAtAxis.Z, 0f, CameraUpAxis.Z); //UP
977 vector[5] = new Vector3(-CameraAtAxis.Z, 0f, -CameraUpAxis.Z); //DOWN
978 vector[6] = new Vector3(CameraUpAxis.Z, 0f, -CameraAtAxis.Z); //FORWARD_NUDGE
979 vector[7] = new Vector3(-CameraUpAxis.Z, 0f, CameraAtAxis.Z); //BACK_NUDGE
980 vector[8] = Vector3.UnitY; //LEFT_NUDGE
981 vector[9] = -Vector3.UnitY; //RIGHT_NUDGE
982 vector[10] = new Vector3(-CameraAtAxis.Z, 0f, -CameraUpAxis.Z); //DOWN_NUDGE
983 return vector;
984 }
985  
986 #endregion
987  
988 #region Status Methods
989  
990 /// <summary>
991 /// Turns a child agent into a root agent.
992 /// </summary>
993 /// <remarks>
994 /// Child agents are logged into neighbouring sims largely to observe changes. Root agents exist when the
995 /// avatar is actual in the sim. They can perform all actions.
996 /// This change is made whenever an avatar enters a region, whether by crossing over from a neighbouring sim,
997 /// teleporting in or on initial login.
998 ///
999 /// This method is on the critical path for transferring an avatar from one region to another. Delay here
1000 /// delays that crossing.
1001 /// </remarks>
1002 private bool MakeRootAgent(Vector3 pos, bool isFlying)
1003 {
1004 lock (m_completeMovementLock)
1005 {
1006 if (!IsChildAgent)
1007 return false;
1008  
1009 //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count);
1010  
1011 // m_log.InfoFormat(
1012 // "[SCENE]: Upgrading child to root agent for {0} in {1}",
1013 // Name, m_scene.RegionInfo.RegionName);
1014  
1015 if (ParentUUID != UUID.Zero)
1016 {
1017 m_log.DebugFormat("[SCENE PRESENCE]: Sitting avatar back on prim {0}", ParentUUID);
1018 SceneObjectPart part = m_scene.GetSceneObjectPart(ParentUUID);
1019 if (part == null)
1020 {
1021 m_log.ErrorFormat("[SCENE PRESENCE]: Can't find prim {0} to sit on", ParentUUID);
1022 }
1023 else
1024 {
1025 part.ParentGroup.AddAvatar(UUID);
1026 if (part.SitTargetPosition != Vector3.Zero)
1027 part.SitTargetAvatar = UUID;
1028 // ParentPosition = part.GetWorldPosition();
1029 ParentID = part.LocalId;
1030 ParentPart = part;
1031 m_pos = PrevSitOffset;
1032 // pos = ParentPosition;
1033 pos = part.GetWorldPosition();
1034 }
1035 ParentUUID = UUID.Zero;
1036  
1037 // Animator.TrySetMovementAnimation("SIT");
1038 }
1039 else
1040 {
1041 IsLoggingIn = false;
1042 }
1043  
1044 IsChildAgent = false;
1045 }
1046  
1047 // Must reset this here so that a teleport to a region next to an existing region does not keep the flag
1048 // set and prevent the close of the connection on a subsequent re-teleport.
1049 // Should not be needed if we are not trying to tell this region to close
1050 // DoNotCloseAfterTeleport = false;
1051  
1052 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
1053 if (gm != null)
1054 Grouptitle = gm.GetGroupTitle(m_uuid);
1055  
1056 RegionHandle = m_scene.RegionInfo.RegionHandle;
1057  
1058 m_scene.EventManager.TriggerSetRootAgentScene(m_uuid, m_scene);
1059  
1060 UUID groupUUID = UUID.Zero;
1061 string GroupName = string.Empty;
1062 ulong groupPowers = 0;
1063  
1064 // ----------------------------------
1065 // Previous Agent Difference - AGNI sends an unsolicited AgentDataUpdate upon root agent status
1066 try
1067 {
1068 if (gm != null)
1069 {
1070 groupUUID = ControllingClient.ActiveGroupId;
1071 GroupRecord record = gm.GetGroupRecord(groupUUID);
1072 if (record != null)
1073 GroupName = record.GroupName;
1074 GroupMembershipData groupMembershipData = gm.GetMembershipData(groupUUID, m_uuid);
1075 if (groupMembershipData != null)
1076 groupPowers = groupMembershipData.GroupPowers;
1077 }
1078 ControllingClient.SendAgentDataUpdate(m_uuid, groupUUID, Firstname, Lastname, groupPowers, GroupName,
1079 Grouptitle);
1080 }
1081 catch (Exception e)
1082 {
1083 m_log.Debug("[AGENTUPDATE]: " + e.ToString());
1084 }
1085 // ------------------------------------
1086  
1087 if (ParentID == 0)
1088 {
1089 // Moved this from SendInitialData to ensure that Appearance is initialized
1090 // before the inventory is processed in MakeRootAgent. This fixes a race condition
1091 // related to the handling of attachments
1092 //m_scene.GetAvatarAppearance(ControllingClient, out Appearance);
1093  
1094 /* RA 20140111: Commented out these TestBorderCross's.
1095 * Not sure why this code is here. It is not checking all the borders
1096 * and 'in region' sanity checking is done in CheckAndAdjustLandingPoint and below.
1097 if (m_scene.TestBorderCross(pos, Cardinals.E))
1098 {
1099 Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.E);
1100 pos.X = crossedBorder.BorderLine.Z - 1;
1101 }
1102  
1103 if (m_scene.TestBorderCross(pos, Cardinals.N))
1104 {
1105 Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N);
1106 pos.Y = crossedBorder.BorderLine.Z - 1;
1107 }
1108 */
1109  
1110 CheckAndAdjustLandingPoint(ref pos);
1111  
1112 if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f)
1113 {
1114 m_log.WarnFormat(
1115 "[SCENE PRESENCE]: MakeRootAgent() was given an illegal position of {0} for avatar {1}, {2}. Clamping",
1116 pos, Name, UUID);
1117  
1118 if (pos.X < 0f) pos.X = 0f;
1119 if (pos.Y < 0f) pos.Y = 0f;
1120 if (pos.Z < 0f) pos.Z = 0f;
1121 }
1122  
1123 float localAVHeight = 1.56f;
1124 if (Appearance.AvatarHeight > 0)
1125 localAVHeight = Appearance.AvatarHeight;
1126  
1127 float posZLimit = 0;
1128  
1129 if (pos.X < m_scene.RegionInfo.RegionSizeX && pos.Y < m_scene.RegionInfo.RegionSizeY)
1130 posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y];
1131  
1132 float newPosZ = posZLimit + localAVHeight / 2;
1133 if (posZLimit >= (pos.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
1134 {
1135 pos.Z = newPosZ;
1136 }
1137 AbsolutePosition = pos;
1138  
1139 if (m_teleportFlags == TeleportFlags.Default)
1140 {
1141 Vector3 vel = Velocity;
1142 AddToPhysicalScene(isFlying);
1143 if (PhysicsActor != null)
1144 PhysicsActor.SetMomentum(vel);
1145 }
1146 else
1147 AddToPhysicalScene(isFlying);
1148  
1149 // XXX: This is to trigger any secondary teleport needed for a megaregion when the user has teleported to a
1150 // location outside the 'root region' (the south-west 256x256 corner). This is the earlist we can do it
1151 // since it requires a physics actor to be present. If it is left any later, then physics appears to reset
1152 // the value to a negative position which does not trigger the border cross.
1153 // This may not be the best location for this.
1154 CheckForBorderCrossing();
1155  
1156 if (ForceFly)
1157 {
1158 Flying = true;
1159 }
1160 else if (FlyDisabled)
1161 {
1162 Flying = false;
1163 }
1164 }
1165 // Don't send an animation pack here, since on a region crossing this will sometimes cause a flying
1166 // avatar to return to the standing position in mid-air. On login it looks like this is being sent
1167 // elsewhere anyway
1168 // Animator.SendAnimPack();
1169  
1170 m_scene.SwapRootAgentCount(false);
1171  
1172 // The initial login scene presence is already root when it gets here
1173 // and it has already rezzed the attachments and started their scripts.
1174 // We do the following only for non-login agents, because their scripts
1175 // haven't started yet.
1176 if (PresenceType == PresenceType.Npc || (TeleportFlags & TeleportFlags.ViaLogin) != 0)
1177 {
1178 // Viewers which have a current outfit folder will actually rez their own attachments. However,
1179 // viewers without (e.g. v1 viewers) will not, so we still need to make this call.
1180 if (Scene.AttachmentsModule != null)
1181 Util.FireAndForget(
1182 o =>
1183 {
1184 // if (PresenceType != PresenceType.Npc && Util.FireAndForgetMethod != FireAndForgetMethod.None)
1185 // System.Threading.Thread.Sleep(7000);
1186  
1187 Scene.AttachmentsModule.RezAttachments(this);
1188 });
1189 }
1190 else
1191 {
1192 // We need to restart scripts here so that they receive the correct changed events (CHANGED_TELEPORT
1193 // and CHANGED_REGION) when the attachments have been rezzed in the new region. This cannot currently
1194 // be done in AttachmentsModule.CopyAttachments(AgentData ad, IScenePresence sp) itself since we are
1195 // not transporting the required data.
1196 //
1197 // We need to restart scripts here so that they receive the correct changed events (CHANGED_TELEPORT
1198 // and CHANGED_REGION) when the attachments have been rezzed in the new region. This cannot currently
1199 // be done in AttachmentsModule.CopyAttachments(AgentData ad, IScenePresence sp) itself since we are
1200 // not transporting the required data.
1201 //
1202 // We must take a copy of the attachments list here (rather than locking) to avoid a deadlock where a script in one of
1203 // the attachments may start processing an event (which locks ScriptInstance.m_Script) that then calls a method here
1204 // which needs to lock m_attachments. ResumeScripts() needs to take a ScriptInstance.m_Script lock to try to unset the Suspend status.
1205 //
1206 // FIXME: In theory, this deadlock should not arise since scripts should not be processing events until ResumeScripts().
1207 // But XEngine starts all scripts unsuspended. Starting them suspended will not currently work because script rezzing
1208 // is placed in an asynchronous queue in XEngine and so the ResumeScripts() call will almost certainly execute before the
1209 // script is rezzed. This means the ResumeScripts() does absolutely nothing when using XEngine.
1210 //
1211 // One cannot simply iterate over attachments in a fire and forget thread because this would no longer
1212 // be locked, allowing race conditions if other code changes the attachments list.
1213 List<SceneObjectGroup> attachments = GetAttachments();
1214  
1215 if (attachments.Count > 0)
1216 {
1217 m_log.DebugFormat(
1218 "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name);
1219  
1220 // Resume scripts
1221 foreach (SceneObjectGroup sog in attachments)
1222 {
1223 sog.ScheduleGroupForFullUpdate();
1224 sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource());
1225 sog.ResumeScripts();
1226 }
1227 }
1228 }
1229  
1230 SendAvatarDataToAllAgents();
1231  
1232 // send the animations of the other presences to me
1233 m_scene.ForEachRootScenePresence(delegate(ScenePresence presence)
1234 {
1235 if (presence != this)
1236 presence.Animator.SendAnimPackToClient(ControllingClient);
1237 });
1238  
1239 // If we don't reset the movement flag here, an avatar that crosses to a neighbouring sim and returns will
1240 // stall on the border crossing since the existing child agent will still have the last movement
1241 // recorded, which stops the input from being processed.
1242  
1243 MovementFlag = 0;
1244  
1245 m_scene.EventManager.TriggerOnMakeRootAgent(this);
1246  
1247 return true;
1248 }
1249  
1250 public int GetStateSource()
1251 {
1252 AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(UUID);
1253  
1254 if (aCircuit != null && (aCircuit.teleportFlags != (uint)TeleportFlags.Default))
1255 {
1256 // This will get your attention
1257 //m_log.Error("[XXX] Triggering CHANGED_TELEPORT");
1258  
1259 return 5; // StateSource.Teleporting
1260 }
1261 return 2; // StateSource.PrimCrossing
1262 }
1263  
1264 /// <summary>
1265 /// This turns a root agent into a child agent
1266 /// </summary>
1267 /// <remarks>
1268 /// when an agent departs this region for a neighbor, this gets called.
1269 ///
1270 /// It doesn't get called for a teleport. Reason being, an agent that
1271 /// teleports out may not end up anywhere near this region
1272 /// </remarks>
1273 public void MakeChildAgent()
1274 {
1275 m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd;
1276  
1277 m_log.DebugFormat("[SCENE PRESENCE]: Making {0} a child agent in {1}", Name, Scene.RegionInfo.RegionName);
1278  
1279 // Reset these so that teleporting in and walking out isn't seen
1280 // as teleporting back
1281 TeleportFlags = TeleportFlags.Default;
1282  
1283 MovementFlag = 0;
1284  
1285 // It looks like Animator is set to null somewhere, and MakeChild
1286 // is called after that. Probably in aborted teleports.
1287 if (Animator == null)
1288 Animator = new ScenePresenceAnimator(this);
1289 else
1290 Animator.ResetAnimations();
1291  
1292  
1293 // m_log.DebugFormat(
1294 // "[SCENE PRESENCE]: Downgrading root agent {0}, {1} to a child agent in {2}",
1295 // Name, UUID, m_scene.RegionInfo.RegionName);
1296  
1297 // Don't zero out the velocity since this can cause problems when an avatar is making a region crossing,
1298 // depending on the exact timing. This shouldn't matter anyway since child agent positions are not updated.
1299 //Velocity = new Vector3(0, 0, 0);
1300  
1301 IsChildAgent = true;
1302 m_scene.SwapRootAgentCount(true);
1303 RemoveFromPhysicalScene();
1304 ParentID = 0; // Child agents can't be sitting
1305  
1306 // FIXME: Set RegionHandle to the region handle of the scene this agent is moving into
1307  
1308 m_scene.EventManager.TriggerOnMakeChildAgent(this);
1309 }
1310  
1311 /// <summary>
1312 /// Removes physics plugin scene representation of this agent if it exists.
1313 /// </summary>
1314 public void RemoveFromPhysicalScene()
1315 {
1316 if (PhysicsActor != null)
1317 {
1318 // PhysicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients;
1319 PhysicsActor.OnOutOfBounds -= OutOfBoundsCall;
1320 PhysicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate;
1321 PhysicsActor.UnSubscribeEvents();
1322 m_scene.PhysicsScene.RemoveAvatar(PhysicsActor);
1323 PhysicsActor = null;
1324 }
1325 // else
1326 // {
1327 // m_log.ErrorFormat(
1328 // "[SCENE PRESENCE]: Attempt to remove physics actor for {0} on {1} but this scene presence has no physics actor",
1329 // Name, Scene.RegionInfo.RegionName);
1330 // }
1331 }
1332  
1333 /// <summary>
1334 /// Do not call this directly. Call Scene.RequestTeleportLocation() instead.
1335 /// </summary>
1336 /// <param name="pos"></param>
1337 public void Teleport(Vector3 pos)
1338 {
1339 TeleportWithMomentum(pos, Vector3.Zero);
1340 }
1341  
1342 public void TeleportWithMomentum(Vector3 pos, Vector3? v)
1343 {
1344 if (ParentID != (uint)0)
1345 StandUp();
1346 bool isFlying = Flying;
1347 Vector3 vel = Velocity;
1348 RemoveFromPhysicalScene();
1349 CheckLandingPoint(ref pos);
1350 AbsolutePosition = pos;
1351 AddToPhysicalScene(isFlying);
1352 if (PhysicsActor != null)
1353 {
1354 if (v.HasValue)
1355 PhysicsActor.SetMomentum((Vector3)v);
1356 else
1357 PhysicsActor.SetMomentum(vel);
1358 }
1359  
1360 SendTerseUpdateToAllClients();
1361 }
1362  
1363 public void avnLocalTeleport(Vector3 newpos, Vector3? newvel, bool rotateToVelXY)
1364 {
1365 CheckLandingPoint(ref newpos);
1366 AbsolutePosition = newpos;
1367  
1368 if (newvel.HasValue)
1369 {
1370 if ((Vector3)newvel == Vector3.Zero)
1371 {
1372 if (PhysicsActor != null)
1373 PhysicsActor.SetMomentum(Vector3.Zero);
1374 m_velocity = Vector3.Zero;
1375 }
1376 else
1377 {
1378 if (PhysicsActor != null)
1379 PhysicsActor.SetMomentum((Vector3)newvel);
1380 m_velocity = (Vector3)newvel;
1381  
1382 if (rotateToVelXY)
1383 {
1384 Vector3 lookAt = (Vector3)newvel;
1385 lookAt.Z = 0;
1386 lookAt.Normalize();
1387 ControllingClient.SendLocalTeleport(newpos, lookAt, (uint)TeleportFlags.ViaLocation);
1388 return;
1389 }
1390 }
1391 }
1392  
1393 SendTerseUpdateToAllClients();
1394 }
1395  
1396  
1397  
1398 public void StopFlying()
1399 {
1400 Vector3 pos = AbsolutePosition;
1401 if (Appearance.AvatarHeight != 127.0f)
1402 pos += new Vector3(0f, 0f, (Appearance.AvatarHeight / 6f));
1403 else
1404 pos += new Vector3(0f, 0f, (1.56f / 6f));
1405  
1406 AbsolutePosition = pos;
1407  
1408 // attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
1409 // Collision plane below the avatar's position a 6th of the avatar's height is suitable.
1410 // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
1411 // certain amount.. because the LLClient wouldn't land in that situation anyway.
1412  
1413 // why are we still testing for this really old height value default???
1414 if (Appearance.AvatarHeight != 127.0f)
1415 CollisionPlane = new Vector4(0, 0, 0, pos.Z - Appearance.AvatarHeight / 6f);
1416 else
1417 CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f / 6f));
1418  
1419 ControllingClient.SendAgentTerseUpdate(this);
1420 }
1421  
1422 /// <summary>
1423 /// Applies a roll accumulator to the avatar's angular velocity for the avatar fly roll effect.
1424 /// </summary>
1425 /// <param name="amount">Postive or negative roll amount in radians</param>
1426 private void ApplyFlyingRoll(float amount, bool PressingUp, bool PressingDown)
1427 {
1428  
1429 float rollAmount = Util.Clamp(m_AngularVelocity.Z + amount, -FLY_ROLL_MAX_RADIANS, FLY_ROLL_MAX_RADIANS);
1430 m_AngularVelocity.Z = rollAmount;
1431  
1432 // APPLY EXTRA consideration for flying up and flying down during this time.
1433 // if we're turning left
1434 if (amount > 0)
1435 {
1436  
1437 // If we're at the max roll and pressing up, we want to swing BACK a bit
1438 // Automatically adds noise
1439 if (PressingUp)
1440 {
1441 if (m_AngularVelocity.Z >= FLY_ROLL_MAX_RADIANS - 0.04f)
1442 m_AngularVelocity.Z -= 0.9f;
1443 }
1444 // If we're at the max roll and pressing down, we want to swing MORE a bit
1445 if (PressingDown)
1446 {
1447 if (m_AngularVelocity.Z >= FLY_ROLL_MAX_RADIANS && m_AngularVelocity.Z < FLY_ROLL_MAX_RADIANS + 0.6f)
1448 m_AngularVelocity.Z += 0.6f;
1449 }
1450 }
1451 else // we're turning right.
1452 {
1453 // If we're at the max roll and pressing up, we want to swing BACK a bit
1454 // Automatically adds noise
1455 if (PressingUp)
1456 {
1457 if (m_AngularVelocity.Z <= (-FLY_ROLL_MAX_RADIANS))
1458 m_AngularVelocity.Z += 0.6f;
1459 }
1460 // If we're at the max roll and pressing down, we want to swing MORE a bit
1461 if (PressingDown)
1462 {
1463 if (m_AngularVelocity.Z >= -FLY_ROLL_MAX_RADIANS - 0.6f)
1464 m_AngularVelocity.Z -= 0.6f;
1465 }
1466 }
1467 }
1468  
1469 /// <summary>
1470 /// incrementally sets roll amount to zero
1471 /// </summary>
1472 /// <param name="amount">Positive roll amount in radians</param>
1473 /// <returns></returns>
1474 private float CalculateFlyingRollResetToZero(float amount)
1475 {
1476 const float rollMinRadians = 0f;
1477  
1478 if (m_AngularVelocity.Z > 0)
1479 {
1480  
1481 float leftOverToMin = m_AngularVelocity.Z - rollMinRadians;
1482 if (amount > leftOverToMin)
1483 return -leftOverToMin;
1484 else
1485 return -amount;
1486  
1487 }
1488 else
1489 {
1490  
1491 float leftOverToMin = -m_AngularVelocity.Z - rollMinRadians;
1492 if (amount > leftOverToMin)
1493 return leftOverToMin;
1494 else
1495 return amount;
1496 }
1497 }
1498  
1499  
1500  
1501 // neighbouring regions we have enabled a child agent in
1502 // holds the seed cap for the child agent in that region
1503 private Dictionary<ulong, string> m_knownChildRegions = new Dictionary<ulong, string>();
1504  
1505 public void AddNeighbourRegion(ulong regionHandle, string cap)
1506 {
1507 lock (m_knownChildRegions)
1508 {
1509 if (!m_knownChildRegions.ContainsKey(regionHandle))
1510 {
1511 uint x, y;
1512 Utils.LongToUInts(regionHandle, out x, out y);
1513 m_knownChildRegions.Add(regionHandle, cap);
1514 }
1515 }
1516 }
1517  
1518 public void RemoveNeighbourRegion(ulong regionHandle)
1519 {
1520 lock (m_knownChildRegions)
1521 {
1522 // Checking ContainsKey is redundant as Remove works either way and returns a bool
1523 // This is here to allow the Debug output to be conditional on removal
1524 //if (m_knownChildRegions.ContainsKey(regionHandle))
1525 // m_log.DebugFormat(" !!! removing known region {0} in {1}. Count = {2}", regionHandle, Scene.RegionInfo.RegionName, m_knownChildRegions.Count);
1526 m_knownChildRegions.Remove(regionHandle);
1527 }
1528 }
1529  
1530 public void DropOldNeighbours(List<ulong> oldRegions)
1531 {
1532 foreach (ulong handle in oldRegions)
1533 {
1534 RemoveNeighbourRegion(handle);
1535 Scene.CapsModule.DropChildSeed(UUID, handle);
1536 }
1537 }
1538  
1539 public Dictionary<ulong, string> KnownRegions
1540 {
1541 get
1542 {
1543 lock (m_knownChildRegions)
1544 return new Dictionary<ulong, string>(m_knownChildRegions);
1545 }
1546 set
1547 {
1548 // Replacing the reference is atomic but we still need to lock on
1549 // the original dictionary object which may be in use elsewhere
1550 lock (m_knownChildRegions)
1551 m_knownChildRegions = value;
1552 }
1553 }
1554  
1555 public List<ulong> KnownRegionHandles
1556 {
1557 get
1558 {
1559 return new List<ulong>(KnownRegions.Keys);
1560 }
1561 }
1562  
1563 public int KnownRegionCount
1564 {
1565 get
1566 {
1567 lock (m_knownChildRegions)
1568 return m_knownChildRegions.Count;
1569 }
1570 }
1571  
1572 #endregion
1573  
1574 #region Event Handlers
1575  
1576 /// <summary>
1577 /// Sets avatar height in the physics plugin
1578 /// </summary>
1579 /// <param name="height">New height of avatar</param>
1580 public void SetHeight(float height)
1581 {
1582 if (PhysicsActor != null && !IsChildAgent)
1583 PhysicsActor.Size = new Vector3(0.45f, 0.6f, height);
1584 }
1585  
1586 public void SetSize(Vector3 size, float feetoffset)
1587 {
1588 // TODO: Merge the physics bits
1589 // if (PhysicsActor != null && !IsChildAgent)
1590 // PhysicsActor.setAvatarSize(size, feetoffset);
1591  
1592 }
1593  
1594 private bool WaitForUpdateAgent(IClientAPI client)
1595 {
1596 // Before the source region executes UpdateAgent
1597 // (which triggers Scene.IncomingUpdateChildAgent(AgentData cAgentData) here in the destination,
1598 // m_originRegionID is UUID.Zero; after, it's non-Zero. The CompleteMovement sequence initiated from the
1599 // viewer (in turn triggered by the source region sending it a TeleportFinish event) waits until it's non-zero
1600 int count = 50;
1601 UUID originID;
1602  
1603 lock (m_originRegionIDAccessLock)
1604 originID = m_originRegionID;
1605  
1606 while (originID.Equals(UUID.Zero) && count-- > 0)
1607 {
1608 lock (m_originRegionIDAccessLock)
1609 originID = m_originRegionID;
1610  
1611 m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.Name);
1612 Thread.Sleep(200);
1613 }
1614  
1615 if (originID.Equals(UUID.Zero))
1616 {
1617 // Movement into region will fail
1618 m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived in {1}", client.Name, Scene.Name);
1619 return false;
1620 }
1621  
1622 return true;
1623 }
1624  
1625 /// <summary>
1626 /// Complete Avatar's movement into the region.
1627 /// </summary>
1628 /// <param name="client"></param>
1629 /// <param name="openChildAgents">
1630 /// If true, send notification to neighbour regions to expect
1631 /// a child agent from the client. These neighbours can be some distance away, depending right now on the
1632 /// configuration of DefaultDrawDistance in the [Startup] section of config
1633 /// </param>
1634 public void CompleteMovement(IClientAPI client, bool openChildAgents)
1635 {
1636 // DateTime startTime = DateTime.Now;
1637  
1638 m_log.InfoFormat(
1639 "[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}",
1640 client.Name, Scene.Name, AbsolutePosition);
1641  
1642 // Make sure it's not a login agent. We don't want to wait for updates during login
1643 if (PresenceType != PresenceType.Npc && (m_teleportFlags & TeleportFlags.ViaLogin) == 0)
1644 {
1645 // Let's wait until UpdateAgent (called by departing region) is done
1646 if (!WaitForUpdateAgent(client))
1647 // The sending region never sent the UpdateAgent data, we have to refuse
1648 return;
1649 }
1650  
1651 Vector3 look = Velocity;
1652  
1653 // if ((look.X == 0) && (look.Y == 0) && (look.Z == 0))
1654 if ((Math.Abs(look.X) < 0.1) && (Math.Abs(look.Y) < 0.1) && (Math.Abs(look.Z) < 0.1))
1655 {
1656 look = new Vector3(0.99f, 0.042f, 0);
1657 }
1658  
1659 // Prevent teleporting to an underground location
1660 // (may crash client otherwise)
1661 //
1662 Vector3 pos = AbsolutePosition;
1663 float ground = m_scene.GetGroundHeight(pos.X, pos.Y);
1664 if (pos.Z < ground + 1.5f)
1665 {
1666 pos.Z = ground + 1.5f;
1667 AbsolutePosition = pos;
1668 }
1669  
1670 bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0);
1671 if (!MakeRootAgent(AbsolutePosition, flying))
1672 {
1673 m_log.DebugFormat(
1674 "[SCENE PRESENCE]: Aborting CompleteMovement call for {0} in {1} as they are already root",
1675 Name, Scene.Name);
1676  
1677 return;
1678 }
1679  
1680 // Tell the client that we're totally ready
1681 ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look);
1682  
1683 // Remember in HandleUseCircuitCode, we delayed this to here
1684 if (m_teleportFlags > 0)
1685 SendInitialDataToMe();
1686  
1687 // m_log.DebugFormat("[SCENE PRESENCE] Completed movement");
1688  
1689 if (!string.IsNullOrEmpty(m_callbackURI))
1690 {
1691 // We cannot sleep here since this would hold up the inbound packet processing thread, as
1692 // CompleteMovement() is executed synchronously. However, it might be better to delay the release
1693 // here until we know for sure that the agent is active in this region. Sending AgentMovementComplete
1694 // is not enough for Imprudence clients - there appears to be a small delay (<200ms, <500ms) until they regard this
1695 // region as the current region, meaning that a close sent before then will fail the teleport.
1696 // System.Threading.Thread.Sleep(2000);
1697  
1698 m_log.DebugFormat(
1699 "[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}",
1700 client.Name, client.AgentId, m_callbackURI);
1701  
1702 UUID originID;
1703  
1704 lock (m_originRegionIDAccessLock)
1705 originID = m_originRegionID;
1706  
1707 Scene.SimulationService.ReleaseAgent(originID, UUID, m_callbackURI);
1708 m_callbackURI = null;
1709 }
1710 // else
1711 // {
1712 // m_log.DebugFormat(
1713 // "[SCENE PRESENCE]: No callback provided on CompleteMovement of {0} {1} to {2}",
1714 // client.Name, client.AgentId, m_scene.RegionInfo.RegionName);
1715 // }
1716  
1717 ValidateAndSendAppearanceAndAgentData();
1718  
1719 // Create child agents in neighbouring regions
1720 if (openChildAgents && !IsChildAgent)
1721 {
1722 IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
1723 if (m_agentTransfer != null)
1724 m_agentTransfer.EnableChildAgents(this);
1725  
1726 IFriendsModule friendsModule = m_scene.RequestModuleInterface<IFriendsModule>();
1727 if (friendsModule != null)
1728 friendsModule.SendFriendsOnlineIfNeeded(ControllingClient);
1729  
1730 }
1731  
1732 // XXX: If we force an update here, then multiple attachments do appear correctly on a destination region
1733 // If we do it a little bit earlier (e.g. when converting the child to a root agent) then this does not work.
1734 // This may be due to viewer code or it may be something we're not doing properly simulator side.
1735 lock (m_attachments)
1736 {
1737 foreach (SceneObjectGroup sog in m_attachments)
1738 sog.ScheduleGroupForFullUpdate();
1739 }
1740  
1741 // m_log.DebugFormat(
1742 // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms",
1743 // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds);
1744  
1745 }
1746  
1747 /// <summary>
1748 /// Callback for the Camera view block check. Gets called with the results of the camera view block test
1749 /// hitYN is true when there's something in the way.
1750 /// </summary>
1751 /// <param name="hitYN"></param>
1752 /// <param name="collisionPoint"></param>
1753 /// <param name="localid"></param>
1754 /// <param name="distance"></param>
1755 ///
1756  
1757 private void UpdateCameraCollisionPlane(Vector4 plane)
1758 {
1759 if (m_lastCameraCollisionPlane != plane)
1760 {
1761 m_lastCameraCollisionPlane = plane;
1762 ControllingClient.SendCameraConstraint(plane);
1763 }
1764 }
1765  
1766 public void RayCastCameraCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 pNormal)
1767 {
1768 const float POSITION_TOLERANCE = 0.02f;
1769 const float ROTATION_TOLERANCE = 0.02f;
1770  
1771 m_doingCamRayCast = false;
1772 if (hitYN && localid != LocalId)
1773 {
1774 SceneObjectGroup group = m_scene.GetGroupByPrim(localid);
1775 bool IsPrim = group != null;
1776 if (IsPrim)
1777 {
1778 SceneObjectPart part = group.GetPart(localid);
1779 if (part != null && !part.VolumeDetectActive)
1780 {
1781 CameraConstraintActive = true;
1782 pNormal.X = (float) Math.Round(pNormal.X, 2);
1783 pNormal.Y = (float) Math.Round(pNormal.Y, 2);
1784 pNormal.Z = (float) Math.Round(pNormal.Z, 2);
1785 pNormal.Normalize();
1786 collisionPoint.X = (float) Math.Round(collisionPoint.X, 1);
1787 collisionPoint.Y = (float) Math.Round(collisionPoint.Y, 1);
1788 collisionPoint.Z = (float) Math.Round(collisionPoint.Z, 1);
1789  
1790 Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z,
1791 Vector3.Dot(collisionPoint, pNormal));
1792 UpdateCameraCollisionPlane(plane);
1793 }
1794 }
1795 else
1796 {
1797 CameraConstraintActive = true;
1798 pNormal.X = (float) Math.Round(pNormal.X, 2);
1799 pNormal.Y = (float) Math.Round(pNormal.Y, 2);
1800 pNormal.Z = (float) Math.Round(pNormal.Z, 2);
1801 pNormal.Normalize();
1802 collisionPoint.X = (float) Math.Round(collisionPoint.X, 1);
1803 collisionPoint.Y = (float) Math.Round(collisionPoint.Y, 1);
1804 collisionPoint.Z = (float) Math.Round(collisionPoint.Z, 1);
1805  
1806 Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z,
1807 Vector3.Dot(collisionPoint, pNormal));
1808 UpdateCameraCollisionPlane(plane);
1809 }
1810 }
1811 else if (!m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) ||
1812 !Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE))
1813 {
1814 Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -9000f); // not right...
1815 UpdateCameraCollisionPlane(plane);
1816 CameraConstraintActive = false;
1817 }
1818 }
1819  
1820 /// <summary>
1821 /// This is the event handler for client movement. If a client is moving, this event is triggering.
1822 /// </summary>
1823 public void HandleAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
1824 {
1825 //m_log.DebugFormat(
1826 // "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}",
1827 // Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags);
1828  
1829 if (IsChildAgent)
1830 {
1831 // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent");
1832 return;
1833 }
1834  
1835 #region Sanity Checking
1836  
1837 // This is irritating. Really.
1838 if (!AbsolutePosition.IsFinite())
1839 {
1840 RemoveFromPhysicalScene();
1841 m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999902");
1842  
1843 m_pos = m_LastFinitePos;
1844 if (!m_pos.IsFinite())
1845 {
1846 m_pos.X = 127f;
1847 m_pos.Y = 127f;
1848 m_pos.Z = 127f;
1849 m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999903");
1850 }
1851  
1852 AddToPhysicalScene(false);
1853 }
1854 else
1855 {
1856 m_LastFinitePos = m_pos;
1857 }
1858  
1859 #endregion Sanity Checking
1860  
1861 #region Inputs
1862  
1863 AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags;
1864  
1865 // The Agent's Draw distance setting
1866 // When we get to the point of re-computing neighbors everytime this
1867 // changes, then start using the agent's drawdistance rather than the
1868 // region's draw distance.
1869 // DrawDistance = agentData.Far;
1870 DrawDistance = Scene.DefaultDrawDistance;
1871  
1872 m_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0;
1873 m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0;
1874  
1875 #endregion Inputs
1876  
1877 // // Make anims work for client side autopilot
1878 // if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) != 0)
1879 // m_updateCount = UPDATE_COUNT;
1880 //
1881 // // Make turning in place work
1882 // if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0 ||
1883 // (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0)
1884 // m_updateCount = UPDATE_COUNT;
1885  
1886 if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) != 0)
1887 {
1888 StandUp();
1889 }
1890  
1891 // Raycast from the avatar's head to the camera to see if there's anything blocking the view
1892 // this exclude checks may not be complete
1893  
1894 if (m_movementUpdateCount % NumMovementsBetweenRayCast == 0 && m_scene.PhysicsScene.SupportsRayCast())
1895 {
1896 if (!m_doingCamRayCast && !m_mouseLook && ParentID == 0)
1897 {
1898 Vector3 posAdjusted = AbsolutePosition;
1899 // posAdjusted.Z += 0.5f * Appearance.AvatarSize.Z - 0.5f;
1900 posAdjusted.Z += 1.0f; // viewer current camera focus point
1901 Vector3 tocam = CameraPosition - posAdjusted;
1902 tocam.X = (float)Math.Round(tocam.X, 1);
1903 tocam.Y = (float)Math.Round(tocam.Y, 1);
1904 tocam.Z = (float)Math.Round(tocam.Z, 1);
1905  
1906 float distTocamlen = tocam.Length();
1907 if (distTocamlen > 0.3f)
1908 {
1909 tocam *= (1.0f / distTocamlen);
1910 posAdjusted.X = (float)Math.Round(posAdjusted.X, 1);
1911 posAdjusted.Y = (float)Math.Round(posAdjusted.Y, 1);
1912 posAdjusted.Z = (float)Math.Round(posAdjusted.Z, 1);
1913  
1914 m_doingCamRayCast = true;
1915 m_scene.PhysicsScene.RaycastWorld(posAdjusted, tocam, distTocamlen + 1.0f, RayCastCameraCallback);
1916 }
1917 }
1918 else if (CameraConstraintActive && (m_mouseLook || ParentID != 0))
1919 {
1920 Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -10000f); // not right...
1921 UpdateCameraCollisionPlane(plane);
1922 CameraConstraintActive = false;
1923 }
1924 }
1925  
1926 uint flagsForScripts = (uint)flags;
1927 flags = RemoveIgnoredControls(flags, IgnoredControls);
1928  
1929 if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0)
1930 HandleAgentSitOnGround();
1931  
1932 // In the future, these values might need to go global.
1933 // Here's where you get them.
1934 m_AgentControlFlags = flags;
1935 m_headrotation = agentData.HeadRotation;
1936 byte oldState = State;
1937 State = agentData.State;
1938  
1939 // We need to send this back to the client in order to stop the edit beams
1940 if ((oldState & (uint)AgentState.Editing) != 0 && State == (uint)AgentState.None)
1941 ControllingClient.SendAgentTerseUpdate(this);
1942  
1943 PhysicsActor actor = PhysicsActor;
1944  
1945 // This will be the case if the agent is sitting on the groudn or on an object.
1946 if (actor == null)
1947 {
1948 SendControlsToScripts(flagsForScripts);
1949 return;
1950 }
1951  
1952 if (AllowMovement && !SitGround)
1953 {
1954 // m_log.DebugFormat("[SCENE PRESENCE]: Initial body rotation {0} for {1}", agentData.BodyRotation, Name);
1955  
1956 bool update_rotation = false;
1957  
1958 if (agentData.BodyRotation != Rotation)
1959 {
1960 Rotation = agentData.BodyRotation;
1961 update_rotation = true;
1962 }
1963  
1964 bool update_movementflag = false;
1965  
1966 if (agentData.UseClientAgentPosition)
1967 {
1968 MovingToTarget = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f;
1969 MoveToPositionTarget = agentData.ClientAgentPosition;
1970 }
1971  
1972 int i = 0;
1973 bool DCFlagKeyPressed = false;
1974 Vector3 agent_control_v3 = Vector3.Zero;
1975  
1976 bool newFlying = actor.Flying;
1977  
1978 if (ForceFly)
1979 newFlying = true;
1980 else if (FlyDisabled)
1981 newFlying = false;
1982 else
1983 newFlying = ((flags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0);
1984  
1985 if (actor.Flying != newFlying)
1986 {
1987 // Note: ScenePresence.Flying is actually fetched from the physical actor
1988 // so setting PhysActor.Flying here also sets the ScenePresence's value.
1989 actor.Flying = newFlying;
1990 update_movementflag = true;
1991 }
1992  
1993 if (ParentID == 0)
1994 {
1995 bool bAllowUpdateMoveToPosition = false;
1996  
1997 Vector3[] dirVectors;
1998  
1999 // use camera up angle when in mouselook and not flying or when holding the left mouse button down and not flying
2000 // this prevents 'jumping' in inappropriate situations.
2001 if (!Flying && (m_mouseLook || m_leftButtonDown))
2002 dirVectors = GetWalkDirectionVectors();
2003 else
2004 dirVectors = Dir_Vectors;
2005  
2006 // A DIR_CONTROL_FLAG occurs when the user is trying to move in a particular direction.
2007 foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS)
2008 {
2009 if (((uint)flags & (uint)DCF) != 0)
2010 {
2011 DCFlagKeyPressed = true;
2012  
2013 try
2014 {
2015 agent_control_v3 += dirVectors[i];
2016 //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]);
2017 }
2018 catch (IndexOutOfRangeException)
2019 {
2020 // Why did I get this?
2021 }
2022  
2023 if (((MovementFlag & (uint)DCF) == 0) & !AgentControlStopActive)
2024 {
2025 //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with {1}", Name, DCF);
2026 MovementFlag += (uint)DCF;
2027 update_movementflag = true;
2028 }
2029 }
2030 else
2031 {
2032 if ((MovementFlag & (uint)DCF) != 0)
2033 {
2034 //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with lack of {1}", Name, DCF);
2035 MovementFlag -= (uint)DCF;
2036 update_movementflag = true;
2037  
2038 /*
2039 if ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE)
2040 && ((MovementFlag & (byte)nudgehack) == nudgehack))
2041 {
2042 m_log.Debug("Removed Hack flag");
2043 }
2044 */
2045 }
2046 else
2047 {
2048 bAllowUpdateMoveToPosition = true;
2049 }
2050 }
2051  
2052 i++;
2053 }
2054  
2055 // Detect AGENT_CONTROL_STOP state changes
2056 if (AgentControlStopActive != ((flags & AgentManager.ControlFlags.AGENT_CONTROL_STOP) != 0))
2057 {
2058 AgentControlStopActive = !AgentControlStopActive;
2059 update_movementflag = true;
2060 }
2061  
2062 if (MovingToTarget)
2063 {
2064 // If the user has pressed a key then we want to cancel any move to target.
2065 if (DCFlagKeyPressed)
2066 {
2067 ResetMoveToTarget();
2068 update_movementflag = true;
2069 }
2070 else if (bAllowUpdateMoveToPosition)
2071 {
2072 // The UseClientAgentPosition is set if parcel ban is forcing the avatar to move to a
2073 // certain position. It's only check for tolerance on returning to that position is 0.2
2074 // rather than 1, at which point it removes its force target.
2075 if (HandleMoveToTargetUpdate(agentData.UseClientAgentPosition ? 0.2 : 1, ref agent_control_v3))
2076 update_movementflag = true;
2077 }
2078 }
2079 }
2080  
2081 // Cause the avatar to stop flying if it's colliding
2082 // with something with the down arrow pressed.
2083  
2084 // Only do this if we're flying
2085 if (Flying && !ForceFly)
2086 {
2087 // Need to stop in mid air if user holds down AGENT_CONTROL_STOP
2088 if (AgentControlStopActive)
2089 {
2090 agent_control_v3 = Vector3.Zero;
2091 }
2092 else
2093 {
2094 // Landing detection code
2095  
2096 // Are the landing controls requirements filled?
2097 bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) ||
2098 ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
2099  
2100 //m_log.Debug("[CONTROL]: " +flags);
2101 // Applies a satisfying roll effect to the avatar when flying.
2102 if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0 && (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0)
2103 {
2104 ApplyFlyingRoll(
2105 FLY_ROLL_RADIANS_PER_UPDATE,
2106 (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0,
2107 (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0);
2108 }
2109 else if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0 &&
2110 (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0)
2111 {
2112 ApplyFlyingRoll(
2113 -FLY_ROLL_RADIANS_PER_UPDATE,
2114 (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0,
2115 (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0);
2116 }
2117 else
2118 {
2119 if (m_AngularVelocity.Z != 0)
2120 m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE);
2121 }
2122  
2123 if (Flying && IsColliding && controlland)
2124 {
2125 // nesting this check because LengthSquared() is expensive and we don't
2126 // want to do it every step when flying.
2127 if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX))
2128 StopFlying();
2129 }
2130 }
2131 }
2132  
2133 // m_log.DebugFormat("[SCENE PRESENCE]: MovementFlag {0} for {1}", MovementFlag, Name);
2134  
2135 // If the agent update does move the avatar, then calculate the force ready for the velocity update,
2136 // which occurs later in the main scene loop
2137 // We also need to update if the user rotates their avatar whilst it is slow walking/running (if they
2138 // held down AGENT_CONTROL_STOP whilst normal walking/running). However, we do not want to update
2139 // if the user rotated whilst holding down AGENT_CONTROL_STOP when already still (which locks the
2140 // avatar location in place).
2141 if (update_movementflag
2142 || (update_rotation && DCFlagKeyPressed && (!AgentControlStopActive || MovementFlag != 0)))
2143 {
2144 // if (update_movementflag || !AgentControlStopActive || MovementFlag != 0)
2145 // {
2146 // m_log.DebugFormat(
2147 // "[SCENE PRESENCE]: In {0} adding velocity of {1} to {2}, umf = {3}, mf = {4}, ur = {5}",
2148 // m_scene.RegionInfo.RegionName, agent_control_v3, Name,
2149 // update_movementflag, MovementFlag, update_rotation);
2150  
2151 float speedModifier;
2152  
2153 if (AgentControlStopActive)
2154 speedModifier = AgentControlStopSlowWhilstMoving;
2155 else
2156 speedModifier = 1;
2157  
2158 AddNewMovement(agent_control_v3, speedModifier);
2159 // }
2160 }
2161 // else
2162 // {
2163 // if (!update_movementflag)
2164 // {
2165 // m_log.DebugFormat(
2166 // "[SCENE PRESENCE]: In {0} ignoring requested update of {1} for {2} as update_movementflag = false",
2167 // m_scene.RegionInfo.RegionName, agent_control_v3, Name);
2168 // }
2169 // }
2170  
2171 if (update_movementflag && ParentID == 0)
2172 {
2173 // m_log.DebugFormat("[SCENE PRESENCE]: Updating movement animations for {0}", Name);
2174 Animator.UpdateMovementAnimations();
2175 }
2176  
2177 SendControlsToScripts(flagsForScripts);
2178 }
2179  
2180 // We need to send this back to the client in order to see the edit beams
2181 if ((State & (uint)AgentState.Editing) != 0)
2182 ControllingClient.SendAgentTerseUpdate(this);
2183  
2184 m_scene.EventManager.TriggerOnClientMovement(this);
2185 }
2186  
2187  
2188 /// <summary>
2189 /// This is the event handler for client cameras. If a client is moving, or moving the camera, this event is triggering.
2190 /// </summary>
2191 private void HandleAgentCamerasUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
2192 {
2193 //m_log.DebugFormat(
2194 // "[SCENE PRESENCE]: In {0} received agent camera update from {1}, flags {2}",
2195 // Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags);
2196  
2197 if (IsChildAgent)
2198 {
2199 // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent");
2200 return;
2201 }
2202  
2203 ++m_movementUpdateCount;
2204 if (m_movementUpdateCount < 1)
2205 m_movementUpdateCount = 1;
2206  
2207 // AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags;
2208  
2209 // Camera location in world. We'll need to raytrace
2210 // from this location from time to time.
2211 CameraPosition = agentData.CameraCenter;
2212 if (Vector3.Distance(m_lastCameraPosition, CameraPosition) >= Scene.RootReprioritizationDistance)
2213 {
2214 ReprioritizeUpdates();
2215 m_lastCameraPosition = CameraPosition;
2216 }
2217  
2218 // Use these three vectors to figure out what the agent is looking at
2219 // Convert it to a Matrix and/or Quaternion
2220 CameraAtAxis = agentData.CameraAtAxis;
2221 CameraLeftAxis = agentData.CameraLeftAxis;
2222 CameraUpAxis = agentData.CameraUpAxis;
2223  
2224 // The Agent's Draw distance setting
2225 // When we get to the point of re-computing neighbors everytime this
2226 // changes, then start using the agent's drawdistance rather than the
2227 // region's draw distance.
2228 // DrawDistance = agentData.Far;
2229 DrawDistance = Scene.DefaultDrawDistance;
2230  
2231 // Check if Client has camera in 'follow cam' or 'build' mode.
2232 Vector3 camdif = (Vector3.One * Rotation - Vector3.One * CameraRotation);
2233  
2234 m_followCamAuto = ((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.98f)
2235 && (Math.Abs(camdif.X) < 0.4f && Math.Abs(camdif.Y) < 0.4f)) ? true : false;
2236  
2237  
2238 //m_log.DebugFormat("[FollowCam]: {0}", m_followCamAuto);
2239 // Raycast from the avatar's head to the camera to see if there's anything blocking the view
2240 if ((m_movementUpdateCount % NumMovementsBetweenRayCast) == 0 && m_scene.PhysicsScene.SupportsRayCast())
2241 {
2242 if (m_followCamAuto)
2243 {
2244 Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT;
2245 m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback);
2246 }
2247 }
2248  
2249 TriggerScenePresenceUpdated();
2250 }
2251  
2252 /// <summary>
2253 /// Calculate an update to move the presence to the set target.
2254 /// </summary>
2255 /// <remarks>
2256 /// This doesn't actually perform the movement. Instead, it adds its vector to agent_control_v3.
2257 /// </remarks>
2258 /// <param value="agent_control_v3">Cumulative agent movement that this method will update.</param>
2259 /// <returns>True if movement has been updated in some way. False otherwise.</returns>
2260 public bool HandleMoveToTargetUpdate(double tolerance, ref Vector3 agent_control_v3)
2261 {
2262 // m_log.DebugFormat("[SCENE PRESENCE]: Called HandleMoveToTargetUpdate() for {0}", Name);
2263  
2264 bool updated = false;
2265  
2266 // m_log.DebugFormat(
2267 // "[SCENE PRESENCE]: bAllowUpdateMoveToPosition {0}, m_moveToPositionInProgress {1}, m_autopilotMoving {2}",
2268 // allowUpdate, m_moveToPositionInProgress, m_autopilotMoving);
2269  
2270 double distanceToTarget = Util.GetDistanceTo(AbsolutePosition, MoveToPositionTarget);
2271  
2272 // m_log.DebugFormat(
2273 // "[SCENE PRESENCE]: Abs pos of {0} is {1}, target {2}, distance {3}",
2274 // Name, AbsolutePosition, MoveToPositionTarget, distanceToTarget);
2275  
2276 // Check the error term of the current position in relation to the target position
2277 if (distanceToTarget <= tolerance)
2278 {
2279 // We are close enough to the target
2280 AbsolutePosition = MoveToPositionTarget;
2281 ResetMoveToTarget();
2282 updated = true;
2283 }
2284 else
2285 {
2286 try
2287 {
2288 // move avatar in 3D at one meter/second towards target, in avatar coordinate frame.
2289 // This movement vector gets added to the velocity through AddNewMovement().
2290 // Theoretically we might need a more complex PID approach here if other
2291 // unknown forces are acting on the avatar and we need to adaptively respond
2292 // to such forces, but the following simple approach seems to works fine.
2293 Vector3 LocalVectorToTarget3D =
2294 (MoveToPositionTarget - AbsolutePosition) // vector from cur. pos to target in global coords
2295 * Matrix4.CreateFromQuaternion(Quaternion.Inverse(Rotation)); // change to avatar coords
2296 // Ignore z component of vector
2297 // Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f);
2298 LocalVectorToTarget3D.Normalize();
2299  
2300 // update avatar movement flags. the avatar coordinate system is as follows:
2301 //
2302 // +X (forward)
2303 //
2304 // ^
2305 // |
2306 // |
2307 // |
2308 // |
2309 // (left) +Y <--------o--------> -Y
2310 // avatar
2311 // |
2312 // |
2313 // |
2314 // |
2315 // v
2316 // -X
2317 //
2318  
2319 // based on the above avatar coordinate system, classify the movement into
2320 // one of left/right/back/forward.
2321 if (LocalVectorToTarget3D.X < 0) //MoveBack
2322 {
2323 MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK;
2324 AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK;
2325 updated = true;
2326 }
2327 else if (LocalVectorToTarget3D.X > 0) //Move Forward
2328 {
2329 MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD;
2330 AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD;
2331 updated = true;
2332 }
2333  
2334 if (LocalVectorToTarget3D.Y > 0) //MoveLeft
2335 {
2336 MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT;
2337 AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT;
2338 updated = true;
2339 }
2340 else if (LocalVectorToTarget3D.Y < 0) //MoveRight
2341 {
2342 MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT;
2343 AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT;
2344 updated = true;
2345 }
2346  
2347 if (LocalVectorToTarget3D.Z > 0) //Up
2348 {
2349 // Don't set these flags for up or down - doing so will make the avatar crouch or
2350 // keep trying to jump even if walking along level ground
2351 //MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_UP;
2352 //AgentControlFlags
2353 //AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_UP;
2354 updated = true;
2355 }
2356 else if (LocalVectorToTarget3D.Z < 0) //Down
2357 {
2358 //MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN;
2359 //AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN;
2360 updated = true;
2361 }
2362  
2363 // m_log.DebugFormat(
2364 // "[SCENE PRESENCE]: HandleMoveToTargetUpdate adding {0} to move vector {1} for {2}",
2365 // LocalVectorToTarget3D, agent_control_v3, Name);
2366  
2367 agent_control_v3 += LocalVectorToTarget3D;
2368 }
2369 catch (Exception e)
2370 {
2371 //Avoid system crash, can be slower but...
2372 m_log.DebugFormat("Crash! {0}", e.ToString());
2373 }
2374 }
2375  
2376 return updated;
2377 }
2378  
2379 /// <summary>
2380 /// Move to the given target over time.
2381 /// </summary>
2382 /// <param name="pos"></param>
2383 /// <param name="noFly">
2384 /// If true, then don't allow the avatar to fly to the target, even if it's up in the air.
2385 /// This is to allow movement to targets that are known to be on an elevated platform with a continuous path
2386 /// from start to finish.
2387 /// </param>
2388 /// <param name="landAtTarget">
2389 /// If true and the avatar starts flying during the move then land at the target.
2390 /// </param>
2391 public void MoveToTarget(Vector3 pos, bool noFly, bool landAtTarget)
2392 {
2393 if (SitGround)
2394 StandUp();
2395  
2396 // m_log.DebugFormat(
2397 // "[SCENE PRESENCE]: Avatar {0} received request to move to position {1} in {2}",
2398 // Name, pos, m_scene.RegionInfo.RegionName);
2399  
2400 // Allow move to another sub-region within a megaregion
2401 Vector2 regionSize;
2402 IRegionCombinerModule regionCombinerModule = m_scene.RequestModuleInterface<IRegionCombinerModule>();
2403 if (regionCombinerModule != null)
2404 regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID);
2405 else
2406 regionSize = new Vector2(m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY);
2407  
2408 if (pos.X < 0 || pos.X >= regionSize.X
2409 || pos.Y < 0 || pos.Y >= regionSize.Y
2410 || pos.Z < 0)
2411 return;
2412  
2413 // Vector3 heightAdjust = new Vector3(0, 0, Appearance.AvatarHeight / 2);
2414 // pos += heightAdjust;
2415 //
2416 // // Anti duck-walking measure
2417 // if (Math.Abs(pos.Z - AbsolutePosition.Z) < 0.2f)
2418 // {
2419 //// m_log.DebugFormat("[SCENE PRESENCE]: Adjusting MoveToPosition from {0} to {1}", pos, AbsolutePosition);
2420 // pos.Z = AbsolutePosition.Z;
2421 // }
2422  
2423 // Get terrain height for sub-region in a megaregion if necessary
2424 int X = (int)((m_scene.RegionInfo.WorldLocX) + pos.X);
2425 int Y = (int)((m_scene.RegionInfo.WorldLocY) + pos.Y);
2426 GridRegion target_region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y);
2427 // If X and Y is NaN, target_region will be null
2428 if (target_region == null)
2429 return;
2430 UUID target_regionID = target_region.RegionID;
2431 Scene targetScene = m_scene;
2432  
2433 if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene))
2434 targetScene = m_scene;
2435  
2436 float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % regionSize.X), (int)(pos.Y % regionSize.Y)];
2437 pos.Z = Math.Max(terrainHeight, pos.Z);
2438  
2439 // Fudge factor. It appears that if one clicks "go here" on a piece of ground, the go here request is
2440 // always slightly higher than the actual terrain height.
2441 // FIXME: This constrains NPC movements as well, so should be somewhere else.
2442 if (pos.Z - terrainHeight < 0.2)
2443 pos.Z = terrainHeight;
2444  
2445 // m_log.DebugFormat(
2446 // "[SCENE PRESENCE]: Avatar {0} set move to target {1} (terrain height {2}) in {3}",
2447 // Name, pos, terrainHeight, m_scene.RegionInfo.RegionName);
2448  
2449 if (noFly)
2450 Flying = false;
2451 else if (pos.Z > terrainHeight)
2452 Flying = true;
2453  
2454 LandAtTarget = landAtTarget;
2455 MovingToTarget = true;
2456 MoveToPositionTarget = pos;
2457  
2458 // Rotate presence around the z-axis to point in same direction as movement.
2459 // Ignore z component of vector
2460 Vector3 localVectorToTarget3D = pos - AbsolutePosition;
2461 Vector3 localVectorToTarget2D = new Vector3((float)(localVectorToTarget3D.X), (float)(localVectorToTarget3D.Y), 0f);
2462  
2463 // m_log.DebugFormat("[SCENE PRESENCE]: Local vector to target is {0}", localVectorToTarget2D);
2464  
2465 // Calculate the yaw.
2466 Vector3 angle = new Vector3(0, 0, (float)(Math.Atan2(localVectorToTarget2D.Y, localVectorToTarget2D.X)));
2467  
2468 // m_log.DebugFormat("[SCENE PRESENCE]: Angle is {0}", angle);
2469  
2470 Rotation = Quaternion.CreateFromEulers(angle);
2471 // m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, Rotation);
2472  
2473 Vector3 agent_control_v3 = new Vector3();
2474 HandleMoveToTargetUpdate(1, ref agent_control_v3);
2475 AddNewMovement(agent_control_v3);
2476 }
2477  
2478 /// <summary>
2479 /// Reset the move to target.
2480 /// </summary>
2481 public void ResetMoveToTarget()
2482 {
2483 // m_log.DebugFormat("[SCENE PRESENCE]: Resetting move to target for {0}", Name);
2484  
2485 MovingToTarget = false;
2486 // MoveToPositionTarget = Vector3.Zero;
2487 m_forceToApply = null; // cancel possible last action
2488  
2489 // We need to reset the control flag as the ScenePresenceAnimator uses this to determine the correct
2490 // resting animation (e.g. hover or stand). NPCs don't have a client that will quickly reset this flag.
2491 // However, the line is here rather than in the NPC module since it also appears necessary to stop a
2492 // viewer that uses "go here" from juddering on all subsequent avatar movements.
2493 AgentControlFlags = (uint)AgentManager.ControlFlags.NONE;
2494 }
2495  
2496 /// <summary>
2497 /// Perform the logic necessary to stand the avatar up. This method also executes
2498 /// the stand animation.
2499 /// </summary>
2500 public void StandUp()
2501 {
2502 // m_log.DebugFormat("[SCENE PRESENCE]: StandUp() for {0}", Name);
2503  
2504 bool satOnObject = IsSatOnObject;
2505 SceneObjectPart part = ParentPart;
2506 SitGround = false;
2507  
2508 if (satOnObject)
2509 {
2510 PrevSitOffset = m_pos; // Save sit offset
2511 UnRegisterSeatControls(part.ParentGroup.UUID);
2512  
2513 TaskInventoryDictionary taskIDict = part.TaskInventory;
2514 if (taskIDict != null)
2515 {
2516 lock (taskIDict)
2517 {
2518 foreach (UUID taskID in taskIDict.Keys)
2519 {
2520 UnRegisterControlEventsToScript(LocalId, taskID);
2521 taskIDict[taskID].PermsMask &= ~(
2522 2048 | //PERMISSION_CONTROL_CAMERA
2523 4); // PERMISSION_TAKE_CONTROLS
2524 }
2525 }
2526 }
2527  
2528 part.ParentGroup.DeleteAvatar(UUID);
2529 Vector3 sitPartWorldPosition = part.GetWorldPosition();
2530 ControllingClient.SendClearFollowCamProperties(part.ParentUUID);
2531  
2532 ParentID = 0;
2533 ParentPart = null;
2534  
2535 Quaternion standRotation;
2536  
2537 if (part.SitTargetAvatar == UUID)
2538 {
2539 standRotation = part.GetWorldRotation();
2540  
2541 if (!part.IsRoot)
2542 standRotation = standRotation * part.SitTargetOrientation;
2543 // standRotation = part.RotationOffset * part.SitTargetOrientation;
2544 // else
2545 // standRotation = part.SitTargetOrientation;
2546  
2547 }
2548 else
2549 {
2550 standRotation = Rotation;
2551 }
2552  
2553 //Vector3 standPos = ParentPosition + new Vector3(0.0f, 0.0f, 2.0f * m_sitAvatarHeight);
2554 //Vector3 standPos = ParentPosition;
2555  
2556 // Vector3 standPositionAdjustment
2557 // = part.SitTargetPosition + new Vector3(0.5f, 0f, m_sitAvatarHeight / 2f);
2558 Vector3 adjustmentForSitPosition = part.SitTargetPosition * part.GetWorldRotation();
2559  
2560 // XXX: This is based on the physics capsule sizes. Need to find a better way to read this rather than
2561 // hardcoding here.
2562 Vector3 adjustmentForSitPose = new Vector3(0.74f, 0f, 0f) * standRotation;
2563  
2564 Vector3 standPos = sitPartWorldPosition + adjustmentForSitPosition + adjustmentForSitPose;
2565  
2566 // m_log.DebugFormat(
2567 // "[SCENE PRESENCE]: Setting stand to pos {0}, (adjustmentForSitPosition {1}, adjustmentForSitPose {2}) rotation {3} for {4} in {5}",
2568 // standPos, adjustmentForSitPosition, adjustmentForSitPose, standRotation, Name, Scene.Name);
2569  
2570 Rotation = standRotation;
2571 AbsolutePosition = standPos;
2572 }
2573  
2574 // We need to wait until we have calculated proper stand positions before sitting up the physical
2575 // avatar to avoid race conditions.
2576 if (PhysicsActor == null)
2577 AddToPhysicalScene(false);
2578  
2579 if (satOnObject)
2580 {
2581 SendAvatarDataToAllAgents();
2582 m_requestedSitTargetID = 0;
2583  
2584 part.RemoveSittingAvatar(UUID);
2585  
2586 part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK);
2587 }
2588  
2589 else if (PhysicsActor == null)
2590 AddToPhysicalScene(false);
2591  
2592 Animator.TrySetMovementAnimation("STAND");
2593 TriggerScenePresenceUpdated();
2594 }
2595  
2596 private SceneObjectPart FindNextAvailableSitTarget(UUID targetID)
2597 {
2598 SceneObjectPart targetPart = m_scene.GetSceneObjectPart(targetID);
2599 if (targetPart == null)
2600 return null;
2601  
2602 // If the primitive the player clicked on has a sit target and that sit target is not full, that sit target is used.
2603 // If the primitive the player clicked on has no sit target, and one or more other linked objects have sit targets that are not full, the sit target of the object with the lowest link number will be used.
2604  
2605 // Get our own copy of the part array, and sort into the order we want to test
2606 SceneObjectPart[] partArray = targetPart.ParentGroup.Parts;
2607 Array.Sort(partArray, delegate(SceneObjectPart p1, SceneObjectPart p2)
2608 {
2609 // we want the originally selected part first, then the rest in link order -- so make the selected part link num (-1)
2610 int linkNum1 = p1==targetPart ? -1 : p1.LinkNum;
2611 int linkNum2 = p2==targetPart ? -1 : p2.LinkNum;
2612 return linkNum1 - linkNum2;
2613 }
2614 );
2615  
2616 //look for prims with explicit sit targets that are available
2617 foreach (SceneObjectPart part in partArray)
2618 {
2619 if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero)
2620 {
2621 //switch the target to this prim
2622 return part;
2623 }
2624 }
2625  
2626 // no explicit sit target found - use original target
2627 return targetPart;
2628 }
2629  
2630 private void SendSitResponse(UUID targetID, Vector3 offset, Quaternion sitOrientation)
2631 {
2632 Vector3 cameraEyeOffset = Vector3.Zero;
2633 Vector3 cameraAtOffset = Vector3.Zero;
2634 bool forceMouselook = false;
2635  
2636 SceneObjectPart part = FindNextAvailableSitTarget(targetID);
2637 if (part == null)
2638 return;
2639  
2640 if (PhysicsActor != null)
2641 m_sitAvatarHeight = PhysicsActor.Size.Z * 0.5f;
2642  
2643 bool canSit = false;
2644  
2645 if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero)
2646 {
2647 // m_log.DebugFormat(
2648 // "[SCENE PRESENCE]: Sitting {0} on {1} {2} because sit target is set and unoccupied",
2649 // Name, part.Name, part.LocalId);
2650  
2651 offset = part.SitTargetPosition;
2652 sitOrientation = part.SitTargetOrientation;
2653  
2654 if (!part.IsRoot)
2655 {
2656 // m_log.DebugFormat("Old sit orient {0}", sitOrientation);
2657 sitOrientation = part.RotationOffset * sitOrientation;
2658 // m_log.DebugFormat("New sit orient {0}", sitOrientation);
2659 // m_log.DebugFormat("Old sit offset {0}", offset);
2660 offset = offset * part.RotationOffset;
2661 // m_log.DebugFormat("New sit offset {0}", offset);
2662 }
2663  
2664 canSit = true;
2665 }
2666 else
2667 {
2668 if (PhysicsSit(part,offset)) // physics engine
2669 return;
2670  
2671 Vector3 pos = part.AbsolutePosition + offset;
2672  
2673 if (Util.GetDistanceTo(AbsolutePosition, pos) <= 10)
2674 {
2675 AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight);
2676 canSit = true;
2677 }
2678 }
2679  
2680 if (canSit)
2681 {
2682  
2683 if (PhysicsActor != null)
2684 {
2685 // We can remove the physicsActor until they stand up.
2686 RemoveFromPhysicalScene();
2687 }
2688  
2689 if (MovingToTarget)
2690 ResetMoveToTarget();
2691  
2692 Velocity = Vector3.Zero;
2693  
2694 part.AddSittingAvatar(UUID);
2695  
2696 cameraAtOffset = part.GetCameraAtOffset();
2697 cameraEyeOffset = part.GetCameraEyeOffset();
2698 forceMouselook = part.GetForceMouselook();
2699  
2700 // An viewer expects to specify sit positions as offsets to the root prim, even if a child prim is
2701 // being sat upon.
2702 offset += part.OffsetPosition;
2703  
2704 ControllingClient.SendSitResponse(
2705 part.ParentGroup.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook);
2706  
2707 m_requestedSitTargetUUID = part.UUID;
2708  
2709 HandleAgentSit(ControllingClient, UUID);
2710  
2711 // Moved here to avoid a race with default sit anim
2712 // The script event needs to be raised after the default sit anim is set.
2713 part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK);
2714 }
2715 }
2716  
2717 public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset)
2718 {
2719 if (IsChildAgent)
2720 return;
2721  
2722 if (ParentID != 0)
2723 {
2724 if (ParentPart.UUID == targetID)
2725 return; // already sitting here, ignore
2726  
2727 StandUp();
2728 }
2729  
2730 SceneObjectPart part = FindNextAvailableSitTarget(targetID);
2731  
2732 if (part != null)
2733 {
2734 m_requestedSitTargetID = part.LocalId;
2735 m_requestedSitTargetUUID = part.UUID;
2736  
2737 }
2738 else
2739 {
2740 m_log.Warn("Sit requested on unknown object: " + targetID.ToString());
2741 }
2742  
2743 SendSitResponse(targetID, offset, Quaternion.Identity);
2744 }
2745  
2746 // returns false if does not suport so older sit can be tried
2747 public bool PhysicsSit(SceneObjectPart part, Vector3 offset)
2748 {
2749 // TODO: Pull in these bits
2750 return false;
2751 /*
2752 if (part == null || part.ParentGroup.IsAttachment)
2753 {
2754 return true;
2755 }
2756  
2757 if ( m_scene.PhysicsScene == null)
2758 return false;
2759  
2760 if (part.PhysActor == null)
2761 {
2762 // none physcis shape
2763 if (part.PhysicsShapeType == (byte)PhysicsShapeType.None)
2764 ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot.");
2765 else
2766 { // non physical phantom TODO
2767 ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot.");
2768 return false;
2769 }
2770 return true;
2771 }
2772  
2773  
2774 // not doing autopilot
2775 m_requestedSitTargetID = 0;
2776  
2777 if (m_scene.PhysicsScene.SitAvatar(part.PhysActor, AbsolutePosition, CameraPosition, offset, new Vector3(0.35f, 0, 0.65f), PhysicsSitResponse) != 0)
2778 return true;
2779  
2780 return false;
2781 */
2782 }
2783  
2784  
2785 private bool CanEnterLandPosition(Vector3 testPos)
2786 {
2787 ILandObject land = m_scene.LandChannel.GetLandObject(testPos.X, testPos.Y);
2788  
2789 if (land == null || land.LandData.Name == "NO_LAND")
2790 return true;
2791  
2792 return land.CanBeOnThisLand(UUID,testPos.Z);
2793 }
2794  
2795 // status
2796 // < 0 ignore
2797 // 0 bad sit spot
2798 public void PhysicsSitResponse(int status, uint partID, Vector3 offset, Quaternion Orientation)
2799 {
2800 if (status < 0)
2801 return;
2802  
2803 if (status == 0)
2804 {
2805 ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot.");
2806 return;
2807 }
2808  
2809 SceneObjectPart part = m_scene.GetSceneObjectPart(partID);
2810 if (part == null)
2811 return;
2812  
2813 Vector3 targetPos = part.GetWorldPosition() + offset * part.GetWorldRotation();
2814 if(!CanEnterLandPosition(targetPos))
2815 {
2816 ControllingClient.SendAlertMessage(" Sit position on restricted land, try another spot");
2817 return;
2818 }
2819  
2820 RemoveFromPhysicalScene();
2821  
2822 if (MovingToTarget)
2823 ResetMoveToTarget();
2824  
2825 Velocity = Vector3.Zero;
2826  
2827 part.AddSittingAvatar(UUID);
2828  
2829 Vector3 cameraAtOffset = part.GetCameraAtOffset();
2830 Vector3 cameraEyeOffset = part.GetCameraEyeOffset();
2831 bool forceMouselook = part.GetForceMouselook();
2832  
2833 ControllingClient.SendSitResponse(
2834 part.UUID, offset, Orientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook);
2835  
2836 // not using autopilot
2837  
2838 Rotation = Orientation;
2839 m_pos = offset;
2840  
2841 m_requestedSitTargetID = 0;
2842 part.ParentGroup.AddAvatar(UUID);
2843  
2844 ParentPart = part;
2845 ParentID = part.LocalId;
2846 if(status == 3)
2847 Animator.TrySetMovementAnimation("SIT_GROUND");
2848 else
2849 Animator.TrySetMovementAnimation("SIT");
2850 SendAvatarDataToAllAgents();
2851  
2852 part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK);
2853 }
2854  
2855  
2856 public void HandleAgentSit(IClientAPI remoteClient, UUID agentID)
2857 {
2858 if (IsChildAgent)
2859 return;
2860  
2861 SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID);
2862  
2863 if (part != null)
2864 {
2865 if (part.ParentGroup.IsAttachment)
2866 {
2867 m_log.WarnFormat(
2868 "[SCENE PRESENCE]: Avatar {0} tried to sit on part {1} from object {2} in {3} but this is an attachment for avatar id {4}",
2869 Name, part.Name, part.ParentGroup.Name, Scene.Name, part.ParentGroup.AttachedAvatar);
2870  
2871 return;
2872 }
2873  
2874  
2875 if (part.SitTargetAvatar == UUID)
2876 {
2877 Vector3 sitTargetPos = part.SitTargetPosition;
2878 Quaternion sitTargetOrient = part.SitTargetOrientation;
2879  
2880 // m_log.DebugFormat(
2881 // "[SCENE PRESENCE]: Sitting {0} at sit target {1}, {2} on {3} {4}",
2882 // Name, sitTargetPos, sitTargetOrient, part.Name, part.LocalId);
2883  
2884 //Quaternion vq = new Quaternion(sitTargetPos.X, sitTargetPos.Y+0.2f, sitTargetPos.Z+0.2f, 0);
2885 //Quaternion nq = new Quaternion(-sitTargetOrient.X, -sitTargetOrient.Y, -sitTargetOrient.Z, sitTargetOrient.w);
2886  
2887 //Quaternion result = (sitTargetOrient * vq) * nq;
2888  
2889 double x, y, z, m;
2890  
2891 Quaternion r = sitTargetOrient;
2892 m = r.X * r.X + r.Y * r.Y + r.Z * r.Z + r.W * r.W;
2893  
2894 if (Math.Abs(1.0 - m) > 0.000001)
2895 {
2896 m = 1.0 / Math.Sqrt(m);
2897 r.X *= (float)m;
2898 r.Y *= (float)m;
2899 r.Z *= (float)m;
2900 r.W *= (float)m;
2901 }
2902  
2903 x = 2 * (r.X * r.Z + r.Y * r.W);
2904 y = 2 * (-r.X * r.W + r.Y * r.Z);
2905 z = -r.X * r.X - r.Y * r.Y + r.Z * r.Z + r.W * r.W;
2906  
2907 Vector3 up = new Vector3((float)x, (float)y, (float)z);
2908 Vector3 sitOffset = up * Appearance.AvatarHeight * 0.02638f;
2909  
2910 Vector3 newPos = sitTargetPos + sitOffset + SIT_TARGET_ADJUSTMENT;
2911 Quaternion newRot;
2912  
2913 if (part.IsRoot)
2914 {
2915 newRot = sitTargetOrient;
2916 }
2917 else
2918 {
2919 newPos = newPos * part.RotationOffset;
2920 newRot = part.RotationOffset * sitTargetOrient;
2921 }
2922  
2923 newPos += part.OffsetPosition;
2924  
2925 m_pos = newPos;
2926 Rotation = newRot;
2927  
2928 // ParentPosition = part.AbsolutePosition;
2929 }
2930 else
2931 {
2932 // An viewer expects to specify sit positions as offsets to the root prim, even if a child prim is
2933 // being sat upon.
2934 m_pos -= part.GroupPosition;
2935  
2936 // ParentPosition = part.AbsolutePosition;
2937  
2938 // m_log.DebugFormat(
2939 // "[SCENE PRESENCE]: Sitting {0} at position {1} ({2} + {3}) on part {4} {5} without sit target",
2940 // Name, part.AbsolutePosition, m_pos, ParentPosition, part.Name, part.LocalId);
2941 }
2942  
2943 part.ParentGroup.AddAvatar(UUID);
2944 ParentPart = m_scene.GetSceneObjectPart(m_requestedSitTargetID);
2945 ParentID = m_requestedSitTargetID;
2946 m_AngularVelocity = Vector3.Zero;
2947 Velocity = Vector3.Zero;
2948 RemoveFromPhysicalScene();
2949  
2950 String sitAnimation = "SIT";
2951 if (!String.IsNullOrEmpty(part.SitAnimation))
2952 {
2953 sitAnimation = part.SitAnimation;
2954 }
2955 Animator.TrySetMovementAnimation(sitAnimation);
2956 SendAvatarDataToAllAgents();
2957 TriggerScenePresenceUpdated();
2958 }
2959 }
2960  
2961 public void HandleAgentSitOnGround()
2962 {
2963 if (IsChildAgent)
2964 return;
2965  
2966 // m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick..
2967 m_AngularVelocity = Vector3.Zero;
2968 Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED");
2969 TriggerScenePresenceUpdated();
2970 SitGround = true;
2971 RemoveFromPhysicalScene();
2972 }
2973  
2974 /// <summary>
2975 /// Event handler for the 'Always run' setting on the client
2976 /// Tells the physics plugin to increase speed of movement.
2977 /// </summary>
2978 public void HandleSetAlwaysRun(IClientAPI remoteClient, bool pSetAlwaysRun)
2979 {
2980 SetAlwaysRun = pSetAlwaysRun;
2981 }
2982  
2983 public void HandleStartAnim(IClientAPI remoteClient, UUID animID)
2984 {
2985 Animator.AddAnimation(animID, UUID.Zero);
2986 TriggerScenePresenceUpdated();
2987 }
2988  
2989 public void HandleStopAnim(IClientAPI remoteClient, UUID animID)
2990 {
2991 Animator.RemoveAnimation(animID, false);
2992 TriggerScenePresenceUpdated();
2993 }
2994  
2995 /// <summary>
2996 /// Rotate the avatar to the given rotation and apply a movement in the given relative vector
2997 /// </summary>
2998 /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param>
2999 /// <param name="thisAddSpeedModifier">
3000 /// Optional additional speed modifier for this particular add. Default is 1</param>
3001 public void AddNewMovement(Vector3 vec, float thisAddSpeedModifier = 1)
3002 {
3003 // m_log.DebugFormat(
3004 // "[SCENE PRESENCE]: Adding new movement {0} with rotation {1}, thisAddSpeedModifier {2} for {3}",
3005 // vec, Rotation, thisAddSpeedModifier, Name);
3006  
3007 Vector3 direc = vec * Rotation;
3008 direc.Normalize();
3009  
3010 if (Flying != FlyingOld) // add for fly velocity control
3011 {
3012 FlyingOld = Flying; // add for fly velocity control
3013 if (!Flying)
3014 WasFlying = true; // add for fly velocity control
3015 }
3016  
3017 if (IsColliding)
3018 WasFlying = false; // add for fly velocity control
3019  
3020 if ((vec.Z == 0f) && !Flying)
3021 direc.Z = 0f; // Prevent camera WASD up.
3022  
3023 direc *= 0.03f * 128f * SpeedModifier * thisAddSpeedModifier;
3024  
3025 // m_log.DebugFormat("[SCENE PRESENCE]: Force to apply before modification was {0} for {1}", direc, Name);
3026  
3027 if (PhysicsActor != null)
3028 {
3029 if (Flying)
3030 {
3031 direc *= 4.0f;
3032 //bool controlland = (((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
3033 //if (controlland)
3034 // m_log.Info("[AGENT]: landCommand");
3035 //if (IsColliding)
3036 // m_log.Info("[AGENT]: colliding");
3037 //if (Flying && IsColliding && controlland)
3038 //{
3039 // StopFlying();
3040 // m_log.Info("[AGENT]: Stop Flying");
3041 //}
3042 }
3043 if (Animator.Falling && WasFlying) // if falling from flying, disable motion add
3044 {
3045 direc *= 0.0f;
3046 }
3047 else if (!Flying && IsColliding)
3048 {
3049 if (direc.Z > 2.0f)
3050 {
3051 direc.Z *= 2.6f;
3052  
3053 // TODO: PreJump and jump happen too quickly. Many times prejump gets ignored.
3054 // Animator.TrySetMovementAnimation("PREJUMP");
3055 // Animator.TrySetMovementAnimation("JUMP");
3056 }
3057 }
3058 }
3059  
3060 // m_log.DebugFormat("[SCENE PRESENCE]: Setting force to apply to {0} for {1}", direc, Name);
3061  
3062 // TODO: Add the force instead of only setting it to support multiple forces per frame?
3063 m_forceToApply = direc;
3064 Animator.UpdateMovementAnimations();
3065 }
3066  
3067 #endregion
3068  
3069 #region Overridden Methods
3070  
3071 public override void Update()
3072 {
3073 const float ROTATION_TOLERANCE = 0.01f;
3074 const float VELOCITY_TOLERANCE = 0.001f;
3075 const float POSITION_TOLERANCE = 0.05f;
3076  
3077 if (IsChildAgent == false)
3078 {
3079 // NOTE: Velocity is not the same as m_velocity. Velocity will attempt to
3080 // grab the latest PhysicsActor velocity, whereas m_velocity is often
3081 // storing a requested force instead of an actual traveling velocity
3082 if (Appearance.AvatarSize != m_lastSize && !IsLoggingIn)
3083 SendAvatarDataToAllAgents();
3084  
3085 if (!Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE) ||
3086 !Velocity.ApproxEquals(m_lastVelocity, VELOCITY_TOLERANCE) ||
3087 !m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE))
3088 {
3089 SendTerseUpdateToAllClients();
3090  
3091 // Update the "last" values
3092 m_lastPosition = m_pos;
3093 m_lastRotation = Rotation;
3094 m_lastVelocity = Velocity;
3095 }
3096  
3097 CheckForBorderCrossing();
3098  
3099 CheckForSignificantMovement(); // sends update to the modules.
3100 }
3101 }
3102  
3103 #endregion
3104  
3105 #region Update Client(s)
3106  
3107  
3108 /// <summary>
3109 /// Sends a location update to the client connected to this scenePresence
3110 /// </summary>
3111 /// <param name="remoteClient"></param>
3112 public void SendTerseUpdateToClient(IClientAPI remoteClient)
3113 {
3114 // If the client is inactive, it's getting its updates from another
3115 // server.
3116 if (remoteClient.IsActive)
3117 {
3118 //m_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, Rotation, m_velocity);
3119  
3120 remoteClient.SendEntityUpdate(
3121 this,
3122 PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity
3123 | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity);
3124  
3125 m_scene.StatsReporter.AddAgentUpdates(1);
3126 }
3127 }
3128  
3129  
3130 // vars to support reduced update frequency when velocity is unchanged
3131 private Vector3 lastVelocitySentToAllClients = Vector3.Zero;
3132 private Vector3 lastPositionSentToAllClients = Vector3.Zero;
3133 private int lastTerseUpdateToAllClientsTick = Util.EnvironmentTickCount();
3134  
3135 /// <summary>
3136 /// Send a location/velocity/accelleration update to all agents in scene
3137 /// </summary>
3138 public void SendTerseUpdateToAllClients()
3139 {
3140 int currentTick = Util.EnvironmentTickCount();
3141  
3142 // Decrease update frequency when avatar is moving but velocity is
3143 // not changing.
3144 // If there is a mismatch between distance travelled and expected
3145 // distance based on last velocity sent and velocity hasnt changed,
3146 // then send a new terse update
3147  
3148 float timeSinceLastUpdate = (currentTick - lastTerseUpdateToAllClientsTick) * 0.001f;
3149  
3150 Vector3 expectedPosition = lastPositionSentToAllClients + lastVelocitySentToAllClients * timeSinceLastUpdate;
3151  
3152 float distanceError = Vector3.Distance(OffsetPosition, expectedPosition);
3153  
3154 float speed = Velocity.Length();
3155 float velocidyDiff = Vector3.Distance(lastVelocitySentToAllClients, Velocity);
3156  
3157 // assuming 5 ms. worst case precision for timer, use 2x that
3158 // for distance error threshold
3159 float distanceErrorThreshold = speed * 0.01f;
3160  
3161 if (speed < 0.01f // allow rotation updates if avatar position is unchanged
3162 || Math.Abs(distanceError) > distanceErrorThreshold
3163 || velocidyDiff > 0.01f) // did velocity change from last update?
3164 {
3165 lastVelocitySentToAllClients = Velocity;
3166 lastTerseUpdateToAllClientsTick = currentTick;
3167 lastPositionSentToAllClients = OffsetPosition;
3168  
3169 // Console.WriteLine("Scheduled update for {0} in {1}", Name, Scene.Name);
3170 m_scene.ForEachClient(SendTerseUpdateToClient);
3171 }
3172 TriggerScenePresenceUpdated();
3173 }
3174  
3175 public void SendCoarseLocations(List<Vector3> coarseLocations, List<UUID> avatarUUIDs)
3176 {
3177 SendCoarseLocationsMethod d = m_sendCoarseLocationsMethod;
3178 if (d != null)
3179 {
3180 d.Invoke(m_scene.RegionInfo.originRegionID, this, coarseLocations, avatarUUIDs);
3181 }
3182 }
3183  
3184 public void SetSendCoarseLocationMethod(SendCoarseLocationsMethod d)
3185 {
3186 if (d != null)
3187 m_sendCoarseLocationsMethod = d;
3188 }
3189  
3190 public void SendCoarseLocationsDefault(UUID sceneId, ScenePresence p, List<Vector3> coarseLocations, List<UUID> avatarUUIDs)
3191 {
3192 ControllingClient.SendCoarseLocationUpdate(avatarUUIDs, coarseLocations);
3193 }
3194  
3195 public void SendInitialDataToMe()
3196 {
3197 // Send all scene object to the new client
3198 Util.FireAndForget(delegate
3199 {
3200 // we created a new ScenePresence (a new child agent) in a fresh region.
3201 // Request info about all the (root) agents in this region
3202 // Note: This won't send data *to* other clients in that region (children don't send)
3203 SendOtherAgentsAvatarDataToMe();
3204 SendOtherAgentsAppearanceToMe();
3205  
3206 EntityBase[] entities = Scene.Entities.GetEntities();
3207 foreach (EntityBase e in entities)
3208 {
3209 if (e != null && e is SceneObjectGroup)
3210 ((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient);
3211 }
3212  
3213 });
3214 }
3215  
3216 /// <summary>
3217 /// Do everything required once a client completes its movement into a region and becomes
3218 /// a root agent.
3219 /// </summary>
3220 private void ValidateAndSendAppearanceAndAgentData()
3221 {
3222 //m_log.DebugFormat("[SCENE PRESENCE] SendInitialData: {0} ({1})", Name, UUID);
3223 // Moved this into CompleteMovement to ensure that Appearance is initialized before
3224 // the inventory arrives
3225 // m_scene.GetAvatarAppearance(ControllingClient, out Appearance);
3226  
3227 bool cachedappearance = false;
3228  
3229 // We have an appearance but we may not have the baked textures. Check the asset cache
3230 // to see if all the baked textures are already here.
3231 if (m_scene.AvatarFactory != null)
3232 cachedappearance = m_scene.AvatarFactory.ValidateBakedTextureCache(this);
3233  
3234 // If we aren't using a cached appearance, then clear out the baked textures
3235 if (!cachedappearance)
3236 {
3237 Appearance.ResetAppearance();
3238 if (m_scene.AvatarFactory != null)
3239 m_scene.AvatarFactory.QueueAppearanceSave(UUID);
3240 }
3241  
3242 // This agent just became root. We are going to tell everyone about it. The process of
3243 // getting other avatars information was initiated elsewhere immediately after the child circuit connected... don't do it
3244 // again here... this comes after the cached appearance check because the avatars
3245 // appearance goes into the avatar update packet
3246 SendAvatarDataToAllAgents();
3247  
3248 // This invocation always shows up in the viewer logs as an error. Is it needed?
3249 SendAppearanceToAgent(this);
3250  
3251 // If we are using the the cached appearance then send it out to everyone
3252 if (cachedappearance)
3253 {
3254 m_log.DebugFormat("[SCENE PRESENCE]: Baked textures are in the cache for {0} in {1}", Name, m_scene.Name);
3255  
3256 // If the avatars baked textures are all in the cache, then we have a
3257 // complete appearance... send it out, if not, then we'll send it when
3258 // the avatar finishes updating its appearance
3259 SendAppearanceToAllOtherAgents();
3260 }
3261 }
3262  
3263 /// <summary>
3264 /// Send this agent's avatar data to all other root and child agents in the scene
3265 /// This agent must be root. This avatar will receive its own update.
3266 /// </summary>
3267 public void SendAvatarDataToAllAgents()
3268 {
3269 //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAllAgents: {0} ({1})", Name, UUID);
3270 // only send update from root agents to other clients; children are only "listening posts"
3271 if (IsChildAgent)
3272 {
3273 m_log.WarnFormat(
3274 "[SCENE PRESENCE]: Attempt to send avatar data from a child agent for {0} in {1}",
3275 Name, Scene.RegionInfo.RegionName);
3276  
3277 return;
3278 }
3279  
3280 m_lastSize = Appearance.AvatarSize;
3281  
3282 int count = 0;
3283 m_scene.ForEachScenePresence(delegate(ScenePresence scenePresence)
3284 {
3285 SendAvatarDataToAgent(scenePresence);
3286 count++;
3287 });
3288  
3289 m_scene.StatsReporter.AddAgentUpdates(count);
3290 }
3291  
3292 /// <summary>
3293 /// Send avatar data for all other root agents to this agent, this agent
3294 /// can be either a child or root
3295 /// </summary>
3296 public void SendOtherAgentsAvatarDataToMe()
3297 {
3298 int count = 0;
3299 m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence)
3300 {
3301 // only send information about other root agents
3302 if (scenePresence.UUID == UUID)
3303 return;
3304  
3305 scenePresence.SendAvatarDataToAgent(this);
3306 count++;
3307 });
3308  
3309 m_scene.StatsReporter.AddAgentUpdates(count);
3310 }
3311  
3312 /// <summary>
3313 /// Send avatar data to an agent.
3314 /// </summary>
3315 /// <param name="avatar"></param>
3316 public void SendAvatarDataToAgent(ScenePresence avatar)
3317 {
3318 //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAgent from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID);
3319  
3320 avatar.ControllingClient.SendAvatarDataImmediate(this);
3321 Animator.SendAnimPackToClient(avatar.ControllingClient);
3322 }
3323  
3324 /// <summary>
3325 /// Send this agent's appearance to all other root and child agents in the scene
3326 /// This agent must be root.
3327 /// </summary>
3328 public void SendAppearanceToAllOtherAgents()
3329 {
3330 // m_log.DebugFormat("[SCENE PRESENCE] SendAppearanceToAllOtherAgents: {0} {1}", Name, UUID);
3331  
3332 // only send update from root agents to other clients; children are only "listening posts"
3333 if (IsChildAgent)
3334 {
3335 m_log.WarnFormat(
3336 "[SCENE PRESENCE]: Attempt to send avatar data from a child agent for {0} in {1}",
3337 Name, Scene.RegionInfo.RegionName);
3338  
3339 return;
3340 }
3341  
3342 int count = 0;
3343 m_scene.ForEachScenePresence(delegate(ScenePresence scenePresence)
3344 {
3345 // only send information to other root agents
3346 if (scenePresence.UUID == UUID)
3347 return;
3348  
3349 SendAppearanceToAgent(scenePresence);
3350 count++;
3351 });
3352  
3353 m_scene.StatsReporter.AddAgentUpdates(count);
3354 }
3355  
3356 /// <summary>
3357 /// Send appearance from all other root agents to this agent. this agent
3358 /// can be either root or child
3359 /// </summary>
3360 public void SendOtherAgentsAppearanceToMe()
3361 {
3362 // m_log.DebugFormat("[SCENE PRESENCE] SendOtherAgentsAppearanceToMe: {0} {1}", Name, UUID);
3363  
3364 int count = 0;
3365 m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence)
3366 {
3367 // only send information about other root agents
3368 if (scenePresence.UUID == UUID)
3369 return;
3370  
3371 scenePresence.SendAppearanceToAgent(this);
3372 count++;
3373 });
3374  
3375 m_scene.StatsReporter.AddAgentUpdates(count);
3376 }
3377  
3378 /// <summary>
3379 /// Send appearance data to an agent.
3380 /// </summary>
3381 /// <param name="avatar"></param>
3382 public void SendAppearanceToAgent(ScenePresence avatar)
3383 {
3384 // m_log.DebugFormat(
3385 // "[SCENE PRESENCE]: Sending appearance data from {0} {1} to {2} {3}", Name, m_uuid, avatar.Name, avatar.UUID);
3386  
3387 avatar.ControllingClient.SendAppearance(
3388 UUID, Appearance.VisualParams, Appearance.Texture.GetBytes());
3389  
3390  
3391 }
3392  
3393 #endregion
3394  
3395 #region Significant Movement Method
3396  
3397 /// <summary>
3398 /// This checks for a significant movement and sends a coarselocationchange update
3399 /// </summary>
3400 protected void CheckForSignificantMovement()
3401 {
3402 if (Util.GetDistanceTo(AbsolutePosition, posLastSignificantMove) > SIGNIFICANT_MOVEMENT)
3403 {
3404 posLastSignificantMove = AbsolutePosition;
3405 m_scene.EventManager.TriggerSignificantClientMovement(this);
3406 }
3407  
3408 // Minimum Draw distance is 64 meters, the Radius of the draw distance sphere is 32m
3409 if (Util.GetDistanceTo(AbsolutePosition, m_lastChildAgentUpdatePosition) >= Scene.ChildReprioritizationDistance)
3410 {
3411 m_lastChildAgentUpdatePosition = AbsolutePosition;
3412 // m_lastChildAgentUpdateCamPosition = CameraPosition;
3413  
3414 ChildAgentDataUpdate cadu = new ChildAgentDataUpdate();
3415 cadu.ActiveGroupID = UUID.Zero.Guid;
3416 cadu.AgentID = UUID.Guid;
3417 cadu.alwaysrun = SetAlwaysRun;
3418 cadu.AVHeight = Appearance.AvatarHeight;
3419 cadu.cameraPosition = CameraPosition;
3420 cadu.drawdistance = DrawDistance;
3421 cadu.GroupAccess = 0;
3422 cadu.Position = AbsolutePosition;
3423 cadu.regionHandle = RegionHandle;
3424  
3425 // Throttles
3426 float multiplier = 1;
3427 int childRegions = KnownRegionCount;
3428 if (childRegions != 0)
3429 multiplier = 1f / childRegions;
3430  
3431 // Minimum throttle for a child region is 1/4 of the root region throttle
3432 if (multiplier <= 0.25f)
3433 multiplier = 0.25f;
3434  
3435 cadu.throttles = ControllingClient.GetThrottlesPacked(multiplier);
3436 cadu.Velocity = Velocity;
3437  
3438 AgentPosition agentpos = new AgentPosition();
3439 agentpos.CopyFrom(cadu, ControllingClient.SessionId);
3440  
3441 // Let's get this out of the update loop
3442 Util.FireAndForget(delegate { m_scene.SendOutChildAgentUpdates(agentpos, this); });
3443 }
3444 }
3445  
3446 #endregion
3447  
3448 #region Border Crossing Methods
3449  
3450 /// <summary>
3451 /// Starts the process of moving an avatar into another region if they are crossing the border.
3452 /// </summary>
3453 /// <remarks>
3454 /// Also removes the avatar from the physical scene if transit has started.
3455 /// </remarks>
3456 protected void CheckForBorderCrossing()
3457 {
3458 // Check that we we are not a child
3459 if (IsChildAgent)
3460 return;
3461  
3462 // If we don't have a PhysActor, we can't cross anyway
3463 // Also don't do this while sat, sitting avatars cross with the
3464 // object they sit on. ParentUUID denoted a pending sit, don't
3465 // interfere with it.
3466 if (ParentID != 0 || PhysicsActor == null || ParentUUID != UUID.Zero)
3467 return;
3468  
3469 if (!IsInTransit)
3470 {
3471 Vector3 pos2 = AbsolutePosition;
3472 Vector3 origPosition = pos2;
3473 Vector3 vel = Velocity;
3474 int neighbor = 0;
3475 int[] fix = new int[2];
3476  
3477 // Compute the avatar position in the next physics tick.
3478 // If the avatar will be crossing, we force the crossing to happen now
3479 // in the hope that this will make the avatar movement smoother when crossing.
3480 float timeStep = 0.1f;
3481 pos2.X = pos2.X + (vel.X * timeStep);
3482 pos2.Y = pos2.Y + (vel.Y * timeStep);
3483 pos2.Z = pos2.Z + (vel.Z * timeStep);
3484  
3485 if (!IsInTransit)
3486 {
3487 if (!m_scene.PositionIsInCurrentRegion(pos2))
3488 {
3489 m_log.DebugFormat("{0} CheckForBorderCrossing: position outside region. {1} in {2} at pos {3}",
3490 LogHeader, Name, Scene.Name, pos2);
3491  
3492 // Disconnect from the current region
3493 bool isFlying = Flying;
3494 RemoveFromPhysicalScene();
3495 // pos2 is the forcasted position so make that the 'current' position so the crossing
3496 // code will move us into the newly addressed region.
3497 m_pos = pos2;
3498 if (CrossToNewRegion())
3499 {
3500 AddToPhysicalScene(isFlying);
3501 }
3502 else
3503 {
3504 // Tried to make crossing happen but it failed.
3505 if (m_requestedSitTargetUUID == UUID.Zero)
3506 {
3507 m_log.DebugFormat("{0} CheckForBorderCrossing: Crossing failed. Restoring old position.", LogHeader);
3508 const float borderFudge = 0.1f;
3509  
3510 if (origPosition.X < 0)
3511 origPosition.X = borderFudge;
3512 else if (origPosition.X > (float)m_scene.RegionInfo.RegionSizeX)
3513 origPosition.X = (float)m_scene.RegionInfo.RegionSizeX - borderFudge;
3514 if (origPosition.Y < 0)
3515 origPosition.Y = borderFudge;
3516 else if (origPosition.Y > (float)m_scene.RegionInfo.RegionSizeY)
3517 origPosition.Y = (float)m_scene.RegionInfo.RegionSizeY - borderFudge;
3518 Velocity = Vector3.Zero;
3519 AbsolutePosition = origPosition;
3520  
3521 AddToPhysicalScene(isFlying);
3522 }
3523 }
3524  
3525 }
3526 }
3527 else
3528 {
3529 // This constant has been inferred from experimentation
3530 // I'm not sure what this value should be, so I tried a few values.
3531 timeStep = 0.04f;
3532 pos2 = AbsolutePosition;
3533 pos2.X = pos2.X + (vel.X * timeStep);
3534 pos2.Y = pos2.Y + (vel.Y * timeStep);
3535 // Don't touch the Z
3536 m_pos = pos2;
3537 m_log.DebugFormat("[SCENE PRESENCE]: In transit m_pos={0}", m_pos);
3538 }
3539 }
3540 }
3541  
3542 /// <summary>
3543 /// Moves the agent outside the region bounds
3544 /// Tells neighbor region that we're crossing to it
3545 /// If the neighbor accepts, remove the agent's viewable avatar from this scene
3546 /// set them to a child agent.
3547 /// </summary>
3548 protected bool CrossToNewRegion()
3549 {
3550 try
3551 {
3552 return m_scene.CrossAgentToNewRegion(this, Flying);
3553 }
3554 catch
3555 {
3556 return m_scene.CrossAgentToNewRegion(this, false);
3557 }
3558 }
3559  
3560 public void Reset()
3561 {
3562 // m_log.DebugFormat("[SCENE PRESENCE]: Resetting {0} in {1}", Name, Scene.RegionInfo.RegionName);
3563  
3564 // Put the child agent back at the center
3565 AbsolutePosition
3566 = new Vector3(((float)m_scene.RegionInfo.RegionSizeX * 0.5f), ((float)m_scene.RegionInfo.RegionSizeY * 0.5f), 70);
3567  
3568 Animator.ResetAnimations();
3569 }
3570  
3571 /// <summary>
3572 /// Computes which child agents to close when the scene presence moves to another region.
3573 /// Removes those regions from m_knownRegions.
3574 /// </summary>
3575 /// <param name="newRegionX">The new region's x on the map</param>
3576 /// <param name="newRegionY">The new region's y on the map</param>
3577 /// <returns></returns>
3578 public void CloseChildAgents(uint newRegionX, uint newRegionY)
3579 {
3580 List<ulong> byebyeRegions = new List<ulong>();
3581 List<ulong> knownRegions = KnownRegionHandles;
3582 m_log.DebugFormat(
3583 "[SCENE PRESENCE]: Closing child agents. Checking {0} regions in {1}",
3584 knownRegions.Count, Scene.RegionInfo.RegionName);
3585 //DumpKnownRegions();
3586  
3587 foreach (ulong handle in knownRegions)
3588 {
3589 // Don't close the agent on this region yet
3590 if (handle != Scene.RegionInfo.RegionHandle)
3591 {
3592 uint x, y;
3593 Util.RegionHandleToRegionLoc(handle, out x, out y);
3594  
3595 // m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX)));
3596 // m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY)));
3597 if (Util.IsOutsideView(DrawDistance, x, newRegionX, y, newRegionY))
3598 {
3599 byebyeRegions.Add(handle);
3600 }
3601 }
3602 }
3603  
3604 if (byebyeRegions.Count > 0)
3605 {
3606 m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents");
3607  
3608 AgentCircuitData acd = Scene.AuthenticateHandler.GetAgentCircuitData(UUID);
3609 string auth = string.Empty;
3610 if (acd != null)
3611 auth = acd.SessionID.ToString();
3612 m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, auth, byebyeRegions);
3613 }
3614  
3615 foreach (ulong handle in byebyeRegions)
3616 {
3617 RemoveNeighbourRegion(handle);
3618 }
3619 }
3620  
3621 #endregion
3622  
3623 /// <summary>
3624 /// This allows the Sim owner the abiility to kick users from their sim currently.
3625 /// It tells the client that the agent has permission to do so.
3626 /// </summary>
3627 public void GrantGodlikePowers(UUID agentID, UUID sessionID, UUID token, bool godStatus)
3628 {
3629 if (godStatus)
3630 {
3631 // For now, assign god level 200 to anyone
3632 // who is granted god powers, but has no god level set.
3633 //
3634 UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, agentID);
3635 if (account != null)
3636 {
3637 if (account.UserLevel > 0)
3638 GodLevel = account.UserLevel;
3639 else
3640 GodLevel = 200;
3641 }
3642 }
3643 else
3644 {
3645 GodLevel = 0;
3646 }
3647  
3648 ControllingClient.SendAdminResponse(token, (uint)GodLevel);
3649 }
3650  
3651 #region Child Agent Updates
3652  
3653 public void UpdateChildAgent(AgentData cAgentData)
3654 {
3655 // m_log.Debug(" >>> ChildAgentDataUpdate <<< " + Scene.RegionInfo.RegionName);
3656 if (!IsChildAgent)
3657 return;
3658  
3659 CopyFrom(cAgentData);
3660 }
3661  
3662 private static Vector3 marker = new Vector3(-1f, -1f, -1f);
3663  
3664 /// <summary>
3665 /// This updates important decision making data about a child agent
3666 /// The main purpose is to figure out what objects to send to a child agent that's in a neighboring region
3667 /// </summary>
3668 public void UpdateChildAgent(AgentPosition cAgentData, uint tRegionX, uint tRegionY, uint rRegionX, uint rRegionY)
3669 {
3670 if (!IsChildAgent)
3671 return;
3672  
3673 //m_log.Debug(" >>> ChildAgentPositionUpdate <<< " + rRegionX + "-" + rRegionY);
3674 // Find the distance (in meters) between the two regions
3675 uint shiftx = Util.RegionToWorldLoc(rRegionX - tRegionX);
3676 uint shifty = Util.RegionToWorldLoc(rRegionY - tRegionY);
3677  
3678 Vector3 offset = new Vector3(shiftx, shifty, 0f);
3679  
3680 // When we get to the point of re-computing neighbors everytime this
3681 // changes, then start using the agent's drawdistance rather than the
3682 // region's draw distance.
3683 // DrawDistance = cAgentData.Far;
3684 DrawDistance = Scene.DefaultDrawDistance;
3685  
3686 if (cAgentData.Position != marker) // UGH!!
3687 m_pos = cAgentData.Position + offset;
3688  
3689 if (Vector3.Distance(AbsolutePosition, posLastSignificantMove) >= Scene.ChildReprioritizationDistance)
3690 {
3691 posLastSignificantMove = AbsolutePosition;
3692 ReprioritizeUpdates();
3693 }
3694  
3695 CameraPosition = cAgentData.Center + offset;
3696  
3697 if ((cAgentData.Throttles != null) && cAgentData.Throttles.Length > 0)
3698 ControllingClient.SetChildAgentThrottle(cAgentData.Throttles);
3699  
3700 //cAgentData.AVHeight;
3701 RegionHandle = cAgentData.RegionHandle;
3702 //m_velocity = cAgentData.Velocity;
3703 }
3704  
3705 public void CopyTo(AgentData cAgent)
3706 {
3707 cAgent.CallbackURI = m_callbackURI;
3708  
3709 cAgent.AgentID = UUID;
3710 cAgent.RegionID = Scene.RegionInfo.RegionID;
3711 cAgent.SessionID = ControllingClient.SessionId;
3712  
3713 cAgent.Position = AbsolutePosition;
3714 cAgent.Velocity = m_velocity;
3715 cAgent.Center = CameraPosition;
3716 cAgent.AtAxis = CameraAtAxis;
3717 cAgent.LeftAxis = CameraLeftAxis;
3718 cAgent.UpAxis = CameraUpAxis;
3719  
3720 cAgent.Far = DrawDistance;
3721  
3722 // Throttles
3723 float multiplier = 1;
3724 int childRegions = KnownRegionCount;
3725 if (childRegions != 0)
3726 multiplier = 1f / childRegions;
3727  
3728 // Minimum throttle for a child region is 1/4 of the root region throttle
3729 if (multiplier <= 0.25f)
3730 multiplier = 0.25f;
3731  
3732 cAgent.Throttles = ControllingClient.GetThrottlesPacked(multiplier);
3733  
3734 cAgent.HeadRotation = m_headrotation;
3735 cAgent.BodyRotation = Rotation;
3736 cAgent.ControlFlags = (uint)m_AgentControlFlags;
3737  
3738 if (m_scene.Permissions.IsGod(new UUID(cAgent.AgentID)))
3739 cAgent.GodLevel = (byte)GodLevel;
3740 else
3741 cAgent.GodLevel = (byte) 0;
3742  
3743 cAgent.AlwaysRun = SetAlwaysRun;
3744  
3745 cAgent.Appearance = new AvatarAppearance(Appearance);
3746  
3747 cAgent.ParentPart = ParentUUID;
3748 cAgent.SitOffset = PrevSitOffset;
3749  
3750 lock (scriptedcontrols)
3751 {
3752 ControllerData[] controls = new ControllerData[scriptedcontrols.Count];
3753 int i = 0;
3754  
3755 foreach (ScriptControllers c in scriptedcontrols.Values)
3756 {
3757 controls[i++] = new ControllerData(c.objectID, c.itemID, (uint)c.ignoreControls, (uint)c.eventControls);
3758 }
3759 cAgent.Controllers = controls;
3760 }
3761  
3762 // Animations
3763 try
3764 {
3765 cAgent.Anims = Animator.Animations.ToArray();
3766 }
3767 catch { }
3768 cAgent.DefaultAnim = Animator.Animations.DefaultAnimation;
3769 cAgent.AnimState = Animator.Animations.ImplicitDefaultAnimation;
3770  
3771 if (Scene.AttachmentsModule != null)
3772 Scene.AttachmentsModule.CopyAttachments(this, cAgent);
3773 }
3774  
3775 private void CopyFrom(AgentData cAgent)
3776 {
3777 lock (m_originRegionIDAccessLock)
3778 m_originRegionID = cAgent.RegionID;
3779  
3780 m_callbackURI = cAgent.CallbackURI;
3781 // m_log.DebugFormat(
3782 // "[SCENE PRESENCE]: Set callback for {0} in {1} to {2} in CopyFrom()",
3783 // Name, m_scene.RegionInfo.RegionName, m_callbackURI);
3784  
3785 m_pos = cAgent.Position;
3786 m_velocity = cAgent.Velocity;
3787 CameraPosition = cAgent.Center;
3788 CameraAtAxis = cAgent.AtAxis;
3789 CameraLeftAxis = cAgent.LeftAxis;
3790 CameraUpAxis = cAgent.UpAxis;
3791 ParentUUID = cAgent.ParentPart;
3792 PrevSitOffset = cAgent.SitOffset;
3793  
3794 // When we get to the point of re-computing neighbors everytime this
3795 // changes, then start using the agent's drawdistance rather than the
3796 // region's draw distance.
3797 // DrawDistance = cAgent.Far;
3798 DrawDistance = Scene.DefaultDrawDistance;
3799  
3800 if ((cAgent.Throttles != null) && cAgent.Throttles.Length > 0)
3801 ControllingClient.SetChildAgentThrottle(cAgent.Throttles);
3802  
3803 m_headrotation = cAgent.HeadRotation;
3804 Rotation = cAgent.BodyRotation;
3805 m_AgentControlFlags = (AgentManager.ControlFlags)cAgent.ControlFlags;
3806  
3807 if (m_scene.Permissions.IsGod(new UUID(cAgent.AgentID)))
3808 GodLevel = cAgent.GodLevel;
3809 SetAlwaysRun = cAgent.AlwaysRun;
3810  
3811 Appearance = new AvatarAppearance(cAgent.Appearance);
3812 if (PhysicsActor != null)
3813 {
3814 bool isFlying = Flying;
3815 RemoveFromPhysicalScene();
3816 AddToPhysicalScene(isFlying);
3817 }
3818  
3819 try
3820 {
3821 lock (scriptedcontrols)
3822 {
3823 if (cAgent.Controllers != null)
3824 {
3825 scriptedcontrols.Clear();
3826  
3827 foreach (ControllerData c in cAgent.Controllers)
3828 {
3829 ScriptControllers sc = new ScriptControllers();
3830 sc.objectID = c.ObjectID;
3831 sc.itemID = c.ItemID;
3832 sc.ignoreControls = (ScriptControlled)c.IgnoreControls;
3833 sc.eventControls = (ScriptControlled)c.EventControls;
3834  
3835 scriptedcontrols[sc.itemID] = sc;
3836 }
3837 }
3838 }
3839 }
3840 catch { }
3841  
3842 // FIXME: Why is this null check necessary? Where are the cases where we get a null Anims object?
3843 if (cAgent.Anims != null)
3844 Animator.Animations.FromArray(cAgent.Anims);
3845 if (cAgent.DefaultAnim != null)
3846 Animator.Animations.SetDefaultAnimation(cAgent.DefaultAnim.AnimID, cAgent.DefaultAnim.SequenceNum, UUID.Zero);
3847 if (cAgent.AnimState != null)
3848 Animator.Animations.SetImplicitDefaultAnimation(cAgent.AnimState.AnimID, cAgent.AnimState.SequenceNum, UUID.Zero);
3849  
3850 if (Scene.AttachmentsModule != null)
3851 Scene.AttachmentsModule.CopyAttachments(cAgent, this);
3852 }
3853  
3854 public bool CopyAgent(out IAgentData agent)
3855 {
3856 agent = new CompleteAgentData();
3857 CopyTo((AgentData)agent);
3858 return true;
3859 }
3860  
3861 #endregion Child Agent Updates
3862  
3863 /// <summary>
3864 /// Handles part of the PID controller function for moving an avatar.
3865 /// </summary>
3866 public void UpdateMovement()
3867 {
3868 if (m_forceToApply.HasValue)
3869 {
3870 Vector3 force = m_forceToApply.Value;
3871  
3872 Velocity = force;
3873  
3874 m_forceToApply = null;
3875 TriggerScenePresenceUpdated();
3876 }
3877 }
3878  
3879 /// <summary>
3880 /// Adds a physical representation of the avatar to the Physics plugin
3881 /// </summary>
3882 public void AddToPhysicalScene(bool isFlying)
3883 {
3884 // m_log.DebugFormat(
3885 // "[SCENE PRESENCE]: Adding physics actor for {0}, ifFlying = {1} in {2}",
3886 // Name, isFlying, Scene.RegionInfo.RegionName);
3887  
3888 if (PhysicsActor != null)
3889 {
3890 m_log.ErrorFormat(
3891 "[SCENE PRESENCE]: Adding physics actor for {0} to {1} but this scene presence already has a physics actor",
3892 Name, Scene.RegionInfo.RegionName);
3893 }
3894  
3895 if (Appearance.AvatarHeight == 0)
3896 // Appearance.SetHeight();
3897 Appearance.SetSize(new Vector3(0.45f,0.6f,1.9f));
3898  
3899 PhysicsScene scene = m_scene.PhysicsScene;
3900  
3901 Vector3 pVec = AbsolutePosition;
3902  
3903 /*
3904 PhysicsActor = scene.AddAvatar(
3905 LocalId, Firstname + "." + Lastname, pVec,
3906 new Vector3(0.45f, 0.6f, Appearance.AvatarHeight), isFlying);
3907 */
3908  
3909 PhysicsActor = scene.AddAvatar(
3910 LocalId, Firstname + "." + Lastname, pVec,
3911 Appearance.AvatarBoxSize, isFlying);
3912  
3913 //PhysicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients;
3914 PhysicsActor.OnCollisionUpdate += PhysicsCollisionUpdate;
3915 PhysicsActor.OnOutOfBounds += OutOfBoundsCall; // Called for PhysicsActors when there's something wrong
3916 PhysicsActor.SubscribeEvents(100);
3917 PhysicsActor.LocalID = LocalId;
3918 }
3919  
3920 private void OutOfBoundsCall(Vector3 pos)
3921 {
3922 //bool flying = Flying;
3923 //RemoveFromPhysicalScene();
3924  
3925 //AddToPhysicalScene(flying);
3926 if (ControllingClient != null)
3927 ControllingClient.SendAgentAlertMessage("Physics is having a problem with your avatar. You may not be able to move until you relog.", true);
3928 }
3929  
3930  
3931 /// <summary>
3932 /// Event called by the physics plugin to tell the avatar about a collision.
3933 /// </summary>
3934 /// <remarks>
3935 /// This function is called continuously, even when there are no collisions. If the avatar is walking on the
3936 /// ground or a prim then there will be collision information between the avatar and the surface.
3937 ///
3938 /// FIXME: However, we can't safely avoid calling this yet where there are no collisions without analyzing whether
3939 /// any part of this method is relying on an every-frame call.
3940 /// </remarks>
3941 /// <param name="e"></param>
3942 public void PhysicsCollisionUpdate(EventArgs e)
3943 {
3944 if (IsChildAgent || Animator == null)
3945 return;
3946  
3947 //if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f))
3948 // The Physics Scene will send updates every 500 ms grep: PhysicsActor.SubscribeEvents(
3949 // as of this comment the interval is set in AddToPhysicalScene
3950  
3951 // if (m_updateCount > 0)
3952 // {
3953 if (Animator.UpdateMovementAnimations())
3954 TriggerScenePresenceUpdated();
3955 // m_updateCount--;
3956 // }
3957  
3958 CollisionEventUpdate collisionData = (CollisionEventUpdate)e;
3959 Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList;
3960  
3961  
3962 // // No collisions at all means we may be flying. Update always
3963 // // to make falling work
3964 // if (m_lastColCount != coldata.Count || coldata.Count == 0)
3965 // {
3966 // m_updateCount = UPDATE_COUNT;
3967 // m_lastColCount = coldata.Count;
3968 // }
3969  
3970 CollisionPlane = Vector4.UnitW;
3971  
3972 // Gods do not take damage and Invulnerable is set depending on parcel/region flags
3973 if (Invulnerable || GodLevel > 0)
3974 return;
3975  
3976 // The following may be better in the ICombatModule
3977 // probably tweaking of the values for ground and normal prim collisions will be needed
3978 float starthealth = Health;
3979 uint killerObj = 0;
3980 SceneObjectPart part = null;
3981 foreach (uint localid in coldata.Keys)
3982 {
3983 if (localid == 0)
3984 {
3985 part = null;
3986 }
3987 else
3988 {
3989 part = Scene.GetSceneObjectPart(localid);
3990 }
3991 if (part != null)
3992 {
3993 // Ignore if it has been deleted or volume detect
3994 if (!part.ParentGroup.IsDeleted && !part.ParentGroup.IsVolumeDetect)
3995 {
3996 if (part.ParentGroup.Damage > 0.0f)
3997 {
3998 // Something with damage...
3999 Health -= part.ParentGroup.Damage;
4000 part.ParentGroup.Scene.DeleteSceneObject(part.ParentGroup, false);
4001 }
4002 else
4003 {
4004 // An ordinary prim
4005 if (coldata[localid].PenetrationDepth >= 0.10f)
4006 Health -= coldata[localid].PenetrationDepth * 5.0f;
4007 }
4008 }
4009 }
4010 else
4011 {
4012 // 0 is the ground
4013 // what about collisions with other avatars?
4014 if (localid == 0 && coldata[localid].PenetrationDepth >= 0.10f)
4015 Health -= coldata[localid].PenetrationDepth * 5.0f;
4016 }
4017  
4018  
4019 if (Health <= 0.0f)
4020 {
4021 if (localid != 0)
4022 killerObj = localid;
4023 }
4024 //m_log.Debug("[AVATAR]: Collision with localid: " + localid.ToString() + " at depth: " + coldata[localid].ToString());
4025 }
4026 //Health = 100;
4027 if (!Invulnerable)
4028 {
4029 if (starthealth != Health)
4030 {
4031 ControllingClient.SendHealth(Health);
4032 }
4033 if (Health <= 0)
4034 {
4035 m_scene.EventManager.TriggerAvatarKill(killerObj, this);
4036 }
4037 if (starthealth == Health && Health < 100.0f)
4038 {
4039 Health += 0.03f;
4040 if (Health > 100.0f)
4041 Health = 100.0f;
4042 ControllingClient.SendHealth(Health);
4043 }
4044 }
4045 }
4046  
4047 public void setHealthWithUpdate(float health)
4048 {
4049 Health = health;
4050 ControllingClient.SendHealth(Health);
4051 }
4052  
4053 protected internal void Close()
4054 {
4055 // Clear known regions
4056 KnownRegions = new Dictionary<ulong, string>();
4057  
4058 lock (m_reprioritization_timer)
4059 {
4060 m_reprioritization_timer.Enabled = false;
4061 m_reprioritization_timer.Elapsed -= new ElapsedEventHandler(Reprioritize);
4062 }
4063  
4064 // I don't get it but mono crashes when you try to dispose of this timer,
4065 // unsetting the elapsed callback should be enough to allow for cleanup however.
4066 // m_reprioritizationTimer.Dispose();
4067  
4068 RemoveFromPhysicalScene();
4069  
4070 m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd;
4071  
4072 // if (Animator != null)
4073 // Animator.Close();
4074 Animator = null;
4075  
4076 LifecycleState = ScenePresenceState.Removed;
4077 }
4078  
4079 public void AddAttachment(SceneObjectGroup gobj)
4080 {
4081 lock (m_attachments)
4082 {
4083 // This may be true when the attachment comes back
4084 // from serialization after login. Clear it.
4085 gobj.IsDeleted = false;
4086  
4087 m_attachments.Add(gobj);
4088 }
4089 }
4090  
4091 /// <summary>
4092 /// Get all the presence's attachments.
4093 /// </summary>
4094 /// <returns>A copy of the list which contains the attachments.</returns>
4095 public List<SceneObjectGroup> GetAttachments()
4096 {
4097 lock (m_attachments)
4098 return new List<SceneObjectGroup>(m_attachments);
4099 }
4100  
4101 /// <summary>
4102 /// Get the scene objects attached to the given point.
4103 /// </summary>
4104 /// <param name="attachmentPoint"></param>
4105 /// <returns>Returns an empty list if there were no attachments at the point.</returns>
4106 public List<SceneObjectGroup> GetAttachments(uint attachmentPoint)
4107 {
4108 List<SceneObjectGroup> attachments = new List<SceneObjectGroup>();
4109  
4110 if (attachmentPoint >= 0)
4111 {
4112 lock (m_attachments)
4113 {
4114 foreach (SceneObjectGroup so in m_attachments)
4115 {
4116 if (attachmentPoint == so.AttachmentPoint)
4117 attachments.Add(so);
4118 }
4119 }
4120 }
4121  
4122 return attachments;
4123 }
4124  
4125 public bool HasAttachments()
4126 {
4127 lock (m_attachments)
4128 return m_attachments.Count > 0;
4129 }
4130  
4131 /// <summary>
4132 /// Returns the total count of scripts in all parts inventories.
4133 /// </summary>
4134 public int ScriptCount()
4135 {
4136 int count = 0;
4137 lock (m_attachments)
4138 {
4139 foreach (SceneObjectGroup gobj in m_attachments)
4140 {
4141 if (gobj != null)
4142 {
4143 count += gobj.ScriptCount();
4144 }
4145 }
4146 }
4147 return count;
4148 }
4149  
4150 /// <summary>
4151 /// A float the value is a representative execution time in milliseconds of all scripts in all attachments.
4152 /// </summary>
4153 public float ScriptExecutionTime()
4154 {
4155 float time = 0.0f;
4156 lock (m_attachments)
4157 {
4158 foreach (SceneObjectGroup gobj in m_attachments)
4159 {
4160 if (gobj != null)
4161 {
4162 time += gobj.ScriptExecutionTime();
4163 }
4164 }
4165 }
4166 return time;
4167 }
4168  
4169 /// <summary>
4170 /// Returns the total count of running scripts in all parts.
4171 /// </summary>
4172 public int RunningScriptCount()
4173 {
4174 int count = 0;
4175 lock (m_attachments)
4176 {
4177 foreach (SceneObjectGroup gobj in m_attachments)
4178 {
4179 if (gobj != null)
4180 {
4181 count += gobj.RunningScriptCount();
4182 }
4183 }
4184 }
4185 return count;
4186 }
4187  
4188 public bool HasScriptedAttachments()
4189 {
4190 lock (m_attachments)
4191 {
4192 foreach (SceneObjectGroup gobj in m_attachments)
4193 {
4194 if (gobj != null)
4195 {
4196 if (gobj.RootPart.Inventory.ContainsScripts())
4197 return true;
4198 }
4199 }
4200 }
4201 return false;
4202 }
4203  
4204 public void RemoveAttachment(SceneObjectGroup gobj)
4205 {
4206 lock (m_attachments)
4207 m_attachments.Remove(gobj);
4208 }
4209  
4210 /// <summary>
4211 /// Clear all attachments
4212 /// </summary>
4213 public void ClearAttachments()
4214 {
4215 lock (m_attachments)
4216 m_attachments.Clear();
4217 }
4218  
4219 /// <summary>
4220 /// This is currently just being done for information.
4221 /// </summary>
4222 public bool ValidateAttachments()
4223 {
4224 bool validated = true;
4225  
4226 lock (m_attachments)
4227 {
4228 // Validate
4229 foreach (SceneObjectGroup gobj in m_attachments)
4230 {
4231 if (gobj == null)
4232 {
4233 m_log.WarnFormat(
4234 "[SCENE PRESENCE]: Failed to validate an attachment for {0} since it was null. Continuing", Name);
4235  
4236 validated = false;
4237 }
4238 else if (gobj.IsDeleted)
4239 {
4240 m_log.WarnFormat(
4241 "[SCENE PRESENCE]: Failed to validate attachment {0} {1} for {2} since it had been deleted. Continuing",
4242 gobj.Name, gobj.UUID, Name);
4243  
4244 validated = false;
4245 }
4246 }
4247 }
4248  
4249 return validated;
4250 }
4251  
4252 /// <summary>
4253 /// Send a script event to this scene presence's attachments
4254 /// </summary>
4255 /// <param name="eventName">The name of the event</param>
4256 /// <param name="args">The arguments for the event</param>
4257 public void SendScriptEventToAttachments(string eventName, Object[] args)
4258 {
4259 Util.FireAndForget(delegate(object x)
4260 {
4261 if (m_scriptEngines.Length == 0)
4262 return;
4263  
4264 lock (m_attachments)
4265 {
4266 foreach (SceneObjectGroup grp in m_attachments)
4267 {
4268 // 16384 is CHANGED_ANIMATION
4269 //
4270 // Send this to all attachment root prims
4271 //
4272 foreach (IScriptModule m in m_scriptEngines)
4273 {
4274 if (m == null) // No script engine loaded
4275 continue;
4276  
4277 m.PostObjectEvent(grp.RootPart.UUID, "changed", new Object[] { (int)Changed.ANIMATION });
4278 }
4279 }
4280 }
4281 });
4282 }
4283  
4284 /// <summary>
4285 /// Gets the mass.
4286 /// </summary>
4287 /// <returns>
4288 /// The mass.
4289 /// </returns>
4290 public float GetMass()
4291 {
4292 PhysicsActor pa = PhysicsActor;
4293  
4294 if (pa != null)
4295 return pa.Mass;
4296 else
4297 return 0;
4298 }
4299  
4300 internal void PushForce(Vector3 impulse)
4301 {
4302 if (PhysicsActor != null)
4303 {
4304 PhysicsActor.AddForce(impulse,true);
4305 }
4306 }
4307  
4308 public void RegisterControlEventsToScript(int controls, int accept, int pass_on, uint Obj_localID, UUID Script_item_UUID)
4309 {
4310 SceneObjectPart p = m_scene.GetSceneObjectPart(Obj_localID);
4311 if (p == null)
4312 return;
4313  
4314 ControllingClient.SendTakeControls(controls, false, false);
4315 ControllingClient.SendTakeControls(controls, true, false);
4316  
4317 ScriptControllers obj = new ScriptControllers();
4318 obj.ignoreControls = ScriptControlled.CONTROL_ZERO;
4319 obj.eventControls = ScriptControlled.CONTROL_ZERO;
4320  
4321 obj.objectID = p.ParentGroup.UUID;
4322 obj.itemID = Script_item_UUID;
4323 if (pass_on == 0 && accept == 0)
4324 {
4325 IgnoredControls |= (ScriptControlled)controls;
4326 obj.ignoreControls = (ScriptControlled)controls;
4327 }
4328  
4329 if (pass_on == 0 && accept == 1)
4330 {
4331 IgnoredControls |= (ScriptControlled)controls;
4332 obj.ignoreControls = (ScriptControlled)controls;
4333 obj.eventControls = (ScriptControlled)controls;
4334 }
4335  
4336 if (pass_on == 1 && accept == 1)
4337 {
4338 IgnoredControls = ScriptControlled.CONTROL_ZERO;
4339 obj.eventControls = (ScriptControlled)controls;
4340 obj.ignoreControls = ScriptControlled.CONTROL_ZERO;
4341 }
4342  
4343 lock (scriptedcontrols)
4344 {
4345 if (pass_on == 1 && accept == 0)
4346 {
4347 IgnoredControls &= ~(ScriptControlled)controls;
4348 if (scriptedcontrols.ContainsKey(Script_item_UUID))
4349 scriptedcontrols.Remove(Script_item_UUID);
4350 }
4351 else
4352 {
4353 scriptedcontrols[Script_item_UUID] = obj;
4354 }
4355 }
4356  
4357 ControllingClient.SendTakeControls(controls, pass_on == 1 ? true : false, true);
4358 }
4359  
4360 public void HandleForceReleaseControls(IClientAPI remoteClient, UUID agentID)
4361 {
4362 IgnoredControls = ScriptControlled.CONTROL_ZERO;
4363 lock (scriptedcontrols)
4364 {
4365 scriptedcontrols.Clear();
4366 }
4367 ControllingClient.SendTakeControls(int.MaxValue, false, false);
4368 }
4369  
4370 private void UnRegisterSeatControls(UUID obj)
4371 {
4372 List<UUID> takers = new List<UUID>();
4373  
4374 foreach (ScriptControllers c in scriptedcontrols.Values)
4375 {
4376 if (c.objectID == obj)
4377 takers.Add(c.itemID);
4378 }
4379 foreach (UUID t in takers)
4380 {
4381 UnRegisterControlEventsToScript(0, t);
4382 }
4383 }
4384  
4385 public void UnRegisterControlEventsToScript(uint Obj_localID, UUID Script_item_UUID)
4386 {
4387 ScriptControllers takecontrols;
4388  
4389 lock (scriptedcontrols)
4390 {
4391 if (scriptedcontrols.TryGetValue(Script_item_UUID, out takecontrols))
4392 {
4393 ScriptControlled sctc = takecontrols.eventControls;
4394  
4395 ControllingClient.SendTakeControls((int)sctc, false, false);
4396 ControllingClient.SendTakeControls((int)sctc, true, false);
4397  
4398 scriptedcontrols.Remove(Script_item_UUID);
4399 IgnoredControls = ScriptControlled.CONTROL_ZERO;
4400 foreach (ScriptControllers scData in scriptedcontrols.Values)
4401 {
4402 IgnoredControls |= scData.ignoreControls;
4403 }
4404 }
4405 }
4406 }
4407  
4408 private void SendControlsToScripts(uint flags)
4409 {
4410 // Notify the scripts only after calling UpdateMovementAnimations(), so that if a script
4411 // (e.g., a walking script) checks which animation is active it will be the correct animation.
4412 lock (scriptedcontrols)
4413 {
4414 if (scriptedcontrols.Count <= 0)
4415 return;
4416  
4417 ScriptControlled allflags = ScriptControlled.CONTROL_ZERO;
4418  
4419 if (MouseDown)
4420 {
4421 allflags = LastCommands & (ScriptControlled.CONTROL_ML_LBUTTON | ScriptControlled.CONTROL_LBUTTON);
4422 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP) != 0 || (flags & unchecked((uint)AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP)) != 0)
4423 {
4424 allflags = ScriptControlled.CONTROL_ZERO;
4425 MouseDown = true;
4426 }
4427 }
4428  
4429 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN) != 0)
4430 {
4431 allflags |= ScriptControlled.CONTROL_ML_LBUTTON;
4432 MouseDown = true;
4433 }
4434  
4435 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0)
4436 {
4437 allflags |= ScriptControlled.CONTROL_LBUTTON;
4438 MouseDown = true;
4439 }
4440  
4441 // find all activated controls, whether the scripts are interested in them or not
4442 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS) != 0)
4443 {
4444 allflags |= ScriptControlled.CONTROL_FWD;
4445 }
4446  
4447 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG) != 0)
4448 {
4449 allflags |= ScriptControlled.CONTROL_BACK;
4450 }
4451  
4452 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS) != 0)
4453 {
4454 allflags |= ScriptControlled.CONTROL_UP;
4455 }
4456  
4457 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)
4458 {
4459 allflags |= ScriptControlled.CONTROL_DOWN;
4460 }
4461  
4462 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS) != 0)
4463 {
4464 allflags |= ScriptControlled.CONTROL_LEFT;
4465 }
4466  
4467 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG) != 0)
4468 {
4469 allflags |= ScriptControlled.CONTROL_RIGHT;
4470 }
4471  
4472 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0)
4473 {
4474 allflags |= ScriptControlled.CONTROL_ROT_RIGHT;
4475 }
4476  
4477 if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0)
4478 {
4479 allflags |= ScriptControlled.CONTROL_ROT_LEFT;
4480 }
4481  
4482 // optimization; we have to check per script, but if nothing is pressed and nothing changed, we can skip that
4483 if (allflags != ScriptControlled.CONTROL_ZERO || allflags != LastCommands)
4484 {
4485 foreach (KeyValuePair<UUID, ScriptControllers> kvp in scriptedcontrols)
4486 {
4487 UUID scriptUUID = kvp.Key;
4488 ScriptControllers scriptControlData = kvp.Value;
4489  
4490 ScriptControlled localHeld = allflags & scriptControlData.eventControls; // the flags interesting for us
4491 ScriptControlled localLast = LastCommands & scriptControlData.eventControls; // the activated controls in the last cycle
4492 ScriptControlled localChange = localHeld ^ localLast; // the changed bits
4493  
4494 if (localHeld != ScriptControlled.CONTROL_ZERO || localChange != ScriptControlled.CONTROL_ZERO)
4495 {
4496 // only send if still pressed or just changed
4497 m_scene.EventManager.TriggerControlEvent(scriptUUID, UUID, (uint)localHeld, (uint)localChange);
4498 }
4499 }
4500 }
4501  
4502 LastCommands = allflags;
4503 }
4504 }
4505  
4506 internal static AgentManager.ControlFlags RemoveIgnoredControls(AgentManager.ControlFlags flags, ScriptControlled ignored)
4507 {
4508 if (ignored == ScriptControlled.CONTROL_ZERO)
4509 return flags;
4510  
4511 if ((ignored & ScriptControlled.CONTROL_BACK) != 0)
4512 flags &= ~(AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG | AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG);
4513 if ((ignored & ScriptControlled.CONTROL_FWD) != 0)
4514 flags &= ~(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS | AgentManager.ControlFlags.AGENT_CONTROL_AT_POS);
4515 if ((ignored & ScriptControlled.CONTROL_DOWN) != 0)
4516 flags &= ~(AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG | AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG);
4517 if ((ignored & ScriptControlled.CONTROL_UP) != 0)
4518 flags &= ~(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS | AgentManager.ControlFlags.AGENT_CONTROL_UP_POS);
4519 if ((ignored & ScriptControlled.CONTROL_LEFT) != 0)
4520 flags &= ~(AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS | AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS);
4521 if ((ignored & ScriptControlled.CONTROL_RIGHT) != 0)
4522 flags &= ~(AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG | AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG);
4523 if ((ignored & ScriptControlled.CONTROL_ROT_LEFT) != 0)
4524 flags &= ~(AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG);
4525 if ((ignored & ScriptControlled.CONTROL_ROT_RIGHT) != 0)
4526 flags &= ~(AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS);
4527 if ((ignored & ScriptControlled.CONTROL_ML_LBUTTON) != 0)
4528 flags &= ~(AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN);
4529 if ((ignored & ScriptControlled.CONTROL_LBUTTON) != 0)
4530 flags &= ~(AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP | AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN);
4531  
4532 //DIR_CONTROL_FLAG_FORWARD = AgentManager.ControlFlags.AGENT_CONTROL_AT_POS,
4533 //DIR_CONTROL_FLAG_BACK = AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG,
4534 //DIR_CONTROL_FLAG_LEFT = AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS,
4535 //DIR_CONTROL_FLAG_RIGHT = AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG,
4536 //DIR_CONTROL_FLAG_UP = AgentManager.ControlFlags.AGENT_CONTROL_UP_POS,
4537 //DIR_CONTROL_FLAG_DOWN = AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG,
4538 //DIR_CONTROL_FLAG_DOWN_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG
4539  
4540 return flags;
4541 }
4542  
4543 private void ReprioritizeUpdates()
4544 {
4545 if (Scene.IsReprioritizationEnabled && Scene.UpdatePrioritizationScheme != UpdatePrioritizationSchemes.Time)
4546 {
4547 lock (m_reprioritization_timer)
4548 {
4549 if (!m_reprioritizing)
4550 m_reprioritization_timer.Enabled = m_reprioritizing = true;
4551 else
4552 m_reprioritization_called = true;
4553 }
4554 }
4555 }
4556  
4557 private void Reprioritize(object sender, ElapsedEventArgs e)
4558 {
4559 ControllingClient.ReprioritizeUpdates();
4560  
4561 lock (m_reprioritization_timer)
4562 {
4563 m_reprioritization_timer.Enabled = m_reprioritizing = m_reprioritization_called;
4564 m_reprioritization_called = false;
4565 }
4566 }
4567  
4568 private void CheckLandingPoint(ref Vector3 pos)
4569 {
4570 // Never constrain lures
4571 if ((TeleportFlags & TeleportFlags.ViaLure) != 0)
4572 return;
4573  
4574 if (m_scene.RegionInfo.EstateSettings.AllowDirectTeleport)
4575 return;
4576  
4577 ILandObject land = m_scene.LandChannel.GetLandObject(pos.X, pos.Y);
4578  
4579 if (land.LandData.LandingType == (byte)LandingType.LandingPoint &&
4580 land.LandData.UserLocation != Vector3.Zero &&
4581 land.LandData.OwnerID != m_uuid &&
4582 (!m_scene.Permissions.IsGod(m_uuid)) &&
4583 (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)))
4584 {
4585 float curr = Vector3.Distance(AbsolutePosition, pos);
4586 if (Vector3.Distance(land.LandData.UserLocation, pos) < curr)
4587 pos = land.LandData.UserLocation;
4588 else
4589 ControllingClient.SendAlertMessage("Can't teleport closer to destination");
4590 }
4591 }
4592  
4593 private void CheckAndAdjustTelehub(SceneObjectGroup telehub, ref Vector3 pos)
4594 {
4595 if ((m_teleportFlags & (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID)) ==
4596 (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID) ||
4597 (m_scene.TelehubAllowLandmarks == true ? false : ((m_teleportFlags & TeleportFlags.ViaLandmark) != 0 )) ||
4598 (m_teleportFlags & TeleportFlags.ViaLocation) != 0 ||
4599 (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0)
4600 {
4601  
4602 if (GodLevel < 200 &&
4603 ((!m_scene.Permissions.IsGod(m_uuid) &&
4604 !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) ||
4605 (m_teleportFlags & TeleportFlags.ViaLocation) != 0 ||
4606 (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0))
4607 {
4608 SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray();
4609 if (spawnPoints.Length == 0)
4610 {
4611 if(m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid))
4612 {
4613 pos.X = 128.0f;
4614 pos.Y = 128.0f;
4615 }
4616 return;
4617 }
4618  
4619 int index;
4620 bool selected = false;
4621  
4622 switch (m_scene.SpawnPointRouting)
4623 {
4624 case "random":
4625  
4626 if (spawnPoints.Length == 0)
4627 return;
4628 do
4629 {
4630 index = Util.RandomClass.Next(spawnPoints.Length - 1);
4631  
4632 Vector3 spawnPosition = spawnPoints[index].GetLocation(
4633 telehub.AbsolutePosition,
4634 telehub.GroupRotation
4635 );
4636 // SpawnPoint sp = spawnPoints[index];
4637  
4638 ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y);
4639  
4640 if (land == null || land.IsEitherBannedOrRestricted(UUID))
4641 selected = false;
4642 else
4643 selected = true;
4644  
4645 } while ( selected == false);
4646  
4647 pos = spawnPoints[index].GetLocation(
4648 telehub.AbsolutePosition,
4649 telehub.GroupRotation
4650 );
4651 return;
4652  
4653 case "sequence":
4654  
4655 do
4656 {
4657 index = m_scene.SpawnPoint();
4658  
4659 Vector3 spawnPosition = spawnPoints[index].GetLocation(
4660 telehub.AbsolutePosition,
4661 telehub.GroupRotation
4662 );
4663 // SpawnPoint sp = spawnPoints[index];
4664  
4665 ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y);
4666 if (land == null || land.IsEitherBannedOrRestricted(UUID))
4667 selected = false;
4668 else
4669 selected = true;
4670  
4671 } while (selected == false);
4672  
4673 pos = spawnPoints[index].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
4674 ;
4675 return;
4676  
4677 default:
4678 case "closest":
4679  
4680 float distance = 9999;
4681 int closest = -1;
4682  
4683 for (int i = 0; i < spawnPoints.Length; i++)
4684 {
4685 Vector3 spawnPosition = spawnPoints[i].GetLocation(
4686 telehub.AbsolutePosition,
4687 telehub.GroupRotation
4688 );
4689 Vector3 offset = spawnPosition - pos;
4690 float d = Vector3.Mag(offset);
4691 if (d >= distance)
4692 continue;
4693 ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y);
4694 if (land == null)
4695 continue;
4696 if (land.IsEitherBannedOrRestricted(UUID))
4697 continue;
4698 distance = d;
4699 closest = i;
4700 }
4701 if (closest == -1)
4702 return;
4703  
4704 pos = spawnPoints[closest].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
4705 return;
4706  
4707 }
4708 }
4709 }
4710 }
4711  
4712 // Modify landing point based on possible banning, telehubs or parcel restrictions.
4713 private void CheckAndAdjustLandingPoint(ref Vector3 pos)
4714 {
4715 string reason;
4716  
4717 // Honor bans
4718 if (!m_scene.TestLandRestrictions(UUID, out reason, ref pos.X, ref pos.Y))
4719 return;
4720  
4721 SceneObjectGroup telehub = null;
4722 if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject)) != null)
4723 {
4724 if (!m_scene.RegionInfo.EstateSettings.AllowDirectTeleport)
4725 {
4726 CheckAndAdjustTelehub(telehub, ref pos);
4727 return;
4728 }
4729 }
4730  
4731 ILandObject land = m_scene.LandChannel.GetLandObject(pos.X, pos.Y);
4732 if (land != null)
4733 {
4734 if (Scene.DebugTeleporting)
4735 TeleportFlagsDebug();
4736  
4737 // If we come in via login, landmark or map, we want to
4738 // honor landing points. If we come in via Lure, we want
4739 // to ignore them.
4740 if ((m_teleportFlags & (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID)) ==
4741 (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID) ||
4742 (m_teleportFlags & TeleportFlags.ViaLandmark) != 0 ||
4743 (m_teleportFlags & TeleportFlags.ViaLocation) != 0 ||
4744 (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0)
4745 {
4746 // Don't restrict gods, estate managers, or land owners to
4747 // the TP point. This behaviour mimics agni.
4748 if (land.LandData.LandingType == (byte)LandingType.LandingPoint &&
4749 land.LandData.UserLocation != Vector3.Zero &&
4750 GodLevel < 200 &&
4751 ((land.LandData.OwnerID != m_uuid &&
4752 !m_scene.Permissions.IsGod(m_uuid) &&
4753 !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) ||
4754 (m_teleportFlags & TeleportFlags.ViaLocation) != 0 ||
4755 (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0))
4756 {
4757 pos = land.LandData.UserLocation;
4758 }
4759 }
4760  
4761 land.SendLandUpdateToClient(ControllingClient);
4762 }
4763 }
4764  
4765 private DetectedObject CreateDetObject(SceneObjectPart obj)
4766 {
4767 DetectedObject detobj = new DetectedObject();
4768 detobj.keyUUID = obj.UUID;
4769 detobj.nameStr = obj.Name;
4770 detobj.ownerUUID = obj.OwnerID;
4771 detobj.posVector = obj.AbsolutePosition;
4772 detobj.rotQuat = obj.GetWorldRotation();
4773 detobj.velVector = obj.Velocity;
4774 detobj.colliderType = 0;
4775 detobj.groupUUID = obj.GroupID;
4776  
4777 return detobj;
4778 }
4779  
4780 private DetectedObject CreateDetObject(ScenePresence av)
4781 {
4782 DetectedObject detobj = new DetectedObject();
4783 detobj.keyUUID = av.UUID;
4784 detobj.nameStr = av.ControllingClient.Name;
4785 detobj.ownerUUID = av.UUID;
4786 detobj.posVector = av.AbsolutePosition;
4787 detobj.rotQuat = av.Rotation;
4788 detobj.velVector = av.Velocity;
4789 detobj.colliderType = 0;
4790 detobj.groupUUID = av.ControllingClient.ActiveGroupId;
4791  
4792 return detobj;
4793 }
4794  
4795 private DetectedObject CreateDetObjectForGround()
4796 {
4797 DetectedObject detobj = new DetectedObject();
4798 detobj.keyUUID = UUID.Zero;
4799 detobj.nameStr = "";
4800 detobj.ownerUUID = UUID.Zero;
4801 detobj.posVector = AbsolutePosition;
4802 detobj.rotQuat = Quaternion.Identity;
4803 detobj.velVector = Vector3.Zero;
4804 detobj.colliderType = 0;
4805 detobj.groupUUID = UUID.Zero;
4806  
4807 return detobj;
4808 }
4809  
4810 private ColliderArgs CreateColliderArgs(SceneObjectPart dest, List<uint> colliders)
4811 {
4812 ColliderArgs colliderArgs = new ColliderArgs();
4813 List<DetectedObject> colliding = new List<DetectedObject>();
4814 foreach (uint localId in colliders)
4815 {
4816 if (localId == 0)
4817 continue;
4818  
4819 SceneObjectPart obj = m_scene.GetSceneObjectPart(localId);
4820 if (obj != null)
4821 {
4822 if (!dest.CollisionFilteredOut(obj.UUID, obj.Name))
4823 colliding.Add(CreateDetObject(obj));
4824 }
4825 else
4826 {
4827 ScenePresence av = m_scene.GetScenePresence(localId);
4828 if (av != null && (!av.IsChildAgent))
4829 {
4830 if (!dest.CollisionFilteredOut(av.UUID, av.Name))
4831 colliding.Add(CreateDetObject(av));
4832 }
4833 }
4834 }
4835  
4836 colliderArgs.Colliders = colliding;
4837  
4838 return colliderArgs;
4839 }
4840  
4841 private delegate void ScriptCollidingNotification(uint localID, ColliderArgs message);
4842  
4843 private void SendCollisionEvent(SceneObjectGroup dest, scriptEvents ev, List<uint> colliders, ScriptCollidingNotification notify)
4844 {
4845 ColliderArgs CollidingMessage;
4846  
4847 if (colliders.Count > 0)
4848 {
4849 if ((dest.RootPart.ScriptEvents & ev) != 0)
4850 {
4851 CollidingMessage = CreateColliderArgs(dest.RootPart, colliders);
4852  
4853 if (CollidingMessage.Colliders.Count > 0)
4854 notify(dest.RootPart.LocalId, CollidingMessage);
4855 }
4856 }
4857 }
4858  
4859 private void SendLandCollisionEvent(SceneObjectGroup dest, scriptEvents ev, ScriptCollidingNotification notify)
4860 {
4861 if ((dest.RootPart.ScriptEvents & ev) != 0)
4862 {
4863 ColliderArgs LandCollidingMessage = new ColliderArgs();
4864 List<DetectedObject> colliding = new List<DetectedObject>();
4865  
4866 colliding.Add(CreateDetObjectForGround());
4867 LandCollidingMessage.Colliders = colliding;
4868  
4869 notify(dest.RootPart.LocalId, LandCollidingMessage);
4870 }
4871 }
4872  
4873 private void TeleportFlagsDebug() {
4874  
4875 // Some temporary debugging help to show all the TeleportFlags we have...
4876 bool HG = false;
4877 if((m_teleportFlags & TeleportFlags.ViaHGLogin) == TeleportFlags.ViaHGLogin)
4878 HG = true;
4879  
4880 m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************");
4881  
4882 uint i = 0u;
4883 for (int x = 0; x <= 30 ; x++, i = 1u << x)
4884 {
4885 i = 1u << x;
4886  
4887 if((m_teleportFlags & (TeleportFlags)i) == (TeleportFlags)i)
4888 if (HG == false)
4889 m_log.InfoFormat("[SCENE PRESENCE]: Teleport Flags include {0}", ((TeleportFlags) i).ToString());
4890 else
4891 m_log.InfoFormat("[SCENE PRESENCE]: HG Teleport Flags include {0}", ((TeleportFlags)i).ToString());
4892 }
4893  
4894 m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************");
4895  
4896 }
4897 }
4898 }