diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/Scene.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/Scene.cs | 352 |
1 files changed, 186 insertions, 166 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 0706905..790ec63 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -190,7 +190,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
190 | private int backupMS; | 190 | private int backupMS; |
191 | private int terrainMS; | 191 | private int terrainMS; |
192 | private int landMS; | 192 | private int landMS; |
193 | private int lastCompletedFrame; | 193 | |
194 | /// <summary> | ||
195 | /// Tick at which the last frame was processed. | ||
196 | /// </summary> | ||
197 | private int m_lastFrameTick; | ||
194 | 198 | ||
195 | /// <summary> | 199 | /// <summary> |
196 | /// Signals whether temporary objects are currently being cleaned up. Needed because this is launched | 200 | /// Signals whether temporary objects are currently being cleaned up. Needed because this is launched |
@@ -464,7 +468,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
464 | public int MonitorBackupTime { get { return backupMS; } } | 468 | public int MonitorBackupTime { get { return backupMS; } } |
465 | public int MonitorTerrainTime { get { return terrainMS; } } | 469 | public int MonitorTerrainTime { get { return terrainMS; } } |
466 | public int MonitorLandTime { get { return landMS; } } | 470 | public int MonitorLandTime { get { return landMS; } } |
467 | public int MonitorLastFrameTick { get { return lastCompletedFrame; } } | 471 | public int MonitorLastFrameTick { get { return m_lastFrameTick; } } |
468 | 472 | ||
469 | public UpdatePrioritizationSchemes UpdatePrioritizationScheme { get { return m_priorityScheme; } } | 473 | public UpdatePrioritizationSchemes UpdatePrioritizationScheme { get { return m_priorityScheme; } } |
470 | public bool IsReprioritizationEnabled { get { return m_reprioritizationEnabled; } } | 474 | public bool IsReprioritizationEnabled { get { return m_reprioritizationEnabled; } } |
@@ -1175,18 +1179,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
1175 | // The first frame can take a very long time due to physics actors being added on startup. Therefore, | 1179 | // The first frame can take a very long time due to physics actors being added on startup. Therefore, |
1176 | // don't turn on the watchdog alarm for this thread until the second frame, in order to prevent false | 1180 | // don't turn on the watchdog alarm for this thread until the second frame, in order to prevent false |
1177 | // alarms for scenes with many objects. | 1181 | // alarms for scenes with many objects. |
1178 | Update(); | 1182 | Update(1); |
1179 | Watchdog.GetCurrentThreadInfo().AlarmIfTimeout = true; | 1183 | Watchdog.GetCurrentThreadInfo().AlarmIfTimeout = true; |
1180 | 1184 | ||
1181 | while (!shuttingdown) | 1185 | while (!shuttingdown) |
1182 | Update(); | 1186 | Update(-1); |
1183 | 1187 | ||
1184 | m_lastUpdate = Util.EnvironmentTickCount(); | 1188 | m_lastUpdate = Util.EnvironmentTickCount(); |
1185 | m_firstHeartbeat = false; | 1189 | m_firstHeartbeat = false; |
1186 | } | 1190 | } |
1187 | catch (ThreadAbortException) | ||
1188 | { | ||
1189 | } | ||
1190 | finally | 1191 | finally |
1191 | { | 1192 | { |
1192 | Monitor.Pulse(m_heartbeatLock); | 1193 | Monitor.Pulse(m_heartbeatLock); |
@@ -1196,188 +1197,207 @@ namespace OpenSim.Region.Framework.Scenes | |||
1196 | Watchdog.RemoveThread(); | 1197 | Watchdog.RemoveThread(); |
1197 | } | 1198 | } |
1198 | 1199 | ||
1199 | public override void Update() | 1200 | public override void Update(int frames) |
1200 | { | 1201 | { |
1201 | float physicsFPS = 0f; | 1202 | long? endFrame = null; |
1202 | 1203 | ||
1203 | int maintc = Util.EnvironmentTickCount(); | 1204 | if (frames >= 0) |
1204 | int tmpFrameMS = maintc; | 1205 | endFrame = Frame + frames; |
1205 | agentMS = tempOnRezMS = eventMS = backupMS = terrainMS = landMS = 0; | ||
1206 | 1206 | ||
1207 | ++Frame; | 1207 | float physicsFPS = 0f; |
1208 | 1208 | int tmpPhysicsMS, tmpPhysicsMS2, tmpAgentMS, tmpTempOnRezMS, evMS, backMS, terMS; | |
1209 | // m_log.DebugFormat("[SCENE]: Processing frame {0} in {1}", Frame, RegionInfo.RegionName); | 1209 | int previousFrameTick; |
1210 | int maintc; | ||
1211 | List<Vector3> coarseLocations; | ||
1212 | List<UUID> avatarUUIDs; | ||
1210 | 1213 | ||
1211 | try | 1214 | while (!shuttingdown && (endFrame == null || Frame < endFrame)) |
1212 | { | 1215 | { |
1213 | int tmpPhysicsMS2 = Util.EnvironmentTickCount(); | 1216 | maintc = Util.EnvironmentTickCount(); |
1214 | if ((Frame % m_update_physics == 0) && m_physics_enabled) | 1217 | ++Frame; |
1215 | m_sceneGraph.UpdatePreparePhysics(); | ||
1216 | physicsMS2 = Util.EnvironmentTickCountSubtract(tmpPhysicsMS2); | ||
1217 | |||
1218 | // Apply any pending avatar force input to the avatar's velocity | ||
1219 | int tmpAgentMS = Util.EnvironmentTickCount(); | ||
1220 | if (Frame % m_update_entitymovement == 0) | ||
1221 | m_sceneGraph.UpdateScenePresenceMovement(); | ||
1222 | agentMS = Util.EnvironmentTickCountSubtract(tmpAgentMS); | ||
1223 | |||
1224 | // Perform the main physics update. This will do the actual work of moving objects and avatars according to their | ||
1225 | // velocity | ||
1226 | int tmpPhysicsMS = Util.EnvironmentTickCount(); | ||
1227 | if (Frame % m_update_physics == 0) | ||
1228 | { | ||
1229 | if (m_physics_enabled) | ||
1230 | physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameTime); | ||
1231 | 1218 | ||
1232 | if (SynchronizeScene != null) | 1219 | // m_log.DebugFormat("[SCENE]: Processing frame {0} in {1}", Frame, RegionInfo.RegionName); |
1233 | SynchronizeScene(this); | ||
1234 | } | ||
1235 | physicsMS = Util.EnvironmentTickCountSubtract(tmpPhysicsMS); | ||
1236 | |||
1237 | tmpAgentMS = Util.EnvironmentTickCount(); | ||
1238 | |||
1239 | // Check if any objects have reached their targets | ||
1240 | CheckAtTargets(); | ||
1241 | |||
1242 | // Update SceneObjectGroups that have scheduled themselves for updates | ||
1243 | // Objects queue their updates onto all scene presences | ||
1244 | if (Frame % m_update_objects == 0) | ||
1245 | m_sceneGraph.UpdateObjectGroups(); | ||
1246 | 1220 | ||
1247 | // Run through all ScenePresences looking for updates | 1221 | agentMS = tempOnRezMS = eventMS = backupMS = terrainMS = landMS = 0; |
1248 | // Presence updates and queued object updates for each presence are sent to clients | ||
1249 | if (Frame % m_update_presences == 0) | ||
1250 | m_sceneGraph.UpdatePresences(); | ||
1251 | 1222 | ||
1252 | // Coarse locations relate to positions of green dots on the mini-map (on a SecondLife client) | 1223 | try |
1253 | if (Frame % m_update_coarse_locations == 0) | ||
1254 | { | 1224 | { |
1255 | List<Vector3> coarseLocations; | 1225 | tmpPhysicsMS2 = Util.EnvironmentTickCount(); |
1256 | List<UUID> avatarUUIDs; | 1226 | if ((Frame % m_update_physics == 0) && m_physics_enabled) |
1257 | SceneGraph.GetCoarseLocations(out coarseLocations, out avatarUUIDs, 60); | 1227 | m_sceneGraph.UpdatePreparePhysics(); |
1258 | // Send coarse locations to clients | 1228 | physicsMS2 = Util.EnvironmentTickCountSubtract(tmpPhysicsMS2); |
1259 | ForEachScenePresence(delegate(ScenePresence presence) | 1229 | |
1230 | // Apply any pending avatar force input to the avatar's velocity | ||
1231 | tmpAgentMS = Util.EnvironmentTickCount(); | ||
1232 | if (Frame % m_update_entitymovement == 0) | ||
1233 | m_sceneGraph.UpdateScenePresenceMovement(); | ||
1234 | agentMS = Util.EnvironmentTickCountSubtract(tmpAgentMS); | ||
1235 | |||
1236 | // Perform the main physics update. This will do the actual work of moving objects and avatars according to their | ||
1237 | // velocity | ||
1238 | tmpPhysicsMS = Util.EnvironmentTickCount(); | ||
1239 | if (Frame % m_update_physics == 0) | ||
1260 | { | 1240 | { |
1261 | presence.SendCoarseLocations(coarseLocations, avatarUUIDs); | 1241 | if (m_physics_enabled) |
1262 | }); | 1242 | physicsFPS = m_sceneGraph.UpdatePhysics(MinFrameTime); |
1263 | } | 1243 | |
1264 | 1244 | if (SynchronizeScene != null) | |
1265 | agentMS += Util.EnvironmentTickCountSubtract(tmpAgentMS); | 1245 | SynchronizeScene(this); |
1266 | 1246 | } | |
1267 | // Delete temp-on-rez stuff | 1247 | physicsMS = Util.EnvironmentTickCountSubtract(tmpPhysicsMS); |
1268 | if (Frame % m_update_temp_cleaning == 0 && !m_cleaningTemps) | ||
1269 | { | ||
1270 | int tmpTempOnRezMS = Util.EnvironmentTickCount(); | ||
1271 | m_cleaningTemps = true; | ||
1272 | Util.FireAndForget(delegate { CleanTempObjects(); m_cleaningTemps = false; }); | ||
1273 | tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpTempOnRezMS); | ||
1274 | } | ||
1275 | |||
1276 | if (Frame % m_update_events == 0) | ||
1277 | { | ||
1278 | int evMS = Util.EnvironmentTickCount(); | ||
1279 | UpdateEvents(); | ||
1280 | eventMS = Util.EnvironmentTickCountSubtract(evMS); ; | ||
1281 | } | ||
1282 | |||
1283 | if (Frame % m_update_backup == 0) | ||
1284 | { | ||
1285 | int backMS = Util.EnvironmentTickCount(); | ||
1286 | UpdateStorageBackup(); | ||
1287 | backupMS = Util.EnvironmentTickCountSubtract(backMS); | ||
1288 | } | ||
1289 | |||
1290 | if (Frame % m_update_terrain == 0) | ||
1291 | { | ||
1292 | int terMS = Util.EnvironmentTickCount(); | ||
1293 | UpdateTerrain(); | ||
1294 | terrainMS = Util.EnvironmentTickCountSubtract(terMS); | ||
1295 | } | ||
1296 | |||
1297 | //if (Frame % m_update_land == 0) | ||
1298 | //{ | ||
1299 | // int ldMS = Util.EnvironmentTickCount(); | ||
1300 | // UpdateLand(); | ||
1301 | // landMS = Util.EnvironmentTickCountSubtract(ldMS); | ||
1302 | //} | ||
1303 | |||
1304 | frameMS = Util.EnvironmentTickCountSubtract(tmpFrameMS); | ||
1305 | otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS; | ||
1306 | lastCompletedFrame = Util.EnvironmentTickCount(); | ||
1307 | |||
1308 | // if (Frame%m_update_avatars == 0) | ||
1309 | // UpdateInWorldTime(); | ||
1310 | StatsReporter.AddPhysicsFPS(physicsFPS); | ||
1311 | StatsReporter.AddTimeDilation(TimeDilation); | ||
1312 | StatsReporter.AddFPS(1); | ||
1313 | StatsReporter.SetRootAgents(m_sceneGraph.GetRootAgentCount()); | ||
1314 | StatsReporter.SetChildAgents(m_sceneGraph.GetChildAgentCount()); | ||
1315 | StatsReporter.SetObjects(m_sceneGraph.GetTotalObjectsCount()); | ||
1316 | StatsReporter.SetActiveObjects(m_sceneGraph.GetActiveObjectsCount()); | ||
1317 | StatsReporter.addFrameMS(frameMS); | ||
1318 | StatsReporter.addAgentMS(agentMS); | ||
1319 | StatsReporter.addPhysicsMS(physicsMS + physicsMS2); | ||
1320 | StatsReporter.addOtherMS(otherMS); | ||
1321 | StatsReporter.SetActiveScripts(m_sceneGraph.GetActiveScriptsCount()); | ||
1322 | StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS()); | ||
1323 | |||
1324 | if (LoginsDisabled && Frame == 20) | ||
1325 | { | ||
1326 | // m_log.DebugFormat("{0} {1} {2}", LoginsDisabled, m_sceneGraph.GetActiveScriptsCount(), LoginLock); | ||
1327 | 1248 | ||
1328 | // In 99.9% of cases it is a bad idea to manually force garbage collection. However, | 1249 | tmpAgentMS = Util.EnvironmentTickCount(); |
1329 | // this is a rare case where we know we have just went through a long cycle of heap | 1250 | |
1330 | // allocations, and there is no more work to be done until someone logs in | 1251 | // Check if any objects have reached their targets |
1331 | GC.Collect(); | 1252 | CheckAtTargets(); |
1253 | |||
1254 | // Update SceneObjectGroups that have scheduled themselves for updates | ||
1255 | // Objects queue their updates onto all scene presences | ||
1256 | if (Frame % m_update_objects == 0) | ||
1257 | m_sceneGraph.UpdateObjectGroups(); | ||
1258 | |||
1259 | // Run through all ScenePresences looking for updates | ||
1260 | // Presence updates and queued object updates for each presence are sent to clients | ||
1261 | if (Frame % m_update_presences == 0) | ||
1262 | m_sceneGraph.UpdatePresences(); | ||
1263 | |||
1264 | // Coarse locations relate to positions of green dots on the mini-map (on a SecondLife client) | ||
1265 | if (Frame % m_update_coarse_locations == 0) | ||
1266 | { | ||
1267 | SceneGraph.GetCoarseLocations(out coarseLocations, out avatarUUIDs, 60); | ||
1268 | // Send coarse locations to clients | ||
1269 | ForEachScenePresence(delegate(ScenePresence presence) | ||
1270 | { | ||
1271 | presence.SendCoarseLocations(coarseLocations, avatarUUIDs); | ||
1272 | }); | ||
1273 | } | ||
1274 | |||
1275 | agentMS += Util.EnvironmentTickCountSubtract(tmpAgentMS); | ||
1276 | |||
1277 | // Delete temp-on-rez stuff | ||
1278 | if (Frame % m_update_temp_cleaning == 0 && !m_cleaningTemps) | ||
1279 | { | ||
1280 | tmpTempOnRezMS = Util.EnvironmentTickCount(); | ||
1281 | m_cleaningTemps = true; | ||
1282 | Util.FireAndForget(delegate { CleanTempObjects(); m_cleaningTemps = false; }); | ||
1283 | tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpTempOnRezMS); | ||
1284 | } | ||
1285 | |||
1286 | if (Frame % m_update_events == 0) | ||
1287 | { | ||
1288 | evMS = Util.EnvironmentTickCount(); | ||
1289 | UpdateEvents(); | ||
1290 | eventMS = Util.EnvironmentTickCountSubtract(evMS); | ||
1291 | } | ||
1292 | |||
1293 | if (Frame % m_update_backup == 0) | ||
1294 | { | ||
1295 | backMS = Util.EnvironmentTickCount(); | ||
1296 | UpdateStorageBackup(); | ||
1297 | backupMS = Util.EnvironmentTickCountSubtract(backMS); | ||
1298 | } | ||
1299 | |||
1300 | if (Frame % m_update_terrain == 0) | ||
1301 | { | ||
1302 | terMS = Util.EnvironmentTickCount(); | ||
1303 | UpdateTerrain(); | ||
1304 | terrainMS = Util.EnvironmentTickCountSubtract(terMS); | ||
1305 | } | ||
1306 | |||
1307 | //if (Frame % m_update_land == 0) | ||
1308 | //{ | ||
1309 | // int ldMS = Util.EnvironmentTickCount(); | ||
1310 | // UpdateLand(); | ||
1311 | // landMS = Util.EnvironmentTickCountSubtract(ldMS); | ||
1312 | //} | ||
1332 | 1313 | ||
1333 | IConfig startupConfig = m_config.Configs["Startup"]; | 1314 | frameMS = Util.EnvironmentTickCountSubtract(maintc); |
1334 | if (startupConfig == null || !startupConfig.GetBoolean("StartDisabled", false)) | 1315 | otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS; |
1316 | |||
1317 | // if (Frame%m_update_avatars == 0) | ||
1318 | // UpdateInWorldTime(); | ||
1319 | StatsReporter.AddPhysicsFPS(physicsFPS); | ||
1320 | StatsReporter.AddTimeDilation(TimeDilation); | ||
1321 | StatsReporter.AddFPS(1); | ||
1322 | StatsReporter.SetRootAgents(m_sceneGraph.GetRootAgentCount()); | ||
1323 | StatsReporter.SetChildAgents(m_sceneGraph.GetChildAgentCount()); | ||
1324 | StatsReporter.SetObjects(m_sceneGraph.GetTotalObjectsCount()); | ||
1325 | StatsReporter.SetActiveObjects(m_sceneGraph.GetActiveObjectsCount()); | ||
1326 | |||
1327 | // frameMS currently records work frame times, not total frame times (work + any required sleep to | ||
1328 | // reach min frame time. | ||
1329 | StatsReporter.addFrameMS(frameMS); | ||
1330 | |||
1331 | StatsReporter.addAgentMS(agentMS); | ||
1332 | StatsReporter.addPhysicsMS(physicsMS + physicsMS2); | ||
1333 | StatsReporter.addOtherMS(otherMS); | ||
1334 | StatsReporter.SetActiveScripts(m_sceneGraph.GetActiveScriptsCount()); | ||
1335 | StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS()); | ||
1336 | |||
1337 | if (LoginsDisabled && Frame == 20) | ||
1335 | { | 1338 | { |
1336 | // This handles a case of a region having no scripts for the RegionReady module | 1339 | // m_log.DebugFormat("{0} {1} {2}", LoginsDisabled, m_sceneGraph.GetActiveScriptsCount(), LoginLock); |
1337 | if (m_sceneGraph.GetActiveScriptsCount() == 0) | 1340 | |
1341 | // In 99.9% of cases it is a bad idea to manually force garbage collection. However, | ||
1342 | // this is a rare case where we know we have just went through a long cycle of heap | ||
1343 | // allocations, and there is no more work to be done until someone logs in | ||
1344 | GC.Collect(); | ||
1345 | |||
1346 | IConfig startupConfig = m_config.Configs["Startup"]; | ||
1347 | if (startupConfig == null || !startupConfig.GetBoolean("StartDisabled", false)) | ||
1338 | { | 1348 | { |
1339 | // need to be able to tell these have changed in RegionReady | 1349 | // This handles a case of a region having no scripts for the RegionReady module |
1340 | LoginLock = false; | 1350 | if (m_sceneGraph.GetActiveScriptsCount() == 0) |
1341 | EventManager.TriggerLoginsEnabled(RegionInfo.RegionName); | 1351 | { |
1352 | // need to be able to tell these have changed in RegionReady | ||
1353 | LoginLock = false; | ||
1354 | EventManager.TriggerLoginsEnabled(RegionInfo.RegionName); | ||
1355 | } | ||
1356 | m_log.DebugFormat("[REGION]: Enabling logins for {0}", RegionInfo.RegionName); | ||
1357 | |||
1358 | // For RegionReady lockouts | ||
1359 | if(LoginLock == false) | ||
1360 | { | ||
1361 | LoginsDisabled = false; | ||
1362 | } | ||
1363 | |||
1364 | m_sceneGridService.InformNeighborsThatRegionisUp(RequestModuleInterface<INeighbourService>(), RegionInfo); | ||
1342 | } | 1365 | } |
1343 | m_log.DebugFormat("[REGION]: Enabling logins for {0}", RegionInfo.RegionName); | 1366 | else |
1344 | |||
1345 | // For RegionReady lockouts | ||
1346 | if(LoginLock == false) | ||
1347 | { | 1367 | { |
1348 | LoginsDisabled = false; | 1368 | StartDisabled = true; |
1369 | LoginsDisabled = true; | ||
1349 | } | 1370 | } |
1350 | |||
1351 | m_sceneGridService.InformNeighborsThatRegionisUp(RequestModuleInterface<INeighbourService>(), RegionInfo); | ||
1352 | } | ||
1353 | else | ||
1354 | { | ||
1355 | StartDisabled = true; | ||
1356 | LoginsDisabled = true; | ||
1357 | } | 1371 | } |
1358 | } | 1372 | } |
1359 | } | 1373 | catch (Exception e) |
1360 | catch (NotImplementedException) | 1374 | { |
1361 | { | 1375 | m_log.ErrorFormat( |
1362 | throw; | 1376 | "[SCENE]: Failed on region {0} with exception {1}{2}", |
1363 | } | 1377 | RegionInfo.RegionName, e.Message, e.StackTrace); |
1364 | catch (Exception e) | 1378 | } |
1365 | { | 1379 | |
1366 | m_log.ErrorFormat( | 1380 | EventManager.TriggerRegionHeartbeatEnd(this); |
1367 | "[SCENE]: Failed on region {0} with exception {1}{2}", | ||
1368 | RegionInfo.RegionName, e.Message, e.StackTrace); | ||
1369 | } | ||
1370 | 1381 | ||
1371 | EventManager.TriggerRegionHeartbeatEnd(this); | 1382 | // Tell the watchdog that this thread is still alive |
1383 | Watchdog.UpdateThread(); | ||
1372 | 1384 | ||
1373 | maintc = Util.EnvironmentTickCountSubtract(maintc); | 1385 | // previousFrameTick = m_lastFrameTick; |
1374 | maintc = (int)(MinFrameTime * 1000) - maintc; | 1386 | m_lastFrameTick = Util.EnvironmentTickCount(); |
1387 | maintc = Util.EnvironmentTickCountSubtract(m_lastFrameTick, maintc); | ||
1388 | maintc = (int)(MinFrameTime * 1000) - maintc; | ||
1375 | 1389 | ||
1376 | if (maintc > 0) | 1390 | if (maintc > 0) |
1377 | Thread.Sleep(maintc); | 1391 | Thread.Sleep(maintc); |
1378 | 1392 | ||
1379 | // Tell the watchdog that this thread is still alive | 1393 | // Optionally warn if a frame takes double the amount of time that it should. |
1380 | Watchdog.UpdateThread(); | 1394 | // if (Util.EnvironmentTickCountSubtract(m_lastFrameTick, previousFrameTick) > (int)(MinFrameTime * 1000 * 2)) |
1395 | // m_log.WarnFormat( | ||
1396 | // "[SCENE]: Frame took {0} ms (desired max {1} ms) in {2}", | ||
1397 | // Util.EnvironmentTickCountSubtract(m_lastFrameTick, previousFrameTick), | ||
1398 | // MinFrameTime * 1000, | ||
1399 | // RegionInfo.RegionName); | ||
1400 | } | ||
1381 | } | 1401 | } |
1382 | 1402 | ||
1383 | public void AddGroupTarget(SceneObjectGroup grp) | 1403 | public void AddGroupTarget(SceneObjectGroup grp) |