/// <summary> /// This method is called by the LLUDPServer and should never be called by anyone else /// It loops through the available updates and sends them out (no waiting) /// </summary> /// <param name="numUpdates">The number of updates to send</param> public void SendPrimUpdates (int numPrimUpdates, int numAvaUpdates) { if (m_inUse || ((ScenePresence)m_presence).IsInTransit) return; if (m_numberOfLoops < NUMBER_OF_LOOPS_TO_WAIT) //Wait for the client to finish connecting fully before sending out bunches of updates { m_numberOfLoops++; return; } m_inUse = true; //This is for stats int AgentMS = Util.EnvironmentTickCount (); #region New client entering the Scene, requires all objects in the Scene ///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 && m_presence.DrawDistance != 0.0f) { //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_prioritizer != null) { m_SentInitialObjects = true; ISceneEntity[] entities = m_presence.Scene.Entities.GetEntities (); PriorityQueue<EntityUpdate, double> m_entsqueue = new PriorityQueue<EntityUpdate, double> (entities.Length, DoubleComparer); List<ISceneEntity> NewGrpsInView = new List<ISceneEntity> (); // build a prioritized list of things we need to send foreach (ISceneEntity e in entities) { if (e != null && e is SceneObjectGroup) { if (e.IsDeleted) continue; if (lastGrpsInView.Contains (e)) continue; //Check for culling here! if (Culler != null) { if (!Culler.ShowEntityToClient (m_presence, e)) continue; NewGrpsInView.Add (e); } //Send the root object first! EntityUpdate rootupdate = new EntityUpdate (e.RootChild, PrimUpdateFlags.FullUpdate); PriorityQueueItem<EntityUpdate, double> rootitem = new PriorityQueueItem<EntityUpdate, double> (); rootitem.Value = rootupdate; rootitem.Priority = m_prioritizer.GetUpdatePriority (m_presence, e.RootChild); m_entsqueue.Enqueue (rootitem); foreach (ISceneChildEntity child in e.ChildrenEntities ()) { if (child == e.RootChild) continue; //Already sent EntityUpdate update = new EntityUpdate (child, PrimUpdateFlags.ForcedFullUpdate); PriorityQueueItem<EntityUpdate, double> item = new PriorityQueueItem<EntityUpdate, double> (); item.Value = update; item.Priority = m_prioritizer.GetUpdatePriority (m_presence, child); m_entsqueue.Enqueue (item); } } } //Merge the last seen lists lastGrpsInView.UnionWith (NewGrpsInView); NewGrpsInView.Clear (); entities = null; // send them SendQueued (m_entsqueue); } } int presenceNumToSend = numAvaUpdates; lock (m_presenceUpdatesToSend) { //Send the numUpdates of them if that many // if we don't have that many, we send as many as possible, then switch to objects if (m_presenceUpdatesToSend.Count != 0) { try { int count = m_presenceUpdatesToSend.Count > presenceNumToSend ? presenceNumToSend : m_presenceUpdatesToSend.Count; List<EntityUpdate> updates = new List<EntityUpdate> (); for (int i = 0; i < count; i++) { EntityUpdate update = ((EntityUpdate)m_presenceUpdatesToSend[0]); if (m_EntitiesInPacketQueue.Contains (update.Entity.UUID)) { m_presenceUpdatesToSend.RemoveAt (0); m_presenceUpdatesToSend.Insert (m_presenceUpdatesToSend.Count, update.Entity.UUID, update); continue; } updates.Add (update); m_EntitiesInPacketQueue.Add (update.Entity.UUID); m_presenceUpdatesToSend.RemoveAt (0); } if (updates.Count != 0) { presenceNumToSend -= updates.Count; //Make sure we don't have an update for us if (updates[0].Entity.UUID == m_presence.UUID) m_ourPresenceHasUpdate = false; m_presence.ControllingClient.SendAvatarUpdate (updates); } } catch (Exception ex) { m_log.WarnFormat ("[SceneViewer]: Exception while running presence loop: {0}", ex.ToString ()); } } } lock (m_presenceAnimationsToSend) { //Send the numUpdates of them if that many // if we don't have that many, we send as many as possible, then switch to objects if (m_presenceAnimationsToSend.Count != 0 && presenceNumToSend > 0) { try { int count = m_presenceAnimationsToSend.Count > presenceNumToSend ? presenceNumToSend : m_presenceAnimationsToSend.Count; for (int i = 0; i < count; i++) { AnimationGroup update = ((AnimationGroup)m_presenceAnimationsToSend[0]); if (m_AnimationsInPacketQueue.Contains (update.AvatarID)) { m_presenceAnimationsToSend.RemoveAt (0); m_presenceAnimationsToSend.Insert (m_presenceAnimationsToSend.Count, update.AvatarID, update); continue; } m_AnimationsInPacketQueue.Add (update.AvatarID); m_presenceAnimationsToSend.RemoveAt (0); m_presence.ControllingClient.SendAnimations (update); } } catch (Exception ex) { m_log.WarnFormat ("[SceneViewer]: Exception while running presence loop: {0}", ex.ToString ()); } } } int primsNumToSend = numPrimUpdates; lock (m_objectPropertiesToSend) { //Send the numUpdates of them if that many // if we don't have that many, we send as many as possible, then switch to objects if (m_objectPropertiesToSend.Count != 0) { try { List<IEntity> entities = new List<IEntity> (); int count = m_objectPropertiesToSend.Count > primsNumToSend ? primsNumToSend : m_objectPropertiesToSend.Count; for (int i = 0; i < count; i++) { ISceneChildEntity entity = ((ISceneChildEntity)m_objectPropertiesToSend[0]); if (m_PropertiesInPacketQueue.Contains (entity.UUID)) { m_objectPropertiesToSend.RemoveAt (0); m_objectPropertiesToSend.Insert (m_objectPropertiesToSend.Count, entity.UUID, entity); continue; } m_PropertiesInPacketQueue.Add (entity.UUID); m_objectPropertiesToSend.RemoveAt (0); entities.Add (entity); } if (entities.Count > 0) { primsNumToSend -= entities.Count; m_presence.ControllingClient.SendObjectPropertiesReply (entities); } } catch (Exception ex) { m_log.WarnFormat ("[SceneViewer]: Exception while running presence loop: {0}", ex.ToString ()); } } } lock (m_objectUpdatesToSend) { if (m_objectUpdatesToSend.Count != 0) { try { int count = m_objectUpdatesToSend.Count > primsNumToSend ? primsNumToSend : m_objectUpdatesToSend.Count; List<EntityUpdate> updates = new List<EntityUpdate> (); for (int i = 0; i < count; i++) { EntityUpdate update = ((EntityUpdate)m_objectUpdatesToSend[0]); if (m_EntitiesInPacketQueue.Contains (update.Entity.UUID)) { m_objectUpdatesToSend.RemoveAt (0); m_objectUpdatesToSend.Insert (m_objectUpdatesToSend.Count, update.Entity.UUID, update); continue; } updates.Add (update); m_EntitiesInPacketQueue.Add (update.Entity.UUID); m_objectUpdatesToSend.RemoveAt (0); } m_presence.ControllingClient.SendPrimUpdate (updates); } catch (Exception ex) { m_log.WarnFormat ("[SceneViewer]: Exception while running object loop: {0}", ex.ToString ()); } } } //Add the time to the stats tracker IAgentUpdateMonitor reporter = (IAgentUpdateMonitor)m_presence.Scene.RequestModuleInterface<IMonitorModule> ().GetMonitor (m_presence.Scene.RegionInfo.RegionID.ToString (), "Agent Update Count"); if (reporter != null) reporter.AddAgentTime (Util.EnvironmentTickCountSubtract (AgentMS)); m_inUse = false; }
private void QueueEntityUpdate(EntityUpdate update) { lock (m_objectUpdatesToSend) { EntityUpdate o = (EntityUpdate)m_objectUpdatesToSend[update.Entity.UUID]; if (o == null) o = update; else { if (o.Flags == update.Flags) return; //Same, leave it alone! o.Flags = o.Flags | update.Flags; m_objectUpdatesToSend.Remove(update.Entity.UUID); } m_objectUpdatesToSend.Insert(m_objectUpdatesToSend.Count, o.Entity.UUID, o); } }
private void DoSignificantClientMovement (object o) { ISceneEntity[] entities = m_presence.Scene.Entities.GetEntities (m_presence.AbsolutePosition, m_presence.DrawDistance * 3); PriorityQueue<EntityUpdate, double> m_entsqueue = new PriorityQueue<EntityUpdate, double> (entities.Length, DoubleComparer); // build a prioritized list of things we need to send HashSet<ISceneEntity> NewGrpsInView = new HashSet<ISceneEntity> (); foreach (ISceneEntity e in entities) { if (e != null) { if (e.IsDeleted) continue; if (lastGrpsInView.Contains (e)) //If we've already sent it, don't send it again continue; if (Culler != null) { if (!Culler.ShowEntityToClient (m_presence, e)) continue; NewGrpsInView.Add (e); } //Send the root object first! EntityUpdate rootupdate = new EntityUpdate (e.RootChild, PrimUpdateFlags.ForcedFullUpdate); PriorityQueueItem<EntityUpdate, double> rootitem = new PriorityQueueItem<EntityUpdate, double> (); rootitem.Value = rootupdate; rootitem.Priority = m_prioritizer.GetUpdatePriority (m_presence, e.RootChild); m_entsqueue.Enqueue (rootitem); foreach (ISceneChildEntity child in e.ChildrenEntities ()) { if (child == e.RootChild) continue; //Already sent EntityUpdate update = new EntityUpdate (child, PrimUpdateFlags.FullUpdate); PriorityQueueItem<EntityUpdate, double> item = new PriorityQueueItem<EntityUpdate, double> (); item.Value = update; item.Priority = m_prioritizer.GetUpdatePriority (m_presence, child); m_entsqueue.Enqueue (item); } } } entities = null; lastGrpsInView.UnionWith (NewGrpsInView); NewGrpsInView.Clear (); // send them SendQueued (m_entsqueue); HashSet<IScenePresence> NewPresencesInView = new HashSet<IScenePresence>(); //Check for scenepresences as well IScenePresence[] presences = m_presence.Scene.Entities.GetPresences(m_presence.AbsolutePosition, m_presence.DrawDistance); foreach (IScenePresence presence in presences) { if (presence != null && presence.UUID != m_presence.UUID) { //Check for culling here! if (!Culler.ShowEntityToClient(m_presence, presence)) continue; // if 2 far ignore NewPresencesInView.Add (presence); if (lastPresencesInView.Contains (presence)) continue; //Don't resend the update SendFullUpdateForPresence (presence); } } presences = null; lastPresencesInView.UnionWith(NewPresencesInView); NewPresencesInView.Clear(); }
public void QueuePresenceForUpdate (IScenePresence presence, PrimUpdateFlags flags) { if (Culler != null && !Culler.ShowEntityToClient (m_presence, presence)) { //They are out of view and they changed, we need to update them when they do come in view lastPresencesInView.Remove (presence); return; // if 2 far ignore } if ((!(m_presence.DrawDistance > m_presence.Scene.RegionInfo.RegionSizeX && m_presence.DrawDistance > m_presence.Scene.RegionInfo.RegionSizeY)) && !lastPresencesInView.Contains (presence)) { //The presence just entered our view, we need to send a full update SendFullUpdateForPresence (presence); lastPresencesInView.Add (presence); return; } lock (m_presenceUpdatesToSend) { EntityUpdate o = (EntityUpdate)m_presenceUpdatesToSend[presence.UUID]; if (o == null) o = new EntityUpdate(presence, flags); else { if ((o.Flags & flags) == o.Flags) return; //Same, leave it alone! o.Flags = o.Flags | flags; m_presenceUpdatesToSend.Remove(presence.UUID); } if (m_presence.UUID == presence.UUID) { //Its us, set us first! m_ourPresenceHasUpdate = true; m_presenceUpdatesToSend.Insert(0, presence.UUID, o); } else if (m_ourPresenceHasUpdate) //If this is set, we start inserting at 1 so that our updates go first // We can also safely assume that 1 is fine, because there has to be 0 already there set by us m_presenceUpdatesToSend.Insert(m_presenceUpdatesToSend.Count, presence.UUID, o); else //Set us at 0, no updates from us m_presenceUpdatesToSend.Insert(m_presenceUpdatesToSend.Count, presence.UUID, o); } }
/// <summary> /// Add the objects to the queue for which we need to send an update to the client /// </summary> /// <param name="part"></param> public void QueuePartForUpdate (ISceneChildEntity part, PrimUpdateFlags flags) { if (Culler != null && !Culler.ShowEntityToClient (m_presence, part.ParentEntity)) { //They are out of view and they changed, we need to update them when they do come in view lastGrpsInView.Remove (part.ParentEntity); return; // if 2 far ignore } if ((!(m_presence.DrawDistance > m_presence.Scene.RegionInfo.RegionSizeX && m_presence.DrawDistance > m_presence.Scene.RegionInfo.RegionSizeY)) && !lastGrpsInView.Contains (part.ParentEntity)) { //This object entered our draw distance on its own, and we havn't seen it before flags = PrimUpdateFlags.ForcedFullUpdate; } EntityUpdate o = new EntityUpdate (part, flags); QueueEntityUpdate (o); }
private void DoSignificantClientMovement (object o) { ISceneEntity[] entities = m_presence.Scene.Entities.GetEntities (m_presence.AbsolutePosition, m_presence.DrawDistance); PriorityQueue<EntityUpdate, double> m_entsqueue = new PriorityQueue<EntityUpdate, double> (entities.Length); // build a prioritized list of things we need to send HashSet<ISceneEntity> NewGrpsInView = new HashSet<ISceneEntity> (); foreach (ISceneEntity e in entities) { if (e != null) { if (e.IsDeleted) continue; //Check for culling here! if (!Culler.ShowEntityToClient(m_presence, e)) continue; // if 2 far ignore double priority = m_prioritizer.GetUpdatePriority (m_presence, e); NewGrpsInView.Add (e); if (lastGrpsInView.Contains (e)) continue; //Send the root object first! EntityUpdate rootupdate = new EntityUpdate (e.RootChild, PrimUpdateFlags.FullUpdate); PriorityQueueItem<EntityUpdate, double> rootitem = new PriorityQueueItem<EntityUpdate, double> (); rootitem.Value = rootupdate; rootitem.Priority = priority; m_entsqueue.Enqueue (rootitem); foreach (ISceneChildEntity child in e.ChildrenEntities ()) { if (child == e.RootChild) continue; //Already sent EntityUpdate update = new EntityUpdate (child, PrimUpdateFlags.FullUpdate); PriorityQueueItem<EntityUpdate, double> item = new PriorityQueueItem<EntityUpdate, double> (); item.Value = update; item.Priority = priority; m_entsqueue.Enqueue (item); } } } entities = null; lastGrpsInView.Clear (); lastGrpsInView.UnionWith (NewGrpsInView); NewGrpsInView.Clear (); // send them SendQueued (m_entsqueue); }
/// <summary> /// This method is called by the LLUDPServer and should never be called by anyone else /// It loops through the available updates and sends them out (no waiting) /// </summary> /// <param name="numUpdates">The number of updates to send</param> public void SendPrimUpdates (int numUpdates) { if (m_inUse) return; m_inUse = true; //This is for stats int AgentMS = Util.EnvironmentTickCount (); #region New client entering the Scene, requires all objects in the Scene ///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 && m_presence.DrawDistance != 0.0f) { 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) && Culler != null && m_prioritizer != null) { ISceneEntity[] entities = m_presence.Scene.Entities.GetEntities (); PriorityQueue<EntityUpdate, double> m_entsqueue = new PriorityQueue<EntityUpdate, double> (entities.Length); // build a prioritized list of things we need to send foreach (ISceneEntity e in entities) { if (e != null && e is SceneObjectGroup) { if (e.IsDeleted) continue; //Check for culling here! if (!Culler.ShowEntityToClient (m_presence, e)) continue; double priority = m_prioritizer.GetUpdatePriority (m_presence, e); //Send the root object first! EntityUpdate rootupdate = new EntityUpdate (e.RootChild, PrimUpdateFlags.FullUpdate); PriorityQueueItem<EntityUpdate, double> rootitem = new PriorityQueueItem<EntityUpdate, double> (); rootitem.Value = rootupdate; rootitem.Priority = priority; m_entsqueue.Enqueue (rootitem); foreach (ISceneChildEntity child in e.ChildrenEntities ()) { if (child == e.RootChild) continue; //Already sent EntityUpdate update = new EntityUpdate (child, PrimUpdateFlags.FullUpdate); PriorityQueueItem<EntityUpdate, double> item = new PriorityQueueItem<EntityUpdate, double> (); item.Value = update; item.Priority = priority; m_entsqueue.Enqueue (item); } } } entities = null; // send them SendQueued (m_entsqueue); } } int numberSent = 0; int presenceNumToSend = (int)(numUpdates * PresenceSendPercentage); lock (m_presenceUpdatesToSend) { //Send the numUpdates of them if that many // if we don't have that many, we send as many as possible, then switch to objects if (m_presenceUpdatesToSend.Count != 0) { int count = m_presenceUpdatesToSend.Count > presenceNumToSend ? presenceNumToSend : m_presenceUpdatesToSend.Count; List<EntityUpdate> updates = new List<EntityUpdate> (); for (int i = 0; i < count; i++) { updates.Add ((EntityUpdate)m_presenceUpdatesToSend[0]); m_presenceUpdatesToSend.RemoveAt (0); } //If we're first, we definitely got set, so we don't need to check this at all m_ourPresenceHasUpdate = false; m_presence.ControllingClient.SendPrimUpdate (updates); } } lock (m_objectUpdatesToSend) { numberSent = presenceNumToSend - numberSent; int numToSend = (int)(numUpdates * PrimSendPercentage) + numberSent; //If we didn't send that many presence updates, send a few more if (m_objectUpdatesToSend.Count != 0) { int count = m_objectUpdatesToSend.Count > numToSend ? numToSend : m_objectUpdatesToSend.Count; List<EntityUpdate> updates = new List<EntityUpdate> (); for (int i = 0; i < count; i++) { updates.Add ((EntityUpdate)m_objectUpdatesToSend[0]); m_objectUpdatesToSend.RemoveAt (0); } m_presence.ControllingClient.SendPrimUpdate (updates); } } //Add the time to the stats tracker IAgentUpdateMonitor reporter = (IAgentUpdateMonitor)m_presence.Scene.RequestModuleInterface<IMonitorModule> ().GetMonitor (m_presence.Scene.RegionInfo.RegionID.ToString (), "Agent Update Count"); if (reporter != null) reporter.AddAgentTime (Util.EnvironmentTickCountSubtract (AgentMS)); m_inUse = false; }
public void QueuePresenceForUpdate (IScenePresence presence, PrimUpdateFlags flags) { if (Culler == null || !Culler.ShowEntityToClient (m_presence, presence)) return; // if 2 far ignore lock (m_presenceUpdatesToSend) { EntityUpdate o = (EntityUpdate)m_presenceUpdatesToSend[presence.UUID]; if (o == null) o = new EntityUpdate(presence, flags); else { if ((o.Flags & flags) == o.Flags) return; //Same, leave it alone! o.Flags = o.Flags & flags; m_presenceUpdatesToSend.Remove(presence.UUID); } if (m_presence.UUID == presence.UUID) { //Its us, set us first! m_ourPresenceHasUpdate = true; m_presenceUpdatesToSend.Insert(0, presence.UUID, o); } else if (m_ourPresenceHasUpdate) //If this is set, we start inserting at 1 so that our updates go first // We can also safely assume that 1 is fine, because there has to be 0 already there set by us m_presenceUpdatesToSend.Insert(m_presenceUpdatesToSend.Count, presence.UUID, o); else //Set us at 0, no updates from us m_presenceUpdatesToSend.Insert(m_presenceUpdatesToSend.Count, presence.UUID, o); } }
/// <summary> /// Add the objects to the queue for which we need to send an update to the client /// </summary> /// <param name="part"></param> public void QueuePartForUpdate (ISceneChildEntity part, PrimUpdateFlags flags) { if (Culler == null || !Culler.ShowEntityToClient(m_presence, part.ParentEntity)) return; // if 2 far ignore EntityUpdate o = new EntityUpdate (part, flags); QueueEntityUpdate (o); }
private void QueueEntityUpdate(EntityUpdate update) { lock (m_objectUpdatesToSend) { EntityUpdate o = (EntityUpdate)m_objectUpdatesToSend[update.Entity.UUID]; if (o == null) { m_objectUpdatesToSend.Insert (0, update.Entity.UUID, update); } else { o.Flags = o.Flags & update.Flags; m_objectUpdatesToSend[update.Entity.UUID] = o; } } }
/// <summary> /// Add the objects to the queue for which we need to send an update to the client /// </summary> /// <param name="part"></param> public void QueuePartForUpdate(SceneObjectPart part, PrimUpdateFlags UpdateFlags) { double priority = m_prioritizer.GetUpdatePriority(m_presence.ControllingClient, part.ParentGroup); EntityUpdate update = new EntityUpdate(part, UpdateFlags); //Fix the version with the newest locked m_version FixVersion(update); PriorityQueueItem<EntityUpdate, double> item = new PriorityQueueItem<EntityUpdate, double>(); item.Priority = priority; item.Value = update; m_partsUpdateQueue.Enqueue(item); //Make it check when the user comes around to it again if (m_objectsInView.Contains(part.UUID)) m_objectsInView.Remove(part.UUID); }
/// <summary> /// Sorts a list of Parts by Link Number so they end up in the correct order /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> public int linkSetSorter(EntityUpdate a, EntityUpdate b) { return a.Entity.LinkNum.CompareTo(b.Entity.LinkNum); }
/// <summary> /// Updates the last version securely and set the update's version correctly /// </summary> /// <param name="update"></param> private void FixVersion(EntityUpdate update) { _versionAllocateMutex.WaitOne(); m_lastVersion++; update.Version = m_lastVersion; _versionAllocateMutex.ReleaseMutex(); }