aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework/Scenes')
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs362
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs41
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs102
3 files changed, 368 insertions, 137 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index aa09092..6323a88 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
@@ -1338,7 +1338,7 @@ namespace OpenSim.Region.Framework.Scenes
1338 Thread.Sleep(500); 1338 Thread.Sleep(500);
1339 1339
1340 // Stop all client threads. 1340 // Stop all client threads.
1341 ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(); }); 1341 ForEachScenePresence(delegate(ScenePresence avatar) { IncomingCloseAgent(avatar.UUID, false); });
1342 1342
1343 m_log.Debug("[SCENE]: TriggerSceneShuttingDown"); 1343 m_log.Debug("[SCENE]: TriggerSceneShuttingDown");
1344 EventManager.TriggerSceneShuttingDown(this); 1344 EventManager.TriggerSceneShuttingDown(this);
@@ -3127,7 +3127,8 @@ namespace OpenSim.Region.Framework.Scenes
3127 if (sp != null) 3127 if (sp != null)
3128 { 3128 {
3129 PresenceService.LogoutAgent(sp.ControllingClient.SessionId); 3129 PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
3130 sp.ControllingClient.Close(); 3130
3131 IncomingCloseAgent(sp.UUID, false);
3131 } 3132 }
3132 3133
3133 // BANG! SLASH! 3134 // BANG! SLASH!
@@ -3541,47 +3542,48 @@ namespace OpenSim.Region.Framework.Scenes
3541 3542
3542 public override void RemoveClient(UUID agentID, bool closeChildAgents) 3543 public override void RemoveClient(UUID agentID, bool closeChildAgents)
3543 { 3544 {
3544// CheckHeartbeat(); 3545 AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID);
3545 bool isChildAgent = false;
3546 AgentCircuitData acd;
3547 3546
3548 lock (m_removeClientLock) 3547 // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which
3548 // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not
3549 // However, will keep for now just in case.
3550 if (acd == null)
3549 { 3551 {
3550 acd = m_authenticateHandler.GetAgentCircuitData(agentID); 3552 m_log.ErrorFormat(
3553 "[SCENE]: No agent circuit found for {0} in {1}, aborting Scene.RemoveClient", agentID, Name);
3551 3554
3552 if (acd == null) 3555 return;
3553 { 3556 }
3554 m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID); 3557 else
3555 return; 3558 {
3556 } 3559 m_authenticateHandler.RemoveCircuit(agentID);
3557 else
3558 {
3559 // We remove the acd up here to avoid later race conditions if two RemoveClient() calls occurred
3560 // simultaneously.
3561 // We also need to remove by agent ID since NPCs will have no circuit code.
3562 m_authenticateHandler.RemoveCircuit(agentID);
3563 }
3564 } 3560 }
3565 3561
3562 // TODO: Can we now remove this lock?
3566 lock (acd) 3563 lock (acd)
3567 { 3564 {
3565 bool isChildAgent = false;
3566
3568 ScenePresence avatar = GetScenePresence(agentID); 3567 ScenePresence avatar = GetScenePresence(agentID);
3569 3568
3569 // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which
3570 // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not
3571 // However, will keep for now just in case.
3570 if (avatar == null) 3572 if (avatar == null)
3571 { 3573 {
3572 m_log.WarnFormat( 3574 m_log.ErrorFormat(
3573 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID); 3575 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
3574 3576
3575 return; 3577 return;
3576 } 3578 }
3577 3579
3578 try 3580 try
3579 { 3581 {
3580 isChildAgent = avatar.IsChildAgent; 3582 isChildAgent = avatar.IsChildAgent;
3581 3583
3582 m_log.DebugFormat( 3584 m_log.DebugFormat(
3583 "[SCENE]: Removing {0} agent {1} {2} from {3}", 3585 "[SCENE]: Removing {0} agent {1} {2} from {3}",
3584 (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName); 3586 isChildAgent ? "child" : "root", avatar.Name, agentID, Name);
3585 3587
3586 // Don't do this to root agents, it's not nice for the viewer 3588 // Don't do this to root agents, it's not nice for the viewer
3587 if (closeChildAgents && isChildAgent) 3589 if (closeChildAgents && isChildAgent)
@@ -3745,13 +3747,13 @@ namespace OpenSim.Region.Framework.Scenes
3745 /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of 3747 /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of
3746 /// the LLUDP stack). 3748 /// the LLUDP stack).
3747 /// </remarks> 3749 /// </remarks>
3748 /// <param name="agent">CircuitData of the agent who is connecting</param> 3750 /// <param name="acd">CircuitData of the agent who is connecting</param>
3749 /// <param name="reason">Outputs the reason for the false response on this string</param> 3751 /// <param name="reason">Outputs the reason for the false response on this string</param>
3750 /// <param name="requirePresenceLookup">True for normal presence. False for NPC 3752 /// <param name="requirePresenceLookup">True for normal presence. False for NPC
3751 /// or other applications where a full grid/Hypergrid presence may not be required.</param> 3753 /// or other applications where a full grid/Hypergrid presence may not be required.</param>
3752 /// <returns>True if the region accepts this agent. False if it does not. False will 3754 /// <returns>True if the region accepts this agent. False if it does not. False will
3753 /// also return a reason.</returns> 3755 /// also return a reason.</returns>
3754 public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, out string reason, bool requirePresenceLookup) 3756 public bool NewUserConnection(AgentCircuitData acd, uint teleportFlags, out string reason, bool requirePresenceLookup)
3755 { 3757 {
3756 bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 || 3758 bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 ||
3757 (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0); 3759 (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0);
@@ -3771,15 +3773,15 @@ namespace OpenSim.Region.Framework.Scenes
3771 m_log.DebugFormat( 3773 m_log.DebugFormat(
3772 "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})", 3774 "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})",
3773 RegionInfo.RegionName, 3775 RegionInfo.RegionName,
3774 (agent.child ? "child" : "root"), 3776 (acd.child ? "child" : "root"),
3775 agent.firstname, 3777 acd.firstname,
3776 agent.lastname, 3778 acd.lastname,
3777 agent.AgentID, 3779 acd.AgentID,
3778 agent.circuitcode, 3780 acd.circuitcode,
3779 agent.IPAddress, 3781 acd.IPAddress,
3780 agent.Viewer, 3782 acd.Viewer,
3781 ((TPFlags)teleportFlags).ToString(), 3783 ((TPFlags)teleportFlags).ToString(),
3782 agent.startpos 3784 acd.startpos
3783 ); 3785 );
3784 3786
3785 if (!LoginsEnabled) 3787 if (!LoginsEnabled)
@@ -3797,7 +3799,7 @@ namespace OpenSim.Region.Framework.Scenes
3797 { 3799 {
3798 foreach (string viewer in m_AllowedViewers) 3800 foreach (string viewer in m_AllowedViewers)
3799 { 3801 {
3800 if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) 3802 if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower())
3801 { 3803 {
3802 ViewerDenied = false; 3804 ViewerDenied = false;
3803 break; 3805 break;
@@ -3814,7 +3816,7 @@ namespace OpenSim.Region.Framework.Scenes
3814 { 3816 {
3815 foreach (string viewer in m_BannedViewers) 3817 foreach (string viewer in m_BannedViewers)
3816 { 3818 {
3817 if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) 3819 if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower())
3818 { 3820 {
3819 ViewerDenied = true; 3821 ViewerDenied = true;
3820 break; 3822 break;
@@ -3826,61 +3828,115 @@ namespace OpenSim.Region.Framework.Scenes
3826 { 3828 {
3827 m_log.DebugFormat( 3829 m_log.DebugFormat(
3828 "[SCENE]: Access denied for {0} {1} using {2}", 3830 "[SCENE]: Access denied for {0} {1} using {2}",
3829 agent.firstname, agent.lastname, agent.Viewer); 3831 acd.firstname, acd.lastname, acd.Viewer);
3830 reason = "Access denied, your viewer is banned by the region owner"; 3832 reason = "Access denied, your viewer is banned by the region owner";
3831 return false; 3833 return false;
3832 } 3834 }
3835
3836 ILandObject land;
3837 ScenePresence sp;
3833 3838
3834 lock (agent) 3839 lock (m_removeClientLock)
3835 { 3840 {
3836 ScenePresence sp = GetScenePresence(agent.AgentID); 3841 sp = GetScenePresence(acd.AgentID);
3837 3842
3838 if (sp != null) 3843 // We need to ensure that we are not already removing the scene presence before we ask it not to be
3844 // closed.
3845 if (sp != null && sp.IsChildAgent && sp.LifecycleState == ScenePresenceState.Running)
3839 { 3846 {
3840 if (!sp.IsChildAgent) 3847 m_log.DebugFormat(
3841 { 3848 "[SCENE]: Reusing existing child scene presence for {0} in {1}", sp.Name, Name);
3842 // We have a root agent. Is it in transit?
3843 if (!EntityTransferModule.IsInTransit(sp.UUID))
3844 {
3845 // We have a zombie from a crashed session.
3846 // Or the same user is trying to be root twice here, won't work.
3847 // Kill it.
3848 m_log.WarnFormat(
3849 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
3850 sp.Name, sp.UUID, RegionInfo.RegionName);
3851 3849
3852 if (sp.ControllingClient != null) 3850 // In the case where, for example, an A B C D region layout, an avatar may
3853 sp.ControllingClient.Close(true, true); 3851 // teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C
3852 // renews the lease on the child agent at B, we must make sure that the close from A does not succeed.
3853 if (!acd.ChildrenCapSeeds.ContainsKey(RegionInfo.RegionHandle))
3854 {
3855 m_log.DebugFormat(
3856 "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.",
3857 sp.Name, Name);
3854 3858
3855 sp = null; 3859 sp.DoNotCloseAfterTeleport = true;
3856 }
3857 //else
3858 // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName);
3859 } 3860 }
3860 else 3861 else if (EntityTransferModule.IsInTransit(sp.UUID))
3861 { 3862 {
3862 // We have a child agent here 3863 m_log.DebugFormat(
3864 "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because this region will attempt previous end-of-teleport close.",
3865 sp.Name, Name);
3866
3863 sp.DoNotCloseAfterTeleport = true; 3867 sp.DoNotCloseAfterTeleport = true;
3864 //m_log.WarnFormat("[SCENE]: Existing child scene presence for {0} {1} in {2}", sp.Name, sp.UUID, RegionInfo.RegionName);
3865 } 3868 }
3866 } 3869 }
3870 }
3871
3872 // Need to poll here in case we are currently deleting an sp. Letting threads run over each other will
3873 // allow unpredictable things to happen.
3874 if (sp != null)
3875 {
3876 const int polls = 10;
3877 const int pollInterval = 1000;
3878 int pollsLeft = polls;
3879
3880 while (sp.LifecycleState == ScenePresenceState.Removing && pollsLeft-- > 0)
3881 Thread.Sleep(pollInterval);
3882
3883 if (sp.LifecycleState == ScenePresenceState.Removing)
3884 {
3885 m_log.WarnFormat(
3886 "[SCENE]: Agent {0} in {1} was still being removed after {2}s. Aborting NewUserConnection.",
3887 sp.Name, Name, polls * pollInterval / 1000);
3888
3889 return false;
3890 }
3891 else if (polls != pollsLeft)
3892 {
3893 m_log.DebugFormat(
3894 "[SCENE]: NewUserConnection for agent {0} in {1} had to wait {2}s for in-progress removal to complete on an old presence.",
3895 sp.Name, Name, polls * pollInterval / 1000);
3896 }
3897 }
3898
3899 // TODO: can we remove this lock?
3900 lock (acd)
3901 {
3902 if (sp != null && !sp.IsChildAgent)
3903 {
3904 // We have a root agent. Is it in transit?
3905 if (!EntityTransferModule.IsInTransit(sp.UUID))
3906 {
3907 // We have a zombie from a crashed session.
3908 // Or the same user is trying to be root twice here, won't work.
3909 // Kill it.
3910 m_log.WarnFormat(
3911 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
3912 sp.Name, sp.UUID, RegionInfo.RegionName);
3913
3914 if (sp.ControllingClient != null)
3915 IncomingCloseAgent(sp.UUID, true);
3916
3917 sp = null;
3918 }
3919 //else
3920 // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName);
3921 }
3867 3922
3868 // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags. 3923 // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags.
3869 // We need the circuit data here for some of the subsequent checks. (groups, for example) 3924 // We need the circuit data here for some of the subsequent checks. (groups, for example)
3870 // If the checks fail, we remove the circuit. 3925 // If the checks fail, we remove the circuit.
3871 agent.teleportFlags = teleportFlags; 3926 acd.teleportFlags = teleportFlags;
3872 m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); 3927 m_authenticateHandler.AddNewCircuit(acd.circuitcode, acd);
3873 3928
3929 land = LandChannel.GetLandObject(acd.startpos.X, acd.startpos.Y);
3930
3874 // On login test land permisions 3931 // On login test land permisions
3875 if (vialogin) 3932 if (vialogin)
3876 { 3933 {
3877 IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>(); 3934 IUserAccountCacheModule cache = RequestModuleInterface<IUserAccountCacheModule>();
3878 if (cache != null) 3935 if (cache != null)
3879 cache.Remove(agent.firstname + " " + agent.lastname); 3936 cache.Remove(acd.firstname + " " + acd.lastname);
3880 if (!TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y)) 3937 if (land != null && !TestLandRestrictions(acd.AgentID, out reason, ref acd.startpos.X, ref acd.startpos.Y))
3881 { 3938 {
3882 m_log.DebugFormat("[CONNECTION BEGIN]: Denying access to {0} due to no land access", agent.AgentID.ToString()); 3939 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3883 m_authenticateHandler.RemoveCircuit(agent.circuitcode);
3884 return false; 3940 return false;
3885 } 3941 }
3886 } 3942 }
@@ -3891,9 +3947,9 @@ namespace OpenSim.Region.Framework.Scenes
3891 { 3947 {
3892 try 3948 try
3893 { 3949 {
3894 if (!VerifyUserPresence(agent, out reason)) 3950 if (!VerifyUserPresence(acd, out reason))
3895 { 3951 {
3896 m_authenticateHandler.RemoveCircuit(agent.circuitcode); 3952 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3897 return false; 3953 return false;
3898 } 3954 }
3899 } 3955 }
@@ -3902,16 +3958,16 @@ namespace OpenSim.Region.Framework.Scenes
3902 m_log.ErrorFormat( 3958 m_log.ErrorFormat(
3903 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); 3959 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
3904 3960
3905 m_authenticateHandler.RemoveCircuit(agent.circuitcode); 3961 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3906 return false; 3962 return false;
3907 } 3963 }
3908 } 3964 }
3909 3965
3910 try 3966 try
3911 { 3967 {
3912 if (!AuthorizeUser(agent, SeeIntoRegion, out reason)) 3968 if (!AuthorizeUser(acd, SeeIntoRegion, out reason))
3913 { 3969 {
3914 m_authenticateHandler.RemoveCircuit(agent.circuitcode); 3970 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3915 return false; 3971 return false;
3916 } 3972 }
3917 } 3973 }
@@ -3920,15 +3976,20 @@ namespace OpenSim.Region.Framework.Scenes
3920 m_log.ErrorFormat( 3976 m_log.ErrorFormat(
3921 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); 3977 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
3922 3978
3923 m_authenticateHandler.RemoveCircuit(agent.circuitcode); 3979 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3924 return false; 3980 return false;
3925 } 3981 }
3926 3982
3927 m_log.InfoFormat( 3983 m_log.InfoFormat(
3928 "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})", 3984 "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
3929 RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname, 3985 Name, (acd.child ? "child" : "root"), acd.firstname, acd.lastname,
3930 agent.AgentID, agent.circuitcode); 3986 acd.AgentID, acd.circuitcode);
3931 3987
3988 if (CapsModule != null)
3989 {
3990 CapsModule.SetAgentCapsSeeds(acd);
3991 CapsModule.CreateCaps(acd.AgentID, acd.circuitcode);
3992 }
3932 } 3993 }
3933 else 3994 else
3934 { 3995 {
@@ -3940,14 +4001,14 @@ namespace OpenSim.Region.Framework.Scenes
3940 { 4001 {
3941 m_log.DebugFormat( 4002 m_log.DebugFormat(
3942 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}", 4003 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
3943 agent.AgentID, RegionInfo.RegionName); 4004 acd.AgentID, RegionInfo.RegionName);
3944 4005
3945 sp.AdjustKnownSeeds(); 4006 sp.AdjustKnownSeeds();
3946 4007
3947 if (CapsModule != null) 4008 if (CapsModule != null)
3948 { 4009 {
3949 CapsModule.SetAgentCapsSeeds(agent); 4010 CapsModule.SetAgentCapsSeeds(acd);
3950 CapsModule.CreateCaps(agent.AgentID, agent.circuitcode); 4011 CapsModule.CreateCaps(acd.AgentID, acd.circuitcode);
3951 } 4012 }
3952 } 4013 }
3953 } 4014 }
@@ -3955,28 +4016,28 @@ namespace OpenSim.Region.Framework.Scenes
3955 // Try caching an incoming user name much earlier on to see if this helps with an issue 4016 // Try caching an incoming user name much earlier on to see if this helps with an issue
3956 // where HG users are occasionally seen by others as "Unknown User" because their UUIDName 4017 // where HG users are occasionally seen by others as "Unknown User" because their UUIDName
3957 // request for the HG avatar appears to trigger before the user name is cached. 4018 // request for the HG avatar appears to trigger before the user name is cached.
3958 CacheUserName(null, agent); 4019 CacheUserName(null, acd);
3959 } 4020 }
3960 4021
3961 if (CapsModule != null) 4022 if (CapsModule != null)
3962 { 4023 {
3963 CapsModule.ActivateCaps(agent.circuitcode); 4024 CapsModule.ActivateCaps(acd.circuitcode);
3964 } 4025 }
3965 4026
3966 if (vialogin) 4027 if (vialogin)
3967 { 4028 {
3968// CleanDroppedAttachments(); 4029// CleanDroppedAttachments();
3969 4030
3970 if (TestBorderCross(agent.startpos, Cardinals.E)) 4031 if (TestBorderCross(acd.startpos, Cardinals.E))
3971 { 4032 {
3972 Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.E); 4033 Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.E);
3973 agent.startpos.X = crossedBorder.BorderLine.Z - 1; 4034 acd.startpos.X = crossedBorder.BorderLine.Z - 1;
3974 } 4035 }
3975 4036
3976 if (TestBorderCross(agent.startpos, Cardinals.N)) 4037 if (TestBorderCross(acd.startpos, Cardinals.N))
3977 { 4038 {
3978 Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.N); 4039 Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.N);
3979 agent.startpos.Y = crossedBorder.BorderLine.Z - 1; 4040 acd.startpos.Y = crossedBorder.BorderLine.Z - 1;
3980 } 4041 }
3981 4042
3982 //Mitigate http://opensimulator.org/mantis/view.php?id=3522 4043 //Mitigate http://opensimulator.org/mantis/view.php?id=3522
@@ -3986,39 +4047,39 @@ namespace OpenSim.Region.Framework.Scenes
3986 { 4047 {
3987 lock (EastBorders) 4048 lock (EastBorders)
3988 { 4049 {
3989 if (agent.startpos.X > EastBorders[0].BorderLine.Z) 4050 if (acd.startpos.X > EastBorders[0].BorderLine.Z)
3990 { 4051 {
3991 m_log.Warn("FIX AGENT POSITION"); 4052 m_log.Warn("FIX AGENT POSITION");
3992 agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; 4053 acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
3993 if (agent.startpos.Z > 720) 4054 if (acd.startpos.Z > 720)
3994 agent.startpos.Z = 720; 4055 acd.startpos.Z = 720;
3995 } 4056 }
3996 } 4057 }
3997 lock (NorthBorders) 4058 lock (NorthBorders)
3998 { 4059 {
3999 if (agent.startpos.Y > NorthBorders[0].BorderLine.Z) 4060 if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
4000 { 4061 {
4001 m_log.Warn("FIX Agent POSITION"); 4062 m_log.Warn("FIX Agent POSITION");
4002 agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; 4063 acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
4003 if (agent.startpos.Z > 720) 4064 if (acd.startpos.Z > 720)
4004 agent.startpos.Z = 720; 4065 acd.startpos.Z = 720;
4005 } 4066 }
4006 } 4067 }
4007 } else 4068 } else
4008 { 4069 {
4009 if (agent.startpos.X > EastBorders[0].BorderLine.Z) 4070 if (acd.startpos.X > EastBorders[0].BorderLine.Z)
4010 { 4071 {
4011 m_log.Warn("FIX AGENT POSITION"); 4072 m_log.Warn("FIX AGENT POSITION");
4012 agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; 4073 acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
4013 if (agent.startpos.Z > 720) 4074 if (acd.startpos.Z > 720)
4014 agent.startpos.Z = 720; 4075 acd.startpos.Z = 720;
4015 } 4076 }
4016 if (agent.startpos.Y > NorthBorders[0].BorderLine.Z) 4077 if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
4017 { 4078 {
4018 m_log.Warn("FIX Agent POSITION"); 4079 m_log.Warn("FIX Agent POSITION");
4019 agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; 4080 acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
4020 if (agent.startpos.Z > 720) 4081 if (acd.startpos.Z > 720)
4021 agent.startpos.Z = 720; 4082 acd.startpos.Z = 720;
4022 } 4083 }
4023 } 4084 }
4024 4085
@@ -4034,12 +4095,12 @@ namespace OpenSim.Region.Framework.Scenes
4034 { 4095 {
4035 // We have multiple SpawnPoints, Route the agent to a random or sequential one 4096 // We have multiple SpawnPoints, Route the agent to a random or sequential one
4036 if (SpawnPointRouting == "random") 4097 if (SpawnPointRouting == "random")
4037 agent.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation( 4098 acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation(
4038 telehub.AbsolutePosition, 4099 telehub.AbsolutePosition,
4039 telehub.GroupRotation 4100 telehub.GroupRotation
4040 ); 4101 );
4041 else 4102 else
4042 agent.startpos = spawnpoints[SpawnPoint()].GetLocation( 4103 acd.startpos = spawnpoints[SpawnPoint()].GetLocation(
4043 telehub.AbsolutePosition, 4104 telehub.AbsolutePosition,
4044 telehub.GroupRotation 4105 telehub.GroupRotation
4045 ); 4106 );
@@ -4047,7 +4108,7 @@ namespace OpenSim.Region.Framework.Scenes
4047 else 4108 else
4048 { 4109 {
4049 // We have a single SpawnPoint and will route the agent to it 4110 // We have a single SpawnPoint and will route the agent to it
4050 agent.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); 4111 acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
4051 } 4112 }
4052 4113
4053 return true; 4114 return true;
@@ -4060,7 +4121,7 @@ namespace OpenSim.Region.Framework.Scenes
4060 { 4121 {
4061 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) 4122 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero)
4062 { 4123 {
4063 agent.startpos = land.LandData.UserLocation; 4124 acd.startpos = land.LandData.UserLocation;
4064 } 4125 }
4065 } 4126 }
4066 */// This is now handled properly in ScenePresence.MakeRootAgent 4127 */// This is now handled properly in ScenePresence.MakeRootAgent
@@ -4444,24 +4505,25 @@ namespace OpenSim.Region.Framework.Scenes
4444 ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID); 4505 ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID);
4445 if (childAgentUpdate != null) 4506 if (childAgentUpdate != null)
4446 { 4507 {
4447 if (childAgentUpdate.ControllingClient.SessionId == cAgentData.SessionID) 4508 if (childAgentUpdate.ControllingClient.SessionId != cAgentData.SessionID)
4509 // Only warn for now
4510 m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}. Neighbor running older version?",
4511 childAgentUpdate.UUID, cAgentData.SessionID);
4512
4513 // I can't imagine *yet* why we would get an update if the agent is a root agent..
4514 // however to avoid a race condition crossing borders..
4515 if (childAgentUpdate.IsChildAgent)
4448 { 4516 {
4449 // I can't imagine *yet* why we would get an update if the agent is a root agent.. 4517 uint rRegionX = (uint)(cAgentData.RegionHandle >> 40);
4450 // however to avoid a race condition crossing borders.. 4518 uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8);
4451 if (childAgentUpdate.IsChildAgent) 4519 uint tRegionX = RegionInfo.RegionLocX;
4452 { 4520 uint tRegionY = RegionInfo.RegionLocY;
4453 uint rRegionX = (uint)(cAgentData.RegionHandle >> 40); 4521 //Send Data to ScenePresence
4454 uint rRegionY = (((uint)(cAgentData.RegionHandle)) >> 8); 4522 childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY);
4455 uint tRegionX = RegionInfo.RegionLocX; 4523 // Not Implemented:
4456 uint tRegionY = RegionInfo.RegionLocY; 4524 //TODO: Do we need to pass the message on to one of our neighbors?
4457 //Send Data to ScenePresence
4458 childAgentUpdate.ChildAgentDataUpdate(cAgentData, tRegionX, tRegionY, rRegionX, rRegionY);
4459 // Not Implemented:
4460 //TODO: Do we need to pass the message on to one of our neighbors?
4461 }
4462 } 4525 }
4463 else 4526
4464 m_log.WarnFormat("[SCENE]: Attempt at updating position of agent {0} with invalid session id {1}", childAgentUpdate.UUID, cAgentData.SessionID);
4465 return true; 4527 return true;
4466 } 4528 }
4467 4529
@@ -4540,11 +4602,51 @@ namespace OpenSim.Region.Framework.Scenes
4540 /// </param> 4602 /// </param>
4541 public bool IncomingCloseAgent(UUID agentID, bool force) 4603 public bool IncomingCloseAgent(UUID agentID, bool force)
4542 { 4604 {
4543 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); 4605 ScenePresence sp;
4544 ScenePresence presence = m_sceneGraph.GetScenePresence(agentID); 4606
4545 if (presence != null) 4607 lock (m_removeClientLock)
4608 {
4609 sp = GetScenePresence(agentID);
4610
4611 if (sp == null)
4612 {
4613 m_log.DebugFormat(
4614 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in {1}",
4615 agentID, Name);
4616
4617 return false;
4618 }
4619
4620 if (sp.LifecycleState != ScenePresenceState.Running)
4621 {
4622 m_log.DebugFormat(
4623 "[SCENE]: Called RemoveClient() for {0} in {1} but presence is already in state {2}",
4624 sp.Name, Name, sp.LifecycleState);
4625
4626 return false;
4627 }
4628
4629 // We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may
4630 // teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not
4631 // want to obey this close since C may have renewed the child agent lease on B.
4632 if (sp.DoNotCloseAfterTeleport)
4633 {
4634 m_log.DebugFormat(
4635 "[SCENE]: Not closing {0} agent {1} in {2} since another simulator has re-established the child connection",
4636 sp.IsChildAgent ? "child" : "root", sp.Name, Name);
4637
4638 // Need to reset the flag so that a subsequent close after another teleport can succeed.
4639 sp.DoNotCloseAfterTeleport = false;
4640
4641 return false;
4642 }
4643
4644 sp.LifecycleState = ScenePresenceState.Removing;
4645 }
4646
4647 if (sp != null)
4546 { 4648 {
4547 presence.ControllingClient.Close(force, force); 4649 sp.ControllingClient.Close(force, force);
4548 return true; 4650 return true;
4549 } 4651 }
4550 4652
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 48bf6f3..5301a82 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -75,6 +75,8 @@ namespace OpenSim.Region.Framework.Scenes
75 75
76 public class ScenePresence : EntityBase, IScenePresence 76 public class ScenePresence : EntityBase, IScenePresence
77 { 77 {
78 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
79
78// ~ScenePresence() 80// ~ScenePresence()
79// { 81// {
80// m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name); 82// m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name);
@@ -86,10 +88,27 @@ namespace OpenSim.Region.Framework.Scenes
86 m_scene.EventManager.TriggerScenePresenceUpdated(this); 88 m_scene.EventManager.TriggerScenePresenceUpdated(this);
87 } 89 }
88 90
89 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
90
91 public PresenceType PresenceType { get; private set; } 91 public PresenceType PresenceType { get; private set; }
92 92
93 private ScenePresenceStateMachine m_stateMachine;
94
95 /// <summary>
96 /// The current state of this presence. Governs only the existence lifecycle. See ScenePresenceStateMachine
97 /// for more details.
98 /// </summary>
99 public ScenePresenceState LifecycleState
100 {
101 get
102 {
103 return m_stateMachine.GetState();
104 }
105
106 set
107 {
108 m_stateMachine.SetState(value);
109 }
110 }
111
93// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); 112// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes();
94 private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); 113 private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags));
95 private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); 114 private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f);
@@ -299,9 +318,9 @@ namespace OpenSim.Region.Framework.Scenes
299 /// <summary> 318 /// <summary>
300 /// In the V1 teleport protocol, the destination simulator sends ReleaseAgent to this address. 319 /// In the V1 teleport protocol, the destination simulator sends ReleaseAgent to this address.
301 /// </summary> 320 /// </summary>
302 string m_callbackURI; 321 private string m_callbackURI;
303 322
304 UUID m_originRegionID; 323 public UUID m_originRegionID;
305 324
306 /// <summary> 325 /// <summary>
307 /// Used by the entity transfer module to signal when the presence should not be closed because a subsequent 326 /// Used by the entity transfer module to signal when the presence should not be closed because a subsequent
@@ -813,7 +832,7 @@ namespace OpenSim.Region.Framework.Scenes
813 832
814 public ScenePresence( 833 public ScenePresence(
815 IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type) 834 IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type)
816 { 835 {
817 AttachmentsSyncLock = new Object(); 836 AttachmentsSyncLock = new Object();
818 AllowMovement = true; 837 AllowMovement = true;
819 IsChildAgent = true; 838 IsChildAgent = true;
@@ -859,6 +878,8 @@ namespace OpenSim.Region.Framework.Scenes
859 SetDirectionVectors(); 878 SetDirectionVectors();
860 879
861 Appearance = appearance; 880 Appearance = appearance;
881
882 m_stateMachine = new ScenePresenceStateMachine(this);
862 } 883 }
863 884
864 private void RegionHeartbeatEnd(Scene scene) 885 private void RegionHeartbeatEnd(Scene scene)
@@ -956,7 +977,7 @@ namespace OpenSim.Region.Framework.Scenes
956 /// </summary> 977 /// </summary>
957 public void MakeRootAgent(Vector3 pos, bool isFlying) 978 public void MakeRootAgent(Vector3 pos, bool isFlying)
958 { 979 {
959 m_log.DebugFormat( 980 m_log.InfoFormat(
960 "[SCENE]: Upgrading child to root agent for {0} in {1}", 981 "[SCENE]: Upgrading child to root agent for {0} in {1}",
961 Name, m_scene.RegionInfo.RegionName); 982 Name, m_scene.RegionInfo.RegionName);
962 983
@@ -996,6 +1017,11 @@ namespace OpenSim.Region.Framework.Scenes
996 1017
997 IsChildAgent = false; 1018 IsChildAgent = false;
998 1019
1020 // Must reset this here so that a teleport to a region next to an existing region does not keep the flag
1021 // set and prevent the close of the connection on a subsequent re-teleport.
1022 // Should not be needed if we are not trying to tell this region to close
1023// DoNotCloseAfterTeleport = false;
1024
999 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); 1025 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
1000 if (gm != null) 1026 if (gm != null)
1001 Grouptitle = gm.GetGroupTitle(m_uuid); 1027 Grouptitle = gm.GetGroupTitle(m_uuid);
@@ -1520,7 +1546,7 @@ namespace OpenSim.Region.Framework.Scenes
1520 private bool WaitForUpdateAgent(IClientAPI client) 1546 private bool WaitForUpdateAgent(IClientAPI client)
1521 { 1547 {
1522 // Before UpdateAgent, m_originRegionID is UUID.Zero; after, it's non-Zero 1548 // Before UpdateAgent, m_originRegionID is UUID.Zero; after, it's non-Zero
1523 int count = 20; 1549 int count = 50;
1524 while (m_originRegionID.Equals(UUID.Zero) && count-- > 0) 1550 while (m_originRegionID.Equals(UUID.Zero) && count-- > 0)
1525 { 1551 {
1526 m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.Name); 1552 m_log.DebugFormat("[SCENE PRESENCE]: Agent {0} waiting for update in {1}", client.Name, Scene.Name);
@@ -3994,6 +4020,7 @@ namespace OpenSim.Region.Framework.Scenes
3994// Animator.Close(); 4020// Animator.Close();
3995 Animator = null; 4021 Animator = null;
3996 4022
4023 LifecycleState = ScenePresenceState.Removed;
3997 } 4024 }
3998 4025
3999 public void AddAttachment(SceneObjectGroup gobj) 4026 public void AddAttachment(SceneObjectGroup gobj)
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs b/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs
new file mode 100644
index 0000000..dc3a212
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs
@@ -0,0 +1,102 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29
30namespace OpenSim.Region.Framework.Scenes
31{
32 /// <summary>
33 /// The possible states that a scene presence can be in. This is currently orthagonal to whether a scene presence
34 /// is root or child.
35 /// </summary>
36 /// <remarks>
37 /// This is a state machine.
38 ///
39 /// [Entry] => Running
40 /// Running => Removing
41 /// Removing => Removed
42 ///
43 /// All other methods should only see the scene presence in running state - this is the normal operational state
44 /// Removed state occurs when the presence has been removed. This is the end state with no exit.
45 /// </remarks>
46 public enum ScenePresenceState
47 {
48 Running, // Normal operation state. The scene presence is available.
49 Removing, // The presence is in the process of being removed from the scene via Scene.RemoveClient.
50 Removed, // The presence has been removed from the scene and is effectively dead.
51 // There is no exit from this state.
52 }
53
54 internal class ScenePresenceStateMachine
55 {
56 private ScenePresence m_sp;
57 private ScenePresenceState m_state;
58
59 internal ScenePresenceStateMachine(ScenePresence sp)
60 {
61 m_sp = sp;
62 m_state = ScenePresenceState.Running;
63 }
64
65 internal ScenePresenceState GetState()
66 {
67 return m_state;
68 }
69
70 /// <summary>
71 /// Updates the state of an agent that is already in transit.
72 /// </summary>
73 /// <param name='id'></param>
74 /// <param name='newState'></param>
75 /// <returns></returns>
76 /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception>
77 internal void SetState(ScenePresenceState newState)
78 {
79 bool transitionOkay = false;
80
81 lock (this)
82 {
83 if (newState == ScenePresenceState.Removing && m_state == ScenePresenceState.Running)
84 transitionOkay = true;
85 else if (newState == ScenePresenceState.Removed && m_state == ScenePresenceState.Removing)
86 transitionOkay = true;
87 }
88
89 if (!transitionOkay)
90 {
91 throw new Exception(
92 string.Format(
93 "Scene presence {0} is not allowed to move from state {1} to new state {2} in {3}",
94 m_sp.Name, m_state, newState, m_sp.Scene.Name));
95 }
96 else
97 {
98 m_state = newState;
99 }
100 }
101 }
102} \ No newline at end of file