diff options
Merge branch 'master' into careminster
Conflicts:
OpenSim/Region/Framework/Scenes/Scene.cs
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/Scene.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/Scene.cs | 152 |
1 files changed, 71 insertions, 81 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index a804e29..3095382 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -3384,10 +3384,23 @@ namespace OpenSim.Region.Framework.Scenes | |||
3384 | // CheckHeartbeat(); | 3384 | // CheckHeartbeat(); |
3385 | bool isChildAgent = false; | 3385 | bool isChildAgent = false; |
3386 | ScenePresence avatar = GetScenePresence(agentID); | 3386 | ScenePresence avatar = GetScenePresence(agentID); |
3387 | if (avatar != null) | 3387 | |
3388 | if (avatar == null) | ||
3389 | { | ||
3390 | m_log.WarnFormat( | ||
3391 | "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID); | ||
3392 | |||
3393 | return; | ||
3394 | } | ||
3395 | |||
3396 | try | ||
3388 | { | 3397 | { |
3389 | isChildAgent = avatar.IsChildAgent; | 3398 | isChildAgent = avatar.IsChildAgent; |
3390 | 3399 | ||
3400 | m_log.DebugFormat( | ||
3401 | "[SCENE]: Removing {0} agent {1} {2} from {3}", | ||
3402 | (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName); | ||
3403 | |||
3391 | // Don't do this to root agents, it's not nice for the viewer | 3404 | // Don't do this to root agents, it's not nice for the viewer |
3392 | if (closeChildAgents && isChildAgent) | 3405 | if (closeChildAgents && isChildAgent) |
3393 | { | 3406 | { |
@@ -3409,101 +3422,78 @@ namespace OpenSim.Region.Framework.Scenes | |||
3409 | avatar.StandUp(); | 3422 | avatar.StandUp(); |
3410 | } | 3423 | } |
3411 | 3424 | ||
3412 | try | 3425 | m_sceneGraph.removeUserCount(!isChildAgent); |
3413 | { | ||
3414 | m_log.DebugFormat( | ||
3415 | "[SCENE]: Removing {0} agent {1} {2} from region {3}", | ||
3416 | (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName); | ||
3417 | |||
3418 | m_sceneGraph.removeUserCount(!isChildAgent); | ||
3419 | 3426 | ||
3420 | // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop | 3427 | // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop |
3421 | // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI | 3428 | // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI |
3422 | if (closeChildAgents && CapsModule != null) | 3429 | if (closeChildAgents && CapsModule != null) |
3423 | CapsModule.RemoveCaps(agentID); | 3430 | CapsModule.RemoveCaps(agentID); |
3424 | 3431 | ||
3425 | // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever | 3432 | // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever |
3426 | // this method is doing is HORRIBLE!!! | 3433 | // this method is doing is HORRIBLE!!! |
3427 | avatar.Scene.NeedSceneCacheClear(avatar.UUID); | 3434 | avatar.Scene.NeedSceneCacheClear(avatar.UUID); |
3428 | 3435 | ||
3429 | if (closeChildAgents && !avatar.IsChildAgent) | 3436 | if (closeChildAgents && !isChildAgent) |
3430 | { | ||
3431 | List<ulong> regions = avatar.KnownRegionHandles; | ||
3432 | regions.Remove(RegionInfo.RegionHandle); | ||
3433 | m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); | ||
3434 | } | ||
3435 | m_log.Debug("[Scene] Beginning ClientClosed"); | ||
3436 | m_eventManager.TriggerClientClosed(agentID, this); | ||
3437 | m_log.Debug("[Scene] Finished ClientClosed"); | ||
3438 | } | ||
3439 | catch (NullReferenceException) | ||
3440 | { | 3437 | { |
3441 | // We don't know which count to remove it from | 3438 | List<ulong> regions = avatar.KnownRegionHandles; |
3442 | // Avatar is already disposed :/ | 3439 | regions.Remove(RegionInfo.RegionHandle); |
3440 | m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); | ||
3443 | } | 3441 | } |
3444 | 3442 | ||
3445 | try | 3443 | m_eventManager.TriggerClientClosed(agentID, this); |
3444 | m_eventManager.TriggerOnRemovePresence(agentID); | ||
3445 | |||
3446 | if (!isChildAgent) | ||
3446 | { | 3447 | { |
3447 | m_eventManager.TriggerOnRemovePresence(agentID); | 3448 | if (AttachmentsModule != null && avatar.PresenceType != PresenceType.Npc) |
3448 | |||
3449 | if (!isChildAgent) | ||
3450 | { | 3449 | { |
3451 | if (AttachmentsModule != null && avatar.PresenceType != PresenceType.Npc) | 3450 | IUserManagement uMan = RequestModuleInterface<IUserManagement>(); |
3452 | { | 3451 | // Don't save attachments for HG visitors, it |
3453 | IUserManagement uMan = RequestModuleInterface<IUserManagement>(); | 3452 | // messes up their inventory. When a HG visitor logs |
3454 | // Don't save attachments for HG visitors, it | 3453 | // out on a foreign grid, their attachments will be |
3455 | // messes up their inventory. When a HG visitor logs | 3454 | // reloaded in the state they were in when they left |
3456 | // out on a foreign grid, their attachments will be | 3455 | // the home grid. This is best anyway as the visited |
3457 | // reloaded in the state they were in when they left | 3456 | // grid may use an incompatible script engine. |
3458 | // the home grid. This is best anyway as the visited | 3457 | if (uMan == null || uMan.IsLocalGridUser(avatar.UUID)) |
3459 | // grid may use an incompatible script engine. | 3458 | AttachmentsModule.SaveChangedAttachments(avatar, false); |
3460 | if (uMan == null || uMan.IsLocalGridUser(avatar.UUID)) | ||
3461 | AttachmentsModule.SaveChangedAttachments(avatar, false); | ||
3462 | } | ||
3463 | |||
3464 | ForEachClient( | ||
3465 | delegate(IClientAPI client) | ||
3466 | { | ||
3467 | //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway | ||
3468 | try { client.SendKillObject(avatar.RegionHandle, new List<uint> { avatar.LocalId }); } | ||
3469 | catch (NullReferenceException) { } | ||
3470 | }); | ||
3471 | } | 3459 | } |
3472 | 3460 | ||
3473 | // It's possible for child agents to have transactions if changes are being made cross-border. | 3461 | ForEachClient( |
3474 | if (AgentTransactionsModule != null) | 3462 | delegate(IClientAPI client) |
3475 | AgentTransactionsModule.RemoveAgentAssetTransactions(agentID); | 3463 | { |
3476 | } | 3464 | //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway |
3477 | finally | 3465 | try { client.SendKillObject(avatar.RegionHandle, new List<uint> { avatar.LocalId }); } |
3478 | { | 3466 | catch (NullReferenceException) { } |
3479 | // Always clean these structures up so that any failure above doesn't cause them to remain in the | 3467 | }); |
3480 | // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering | ||
3481 | // the same cleanup exception continually. | ||
3482 | // TODO: This should probably extend to the whole method, but we don't want to also catch the NRE | ||
3483 | // since this would hide the underlying failure and other associated problems. | ||
3484 | m_sceneGraph.RemoveScenePresence(agentID); | ||
3485 | m_clientManager.Remove(agentID); | ||
3486 | } | 3468 | } |
3487 | 3469 | ||
3488 | try | 3470 | // It's possible for child agents to have transactions if changes are being made cross-border. |
3489 | { | 3471 | if (AgentTransactionsModule != null) |
3490 | avatar.Close(); | 3472 | AgentTransactionsModule.RemoveAgentAssetTransactions(agentID); |
3491 | } | 3473 | |
3492 | catch (NullReferenceException) | 3474 | avatar.Close(); |
3493 | { | 3475 | |
3494 | //We can safely ignore null reference exceptions. It means the avatar are dead and cleaned up anyway. | ||
3495 | } | ||
3496 | catch (Exception e) | ||
3497 | { | ||
3498 | m_log.ErrorFormat("[SCENE] Scene.cs:RemoveClient exception {0}{1}", e.Message, e.StackTrace); | ||
3499 | } | ||
3500 | m_log.Debug("[Scene] Done. Firing RemoveCircuit"); | ||
3501 | m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode); | 3476 | m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode); |
3502 | // CleanDroppedAttachments(); | ||
3503 | m_log.Debug("[Scene] The avatar has left the building"); | 3477 | m_log.Debug("[Scene] The avatar has left the building"); |
3504 | //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false)); | ||
3505 | //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true)); | ||
3506 | } | 3478 | } |
3479 | catch (Exception e) | ||
3480 | { | ||
3481 | m_log.Error( | ||
3482 | string.Format("[SCENE]: Exception removing {0} from {1}, ", avatar.Name, RegionInfo.RegionName), e); | ||
3483 | } | ||
3484 | finally | ||
3485 | { | ||
3486 | // Always clean these structures up so that any failure above doesn't cause them to remain in the | ||
3487 | // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering | ||
3488 | // the same cleanup exception continually. | ||
3489 | // TODO: This should probably extend to the whole method, but we don't want to also catch the NRE | ||
3490 | // since this would hide the underlying failure and other associated problems. | ||
3491 | m_sceneGraph.RemoveScenePresence(agentID); | ||
3492 | m_clientManager.Remove(agentID); | ||
3493 | } | ||
3494 | |||
3495 | //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false)); | ||
3496 | //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true)); | ||
3507 | } | 3497 | } |
3508 | 3498 | ||
3509 | /// <summary> | 3499 | /// <summary> |