From 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 21:24:15 +1000 Subject: Dump OpenSim 0.9.0.1 into it's own branch. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 5029 +++++++++++++++------- 1 file changed, 3366 insertions(+), 1663 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 1fddd91..74f765d 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -90,7 +90,26 @@ namespace OpenSim.Region.Framework.Scenes m_scene.EventManager.TriggerScenePresenceUpdated(this); } - public PresenceType PresenceType { get; private set; } + public bool IsNPC { get; private set; } + + // simple yes or no isGOD from god level >= 200 + // should only be set by GodController + // we have two to suport legacy behaviour + // IsViewerUIGod was controlled by viewer in older versions + // IsGod may now be also controled by viewer acording to options + public bool IsViewerUIGod { get; set; } + public bool IsGod { get; set; } + + private PresenceType m_presenceType; + public PresenceType PresenceType + { + get {return m_presenceType;} + private set + { + m_presenceType = value; + IsNPC = (m_presenceType == PresenceType.Npc); + } + } private ScenePresenceStateMachine m_stateMachine; @@ -98,8 +117,8 @@ namespace OpenSim.Region.Framework.Scenes /// The current state of this presence. Governs only the existence lifecycle. See ScenePresenceStateMachine /// for more details. /// - public ScenePresenceState LifecycleState - { + public ScenePresenceState LifecycleState + { get { return m_stateMachine.GetState(); @@ -116,7 +135,7 @@ namespace OpenSim.Region.Framework.Scenes /// the viewer fires these in quick succession. /// /// - /// TODO: The child -> agent transition should be folded into LifecycleState and the CompleteMovement + /// TODO: The child -> agent transition should be folded into LifecycleState and the CompleteMovement /// regulation done there. /// private object m_completeMovementLock = new object(); @@ -124,7 +143,7 @@ namespace OpenSim.Region.Framework.Scenes // 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); - + /// /// Experimentally determined "fudge factor" to make sit-target positions /// the same as in SecondLife. Fudge factor was tested for 36 different @@ -134,21 +153,116 @@ namespace OpenSim.Region.Framework.Scenes /// issue #1716 /// public static readonly Vector3 SIT_TARGET_ADJUSTMENT = new Vector3(0.0f, 0.0f, 0.4f); + public bool LegacySitOffsets = true; /// /// Movement updates for agents in neighboring regions are sent directly to clients. /// This value only affects how often agent positions are sent to neighbor regions /// for things such as distance-based update prioritization + /// this are the square of real distances /// - public static readonly float SIGNIFICANT_MOVEMENT = 2.0f; + public static readonly float MOVEMENT = .25f; + public static readonly float SIGNIFICANT_MOVEMENT = 16.0f; + public static readonly float CHILDUPDATES_MOVEMENT = 100.0f; + public static readonly float CHILDUPDATES_TIME = 2000f; // min time between child updates (ms) + + private UUID m_previusParcelUUID = UUID.Zero; + private UUID m_currentParcelUUID = UUID.Zero; + private bool m_previusParcelHide = false; + private bool m_currentParcelHide = false; + private object parcelLock = new Object(); + public double ParcelDwellTickMS; + + public UUID currentParcelUUID + { + get { return m_currentParcelUUID; } + set + { + lock (parcelLock) + { + bool oldhide = m_currentParcelHide; + bool checksame = true; + if (value != m_currentParcelUUID) + { + ParcelDwellTickMS = Util.GetTimeStampMS(); + m_previusParcelHide = m_currentParcelHide; + m_previusParcelUUID = m_currentParcelUUID; + checksame = false; + } + m_currentParcelUUID = value; + m_currentParcelHide = false; + + ILandObject land = m_scene.LandChannel.GetLandObject(AbsolutePosition.X, AbsolutePosition.Y); + if (land != null && !land.LandData.SeeAVs) + m_currentParcelHide = true; + + if (m_previusParcelUUID != UUID.Zero || checksame) + ParcelCrossCheck(m_currentParcelUUID, m_previusParcelUUID, m_currentParcelHide, m_previusParcelHide, oldhide,checksame); + } + } + } + + public void sitSOGmoved() + { +/* + if (IsDeleted || !IsSatOnObject) + //what me? nahh + return; + if (IsInTransit) + return; + + ILandObject land = m_scene.LandChannel.GetLandObject(AbsolutePosition.X, AbsolutePosition.Y); + if (land == null) + return; //?? + UUID parcelID = land.LandData.GlobalID; + if (m_currentParcelUUID != parcelID) + currentParcelUUID = parcelID; +*/ + } + + public bool ParcelAllowThisAvatarSounds + { + get + { + try + { + lock (parcelLock) + { + ILandObject land = m_scene.LandChannel.GetLandObject(AbsolutePosition.X, AbsolutePosition.Y); + if (land == null) + return true; + if (land.LandData.AnyAVSounds) + return true; + if (!land.LandData.GroupAVSounds) + return false; + return ControllingClient.IsGroupMember(land.LandData.GroupID); + } + } + catch + { + return true; + } + } + } - public UUID currentParcelUUID = UUID.Zero; + public bool ParcelHideThisAvatar + { + get + { + return m_currentParcelHide; + } + } /// /// The animator for this avatar /// public ScenePresenceAnimator Animator { get; private set; } + /// + /// Server Side Animation Override + /// + public MovementAnimationOverrides Overrides { get; private set; } + public String sitAnimation = "SIT"; /// /// Attachments recorded on this avatar. /// @@ -164,21 +278,19 @@ namespace OpenSim.Region.Framework.Scenes private ScriptControlled IgnoredControls = ScriptControlled.CONTROL_ZERO; private ScriptControlled LastCommands = ScriptControlled.CONTROL_ZERO; private bool MouseDown = false; -// private SceneObjectGroup proxyObjectGroup; - //private SceneObjectPart proxyObjectPart = null; public Vector3 lastKnownAllowedPosition; public bool sentMessageAboutRestrictedParcelFlyingDown; + public Vector4 CollisionPlane = Vector4.UnitW; + public Vector4 m_lastCollisionPlane = Vector4.UnitW; + private byte m_lastState; 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 SentInitialData = false; - private bool m_followCamAuto = false; - - - private Vector3? m_forceToApply; private int m_userFlags; public int UserFlags { @@ -192,23 +304,14 @@ namespace OpenSim.Region.Framework.Scenes set { PhysicsActor.Flying = value; } } - // add for fly velocity control - private bool FlyingOld {get; set;} - public bool WasFlying - { - get; private set; - } - - public bool IsColliding + public bool IsColliding { get { return PhysicsActor != null && PhysicsActor.IsColliding; } // We would expect setting IsColliding to be private but it's used by a hack in Scene set { PhysicsActor.IsColliding = value; } } -// private int m_lastColCount = -1; //KF: Look for Collision chnages -// private int m_updateCount = 0; //KF: Update Anims for a while -// private static readonly int UPDATE_COUNT = 10; // how many frames to update for + private List m_lastColliders = new List(); private TeleportFlags m_teleportFlags; public TeleportFlags TeleportFlags @@ -233,9 +336,18 @@ namespace OpenSim.Region.Framework.Scenes private float m_sitAvatarHeight = 2.0f; + private bool m_childUpdatesBusy = false; + private int m_lastChildUpdatesTime; + private int m_lastChildAgentUpdateGodLevel; + private float m_lastChildAgentUpdateDrawDistance; private Vector3 m_lastChildAgentUpdatePosition; // private Vector3 m_lastChildAgentUpdateCamPosition; + private Vector3 m_lastCameraRayCastCam; + private Vector3 m_lastCameraRayCastPos; + + private float m_FOV = 1.04f; + private const int LAND_VELOCITYMAG_MAX = 12; private const float FLY_ROLL_MAX_RADIANS = 1.1f; @@ -244,32 +356,51 @@ namespace OpenSim.Region.Framework.Scenes private const float FLY_ROLL_RESET_RADIANS_PER_UPDATE = 0.02f; private float m_health = 100f; + private float m_healRate = 1f; + private float m_healRatePerFrame = 0.05f; - protected ulong crossingFromRegion; - - private readonly Vector3[] Dir_Vectors = new Vector3[11]; + private readonly Vector3[] Dir_Vectors = new Vector3[12]; - protected Timer m_reprioritization_timer; - protected bool m_reprioritizing; - protected bool m_reprioritization_called; + protected int m_reprioritizationLastTime; + protected bool m_reprioritizationBusy; + protected Vector3 m_reprioritizationLastPosition; + protected float m_reprioritizationLastDrawDistance; private Quaternion m_headrotation = Quaternion.Identity; //PauPaw:Proper PID Controler for autopilot************ - public bool MovingToTarget { get; private set; } - public Vector3 MoveToPositionTarget { get; private set; } + + private bool m_movingToTarget; + public bool MovingToTarget + { + get {return m_movingToTarget;} + private set {m_movingToTarget = value; } + } + + private Vector3 m_moveToPositionTarget; + public Vector3 MoveToPositionTarget + { + get {return m_moveToPositionTarget;} + private set {m_moveToPositionTarget = value; } + } + + private float m_moveToSpeed; + public float MoveToSpeed + { + get {return m_moveToSpeed;} + private set {m_moveToSpeed = value; } + } + + private double m_delayedStop = -1.0; /// /// Controls whether an avatar automatically moving to a target will land when it gets there (if flying). /// public bool LandAtTarget { get; private set; } - private int m_movementUpdateCount; - private const int NumMovementsBetweenRayCast = 5; - private bool CameraConstraintActive; - //private int m_moveToPositionStateStatus; - //***************************************************** + + private object m_collisionEventLock = new Object(); private int m_movementAnimationUpdateCounter = 0; @@ -287,7 +418,6 @@ 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 @@ -303,7 +433,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// Implemented Control Flags /// - private enum Dir_ControlFlags + private enum Dir_ControlFlags:uint { DIR_CONTROL_FLAG_FORWARD = AgentManager.ControlFlags.AGENT_CONTROL_AT_POS, DIR_CONTROL_FLAG_BACK = AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG, @@ -315,13 +445,15 @@ namespace OpenSim.Region.Framework.Scenes DIR_CONTROL_FLAG_BACKWARD_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG, DIR_CONTROL_FLAG_LEFT_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS, DIR_CONTROL_FLAG_RIGHT_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG, + DIR_CONTROL_FLAG_UP_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS, DIR_CONTROL_FLAG_DOWN_NUDGE = AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG } - + /// /// Position at which a significant movement was made /// private Vector3 posLastSignificantMove; + private Vector3 posLastMove; #region For teleports and crossings callbacks @@ -346,10 +478,7 @@ namespace OpenSim.Region.Framework.Scenes /// 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); /// @@ -366,6 +495,14 @@ namespace OpenSim.Region.Framework.Scenes /// private IScriptModule[] m_scriptEngines; + private enum LandingPointBehavior + { + OS = 1, + SL = 2 + } + + private LandingPointBehavior m_LandingPointBehavior = LandingPointBehavior.OS; + #region Properties /// @@ -379,11 +516,6 @@ namespace OpenSim.Region.Framework.Scenes public uint MovementFlag { get; private set; } /// - /// Set this if we need to force a movement update on the next received AgentUpdate from the viewer. - /// - private const uint ForceUpdateMovementFlagValue = uint.MaxValue; - - /// /// Is the agent stop control flag currently active? /// public bool AgentControlStopActive { get; private set; } @@ -396,28 +528,21 @@ namespace OpenSim.Region.Framework.Scenes get { return m_invulnerable; } } - private int m_userLevel; - - public int UserLevel - { - get { return m_userLevel; } - private set { m_userLevel = value; } - } - - private int m_godLevel; - - public int GodLevel - { - get { return m_godLevel; } - private set { m_godLevel = value; } - } + public GodController GodController { get; private set; } private ulong m_rootRegionHandle; + private Vector3 m_rootRegionPosition = new Vector3(); public ulong RegionHandle { get { return m_rootRegionHandle; } - private set { m_rootRegionHandle = value; } + private set + { + m_rootRegionHandle = value; + // position rounded to lower multiple of 256m + m_rootRegionPosition.X = (float)((m_rootRegionHandle >> 32) & 0xffffff00); + m_rootRegionPosition.Y = (float)(m_rootRegionHandle & 0xffffff00); + } } #region Client Camera @@ -425,17 +550,13 @@ namespace OpenSim.Region.Framework.Scenes /// /// Position of agent's camera in world (region cordinates) /// - protected Vector3 m_lastCameraPosition; +// 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 - { - get { return Util.Axes2Rot(CameraAtAxis, CameraLeftAxis, CameraUpAxis); } - } + public Quaternion CameraRotation { get; private set; } // Use these three vectors to figure out what the agent is looking at // Convert it to a Matrix and/or Quaternion @@ -449,39 +570,51 @@ namespace OpenSim.Region.Framework.Scenes get { Vector3 a = new Vector3(CameraAtAxis.X, CameraAtAxis.Y, 0); - - if (a == Vector3.Zero) - return a; - - return Util.GetNormalizedVector(a); + a.Normalize(); + return a; } } - #endregion + #endregion public string Firstname { get; private set; } public string Lastname { get; private set; } + public bool haveGroupInformation; + public bool gotCrossUpdate; + public byte crossingFlags; + public string Grouptitle { - get { return UseFakeGroupTitle ? "(Loading)" : m_groupTitle; } + get { return 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; } + private float m_drawDistance = 255f; + public float DrawDistance + { + get + { + return m_drawDistance; + } + set + { + m_drawDistance = Util.Clamp(value, 32f, m_scene.MaxDrawDistance); + } + } + + public float RegionViewDistance + { + get + { + return Util.Clamp(m_drawDistance, 32f, m_scene.MaxRegionViewDistance); + } + } public bool AllowMovement { get; set; } private bool m_setAlwaysRun; - public bool SetAlwaysRun { get @@ -557,12 +690,16 @@ namespace OpenSim.Region.Framework.Scenes // in the sim unless the avatar is on a sit target. While // on a sit target, m_pos will contain the desired offset // without the parent rotation applied. - SceneObjectPart sitPart = ParentPart; - - if (sitPart != null) - return sitPart.ParentGroup.AbsolutePosition + (m_pos * sitPart.GetWorldRotation()); + if (ParentPart != null) + { + SceneObjectPart rootPart = ParentPart.ParentGroup.RootPart; + // if (sitPart != null) + // return sitPart.AbsolutePosition + (m_pos * sitPart.GetWorldRotation()); + if (rootPart != null) + return rootPart.AbsolutePosition + (m_pos * rootPart.GetWorldRotation()); + } } - + return m_pos; } set @@ -614,11 +751,8 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Velocity of the avatar with respect to its local reference frame. + /// Current velocity of the avatar. /// - /// - /// 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 @@ -631,21 +765,12 @@ 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 @@ -658,27 +783,42 @@ namespace OpenSim.Region.Framework.Scenes } } - m_velocity = value; + m_velocity = value; + +// m_log.DebugFormat( +// "[SCENE PRESENCE]: In {0} set velocity of {1} to {2}", +// Scene.RegionInfo.RegionName, Name, m_velocity); } } -/* - public override Vector3 AngularVelocity + + // requested Velocity for physics engines avatar motors + // only makes sense if there is a physical rep + public Vector3 TargetVelocity { get { if (PhysicsActor != null) - { - m_rotationalvelocity = PhysicsActor.RotationalVelocity; + return PhysicsActor.TargetVelocity; + else + return Vector3.Zero; + } - // m_log.DebugFormat( - // "[SCENE PRESENCE]: Set velocity {0} for {1} in {2} via getting Velocity!", - // m_velocity, Name, Scene.RegionInfo.RegionName); + set + { + if (PhysicsActor != null) + { + try + { + PhysicsActor.TargetVelocity = value; + } + catch (Exception e) + { + m_log.Error("[SCENE PRESENCE]: TARGETVELOCITY " + e.Message); + } } - - return m_rotationalvelocity; } } -*/ + private Quaternion m_bodyRot = Quaternion.Identity; /// @@ -691,9 +831,9 @@ namespace OpenSim.Region.Framework.Scenes /// public Quaternion Rotation { - get - { - return m_bodyRot; + get + { + return m_bodyRot; } set @@ -758,16 +898,42 @@ namespace OpenSim.Region.Framework.Scenes set { m_health = value; } } + public float HealRate + { + get { return m_healRate; } + set + { + if(value > 100.0f) + m_healRate = 100.0f; + else if (value <= 0.0) + m_healRate = 0.0f; + else + m_healRate = value; + + if(Scene != null) + m_healRatePerFrame = m_healRate * Scene.FrameTime; + else + m_healRatePerFrame = 0.05f; + } + } + + /// - /// Get rotation relative to the world. + /// Gets the world rotation of this presence. /// + /// + /// Unlike Rotation, this returns the world rotation no matter whether the avatar is sitting on a prim or not. + /// /// public Quaternion GetWorldRotation() { - SceneObjectPart sitPart = ParentPart; + if (IsSatOnObject) + { + SceneObjectPart sitPart = ParentPart; - if (sitPart != null) - return sitPart.GetWorldRotation() * Rotation; + if (sitPart != null) + return sitPart.GetWorldRotation() * Rotation; + } return Rotation; } @@ -793,26 +959,7 @@ namespace OpenSim.Region.Framework.Scenes seeds = Scene.CapsModule.GetChildrenSeeds(UUID); else seeds = new Dictionary(); - - List old = new List(); - foreach (ulong handle in seeds.Keys) - { - uint x, y; - Util.RegionHandleToRegionLoc(handle, out x, out y); - - if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY)) - { - old.Add(handle); - } - } - DropOldNeighbours(old); - - if (Scene.CapsModule != null) - Scene.CapsModule.SetChildrenSeed(UUID, seeds); - KnownRegions = seeds; - //m_log.Debug(" ++++++++++AFTER+++++++++++++ "); - //DumpKnownRegions(); } public void DumpKnownRegions() @@ -827,20 +974,20 @@ namespace OpenSim.Region.Framework.Scenes } 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; } - set { + set { if(value) { if (Flying) @@ -851,14 +998,11 @@ namespace OpenSim.Region.Framework.Scenes m_inTransit = value; } } + // this is is only valid if IsInTransit is true + // only false on HG tps + // used work arounf viewers asking source region about destination user + public bool IsInLocalTransit {get; set; } - private float m_speedModifier = 1.0f; - - public float SpeedModifier - { - get { return m_speedModifier; } - set { m_speedModifier = value; } - } /// /// Modifier for agent movement if we get an AGENT_CONTROL_STOP whilst walking or running @@ -866,7 +1010,20 @@ namespace OpenSim.Region.Framework.Scenes /// /// AGENT_CONTRL_STOP comes about if user holds down space key on viewers. /// - private float AgentControlStopSlowWhilstMoving = 0.5f; + private const float AgentControlStopSlowVel = 0.2f; + // velocities + public const float AgentControlNudgeVel = 1.0f; // setting this diferent from normal as no effect currently + public const float AgentControlNormalVel = 1.0f; + + // old normal speed was tuned to match sl normal plus Fast modifiers + // so we need to rescale it + private float m_speedModifier = 1.0f; + + public float SpeedModifier + { + get { return m_speedModifier; } + set { m_speedModifier = value; } + } private bool m_forceFly; @@ -889,35 +1046,32 @@ namespace OpenSim.Region.Framework.Scenes 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) - { + { + m_scene = world; AttachmentsSyncLock = new Object(); AllowMovement = true; IsChildAgent = true; IsLoggingIn = false; m_sendCoarseLocationsMethod = SendCoarseLocationsDefault; Animator = new ScenePresenceAnimator(this); + Overrides = new MovementAnimationOverrides(); PresenceType = type; - // DrawDistance = world.DefaultDrawDistance; - DrawDistance = Constants.RegionSize; + DrawDistance = world.DefaultDrawDistance; RegionHandle = world.RegionInfo.RegionHandle; ControllingClient = client; Firstname = ControllingClient.FirstName; Lastname = ControllingClient.LastName; m_name = String.Format("{0} {1}", Firstname, Lastname); - m_scene = world; m_uuid = client.AgentId; LocalId = m_scene.AllocateLocalId(); + LegacySitOffsets = m_scene.LegacySitOffsets; + IsInLocalTransit = true; UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, m_uuid); if (account != null) @@ -925,32 +1079,52 @@ namespace OpenSim.Region.Framework.Scenes else m_userFlags = 0; + int userlevel = 0; if (account != null) - UserLevel = account.UserLevel; + userlevel = account.UserLevel; - IGroupsModule gm = m_scene.RequestModuleInterface(); - if (gm != null) - Grouptitle = gm.GetGroupTitle(m_uuid); + GodController = new GodController(world, this, userlevel); + + // IGroupsModule gm = m_scene.RequestModuleInterface(); + // if (gm != null) + // Grouptitle = gm.GetGroupTitle(m_uuid); m_scriptEngines = m_scene.RequestModuleInterfaces(); - - AbsolutePosition = posLastSignificantMove = CameraPosition = - m_lastCameraPosition = ControllingClient.StartPos; - m_reprioritization_timer = new Timer(world.ReprioritizationInterval); - m_reprioritization_timer.Elapsed += new ElapsedEventHandler(Reprioritize); - m_reprioritization_timer.AutoReset = false; + AbsolutePosition = posLastMove = posLastSignificantMove = CameraPosition = + m_reprioritizationLastPosition = ControllingClient.StartPos; + + m_reprioritizationLastDrawDistance = DrawDistance; + + // disable updates workjobs for now + m_childUpdatesBusy = true; + m_reprioritizationBusy = true; AdjustKnownSeeds(); - RegisterToEvents(); + RegisterToClientEvents(); SetDirectionVectors(); Appearance = appearance; m_stateMachine = new ScenePresenceStateMachine(this); + + HealRate = 0.5f; + + IConfig sconfig = m_scene.Config.Configs["EntityTransfer"]; + if (sconfig != null) + { + string lpb = sconfig.GetString("LandingPointBehavior", "LandingPointBehavior_OS"); + if (lpb == "LandingPointBehavior_SL") + m_LandingPointBehavior = LandingPointBehavior.SL; + } + + ControllingClient.RefreshGroupMembership(); + } + private float lastHealthSent = 0; + private void RegionHeartbeatEnd(Scene scene) { if (IsChildAgent) @@ -973,12 +1147,29 @@ namespace OpenSim.Region.Framework.Scenes } else { - m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd; +// m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd; + } + } + + if(m_healRatePerFrame != 0f && Health != 100.0f) + { + float last = Health; + Health += m_healRatePerFrame; + if(Health > 100.0f) + { + Health = 100.0f; + lastHealthSent = Health; + ControllingClient.SendHealth(Health); + } + else if(Math.Abs(Health - lastHealthSent) > 1.0) + { + lastHealthSent = Health; + ControllingClient.SendHealth(Health); } } } - public void RegisterToEvents() + public void RegisterToClientEvents() { ControllingClient.OnCompleteMovementToRegion += CompleteMovement; ControllingClient.OnAgentUpdate += HandleAgentUpdate; @@ -988,28 +1179,48 @@ namespace OpenSim.Region.Framework.Scenes ControllingClient.OnSetAlwaysRun += HandleSetAlwaysRun; ControllingClient.OnStartAnim += HandleStartAnim; ControllingClient.OnStopAnim += HandleStopAnim; + ControllingClient.OnChangeAnim += avnHandleChangeAnim; ControllingClient.OnForceReleaseControls += HandleForceReleaseControls; - ControllingClient.OnAutoPilotGo += MoveToTarget; + ControllingClient.OnAutoPilotGo += MoveToTargetHandle; + ControllingClient.OnUpdateThrottles += RaiseUpdateThrottles; +// ControllingClient.OnAgentFOV += HandleAgentFOV; // ControllingClient.OnChildAgentStatus += new StatusChange(this.ChildStatusChange); // ControllingClient.OnStopMovement += new GenericCall2(this.StopMovement); } - private void SetDirectionVectors() + public void RemoveClientEvents() { - Dir_Vectors[0] = Vector3.UnitX; //FORWARD - Dir_Vectors[1] = -Vector3.UnitX; //BACK - Dir_Vectors[2] = Vector3.UnitY; //LEFT - Dir_Vectors[3] = -Vector3.UnitY; //RIGHT - Dir_Vectors[4] = Vector3.UnitZ; //UP - Dir_Vectors[5] = -Vector3.UnitZ; //DOWN - Dir_Vectors[6] = new Vector3(0.5f, 0f, 0f); //FORWARD_NUDGE - Dir_Vectors[7] = new Vector3(-0.5f, 0f, 0f); //BACK_NUDGE - Dir_Vectors[8] = new Vector3(0f, 0.5f, 0f); //LEFT_NUDGE - Dir_Vectors[9] = new Vector3(0f, -0.5f, 0f); //RIGHT_NUDGE - Dir_Vectors[10] = new Vector3(0f, 0f, -0.5f); //DOWN_Nudge + ControllingClient.OnCompleteMovementToRegion -= CompleteMovement; + ControllingClient.OnAgentUpdate -= HandleAgentUpdate; + ControllingClient.OnAgentCameraUpdate -= HandleAgentCamerasUpdate; + ControllingClient.OnAgentRequestSit -= HandleAgentRequestSit; + ControllingClient.OnAgentSit -= HandleAgentSit; + ControllingClient.OnSetAlwaysRun -= HandleSetAlwaysRun; + ControllingClient.OnStartAnim -= HandleStartAnim; + ControllingClient.OnStopAnim -= HandleStopAnim; + ControllingClient.OnChangeAnim -= avnHandleChangeAnim; + ControllingClient.OnForceReleaseControls -= HandleForceReleaseControls; + ControllingClient.OnAutoPilotGo -= MoveToTargetHandle; + ControllingClient.OnUpdateThrottles -= RaiseUpdateThrottles; +// ControllingClient.OnAgentFOV += HandleAgentFOV; } + private void SetDirectionVectors() + { + Dir_Vectors[0] = new Vector3(AgentControlNormalVel,0,0); //FORWARD + Dir_Vectors[1] = new Vector3(-AgentControlNormalVel,0,0);; //BACK + Dir_Vectors[2] = new Vector3(0,AgentControlNormalVel,0); //LEFT + Dir_Vectors[3] = new Vector3(0,-AgentControlNormalVel,0); //RIGHT + Dir_Vectors[4] = new Vector3(0,0,AgentControlNormalVel); //UP + Dir_Vectors[5] = new Vector3(0,0,-AgentControlNormalVel); //DOWN + Dir_Vectors[6] = new Vector3(AgentControlNudgeVel, 0f, 0f); //FORWARD_NUDGE + Dir_Vectors[7] = new Vector3(-AgentControlNudgeVel, 0f, 0f); //BACK_NUDGE + Dir_Vectors[8] = new Vector3(0f, AgentControlNudgeVel, 0f); //LEFT_NUDGE + Dir_Vectors[9] = new Vector3(0f, -AgentControlNudgeVel, 0f); //RIGHT_NUDGE + Dir_Vectors[10] = new Vector3(0f, 0f, AgentControlNudgeVel); //UP_Nudge + Dir_Vectors[11] = new Vector3(0f, 0f, -AgentControlNudgeVel); //DOWN_Nudge + } #endregion #region Status Methods @@ -1026,18 +1237,29 @@ 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. /// - private bool MakeRootAgent(Vector3 pos, bool isFlying) + + // constants for physics position search + const float PhysSearchHeight = 600f; + const float PhysMinSkipGap = 50f; + const int PhysNumberCollisions = 30; + + // only in use as part of completemovement + // other uses need fix + private bool MakeRootAgent(Vector3 pos, bool isFlying, ref Vector3 lookat) { + //int ts = Util.EnvironmentTickCount(); + lock (m_completeMovementLock) { if (!IsChildAgent) return false; + //m_log.DebugFormat("[MakeRootAgent] enter lock: {0}ms", Util.EnvironmentTickCountSubtract(ts)); //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); + // m_log.InfoFormat( + // "[SCENE]: Upgrading child to root agent for {0} in {1}", + // Name, m_scene.RegionInfo.RegionName); if (ParentUUID != UUID.Zero) { @@ -1046,20 +1268,33 @@ namespace OpenSim.Region.Framework.Scenes if (part == null) { m_log.ErrorFormat("[SCENE PRESENCE]: Can't find prim {0} to sit on", ParentUUID); + ParentID = 0; + ParentPart = null; + PrevSitOffset = Vector3.Zero; + HandleForceReleaseControls(ControllingClient, UUID); // needs testing + IsLoggingIn = false; } else { part.AddSittingAvatar(this); - // ParentPosition = part.GetWorldPosition(); + // if not actually on the target invalidate it + if(gotCrossUpdate && (crossingFlags & 0x04) == 0) + part.SitTargetAvatar = UUID.Zero; + ParentID = part.LocalId; ParentPart = part; m_pos = PrevSitOffset; - // pos = ParentPosition; pos = part.GetWorldPosition(); + PhysicsActor partPhysActor = part.PhysActor; + if(partPhysActor != null) + { + partPhysActor.OnPhysicsRequestingCameraData -= + physActor_OnPhysicsRequestingCameraData; + partPhysActor.OnPhysicsRequestingCameraData += + physActor_OnPhysicsRequestingCameraData; + } } ParentUUID = UUID.Zero; - - // Animator.TrySetMovementAnimation("SIT"); } else { @@ -1069,135 +1304,144 @@ namespace OpenSim.Region.Framework.Scenes IsChildAgent = false; } + //m_log.DebugFormat("[MakeRootAgent] out lock: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + // 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(); - } + // DoNotCloseAfterTeleport = false; RegionHandle = m_scene.RegionInfo.RegionHandle; m_scene.EventManager.TriggerSetRootAgentScene(m_uuid, m_scene); - - UUID groupUUID = ControllingClient.ActiveGroupId; - string groupName = string.Empty; - ulong groupPowers = 0; - - // ---------------------------------- - // Previous Agent Difference - AGNI sends an unsolicited AgentDataUpdate upon root agent status - try - { - 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 (groupMembershipData != null) - groupPowers = groupMembershipData.GroupPowers; - } - - ControllingClient.SendAgentDataUpdate( - m_uuid, groupUUID, Firstname, Lastname, groupPowers, groupName, Grouptitle); - } - catch (Exception e) - { - m_log.Error("[AGENTUPDATE]: Error ", e); - } - // ------------------------------------ + //m_log.DebugFormat("[MakeRootAgent] TriggerSetRootAgentScene: {0}ms", Util.EnvironmentTickCountSubtract(ts)); if (ParentID == 0) { - // 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 (m_scene.TestBorderCross(pos, Cardinals.N)) - { - Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N); - pos.Y = crossedBorder.BorderLine.Z - 1; - } - */ + bool positionChanged = false; + bool success = true; + if (m_LandingPointBehavior == LandingPointBehavior.OS) + success = CheckAndAdjustLandingPoint_OS(ref pos, ref lookat, ref positionChanged); + else + success = CheckAndAdjustLandingPoint_SL(ref pos, ref lookat, ref positionChanged); - CheckAndAdjustLandingPoint(ref pos); + if (!success) + m_log.DebugFormat("[SCENE PRESENCE MakeRootAgent]: houston we have a problem.. {0} ({1} got banned)", Name, UUID); - if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f) + if (pos.X < 0f || pos.Y < 0f + || pos.X >= m_scene.RegionInfo.RegionSizeX + || pos.Y >= m_scene.RegionInfo.RegionSizeY) { m_log.WarnFormat( "[SCENE PRESENCE]: MakeRootAgent() was given an illegal position of {0} for avatar {1}, {2}. Clamping", pos, Name, UUID); - if (pos.X < 0f) pos.X = 0f; - if (pos.Y < 0f) pos.Y = 0f; - if (pos.Z < 0f) pos.Z = 0f; + if (pos.X < 0f) + pos.X = 0.5f; + else if(pos.X >= m_scene.RegionInfo.RegionSizeX) + pos.X = m_scene.RegionInfo.RegionSizeX - 0.5f; + if (pos.Y < 0f) + pos.Y = 0.5f; + else if(pos.Y >= m_scene.RegionInfo.RegionSizeY) + pos.Y = m_scene.RegionInfo.RegionSizeY - 0.5f; } - float localAVHeight = 1.56f; - if (Appearance.AvatarHeight > 0) - localAVHeight = Appearance.AvatarHeight; + float groundHeight = m_scene.GetGroundHeight(pos.X, pos.Y) + .01f; + float physTestHeight; - float posZLimit = 0; + if(PhysSearchHeight < groundHeight + 100f) + physTestHeight = groundHeight + 100f; + else + physTestHeight = PhysSearchHeight; - 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))) + float localAVHalfHeight = 0.8f; + if (Appearance != null && Appearance.AvatarHeight > 0) + localAVHalfHeight = 0.5f * Appearance.AvatarHeight; + + groundHeight += localAVHalfHeight; + if (groundHeight > pos.Z) + pos.Z = groundHeight; + + bool checkPhysics = !positionChanged && + m_scene.SupportsRayCastFiltered() && + pos.Z < physTestHeight && + ((m_teleportFlags & (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID)) == + (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID) + || (m_teleportFlags & TeleportFlags.ViaLocation) != 0 + || (m_teleportFlags & TeleportFlags.ViaHGLogin) != 0); + + if(checkPhysics) { - pos.Z = newPosZ; + // land check was done above + RayFilterFlags rayfilter = RayFilterFlags.BackFaceCull; + rayfilter |= RayFilterFlags.PrimsNonPhantomAgents; + + int physcount = PhysNumberCollisions; + + float dist = physTestHeight - groundHeight + localAVHalfHeight; + + Vector3 direction = new Vector3(0f, 0f, -1f); + Vector3 RayStart = pos; + RayStart.Z = physTestHeight; + + List physresults = + (List)m_scene.RayCastFiltered(RayStart, direction, dist, physcount, rayfilter); + if (physresults != null && physresults.Count > 0) + { + float dest = physresults[0].Pos.Z; + + if(physresults.Count > 1) + { + physresults.Sort(delegate(ContactResult a, ContactResult b) + { + return a.Depth.CompareTo(b.Depth); + }); + + int sel = 0; + int count = physresults.Count; + float curd = physresults[0].Depth; + float nextd = curd + PhysMinSkipGap; + float maxDepth = dist - pos.Z; + for(int i = 1; i < count; i++) + { + curd = physresults[i].Depth; + if(curd >= nextd) + { + sel = i; + if(curd >= maxDepth) + break; + } + nextd = curd + PhysMinSkipGap; + } + dest = physresults[sel].Pos.Z; + } + + dest += localAVHalfHeight; + if(dest > pos.Z) + pos.Z = dest; + } } + AbsolutePosition = pos; // m_log.DebugFormat( -// "Set pos {0}, vel {1} in {1} to {2} from input position of {3} on MakeRootAgent", +// "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) { + Vector3 vel = Velocity; 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); -// } + if (PhysicsActor != null) + PhysicsActor.SetMomentum(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(); + // reset camera to avatar pos + CameraPosition = pos; + } if (ForceFly) { @@ -1209,53 +1453,16 @@ namespace OpenSim.Region.Framework.Scenes } } - // Don't send an animation pack here, since on a region crossing this will sometimes cause a flying - // avatar to return to the standing position in mid-air. On login it looks like this is being sent - // elsewhere anyway - // Animator.SendAnimPack(); - + //m_log.DebugFormat("[MakeRootAgent] position and physical: {0}ms", Util.EnvironmentTickCountSubtract(ts)); m_scene.SwapRootAgentCount(false); - if (Scene.AttachmentsModule != null) - { - // 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)) - { - 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) - { - if (presence != this) - presence.Animator.SendAnimPackToClient(ControllingClient); - }); - // 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 = ForceUpdateMovementFlagValue; + MovementFlag = 0; m_scene.EventManager.TriggerOnMakeRootAgent(this); + //m_log.DebugFormat("[MakeRootAgent] TriggerOnMakeRootAgent and done: {0}ms", Util.EnvironmentTickCountSubtract(ts)); return true; } @@ -1304,12 +1511,13 @@ namespace OpenSim.Region.Framework.Scenes /// 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 => { @@ -1323,7 +1531,7 @@ namespace OpenSim.Region.Framework.Scenes SendAvatarDataToAllClients(false); }, null, "Scenepresence.ForceViewersUpdateName"); } - +*/ public int GetStateSource() { AgentCircuitData aCircuit = m_scene.AuthenticateHandler.GetAgentCircuitData(UUID); @@ -1347,11 +1555,17 @@ namespace OpenSim.Region.Framework.Scenes /// It doesn't get called for a teleport. Reason being, an agent that /// teleports out may not end up anywhere near this region /// - public void MakeChildAgent() + public void MakeChildAgent(ulong newRegionHandle) { + haveGroupInformation = false; + gotCrossUpdate = false; + crossingFlags = 0; m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd; - m_log.DebugFormat("[SCENE PRESENCE]: Making {0} a child agent in {1}", Name, Scene.RegionInfo.RegionName); + RegionHandle = newRegionHandle; + + m_log.DebugFormat("[SCENE PRESENCE]: Making {0} a child agent in {1} from root region {2}", + Name, Scene.RegionInfo.RegionName, newRegionHandle); // 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. @@ -1371,7 +1585,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); @@ -1379,14 +1593,21 @@ namespace OpenSim.Region.Framework.Scenes // Don't zero out the velocity since this can cause problems when an avatar is making a region crossing, // depending on the exact timing. This shouldn't matter anyway since child agent positions are not updated. //Velocity = new Vector3(0, 0, 0); - + IsChildAgent = true; m_scene.SwapRootAgentCount(true); RemoveFromPhysicalScene(); ParentID = 0; // Child agents can't be sitting +// we dont have land information for child + m_previusParcelHide = false; + m_previusParcelUUID = UUID.Zero; + m_currentParcelHide = false; + m_currentParcelUUID = UUID.Zero; // FIXME: Set RegionHandle to the region handle of the scene this agent is moving into - + + CollisionPlane = Vector4.UnitW; + m_scene.EventManager.TriggerOnMakeChildAgent(this); } @@ -1398,9 +1619,10 @@ namespace OpenSim.Region.Framework.Scenes if (PhysicsActor != null) { // PhysicsActor.OnRequestTerseUpdate -= SendTerseUpdateToAllClients; - PhysicsActor.UnSubscribeEvents(); + PhysicsActor.OnOutOfBounds -= OutOfBoundsCall; PhysicsActor.OnCollisionUpdate -= PhysicsCollisionUpdate; + PhysicsActor.UnSubscribeEvents(); m_scene.PhysicsScene.RemoveAvatar(PhysicsActor); PhysicsActor = null; } @@ -1423,12 +1645,16 @@ namespace OpenSim.Region.Framework.Scenes public void TeleportWithMomentum(Vector3 pos, Vector3? v) { + if(!CheckLocalTPLandingPoint(ref pos)) + return; + if (ParentID != (uint)0) StandUp(); + bool isFlying = Flying; Vector3 vel = Velocity; RemoveFromPhysicalScene(); - CheckLandingPoint(ref pos); + AbsolutePosition = pos; AddToPhysicalScene(isFlying); if (PhysicsActor != null) @@ -1438,11 +1664,29 @@ namespace OpenSim.Region.Framework.Scenes else PhysicsActor.SetMomentum(vel); } + + SendTerseUpdateToAllClients(); + } + + public void TeleportOnEject(Vector3 pos) + { + if (ParentID != (uint)0) + StandUp(); + + bool isFlying = Flying; + RemoveFromPhysicalScene(); + + AbsolutePosition = pos; + + AddToPhysicalScene(isFlying); + SendTerseUpdateToAllClients(); } public void avnLocalTeleport(Vector3 newpos, Vector3? newvel, bool rotateToVelXY) { - CheckLandingPoint(ref newpos); + if(!CheckLocalTPLandingPoint(ref newpos)) + return; + AbsolutePosition = newpos; if (newvel.HasValue) @@ -1469,11 +1713,15 @@ namespace OpenSim.Region.Framework.Scenes } } } + SendTerseUpdateToAllClients(); } public void StopFlying() { - Vector3 pos = AbsolutePosition; + if (IsInTransit) + return; + + Vector3 pos = AbsolutePosition; if (Appearance.AvatarHeight != 127.0f) pos += new Vector3(0f, 0f, (Appearance.AvatarHeight / 6f)); else @@ -1492,7 +1740,7 @@ namespace OpenSim.Region.Framework.Scenes else CollisionPlane = new Vector4(0, 0, 0, pos.Z - (1.56f / 6f)); - ControllingClient.SendAgentTerseUpdate(this); + SendAgentTerseUpdate(this); } /// @@ -1501,7 +1749,7 @@ namespace OpenSim.Region.Framework.Scenes /// 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; @@ -1553,17 +1801,14 @@ namespace OpenSim.Region.Framework.Scenes 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; @@ -1571,22 +1816,65 @@ namespace OpenSim.Region.Framework.Scenes return amount; } } - - // neighbouring regions we have enabled a child agent in // holds the seed cap for the child agent in that region private Dictionary m_knownChildRegions = new Dictionary(); - public void AddNeighbourRegion(ulong regionHandle, string cap) + struct spRegionSizeInfo + { + public int sizeX; + public int sizeY; + } + + private Dictionary m_knownChildRegionsSizeInfo = new Dictionary(); + + public void AddNeighbourRegion(GridRegion region, string capsPath) + { + lock (m_knownChildRegions) + { + ulong regionHandle = region.RegionHandle; + m_knownChildRegions.Add(regionHandle,capsPath); + + spRegionSizeInfo sizeInfo = new spRegionSizeInfo(); + sizeInfo.sizeX = region.RegionSizeX; + sizeInfo.sizeY = region.RegionSizeY; + m_knownChildRegionsSizeInfo[regionHandle] = sizeInfo; + } + } + + public void AddNeighbourRegionSizeInfo(GridRegion region) + { + lock (m_knownChildRegions) + { + spRegionSizeInfo sizeInfo = new spRegionSizeInfo(); + sizeInfo.sizeX = region.RegionSizeX; + sizeInfo.sizeY = region.RegionSizeY; + ulong regionHandle = region.RegionHandle; + + if (!m_knownChildRegionsSizeInfo.ContainsKey(regionHandle)) + { + m_knownChildRegionsSizeInfo.Add(regionHandle, sizeInfo); + + } + else + m_knownChildRegionsSizeInfo[regionHandle] = sizeInfo; + } + } + + public void SetNeighbourRegionSizeInfo(List regionsList) { lock (m_knownChildRegions) { - if (!m_knownChildRegions.ContainsKey(regionHandle)) + m_knownChildRegionsSizeInfo.Clear(); + + foreach (GridRegion region in regionsList) { - uint x, y; - Utils.LongToUInts(regionHandle, out x, out y); - m_knownChildRegions.Add(regionHandle, cap); + spRegionSizeInfo sizeInfo = new spRegionSizeInfo(); + sizeInfo.sizeX = region.RegionSizeX; + sizeInfo.sizeY = region.RegionSizeY; + ulong regionHandle = region.RegionHandle; + m_knownChildRegionsSizeInfo.Add(regionHandle, sizeInfo); } } } @@ -1600,9 +1888,16 @@ namespace OpenSim.Region.Framework.Scenes //if (m_knownChildRegions.ContainsKey(regionHandle)) // m_log.DebugFormat(" !!! removing known region {0} in {1}. Count = {2}", regionHandle, Scene.RegionInfo.RegionName, m_knownChildRegions.Count); m_knownChildRegions.Remove(regionHandle); + m_knownChildRegionsSizeInfo.Remove(regionHandle); } } + public bool knowsNeighbourRegion(ulong regionHandle) + { + lock (m_knownChildRegions) + return m_knownChildRegions.ContainsKey(regionHandle); + } + public void DropOldNeighbours(List oldRegions) { foreach (ulong handle in oldRegions) @@ -1612,6 +1907,13 @@ namespace OpenSim.Region.Framework.Scenes } } + public void DropThisRootRegionFromNeighbours() + { + ulong handle = m_scene.RegionInfo.RegionHandle; + RemoveNeighbourRegion(handle); + Scene.CapsModule.DropChildSeed(UUID, handle); + } + public Dictionary KnownRegions { get @@ -1632,7 +1934,8 @@ namespace OpenSim.Region.Framework.Scenes { get { - return new List(KnownRegions.Keys); + lock (m_knownChildRegions) + return new List(m_knownChildRegions.Keys); } } @@ -1662,35 +1965,66 @@ namespace OpenSim.Region.Framework.Scenes 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); - } + 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, + // (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; + try + { + if(m_updateAgentReceivedAfterTransferEvent.WaitOne(10000)) + { + UUID originID = UUID.Zero; - lock (m_originRegionIDAccessLock) - originID = m_originRegionID; + lock (m_originRegionIDAccessLock) + originID = m_originRegionID; + if (originID.Equals(UUID.Zero)) + { + // Movement into region will fail + m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} at {1} got invalid origin region id ", client.Name, Scene.Name); + return false; + } + return true; + } + else + { + m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} at {1} did not receive agent update ", client.Name, Scene.Name); + return false; + } + } + catch { } + + return false; + } - if (originID.Equals(UUID.Zero)) + public void RotateToLookAt(Vector3 lookAt) + { + if(ParentID == 0) { - // Movement into region will fail - m_log.WarnFormat("[SCENE PRESENCE]: Update agent {0} never arrived in {1}", client.Name, Scene.Name); - return false; + float n = lookAt.X * lookAt.X + lookAt.Y * lookAt.Y; + if(n < 0.0001f) + { + Rotation = Quaternion.Identity; + return; + } + n = lookAt.X/(float)Math.Sqrt(n); + float angle = (float)Math.Acos(n); + angle *= 0.5f; + float s = (float)Math.Sin(angle); + if(lookAt.Y < 0) + s = -s; + Rotation = new Quaternion( + 0f, + 0f, + s, + (float)Math.Cos(angle) + ); } - - return true; } /// @@ -1704,62 +2038,72 @@ namespace OpenSim.Region.Framework.Scenes /// public void CompleteMovement(IClientAPI client, bool openChildAgents) { -// DateTime startTime = DateTime.Now; + int ts = Util.EnvironmentTickCount(); m_log.InfoFormat( "[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}", client.Name, Scene.Name, AbsolutePosition); - bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); // Get this ahead of time because IsInTransit modifies 'm_AgentControlFlags' + m_inTransit = true; - IsInTransit = true; try { // 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))) + if (!IsNPC && !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; } - Vector3 look = Velocity; + //m_log.DebugFormat("[CompleteMovement] WaitForUpdateAgent: {0}ms", Util.EnvironmentTickCountSubtract(ts)); - // 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); - } + bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); - // 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) + Vector3 look = Lookat; + look.Z = 0f; + if ((Math.Abs(look.X) < 0.01) && (Math.Abs(look.Y) < 0.01)) { - pos.Z = ground + 1.5f; - AbsolutePosition = pos; + look = Velocity; + look.Normalize(); + if ((Math.Abs(look.X) < 0.01) && (Math.Abs(look.Y) < 0.01) ) + look = new Vector3(0.99f, 0.042f, 0); } - if (!MakeRootAgent(AbsolutePosition, flying)) + // Check Default Location (Also See EntityTransferModule.TeleportAgentWithinRegion) + if (AbsolutePosition.X == 128f && AbsolutePosition.Y == 128f && AbsolutePosition.Z == 22.5f) + AbsolutePosition = Scene.RegionInfo.DefaultLandingPoint; + + if (!MakeRootAgent(AbsolutePosition, flying, ref look)) { m_log.DebugFormat( - "[SCENE PRESENCE]: Aborting CompleteMovement call for {0} in {1} as they are already root", + "[SCENE PRESENCE]: Aborting CompleteMovement call for {0} in {1} as they are already root", Name, Scene.Name); return; } - // Tell the client that we're totally ready - ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); - // Child agents send initial data up in LLUDPServer.HandleUseCircuitCode() - if (!SentInitialDataToClient) - SendInitialDataToClient(); + //m_log.DebugFormat("[CompleteMovement] MakeRootAgent: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + + if(!haveGroupInformation && !IsChildAgent && !IsNPC) + { + IGroupsModule gm = m_scene.RequestModuleInterface(); + if (gm != null) + Grouptitle = gm.GetGroupTitle(m_uuid); + + //m_log.DebugFormat("[CompleteMovement] Missing Grouptitle: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + + InventoryFolderBase cof = m_scene.InventoryService.GetFolderForType(client.AgentId, (FolderType)46); + if (cof == null) + COF = UUID.Zero; + else + COF = cof.ID; - // m_log.DebugFormat("[SCENE PRESENCE] Completed movement"); + m_log.DebugFormat("[CompleteMovement]: Missing COF for {0} is {1}", client.AgentId, COF); + } if (!string.IsNullOrEmpty(m_callbackURI)) { @@ -1768,69 +2112,260 @@ namespace OpenSim.Region.Framework.Scenes // 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); + // 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); + UUID originID; + + lock (m_originRegionIDAccessLock) + originID = m_originRegionID; + + Scene.SimulationService.ReleaseAgent(originID, UUID, m_callbackURI); m_callbackURI = null; + //m_log.DebugFormat("[CompleteMovement] ReleaseAgent: {0}ms", Util.EnvironmentTickCountSubtract(ts)); } - // else - // { - // m_log.DebugFormat( - // "[SCENE PRESENCE]: No callback provided on CompleteMovement of {0} {1} to {2}", - // client.Name, client.AgentId, m_scene.RegionInfo.RegionName); - // } +// 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) + // Tell the client that we're totally ready + ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); + //m_log.DebugFormat("[CompleteMovement] MoveAgentIntoRegion: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + + bool isHGTP = (m_teleportFlags & TeleportFlags.ViaHGLogin) != 0; + + int delayctnr = Util.EnvironmentTickCount(); + + if (!IsChildAgent) { - IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); - if (m_agentTransfer != null) + if( ParentPart != null && !IsNPC && (crossingFlags & 0x08) != 0) { - // 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); + +// SceneObjectPart root = ParentPart.ParentGroup.RootPart; +// if(root.LocalId != ParentPart.LocalId) +// ControllingClient.SendEntityTerseUpdateImmediate(root); +// ControllingClient.SendEntityTerseUpdateImmediate(ParentPart); + ParentPart.ParentGroup.SendFullUpdateToClient(ControllingClient); } - IFriendsModule friendsModule = m_scene.RequestModuleInterface(); - if (friendsModule != null) - friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); + // verify baked textures and cache + bool cachedbaked = false; + + if (IsNPC) + cachedbaked = true; + else + { + if (m_scene.AvatarFactory != null && !isHGTP) + cachedbaked = m_scene.AvatarFactory.ValidateBakedTextureCache(this); + + // not sure we need this + if (!cachedbaked) + { + if (m_scene.AvatarFactory != null) + m_scene.AvatarFactory.QueueAppearanceSave(UUID); + } + } + //m_log.DebugFormat("[CompleteMovement] Baked check: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + } + + if(m_teleportFlags > 0) + { + gotCrossUpdate = false; // sanity check + if(Util.EnvironmentTickCountSubtract(delayctnr)< 500) + Thread.Sleep(500); // let viewers catch us + } + + if(!gotCrossUpdate) + RotateToLookAt(look); + + // HG + if(isHGTP) + { +// ControllingClient.SendNameReply(m_uuid, Firstname, Lastname); + m_log.DebugFormat("[CompleteMovement] HG"); + } + + m_previusParcelHide = false; + m_previusParcelUUID = UUID.Zero; + m_currentParcelHide = false; + m_currentParcelUUID = UUID.Zero; + ParcelDwellTickMS = Util.GetTimeStampMS(); + + if(!IsNPC) + { + GodController.SyncViewerState(); + + // start sending terrain patchs + if (!gotCrossUpdate) + Scene.SendLayerData(ControllingClient); + } + // send initial land overlay and parcel + ILandChannel landch = m_scene.LandChannel; + if (landch != null) + landch.sendClientInitialLandInfo(client); + + if (!IsChildAgent) + { + List allpresences = m_scene.GetScenePresences(); + + // send avatar object to all presences including us, so they cross it into region + // then hide if necessary + + SendInitialAvatarDataToAllAgents(allpresences); + + // send this look + SendAppearanceToAgent(this); + + // send this animations + + UUID[] animIDs = null; + int[] animseqs = null; + UUID[] animsobjs = null; + + if (Animator != null) + Animator.GetArrays(out animIDs, out animseqs, out animsobjs); + + bool haveAnims = (animIDs != null && animseqs != null && animsobjs != null); + + if (haveAnims) + SendAnimPackToAgent(this, animIDs, animseqs, animsobjs); + + // we should be able to receive updates, etc + // so release them + m_inTransit = false; + + // send look and animations to others + // if not cached we send greys + // uncomented if will wait till avatar does baking + //if (cachedbaked) + { + foreach (ScenePresence p in allpresences) + { + if (p == this) + continue; + + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + continue; + + SendAppearanceToAgentNF(p); + if (haveAnims) + SendAnimPackToAgentNF(p, animIDs, animseqs, animsobjs); + } + } // greys if + + //m_log.DebugFormat("[CompleteMovement] ValidateAndSendAppearanceAndAgentData: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + + // attachments + if (IsNPC || IsRealLogin(m_teleportFlags)) + { + if (Scene.AttachmentsModule != null) + // Util.FireAndForget( + // o => + // { + + if (!IsNPC) + Scene.AttachmentsModule.RezAttachments(this); + else + Util.FireAndForget(x => + { + Scene.AttachmentsModule.RezAttachments(this); + }); + + // }); + } + else + { + if (m_attachments.Count > 0) + { + m_log.DebugFormat( + "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name); + + foreach (SceneObjectGroup sog in m_attachments) + { + sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); + sog.ResumeScripts(); + } + + foreach (ScenePresence p in allpresences) + { + if (p == this) + { + SendAttachmentsToAgentNF(this); + continue; + } + + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + continue; + + SendAttachmentsToAgentNF(p); + } + } + } + //m_log.DebugFormat("[CompleteMovement] attachments: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + if (openChildAgents) + { + // Create child agents in neighbouring regions + IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); + if (m_agentTransfer != null) + { + m_agentTransfer.EnableChildAgents(this); + } + } + // let updates be sent, with some delay + m_lastChildUpdatesTime = Util.EnvironmentTickCount() + 10000; + m_lastChildAgentUpdateGodLevel = GodController.ViwerUIGodLevel; + m_lastChildAgentUpdateDrawDistance = DrawDistance; + m_lastChildAgentUpdatePosition = AbsolutePosition; + m_childUpdatesBusy = false; // allow them } - // 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("[CompleteMovement] openChildAgents: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + + // send the rest of the world + if (m_teleportFlags > 0 && !IsNPC || m_currentParcelHide) + SendInitialDataToMe(); + + // priority uses avatar position only +// m_reprioritizationLastPosition = AbsolutePosition; +// m_reprioritizationLastDrawDistance = DrawDistance; +// m_reprioritizationLastTime = Util.EnvironmentTickCount() + 15000; // delay it +// m_reprioritizationBusy = false; + + //m_log.DebugFormat("[CompleteMovement] SendInitialDataToMe: {0}ms", Util.EnvironmentTickCountSubtract(ts)); + + if (!IsChildAgent && openChildAgents) + { + IFriendsModule friendsModule = m_scene.RequestModuleInterface(); + if (friendsModule != null) + { + if(gotCrossUpdate) + friendsModule.IsNowRoot(this); + else + friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); + } + //m_log.DebugFormat("[CompleteMovement] friendsModule: {0}ms", Util.EnvironmentTickCountSubtract(ts)); - // 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; + haveGroupInformation = false; + gotCrossUpdate = false; + crossingFlags = 0; + m_inTransit = false; } - } + + m_scene.EventManager.OnRegionHeartbeatEnd += RegionHeartbeatEnd; - private void ScheduleAttachmentsForFullUpdate() - { - lock (m_attachments) - { - foreach (SceneObjectGroup sog in m_attachments) - sog.ScheduleGroupForFullUpdate(); - } + m_log.DebugFormat("[CompleteMovement] end: {0}ms", Util.EnvironmentTickCountSubtract(ts)); } /// @@ -1841,30 +2376,71 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// - /// + /// - private void UpdateCameraCollisionPlane(Vector4 plane) + private void checkCameraCollision() { - if (m_lastCameraCollisionPlane != plane) + if(m_doingCamRayCast || !m_scene.PhysicsScene.SupportsRayCast()) + return; + + if(m_mouseLook || ParentID != 0) { - m_lastCameraCollisionPlane = plane; - ControllingClient.SendCameraConstraint(plane); + if (CameraConstraintActive) + { + Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -10000f); // not right... + UpdateCameraCollisionPlane(plane); + CameraConstraintActive = false; + } + return; } - } + + Vector3 posAdjusted = AbsolutePosition; + posAdjusted.Z += 1.0f; // viewer current camera focus point - public void RayCastCameraCallback(bool hitYN, Vector3 collisionPoint, uint localid, float distance, Vector3 pNormal) - { - const float POSITION_TOLERANCE = 0.02f; - const float ROTATION_TOLERANCE = 0.02f; + if(posAdjusted.ApproxEquals(m_lastCameraRayCastPos, 0.2f) && + CameraPosition.ApproxEquals(m_lastCameraRayCastCam, 0.2f)) + return; - m_doingCamRayCast = false; - if (hitYN && localid != LocalId) - { - SceneObjectGroup group = m_scene.GetGroupByPrim(localid); - bool IsPrim = group != null; - if (IsPrim) + m_lastCameraRayCastCam = CameraPosition; + m_lastCameraRayCastPos = posAdjusted; + + Vector3 tocam = CameraPosition - posAdjusted; + + float distTocamlen = tocam.LengthSquared(); + if (distTocamlen > 0.01f && distTocamlen < 400) + { + distTocamlen = (float)Math.Sqrt(distTocamlen); + tocam *= (1.0f / distTocamlen); + + m_doingCamRayCast = true; + m_scene.PhysicsScene.RaycastWorld(posAdjusted, tocam, distTocamlen + 1.0f, RayCastCameraCallback); + return; + } + + if (CameraConstraintActive) + { + Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -10000f); // not right... + UpdateCameraCollisionPlane(plane); + CameraConstraintActive = false; + } + } + + 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) + { + if (hitYN && localid != LocalId) + { + if (localid != 0) { - SceneObjectPart part = group.GetPart(localid); + SceneObjectPart part = m_scene.GetSceneObjectPart(localid); if (part != null && !part.VolumeDetectActive) { CameraConstraintActive = true; @@ -1897,13 +2473,14 @@ namespace OpenSim.Region.Framework.Scenes UpdateCameraCollisionPlane(plane); } } - else if (!m_pos.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) || - !Rotation.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE)) + else if(CameraConstraintActive) { Vector4 plane = new Vector4(0.9f, 0.0f, 0.361f, -9000f); // not right... UpdateCameraCollisionPlane(plane); CameraConstraintActive = false; } + + m_doingCamRayCast = false; } /// @@ -1921,12 +2498,17 @@ namespace OpenSim.Region.Framework.Scenes return; } + if (IsInTransit) + return; + #region Sanity Checking // This is irritating. Really. if (!AbsolutePosition.IsFinite()) { - RemoveFromPhysicalScene(); + bool isphysical = PhysicsActor != null; + if(isphysical) + RemoveFromPhysicalScene(); m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999902"); m_pos = m_LastFinitePos; @@ -1938,7 +2520,8 @@ namespace OpenSim.Region.Framework.Scenes m_log.Error("[AVATAR]: NonFinite Avatar position detected... Reset Position. Mantis this please. Error #9999903"); } - AddToPhysicalScene(false); + if(isphysical) + AddToPhysicalScene(false); } else { @@ -1953,18 +2536,18 @@ namespace OpenSim.Region.Framework.Scenes // 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 + // changes, then start using the agent's drawdistance rather than the // region's draw distance. + DrawDistance = agentData.Far; - // DrawDistance = Scene.DefaultDrawDistance; m_mouseLook = (flags & AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 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 + // 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; + m_leftButtonDown = (flags & AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0; #endregion Inputs @@ -1977,6 +2560,7 @@ namespace OpenSim.Region.Framework.Scenes // (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0) // m_updateCount = UPDATE_COUNT; + if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_STAND_UP) != 0) { StandUp(); @@ -1984,38 +2568,8 @@ namespace OpenSim.Region.Framework.Scenes // Raycast from the avatar's head to the camera to see if there's anything blocking the view // this exclude checks may not be complete - - if (m_movementUpdateCount % NumMovementsBetweenRayCast == 0 && m_scene.PhysicsScene.SupportsRayCast()) - { - if (!m_doingCamRayCast && !m_mouseLook && ParentID == 0) - { - 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; - } - } + if(agentData.NeedsCameraCollision) // condition parentID may be wrong + checkCameraCollision(); uint flagsForScripts = (uint)flags; flags = RemoveIgnoredControls(flags, IgnoredControls); @@ -2032,7 +2586,7 @@ namespace OpenSim.Region.Framework.Scenes // 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); + SendAgentTerseUpdate(this); PhysicsActor actor = PhysicsActor; @@ -2046,9 +2600,7 @@ namespace OpenSim.Region.Framework.Scenes if (AllowMovement && !SitGround) { // m_log.DebugFormat("[SCENE PRESENCE]: Initial body rotation {0} for {1}", agentData.BodyRotation, Name); - bool update_rotation = false; - if (agentData.BodyRotation != Rotation) { Rotation = agentData.BodyRotation; @@ -2056,31 +2608,26 @@ namespace OpenSim.Region.Framework.Scenes } 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; - } - + bool mvToTarget = m_movingToTarget; if (agentData.UseClientAgentPosition) { - MovingToTarget = (agentData.ClientAgentPosition - AbsolutePosition).Length() > 0.2f; - MoveToPositionTarget = agentData.ClientAgentPosition; + m_movingToTarget = (agentData.ClientAgentPosition - AbsolutePosition).LengthSquared() > 0.04f; + m_moveToPositionTarget = agentData.ClientAgentPosition; + m_moveToSpeed = -1f; } int i = 0; bool DCFlagKeyPressed = false; Vector3 agent_control_v3 = Vector3.Zero; - bool newFlying = actor.Flying; + bool newFlying = false; if (ForceFly) newFlying = true; else if (FlyDisabled) newFlying = false; + else if(mvToTarget) + newFlying = actor.Flying; else newFlying = ((flags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); @@ -2096,6 +2643,15 @@ 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; + // A DIR_CONTROL_FLAG occurs when the user is trying to move in a particular direction. foreach (Dir_ControlFlags DCF in DIR_CONTROL_FLAGS) { @@ -2105,9 +2661,7 @@ namespace OpenSim.Region.Framework.Scenes try { - // 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]; + agent_control_v3 += Dir_Vectors[i]; //m_log.DebugFormat("[Motion]: {0}, {1}",i, dirVectors[i]); } catch (IndexOutOfRangeException) @@ -2115,10 +2669,10 @@ namespace OpenSim.Region.Framework.Scenes // Why did I get this? } - if (((MovementFlag & (uint)DCF) == 0) & !AgentControlStopActive) - { + if (((MovementFlag & (uint)DCF) == 0)) + { //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with {1}", Name, DCF); - MovementFlag += (uint)DCF; + MovementFlag |= (uint)DCF; update_movementflag = true; } } @@ -2127,7 +2681,7 @@ namespace OpenSim.Region.Framework.Scenes if ((MovementFlag & (uint)DCF) != 0) { //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with lack of {1}", Name, DCF); - MovementFlag -= (uint)DCF; + MovementFlag &= (uint)~DCF; update_movementflag = true; /* @@ -2154,7 +2708,7 @@ namespace OpenSim.Region.Framework.Scenes update_movementflag = true; } - if (MovingToTarget) + if (m_movingToTarget) { // If the user has pressed a key then we want to cancel any move to target. if (DCFlagKeyPressed) @@ -2167,7 +2721,7 @@ namespace OpenSim.Region.Framework.Scenes // The UseClientAgentPosition is set if parcel ban is forcing the avatar to move to a // certain position. It's only check for tolerance on returning to that position is 0.2 // rather than 1, at which point it removes its force target. - if (HandleMoveToTargetUpdate(agentData.UseClientAgentPosition ? 0.2 : 1, ref agent_control_v3)) + if (HandleMoveToTargetUpdate(agentData.UseClientAgentPosition ? 0.2f : 1f, ref agent_control_v3)) update_movementflag = true; } } @@ -2180,11 +2734,11 @@ namespace OpenSim.Region.Framework.Scenes if (Flying && !ForceFly) { // Need to stop in mid air if user holds down AGENT_CONTROL_STOP - if (AgentControlStopActive) - { - agent_control_v3 = Vector3.Zero; - } - else + // if (AgentControlStopActive) + // { + // agent_control_v3 = Vector3.Zero; + // } + // else { // Landing detection code @@ -2192,38 +2746,43 @@ namespace OpenSim.Region.Framework.Scenes bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); - //m_log.Debug("[CONTROL]: " +flags); + //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, + 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); + -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_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(); + } + */ } } + else if (IsColliding && agent_control_v3.Z < 0f) + agent_control_v3.Z = 0; +// else if(AgentControlStopActive %% Velocity.Z <0.01f) // m_log.DebugFormat("[SCENE PRESENCE]: MovementFlag {0} for {1}", MovementFlag, Name); @@ -2231,54 +2790,60 @@ namespace OpenSim.Region.Framework.Scenes // which occurs later in the main scene loop // 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 + // if the user rotated whilst holding down AGENT_CONTROL_STOP when already still (which locks the // avatar location in place). - if (update_movementflag + + if (update_movementflag || (update_rotation && DCFlagKeyPressed && (!AgentControlStopActive || MovementFlag != 0))) { -// 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; + if (AgentControlStopActive) + { + // if (MovementFlag == 0 && Animator.Falling) + if (MovementFlag == 0 && Animator.currentControlState == ScenePresenceAnimator.motionControlStates.falling) + { + AddNewMovement(agent_control_v3, AgentControlStopSlowVel, true); + } else - speedModifier = 1; - - AddNewMovement(agent_control_v3, speedModifier); -// } + AddNewMovement(agent_control_v3, AgentControlStopSlowVel); + } + else + { + if(m_movingToTarget || + (Animator.currentControlState != ScenePresenceAnimator.motionControlStates.flying && + Animator.currentControlState != ScenePresenceAnimator.motionControlStates.onsurface) + ) + AddNewMovement(agent_control_v3); + else + { + if (MovementFlag != 0) + AddNewMovement(agent_control_v3); + else + m_delayedStop = Util.GetTimeStampMS() + 200.0; + } + } } -// else -// { -// if (!update_movementflag) -// { -// m_log.DebugFormat( -// "[SCENE PRESENCE]: In {0} ignoring requested update of {1} for {2} as update_movementflag = false", -// m_scene.RegionInfo.RegionName, agent_control_v3, Name); -// } -// } - - if (update_movementflag && ParentID == 0) +/* + if (update_movementflag && ParentID == 0 && m_delayedStop < 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); + SendAgentTerseUpdate(this); - m_scene.EventManager.TriggerOnClientMovement(this); +// m_scene.EventManager.TriggerOnClientMovement(this); } + private void HandleAgentFOV(IClientAPI remoteClient, float _fov) + { + m_FOV = _fov; + } /// /// This is the event handler for client cameras. If a client is moving, or moving the camera, this event is triggering. @@ -2290,60 +2855,37 @@ namespace OpenSim.Region.Framework.Scenes // 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; + if(IsInTransit) + return; // 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 + + // this may need lock 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; + CameraAtAxis.Normalize(); + CameraLeftAxis.Normalize(); + CameraUpAxis.Normalize(); + Quaternion camRot = Util.Axes2Rot(CameraAtAxis, CameraLeftAxis, CameraUpAxis); + CameraRotation = camRot; - //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); - } - } + if(agentData.NeedsCameraCollision) + checkCameraCollision(); TriggerScenePresenceUpdated(); } - + /// /// Calculate an update to move the presence to the set target. /// @@ -2352,125 +2894,158 @@ namespace OpenSim.Region.Framework.Scenes /// /// Cumulative agent movement that this method will update. /// True if movement has been updated in some way. False otherwise. - public bool HandleMoveToTargetUpdate(double tolerance, ref Vector3 agent_control_v3) + public bool HandleMoveToTargetUpdate(float tolerance, ref Vector3 agent_control_v3) { // m_log.DebugFormat("[SCENE PRESENCE]: Called HandleMoveToTargetUpdate() for {0}", Name); bool updated = false; + Vector3 LocalVectorToTarget3D = m_moveToPositionTarget - AbsolutePosition; + // m_log.DebugFormat( // "[SCENE PRESENCE]: bAllowUpdateMoveToPosition {0}, m_moveToPositionInProgress {1}, m_autopilotMoving {2}", // allowUpdate, m_moveToPositionInProgress, m_autopilotMoving); - double distanceToTarget = Util.GetDistanceTo(AbsolutePosition, MoveToPositionTarget); + float distanceToTarget; + if(Flying && !LandAtTarget) + { + distanceToTarget = LocalVectorToTarget3D.Length(); + } + else + { + distanceToTarget = (float)Math.Sqrt(LocalVectorToTarget3D.X * LocalVectorToTarget3D.X + + LocalVectorToTarget3D.Y * LocalVectorToTarget3D.Y); + } -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Abs pos of {0} is {1}, target {2}, distance {3}", -// Name, AbsolutePosition, MoveToPositionTarget, distanceToTarget); + // m_log.DebugFormat( + // "[SCENE PRESENCE]: Abs pos of {0} is {1}, target {2}, distance {3}", + // Name, AbsolutePosition, MoveToPositionTarget, distanceToTarget); // Check the error term of the current position in relation to the target position if (distanceToTarget <= tolerance) { // We are close enough to the target - AbsolutePosition = MoveToPositionTarget; + Velocity = Vector3.Zero; + AbsolutePosition = m_moveToPositionTarget; + if (Flying) + { + if (LandAtTarget) + Flying = false; + + // A horrible hack to stop the avatar dead in its tracks rather than having them overshoot + // the target if flying. + // We really need to be more subtle (slow the avatar as it approaches the target) or at + // least be able to set collision status once, rather than 5 times to give it enough + // weighting so that that PhysicsActor thinks it really is colliding. + for (int i = 0; i < 5; i++) + IsColliding = true; + } ResetMoveToTarget(); - updated = true; + return false; } - else + + if(m_moveToSpeed > 0 && distanceToTarget <= m_moveToSpeed * Scene.FrameTime) + m_moveToSpeed = distanceToTarget / Scene.FrameTime; + + try { - try - { - // move avatar in 3D at one meter/second towards target, in avatar coordinate frame. - // This movement vector gets added to the velocity through AddNewMovement(). - // Theoretically we might need a more complex PID approach here if other - // unknown forces are acting on the avatar and we need to adaptively respond - // to such forces, but the following simple approach seems to works fine. - Vector3 LocalVectorToTarget3D = - (MoveToPositionTarget - AbsolutePosition) // vector from cur. pos to target in global coords - * Matrix4.CreateFromQuaternion(Quaternion.Inverse(Rotation)); // change to avatar coords - // Ignore z component of vector -// Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f); - LocalVectorToTarget3D.Normalize(); - - // update avatar movement flags. the avatar coordinate system is as follows: - // - // +X (forward) - // - // ^ - // | - // | - // | - // | - // (left) +Y <--------o--------> -Y - // avatar - // | - // | - // | - // | - // v - // -X - // + // move avatar in 3D towards target, in avatar coordinate frame. + // This movement vector gets added to the velocity through AddNewMovement(). + // Theoretically we might need a more complex PID approach here if other + // unknown forces are acting on the avatar and we need to adaptively respond + // to such forces, but the following simple approach seems to works fine. - // based on the above avatar coordinate system, classify the movement into - // one of left/right/back/forward. - if (LocalVectorToTarget3D.X < 0) //MoveBack - { - MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; - AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; - updated = true; - } - else if (LocalVectorToTarget3D.X > 0) //Move Forward - { - MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; - AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; - updated = true; - } + float angle = 0.5f * (float)Math.Atan2(LocalVectorToTarget3D.Y, LocalVectorToTarget3D.X); + Quaternion rot = new Quaternion(0,0, (float)Math.Sin(angle),(float)Math.Cos(angle)); + Rotation = rot; + LocalVectorToTarget3D = LocalVectorToTarget3D * Quaternion.Inverse(rot); // change to avatar coords + LocalVectorToTarget3D.Normalize(); - if (LocalVectorToTarget3D.Y > 0) //MoveLeft - { - MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; - AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; - updated = true; - } - else if (LocalVectorToTarget3D.Y < 0) //MoveRight - { - MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; - AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; - updated = true; - } + // update avatar movement flags. the avatar coordinate system is as follows: + // + // +X (forward) + // + // ^ + // | + // | + // | + // | + // (left) +Y <--------o--------> -Y + // avatar + // | + // | + // | + // | + // v + // -X + // - if (LocalVectorToTarget3D.Z > 0) //Up - { - // Don't set these flags for up or down - doing so will make the avatar crouch or - // keep trying to jump even if walking along level ground - //MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_UP; - //AgentControlFlags - //AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_UP; - updated = true; - } - else if (LocalVectorToTarget3D.Z < 0) //Down - { - //MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN; - //AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN; - updated = true; - } + // based on the above avatar coordinate system, classify the movement into + // one of left/right/back/forward. + + const uint noMovFlagsMask = (uint)(~(Dir_ControlFlags.DIR_CONTROL_FLAG_BACK | + Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD | Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT | + Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT | Dir_ControlFlags.DIR_CONTROL_FLAG_UP | + Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN)); + + MovementFlag &= noMovFlagsMask; + uint tmpAgentControlFlags = (uint)m_AgentControlFlags; + tmpAgentControlFlags &= noMovFlagsMask; + if (LocalVectorToTarget3D.X < 0) //MoveBack + { + MovementFlag |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; + tmpAgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; + updated = true; + } + else if (LocalVectorToTarget3D.X > 0) //Move Forward + { + MovementFlag |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; + tmpAgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; + updated = true; + } + + if (LocalVectorToTarget3D.Y > 0) //MoveLeft + { + MovementFlag |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; + tmpAgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; + updated = true; + } + else if (LocalVectorToTarget3D.Y < 0) //MoveRight + { + MovementFlag |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; + tmpAgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; + updated = true; + } + + if (LocalVectorToTarget3D.Z > 0) //Up + updated = true; + + else if (LocalVectorToTarget3D.Z < 0) //Down + updated = true; + // m_log.DebugFormat( // "[SCENE PRESENCE]: HandleMoveToTargetUpdate adding {0} to move vector {1} for {2}", // LocalVectorToTarget3D, agent_control_v3, Name); + m_AgentControlFlags = (AgentManager.ControlFlags) tmpAgentControlFlags; + if(updated) agent_control_v3 += LocalVectorToTarget3D; - } - catch (Exception e) - { - //Avoid system crash, can be slower but... - m_log.DebugFormat("Crash! {0}", e.ToString()); - } + } + catch (Exception e) + { + //Avoid system crash, can be slower but... + m_log.DebugFormat("Crash! {0}", e.ToString()); } return updated; +// AddNewMovement(agent_control_v3); } + public void MoveToTargetHandle(Vector3 pos, bool noFly, bool landAtTarget) + { + MoveToTarget(pos, noFly, landAtTarget); + } /// /// Move to the given target over time. /// @@ -2483,8 +3058,10 @@ namespace OpenSim.Region.Framework.Scenes /// /// If true and the avatar starts flying during the move then land at the target. /// - public void MoveToTarget(Vector3 pos, bool noFly, bool landAtTarget) - { + public void MoveToTarget(Vector3 pos, bool noFly, bool landAtTarget, float tau = -1f) + { + m_delayedStop = -1; + if (SitGround) StandUp(); @@ -2494,89 +3071,61 @@ namespace OpenSim.Region.Framework.Scenes // Allow move to another sub-region within a megaregion Vector2 regionSize; - IRegionCombinerModule regionCombinerModule = m_scene.RequestModuleInterface(); - if (regionCombinerModule != null) - regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID); - else - regionSize = new Vector2(m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY); + 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; + float terrainHeight; Scene targetScene = m_scene; + terrainHeight = m_scene.GetGroundHeight(pos.X, pos.Y); -// Vector3 heightAdjust = new Vector3(0, 0, Appearance.AvatarHeight / 2); -// pos += heightAdjust; -// -// // Anti duck-walking measure -// if (Math.Abs(pos.Z - AbsolutePosition.Z) < 0.2f) -// { -//// m_log.DebugFormat("[SCENE PRESENCE]: Adjusting MoveToPosition from {0} to {1}", pos, AbsolutePosition); -// pos.Z = AbsolutePosition.Z; -// } - - // Get terrain height for sub-region in a megaregion if necessary - - //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 % regionSize.X), (int)(pos.Y % regionSize.Y)]; - pos.Z = Math.Max(terrainHeight, pos.Z); + // dont try to land underground + terrainHeight += Appearance.AvatarHeight * 0.5f + 0.2f; - // Fudge factor. It appears that if one clicks "go here" on a piece of ground, the go here request is - // always slightly higher than the actual terrain height. - // FIXME: This constrains NPC movements as well, so should be somewhere else. - if (pos.Z - terrainHeight < 0.2) + if(terrainHeight > pos.Z) pos.Z = terrainHeight; - 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; + terrainHeight += Appearance.AvatarHeight; // so 1.5 * AvatarHeight above ground at target + bool shouldfly = Flying; + if (noFly) + shouldfly = false; + else if (pos.Z > terrainHeight || Flying) + shouldfly = true; - // Rotate presence around the z-axis to point in same direction as movement. - // Ignore z component of vector Vector3 localVectorToTarget3D = pos - AbsolutePosition; - Vector3 localVectorToTarget2D = new Vector3((float)(localVectorToTarget3D.X), (float)(localVectorToTarget3D.Y), 0f); -// m_log.DebugFormat("[SCENE PRESENCE]: Local vector to target is {0}", localVectorToTarget2D); +// m_log.DebugFormat("[SCENE PRESENCE]: Local vector to target is {0},[1}", localVectorToTarget3D.X,localVectorToTarget3D.Y); + + m_movingToTarget = true; + LandAtTarget = landAtTarget; + m_moveToPositionTarget = pos; + if(tau > 0) + { + if(tau < Scene.FrameTime) + tau = Scene.FrameTime; + m_moveToSpeed = localVectorToTarget3D.Length() / tau; + if(m_moveToSpeed < 0.5f) //to tune + m_moveToSpeed = 0.5f; + else if(m_moveToSpeed > 50f) + m_moveToSpeed = 50f; - // Calculate the yaw. - Vector3 angle = new Vector3(0, 0, (float)(Math.Atan2(localVectorToTarget2D.Y, localVectorToTarget2D.X))); + SetAlwaysRun = false; + } + else + m_moveToSpeed = 4.096f * m_speedModifier; -// m_log.DebugFormat("[SCENE PRESENCE]: Angle is {0}", angle); + Flying = shouldfly; - Rotation = Quaternion.CreateFromEulers(angle); -// m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, Rotation); - - Vector3 agent_control_v3 = new Vector3(); - HandleMoveToTargetUpdate(1, ref agent_control_v3); - AddNewMovement(agent_control_v3); + Vector3 control = Vector3.Zero; + if(HandleMoveToTargetUpdate(1f, ref control)) + AddNewMovement(control); } /// @@ -2586,9 +3135,11 @@ namespace OpenSim.Region.Framework.Scenes { // m_log.DebugFormat("[SCENE PRESENCE]: Resetting move to target for {0}", Name); - MovingToTarget = false; + m_movingToTarget = false; + m_moveToSpeed = -1f; // MoveToPositionTarget = Vector3.Zero; - m_forceToApply = null; // cancel possible last action +// lock(m_forceToApplyLock) +// m_forceToApplyValid = false; // 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. @@ -2629,69 +3180,65 @@ namespace OpenSim.Region.Framework.Scenes } } +// part.ParentGroup.DeleteAvatar(UUID); + + Quaternion standRotation = part.ParentGroup.RootPart.RotationOffset; + Vector3 sitPartWorldPosition = part.ParentGroup.AbsolutePosition + m_pos * standRotation; ControllingClient.SendClearFollowCamProperties(part.ParentUUID); ParentID = 0; ParentPart = null; - Quaternion standRotation; - if (part.SitTargetAvatar == UUID) - { - standRotation = part.GetWorldRotation(); + standRotation = standRotation * part.SitTargetOrientation; + else + standRotation = standRotation * m_bodyRot; - if (!part.IsRoot) - standRotation = standRotation * part.SitTargetOrientation; -// standRotation = part.RotationOffset * part.SitTargetOrientation; -// else -// standRotation = part.SitTargetOrientation; + m_bodyRot = standRotation; + Quaternion standRotationZ = new Quaternion(0,0,standRotation.Z,standRotation.W); + + float t = standRotationZ.W * standRotationZ.W + standRotationZ.Z * standRotationZ.Z; + if (t > 0) + { + t = 1.0f / (float)Math.Sqrt(t); + standRotationZ.W *= t; + standRotationZ.Z *= t; } else { - standRotation = Rotation; + standRotationZ.W = 1.0f; + standRotationZ.Z = 0f; } - //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 adjustmentForSitPose = new Vector3(0.75f, 0, m_sitAvatarHeight + .3f) * standRotationZ; - Vector3 standPos = part.ParentGroup.AbsolutePosition + adjustmentForSitPosition + adjustmentForSitPose; + Vector3 standPos = sitPartWorldPosition + adjustmentForSitPose; + m_pos = standPos; -// 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 + // 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(this); - part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); + + SendAvatarDataToAllAgents(); + m_scene.EventManager.TriggerParcelPrimCountTainted(); // update select/ sat on } - else if (PhysicsActor == null) - AddToPhysicalScene(false); + // reset to default sitAnimation + sitAnimation = "SIT"; + +// Animator.TrySetMovementAnimation("STAND"); + Animator.SetMovementAnimations("STAND"); - Animator.TrySetMovementAnimation("STAND"); TriggerScenePresenceUpdated(); } @@ -2746,28 +3293,14 @@ namespace OpenSim.Region.Framework.Scenes if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero) { -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Sitting {0} on {1} {2} because sit target is set and unoccupied", -// Name, part.Name, part.LocalId); - 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 + if (PhysicsSit(part,offset)) // physics engine return; Vector3 pos = part.AbsolutePosition + offset; @@ -2781,55 +3314,45 @@ namespace OpenSim.Region.Framework.Scenes if (canSit) { - if (PhysicsActor != null) { // We can remove the physicsActor until they stand up. RemoveFromPhysicalScene(); } - if (MovingToTarget) + if (m_movingToTarget) ResetMoveToTarget(); Velocity = Vector3.Zero; + m_AngularVelocity = 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; - } + forceMouselook = part.GetForceMouselook(); - if ((cameraEyeOffset != Vector3.Zero && !cameraEyeOffsetFromRootForChild) || cameraAtOffset != Vector3.Zero) + if (!part.IsRoot) { - if (!part.IsRoot) + sitOrientation = part.RotationOffset * sitOrientation; + offset = offset * part.RotationOffset; + offset += part.OffsetPosition; + + if (cameraAtOffset == Vector3.Zero && cameraEyeOffset == Vector3.Zero) { - cameraEyeOffset = cameraEyeOffset * part.RotationOffset; + cameraAtOffset = part.ParentGroup.RootPart.GetCameraAtOffset(); + cameraEyeOffset = part.ParentGroup.RootPart.GetCameraEyeOffset(); + } + else + { + cameraAtOffset = cameraAtOffset * part.RotationOffset; cameraAtOffset += part.OffsetPosition; + cameraEyeOffset = cameraEyeOffset * part.RotationOffset; + cameraEyeOffset += 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( part.ParentGroup.UUID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); @@ -2840,6 +3363,7 @@ namespace OpenSim.Region.Framework.Scenes // Moved here to avoid a race with default sit anim // The script event needs to be raised after the default sit anim is set. part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); + m_scene.EventManager.TriggerParcelPrimCountTainted(); // update select/ sat on } } @@ -2862,7 +3386,6 @@ namespace OpenSim.Region.Framework.Scenes { m_requestedSitTargetID = part.LocalId; m_requestedSitTargetUUID = part.UUID; - } else { @@ -2875,13 +3398,8 @@ namespace OpenSim.Region.Framework.Scenes // returns false if does not suport so older sit can be tried public bool PhysicsSit(SceneObjectPart part, Vector3 offset) { -// TODO: Pull in these bits - return false; -/* if (part == null || part.ParentGroup.IsAttachment) - { return true; - } if ( m_scene.PhysicsScene == null) return false; @@ -2893,24 +3411,20 @@ namespace OpenSim.Region.Framework.Scenes ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot."); else { // non physical phantom TODO - ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot."); +// ControllingClient.SendAlertMessage(" There is no suitable surface to sit on, try another spot."); return false; } return true; } - - // not doing autopilot - m_requestedSitTargetID = 0; - if (m_scene.PhysicsScene.SitAvatar(part.PhysActor, AbsolutePosition, CameraPosition, offset, new Vector3(0.35f, 0, 0.65f), PhysicsSitResponse) != 0) + { return true; + } return false; -*/ } - private bool CanEnterLandPosition(Vector3 testPos) { ILandObject land = m_scene.LandChannel.GetLandObject(testPos.X, testPos.Y); @@ -2939,7 +3453,7 @@ namespace OpenSim.Region.Framework.Scenes if (part == null) return; - Vector3 targetPos = part.GetWorldPosition() + offset * part.GetWorldRotation(); + Vector3 targetPos = part.GetWorldPosition() + offset * part.GetWorldRotation(); if(!CanEnterLandPosition(targetPos)) { ControllingClient.SendAlertMessage(" Sit position on restricted land, try another spot"); @@ -2948,36 +3462,58 @@ namespace OpenSim.Region.Framework.Scenes RemoveFromPhysicalScene(); - if (MovingToTarget) + if (m_movingToTarget) ResetMoveToTarget(); Velocity = Vector3.Zero; + m_AngularVelocity = Vector3.Zero; + m_requestedSitTargetID = 0; part.AddSittingAvatar(this); + ParentPart = part; + ParentID = part.LocalId; + Vector3 cameraAtOffset = part.GetCameraAtOffset(); Vector3 cameraEyeOffset = part.GetCameraEyeOffset(); bool forceMouselook = part.GetForceMouselook(); - ControllingClient.SendSitResponse( - part.UUID, offset, Orientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); + if (!part.IsRoot) + { + Orientation = part.RotationOffset * Orientation; + offset = offset * part.RotationOffset; + offset += part.OffsetPosition; - // not using autopilot + if (cameraAtOffset == Vector3.Zero && cameraEyeOffset == Vector3.Zero) + { + cameraAtOffset = part.ParentGroup.RootPart.GetCameraAtOffset(); + cameraEyeOffset = part.ParentGroup.RootPart.GetCameraEyeOffset(); + } + else + { + cameraAtOffset = cameraAtOffset * part.RotationOffset; + cameraAtOffset += part.OffsetPosition; + cameraEyeOffset = cameraEyeOffset * part.RotationOffset; + cameraEyeOffset += part.OffsetPosition; + } + } - Rotation = Orientation; + m_bodyRot = Orientation; m_pos = offset; - m_requestedSitTargetID = 0; + ControllingClient.SendSitResponse( + part.ParentGroup.UUID, offset, Orientation, true, cameraAtOffset, cameraEyeOffset, forceMouselook); - ParentPart = part; - ParentID = part.LocalId; - if(status == 3) - Animator.TrySetMovementAnimation("SIT_GROUND"); + SendAvatarDataToAllAgents(); + + if (status == 3) + sitAnimation = "SIT_GROUND"; else - Animator.TrySetMovementAnimation("SIT"); - SendAvatarDataToAllClients(); + sitAnimation = "SIT"; + Animator.SetMovementAnimations("SIT"); part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); + m_scene.EventManager.TriggerParcelPrimCountTainted(); // update select/ sat on } public void HandleAgentSit(IClientAPI remoteClient, UUID agentID) @@ -2985,7 +3521,7 @@ namespace OpenSim.Region.Framework.Scenes if (IsChildAgent) return; - SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); + SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); if (part != null) { @@ -3007,45 +3543,77 @@ namespace OpenSim.Region.Framework.Scenes // "[SCENE PRESENCE]: Sitting {0} at sit target {1}, {2} on {3} {4}", // Name, sitTargetPos, sitTargetOrient, part.Name, part.LocalId); - //Quaternion vq = new Quaternion(sitTargetPos.X, sitTargetPos.Y+0.2f, sitTargetPos.Z+0.2f, 0); - //Quaternion nq = new Quaternion(-sitTargetOrient.X, -sitTargetOrient.Y, -sitTargetOrient.Z, sitTargetOrient.w); - - //Quaternion result = (sitTargetOrient * vq) * nq; + double x, y, z, m; + Vector3 sitOffset; + Quaternion r = sitTargetOrient; - double x, y, z, m1, m2; + Vector3 newPos; - 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) + if (LegacySitOffsets) { - offset /= m; + double m1,m2; + + 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. + 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); + sitOffset = up * (float)offset; + newPos = sitTargetPos - sitOffset + SIT_TARGET_ADJUSTMENT; } + else + { + m = r.X * r.X + r.Y * r.Y + r.Z * r.Z + r.W * r.W; + + if (Math.Abs(1.0 - m) > 0.000001) + { + if(m != 0) + { + m = 1.0 / Math.Sqrt(m); + r.X *= (float)m; + r.Y *= (float)m; + r.Z *= (float)m; + r.W *= (float)m; + } + else + { + r.X = 0.0f; + r.Y = 0.0f; + r.Z = 0.0f; + r.W = 1.0f; + m = 1.0f; + } + } - Vector3 up = new Vector3((float)x, (float)y, (float)z); - Vector3 sitOffset = up * (float)offset; + x = 2 * (r.X * r.Z + r.Y * r.W); + y = 2 * (-r.X * r.W + r.Y * r.Z); + z = -r.X * r.X - r.Y * r.Y + r.Z * r.Z + r.W * r.W; + Vector3 up = new Vector3((float)x, (float)y, (float)z); + sitOffset = up * Appearance.AvatarHeight * 0.02638f; + newPos = sitTargetPos + sitOffset + SIT_TARGET_ADJUSTMENT; + } - // 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) @@ -3078,19 +3646,25 @@ namespace OpenSim.Region.Framework.Scenes // Name, part.AbsolutePosition, m_pos, ParentPosition, part.Name, part.LocalId); } + part.AddSittingAvatar(this); ParentPart = part; ParentID = m_requestedSitTargetID; + + RemoveFromPhysicalScene(); m_AngularVelocity = Vector3.Zero; Velocity = Vector3.Zero; - RemoveFromPhysicalScene(); - String sitAnimation = "SIT"; + m_requestedSitTargetID = 0; + + SendAvatarDataToAllAgents(); + + sitAnimation = "SIT"; if (!String.IsNullOrEmpty(part.SitAnimation)) { sitAnimation = part.SitAnimation; } - Animator.TrySetMovementAnimation(sitAnimation); - SendAvatarDataToAllClients(); +// Animator.TrySetMovementAnimation(sitAnimation); + Animator.SetMovementAnimations("SIT"); TriggerScenePresenceUpdated(); } } @@ -3101,11 +3675,17 @@ namespace OpenSim.Region.Framework.Scenes 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(); + sitAnimation = "SIT_GROUND_CONSTRAINED"; +// Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); +// TriggerScenePresenceUpdated(); SitGround = true; RemoveFromPhysicalScene(); + + m_AngularVelocity = Vector3.Zero; + Velocity = Vector3.Zero; + + Animator.SetMovementAnimations("SITGROUND"); + TriggerScenePresenceUpdated(); } /// @@ -3129,86 +3709,84 @@ namespace OpenSim.Region.Framework.Scenes TriggerScenePresenceUpdated(); } + public void avnHandleChangeAnim(UUID animID, bool addRemove,bool sendPack) + { + Animator.avnChangeAnim(animID, addRemove, sendPack); + } + /// /// 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 /// /// Optional additional speed modifier for this particular add. Default is 1 - public void AddNewMovement(Vector3 vec, float thisAddSpeedModifier = 1) + public void AddNewMovement(Vector3 vec, float thisAddSpeedModifier = 1, bool breaking = false) { -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Adding new movement {0} with rotation {1}, thisAddSpeedModifier {2} for {3}", -// vec, Rotation, thisAddSpeedModifier, Name); - + // m_log.DebugFormat( + // "[SCENE PRESENCE]: Adding new movement {0} with rotation {1}, thisAddSpeedModifier {2} for {3}", + // vec, Rotation, thisAddSpeedModifier, Name); + m_delayedStop = -1; + // rotate from avatar coord space to world 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. + // force rotation to be around Z only, if not flying + // needed for mouselook rot.X = 0; rot.Y = 0; - rot.Normalize(); } Vector3 direc = vec * rot; direc.Normalize(); - if (Flying != FlyingOld) // add for fly velocity control - { - FlyingOld = Flying; // add for fly velocity control - if (!Flying) - WasFlying = true; // add for fly velocity control - } - - if (IsColliding) - WasFlying = false; // add for fly velocity control - if ((vec.Z == 0f) && !Flying) direc.Z = 0f; // Prevent camera WASD up. - direc *= 0.03f * 128f * SpeedModifier * thisAddSpeedModifier; + bool notmvtrgt = !m_movingToTarget || m_moveToSpeed <= 0; + // odd rescalings + if(notmvtrgt) + direc *= 4.096f * SpeedModifier * thisAddSpeedModifier; + else + direc *= m_moveToSpeed; -// m_log.DebugFormat("[SCENE PRESENCE]: Force to apply before modification was {0} for {1}", direc, Name); + // m_log.DebugFormat("[SCENE PRESENCE]: Force to apply before modification was {0} for {1}", direc, Name); - if (PhysicsActor != null) + if (Animator.currentControlState == ScenePresenceAnimator.motionControlStates.falling + && (PhysicsActor == null || !PhysicsActor.PIDHoverActive)) { - if (Flying) - { + if (breaking) + direc.Z = -9999f; //hack to tell physics to stop on Z + else + direc = Vector3.Zero; + } + else if (Flying) + { + if (IsColliding && direc.Z < 0) + // landing situation, prevent avatar moving or it may fail to land + // animator will handle this condition and do the land + direc = Vector3.Zero; + else if(notmvtrgt) direc *= 4.0f; - //bool controlland = (((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0)); - //if (controlland) - // m_log.Info("[AGENT]: landCommand"); - //if (IsColliding) - // m_log.Info("[AGENT]: colliding"); - //if (Flying && IsColliding && controlland) - //{ - // StopFlying(); - // m_log.Info("[AGENT]: Stop Flying"); - //} - } - if (Animator.Falling && WasFlying) // if falling from flying, disable motion add - { - direc *= 0.0f; - } - else if (!Flying && IsColliding) + } + else if (IsColliding) + { + if (direc.Z > 2.0f && notmvtrgt) // reinforce jumps { - if (direc.Z > 2.0f) - { - direc.Z *= 2.6f; - - // TODO: PreJump and jump happen too quickly. Many times prejump gets ignored. -// Animator.TrySetMovementAnimation("PREJUMP"); -// Animator.TrySetMovementAnimation("JUMP"); - } + direc.Z *= 2.6f; } + else if (direc.Z < 0) // on a surface moving down (pg down) only changes animation + direc.Z = 0; } -// 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; + // m_log.DebugFormat("[SCENE PRESENCE]: Setting force to apply to {0} for {1}", direc, Name); +/* + lock(m_forceToApplyLock) + { + m_forceToApply = direc; + m_forceToApplyValid = true; + } +*/ + TargetVelocity = direc; Animator.UpdateMovementAnimations(); } @@ -3216,51 +3794,116 @@ namespace OpenSim.Region.Framework.Scenes #region Overridden Methods + const float ROTATION_TOLERANCE = 0.01f; + const float VELOCITY_TOLERANCE = 0.1f; + const float LOWVELOCITYSQ = 0.1f; + const float POSITION_LARGETOLERANCE = 5f; + const float POSITION_SMALLTOLERANCE = 0.05f; + public override void Update() { - 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 - if (Appearance.AvatarSize != m_lastSize && !IsLoggingIn) - SendAvatarDataToAllClients(); + if(IsChildAgent || IsDeleted) + return; - // 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); + CheckForBorderCrossing(); + + if (IsInTransit || IsLoggingIn) + return; - if (updateClients) + if(m_movingToTarget) + { + m_delayedStop = -1; + Vector3 control = Vector3.Zero; + if(HandleMoveToTargetUpdate(1f, ref control)) + AddNewMovement(control); + } + else if(m_delayedStop > 0) + { + if(IsSatOnObject) + m_delayedStop = -1; + else + if(Util.GetTimeStampMS() > m_delayedStop) + AddNewMovement(Vector3.Zero); + } + + if (Appearance.AvatarSize != m_lastSize) + SendAvatarDataToAllAgents(); + + // Send terse position update if not sitting and position, velocity, or rotation + // has changed significantly from last sent update + if (!IsSatOnObject) + { + // this does need to be more complex later + Vector3 vel = Velocity; + Vector3 dpos = m_pos - m_lastPosition; + if( State != m_lastState || + Math.Abs(vel.X - m_lastVelocity.X) > VELOCITY_TOLERANCE || + Math.Abs(vel.Y - m_lastVelocity.Y) > VELOCITY_TOLERANCE || + Math.Abs(vel.Z - m_lastVelocity.Z) > VELOCITY_TOLERANCE || + + Math.Abs(m_bodyRot.X - m_lastRotation.X) > ROTATION_TOLERANCE || + Math.Abs(m_bodyRot.Y - m_lastRotation.Y) > ROTATION_TOLERANCE || + Math.Abs(m_bodyRot.Z - m_lastRotation.Z) > ROTATION_TOLERANCE || + + (vel == Vector3.Zero && m_lastVelocity != Vector3.Zero) || + + Math.Abs(dpos.X) > POSITION_LARGETOLERANCE || + Math.Abs(dpos.Y) > POSITION_LARGETOLERANCE || + Math.Abs(dpos.Z) > POSITION_LARGETOLERANCE || + + ( (Math.Abs(dpos.X) > POSITION_SMALLTOLERANCE || + Math.Abs(dpos.Y) > POSITION_SMALLTOLERANCE || + Math.Abs(dpos.Z) > POSITION_SMALLTOLERANCE) + && vel.LengthSquared() < LOWVELOCITYSQ + ) || + + Math.Abs(CollisionPlane.X - m_lastCollisionPlane.X) > POSITION_SMALLTOLERANCE || + Math.Abs(CollisionPlane.Y - m_lastCollisionPlane.Y) > POSITION_SMALLTOLERANCE || + Math.Abs(CollisionPlane.W - m_lastCollisionPlane.W) > POSITION_SMALLTOLERANCE + ) { SendTerseUpdateToAllClients(); - - // Update the "last" values - m_lastPosition = m_pos; - m_lastRotation = Rotation; - m_lastVelocity = Velocity; } - - if (Scene.AllowAvatarCrossing) - CheckForBorderCrossing(); - - CheckForSignificantMovement(); // sends update to the modules. } + CheckForSignificantMovement(); } #endregion #region Update Client(s) + public void SendUpdateToAgent(ScenePresence p) + { + IClientAPI remoteClient = p.ControllingClient; + + if (remoteClient.IsActive) + { + //m_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, Rotation, m_velocity); + remoteClient.SendEntityUpdate(this, PrimUpdateFlags.FullUpdate); + m_scene.StatsReporter.AddAgentUpdates(1); + } + } + + public void SendFullUpdateToClient(IClientAPI remoteClient) + { + if (remoteClient.IsActive) + { + //m_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, Rotation, m_velocity); + remoteClient.SendEntityUpdate(this, PrimUpdateFlags.FullUpdate); + m_scene.StatsReporter.AddAgentUpdates(1); + } + } + + // this is diferente from SendTerseUpdateToClient + // this sends bypassing entities updates + public void SendAgentTerseUpdate(ISceneEntity p) + { + ControllingClient.SendAgentTerseUpdate(p); + } + /// /// Sends a location update to the client connected to this scenePresence + /// via entity updates /// /// public void SendTerseUpdateToClient(IClientAPI remoteClient) @@ -3269,31 +3912,7 @@ 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( this, PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity @@ -3303,59 +3922,51 @@ namespace OpenSim.Region.Framework.Scenes } } - - // vars to support reduced update frequency when velocity is unchanged - private Vector3 lastVelocitySentToAllClients = Vector3.Zero; - private Vector3 lastPositionSentToAllClients = Vector3.Zero; - private int lastTerseUpdateToAllClientsTick = Util.EnvironmentTickCount(); - - /// - /// Send a location/velocity/accelleration update to all agents in scene - /// - public void SendTerseUpdateToAllClients() + public void SendTerseUpdateToAgent(ScenePresence p) { - int currentTick = Util.EnvironmentTickCount(); - - // Decrease update frequency when avatar is moving but velocity is - // not changing. - // If there is a mismatch between distance travelled and expected - // distance based on last velocity sent and velocity hasnt changed, - // then send a new terse update + IClientAPI remoteClient = p.ControllingClient; - float timeSinceLastUpdate = (currentTick - lastTerseUpdateToAllClientsTick) * 0.001f; - - Vector3 expectedPosition = lastPositionSentToAllClients + lastVelocitySentToAllClients * timeSinceLastUpdate; - - float distanceError = Vector3.Distance(OffsetPosition, expectedPosition); + if (!remoteClient.IsActive) + return; - float speed = Velocity.Length(); - float velocityDiff = Vector3.Distance(lastVelocitySentToAllClients, Velocity); + if (ParcelHideThisAvatar && p.currentParcelUUID != currentParcelUUID && !p.IsViewerUIGod) + return; -// m_log.DebugFormat( -// "[SCENE PRESENCE]: Delta-v {0}, lastVelocity {1}, Velocity {2} for {3} in {4}", -// velocidyDiff, lastVelocitySentToAllClients, Velocity, Name, Scene.Name); + //m_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, Rotation, m_velocity); + remoteClient.SendEntityUpdate( + this, + PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity + | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity); - // assuming 5 ms. worst case precision for timer, use 2x that - // for distance error threshold - float distanceErrorThreshold = speed * 0.01f; + m_scene.StatsReporter.AddAgentUpdates(1); + } - if (speed < 0.01f // allow rotation updates if avatar position is unchanged - || Math.Abs(distanceError) > distanceErrorThreshold - || velocityDiff > 0.01f) // did velocity change from last update? + public void SendTerseUpdateToAgentNF(ScenePresence p) + { + IClientAPI remoteClient = p.ControllingClient; + if (remoteClient.IsActive) { -// 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_log.DebugFormat("[SCENE PRESENCE]: " + Name + " sending TerseUpdate to " + remoteClient.Name + " : Pos={0} Rot={1} Vel={2}", m_pos, Rotation, m_velocity); + remoteClient.SendEntityUpdate(this, + PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity + | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity); + m_scene.StatsReporter.AddAgentUpdates(1); + } + } - m_terseUpdateCount++; + /// + /// Send a location/velocity/accelleration update to all agents in scene + /// + public void SendTerseUpdateToAllClients() + { + m_lastState = State; + m_lastPosition = m_pos; + m_lastRotation = m_bodyRot; + m_lastVelocity = Velocity; + m_lastCollisionPlane = CollisionPlane; -// Console.WriteLine("Scheduled update for {0} in {1}", Name, Scene.Name); - m_scene.ForEachClient(SendTerseUpdateToClient); - } + m_scene.ForEachScenePresence(SendTerseUpdateToAgent); + // Update the "last" values TriggerScenePresenceUpdated(); } @@ -3379,89 +3990,75 @@ namespace OpenSim.Region.Framework.Scenes ControllingClient.SendCoarseLocationUpdate(avatarUUIDs, coarseLocations); } - public void SendInitialDataToClient() + public void SendInitialDataToMe() { - SentInitialDataToClient = true; - // Send all scene object to the new client - WorkManager.RunJob("SendInitialDataToClient", delegate + SentInitialData = true; + Util.FireAndForget(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) - SendOtherAgentsAvatarDataToClient(); - SendOtherAgentsAppearanceToClient(); + if (m_teleportFlags <= 0) + { + Scene.SendLayerData(ControllingClient); + + ILandChannel landch = m_scene.LandChannel; + if (landch != null) + { + landch.sendClientInitialLandInfo(ControllingClient); + } + } + SendOtherAgentsAvatarFullToMe(); EntityBase[] entities = Scene.Entities.GetEntities(); foreach (EntityBase e in entities) { - if (e != null && e is SceneObjectGroup) + if (e != null && e is SceneObjectGroup && !((SceneObjectGroup)e).IsAttachment) ((SceneObjectGroup)e).SendFullUpdateToClient(ControllingClient); } - }, null, string.Format("SendInitialDataToClient ({0} in {1})", Name, Scene.Name), false, true); + + m_reprioritizationLastPosition = AbsolutePosition; + m_reprioritizationLastDrawDistance = DrawDistance; + m_reprioritizationLastTime = Util.EnvironmentTickCount() + 15000; // delay it + m_reprioritizationBusy = false; + + }); } /// - /// Do everything required once a client completes its movement into a region and becomes - /// a root agent. + /// Send avatar full data appearance and animations for all other root agents to this agent, this agent + /// can be either a child or root /// - private void ValidateAndSendAppearanceAndAgentData() + public void SendOtherAgentsAvatarFullToMe() { - //m_log.DebugFormat("[SCENE PRESENCE] SendInitialData: {0} ({1})", Name, UUID); - // Moved this into CompleteMovement to ensure that Appearance is initialized before - // the inventory arrives - // m_scene.GetAvatarAppearance(ControllingClient, out Appearance); - - bool cachedappearance = false; - - // We have an appearance but we may not have the baked textures. Check the asset cache - // to see if all the baked textures are already here. - if (m_scene.AvatarFactory != null) - cachedappearance = m_scene.AvatarFactory.ValidateBakedTextureCache(this); - - // If we aren't using a cached appearance, then clear out the baked textures - if (!cachedappearance) + int count = 0; + m_scene.ForEachRootScenePresence(delegate(ScenePresence p) { - Appearance.ResetAppearance(); - if (m_scene.AvatarFactory != null) - m_scene.AvatarFactory.QueueAppearanceSave(UUID); - } - - // This agent just became root. We are going to tell everyone about it. The process of - // 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 - SendAvatarDataToAllClients(); + // only send information about other root agents + if (p.UUID == UUID) + return; - // This invocation always shows up in the viewer logs as an error. Is it needed? - SendAppearanceToClient(this); + // get the avatar, then a kill if can't see it + p.SendInitialAvatarDataToAgent(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} in {1}", Name, m_scene.Name); + if (p.ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !IsViewerUIGod) + return; - // 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 - SendAppearanceToAllOtherClients(); - } - } + p.SendAppearanceToAgentNF(this); + p.SendAnimPackToAgentNF(this); + p.SendAttachmentsToAgentNF(this); + count++; + }); - public void SendAvatarDataToAllClients() - { - SendAvatarDataToAllClients(true); + m_scene.StatsReporter.AddAgentUpdates(count); } /// /// 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. + /// This agent must be root. This avatar will receive its own update. /// - public void SendAvatarDataToAllClients(bool full) + public void SendAvatarDataToAllAgents() { //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAllAgents: {0} ({1})", Name, UUID); // only send update from root agents to other clients; children are only "listening posts" @@ -3470,64 +4067,73 @@ namespace OpenSim.Region.Framework.Scenes m_log.WarnFormat( "[SCENE PRESENCE]: Attempt to send avatar data from a child agent for {0} in {1}", Name, Scene.RegionInfo.RegionName); - return; } m_lastSize = Appearance.AvatarSize; - int count = 0; + m_scene.ForEachScenePresence(delegate(ScenePresence scenePresence) { - if (full) - SendAvatarDataToClient(scenePresence); - else - scenePresence.ControllingClient.SendAvatarDataImmediate(this); + SendAvatarDataToAgent(scenePresence); count++; }); m_scene.StatsReporter.AddAgentUpdates(count); } - - /// - /// Send avatar data for all other root agents to this agent, this agent - /// can be either a child or root - /// - public void SendOtherAgentsAvatarDataToClient() + // sends avatar object to all clients so they cross it into region + // then sends kills to hide + public void SendInitialAvatarDataToAllAgents(List presences) { + m_lastSize = Appearance.AvatarSize; int count = 0; - m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence) - { - // only send information about other root agents - if (scenePresence.UUID == UUID) - return; - - scenePresence.SendAvatarDataToClient(this); - count++; - }); - + foreach (ScenePresence p in presences) + { + p.ControllingClient.SendEntityFullUpdateImmediate(this); + if (p != this && ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + // either just kill the object + // p.ControllingClient.SendKillObject(new List {LocalId}); + // or also attachments viewer may still know about + SendKillTo(p); + count++; + } m_scene.StatsReporter.AddAgentUpdates(count); } + public void SendInitialAvatarDataToAgent(ScenePresence p) + { + p.ControllingClient.SendEntityFullUpdateImmediate(this); + if (p != this && ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + // either just kill the object + // p.ControllingClient.SendKillObject(new List {LocalId}); + // or also attachments viewer may still know about + SendKillTo(p); + } + /// /// Send avatar data to an agent. /// /// - public void SendAvatarDataToClient(ScenePresence avatar) + public void SendAvatarDataToAgent(ScenePresence avatar) { - //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToClient from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID); + //m_log.DebugFormat("[SCENE PRESENCE] SendAvatarDataToAgent from {0} ({1}) to {2} ({3})", Name, UUID, avatar.Name, avatar.UUID); + if (ParcelHideThisAvatar && currentParcelUUID != avatar.currentParcelUUID && !avatar.IsViewerUIGod) + return; + avatar.ControllingClient.SendEntityFullUpdateImmediate(this); + } - avatar.ControllingClient.SendAvatarDataImmediate(this); - Animator.SendAnimPackToClient(avatar.ControllingClient); + public void SendAvatarDataToAgentNF(ScenePresence avatar) + { + avatar.ControllingClient.SendEntityFullUpdateImmediate(this); } /// /// Send this agent's appearance to all other root and child agents in the scene /// This agent must be root. /// - public void SendAppearanceToAllOtherClients() + public void SendAppearanceToAllOtherAgents() { -// m_log.DebugFormat("[SCENE PRESENCE] SendAppearanceToAllOtherClients: {0} {1}", Name, UUID); + // m_log.DebugFormat("[SCENE PRESENCE] SendAppearanceToAllOtherAgents: {0} {1}", Name, UUID); // only send update from root agents to other clients; children are only "listening posts" if (IsChildAgent) @@ -3538,115 +4144,223 @@ namespace OpenSim.Region.Framework.Scenes return; } - + int count = 0; m_scene.ForEachScenePresence(delegate(ScenePresence scenePresence) - { - // only send information to other root agents - if (scenePresence.UUID == UUID) - return; - - SendAppearanceToClient(scenePresence); - count++; - }); + { + // only send information to other root agents + if (scenePresence.UUID == UUID) + return; + SendAppearanceToAgent(scenePresence); + count++; + }); m_scene.StatsReporter.AddAgentUpdates(count); } - /// - /// Send appearance from all other root agents to this agent. this agent - /// can be either root or child - /// - public void SendOtherAgentsAppearanceToClient() + public void SendAppearanceToAgent(ScenePresence avatar) { -// m_log.DebugFormat("[SCENE PRESENCE] SendOtherAgentsAppearanceToClient {0} {1}", Name, UUID); - - int count = 0; - m_scene.ForEachRootScenePresence(delegate(ScenePresence scenePresence) - { - // only send information about other root agents - if (scenePresence.UUID == UUID) - return; - - scenePresence.SendAppearanceToClient(this); - count++; - }); - - m_scene.StatsReporter.AddAgentUpdates(count); + // m_log.DebugFormat( + // "[SCENE PRESENCE]: Sending appearance data from {0} {1} to {2} {3}", Name, m_uuid, avatar.Name, avatar.UUID); + if (ParcelHideThisAvatar && currentParcelUUID != avatar.currentParcelUUID && !avatar.IsViewerUIGod) + return; + SendAppearanceToAgentNF(avatar); } - /// - /// Send appearance data to an agent. - /// - /// - public void SendAppearanceToClient(ScenePresence avatar) + public void SendAppearanceToAgentNF(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 - - #region Significant Movement Method - - /// - /// This checks for a significant movement and sends a coarselocationchange update - /// - protected void CheckForSignificantMovement() + public void SendAnimPackToAgent(ScenePresence p) { - if (Util.GetDistanceTo(AbsolutePosition, posLastSignificantMove) > SIGNIFICANT_MOVEMENT) - { - posLastSignificantMove = AbsolutePosition; - m_scene.EventManager.TriggerSignificantClientMovement(this); - } - - // Minimum Draw distance is 64 meters, the Radius of the draw distance sphere is 32m - if (Util.GetDistanceTo(AbsolutePosition, m_lastChildAgentUpdatePosition) >= Scene.ChildReprioritizationDistance) - { - m_lastChildAgentUpdatePosition = AbsolutePosition; -// m_lastChildAgentUpdateCamPosition = CameraPosition; + if (IsChildAgent || Animator == null) + return; - ChildAgentDataUpdate cadu = new ChildAgentDataUpdate(); - cadu.ActiveGroupID = UUID.Zero.Guid; - cadu.AgentID = UUID.Guid; - cadu.alwaysrun = SetAlwaysRun; - cadu.AVHeight = Appearance.AvatarHeight; - cadu.cameraPosition = CameraPosition; - cadu.drawdistance = DrawDistance; - cadu.GroupAccess = 0; - cadu.Position = AbsolutePosition; - cadu.regionHandle = RegionHandle; + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + return; - // Throttles - float multiplier = 1; - int childRegions = KnownRegionCount; - if (childRegions != 0) - multiplier = 1f / childRegions; + Animator.SendAnimPackToClient(p.ControllingClient); + } - // Minimum throttle for a child region is 1/4 of the root region throttle - if (multiplier <= 0.25f) - multiplier = 0.25f; + public void SendAnimPackToAgent(ScenePresence p, UUID[] animations, int[] seqs, UUID[] objectIDs) + { + if (IsChildAgent) + return; - cadu.throttles = ControllingClient.GetThrottlesPacked(multiplier); - cadu.Velocity = Velocity; + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + return; - AgentPosition agentpos = new AgentPosition(); - agentpos.CopyFrom(cadu, ControllingClient.SessionId); + p.ControllingClient.SendAnimations(animations, seqs, ControllingClient.AgentId, objectIDs); + } - // Let's get this out of the update loop - Util.FireAndForget( - o => m_scene.SendOutChildAgentUpdates(agentpos, this), null, "ScenePresence.SendOutChildAgentUpdates"); - } + public void SendAnimPackToAgentNF(ScenePresence p) + { + if (IsChildAgent || Animator == null) + return; + Animator.SendAnimPackToClient(p.ControllingClient); } - #endregion + public void SendAnimPackToAgentNF(ScenePresence p, UUID[] animations, int[] seqs, UUID[] objectIDs) + { + p.ControllingClient.SendAnimations(animations, seqs, ControllingClient.AgentId, objectIDs); + } - #region Border Crossing Methods + public void SendAnimPack(UUID[] animations, int[] seqs, UUID[] objectIDs) + { + if (IsChildAgent) + return; + + m_scene.ForEachScenePresence(delegate(ScenePresence p) + { + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + return; + p.ControllingClient.SendAnimations(animations, seqs, ControllingClient.AgentId, objectIDs); + }); + } + + #endregion + + #region Significant Movement Method + + private void checkRePrioritization() + { + if(IsDeleted || !ControllingClient.IsActive) + return; + + if(!SentInitialData) + { + SendInitialDataToMe(); + return; + } + + if(m_reprioritizationBusy) + return; + + float limit = Scene.ReprioritizationDistance; + bool byDrawdistance = Scene.ObjectsCullingByDistance; + if(byDrawdistance) + { + float minregionSize = (float)Scene.RegionInfo.RegionSizeX; + if(minregionSize > (float)Scene.RegionInfo.RegionSizeY) + minregionSize = (float)Scene.RegionInfo.RegionSizeY; + minregionSize *= 0.5f; + if(DrawDistance > minregionSize && m_reprioritizationLastDrawDistance > minregionSize) + byDrawdistance = false; + else + byDrawdistance = (Math.Abs(DrawDistance - m_reprioritizationLastDrawDistance) > 0.5f * limit); + } + + int tdiff = Util.EnvironmentTickCountSubtract(m_reprioritizationLastTime); + if(!byDrawdistance && tdiff < Scene.ReprioritizationInterval) + return; + // priority uses avatar position + Vector3 pos = AbsolutePosition; + Vector3 diff = pos - m_reprioritizationLastPosition; + limit *= limit; + if (!byDrawdistance && diff.LengthSquared() < limit) + return; + + m_reprioritizationBusy = true; + m_reprioritizationLastPosition = pos; + m_reprioritizationLastDrawDistance = DrawDistance; + + Util.FireAndForget( + o => + { + ControllingClient.ReprioritizeUpdates(); + m_reprioritizationLastTime = Util.EnvironmentTickCount(); + m_reprioritizationBusy = false; + }, null, "ScenePresence.Reprioritization"); + } + /// + /// This checks for a significant movement and sends a coarselocationchange update + /// + protected void CheckForSignificantMovement() + { + Vector3 pos = AbsolutePosition; + + Vector3 diff = pos - posLastMove; + if (diff.LengthSquared() > MOVEMENT) + { + posLastMove = pos; + m_scene.EventManager.TriggerOnClientMovement(this); + } + + diff = pos - posLastSignificantMove; + if (diff.LengthSquared() > SIGNIFICANT_MOVEMENT) + { + posLastSignificantMove = pos; + m_scene.EventManager.TriggerSignificantClientMovement(this); + } + + // updates priority recalc + checkRePrioritization(); + + if(m_childUpdatesBusy) + return; + + //possible KnownRegionHandles always contains current region and this check is not needed + int minhandles = 0; + if(KnownRegionHandles.Contains(RegionHandle)) + minhandles++; + + if(KnownRegionHandles.Count > minhandles) + { + int tdiff = Util.EnvironmentTickCountSubtract(m_lastChildUpdatesTime); + if(tdiff < CHILDUPDATES_TIME) + return; + + bool doUpdate = false; + if(m_lastChildAgentUpdateGodLevel != GodController.ViwerUIGodLevel) + doUpdate = true; + + if(!doUpdate && Math.Abs(DrawDistance - m_lastChildAgentUpdateDrawDistance) > 32.0f) + doUpdate = true; + + if(!doUpdate) + { + diff = pos - m_lastChildAgentUpdatePosition; + if (diff.LengthSquared() > CHILDUPDATES_MOVEMENT) + doUpdate = true; + } + + if(doUpdate) + { + m_childUpdatesBusy = true; + m_lastChildAgentUpdatePosition = pos; + m_lastChildAgentUpdateGodLevel = GodController.ViwerUIGodLevel; + m_lastChildAgentUpdateDrawDistance = DrawDistance; +// m_lastChildAgentUpdateCamPosition = CameraPosition; + + AgentPosition agentpos = new AgentPosition(); + agentpos.AgentID = new UUID(UUID.Guid); + agentpos.SessionID = ControllingClient.SessionId; + agentpos.Size = Appearance.AvatarSize; + agentpos.Center = CameraPosition; + agentpos.Far = DrawDistance; + agentpos.Position = AbsolutePosition; + agentpos.Velocity = Velocity; + agentpos.RegionHandle = RegionHandle; + agentpos.GodData = GodController.State(); + agentpos.Throttles = ControllingClient.GetThrottlesPacked(1); + + // Let's get this out of the update loop + Util.FireAndForget( + o => + { + m_scene.SendOutChildAgentUpdates(agentpos, this); + m_lastChildUpdatesTime = Util.EnvironmentTickCount(); + m_childUpdatesBusy = false; + }, null, "ScenePresence.SendOutChildAgentUpdates"); + } + } + } + + #endregion + + #region Border Crossing Methods /// /// Starts the process of moving an avatar into another region if they are crossing the border. @@ -3657,7 +4371,7 @@ namespace OpenSim.Region.Framework.Scenes protected void CheckForBorderCrossing() { // Check that we we are not a child - if (IsChildAgent) + if (IsChildAgent || IsInTransit) return; // If we don't have a PhysActor, we can't cross anyway @@ -3667,79 +4381,71 @@ namespace OpenSim.Region.Framework.Scenes if (ParentID != 0 || PhysicsActor == null || ParentUUID != UUID.Zero) return; - if (IsInTransit) - return; - Vector3 pos2 = AbsolutePosition; - Vector3 origPosition = pos2; Vector3 vel = Velocity; - // 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; - - 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); + float timeStep = 0.1f; + pos2.X += vel.X * timeStep; + pos2.Y += vel.Y * timeStep; + pos2.Z += vel.Z * timeStep; - // Disconnect from the current region - bool isFlying = Flying; - RemoveFromPhysicalScene(); +// m_log.DebugFormat( +// "[SCENE PRESENCE]: Testing border check for projected position {0} of {1} in {2}", +// pos2, Name, Scene.Name); - // 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 (Scene.PositionIsInCurrentRegion(pos2)) + return; - if (CrossToNewRegion()) - { - AddToPhysicalScene(isFlying); - } - else + if (!CrossToNewRegion() && m_requestedSitTargetUUID == UUID.Zero) { - // Tried to make crossing happen but it failed. - if (m_requestedSitTargetUUID == UUID.Zero) - { - m_log.DebugFormat("{0} CheckForBorderCrossing: Crossing failed. Restoring old position.", LogHeader); - - Velocity = Vector3.Zero; - AbsolutePosition = EnforceSanityOnPosition(origPosition); + // we don't have entity transfer module + Vector3 pos = AbsolutePosition; + vel = Velocity; + float px = pos.X; + if (px < 0) + pos.X += vel.X * 2; + else if (px > m_scene.RegionInfo.RegionSizeX) + pos.X -= vel.X * 2; + + float py = pos.Y; + if (py < 0) + pos.Y += vel.Y * 2; + else if (py > m_scene.RegionInfo.RegionSizeY) + pos.Y -= vel.Y * 2; - AddToPhysicalScene(isFlying); - } + Velocity = Vector3.Zero; + m_AngularVelocity = Vector3.Zero; + AbsolutePosition = pos; } } - // 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) + public void CrossToNewRegionFail() { - 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 (m_requestedSitTargetUUID == UUID.Zero) { - // 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; + bool isFlying = Flying; + RemoveFromPhysicalScene(); + + Vector3 pos = AbsolutePosition; + Vector3 vel = Velocity; + float px = pos.X; + if (px < 0) + pos.X += vel.X * 2; + else if (px > m_scene.RegionInfo.RegionSizeX) + pos.X -= vel.X * 2; + + float py = pos.Y; + if (py < 0) + pos.Y += vel.Y * 2; + else if (py > m_scene.RegionInfo.RegionSizeY) + pos.Y -= vel.Y * 2; + + Velocity = Vector3.Zero; + m_AngularVelocity = Vector3.Zero; + AbsolutePosition = pos; - return ret; + AddToPhysicalScene(isFlying); + } } /// @@ -3750,62 +4456,93 @@ namespace OpenSim.Region.Framework.Scenes /// protected bool CrossToNewRegion() { + bool result = false; +// parcelRegionCross(false); try { - return m_scene.CrossAgentToNewRegion(this, Flying); + result = m_scene.CrossAgentToNewRegion(this, Flying); } catch { - return m_scene.CrossAgentToNewRegion(this, false); +// result = m_scene.CrossAgentToNewRegion(this, false); + return false; } - } - - public void Reset() - { -// m_log.DebugFormat("[SCENE PRESENCE]: Resetting {0} in {1}", Name, Scene.RegionInfo.RegionName); + // if(!result) + // parcelRegionCross(true); - // Put the child agent back at the center - AbsolutePosition - = new Vector3(((float)m_scene.RegionInfo.RegionSizeX * 0.5f), ((float)m_scene.RegionInfo.RegionSizeY * 0.5f), 70); + return result; - Animator.ResetAnimations(); } /// /// Computes which child agents to close when the scene presence moves to another region. /// Removes those regions from m_knownRegions. /// - /// The new region's x on the map - /// The new region's y on the map + /// The new region's handle + /// The new region's size x + /// The new region's size y /// - public void CloseChildAgents(uint newRegionX, uint newRegionY) + public List GetChildAgentsToClose(ulong newRegionHandle, int newRegionSizeX, int newRegionSizeY) { + ulong curRegionHandle = m_scene.RegionInfo.RegionHandle; List byebyeRegions = new List(); + + if(newRegionHandle == curRegionHandle) //?? + return byebyeRegions; + + uint newRegionX, newRegionY; List knownRegions = KnownRegionHandles; m_log.DebugFormat( - "[SCENE PRESENCE]: Closing child agents. Checking {0} regions in {1}", + "[SCENE PRESENCE]: Closing child agents. Checking {0} regions in {1}", knownRegions.Count, Scene.RegionInfo.RegionName); - //DumpKnownRegions(); + + Util.RegionHandleToRegionLoc(newRegionHandle, out newRegionX, out newRegionY); + uint x, y; + spRegionSizeInfo regInfo; foreach (ulong handle in knownRegions) { - // Don't close the agent on this region yet - if (handle != Scene.RegionInfo.RegionHandle) + if(newRegionY == 0) // HG + byebyeRegions.Add(handle); + else if(handle == curRegionHandle) { - uint x, y; - 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))); - float dist = (float)Math.Max(Scene.DefaultDrawDistance, - (float)Math.Max(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY)); - if (Util.IsOutsideView(dist, x, newRegionX, y, newRegionY)) + RegionInfo curreg = m_scene.RegionInfo; + if (Util.IsOutsideView(255, curreg.RegionLocX, newRegionX, curreg.RegionLocY, newRegionY, + (int)curreg.RegionSizeX, (int)curreg.RegionSizeX, newRegionSizeX, newRegionSizeY)) { byebyeRegions.Add(handle); } } + else + { + Util.RegionHandleToRegionLoc(handle, out x, out y); + if (m_knownChildRegionsSizeInfo.TryGetValue(handle, out regInfo)) + { +// if (Util.IsOutsideView(RegionViewDistance, x, newRegionX, y, newRegionY, + // for now need to close all but first order bc RegionViewDistance it the target value not ours + if (Util.IsOutsideView(255, x, newRegionX, y, newRegionY, + regInfo.sizeX, regInfo.sizeY, newRegionSizeX, newRegionSizeY)) + { + byebyeRegions.Add(handle); + } + } + else + { +// if (Util.IsOutsideView(RegionViewDistance, x, newRegionX, y, newRegionY, + if (Util.IsOutsideView(255, x, newRegionX, y, newRegionY, + (int)Constants.RegionSize, (int)Constants.RegionSize, newRegionSizeX, newRegionSizeY)) + { + byebyeRegions.Add(handle); + } + } + } } - + return byebyeRegions; + } + + public void CloseChildAgents(List byebyeRegions) + { + byebyeRegions.Remove(Scene.RegionInfo.RegionHandle); if (byebyeRegions.Count > 0) { m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents"); @@ -3814,43 +4551,56 @@ namespace OpenSim.Region.Framework.Scenes string auth = string.Empty; if (acd != null) auth = acd.SessionID.ToString(); - m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, auth, byebyeRegions); + m_scene.SceneGridService.SendCloseChildAgentConnections(ControllingClient.AgentId, auth, byebyeRegions); } - + foreach (ulong handle in byebyeRegions) { RemoveNeighbourRegion(handle); + Scene.CapsModule.DropChildSeed(UUID, handle); } } - #endregion - - /// - /// This allows the Sim owner the abiility to kick users from their sim currently. - /// It tells the client that the agent has permission to do so. - /// - public void GrantGodlikePowers(UUID agentID, UUID sessionID, UUID token, bool godStatus) + public void closeAllChildAgents() { - if (godStatus) + List byebyeRegions = new List(); + List knownRegions = KnownRegionHandles; + foreach (ulong handle in knownRegions) { - // For now, assign god level 200 to anyone - // who is granted god powers, but has no god level set. - // - UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, agentID); - if (account != null) + if (handle != Scene.RegionInfo.RegionHandle) { - if (account.UserLevel > 0) - GodLevel = account.UserLevel; - else - GodLevel = 200; + byebyeRegions.Add(handle); + RemoveNeighbourRegion(handle); + Scene.CapsModule.DropChildSeed(UUID, handle); } } - else + + if (byebyeRegions.Count > 0) { - GodLevel = 0; + m_log.Debug("[SCENE PRESENCE]: Closing " + byebyeRegions.Count + " child agents"); + + 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); } + } + + #endregion + + /// + /// handle god level requests. + /// + public void GrantGodlikePowers(UUID token, bool godStatus) + { + if (IsNPC) + return; - ControllingClient.SendAdminResponse(token, (uint)GodLevel); + bool wasgod = IsViewerUIGod; + GodController.RequestGodMode(godStatus); + if (wasgod != IsViewerUIGod) + parcelGodCheck(m_currentParcelUUID); } #region Child Agent Updates @@ -3862,12 +4612,16 @@ namespace OpenSim.Region.Framework.Scenes return; CopyFrom(cAgentData); - m_updateAgentReceivedAfterTransferEvent.Set(); } private static Vector3 marker = new Vector3(-1f, -1f, -1f); + private void RaiseUpdateThrottles() + { + m_scene.EventManager.TriggerThrottleUpdate(this); + } + /// /// 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 @@ -3877,44 +4631,59 @@ namespace OpenSim.Region.Framework.Scenes if (!IsChildAgent) return; -// 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); + GodController.SetState(cAgentData.GodData); + + RegionHandle = cAgentData.RegionHandle; - // 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); + //m_log.Debug(" >>> ChildAgentPositionUpdate <<< " + rRegionX + "-" + rRegionY); + int shiftx = ((int)rRegionX - (int)tRegionX) * (int)Constants.RegionSize; + int shifty = ((int)rRegionY - (int)tRegionY) * (int)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; if (cAgentData.Position != marker) // UGH!! m_pos = cAgentData.Position + offset; - if (Vector3.Distance(AbsolutePosition, posLastSignificantMove) >= Scene.ChildReprioritizationDistance) + CameraPosition = cAgentData.Center + offset; + + if ((cAgentData.Throttles != null) && cAgentData.Throttles.Length > 0) { - posLastSignificantMove = AbsolutePosition; - ReprioritizeUpdates(); + // some scaling factor + float x = m_pos.X; + if (x > m_scene.RegionInfo.RegionSizeX) + x -= m_scene.RegionInfo.RegionSizeX; + float y = m_pos.Y; + if (y > m_scene.RegionInfo.RegionSizeY) + y -= m_scene.RegionInfo.RegionSizeY; + + x = x * x + y * y; + + const float distScale = 0.4f / Constants.RegionSize / Constants.RegionSize; + float factor = 1.0f - distScale * x; + if (factor < 0.2f) + factor = 0.2f; + + ControllingClient.SetChildAgentThrottle(cAgentData.Throttles,factor); } - CameraPosition = cAgentData.Center + offset; + if(cAgentData.ChildrenCapSeeds != null && cAgentData.ChildrenCapSeeds.Count >0) + { + if (Scene.CapsModule != null) + { + Scene.CapsModule.SetChildrenSeed(UUID, cAgentData.ChildrenCapSeeds); + } - if ((cAgentData.Throttles != null) && cAgentData.Throttles.Length > 0) - ControllingClient.SetChildAgentThrottle(cAgentData.Throttles); + KnownRegions = cAgentData.ChildrenCapSeeds; + } //cAgentData.AVHeight; - RegionHandle = cAgentData.RegionHandle; //m_velocity = cAgentData.Velocity; + checkRePrioritization(); } - public void CopyTo(AgentData cAgent) + public void CopyTo(AgentData cAgent, bool isCrossUpdate) { cAgent.CallbackURI = m_callbackURI; @@ -3930,35 +4699,23 @@ namespace OpenSim.Region.Framework.Scenes cAgent.UpAxis = CameraUpAxis; cAgent.Far = DrawDistance; + cAgent.GodData = GodController.State(); - // Throttles - float multiplier = 1; - int childRegions = KnownRegionCount; - if (childRegions != 0) - multiplier = 1f / childRegions; - - // Minimum throttle for a child region is 1/4 of the root region throttle - if (multiplier <= 0.25f) - multiplier = 0.25f; - - cAgent.Throttles = ControllingClient.GetThrottlesPacked(multiplier); + // Throttles + cAgent.Throttles = ControllingClient.GetThrottlesPacked(1); cAgent.HeadRotation = m_headrotation; cAgent.BodyRotation = Rotation; cAgent.ControlFlags = (uint)m_AgentControlFlags; - if (m_scene.Permissions.IsGod(new UUID(cAgent.AgentID))) - cAgent.GodLevel = (byte)GodLevel; - else - cAgent.GodLevel = (byte) 0; - cAgent.AlwaysRun = SetAlwaysRun; - cAgent.Appearance = new AvatarAppearance(Appearance); + // make clear we want the all thing + cAgent.Appearance = new AvatarAppearance(Appearance,true,true); cAgent.ParentPart = ParentUUID; cAgent.SitOffset = PrevSitOffset; - + lock (scriptedcontrols) { ControllerData[] controls = new ControllerData[scriptedcontrols.Count]; @@ -3980,8 +4737,36 @@ namespace OpenSim.Region.Framework.Scenes cAgent.DefaultAnim = Animator.Animations.DefaultAnimation; cAgent.AnimState = Animator.Animations.ImplicitDefaultAnimation; + cAgent.MovementAnimationOverRides = Overrides.CloneAOPairs(); + + cAgent.MotionState = (byte)Animator.currentControlState; + if (Scene.AttachmentsModule != null) Scene.AttachmentsModule.CopyAttachments(this, cAgent); + + if(isCrossUpdate) + { + cAgent.CrossingFlags = crossingFlags; + cAgent.CrossingFlags |= 1; + cAgent.CrossExtraFlags = 0; + if((LastCommands & ScriptControlled.CONTROL_LBUTTON) != 0) + cAgent.CrossExtraFlags |= 1; + if((LastCommands & ScriptControlled.CONTROL_ML_LBUTTON) != 0) + cAgent.CrossExtraFlags |= 2; + } + else + cAgent.CrossingFlags = 0; + + if(isCrossUpdate) + { + cAgent.agentCOF = COF; + cAgent.ActiveGroupID = ControllingClient.ActiveGroupId; + cAgent.ActiveGroupName = ControllingClient.ActiveGroupName; + if(Grouptitle == null) + cAgent.ActiveGroupTitle = String.Empty; + else + cAgent.ActiveGroupTitle = Grouptitle; + } } private void CopyFrom(AgentData cAgent) @@ -3991,40 +4776,59 @@ namespace OpenSim.Region.Framework.Scenes // "[SCENE PRESENCE]: Set callback for {0} in {1} to {2} in CopyFrom()", // Name, m_scene.RegionInfo.RegionName, m_callbackURI); + GodController.SetState(cAgent.GodData); + m_pos = cAgent.Position; m_velocity = cAgent.Velocity; CameraPosition = cAgent.Center; CameraAtAxis = cAgent.AtAxis; CameraLeftAxis = cAgent.LeftAxis; CameraUpAxis = cAgent.UpAxis; + + Quaternion camRot = Util.Axes2Rot(CameraAtAxis, CameraLeftAxis, CameraUpAxis); + CameraRotation = camRot; + 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 + // changes, then start using the agent's drawdistance rather than the // region's draw distance. DrawDistance = cAgent.Far; - // DrawDistance = Scene.DefaultDrawDistance; + //DrawDistance = Scene.DefaultDrawDistance; + + if (cAgent.ChildrenCapSeeds != null && cAgent.ChildrenCapSeeds.Count > 0) + { + if (Scene.CapsModule != null) + { + Scene.CapsModule.SetChildrenSeed(UUID, cAgent.ChildrenCapSeeds); + } + KnownRegions = cAgent.ChildrenCapSeeds; + } if ((cAgent.Throttles != null) && cAgent.Throttles.Length > 0) ControllingClient.SetChildAgentThrottle(cAgent.Throttles); m_headrotation = cAgent.HeadRotation; Rotation = cAgent.BodyRotation; - m_AgentControlFlags = (AgentManager.ControlFlags)cAgent.ControlFlags; + m_AgentControlFlags = (AgentManager.ControlFlags)cAgent.ControlFlags; - if (m_scene.Permissions.IsGod(new UUID(cAgent.AgentID))) - GodLevel = cAgent.GodLevel; SetAlwaysRun = cAgent.AlwaysRun; Appearance = new AvatarAppearance(cAgent.Appearance); +/* + bool isFlying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); + if (PhysicsActor != null) { - bool isFlying = Flying; RemoveFromPhysicalScene(); AddToPhysicalScene(isFlying); } - +*/ + + if (Scene.AttachmentsModule != null) + Scene.AttachmentsModule.CopyAttachments(cAgent, this); + try { lock (scriptedcontrols) @@ -4032,6 +4836,7 @@ namespace OpenSim.Region.Framework.Scenes if (cAgent.Controllers != null) { scriptedcontrols.Clear(); + IgnoredControls = ScriptControlled.CONTROL_ZERO; foreach (ControllerData c in cAgent.Controllers) { @@ -4042,40 +4847,63 @@ namespace OpenSim.Region.Framework.Scenes sc.eventControls = (ScriptControlled)c.EventControls; scriptedcontrols[sc.itemID] = sc; + IgnoredControls |= sc.ignoreControls; // this is not correct, aparently only last applied should count } } } } catch { } + Animator.ResetAnimations(); + + Overrides.CopyAOPairsFrom(cAgent.MovementAnimationOverRides); + // FIXME: Why is this null check necessary? Where are the cases where we get a null Anims object? - if (cAgent.Anims != null) - Animator.Animations.FromArray(cAgent.Anims); if (cAgent.DefaultAnim != null) Animator.Animations.SetDefaultAnimation(cAgent.DefaultAnim.AnimID, cAgent.DefaultAnim.SequenceNum, UUID.Zero); if (cAgent.AnimState != null) Animator.Animations.SetImplicitDefaultAnimation(cAgent.AnimState.AnimID, cAgent.AnimState.SequenceNum, UUID.Zero); + if (cAgent.Anims != null) + Animator.Animations.FromArray(cAgent.Anims); + if (cAgent.MotionState != 0) + Animator.currentControlState = (ScenePresenceAnimator.motionControlStates) cAgent.MotionState; - if (Scene.AttachmentsModule != null) + + crossingFlags = cAgent.CrossingFlags; + gotCrossUpdate = (crossingFlags != 0); + if(gotCrossUpdate) { - // 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. + LastCommands &= ~(ScriptControlled.CONTROL_LBUTTON | ScriptControlled.CONTROL_ML_LBUTTON); + if((cAgent.CrossExtraFlags & 1) != 0) + LastCommands |= ScriptControlled.CONTROL_LBUTTON; + if((cAgent.CrossExtraFlags & 2) != 0) + LastCommands |= ScriptControlled.CONTROL_ML_LBUTTON; + MouseDown = (cAgent.CrossExtraFlags & 3) != 0; + } + + haveGroupInformation = false; + // using this as protocol detection don't want to mess with the numbers for now + if(cAgent.ActiveGroupTitle != null) + { + haveGroupInformation = true; + COF = cAgent.agentCOF; + if(ControllingClient.IsGroupMember(cAgent.ActiveGroupID)) + { + ControllingClient.ActiveGroupId = cAgent.ActiveGroupID; + ControllingClient.ActiveGroupName = cAgent.ActiveGroupName; + Grouptitle = cAgent.ActiveGroupTitle; + ControllingClient.ActiveGroupPowers = + ControllingClient.GetGroupPowers(cAgent.ActiveGroupID); + } + else + { + // we got a unknown active group so get what groups thinks about us + IGroupsModule gm = m_scene.RequestModuleInterface(); + if (gm != null) + gm.SendAgentGroupDataUpdate(ControllingClient); + } + } + lock (m_originRegionIDAccessLock) m_originRegionID = cAgent.RegionID; } @@ -4083,7 +4911,7 @@ namespace OpenSim.Region.Framework.Scenes public bool CopyAgent(out IAgentData agent) { agent = new CompleteAgentData(); - CopyTo((AgentData)agent); + CopyTo((AgentData)agent, false); return true; } @@ -4094,15 +4922,21 @@ namespace OpenSim.Region.Framework.Scenes /// public void UpdateMovement() { - if (m_forceToApply.HasValue) - { - Vector3 force = m_forceToApply.Value; +/* + if (IsInTransit) + return; - Velocity = force; + lock(m_forceToApplyLock) + { + if (m_forceToApplyValid) + { + Velocity = m_forceToApply; - m_forceToApply = null; - TriggerScenePresenceUpdated(); + m_forceToApplyValid = false; + TriggerScenePresenceUpdated(); + } } +*/ } /// @@ -4124,22 +4958,23 @@ namespace OpenSim.Region.Framework.Scenes if (Appearance.AvatarHeight == 0) // Appearance.SetHeight(); Appearance.SetSize(new Vector3(0.45f,0.6f,1.9f)); - -/* - PhysicsActor = scene.AddAvatar( - LocalId, Firstname + "." + Lastname, pVec, - new Vector3(0.45f, 0.6f, Appearance.AvatarHeight), isFlying); -*/ - PhysicsActor = m_scene.PhysicsScene.AddAvatar( - LocalId, Firstname + "." + Lastname, AbsolutePosition, Velocity, - Appearance.AvatarBoxSize, isFlying); +// lock(m_forceToApplyLock) +// m_forceToApplyValid = false; + PhysicsScene scene = m_scene.PhysicsScene; + Vector3 pVec = AbsolutePosition; + + PhysicsActor = scene.AddAvatar( + LocalId, Firstname + "." + Lastname, pVec, + Appearance.AvatarBoxSize,Appearance.AvatarFeetOffset, isFlying); + PhysicsActor.Orientation = m_bodyRot; //PhysicsActor.OnRequestTerseUpdate += SendTerseUpdateToAllClients; PhysicsActor.OnCollisionUpdate += PhysicsCollisionUpdate; PhysicsActor.OnOutOfBounds += OutOfBoundsCall; // Called for PhysicsActors when there's something wrong PhysicsActor.SubscribeEvents(100); PhysicsActor.LocalID = LocalId; + PhysicsActor.SetAlwaysRun = m_setAlwaysRun; } private void OutOfBoundsCall(Vector3 pos) @@ -4152,7 +4987,6 @@ 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. /// @@ -4166,24 +5000,26 @@ namespace OpenSim.Region.Framework.Scenes /// public void PhysicsCollisionUpdate(EventArgs e) { - if (IsChildAgent || Animator == null) + if (IsChildAgent) + return; + + if(IsInTransit) return; - + //if ((Math.Abs(Velocity.X) > 0.1e-9f) || (Math.Abs(Velocity.Y) > 0.1e-9f)) // The Physics Scene will send updates every 500 ms grep: PhysicsActor.SubscribeEvents( // as of this comment the interval is set in AddToPhysicalScene // if (m_updateCount > 0) // { - if (Animator.UpdateMovementAnimations()) - TriggerScenePresenceUpdated(); +// if (Animator != null && Animator.UpdateMovementAnimations()) +// TriggerScenePresenceUpdated(); // m_updateCount--; // } CollisionEventUpdate collisionData = (CollisionEventUpdate)e; Dictionary coldata = collisionData.m_objCollisionList; - // // No collisions at all means we may be flying. Update always // // to make falling work // if (m_lastColCount != coldata.Count || coldata.Count == 0) @@ -4192,81 +5028,98 @@ namespace OpenSim.Region.Framework.Scenes // m_lastColCount = coldata.Count; // } - CollisionPlane = Vector4.UnitW; + if (coldata.Count != 0) + { + ContactPoint lowest; + lowest.SurfaceNormal = Vector3.Zero; + lowest.Position = Vector3.Zero; + lowest.Position.Z = float.MaxValue; - // Gods do not take damage and Invulnerable is set depending on parcel/region flags - if (Invulnerable || GodLevel > 0) - return; + foreach (ContactPoint contact in coldata.Values) + { + if (contact.CharacterFeet && contact.Position.Z < lowest.Position.Z) + lowest = contact; + } - // The following may be better in the ICombatModule - // probably tweaking of the values for ground and normal prim collisions will be needed - float starthealth = Health; - uint killerObj = 0; - SceneObjectPart part = null; - foreach (uint localid in coldata.Keys) - { - if (localid == 0) + if (lowest.Position.Z != float.MaxValue) { - part = null; + lowest.SurfaceNormal = -lowest.SurfaceNormal; + CollisionPlane = new Vector4(lowest.SurfaceNormal, Vector3.Dot(lowest.Position, lowest.SurfaceNormal)); } else + CollisionPlane = Vector4.UnitW; + } + else + CollisionPlane = Vector4.UnitW; + + RaiseCollisionScriptEvents(coldata); + + // Gods do not take damage and Invulnerable is set depending on parcel/region flags + if (Invulnerable || IsViewerUIGod) + return; + + // The following may be better in the ICombatModule + // probably tweaking of the values for ground and normal prim collisions will be needed + float startHealth = Health; + if(coldata.Count > 0) + { + uint killerObj = 0; + SceneObjectPart part = null; + float rvel; // relative velocity, negative on approch + foreach (uint localid in coldata.Keys) { - part = Scene.GetSceneObjectPart(localid); - } - if (part != null) - { - // Ignore if it has been deleted or volume detect - if (!part.ParentGroup.IsDeleted && !part.ParentGroup.IsVolumeDetect) + if (localid == 0) { - if (part.ParentGroup.Damage > 0.0f) + // 0 is the ground + rvel = coldata[0].RelativeSpeed; + if(rvel < -5.0f) + Health -= 0.01f * rvel * rvel; + } + else + { + part = Scene.GetSceneObjectPart(localid); + + if(part != null && !part.ParentGroup.IsVolumeDetect) { - // Something with damage... - Health -= part.ParentGroup.Damage; - part.ParentGroup.Scene.DeleteSceneObject(part.ParentGroup, false); + if (part.ParentGroup.Damage > 0.0f) + { + // Something with damage... + Health -= part.ParentGroup.Damage; + part.ParentGroup.Scene.DeleteSceneObject(part.ParentGroup, false); + } + else + { + // An ordinary prim + rvel = coldata[localid].RelativeSpeed; + if(rvel < -5.0f) + { + Health -= 0.005f * rvel * rvel; + } + } } else { - // An ordinary prim - if (coldata[localid].PenetrationDepth >= 0.10f) - Health -= coldata[localid].PenetrationDepth * 5.0f; + } } - } - else - { - // 0 is the ground - // what about collisions with other avatars? - if (localid == 0 && coldata[localid].PenetrationDepth >= 0.10f) - Health -= coldata[localid].PenetrationDepth * 5.0f; - } - - if (Health <= 0.0f) - { - if (localid != 0) - killerObj = localid; - } - //m_log.Debug("[AVATAR]: Collision with localid: " + localid.ToString() + " at depth: " + coldata[localid].ToString()); - } - //Health = 100; - if (!Invulnerable) - { - if (starthealth != Health) - { - ControllingClient.SendHealth(Health); + if (Health <= 0.0f) + { + if (localid != 0) + killerObj = localid; + } } + if (Health <= 0) { - m_scene.EventManager.TriggerAvatarKill(killerObj, this); - } - if (starthealth == Health && Health < 100.0f) - { - Health += 0.03f; - if (Health > 100.0f) - Health = 100.0f; ControllingClient.SendHealth(Health); + m_scene.EventManager.TriggerAvatarKill(killerObj, this); + return; } } + + if(Math.Abs(Health - startHealth) > 1.0) + ControllingClient.SendHealth(Health); } public void setHealthWithUpdate(float health) @@ -4280,25 +5133,25 @@ namespace OpenSim.Region.Framework.Scenes // Clear known regions KnownRegions = new Dictionary(); - lock (m_reprioritization_timer) - { - m_reprioritization_timer.Enabled = false; - m_reprioritization_timer.Elapsed -= new ElapsedEventHandler(Reprioritize); - } - // I don't get it but mono crashes when you try to dispose of this timer, // unsetting the elapsed callback should be enough to allow for cleanup however. - // m_reprioritizationTimer.Dispose(); + // m_reprioritizationTimer.Dispose(); RemoveFromPhysicalScene(); - + m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd; + RemoveClientEvents(); // if (Animator != null) // Animator.Close(); Animator = null; + scriptedcontrols.Clear(); + ControllingClient = null; LifecycleState = ScenePresenceState.Removed; + IsDeleted = true; + m_updateAgentReceivedAfterTransferEvent.Dispose(); + m_updateAgentReceivedAfterTransferEvent = null; } public void AddAttachment(SceneObjectGroup gobj) @@ -4311,6 +5164,10 @@ namespace OpenSim.Region.Framework.Scenes m_attachments.Add(gobj); } + + IBakedTextureModule bakedModule = m_scene.RequestModuleInterface(); + if (bakedModule != null) + bakedModule.UpdateMeshAvatar(m_uuid); } /// @@ -4343,7 +5200,7 @@ namespace OpenSim.Region.Framework.Scenes } } } - + return attachments; } @@ -4474,6 +5331,287 @@ namespace OpenSim.Region.Framework.Scenes return validated; } + public void SendAttachmentsToAllAgents() + { + lock (m_attachments) + { + foreach (SceneObjectGroup sog in m_attachments) + { + m_scene.ForEachScenePresence(delegate(ScenePresence p) + { + if (p != this && sog.HasPrivateAttachmentPoint) + return; + + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + return; + + SendTerseUpdateToAgentNF(p); + SendAttachmentFullUpdateToAgentNF(sog, p); + }); + } + } + } + + // send attachments to a client without filters except for huds + // for now they are checked in several places down the line... + public void SendAttachmentsToAgentNF(ScenePresence p) + { + SendTerseUpdateToAgentNF(p); +// SendAvatarDataToAgentNF(this); + lock (m_attachments) + { + foreach (SceneObjectGroup sog in m_attachments) + { + SendAttachmentFullUpdateToAgentNF(sog, p); + } + } + } + + public void SendAttachmentFullUpdateToAgentNF(SceneObjectGroup sog, ScenePresence p) + { + if (p != this && sog.HasPrivateAttachmentPoint) + return; + + SceneObjectPart[] parts = sog.Parts; + SceneObjectPart rootpart = sog.RootPart; + + p.ControllingClient.SendEntityUpdate(rootpart, PrimUpdateFlags.FullUpdate); + + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart part = parts[i]; + if (part == rootpart) + continue; + p.ControllingClient.SendEntityUpdate(part, PrimUpdateFlags.FullUpdate); + } + } + + public void SendAttachmentScheduleUpdate(SceneObjectGroup sog) + { + if (IsChildAgent || IsInTransit) + return; + + SceneObjectPart[] origparts = sog.Parts; + SceneObjectPart[] parts = new SceneObjectPart[origparts.Length]; + PrimUpdateFlags[] flags = new PrimUpdateFlags[origparts.Length]; + + SceneObjectPart rootpart = sog.RootPart; + UpdateRequired rootreq = sog.RootPart.UpdateFlag; + + int j = 0; + bool allterse = true; + for (int i = 0; i < origparts.Length; i++) + { + if (origparts[i] != rootpart) + { + switch (origparts[i].UpdateFlag) + { + case UpdateRequired.NONE: + break; + + case UpdateRequired.TERSE: + flags[j] = PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity + | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity; + parts[j] = origparts[i]; + j++; + break; + + case UpdateRequired.FULL: + flags[j] = PrimUpdateFlags.FullUpdate; + allterse = false; + parts[j] = origparts[i]; + j++; + break; + } + } + origparts[i].UpdateFlag = 0; + } + + if (j == 0 && rootreq == UpdateRequired.NONE) + return; + + PrimUpdateFlags rootflag = PrimUpdateFlags.FullUpdate; + + if (rootreq != UpdateRequired.FULL && allterse) + { + rootflag = PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity + | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity; + } + + int nparts = j; + + ControllingClient.SendEntityUpdate(rootpart, rootflag); + + for (int i = 0; i < nparts; i++) + { + ControllingClient.SendEntityUpdate(parts[i], flags[i]); + } + + if (sog.HasPrivateAttachmentPoint) + return; + + List allPresences = m_scene.GetScenePresences(); + foreach (ScenePresence p in allPresences) + { + if (p == this) + continue; + + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + continue; + + p.ControllingClient.SendEntityUpdate(rootpart, rootflag); + + for (int i = 0; i < nparts; i++) + { + p.ControllingClient.SendEntityUpdate(parts[i], flags[i]); + } + } + } + + public void SendAttachmentUpdate(SceneObjectGroup sog, UpdateRequired UpdateFlag) + { + if (IsChildAgent || IsInTransit) + return; + + PrimUpdateFlags flag; + switch (UpdateFlag) + { + case UpdateRequired.TERSE: + flag = PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity + | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity; + break; + + case UpdateRequired.FULL: + flag = PrimUpdateFlags.FullUpdate; + break; + + default: + return; + } + + SceneObjectPart[] parts = sog.Parts; + SceneObjectPart rootpart = sog.RootPart; + +// rootpart.UpdateFlag = 0; + + ControllingClient.SendEntityUpdate(rootpart, flag); + + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart part = parts[i]; + if (part == rootpart) + continue; + ControllingClient.SendEntityUpdate(part, flag); +// part.UpdateFlag = 0; + } + + if (sog.HasPrivateAttachmentPoint) + return; + + List allPresences = m_scene.GetScenePresences(); + foreach (ScenePresence p in allPresences) + { + if (p == this) + continue; + + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + continue; + + p.ControllingClient.SendEntityUpdate(rootpart, flag); + + for (int i = 0; i < parts.Length; i++) + { + SceneObjectPart part = parts[i]; + if (part == rootpart) + continue; + p.ControllingClient.SendEntityUpdate(part, flag); + } + } + } + + public void SendAttachmentScheduleUpdate(SceneObjectPart part) + { + if (IsChildAgent || IsInTransit) + return; + + + PrimUpdateFlags flag; + switch (part.UpdateFlag) + { + case UpdateRequired.TERSE: + flag = PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity + | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity; + break; + + case UpdateRequired.FULL: + flag = PrimUpdateFlags.FullUpdate; + break; + + default: + return; + } + + part.UpdateFlag = 0; + + ControllingClient.SendEntityUpdate(part, flag); + + if (part.ParentGroup.HasPrivateAttachmentPoint) + return; + + List allPresences = m_scene.GetScenePresences(); + foreach (ScenePresence p in allPresences) + { + if (p == this) + continue; + + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + continue; + + p.ControllingClient.SendEntityUpdate(part, flag); + } + } + + + public void SendAttachmentUpdate(SceneObjectPart part, UpdateRequired UpdateFlag) + { + if (IsChildAgent || IsInTransit) + return; + + PrimUpdateFlags flag; + switch (UpdateFlag) + { + case UpdateRequired.TERSE: + flag = PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity + | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity; + break; + + case UpdateRequired.FULL: + flag = PrimUpdateFlags.FullUpdate; + break; + + default: + return; + } + +// part.UpdateFlag = 0; + + ControllingClient.SendEntityUpdate(part, flag); + + if (part.ParentGroup.HasPrivateAttachmentPoint) + return; + + List allPresences = m_scene.GetScenePresences(); + foreach (ScenePresence p in allPresences) + { + if (p == this) + continue; + if (ParcelHideThisAvatar && currentParcelUUID != p.currentParcelUUID && !p.IsViewerUIGod) + continue; + + p.ControllingClient.SendEntityUpdate(part, flag); + } + } + /// /// Send a script event to this scene presence's attachments /// @@ -4530,10 +5668,21 @@ namespace OpenSim.Region.Framework.Scenes } } + CameraData physActor_OnPhysicsRequestingCameraData() + { + return new CameraData + { + Valid = true, + MouseLook = this.m_mouseLook, + CameraRotation = this.CameraRotation, + CameraAtAxis = this.CameraAtAxis + }; + } + 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) + SceneObjectPart part = m_scene.GetSceneObjectPart(Obj_localID); + if (part == null) return; ControllingClient.SendTakeControls(controls, false, false); @@ -4543,7 +5692,7 @@ namespace OpenSim.Region.Framework.Scenes obj.ignoreControls = ScriptControlled.CONTROL_ZERO; obj.eventControls = ScriptControlled.CONTROL_ZERO; - obj.objectID = p.ParentGroup.UUID; + obj.objectID = part.ParentGroup.UUID; obj.itemID = Script_item_UUID; if (pass_on == 0 && accept == 0) { @@ -4562,7 +5711,6 @@ namespace OpenSim.Region.Framework.Scenes { IgnoredControls = ScriptControlled.CONTROL_ZERO; obj.eventControls = (ScriptControlled)controls; - obj.ignoreControls = ScriptControlled.CONTROL_ZERO; } lock (scriptedcontrols) @@ -4571,19 +5719,52 @@ namespace OpenSim.Region.Framework.Scenes { IgnoredControls &= ~(ScriptControlled)controls; if (scriptedcontrols.ContainsKey(Script_item_UUID)) - scriptedcontrols.Remove(Script_item_UUID); + RemoveScriptFromControlNotifications(Script_item_UUID, part); } else { - scriptedcontrols[Script_item_UUID] = obj; + AddScriptToControlNotifications(Script_item_UUID, part, ref obj); } } ControllingClient.SendTakeControls(controls, pass_on == 1 ? true : false, true); } + private void AddScriptToControlNotifications(OpenMetaverse.UUID Script_item_UUID, SceneObjectPart part, ref ScriptControllers obj) + { + scriptedcontrols[Script_item_UUID] = obj; + + PhysicsActor physActor = part.ParentGroup.RootPart.PhysActor; + if (physActor != null) + { + physActor.OnPhysicsRequestingCameraData -= physActor_OnPhysicsRequestingCameraData; + physActor.OnPhysicsRequestingCameraData += physActor_OnPhysicsRequestingCameraData; + } + } + + private void RemoveScriptFromControlNotifications(OpenMetaverse.UUID Script_item_UUID, SceneObjectPart part) + { + scriptedcontrols.Remove(Script_item_UUID); + + if (part != null) + { + PhysicsActor physActor = part.ParentGroup.RootPart.PhysActor; + if (physActor != null) + { + physActor.OnPhysicsRequestingCameraData -= physActor_OnPhysicsRequestingCameraData; + } + } + } + public void HandleForceReleaseControls(IClientAPI remoteClient, UUID agentID) { + foreach (ScriptControllers c in scriptedcontrols.Values) + { + SceneObjectGroup sog = m_scene.GetSceneObjectGroup(c.objectID); + if(sog != null && !sog.IsDeleted && sog.RootPart.PhysActor != null) + sog.RootPart.PhysActor.OnPhysicsRequestingCameraData -= physActor_OnPhysicsRequestingCameraData; + } + IgnoredControls = ScriptControlled.CONTROL_ZERO; lock (scriptedcontrols) { @@ -4592,7 +5773,36 @@ namespace OpenSim.Region.Framework.Scenes ControllingClient.SendTakeControls(int.MaxValue, false, false); } - private void UnRegisterSeatControls(UUID obj) + public void HandleRevokePermissions(UUID objectID, uint permissions ) + { + + // still skeleton code + if((permissions & (16 | 0x8000 )) == 0) //PERMISSION_TRIGGER_ANIMATION | PERMISSION_OVERRIDE_ANIMATIONS + return; + if(objectID == m_scene.RegionInfo.RegionID) // for all objects + { + + } + else + { + SceneObjectPart part = m_scene.GetSceneObjectPart(objectID); + if(part != null) + { + + } + } + } + + public void ClearControls() + { + IgnoredControls = ScriptControlled.CONTROL_ZERO; + lock (scriptedcontrols) + { + scriptedcontrols.Clear(); + } + } + + public void UnRegisterSeatControls(UUID obj) { List takers = new List(); @@ -4610,17 +5820,18 @@ namespace OpenSim.Region.Framework.Scenes public void UnRegisterControlEventsToScript(uint Obj_localID, UUID Script_item_UUID) { ScriptControllers takecontrols; + SceneObjectPart part = m_scene.GetSceneObjectPart(Obj_localID); lock (scriptedcontrols) { if (scriptedcontrols.TryGetValue(Script_item_UUID, out takecontrols)) { - ScriptControlled sctc = takecontrols.eventControls; + ScriptControlled sctc = takecontrols.eventControls; ControllingClient.SendTakeControls((int)sctc, false, false); ControllingClient.SendTakeControls((int)sctc, true, false); - scriptedcontrols.Remove(Script_item_UUID); + RemoveScriptFromControlNotifications(Script_item_UUID, part); IgnoredControls = ScriptControlled.CONTROL_ZERO; foreach (ScriptControllers scData in scriptedcontrols.Values) { @@ -4639,46 +5850,38 @@ namespace OpenSim.Region.Framework.Scenes if (scriptedcontrols.Count <= 0) return; - ScriptControlled allflags = ScriptControlled.CONTROL_ZERO; - - if (MouseDown) + ScriptControlled allflags; + // convert mouse from edge to level + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP) != 0 || + (flags & unchecked((uint)AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP)) != 0) { - allflags = LastCommands & (ScriptControlled.CONTROL_ML_LBUTTON | ScriptControlled.CONTROL_LBUTTON); - if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP) != 0 || (flags & unchecked((uint)AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP)) != 0) - { - allflags = ScriptControlled.CONTROL_ZERO; - MouseDown = true; - } + allflags = ScriptControlled.CONTROL_ZERO; } - + else // recover last state of mouse + allflags = LastCommands & (ScriptControlled.CONTROL_ML_LBUTTON | ScriptControlled.CONTROL_LBUTTON); + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN) != 0) - { allflags |= ScriptControlled.CONTROL_ML_LBUTTON; - MouseDown = true; - } - + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0) - { allflags |= ScriptControlled.CONTROL_LBUTTON; - MouseDown = true; - } - + // find all activated controls, whether the scripts are interested in them or not if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS) != 0) { allflags |= ScriptControlled.CONTROL_FWD; } - + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG) != 0) { allflags |= ScriptControlled.CONTROL_BACK; } - + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS) != 0) { allflags |= ScriptControlled.CONTROL_UP; } - + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0) { allflags |= ScriptControlled.CONTROL_DOWN; @@ -4688,17 +5891,17 @@ namespace OpenSim.Region.Framework.Scenes { allflags |= ScriptControlled.CONTROL_LEFT; } - + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG) != 0) { allflags |= ScriptControlled.CONTROL_RIGHT; } - + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0) { allflags |= ScriptControlled.CONTROL_ROT_RIGHT; } - + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0) { allflags |= ScriptControlled.CONTROL_ROT_LEFT; @@ -4711,7 +5914,7 @@ namespace OpenSim.Region.Framework.Scenes { UUID scriptUUID = kvp.Key; ScriptControllers scriptControlData = kvp.Value; - + ScriptControlled localHeld = allflags & scriptControlData.eventControls; // the flags interesting for us ScriptControlled localLast = LastCommands & scriptControlData.eventControls; // the activated controls in the last cycle ScriptControlled localChange = localHeld ^ localLast; // the changed bits @@ -4723,8 +5926,9 @@ namespace OpenSim.Region.Framework.Scenes } } } - + LastCommands = allflags; + MouseDown = (allflags & (ScriptControlled.CONTROL_ML_LBUTTON | ScriptControlled.CONTROL_LBUTTON)) != 0; } } @@ -4765,191 +5969,252 @@ namespace OpenSim.Region.Framework.Scenes return flags; } - private void ReprioritizeUpdates() + // returns true it local teleport allowed and sets the destiny position into pos + + private bool CheckLocalTPLandingPoint(ref Vector3 pos) { - if (Scene.IsReprioritizationEnabled && Scene.UpdatePrioritizationScheme != UpdatePrioritizationSchemes.Time) - { - lock (m_reprioritization_timer) - { - if (!m_reprioritizing) - m_reprioritization_timer.Enabled = m_reprioritizing = true; - else - m_reprioritization_called = true; - } - } - } + // Never constrain lures + if ((TeleportFlags & TeleportFlags.ViaLure) != 0) + return true; - private void Reprioritize(object sender, ElapsedEventArgs e) - { - ControllingClient.ReprioritizeUpdates(); + if (m_scene.RegionInfo.EstateSettings.AllowDirectTeleport) + return true; - lock (m_reprioritization_timer) + // do not constrain gods and estate managers + if(m_scene.Permissions.IsGod(m_uuid) || + m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) + return true; + + // will teleport to a telehub spawn point or landpoint if that results in getting closer to target + // if not the local teleport fails. + + float currDistanceSQ = Vector3.DistanceSquared(AbsolutePosition, pos); + + // first check telehub + + UUID TelehubObjectID = m_scene.RegionInfo.RegionSettings.TelehubObject; + if ( TelehubObjectID != UUID.Zero) { - m_reprioritization_timer.Enabled = m_reprioritizing = m_reprioritization_called; - m_reprioritization_called = false; - } - } + SceneObjectGroup telehubSOG = m_scene.GetSceneObjectGroup(TelehubObjectID); + if(telehubSOG != null) + { + Vector3 spawnPos; + float spawnDistSQ; - private void CheckLandingPoint(ref Vector3 pos) - { - // Never constrain lures - if ((TeleportFlags & TeleportFlags.ViaLure) != 0) - return; + SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray(); + if(spawnPoints.Length == 0) + { + spawnPos = new Vector3(128.0f, 128.0f, pos.Z); + spawnDistSQ = Vector3.DistanceSquared(spawnPos, pos); + } + else + { + Vector3 hubPos = telehubSOG.AbsolutePosition; + Quaternion hubRot = telehubSOG.GroupRotation; - if (m_scene.RegionInfo.EstateSettings.AllowDirectTeleport) - return; + spawnPos = spawnPoints[0].GetLocation(hubPos, hubRot); + spawnDistSQ = Vector3.DistanceSquared(spawnPos, pos); + + float testDistSQ; + Vector3 testSpawnPos; + for(int i = 1; i< spawnPoints.Length; i++) + { + testSpawnPos = spawnPoints[i].GetLocation(hubPos, hubRot); + testDistSQ = Vector3.DistanceSquared(testSpawnPos, pos); + + if(testDistSQ < spawnDistSQ) + { + spawnPos = testSpawnPos; + spawnDistSQ = testDistSQ; + } + } + } + if (currDistanceSQ < spawnDistSQ) + { + // we are already close + ControllingClient.SendAlertMessage("Can't teleport closer to destination"); + return false; + } + else + { + pos = spawnPos; + return true; + } + } + } ILandObject land = m_scene.LandChannel.GetLandObject(pos.X, pos.Y); - if (land.LandData.LandingType == (byte)LandingType.LandingPoint && - land.LandData.UserLocation != Vector3.Zero && - land.LandData.OwnerID != m_uuid && - (!m_scene.Permissions.IsGod(m_uuid)) && - (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid))) + if (land.LandData.LandingType != (byte)LandingType.LandingPoint + || land.LandData.OwnerID == m_uuid) + return true; + + Vector3 landLocation = land.LandData.UserLocation; + if(landLocation == Vector3.Zero) + return true; + + if (currDistanceSQ < Vector3.DistanceSquared(landLocation, pos)) { - float curr = Vector3.Distance(AbsolutePosition, pos); - if (Vector3.Distance(land.LandData.UserLocation, pos) < curr) - pos = land.LandData.UserLocation; - else - ControllingClient.SendAlertMessage("Can't teleport closer to destination"); + ControllingClient.SendAlertMessage("Can't teleport closer to destination"); + return false; } + + pos = land.LandData.UserLocation; + return true; } - private void CheckAndAdjustTelehub(SceneObjectGroup telehub, ref Vector3 pos) + const TeleportFlags TeleHubTPFlags = TeleportFlags.ViaLogin + | TeleportFlags.ViaHGLogin | TeleportFlags.ViaLocation; + + private bool CheckAndAdjustTelehub(SceneObjectGroup telehub, ref Vector3 pos, ref bool positionChanged) { - if ((m_teleportFlags & (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID)) == - (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID) || - (m_scene.TelehubAllowLandmarks == true ? false : ((m_teleportFlags & TeleportFlags.ViaLandmark) != 0 )) || - (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || - (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0) + // forcing telehubs on any tp that reachs this + if ((m_teleportFlags & TeleHubTPFlags) != 0 || + (m_scene.TelehubAllowLandmarks == true ? false : ((m_teleportFlags & TeleportFlags.ViaLandmark) != 0 ))) { + ILandObject land; + Vector3 teleHubPosition = telehub.AbsolutePosition; - if (GodLevel < 200 && - ((!m_scene.Permissions.IsGod(m_uuid) && - !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) || - (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || - (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0)) + SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray(); + if(spawnPoints.Length == 0) { - SpawnPoint[] spawnPoints = m_scene.RegionInfo.RegionSettings.SpawnPoints().ToArray(); - if (spawnPoints.Length == 0) + land = m_scene.LandChannel.GetLandObject(teleHubPosition.X,teleHubPosition.Y); + if(land != null) { - if(m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) - { - pos.X = 128.0f; - pos.Y = 128.0f; - } - return; + pos = teleHubPosition; + if(land.IsEitherBannedOrRestricted(UUID)) + return false; + positionChanged = true; + return true; } + else + return false; + } - int index; - bool selected = false; - - switch (m_scene.SpawnPointRouting) - { - case "random": + int index; + int tries; + bool selected = false; + bool validhub = false; + Vector3 spawnPosition; - if (spawnPoints.Length == 0) - return; - do - { - index = Util.RandomClass.Next(spawnPoints.Length - 1); - - Vector3 spawnPosition = spawnPoints[index].GetLocation( - telehub.AbsolutePosition, - telehub.GroupRotation - ); - // SpawnPoint sp = spawnPoints[index]; + Quaternion teleHubRotation = telehub.GroupRotation; - ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); + switch(m_scene.SpawnPointRouting) + { + case "random": + tries = spawnPoints.Length; + if(tries < 3) // no much sense in random with a few points when there same can have bans + goto case "sequence"; + do + { + index = Util.RandomClass.Next(spawnPoints.Length - 1); - if (land == null || land.IsEitherBannedOrRestricted(UUID)) - selected = false; - else - selected = true; + spawnPosition = spawnPoints[index].GetLocation(teleHubPosition, teleHubRotation); + land = m_scene.LandChannel.GetLandObject(spawnPosition.X,spawnPosition.Y); + if(land != null && !land.IsEitherBannedOrRestricted(UUID)) + selected = true; - } while ( selected == false); + } while(selected == false && --tries > 0 ); - pos = spawnPoints[index].GetLocation( - telehub.AbsolutePosition, - telehub.GroupRotation - ); - return; + if(tries <= 0) + goto case "sequence"; - case "sequence": + pos = spawnPosition; + return true; - do + case "sequence": + tries = spawnPoints.Length; + selected = false; + validhub = false; + do + { + index = m_scene.SpawnPoint(); + spawnPosition = spawnPoints[index].GetLocation(teleHubPosition, teleHubRotation); + land = m_scene.LandChannel.GetLandObject(spawnPosition.X,spawnPosition.Y); + if(land != null) { - index = m_scene.SpawnPoint(); - - Vector3 spawnPosition = spawnPoints[index].GetLocation( - telehub.AbsolutePosition, - telehub.GroupRotation - ); - // SpawnPoint sp = spawnPoints[index]; - - ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); - if (land == null || land.IsEitherBannedOrRestricted(UUID)) + validhub = true; + if(land.IsEitherBannedOrRestricted(UUID)) selected = false; else selected = true; + } - } while (selected == false); + } while(selected == false && --tries > 0); - pos = spawnPoints[index].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); - ; - return; + if(!validhub) + return false; - default: - case "closest": + pos = spawnPosition; - float distance = 9999; - int closest = -1; - - for (int i = 0; i < spawnPoints.Length; i++) - { - Vector3 spawnPosition = spawnPoints[i].GetLocation( - telehub.AbsolutePosition, - telehub.GroupRotation - ); - Vector3 offset = spawnPosition - pos; - float d = Vector3.Mag(offset); - if (d >= distance) - continue; - ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); - if (land == null) - continue; - if (land.IsEitherBannedOrRestricted(UUID)) - continue; - distance = d; - closest = i; - } - if (closest == -1) - return; - - pos = spawnPoints[closest].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); - return; + if(!selected) + return false; + positionChanged = true; + return true; - } + default: + case "closest": + float distancesq = float.MaxValue; + int closest = -1; + validhub = false; + + for(int i = 0; i < spawnPoints.Length; i++) + { + spawnPosition = spawnPoints[i].GetLocation(teleHubPosition, teleHubRotation); + Vector3 offset = spawnPosition - pos; + float dsq = offset.LengthSquared(); + land = m_scene.LandChannel.GetLandObject(spawnPosition.X,spawnPosition.Y); + if(land == null) + continue; + + validhub = true; + if(land.IsEitherBannedOrRestricted(UUID)) + continue; + + if(dsq >= distancesq) + continue; + distancesq = dsq; + closest = i; + } + + if(!validhub) + return false; + + if(closest < 0) + { + pos = spawnPoints[0].GetLocation(teleHubPosition, teleHubRotation); + positionChanged = true; + return false; + } + + pos = spawnPoints[closest].GetLocation(teleHubPosition, teleHubRotation); + positionChanged = true; + return true; } } + return false; } + const TeleportFlags adicionalLandPointFlags = TeleportFlags.ViaLandmark | + TeleportFlags.ViaLocation | TeleportFlags.ViaHGLogin; + // Modify landing point based on possible banning, telehubs or parcel restrictions. - private void CheckAndAdjustLandingPoint(ref Vector3 pos) + // This is the behavior in OpenSim for a very long time, different from SL + private bool CheckAndAdjustLandingPoint_OS(ref Vector3 pos, ref Vector3 lookat, ref bool positionChanged) { string reason; // Honor bans if (!m_scene.TestLandRestrictions(UUID, out reason, ref pos.X, ref pos.Y)) - return; + return false; SceneObjectGroup telehub = null; if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject)) != null) { if (!m_scene.RegionInfo.EstateSettings.AllowDirectTeleport) { - CheckAndAdjustTelehub(telehub, ref pos); - return; + CheckAndAdjustTelehub(telehub, ref pos, ref positionChanged); + return true; } } @@ -4964,27 +6229,84 @@ namespace OpenSim.Region.Framework.Scenes // to ignore them. if ((m_teleportFlags & (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID)) == (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID) || - (m_teleportFlags & TeleportFlags.ViaLandmark) != 0 || - (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || - (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0) + (m_teleportFlags & adicionalLandPointFlags) != 0) { // Don't restrict gods, estate managers, or land owners to // the TP point. This behaviour mimics agni. if (land.LandData.LandingType == (byte)LandingType.LandingPoint && land.LandData.UserLocation != Vector3.Zero && - GodLevel < 200 && - ((land.LandData.OwnerID != m_uuid && + !IsViewerUIGod && + ((land.LandData.OwnerID != m_uuid && !m_scene.Permissions.IsGod(m_uuid) && - !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) || + !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) || (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0)) { pos = land.LandData.UserLocation; + positionChanged = true; } } - + land.SendLandUpdateToClient(ControllingClient); } + + return true; + } + + // Modify landing point based on telehubs or parcel restrictions. + // This is a behavior coming from AVN, somewhat mimicking SL + private bool CheckAndAdjustLandingPoint_SL(ref Vector3 pos, ref Vector3 lookat, ref bool positionChanged) + { + string reason; + + // dont mess with gods + if(IsGod) + return true; + + // respect region owner and managers +// if(m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) +// return true; + + if (!m_scene.RegionInfo.EstateSettings.AllowDirectTeleport) + { + SceneObjectGroup telehub = null; + if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero && (telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject)) != null) + { + if(CheckAndAdjustTelehub(telehub, ref pos, ref positionChanged)) + return true; + } + } + + // Honor bans, actually we don't honour them + if (!m_scene.TestLandRestrictions(UUID, out reason, ref pos.X, ref pos.Y)) + return false; + + ILandObject land = m_scene.LandChannel.GetLandObject(pos.X, pos.Y); + if (land != null) + { + if (Scene.DebugTeleporting) + TeleportFlagsDebug(); + + // If we come in via login, landmark or map, we want to + // honor landing points. If we come in via Lure, we want + // to ignore them. + if ((m_teleportFlags & (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID)) == + (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID) + || (m_teleportFlags & adicionalLandPointFlags) != 0) + { + if (land.LandData.LandingType == (byte)LandingType.LandingPoint && + land.LandData.UserLocation != Vector3.Zero ) + // && + // land.LandData.OwnerID != m_uuid ) + { + pos = land.LandData.UserLocation; + if(land.LandData.UserLookAt != Vector3.Zero) + lookat = land.LandData.UserLookAt; + positionChanged = true; + } + } + } + return true; } private DetectedObject CreateDetObject(SceneObjectPart obj) @@ -4998,6 +6320,7 @@ namespace OpenSim.Region.Framework.Scenes detobj.velVector = obj.Velocity; detobj.colliderType = 0; detobj.groupUUID = obj.GroupID; + detobj.linkNumber = 0; return detobj; } @@ -5011,8 +6334,13 @@ namespace OpenSim.Region.Framework.Scenes detobj.posVector = av.AbsolutePosition; detobj.rotQuat = av.Rotation; detobj.velVector = av.Velocity; - detobj.colliderType = 0; + detobj.colliderType = av.IsNPC ? 0x20 : 0x1; // OpenSim\Region\ScriptEngine\Shared\Helpers.cs + if(av.IsSatOnObject) + detobj.colliderType |= 0x4; //passive + else if(detobj.velVector != Vector3.Zero) + detobj.colliderType |= 0x2; //active detobj.groupUUID = av.ControllingClient.ActiveGroupId; + detobj.linkNumber = 0; return detobj; } @@ -5028,7 +6356,7 @@ namespace OpenSim.Region.Framework.Scenes detobj.velVector = Vector3.Zero; detobj.colliderType = 0; detobj.groupUUID = UUID.Zero; - + detobj.linkNumber = 0; return detobj; } @@ -5095,29 +6423,404 @@ namespace OpenSim.Region.Framework.Scenes } } + private void RaiseCollisionScriptEvents(Dictionary coldata) + { + try + { + List thisHitColliders = new List(); + List endedColliders = new List(); + List startedColliders = new List(); + + if (coldata.Count == 0) + { + if (m_lastColliders.Count == 0) + return; // nothing to do + + foreach (uint localID in m_lastColliders) + { + endedColliders.Add(localID); + } + m_lastColliders.Clear(); + } + else + { + List soundinfolist = new List(); + if(ParcelAllowThisAvatarSounds) + { + CollisionForSoundInfo soundinfo; + ContactPoint curcontact; + + foreach (uint id in coldata.Keys) + { + thisHitColliders.Add(id); + if (!m_lastColliders.Contains(id)) + { + startedColliders.Add(id); + curcontact = coldata[id]; + if (Math.Abs(curcontact.RelativeSpeed) > 0.2) + { + soundinfo = new CollisionForSoundInfo(); + soundinfo.colliderID = id; + soundinfo.position = curcontact.Position; + soundinfo.relativeVel = curcontact.RelativeSpeed; + soundinfolist.Add(soundinfo); + } + } + } + } + else + { + foreach (uint id in coldata.Keys) + { + thisHitColliders.Add(id); + if (!m_lastColliders.Contains(id)) + startedColliders.Add(id); + } + } + // calculate things that ended colliding + foreach (uint localID in m_lastColliders) + { + if (!thisHitColliders.Contains(localID)) + { + endedColliders.Add(localID); + } + } + //add the items that started colliding this time to the last colliders list. + foreach (uint localID in startedColliders) + { + m_lastColliders.Add(localID); + } + // remove things that ended colliding from the last colliders list + foreach (uint localID in endedColliders) + { + m_lastColliders.Remove(localID); + } + + if (soundinfolist.Count > 0) + CollisionSounds.AvatarCollisionSound(this, soundinfolist); + } + + foreach (SceneObjectGroup att in GetAttachments()) + { + SendCollisionEvent(att, scriptEvents.collision_start, startedColliders, m_scene.EventManager.TriggerScriptCollidingStart); + SendCollisionEvent(att, scriptEvents.collision , m_lastColliders , m_scene.EventManager.TriggerScriptColliding); + SendCollisionEvent(att, scriptEvents.collision_end , endedColliders , m_scene.EventManager.TriggerScriptCollidingEnd); + + if (startedColliders.Contains(0)) + SendLandCollisionEvent(att, scriptEvents.land_collision_start, m_scene.EventManager.TriggerScriptLandCollidingStart); + if (m_lastColliders.Contains(0)) + SendLandCollisionEvent(att, scriptEvents.land_collision, m_scene.EventManager.TriggerScriptLandColliding); + if (endedColliders.Contains(0)) + SendLandCollisionEvent(att, scriptEvents.land_collision_end, m_scene.EventManager.TriggerScriptLandCollidingEnd); + } + } + catch { } +// finally +// { +// m_collisionEventFlag = false; +// } + } + private void TeleportFlagsDebug() { - + // Some temporary debugging help to show all the TeleportFlags we have... bool HG = false; if((m_teleportFlags & TeleportFlags.ViaHGLogin) == TeleportFlags.ViaHGLogin) HG = true; - + m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************"); - + uint i = 0u; for (int x = 0; x <= 30 ; x++, i = 1u << x) { i = 1u << x; - + if((m_teleportFlags & (TeleportFlags)i) == (TeleportFlags)i) if (HG == false) m_log.InfoFormat("[SCENE PRESENCE]: Teleport Flags include {0}", ((TeleportFlags) i).ToString()); else m_log.InfoFormat("[SCENE PRESENCE]: HG Teleport Flags include {0}", ((TeleportFlags)i).ToString()); } - + m_log.InfoFormat("[SCENE PRESENCE]: TELEPORT ******************"); - + + } + + private void parcelGodCheck(UUID currentParcelID) + { + List allpresences = m_scene.GetScenePresences(); + + foreach (ScenePresence p in allpresences) + { + if (p.IsDeleted || p.IsChildAgent || p == this || p.ControllingClient == null || !p.ControllingClient.IsActive) + continue; + + if (p.ParcelHideThisAvatar && p.currentParcelUUID != currentParcelID) + { + if (IsViewerUIGod) + p.SendViewTo(this); + else + p.SendKillTo(this); + } + } + } + + private void ParcelCrossCheck(UUID currentParcelID,UUID previusParcelID, + bool currentParcelHide, bool previusParcelHide, bool oldhide, bool check) + { + List killsToSendto = new List(); + List killsToSendme = new List(); + List viewsToSendto = new List(); + List viewsToSendme = new List(); + List allpresences = null; + + if (IsInTransit || IsChildAgent) + return; + + if (check) + { + // check is relative to current parcel only + if (oldhide == currentParcelHide) + return; + + allpresences = m_scene.GetScenePresences(); + + if (oldhide) + { // where private + foreach (ScenePresence p in allpresences) + { + if (p.IsDeleted || p == this || p.ControllingClient == null || !p.ControllingClient.IsActive) + continue; + + // those on not on parcel see me + if (currentParcelID != p.currentParcelUUID) + { + viewsToSendto.Add(p); // they see me + } + } + } // where private end + + else + { // where public + foreach (ScenePresence p in allpresences) + { + if (p.IsDeleted || p == this || p.ControllingClient == null || !p.ControllingClient.IsActive) + continue; + + // those not on parcel dont see me + if (currentParcelID != p.currentParcelUUID && !p.IsViewerUIGod) + { + killsToSendto.Add(p); // they dont see me + } + } + } // where public end + + allpresences.Clear(); + } + else + { + if (currentParcelHide) + { + // now on a private parcel + allpresences = m_scene.GetScenePresences(); + + if (previusParcelHide && previusParcelID != UUID.Zero) + { + foreach (ScenePresence p in allpresences) + { + if (p.IsDeleted || p == this || p.ControllingClient == null || !p.ControllingClient.IsActive) + continue; + + // only those on previus parcel need receive kills + if (previusParcelID == p.currentParcelUUID) + { + if(!p.IsViewerUIGod) + killsToSendto.Add(p); // they dont see me + if(!IsViewerUIGod) + killsToSendme.Add(p); // i dont see them + } + // only those on new parcel need see + if (currentParcelID == p.currentParcelUUID) + { + viewsToSendto.Add(p); // they see me + viewsToSendme.Add(p); // i see them + } + } + } + else + { + //was on a public area + allpresences = m_scene.GetScenePresences(); + + foreach (ScenePresence p in allpresences) + { + if (p.IsDeleted || p == this || p.ControllingClient == null || !p.ControllingClient.IsActive) + continue; + + // those not on new parcel dont see me + if (currentParcelID != p.currentParcelUUID && !p.IsViewerUIGod) + { + killsToSendto.Add(p); // they dont see me + } + else + { + viewsToSendme.Add(p); // i see those on it + } + } + } + allpresences.Clear(); + } // now on a private parcel end + + else + { + // now on public parcel + if (previusParcelHide && previusParcelID != UUID.Zero) + { + // was on private area + allpresences = m_scene.GetScenePresences(); + + foreach (ScenePresence p in allpresences) + { + if (p.IsDeleted || p == this || p.ControllingClient == null || !p.ControllingClient.IsActive) + continue; + // only those old parcel need kills + if (previusParcelID == p.currentParcelUUID && !IsViewerUIGod) + { + killsToSendme.Add(p); // i dont see them + } + else + { + viewsToSendto.Add(p); // they see me + } + } + } + else + return; // was on a public area also + } // now on public parcel end + } + + // send the things + + if (killsToSendto.Count > 0) + { + foreach (ScenePresence p in killsToSendto) + { +// m_log.Debug("[AVATAR]: killTo: " + Lastname + " " + p.Lastname); + SendKillTo(p); + } + } + + if (killsToSendme.Count > 0) + { + foreach (ScenePresence p in killsToSendme) + { +// m_log.Debug("[AVATAR]: killToMe: " + Lastname + " " + p.Lastname); + p.SendKillTo(this); + } + } + + if (viewsToSendto.Count > 0) + { + foreach (ScenePresence p in viewsToSendto) + { + SendViewTo(p); + } + } + + if (viewsToSendme.Count > 0 ) + { + foreach (ScenePresence p in viewsToSendme) + { + if (p.IsChildAgent) + continue; +// m_log.Debug("[AVATAR]: viewMe: " + Lastname + "<-" + p.Lastname); + p.SendViewTo(this); + } + } + } + + public void HasMovedAway(bool nearRegion) + { + if (nearRegion) + { + if (Scene.AttachmentsModule != null) + Scene.AttachmentsModule.DeleteAttachmentsFromScene(this, true); + + if (!ParcelHideThisAvatar || IsViewerUIGod) + return; + + List allpresences = m_scene.GetScenePresences(); + foreach (ScenePresence p in allpresences) + { + if (p.IsDeleted || p == this || p.IsChildAgent || p.ControllingClient == null || !p.ControllingClient.IsActive) + continue; + + if (p.currentParcelUUID == m_currentParcelUUID) + { + p.SendKillTo(this); + } + } + } + else + { + GodController.HasMovedAway(); + List allpresences = m_scene.GetScenePresences(); + foreach (ScenePresence p in allpresences) + { + if (p == this) + continue; + SendKillTo(p); + if (!p.IsChildAgent) + p.SendKillTo(this); + } + + if (Scene.AttachmentsModule != null) + Scene.AttachmentsModule.DeleteAttachmentsFromScene(this, true); + } + } + + +// kill with attachs root kills + public void SendKillTo(ScenePresence p) + { + List ids = new List(m_attachments.Count + 1); + foreach (SceneObjectGroup sog in m_attachments) + { + ids.Add(sog.RootPart.LocalId); + } + + ids.Add(LocalId); + p.ControllingClient.SendKillObject(ids); + } + +/* +// kill with hack + public void SendKillTo(ScenePresence p) + { + foreach (SceneObjectGroup sog in m_attachments) + p.ControllingClient.SendPartFullUpdate(sog.RootPart, LocalId + 1); + p.ControllingClient.SendKillObject(new List { LocalId }); + } +*/ + public void SendViewTo(ScenePresence p) + { + SendAvatarDataToAgentNF(p); + SendAppearanceToAgent(p); + if (Animator != null) + Animator.SendAnimPackToClient(p.ControllingClient); + SendAttachmentsToAgentNF(p); + } + + public void SetAnimationOverride(string animState, UUID animID) + { + Overrides.SetOverride(animState, animID); +// Animator.SendAnimPack(); + Animator.ForceUpdateMovementAnimations(); + } + + public UUID GetAnimationOverride(string animState) + { + return Overrides.GetOverriddenAnimation(animState); } } } -- cgit v1.1