diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index e75b3249a6..0fc1d1df3f 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -4061,6 +4061,10 @@ public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags,doub public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) { + + if(entity is ScenePresence) + SendAvatarUpdate(entity, updateFlags); // don't queue avatars info + object[] o = new object[]{ entity, updateFlags }; m_UpdatesQueue.Enqueue(o); } @@ -4075,7 +4079,7 @@ public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags) public void DequeueUpdates(int nupdates) { object o; - while (m_UpdatesQueue.Dequeue(out o) && nupdates-- > 0) + while (m_UpdatesQueue.Dequeue(out o)) { ISceneEntity entity = (ISceneEntity)((object[])o)[0]; PrimUpdateFlags updateFlags = (PrimUpdateFlags)((object[])o)[1]; @@ -4083,12 +4087,11 @@ public void DequeueUpdates(int nupdates) SendAvatarUpdate(entity, updateFlags); else intSendPrimUpdate(entity, updateFlags); + if (--nupdates <= 0) + break; } } - - - public void QueueDelayedUpdate(PriorityQueueItem it) { PriorityQueueItem item = new PriorityQueueItem(); diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index af76b29cb0..6c6bb2b626 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs @@ -202,13 +202,13 @@ private double GetPriorityByOOBDistance(IClientAPI client, ISceneEntity entity) // before its scheduled update was triggered //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition; SceneObjectPart p = (SceneObjectPart)entity; - entityPos = p.ParentGroup.AbsolutePosition + p.OOBoffset; + entityPos = p.ParentGroup.AbsolutePosition + p.OOBoffset * p.ParentGroup.GroupRotation; oobSQ = p.ParentGroup.BSphereRadiusSQ; } else if (entity is SceneObjectGroup) { SceneObjectGroup p = (SceneObjectGroup)entity; - entityPos = p.AbsolutePosition + p.OOBoffset; + entityPos = p.AbsolutePosition + p.OOBoffset * p.GroupRotation; oobSQ = p.BSphereRadiusSQ; } else diff --git a/OpenSim/Region/Framework/Scenes/SceneViewer.cs b/OpenSim/Region/Framework/Scenes/SceneViewer.cs index f130df8d69..9a9278d7e9 100644 --- a/OpenSim/Region/Framework/Scenes/SceneViewer.cs +++ b/OpenSim/Region/Framework/Scenes/SceneViewer.cs @@ -43,30 +43,40 @@ public class SceneViewer : ISceneViewer { #region Declares + private const double MINVIEWDSTEP = 16; + private const double MINVIEWDSTEPSQ = MINVIEWDSTEP * MINVIEWDSTEP; + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected ScenePresence m_presence; - protected PriorityQueue m_partsUpdateQueue; +// protected PriorityQueue m_partsUpdateQueue; /// /// Param 1 - LocalID of the object, Param 2 - The last version when this was added to the list /// - protected Dictionary m_removeNextUpdateOf = new Dictionary(); - protected List m_removeUpdateOf = new List(); +// protected Dictionary m_removeNextUpdateOf = new Dictionary(); +// protected List m_removeUpdateOf = new List(); protected bool m_SentInitialObjects = false; protected volatile bool m_queueing =false; protected volatile bool m_inUse = false; - protected volatile bool m_updatesNeedReprioritization = false; - protected volatile List m_objectsInView = new List(); +// protected volatile bool m_updatesNeedReprioritization = false; +// protected volatile List m_objectsInView = new List(); protected Prioritizer m_prioritizer; - private readonly Mutex _versionAllocateMutex = new Mutex(false); - protected int m_lastVersion = 0; +// private readonly Mutex _versionAllocateMutex = new Mutex(false); +// protected int m_lastVersion = 0; private Queue m_delayedUpdates = new Queue(); + private HashSet lastGrpsInView = new HashSet(); + + private Vector3 m_lastUpdatePos; + private float lastDrawDistance; public Prioritizer Prioritizer { get { return m_prioritizer; } } + + + #endregion #region Constructor @@ -76,13 +86,22 @@ public SceneViewer(ScenePresence presence) m_presence = presence; m_presence.Scene.EventManager.OnSignificantClientMovement += SignificantClientMovement; m_prioritizer = new Prioritizer(presence.Scene); - m_partsUpdateQueue = new PriorityQueue(presence.Scene.Entities.Count > 1000 ? presence.Scene.Entities.Count + 1000 : 1000); +// m_partsUpdateQueue = new PriorityQueue(presence.Scene.Entities.Count > 1000 ? presence.Scene.Entities.Count + 1000 : 1000); } #endregion #region Enqueue/Remove updates for objects + private double calcMinPrio() + { + double p = -m_presence.DrawDistance * m_presence.DrawDistance; + if (p == 0) + p = -1024; + p -= MINVIEWDSTEPSQ; + return p; + } + /// /// Add the objects to the queue for which we need to send an update to the client /// @@ -98,8 +117,13 @@ public void QueuePartForUpdate(SceneObjectPart part, PrimUpdateFlags UpdateFlags if (ignore) return; */ - double priority = m_prioritizer.GetUpdatePriority(m_presence.ControllingClient, part.ParentGroup); -// check vis + if (m_presence.Scene.CheckForObjectCulling) + { + // priority is negative of distance + double priority = m_prioritizer.GetUpdatePriority(m_presence.ControllingClient, part.ParentGroup); + if (priority < calcMinPrio()) + return; // if 2 far ignore + } lock (m_delayedUpdates) { @@ -132,6 +156,7 @@ public void QueuePartForUpdate(SceneObjectPart part, PrimUpdateFlags UpdateFlags /// Updates the last version securely and set the update's version correctly /// /// +/* private void FixVersion(EntityUpdate update) { _versionAllocateMutex.WaitOne(); @@ -154,13 +179,14 @@ private int GetVersion() return version; } - +*/ /// /// Clear the updates for this part in the next update loop /// /// public void ClearUpdatesForPart(SceneObjectPart part) { +/* lock (m_removeUpdateOf) { //Add it to the list to check and make sure that we do not send updates for this object @@ -169,6 +195,7 @@ public void ClearUpdatesForPart(SceneObjectPart part) if (m_objectsInView.Contains(part.UUID)) m_objectsInView.Remove(part.UUID); } + */ } /// @@ -177,6 +204,7 @@ public void ClearUpdatesForPart(SceneObjectPart part) /// public void ClearUpdatesForOneLoopForPart(SceneObjectPart part) { +/* lock (m_removeNextUpdateOf) { //Add it to the list to check and make sure that we do not send updates for this object @@ -185,6 +213,7 @@ public void ClearUpdatesForOneLoopForPart(SceneObjectPart part) if (m_objectsInView.Contains(part.UUID)) m_objectsInView.Remove(part.UUID); } + */ } /// @@ -193,7 +222,7 @@ public void ClearUpdatesForOneLoopForPart(SceneObjectPart part) /// public void Reprioritize() { - m_updatesNeedReprioritization = true; +// m_updatesNeedReprioritization = true; } #endregion @@ -206,7 +235,7 @@ public void Reprioritize() /// /// private void SignificantClientMovement(IClientAPI remote_client) - { + { if (!m_presence.Scene.CheckForObjectCulling) return; @@ -214,10 +243,85 @@ private void SignificantClientMovement(IClientAPI remote_client) if (remote_client.AgentId != m_presence.UUID) return; - //If the draw distance is 0, the client has gotten messed up or something and we can't do this... - if(m_presence.DrawDistance == 0) + if (m_presence.DrawDistance == 0) return; + + + //If the draw distance is 0, the client has gotten messed up or something and we can't do this... + if (!m_presence.IsChildAgent || (m_presence.Scene.RegionInfo.SeeIntoThisSimFromNeighbor)) + { + Vector3 pos = m_presence.CameraPosition; + float distsq = Vector3.DistanceSquared(pos, m_lastUpdatePos); + distsq += 0.2f * m_presence.Velocity.LengthSquared(); + if (lastDrawDistance == m_presence.DrawDistance && distsq < MINVIEWDSTEPSQ) + return; + + if ( + lastDrawDistance > m_presence.Scene.RegionInfo.RegionSizeX && + lastDrawDistance > m_presence.Scene.RegionInfo.RegionSizeY + ) + { + lastDrawDistance = m_presence.DrawDistance; + lastGrpsInView.Clear(); + return; + } + + lock (m_delayedUpdates) + { + if (m_queueing) + return; + m_queueing = true; + Util.FireAndForget(DoSignificantClientMovement); + } + } + } + + private void DoSignificantClientMovement(object o) + { + EntityBase[] entities = m_presence.Scene.Entities.GetEntities(); + PriorityQueue m_entsqueue = new PriorityQueue(entities.Length); + + double newminp = calcMinPrio() - 0.2*m_presence.Velocity.LengthSquared();; + + // build a prioritized list of things we need to send + + HashSet NewGrpsInView = new HashSet(); + + foreach (EntityBase e in entities) + { + if (e != null && e is SceneObjectGroup) + { + if (e.IsDeleted) + continue; + + double priority = m_prioritizer.GetUpdatePriority(m_presence.ControllingClient, e); + + //Check for culling here! + if (priority < newminp) + continue; // if 2 far ignore + + NewGrpsInView.Add((SceneObjectGroup)e); + + if (lastGrpsInView.Contains((SceneObjectGroup)e)) + continue; + + EntityUpdate update = new EntityUpdate(e, PrimUpdateFlags.FullUpdate); + PriorityQueueItem item = new PriorityQueueItem(); + item.Value = update; + item.Priority = priority; + m_entsqueue.Enqueue(item); + } + } + entities = null; + lastGrpsInView.Clear(); + lastGrpsInView.UnionWith(NewGrpsInView); + NewGrpsInView.Clear(); + + // send them + SendQueued(m_entsqueue); + } +/* //This checks to see if we need to send more updates to the avatar since they last moved EntityBase[] Entities = m_presence.Scene.Entities.GetEntities(); @@ -226,6 +330,7 @@ private void SignificantClientMovement(IClientAPI remote_client) if (entity is SceneObjectGroup) //Only objects { //Check to see if they are in range + if (CheckForCulling(entity)) { //Check if we already have sent them an update @@ -241,13 +346,14 @@ private void SignificantClientMovement(IClientAPI remote_client) } Entities = null; } - +*/ /// /// Checks to see whether the object should be sent to the client /// Returns true if the client should be able to see the object, false if not /// /// /// +/* private bool CheckForCulling(ISceneEntity grp) { if (!m_presence.Scene.CheckForObjectCulling) @@ -299,7 +405,7 @@ private bool CheckCullingAgainstPosition(Vector3 checkPosition, Vector3 groupPos //All done then... return false; } - +*/ #endregion #region SendPrimUpdates @@ -323,15 +429,24 @@ public void SendPrimUpdates() ///If we havn't started processing this client yet, we need to send them ALL the prims that we have in this Scene (and deal with culling as well...) if (!m_SentInitialObjects) { - lock (m_delayedUpdates) - { - m_queueing = true; - } m_SentInitialObjects = true; //If they are not in this region, we check to make sure that we allow seeing into neighbors if (!m_presence.IsChildAgent || (m_presence.Scene.RegionInfo.SeeIntoThisSimFromNeighbor)) { - m_queueing = true; + lock (m_delayedUpdates) + { + m_queueing = true; + } + double minp = calcMinPrio(); + bool doculling = m_presence.Scene.CheckForObjectCulling; + + if (doculling && + m_presence.DrawDistance > m_presence.Scene.RegionInfo.RegionSizeX && + m_presence.DrawDistance > m_presence.Scene.RegionInfo.RegionSizeY + ) + doculling = false; + + EntityBase[] entities = m_presence.Scene.Entities.GetEntities(); PriorityQueue m_entsqueue = new PriorityQueue(entities.Length); @@ -347,11 +462,13 @@ public void SendPrimUpdates() double priority = m_prioritizer.GetUpdatePriority(m_presence.ControllingClient, e); //Check for culling here! - if (!CheckForCulling(e)) - continue; - - if (e is IScenePresence) - priority += 1; + if (doculling) + { + // priority is negative of distance + if (priority < minp) + continue; // if 2 far ignore + lastGrpsInView.Add((SceneObjectGroup)e); + } EntityUpdate update = new EntityUpdate(e, PrimUpdateFlags.FullUpdate); PriorityQueueItem item = new PriorityQueueItem(); @@ -362,78 +479,75 @@ public void SendPrimUpdates() } entities = null; // send them + SendQueued(m_entsqueue); + } + } - PriorityQueueItem up; - bool cont = true; - while (cont) - { - cont = m_entsqueue.TryDequeue(out up); - if (!cont) - break; + //Add the time to the stats tracker + IAgentUpdateMonitor reporter = (IAgentUpdateMonitor)m_presence.Scene.RequestModuleInterface().GetMonitor(m_presence.Scene.RegionInfo.RegionID.ToString(), "Agent Update Count"); + if (reporter != null) + reporter.AddAgentTime(Util.EnvironmentTickCountSubtract(AgentMS)); - //Make sure not send deleted or null objects - - SceneObjectGroup ent =(SceneObjectGroup)up.Value.Entity; + m_inUse = false; + } + private void SendQueued(PriorityQueue m_entsqueue) + { + PriorityQueueItem up; + + while (m_entsqueue.TryDequeue(out up)) + { + //Make sure not send deleted or null objects - if (ent == null || ent.IsDeleted) - continue; + SceneObjectGroup ent = (SceneObjectGroup)up.Value.Entity; + if (ent == null || ent.IsDeleted) + continue; - if (ent.RootPart.Shape.PCode == 9 && ent.RootPart.Shape.State != 0) - { - byte state = ent.RootPart.Shape.State; - if (( - state == (byte)AttachmentPoint.HUDBottom || - state == (byte)AttachmentPoint.HUDBottomLeft || - state == (byte)AttachmentPoint.HUDBottomRight || - state == (byte)AttachmentPoint.HUDCenter || - state == (byte)AttachmentPoint.HUDCenter2 || - state == (byte)AttachmentPoint.HUDTop || - state == (byte)AttachmentPoint.HUDTopLeft || - state == (byte)AttachmentPoint.HUDTopRight - ) - && - ent.RootPart.OwnerID != m_presence.UUID) - continue; - SendUpdate(up.Value.Flags, ent); - } - else - { - List parts = ent.ChildrenList; - foreach (SceneObjectPart part in parts) - { - SendUpdate(part, m_presence.GenerateClientFlags(part), up.Value.Flags); - } - } - } - m_entsqueue.Clear(); + if (ent.RootPart.Shape.PCode == 9 && ent.RootPart.Shape.State != 0) + { + byte state = ent.RootPart.Shape.State; + if (( + state == (byte)AttachmentPoint.HUDBottom || + state == (byte)AttachmentPoint.HUDBottomLeft || + state == (byte)AttachmentPoint.HUDBottomRight || + state == (byte)AttachmentPoint.HUDCenter || + state == (byte)AttachmentPoint.HUDCenter2 || + state == (byte)AttachmentPoint.HUDTop || + state == (byte)AttachmentPoint.HUDTopLeft || + state == (byte)AttachmentPoint.HUDTopRight + ) + && + ent.RootPart.OwnerID != m_presence.UUID) + continue; + } + SendUpdate(up.Value.Flags, ent); + } + m_entsqueue.Clear(); - // send things that arrived meanwhile - lock (m_delayedUpdates) - { - object o; - while (m_delayedUpdates.Count>0) - { - o = m_delayedUpdates.Dequeue(); - if (o == null) - break; - SceneObjectPart p = (SceneObjectPart)((object[])o)[0]; - PrimUpdateFlags updateFlags = (PrimUpdateFlags)((object[])o)[1]; - SendUpdate(p, m_presence.GenerateClientFlags(p), updateFlags); - } - m_queueing = false; - } + // send things that arrived meanwhile + lock (m_delayedUpdates) + { + object o; + while (m_delayedUpdates.Count > 0) + { + o = m_delayedUpdates.Dequeue(); + if (o == null) + break; + SceneObjectPart p = (SceneObjectPart)((object[])o)[0]; + PrimUpdateFlags updateFlags = (PrimUpdateFlags)((object[])o)[1]; + SendUpdate(p, m_presence.GenerateClientFlags(p), updateFlags); } - //Add the time to the stats tracker + m_lastUpdatePos = (m_presence.IsChildAgent) ? + m_presence.AbsolutePosition : + m_presence.CameraPosition; + lastDrawDistance = m_presence.DrawDistance; + if (lastDrawDistance < 32) + lastDrawDistance = 32; + m_queueing = false; } + } - IAgentUpdateMonitor reporter = (IAgentUpdateMonitor)m_presence.Scene.RequestModuleInterface().GetMonitor(m_presence.Scene.RegionInfo.RegionID.ToString(), "Agent Update Count"); - if (reporter != null) - reporter.AddAgentTime(Util.EnvironmentTickCountSubtract(AgentMS)); - m_inUse = false; - } - #endregion /* #region Update loop that sends objects that have been recently added to the queue