From 134f86e8d5c414409631b25b8c6f0ee45fbd8631 Mon Sep 17 00:00:00 2001
From: David Walter Seikel
Date: Thu, 3 Nov 2016 21:44:39 +1000
Subject: Initial update to OpenSim 0.8.2.1 source code.
---
OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2595 +++++++++++++++-------
1 file changed, 1822 insertions(+), 773 deletions(-)
(limited to 'OpenSim/Region/Framework/Scenes/ScenePresence.cs')
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;
using System.Xml;
using System.Collections.Generic;
using System.Reflection;
+using System.Threading;
using System.Timers;
+using Timer = System.Timers.Timer;
using OpenMetaverse;
using log4net;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Framework.Client;
+using OpenSim.Framework.Monitoring;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes.Animation;
using OpenSim.Region.Framework.Scenes.Types;
-using OpenSim.Region.Physics.Manager;
+using OpenSim.Region.PhysicsModules.SharedBase;
using GridRegion = OpenSim.Services.Interfaces.GridRegion;
using OpenSim.Services.Interfaces;
using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags;
@@ -63,6 +66,7 @@ namespace OpenSim.Region.Framework.Scenes
struct ScriptControllers
{
+ public UUID objectID;
public UUID itemID;
public ScriptControlled ignoreControls;
public ScriptControlled eventControls;
@@ -72,21 +76,51 @@ namespace OpenSim.Region.Framework.Scenes
public class ScenePresence : EntityBase, IScenePresence
{
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private static readonly String LogHeader = "[SCENE PRESENCE]";
+
// ~ScenePresence()
// {
// m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name);
// }
- private void TriggerScenePresenceUpdated()
+ public void TriggerScenePresenceUpdated()
{
if (m_scene != null)
m_scene.EventManager.TriggerScenePresenceUpdated(this);
}
- private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
-
public PresenceType PresenceType { get; private set; }
+ private ScenePresenceStateMachine m_stateMachine;
+
+ ///
+ /// The current state of this presence. Governs only the existence lifecycle. See ScenePresenceStateMachine
+ /// for more details.
+ ///
+ public ScenePresenceState LifecycleState
+ {
+ get
+ {
+ return m_stateMachine.GetState();
+ }
+
+ set
+ {
+ m_stateMachine.SetState(value);
+ }
+ }
+
+ ///
+ /// This exists to prevent race conditions between two CompleteMovement threads if the simulator is slow and
+ /// the viewer fires these in quick succession.
+ ///
+ ///
+ /// TODO: The child -> agent transition should be folded into LifecycleState and the CompleteMovement
+ /// regulation done there.
+ ///
+ private object m_completeMovementLock = new object();
+
// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes();
private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags));
private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f);
@@ -99,7 +133,7 @@ namespace OpenSim.Region.Framework.Scenes
/// rotation, prim cut, prim twist, prim taper, and prim shear. See mantis
/// issue #1716
///
- public static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.418f);
+ public static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.4f);
///
/// Movement updates for agents in neighboring regions are sent directly to clients.
@@ -139,6 +173,10 @@ namespace OpenSim.Region.Framework.Scenes
private Vector3 m_lastPosition;
private Quaternion m_lastRotation;
private Vector3 m_lastVelocity;
+ private Vector3 m_lastSize = new Vector3(0.45f,0.6f,1.9f);
+
+ private bool m_followCamAuto = false;
+
private Vector3? m_forceToApply;
private int m_userFlags;
@@ -196,10 +234,15 @@ namespace OpenSim.Region.Framework.Scenes
private float m_sitAvatarHeight = 2.0f;
private Vector3 m_lastChildAgentUpdatePosition;
- private Vector3 m_lastChildAgentUpdateCamPosition;
+// private Vector3 m_lastChildAgentUpdateCamPosition;
private const int LAND_VELOCITYMAG_MAX = 12;
+ private const float FLY_ROLL_MAX_RADIANS = 1.1f;
+
+ private const float FLY_ROLL_RADIANS_PER_UPDATE = 0.06f;
+ private const float FLY_ROLL_RESET_RADIANS_PER_UPDATE = 0.02f;
+
private float m_health = 100f;
protected ulong crossingFromRegion;
@@ -221,8 +264,6 @@ namespace OpenSim.Region.Framework.Scenes
///
public bool LandAtTarget { get; private set; }
- private bool m_followCamAuto;
-
private int m_movementUpdateCount;
private const int NumMovementsBetweenRayCast = 5;
@@ -230,6 +271,10 @@ namespace OpenSim.Region.Framework.Scenes
//private int m_moveToPositionStateStatus;
//*****************************************************
+ private int m_movementAnimationUpdateCounter = 0;
+
+ public Vector3 PrevSitOffset { get; set; }
+
protected AvatarAppearance m_appearance;
public AvatarAppearance Appearance
@@ -242,6 +287,8 @@ namespace OpenSim.Region.Framework.Scenes
}
}
+ public bool SentInitialDataToClient { get; private set; }
+
///
/// Copy of the script states while the agent is in transit. This state may
/// need to be placed back in case of transfer fail.
@@ -276,9 +323,43 @@ namespace OpenSim.Region.Framework.Scenes
///
private Vector3 posLastSignificantMove;
- // For teleports and crossings callbacks
- string m_callbackURI;
- UUID m_originRegionID;
+ #region For teleports and crossings callbacks
+
+ ///
+ /// In the V1 teleport protocol, the destination simulator sends ReleaseAgent to this address.
+ ///
+ private string m_callbackURI;
+
+ ///
+ /// Records the region from which this presence originated, if not from login.
+ ///
+ ///
+ /// Also acts as a signal in the teleport V2 process to release UpdateAgent after a viewer has triggered
+ /// CompleteMovement and made the previous child agent a root agent.
+ ///
+ private UUID m_originRegionID;
+
+ ///
+ /// This object is used as a lock before accessing m_originRegionID to make sure that every thread is seeing
+ /// the very latest value and not using some cached version. Cannot make m_originRegionID itself volatite as
+ /// it is a value type.
+ ///
+ private object m_originRegionIDAccessLock = new object();
+
+ ///
+ /// Triggered on entity transfer after to allow CompleteMovement() to proceed after we have received an
+ /// UpdateAgent from the originating region.ddkjjkj
+ ///
+ private AutoResetEvent m_updateAgentReceivedAfterTransferEvent = new AutoResetEvent(false);
+
+ ///
+ /// Used by the entity transfer module to signal when the presence should not be closed because a subsequent
+ /// teleport is reusing the connection.
+ ///
+ /// May be refactored or move somewhere else soon.
+ public bool DoNotCloseAfterTeleport { get; set; }
+
+ #endregion
///
/// Script engines present in the scene
@@ -295,15 +376,17 @@ namespace OpenSim.Region.Framework.Scenes
///
/// Record user movement inputs.
///
- public byte MovementFlag { get; private set; }
+ public uint MovementFlag { get; private set; }
- private bool m_updateflag;
+ ///
+ /// Set this if we need to force a movement update on the next received AgentUpdate from the viewer.
+ ///
+ private const uint ForceUpdateMovementFlagValue = uint.MaxValue;
- public bool Updated
- {
- set { m_updateflag = value; }
- get { return m_updateflag; }
- }
+ ///
+ /// Is the agent stop control flag currently active?
+ ///
+ public bool AgentControlStopActive { get; private set; }
private bool m_invulnerable = true;
@@ -344,6 +427,9 @@ namespace OpenSim.Region.Framework.Scenes
///
protected Vector3 m_lastCameraPosition;
+ private Vector4 m_lastCameraCollisionPlane = new Vector4(0f, 0f, 0f, 1);
+ private bool m_doingCamRayCast = false;
+
public Vector3 CameraPosition { get; set; }
public Quaternion CameraRotation
@@ -375,7 +461,19 @@ namespace OpenSim.Region.Framework.Scenes
public string Firstname { get; private set; }
public string Lastname { get; private set; }
- public string Grouptitle { get; set; }
+ public string Grouptitle
+ {
+ get { return UseFakeGroupTitle ? "(Loading)" : m_groupTitle; }
+ set { m_groupTitle = value; }
+ }
+ private string m_groupTitle;
+
+ ///
+ /// When this is 'true', return a dummy group title instead of the real group title. This is
+ /// used as part of a hack to force viewers to update the displayed avatar name.
+ ///
+ public bool UseFakeGroupTitle { get; set; }
+
// Agent's Draw distance.
public float DrawDistance { get; set; }
@@ -424,7 +522,9 @@ namespace OpenSim.Region.Framework.Scenes
get { return (IClientCore)ControllingClient; }
}
- public Vector3 ParentPosition { get; set; }
+ public UUID COF { get; set; }
+
+// public Vector3 ParentPosition { get; set; }
///
/// Position of this avatar relative to the region the avatar is in
@@ -437,12 +537,13 @@ namespace OpenSim.Region.Framework.Scenes
{
m_pos = PhysicsActor.Position;
- //m_log.DebugFormat(
- // "[SCENE PRESENCE]: Set position {0} for {1} in {2} via getting AbsolutePosition!",
- // m_pos, Name, Scene.RegionInfo.RegionName);
+// m_log.DebugFormat(
+// "[SCENE PRESENCE]: Set position of {0} in {1} to {2} via getting AbsolutePosition!",
+// Name, Scene.Name, m_pos);
}
else
{
+// m_log.DebugFormat("[SCENE PRESENCE]: Fetching abs pos where PhysicsActor == null and parent part {0} for {1}", Name, Scene.Name);
// Obtain the correct position of a seated avatar.
// In addition to providing the correct position while
// the avatar is seated, this value will also
@@ -459,13 +560,16 @@ namespace OpenSim.Region.Framework.Scenes
SceneObjectPart sitPart = ParentPart;
if (sitPart != null)
- return sitPart.AbsolutePosition + (m_pos * sitPart.GetWorldRotation());
+ return sitPart.ParentGroup.AbsolutePosition + (m_pos * sitPart.GetWorldRotation());
}
return m_pos;
}
set
{
+// m_log.DebugFormat("[SCENE PRESENCE]: Setting position of {0} to {1} in {2}", Name, value, Scene.Name);
+// Util.PrintCallStack();
+
if (PhysicsActor != null)
{
try
@@ -480,10 +584,7 @@ namespace OpenSim.Region.Framework.Scenes
// Don't update while sitting. The PhysicsActor above is null whilst sitting.
if (ParentID == 0)
- {
m_pos = value;
- ParentPosition = Vector3.Zero;
- }
//m_log.DebugFormat(
// "[ENTITY BASE]: In {0} set AbsolutePosition of {1} to {2}",
@@ -513,8 +614,11 @@ namespace OpenSim.Region.Framework.Scenes
}
///
- /// Current velocity of the avatar.
+ /// Velocity of the avatar with respect to its local reference frame.
///
+ ///
+ /// So when sat on a vehicle this will be 0. To get velocity with respect to the world use GetWorldVelocity()
+ ///
public override Vector3 Velocity
{
get
@@ -527,11 +631,21 @@ namespace OpenSim.Region.Framework.Scenes
// "[SCENE PRESENCE]: Set velocity {0} for {1} in {2} via getting Velocity!",
// m_velocity, Name, Scene.RegionInfo.RegionName);
}
+// else if (ParentPart != null)
+// {
+// return ParentPart.ParentGroup.Velocity;
+// }
return m_velocity;
}
+
set
{
+// Util.PrintCallStack();
+// m_log.DebugFormat(
+// "[SCENE PRESENCE]: In {0} set velocity of {1} to {2}",
+// Scene.RegionInfo.RegionName, Name, value);
+
if (PhysicsActor != null)
{
try
@@ -544,37 +658,86 @@ namespace OpenSim.Region.Framework.Scenes
}
}
- m_velocity = value;
-
-// m_log.DebugFormat(
-// "[SCENE PRESENCE]: In {0} set velocity of {1} to {2}",
-// Scene.RegionInfo.RegionName, Name, m_velocity);
+ m_velocity = value;
}
}
+/*
+ public override Vector3 AngularVelocity
+ {
+ get
+ {
+ if (PhysicsActor != null)
+ {
+ m_rotationalvelocity = PhysicsActor.RotationalVelocity;
+
+ // m_log.DebugFormat(
+ // "[SCENE PRESENCE]: Set velocity {0} for {1} in {2} via getting Velocity!",
+ // m_velocity, Name, Scene.RegionInfo.RegionName);
+ }
+ return m_rotationalvelocity;
+ }
+ }
+*/
private Quaternion m_bodyRot = Quaternion.Identity;
+ ///
+ /// The rotation of the avatar.
+ ///
+ ///
+ /// If the avatar is not sitting, this is with respect to the world
+ /// If the avatar is sitting, this is a with respect to the part that it's sitting upon (a local rotation).
+ /// If you always want the world rotation, use GetWorldRotation()
+ ///
public Quaternion Rotation
{
- get { return m_bodyRot; }
+ get
+ {
+ return m_bodyRot;
+ }
+
set
{
m_bodyRot = value;
+
if (PhysicsActor != null)
{
- PhysicsActor.Orientation = m_bodyRot;
+ try
+ {
+ PhysicsActor.Orientation = m_bodyRot;
+ }
+ catch (Exception e)
+ {
+ m_log.Error("[SCENE PRESENCE]: Orientation " + e.Message);
+ }
}
// m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot);
}
}
+ // Used for limited viewer 'fake' user rotations.
+ private Vector3 m_AngularVelocity = Vector3.Zero;
+
+ public Vector3 AngularVelocity
+ {
+ get { return m_AngularVelocity; }
+ }
+
public bool IsChildAgent { get; set; }
+ public bool IsLoggingIn { get; set; }
///
/// If the avatar is sitting, the local ID of the prim that it's sitting on. If not sitting then zero.
///
public uint ParentID { get; set; }
+ public UUID ParentUUID
+ {
+ get { return m_parentUUID; }
+ set { m_parentUUID = value; }
+ }
+ private UUID m_parentUUID = UUID.Zero;
+
///
/// Are we sitting on an object?
///
@@ -595,6 +758,33 @@ namespace OpenSim.Region.Framework.Scenes
set { m_health = value; }
}
+ ///
+ /// Get rotation relative to the world.
+ ///
+ ///
+ public Quaternion GetWorldRotation()
+ {
+ SceneObjectPart sitPart = ParentPart;
+
+ if (sitPart != null)
+ return sitPart.GetWorldRotation() * Rotation;
+
+ return Rotation;
+ }
+
+ ///
+ /// Get velocity relative to the world.
+ ///
+ public Vector3 GetWorldVelocity()
+ {
+ SceneObjectPart sitPart = ParentPart;
+
+ if (sitPart != null)
+ return sitPart.ParentGroup.Velocity;
+
+ return Velocity;
+ }
+
public void AdjustKnownSeeds()
{
Dictionary seeds;
@@ -608,9 +798,8 @@ namespace OpenSim.Region.Framework.Scenes
foreach (ulong handle in seeds.Keys)
{
uint x, y;
- Utils.LongToUInts(handle, out x, out y);
- x = x / Constants.RegionSize;
- y = y / Constants.RegionSize;
+ Util.RegionHandleToRegionLoc(handle, out x, out y);
+
if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY))
{
old.Add(handle);
@@ -632,18 +821,22 @@ namespace OpenSim.Region.Framework.Scenes
foreach (KeyValuePair kvp in KnownRegions)
{
uint x, y;
- Utils.LongToUInts(kvp.Key, out x, out y);
- x = x / Constants.RegionSize;
- y = y / Constants.RegionSize;
+ Util.RegionHandleToRegionLoc(kvp.Key, out x, out y);
m_log.Info(" >> "+x+", "+y+": "+kvp.Value);
}
}
private bool m_mouseLook;
- private bool m_leftButtonDown;
+// private bool m_leftButtonDown;
private bool m_inTransit;
+ ///
+ /// This signals whether the presence is in transit between neighbouring regions.
+ ///
+ ///
+ /// It is not set when the presence is teleporting or logging in/out directly to a region.
+ ///
public bool IsInTransit
{
get { return m_inTransit; }
@@ -667,6 +860,14 @@ namespace OpenSim.Region.Framework.Scenes
set { m_speedModifier = value; }
}
+ ///
+ /// Modifier for agent movement if we get an AGENT_CONTROL_STOP whilst walking or running
+ ///
+ ///
+ /// AGENT_CONTRL_STOP comes about if user holds down space key on viewers.
+ ///
+ private float AgentControlStopSlowWhilstMoving = 0.5f;
+
private bool m_forceFly;
public bool ForceFly
@@ -685,23 +886,30 @@ namespace OpenSim.Region.Framework.Scenes
public string Viewer
{
- get { return m_scene.AuthenticateHandler.GetAgentCircuitData(ControllingClient.CircuitCode).Viewer; }
+ get { return Util.GetViewerName(m_scene.AuthenticateHandler.GetAgentCircuitData(ControllingClient.CircuitCode)); }
}
+ ///
+ /// Count of how many terse updates we have sent out. It doesn't matter if this overflows.
+ ///
+ private int m_terseUpdateCount;
+
#endregion
#region Constructor(s)
public ScenePresence(
IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type)
- {
+ {
AttachmentsSyncLock = new Object();
AllowMovement = true;
IsChildAgent = true;
+ IsLoggingIn = false;
m_sendCoarseLocationsMethod = SendCoarseLocationsDefault;
Animator = new ScenePresenceAnimator(this);
PresenceType = type;
- DrawDistance = world.DefaultDrawDistance;
+ // DrawDistance = world.DefaultDrawDistance;
+ DrawDistance = Constants.RegionSize;
RegionHandle = world.RegionInfo.RegionHandle;
ControllingClient = client;
Firstname = ControllingClient.FirstName;
@@ -739,12 +947,42 @@ namespace OpenSim.Region.Framework.Scenes
SetDirectionVectors();
Appearance = appearance;
+
+ m_stateMachine = new ScenePresenceStateMachine(this);
+ }
+
+ private void RegionHeartbeatEnd(Scene scene)
+ {
+ if (IsChildAgent)
+ return;
+
+ m_movementAnimationUpdateCounter ++;
+ if (m_movementAnimationUpdateCounter >= 2)
+ {
+ m_movementAnimationUpdateCounter = 0;
+ if (Animator != null)
+ {
+ // If the parentID == 0 we are not sitting
+ // if !SitGournd then we are not sitting on the ground
+ // Fairly straightforward, now here comes the twist
+ // if ParentUUID is NOT UUID.Zero, we are looking to
+ // be sat on an object that isn't there yet. Should
+ // be treated as if sat.
+ if(ParentID == 0 && !SitGround && ParentUUID == UUID.Zero) // skip it if sitting
+ Animator.UpdateMovementAnimations();
+ }
+ else
+ {
+ m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd;
+ }
+ }
}
public void RegisterToEvents()
{
ControllingClient.OnCompleteMovementToRegion += CompleteMovement;
ControllingClient.OnAgentUpdate += HandleAgentUpdate;
+ ControllingClient.OnAgentCameraUpdate += HandleAgentCamerasUpdate;
ControllingClient.OnAgentRequestSit += HandleAgentRequestSit;
ControllingClient.OnAgentSit += HandleAgentSit;
ControllingClient.OnSetAlwaysRun += HandleSetAlwaysRun;
@@ -772,23 +1010,6 @@ namespace OpenSim.Region.Framework.Scenes
Dir_Vectors[10] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge
}
- private Vector3[] GetWalkDirectionVectors()
- {
- Vector3[] vector = new Vector3[11];
- vector[0] = new Vector3(CameraUpAxis.Z, 0f, -CameraAtAxis.Z); //FORWARD
- vector[1] = new Vector3(-CameraUpAxis.Z, 0f, CameraAtAxis.Z); //BACK
- vector[2] = Vector3.UnitY; //LEFT
- vector[3] = -Vector3.UnitY; //RIGHT
- vector[4] = new Vector3(CameraAtAxis.Z, 0f, CameraUpAxis.Z); //UP
- vector[5] = new Vector3(-CameraAtAxis.Z, 0f, -CameraUpAxis.Z); //DOWN
- vector[6] = new Vector3(CameraUpAxis.Z, 0f, -CameraAtAxis.Z); //FORWARD_NUDGE
- vector[7] = new Vector3(-CameraUpAxis.Z, 0f, CameraAtAxis.Z); //BACK_NUDGE
- vector[8] = Vector3.UnitY; //LEFT_NUDGE
- vector[9] = -Vector3.UnitY; //RIGHT_NUDGE
- vector[10] = new Vector3(-CameraAtAxis.Z, 0f, -CameraUpAxis.Z); //DOWN_NUDGE
- return vector;
- }
-
#endregion
#region Status Methods
@@ -796,6 +1017,7 @@ namespace OpenSim.Region.Framework.Scenes
///
/// Turns a child agent into a root agent.
///
+ ///
/// Child agents are logged into neighbouring sims largely to observe changes. Root agents exist when the
/// avatar is actual in the sim. They can perform all actions.
/// 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
///
/// This method is on the critical path for transferring an avatar from one region to another. Delay here
/// delays that crossing.
- ///
- public void MakeRootAgent(Vector3 pos, bool isFlying)
+ ///
+ private bool MakeRootAgent(Vector3 pos, bool isFlying)
{
- m_log.DebugFormat(
- "[SCENE]: Upgrading child to root agent for {0} in {1}",
- Name, m_scene.RegionInfo.RegionName);
+ lock (m_completeMovementLock)
+ {
+ if (!IsChildAgent)
+ return false;
+
+ //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count);
+
+ // m_log.InfoFormat(
+ // "[SCENE]: Upgrading child to root agent for {0} in {1}",
+ // Name, m_scene.RegionInfo.RegionName);
+
+ if (ParentUUID != UUID.Zero)
+ {
+ m_log.DebugFormat("[SCENE PRESENCE]: Sitting avatar back on prim {0}", ParentUUID);
+ SceneObjectPart part = m_scene.GetSceneObjectPart(ParentUUID);
+ if (part == null)
+ {
+ m_log.ErrorFormat("[SCENE PRESENCE]: Can't find prim {0} to sit on", ParentUUID);
+ }
+ else
+ {
+ part.AddSittingAvatar(this);
+ // ParentPosition = part.GetWorldPosition();
+ ParentID = part.LocalId;
+ ParentPart = part;
+ m_pos = PrevSitOffset;
+ // pos = ParentPosition;
+ pos = part.GetWorldPosition();
+ }
+ ParentUUID = UUID.Zero;
+
+ // Animator.TrySetMovementAnimation("SIT");
+ }
+ else
+ {
+ IsLoggingIn = false;
+ }
- //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count);
+ IsChildAgent = false;
+ }
- bool wasChild = IsChildAgent;
- IsChildAgent = false;
+ // Must reset this here so that a teleport to a region next to an existing region does not keep the flag
+ // set and prevent the close of the connection on a subsequent re-teleport.
+ // Should not be needed if we are not trying to tell this region to close
+// DoNotCloseAfterTeleport = false;
IGroupsModule gm = m_scene.RequestModuleInterface();
if (gm != null)
Grouptitle = gm.GetGroupTitle(m_uuid);
+ AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(ControllingClient.CircuitCode);
+ uint teleportFlags = (aCircuit == null) ? 0 : aCircuit.teleportFlags;
+ if ((teleportFlags & (uint)TeleportFlags.ViaHGLogin) != 0)
+ {
+ // The avatar is arriving from another grid. This means that we may have changed the
+ // avatar's name to or from the special Hypergrid format ("First.Last @grid.example.com").
+ // Unfortunately, due to a viewer bug, viewers don't always show the new name.
+ // But we have a trick that can force them to update the name anyway.
+ ForceViewersUpdateName();
+ }
+
RegionHandle = m_scene.RegionInfo.RegionHandle;
m_scene.EventManager.TriggerSetRootAgentScene(m_uuid, m_scene);
- // Moved this from SendInitialData to ensure that Appearance is initialized
- // before the inventory is processed in MakeRootAgent. This fixes a race condition
- // related to the handling of attachments
- //m_scene.GetAvatarAppearance(ControllingClient, out Appearance);
- if (m_scene.TestBorderCross(pos, Cardinals.E))
+ UUID groupUUID = ControllingClient.ActiveGroupId;
+ string groupName = string.Empty;
+ ulong groupPowers = 0;
+
+ // ----------------------------------
+ // Previous Agent Difference - AGNI sends an unsolicited AgentDataUpdate upon root agent status
+ try
{
- Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.E);
- pos.X = crossedBorder.BorderLine.Z - 1;
- }
+ if (groupUUID != UUID.Zero && gm != null)
+ {
+ GroupRecord record = gm.GetGroupRecord(groupUUID);
+ if (record != null)
+ groupName = record.GroupName;
+
+ GroupMembershipData groupMembershipData = gm.GetMembershipData(groupUUID, m_uuid);
- if (m_scene.TestBorderCross(pos, Cardinals.N))
+ if (groupMembershipData != null)
+ groupPowers = groupMembershipData.GroupPowers;
+ }
+
+ ControllingClient.SendAgentDataUpdate(
+ m_uuid, groupUUID, Firstname, Lastname, groupPowers, groupName, Grouptitle);
+ }
+ catch (Exception e)
{
- Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N);
- pos.Y = crossedBorder.BorderLine.Z - 1;
+ m_log.Error("[AGENTUPDATE]: Error ", e);
}
+ // ------------------------------------
- CheckAndAdjustLandingPoint(ref pos);
-
- if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f)
+ if (ParentID == 0)
{
- m_log.WarnFormat(
- "[SCENE PRESENCE]: MakeRootAgent() was given an illegal position of {0} for avatar {1}, {2}. Clamping",
- pos, Name, UUID);
+ // Moved this from SendInitialData to ensure that Appearance is initialized
+ // before the inventory is processed in MakeRootAgent. This fixes a race condition
+ // related to the handling of attachments
+ //m_scene.GetAvatarAppearance(ControllingClient, out Appearance);
+
+ /* RA 20140111: Commented out these TestBorderCross's.
+ * Not sure why this code is here. It is not checking all the borders
+ * and 'in region' sanity checking is done in CheckAndAdjustLandingPoint and below.
+ if (m_scene.TestBorderCross(pos, Cardinals.E))
+ {
+ Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.E);
+ pos.X = crossedBorder.BorderLine.Z - 1;
+ }
- if (pos.X < 0f) pos.X = 0f;
- if (pos.Y < 0f) pos.Y = 0f;
- if (pos.Z < 0f) pos.Z = 0f;
- }
+ if (m_scene.TestBorderCross(pos, Cardinals.N))
+ {
+ Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N);
+ pos.Y = crossedBorder.BorderLine.Z - 1;
+ }
+ */
+
+ CheckAndAdjustLandingPoint(ref pos);
+
+ if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f)
+ {
+ m_log.WarnFormat(
+ "[SCENE PRESENCE]: MakeRootAgent() was given an illegal position of {0} for avatar {1}, {2}. Clamping",
+ pos, Name, UUID);
- float localAVHeight = 1.56f;
- if (Appearance.AvatarHeight > 0)
- localAVHeight = Appearance.AvatarHeight;
+ if (pos.X < 0f) pos.X = 0f;
+ if (pos.Y < 0f) pos.Y = 0f;
+ if (pos.Z < 0f) pos.Z = 0f;
+ }
- float posZLimit = 0;
+ float localAVHeight = 1.56f;
+ if (Appearance.AvatarHeight > 0)
+ localAVHeight = Appearance.AvatarHeight;
- if (pos.X < Constants.RegionSize && pos.Y < Constants.RegionSize)
- posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y];
-
- float newPosZ = posZLimit + localAVHeight / 2;
- if (posZLimit >= (pos.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
- {
- pos.Z = newPosZ;
- }
- AbsolutePosition = pos;
+ float posZLimit = 0;
- AddToPhysicalScene(isFlying);
+ if (pos.X < m_scene.RegionInfo.RegionSizeX && pos.Y < m_scene.RegionInfo.RegionSizeY)
+ posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y];
+
+ float newPosZ = posZLimit + localAVHeight / 2;
+ if (posZLimit >= (pos.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
+ {
+ pos.Z = newPosZ;
+ }
+ AbsolutePosition = pos;
- if (ForceFly)
- {
- Flying = true;
- }
- else if (FlyDisabled)
- {
- Flying = false;
+// m_log.DebugFormat(
+// "Set pos {0}, vel {1} in {1} to {2} from input position of {3} on MakeRootAgent",
+// Name, Scene.Name, AbsolutePosition, pos);
+//
+ if (m_teleportFlags == TeleportFlags.Default)
+ {
+ AddToPhysicalScene(isFlying);
+//
+// Console.WriteLine(
+// "Set velocity of {0} in {1} to {2} from input velocity of {3} on MakeRootAgent",
+// Name, Scene.Name, PhysicsActor.Velocity, vel);
+// }
+ }
+ else
+ {
+ AddToPhysicalScene(isFlying);
+ }
+
+ // XXX: This is to trigger any secondary teleport needed for a megaregion when the user has teleported to a
+ // location outside the 'root region' (the south-west 256x256 corner). This is the earlist we can do it
+ // since it requires a physics actor to be present. If it is left any later, then physics appears to reset
+ // the value to a negative position which does not trigger the border cross.
+ // This may not be the best location for this.
+ CheckForBorderCrossing();
+
+ if (ForceFly)
+ {
+ Flying = true;
+ }
+ else if (FlyDisabled)
+ {
+ Flying = false;
+ }
}
// 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
m_scene.SwapRootAgentCount(false);
- // The initial login scene presence is already root when it gets here
- // and it has already rezzed the attachments and started their scripts.
- // We do the following only for non-login agents, because their scripts
- // haven't started yet.
- lock (m_attachments)
+ if (Scene.AttachmentsModule != null)
{
- if (wasChild && HasAttachments())
+ // The initial login scene presence is already root when it gets here
+ // and it has already rezzed the attachments and started their scripts.
+ // We do the following only for non-login agents, because their scripts
+ // haven't started yet.
+ if (PresenceType == PresenceType.Npc || IsRealLogin(m_teleportFlags))
{
- m_log.DebugFormat(
- "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name);
-
- // Resume scripts
- foreach (SceneObjectGroup sog in m_attachments)
- {
- sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource());
- sog.ResumeScripts();
- }
+ WorkManager.RunJob(
+ "RezAttachments",
+ o => Scene.AttachmentsModule.RezAttachments(this),
+ null,
+ string.Format("Rez attachments for {0} in {1}", Name, Scene.Name));
+ }
+ else
+ {
+ WorkManager.RunJob(
+ "StartAttachmentScripts",
+ o => RestartAttachmentScripts(),
+ null,
+ string.Format("Start attachment scripts for {0} in {1}", Name, Scene.Name),
+ true);
}
}
+ SendAvatarDataToAllClients();
+
// send the animations of the other presences to me
m_scene.ForEachRootScenePresence(delegate(ScenePresence presence)
{
@@ -916,27 +1253,93 @@ namespace OpenSim.Region.Framework.Scenes
// If we don't reset the movement flag here, an avatar that crosses to a neighbouring sim and returns will
// stall on the border crossing since the existing child agent will still have the last movement
// recorded, which stops the input from being processed.
- MovementFlag = 0;
+ MovementFlag = ForceUpdateMovementFlagValue;
m_scene.EventManager.TriggerOnMakeRootAgent(this);
+
+ return true;
}
- public int GetStateSource()
+ private void RestartAttachmentScripts()
{
- AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(UUID);
+ // We need to restart scripts here so that they receive the correct changed events (CHANGED_TELEPORT
+ // and CHANGED_REGION) when the attachments have been rezzed in the new region. This cannot currently
+ // be done in AttachmentsModule.CopyAttachments(AgentData ad, IScenePresence sp) itself since we are
+ // not transporting the required data.
+ //
+ // We must take a copy of the attachments list here (rather than locking) to avoid a deadlock where a script in one of
+ // the attachments may start processing an event (which locks ScriptInstance.m_Script) that then calls a method here
+ // which needs to lock m_attachments. ResumeScripts() needs to take a ScriptInstance.m_Script lock to try to unset the Suspend status.
+ //
+ // FIXME: In theory, this deadlock should not arise since scripts should not be processing events until ResumeScripts().
+ // But XEngine starts all scripts unsuspended. Starting them suspended will not currently work because script rezzing
+ // is placed in an asynchronous queue in XEngine and so the ResumeScripts() call will almost certainly execute before the
+ // script is rezzed. This means the ResumeScripts() does absolutely nothing when using XEngine.
+ List attachments = GetAttachments();
- if (aCircuit != null && (aCircuit.teleportFlags != (uint)TeleportFlags.Default))
- {
- // This will get your attention
- //m_log.Error("[XXX] Triggering CHANGED_TELEPORT");
+ m_log.DebugFormat(
+ "[SCENE PRESENCE]: Restarting scripts in {0} attachments for {1} in {2}", attachments.Count, Name, Scene.Name);
- return 5; // StateSource.Teleporting
+ // Resume scripts
+ foreach (SceneObjectGroup sog in attachments)
+ {
+ sog.ScheduleGroupForFullUpdate();
+ sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource());
+ sog.ResumeScripts();
}
- return 2; // StateSource.PrimCrossing
+ }
+
+ private static bool IsRealLogin(TeleportFlags teleportFlags)
+ {
+ return ((teleportFlags & TeleportFlags.ViaLogin) != 0) && ((teleportFlags & TeleportFlags.ViaHGLogin) == 0);
}
///
- /// This turns a root agent into a child agent
+ /// Force viewers to show the avatar's current name.
+ ///
+ ///
+ /// The avatar name that is shown above the avatar in the viewers is sent in ObjectUpdate packets,
+ /// and they get the name from the ScenePresence. Unfortunately, viewers have a bug (as of April 2014)
+ /// where they ignore changes to the avatar name. However, tey don't ignore changes to the avatar's
+ /// Group Title. So the following trick makes viewers update the avatar's name by briefly changing
+ /// the group title (to "(Loading)"), and then restoring it.
+ ///
+ public void ForceViewersUpdateName()
+ {
+ m_log.DebugFormat("[SCENE PRESENCE]: Forcing viewers to update the avatar name for " + Name);
+
+ UseFakeGroupTitle = true;
+ SendAvatarDataToAllClients(false);
+
+ Util.FireAndForget(o =>
+ {
+ // Viewers only update the avatar name when idle. Therefore, we must wait long
+ // enough for the viewer to show the fake name that we had set above, and only
+ // then switch back to the true name. This delay was chosen because it has a high
+ // chance of succeeding (we don't want to choose a value that's too low).
+ Thread.Sleep(5000);
+
+ UseFakeGroupTitle = false;
+ SendAvatarDataToAllClients(false);
+ }, null, "Scenepresence.ForceViewersUpdateName");
+ }
+
+ public int GetStateSource()
+ {
+ AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(UUID);
+
+ if (aCircuit != null && (aCircuit.teleportFlags != (uint)TeleportFlags.Default))
+ {
+ // This will get your attention
+ //m_log.Error("[XXX] Triggering CHANGED_TELEPORT");
+
+ return 5; // StateSource.Teleporting
+ }
+ return 2; // StateSource.PrimCrossing
+ }
+
+ ///
+ /// This turns a root agent into a child agent
///
///
/// when an agent departs this region for a neighbor, this gets called.
@@ -946,12 +1349,21 @@ namespace OpenSim.Region.Framework.Scenes
///
public void MakeChildAgent()
{
+ m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd;
+
m_log.DebugFormat("[SCENE PRESENCE]: Making {0} a child agent in {1}", Name, Scene.RegionInfo.RegionName);
+ // Reset the m_originRegionID as it has dual use as a flag to signal that the UpdateAgent() call orignating
+ // from the source simulator has completed on a V2 teleport.
+ lock (m_originRegionIDAccessLock)
+ m_originRegionID = UUID.Zero;
+
// Reset these so that teleporting in and walking out isn't seen
// as teleporting back
TeleportFlags = TeleportFlags.Default;
+ MovementFlag = 0;
+
// It looks like Animator is set to null somewhere, and MakeChild
// is called after that. Probably in aborted teleports.
if (Animator == null)
@@ -959,6 +1371,7 @@ namespace OpenSim.Region.Framework.Scenes
else
Animator.ResetAnimations();
+
// m_log.DebugFormat(
// "[SCENE PRESENCE]: Downgrading root agent {0}, {1} to a child agent in {2}",
// Name, UUID, m_scene.RegionInfo.RegionName);
@@ -970,6 +1383,7 @@ namespace OpenSim.Region.Framework.Scenes
IsChildAgent = true;
m_scene.SwapRootAgentCount(true);
RemoveFromPhysicalScene();
+ ParentID = 0; // Child agents can't be sitting
// FIXME: Set RegionHandle to the region handle of the scene this agent is moving into
@@ -984,10 +1398,10 @@ namespace OpenSim.Region.Framework.Scenes
if (PhysicsActor != null)
{
// PhysicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients;
- PhysicsActor.OnOutOfBounds -= OutOfBoundsCall;
- m_scene.PhysicsScene.RemoveAvatar(PhysicsActor);
PhysicsActor.UnSubscribeEvents();
+ PhysicsActor.OnOutOfBounds -= OutOfBoundsCall;
PhysicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate;
+ m_scene.PhysicsScene.RemoveAvatar(PhysicsActor);
PhysicsActor = null;
}
// else
@@ -1004,7 +1418,7 @@ namespace OpenSim.Region.Framework.Scenes
///
public void Teleport(Vector3 pos)
{
- TeleportWithMomentum(pos, null);
+ TeleportWithMomentum(pos, Vector3.Zero);
}
public void TeleportWithMomentum(Vector3 pos, Vector3? v)
@@ -1024,14 +1438,141 @@ namespace OpenSim.Region.Framework.Scenes
else
PhysicsActor.SetMomentum(vel);
}
+ }
+
+ public void avnLocalTeleport(Vector3 newpos, Vector3? newvel, bool rotateToVelXY)
+ {
+ CheckLandingPoint(ref newpos);
+ AbsolutePosition = newpos;
- SendTerseUpdateToAllClients();
+ if (newvel.HasValue)
+ {
+ if ((Vector3)newvel == Vector3.Zero)
+ {
+ if (PhysicsActor != null)
+ PhysicsActor.SetMomentum(Vector3.Zero);
+ m_velocity = Vector3.Zero;
+ }
+ else
+ {
+ if (PhysicsActor != null)
+ PhysicsActor.SetMomentum((Vector3)newvel);
+ m_velocity = (Vector3)newvel;
+
+ if (rotateToVelXY)
+ {
+ Vector3 lookAt = (Vector3)newvel;
+ lookAt.Z = 0;
+ lookAt.Normalize();
+ ControllingClient.SendLocalTeleport(newpos, lookAt, (uint)TeleportFlags.ViaLocation);
+ return;
+ }
+ }
+ }
}
public void StopFlying()
{
- ControllingClient.StopFlying(this);
+ Vector3 pos = AbsolutePosition;
+ if (Appearance.AvatarHeight != 127.0f)
+ pos += new Vector3(0f, 0f, (Appearance.AvatarHeight / 6f));
+ else
+ pos += new Vector3(0f, 0f, (1.56f / 6f));
+
+ AbsolutePosition = pos;
+
+ // attach a suitable collision plane regardless of the actual situation to force the LLClient to land.
+ // Collision plane below the avatar's position a 6th of the avatar's height is suitable.
+ // Mind you, that this method doesn't get called if the avatar's velocity magnitude is greater then a
+ // certain amount.. because the LLClient wouldn't land in that situation anyway.
+
+ // why are we still testing for this really old height value default???
+ if (Appearance.AvatarHeight != 127.0f)
+ CollisionPlane = new Vector4(0, 0, 0, pos.Z - Appearance.AvatarHeight / 6f);
+ else
+ CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f / 6f));
+
+ ControllingClient.SendAgentTerseUpdate(this);
+ }
+
+ ///
+ /// Applies a roll accumulator to the avatar's angular velocity for the avatar fly roll effect.
+ ///
+ /// Postive or negative roll amount in radians
+ private void ApplyFlyingRoll(float amount, bool PressingUp, bool PressingDown)
+ {
+
+ float rollAmount = Util.Clamp(m_AngularVelocity.Z + amount, -FLY_ROLL_MAX_RADIANS, FLY_ROLL_MAX_RADIANS);
+ m_AngularVelocity.Z = rollAmount;
+
+ // APPLY EXTRA consideration for flying up and flying down during this time.
+ // if we're turning left
+ if (amount > 0)
+ {
+
+ // If we're at the max roll and pressing up, we want to swing BACK a bit
+ // Automatically adds noise
+ if (PressingUp)
+ {
+ if (m_AngularVelocity.Z >= FLY_ROLL_MAX_RADIANS - 0.04f)
+ m_AngularVelocity.Z -= 0.9f;
+ }
+ // If we're at the max roll and pressing down, we want to swing MORE a bit
+ if (PressingDown)
+ {
+ if (m_AngularVelocity.Z >= FLY_ROLL_MAX_RADIANS && m_AngularVelocity.Z < FLY_ROLL_MAX_RADIANS + 0.6f)
+ m_AngularVelocity.Z += 0.6f;
+ }
+ }
+ else // we're turning right.
+ {
+ // If we're at the max roll and pressing up, we want to swing BACK a bit
+ // Automatically adds noise
+ if (PressingUp)
+ {
+ if (m_AngularVelocity.Z <= (-FLY_ROLL_MAX_RADIANS))
+ m_AngularVelocity.Z += 0.6f;
+ }
+ // If we're at the max roll and pressing down, we want to swing MORE a bit
+ if (PressingDown)
+ {
+ if (m_AngularVelocity.Z >= -FLY_ROLL_MAX_RADIANS - 0.6f)
+ m_AngularVelocity.Z -= 0.6f;
+ }
+ }
+ }
+
+ ///
+ /// incrementally sets roll amount to zero
+ ///
+ /// Positive roll amount in radians
+ ///
+ private float CalculateFlyingRollResetToZero(float amount)
+ {
+ const float rollMinRadians = 0f;
+
+ if (m_AngularVelocity.Z > 0)
+ {
+
+ float leftOverToMin = m_AngularVelocity.Z - rollMinRadians;
+ if (amount > leftOverToMin)
+ return -leftOverToMin;
+ else
+ return -amount;
+
+ }
+ else
+ {
+
+ float leftOverToMin = -m_AngularVelocity.Z - rollMinRadians;
+ if (amount > leftOverToMin)
+ return leftOverToMin;
+ else
+ return amount;
+ }
}
+
+
// neighbouring regions we have enabled a child agent in
// holds the seed cap for the child agent in that region
@@ -1118,6 +1659,40 @@ namespace OpenSim.Region.Framework.Scenes
PhysicsActor.Size = new Vector3(0.45f, 0.6f, height);
}
+ public void SetSize(Vector3 size, float feetoffset)
+ {
+ if (PhysicsActor != null && !IsChildAgent)
+ {
+ // Eventually there will be a physics call that sets avatar size that includes offset info.
+ // For the moment, just set the size as passed.
+ PhysicsActor.Size = size;
+ // PhysicsActor.setAvatarSize(size, feetoffset);
+ }
+ }
+
+ private bool WaitForUpdateAgent(IClientAPI client)
+ {
+ // Before the source region executes UpdateAgent
+ // (which triggers Scene.IncomingUpdateChildAgent(AgentData cAgentData) here in the destination,
+ // m_originRegionID is UUID.Zero; after, it's non-Zero. The CompleteMovement sequence initiated from the
+ // viewer (in turn triggered by the source region sending it a TeleportFinish event) waits until it's non-zero
+ m_updateAgentReceivedAfterTransferEvent.WaitOne(10000);
+
+ UUID originID = UUID.Zero;
+
+ lock (m_originRegionIDAccessLock)
+ originID = m_originRegionID;
+
+ if (originID.Equals(UUID.Zero))
+ {
+ // Movement into region will fail
+ m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived in {1}", client.Name, Scene.Name);
+ return false;
+ }
+
+ return true;
+ }
+
///
/// Complete Avatar's movement into the region.
///
@@ -1131,74 +1706,131 @@ namespace OpenSim.Region.Framework.Scenes
{
// DateTime startTime = DateTime.Now;
- m_log.DebugFormat(
+ m_log.InfoFormat(
"[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}",
- client.Name, Scene.RegionInfo.RegionName, AbsolutePosition);
+ client.Name, Scene.Name, AbsolutePosition);
- Vector3 look = Velocity;
+ bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); // Get this ahead of time because IsInTransit modifies 'm_AgentControlFlags'
- if ((look.X == 0) && (look.Y == 0) && (look.Z == 0))
+ IsInTransit = true;
+ try
{
- look = new Vector3(0.99f, 0.042f, 0);
- }
+ // Make sure it's not a login agent. We don't want to wait for updates during login
+ if (!(PresenceType == PresenceType.Npc || IsRealLogin(m_teleportFlags)))
+ {
+ // Let's wait until UpdateAgent (called by departing region) is done
+ if (!WaitForUpdateAgent(client))
+ // The sending region never sent the UpdateAgent data, we have to refuse
+ return;
+ }
- // Prevent teleporting to an underground location
- // (may crash client otherwise)
- //
- Vector3 pos = AbsolutePosition;
- float ground = m_scene.GetGroundHeight(pos.X, pos.Y);
- if (pos.Z < ground + 1.5f)
- {
- pos.Z = ground + 1.5f;
- AbsolutePosition = pos;
- }
+ Vector3 look = Velocity;
- bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0);
- MakeRootAgent(AbsolutePosition, flying);
- ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look);
+ // if ((look.X == 0) && (look.Y == 0) && (look.Z == 0))
+ if ((Math.Abs(look.X) < 0.1) && (Math.Abs(look.Y) < 0.1) && (Math.Abs(look.Z) < 0.1))
+ {
+ look = new Vector3(0.99f, 0.042f, 0);
+ }
-// m_log.DebugFormat("[SCENE PRESENCE] Completed movement");
+ // Prevent teleporting to an underground location
+ // (may crash client otherwise)
+ //
+ Vector3 pos = AbsolutePosition;
+ float ground = m_scene.GetGroundHeight(pos.X, pos.Y);
+ if (pos.Z < ground + 1.5f)
+ {
+ pos.Z = ground + 1.5f;
+ AbsolutePosition = pos;
+ }
- if ((m_callbackURI != null) && !m_callbackURI.Equals(""))
- {
- // We cannot sleep here since this would hold up the inbound packet processing thread, as
- // CompleteMovement() is executed synchronously. However, it might be better to delay the release
- // here until we know for sure that the agent is active in this region. Sending AgentMovementComplete
- // is not enough for Imprudence clients - there appears to be a small delay (<200ms, <500ms) until they regard this
- // region as the current region, meaning that a close sent before then will fail the teleport.
-// System.Threading.Thread.Sleep(2000);
+ if (!MakeRootAgent(AbsolutePosition, flying))
+ {
+ m_log.DebugFormat(
+ "[SCENE PRESENCE]: Aborting CompleteMovement call for {0} in {1} as they are already root",
+ Name, Scene.Name);
- m_log.DebugFormat(
- "[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}",
- client.Name, client.AgentId, m_callbackURI);
+ return;
+ }
- Scene.SimulationService.ReleaseAgent(m_originRegionID, UUID, m_callbackURI);
- m_callbackURI = null;
- }
-// else
-// {
-// m_log.DebugFormat(
-// "[SCENE PRESENCE]: No callback provided on CompleteMovement of {0} {1} to {2}",
-// client.Name, client.AgentId, m_scene.RegionInfo.RegionName);
-// }
+ // Tell the client that we're totally ready
+ ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look);
- ValidateAndSendAppearanceAndAgentData();
+ // Child agents send initial data up in LLUDPServer.HandleUseCircuitCode()
+ if (!SentInitialDataToClient)
+ SendInitialDataToClient();
- // Create child agents in neighbouring regions
- if (openChildAgents && !IsChildAgent)
- {
- IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface();
- if (m_agentTransfer != null)
- Util.FireAndForget(delegate { m_agentTransfer.EnableChildAgents(this); });
+ // m_log.DebugFormat("[SCENE PRESENCE] Completed movement");
+
+ if (!string.IsNullOrEmpty(m_callbackURI))
+ {
+ // We cannot sleep here since this would hold up the inbound packet processing thread, as
+ // CompleteMovement() is executed synchronously. However, it might be better to delay the release
+ // here until we know for sure that the agent is active in this region. Sending AgentMovementComplete
+ // is not enough for Imprudence clients - there appears to be a small delay (<200ms, <500ms) until they regard this
+ // region as the current region, meaning that a close sent before then will fail the teleport.
+ // System.Threading.Thread.Sleep(2000);
+
+ m_log.DebugFormat(
+ "[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}",
+ client.Name, client.AgentId, m_callbackURI);
+
+ Scene.SimulationService.ReleaseAgent(m_originRegionID, UUID, m_callbackURI);
+ m_callbackURI = null;
+ }
+ // else
+ // {
+ // m_log.DebugFormat(
+ // "[SCENE PRESENCE]: No callback provided on CompleteMovement of {0} {1} to {2}",
+ // client.Name, client.AgentId, m_scene.RegionInfo.RegionName);
+ // }
+
+ ValidateAndSendAppearanceAndAgentData();
+
+ // Create child agents in neighbouring regions
+ if (openChildAgents && !IsChildAgent)
+ {
+ IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface();
+ if (m_agentTransfer != null)
+ {
+ // Note: this call can take a while, because it notifies each of the simulator's neighbours.
+ // It's important that we don't allow the avatar to cross regions meanwhile, as that will
+ // cause serious errors. We've prevented that from happening by setting IsInTransit=true.
+ m_agentTransfer.EnableChildAgents(this);
+ }
+
+ IFriendsModule friendsModule = m_scene.RequestModuleInterface();
+ if (friendsModule != null)
+ friendsModule.SendFriendsOnlineIfNeeded(ControllingClient);
+
+ }
- IFriendsModule friendsModule = m_scene.RequestModuleInterface();
- if (friendsModule != null)
- friendsModule.SendFriendsOnlineIfNeeded(ControllingClient);
+ // XXX: If we force an update after activity has completed, then multiple attachments do appear correctly on a destination region
+ // If we do it a little bit earlier (e.g. when converting the child to a root agent) then this does not work.
+ // This may be due to viewer code or it may be something we're not doing properly simulator side.
+ WorkManager.RunJob(
+ "ScheduleAttachmentsForFullUpdate",
+ o => ScheduleAttachmentsForFullUpdate(),
+ null,
+ string.Format("Schedule attachments for full update for {0} in {1}", Name, Scene.Name),
+ true);
+
+ // m_log.DebugFormat(
+ // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms",
+ // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds);
}
+ finally
+ {
+ IsInTransit = false;
+ }
+ }
-// m_log.DebugFormat(
-// "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms",
-// client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds);
+ private void ScheduleAttachmentsForFullUpdate()
+ {
+ lock (m_attachments)
+ {
+ foreach (SceneObjectGroup sog in m_attachments)
+ sog.ScheduleGroupForFullUpdate();
+ }
}
///
@@ -1209,36 +1841,69 @@ namespace OpenSim.Region.Framework.Scenes
///
///
///
+ ///
+
+ private void UpdateCameraCollisionPlane(Vector4 plane)
+ {
+ if (m_lastCameraCollisionPlane != plane)
+ {
+ m_lastCameraCollisionPlane = plane;
+ ControllingClient.SendCameraConstraint(plane);
+ }
+ }
+
public void RayCastCameraCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 pNormal)
{
const float POSITION_TOLERANCE = 0.02f;
- const float VELOCITY_TOLERANCE = 0.02f;
const float ROTATION_TOLERANCE = 0.02f;
- if (m_followCamAuto)
+ m_doingCamRayCast = false;
+ if (hitYN && localid != LocalId)
{
- if (hitYN)
+ SceneObjectGroup group = m_scene.GetGroupByPrim(localid);
+ bool IsPrim = group != null;
+ if (IsPrim)
{
- CameraConstraintActive = true;
- //m_log.DebugFormat("[RAYCASTRESULT]: {0}, {1}, {2}, {3}", hitYN, collisionPoint, localid, distance);
-
- Vector3 normal = Vector3.Normalize(new Vector3(0f, 0f, collisionPoint.Z) - collisionPoint);
- ControllingClient.SendCameraConstraint(new Vector4(normal.X, normal.Y, normal.Z, -1 * Vector3.Distance(new Vector3(0,0,collisionPoint.Z),collisionPoint)));
+ SceneObjectPart part = group.GetPart(localid);
+ if (part != null && !part.VolumeDetectActive)
+ {
+ CameraConstraintActive = true;
+ pNormal.X = (float) Math.Round(pNormal.X, 2);
+ pNormal.Y = (float) Math.Round(pNormal.Y, 2);
+ pNormal.Z = (float) Math.Round(pNormal.Z, 2);
+ pNormal.Normalize();
+ collisionPoint.X = (float) Math.Round(collisionPoint.X, 1);
+ collisionPoint.Y = (float) Math.Round(collisionPoint.Y, 1);
+ collisionPoint.Z = (float) Math.Round(collisionPoint.Z, 1);
+
+ Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z,
+ Vector3.Dot(collisionPoint, pNormal));
+ UpdateCameraCollisionPlane(plane);
+ }
}
else
{
- if (!m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) ||
- !Velocity.ApproxEquals(m_lastVelocity, VELOCITY_TOLERANCE) ||
- !Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE))
- {
- if (CameraConstraintActive)
- {
- ControllingClient.SendCameraConstraint(new Vector4(0f, 0.5f, 0.9f, -3000f));
- CameraConstraintActive = false;
- }
- }
+ CameraConstraintActive = true;
+ pNormal.X = (float) Math.Round(pNormal.X, 2);
+ pNormal.Y = (float) Math.Round(pNormal.Y, 2);
+ pNormal.Z = (float) Math.Round(pNormal.Z, 2);
+ pNormal.Normalize();
+ collisionPoint.X = (float) Math.Round(collisionPoint.X, 1);
+ collisionPoint.Y = (float) Math.Round(collisionPoint.Y, 1);
+ collisionPoint.Z = (float) Math.Round(collisionPoint.Z, 1);
+
+ Vector4 plane = new Vector4(pNormal.X, pNormal.Y, pNormal.Z,
+ Vector3.Dot(collisionPoint, pNormal));
+ UpdateCameraCollisionPlane(plane);
}
}
+ else if (!m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) ||
+ !Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE))
+ {
+ Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -9000f); // not right...
+ UpdateCameraCollisionPlane(plane);
+ CameraConstraintActive = false;
+ }
}
///
@@ -1248,18 +1913,14 @@ namespace OpenSim.Region.Framework.Scenes
{
// m_log.DebugFormat(
// "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}",
-// Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags);
+// Scene.Name, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags);
if (IsChildAgent)
{
- // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent");
+// m_log.DebugFormat("DEBUG: HandleAgentUpdate: child agent in {0}", Scene.Name);
return;
}
- ++m_movementUpdateCount;
- if (m_movementUpdateCount < 1)
- m_movementUpdateCount = 1;
-
#region Sanity Checking
// This is irritating. Really.
@@ -1290,36 +1951,20 @@ namespace OpenSim.Region.Framework.Scenes
AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags;
- // Camera location in world. We'll need to raytrace
- // from this location from time to time.
- CameraPosition = agentData.CameraCenter;
- if (Vector3.Distance(m_lastCameraPosition, CameraPosition) >= Scene.RootReprioritizationDistance)
- {
- ReprioritizeUpdates();
- m_lastCameraPosition = CameraPosition;
- }
-
- // Use these three vectors to figure out what the agent is looking at
- // Convert it to a Matrix and/or Quaternion
- CameraAtAxis = agentData.CameraAtAxis;
- CameraLeftAxis = agentData.CameraLeftAxis;
- CameraUpAxis = agentData.CameraUpAxis;
-
// The Agent's Draw distance setting
// When we get to the point of re-computing neighbors everytime this
// changes, then start using the agent's drawdistance rather than the
// region's draw distance.
- // DrawDistance = agentData.Far;
- DrawDistance = Scene.DefaultDrawDistance;
-
- // Check if Client has camera in 'follow cam' or 'build' mode.
- Vector3 camdif = (Vector3.One * Rotation - Vector3.One * CameraRotation);
-
- m_followCamAuto = ((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.98f)
- && (Math.Abs(camdif.X) < 0.4f && Math.Abs(camdif.Y) < 0.4f)) ? true : false;
+ DrawDistance = agentData.Far;
+ // DrawDistance = Scene.DefaultDrawDistance;
m_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0;
- m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0;
+
+ // FIXME: This does not work as intended because the viewer only sends the lbutton down when the button
+ // is first pressed, not whilst it is held down. If this is required in the future then need to look
+ // for an AGENT_CONTROL_LBUTTON_UP event and make sure to handle cases where an initial DOWN is not
+ // received (e.g. on holding LMB down on the avatar in a viewer).
+// m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0;
#endregion Inputs
@@ -1337,14 +1982,38 @@ namespace OpenSim.Region.Framework.Scenes
StandUp();
}
- //m_log.DebugFormat("[FollowCam]: {0}", m_followCamAuto);
// Raycast from the avatar's head to the camera to see if there's anything blocking the view
- if ((m_movementUpdateCount % NumMovementsBetweenRayCast) == 0 && m_scene.PhysicsScene.SupportsRayCast())
+ // this exclude checks may not be complete
+
+ if (m_movementUpdateCount % NumMovementsBetweenRayCast == 0 && m_scene.PhysicsScene.SupportsRayCast())
{
- if (m_followCamAuto)
+ if (!m_doingCamRayCast && !m_mouseLook && ParentID == 0)
{
- Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT;
- m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback);
+ Vector3 posAdjusted = AbsolutePosition;
+// posAdjusted.Z += 0.5f * Appearance.AvatarSize.Z - 0.5f;
+ posAdjusted.Z += 1.0f; // viewer current camera focus point
+ Vector3 tocam = CameraPosition - posAdjusted;
+ tocam.X = (float)Math.Round(tocam.X, 1);
+ tocam.Y = (float)Math.Round(tocam.Y, 1);
+ tocam.Z = (float)Math.Round(tocam.Z, 1);
+
+ float distTocamlen = tocam.Length();
+ if (distTocamlen > 0.3f)
+ {
+ tocam *= (1.0f / distTocamlen);
+ posAdjusted.X = (float)Math.Round(posAdjusted.X, 1);
+ posAdjusted.Y = (float)Math.Round(posAdjusted.Y, 1);
+ posAdjusted.Z = (float)Math.Round(posAdjusted.Z, 1);
+
+ m_doingCamRayCast = true;
+ m_scene.PhysicsScene.RaycastWorld(posAdjusted, tocam, distTocamlen + 1.0f, RayCastCameraCallback);
+ }
+ }
+ else if (CameraConstraintActive && (m_mouseLook || ParentID != 0))
+ {
+ Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -10000f); // not right...
+ UpdateCameraCollisionPlane(plane);
+ CameraConstraintActive = false;
}
}
@@ -1358,9 +2027,16 @@ namespace OpenSim.Region.Framework.Scenes
// Here's where you get them.
m_AgentControlFlags = flags;
m_headrotation = agentData.HeadRotation;
+ byte oldState = State;
State = agentData.State;
+ // We need to send this back to the client in order to stop the edit beams
+ if ((oldState & (uint)AgentState.Editing) != 0 && State == (uint)AgentState.None)
+ ControllingClient.SendAgentTerseUpdate(this);
+
PhysicsActor actor = PhysicsActor;
+
+ // This will be the case if the agent is sitting on the groudn or on an object.
if (actor == null)
{
SendControlsToScripts(flagsForScripts);
@@ -1369,17 +2045,26 @@ namespace OpenSim.Region.Framework.Scenes
if (AllowMovement && !SitGround)
{
- Quaternion bodyRotation = agentData.BodyRotation;
+// m_log.DebugFormat("[SCENE PRESENCE]: Initial body rotation {0} for {1}", agentData.BodyRotation, Name);
+
bool update_rotation = false;
- if (bodyRotation != Rotation)
+ if (agentData.BodyRotation != Rotation)
{
- Rotation = bodyRotation;
+ Rotation = agentData.BodyRotation;
update_rotation = true;
}
bool update_movementflag = false;
+ // If we were just made root agent then we must perform movement updates for the first AgentUpdate that
+ // we get
+ if (MovementFlag == ForceUpdateMovementFlagValue)
+ {
+ MovementFlag = 0;
+ update_movementflag = true;
+ }
+
if (agentData.UseClientAgentPosition)
{
MovingToTarget = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f;
@@ -1411,19 +2096,7 @@ namespace OpenSim.Region.Framework.Scenes
{
bool bAllowUpdateMoveToPosition = false;
- Vector3[] dirVectors;
-
- // use camera up angle when in mouselook and not flying or when holding the left mouse button down and not flying
- // this prevents 'jumping' in inappropriate situations.
- if (!Flying && (m_mouseLook || m_leftButtonDown))
- dirVectors = GetWalkDirectionVectors();
- else
- dirVectors = Dir_Vectors;
-
- // The fact that MovementFlag is a byte needs to be fixed
- // it really should be a uint
// A DIR_CONTROL_FLAG occurs when the user is trying to move in a particular direction.
- uint nudgehack = 250;
foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS)
{
if (((uint)flags & (uint)DCF) != 0)
@@ -1432,7 +2105,9 @@ namespace OpenSim.Region.Framework.Scenes
try
{
- agent_control_v3 += dirVectors[i];
+ // Don't slide against ground when crouching if camera is panned around avatar
+ if (Flying || DCF != Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN)
+ agent_control_v3 += Dir_Vectors[i];
//m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]);
}
catch (IndexOutOfRangeException)
@@ -1440,29 +2115,19 @@ namespace OpenSim.Region.Framework.Scenes
// Why did I get this?
}
- if ((MovementFlag & (byte)(uint)DCF) == 0)
- {
- if (DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE ||
- DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT_NUDGE)
- {
- MovementFlag |= (byte)nudgehack;
- }
-
+ if (((MovementFlag & (uint)DCF) == 0) & !AgentControlStopActive)
+ {
//m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with {1}", Name, DCF);
- MovementFlag += (byte)(uint)DCF;
+ MovementFlag += (uint)DCF;
update_movementflag = true;
}
}
else
{
- if ((MovementFlag & (byte)(uint)DCF) != 0 ||
- ((DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_BACKWARD_NUDGE ||
- DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT_NUDGE || DCF == Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT_NUDGE)
- && ((MovementFlag & (byte)nudgehack) == nudgehack))
- ) // This or is for Nudge forward
+ if ((MovementFlag & (uint)DCF) != 0)
{
//m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with lack of {1}", Name, DCF);
- MovementFlag -= ((byte)(uint)DCF);
+ MovementFlag -= (uint)DCF;
update_movementflag = true;
/*
@@ -1482,6 +2147,13 @@ namespace OpenSim.Region.Framework.Scenes
i++;
}
+ // Detect AGENT_CONTROL_STOP state changes
+ if (AgentControlStopActive != ((flags & AgentManager.ControlFlags.AGENT_CONTROL_STOP) != 0))
+ {
+ AgentControlStopActive = !AgentControlStopActive;
+ update_movementflag = true;
+ }
+
if (MovingToTarget)
{
// 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
// Only do this if we're flying
if (Flying && !ForceFly)
{
- // Landing detection code
+ // Need to stop in mid air if user holds down AGENT_CONTROL_STOP
+ if (AgentControlStopActive)
+ {
+ agent_control_v3 = Vector3.Zero;
+ }
+ else
+ {
+ // Landing detection code
- // Are the landing controls requirements filled?
- bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) ||
- ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
+ // Are the landing controls requirements filled?
+ bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) ||
+ ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
- if (Flying && IsColliding && controlland)
- {
- // nesting this check because LengthSquared() is expensive and we don't
- // want to do it every step when flying.
- if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX))
- StopFlying();
+ //m_log.Debug("[CONTROL]: " +flags);
+ // Applies a satisfying roll effect to the avatar when flying.
+ if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0 && (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0)
+ {
+ ApplyFlyingRoll(
+ FLY_ROLL_RADIANS_PER_UPDATE,
+ (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0,
+ (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0);
+ }
+ else if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0 &&
+ (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0)
+ {
+ ApplyFlyingRoll(
+ -FLY_ROLL_RADIANS_PER_UPDATE,
+ (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0,
+ (flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0);
+ }
+ else
+ {
+ if (m_AngularVelocity.Z != 0)
+ m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE);
+ }
+
+ if (Flying && IsColliding && controlland)
+ {
+ // nesting this check because LengthSquared() is expensive and we don't
+ // want to do it every step when flying.
+ if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX))
+ StopFlying();
+ }
}
}
+// m_log.DebugFormat("[SCENE PRESENCE]: MovementFlag {0} for {1}", MovementFlag, Name);
+
// If the agent update does move the avatar, then calculate the force ready for the velocity update,
// which occurs later in the main scene loop
- if (update_movementflag || (update_rotation && DCFlagKeyPressed))
+ // We also need to update if the user rotates their avatar whilst it is slow walking/running (if they
+ // held down AGENT_CONTROL_STOP whilst normal walking/running). However, we do not want to update
+ // if the user rotated whilst holding down AGENT_CONTROL_STOP when already still (which locks the
+ // avatar location in place).
+ if (update_movementflag
+ || (update_rotation && DCFlagKeyPressed && (!AgentControlStopActive || MovementFlag != 0)))
{
-// m_log.DebugFormat(
-// "[SCENE PRESENCE]: In {0} adding velocity of {1} to {2}, umf = {3}, ur = {4}",
-// m_scene.RegionInfo.RegionName, agent_control_v3, Name, update_movementflag, update_rotation);
+// if (update_movementflag || !AgentControlStopActive || MovementFlag != 0)
+// {
+// m_log.DebugFormat(
+// "[SCENE PRESENCE]: In {0} adding velocity of {1} to {2}, umf = {3}, mf = {4}, ur = {5}",
+// m_scene.RegionInfo.RegionName, agent_control_v3, Name,
+// update_movementflag, MovementFlag, update_rotation);
+
+ float speedModifier;
+
+ if (AgentControlStopActive)
+ speedModifier = AgentControlStopSlowWhilstMoving;
+ else
+ speedModifier = 1;
- AddNewMovement(agent_control_v3);
+ AddNewMovement(agent_control_v3, speedModifier);
+// }
}
// else
// {
@@ -1543,15 +2264,86 @@ namespace OpenSim.Region.Framework.Scenes
// }
if (update_movementflag && ParentID == 0)
+ {
+// m_log.DebugFormat("[SCENE PRESENCE]: Updating movement animations for {0}", Name);
Animator.UpdateMovementAnimations();
+ }
SendControlsToScripts(flagsForScripts);
}
+ // We need to send this back to the client in order to see the edit beams
+ if ((State & (uint)AgentState.Editing) != 0)
+ ControllingClient.SendAgentTerseUpdate(this);
+
m_scene.EventManager.TriggerOnClientMovement(this);
- TriggerScenePresenceUpdated();
}
+
+ ///
+ /// This is the event handler for client cameras. If a client is moving, or moving the camera, this event is triggering.
+ ///
+ private void HandleAgentCamerasUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
+ {
+ //m_log.DebugFormat(
+ // "[SCENE PRESENCE]: In {0} received agent camera update from {1}, flags {2}",
+ // Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags);
+
+ if (IsChildAgent)
+ {
+ // // m_log.Debug("DEBUG: HandleAgentUpdate: child agent");
+ return;
+ }
+
+ ++m_movementUpdateCount;
+ if (m_movementUpdateCount < 1)
+ m_movementUpdateCount = 1;
+
+// AgentManager.ControlFlags flags = (AgentManager.ControlFlags)agentData.ControlFlags;
+
+ // Camera location in world. We'll need to raytrace
+ // from this location from time to time.
+ CameraPosition = agentData.CameraCenter;
+ if (Vector3.Distance(m_lastCameraPosition, CameraPosition) >= Scene.RootReprioritizationDistance)
+ {
+ ReprioritizeUpdates();
+ m_lastCameraPosition = CameraPosition;
+ }
+
+ // Use these three vectors to figure out what the agent is looking at
+ // Convert it to a Matrix and/or Quaternion
+ CameraAtAxis = agentData.CameraAtAxis;
+ CameraLeftAxis = agentData.CameraLeftAxis;
+ CameraUpAxis = agentData.CameraUpAxis;
+
+ // The Agent's Draw distance setting
+ // When we get to the point of re-computing neighbors everytime this
+ // changes, then start using the agent's drawdistance rather than the
+ // region's draw distance.
+ DrawDistance = agentData.Far;
+ // DrawDistance = Scene.DefaultDrawDistance;
+
+ // Check if Client has camera in 'follow cam' or 'build' mode.
+ Vector3 camdif = (Vector3.One * Rotation - Vector3.One * CameraRotation);
+
+ m_followCamAuto = ((CameraUpAxis.Z > 0.959f && CameraUpAxis.Z < 0.98f)
+ && (Math.Abs(camdif.X) < 0.4f && Math.Abs(camdif.Y) < 0.4f)) ? true : false;
+
+
+ //m_log.DebugFormat("[FollowCam]: {0}", m_followCamAuto);
+ // Raycast from the avatar's head to the camera to see if there's anything blocking the view
+ if ((m_movementUpdateCount % NumMovementsBetweenRayCast) == 0 && m_scene.PhysicsScene.SupportsRayCast())
+ {
+ if (m_followCamAuto)
+ {
+ Vector3 posAdjusted = m_pos + HEAD_ADJUSTMENT;
+ m_scene.PhysicsScene.RaycastWorld(m_pos, Vector3.Normalize(CameraPosition - posAdjusted), Vector3.Distance(CameraPosition, posAdjusted) + 0.3f, RayCastCameraCallback);
+ }
+ }
+
+ TriggerScenePresenceUpdated();
+ }
+
///
/// Calculate an update to move the presence to the set target.
///
@@ -1706,13 +2498,15 @@ namespace OpenSim.Region.Framework.Scenes
if (regionCombinerModule != null)
regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID);
else
- regionSize = new Vector2(Constants.RegionSize);
+ regionSize = new Vector2(m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY);
if (pos.X < 0 || pos.X >= regionSize.X
|| pos.Y < 0 || pos.Y >= regionSize.Y
|| pos.Z < 0)
return;
+ Scene targetScene = m_scene;
+
// Vector3 heightAdjust = new Vector3(0, 0, Appearance.AvatarHeight / 2);
// pos += heightAdjust;
//
@@ -1724,15 +2518,23 @@ namespace OpenSim.Region.Framework.Scenes
// }
// Get terrain height for sub-region in a megaregion if necessary
- int X = (int)((m_scene.RegionInfo.RegionLocX * Constants.RegionSize) + pos.X);
- int Y = (int)((m_scene.RegionInfo.RegionLocY * Constants.RegionSize) + pos.Y);
- UUID target_regionID = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y).RegionID;
- Scene targetScene = m_scene;
- if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene))
- targetScene = m_scene;
+ //COMMENT: If its only nessesary in a megaregion, why do it on normal region's too?
+
+ if (regionCombinerModule != null)
+ {
+ int x = (int)((m_scene.RegionInfo.WorldLocX) + pos.X);
+ int y = (int)((m_scene.RegionInfo.WorldLocY) + pos.Y);
+ GridRegion target_region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, x, y);
+
+ // If X and Y is NaN, target_region will be null
+ if (target_region == null)
+ return;
+
+ SceneManager.Instance.TryGetScene(target_region.RegionID, out targetScene);
+ }
- float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % Constants.RegionSize), (int)(pos.Y % Constants.RegionSize)];
+ float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % regionSize.X), (int)(pos.Y % regionSize.Y)];
pos.Z = Math.Max(terrainHeight, pos.Z);
// 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
if (pos.Z - terrainHeight < 0.2)
pos.Z = terrainHeight;
-// m_log.DebugFormat(
-// "[SCENE PRESENCE]: Avatar {0} set move to target {1} (terrain height {2}) in {3}",
-// Name, pos, terrainHeight, m_scene.RegionInfo.RegionName);
-
if (noFly)
Flying = false;
else if (pos.Z > terrainHeight)
Flying = true;
+// m_log.DebugFormat(
+// "[SCENE PRESENCE]: Avatar {0} set move to target {1} (terrain height {2}) in {3}",
+// Name, pos, terrainHeight, m_scene.RegionInfo.RegionName);
+
+ if (noFly)
+ Flying = false;
+
LandAtTarget = landAtTarget;
MovingToTarget = true;
MoveToPositionTarget = pos;
@@ -1782,7 +2587,8 @@ namespace OpenSim.Region.Framework.Scenes
// m_log.DebugFormat("[SCENE PRESENCE]: Resetting move to target for {0}", Name);
MovingToTarget = false;
- MoveToPositionTarget = Vector3.Zero;
+// MoveToPositionTarget = Vector3.Zero;
+ m_forceToApply = null; // cancel possible last action
// We need to reset the control flag as the ScenePresenceAnimator uses this to determine the correct
// 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
{
// m_log.DebugFormat("[SCENE PRESENCE]: StandUp() for {0}", Name);
+ bool satOnObject = IsSatOnObject;
+ SceneObjectPart part = ParentPart;
SitGround = false;
- if (PhysicsActor == null)
- AddToPhysicalScene(false);
- if (ParentID != 0)
+ if (satOnObject)
{
- SceneObjectPart part = ParentPart;
+ PrevSitOffset = m_pos; // Save sit offset
+ UnRegisterSeatControls(part.ParentGroup.UUID);
+
TaskInventoryDictionary taskIDict = part.TaskInventory;
if (taskIDict != null)
{
@@ -1821,24 +2629,70 @@ namespace OpenSim.Region.Framework.Scenes
}
}
- ParentPosition = part.GetWorldPosition();
ControllingClient.SendClearFollowCamProperties(part.ParentUUID);
- m_pos += ParentPosition + new Vector3(0.0f, 0.0f, 2.0f * m_sitAvatarHeight);
- ParentPosition = Vector3.Zero;
-
ParentID = 0;
ParentPart = null;
- SendAvatarDataToAllAgents();
+
+ Quaternion standRotation;
+
+ if (part.SitTargetAvatar == UUID)
+ {
+ standRotation = part.GetWorldRotation();
+
+ if (!part.IsRoot)
+ standRotation = standRotation * part.SitTargetOrientation;
+// standRotation = part.RotationOffset * part.SitTargetOrientation;
+// else
+// standRotation = part.SitTargetOrientation;
+
+ }
+ else
+ {
+ standRotation = Rotation;
+ }
+
+ //Vector3 standPos = ParentPosition + new Vector3(0.0f, 0.0f, 2.0f * m_sitAvatarHeight);
+ //Vector3 standPos = ParentPosition;
+
+// Vector3 standPositionAdjustment
+// = part.SitTargetPosition + new Vector3(0.5f, 0f, m_sitAvatarHeight / 2f);
+ Vector3 adjustmentForSitPosition = OffsetPosition * part.ParentGroup.GroupRotation - SIT_TARGET_ADJUSTMENT * part.GetWorldRotation();
+
+ // XXX: This is based on the physics capsule sizes. Need to find a better way to read this rather than
+ // hardcoding here.
+ Vector3 adjustmentForSitPose = new Vector3(0.74f, 0f, 0f) * standRotation;
+
+ Vector3 standPos = part.ParentGroup.AbsolutePosition + adjustmentForSitPosition + adjustmentForSitPose;
+
+// m_log.DebugFormat(
+// "[SCENE PRESENCE]: Setting stand to pos {0}, (adjustmentForSitPosition {1}, adjustmentForSitPose {2}) rotation {3} for {4} in {5}",
+// standPos, adjustmentForSitPosition, adjustmentForSitPose, standRotation, Name, Scene.Name);
+
+ Rotation = standRotation;
+ AbsolutePosition = standPos;
+ }
+
+ // We need to wait until we have calculated proper stand positions before sitting up the physical
+ // avatar to avoid race conditions.
+ if (PhysicsActor == null)
+ AddToPhysicalScene(false);
+
+ if (satOnObject)
+ {
+ SendAvatarDataToAllClients();
m_requestedSitTargetID = 0;
- part.RemoveSittingAvatar(UUID);
+ part.RemoveSittingAvatar(this);
- if (part != null)
- part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK);
+ part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK);
}
+ else if (PhysicsActor == null)
+ AddToPhysicalScene(false);
+
Animator.TrySetMovementAnimation("STAND");
+ TriggerScenePresenceUpdated();
}
private SceneObjectPart FindNextAvailableSitTarget(UUID targetID)
@@ -1885,14 +2739,10 @@ namespace OpenSim.Region.Framework.Scenes
if (part == null)
return;
- // TODO: determine position to sit at based on scene geometry; don't trust offset from client
- // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it
-
if (PhysicsActor != null)
- m_sitAvatarHeight = PhysicsActor.Size.Z;
+ m_sitAvatarHeight = PhysicsActor.Size.Z * 0.5f;
bool canSit = false;
- Vector3 pos = part.AbsolutePosition + offset;
if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero)
{
@@ -1902,45 +2752,88 @@ namespace OpenSim.Region.Framework.Scenes
offset = part.SitTargetPosition;
sitOrientation = part.SitTargetOrientation;
+
+ if (!part.IsRoot)
+ {
+ // m_log.DebugFormat("Old sit orient {0}", sitOrientation);
+ sitOrientation = part.RotationOffset * sitOrientation;
+ // m_log.DebugFormat("New sit orient {0}", sitOrientation);
+// m_log.DebugFormat("Old sit offset {0}", offset);
+ offset = offset * part.RotationOffset;
+// m_log.DebugFormat("New sit offset {0}", offset);
+ }
+
canSit = true;
}
else
{
+ if (PhysicsSit(part,offset)) // physics engine
+ return;
+
+ Vector3 pos = part.AbsolutePosition + offset;
+
if (Util.GetDistanceTo(AbsolutePosition, pos) <= 10)
{
-// m_log.DebugFormat(
-// "[SCENE PRESENCE]: Sitting {0} on {1} {2} because sit target is unset and within 10m",
-// Name, part.Name, part.LocalId);
-
AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight);
canSit = true;
}
-// else
-// {
-// m_log.DebugFormat(
-// "[SCENE PRESENCE]: Ignoring sit request of {0} on {1} {2} because sit target is unset and outside 10m",
-// Name, part.Name, part.LocalId);
-// }
}
if (canSit)
{
+
if (PhysicsActor != null)
{
// We can remove the physicsActor until they stand up.
RemoveFromPhysicalScene();
}
- part.AddSittingAvatar(UUID);
+ if (MovingToTarget)
+ ResetMoveToTarget();
+
+ Velocity = Vector3.Zero;
+
+ part.AddSittingAvatar(this);
cameraAtOffset = part.GetCameraAtOffset();
+
+ if (!part.IsRoot && cameraAtOffset == Vector3.Zero)
+ cameraAtOffset = part.ParentGroup.RootPart.GetCameraAtOffset();
+
+ bool cameraEyeOffsetFromRootForChild = false;
cameraEyeOffset = part.GetCameraEyeOffset();
+
+ if (!part.IsRoot && cameraEyeOffset == Vector3.Zero)
+ {
+ cameraEyeOffset = part.ParentGroup.RootPart.GetCameraEyeOffset();
+ cameraEyeOffsetFromRootForChild = true;
+ }
+
+ if ((cameraEyeOffset != Vector3.Zero && !cameraEyeOffsetFromRootForChild) || cameraAtOffset != Vector3.Zero)
+ {
+ if (!part.IsRoot)
+ {
+ cameraEyeOffset = cameraEyeOffset * part.RotationOffset;
+ cameraAtOffset += part.OffsetPosition;
+ }
+
+ cameraEyeOffset += part.OffsetPosition;
+ }
+
+// m_log.DebugFormat(
+// "[SCENE PRESENCE]: Using cameraAtOffset {0}, cameraEyeOffset {1} for sit on {2} by {3} in {4}",
+// cameraAtOffset, cameraEyeOffset, part.Name, Name, Scene.Name);
+
forceMouselook = part.GetForceMouselook();
+ // An viewer expects to specify sit positions as offsets to the root prim, even if a child prim is
+ // being sat upon.
+ offset += part.OffsetPosition;
+
ControllingClient.SendSitResponse(
- targetID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook);
+ part.ParentGroup.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook);
- m_requestedSitTargetUUID = targetID;
+ m_requestedSitTargetUUID = part.UUID;
HandleAgentSit(ControllingClient, UUID);
@@ -1952,6 +2845,9 @@ namespace OpenSim.Region.Framework.Scenes
public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset)
{
+ if (IsChildAgent)
+ return;
+
if (ParentID != 0)
{
if (ParentPart.UUID == targetID)
@@ -1965,16 +2861,8 @@ namespace OpenSim.Region.Framework.Scenes
if (part != null)
{
m_requestedSitTargetID = part.LocalId;
- m_requestedSitTargetUUID = targetID;
+ m_requestedSitTargetUUID = part.UUID;
-// m_log.DebugFormat("[SIT]: Client requested Sit Position: {0}", offset);
-
- if (m_scene.PhysicsScene.SupportsRayCast())
- {
- //m_scene.PhysicsScene.RaycastWorld(Vector3.Zero,Vector3.Zero, 0.01f,new RaycastCallback());
- //SitRayCastAvatarPosition(part);
- //return;
- }
}
else
{
@@ -1984,200 +2872,119 @@ namespace OpenSim.Region.Framework.Scenes
SendSitResponse(targetID, offset, Quaternion.Identity);
}
- /*
- public void SitRayCastAvatarPosition(SceneObjectPart part)
- {
- Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset;
- Vector3 StartRayCastPosition = AbsolutePosition;
- Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition);
- float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition);
- m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastAvatarPositionResponse);
- }
-
- public void SitRayCastAvatarPositionResponse(bool hitYN, Vector3 collisionPoint, uint localid, float pdistance, Vector3 normal)
+ // returns false if does not suport so older sit can be tried
+ public bool PhysicsSit(SceneObjectPart part, Vector3 offset)
{
- SceneObjectPart part = FindNextAvailableSitTarget(m_requestedSitTargetUUID);
- if (part != null)
- {
- if (hitYN)
- {
- if (collisionPoint.ApproxEquals(m_requestedSitOffset + part.AbsolutePosition, 0.2f))
- {
- SitRaycastFindEdge(collisionPoint, normal);
- m_log.DebugFormat("[SIT]: Raycast Avatar Position succeeded at point: {0}, normal:{1}", collisionPoint, normal);
- }
- else
- {
- SitRayCastAvatarPositionCameraZ(part);
- }
- }
- else
- {
- SitRayCastAvatarPositionCameraZ(part);
- }
- }
- else
+// TODO: Pull in these bits
+ return false;
+/*
+ if (part == null || part.ParentGroup.IsAttachment)
{
- ControllingClient.SendAlertMessage("Sit position no longer exists");
- m_requestedSitTargetUUID = UUID.Zero;
- m_requestedSitTargetID = 0;
- m_requestedSitOffset = Vector3.Zero;
+ return true;
}
- }
+ if ( m_scene.PhysicsScene == null)
+ return false;
- public void SitRayCastAvatarPositionCameraZ(SceneObjectPart part)
- {
- // Next, try to raycast from the camera Z position
- Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset;
- Vector3 StartRayCastPosition = AbsolutePosition; StartRayCastPosition.Z = CameraPosition.Z;
- Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition);
- float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition);
- m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastAvatarPositionCameraZResponse);
- }
-
- public void SitRayCastAvatarPositionCameraZResponse(bool hitYN, Vector3 collisionPoint, uint localid, float pdistance, Vector3 normal)
- {
- SceneObjectPart part = FindNextAvailableSitTarget(m_requestedSitTargetUUID);
- if (part != null)
+ if (part.PhysActor == null)
{
- if (hitYN)
- {
- if (collisionPoint.ApproxEquals(m_requestedSitOffset + part.AbsolutePosition, 0.2f))
- {
- SitRaycastFindEdge(collisionPoint, normal);
- m_log.DebugFormat("[SIT]: Raycast Avatar Position + CameraZ succeeded at point: {0}, normal:{1}", collisionPoint, normal);
- }
- else
- {
- SitRayCastCameraPosition(part);
- }
- }
+ // none physcis shape
+ if (part.PhysicsShapeType == (byte)PhysicsShapeType.None)
+ ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot.");
else
- {
- SitRayCastCameraPosition(part);
+ { // non physical phantom TODO
+ ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot.");
+ return false;
}
- }
- else
- {
- ControllingClient.SendAlertMessage("Sit position no longer exists");
- m_requestedSitTargetUUID = UUID.Zero;
- m_requestedSitTargetID = 0;
- m_requestedSitOffset = Vector3.Zero;
+ return true;
}
- }
- public void SitRayCastCameraPosition(SceneObjectPart part)
- {
- // Next, try to raycast from the camera position
- Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset;
- Vector3 StartRayCastPosition = CameraPosition;
- Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition);
- float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition);
- m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastCameraPositionResponse);
- }
+ // not doing autopilot
+ m_requestedSitTargetID = 0;
- public void SitRayCastCameraPositionResponse(bool hitYN, Vector3 collisionPoint, uint localid, float pdistance, Vector3 normal)
- {
- SceneObjectPart part = FindNextAvailableSitTarget(m_requestedSitTargetUUID);
- if (part != null)
- {
- if (hitYN)
- {
- if (collisionPoint.ApproxEquals(m_requestedSitOffset + part.AbsolutePosition, 0.2f))
- {
- SitRaycastFindEdge(collisionPoint, normal);
- m_log.DebugFormat("[SIT]: Raycast Camera Position succeeded at point: {0}, normal:{1}", collisionPoint, normal);
- }
- else
- {
- SitRayHorizontal(part);
- }
- }
- else
- {
- SitRayHorizontal(part);
- }
- }
- else
- {
- ControllingClient.SendAlertMessage("Sit position no longer exists");
- m_requestedSitTargetUUID = UUID.Zero;
- m_requestedSitTargetID = 0;
- m_requestedSitOffset = Vector3.Zero;
- }
+ if (m_scene.PhysicsScene.SitAvatar(part.PhysActor, AbsolutePosition, CameraPosition, offset, new Vector3(0.35f, 0, 0.65f), PhysicsSitResponse) != 0)
+ return true;
+ return false;
+*/
}
- public void SitRayHorizontal(SceneObjectPart part)
+
+ private bool CanEnterLandPosition(Vector3 testPos)
{
- // Next, try to raycast from the avatar position to fwd
- Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset;
- Vector3 StartRayCastPosition = CameraPosition;
- Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition);
- float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition);
- m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastHorizontalResponse);
+ ILandObject land = m_scene.LandChannel.GetLandObject(testPos.X, testPos.Y);
+
+ if (land == null || land.LandData.Name == "NO_LAND")
+ return true;
+
+ return land.CanBeOnThisLand(UUID,testPos.Z);
}
- public void SitRayCastHorizontalResponse(bool hitYN, Vector3 collisionPoint, uint localid, float pdistance, Vector3 normal)
+ // status
+ // < 0 ignore
+ // 0 bad sit spot
+ public void PhysicsSitResponse(int status, uint partID, Vector3 offset, Quaternion Orientation)
{
- SceneObjectPart part = FindNextAvailableSitTarget(m_requestedSitTargetUUID);
- if (part != null)
+ if (status < 0)
+ return;
+
+ if (status == 0)
{
- if (hitYN)
- {
- if (collisionPoint.ApproxEquals(m_requestedSitOffset + part.AbsolutePosition, 0.2f))
- {
- SitRaycastFindEdge(collisionPoint, normal);
- m_log.DebugFormat("[SIT]: Raycast Horizontal Position succeeded at point: {0}, normal:{1}", collisionPoint, normal);
- // Next, try to raycast from the camera position
- Vector3 EndRayCastPosition = part.AbsolutePosition + m_requestedSitOffset;
- Vector3 StartRayCastPosition = CameraPosition;
- Vector3 direction = Vector3.Normalize(EndRayCastPosition - StartRayCastPosition);
- float distance = Vector3.Distance(EndRayCastPosition, StartRayCastPosition);
- //m_scene.PhysicsScene.RaycastWorld(StartRayCastPosition, direction, distance, SitRayCastResponseAvatarPosition);
- }
- else
- {
- ControllingClient.SendAlertMessage("Sit position not accessable.");
- m_requestedSitTargetUUID = UUID.Zero;
- m_requestedSitTargetID = 0;
- m_requestedSitOffset = Vector3.Zero;
- }
- }
- else
- {
- ControllingClient.SendAlertMessage("Sit position not accessable.");
- m_requestedSitTargetUUID = UUID.Zero;
- m_requestedSitTargetID = 0;
- m_requestedSitOffset = Vector3.Zero;
- }
+ ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot.");
+ return;
}
- else
+
+ SceneObjectPart part = m_scene.GetSceneObjectPart(partID);
+ if (part == null)
+ return;
+
+ Vector3 targetPos = part.GetWorldPosition() + offset * part.GetWorldRotation();
+ if(!CanEnterLandPosition(targetPos))
{
- ControllingClient.SendAlertMessage("Sit position no longer exists");
- m_requestedSitTargetUUID = UUID.Zero;
- m_requestedSitTargetID = 0;
- m_requestedSitOffset = Vector3.Zero;
+ ControllingClient.SendAlertMessage(" Sit position on restricted land, try another spot");
+ return;
}
- }
+ RemoveFromPhysicalScene();
- private void SitRaycastFindEdge(Vector3 collisionPoint, Vector3 collisionNormal)
- {
- int i = 0;
- //throw new NotImplementedException();
- //m_requestedSitTargetUUID = UUID.Zero;
- //m_requestedSitTargetID = 0;
- //m_requestedSitOffset = Vector3.Zero;
+ if (MovingToTarget)
+ ResetMoveToTarget();
+
+ Velocity = Vector3.Zero;
+
+ part.AddSittingAvatar(this);
+
+ Vector3 cameraAtOffset = part.GetCameraAtOffset();
+ Vector3 cameraEyeOffset = part.GetCameraEyeOffset();
+ bool forceMouselook = part.GetForceMouselook();
+
+ ControllingClient.SendSitResponse(
+ part.UUID, offset, Orientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook);
+
+ // not using autopilot
+
+ Rotation = Orientation;
+ m_pos = offset;
+
+ m_requestedSitTargetID = 0;
+
+ ParentPart = part;
+ ParentID = part.LocalId;
+ if(status == 3)
+ Animator.TrySetMovementAnimation("SIT_GROUND");
+ else
+ Animator.TrySetMovementAnimation("SIT");
+ SendAvatarDataToAllClients();
- SendSitResponse(ControllingClient, m_requestedSitTargetUUID, collisionPoint - m_requestedSitOffset, Quaternion.Identity);
+ part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK);
}
- */
public void HandleAgentSit(IClientAPI remoteClient, UUID agentID)
{
+ if (IsChildAgent)
+ return;
+
SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID);
if (part != null)
@@ -2205,23 +3012,75 @@ namespace OpenSim.Region.Framework.Scenes
//Quaternion result = (sitTargetOrient * vq) * nq;
- m_pos = sitTargetPos + SIT_TARGET_ADJUSTMENT;
- Rotation = sitTargetOrient;
- ParentPosition = part.AbsolutePosition;
+ double x, y, z, m1, m2;
+
+ Quaternion r = sitTargetOrient;
+ m1 = r.X * r.X + r.Y * r.Y;
+ m2 = r.Z * r.Z + r.W * r.W;
+
+ // Rotate the vector <0, 0, 1>
+ x = 2 * (r.X * r.Z + r.Y * r.W);
+ y = 2 * (-r.X * r.W + r.Y * r.Z);
+ z = m2 - m1;
+
+ // Set m to be the square of the norm of r.
+ double m = m1 + m2;
+
+ // This constant is emperically determined to be what is used in SL.
+ // See also http://opensimulator.org/mantis/view.php?id=7096
+ double offset = 0.05;
+
+ // Normally m will be ~ 1, but if someone passed a handcrafted quaternion
+ // to llSitTarget with values so small that squaring them is rounded off
+ // to zero, then m could be zero. The result of this floating point
+ // round off error (causing us to skip this impossible normalization)
+ // is only 5 cm.
+ if (m > 0.000001)
+ {
+ offset /= m;
+ }
+
+ Vector3 up = new Vector3((float)x, (float)y, (float)z);
+ Vector3 sitOffset = up * (float)offset;
+
+ // sitOffset is in Avatar Center coordinates: from origin to 'sitTargetPos + SIT_TARGET_ADJUSTMENT'.
+ // So, we need to _substract_ it to get to the origin of the Avatar Center.
+ Vector3 newPos = sitTargetPos + SIT_TARGET_ADJUSTMENT - sitOffset;
+ Quaternion newRot;
+
+ if (part.IsRoot)
+ {
+ newRot = sitTargetOrient;
+ }
+ else
+ {
+ newPos = newPos * part.RotationOffset;
+ newRot = part.RotationOffset * sitTargetOrient;
+ }
+
+ newPos += part.OffsetPosition;
+
+ m_pos = newPos;
+ Rotation = newRot;
+
+// ParentPosition = part.AbsolutePosition;
}
else
{
- m_pos -= part.AbsolutePosition;
- ParentPosition = part.AbsolutePosition;
+ // An viewer expects to specify sit positions as offsets to the root prim, even if a child prim is
+ // being sat upon.
+ m_pos -= part.GroupPosition;
+
+// ParentPosition = part.AbsolutePosition;
// m_log.DebugFormat(
// "[SCENE PRESENCE]: Sitting {0} at position {1} ({2} + {3}) on part {4} {5} without sit target",
// Name, part.AbsolutePosition, m_pos, ParentPosition, part.Name, part.LocalId);
}
- ParentPart = m_scene.GetSceneObjectPart(m_requestedSitTargetID);
+ ParentPart = part;
ParentID = m_requestedSitTargetID;
-
+ m_AngularVelocity = Vector3.Zero;
Velocity = Vector3.Zero;
RemoveFromPhysicalScene();
@@ -2231,14 +3090,20 @@ namespace OpenSim.Region.Framework.Scenes
sitAnimation = part.SitAnimation;
}
Animator.TrySetMovementAnimation(sitAnimation);
- SendAvatarDataToAllAgents();
+ SendAvatarDataToAllClients();
+ TriggerScenePresenceUpdated();
}
}
public void HandleAgentSitOnGround()
{
-// m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick.
+ if (IsChildAgent)
+ return;
+
+// m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick..
+ m_AngularVelocity = Vector3.Zero;
Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED");
+ TriggerScenePresenceUpdated();
SitGround = true;
RemoveFromPhysicalScene();
}
@@ -2255,22 +3120,39 @@ namespace OpenSim.Region.Framework.Scenes
public void HandleStartAnim(IClientAPI remoteClient, UUID animID)
{
Animator.AddAnimation(animID, UUID.Zero);
+ TriggerScenePresenceUpdated();
}
public void HandleStopAnim(IClientAPI remoteClient, UUID animID)
{
Animator.RemoveAnimation(animID, false);
+ TriggerScenePresenceUpdated();
}
///
/// Rotate the avatar to the given rotation and apply a movement in the given relative vector
///
/// The vector in which to move. This is relative to the rotation argument
- public void AddNewMovement(Vector3 vec)
+ ///
+ /// Optional additional speed modifier for this particular add. Default is 1
+ public void AddNewMovement(Vector3 vec, float thisAddSpeedModifier = 1)
{
-// m_log.DebugFormat("[SCENE PRESENCE]: Adding new movement {0} for {1}", vec, Name);
+// m_log.DebugFormat(
+// "[SCENE PRESENCE]: Adding new movement {0} with rotation {1}, thisAddSpeedModifier {2} for {3}",
+// vec, Rotation, thisAddSpeedModifier, Name);
- Vector3 direc = vec * Rotation;
+ Quaternion rot = Rotation;
+ if (!Flying && PresenceType != PresenceType.Npc)
+ {
+ // The only situation in which we care about X and Y is avatar flying. The rest of the time
+ // these parameters are not relevant for determining avatar movement direction and cause issues such
+ // as wrong walk speed if the camera is rotated.
+ rot.X = 0;
+ rot.Y = 0;
+ rot.Normalize();
+ }
+
+ Vector3 direc = vec * rot;
direc.Normalize();
if (Flying != FlyingOld) // add for fly velocity control
@@ -2286,7 +3168,9 @@ namespace OpenSim.Region.Framework.Scenes
if ((vec.Z == 0f) && !Flying)
direc.Z = 0f; // Prevent camera WASD up.
- direc *= 0.03f * 128f * SpeedModifier;
+ direc *= 0.03f * 128f * SpeedModifier * thisAddSpeedModifier;
+
+// m_log.DebugFormat("[SCENE PRESENCE]: Force to apply before modification was {0} for {1}", direc, Name);
if (PhysicsActor != null)
{
@@ -2315,14 +3199,17 @@ namespace OpenSim.Region.Framework.Scenes
direc.Z *= 2.6f;
// TODO: PreJump and jump happen too quickly. Many times prejump gets ignored.
- Animator.TrySetMovementAnimation("PREJUMP");
- Animator.TrySetMovementAnimation("JUMP");
+// Animator.TrySetMovementAnimation("PREJUMP");
+// Animator.TrySetMovementAnimation("JUMP");
}
}
}
+// m_log.DebugFormat("[SCENE PRESENCE]: Setting force to apply to {0} for {1}", direc, Name);
+
// TODO: Add the force instead of only setting it to support multiple forces per frame?
m_forceToApply = direc;
+ Animator.UpdateMovementAnimations();
}
#endregion
@@ -2331,25 +3218,27 @@ namespace OpenSim.Region.Framework.Scenes
public override void Update()
{
- const float ROTATION_TOLERANCE = 0.01f;
- const float VELOCITY_TOLERANCE = 0.001f;
- const float POSITION_TOLERANCE = 0.05f;
-
if (IsChildAgent == false)
{
// NOTE: Velocity is not the same as m_velocity. Velocity will attempt to
// grab the latest PhysicsActor velocity, whereas m_velocity is often
// storing a requested force instead of an actual traveling velocity
-
- // Throw away duplicate or insignificant updates
- if (
- // If the velocity has become zero, send it no matter what.
- (Velocity != m_lastVelocity && Velocity == Vector3.Zero)
- // otherwise, if things have changed reasonably, send the update
- || (!Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE)
- || !Velocity.ApproxEquals(m_lastVelocity, VELOCITY_TOLERANCE)
- || !m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE)))
-
+ if (Appearance.AvatarSize != m_lastSize && !IsLoggingIn)
+ SendAvatarDataToAllClients();
+
+ // Allow any updates for sitting avatars to that llSetPrimitiveLinkParams() can work for very
+ // small increments (e.g. sit position adjusters). An alternative may be to eliminate the tolerance
+ // checks on all updates but the ramifications of this would need careful consideration.
+ bool updateClients
+ = IsSatOnObject && (Rotation != m_lastRotation || Velocity != m_lastVelocity || m_pos != m_lastPosition);
+
+ if (!updateClients)
+ updateClients
+ = !Rotation.ApproxEquals(m_lastRotation, Scene.RootRotationUpdateTolerance)
+ || !Velocity.ApproxEquals(m_lastVelocity, Scene.RootVelocityUpdateTolerance)
+ || !m_pos.ApproxEquals(m_lastPosition, Scene.RootPositionUpdateTolerance);
+
+ if (updateClients)
{
SendTerseUpdateToAllClients();
@@ -2359,7 +3248,8 @@ namespace OpenSim.Region.Framework.Scenes
m_lastVelocity = Velocity;
}
- CheckForBorderCrossing();
+ if (Scene.AllowAvatarCrossing)
+ CheckForBorderCrossing();
CheckForSignificantMovement(); // sends update to the modules.
}
@@ -2369,7 +3259,6 @@ namespace OpenSim.Region.Framework.Scenes
#region Update Client(s)
-
///
/// Sends a location update to the client connected to this scenePresence
///
@@ -2380,6 +3269,29 @@ namespace OpenSim.Region.Framework.Scenes
// server.
if (remoteClient.IsActive)
{
+ if (Scene.RootTerseUpdatePeriod > 1)
+ {
+// Console.WriteLine(
+// "{0} {1} {2} {3} {4} {5} for {6} to {7}",
+// remoteClient.AgentId, UUID, remoteClient.SceneAgent.IsChildAgent, m_terseUpdateCount, Scene.RootTerseUpdatePeriod, Velocity.ApproxEquals(Vector3.Zero, 0.001f), Name, remoteClient.Name);
+ if (remoteClient.AgentId != UUID
+ && !remoteClient.SceneAgent.IsChildAgent
+ && m_terseUpdateCount % Scene.RootTerseUpdatePeriod != 0
+ && !Velocity.ApproxEquals(Vector3.Zero, 0.001f))
+ {
+// m_log.DebugFormat("[SCENE PRESENCE]: Discarded update from {0} to {1}, args {2} {3} {4} {5} {6} {7}",
+// Name, remoteClient.Name, remoteClient.AgentId, UUID, remoteClient.SceneAgent.IsChildAgent, m_terseUpdateCount, Scene.RootTerseUpdatePeriod, Velocity.ApproxEquals(Vector3.Zero, 0.001f));
+
+ return;
+ }
+ }
+
+ if (Scene.ChildTerseUpdatePeriod > 1
+ && remoteClient.SceneAgent.IsChildAgent
+ && m_terseUpdateCount % Scene.ChildTerseUpdatePeriod != 0
+ && !Velocity.ApproxEquals(Vector3.Zero, 0.001f))
+ return;
+
//m_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, Rotation, m_velocity);
remoteClient.SendEntityUpdate(
@@ -2417,7 +3329,11 @@ namespace OpenSim.Region.Framework.Scenes
float distanceError = Vector3.Distance(OffsetPosition, expectedPosition);
float speed = Velocity.Length();
- float velocidyDiff = Vector3.Distance(lastVelocitySentToAllClients, Velocity);
+ float velocityDiff = Vector3.Distance(lastVelocitySentToAllClients, Velocity);
+
+// m_log.DebugFormat(
+// "[SCENE PRESENCE]: Delta-v {0}, lastVelocity {1}, Velocity {2} for {3} in {4}",
+// velocidyDiff, lastVelocitySentToAllClients, Velocity, Name, Scene.Name);
// assuming 5 ms. worst case precision for timer, use 2x that
// for distance error threshold
@@ -2425,12 +3341,19 @@ namespace OpenSim.Region.Framework.Scenes
if (speed < 0.01f // allow rotation updates if avatar position is unchanged
|| Math.Abs(distanceError) > distanceErrorThreshold
- || velocidyDiff > 0.01f) // did velocity change from last update?
+ || velocityDiff > 0.01f) // did velocity change from last update?
{
+// m_log.DebugFormat(
+// "[SCENE PRESENCE]: Update triggered with speed {0}, distanceError {1}, distanceThreshold {2}, delta-v {3} for {4} in {5}",
+// speed, distanceError, distanceErrorThreshold, velocidyDiff, Name, Scene.Name);
+
lastVelocitySentToAllClients = Velocity;
lastTerseUpdateToAllClientsTick = currentTick;
lastPositionSentToAllClients = OffsetPosition;
+ m_terseUpdateCount++;
+
+// Console.WriteLine("Scheduled update for {0} in {1}", Name, Scene.Name);
m_scene.ForEachClient(SendTerseUpdateToClient);
}
TriggerScenePresenceUpdated();
@@ -2456,24 +3379,30 @@ namespace OpenSim.Region.Framework.Scenes
ControllingClient.SendCoarseLocationUpdate(avatarUUIDs, coarseLocations);
}
- public void SendInitialDataToMe()
+ public void SendInitialDataToClient()
{
+ SentInitialDataToClient = true;
+
// Send all scene object to the new client
- Util.FireAndForget(delegate
+ WorkManager.RunJob("SendInitialDataToClient", delegate
{
+// m_log.DebugFormat(
+// "[SCENE PRESENCE]: Sending initial data to {0} agent {1} in {2}, tp flags {3}",
+// IsChildAgent ? "child" : "root", Name, Scene.Name, m_teleportFlags);
+
// we created a new ScenePresence (a new child agent) in a fresh region.
// Request info about all the (root) agents in this region
// Note: This won't send data *to* other clients in that region (children don't send)
- SendOtherAgentsAvatarDataToMe();
- SendOtherAgentsAppearanceToMe();
+ SendOtherAgentsAvatarDataToClient();
+ SendOtherAgentsAppearanceToClient();
EntityBase[] entities = Scene.Entities.GetEntities();
- foreach(EntityBase e in entities)
+ foreach (EntityBase e in entities)
{
if (e != null && e is SceneObjectGroup)
((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient);
}
- });
+ }, null, string.Format("SendInitialDataToClient ({0} in {1})", Name, Scene.Name), false, true);
}
///
@@ -2506,26 +3435,33 @@ namespace OpenSim.Region.Framework.Scenes
// getting other avatars information was initiated elsewhere immediately after the child circuit connected... don't do it
// again here... this comes after the cached appearance check because the avatars
// appearance goes into the avatar update packet
- SendAvatarDataToAllAgents();
- SendAppearanceToAgent(this);
+ SendAvatarDataToAllClients();
+
+ // This invocation always shows up in the viewer logs as an error. Is it needed?
+ SendAppearanceToClient(this);
// If we are using the the cached appearance then send it out to everyone
if (cachedappearance)
{
- m_log.DebugFormat("[SCENE PRESENCE]: baked textures are in the cache for {0}", Name);
+ m_log.DebugFormat("[SCENE PRESENCE]: Baked textures are in the cache for {0} in {1}", Name, m_scene.Name);
// If the avatars baked textures are all in the cache, then we have a
// complete appearance... send it out, if not, then we'll send it when
// the avatar finishes updating its appearance
- SendAppearanceToAllOtherAgents();
+ SendAppearanceToAllOtherClients();
}
}
+ public void SendAvatarDataToAllClients()
+ {
+ SendAvatarDataToAllClients(true);
+ }
+
///
/// Send this agent's avatar data to all other root and child agents in the scene
/// This agent must be root. This avatar will receive its own update.
///
- public void SendAvatarDataToAllAgents()
+ public void SendAvatarDataToAllClients(bool full)
{
//m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAllAgents: {0} ({1})", Name, UUID);
// only send update from root agents to other clients; children are only "listening posts"
@@ -2538,12 +3474,17 @@ namespace OpenSim.Region.Framework.Scenes
return;
}
+ m_lastSize = Appearance.AvatarSize;
+
int count = 0;
m_scene.ForEachScenePresence(delegate(ScenePresence scenePresence)
- {
- SendAvatarDataToAgent(scenePresence);
- count++;
- });
+ {
+ if (full)
+ SendAvatarDataToClient(scenePresence);
+ else
+ scenePresence.ControllingClient.SendAvatarDataImmediate(this);
+ count++;
+ });
m_scene.StatsReporter.AddAgentUpdates(count);
}
@@ -2552,7 +3493,7 @@ namespace OpenSim.Region.Framework.Scenes
/// Send avatar data for all other root agents to this agent, this agent
/// can be either a child or root
///
- public void SendOtherAgentsAvatarDataToMe()
+ public void SendOtherAgentsAvatarDataToClient()
{
int count = 0;
m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence)
@@ -2561,7 +3502,7 @@ namespace OpenSim.Region.Framework.Scenes
if (scenePresence.UUID == UUID)
return;
- scenePresence.SendAvatarDataToAgent(this);
+ scenePresence.SendAvatarDataToClient(this);
count++;
});
@@ -2572,9 +3513,9 @@ namespace OpenSim.Region.Framework.Scenes
/// Send avatar data to an agent.
///
///
- public void SendAvatarDataToAgent(ScenePresence avatar)
+ public void SendAvatarDataToClient(ScenePresence avatar)
{
- //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAgent from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID);
+ //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToClient from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID);
avatar.ControllingClient.SendAvatarDataImmediate(this);
Animator.SendAnimPackToClient(avatar.ControllingClient);
@@ -2584,9 +3525,9 @@ namespace OpenSim.Region.Framework.Scenes
/// Send this agent's appearance to all other root and child agents in the scene
/// This agent must be root.
///
- public void SendAppearanceToAllOtherAgents()
+ public void SendAppearanceToAllOtherClients()
{
-// m_log.DebugFormat("[SCENE PRESENCE] SendAppearanceToAllOtherAgents: {0} {1}", Name, UUID);
+// m_log.DebugFormat("[SCENE PRESENCE] SendAppearanceToAllOtherClients: {0} {1}", Name, UUID);
// only send update from root agents to other clients; children are only "listening posts"
if (IsChildAgent)
@@ -2605,7 +3546,7 @@ namespace OpenSim.Region.Framework.Scenes
if (scenePresence.UUID == UUID)
return;
- SendAppearanceToAgent(scenePresence);
+ SendAppearanceToClient(scenePresence);
count++;
});
@@ -2616,9 +3557,9 @@ namespace OpenSim.Region.Framework.Scenes
/// Send appearance from all other root agents to this agent. this agent
/// can be either root or child
///
- public void SendOtherAgentsAppearanceToMe()
+ public void SendOtherAgentsAppearanceToClient()
{
-// m_log.DebugFormat("[SCENE PRESENCE] SendOtherAgentsAppearanceToMe: {0} {1}", Name, UUID);
+// m_log.DebugFormat("[SCENE PRESENCE] SendOtherAgentsAppearanceToClient {0} {1}", Name, UUID);
int count = 0;
m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence)
@@ -2627,7 +3568,7 @@ namespace OpenSim.Region.Framework.Scenes
if (scenePresence.UUID == UUID)
return;
- scenePresence.SendAppearanceToAgent(this);
+ scenePresence.SendAppearanceToClient(this);
count++;
});
@@ -2638,13 +3579,15 @@ namespace OpenSim.Region.Framework.Scenes
/// Send appearance data to an agent.
///
///
- public void SendAppearanceToAgent(ScenePresence avatar)
+ public void SendAppearanceToClient(ScenePresence avatar)
{
// m_log.DebugFormat(
// "[SCENE PRESENCE]: Sending appearance data from {0} {1} to {2} {3}", Name, m_uuid, avatar.Name, avatar.UUID);
avatar.ControllingClient.SendAppearance(
UUID, Appearance.VisualParams, Appearance.Texture.GetBytes());
+
+
}
#endregion
@@ -2663,11 +3606,10 @@ namespace OpenSim.Region.Framework.Scenes
}
// Minimum Draw distance is 64 meters, the Radius of the draw distance sphere is 32m
- if (Util.GetDistanceTo(AbsolutePosition, m_lastChildAgentUpdatePosition) >= Scene.ChildReprioritizationDistance ||
- Util.GetDistanceTo(CameraPosition, m_lastChildAgentUpdateCamPosition) >= Scene.ChildReprioritizationDistance)
+ if (Util.GetDistanceTo(AbsolutePosition, m_lastChildAgentUpdatePosition) >= Scene.ChildReprioritizationDistance)
{
m_lastChildAgentUpdatePosition = AbsolutePosition;
- m_lastChildAgentUpdateCamPosition = CameraPosition;
+// m_lastChildAgentUpdateCamPosition = CameraPosition;
ChildAgentDataUpdate cadu = new ChildAgentDataUpdate();
cadu.ActiveGroupID = UUID.Zero.Guid;
@@ -2694,10 +3636,11 @@ namespace OpenSim.Region.Framework.Scenes
cadu.Velocity = Velocity;
AgentPosition agentpos = new AgentPosition();
- agentpos.CopyFrom(cadu);
+ agentpos.CopyFrom(cadu, ControllingClient.SessionId);
// Let's get this out of the update loop
- Util.FireAndForget(delegate { m_scene.SendOutChildAgentUpdates(agentpos, this); });
+ Util.FireAndForget(
+ o => m_scene.SendOutChildAgentUpdates(agentpos, this), null, "ScenePresence.SendOutChildAgentUpdates");
}
}
@@ -2719,140 +3662,84 @@ namespace OpenSim.Region.Framework.Scenes
// If we don't have a PhysActor, we can't cross anyway
// Also don't do this while sat, sitting avatars cross with the
- // object they sit on.
- if (ParentID != 0 || PhysicsActor == null)
+ // object they sit on. ParentUUID denoted a pending sit, don't
+ // interfere with it.
+ if (ParentID != 0 || PhysicsActor == null || ParentUUID != UUID.Zero)
return;
- if (!IsInTransit)
- {
- Vector3 pos2 = AbsolutePosition;
- Vector3 vel = Velocity;
- int neighbor = 0;
- int[] fix = new int[2];
+ if (IsInTransit)
+ return;
- float timeStep = 0.1f;
- pos2.X = pos2.X + (vel.X * timeStep);
- pos2.Y = pos2.Y + (vel.Y * timeStep);
- pos2.Z = pos2.Z + (vel.Z * timeStep);
+ Vector3 pos2 = AbsolutePosition;
+ Vector3 origPosition = pos2;
+ Vector3 vel = Velocity;
- if (!IsInTransit)
- {
- // Checks if where it's headed exists a region
- bool needsTransit = false;
- if (m_scene.TestBorderCross(pos2, Cardinals.W))
- {
- if (m_scene.TestBorderCross(pos2, Cardinals.S))
- {
- needsTransit = true;
- neighbor = m_scene.HaveNeighbor(Cardinals.SW, ref fix);
- }
- else if (m_scene.TestBorderCross(pos2, Cardinals.N))
- {
- needsTransit = true;
- neighbor = m_scene.HaveNeighbor(Cardinals.NW, ref fix);
- }
- else
- {
- needsTransit = true;
- neighbor = m_scene.HaveNeighbor(Cardinals.W, ref fix);
- }
- }
- else if (m_scene.TestBorderCross(pos2, Cardinals.E))
- {
- if (m_scene.TestBorderCross(pos2, Cardinals.S))
- {
- needsTransit = true;
- neighbor = m_scene.HaveNeighbor(Cardinals.SE, ref fix);
- }
- else if (m_scene.TestBorderCross(pos2, Cardinals.N))
- {
- needsTransit = true;
- neighbor = m_scene.HaveNeighbor(Cardinals.NE, ref fix);
- }
- else
- {
- needsTransit = true;
- neighbor = m_scene.HaveNeighbor(Cardinals.E, ref fix);
- }
- }
- else if (m_scene.TestBorderCross(pos2, Cardinals.S))
- {
- needsTransit = true;
- neighbor = m_scene.HaveNeighbor(Cardinals.S, ref fix);
- }
- else if (m_scene.TestBorderCross(pos2, Cardinals.N))
- {
- needsTransit = true;
- neighbor = m_scene.HaveNeighbor(Cardinals.N, ref fix);
- }
+ // Compute the future avatar position.
+ // If the avatar will be crossing, we force the crossing to happen now
+ // in the hope that this will make the avatar movement smoother when crossing.
+ pos2 += vel * 0.05f;
- // Makes sure avatar does not end up outside region
- if (neighbor <= 0)
- {
- if (needsTransit)
- {
- if (m_requestedSitTargetUUID == UUID.Zero)
- {
- bool isFlying = Flying;
- RemoveFromPhysicalScene();
-
- Vector3 pos = AbsolutePosition;
- if (AbsolutePosition.X < 0)
- pos.X += Velocity.X * 2;
- else if (AbsolutePosition.X > Constants.RegionSize)
- pos.X -= Velocity.X * 2;
- if (AbsolutePosition.Y < 0)
- pos.Y += Velocity.Y * 2;
- else if (AbsolutePosition.Y > Constants.RegionSize)
- pos.Y -= Velocity.Y * 2;
- Velocity = Vector3.Zero;
- AbsolutePosition = pos;
-
-// m_log.DebugFormat("[SCENE PRESENCE]: Prevented flyoff for {0} at {1}", Name, AbsolutePosition);
-
- AddToPhysicalScene(isFlying);
- }
- }
- }
- else if (neighbor > 0)
- {
- if (!CrossToNewRegion())
- {
- if (m_requestedSitTargetUUID == UUID.Zero)
- {
- bool isFlying = Flying;
- RemoveFromPhysicalScene();
-
- Vector3 pos = AbsolutePosition;
- if (AbsolutePosition.X < 0)
- pos.X += Velocity.X * 2;
- else if (AbsolutePosition.X > Constants.RegionSize)
- pos.X -= Velocity.X * 2;
- if (AbsolutePosition.Y < 0)
- pos.Y += Velocity.Y * 2;
- else if (AbsolutePosition.Y > Constants.RegionSize)
- pos.Y -= Velocity.Y * 2;
- Velocity = Vector3.Zero;
- AbsolutePosition = pos;
-
- AddToPhysicalScene(isFlying);
- }
- }
- }
- }
- else
+ if (m_scene.PositionIsInCurrentRegion(pos2))
+ return;
+
+ m_log.DebugFormat("{0} CheckForBorderCrossing: position outside region. {1} in {2} at pos {3}",
+ LogHeader, Name, Scene.Name, pos2);
+
+ // Disconnect from the current region
+ bool isFlying = Flying;
+ RemoveFromPhysicalScene();
+
+ // pos2 is the forcasted position so make that the 'current' position so the crossing
+ // code will move us into the newly addressed region.
+ m_pos = pos2;
+
+ if (CrossToNewRegion())
+ {
+ AddToPhysicalScene(isFlying);
+ }
+ else
+ {
+ // Tried to make crossing happen but it failed.
+ if (m_requestedSitTargetUUID == UUID.Zero)
{
- // This constant has been inferred from experimentation
- // I'm not sure what this value should be, so I tried a few values.
- timeStep = 0.04f;
- pos2 = AbsolutePosition;
- pos2.X = pos2.X + (vel.X * timeStep);
- pos2.Y = pos2.Y + (vel.Y * timeStep);
- // Don't touch the Z
- m_pos = pos2;
- m_log.DebugFormat("[SCENE PRESENCE]: In transit m_pos={0}", m_pos);
+ m_log.DebugFormat("{0} CheckForBorderCrossing: Crossing failed. Restoring old position.", LogHeader);
+
+ Velocity = Vector3.Zero;
+ AbsolutePosition = EnforceSanityOnPosition(origPosition);
+
+ AddToPhysicalScene(isFlying);
}
- }
+ }
+ }
+
+ // Given a position, make sure it is within the current region.
+ // If just outside some border, the returned position will be just inside the border on that side.
+ private Vector3 EnforceSanityOnPosition(Vector3 origPosition)
+ {
+ const float borderFudge = 0.1f;
+ Vector3 ret = origPosition;
+
+ // Sanity checking on the position to make sure it is in the region we couldn't cross from
+ float extentX = (float)m_scene.RegionInfo.RegionSizeX;
+ float extentY = (float)m_scene.RegionInfo.RegionSizeY;
+ IRegionCombinerModule combiner = m_scene.RequestModuleInterface();
+ if (combiner != null)
+ {
+ // If a mega-region, the size could be much bigger
+ Vector2 megaExtent = combiner.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID);
+ extentX = megaExtent.X;
+ extentY = megaExtent.Y;
+ }
+ if (ret.X < 0)
+ ret.X = borderFudge;
+ else if (ret.X >= extentX)
+ ret.X = extentX - borderFudge;
+ if (ret.Y < 0)
+ ret.Y = borderFudge;
+ else if (ret.Y >= extentY)
+ ret.Y = extentY - borderFudge;
+
+ return ret;
}
///
@@ -2873,18 +3760,13 @@ namespace OpenSim.Region.Framework.Scenes
}
}
- public void RestoreInCurrentScene()
- {
- AddToPhysicalScene(false); // not exactly false
- }
-
public void Reset()
{
// m_log.DebugFormat("[SCENE PRESENCE]: Resetting {0} in {1}", Name, Scene.RegionInfo.RegionName);
// Put the child agent back at the center
AbsolutePosition
- = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 70);
+ = new Vector3(((float)m_scene.RegionInfo.RegionSizeX * 0.5f), ((float)m_scene.RegionInfo.RegionSizeY * 0.5f), 70);
Animator.ResetAnimations();
}
@@ -2911,13 +3793,13 @@ namespace OpenSim.Region.Framework.Scenes
if (handle != Scene.RegionInfo.RegionHandle)
{
uint x, y;
- Utils.LongToUInts(handle, out x, out y);
- x = x / Constants.RegionSize;
- y = y / Constants.RegionSize;
+ Util.RegionHandleToRegionLoc(handle, out x, out y);
// m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX)));
// m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY)));
- if (Util.IsOutsideView(DrawDistance, x, newRegionX, y, newRegionY))
+ float dist = (float)Math.Max(Scene.DefaultDrawDistance,
+ (float)Math.Max(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY));
+ if (Util.IsOutsideView(dist, x, newRegionX, y, newRegionY))
{
byebyeRegions.Add(handle);
}
@@ -2927,10 +3809,12 @@ namespace OpenSim.Region.Framework.Scenes
if (byebyeRegions.Count > 0)
{
m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents");
- Util.FireAndForget(delegate
- {
- m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, byebyeRegions);
- });
+
+ AgentCircuitData acd = Scene.AuthenticateHandler.GetAgentCircuitData(UUID);
+ string auth = string.Empty;
+ if (acd != null)
+ auth = acd.SessionID.ToString();
+ m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, auth, byebyeRegions);
}
foreach (ulong handle in byebyeRegions)
@@ -2971,36 +3855,45 @@ namespace OpenSim.Region.Framework.Scenes
#region Child Agent Updates
- public void ChildAgentDataUpdate(AgentData cAgentData)
+ public void UpdateChildAgent(AgentData cAgentData)
{
// m_log.Debug(" >>> ChildAgentDataUpdate <<< " + Scene.RegionInfo.RegionName);
if (!IsChildAgent)
return;
CopyFrom(cAgentData);
+
+ m_updateAgentReceivedAfterTransferEvent.Set();
}
private static Vector3 marker = new Vector3(-1f, -1f, -1f);
+
///
/// This updates important decision making data about a child agent
/// The main purpose is to figure out what objects to send to a child agent that's in a neighboring region
///
- public void ChildAgentDataUpdate(AgentPosition cAgentData, uint tRegionX, uint tRegionY, uint rRegionX, uint rRegionY)
+ public void UpdateChildAgent(AgentPosition cAgentData, uint tRegionX, uint tRegionY, uint rRegionX, uint rRegionY)
{
if (!IsChildAgent)
return;
- //m_log.Debug(" >>> ChildAgentPositionUpdate <<< " + rRegionX + "-" + rRegionY);
- int shiftx = ((int)rRegionX - (int)tRegionX) * (int)Constants.RegionSize;
- int shifty = ((int)rRegionY - (int)tRegionY) * (int)Constants.RegionSize;
+// m_log.DebugFormat(
+// "[SCENE PRESENCE]: ChildAgentPositionUpdate for {0} in {1}, tRegion {2},{3}, rRegion {4},{5}, pos {6}",
+// Name, Scene.Name, tRegionX, tRegionY, rRegionX, rRegionY, cAgentData.Position);
+
+ // Find the distance (in meters) between the two regions
+ // XXX: We cannot use Util.RegionLocToHandle() here because a negative value will silently overflow the
+ // uint
+ int shiftx = (int)(((int)rRegionX - (int)tRegionX) * Constants.RegionSize);
+ int shifty = (int)(((int)rRegionY - (int)tRegionY) * Constants.RegionSize);
Vector3 offset = new Vector3(shiftx, shifty, 0f);
// When we get to the point of re-computing neighbors everytime this
// changes, then start using the agent's drawdistance rather than the
// region's draw distance.
- // DrawDistance = cAgentData.Far;
- DrawDistance = Scene.DefaultDrawDistance;
+ DrawDistance = cAgentData.Far;
+ // DrawDistance = Scene.DefaultDrawDistance;
if (cAgentData.Position != marker) // UGH!!
m_pos = cAgentData.Position + offset;
@@ -3027,6 +3920,7 @@ namespace OpenSim.Region.Framework.Scenes
cAgent.AgentID = UUID;
cAgent.RegionID = Scene.RegionInfo.RegionID;
+ cAgent.SessionID = ControllingClient.SessionId;
cAgent.Position = AbsolutePosition;
cAgent.Velocity = m_velocity;
@@ -3061,6 +3955,9 @@ namespace OpenSim.Region.Framework.Scenes
cAgent.AlwaysRun = SetAlwaysRun;
cAgent.Appearance = new AvatarAppearance(Appearance);
+
+ cAgent.ParentPart = ParentUUID;
+ cAgent.SitOffset = PrevSitOffset;
lock (scriptedcontrols)
{
@@ -3069,7 +3966,7 @@ namespace OpenSim.Region.Framework.Scenes
foreach (ScriptControllers c in scriptedcontrols.Values)
{
- controls[i++] = new ControllerData(c.itemID, (uint)c.ignoreControls, (uint)c.eventControls);
+ controls[i++] = new ControllerData(c.objectID, c.itemID, (uint)c.ignoreControls, (uint)c.eventControls);
}
cAgent.Controllers = controls;
}
@@ -3089,8 +3986,6 @@ namespace OpenSim.Region.Framework.Scenes
private void CopyFrom(AgentData cAgent)
{
- m_originRegionID = cAgent.RegionID;
-
m_callbackURI = cAgent.CallbackURI;
// m_log.DebugFormat(
// "[SCENE PRESENCE]: Set callback for {0} in {1} to {2} in CopyFrom()",
@@ -3102,12 +3997,14 @@ namespace OpenSim.Region.Framework.Scenes
CameraAtAxis = cAgent.AtAxis;
CameraLeftAxis = cAgent.LeftAxis;
CameraUpAxis = cAgent.UpAxis;
+ ParentUUID = cAgent.ParentPart;
+ PrevSitOffset = cAgent.SitOffset;
// When we get to the point of re-computing neighbors everytime this
// changes, then start using the agent's drawdistance rather than the
// region's draw distance.
- // DrawDistance = cAgent.Far;
- DrawDistance = Scene.DefaultDrawDistance;
+ DrawDistance = cAgent.Far;
+ // DrawDistance = Scene.DefaultDrawDistance;
if ((cAgent.Throttles != null) && cAgent.Throttles.Length > 0)
ControllingClient.SetChildAgentThrottle(cAgent.Throttles);
@@ -3139,6 +4036,7 @@ namespace OpenSim.Region.Framework.Scenes
foreach (ControllerData c in cAgent.Controllers)
{
ScriptControllers sc = new ScriptControllers();
+ sc.objectID = c.ObjectID;
sc.itemID = c.ItemID;
sc.ignoreControls = (ScriptControlled)c.IgnoreControls;
sc.eventControls = (ScriptControlled)c.EventControls;
@@ -3159,7 +4057,27 @@ namespace OpenSim.Region.Framework.Scenes
Animator.Animations.SetImplicitDefaultAnimation(cAgent.AnimState.AnimID, cAgent.AnimState.SequenceNum, UUID.Zero);
if (Scene.AttachmentsModule != null)
- Scene.AttachmentsModule.CopyAttachments(cAgent, this);
+ {
+ // If the JobEngine is running we can schedule this job now and continue rather than waiting for all
+ // attachments to copy, which might take a long time in the Hypergrid case as the entire inventory
+ // graph is inspected for each attachments and assets possibly fetched.
+ //
+ // We don't need to worry about a race condition as the job to later start the scripts is also
+ // JobEngine scheduled and so will always occur after this task.
+ // XXX: This will not be true if JobEngine ever gets more than one thread.
+ WorkManager.RunJob(
+ "CopyAttachments",
+ o => Scene.AttachmentsModule.CopyAttachments(cAgent, this),
+ null,
+ string.Format("Copy attachments for {0} entering {1}", Name, Scene.Name),
+ true);
+ }
+
+ // This must occur after attachments are copied or scheduled to be copied, as it releases the CompleteMovement() calling thread
+ // originating from the client completing a teleport. Otherwise, CompleteMovement() code to restart
+ // script attachments can outrace this thread.
+ lock (m_originRegionIDAccessLock)
+ m_originRegionID = cAgent.RegionID;
}
public bool CopyAgent(out IAgentData agent)
@@ -3180,8 +4098,6 @@ namespace OpenSim.Region.Framework.Scenes
{
Vector3 force = m_forceToApply.Value;
- Updated = true;
-
Velocity = force;
m_forceToApply = null;
@@ -3206,20 +4122,23 @@ namespace OpenSim.Region.Framework.Scenes
}
if (Appearance.AvatarHeight == 0)
- Appearance.SetHeight();
-
- PhysicsScene scene = m_scene.PhysicsScene;
-
- Vector3 pVec = AbsolutePosition;
-
+// Appearance.SetHeight();
+ Appearance.SetSize(new Vector3(0.45f,0.6f,1.9f));
+
+/*
PhysicsActor = scene.AddAvatar(
LocalId, Firstname + "." + Lastname, pVec,
- new Vector3(0f, 0f, Appearance.AvatarHeight), isFlying);
+ new Vector3(0.45f, 0.6f, Appearance.AvatarHeight), isFlying);
+*/
+
+ PhysicsActor = m_scene.PhysicsScene.AddAvatar(
+ LocalId, Firstname + "." + Lastname, AbsolutePosition, Velocity,
+ Appearance.AvatarBoxSize, isFlying);
//PhysicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients;
PhysicsActor.OnCollisionUpdate += PhysicsCollisionUpdate;
PhysicsActor.OnOutOfBounds += OutOfBoundsCall; // Called for PhysicsActors when there's something wrong
- PhysicsActor.SubscribeEvents(500);
+ PhysicsActor.SubscribeEvents(100);
PhysicsActor.LocalID = LocalId;
}
@@ -3233,6 +4152,7 @@ namespace OpenSim.Region.Framework.Scenes
ControllingClient.SendAgentAlertMessage("Physics is having a problem with your avatar. You may not be able to move until you relog.", true);
}
+
///
/// Event called by the physics plugin to tell the avatar about a collision.
///
@@ -3246,7 +4166,7 @@ namespace OpenSim.Region.Framework.Scenes
///
public void PhysicsCollisionUpdate(EventArgs e)
{
- if (IsChildAgent)
+ if (IsChildAgent || Animator == null)
return;
//if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f))
@@ -3255,14 +4175,14 @@ namespace OpenSim.Region.Framework.Scenes
// if (m_updateCount > 0)
// {
- Animator.UpdateMovementAnimations();
+ if (Animator.UpdateMovementAnimations())
+ TriggerScenePresenceUpdated();
// m_updateCount--;
// }
CollisionEventUpdate collisionData = (CollisionEventUpdate)e;
Dictionary coldata = collisionData.m_objCollisionList;
- CollisionPlane = Vector4.UnitW;
// // No collisions at all means we may be flying. Update always
// // to make falling work
@@ -3272,34 +4192,7 @@ namespace OpenSim.Region.Framework.Scenes
// m_lastColCount = coldata.Count;
// }
- if (coldata.Count != 0)
- {
- switch (Animator.CurrentMovementAnimation)
- {
- case "STAND":
- case "WALK":
- case "RUN":
- case "CROUCH":
- case "CROUCHWALK":
- {
- ContactPoint lowest;
- lowest.SurfaceNormal = Vector3.Zero;
- lowest.Position = Vector3.Zero;
- lowest.Position.Z = Single.NaN;
-
- foreach (ContactPoint contact in coldata.Values)
- {
- if (Single.IsNaN(lowest.Position.Z) || contact.Position.Z < lowest.Position.Z)
- {
- lowest = contact;
- }
- }
-
- CollisionPlane = new Vector4(-lowest.SurfaceNormal, -Vector3.Dot(lowest.Position, lowest.SurfaceNormal));
- }
- break;
- }
- }
+ CollisionPlane = Vector4.UnitW;
// Gods do not take damage and Invulnerable is set depending on parcel/region flags
if (Invulnerable || GodLevel > 0)
@@ -3398,6 +4291,14 @@ namespace OpenSim.Region.Framework.Scenes
// m_reprioritizationTimer.Dispose();
RemoveFromPhysicalScene();
+
+ m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd;
+
+// if (Animator != null)
+// Animator.Close();
+ Animator = null;
+
+ LifecycleState = ScenePresenceState.Removed;
}
public void AddAttachment(SceneObjectGroup gobj)
@@ -3602,7 +4503,7 @@ namespace OpenSim.Region.Framework.Scenes
}
}
}
- });
+ }, null, "ScenePresence.SendScriptEventToAttachments");
}
///
@@ -3631,10 +4532,18 @@ namespace OpenSim.Region.Framework.Scenes
public void RegisterControlEventsToScript(int controls, int accept, int pass_on, uint Obj_localID, UUID Script_item_UUID)
{
+ SceneObjectPart p = m_scene.GetSceneObjectPart(Obj_localID);
+ if (p == null)
+ return;
+
+ ControllingClient.SendTakeControls(controls, false, false);
+ ControllingClient.SendTakeControls(controls, true, false);
+
ScriptControllers obj = new ScriptControllers();
obj.ignoreControls = ScriptControlled.CONTROL_ZERO;
obj.eventControls = ScriptControlled.CONTROL_ZERO;
+ obj.objectID = p.ParentGroup.UUID;
obj.itemID = Script_item_UUID;
if (pass_on == 0 && accept == 0)
{
@@ -3683,6 +4592,21 @@ namespace OpenSim.Region.Framework.Scenes
ControllingClient.SendTakeControls(int.MaxValue, false, false);
}
+ private void UnRegisterSeatControls(UUID obj)
+ {
+ List takers = new List();
+
+ foreach (ScriptControllers c in scriptedcontrols.Values)
+ {
+ if (c.objectID == obj)
+ takers.Add(c.itemID);
+ }
+ foreach (UUID t in takers)
+ {
+ UnRegisterControlEventsToScript(0, t);
+ }
+ }
+
public void UnRegisterControlEventsToScript(uint Obj_localID, UUID Script_item_UUID)
{
ScriptControllers takecontrols;
@@ -3899,6 +4823,7 @@ namespace OpenSim.Region.Framework.Scenes
(m_teleportFlags & TeleportFlags.ViaLocation) != 0 ||
(m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0)
{
+
if (GodLevel < 200 &&
((!m_scene.Permissions.IsGod(m_uuid) &&
!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) ||
@@ -3907,7 +4832,14 @@ namespace OpenSim.Region.Framework.Scenes
{
SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray();
if (spawnPoints.Length == 0)
+ {
+ if(m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid))
+ {
+ pos.X = 128.0f;
+ pos.Y = 128.0f;
+ }
return;
+ }
int index;
bool selected = false;
@@ -3916,6 +4848,8 @@ namespace OpenSim.Region.Framework.Scenes
{
case "random":
+ if (spawnPoints.Length == 0)
+ return;
do
{
index = Util.RandomClass.Next(spawnPoints.Length - 1);
@@ -3927,6 +4861,7 @@ namespace OpenSim.Region.Framework.Scenes
// SpawnPoint sp = spawnPoints[index];
ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y);
+
if (land == null || land.IsEitherBannedOrRestricted(UUID))
selected = false;
else
@@ -3999,8 +4934,15 @@ namespace OpenSim.Region.Framework.Scenes
}
}
+ // Modify landing point based on possible banning, telehubs or parcel restrictions.
private void CheckAndAdjustLandingPoint(ref Vector3 pos)
{
+ string reason;
+
+ // Honor bans
+ if (!m_scene.TestLandRestrictions(UUID, out reason, ref pos.X, ref pos.Y))
+ return;
+
SceneObjectGroup telehub = null;
if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject)) != null)
{
@@ -4040,11 +4982,119 @@ namespace OpenSim.Region.Framework.Scenes
pos = land.LandData.UserLocation;
}
}
-
+
land.SendLandUpdateToClient(ControllingClient);
}
}
+ private DetectedObject CreateDetObject(SceneObjectPart obj)
+ {
+ DetectedObject detobj = new DetectedObject();
+ detobj.keyUUID = obj.UUID;
+ detobj.nameStr = obj.Name;
+ detobj.ownerUUID = obj.OwnerID;
+ detobj.posVector = obj.AbsolutePosition;
+ detobj.rotQuat = obj.GetWorldRotation();
+ detobj.velVector = obj.Velocity;
+ detobj.colliderType = 0;
+ detobj.groupUUID = obj.GroupID;
+
+ return detobj;
+ }
+
+ private DetectedObject CreateDetObject(ScenePresence av)
+ {
+ DetectedObject detobj = new DetectedObject();
+ detobj.keyUUID = av.UUID;
+ detobj.nameStr = av.ControllingClient.Name;
+ detobj.ownerUUID = av.UUID;
+ detobj.posVector = av.AbsolutePosition;
+ detobj.rotQuat = av.Rotation;
+ detobj.velVector = av.Velocity;
+ detobj.colliderType = 0;
+ detobj.groupUUID = av.ControllingClient.ActiveGroupId;
+
+ return detobj;
+ }
+
+ private DetectedObject CreateDetObjectForGround()
+ {
+ DetectedObject detobj = new DetectedObject();
+ detobj.keyUUID = UUID.Zero;
+ detobj.nameStr = "";
+ detobj.ownerUUID = UUID.Zero;
+ detobj.posVector = AbsolutePosition;
+ detobj.rotQuat = Quaternion.Identity;
+ detobj.velVector = Vector3.Zero;
+ detobj.colliderType = 0;
+ detobj.groupUUID = UUID.Zero;
+
+ return detobj;
+ }
+
+ private ColliderArgs CreateColliderArgs(SceneObjectPart dest, List colliders)
+ {
+ ColliderArgs colliderArgs = new ColliderArgs();
+ List colliding = new List();
+ foreach (uint localId in colliders)
+ {
+ if (localId == 0)
+ continue;
+
+ SceneObjectPart obj = m_scene.GetSceneObjectPart(localId);
+ if (obj != null)
+ {
+ if (!dest.CollisionFilteredOut(obj.UUID, obj.Name))
+ colliding.Add(CreateDetObject(obj));
+ }
+ else
+ {
+ ScenePresence av = m_scene.GetScenePresence(localId);
+ if (av != null && (!av.IsChildAgent))
+ {
+ if (!dest.CollisionFilteredOut(av.UUID, av.Name))
+ colliding.Add(CreateDetObject(av));
+ }
+ }
+ }
+
+ colliderArgs.Colliders = colliding;
+
+ return colliderArgs;
+ }
+
+ private delegate void ScriptCollidingNotification(uint localID, ColliderArgs message);
+
+ private void SendCollisionEvent(SceneObjectGroup dest, scriptEvents ev, List colliders, ScriptCollidingNotification notify)
+ {
+ ColliderArgs CollidingMessage;
+
+ if (colliders.Count > 0)
+ {
+ if ((dest.RootPart.ScriptEvents & ev) != 0)
+ {
+ CollidingMessage = CreateColliderArgs(dest.RootPart, colliders);
+
+ if (CollidingMessage.Colliders.Count > 0)
+ notify(dest.RootPart.LocalId, CollidingMessage);
+ }
+ }
+ }
+
+ private void SendLandCollisionEvent(SceneObjectGroup dest, scriptEvents ev, ScriptCollidingNotification notify)
+ {
+ if ((dest.RootPart.ScriptEvents & ev) != 0)
+ {
+ ColliderArgs LandCollidingMessage = new ColliderArgs();
+ List colliding = new List();
+
+ colliding.Add(CreateDetObjectForGround());
+ LandCollidingMessage.Colliders = colliding;
+
+ notify(dest.RootPart.LocalId, LandCollidingMessage);
+ }
+ }
+
private void TeleportFlagsDebug() {
// Some temporary debugging help to show all the TeleportFlags we have...
@@ -4069,6 +5119,5 @@ namespace OpenSim.Region.Framework.Scenes
m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************");
}
-
}
}
--
cgit v1.1