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