diff options
author | Justin Clark-Casey (justincc) | 2013-08-08 23:29:30 +0100 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2013-08-08 23:29:30 +0100 |
commit | b1c26a56b3d615f3709363e3a2f91b5423f5891f (patch) | |
tree | ea87893e6a13813dcf383d064fe33d3b3740c7ce /OpenSim/Region/Framework/Scenes | |
parent | minor: Remove console lines at bottom of FakeParcelIDTests() regression test ... (diff) | |
download | opensim-SC_OLD-b1c26a56b3d615f3709363e3a2f91b5423f5891f.zip opensim-SC_OLD-b1c26a56b3d615f3709363e3a2f91b5423f5891f.tar.gz opensim-SC_OLD-b1c26a56b3d615f3709363e3a2f91b5423f5891f.tar.bz2 opensim-SC_OLD-b1c26a56b3d615f3709363e3a2f91b5423f5891f.tar.xz |
Fix an issue where under teleport v2 protocol, teleporting from regions in an line from A->B->C would not close region A when reaching C
The root cause was that v2 was only closing neighbour agents if the root connection also needed a close.
However, fixing this requires the neighbour regions also detect when they should not close due to re-teleports re-establishing the child connection.
This involves restructuring the code to introduce a scene presence state machine that can serialize the different add and remove client calls that are now possible with the late close of the
This commit appears to fix these issues and improve teleport, but still has holes on at least quick reteleporting (and possibly occasionally on ordinary teleports).
Also, has not been completely tested yet in scenarios where regions are running on different simulators
Diffstat (limited to 'OpenSim/Region/Framework/Scenes')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/Scene.cs | 308 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/ScenePresence.cs | 36 |
2 files changed, 228 insertions, 116 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 56cd57e..5f10869 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -151,7 +151,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
151 | public SynchronizeSceneHandler SynchronizeScene; | 151 | public SynchronizeSceneHandler SynchronizeScene; |
152 | 152 | ||
153 | /// <summary> | 153 | /// <summary> |
154 | /// Used to prevent simultaneous calls to RemoveClient() for the same agent from interfering with each other. | 154 | /// Used to prevent simultaneous calls to code that adds and removes agents. |
155 | /// </summary> | 155 | /// </summary> |
156 | private object m_removeClientLock = new object(); | 156 | private object m_removeClientLock = new object(); |
157 | 157 | ||
@@ -1312,7 +1312,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1312 | Thread.Sleep(500); | 1312 | Thread.Sleep(500); |
1313 | 1313 | ||
1314 | // Stop all client threads. | 1314 | // Stop all client threads. |
1315 | ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(); }); | 1315 | ForEachScenePresence(delegate(ScenePresence avatar) { IncomingCloseAgent(avatar.UUID, false); }); |
1316 | 1316 | ||
1317 | m_log.Debug("[SCENE]: Persisting changed objects"); | 1317 | m_log.Debug("[SCENE]: Persisting changed objects"); |
1318 | EventManager.TriggerSceneShuttingDown(this); | 1318 | EventManager.TriggerSceneShuttingDown(this); |
@@ -2972,7 +2972,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2972 | { | 2972 | { |
2973 | PresenceService.LogoutAgent(sp.ControllingClient.SessionId); | 2973 | PresenceService.LogoutAgent(sp.ControllingClient.SessionId); |
2974 | 2974 | ||
2975 | sp.ControllingClient.Close(); | 2975 | IncomingCloseAgent(sp.UUID, false); |
2976 | } | 2976 | } |
2977 | else | 2977 | else |
2978 | { | 2978 | { |
@@ -3384,47 +3384,48 @@ namespace OpenSim.Region.Framework.Scenes | |||
3384 | 3384 | ||
3385 | public override void RemoveClient(UUID agentID, bool closeChildAgents) | 3385 | public override void RemoveClient(UUID agentID, bool closeChildAgents) |
3386 | { | 3386 | { |
3387 | // CheckHeartbeat(); | 3387 | AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID); |
3388 | bool isChildAgent = false; | ||
3389 | AgentCircuitData acd; | ||
3390 | 3388 | ||
3391 | lock (m_removeClientLock) | 3389 | // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which |
3390 | // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not | ||
3391 | // However, will keep for now just in case. | ||
3392 | if (acd == null) | ||
3392 | { | 3393 | { |
3393 | acd = m_authenticateHandler.GetAgentCircuitData(agentID); | 3394 | m_log.ErrorFormat( |
3395 | "[SCENE]: No agent circuit found for {0} in {1}, aborting Scene.RemoveClient", agentID, Name); | ||
3394 | 3396 | ||
3395 | if (acd == null) | 3397 | return; |
3396 | { | 3398 | } |
3397 | m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID); | 3399 | else |
3398 | return; | 3400 | { |
3399 | } | 3401 | m_authenticateHandler.RemoveCircuit(agentID); |
3400 | else | ||
3401 | { | ||
3402 | // We remove the acd up here to avoid later race conditions if two RemoveClient() calls occurred | ||
3403 | // simultaneously. | ||
3404 | // We also need to remove by agent ID since NPCs will have no circuit code. | ||
3405 | m_authenticateHandler.RemoveCircuit(agentID); | ||
3406 | } | ||
3407 | } | 3402 | } |
3408 | 3403 | ||
3404 | // TODO: Can we now remove this lock? | ||
3409 | lock (acd) | 3405 | lock (acd) |
3410 | { | 3406 | { |
3407 | bool isChildAgent = false; | ||
3408 | |||
3411 | ScenePresence avatar = GetScenePresence(agentID); | 3409 | ScenePresence avatar = GetScenePresence(agentID); |
3412 | 3410 | ||
3411 | // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which | ||
3412 | // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not | ||
3413 | // However, will keep for now just in case. | ||
3413 | if (avatar == null) | 3414 | if (avatar == null) |
3414 | { | 3415 | { |
3415 | m_log.WarnFormat( | 3416 | m_log.ErrorFormat( |
3416 | "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID); | 3417 | "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID); |
3417 | 3418 | ||
3418 | return; | 3419 | return; |
3419 | } | 3420 | } |
3420 | 3421 | ||
3421 | try | 3422 | try |
3422 | { | 3423 | { |
3423 | isChildAgent = avatar.IsChildAgent; | 3424 | isChildAgent = avatar.IsChildAgent; |
3424 | 3425 | ||
3425 | m_log.DebugFormat( | 3426 | m_log.DebugFormat( |
3426 | "[SCENE]: Removing {0} agent {1} {2} from {3}", | 3427 | "[SCENE]: Removing {0} agent {1} {2} from {3}", |
3427 | (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName); | 3428 | isChildAgent ? "child" : "root", avatar.Name, agentID, Name); |
3428 | 3429 | ||
3429 | // Don't do this to root agents, it's not nice for the viewer | 3430 | // Don't do this to root agents, it's not nice for the viewer |
3430 | if (closeChildAgents && isChildAgent) | 3431 | if (closeChildAgents && isChildAgent) |
@@ -3587,13 +3588,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
3587 | /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of | 3588 | /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of |
3588 | /// the LLUDP stack). | 3589 | /// the LLUDP stack). |
3589 | /// </remarks> | 3590 | /// </remarks> |
3590 | /// <param name="agent">CircuitData of the agent who is connecting</param> | 3591 | /// <param name="acd">CircuitData of the agent who is connecting</param> |
3591 | /// <param name="reason">Outputs the reason for the false response on this string</param> | 3592 | /// <param name="reason">Outputs the reason for the false response on this string</param> |
3592 | /// <param name="requirePresenceLookup">True for normal presence. False for NPC | 3593 | /// <param name="requirePresenceLookup">True for normal presence. False for NPC |
3593 | /// or other applications where a full grid/Hypergrid presence may not be required.</param> | 3594 | /// or other applications where a full grid/Hypergrid presence may not be required.</param> |
3594 | /// <returns>True if the region accepts this agent. False if it does not. False will | 3595 | /// <returns>True if the region accepts this agent. False if it does not. False will |
3595 | /// also return a reason.</returns> | 3596 | /// also return a reason.</returns> |
3596 | public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, out string reason, bool requirePresenceLookup) | 3597 | public bool NewUserConnection(AgentCircuitData acd, uint teleportFlags, out string reason, bool requirePresenceLookup) |
3597 | { | 3598 | { |
3598 | bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 || | 3599 | bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 || |
3599 | (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0); | 3600 | (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0); |
@@ -3613,15 +3614,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
3613 | m_log.DebugFormat( | 3614 | m_log.DebugFormat( |
3614 | "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})", | 3615 | "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})", |
3615 | RegionInfo.RegionName, | 3616 | RegionInfo.RegionName, |
3616 | (agent.child ? "child" : "root"), | 3617 | (acd.child ? "child" : "root"), |
3617 | agent.firstname, | 3618 | acd.firstname, |
3618 | agent.lastname, | 3619 | acd.lastname, |
3619 | agent.AgentID, | 3620 | acd.AgentID, |
3620 | agent.circuitcode, | 3621 | acd.circuitcode, |
3621 | agent.IPAddress, | 3622 | acd.IPAddress, |
3622 | agent.Viewer, | 3623 | acd.Viewer, |
3623 | ((TPFlags)teleportFlags).ToString(), | 3624 | ((TPFlags)teleportFlags).ToString(), |
3624 | agent.startpos | 3625 | acd.startpos |
3625 | ); | 3626 | ); |
3626 | 3627 | ||
3627 | if (!LoginsEnabled) | 3628 | if (!LoginsEnabled) |
@@ -3639,7 +3640,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3639 | { | 3640 | { |
3640 | foreach (string viewer in m_AllowedViewers) | 3641 | foreach (string viewer in m_AllowedViewers) |
3641 | { | 3642 | { |
3642 | if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) | 3643 | if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower()) |
3643 | { | 3644 | { |
3644 | ViewerDenied = false; | 3645 | ViewerDenied = false; |
3645 | break; | 3646 | break; |
@@ -3656,7 +3657,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3656 | { | 3657 | { |
3657 | foreach (string viewer in m_BannedViewers) | 3658 | foreach (string viewer in m_BannedViewers) |
3658 | { | 3659 | { |
3659 | if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) | 3660 | if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower()) |
3660 | { | 3661 | { |
3661 | ViewerDenied = true; | 3662 | ViewerDenied = true; |
3662 | break; | 3663 | break; |
@@ -3668,61 +3669,104 @@ namespace OpenSim.Region.Framework.Scenes | |||
3668 | { | 3669 | { |
3669 | m_log.DebugFormat( | 3670 | m_log.DebugFormat( |
3670 | "[SCENE]: Access denied for {0} {1} using {2}", | 3671 | "[SCENE]: Access denied for {0} {1} using {2}", |
3671 | agent.firstname, agent.lastname, agent.Viewer); | 3672 | acd.firstname, acd.lastname, acd.Viewer); |
3672 | reason = "Access denied, your viewer is banned by the region owner"; | 3673 | reason = "Access denied, your viewer is banned by the region owner"; |
3673 | return false; | 3674 | return false; |
3674 | } | 3675 | } |
3675 | 3676 | ||
3676 | ILandObject land; | 3677 | ILandObject land; |
3678 | ScenePresence sp; | ||
3677 | 3679 | ||
3678 | lock (agent) | 3680 | lock (m_removeClientLock) |
3679 | { | 3681 | { |
3680 | ScenePresence sp = GetScenePresence(agent.AgentID); | 3682 | sp = GetScenePresence(acd.AgentID); |
3681 | 3683 | ||
3682 | if (sp != null) | 3684 | // We need to ensure that we are not already removing the scene presence before we ask it not to be |
3685 | // closed. | ||
3686 | if (sp != null && sp.IsChildAgent && sp.LifecycleState == ScenePresenceState.Running) | ||
3683 | { | 3687 | { |
3684 | if (!sp.IsChildAgent) | 3688 | m_log.DebugFormat( |
3685 | { | 3689 | "[SCENE]: Reusing existing child scene presence for {0} in {1}", sp.Name, Name); |
3686 | // We have a root agent. Is it in transit? | ||
3687 | if (!EntityTransferModule.IsInTransit(sp.UUID)) | ||
3688 | { | ||
3689 | // We have a zombie from a crashed session. | ||
3690 | // Or the same user is trying to be root twice here, won't work. | ||
3691 | // Kill it. | ||
3692 | m_log.WarnFormat( | ||
3693 | "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", | ||
3694 | sp.Name, sp.UUID, RegionInfo.RegionName); | ||
3695 | 3690 | ||
3696 | if (sp.ControllingClient != null) | 3691 | // In the case where, for example, an A B C D region layout, an avatar may |
3697 | sp.ControllingClient.Close(true); | 3692 | // teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C |
3693 | // renews the lease on the child agent at B, we must make sure that the close from A does not succeed. | ||
3694 | if (!acd.ChildrenCapSeeds.ContainsKey(RegionInfo.RegionHandle)) | ||
3695 | { | ||
3696 | m_log.DebugFormat( | ||
3697 | "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.", | ||
3698 | sp.Name, Name); | ||
3698 | 3699 | ||
3699 | sp = null; | 3700 | sp.DoNotCloseAfterTeleport = true; |
3700 | } | ||
3701 | //else | ||
3702 | // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName); | ||
3703 | } | 3701 | } |
3704 | else | 3702 | } |
3703 | } | ||
3704 | |||
3705 | // Need to poll here in case we are currently deleting an sp. Letting threads run over each other will | ||
3706 | // allow unpredictable things to happen. | ||
3707 | if (sp != null) | ||
3708 | { | ||
3709 | const int polls = 10; | ||
3710 | const int pollInterval = 1000; | ||
3711 | int pollsLeft = polls; | ||
3712 | |||
3713 | while (sp.LifecycleState == ScenePresenceState.Removing && pollsLeft-- > 0) | ||
3714 | Thread.Sleep(pollInterval); | ||
3715 | |||
3716 | if (sp.LifecycleState == ScenePresenceState.Removing) | ||
3717 | { | ||
3718 | m_log.WarnFormat( | ||
3719 | "[SCENE]: Agent {0} in {1} was still being removed after {2}s. Aborting NewUserConnection.", | ||
3720 | sp.Name, Name, polls * pollInterval / 1000); | ||
3721 | |||
3722 | return false; | ||
3723 | } | ||
3724 | else if (polls != pollsLeft) | ||
3725 | { | ||
3726 | m_log.DebugFormat( | ||
3727 | "[SCENE]: NewUserConnection for agent {0} in {1} had to wait {2}s for in-progress removal to complete on an old presence.", | ||
3728 | sp.Name, Name, polls * pollInterval / 1000); | ||
3729 | } | ||
3730 | } | ||
3731 | |||
3732 | // TODO: can we remove this lock? | ||
3733 | lock (acd) | ||
3734 | { | ||
3735 | if (sp != null && !sp.IsChildAgent) | ||
3736 | { | ||
3737 | // We have a root agent. Is it in transit? | ||
3738 | if (!EntityTransferModule.IsInTransit(sp.UUID)) | ||
3705 | { | 3739 | { |
3706 | // We have a child agent here | 3740 | // We have a zombie from a crashed session. |
3707 | sp.DoNotCloseAfterTeleport = true; | 3741 | // Or the same user is trying to be root twice here, won't work. |
3708 | //m_log.WarnFormat("[SCENE]: Existing child scene presence for {0} {1} in {2}", sp.Name, sp.UUID, RegionInfo.RegionName); | 3742 | // Kill it. |
3743 | m_log.WarnFormat( | ||
3744 | "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", | ||
3745 | sp.Name, sp.UUID, RegionInfo.RegionName); | ||
3746 | |||
3747 | if (sp.ControllingClient != null) | ||
3748 | IncomingCloseAgent(sp.UUID, true); | ||
3749 | |||
3750 | sp = null; | ||
3709 | } | 3751 | } |
3752 | //else | ||
3753 | // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName); | ||
3710 | } | 3754 | } |
3711 | 3755 | ||
3712 | // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags. | 3756 | // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags. |
3713 | // We need the circuit data here for some of the subsequent checks. (groups, for example) | 3757 | // We need the circuit data here for some of the subsequent checks. (groups, for example) |
3714 | // If the checks fail, we remove the circuit. | 3758 | // If the checks fail, we remove the circuit. |
3715 | agent.teleportFlags = teleportFlags; | 3759 | acd.teleportFlags = teleportFlags; |
3716 | m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); | 3760 | m_authenticateHandler.AddNewCircuit(acd.circuitcode, acd); |
3717 | 3761 | ||
3718 | land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y); | 3762 | land = LandChannel.GetLandObject(acd.startpos.X, acd.startpos.Y); |
3719 | 3763 | ||
3720 | // On login test land permisions | 3764 | // On login test land permisions |
3721 | if (vialogin) | 3765 | if (vialogin) |
3722 | { | 3766 | { |
3723 | if (land != null && !TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y)) | 3767 | if (land != null && !TestLandRestrictions(acd.AgentID, out reason, ref acd.startpos.X, ref acd.startpos.Y)) |
3724 | { | 3768 | { |
3725 | m_authenticateHandler.RemoveCircuit(agent.circuitcode); | 3769 | m_authenticateHandler.RemoveCircuit(acd.circuitcode); |
3726 | return false; | 3770 | return false; |
3727 | } | 3771 | } |
3728 | } | 3772 | } |
@@ -3733,9 +3777,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
3733 | { | 3777 | { |
3734 | try | 3778 | try |
3735 | { | 3779 | { |
3736 | if (!VerifyUserPresence(agent, out reason)) | 3780 | if (!VerifyUserPresence(acd, out reason)) |
3737 | { | 3781 | { |
3738 | m_authenticateHandler.RemoveCircuit(agent.circuitcode); | 3782 | m_authenticateHandler.RemoveCircuit(acd.circuitcode); |
3739 | return false; | 3783 | return false; |
3740 | } | 3784 | } |
3741 | } | 3785 | } |
@@ -3744,16 +3788,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
3744 | m_log.ErrorFormat( | 3788 | m_log.ErrorFormat( |
3745 | "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); | 3789 | "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); |
3746 | 3790 | ||
3747 | m_authenticateHandler.RemoveCircuit(agent.circuitcode); | 3791 | m_authenticateHandler.RemoveCircuit(acd.circuitcode); |
3748 | return false; | 3792 | return false; |
3749 | } | 3793 | } |
3750 | } | 3794 | } |
3751 | 3795 | ||
3752 | try | 3796 | try |
3753 | { | 3797 | { |
3754 | if (!AuthorizeUser(agent, SeeIntoRegion, out reason)) | 3798 | if (!AuthorizeUser(acd, SeeIntoRegion, out reason)) |
3755 | { | 3799 | { |
3756 | m_authenticateHandler.RemoveCircuit(agent.circuitcode); | 3800 | m_authenticateHandler.RemoveCircuit(acd.circuitcode); |
3757 | return false; | 3801 | return false; |
3758 | } | 3802 | } |
3759 | } | 3803 | } |
@@ -3762,19 +3806,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
3762 | m_log.ErrorFormat( | 3806 | m_log.ErrorFormat( |
3763 | "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); | 3807 | "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); |
3764 | 3808 | ||
3765 | m_authenticateHandler.RemoveCircuit(agent.circuitcode); | 3809 | m_authenticateHandler.RemoveCircuit(acd.circuitcode); |
3766 | return false; | 3810 | return false; |
3767 | } | 3811 | } |
3768 | 3812 | ||
3769 | m_log.InfoFormat( | 3813 | m_log.InfoFormat( |
3770 | "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})", | 3814 | "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})", |
3771 | RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname, | 3815 | Name, (acd.child ? "child" : "root"), acd.firstname, acd.lastname, |
3772 | agent.AgentID, agent.circuitcode); | 3816 | acd.AgentID, acd.circuitcode); |
3773 | 3817 | ||
3774 | if (CapsModule != null) | 3818 | if (CapsModule != null) |
3775 | { | 3819 | { |
3776 | CapsModule.SetAgentCapsSeeds(agent); | 3820 | CapsModule.SetAgentCapsSeeds(acd); |
3777 | CapsModule.CreateCaps(agent.AgentID); | 3821 | CapsModule.CreateCaps(acd.AgentID); |
3778 | } | 3822 | } |
3779 | } | 3823 | } |
3780 | else | 3824 | else |
@@ -3787,14 +3831,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
3787 | { | 3831 | { |
3788 | m_log.DebugFormat( | 3832 | m_log.DebugFormat( |
3789 | "[SCENE]: Adjusting known seeds for existing agent {0} in {1}", | 3833 | "[SCENE]: Adjusting known seeds for existing agent {0} in {1}", |
3790 | agent.AgentID, RegionInfo.RegionName); | 3834 | acd.AgentID, RegionInfo.RegionName); |
3791 | 3835 | ||
3792 | sp.AdjustKnownSeeds(); | 3836 | sp.AdjustKnownSeeds(); |
3793 | 3837 | ||
3794 | if (CapsModule != null) | 3838 | if (CapsModule != null) |
3795 | { | 3839 | { |
3796 | CapsModule.SetAgentCapsSeeds(agent); | 3840 | CapsModule.SetAgentCapsSeeds(acd); |
3797 | CapsModule.CreateCaps(agent.AgentID); | 3841 | CapsModule.CreateCaps(acd.AgentID); |
3798 | } | 3842 | } |
3799 | } | 3843 | } |
3800 | } | 3844 | } |
@@ -3802,23 +3846,23 @@ namespace OpenSim.Region.Framework.Scenes | |||
3802 | // Try caching an incoming user name much earlier on to see if this helps with an issue | 3846 | // Try caching an incoming user name much earlier on to see if this helps with an issue |
3803 | // where HG users are occasionally seen by others as "Unknown User" because their UUIDName | 3847 | // where HG users are occasionally seen by others as "Unknown User" because their UUIDName |
3804 | // request for the HG avatar appears to trigger before the user name is cached. | 3848 | // request for the HG avatar appears to trigger before the user name is cached. |
3805 | CacheUserName(null, agent); | 3849 | CacheUserName(null, acd); |
3806 | } | 3850 | } |
3807 | 3851 | ||
3808 | if (vialogin) | 3852 | if (vialogin) |
3809 | { | 3853 | { |
3810 | // CleanDroppedAttachments(); | 3854 | // CleanDroppedAttachments(); |
3811 | 3855 | ||
3812 | if (TestBorderCross(agent.startpos, Cardinals.E)) | 3856 | if (TestBorderCross(acd.startpos, Cardinals.E)) |
3813 | { | 3857 | { |
3814 | Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.E); | 3858 | Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.E); |
3815 | agent.startpos.X = crossedBorder.BorderLine.Z - 1; | 3859 | acd.startpos.X = crossedBorder.BorderLine.Z - 1; |
3816 | } | 3860 | } |
3817 | 3861 | ||
3818 | if (TestBorderCross(agent.startpos, Cardinals.N)) | 3862 | if (TestBorderCross(acd.startpos, Cardinals.N)) |
3819 | { | 3863 | { |
3820 | Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.N); | 3864 | Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.N); |
3821 | agent.startpos.Y = crossedBorder.BorderLine.Z - 1; | 3865 | acd.startpos.Y = crossedBorder.BorderLine.Z - 1; |
3822 | } | 3866 | } |
3823 | 3867 | ||
3824 | //Mitigate http://opensimulator.org/mantis/view.php?id=3522 | 3868 | //Mitigate http://opensimulator.org/mantis/view.php?id=3522 |
@@ -3828,39 +3872,39 @@ namespace OpenSim.Region.Framework.Scenes | |||
3828 | { | 3872 | { |
3829 | lock (EastBorders) | 3873 | lock (EastBorders) |
3830 | { | 3874 | { |
3831 | if (agent.startpos.X > EastBorders[0].BorderLine.Z) | 3875 | if (acd.startpos.X > EastBorders[0].BorderLine.Z) |
3832 | { | 3876 | { |
3833 | m_log.Warn("FIX AGENT POSITION"); | 3877 | m_log.Warn("FIX AGENT POSITION"); |
3834 | agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; | 3878 | acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; |
3835 | if (agent.startpos.Z > 720) | 3879 | if (acd.startpos.Z > 720) |
3836 | agent.startpos.Z = 720; | 3880 | acd.startpos.Z = 720; |
3837 | } | 3881 | } |
3838 | } | 3882 | } |
3839 | lock (NorthBorders) | 3883 | lock (NorthBorders) |
3840 | { | 3884 | { |
3841 | if (agent.startpos.Y > NorthBorders[0].BorderLine.Z) | 3885 | if (acd.startpos.Y > NorthBorders[0].BorderLine.Z) |
3842 | { | 3886 | { |
3843 | m_log.Warn("FIX Agent POSITION"); | 3887 | m_log.Warn("FIX Agent POSITION"); |
3844 | agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; | 3888 | acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; |
3845 | if (agent.startpos.Z > 720) | 3889 | if (acd.startpos.Z > 720) |
3846 | agent.startpos.Z = 720; | 3890 | acd.startpos.Z = 720; |
3847 | } | 3891 | } |
3848 | } | 3892 | } |
3849 | } else | 3893 | } else |
3850 | { | 3894 | { |
3851 | if (agent.startpos.X > EastBorders[0].BorderLine.Z) | 3895 | if (acd.startpos.X > EastBorders[0].BorderLine.Z) |
3852 | { | 3896 | { |
3853 | m_log.Warn("FIX AGENT POSITION"); | 3897 | m_log.Warn("FIX AGENT POSITION"); |
3854 | agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; | 3898 | acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; |
3855 | if (agent.startpos.Z > 720) | 3899 | if (acd.startpos.Z > 720) |
3856 | agent.startpos.Z = 720; | 3900 | acd.startpos.Z = 720; |
3857 | } | 3901 | } |
3858 | if (agent.startpos.Y > NorthBorders[0].BorderLine.Z) | 3902 | if (acd.startpos.Y > NorthBorders[0].BorderLine.Z) |
3859 | { | 3903 | { |
3860 | m_log.Warn("FIX Agent POSITION"); | 3904 | m_log.Warn("FIX Agent POSITION"); |
3861 | agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; | 3905 | acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; |
3862 | if (agent.startpos.Z > 720) | 3906 | if (acd.startpos.Z > 720) |
3863 | agent.startpos.Z = 720; | 3907 | acd.startpos.Z = 720; |
3864 | } | 3908 | } |
3865 | } | 3909 | } |
3866 | 3910 | ||
@@ -3876,12 +3920,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
3876 | { | 3920 | { |
3877 | // We have multiple SpawnPoints, Route the agent to a random or sequential one | 3921 | // We have multiple SpawnPoints, Route the agent to a random or sequential one |
3878 | if (SpawnPointRouting == "random") | 3922 | if (SpawnPointRouting == "random") |
3879 | agent.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation( | 3923 | acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation( |
3880 | telehub.AbsolutePosition, | 3924 | telehub.AbsolutePosition, |
3881 | telehub.GroupRotation | 3925 | telehub.GroupRotation |
3882 | ); | 3926 | ); |
3883 | else | 3927 | else |
3884 | agent.startpos = spawnpoints[SpawnPoint()].GetLocation( | 3928 | acd.startpos = spawnpoints[SpawnPoint()].GetLocation( |
3885 | telehub.AbsolutePosition, | 3929 | telehub.AbsolutePosition, |
3886 | telehub.GroupRotation | 3930 | telehub.GroupRotation |
3887 | ); | 3931 | ); |
@@ -3889,7 +3933,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3889 | else | 3933 | else |
3890 | { | 3934 | { |
3891 | // We have a single SpawnPoint and will route the agent to it | 3935 | // We have a single SpawnPoint and will route the agent to it |
3892 | agent.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); | 3936 | acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); |
3893 | } | 3937 | } |
3894 | 3938 | ||
3895 | return true; | 3939 | return true; |
@@ -3900,7 +3944,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3900 | { | 3944 | { |
3901 | if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) | 3945 | if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) |
3902 | { | 3946 | { |
3903 | agent.startpos = land.LandData.UserLocation; | 3947 | acd.startpos = land.LandData.UserLocation; |
3904 | } | 3948 | } |
3905 | } | 3949 | } |
3906 | } | 3950 | } |
@@ -4359,11 +4403,51 @@ namespace OpenSim.Region.Framework.Scenes | |||
4359 | /// </param> | 4403 | /// </param> |
4360 | public bool IncomingCloseAgent(UUID agentID, bool force) | 4404 | public bool IncomingCloseAgent(UUID agentID, bool force) |
4361 | { | 4405 | { |
4362 | //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); | 4406 | ScenePresence sp; |
4363 | ScenePresence presence = m_sceneGraph.GetScenePresence(agentID); | 4407 | |
4364 | if (presence != null) | 4408 | lock (m_removeClientLock) |
4409 | { | ||
4410 | sp = GetScenePresence(agentID); | ||
4411 | |||
4412 | if (sp == null) | ||
4413 | { | ||
4414 | m_log.DebugFormat( | ||
4415 | "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in {1}", | ||
4416 | agentID, Name); | ||
4417 | |||
4418 | return false; | ||
4419 | } | ||
4420 | |||
4421 | if (sp.LifecycleState != ScenePresenceState.Running) | ||
4422 | { | ||
4423 | m_log.DebugFormat( | ||
4424 | "[SCENE]: Called RemoveClient() for {0} in {1} but presence is already in state {2}", | ||
4425 | sp.Name, Name, sp.LifecycleState); | ||
4426 | |||
4427 | return false; | ||
4428 | } | ||
4429 | |||
4430 | // We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may | ||
4431 | // teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not | ||
4432 | // want to obey this close since C may have renewed the child agent lease on B. | ||
4433 | if (sp.DoNotCloseAfterTeleport) | ||
4434 | { | ||
4435 | m_log.DebugFormat( | ||
4436 | "[SCENE]: Not closing {0} agent {1} in {2} since another simulator has re-established the child connection", | ||
4437 | sp.IsChildAgent ? "child" : "root", sp.Name, Name); | ||
4438 | |||
4439 | // Need to reset the flag so that a subsequent close after another teleport can succeed. | ||
4440 | sp.DoNotCloseAfterTeleport = false; | ||
4441 | |||
4442 | return false; | ||
4443 | } | ||
4444 | |||
4445 | sp.LifecycleState = ScenePresenceState.Removing; | ||
4446 | } | ||
4447 | |||
4448 | if (sp != null) | ||
4365 | { | 4449 | { |
4366 | presence.ControllingClient.Close(force); | 4450 | sp.ControllingClient.Close(force); |
4367 | return true; | 4451 | return true; |
4368 | } | 4452 | } |
4369 | 4453 | ||
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 7fd1302..bdcdf03 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -74,6 +74,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
74 | 74 | ||
75 | public class ScenePresence : EntityBase, IScenePresence | 75 | public class ScenePresence : EntityBase, IScenePresence |
76 | { | 76 | { |
77 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
78 | |||
77 | // ~ScenePresence() | 79 | // ~ScenePresence() |
78 | // { | 80 | // { |
79 | // m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name); | 81 | // m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name); |
@@ -85,10 +87,27 @@ namespace OpenSim.Region.Framework.Scenes | |||
85 | m_scene.EventManager.TriggerScenePresenceUpdated(this); | 87 | m_scene.EventManager.TriggerScenePresenceUpdated(this); |
86 | } | 88 | } |
87 | 89 | ||
88 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
89 | |||
90 | public PresenceType PresenceType { get; private set; } | 90 | public PresenceType PresenceType { get; private set; } |
91 | 91 | ||
92 | private ScenePresenceStateMachine m_stateMachine; | ||
93 | |||
94 | /// <summary> | ||
95 | /// The current state of this presence. Governs only the existence lifecycle. See ScenePresenceStateMachine | ||
96 | /// for more details. | ||
97 | /// </summary> | ||
98 | public ScenePresenceState LifecycleState | ||
99 | { | ||
100 | get | ||
101 | { | ||
102 | return m_stateMachine.GetState(); | ||
103 | } | ||
104 | |||
105 | set | ||
106 | { | ||
107 | m_stateMachine.SetState(value); | ||
108 | } | ||
109 | } | ||
110 | |||
92 | // private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); | 111 | // private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); |
93 | private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); | 112 | private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); |
94 | private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); | 113 | private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); |
@@ -766,7 +785,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
766 | 785 | ||
767 | public ScenePresence( | 786 | public ScenePresence( |
768 | IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type) | 787 | IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type) |
769 | { | 788 | { |
770 | AttachmentsSyncLock = new Object(); | 789 | AttachmentsSyncLock = new Object(); |
771 | AllowMovement = true; | 790 | AllowMovement = true; |
772 | IsChildAgent = true; | 791 | IsChildAgent = true; |
@@ -811,6 +830,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
811 | SetDirectionVectors(); | 830 | SetDirectionVectors(); |
812 | 831 | ||
813 | Appearance = appearance; | 832 | Appearance = appearance; |
833 | |||
834 | m_stateMachine = new ScenePresenceStateMachine(this); | ||
814 | } | 835 | } |
815 | 836 | ||
816 | public void RegisterToEvents() | 837 | public void RegisterToEvents() |
@@ -879,7 +900,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
879 | /// </summary> | 900 | /// </summary> |
880 | public void MakeRootAgent(Vector3 pos, bool isFlying) | 901 | public void MakeRootAgent(Vector3 pos, bool isFlying) |
881 | { | 902 | { |
882 | m_log.DebugFormat( | 903 | m_log.InfoFormat( |
883 | "[SCENE]: Upgrading child to root agent for {0} in {1}", | 904 | "[SCENE]: Upgrading child to root agent for {0} in {1}", |
884 | Name, m_scene.RegionInfo.RegionName); | 905 | Name, m_scene.RegionInfo.RegionName); |
885 | 906 | ||
@@ -887,6 +908,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
887 | 908 | ||
888 | IsChildAgent = false; | 909 | IsChildAgent = false; |
889 | 910 | ||
911 | // Must reset this here so that a teleport to a region next to an existing region does not keep the flag | ||
912 | // set and prevent the close of the connection on a subsequent re-teleport. | ||
913 | // Should not be needed if we are not trying to tell this region to close | ||
914 | // DoNotCloseAfterTeleport = false; | ||
915 | |||
890 | IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); | 916 | IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); |
891 | if (gm != null) | 917 | if (gm != null) |
892 | Grouptitle = gm.GetGroupTitle(m_uuid); | 918 | Grouptitle = gm.GetGroupTitle(m_uuid); |
@@ -3738,6 +3764,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
3738 | // m_reprioritizationTimer.Dispose(); | 3764 | // m_reprioritizationTimer.Dispose(); |
3739 | 3765 | ||
3740 | RemoveFromPhysicalScene(); | 3766 | RemoveFromPhysicalScene(); |
3767 | |||
3768 | LifecycleState = ScenePresenceState.Removed; | ||
3741 | } | 3769 | } |
3742 | 3770 | ||
3743 | public void AddAttachment(SceneObjectGroup gobj) | 3771 | public void AddAttachment(SceneObjectGroup gobj) |