diff options
author | David Walter Seikel | 2016-11-03 21:44:39 +1000 |
---|---|---|
committer | David Walter Seikel | 2016-11-03 21:44:39 +1000 |
commit | 134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch) | |
tree | 216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Region/Framework/Scenes/ScenePresence.cs | |
parent | More changing to production grid. Double oops. (diff) | |
download | opensim-SC-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip opensim-SC-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz opensim-SC-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2 opensim-SC-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz |
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/ScenePresence.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2577 |
1 files changed, 1813 insertions, 764 deletions
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index a90872e..1fddd91 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -29,16 +29,19 @@ using System; | |||
29 | using System.Xml; | 29 | using System.Xml; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using System.Threading; | ||
32 | using System.Timers; | 33 | using System.Timers; |
34 | using Timer = System.Timers.Timer; | ||
33 | using OpenMetaverse; | 35 | using OpenMetaverse; |
34 | using log4net; | 36 | using log4net; |
35 | using Nini.Config; | 37 | using Nini.Config; |
36 | using OpenSim.Framework; | 38 | using OpenSim.Framework; |
37 | using OpenSim.Framework.Client; | 39 | using OpenSim.Framework.Client; |
40 | using OpenSim.Framework.Monitoring; | ||
38 | using OpenSim.Region.Framework.Interfaces; | 41 | using OpenSim.Region.Framework.Interfaces; |
39 | using OpenSim.Region.Framework.Scenes.Animation; | 42 | using OpenSim.Region.Framework.Scenes.Animation; |
40 | using OpenSim.Region.Framework.Scenes.Types; | 43 | using OpenSim.Region.Framework.Scenes.Types; |
41 | using OpenSim.Region.Physics.Manager; | 44 | using OpenSim.Region.PhysicsModules.SharedBase; |
42 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | 45 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; |
43 | using OpenSim.Services.Interfaces; | 46 | using OpenSim.Services.Interfaces; |
44 | using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags; | 47 | using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags; |
@@ -63,6 +66,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
63 | 66 | ||
64 | struct ScriptControllers | 67 | struct ScriptControllers |
65 | { | 68 | { |
69 | public UUID objectID; | ||
66 | public UUID itemID; | 70 | public UUID itemID; |
67 | public ScriptControlled ignoreControls; | 71 | public ScriptControlled ignoreControls; |
68 | public ScriptControlled eventControls; | 72 | public ScriptControlled eventControls; |
@@ -72,21 +76,51 @@ namespace OpenSim.Region.Framework.Scenes | |||
72 | 76 | ||
73 | public class ScenePresence : EntityBase, IScenePresence | 77 | public class ScenePresence : EntityBase, IScenePresence |
74 | { | 78 | { |
79 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
80 | private static readonly String LogHeader = "[SCENE PRESENCE]"; | ||
81 | |||
75 | // ~ScenePresence() | 82 | // ~ScenePresence() |
76 | // { | 83 | // { |
77 | // m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name); | 84 | // m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name); |
78 | // } | 85 | // } |
79 | 86 | ||
80 | private void TriggerScenePresenceUpdated() | 87 | public void TriggerScenePresenceUpdated() |
81 | { | 88 | { |
82 | if (m_scene != null) | 89 | if (m_scene != null) |
83 | m_scene.EventManager.TriggerScenePresenceUpdated(this); | 90 | m_scene.EventManager.TriggerScenePresenceUpdated(this); |
84 | } | 91 | } |
85 | 92 | ||
86 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
87 | |||
88 | public PresenceType PresenceType { get; private set; } | 93 | public PresenceType PresenceType { get; private set; } |
89 | 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 | |||
90 | // private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); | 124 | // private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); |
91 | private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); | 125 | private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); |
92 | private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); | 126 | private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); |
@@ -99,7 +133,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
99 | /// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis | 133 | /// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis |
100 | /// issue #1716 | 134 | /// issue #1716 |
101 | /// </summary> | 135 | /// </summary> |
102 | public static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.418f); | 136 | public static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.4f); |
103 | 137 | ||
104 | /// <summary> | 138 | /// <summary> |
105 | /// Movement updates for agents in neighboring regions are sent directly to clients. | 139 | /// Movement updates for agents in neighboring regions are sent directly to clients. |
@@ -139,6 +173,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
139 | private Vector3 m_lastPosition; | 173 | private Vector3 m_lastPosition; |
140 | private Quaternion m_lastRotation; | 174 | private Quaternion m_lastRotation; |
141 | private Vector3 m_lastVelocity; | 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 | |||
142 | 180 | ||
143 | private Vector3? m_forceToApply; | 181 | private Vector3? m_forceToApply; |
144 | private int m_userFlags; | 182 | private int m_userFlags; |
@@ -196,10 +234,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
196 | private float m_sitAvatarHeight = 2.0f; | 234 | private float m_sitAvatarHeight = 2.0f; |
197 | 235 | ||
198 | private Vector3 m_lastChildAgentUpdatePosition; | 236 | private Vector3 m_lastChildAgentUpdatePosition; |
199 | private Vector3 m_lastChildAgentUpdateCamPosition; | 237 | // private Vector3 m_lastChildAgentUpdateCamPosition; |
200 | 238 | ||
201 | private const int LAND_VELOCITYMAG_MAX = 12; | 239 | private const int LAND_VELOCITYMAG_MAX = 12; |
202 | 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 | |||
203 | private float m_health = 100f; | 246 | private float m_health = 100f; |
204 | 247 | ||
205 | protected ulong crossingFromRegion; | 248 | protected ulong crossingFromRegion; |
@@ -221,8 +264,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
221 | /// </summary> | 264 | /// </summary> |
222 | public bool LandAtTarget { get; private set; } | 265 | public bool LandAtTarget { get; private set; } |
223 | 266 | ||
224 | private bool m_followCamAuto; | ||
225 | |||
226 | private int m_movementUpdateCount; | 267 | private int m_movementUpdateCount; |
227 | private const int NumMovementsBetweenRayCast = 5; | 268 | private const int NumMovementsBetweenRayCast = 5; |
228 | 269 | ||
@@ -230,6 +271,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
230 | //private int m_moveToPositionStateStatus; | 271 | //private int m_moveToPositionStateStatus; |
231 | //***************************************************** | 272 | //***************************************************** |
232 | 273 | ||
274 | private int m_movementAnimationUpdateCounter = 0; | ||
275 | |||
276 | public Vector3 PrevSitOffset { get; set; } | ||
277 | |||
233 | protected AvatarAppearance m_appearance; | 278 | protected AvatarAppearance m_appearance; |
234 | 279 | ||
235 | public AvatarAppearance Appearance | 280 | public AvatarAppearance Appearance |
@@ -242,6 +287,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
242 | } | 287 | } |
243 | } | 288 | } |
244 | 289 | ||
290 | public bool SentInitialDataToClient { get; private set; } | ||
291 | |||
245 | /// <summary> | 292 | /// <summary> |
246 | /// Copy of the script states while the agent is in transit. This state may | 293 | /// Copy of the script states while the agent is in transit. This state may |
247 | /// need to be placed back in case of transfer fail. | 294 | /// need to be placed back in case of transfer fail. |
@@ -276,9 +323,43 @@ namespace OpenSim.Region.Framework.Scenes | |||
276 | /// </summary> | 323 | /// </summary> |
277 | private Vector3 posLastSignificantMove; | 324 | private Vector3 posLastSignificantMove; |
278 | 325 | ||
279 | // For teleports and crossings callbacks | 326 | #region For teleports and crossings callbacks |
280 | string m_callbackURI; | 327 | |
281 | UUID m_originRegionID; | 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 | ||
282 | 363 | ||
283 | /// <value> | 364 | /// <value> |
284 | /// Script engines present in the scene | 365 | /// Script engines present in the scene |
@@ -295,15 +376,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
295 | /// <summary> | 376 | /// <summary> |
296 | /// Record user movement inputs. | 377 | /// Record user movement inputs. |
297 | /// </summary> | 378 | /// </summary> |
298 | public byte MovementFlag { get; private set; } | 379 | public uint MovementFlag { get; private set; } |
299 | 380 | ||
300 | private bool m_updateflag; | 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; | ||
301 | 385 | ||
302 | public bool Updated | 386 | /// <summary> |
303 | { | 387 | /// Is the agent stop control flag currently active? |
304 | set { m_updateflag = value; } | 388 | /// </summary> |
305 | get { return m_updateflag; } | 389 | public bool AgentControlStopActive { get; private set; } |
306 | } | ||
307 | 390 | ||
308 | private bool m_invulnerable = true; | 391 | private bool m_invulnerable = true; |
309 | 392 | ||
@@ -344,6 +427,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
344 | /// </summary> | 427 | /// </summary> |
345 | protected Vector3 m_lastCameraPosition; | 428 | protected Vector3 m_lastCameraPosition; |
346 | 429 | ||
430 | private Vector4 m_lastCameraCollisionPlane = new Vector4(0f, 0f, 0f, 1); | ||
431 | private bool m_doingCamRayCast = false; | ||
432 | |||
347 | public Vector3 CameraPosition { get; set; } | 433 | public Vector3 CameraPosition { get; set; } |
348 | 434 | ||
349 | public Quaternion CameraRotation | 435 | public Quaternion CameraRotation |
@@ -375,7 +461,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
375 | public string Firstname { get; private set; } | 461 | public string Firstname { get; private set; } |
376 | public string Lastname { get; private set; } | 462 | public string Lastname { get; private set; } |
377 | 463 | ||
378 | public string Grouptitle { get; set; } | 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 | |||
379 | 477 | ||
380 | // Agent's Draw distance. | 478 | // Agent's Draw distance. |
381 | public float DrawDistance { get; set; } | 479 | public float DrawDistance { get; set; } |
@@ -424,7 +522,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
424 | get { return (IClientCore)ControllingClient; } | 522 | get { return (IClientCore)ControllingClient; } |
425 | } | 523 | } |
426 | 524 | ||
427 | public Vector3 ParentPosition { get; set; } | 525 | public UUID COF { get; set; } |
526 | |||
527 | // public Vector3 ParentPosition { get; set; } | ||
428 | 528 | ||
429 | /// <summary> | 529 | /// <summary> |
430 | /// Position of this avatar relative to the region the avatar is in | 530 | /// Position of this avatar relative to the region the avatar is in |
@@ -437,12 +537,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
437 | { | 537 | { |
438 | m_pos = PhysicsActor.Position; | 538 | m_pos = PhysicsActor.Position; |
439 | 539 | ||
440 | //m_log.DebugFormat( | 540 | // m_log.DebugFormat( |
441 | // "[SCENE PRESENCE]: Set position {0} for {1} in {2} via getting AbsolutePosition!", | 541 | // "[SCENE PRESENCE]: Set position of {0} in {1} to {2} via getting AbsolutePosition!", |
442 | // m_pos, Name, Scene.RegionInfo.RegionName); | 542 | // Name, Scene.Name, m_pos); |
443 | } | 543 | } |
444 | else | 544 | else |
445 | { | 545 | { |
546 | // m_log.DebugFormat("[SCENE PRESENCE]: Fetching abs pos where PhysicsActor == null and parent part {0} for {1}", Name, Scene.Name); | ||
446 | // Obtain the correct position of a seated avatar. | 547 | // Obtain the correct position of a seated avatar. |
447 | // In addition to providing the correct position while | 548 | // In addition to providing the correct position while |
448 | // the avatar is seated, this value will also | 549 | // the avatar is seated, this value will also |
@@ -459,13 +560,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
459 | SceneObjectPart sitPart = ParentPart; | 560 | SceneObjectPart sitPart = ParentPart; |
460 | 561 | ||
461 | if (sitPart != null) | 562 | if (sitPart != null) |
462 | return sitPart.AbsolutePosition + (m_pos * sitPart.GetWorldRotation()); | 563 | return sitPart.ParentGroup.AbsolutePosition + (m_pos * sitPart.GetWorldRotation()); |
463 | } | 564 | } |
464 | 565 | ||
465 | return m_pos; | 566 | return m_pos; |
466 | } | 567 | } |
467 | set | 568 | set |
468 | { | 569 | { |
570 | // m_log.DebugFormat("[SCENE PRESENCE]: Setting position of {0} to {1} in {2}", Name, value, Scene.Name); | ||
571 | // Util.PrintCallStack(); | ||
572 | |||
469 | if (PhysicsActor != null) | 573 | if (PhysicsActor != null) |
470 | { | 574 | { |
471 | try | 575 | try |
@@ -480,10 +584,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
480 | 584 | ||
481 | // Don't update while sitting. The PhysicsActor above is null whilst sitting. | 585 | // Don't update while sitting. The PhysicsActor above is null whilst sitting. |
482 | if (ParentID == 0) | 586 | if (ParentID == 0) |
483 | { | ||
484 | m_pos = value; | 587 | m_pos = value; |
485 | ParentPosition = Vector3.Zero; | ||
486 | } | ||
487 | 588 | ||
488 | //m_log.DebugFormat( | 589 | //m_log.DebugFormat( |
489 | // "[ENTITY BASE]: In {0} set AbsolutePosition of {1} to {2}", | 590 | // "[ENTITY BASE]: In {0} set AbsolutePosition of {1} to {2}", |
@@ -513,8 +614,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
513 | } | 614 | } |
514 | 615 | ||
515 | /// <summary> | 616 | /// <summary> |
516 | /// Current velocity of the avatar. | 617 | /// Velocity of the avatar with respect to its local reference frame. |
517 | /// </summary> | 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> | ||
518 | public override Vector3 Velocity | 622 | public override Vector3 Velocity |
519 | { | 623 | { |
520 | get | 624 | get |
@@ -527,11 +631,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
527 | // "[SCENE PRESENCE]: Set velocity {0} for {1} in {2} via getting Velocity!", | 631 | // "[SCENE PRESENCE]: Set velocity {0} for {1} in {2} via getting Velocity!", |
528 | // m_velocity, Name, Scene.RegionInfo.RegionName); | 632 | // m_velocity, Name, Scene.RegionInfo.RegionName); |
529 | } | 633 | } |
634 | // else if (ParentPart != null) | ||
635 | // { | ||
636 | // return ParentPart.ParentGroup.Velocity; | ||
637 | // } | ||
530 | 638 | ||
531 | return m_velocity; | 639 | return m_velocity; |
532 | } | 640 | } |
641 | |||
533 | set | 642 | set |
534 | { | 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 | |||
535 | if (PhysicsActor != null) | 649 | if (PhysicsActor != null) |
536 | { | 650 | { |
537 | try | 651 | try |
@@ -544,37 +658,86 @@ namespace OpenSim.Region.Framework.Scenes | |||
544 | } | 658 | } |
545 | } | 659 | } |
546 | 660 | ||
547 | m_velocity = value; | 661 | m_velocity = value; |
548 | |||
549 | // m_log.DebugFormat( | ||
550 | // "[SCENE PRESENCE]: In {0} set velocity of {1} to {2}", | ||
551 | // Scene.RegionInfo.RegionName, Name, m_velocity); | ||
552 | } | 662 | } |
553 | } | 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 | } | ||
554 | 677 | ||
678 | return m_rotationalvelocity; | ||
679 | } | ||
680 | } | ||
681 | */ | ||
555 | private Quaternion m_bodyRot = Quaternion.Identity; | 682 | private Quaternion m_bodyRot = Quaternion.Identity; |
556 | 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> | ||
557 | public Quaternion Rotation | 692 | public Quaternion Rotation |
558 | { | 693 | { |
559 | get { return m_bodyRot; } | 694 | get |
695 | { | ||
696 | return m_bodyRot; | ||
697 | } | ||
698 | |||
560 | set | 699 | set |
561 | { | 700 | { |
562 | m_bodyRot = value; | 701 | m_bodyRot = value; |
702 | |||
563 | if (PhysicsActor != null) | 703 | if (PhysicsActor != null) |
564 | { | 704 | { |
565 | PhysicsActor.Orientation = m_bodyRot; | 705 | try |
706 | { | ||
707 | PhysicsActor.Orientation = m_bodyRot; | ||
708 | } | ||
709 | catch (Exception e) | ||
710 | { | ||
711 | m_log.Error("[SCENE PRESENCE]: Orientation " + e.Message); | ||
712 | } | ||
566 | } | 713 | } |
567 | // m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot); | 714 | // m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot); |
568 | } | 715 | } |
569 | } | 716 | } |
570 | 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 | |||
571 | public bool IsChildAgent { get; set; } | 726 | public bool IsChildAgent { get; set; } |
727 | public bool IsLoggingIn { get; set; } | ||
572 | 728 | ||
573 | /// <summary> | 729 | /// <summary> |
574 | /// If the avatar is sitting, the local ID of the prim that it's sitting on. If not sitting then zero. | 730 | /// If the avatar is sitting, the local ID of the prim that it's sitting on. If not sitting then zero. |
575 | /// </summary> | 731 | /// </summary> |
576 | public uint ParentID { get; set; } | 732 | public uint ParentID { get; set; } |
577 | 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 | |||
578 | /// <summary> | 741 | /// <summary> |
579 | /// Are we sitting on an object? | 742 | /// Are we sitting on an object? |
580 | /// </summary> | 743 | /// </summary> |
@@ -595,6 +758,33 @@ namespace OpenSim.Region.Framework.Scenes | |||
595 | set { m_health = value; } | 758 | set { m_health = value; } |
596 | } | 759 | } |
597 | 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 | |||
598 | public void AdjustKnownSeeds() | 788 | public void AdjustKnownSeeds() |
599 | { | 789 | { |
600 | Dictionary<ulong, string> seeds; | 790 | Dictionary<ulong, string> seeds; |
@@ -608,9 +798,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
608 | foreach (ulong handle in seeds.Keys) | 798 | foreach (ulong handle in seeds.Keys) |
609 | { | 799 | { |
610 | uint x, y; | 800 | uint x, y; |
611 | Utils.LongToUInts(handle, out x, out y); | 801 | Util.RegionHandleToRegionLoc(handle, out x, out y); |
612 | x = x / Constants.RegionSize; | 802 | |
613 | y = y / Constants.RegionSize; | ||
614 | if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY)) | 803 | if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY)) |
615 | { | 804 | { |
616 | old.Add(handle); | 805 | old.Add(handle); |
@@ -632,18 +821,22 @@ namespace OpenSim.Region.Framework.Scenes | |||
632 | foreach (KeyValuePair<ulong, string> kvp in KnownRegions) | 821 | foreach (KeyValuePair<ulong, string> kvp in KnownRegions) |
633 | { | 822 | { |
634 | uint x, y; | 823 | uint x, y; |
635 | Utils.LongToUInts(kvp.Key, out x, out y); | 824 | Util.RegionHandleToRegionLoc(kvp.Key, out x, out y); |
636 | x = x / Constants.RegionSize; | ||
637 | y = y / Constants.RegionSize; | ||
638 | m_log.Info(" >> "+x+", "+y+": "+kvp.Value); | 825 | m_log.Info(" >> "+x+", "+y+": "+kvp.Value); |
639 | } | 826 | } |
640 | } | 827 | } |
641 | 828 | ||
642 | private bool m_mouseLook; | 829 | private bool m_mouseLook; |
643 | private bool m_leftButtonDown; | 830 | // private bool m_leftButtonDown; |
644 | 831 | ||
645 | private bool m_inTransit; | 832 | private bool m_inTransit; |
646 | 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> | ||
647 | public bool IsInTransit | 840 | public bool IsInTransit |
648 | { | 841 | { |
649 | get { return m_inTransit; } | 842 | get { return m_inTransit; } |
@@ -667,6 +860,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
667 | set { m_speedModifier = value; } | 860 | set { m_speedModifier = value; } |
668 | } | 861 | } |
669 | 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 | |||
670 | private bool m_forceFly; | 871 | private bool m_forceFly; |
671 | 872 | ||
672 | public bool ForceFly | 873 | public bool ForceFly |
@@ -685,23 +886,30 @@ namespace OpenSim.Region.Framework.Scenes | |||
685 | 886 | ||
686 | public string Viewer | 887 | public string Viewer |
687 | { | 888 | { |
688 | get { return m_scene.AuthenticateHandler.GetAgentCircuitData(ControllingClient.CircuitCode).Viewer; } | 889 | get { return Util.GetViewerName(m_scene.AuthenticateHandler.GetAgentCircuitData(ControllingClient.CircuitCode)); } |
689 | } | 890 | } |
690 | 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 | |||
691 | #endregion | 897 | #endregion |
692 | 898 | ||
693 | #region Constructor(s) | 899 | #region Constructor(s) |
694 | 900 | ||
695 | public ScenePresence( | 901 | public ScenePresence( |
696 | IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type) | 902 | IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type) |
697 | { | 903 | { |
698 | AttachmentsSyncLock = new Object(); | 904 | AttachmentsSyncLock = new Object(); |
699 | AllowMovement = true; | 905 | AllowMovement = true; |
700 | IsChildAgent = true; | 906 | IsChildAgent = true; |
907 | IsLoggingIn = false; | ||
701 | m_sendCoarseLocationsMethod = SendCoarseLocationsDefault; | 908 | m_sendCoarseLocationsMethod = SendCoarseLocationsDefault; |
702 | Animator = new ScenePresenceAnimator(this); | 909 | Animator = new ScenePresenceAnimator(this); |
703 | PresenceType = type; | 910 | PresenceType = type; |
704 | DrawDistance = world.DefaultDrawDistance; | 911 | // DrawDistance = world.DefaultDrawDistance; |
912 | DrawDistance = Constants.RegionSize; | ||
705 | RegionHandle = world.RegionInfo.RegionHandle; | 913 | RegionHandle = world.RegionInfo.RegionHandle; |
706 | ControllingClient = client; | 914 | ControllingClient = client; |
707 | Firstname = ControllingClient.FirstName; | 915 | Firstname = ControllingClient.FirstName; |
@@ -739,12 +947,42 @@ namespace OpenSim.Region.Framework.Scenes | |||
739 | SetDirectionVectors(); | 947 | SetDirectionVectors(); |
740 | 948 | ||
741 | Appearance = appearance; | 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 | } | ||
742 | } | 979 | } |
743 | 980 | ||
744 | public void RegisterToEvents() | 981 | public void RegisterToEvents() |
745 | { | 982 | { |
746 | ControllingClient.OnCompleteMovementToRegion += CompleteMovement; | 983 | ControllingClient.OnCompleteMovementToRegion += CompleteMovement; |
747 | ControllingClient.OnAgentUpdate += HandleAgentUpdate; | 984 | ControllingClient.OnAgentUpdate += HandleAgentUpdate; |
985 | ControllingClient.OnAgentCameraUpdate += HandleAgentCamerasUpdate; | ||
748 | ControllingClient.OnAgentRequestSit += HandleAgentRequestSit; | 986 | ControllingClient.OnAgentRequestSit += HandleAgentRequestSit; |
749 | ControllingClient.OnAgentSit += HandleAgentSit; | 987 | ControllingClient.OnAgentSit += HandleAgentSit; |
750 | ControllingClient.OnSetAlwaysRun += HandleSetAlwaysRun; | 988 | ControllingClient.OnSetAlwaysRun += HandleSetAlwaysRun; |
@@ -772,23 +1010,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
772 | Dir_Vectors[10] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge | 1010 | Dir_Vectors[10] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge |
773 | } | 1011 | } |
774 | 1012 | ||
775 | private Vector3[] GetWalkDirectionVectors() | ||
776 | { | ||
777 | Vector3[] vector = new Vector3[11]; | ||
778 | vector[0] = new Vector3(CameraUpAxis.Z, 0f, -CameraAtAxis.Z); //FORWARD | ||
779 | vector[1] = new Vector3(-CameraUpAxis.Z, 0f, CameraAtAxis.Z); //BACK | ||
780 | vector[2] = Vector3.UnitY; //LEFT | ||
781 | vector[3] = -Vector3.UnitY; //RIGHT | ||
782 | vector[4] = new Vector3(CameraAtAxis.Z, 0f, CameraUpAxis.Z); //UP | ||
783 | vector[5] = new Vector3(-CameraAtAxis.Z, 0f, -CameraUpAxis.Z); //DOWN | ||
784 | vector[6] = new Vector3(CameraUpAxis.Z, 0f, -CameraAtAxis.Z); //FORWARD_NUDGE | ||
785 | vector[7] = new Vector3(-CameraUpAxis.Z, 0f, CameraAtAxis.Z); //BACK_NUDGE | ||
786 | vector[8] = Vector3.UnitY; //LEFT_NUDGE | ||
787 | vector[9] = -Vector3.UnitY; //RIGHT_NUDGE | ||
788 | vector[10] = new Vector3(-CameraAtAxis.Z, 0f, -CameraUpAxis.Z); //DOWN_NUDGE | ||
789 | return vector; | ||
790 | } | ||
791 | |||
792 | #endregion | 1013 | #endregion |
793 | 1014 | ||
794 | #region Status Methods | 1015 | #region Status Methods |
@@ -796,6 +1017,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
796 | /// <summary> | 1017 | /// <summary> |
797 | /// Turns a child agent into a root agent. | 1018 | /// Turns a child agent into a root agent. |
798 | /// </summary> | 1019 | /// </summary> |
1020 | /// <remarks> | ||
799 | /// Child agents are logged into neighbouring sims largely to observe changes. Root agents exist when the | 1021 | /// Child agents are logged into neighbouring sims largely to observe changes. Root agents exist when the |
800 | /// avatar is actual in the sim. They can perform all actions. | 1022 | /// avatar is actual in the sim. They can perform all actions. |
801 | /// This change is made whenever an avatar enters a region, whether by crossing over from a neighbouring sim, | 1023 | /// This change is made whenever an avatar enters a region, whether by crossing over from a neighbouring sim, |
@@ -803,80 +1025,188 @@ namespace OpenSim.Region.Framework.Scenes | |||
803 | /// | 1025 | /// |
804 | /// This method is on the critical path for transferring an avatar from one region to another. Delay here | 1026 | /// This method is on the critical path for transferring an avatar from one region to another. Delay here |
805 | /// delays that crossing. | 1027 | /// delays that crossing. |
806 | /// </summary> | 1028 | /// </remarks> |
807 | public void MakeRootAgent(Vector3 pos, bool isFlying) | 1029 | private bool MakeRootAgent(Vector3 pos, bool isFlying) |
808 | { | 1030 | { |
809 | m_log.DebugFormat( | 1031 | lock (m_completeMovementLock) |
810 | "[SCENE]: Upgrading child to root agent for {0} in {1}", | 1032 | { |
811 | Name, m_scene.RegionInfo.RegionName); | 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 | } | ||
812 | 1068 | ||
813 | //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count); | 1069 | IsChildAgent = false; |
1070 | } | ||
814 | 1071 | ||
815 | bool wasChild = IsChildAgent; | 1072 | // Must reset this here so that a teleport to a region next to an existing region does not keep the flag |
816 | IsChildAgent = false; | 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; | ||
817 | 1076 | ||
818 | IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); | 1077 | IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); |
819 | if (gm != null) | 1078 | if (gm != null) |
820 | Grouptitle = gm.GetGroupTitle(m_uuid); | 1079 | Grouptitle = gm.GetGroupTitle(m_uuid); |
821 | 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 | |||
822 | RegionHandle = m_scene.RegionInfo.RegionHandle; | 1092 | RegionHandle = m_scene.RegionInfo.RegionHandle; |
823 | 1093 | ||
824 | m_scene.EventManager.TriggerSetRootAgentScene(m_uuid, m_scene); | 1094 | m_scene.EventManager.TriggerSetRootAgentScene(m_uuid, m_scene); |
825 | 1095 | ||
826 | // Moved this from SendInitialData to ensure that Appearance is initialized | 1096 | UUID groupUUID = ControllingClient.ActiveGroupId; |
827 | // before the inventory is processed in MakeRootAgent. This fixes a race condition | 1097 | string groupName = string.Empty; |
828 | // related to the handling of attachments | 1098 | ulong groupPowers = 0; |
829 | //m_scene.GetAvatarAppearance(ControllingClient, out Appearance); | 1099 | |
830 | if (m_scene.TestBorderCross(pos, Cardinals.E)) | 1100 | // ---------------------------------- |
1101 | // Previous Agent Difference - AGNI sends an unsolicited AgentDataUpdate upon root agent status | ||
1102 | try | ||
831 | { | 1103 | { |
832 | Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.E); | 1104 | if (groupUUID != UUID.Zero && gm != null) |
833 | pos.X = crossedBorder.BorderLine.Z - 1; | 1105 | { |
834 | } | 1106 | GroupRecord record = gm.GetGroupRecord(groupUUID); |
1107 | if (record != null) | ||
1108 | groupName = record.GroupName; | ||
1109 | |||
1110 | GroupMembershipData groupMembershipData = gm.GetMembershipData(groupUUID, m_uuid); | ||
835 | 1111 | ||
836 | if (m_scene.TestBorderCross(pos, Cardinals.N)) | 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) | ||
837 | { | 1120 | { |
838 | Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N); | 1121 | m_log.Error("[AGENTUPDATE]: Error ", e); |
839 | pos.Y = crossedBorder.BorderLine.Z - 1; | ||
840 | } | 1122 | } |
1123 | // ------------------------------------ | ||
841 | 1124 | ||
842 | CheckAndAdjustLandingPoint(ref pos); | 1125 | if (ParentID == 0) |
843 | |||
844 | if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f) | ||
845 | { | 1126 | { |
846 | m_log.WarnFormat( | 1127 | // Moved this from SendInitialData to ensure that Appearance is initialized |
847 | "[SCENE PRESENCE]: MakeRootAgent() was given an illegal position of {0} for avatar {1}, {2}. Clamping", | 1128 | // before the inventory is processed in MakeRootAgent. This fixes a race condition |
848 | pos, Name, UUID); | 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 | } | ||
849 | 1140 | ||
850 | if (pos.X < 0f) pos.X = 0f; | 1141 | if (m_scene.TestBorderCross(pos, Cardinals.N)) |
851 | if (pos.Y < 0f) pos.Y = 0f; | 1142 | { |
852 | if (pos.Z < 0f) pos.Z = 0f; | 1143 | Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N); |
853 | } | 1144 | pos.Y = crossedBorder.BorderLine.Z - 1; |
1145 | } | ||
1146 | */ | ||
854 | 1147 | ||
855 | float localAVHeight = 1.56f; | 1148 | CheckAndAdjustLandingPoint(ref pos); |
856 | if (Appearance.AvatarHeight > 0) | ||
857 | localAVHeight = Appearance.AvatarHeight; | ||
858 | 1149 | ||
859 | float posZLimit = 0; | 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); | ||
860 | 1155 | ||
861 | if (pos.X < Constants.RegionSize && pos.Y < Constants.RegionSize) | 1156 | if (pos.X < 0f) pos.X = 0f; |
862 | posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y]; | 1157 | if (pos.Y < 0f) pos.Y = 0f; |
863 | 1158 | if (pos.Z < 0f) pos.Z = 0f; | |
864 | float newPosZ = posZLimit + localAVHeight / 2; | 1159 | } |
865 | if (posZLimit >= (pos.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) | ||
866 | { | ||
867 | pos.Z = newPosZ; | ||
868 | } | ||
869 | AbsolutePosition = pos; | ||
870 | 1160 | ||
871 | AddToPhysicalScene(isFlying); | 1161 | float localAVHeight = 1.56f; |
1162 | if (Appearance.AvatarHeight > 0) | ||
1163 | localAVHeight = Appearance.AvatarHeight; | ||
872 | 1164 | ||
873 | if (ForceFly) | 1165 | float posZLimit = 0; |
874 | { | 1166 | |
875 | Flying = true; | 1167 | if (pos.X < m_scene.RegionInfo.RegionSizeX && pos.Y < m_scene.RegionInfo.RegionSizeY) |
876 | } | 1168 | posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y]; |
877 | else if (FlyDisabled) | 1169 | |
878 | { | 1170 | float newPosZ = posZLimit + localAVHeight / 2; |
879 | Flying = false; | 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 | } | ||
880 | } | 1210 | } |
881 | 1211 | ||
882 | // Don't send an animation pack here, since on a region crossing this will sometimes cause a flying | 1212 | // Don't send an animation pack here, since on a region crossing this will sometimes cause a flying |
@@ -886,26 +1216,33 @@ namespace OpenSim.Region.Framework.Scenes | |||
886 | 1216 | ||
887 | m_scene.SwapRootAgentCount(false); | 1217 | m_scene.SwapRootAgentCount(false); |
888 | 1218 | ||
889 | // The initial login scene presence is already root when it gets here | 1219 | if (Scene.AttachmentsModule != null) |
890 | // and it has already rezzed the attachments and started their scripts. | ||
891 | // We do the following only for non-login agents, because their scripts | ||
892 | // haven't started yet. | ||
893 | lock (m_attachments) | ||
894 | { | 1220 | { |
895 | if (wasChild && HasAttachments()) | 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)) | ||
896 | { | 1226 | { |
897 | m_log.DebugFormat( | 1227 | WorkManager.RunJob( |
898 | "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name); | 1228 | "RezAttachments", |
899 | 1229 | o => Scene.AttachmentsModule.RezAttachments(this), | |
900 | // Resume scripts | 1230 | null, |
901 | foreach (SceneObjectGroup sog in m_attachments) | 1231 | string.Format("Rez attachments for {0} in {1}", Name, Scene.Name)); |
902 | { | 1232 | } |
903 | sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); | 1233 | else |
904 | sog.ResumeScripts(); | 1234 | { |
905 | } | 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); | ||
906 | } | 1241 | } |
907 | } | 1242 | } |
908 | 1243 | ||
1244 | SendAvatarDataToAllClients(); | ||
1245 | |||
909 | // send the animations of the other presences to me | 1246 | // send the animations of the other presences to me |
910 | m_scene.ForEachRootScenePresence(delegate(ScenePresence presence) | 1247 | m_scene.ForEachRootScenePresence(delegate(ScenePresence presence) |
911 | { | 1248 | { |
@@ -916,9 +1253,75 @@ namespace OpenSim.Region.Framework.Scenes | |||
916 | // If we don't reset the movement flag here, an avatar that crosses to a neighbouring sim and returns will | 1253 | // If we don't reset the movement flag here, an avatar that crosses to a neighbouring sim and returns will |
917 | // stall on the border crossing since the existing child agent will still have the last movement | 1254 | // stall on the border crossing since the existing child agent will still have the last movement |
918 | // recorded, which stops the input from being processed. | 1255 | // recorded, which stops the input from being processed. |
919 | MovementFlag = 0; | 1256 | MovementFlag = ForceUpdateMovementFlagValue; |
920 | 1257 | ||
921 | m_scene.EventManager.TriggerOnMakeRootAgent(this); | 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"); | ||
922 | } | 1325 | } |
923 | 1326 | ||
924 | public int GetStateSource() | 1327 | public int GetStateSource() |
@@ -946,12 +1349,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
946 | /// </remarks> | 1349 | /// </remarks> |
947 | public void MakeChildAgent() | 1350 | public void MakeChildAgent() |
948 | { | 1351 | { |
1352 | m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd; | ||
1353 | |||
949 | m_log.DebugFormat("[SCENE PRESENCE]: Making {0} a child agent in {1}", Name, Scene.RegionInfo.RegionName); | 1354 | m_log.DebugFormat("[SCENE PRESENCE]: Making {0} a child agent in {1}", Name, Scene.RegionInfo.RegionName); |
950 | 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 | |||
951 | // Reset these so that teleporting in and walking out isn't seen | 1361 | // Reset these so that teleporting in and walking out isn't seen |
952 | // as teleporting back | 1362 | // as teleporting back |
953 | TeleportFlags = TeleportFlags.Default; | 1363 | TeleportFlags = TeleportFlags.Default; |
954 | 1364 | ||
1365 | MovementFlag = 0; | ||
1366 | |||
955 | // It looks like Animator is set to null somewhere, and MakeChild | 1367 | // It looks like Animator is set to null somewhere, and MakeChild |
956 | // is called after that. Probably in aborted teleports. | 1368 | // is called after that. Probably in aborted teleports. |
957 | if (Animator == null) | 1369 | if (Animator == null) |
@@ -959,6 +1371,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
959 | else | 1371 | else |
960 | Animator.ResetAnimations(); | 1372 | Animator.ResetAnimations(); |
961 | 1373 | ||
1374 | |||
962 | // m_log.DebugFormat( | 1375 | // m_log.DebugFormat( |
963 | // "[SCENE PRESENCE]: Downgrading root agent {0}, {1} to a child agent in {2}", | 1376 | // "[SCENE PRESENCE]: Downgrading root agent {0}, {1} to a child agent in {2}", |
964 | // Name, UUID, m_scene.RegionInfo.RegionName); | 1377 | // Name, UUID, m_scene.RegionInfo.RegionName); |
@@ -970,6 +1383,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
970 | IsChildAgent = true; | 1383 | IsChildAgent = true; |
971 | m_scene.SwapRootAgentCount(true); | 1384 | m_scene.SwapRootAgentCount(true); |
972 | RemoveFromPhysicalScene(); | 1385 | RemoveFromPhysicalScene(); |
1386 | ParentID = 0; // Child agents can't be sitting | ||
973 | 1387 | ||
974 | // FIXME: Set RegionHandle to the region handle of the scene this agent is moving into | 1388 | // FIXME: Set RegionHandle to the region handle of the scene this agent is moving into |
975 | 1389 | ||
@@ -984,10 +1398,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
984 | if (PhysicsActor != null) | 1398 | if (PhysicsActor != null) |
985 | { | 1399 | { |
986 | // PhysicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients; | 1400 | // PhysicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients; |
987 | PhysicsActor.OnOutOfBounds -= OutOfBoundsCall; | ||
988 | m_scene.PhysicsScene.RemoveAvatar(PhysicsActor); | ||
989 | PhysicsActor.UnSubscribeEvents(); | 1401 | PhysicsActor.UnSubscribeEvents(); |
1402 | PhysicsActor.OnOutOfBounds -= OutOfBoundsCall; | ||
990 | PhysicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate; | 1403 | PhysicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate; |
1404 | m_scene.PhysicsScene.RemoveAvatar(PhysicsActor); | ||
991 | PhysicsActor = null; | 1405 | PhysicsActor = null; |
992 | } | 1406 | } |
993 | // else | 1407 | // else |
@@ -1004,7 +1418,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1004 | /// <param name="pos"></param> | 1418 | /// <param name="pos"></param> |
1005 | public void Teleport(Vector3 pos) | 1419 | public void Teleport(Vector3 pos) |
1006 | { | 1420 | { |
1007 | TeleportWithMomentum(pos, null); | 1421 | TeleportWithMomentum(pos, Vector3.Zero); |
1008 | } | 1422 | } |
1009 | 1423 | ||
1010 | public void TeleportWithMomentum(Vector3 pos, Vector3? v) | 1424 | public void TeleportWithMomentum(Vector3 pos, Vector3? v) |
@@ -1024,14 +1438,141 @@ namespace OpenSim.Region.Framework.Scenes | |||
1024 | else | 1438 | else |
1025 | PhysicsActor.SetMomentum(vel); | 1439 | PhysicsActor.SetMomentum(vel); |
1026 | } | 1440 | } |
1441 | } | ||
1027 | 1442 | ||
1028 | SendTerseUpdateToAllClients(); | 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 | } | ||
1029 | } | 1472 | } |
1030 | 1473 | ||
1031 | public void StopFlying() | 1474 | public void StopFlying() |
1032 | { | 1475 | { |
1033 | ControllingClient.StopFlying(this); | 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 | } | ||
1034 | } | 1573 | } |
1574 | |||
1575 | |||
1035 | 1576 | ||
1036 | // neighbouring regions we have enabled a child agent in | 1577 | // neighbouring regions we have enabled a child agent in |
1037 | // holds the seed cap for the child agent in that region | 1578 | // holds the seed cap for the child agent in that region |
@@ -1118,6 +1659,40 @@ namespace OpenSim.Region.Framework.Scenes | |||
1118 | PhysicsActor.Size = new Vector3(0.45f, 0.6f, height); | 1659 | PhysicsActor.Size = new Vector3(0.45f, 0.6f, height); |
1119 | } | 1660 | } |
1120 | 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 | |||
1121 | /// <summary> | 1696 | /// <summary> |
1122 | /// Complete Avatar's movement into the region. | 1697 | /// Complete Avatar's movement into the region. |
1123 | /// </summary> | 1698 | /// </summary> |
@@ -1131,74 +1706,131 @@ namespace OpenSim.Region.Framework.Scenes | |||
1131 | { | 1706 | { |
1132 | // DateTime startTime = DateTime.Now; | 1707 | // DateTime startTime = DateTime.Now; |
1133 | 1708 | ||
1134 | m_log.DebugFormat( | 1709 | m_log.InfoFormat( |
1135 | "[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}", | 1710 | "[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}", |
1136 | client.Name, Scene.RegionInfo.RegionName, AbsolutePosition); | 1711 | client.Name, Scene.Name, AbsolutePosition); |
1137 | 1712 | ||
1138 | Vector3 look = Velocity; | 1713 | bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); // Get this ahead of time because IsInTransit modifies 'm_AgentControlFlags' |
1139 | 1714 | ||
1140 | if ((look.X == 0) && (look.Y == 0) && (look.Z == 0)) | 1715 | IsInTransit = true; |
1716 | try | ||
1141 | { | 1717 | { |
1142 | look = new Vector3(0.99f, 0.042f, 0); | 1718 | // Make sure it's not a login agent. We don't want to wait for updates during login |
1143 | } | 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 | } | ||
1144 | 1726 | ||
1145 | // Prevent teleporting to an underground location | 1727 | Vector3 look = Velocity; |
1146 | // (may crash client otherwise) | ||
1147 | // | ||
1148 | Vector3 pos = AbsolutePosition; | ||
1149 | float ground = m_scene.GetGroundHeight(pos.X, pos.Y); | ||
1150 | if (pos.Z < ground + 1.5f) | ||
1151 | { | ||
1152 | pos.Z = ground + 1.5f; | ||
1153 | AbsolutePosition = pos; | ||
1154 | } | ||
1155 | 1728 | ||
1156 | bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); | 1729 | // if ((look.X == 0) && (look.Y == 0) && (look.Z == 0)) |
1157 | MakeRootAgent(AbsolutePosition, flying); | 1730 | if ((Math.Abs(look.X) < 0.1) && (Math.Abs(look.Y) < 0.1) && (Math.Abs(look.Z) < 0.1)) |
1158 | ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); | 1731 | { |
1732 | look = new Vector3(0.99f, 0.042f, 0); | ||
1733 | } | ||
1159 | 1734 | ||
1160 | // m_log.DebugFormat("[SCENE PRESENCE] Completed movement"); | 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 | } | ||
1161 | 1745 | ||
1162 | if ((m_callbackURI != null) && !m_callbackURI.Equals("")) | 1746 | if (!MakeRootAgent(AbsolutePosition, flying)) |
1163 | { | 1747 | { |
1164 | // We cannot sleep here since this would hold up the inbound packet processing thread, as | 1748 | m_log.DebugFormat( |
1165 | // CompleteMovement() is executed synchronously. However, it might be better to delay the release | 1749 | "[SCENE PRESENCE]: Aborting CompleteMovement call for {0} in {1} as they are already root", |
1166 | // here until we know for sure that the agent is active in this region. Sending AgentMovementComplete | 1750 | Name, Scene.Name); |
1167 | // is not enough for Imprudence clients - there appears to be a small delay (<200ms, <500ms) until they regard this | ||
1168 | // region as the current region, meaning that a close sent before then will fail the teleport. | ||
1169 | // System.Threading.Thread.Sleep(2000); | ||
1170 | 1751 | ||
1171 | m_log.DebugFormat( | 1752 | return; |
1172 | "[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}", | 1753 | } |
1173 | client.Name, client.AgentId, m_callbackURI); | ||
1174 | 1754 | ||
1175 | Scene.SimulationService.ReleaseAgent(m_originRegionID, UUID, m_callbackURI); | 1755 | // Tell the client that we're totally ready |
1176 | m_callbackURI = null; | 1756 | ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); |
1177 | } | ||
1178 | // else | ||
1179 | // { | ||
1180 | // m_log.DebugFormat( | ||
1181 | // "[SCENE PRESENCE]: No callback provided on CompleteMovement of {0} {1} to {2}", | ||
1182 | // client.Name, client.AgentId, m_scene.RegionInfo.RegionName); | ||
1183 | // } | ||
1184 | 1757 | ||
1185 | ValidateAndSendAppearanceAndAgentData(); | 1758 | // Child agents send initial data up in LLUDPServer.HandleUseCircuitCode() |
1759 | if (!SentInitialDataToClient) | ||
1760 | SendInitialDataToClient(); | ||
1186 | 1761 | ||
1187 | // Create child agents in neighbouring regions | 1762 | // m_log.DebugFormat("[SCENE PRESENCE] Completed movement"); |
1188 | if (openChildAgents && !IsChildAgent) | 1763 | |
1189 | { | 1764 | if (!string.IsNullOrEmpty(m_callbackURI)) |
1190 | IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); | 1765 | { |
1191 | if (m_agentTransfer != null) | 1766 | // We cannot sleep here since this would hold up the inbound packet processing thread, as |
1192 | Util.FireAndForget(delegate { m_agentTransfer.EnableChildAgents(this); }); | 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(); | ||
1193 | 1788 | ||
1194 | IFriendsModule friendsModule = m_scene.RequestModuleInterface<IFriendsModule>(); | 1789 | // Create child agents in neighbouring regions |
1195 | if (friendsModule != null) | 1790 | if (openChildAgents && !IsChildAgent) |
1196 | friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); | 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); | ||
1197 | } | 1820 | } |
1821 | finally | ||
1822 | { | ||
1823 | IsInTransit = false; | ||
1824 | } | ||
1825 | } | ||
1198 | 1826 | ||
1199 | // m_log.DebugFormat( | 1827 | private void ScheduleAttachmentsForFullUpdate() |
1200 | // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", | 1828 | { |
1201 | // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); | 1829 | lock (m_attachments) |
1830 | { | ||
1831 | foreach (SceneObjectGroup sog in m_attachments) | ||
1832 | sog.ScheduleGroupForFullUpdate(); | ||
1833 | } | ||
1202 | } | 1834 | } |
1203 | 1835 | ||
1204 | /// <summary> | 1836 | /// <summary> |
@@ -1209,36 +1841,69 @@ namespace OpenSim.Region.Framework.Scenes | |||
1209 | /// <param name="collisionPoint"></param> | 1841 | /// <param name="collisionPoint"></param> |
1210 | /// <param name="localid"></param> | 1842 | /// <param name="localid"></param> |
1211 | /// <param name="distance"></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 | |||
1212 | public void RayCastCameraCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 pNormal) | 1855 | public void RayCastCameraCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 pNormal) |
1213 | { | 1856 | { |
1214 | const float POSITION_TOLERANCE = 0.02f; | 1857 | const float POSITION_TOLERANCE = 0.02f; |
1215 | const float VELOCITY_TOLERANCE = 0.02f; | ||
1216 | const float ROTATION_TOLERANCE = 0.02f; | 1858 | const float ROTATION_TOLERANCE = 0.02f; |
1217 | 1859 | ||
1218 | if (m_followCamAuto) | 1860 | m_doingCamRayCast = false; |
1861 | if (hitYN && localid != LocalId) | ||
1219 | { | 1862 | { |
1220 | if (hitYN) | 1863 | SceneObjectGroup group = m_scene.GetGroupByPrim(localid); |
1864 | bool IsPrim = group != null; | ||
1865 | if (IsPrim) | ||
1221 | { | 1866 | { |
1222 | CameraConstraintActive = true; | 1867 | SceneObjectPart part = group.GetPart(localid); |
1223 | //m_log.DebugFormat("[RAYCASTRESULT]: {0}, {1}, {2}, {3}", hitYN, collisionPoint, localid, distance); | 1868 | if (part != null && !part.VolumeDetectActive) |
1224 | 1869 | { | |
1225 | Vector3 normal = Vector3.Normalize(new Vector3(0f, 0f, collisionPoint.Z) - collisionPoint); | 1870 | CameraConstraintActive = true; |
1226 | ControllingClient.SendCameraConstraint(new Vector4(normal.X, normal.Y, normal.Z, -1 * Vector3.Distance(new Vector3(0,0,collisionPoint.Z),collisionPoint))); | 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 | } | ||
1227 | } | 1883 | } |
1228 | else | 1884 | else |
1229 | { | 1885 | { |
1230 | if (!m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) || | 1886 | CameraConstraintActive = true; |
1231 | !Velocity.ApproxEquals(m_lastVelocity, VELOCITY_TOLERANCE) || | 1887 | pNormal.X = (float) Math.Round(pNormal.X, 2); |
1232 | !Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE)) | 1888 | pNormal.Y = (float) Math.Round(pNormal.Y, 2); |
1233 | { | 1889 | pNormal.Z = (float) Math.Round(pNormal.Z, 2); |
1234 | if (CameraConstraintActive) | 1890 | pNormal.Normalize(); |
1235 | { | 1891 | collisionPoint.X = (float) Math.Round(collisionPoint.X, 1); |
1236 | ControllingClient.SendCameraConstraint(new Vector4(0f, 0.5f, 0.9f, -3000f)); | 1892 | collisionPoint.Y = (float) Math.Round(collisionPoint.Y, 1); |
1237 | CameraConstraintActive = false; | 1893 | collisionPoint.Z = (float) Math.Round(collisionPoint.Z, 1); |
1238 | } | 1894 | |
1239 | } | 1895 | Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z, |
1896 | Vector3.Dot(collisionPoint, pNormal)); | ||
1897 | UpdateCameraCollisionPlane(plane); | ||
1240 | } | 1898 | } |
1241 | } | 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 | } | ||
1242 | } | 1907 | } |
1243 | 1908 | ||
1244 | /// <summary> | 1909 | /// <summary> |
@@ -1248,18 +1913,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
1248 | { | 1913 | { |
1249 | // m_log.DebugFormat( | 1914 | // m_log.DebugFormat( |
1250 | // "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}", | 1915 | // "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}", |
1251 | // Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags); | 1916 | // Scene.Name, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags); |
1252 | 1917 | ||
1253 | if (IsChildAgent) | 1918 | if (IsChildAgent) |
1254 | { | 1919 | { |
1255 | // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent"); | 1920 | // m_log.DebugFormat("DEBUG: HandleAgentUpdate: child agent in {0}", Scene.Name); |
1256 | return; | 1921 | return; |
1257 | } | 1922 | } |
1258 | 1923 | ||
1259 | ++m_movementUpdateCount; | ||
1260 | if (m_movementUpdateCount < 1) | ||
1261 | m_movementUpdateCount = 1; | ||
1262 | |||
1263 | #region Sanity Checking | 1924 | #region Sanity Checking |
1264 | 1925 | ||
1265 | // This is irritating. Really. | 1926 | // This is irritating. Really. |
@@ -1290,36 +1951,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
1290 | 1951 | ||
1291 | AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; | 1952 | AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags; |
1292 | 1953 | ||
1293 | // Camera location in world. We'll need to raytrace | ||
1294 | // from this location from time to time. | ||
1295 | CameraPosition = agentData.CameraCenter; | ||
1296 | if (Vector3.Distance(m_lastCameraPosition, CameraPosition) >= Scene.RootReprioritizationDistance) | ||
1297 | { | ||
1298 | ReprioritizeUpdates(); | ||
1299 | m_lastCameraPosition = CameraPosition; | ||
1300 | } | ||
1301 | |||
1302 | // Use these three vectors to figure out what the agent is looking at | ||
1303 | // Convert it to a Matrix and/or Quaternion | ||
1304 | CameraAtAxis = agentData.CameraAtAxis; | ||
1305 | CameraLeftAxis = agentData.CameraLeftAxis; | ||
1306 | CameraUpAxis = agentData.CameraUpAxis; | ||
1307 | |||
1308 | // The Agent's Draw distance setting | 1954 | // The Agent's Draw distance setting |
1309 | // When we get to the point of re-computing neighbors everytime this | 1955 | // When we get to the point of re-computing neighbors everytime this |
1310 | // changes, then start using the agent's drawdistance rather than the | 1956 | // changes, then start using the agent's drawdistance rather than the |
1311 | // region's draw distance. | 1957 | // region's draw distance. |
1312 | // DrawDistance = agentData.Far; | 1958 | DrawDistance = agentData.Far; |
1313 | DrawDistance = Scene.DefaultDrawDistance; | 1959 | // DrawDistance = Scene.DefaultDrawDistance; |
1314 | |||
1315 | // Check if Client has camera in 'follow cam' or 'build' mode. | ||
1316 | Vector3 camdif = (Vector3.One * Rotation - Vector3.One * CameraRotation); | ||
1317 | |||
1318 | m_followCamAuto = ((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.98f) | ||
1319 | && (Math.Abs(camdif.X) < 0.4f && Math.Abs(camdif.Y) < 0.4f)) ? true : false; | ||
1320 | 1960 | ||
1321 | m_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0; | 1961 | m_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0; |
1322 | m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 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; | ||
1323 | 1968 | ||
1324 | #endregion Inputs | 1969 | #endregion Inputs |
1325 | 1970 | ||
@@ -1337,14 +1982,38 @@ namespace OpenSim.Region.Framework.Scenes | |||
1337 | StandUp(); | 1982 | StandUp(); |
1338 | } | 1983 | } |
1339 | 1984 | ||
1340 | //m_log.DebugFormat("[FollowCam]: {0}", m_followCamAuto); | ||
1341 | // Raycast from the avatar's head to the camera to see if there's anything blocking the view | 1985 | // Raycast from the avatar's head to the camera to see if there's anything blocking the view |
1342 | if ((m_movementUpdateCount % NumMovementsBetweenRayCast) == 0 && m_scene.PhysicsScene.SupportsRayCast()) | 1986 | // this exclude checks may not be complete |
1987 | |||
1988 | if (m_movementUpdateCount % NumMovementsBetweenRayCast == 0 && m_scene.PhysicsScene.SupportsRayCast()) | ||
1343 | { | 1989 | { |
1344 | if (m_followCamAuto) | 1990 | if (!m_doingCamRayCast && !m_mouseLook && ParentID == 0) |
1345 | { | 1991 | { |
1346 | Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT; | 1992 | Vector3 posAdjusted = AbsolutePosition; |
1347 | m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback); | 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; | ||
1348 | } | 2017 | } |
1349 | } | 2018 | } |
1350 | 2019 | ||
@@ -1358,9 +2027,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
1358 | // Here's where you get them. | 2027 | // Here's where you get them. |
1359 | m_AgentControlFlags = flags; | 2028 | m_AgentControlFlags = flags; |
1360 | m_headrotation = agentData.HeadRotation; | 2029 | m_headrotation = agentData.HeadRotation; |
2030 | byte oldState = State; | ||
1361 | State = agentData.State; | 2031 | State = agentData.State; |
1362 | 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 | |||
1363 | PhysicsActor actor = PhysicsActor; | 2037 | PhysicsActor actor = PhysicsActor; |
2038 | |||
2039 | // This will be the case if the agent is sitting on the groudn or on an object. | ||
1364 | if (actor == null) | 2040 | if (actor == null) |
1365 | { | 2041 | { |
1366 | SendControlsToScripts(flagsForScripts); | 2042 | SendControlsToScripts(flagsForScripts); |
@@ -1369,17 +2045,26 @@ namespace OpenSim.Region.Framework.Scenes | |||
1369 | 2045 | ||
1370 | if (AllowMovement && !SitGround) | 2046 | if (AllowMovement && !SitGround) |
1371 | { | 2047 | { |
1372 | Quaternion bodyRotation = agentData.BodyRotation; | 2048 | // m_log.DebugFormat("[SCENE PRESENCE]: Initial body rotation {0} for {1}", agentData.BodyRotation, Name); |
2049 | |||
1373 | bool update_rotation = false; | 2050 | bool update_rotation = false; |
1374 | 2051 | ||
1375 | if (bodyRotation != Rotation) | 2052 | if (agentData.BodyRotation != Rotation) |
1376 | { | 2053 | { |
1377 | Rotation = bodyRotation; | 2054 | Rotation = agentData.BodyRotation; |
1378 | update_rotation = true; | 2055 | update_rotation = true; |
1379 | } | 2056 | } |
1380 | 2057 | ||
1381 | bool update_movementflag = false; | 2058 | bool update_movementflag = false; |
1382 | 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 | |||
1383 | if (agentData.UseClientAgentPosition) | 2068 | if (agentData.UseClientAgentPosition) |
1384 | { | 2069 | { |
1385 | MovingToTarget = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f; | 2070 | MovingToTarget = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f; |
@@ -1411,19 +2096,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1411 | { | 2096 | { |
1412 | bool bAllowUpdateMoveToPosition = false; | 2097 | bool bAllowUpdateMoveToPosition = false; |
1413 | 2098 | ||
1414 | Vector3[] dirVectors; | ||
1415 | |||
1416 | // use camera up angle when in mouselook and not flying or when holding the left mouse button down and not flying | ||
1417 | // this prevents 'jumping' in inappropriate situations. | ||
1418 | if (!Flying && (m_mouseLook || m_leftButtonDown)) | ||
1419 | dirVectors = GetWalkDirectionVectors(); | ||
1420 | else | ||
1421 | dirVectors = Dir_Vectors; | ||
1422 | |||
1423 | // The fact that MovementFlag is a byte needs to be fixed | ||
1424 | // it really should be a uint | ||
1425 | // A DIR_CONTROL_FLAG occurs when the user is trying to move in a particular direction. | 2099 | // A DIR_CONTROL_FLAG occurs when the user is trying to move in a particular direction. |
1426 | uint nudgehack = 250; | ||
1427 | foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) | 2100 | foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) |
1428 | { | 2101 | { |
1429 | if (((uint)flags & (uint)DCF) != 0) | 2102 | if (((uint)flags & (uint)DCF) != 0) |
@@ -1432,7 +2105,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
1432 | 2105 | ||
1433 | try | 2106 | try |
1434 | { | 2107 | { |
1435 | agent_control_v3 += dirVectors[i]; | 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]; | ||
1436 | //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]); | 2111 | //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]); |
1437 | } | 2112 | } |
1438 | catch (IndexOutOfRangeException) | 2113 | catch (IndexOutOfRangeException) |
@@ -1440,29 +2115,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
1440 | // Why did I get this? | 2115 | // Why did I get this? |
1441 | } | 2116 | } |
1442 | 2117 | ||
1443 | if ((MovementFlag & (byte)(uint)DCF) == 0) | 2118 | if (((MovementFlag & (uint)DCF) == 0) & !AgentControlStopActive) |
1444 | { | 2119 | { |
1445 | if (DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE || | ||
1446 | DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT_NUDGE) | ||
1447 | { | ||
1448 | MovementFlag |= (byte)nudgehack; | ||
1449 | } | ||
1450 | |||
1451 | //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with {1}", Name, DCF); | 2120 | //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with {1}", Name, DCF); |
1452 | MovementFlag += (byte)(uint)DCF; | 2121 | MovementFlag += (uint)DCF; |
1453 | update_movementflag = true; | 2122 | update_movementflag = true; |
1454 | } | 2123 | } |
1455 | } | 2124 | } |
1456 | else | 2125 | else |
1457 | { | 2126 | { |
1458 | if ((MovementFlag & (byte)(uint)DCF) != 0 || | 2127 | if ((MovementFlag & (uint)DCF) != 0) |
1459 | ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE || | ||
1460 | DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT_NUDGE) | ||
1461 | && ((MovementFlag & (byte)nudgehack) == nudgehack)) | ||
1462 | ) // This or is for Nudge forward | ||
1463 | { | 2128 | { |
1464 | //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with lack of {1}", Name, DCF); | 2129 | //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with lack of {1}", Name, DCF); |
1465 | MovementFlag -= ((byte)(uint)DCF); | 2130 | MovementFlag -= (uint)DCF; |
1466 | update_movementflag = true; | 2131 | update_movementflag = true; |
1467 | 2132 | ||
1468 | /* | 2133 | /* |
@@ -1482,6 +2147,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
1482 | i++; | 2147 | i++; |
1483 | } | 2148 | } |
1484 | 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 | |||
1485 | if (MovingToTarget) | 2157 | if (MovingToTarget) |
1486 | { | 2158 | { |
1487 | // If the user has pressed a key then we want to cancel any move to target. | 2159 | // If the user has pressed a key then we want to cancel any move to target. |
@@ -1507,30 +2179,79 @@ namespace OpenSim.Region.Framework.Scenes | |||
1507 | // Only do this if we're flying | 2179 | // Only do this if we're flying |
1508 | if (Flying && !ForceFly) | 2180 | if (Flying && !ForceFly) |
1509 | { | 2181 | { |
1510 | // Landing detection code | 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 | ||
1511 | 2190 | ||
1512 | // Are the landing controls requirements filled? | 2191 | // Are the landing controls requirements filled? |
1513 | bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || | 2192 | bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || |
1514 | ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); | 2193 | ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); |
1515 | 2194 | ||
1516 | if (Flying && IsColliding && controlland) | 2195 | //m_log.Debug("[CONTROL]: " +flags); |
1517 | { | 2196 | // Applies a satisfying roll effect to the avatar when flying. |
1518 | // nesting this check because LengthSquared() is expensive and we don't | 2197 | if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0 && (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0) |
1519 | // want to do it every step when flying. | 2198 | { |
1520 | if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX)) | 2199 | ApplyFlyingRoll( |
1521 | StopFlying(); | 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 | } | ||
1522 | } | 2225 | } |
1523 | } | 2226 | } |
1524 | 2227 | ||
2228 | // m_log.DebugFormat("[SCENE PRESENCE]: MovementFlag {0} for {1}", MovementFlag, Name); | ||
2229 | |||
1525 | // If the agent update does move the avatar, then calculate the force ready for the velocity update, | 2230 | // If the agent update does move the avatar, then calculate the force ready for the velocity update, |
1526 | // which occurs later in the main scene loop | 2231 | // which occurs later in the main scene loop |
1527 | if (update_movementflag || (update_rotation && DCFlagKeyPressed)) | 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))) | ||
1528 | { | 2238 | { |
1529 | // m_log.DebugFormat( | 2239 | // if (update_movementflag || !AgentControlStopActive || MovementFlag != 0) |
1530 | // "[SCENE PRESENCE]: In {0} adding velocity of {1} to {2}, umf = {3}, ur = {4}", | 2240 | // { |
1531 | // m_scene.RegionInfo.RegionName, agent_control_v3, Name, update_movementflag, update_rotation); | 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; | ||
1532 | 2247 | ||
1533 | AddNewMovement(agent_control_v3); | 2248 | if (AgentControlStopActive) |
2249 | speedModifier = AgentControlStopSlowWhilstMoving; | ||
2250 | else | ||
2251 | speedModifier = 1; | ||
2252 | |||
2253 | AddNewMovement(agent_control_v3, speedModifier); | ||
2254 | // } | ||
1534 | } | 2255 | } |
1535 | // else | 2256 | // else |
1536 | // { | 2257 | // { |
@@ -1543,15 +2264,86 @@ namespace OpenSim.Region.Framework.Scenes | |||
1543 | // } | 2264 | // } |
1544 | 2265 | ||
1545 | if (update_movementflag && ParentID == 0) | 2266 | if (update_movementflag && ParentID == 0) |
2267 | { | ||
2268 | // m_log.DebugFormat("[SCENE PRESENCE]: Updating movement animations for {0}", Name); | ||
1546 | Animator.UpdateMovementAnimations(); | 2269 | Animator.UpdateMovementAnimations(); |
2270 | } | ||
1547 | 2271 | ||
1548 | SendControlsToScripts(flagsForScripts); | 2272 | SendControlsToScripts(flagsForScripts); |
1549 | } | 2273 | } |
1550 | 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 | |||
1551 | m_scene.EventManager.TriggerOnClientMovement(this); | 2279 | m_scene.EventManager.TriggerOnClientMovement(this); |
1552 | TriggerScenePresenceUpdated(); | ||
1553 | } | 2280 | } |
1554 | 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 | |||
1555 | /// <summary> | 2347 | /// <summary> |
1556 | /// Calculate an update to move the presence to the set target. | 2348 | /// Calculate an update to move the presence to the set target. |
1557 | /// </summary> | 2349 | /// </summary> |
@@ -1706,13 +2498,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
1706 | if (regionCombinerModule != null) | 2498 | if (regionCombinerModule != null) |
1707 | regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID); | 2499 | regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID); |
1708 | else | 2500 | else |
1709 | regionSize = new Vector2(Constants.RegionSize); | 2501 | regionSize = new Vector2(m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY); |
1710 | 2502 | ||
1711 | if (pos.X < 0 || pos.X >= regionSize.X | 2503 | if (pos.X < 0 || pos.X >= regionSize.X |
1712 | || pos.Y < 0 || pos.Y >= regionSize.Y | 2504 | || pos.Y < 0 || pos.Y >= regionSize.Y |
1713 | || pos.Z < 0) | 2505 | || pos.Z < 0) |
1714 | return; | 2506 | return; |
1715 | 2507 | ||
2508 | Scene targetScene = m_scene; | ||
2509 | |||
1716 | // Vector3 heightAdjust = new Vector3(0, 0, Appearance.AvatarHeight / 2); | 2510 | // Vector3 heightAdjust = new Vector3(0, 0, Appearance.AvatarHeight / 2); |
1717 | // pos += heightAdjust; | 2511 | // pos += heightAdjust; |
1718 | // | 2512 | // |
@@ -1724,15 +2518,23 @@ namespace OpenSim.Region.Framework.Scenes | |||
1724 | // } | 2518 | // } |
1725 | 2519 | ||
1726 | // Get terrain height for sub-region in a megaregion if necessary | 2520 | // Get terrain height for sub-region in a megaregion if necessary |
1727 | int X = (int)((m_scene.RegionInfo.RegionLocX * Constants.RegionSize) + pos.X); | ||
1728 | int Y = (int)((m_scene.RegionInfo.RegionLocY * Constants.RegionSize) + pos.Y); | ||
1729 | UUID target_regionID = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y).RegionID; | ||
1730 | Scene targetScene = m_scene; | ||
1731 | 2521 | ||
1732 | if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene)) | 2522 | //COMMENT: If its only nessesary in a megaregion, why do it on normal region's too? |
1733 | targetScene = m_scene; | 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 | } | ||
1734 | 2536 | ||
1735 | float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % Constants.RegionSize), (int)(pos.Y % Constants.RegionSize)]; | 2537 | float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % regionSize.X), (int)(pos.Y % regionSize.Y)]; |
1736 | pos.Z = Math.Max(terrainHeight, pos.Z); | 2538 | pos.Z = Math.Max(terrainHeight, pos.Z); |
1737 | 2539 | ||
1738 | // Fudge factor. It appears that if one clicks "go here" on a piece of ground, the go here request is | 2540 | // Fudge factor. It appears that if one clicks "go here" on a piece of ground, the go here request is |
@@ -1741,15 +2543,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
1741 | if (pos.Z - terrainHeight < 0.2) | 2543 | if (pos.Z - terrainHeight < 0.2) |
1742 | pos.Z = terrainHeight; | 2544 | pos.Z = terrainHeight; |
1743 | 2545 | ||
1744 | // m_log.DebugFormat( | ||
1745 | // "[SCENE PRESENCE]: Avatar {0} set move to target {1} (terrain height {2}) in {3}", | ||
1746 | // Name, pos, terrainHeight, m_scene.RegionInfo.RegionName); | ||
1747 | |||
1748 | if (noFly) | 2546 | if (noFly) |
1749 | Flying = false; | 2547 | Flying = false; |
1750 | else if (pos.Z > terrainHeight) | 2548 | else if (pos.Z > terrainHeight) |
1751 | Flying = true; | 2549 | Flying = true; |
1752 | 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 | |||
1753 | LandAtTarget = landAtTarget; | 2558 | LandAtTarget = landAtTarget; |
1754 | MovingToTarget = true; | 2559 | MovingToTarget = true; |
1755 | MoveToPositionTarget = pos; | 2560 | MoveToPositionTarget = pos; |
@@ -1782,7 +2587,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1782 | // m_log.DebugFormat("[SCENE PRESENCE]: Resetting move to target for {0}", Name); | 2587 | // m_log.DebugFormat("[SCENE PRESENCE]: Resetting move to target for {0}", Name); |
1783 | 2588 | ||
1784 | MovingToTarget = false; | 2589 | MovingToTarget = false; |
1785 | MoveToPositionTarget = Vector3.Zero; | 2590 | // MoveToPositionTarget = Vector3.Zero; |
2591 | m_forceToApply = null; // cancel possible last action | ||
1786 | 2592 | ||
1787 | // We need to reset the control flag as the ScenePresenceAnimator uses this to determine the correct | 2593 | // We need to reset the control flag as the ScenePresenceAnimator uses this to determine the correct |
1788 | // resting animation (e.g. hover or stand). NPCs don't have a client that will quickly reset this flag. | 2594 | // resting animation (e.g. hover or stand). NPCs don't have a client that will quickly reset this flag. |
@@ -1799,13 +2605,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
1799 | { | 2605 | { |
1800 | // m_log.DebugFormat("[SCENE PRESENCE]: StandUp() for {0}", Name); | 2606 | // m_log.DebugFormat("[SCENE PRESENCE]: StandUp() for {0}", Name); |
1801 | 2607 | ||
2608 | bool satOnObject = IsSatOnObject; | ||
2609 | SceneObjectPart part = ParentPart; | ||
1802 | SitGround = false; | 2610 | SitGround = false; |
1803 | if (PhysicsActor == null) | ||
1804 | AddToPhysicalScene(false); | ||
1805 | 2611 | ||
1806 | if (ParentID != 0) | 2612 | if (satOnObject) |
1807 | { | 2613 | { |
1808 | SceneObjectPart part = ParentPart; | 2614 | PrevSitOffset = m_pos; // Save sit offset |
2615 | UnRegisterSeatControls(part.ParentGroup.UUID); | ||
2616 | |||
1809 | TaskInventoryDictionary taskIDict = part.TaskInventory; | 2617 | TaskInventoryDictionary taskIDict = part.TaskInventory; |
1810 | if (taskIDict != null) | 2618 | if (taskIDict != null) |
1811 | { | 2619 | { |
@@ -1821,24 +2629,70 @@ namespace OpenSim.Region.Framework.Scenes | |||
1821 | } | 2629 | } |
1822 | } | 2630 | } |
1823 | 2631 | ||
1824 | ParentPosition = part.GetWorldPosition(); | ||
1825 | ControllingClient.SendClearFollowCamProperties(part.ParentUUID); | 2632 | ControllingClient.SendClearFollowCamProperties(part.ParentUUID); |
1826 | 2633 | ||
1827 | m_pos += ParentPosition + new Vector3(0.0f, 0.0f, 2.0f * m_sitAvatarHeight); | ||
1828 | ParentPosition = Vector3.Zero; | ||
1829 | |||
1830 | ParentID = 0; | 2634 | ParentID = 0; |
1831 | ParentPart = null; | 2635 | ParentPart = null; |
1832 | SendAvatarDataToAllAgents(); | 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(); | ||
1833 | m_requestedSitTargetID = 0; | 2684 | m_requestedSitTargetID = 0; |
1834 | 2685 | ||
1835 | part.RemoveSittingAvatar(UUID); | 2686 | part.RemoveSittingAvatar(this); |
1836 | 2687 | ||
1837 | if (part != null) | 2688 | part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); |
1838 | part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); | ||
1839 | } | 2689 | } |
1840 | 2690 | ||
2691 | else if (PhysicsActor == null) | ||
2692 | AddToPhysicalScene(false); | ||
2693 | |||
1841 | Animator.TrySetMovementAnimation("STAND"); | 2694 | Animator.TrySetMovementAnimation("STAND"); |
2695 | TriggerScenePresenceUpdated(); | ||
1842 | } | 2696 | } |
1843 | 2697 | ||
1844 | private SceneObjectPart FindNextAvailableSitTarget(UUID targetID) | 2698 | private SceneObjectPart FindNextAvailableSitTarget(UUID targetID) |
@@ -1885,14 +2739,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1885 | if (part == null) | 2739 | if (part == null) |
1886 | return; | 2740 | return; |
1887 | 2741 | ||
1888 | // TODO: determine position to sit at based on scene geometry; don't trust offset from client | ||
1889 | // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it | ||
1890 | |||
1891 | if (PhysicsActor != null) | 2742 | if (PhysicsActor != null) |
1892 | m_sitAvatarHeight = PhysicsActor.Size.Z; | 2743 | m_sitAvatarHeight = PhysicsActor.Size.Z * 0.5f; |
1893 | 2744 | ||
1894 | bool canSit = false; | 2745 | bool canSit = false; |
1895 | Vector3 pos = part.AbsolutePosition + offset; | ||
1896 | 2746 | ||
1897 | if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero) | 2747 | if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero) |
1898 | { | 2748 | { |
@@ -1902,45 +2752,88 @@ namespace OpenSim.Region.Framework.Scenes | |||
1902 | 2752 | ||
1903 | offset = part.SitTargetPosition; | 2753 | offset = part.SitTargetPosition; |
1904 | sitOrientation = part.SitTargetOrientation; | 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 | |||
1905 | canSit = true; | 2766 | canSit = true; |
1906 | } | 2767 | } |
1907 | else | 2768 | else |
1908 | { | 2769 | { |
2770 | if (PhysicsSit(part,offset)) // physics engine | ||
2771 | return; | ||
2772 | |||
2773 | Vector3 pos = part.AbsolutePosition + offset; | ||
2774 | |||
1909 | if (Util.GetDistanceTo(AbsolutePosition, pos) <= 10) | 2775 | if (Util.GetDistanceTo(AbsolutePosition, pos) <= 10) |
1910 | { | 2776 | { |
1911 | // m_log.DebugFormat( | ||
1912 | // "[SCENE PRESENCE]: Sitting {0} on {1} {2} because sit target is unset and within 10m", | ||
1913 | // Name, part.Name, part.LocalId); | ||
1914 | |||
1915 | AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight); | 2777 | AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight); |
1916 | canSit = true; | 2778 | canSit = true; |
1917 | } | 2779 | } |
1918 | // else | ||
1919 | // { | ||
1920 | // m_log.DebugFormat( | ||
1921 | // "[SCENE PRESENCE]: Ignoring sit request of {0} on {1} {2} because sit target is unset and outside 10m", | ||
1922 | // Name, part.Name, part.LocalId); | ||
1923 | // } | ||
1924 | } | 2780 | } |
1925 | 2781 | ||
1926 | if (canSit) | 2782 | if (canSit) |
1927 | { | 2783 | { |
2784 | |||
1928 | if (PhysicsActor != null) | 2785 | if (PhysicsActor != null) |
1929 | { | 2786 | { |
1930 | // We can remove the physicsActor until they stand up. | 2787 | // We can remove the physicsActor until they stand up. |
1931 | RemoveFromPhysicalScene(); | 2788 | RemoveFromPhysicalScene(); |
1932 | } | 2789 | } |
1933 | 2790 | ||
1934 | part.AddSittingAvatar(UUID); | 2791 | if (MovingToTarget) |
2792 | ResetMoveToTarget(); | ||
2793 | |||
2794 | Velocity = Vector3.Zero; | ||
2795 | |||
2796 | part.AddSittingAvatar(this); | ||
1935 | 2797 | ||
1936 | cameraAtOffset = part.GetCameraAtOffset(); | 2798 | cameraAtOffset = part.GetCameraAtOffset(); |
2799 | |||
2800 | if (!part.IsRoot && cameraAtOffset == Vector3.Zero) | ||
2801 | cameraAtOffset = part.ParentGroup.RootPart.GetCameraAtOffset(); | ||
2802 | |||
2803 | bool cameraEyeOffsetFromRootForChild = false; | ||
1937 | cameraEyeOffset = part.GetCameraEyeOffset(); | 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 | |||
1938 | forceMouselook = part.GetForceMouselook(); | 2827 | forceMouselook = part.GetForceMouselook(); |
1939 | 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 | |||
1940 | ControllingClient.SendSitResponse( | 2833 | ControllingClient.SendSitResponse( |
1941 | targetID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); | 2834 | part.ParentGroup.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); |
1942 | 2835 | ||
1943 | m_requestedSitTargetUUID = targetID; | 2836 | m_requestedSitTargetUUID = part.UUID; |
1944 | 2837 | ||
1945 | HandleAgentSit(ControllingClient, UUID); | 2838 | HandleAgentSit(ControllingClient, UUID); |
1946 | 2839 | ||
@@ -1952,6 +2845,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
1952 | 2845 | ||
1953 | public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset) | 2846 | public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset) |
1954 | { | 2847 | { |
2848 | if (IsChildAgent) | ||
2849 | return; | ||
2850 | |||
1955 | if (ParentID != 0) | 2851 | if (ParentID != 0) |
1956 | { | 2852 | { |
1957 | if (ParentPart.UUID == targetID) | 2853 | if (ParentPart.UUID == targetID) |
@@ -1965,16 +2861,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1965 | if (part != null) | 2861 | if (part != null) |
1966 | { | 2862 | { |
1967 | m_requestedSitTargetID = part.LocalId; | 2863 | m_requestedSitTargetID = part.LocalId; |
1968 | m_requestedSitTargetUUID = targetID; | 2864 | m_requestedSitTargetUUID = part.UUID; |
1969 | |||
1970 | // m_log.DebugFormat("[SIT]: Client requested Sit Position: {0}", offset); | ||
1971 | 2865 | ||
1972 | if (m_scene.PhysicsScene.SupportsRayCast()) | ||
1973 | { | ||
1974 | //m_scene.PhysicsScene.RaycastWorld(Vector3.Zero,Vector3.Zero, 0.01f,new RaycastCallback()); | ||
1975 | //SitRayCastAvatarPosition(part); | ||
1976 | //return; | ||
1977 | } | ||
1978 | } | 2866 | } |
1979 | else | 2867 | else |
1980 | { | 2868 | { |
@@ -1984,200 +2872,119 @@ namespace OpenSim.Region.Framework.Scenes | |||
1984 | SendSitResponse(targetID, offset, Quaternion.Identity); | 2872 | SendSitResponse(targetID, offset, Quaternion.Identity); |
1985 | } | 2873 | } |
1986 | 2874 | ||
1987 | /* | 2875 | // returns false if does not suport so older sit can be tried |
1988 | public void SitRayCastAvatarPosition(SceneObjectPart part) | 2876 | public bool PhysicsSit(SceneObjectPart part, Vector3 offset) |
1989 | { | ||
1990 | Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset; | ||
1991 | Vector3 StartRayCastPosition = AbsolutePosition; | ||
1992 | Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition); | ||
1993 | float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition); | ||
1994 | m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastAvatarPositionResponse); | ||
1995 | } | ||
1996 | |||
1997 | public void SitRayCastAvatarPositionResponse(bool hitYN, Vector3 collisionPoint, uint localid, float pdistance, Vector3 normal) | ||
1998 | { | 2877 | { |
1999 | SceneObjectPart part = FindNextAvailableSitTarget(m_requestedSitTargetUUID); | 2878 | // TODO: Pull in these bits |
2000 | if (part != null) | 2879 | return false; |
2001 | { | 2880 | /* |
2002 | if (hitYN) | 2881 | if (part == null || part.ParentGroup.IsAttachment) |
2003 | { | ||
2004 | if (collisionPoint.ApproxEquals(m_requestedSitOffset + part.AbsolutePosition, 0.2f)) | ||
2005 | { | ||
2006 | SitRaycastFindEdge(collisionPoint, normal); | ||
2007 | m_log.DebugFormat("[SIT]: Raycast Avatar Position succeeded at point: {0}, normal:{1}", collisionPoint, normal); | ||
2008 | } | ||
2009 | else | ||
2010 | { | ||
2011 | SitRayCastAvatarPositionCameraZ(part); | ||
2012 | } | ||
2013 | } | ||
2014 | else | ||
2015 | { | ||
2016 | SitRayCastAvatarPositionCameraZ(part); | ||
2017 | } | ||
2018 | } | ||
2019 | else | ||
2020 | { | 2882 | { |
2021 | ControllingClient.SendAlertMessage("Sit position no longer exists"); | 2883 | return true; |
2022 | m_requestedSitTargetUUID = UUID.Zero; | ||
2023 | m_requestedSitTargetID = 0; | ||
2024 | m_requestedSitOffset = Vector3.Zero; | ||
2025 | } | 2884 | } |
2026 | 2885 | ||
2027 | } | 2886 | if ( m_scene.PhysicsScene == null) |
2028 | 2887 | return false; | |
2029 | public void SitRayCastAvatarPositionCameraZ(SceneObjectPart part) | ||
2030 | { | ||
2031 | // Next, try to raycast from the camera Z position | ||
2032 | Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset; | ||
2033 | Vector3 StartRayCastPosition = AbsolutePosition; StartRayCastPosition.Z = CameraPosition.Z; | ||
2034 | Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition); | ||
2035 | float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition); | ||
2036 | m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastAvatarPositionCameraZResponse); | ||
2037 | } | ||
2038 | 2888 | ||
2039 | public void SitRayCastAvatarPositionCameraZResponse(bool hitYN, Vector3 collisionPoint, uint localid, float pdistance, Vector3 normal) | 2889 | if (part.PhysActor == null) |
2040 | { | ||
2041 | SceneObjectPart part = FindNextAvailableSitTarget(m_requestedSitTargetUUID); | ||
2042 | if (part != null) | ||
2043 | { | 2890 | { |
2044 | if (hitYN) | 2891 | // none physcis shape |
2045 | { | 2892 | if (part.PhysicsShapeType == (byte)PhysicsShapeType.None) |
2046 | if (collisionPoint.ApproxEquals(m_requestedSitOffset + part.AbsolutePosition, 0.2f)) | 2893 | ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot."); |
2047 | { | ||
2048 | SitRaycastFindEdge(collisionPoint, normal); | ||
2049 | m_log.DebugFormat("[SIT]: Raycast Avatar Position + CameraZ succeeded at point: {0}, normal:{1}", collisionPoint, normal); | ||
2050 | } | ||
2051 | else | ||
2052 | { | ||
2053 | SitRayCastCameraPosition(part); | ||
2054 | } | ||
2055 | } | ||
2056 | else | 2894 | else |
2057 | { | 2895 | { // non physical phantom TODO |
2058 | SitRayCastCameraPosition(part); | 2896 | ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot."); |
2897 | return false; | ||
2059 | } | 2898 | } |
2060 | } | 2899 | return true; |
2061 | else | ||
2062 | { | ||
2063 | ControllingClient.SendAlertMessage("Sit position no longer exists"); | ||
2064 | m_requestedSitTargetUUID = UUID.Zero; | ||
2065 | m_requestedSitTargetID = 0; | ||
2066 | m_requestedSitOffset = Vector3.Zero; | ||
2067 | } | 2900 | } |
2068 | 2901 | ||
2069 | } | ||
2070 | 2902 | ||
2071 | public void SitRayCastCameraPosition(SceneObjectPart part) | 2903 | // not doing autopilot |
2072 | { | 2904 | m_requestedSitTargetID = 0; |
2073 | // Next, try to raycast from the camera position | ||
2074 | Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset; | ||
2075 | Vector3 StartRayCastPosition = CameraPosition; | ||
2076 | Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition); | ||
2077 | float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition); | ||
2078 | m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastCameraPositionResponse); | ||
2079 | } | ||
2080 | 2905 | ||
2081 | public void SitRayCastCameraPositionResponse(bool hitYN, Vector3 collisionPoint, uint localid, float pdistance, Vector3 normal) | 2906 | if (m_scene.PhysicsScene.SitAvatar(part.PhysActor, AbsolutePosition, CameraPosition, offset, new Vector3(0.35f, 0, 0.65f), PhysicsSitResponse) != 0) |
2082 | { | 2907 | return true; |
2083 | SceneObjectPart part = FindNextAvailableSitTarget(m_requestedSitTargetUUID); | ||
2084 | if (part != null) | ||
2085 | { | ||
2086 | if (hitYN) | ||
2087 | { | ||
2088 | if (collisionPoint.ApproxEquals(m_requestedSitOffset + part.AbsolutePosition, 0.2f)) | ||
2089 | { | ||
2090 | SitRaycastFindEdge(collisionPoint, normal); | ||
2091 | m_log.DebugFormat("[SIT]: Raycast Camera Position succeeded at point: {0}, normal:{1}", collisionPoint, normal); | ||
2092 | } | ||
2093 | else | ||
2094 | { | ||
2095 | SitRayHorizontal(part); | ||
2096 | } | ||
2097 | } | ||
2098 | else | ||
2099 | { | ||
2100 | SitRayHorizontal(part); | ||
2101 | } | ||
2102 | } | ||
2103 | else | ||
2104 | { | ||
2105 | ControllingClient.SendAlertMessage("Sit position no longer exists"); | ||
2106 | m_requestedSitTargetUUID = UUID.Zero; | ||
2107 | m_requestedSitTargetID = 0; | ||
2108 | m_requestedSitOffset = Vector3.Zero; | ||
2109 | } | ||
2110 | 2908 | ||
2909 | return false; | ||
2910 | */ | ||
2111 | } | 2911 | } |
2112 | 2912 | ||
2113 | public void SitRayHorizontal(SceneObjectPart part) | 2913 | |
2914 | private bool CanEnterLandPosition(Vector3 testPos) | ||
2114 | { | 2915 | { |
2115 | // Next, try to raycast from the avatar position to fwd | 2916 | ILandObject land = m_scene.LandChannel.GetLandObject(testPos.X, testPos.Y); |
2116 | Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset; | 2917 | |
2117 | Vector3 StartRayCastPosition = CameraPosition; | 2918 | if (land == null || land.LandData.Name == "NO_LAND") |
2118 | Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition); | 2919 | return true; |
2119 | float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition); | 2920 | |
2120 | m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastHorizontalResponse); | 2921 | return land.CanBeOnThisLand(UUID,testPos.Z); |
2121 | } | 2922 | } |
2122 | 2923 | ||
2123 | public void SitRayCastHorizontalResponse(bool hitYN, Vector3 collisionPoint, uint localid, float pdistance, Vector3 normal) | 2924 | // status |
2925 | // < 0 ignore | ||
2926 | // 0 bad sit spot | ||
2927 | public void PhysicsSitResponse(int status, uint partID, Vector3 offset, Quaternion Orientation) | ||
2124 | { | 2928 | { |
2125 | SceneObjectPart part = FindNextAvailableSitTarget(m_requestedSitTargetUUID); | 2929 | if (status < 0) |
2126 | if (part != null) | 2930 | return; |
2931 | |||
2932 | if (status == 0) | ||
2127 | { | 2933 | { |
2128 | if (hitYN) | 2934 | ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot."); |
2129 | { | 2935 | return; |
2130 | if (collisionPoint.ApproxEquals(m_requestedSitOffset + part.AbsolutePosition, 0.2f)) | ||
2131 | { | ||
2132 | SitRaycastFindEdge(collisionPoint, normal); | ||
2133 | m_log.DebugFormat("[SIT]: Raycast Horizontal Position succeeded at point: {0}, normal:{1}", collisionPoint, normal); | ||
2134 | // Next, try to raycast from the camera position | ||
2135 | Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset; | ||
2136 | Vector3 StartRayCastPosition = CameraPosition; | ||
2137 | Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition); | ||
2138 | float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition); | ||
2139 | //m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastResponseAvatarPosition); | ||
2140 | } | ||
2141 | else | ||
2142 | { | ||
2143 | ControllingClient.SendAlertMessage("Sit position not accessable."); | ||
2144 | m_requestedSitTargetUUID = UUID.Zero; | ||
2145 | m_requestedSitTargetID = 0; | ||
2146 | m_requestedSitOffset = Vector3.Zero; | ||
2147 | } | ||
2148 | } | ||
2149 | else | ||
2150 | { | ||
2151 | ControllingClient.SendAlertMessage("Sit position not accessable."); | ||
2152 | m_requestedSitTargetUUID = UUID.Zero; | ||
2153 | m_requestedSitTargetID = 0; | ||
2154 | m_requestedSitOffset = Vector3.Zero; | ||
2155 | } | ||
2156 | } | 2936 | } |
2157 | else | 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)) | ||
2158 | { | 2944 | { |
2159 | ControllingClient.SendAlertMessage("Sit position no longer exists"); | 2945 | ControllingClient.SendAlertMessage(" Sit position on restricted land, try another spot"); |
2160 | m_requestedSitTargetUUID = UUID.Zero; | 2946 | return; |
2161 | m_requestedSitTargetID = 0; | ||
2162 | m_requestedSitOffset = Vector3.Zero; | ||
2163 | } | 2947 | } |
2164 | 2948 | ||
2165 | } | 2949 | RemoveFromPhysicalScene(); |
2166 | 2950 | ||
2167 | private void SitRaycastFindEdge(Vector3 collisionPoint, Vector3 collisionNormal) | 2951 | if (MovingToTarget) |
2168 | { | 2952 | ResetMoveToTarget(); |
2169 | int i = 0; | 2953 | |
2170 | //throw new NotImplementedException(); | 2954 | Velocity = Vector3.Zero; |
2171 | //m_requestedSitTargetUUID = UUID.Zero; | 2955 | |
2172 | //m_requestedSitTargetID = 0; | 2956 | part.AddSittingAvatar(this); |
2173 | //m_requestedSitOffset = Vector3.Zero; | 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 | ||
2174 | 2966 | ||
2175 | SendSitResponse(ControllingClient, m_requestedSitTargetUUID, collisionPoint - m_requestedSitOffset, Quaternion.Identity); | 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); | ||
2176 | } | 2981 | } |
2177 | */ | ||
2178 | 2982 | ||
2179 | public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) | 2983 | public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) |
2180 | { | 2984 | { |
2985 | if (IsChildAgent) | ||
2986 | return; | ||
2987 | |||
2181 | SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); | 2988 | SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); |
2182 | 2989 | ||
2183 | if (part != null) | 2990 | if (part != null) |
@@ -2205,23 +3012,75 @@ namespace OpenSim.Region.Framework.Scenes | |||
2205 | 3012 | ||
2206 | //Quaternion result = (sitTargetOrient * vq) * nq; | 3013 | //Quaternion result = (sitTargetOrient * vq) * nq; |
2207 | 3014 | ||
2208 | m_pos = sitTargetPos + SIT_TARGET_ADJUSTMENT; | 3015 | double x, y, z, m1, m2; |
2209 | Rotation = sitTargetOrient; | 3016 | |
2210 | ParentPosition = part.AbsolutePosition; | 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; | ||
2211 | } | 3067 | } |
2212 | else | 3068 | else |
2213 | { | 3069 | { |
2214 | m_pos -= part.AbsolutePosition; | 3070 | // An viewer expects to specify sit positions as offsets to the root prim, even if a child prim is |
2215 | ParentPosition = part.AbsolutePosition; | 3071 | // being sat upon. |
3072 | m_pos -= part.GroupPosition; | ||
3073 | |||
3074 | // ParentPosition = part.AbsolutePosition; | ||
2216 | 3075 | ||
2217 | // m_log.DebugFormat( | 3076 | // m_log.DebugFormat( |
2218 | // "[SCENE PRESENCE]: Sitting {0} at position {1} ({2} + {3}) on part {4} {5} without sit target", | 3077 | // "[SCENE PRESENCE]: Sitting {0} at position {1} ({2} + {3}) on part {4} {5} without sit target", |
2219 | // Name, part.AbsolutePosition, m_pos, ParentPosition, part.Name, part.LocalId); | 3078 | // Name, part.AbsolutePosition, m_pos, ParentPosition, part.Name, part.LocalId); |
2220 | } | 3079 | } |
2221 | 3080 | ||
2222 | ParentPart = m_scene.GetSceneObjectPart(m_requestedSitTargetID); | 3081 | ParentPart = part; |
2223 | ParentID = m_requestedSitTargetID; | 3082 | ParentID = m_requestedSitTargetID; |
2224 | 3083 | m_AngularVelocity = Vector3.Zero; | |
2225 | Velocity = Vector3.Zero; | 3084 | Velocity = Vector3.Zero; |
2226 | RemoveFromPhysicalScene(); | 3085 | RemoveFromPhysicalScene(); |
2227 | 3086 | ||
@@ -2231,14 +3090,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
2231 | sitAnimation = part.SitAnimation; | 3090 | sitAnimation = part.SitAnimation; |
2232 | } | 3091 | } |
2233 | Animator.TrySetMovementAnimation(sitAnimation); | 3092 | Animator.TrySetMovementAnimation(sitAnimation); |
2234 | SendAvatarDataToAllAgents(); | 3093 | SendAvatarDataToAllClients(); |
3094 | TriggerScenePresenceUpdated(); | ||
2235 | } | 3095 | } |
2236 | } | 3096 | } |
2237 | 3097 | ||
2238 | public void HandleAgentSitOnGround() | 3098 | public void HandleAgentSitOnGround() |
2239 | { | 3099 | { |
2240 | // m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick. | 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; | ||
2241 | Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); | 3105 | Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); |
3106 | TriggerScenePresenceUpdated(); | ||
2242 | SitGround = true; | 3107 | SitGround = true; |
2243 | RemoveFromPhysicalScene(); | 3108 | RemoveFromPhysicalScene(); |
2244 | } | 3109 | } |
@@ -2255,22 +3120,39 @@ namespace OpenSim.Region.Framework.Scenes | |||
2255 | public void HandleStartAnim(IClientAPI remoteClient, UUID animID) | 3120 | public void HandleStartAnim(IClientAPI remoteClient, UUID animID) |
2256 | { | 3121 | { |
2257 | Animator.AddAnimation(animID, UUID.Zero); | 3122 | Animator.AddAnimation(animID, UUID.Zero); |
3123 | TriggerScenePresenceUpdated(); | ||
2258 | } | 3124 | } |
2259 | 3125 | ||
2260 | public void HandleStopAnim(IClientAPI remoteClient, UUID animID) | 3126 | public void HandleStopAnim(IClientAPI remoteClient, UUID animID) |
2261 | { | 3127 | { |
2262 | Animator.RemoveAnimation(animID, false); | 3128 | Animator.RemoveAnimation(animID, false); |
3129 | TriggerScenePresenceUpdated(); | ||
2263 | } | 3130 | } |
2264 | 3131 | ||
2265 | /// <summary> | 3132 | /// <summary> |
2266 | /// Rotate the avatar to the given rotation and apply a movement in the given relative vector | 3133 | /// Rotate the avatar to the given rotation and apply a movement in the given relative vector |
2267 | /// </summary> | 3134 | /// </summary> |
2268 | /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param> | 3135 | /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param> |
2269 | public void AddNewMovement(Vector3 vec) | 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) | ||
2270 | { | 3139 | { |
2271 | // m_log.DebugFormat("[SCENE PRESENCE]: Adding new movement {0} for {1}", vec, Name); | 3140 | // m_log.DebugFormat( |
3141 | // "[SCENE PRESENCE]: Adding new movement {0} with rotation {1}, thisAddSpeedModifier {2} for {3}", | ||
3142 | // vec, Rotation, thisAddSpeedModifier, Name); | ||
2272 | 3143 | ||
2273 | Vector3 direc = vec * Rotation; | 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; | ||
2274 | direc.Normalize(); | 3156 | direc.Normalize(); |
2275 | 3157 | ||
2276 | if (Flying != FlyingOld) // add for fly velocity control | 3158 | if (Flying != FlyingOld) // add for fly velocity control |
@@ -2286,7 +3168,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2286 | if ((vec.Z == 0f) && !Flying) | 3168 | if ((vec.Z == 0f) && !Flying) |
2287 | direc.Z = 0f; // Prevent camera WASD up. | 3169 | direc.Z = 0f; // Prevent camera WASD up. |
2288 | 3170 | ||
2289 | direc *= 0.03f * 128f * SpeedModifier; | 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); | ||
2290 | 3174 | ||
2291 | if (PhysicsActor != null) | 3175 | if (PhysicsActor != null) |
2292 | { | 3176 | { |
@@ -2315,14 +3199,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
2315 | direc.Z *= 2.6f; | 3199 | direc.Z *= 2.6f; |
2316 | 3200 | ||
2317 | // TODO: PreJump and jump happen too quickly. Many times prejump gets ignored. | 3201 | // TODO: PreJump and jump happen too quickly. Many times prejump gets ignored. |
2318 | Animator.TrySetMovementAnimation("PREJUMP"); | 3202 | // Animator.TrySetMovementAnimation("PREJUMP"); |
2319 | Animator.TrySetMovementAnimation("JUMP"); | 3203 | // Animator.TrySetMovementAnimation("JUMP"); |
2320 | } | 3204 | } |
2321 | } | 3205 | } |
2322 | } | 3206 | } |
2323 | 3207 | ||
3208 | // m_log.DebugFormat("[SCENE PRESENCE]: Setting force to apply to {0} for {1}", direc, Name); | ||
3209 | |||
2324 | // TODO: Add the force instead of only setting it to support multiple forces per frame? | 3210 | // TODO: Add the force instead of only setting it to support multiple forces per frame? |
2325 | m_forceToApply = direc; | 3211 | m_forceToApply = direc; |
3212 | Animator.UpdateMovementAnimations(); | ||
2326 | } | 3213 | } |
2327 | 3214 | ||
2328 | #endregion | 3215 | #endregion |
@@ -2331,25 +3218,27 @@ namespace OpenSim.Region.Framework.Scenes | |||
2331 | 3218 | ||
2332 | public override void Update() | 3219 | public override void Update() |
2333 | { | 3220 | { |
2334 | const float ROTATION_TOLERANCE = 0.01f; | ||
2335 | const float VELOCITY_TOLERANCE = 0.001f; | ||
2336 | const float POSITION_TOLERANCE = 0.05f; | ||
2337 | |||
2338 | if (IsChildAgent == false) | 3221 | if (IsChildAgent == false) |
2339 | { | 3222 | { |
2340 | // NOTE: Velocity is not the same as m_velocity. Velocity will attempt to | 3223 | // NOTE: Velocity is not the same as m_velocity. Velocity will attempt to |
2341 | // grab the latest PhysicsActor velocity, whereas m_velocity is often | 3224 | // grab the latest PhysicsActor velocity, whereas m_velocity is often |
2342 | // storing a requested force instead of an actual traveling velocity | 3225 | // storing a requested force instead of an actual traveling velocity |
2343 | 3226 | if (Appearance.AvatarSize != m_lastSize && !IsLoggingIn) | |
2344 | // Throw away duplicate or insignificant updates | 3227 | SendAvatarDataToAllClients(); |
2345 | if ( | 3228 | |
2346 | // If the velocity has become zero, send it no matter what. | 3229 | // Allow any updates for sitting avatars to that llSetPrimitiveLinkParams() can work for very |
2347 | (Velocity != m_lastVelocity && Velocity == Vector3.Zero) | 3230 | // small increments (e.g. sit position adjusters). An alternative may be to eliminate the tolerance |
2348 | // otherwise, if things have changed reasonably, send the update | 3231 | // checks on all updates but the ramifications of this would need careful consideration. |
2349 | || (!Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE) | 3232 | bool updateClients |
2350 | || !Velocity.ApproxEquals(m_lastVelocity, VELOCITY_TOLERANCE) | 3233 | = IsSatOnObject && (Rotation != m_lastRotation || Velocity != m_lastVelocity || m_pos != m_lastPosition); |
2351 | || !m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE))) | 3234 | |
2352 | 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) | ||
2353 | { | 3242 | { |
2354 | SendTerseUpdateToAllClients(); | 3243 | SendTerseUpdateToAllClients(); |
2355 | 3244 | ||
@@ -2359,7 +3248,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2359 | m_lastVelocity = Velocity; | 3248 | m_lastVelocity = Velocity; |
2360 | } | 3249 | } |
2361 | 3250 | ||
2362 | CheckForBorderCrossing(); | 3251 | if (Scene.AllowAvatarCrossing) |
3252 | CheckForBorderCrossing(); | ||
2363 | 3253 | ||
2364 | CheckForSignificantMovement(); // sends update to the modules. | 3254 | CheckForSignificantMovement(); // sends update to the modules. |
2365 | } | 3255 | } |
@@ -2369,7 +3259,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2369 | 3259 | ||
2370 | #region Update Client(s) | 3260 | #region Update Client(s) |
2371 | 3261 | ||
2372 | |||
2373 | /// <summary> | 3262 | /// <summary> |
2374 | /// Sends a location update to the client connected to this scenePresence | 3263 | /// Sends a location update to the client connected to this scenePresence |
2375 | /// </summary> | 3264 | /// </summary> |
@@ -2380,6 +3269,29 @@ namespace OpenSim.Region.Framework.Scenes | |||
2380 | // server. | 3269 | // server. |
2381 | if (remoteClient.IsActive) | 3270 | if (remoteClient.IsActive) |
2382 | { | 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 | |||
2383 | //m_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, Rotation, m_velocity); | 3295 | //m_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, Rotation, m_velocity); |
2384 | 3296 | ||
2385 | remoteClient.SendEntityUpdate( | 3297 | remoteClient.SendEntityUpdate( |
@@ -2417,7 +3329,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
2417 | float distanceError = Vector3.Distance(OffsetPosition, expectedPosition); | 3329 | float distanceError = Vector3.Distance(OffsetPosition, expectedPosition); |
2418 | 3330 | ||
2419 | float speed = Velocity.Length(); | 3331 | float speed = Velocity.Length(); |
2420 | float velocidyDiff = Vector3.Distance(lastVelocitySentToAllClients, Velocity); | 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); | ||
2421 | 3337 | ||
2422 | // assuming 5 ms. worst case precision for timer, use 2x that | 3338 | // assuming 5 ms. worst case precision for timer, use 2x that |
2423 | // for distance error threshold | 3339 | // for distance error threshold |
@@ -2425,12 +3341,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
2425 | 3341 | ||
2426 | if (speed < 0.01f // allow rotation updates if avatar position is unchanged | 3342 | if (speed < 0.01f // allow rotation updates if avatar position is unchanged |
2427 | || Math.Abs(distanceError) > distanceErrorThreshold | 3343 | || Math.Abs(distanceError) > distanceErrorThreshold |
2428 | || velocidyDiff > 0.01f) // did velocity change from last update? | 3344 | || velocityDiff > 0.01f) // did velocity change from last update? |
2429 | { | 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 | |||
2430 | lastVelocitySentToAllClients = Velocity; | 3350 | lastVelocitySentToAllClients = Velocity; |
2431 | lastTerseUpdateToAllClientsTick = currentTick; | 3351 | lastTerseUpdateToAllClientsTick = currentTick; |
2432 | lastPositionSentToAllClients = OffsetPosition; | 3352 | lastPositionSentToAllClients = OffsetPosition; |
2433 | 3353 | ||
3354 | m_terseUpdateCount++; | ||
3355 | |||
3356 | // Console.WriteLine("Scheduled update for {0} in {1}", Name, Scene.Name); | ||
2434 | m_scene.ForEachClient(SendTerseUpdateToClient); | 3357 | m_scene.ForEachClient(SendTerseUpdateToClient); |
2435 | } | 3358 | } |
2436 | TriggerScenePresenceUpdated(); | 3359 | TriggerScenePresenceUpdated(); |
@@ -2456,24 +3379,30 @@ namespace OpenSim.Region.Framework.Scenes | |||
2456 | ControllingClient.SendCoarseLocationUpdate(avatarUUIDs, coarseLocations); | 3379 | ControllingClient.SendCoarseLocationUpdate(avatarUUIDs, coarseLocations); |
2457 | } | 3380 | } |
2458 | 3381 | ||
2459 | public void SendInitialDataToMe() | 3382 | public void SendInitialDataToClient() |
2460 | { | 3383 | { |
3384 | SentInitialDataToClient = true; | ||
3385 | |||
2461 | // Send all scene object to the new client | 3386 | // Send all scene object to the new client |
2462 | Util.FireAndForget(delegate | 3387 | WorkManager.RunJob("SendInitialDataToClient", delegate |
2463 | { | 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 | |||
2464 | // we created a new ScenePresence (a new child agent) in a fresh region. | 3393 | // we created a new ScenePresence (a new child agent) in a fresh region. |
2465 | // Request info about all the (root) agents in this region | 3394 | // Request info about all the (root) agents in this region |
2466 | // Note: This won't send data *to* other clients in that region (children don't send) | 3395 | // Note: This won't send data *to* other clients in that region (children don't send) |
2467 | SendOtherAgentsAvatarDataToMe(); | 3396 | SendOtherAgentsAvatarDataToClient(); |
2468 | SendOtherAgentsAppearanceToMe(); | 3397 | SendOtherAgentsAppearanceToClient(); |
2469 | 3398 | ||
2470 | EntityBase[] entities = Scene.Entities.GetEntities(); | 3399 | EntityBase[] entities = Scene.Entities.GetEntities(); |
2471 | foreach(EntityBase e in entities) | 3400 | foreach (EntityBase e in entities) |
2472 | { | 3401 | { |
2473 | if (e != null && e is SceneObjectGroup) | 3402 | if (e != null && e is SceneObjectGroup) |
2474 | ((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient); | 3403 | ((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient); |
2475 | } | 3404 | } |
2476 | }); | 3405 | }, null, string.Format("SendInitialDataToClient ({0} in {1})", Name, Scene.Name), false, true); |
2477 | } | 3406 | } |
2478 | 3407 | ||
2479 | /// <summary> | 3408 | /// <summary> |
@@ -2506,26 +3435,33 @@ namespace OpenSim.Region.Framework.Scenes | |||
2506 | // getting other avatars information was initiated elsewhere immediately after the child circuit connected... don't do it | 3435 | // getting other avatars information was initiated elsewhere immediately after the child circuit connected... don't do it |
2507 | // again here... this comes after the cached appearance check because the avatars | 3436 | // again here... this comes after the cached appearance check because the avatars |
2508 | // appearance goes into the avatar update packet | 3437 | // appearance goes into the avatar update packet |
2509 | SendAvatarDataToAllAgents(); | 3438 | SendAvatarDataToAllClients(); |
2510 | SendAppearanceToAgent(this); | 3439 | |
3440 | // This invocation always shows up in the viewer logs as an error. Is it needed? | ||
3441 | SendAppearanceToClient(this); | ||
2511 | 3442 | ||
2512 | // If we are using the the cached appearance then send it out to everyone | 3443 | // If we are using the the cached appearance then send it out to everyone |
2513 | if (cachedappearance) | 3444 | if (cachedappearance) |
2514 | { | 3445 | { |
2515 | m_log.DebugFormat("[SCENE PRESENCE]: baked textures are in the cache for {0}", Name); | 3446 | m_log.DebugFormat("[SCENE PRESENCE]: Baked textures are in the cache for {0} in {1}", Name, m_scene.Name); |
2516 | 3447 | ||
2517 | // If the avatars baked textures are all in the cache, then we have a | 3448 | // If the avatars baked textures are all in the cache, then we have a |
2518 | // complete appearance... send it out, if not, then we'll send it when | 3449 | // complete appearance... send it out, if not, then we'll send it when |
2519 | // the avatar finishes updating its appearance | 3450 | // the avatar finishes updating its appearance |
2520 | SendAppearanceToAllOtherAgents(); | 3451 | SendAppearanceToAllOtherClients(); |
2521 | } | 3452 | } |
2522 | } | 3453 | } |
2523 | 3454 | ||
3455 | public void SendAvatarDataToAllClients() | ||
3456 | { | ||
3457 | SendAvatarDataToAllClients(true); | ||
3458 | } | ||
3459 | |||
2524 | /// <summary> | 3460 | /// <summary> |
2525 | /// Send this agent's avatar data to all other root and child agents in the scene | 3461 | /// Send this agent's avatar data to all other root and child agents in the scene |
2526 | /// This agent must be root. This avatar will receive its own update. | 3462 | /// This agent must be root. This avatar will receive its own update. |
2527 | /// </summary> | 3463 | /// </summary> |
2528 | public void SendAvatarDataToAllAgents() | 3464 | public void SendAvatarDataToAllClients(bool full) |
2529 | { | 3465 | { |
2530 | //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAllAgents: {0} ({1})", Name, UUID); | 3466 | //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAllAgents: {0} ({1})", Name, UUID); |
2531 | // only send update from root agents to other clients; children are only "listening posts" | 3467 | // only send update from root agents to other clients; children are only "listening posts" |
@@ -2538,12 +3474,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
2538 | return; | 3474 | return; |
2539 | } | 3475 | } |
2540 | 3476 | ||
3477 | m_lastSize = Appearance.AvatarSize; | ||
3478 | |||
2541 | int count = 0; | 3479 | int count = 0; |
2542 | m_scene.ForEachScenePresence(delegate(ScenePresence scenePresence) | 3480 | m_scene.ForEachScenePresence(delegate(ScenePresence scenePresence) |
2543 | { | 3481 | { |
2544 | SendAvatarDataToAgent(scenePresence); | 3482 | if (full) |
2545 | count++; | 3483 | SendAvatarDataToClient(scenePresence); |
2546 | }); | 3484 | else |
3485 | scenePresence.ControllingClient.SendAvatarDataImmediate(this); | ||
3486 | count++; | ||
3487 | }); | ||
2547 | 3488 | ||
2548 | m_scene.StatsReporter.AddAgentUpdates(count); | 3489 | m_scene.StatsReporter.AddAgentUpdates(count); |
2549 | } | 3490 | } |
@@ -2552,7 +3493,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2552 | /// Send avatar data for all other root agents to this agent, this agent | 3493 | /// Send avatar data for all other root agents to this agent, this agent |
2553 | /// can be either a child or root | 3494 | /// can be either a child or root |
2554 | /// </summary> | 3495 | /// </summary> |
2555 | public void SendOtherAgentsAvatarDataToMe() | 3496 | public void SendOtherAgentsAvatarDataToClient() |
2556 | { | 3497 | { |
2557 | int count = 0; | 3498 | int count = 0; |
2558 | m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence) | 3499 | m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence) |
@@ -2561,7 +3502,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2561 | if (scenePresence.UUID == UUID) | 3502 | if (scenePresence.UUID == UUID) |
2562 | return; | 3503 | return; |
2563 | 3504 | ||
2564 | scenePresence.SendAvatarDataToAgent(this); | 3505 | scenePresence.SendAvatarDataToClient(this); |
2565 | count++; | 3506 | count++; |
2566 | }); | 3507 | }); |
2567 | 3508 | ||
@@ -2572,9 +3513,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2572 | /// Send avatar data to an agent. | 3513 | /// Send avatar data to an agent. |
2573 | /// </summary> | 3514 | /// </summary> |
2574 | /// <param name="avatar"></param> | 3515 | /// <param name="avatar"></param> |
2575 | public void SendAvatarDataToAgent(ScenePresence avatar) | 3516 | public void SendAvatarDataToClient(ScenePresence avatar) |
2576 | { | 3517 | { |
2577 | //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAgent from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID); | 3518 | //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToClient from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID); |
2578 | 3519 | ||
2579 | avatar.ControllingClient.SendAvatarDataImmediate(this); | 3520 | avatar.ControllingClient.SendAvatarDataImmediate(this); |
2580 | Animator.SendAnimPackToClient(avatar.ControllingClient); | 3521 | Animator.SendAnimPackToClient(avatar.ControllingClient); |
@@ -2584,9 +3525,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2584 | /// Send this agent's appearance to all other root and child agents in the scene | 3525 | /// Send this agent's appearance to all other root and child agents in the scene |
2585 | /// This agent must be root. | 3526 | /// This agent must be root. |
2586 | /// </summary> | 3527 | /// </summary> |
2587 | public void SendAppearanceToAllOtherAgents() | 3528 | public void SendAppearanceToAllOtherClients() |
2588 | { | 3529 | { |
2589 | // m_log.DebugFormat("[SCENE PRESENCE] SendAppearanceToAllOtherAgents: {0} {1}", Name, UUID); | 3530 | // m_log.DebugFormat("[SCENE PRESENCE] SendAppearanceToAllOtherClients: {0} {1}", Name, UUID); |
2590 | 3531 | ||
2591 | // only send update from root agents to other clients; children are only "listening posts" | 3532 | // only send update from root agents to other clients; children are only "listening posts" |
2592 | if (IsChildAgent) | 3533 | if (IsChildAgent) |
@@ -2605,7 +3546,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2605 | if (scenePresence.UUID == UUID) | 3546 | if (scenePresence.UUID == UUID) |
2606 | return; | 3547 | return; |
2607 | 3548 | ||
2608 | SendAppearanceToAgent(scenePresence); | 3549 | SendAppearanceToClient(scenePresence); |
2609 | count++; | 3550 | count++; |
2610 | }); | 3551 | }); |
2611 | 3552 | ||
@@ -2616,9 +3557,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2616 | /// Send appearance from all other root agents to this agent. this agent | 3557 | /// Send appearance from all other root agents to this agent. this agent |
2617 | /// can be either root or child | 3558 | /// can be either root or child |
2618 | /// </summary> | 3559 | /// </summary> |
2619 | public void SendOtherAgentsAppearanceToMe() | 3560 | public void SendOtherAgentsAppearanceToClient() |
2620 | { | 3561 | { |
2621 | // m_log.DebugFormat("[SCENE PRESENCE] SendOtherAgentsAppearanceToMe: {0} {1}", Name, UUID); | 3562 | // m_log.DebugFormat("[SCENE PRESENCE] SendOtherAgentsAppearanceToClient {0} {1}", Name, UUID); |
2622 | 3563 | ||
2623 | int count = 0; | 3564 | int count = 0; |
2624 | m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence) | 3565 | m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence) |
@@ -2627,7 +3568,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2627 | if (scenePresence.UUID == UUID) | 3568 | if (scenePresence.UUID == UUID) |
2628 | return; | 3569 | return; |
2629 | 3570 | ||
2630 | scenePresence.SendAppearanceToAgent(this); | 3571 | scenePresence.SendAppearanceToClient(this); |
2631 | count++; | 3572 | count++; |
2632 | }); | 3573 | }); |
2633 | 3574 | ||
@@ -2638,13 +3579,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
2638 | /// Send appearance data to an agent. | 3579 | /// Send appearance data to an agent. |
2639 | /// </summary> | 3580 | /// </summary> |
2640 | /// <param name="avatar"></param> | 3581 | /// <param name="avatar"></param> |
2641 | public void SendAppearanceToAgent(ScenePresence avatar) | 3582 | public void SendAppearanceToClient(ScenePresence avatar) |
2642 | { | 3583 | { |
2643 | // m_log.DebugFormat( | 3584 | // m_log.DebugFormat( |
2644 | // "[SCENE PRESENCE]: Sending appearance data from {0} {1} to {2} {3}", Name, m_uuid, avatar.Name, avatar.UUID); | 3585 | // "[SCENE PRESENCE]: Sending appearance data from {0} {1} to {2} {3}", Name, m_uuid, avatar.Name, avatar.UUID); |
2645 | 3586 | ||
2646 | avatar.ControllingClient.SendAppearance( | 3587 | avatar.ControllingClient.SendAppearance( |
2647 | UUID, Appearance.VisualParams, Appearance.Texture.GetBytes()); | 3588 | UUID, Appearance.VisualParams, Appearance.Texture.GetBytes()); |
3589 | |||
3590 | |||
2648 | } | 3591 | } |
2649 | 3592 | ||
2650 | #endregion | 3593 | #endregion |
@@ -2663,11 +3606,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
2663 | } | 3606 | } |
2664 | 3607 | ||
2665 | // Minimum Draw distance is 64 meters, the Radius of the draw distance sphere is 32m | 3608 | // Minimum Draw distance is 64 meters, the Radius of the draw distance sphere is 32m |
2666 | if (Util.GetDistanceTo(AbsolutePosition, m_lastChildAgentUpdatePosition) >= Scene.ChildReprioritizationDistance || | 3609 | if (Util.GetDistanceTo(AbsolutePosition, m_lastChildAgentUpdatePosition) >= Scene.ChildReprioritizationDistance) |
2667 | Util.GetDistanceTo(CameraPosition, m_lastChildAgentUpdateCamPosition) >= Scene.ChildReprioritizationDistance) | ||
2668 | { | 3610 | { |
2669 | m_lastChildAgentUpdatePosition = AbsolutePosition; | 3611 | m_lastChildAgentUpdatePosition = AbsolutePosition; |
2670 | m_lastChildAgentUpdateCamPosition = CameraPosition; | 3612 | // m_lastChildAgentUpdateCamPosition = CameraPosition; |
2671 | 3613 | ||
2672 | ChildAgentDataUpdate cadu = new ChildAgentDataUpdate(); | 3614 | ChildAgentDataUpdate cadu = new ChildAgentDataUpdate(); |
2673 | cadu.ActiveGroupID = UUID.Zero.Guid; | 3615 | cadu.ActiveGroupID = UUID.Zero.Guid; |
@@ -2694,10 +3636,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
2694 | cadu.Velocity = Velocity; | 3636 | cadu.Velocity = Velocity; |
2695 | 3637 | ||
2696 | AgentPosition agentpos = new AgentPosition(); | 3638 | AgentPosition agentpos = new AgentPosition(); |
2697 | agentpos.CopyFrom(cadu); | 3639 | agentpos.CopyFrom(cadu, ControllingClient.SessionId); |
2698 | 3640 | ||
2699 | // Let's get this out of the update loop | 3641 | // Let's get this out of the update loop |
2700 | Util.FireAndForget(delegate { m_scene.SendOutChildAgentUpdates(agentpos, this); }); | 3642 | Util.FireAndForget( |
3643 | o => m_scene.SendOutChildAgentUpdates(agentpos, this), null, "ScenePresence.SendOutChildAgentUpdates"); | ||
2701 | } | 3644 | } |
2702 | } | 3645 | } |
2703 | 3646 | ||
@@ -2719,140 +3662,84 @@ namespace OpenSim.Region.Framework.Scenes | |||
2719 | 3662 | ||
2720 | // If we don't have a PhysActor, we can't cross anyway | 3663 | // If we don't have a PhysActor, we can't cross anyway |
2721 | // Also don't do this while sat, sitting avatars cross with the | 3664 | // Also don't do this while sat, sitting avatars cross with the |
2722 | // object they sit on. | 3665 | // object they sit on. ParentUUID denoted a pending sit, don't |
2723 | if (ParentID != 0 || PhysicsActor == null) | 3666 | // interfere with it. |
3667 | if (ParentID != 0 || PhysicsActor == null || ParentUUID != UUID.Zero) | ||
2724 | return; | 3668 | return; |
2725 | 3669 | ||
2726 | if (!IsInTransit) | 3670 | if (IsInTransit) |
2727 | { | 3671 | return; |
2728 | Vector3 pos2 = AbsolutePosition; | ||
2729 | Vector3 vel = Velocity; | ||
2730 | int neighbor = 0; | ||
2731 | int[] fix = new int[2]; | ||
2732 | 3672 | ||
2733 | float timeStep = 0.1f; | 3673 | Vector3 pos2 = AbsolutePosition; |
2734 | pos2.X = pos2.X + (vel.X * timeStep); | 3674 | Vector3 origPosition = pos2; |
2735 | pos2.Y = pos2.Y + (vel.Y * timeStep); | 3675 | Vector3 vel = Velocity; |
2736 | pos2.Z = pos2.Z + (vel.Z * timeStep); | ||
2737 | 3676 | ||
2738 | if (!IsInTransit) | 3677 | // Compute the future avatar position. |
2739 | { | 3678 | // If the avatar will be crossing, we force the crossing to happen now |
2740 | // Checks if where it's headed exists a region | 3679 | // in the hope that this will make the avatar movement smoother when crossing. |
2741 | bool needsTransit = false; | 3680 | pos2 += vel * 0.05f; |
2742 | if (m_scene.TestBorderCross(pos2, Cardinals.W)) | ||
2743 | { | ||
2744 | if (m_scene.TestBorderCross(pos2, Cardinals.S)) | ||
2745 | { | ||
2746 | needsTransit = true; | ||
2747 | neighbor = m_scene.HaveNeighbor(Cardinals.SW, ref fix); | ||
2748 | } | ||
2749 | else if (m_scene.TestBorderCross(pos2, Cardinals.N)) | ||
2750 | { | ||
2751 | needsTransit = true; | ||
2752 | neighbor = m_scene.HaveNeighbor(Cardinals.NW, ref fix); | ||
2753 | } | ||
2754 | else | ||
2755 | { | ||
2756 | needsTransit = true; | ||
2757 | neighbor = m_scene.HaveNeighbor(Cardinals.W, ref fix); | ||
2758 | } | ||
2759 | } | ||
2760 | else if (m_scene.TestBorderCross(pos2, Cardinals.E)) | ||
2761 | { | ||
2762 | if (m_scene.TestBorderCross(pos2, Cardinals.S)) | ||
2763 | { | ||
2764 | needsTransit = true; | ||
2765 | neighbor = m_scene.HaveNeighbor(Cardinals.SE, ref fix); | ||
2766 | } | ||
2767 | else if (m_scene.TestBorderCross(pos2, Cardinals.N)) | ||
2768 | { | ||
2769 | needsTransit = true; | ||
2770 | neighbor = m_scene.HaveNeighbor(Cardinals.NE, ref fix); | ||
2771 | } | ||
2772 | else | ||
2773 | { | ||
2774 | needsTransit = true; | ||
2775 | neighbor = m_scene.HaveNeighbor(Cardinals.E, ref fix); | ||
2776 | } | ||
2777 | } | ||
2778 | else if (m_scene.TestBorderCross(pos2, Cardinals.S)) | ||
2779 | { | ||
2780 | needsTransit = true; | ||
2781 | neighbor = m_scene.HaveNeighbor(Cardinals.S, ref fix); | ||
2782 | } | ||
2783 | else if (m_scene.TestBorderCross(pos2, Cardinals.N)) | ||
2784 | { | ||
2785 | needsTransit = true; | ||
2786 | neighbor = m_scene.HaveNeighbor(Cardinals.N, ref fix); | ||
2787 | } | ||
2788 | 3681 | ||
2789 | // Makes sure avatar does not end up outside region | 3682 | if (m_scene.PositionIsInCurrentRegion(pos2)) |
2790 | if (neighbor <= 0) | 3683 | return; |
2791 | { | 3684 | |
2792 | if (needsTransit) | 3685 | m_log.DebugFormat("{0} CheckForBorderCrossing: position outside region. {1} in {2} at pos {3}", |
2793 | { | 3686 | LogHeader, Name, Scene.Name, pos2); |
2794 | if (m_requestedSitTargetUUID == UUID.Zero) | 3687 | |
2795 | { | 3688 | // Disconnect from the current region |
2796 | bool isFlying = Flying; | 3689 | bool isFlying = Flying; |
2797 | RemoveFromPhysicalScene(); | 3690 | RemoveFromPhysicalScene(); |
2798 | 3691 | ||
2799 | Vector3 pos = AbsolutePosition; | 3692 | // pos2 is the forcasted position so make that the 'current' position so the crossing |
2800 | if (AbsolutePosition.X < 0) | 3693 | // code will move us into the newly addressed region. |
2801 | pos.X += Velocity.X * 2; | 3694 | m_pos = pos2; |
2802 | else if (AbsolutePosition.X > Constants.RegionSize) | 3695 | |
2803 | pos.X -= Velocity.X * 2; | 3696 | if (CrossToNewRegion()) |
2804 | if (AbsolutePosition.Y < 0) | 3697 | { |
2805 | pos.Y += Velocity.Y * 2; | 3698 | AddToPhysicalScene(isFlying); |
2806 | else if (AbsolutePosition.Y > Constants.RegionSize) | 3699 | } |
2807 | pos.Y -= Velocity.Y * 2; | 3700 | else |
2808 | Velocity = Vector3.Zero; | 3701 | { |
2809 | AbsolutePosition = pos; | 3702 | // Tried to make crossing happen but it failed. |
2810 | 3703 | if (m_requestedSitTargetUUID == UUID.Zero) | |
2811 | // m_log.DebugFormat("[SCENE PRESENCE]: Prevented flyoff for {0} at {1}", Name, AbsolutePosition); | ||
2812 | |||
2813 | AddToPhysicalScene(isFlying); | ||
2814 | } | ||
2815 | } | ||
2816 | } | ||
2817 | else if (neighbor > 0) | ||
2818 | { | ||
2819 | if (!CrossToNewRegion()) | ||
2820 | { | ||
2821 | if (m_requestedSitTargetUUID == UUID.Zero) | ||
2822 | { | ||
2823 | bool isFlying = Flying; | ||
2824 | RemoveFromPhysicalScene(); | ||
2825 | |||
2826 | Vector3 pos = AbsolutePosition; | ||
2827 | if (AbsolutePosition.X < 0) | ||
2828 | pos.X += Velocity.X * 2; | ||
2829 | else if (AbsolutePosition.X > Constants.RegionSize) | ||
2830 | pos.X -= Velocity.X * 2; | ||
2831 | if (AbsolutePosition.Y < 0) | ||
2832 | pos.Y += Velocity.Y * 2; | ||
2833 | else if (AbsolutePosition.Y > Constants.RegionSize) | ||
2834 | pos.Y -= Velocity.Y * 2; | ||
2835 | Velocity = Vector3.Zero; | ||
2836 | AbsolutePosition = pos; | ||
2837 | |||
2838 | AddToPhysicalScene(isFlying); | ||
2839 | } | ||
2840 | } | ||
2841 | } | ||
2842 | } | ||
2843 | else | ||
2844 | { | 3704 | { |
2845 | // This constant has been inferred from experimentation | 3705 | m_log.DebugFormat("{0} CheckForBorderCrossing: Crossing failed. Restoring old position.", LogHeader); |
2846 | // I'm not sure what this value should be, so I tried a few values. | 3706 | |
2847 | timeStep = 0.04f; | 3707 | Velocity = Vector3.Zero; |
2848 | pos2 = AbsolutePosition; | 3708 | AbsolutePosition = EnforceSanityOnPosition(origPosition); |
2849 | pos2.X = pos2.X + (vel.X * timeStep); | 3709 | |
2850 | pos2.Y = pos2.Y + (vel.Y * timeStep); | 3710 | AddToPhysicalScene(isFlying); |
2851 | // Don't touch the Z | ||
2852 | m_pos = pos2; | ||
2853 | m_log.DebugFormat("[SCENE PRESENCE]: In transit m_pos={0}", m_pos); | ||
2854 | } | 3711 | } |
2855 | } | 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; | ||
2856 | } | 3743 | } |
2857 | 3744 | ||
2858 | /// <summary> | 3745 | /// <summary> |
@@ -2873,18 +3760,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
2873 | } | 3760 | } |
2874 | } | 3761 | } |
2875 | 3762 | ||
2876 | public void RestoreInCurrentScene() | ||
2877 | { | ||
2878 | AddToPhysicalScene(false); // not exactly false | ||
2879 | } | ||
2880 | |||
2881 | public void Reset() | 3763 | public void Reset() |
2882 | { | 3764 | { |
2883 | // m_log.DebugFormat("[SCENE PRESENCE]: Resetting {0} in {1}", Name, Scene.RegionInfo.RegionName); | 3765 | // m_log.DebugFormat("[SCENE PRESENCE]: Resetting {0} in {1}", Name, Scene.RegionInfo.RegionName); |
2884 | 3766 | ||
2885 | // Put the child agent back at the center | 3767 | // Put the child agent back at the center |
2886 | AbsolutePosition | 3768 | AbsolutePosition |
2887 | = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 70); | 3769 | = new Vector3(((float)m_scene.RegionInfo.RegionSizeX * 0.5f), ((float)m_scene.RegionInfo.RegionSizeY * 0.5f), 70); |
2888 | 3770 | ||
2889 | Animator.ResetAnimations(); | 3771 | Animator.ResetAnimations(); |
2890 | } | 3772 | } |
@@ -2911,13 +3793,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
2911 | if (handle != Scene.RegionInfo.RegionHandle) | 3793 | if (handle != Scene.RegionInfo.RegionHandle) |
2912 | { | 3794 | { |
2913 | uint x, y; | 3795 | uint x, y; |
2914 | Utils.LongToUInts(handle, out x, out y); | 3796 | Util.RegionHandleToRegionLoc(handle, out x, out y); |
2915 | x = x / Constants.RegionSize; | ||
2916 | y = y / Constants.RegionSize; | ||
2917 | 3797 | ||
2918 | // m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX))); | 3798 | // m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX))); |
2919 | // m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY))); | 3799 | // m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY))); |
2920 | if (Util.IsOutsideView(DrawDistance, x, newRegionX, 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)) | ||
2921 | { | 3803 | { |
2922 | byebyeRegions.Add(handle); | 3804 | byebyeRegions.Add(handle); |
2923 | } | 3805 | } |
@@ -2927,10 +3809,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2927 | if (byebyeRegions.Count > 0) | 3809 | if (byebyeRegions.Count > 0) |
2928 | { | 3810 | { |
2929 | m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents"); | 3811 | m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents"); |
2930 | Util.FireAndForget(delegate | 3812 | |
2931 | { | 3813 | AgentCircuitData acd = Scene.AuthenticateHandler.GetAgentCircuitData(UUID); |
2932 | m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, byebyeRegions); | 3814 | string auth = string.Empty; |
2933 | }); | 3815 | if (acd != null) |
3816 | auth = acd.SessionID.ToString(); | ||
3817 | m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, auth, byebyeRegions); | ||
2934 | } | 3818 | } |
2935 | 3819 | ||
2936 | foreach (ulong handle in byebyeRegions) | 3820 | foreach (ulong handle in byebyeRegions) |
@@ -2971,36 +3855,45 @@ namespace OpenSim.Region.Framework.Scenes | |||
2971 | 3855 | ||
2972 | #region Child Agent Updates | 3856 | #region Child Agent Updates |
2973 | 3857 | ||
2974 | public void ChildAgentDataUpdate(AgentData cAgentData) | 3858 | public void UpdateChildAgent(AgentData cAgentData) |
2975 | { | 3859 | { |
2976 | // m_log.Debug(" >>> ChildAgentDataUpdate <<< " + Scene.RegionInfo.RegionName); | 3860 | // m_log.Debug(" >>> ChildAgentDataUpdate <<< " + Scene.RegionInfo.RegionName); |
2977 | if (!IsChildAgent) | 3861 | if (!IsChildAgent) |
2978 | return; | 3862 | return; |
2979 | 3863 | ||
2980 | CopyFrom(cAgentData); | 3864 | CopyFrom(cAgentData); |
3865 | |||
3866 | m_updateAgentReceivedAfterTransferEvent.Set(); | ||
2981 | } | 3867 | } |
2982 | 3868 | ||
2983 | private static Vector3 marker = new Vector3(-1f, -1f, -1f); | 3869 | private static Vector3 marker = new Vector3(-1f, -1f, -1f); |
3870 | |||
2984 | /// <summary> | 3871 | /// <summary> |
2985 | /// This updates important decision making data about a child agent | 3872 | /// This updates important decision making data about a child agent |
2986 | /// The main purpose is to figure out what objects to send to a child agent that's in a neighboring region | 3873 | /// The main purpose is to figure out what objects to send to a child agent that's in a neighboring region |
2987 | /// </summary> | 3874 | /// </summary> |
2988 | public void ChildAgentDataUpdate(AgentPosition cAgentData, uint tRegionX, uint tRegionY, uint rRegionX, uint rRegionY) | 3875 | public void UpdateChildAgent(AgentPosition cAgentData, uint tRegionX, uint tRegionY, uint rRegionX, uint rRegionY) |
2989 | { | 3876 | { |
2990 | if (!IsChildAgent) | 3877 | if (!IsChildAgent) |
2991 | return; | 3878 | return; |
2992 | 3879 | ||
2993 | //m_log.Debug(" >>> ChildAgentPositionUpdate <<< " + rRegionX + "-" + rRegionY); | 3880 | // m_log.DebugFormat( |
2994 | int shiftx = ((int)rRegionX - (int)tRegionX) * (int)Constants.RegionSize; | 3881 | // "[SCENE PRESENCE]: ChildAgentPositionUpdate for {0} in {1}, tRegion {2},{3}, rRegion {4},{5}, pos {6}", |
2995 | int shifty = ((int)rRegionY - (int)tRegionY) * (int)Constants.RegionSize; | 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); | ||
2996 | 3889 | ||
2997 | Vector3 offset = new Vector3(shiftx, shifty, 0f); | 3890 | Vector3 offset = new Vector3(shiftx, shifty, 0f); |
2998 | 3891 | ||
2999 | // When we get to the point of re-computing neighbors everytime this | 3892 | // When we get to the point of re-computing neighbors everytime this |
3000 | // changes, then start using the agent's drawdistance rather than the | 3893 | // changes, then start using the agent's drawdistance rather than the |
3001 | // region's draw distance. | 3894 | // region's draw distance. |
3002 | // DrawDistance = cAgentData.Far; | 3895 | DrawDistance = cAgentData.Far; |
3003 | DrawDistance = Scene.DefaultDrawDistance; | 3896 | // DrawDistance = Scene.DefaultDrawDistance; |
3004 | 3897 | ||
3005 | if (cAgentData.Position != marker) // UGH!! | 3898 | if (cAgentData.Position != marker) // UGH!! |
3006 | m_pos = cAgentData.Position + offset; | 3899 | m_pos = cAgentData.Position + offset; |
@@ -3027,6 +3920,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3027 | 3920 | ||
3028 | cAgent.AgentID = UUID; | 3921 | cAgent.AgentID = UUID; |
3029 | cAgent.RegionID = Scene.RegionInfo.RegionID; | 3922 | cAgent.RegionID = Scene.RegionInfo.RegionID; |
3923 | cAgent.SessionID = ControllingClient.SessionId; | ||
3030 | 3924 | ||
3031 | cAgent.Position = AbsolutePosition; | 3925 | cAgent.Position = AbsolutePosition; |
3032 | cAgent.Velocity = m_velocity; | 3926 | cAgent.Velocity = m_velocity; |
@@ -3061,6 +3955,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
3061 | cAgent.AlwaysRun = SetAlwaysRun; | 3955 | cAgent.AlwaysRun = SetAlwaysRun; |
3062 | 3956 | ||
3063 | cAgent.Appearance = new AvatarAppearance(Appearance); | 3957 | cAgent.Appearance = new AvatarAppearance(Appearance); |
3958 | |||
3959 | cAgent.ParentPart = ParentUUID; | ||
3960 | cAgent.SitOffset = PrevSitOffset; | ||
3064 | 3961 | ||
3065 | lock (scriptedcontrols) | 3962 | lock (scriptedcontrols) |
3066 | { | 3963 | { |
@@ -3069,7 +3966,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3069 | 3966 | ||
3070 | foreach (ScriptControllers c in scriptedcontrols.Values) | 3967 | foreach (ScriptControllers c in scriptedcontrols.Values) |
3071 | { | 3968 | { |
3072 | controls[i++] = new ControllerData(c.itemID, (uint)c.ignoreControls, (uint)c.eventControls); | 3969 | controls[i++] = new ControllerData(c.objectID, c.itemID, (uint)c.ignoreControls, (uint)c.eventControls); |
3073 | } | 3970 | } |
3074 | cAgent.Controllers = controls; | 3971 | cAgent.Controllers = controls; |
3075 | } | 3972 | } |
@@ -3089,8 +3986,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
3089 | 3986 | ||
3090 | private void CopyFrom(AgentData cAgent) | 3987 | private void CopyFrom(AgentData cAgent) |
3091 | { | 3988 | { |
3092 | m_originRegionID = cAgent.RegionID; | ||
3093 | |||
3094 | m_callbackURI = cAgent.CallbackURI; | 3989 | m_callbackURI = cAgent.CallbackURI; |
3095 | // m_log.DebugFormat( | 3990 | // m_log.DebugFormat( |
3096 | // "[SCENE PRESENCE]: Set callback for {0} in {1} to {2} in CopyFrom()", | 3991 | // "[SCENE PRESENCE]: Set callback for {0} in {1} to {2} in CopyFrom()", |
@@ -3102,12 +3997,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
3102 | CameraAtAxis = cAgent.AtAxis; | 3997 | CameraAtAxis = cAgent.AtAxis; |
3103 | CameraLeftAxis = cAgent.LeftAxis; | 3998 | CameraLeftAxis = cAgent.LeftAxis; |
3104 | CameraUpAxis = cAgent.UpAxis; | 3999 | CameraUpAxis = cAgent.UpAxis; |
4000 | ParentUUID = cAgent.ParentPart; | ||
4001 | PrevSitOffset = cAgent.SitOffset; | ||
3105 | 4002 | ||
3106 | // When we get to the point of re-computing neighbors everytime this | 4003 | // When we get to the point of re-computing neighbors everytime this |
3107 | // changes, then start using the agent's drawdistance rather than the | 4004 | // changes, then start using the agent's drawdistance rather than the |
3108 | // region's draw distance. | 4005 | // region's draw distance. |
3109 | // DrawDistance = cAgent.Far; | 4006 | DrawDistance = cAgent.Far; |
3110 | DrawDistance = Scene.DefaultDrawDistance; | 4007 | // DrawDistance = Scene.DefaultDrawDistance; |
3111 | 4008 | ||
3112 | if ((cAgent.Throttles != null) && cAgent.Throttles.Length > 0) | 4009 | if ((cAgent.Throttles != null) && cAgent.Throttles.Length > 0) |
3113 | ControllingClient.SetChildAgentThrottle(cAgent.Throttles); | 4010 | ControllingClient.SetChildAgentThrottle(cAgent.Throttles); |
@@ -3139,6 +4036,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3139 | foreach (ControllerData c in cAgent.Controllers) | 4036 | foreach (ControllerData c in cAgent.Controllers) |
3140 | { | 4037 | { |
3141 | ScriptControllers sc = new ScriptControllers(); | 4038 | ScriptControllers sc = new ScriptControllers(); |
4039 | sc.objectID = c.ObjectID; | ||
3142 | sc.itemID = c.ItemID; | 4040 | sc.itemID = c.ItemID; |
3143 | sc.ignoreControls = (ScriptControlled)c.IgnoreControls; | 4041 | sc.ignoreControls = (ScriptControlled)c.IgnoreControls; |
3144 | sc.eventControls = (ScriptControlled)c.EventControls; | 4042 | sc.eventControls = (ScriptControlled)c.EventControls; |
@@ -3159,7 +4057,27 @@ namespace OpenSim.Region.Framework.Scenes | |||
3159 | Animator.Animations.SetImplicitDefaultAnimation(cAgent.AnimState.AnimID, cAgent.AnimState.SequenceNum, UUID.Zero); | 4057 | Animator.Animations.SetImplicitDefaultAnimation(cAgent.AnimState.AnimID, cAgent.AnimState.SequenceNum, UUID.Zero); |
3160 | 4058 | ||
3161 | if (Scene.AttachmentsModule != null) | 4059 | if (Scene.AttachmentsModule != null) |
3162 | Scene.AttachmentsModule.CopyAttachments(cAgent, this); | 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; | ||
3163 | } | 4081 | } |
3164 | 4082 | ||
3165 | public bool CopyAgent(out IAgentData agent) | 4083 | public bool CopyAgent(out IAgentData agent) |
@@ -3180,8 +4098,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
3180 | { | 4098 | { |
3181 | Vector3 force = m_forceToApply.Value; | 4099 | Vector3 force = m_forceToApply.Value; |
3182 | 4100 | ||
3183 | Updated = true; | ||
3184 | |||
3185 | Velocity = force; | 4101 | Velocity = force; |
3186 | 4102 | ||
3187 | m_forceToApply = null; | 4103 | m_forceToApply = null; |
@@ -3206,20 +4122,23 @@ namespace OpenSim.Region.Framework.Scenes | |||
3206 | } | 4122 | } |
3207 | 4123 | ||
3208 | if (Appearance.AvatarHeight == 0) | 4124 | if (Appearance.AvatarHeight == 0) |
3209 | Appearance.SetHeight(); | 4125 | // Appearance.SetHeight(); |
3210 | 4126 | Appearance.SetSize(new Vector3(0.45f,0.6f,1.9f)); | |
3211 | PhysicsScene scene = m_scene.PhysicsScene; | 4127 | |
3212 | 4128 | /* | |
3213 | Vector3 pVec = AbsolutePosition; | ||
3214 | |||
3215 | PhysicsActor = scene.AddAvatar( | 4129 | PhysicsActor = scene.AddAvatar( |
3216 | LocalId, Firstname + "." + Lastname, pVec, | 4130 | LocalId, Firstname + "." + Lastname, pVec, |
3217 | new Vector3(0f, 0f, Appearance.AvatarHeight), isFlying); | 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); | ||
3218 | 4137 | ||
3219 | //PhysicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients; | 4138 | //PhysicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients; |
3220 | PhysicsActor.OnCollisionUpdate += PhysicsCollisionUpdate; | 4139 | PhysicsActor.OnCollisionUpdate += PhysicsCollisionUpdate; |
3221 | PhysicsActor.OnOutOfBounds += OutOfBoundsCall; // Called for PhysicsActors when there's something wrong | 4140 | PhysicsActor.OnOutOfBounds += OutOfBoundsCall; // Called for PhysicsActors when there's something wrong |
3222 | PhysicsActor.SubscribeEvents(500); | 4141 | PhysicsActor.SubscribeEvents(100); |
3223 | PhysicsActor.LocalID = LocalId; | 4142 | PhysicsActor.LocalID = LocalId; |
3224 | } | 4143 | } |
3225 | 4144 | ||
@@ -3233,6 +4152,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3233 | ControllingClient.SendAgentAlertMessage("Physics is having a problem with your avatar. You may not be able to move until you relog.", true); | 4152 | ControllingClient.SendAgentAlertMessage("Physics is having a problem with your avatar. You may not be able to move until you relog.", true); |
3234 | } | 4153 | } |
3235 | 4154 | ||
4155 | |||
3236 | /// <summary> | 4156 | /// <summary> |
3237 | /// Event called by the physics plugin to tell the avatar about a collision. | 4157 | /// Event called by the physics plugin to tell the avatar about a collision. |
3238 | /// </summary> | 4158 | /// </summary> |
@@ -3246,7 +4166,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3246 | /// <param name="e"></param> | 4166 | /// <param name="e"></param> |
3247 | public void PhysicsCollisionUpdate(EventArgs e) | 4167 | public void PhysicsCollisionUpdate(EventArgs e) |
3248 | { | 4168 | { |
3249 | if (IsChildAgent) | 4169 | if (IsChildAgent || Animator == null) |
3250 | return; | 4170 | return; |
3251 | 4171 | ||
3252 | //if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f)) | 4172 | //if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f)) |
@@ -3255,14 +4175,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
3255 | 4175 | ||
3256 | // if (m_updateCount > 0) | 4176 | // if (m_updateCount > 0) |
3257 | // { | 4177 | // { |
3258 | Animator.UpdateMovementAnimations(); | 4178 | if (Animator.UpdateMovementAnimations()) |
4179 | TriggerScenePresenceUpdated(); | ||
3259 | // m_updateCount--; | 4180 | // m_updateCount--; |
3260 | // } | 4181 | // } |
3261 | 4182 | ||
3262 | CollisionEventUpdate collisionData = (CollisionEventUpdate)e; | 4183 | CollisionEventUpdate collisionData = (CollisionEventUpdate)e; |
3263 | Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList; | 4184 | Dictionary<uint, ContactPoint> coldata = collisionData.m_objCollisionList; |
3264 | 4185 | ||
3265 | CollisionPlane = Vector4.UnitW; | ||
3266 | 4186 | ||
3267 | // // No collisions at all means we may be flying. Update always | 4187 | // // No collisions at all means we may be flying. Update always |
3268 | // // to make falling work | 4188 | // // to make falling work |
@@ -3272,34 +4192,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3272 | // m_lastColCount = coldata.Count; | 4192 | // m_lastColCount = coldata.Count; |
3273 | // } | 4193 | // } |
3274 | 4194 | ||
3275 | if (coldata.Count != 0) | 4195 | CollisionPlane = Vector4.UnitW; |
3276 | { | ||
3277 | switch (Animator.CurrentMovementAnimation) | ||
3278 | { | ||
3279 | case "STAND": | ||
3280 | case "WALK": | ||
3281 | case "RUN": | ||
3282 | case "CROUCH": | ||
3283 | case "CROUCHWALK": | ||
3284 | { | ||
3285 | ContactPoint lowest; | ||
3286 | lowest.SurfaceNormal = Vector3.Zero; | ||
3287 | lowest.Position = Vector3.Zero; | ||
3288 | lowest.Position.Z = Single.NaN; | ||
3289 | |||
3290 | foreach (ContactPoint contact in coldata.Values) | ||
3291 | { | ||
3292 | if (Single.IsNaN(lowest.Position.Z) || contact.Position.Z < lowest.Position.Z) | ||
3293 | { | ||
3294 | lowest = contact; | ||
3295 | } | ||
3296 | } | ||
3297 | |||
3298 | CollisionPlane = new Vector4(-lowest.SurfaceNormal, -Vector3.Dot(lowest.Position, lowest.SurfaceNormal)); | ||
3299 | } | ||
3300 | break; | ||
3301 | } | ||
3302 | } | ||
3303 | 4196 | ||
3304 | // Gods do not take damage and Invulnerable is set depending on parcel/region flags | 4197 | // Gods do not take damage and Invulnerable is set depending on parcel/region flags |
3305 | if (Invulnerable || GodLevel > 0) | 4198 | if (Invulnerable || GodLevel > 0) |
@@ -3398,6 +4291,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
3398 | // m_reprioritizationTimer.Dispose(); | 4291 | // m_reprioritizationTimer.Dispose(); |
3399 | 4292 | ||
3400 | RemoveFromPhysicalScene(); | 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; | ||
3401 | } | 4302 | } |
3402 | 4303 | ||
3403 | public void AddAttachment(SceneObjectGroup gobj) | 4304 | public void AddAttachment(SceneObjectGroup gobj) |
@@ -3602,7 +4503,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3602 | } | 4503 | } |
3603 | } | 4504 | } |
3604 | } | 4505 | } |
3605 | }); | 4506 | }, null, "ScenePresence.SendScriptEventToAttachments"); |
3606 | } | 4507 | } |
3607 | 4508 | ||
3608 | /// <summary> | 4509 | /// <summary> |
@@ -3631,10 +4532,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
3631 | 4532 | ||
3632 | public void RegisterControlEventsToScript(int controls, int accept, int pass_on, uint Obj_localID, UUID Script_item_UUID) | 4533 | public void RegisterControlEventsToScript(int controls, int accept, int pass_on, uint Obj_localID, UUID Script_item_UUID) |
3633 | { | 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 | |||
3634 | ScriptControllers obj = new ScriptControllers(); | 4542 | ScriptControllers obj = new ScriptControllers(); |
3635 | obj.ignoreControls = ScriptControlled.CONTROL_ZERO; | 4543 | obj.ignoreControls = ScriptControlled.CONTROL_ZERO; |
3636 | obj.eventControls = ScriptControlled.CONTROL_ZERO; | 4544 | obj.eventControls = ScriptControlled.CONTROL_ZERO; |
3637 | 4545 | ||
4546 | obj.objectID = p.ParentGroup.UUID; | ||
3638 | obj.itemID = Script_item_UUID; | 4547 | obj.itemID = Script_item_UUID; |
3639 | if (pass_on == 0 && accept == 0) | 4548 | if (pass_on == 0 && accept == 0) |
3640 | { | 4549 | { |
@@ -3683,6 +4592,21 @@ namespace OpenSim.Region.Framework.Scenes | |||
3683 | ControllingClient.SendTakeControls(int.MaxValue, false, false); | 4592 | ControllingClient.SendTakeControls(int.MaxValue, false, false); |
3684 | } | 4593 | } |
3685 | 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 | |||
3686 | public void UnRegisterControlEventsToScript(uint Obj_localID, UUID Script_item_UUID) | 4610 | public void UnRegisterControlEventsToScript(uint Obj_localID, UUID Script_item_UUID) |
3687 | { | 4611 | { |
3688 | ScriptControllers takecontrols; | 4612 | ScriptControllers takecontrols; |
@@ -3899,6 +4823,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3899 | (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || | 4823 | (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || |
3900 | (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0) | 4824 | (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0) |
3901 | { | 4825 | { |
4826 | |||
3902 | if (GodLevel < 200 && | 4827 | if (GodLevel < 200 && |
3903 | ((!m_scene.Permissions.IsGod(m_uuid) && | 4828 | ((!m_scene.Permissions.IsGod(m_uuid) && |
3904 | !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) || | 4829 | !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) || |
@@ -3907,7 +4832,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
3907 | { | 4832 | { |
3908 | SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray(); | 4833 | SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray(); |
3909 | if (spawnPoints.Length == 0) | 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 | } | ||
3910 | return; | 4841 | return; |
4842 | } | ||
3911 | 4843 | ||
3912 | int index; | 4844 | int index; |
3913 | bool selected = false; | 4845 | bool selected = false; |
@@ -3916,6 +4848,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3916 | { | 4848 | { |
3917 | case "random": | 4849 | case "random": |
3918 | 4850 | ||
4851 | if (spawnPoints.Length == 0) | ||
4852 | return; | ||
3919 | do | 4853 | do |
3920 | { | 4854 | { |
3921 | index = Util.RandomClass.Next(spawnPoints.Length - 1); | 4855 | index = Util.RandomClass.Next(spawnPoints.Length - 1); |
@@ -3927,6 +4861,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3927 | // SpawnPoint sp = spawnPoints[index]; | 4861 | // SpawnPoint sp = spawnPoints[index]; |
3928 | 4862 | ||
3929 | ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); | 4863 | ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); |
4864 | |||
3930 | if (land == null || land.IsEitherBannedOrRestricted(UUID)) | 4865 | if (land == null || land.IsEitherBannedOrRestricted(UUID)) |
3931 | selected = false; | 4866 | selected = false; |
3932 | else | 4867 | else |
@@ -3999,8 +4934,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
3999 | } | 4934 | } |
4000 | } | 4935 | } |
4001 | 4936 | ||
4937 | // Modify landing point based on possible banning, telehubs or parcel restrictions. | ||
4002 | private void CheckAndAdjustLandingPoint(ref Vector3 pos) | 4938 | private void CheckAndAdjustLandingPoint(ref Vector3 pos) |
4003 | { | 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 | |||
4004 | SceneObjectGroup telehub = null; | 4946 | SceneObjectGroup telehub = null; |
4005 | if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject)) != null) | 4947 | if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject)) != null) |
4006 | { | 4948 | { |
@@ -4040,11 +4982,119 @@ namespace OpenSim.Region.Framework.Scenes | |||
4040 | pos = land.LandData.UserLocation; | 4982 | pos = land.LandData.UserLocation; |
4041 | } | 4983 | } |
4042 | } | 4984 | } |
4043 | 4985 | ||
4044 | land.SendLandUpdateToClient(ControllingClient); | 4986 | land.SendLandUpdateToClient(ControllingClient); |
4045 | } | 4987 | } |
4046 | } | 4988 | } |
4047 | 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 | |||
4048 | private void TeleportFlagsDebug() { | 5098 | private void TeleportFlagsDebug() { |
4049 | 5099 | ||
4050 | // Some temporary debugging help to show all the TeleportFlags we have... | 5100 | // Some temporary debugging help to show all the TeleportFlags we have... |
@@ -4069,6 +5119,5 @@ namespace OpenSim.Region.Framework.Scenes | |||
4069 | m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************"); | 5119 | m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************"); |
4070 | 5120 | ||
4071 | } | 5121 | } |
4072 | |||
4073 | } | 5122 | } |
4074 | } | 5123 | } |