diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/Scene.cs | 362 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/ScenePresence.cs | 41 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/ScenePresenceStateMachine.cs | 102 |
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 | |||
28 | using System; | ||
29 | |||
30 | namespace 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 | ||