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); }
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); 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(1, presence.UUID, o); } else //Set us at 0, no updates from us { m_presenceUpdatesToSend.Insert(0, presence.UUID, o); } } else { o.Flags = o.Flags & flags; m_presenceUpdatesToSend[presence.UUID] = o; } } }
public EntityUpdate RemoveNext() { if (m_size == 0) { throw new InvalidOperationException("Heap is empty"); } EntityUpdate item = m_items[0]; --m_size; if (m_size > 0) { EntityUpdate tmp = m_items[m_size]; tmp.PriorityQueueIndex = 0; m_items[0] = tmp; m_items[m_size] = null; BubbleDown(0); } else if (m_items.Length > 4 * minCapacity) { m_items = new EntityUpdate[minCapacity]; } return(item); }
private void SendQueued(HashSet <ISceneEntity> entsqueue) { //NO LOCKING REQUIRED HERE, THE PRIORITYQUEUE IS LOCAL //Enqueue them all List <ISceneEntity> sortableList = new List <ISceneEntity>(entsqueue); sortableList.Sort(sortPriority); lock (m_objectUpdatesToSendLock) { foreach (ISceneEntity t in sortableList) { //Always send the root child first! EntityUpdate update = new EntityUpdate(t.RootChild, PrimUpdateFlags.ForcedFullUpdate); QueueEntityUpdate(update); foreach (ISceneChildEntity child in t.ChildrenEntities().Where(child => !child.IsRoot)) { update = new EntityUpdate(child, PrimUpdateFlags.ForcedFullUpdate); QueueEntityUpdate(update); } } } m_lastUpdatePos = (m_presence.IsChildAgent) ? m_presence.AbsolutePosition : m_presence.CameraPosition; }
public void RemoveAt(int index) { if (m_size == 0) { throw new InvalidOperationException("Heap is empty"); } if (index >= m_size) { throw new ArgumentOutOfRangeException("index"); } --m_size; if (m_size > 0) { if (index != m_size) { EntityUpdate tmp = m_items[m_size]; tmp.PriorityQueueIndex = index; m_items[index] = tmp; m_items[m_size] = null; if (!BubbleUp(index)) { BubbleDown(index); } } } else if (m_items.Length > 4 * minCapacity) { m_items = new EntityUpdate[minCapacity]; } }
public void UpdateFromNew(EntityUpdate newupdate, int pqueue) { m_propsFlags |= newupdate.PropsFlags; PrimUpdateFlags newFlags = newupdate.Flags; if ((newFlags & PrimUpdateFlags.UpdateProbe) != 0) { m_flags &= ~PrimUpdateFlags.UpdateProbe; } if ((newFlags & PrimUpdateFlags.CancelKill) != 0) { if ((newFlags & PrimUpdateFlags.UpdateProbe) != 0) { m_flags = PrimUpdateFlags.UpdateProbe; } else { newFlags = PrimUpdateFlags.FullUpdatewithAnim; } } else { m_flags |= newFlags; } PriorityQueue = pqueue; }
public static EntityUpdate Get(ISceneEntity entity, PrimUpdateFlags flags, bool sendfam, bool sendobj) { lock (m_poollock) { if (m_poolPtr >= 0) { EntityUpdate eu = m_pool[m_poolPtr]; m_pool[m_poolPtr] = null; m_poolPtr--; //if (m_min > m_poolPtr) // m_min = m_poolPtr; eu.Entity = entity; eu.Flags = flags; ObjectPropertyUpdateFlags tmp = 0; if (sendfam) { tmp |= ObjectPropertyUpdateFlags.Family; } if (sendobj) { tmp |= ObjectPropertyUpdateFlags.Object; } eu.PropsFlags = tmp; return(eu); } } return(new EntityUpdate(entity, flags, sendfam, sendobj)); }
/// <summary> /// Enqueue an item into the specified priority queue /// </summary> public bool Enqueue(int pqueue, EntityUpdate value) { ulong entry; EntityUpdate existentup; uint localid = value.Entity.LocalId; if (m_lookupTable.TryGetValue(localid, out existentup)) { int eqqueue = existentup.PriorityQueue; existentup.UpdateFromNew(value, pqueue); value.Free(); if (pqueue != eqqueue) { m_heaps[eqqueue].RemoveAt(existentup.PriorityQueueIndex); m_heaps[pqueue].Add(existentup); } return(true); } entry = m_nextRequest++; value.Update(pqueue, entry); m_heaps[pqueue].Add(value); m_lookupTable[localid] = value; return(true); }
//private static int m_min = int.MaxValue; //private static int m_max = int.MinValue; static EntityUpdatesPool() { for (int i = 0; i < PREALLOC; ++i) { m_pool[i] = new EntityUpdate(null, 0); } m_poolPtr = PREALLOC - 1; }
/// <summary> /// Remove an item from one of the queues. Specifically, it removes the /// oldest item from the next queue in order to provide fair access to /// all of the queues /// </summary> public bool TryDequeue(out EntityUpdate value) { // If there is anything in immediate queues, return it first no // matter what else. Breaks fairness. But very useful. for (int iq = 0; iq < NumberOfImmediateQueues; iq++) { if (m_heaps[iq].Count > 0) { value = m_heaps[iq].RemoveNext(); return(m_lookupTable.TryRemove(value.Entity.LocalId, out value)); } } // To get the fair queing, we cycle through each of the // queues when finding an element to dequeue. // We pull (NumberOfQueues - QueueIndex) items from each queue in order // to give lower numbered queues a higher priority and higher percentage // of the bandwidth. PriorityMinHeap curheap = m_heaps[m_nextQueue]; // Check for more items to be pulled from the current queue if (m_countFromQueue > 0 && curheap.Count > 0) { --m_countFromQueue; value = curheap.RemoveNext(); return(m_lookupTable.TryRemove(value.Entity.LocalId, out value)); } // Find the next non-immediate queue with updates in it for (int i = NumberOfImmediateQueues; i < NumberOfQueues; ++i) { m_nextQueue++; if (m_nextQueue >= NumberOfQueues) { m_nextQueue = NumberOfImmediateQueues; } curheap = m_heaps[m_nextQueue]; if (curheap.Count == 0) { continue; } m_countFromQueue = m_queueCounts[m_nextQueue]; --m_countFromQueue; value = curheap.RemoveNext(); return(m_lookupTable.TryRemove(value.Entity.LocalId, out value)); } value = null; return(false); }
/// <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); }
public bool Remove(EntityUpdate value) { int index = value.PriorityQueueIndex; if (index != -1) { RemoveAt(index); return(true); } return(false); }
public static void Free(EntityUpdate eu) { lock (m_poollock) { if (m_poolPtr < MAXSIZE - 1) { m_poolPtr++; //if (m_max < m_poolPtr) // m_max = m_poolPtr; m_pool[m_poolPtr] = eu; } } }
private void AddPresenceUpdate(IScenePresence presence, PrimUpdateFlags flags) { lock (m_presenceUpdatesToSendLock) { #if UseRemovingEntityUpdates 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 |= flags; return;//All done, its updated } if (m_presence.UUID == presence.UUID) //Its us, set us first! { m_presenceUpdatesToSend.Insert(0, presence.UUID, o); } else //Not us, set at the end { m_presenceUpdatesToSend.Insert(m_presenceUpdatesToSend.Count, presence.UUID, o); } #elif UseDictionaryForEntityUpdates EntityUpdate o = null; if (!m_presenceUpdatesToSend.TryGetValue(presence.LocalId, out o)) { o = new EntityUpdate(presence, flags); } else { if ((o.Flags & flags) == o.Flags) { return; //Same, leave it alone! } o.Flags |= flags; return; //All done, its updated, no need to readd } m_presenceUpdatesToSend[presence.LocalId] = o; #else m_presenceUpdatesToSend.Enqueue(new EntityUpdate(presence, flags)); #endif } }
public bool TryOrderedDequeue(out EntityUpdate value) { for (int iq = 0; iq < NumberOfQueues; ++iq) { PriorityMinHeap curheap = m_heaps[iq]; if (curheap.Count > 0) { value = curheap.RemoveNext(); return(m_lookupTable.TryRemove(value.Entity.LocalId, out value)); } } value = null; return(false); }
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; } } }
private void BubbleDown(int index) { if (m_size < 2) { return; } EntityUpdate childItem; EntityUpdate childItemR; EntityUpdate item = m_items[index]; ulong itemEntryOrder = item.EntryOrder; int current; int child; int childlimit = m_size - 1; for (current = index, child = (2 * current) + 1; current < m_size / 2; current = child, child = (2 * current) + 1) { childItem = m_items[child]; if (child < childlimit) { childItemR = m_items[child + 1]; if (childItem.EntryOrder > childItemR.EntryOrder) { childItem = childItemR; ++child; } } if (childItem.EntryOrder >= itemEntryOrder) { break; } childItem.PriorityQueueIndex = current; m_items[current] = childItem; } if (current != index) { item.PriorityQueueIndex = current; m_items[current] = item; } }
public static EntityUpdate Get(ISceneEntity entity, PrimUpdateFlags flags) { lock (m_poollock) { if (m_poolPtr >= 0) { EntityUpdate eu = m_pool[m_poolPtr]; m_pool[m_poolPtr] = null; m_poolPtr--; //if (m_min > m_poolPtr) // m_min = m_poolPtr; eu.Entity = entity; eu.Flags = flags; return(eu); } } return(new EntityUpdate(entity, flags)); }
public void Add(EntityUpdate value) { if (m_size == m_items.Length) { int newcapacity = (int)((m_items.Length * 200L) / 100L); if (newcapacity < (m_items.Length + MIN_CAPACITY)) { newcapacity = m_items.Length + MIN_CAPACITY; } Array.Resize <EntityUpdate>(ref m_items, newcapacity); } value.PriorityQueueIndex = m_size; m_items[m_size] = value; BubbleUp(m_size); ++m_size; }
/// <summary> /// NOTE: DO THE LOCKING ON YOUR OWN /// </summary> /// <param name = "update"></param> private void QueueEntityUpdate(EntityUpdate update) { EntityUpdate o = (EntityUpdate)m_objectUpdatesToSend[update.Entity.UUID]; if (o == null) { o = update; } else { if (o.Flags == update.Flags) { return; //Same, leave it alone! } m_objectUpdatesToSend.Remove(update.Entity.UUID); o.Flags = o.Flags | update.Flags; } m_objectUpdatesToSend.Insert(m_objectUpdatesToSend.Count, o.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(ISceneChildEntity part, PrimUpdateFlags flags) { if (m_presence == null) { return; } if (m_culler != null && !m_culler.ShowEntityToClient(m_presence, part.ParentEntity, m_scene)) { //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; lock (m_objectUpdatesToSendLock) { #if (!ISWIN) foreach (ISceneChildEntity child in part.ParentEntity.ChildrenEntities()) { QueueEntityUpdate(new EntityUpdate(child, flags)); } #else foreach (EntityUpdate update in part.ParentEntity.ChildrenEntities().Select(child => new EntityUpdate(child, flags))) { QueueEntityUpdate(update); } #endif } lastGrpsInView.Add(part.ParentEntity); return; } EntityUpdate o = new EntityUpdate(part, flags); lock (m_objectUpdatesToSendLock) QueueEntityUpdate(o); }
private bool BubbleUp(int index) { EntityUpdate tmp; EntityUpdate item = m_items[index]; ulong itemEntryOrder = item.EntryOrder; int current, parent; for (current = index, parent = (current - 1) / 2; (current > 0) && m_items[parent].EntryOrder > itemEntryOrder; current = parent, parent = (current - 1) / 2) { tmp = m_items[parent]; tmp.PriorityQueueIndex = current; m_items[current] = tmp; } if (current != index) { item.PriorityQueueIndex = current; m_items[current] = item; return(true); } return(false); }
/// <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_numberOfLoops < NUMBER_OF_LOOPS_TO_WAIT) //Wait for the client to finish connecting fully before sending out bunches of updates { m_numberOfLoops++; return; } if (m_inUse || m_presence.IsInTransit) { 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) { SendInitialObjects(); } int presenceNumToSend = numAvaUpdates; List <EntityUpdate> updates = new List <EntityUpdate>(); lock (m_presenceUpdatesToSendLock) { //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 { #if UseDictionaryForEntityUpdates Dictionary <uint, EntityUpdate> .Enumerator e = m_presenceUpdatesToSend.GetEnumerator(); e.MoveNext(); List <uint> entitiesToRemove = new List <uint>(); #endif int count = m_presenceUpdatesToSend.Count > presenceNumToSend ? presenceNumToSend : m_presenceUpdatesToSend.Count; for (int i = 0; i < count; i++) { #if UseRemovingEntityUpdates 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; * } * m_EntitiesInPacketQueue.Add (update.Entity.UUID);*/ m_presenceUpdatesToSend.RemoveAt(0); if (update.Flags == PrimUpdateFlags.ForcedFullUpdate) { SendFullUpdateForPresence((IScenePresence)update.Entity); } else { updates.Add(update); } #elif UseDictionaryForEntityUpdates EntityUpdate update = e.Current.Value; entitiesToRemove.Add(update.Entity.LocalId); //Remove it later if (update.Flags == PrimUpdateFlags.ForcedFullUpdate) { SendFullUpdateForPresence((IScenePresence)update.Entity); } else { updates.Add(update); } e.MoveNext(); #else EntityUpdate update = m_presenceUpdatesToSend.Dequeue(); if (update.Flags == PrimUpdateFlags.ForcedFullUpdate) { SendFullUpdateForPresence((IScenePresence)update.Entity); } else { updates.Add(update); } #endif } #if UseDictionaryForEntityUpdates foreach (uint id in entitiesToRemove) { m_presenceUpdatesToSend.Remove(id); } #endif } catch (Exception ex) { MainConsole.Instance.WarnFormat("[SceneViewer]: Exception while running presence loop: {0}", ex); } } } if (updates.Count != 0) { presenceNumToSend -= updates.Count; m_presence.ControllingClient.SendAvatarUpdate(updates); } updates.Clear(); List <AnimationGroup> animationsToSend = new List <AnimationGroup>(); lock (m_presenceAnimationsToSendLock) { //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 = m_presenceAnimationsToSend.Dequeue(); /*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);*/ animationsToSend.Add(update); } } catch (Exception ex) { MainConsole.Instance.WarnFormat("[SceneViewer]: Exception while running presence loop: {0}", ex); } } } foreach (AnimationGroup update in animationsToSend) { m_presence.ControllingClient.SendAnimations(update); } animationsToSend.Clear(); int primsNumToSend = numPrimUpdates; List <IEntity> entities = new List <IEntity>(); lock (m_objectPropertiesToSendLock) { //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 { 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); } } catch (Exception ex) { MainConsole.Instance.WarnFormat("[SceneViewer]: Exception while running presence loop: {0}", ex); } } } if (entities.Count > 0) { primsNumToSend -= entities.Count; m_presence.ControllingClient.SendObjectPropertiesReply(entities); } updates = new List <EntityUpdate>(); lock (m_objectUpdatesToSendLock) { if (m_objectUpdatesToSend.Count != 0) { try { int count = m_objectUpdatesToSend.Count > primsNumToSend ? primsNumToSend : m_objectUpdatesToSend.Count; 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; * } * m_EntitiesInPacketQueue.Add (update.Entity.UUID);*/ //Fix the CRC for this update //Increment the CRC code so that the client won't be sent a cached update for this if (update.Flags != PrimUpdateFlags.PrimFlags) { ((ISceneChildEntity)update.Entity).CRC++; } updates.Add(update); m_objectUpdatesToSend.RemoveAt(0); } } catch (Exception ex) { MainConsole.Instance.WarnFormat("[SceneViewer]: Exception while running object loop: {0}", ex); } 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(), MonitorModuleHelper.AgentUpdateCount); if (reporter != null) { reporter.AddAgentTime(Util.EnvironmentTickCountSubtract(AgentMS)); } m_inUse = false; }
/// <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_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); } } lock (m_presenceUpdatesToSend) { int numToSend = (int)(numUpdates * PresenceSendPercentage); //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 > numToSend ? numToSend : 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) { int numToSend = (int)(numUpdates * PrimSendPercentage); 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; }