diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index e19608e7cf..07e73f0403 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -177,13 +177,24 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) return; - // Reset animations; the viewer does that in teleports. - sp.Animator.ResetAnimations(); - string destinationRegionName = "(not found)"; + // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection + // of whether the destination region completes the teleport. + if (!m_entityTransferStateMachine.SetInTransit(sp.UUID)) + { + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2}@{3} - agent is already in transit.", + sp.Name, sp.UUID, position, regionHandle); + + return; + } + try { + // Reset animations; the viewer does that in teleports. + sp.Animator.ResetAnimations(); + if (regionHandle == sp.Scene.RegionInfo.RegionHandle) { destinationRegionName = sp.Scene.RegionInfo.RegionName; @@ -192,12 +203,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } else // Another region possibly in another simulator { - GridRegion finalDestination; - TeleportAgentToDifferentRegion( - sp, regionHandle, position, lookAt, teleportFlags, out finalDestination); - - if (finalDestination != null) - destinationRegionName = finalDestination.RegionName; + GridRegion finalDestination = null; + try + { + TeleportAgentToDifferentRegion( + sp, regionHandle, position, lookAt, teleportFlags, out finalDestination); + } + finally + { + if (finalDestination != null) + destinationRegionName = finalDestination.RegionName; + } } } catch (Exception e) @@ -207,11 +223,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName, e.Message, e.StackTrace); - // Make sure that we clear the in-transit flag so that future teleport attempts don't always fail. - m_entityTransferStateMachine.ResetFromTransit(sp.UUID); - sp.ControllingClient.SendTeleportFailed("Internal error"); } + finally + { + m_entityTransferStateMachine.ResetFromTransit(sp.UUID); + } } /// @@ -227,15 +244,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}", sp.Name, position, sp.Scene.RegionInfo.RegionName); - if (!m_entityTransferStateMachine.SetInTransit(sp.UUID)) - { - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Ignoring within region teleport request of {0} {1} to {2} - agent is already in transit.", - sp.Name, sp.UUID, position); - - return; - } - // Teleport within the same region if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) { @@ -280,7 +288,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); - m_entityTransferStateMachine.ResetFromTransit(sp.UUID); } /// @@ -326,7 +333,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // // This is it // - DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags); + DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags); // // // @@ -374,6 +381,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance; } + /// + /// Wraps DoTeleportInternal() and manages the transfer state. + /// public void DoTeleport( ScenePresence sp, GridRegion reg, GridRegion finalDestination, Vector3 position, Vector3 lookAt, uint teleportFlags) @@ -388,12 +398,37 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return; } + + try + { + DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}", + sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, finalDestination.RegionName, + e.Message, e.StackTrace); + sp.ControllingClient.SendTeleportFailed("Internal error"); + } + finally + { + m_entityTransferStateMachine.ResetFromTransit(sp.UUID); + } + } + + /// + /// Teleports the agent to another region. + /// This method doesn't manage the transfer state; the caller must do that. + /// + private void DoTeleportInternal( + ScenePresence sp, GridRegion reg, GridRegion finalDestination, + Vector3 position, Vector3 lookAt, uint teleportFlags) + { if (reg == null || finalDestination == null) { sp.ControllingClient.SendTeleportFailed("Unable to locate destination"); - m_entityTransferStateMachine.ResetFromTransit(sp.UUID); - return; } @@ -413,8 +448,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, MaxTransferDistance)); - m_entityTransferStateMachine.ResetFromTransit(sp.UUID); - return; } @@ -433,7 +466,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (endPoint.Address == null) { sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); - m_entityTransferStateMachine.ResetFromTransit(sp.UUID); return; } @@ -455,7 +487,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) { sp.ControllingClient.SendTeleportFailed(reason); - m_entityTransferStateMachine.ResetFromTransit(sp.UUID); m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", @@ -511,7 +542,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) { sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); - m_entityTransferStateMachine.ResetFromTransit(sp.UUID); m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}", @@ -612,7 +642,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); - Fail(sp, finalDestination, logout); + Fail(sp, finalDestination, logout); return; } @@ -665,8 +695,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed", // sp.UUID); // } - - m_entityTransferStateMachine.ResetFromTransit(sp.UUID); } protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout) @@ -686,8 +714,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); - - m_entityTransferStateMachine.ResetFromTransit(sp.UUID); } protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) @@ -1104,16 +1130,24 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (neighbourRegion == null) return agent; + if (!m_entityTransferStateMachine.SetInTransit(agent.UUID)) + { + m_log.ErrorFormat( + "[ENTITY TRANSFER MODULE]: Problem crossing user {0} to new region {1} from {2} - agent is already in transit", + agent.Name, neighbourRegion.RegionName, agent.Scene.RegionInfo.RegionName); + return agent; + } + + bool transitWasReset = false; + try { - m_entityTransferStateMachine.SetInTransit(agent.UUID); - ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize)); - + m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} to {2}-{3} running version {4}", agent.Firstname, agent.Lastname, neighbourx, neighboury, version); - + Scene m_scene = agent.Scene; if (!agent.ValidateAttachments()) @@ -1126,7 +1160,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer agent.RemoveFromPhysicalScene(); - AgentData cAgent = new AgentData(); + AgentData cAgent = new AgentData(); agent.CopyTo(cAgent); cAgent.Position = pos; if (isFlying) @@ -1145,7 +1179,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer ReInstantiateScripts(agent); agent.AddToPhysicalScene(isFlying); - m_entityTransferStateMachine.ResetFromTransit(agent.UUID); return agent; } @@ -1193,6 +1226,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // FIXME: Possibly this should occur lower down after other commands to close other agents, // but not sure yet what the side effects would be. m_entityTransferStateMachine.ResetFromTransit(agent.UUID); + transitWasReset = true; // now we have a child agent in this region. Request all interesting data about other (root) agents agent.SendOtherAgentsAvatarDataToMe(); @@ -1232,6 +1266,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // TODO: Might be worth attempting other restoration here such as reinstantiation of scripts, etc. } + finally + { + if (!transitWasReset) + m_entityTransferStateMachine.ResetFromTransit(agent.UUID); + } return agent; } @@ -2054,4 +2093,4 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer #endregion } -} \ No newline at end of file +}