/// <summary> /// Send appearance from all other root agents to this agent. this agent /// can be either root or child /// </summary> public void SendOtherAgentsAppearanceToMe() { int count = 0; m_sp.Scene.ForEachScenePresence(delegate(IScenePresence scenePresence) { // only send information about root agents if (scenePresence.IsChildAgent) { return; } // only send information about other root agents if (scenePresence.UUID == m_sp.UUID) { return; } IAvatarAppearanceModule appearance = scenePresence.RequestModuleInterface <IAvatarAppearanceModule> (); if (appearance != null) { appearance.SendAppearanceToAgent(m_sp); } count++; }); IAgentUpdateMonitor reporter = (IAgentUpdateMonitor)m_sp.Scene.RequestModuleInterface <IMonitorModule> ().GetMonitor(m_sp.Scene.RegionInfo.RegionID.ToString(), "Agent Update Count"); if (reporter != null) { reporter.AddAgentUpdates(count); } }
/// <summary> /// Send this agent's appearance to all other root and child agents in the scene /// This agent must be root. /// </summary> public void SendAppearanceToAllOtherAgents() { // only send update from root agents to other clients; children are only "listening posts" if (m_sp.IsChildAgent) { m_log.Warn("[SCENEPRESENCE] attempt to send avatar data from a child agent"); return; } int count = 0; m_sp.Scene.ForEachScenePresence(delegate(IScenePresence scenePresence) { if (scenePresence.UUID == m_sp.UUID) { return; } SendAppearanceToAgent(scenePresence); count++; }); IAgentUpdateMonitor reporter = (IAgentUpdateMonitor)m_sp.Scene.RequestModuleInterface <IMonitorModule> ().GetMonitor(m_sp.Scene.RegionInfo.RegionID.ToString(), "Agent Update Count"); if (reporter != null) { reporter.AddAgentUpdates(count); } }
public AvatarAppearanceModule(IScenePresence sp) { m_sp = sp; m_sp.Scene.EventManager.OnMakeRootAgent += EventManager_OnMakeRootAgent; AgentCircuitData circuitInfo = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.UUID); if (circuitInfo.CachedUserInfo != null) { Appearance = circuitInfo.CachedUserInfo.Appearance; } if (Appearance == null) { Appearance = sp.Scene.AvatarService.GetAppearance(sp.UUID); } if (Appearance == null) { MainConsole.Instance.Debug("[Scene]: No avatar appearance found for " + sp.Name); Appearance = new AvatarAppearance(sp.UUID); } _updateMonitor = m_sp.Scene.RequestModuleInterface <IMonitorModule> ().GetMonitor <IAgentUpdateMonitor> (sp.Scene); }
public AvatarAppearanceModule (IScenePresence sp) { m_sp = sp; m_sp.Scene.EventManager.OnMakeRootAgent += EventManager_OnMakeRootAgent; AgentCircuitData circuitInfo = sp.Scene.AuthenticateHandler.GetAgentCircuitData (sp.UUID); if (circuitInfo.CachedUserInfo != null) Appearance = circuitInfo.CachedUserInfo.Appearance; if (Appearance == null) Appearance = sp.Scene.AvatarService.GetAppearance (sp.UUID); if (Appearance == null) { MainConsole.Instance.Debug ("[Scene]: No avatar appearance found for " + sp.Name); Appearance = new AvatarAppearance (sp.UUID); } _updateMonitor = m_sp.Scene.RequestModuleInterface<IMonitorModule> ().GetMonitor<IAgentUpdateMonitor> (sp.Scene); }
/// <summary> /// This is called by a timer and makes a SimStats class of the current stats that we have in this simulator. /// It then sends the packet to the client and triggers the events to tell followers about the updated stats /// and updates the LastSet* values for monitors. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void statsHeartBeat(object sender, EventArgs e) { if (m_currentScene.PhysicsScene == null) { return; } m_report.Stop(); if (rb == null) { buildInitialRegionBlock(); } // Know what's not thread safe in Mono... modifying timers. lock (m_report) { ISimFrameMonitor simFrameMonitor = GetMonitor <ISimFrameMonitor>(); ITimeDilationMonitor timeDilationMonitor = GetMonitor <ITimeDilationMonitor>(); ITotalFrameTimeMonitor totalFrameMonitor = GetMonitor <ITotalFrameTimeMonitor>(); ISleepFrameMonitor sleepFrameMonitor = GetMonitor <ISleepFrameMonitor>(); IOtherFrameMonitor otherFrameMonitor = GetMonitor <IOtherFrameMonitor>(); IPhysicsFrameMonitor physicsFrameMonitor = GetMonitor <IPhysicsFrameMonitor>(); IPhysicsSyncFrameMonitor physicsSyncFrameMonitor = GetMonitor <IPhysicsSyncFrameMonitor>(); IPhysicsUpdateFrameMonitor physicsTimeFrameMonitor = GetMonitor <IPhysicsUpdateFrameMonitor>(); IAgentUpdateMonitor agentUpdateFrameMonitor = GetMonitor <IAgentUpdateMonitor>(); INetworkMonitor networkMonitor = GetMonitor <INetworkMonitor>(); IImageFrameTimeMonitor imagesMonitor = GetMonitor <IImageFrameTimeMonitor>(); IScriptFrameTimeMonitor scriptMonitor = GetMonitor <IScriptFrameTimeMonitor>(); IScriptCountMonitor totalScriptMonitor = GetMonitor <IScriptCountMonitor>(); #region various statistic googly moogly float simfps = simFrameMonitor.SimFPS / statsUpdateFactor; // save the reported value so there is something available for llGetRegionFPS simFrameMonitor.LastReportedSimFPS = simfps; float physfps = physicsFrameMonitor.PhysicsFPS / statsUpdateFactor; physicsFrameMonitor.LastReportedPhysicsFPS = physfps; //Update the time dilation with the newest physicsFPS timeDilationMonitor.SetPhysicsFPS(physfps); #endregion #region Add the stats packets //Some info on this packet http://wiki.secondlife.com/wiki/Statistics_Bar_Guide sb[0].StatID = (uint)Stats.TimeDilation; sb[0].StatValue = (float)timeDilationMonitor.GetValue(); sb[1].StatID = (uint)Stats.FPS; sb[1].StatValue = simfps; float realsimfps = simfps * 2; sb[2].StatID = (uint)Stats.PhysFPS; sb[2].StatValue = physfps; sb[3].StatID = (uint)Stats.AgentUpdates; sb[3].StatValue = (agentUpdateFrameMonitor.AgentUpdates / realsimfps); sb[4].StatID = (uint)Stats.FrameMS; float TotalFrames = (float)(totalFrameMonitor.GetValue() / realsimfps); sb[4].StatValue = TotalFrames; sb[5].StatID = (uint)Stats.NetMS; sb[5].StatValue = 0; //TODO: Implement this sb[6].StatID = (uint)Stats.SimOtherMS; float otherMS = (float)(otherFrameMonitor.GetValue() / realsimfps); sb[6].StatValue = otherMS; sb[7].StatID = (uint)Stats.SimPhysicsMS; float PhysicsMS = (float)(physicsTimeFrameMonitor.GetValue() / realsimfps); sb[7].StatValue = PhysicsMS; sb[8].StatID = (uint)Stats.AgentMS; sb[8].StatValue = (agentUpdateFrameMonitor.AgentFrameTime / realsimfps); sb[9].StatID = (uint)Stats.ImagesMS; float imageMS = (float)(imagesMonitor.GetValue() / realsimfps); sb[9].StatValue = imageMS; sb[10].StatID = (uint)Stats.ScriptMS; float ScriptMS = (float)(scriptMonitor.GetValue() / realsimfps); sb[10].StatValue = ScriptMS; sb[11].StatID = (uint)Stats.TotalObjects; sb[12].StatID = (uint)Stats.ActiveObjects; sb[13].StatID = (uint)Stats.NumAgentMain; sb[14].StatID = (uint)Stats.NumAgentChild; IEntityCountModule entityCountModule = m_currentScene.RequestModuleInterface <IEntityCountModule>(); if (entityCountModule != null) { sb[11].StatValue = entityCountModule.Objects; sb[12].StatValue = entityCountModule.ActiveObjects; sb[13].StatValue = entityCountModule.RootAgents; sb[14].StatValue = entityCountModule.ChildAgents; } sb[15].StatID = (uint)Stats.NumScriptActive; sb[15].StatValue = totalScriptMonitor.ActiveScripts; sb[16].StatID = (uint)Stats.LSLIPS; sb[16].StatValue = 0; //This isn't used anymore, and has been superseeded by LSLEPS sb[17].StatID = (uint)Stats.InPPS; sb[17].StatValue = (networkMonitor.InPacketsPerSecond / statsUpdateFactor); sb[18].StatID = (uint)Stats.OutPPS; sb[18].StatValue = (networkMonitor.OutPacketsPerSecond / statsUpdateFactor); sb[19].StatID = (uint)Stats.PendingDownloads; sb[19].StatValue = (networkMonitor.PendingDownloads); sb[20].StatID = (uint)Stats.PendingUploads; sb[20].StatValue = (networkMonitor.PendingUploads); //21 and 22 are forced to the GC memory as they WILL make memory usage go up rapidly otherwise! sb[21].StatID = (uint)Stats.VirtualSizeKB; sb[21].StatValue = GC.GetTotalMemory(false) / 1024; // System.Diagnostics.Process.GetCurrentProcess().WorkingSet64 / (1024); sb[22].StatID = (uint)Stats.ResidentSizeKB; sb[22].StatValue = GC.GetTotalMemory(false) / 1024; //(float)System.Diagnostics.Process.GetCurrentProcess().PrivateMemorySize64 / (1024); sb[23].StatID = (uint)Stats.PendingLocalUploads; sb[23].StatValue = (networkMonitor.PendingUploads / statsUpdateFactor); sb[24].StatID = (uint)Stats.TotalUnackedBytes; sb[24].StatValue = (networkMonitor.UnackedBytes); sb[25].StatID = (uint)Stats.PhysicsPinnedTasks; sb[25].StatValue = 0; sb[26].StatID = (uint)Stats.PhysicsLODTasks; sb[26].StatValue = 0; sb[27].StatID = (uint)Stats.SimPhysicsStepMS; sb[27].StatValue = m_currentScene.PhysicsScene.StepTime; sb[28].StatID = (uint)Stats.SimPhysicsShape; sb[28].StatValue = 0; sb[29].StatID = (uint)Stats.SimPhysicsOtherMS; sb[29].StatValue = (float)(physicsSyncFrameMonitor.GetValue() / realsimfps); sb[30].StatID = (uint)Stats.SimPhysicsMemory; sb[30].StatValue = 0; sb[31].StatID = (uint)Stats.ScriptEPS; sb[31].StatValue = totalScriptMonitor.ScriptEPS / statsUpdateFactor; sb[32].StatID = (uint)Stats.SimSpareTime; //Spare time is the total time minus the stats that are in the same category in the client // It is the sleep time, physics step, update physics shape, physics other, and pumpI0. // Note: take out agent Update and script time for now, as they are not a part of the heartbeat right now and will mess this calc up float SpareTime = TotalFrames - ( /*NetMS + */ PhysicsMS + otherMS + imageMS); // + /*(agentUpdateFrameMonitor.AgentFrameTime / statsUpdateFactor) +*/ // (imagesMonitor.GetValue() / statsUpdateFactor) /* + ScriptMS*/)); sb[32].StatValue = SpareTime; sb[33].StatID = (uint)Stats.SimSleepTime; sb[33].StatValue = (float)(sleepFrameMonitor.GetValue() / realsimfps); sb[34].StatID = (uint)Stats.IOPumpTime; sb[34].StatValue = 0; //TODO: implement this #endregion for (int i = 0; i < sb.Length; i++) { if (float.IsInfinity(sb[i].StatValue) || float.IsNaN(sb[i].StatValue)) { sb[i].StatValue = 0; //Don't send huge values } lastReportedSimStats[i] = sb[i].StatValue; } SimStats simStats = new SimStats(rb, sb, m_currentScene.RegionInfo.RegionID); //Fire the event and tell followers about the new stats m_module.SendStatsResults(simStats); //Tell all the scene presences about the new stats foreach (IScenePresence agent in m_currentScene.GetScenePresences().Where(agent => !agent.IsChildAgent)) { agent.ControllingClient.SendSimStats(simStats); } //Now fix any values that require reseting ResetValues(); } m_report.Start(); }
/// <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; }