clockwerk-opensim – Blame information for rev 1

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