diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs index 221f02bda9..5fcf376b84 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs @@ -79,7 +79,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests J2KDecoderModule j2kdm = new J2KDecoderModule(); - scene = new SceneHelpers().SetupScene(); + SceneHelpers sceneHelpers = new SceneHelpers(); + scene = sceneHelpers.SetupScene(); SceneHelpers.SetupSceneModules(scene, j2kdm); tc = new TestClient(SceneHelpers.GenerateAgentData(userId), scene); diff --git a/OpenSim/Region/ClientStack/RegionApplicationBase.cs b/OpenSim/Region/ClientStack/RegionApplicationBase.cs index 6e3a58e63a..6e78d6d774 100644 --- a/OpenSim/Region/ClientStack/RegionApplicationBase.cs +++ b/OpenSim/Region/ClientStack/RegionApplicationBase.cs @@ -111,7 +111,7 @@ namespace OpenSim.Region.ClientStack server.Start(); } } - + base.StartupSpecific(); } diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs index bc5c1ff2c2..92cf9d1616 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs @@ -240,13 +240,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure { ScenePresence sp = scene.GetScenePresence(client.AgentId); IEntityTransferModule transferMod = scene.RequestModuleInterface(); - IEventQueue eq = sp.Scene.RequestModuleInterface(); - if (transferMod != null && sp != null && eq != null) - transferMod.DoTeleport(sp, gatekeeper, finalDestination, im.Position + new Vector3(0.5f, 0.5f, 0f), Vector3.UnitX, teleportflags, eq); + + if (transferMod != null && sp != null) + transferMod.DoTeleport( + sp, gatekeeper, finalDestination, im.Position + new Vector3(0.5f, 0.5f, 0f), + Vector3.UnitX, teleportflags); } } } } } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 07ea35e131..a31e0aab47 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -51,15 +51,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public const int DefaultMaxTransferDistance = 4095; + public const bool EnableWaitForCallbackFromTeleportDestDefault = true; + + /// /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer. /// - private int m_MaxTransferDistance = 4095; - public int MaxTransferDistance - { - get { return m_MaxTransferDistance; } - set { m_MaxTransferDistance = value; } - } + public int MaxTransferDistance { get; set; } + + /// + /// If true then on a teleport, the source region waits for a callback from the destination region. If + /// a callback fails to arrive within a set time then the user is pulled back into the source region. + /// + public bool EnableWaitForCallbackFromTeleportDest { get; set; } protected bool m_Enabled = false; protected Scene m_aScene; @@ -103,7 +108,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer IConfig transferConfig = source.Configs["EntityTransfer"]; if (transferConfig != null) { - MaxTransferDistance = transferConfig.GetInt("max_distance", 4095); + EnableWaitForCallbackFromTeleportDest + = transferConfig.GetBoolean("wait_for_callback", EnableWaitForCallbackFromTeleportDestDefault); + + MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance); + } + else + { + MaxTransferDistance = DefaultMaxTransferDistance; } m_agentsInTransit = new List(); @@ -170,8 +182,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) return; - IEventQueue eq = sp.Scene.RequestModuleInterface(); - // Reset animations; the viewer does that in teleports. sp.Animator.ResetAnimations(); @@ -183,131 +193,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { destinationRegionName = sp.Scene.RegionInfo.RegionName; - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Teleport for {0} to {1} within {2}", - sp.Name, position, destinationRegionName); - - // Teleport within the same region - if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) - { - Vector3 emergencyPos = new Vector3(128, 128, 128); - - m_log.WarnFormat( - "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", - position, sp.Name, sp.UUID, emergencyPos); - - position = emergencyPos; - } - - // TODO: Get proper AVG Height - float localAVHeight = 1.56f; - float posZLimit = 22; - - // TODO: Check other Scene HeightField - if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) - { - posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; - } - - float newPosZ = posZLimit + localAVHeight; - if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) - { - position.Z = newPosZ; - } - - sp.ControllingClient.SendTeleportStart(teleportFlags); - - sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); - sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags; - sp.Velocity = Vector3.Zero; - sp.Teleport(position); - - foreach (SceneObjectGroup grp in sp.GetAttachments()) - { - sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT); - } + TeleportAgentWithinRegion(sp, position, lookAt, teleportFlags); } else // Another region possibly in another simulator { - uint x = 0, y = 0; - Utils.LongToUInts(regionHandle, out x, out y); - GridRegion reg = m_aScene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); - - if (reg != null) - { - GridRegion finalDestination = GetFinalDestination(reg); - if (finalDestination == null) - { - m_log.WarnFormat( - "[ENTITY TRANSFER MODULE]: Final destination is having problems. Unable to teleport {0} {1}", - sp.Name, sp.UUID); - - sp.ControllingClient.SendTeleportFailed("Problem at destination"); - return; - } + GridRegion finalDestination; + TeleportAgentToDifferentRegion( + sp, regionHandle, position, lookAt, teleportFlags, out finalDestination); + if (finalDestination != null) destinationRegionName = finalDestination.RegionName; - - uint curX = 0, curY = 0; - Utils.LongToUInts(sp.Scene.RegionInfo.RegionHandle, out curX, out curY); - int curCellX = (int)(curX / Constants.RegionSize); - int curCellY = (int)(curY / Constants.RegionSize); - int destCellX = (int)(finalDestination.RegionLocX / Constants.RegionSize); - int destCellY = (int)(finalDestination.RegionLocY / Constants.RegionSize); - -// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY); -// -// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}", -// destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI); - - // Check that these are not the same coordinates - if (finalDestination.RegionLocX == sp.Scene.RegionInfo.RegionLocX && - finalDestination.RegionLocY == sp.Scene.RegionInfo.RegionLocY) - { - // Can't do. Viewer crashes - sp.ControllingClient.SendTeleportFailed("Space warp! You would crash. Move to a different region and try again."); - return; - } - - if (Math.Abs(curCellX - destCellX) > MaxTransferDistance || Math.Abs(curCellY - destCellY) > MaxTransferDistance) - { - sp.ControllingClient.SendTeleportFailed( - string.Format( - "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way", - finalDestination.RegionName, destCellX, destCellY, - sp.Scene.RegionInfo.RegionName, curCellX, curCellY, - MaxTransferDistance)); - - return; - } - - // - // This is it - // - DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags, eq); - // - // - // - } - else - { - // TP to a place that doesn't exist (anymore) - // Inform the viewer about that - sp.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); - - // and set the map-tile to '(Offline)' - uint regX, regY; - Utils.LongToUInts(regionHandle, out regX, out regY); - - MapBlockData block = new MapBlockData(); - block.X = (ushort)(regX / Constants.RegionSize); - block.Y = (ushort)(regY / Constants.RegionSize); - block.Access = 254; // == not there - - List blocks = new List(); - blocks.Add(block); - sp.ControllingClient.SendMapBlock(blocks, 0); - } } } catch (Exception e) @@ -321,8 +216,171 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } } - public void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination, Vector3 position, Vector3 lookAt, uint teleportFlags, IEventQueue eq) + /// + /// Teleports the agent within its current region. + /// + /// + /// + /// + /// 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) + { + posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; + } + + float newPosZ = posZLimit + localAVHeight; + if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) + { + position.Z = newPosZ; + } + + sp.ControllingClient.SendTeleportStart(teleportFlags); + + sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); + sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags; + sp.Velocity = Vector3.Zero; + sp.Teleport(position); + + foreach (SceneObjectGroup grp in sp.GetAttachments()) + { + sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT); + } + } + + /// + /// Teleports the agent to a different region. + /// + /// + /// /param> + /// + /// + /// + /// + private void TeleportAgentToDifferentRegion( + ScenePresence sp, ulong regionHandle, Vector3 position, + Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination) + { + uint x = 0, y = 0; + Utils.LongToUInts(regionHandle, out x, out y); + GridRegion reg = m_aScene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); + + if (reg != null) + { + finalDestination = GetFinalDestination(reg); + + if (finalDestination == null) + { + m_log.WarnFormat( + "[ENTITY TRANSFER MODULE]: Final destination is having problems. Unable to teleport {0} {1}", + sp.Name, sp.UUID); + + sp.ControllingClient.SendTeleportFailed("Problem at destination"); + return; + } + + // Check that these are not the same coordinates + if (finalDestination.RegionLocX == sp.Scene.RegionInfo.RegionLocX && + finalDestination.RegionLocY == sp.Scene.RegionInfo.RegionLocY) + { + // Can't do. Viewer crashes + sp.ControllingClient.SendTeleportFailed("Space warp! You would crash. Move to a different region and try again."); + return; + } + + // + // This is it + // + DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags); + // + // + // + } + else + { + finalDestination = null; + + // TP to a place that doesn't exist (anymore) + // Inform the viewer about that + sp.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); + + // and set the map-tile to '(Offline)' + uint regX, regY; + Utils.LongToUInts(regionHandle, out regX, out regY); + + MapBlockData block = new MapBlockData(); + block.X = (ushort)(regX / Constants.RegionSize); + block.Y = (ushort)(regY / Constants.RegionSize); + block.Access = 254; // == not there + + List blocks = new List(); + blocks.Add(block); + sp.ControllingClient.SendMapBlock(blocks, 0); + } + } + + /// + /// Determines whether this instance is within the max transfer distance. + /// + /// + /// + /// + /// true if this instance is within max transfer distance; otherwise, false. + /// + private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion) + { +// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY); +// +// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}", +// destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI); + + // Insanely, RegionLoc on RegionInfo is the 256m map co-ord whilst GridRegion.RegionLoc is the raw meters position. + return Math.Abs(sourceRegion.RegionLocX - destRegion.RegionCoordX) <= MaxTransferDistance + && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance; + } + + public void DoTeleport( + ScenePresence sp, GridRegion reg, GridRegion finalDestination, + Vector3 position, Vector3 lookAt, uint teleportFlags) + { + RegionInfo sourceRegion = sp.Scene.RegionInfo; + + if (!IsWithinMaxTeleportDistance(sourceRegion, finalDestination)) + { + sp.ControllingClient.SendTeleportFailed( + string.Format( + "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way", + finalDestination.RegionName, finalDestination.RegionCoordX, finalDestination.RegionCoordY, + sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, + MaxTransferDistance)); + + return; + } + + IEventQueue eq = sp.Scene.RequestModuleInterface(); + if (reg == null || finalDestination == null) { sp.ControllingClient.SendTeleportFailed("Unable to locate destination"); @@ -485,7 +543,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest"); m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, sp.UUID); + "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", + capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); if (eq != null) { @@ -504,7 +563,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation // that the client contacted the destination before we close things here. - if (!WaitForCallback(sp.UUID)) + if (EnableWaitForCallbackFromTeleportDest && !WaitForCallback(sp.UUID)) { m_log.WarnFormat( "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} failed due to no callback from destination region. Returning avatar to source region.", @@ -537,7 +596,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) { - Thread.Sleep(5000); +// Thread.Sleep(5000); sp.Close(); sp.Scene.IncomingCloseAgent(sp.UUID); } @@ -630,7 +689,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer protected virtual bool IsOutsideRegion(Scene s, Vector3 pos) { - if (s.TestBorderCross(pos, Cardinals.N)) return true; if (s.TestBorderCross(pos, Cardinals.S)) @@ -752,7 +810,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer neighbourx--; newpos.X = Constants.RegionSize - enterDistance; - } else if (scene.TestBorderCross(pos + eastCross, Cardinals.E)) { @@ -1202,7 +1259,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) { - AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); AgentCircuitData agent = sp.ControllingClient.RequestClientInfo(); agent.BaseFolder = UUID.Zero; @@ -1227,7 +1283,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer seeds.Add(neighbour.RegionHandle, agent.CapsPath); } else + { agent.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, neighbour.RegionHandle); + } cagents.Add(agent); } @@ -1851,7 +1909,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer int count = 200; while (m_agentsInTransit.Contains(id) && count-- > 0) { - //m_log.Debug(" >>> Waiting... " + count); +// m_log.Debug(" >>> Waiting... " + count); Thread.Sleep(100); } @@ -1859,6 +1917,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return true; else return false; + + return true; } protected void SetInTransit(UUID id) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index a9ffd8fe30..6e27299ef0 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -246,13 +246,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return false; } - IEventQueue eq = sp.Scene.RequestModuleInterface(); GridRegion homeGatekeeper = MakeRegion(aCircuit); m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: teleporting user {0} {1} home to {2} via {3}:{4}", aCircuit.firstname, aCircuit.lastname, finalDestination.RegionName, homeGatekeeper.ServerURI, homeGatekeeper.RegionName); - DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome), eq); + DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); return true; } @@ -293,17 +292,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { ScenePresence sp = scene.GetScenePresence(remoteClient.AgentId); IEntityTransferModule transferMod = scene.RequestModuleInterface(); - IEventQueue eq = sp.Scene.RequestModuleInterface(); - if (transferMod != null && sp != null && eq != null) - transferMod.DoTeleport(sp, gatekeeper, finalDestination, lm.Position, - Vector3.UnitX, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark), eq); + + if (transferMod != null && sp != null) + transferMod.DoTeleport( + sp, gatekeeper, finalDestination, lm.Position, Vector3.UnitX, + (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); } } // can't find the region: Tell viewer and abort remoteClient.SendTeleportFailed("The teleport destination could not be found."); - } #endregion diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index d6afaa9e75..21d8bd77a9 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -64,8 +64,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests IConfigSource config = new IniConfigSource(); config.AddConfig("Modules"); config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); - - m_scene = new SceneHelpers().SetupScene(); + + SceneHelpers sceneHelpers = new SceneHelpers(); + m_scene = sceneHelpers.SetupScene(); SceneHelpers.SetupSceneModules(m_scene, config, m_iam); // Create user @@ -76,7 +77,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests AgentCircuitData acd = new AgentCircuitData(); acd.AgentID = m_userId; - m_tc = new TestClient(acd, m_scene); + m_tc = new TestClient(acd, m_scene); } [Test] diff --git a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs index 76f1641a92..9cd27f9ac8 100644 --- a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs @@ -39,13 +39,23 @@ namespace OpenSim.Region.Framework.Interfaces public interface IEntityTransferModule { - void Teleport(ScenePresence agent, ulong regionHandle, Vector3 position, - Vector3 lookAt, uint teleportFlags); + /// + /// Teleport an agent within the same or to a different region. + /// + /// + /// + /// The handle of the destination region. If it's the same as the region currently + /// occupied by the agent then the teleport will be within that region. + /// + /// + /// + /// + void Teleport(ScenePresence agent, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags); bool TeleportHome(UUID id, IClientAPI client); void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination, - Vector3 position, Vector3 lookAt, uint teleportFlags, IEventQueue eq); + Vector3 position, Vector3 lookAt, uint teleportFlags); bool Cross(ScenePresence agent, bool isFlying); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 3452f902d2..35c920bd42 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3049,8 +3049,8 @@ namespace OpenSim.Region.Framework.Scenes x = x / Constants.RegionSize; y = y / Constants.RegionSize; - //m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX))); - //m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY))); +// m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX))); +// m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY))); if (Util.IsOutsideView(DrawDistance, x, newRegionX, y, newRegionY)) { byebyeRegions.Add(handle); diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs index 2e46377901..1aa48d7520 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs @@ -128,7 +128,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests IConfig config = configSource.AddConfig("Modules"); config.Set("SimulationServices", "LocalSimulationConnectorModule"); - TestScene scene = new SceneHelpers().SetupScene(); + SceneHelpers sceneHelpers = new SceneHelpers(); + TestScene scene = sceneHelpers.SetupScene(); SceneHelpers.SetupSceneModules(scene, configSource, lsc); UUID agentId = TestHelpers.ParseTail(0x01); diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs index c750cc5d10..ea4fb66b4e 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs @@ -33,8 +33,9 @@ using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Communications; using OpenSim.Framework.Servers; -using OpenSim.Region.CoreModules.Framework.EntityTransfer; using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; using OpenSim.Tests.Common; using OpenSim.Tests.Common.Mock; @@ -49,6 +50,22 @@ namespace OpenSim.Region.Framework.Scenes.Tests [TestFixture] public class ScenePresenceTeleportTests { + [TestFixtureSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; + } + + [TestFixtureTearDown] + public void TearDown() + { + // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple + // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression + // tests really shouldn't). + Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; + } + [Test] public void TestSameRegionTeleport() { @@ -96,10 +113,14 @@ namespace OpenSim.Region.Framework.Scenes.Tests LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); IConfigSource config = new IniConfigSource(); - config.AddConfig("Modules"); - // Not strictly necessary since FriendsModule assumes it is the default (!) - config.Configs["Modules"].Set("EntityTransferModule", etm.Name); - config.Configs["Modules"].Set("SimulationServices", lscm.Name); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etm.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + entityTransferConfig.Set("wait_for_callback", false); SceneHelpers sh = new SceneHelpers(); TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); @@ -110,12 +131,12 @@ namespace OpenSim.Region.Framework.Scenes.Tests Vector3 teleportPosition = new Vector3(10, 11, 12); Vector3 teleportLookAt = new Vector3(20, 21, 22); - ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId); + ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); sp.AbsolutePosition = new Vector3(30, 31, 32); // XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole // UDP stack (?) - ((TestClient)sp.ControllingClient).TeleportTargetScene = sceneB; +// ((TestClient)sp.ControllingClient).TeleportTargetScene = sceneB; sceneA.RequestTeleportLocation( sp.ControllingClient, @@ -124,6 +145,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests teleportLookAt, (uint)TeleportFlags.ViaLocation); + ((TestClient)sp.ControllingClient).CompleteTeleportClientSide(); + Assert.That(sceneA.GetScenePresence(userId), Is.Null); ScenePresence sceneBSp = sceneB.GetScenePresence(userId); @@ -137,5 +160,80 @@ namespace OpenSim.Region.Framework.Scenes.Tests // position instead). // Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); } + + [Test] + public void TestSameSimulatorNeighbouringRegionsTeleport() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + EntityTransferModule etm = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etm.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + entityTransferConfig.Set("wait_for_callback", false); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1001, 1000); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, etm, lscm); + SceneHelpers.SetupSceneModules(sceneA, new CapabilitiesModule()); + SceneHelpers.SetupSceneModules(sceneB, new CapabilitiesModule()); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); + originalSp.AbsolutePosition = new Vector3(30, 31, 32); + + ScenePresence beforeSceneASp = sceneA.GetScenePresence(userId); + Assert.That(beforeSceneASp, Is.Not.Null); + Assert.That(beforeSceneASp.IsChildAgent, Is.False); + + ScenePresence beforeSceneBSp = sceneB.GetScenePresence(userId); + Assert.That(beforeSceneBSp, Is.Not.Null); + Assert.That(beforeSceneBSp.IsChildAgent, Is.True); + + // XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole + // UDP stack (?) +// ((TestClient)beforeSceneASp.ControllingClient).TeleportTargetScene = sceneB; + + sceneA.RequestTeleportLocation( + beforeSceneASp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + ((TestClient)beforeSceneASp.ControllingClient).CompleteTeleportClientSide(); + + ScenePresence afterSceneASp = sceneA.GetScenePresence(userId); + Assert.That(afterSceneASp, Is.Not.Null); + Assert.That(afterSceneASp.IsChildAgent, Is.True); + + ScenePresence afterSceneBSp = sceneB.GetScenePresence(userId); + Assert.That(afterSceneBSp, Is.Not.Null); + Assert.That(afterSceneBSp.IsChildAgent, Is.False); + Assert.That(afterSceneBSp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneB.RegionInfo.RegionName)); + Assert.That(afterSceneBSp.AbsolutePosition, Is.EqualTo(teleportPosition)); + + // TODO: Add assertions to check correct circuit details in both scenes. + + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). +// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + +// TestHelpers.DisableLogging(); + } } } \ No newline at end of file diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs index 8e547077fc..dc24418145 100644 --- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs @@ -58,6 +58,11 @@ namespace OpenSim.Tests.Common /// public class SceneHelpers { + /// + /// We need a scene manager so that test clients can retrieve a scene when performing teleport tests. + /// + public SceneManager SceneManager { get; private set; } + private AgentCircuitManager m_acm = new AgentCircuitManager(); private ISimulationDataService m_simDataService = OpenSim.Server.Base.ServerUtils.LoadPlugin("OpenSim.Tests.Common.dll", null); @@ -76,6 +81,8 @@ namespace OpenSim.Tests.Common public SceneHelpers(CoreAssetCache cache) { + SceneManager = new SceneManager(); + m_assetService = StartAssetService(cache); m_authenticationService = StartAuthenticationService(); m_inventoryService = StartInventoryService(); @@ -186,6 +193,8 @@ namespace OpenSim.Tests.Common testScene.LoginsDisabled = false; testScene.RegisterRegionWithGrid(); + SceneManager.Add(testScene); + return testScene; } @@ -350,6 +359,7 @@ namespace OpenSim.Tests.Common List newModules = new List(); foreach (object module in modules) { +// Console.WriteLine("MODULE RAW {0}", module); if (module is IRegionModule) { IRegionModule m = (IRegionModule)module; @@ -367,6 +377,7 @@ namespace OpenSim.Tests.Common // for the new system, everything has to be initialised first, // shared modules have to be post-initialised, then all get an AddRegion with the scene IRegionModuleBase m = (IRegionModuleBase)module; +// Console.WriteLine("MODULE {0}", m.Name); m.Initialise(config); newModules.Add(m); } @@ -426,6 +437,10 @@ namespace OpenSim.Tests.Common /// /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test /// + /// + /// This can be used for tests where there is only one region or where there are multiple non-neighbour regions + /// and teleport doesn't take place. + /// /// /// /// @@ -434,6 +449,18 @@ namespace OpenSim.Tests.Common return AddScenePresence(scene, GenerateAgentData(agentId)); } + /// + /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test + /// + /// + /// + /// + /// + public static ScenePresence AddScenePresence(Scene scene, UUID agentId, SceneManager sceneManager) + { + return AddScenePresence(scene, GenerateAgentData(agentId), sceneManager); + } + /// /// Add a root agent. /// @@ -453,6 +480,30 @@ namespace OpenSim.Tests.Common /// /// public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData) + { + return AddScenePresence(scene, agentData, null); + } + + /// + /// Add a root agent. + /// + /// + /// This function + /// + /// 1) Tells the scene that an agent is coming. Normally, the login service (local if standalone, from the + /// userserver if grid) would give initial login data back to the client and separately tell the scene that the + /// agent was coming. + /// + /// 2) Connects the agent with the scene + /// + /// This function performs actions equivalent with notifying the scene that an agent is + /// coming and then actually connecting the agent to the scene. The one step missed out is the very first + /// + /// + /// + /// + /// + public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData, SceneManager sceneManager) { // We emulate the proper login sequence here by doing things in four stages @@ -463,7 +514,7 @@ namespace OpenSim.Tests.Common lpsc.m_PresenceService.LoginAgent(agentData.AgentID.ToString(), agentData.SessionID, agentData.SecureSessionID); // Stages 1 & 2 - ScenePresence sp = IntroduceClientToScene(scene, agentData, TeleportFlags.ViaLogin); + ScenePresence sp = IntroduceClientToScene(scene, sceneManager, agentData, TeleportFlags.ViaLogin); // Stage 3: Complete the entrance into the region. This converts the child agent into a root agent. sp.CompleteMovement(sp.ControllingClient, true); @@ -471,7 +522,20 @@ namespace OpenSim.Tests.Common return sp; } - private static ScenePresence IntroduceClientToScene(Scene scene, AgentCircuitData agentData, TeleportFlags tf) + /// + /// Introduce an agent into the scene by adding a new client. + /// + /// The scene presence added + /// + /// Scene manager. Can be null if there is only one region in the test or multiple regions that are not + /// neighbours and where no teleporting takes place. + /// + /// + /// + /// + private static ScenePresence IntroduceClientToScene( + Scene scene, SceneManager sceneManager, AgentCircuitData agentData, TeleportFlags tf) { string reason; @@ -480,7 +544,7 @@ namespace OpenSim.Tests.Common Console.WriteLine("NewUserConnection failed: " + reason); // Stage 2: add the new client as a child agent to the scene - TestClient client = new TestClient(agentData, scene); + TestClient client = new TestClient(agentData, scene, sceneManager); scene.AddNewClient(client, PresenceType.User); return scene.GetScenePresence(agentData.AgentID); @@ -492,7 +556,7 @@ namespace OpenSim.Tests.Common acd.child = true; // XXX: ViaLogin may not be correct for child agents - return IntroduceClientToScene(scene, acd, TeleportFlags.ViaLogin); + return IntroduceClientToScene(scene, null, acd, TeleportFlags.ViaLogin); } /// diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 6a7cb0aa83..8cedebbca8 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -46,12 +46,10 @@ namespace OpenSim.Tests.Common.Mock EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing"); - // TODO: This is a really nasty (and temporary) means of telling the test client which scene to invoke setup - // methods on when a teleport is requested - public Scene TeleportTargetScene; private TestClient TeleportSceneClient; private Scene m_scene; + private SceneManager m_sceneManager; // Properties so that we can get at received data for test purposes public List ReceivedOfflineNotifications { get; private set; } @@ -434,15 +432,29 @@ namespace OpenSim.Tests.Common.Mock /// /// Constructor /// + /// + /// Can be used for a test where there is only one region or where there are multiple regions that are not + /// neighbours and where no teleporting takes place. In other situations, the constructor that takes in a + /// scene manager should be used. + /// /// /// - public TestClient(AgentCircuitData agentData, Scene scene) + public TestClient(AgentCircuitData agentData, Scene scene) : this(agentData, scene, null) {} + + /// + /// Constructor + /// + /// + /// + /// + public TestClient(AgentCircuitData agentData, Scene scene, SceneManager sceneManager) { m_agentId = agentData.AgentID; m_firstName = agentData.firstname; m_lastName = agentData.lastname; m_circuitCode = agentData.circuitcode; m_scene = scene; + m_sceneManager = sceneManager; SessionId = agentData.SessionID; SecureSessionId = agentData.SecureSessionID; CapsSeedUrl = agentData.CapsPath; @@ -592,8 +604,16 @@ namespace OpenSim.Tests.Common.Mock AgentCircuitData newAgent = RequestClientInfo(); // Stage 2: add the new client as a child agent to the scene - TeleportSceneClient = new TestClient(newAgent, TeleportTargetScene); - TeleportTargetScene.AddNewClient(TeleportSceneClient, PresenceType.User); + uint x, y; + Utils.LongToUInts(neighbourHandle, out x, out y); + x /= Constants.RegionSize; + y /= Constants.RegionSize; + + Scene neighbourScene; + m_sceneManager.TryGetScene(x, y, out neighbourScene); + + TeleportSceneClient = new TestClient(newAgent, neighbourScene, m_sceneManager); + neighbourScene.AddNewClient(TeleportSceneClient, PresenceType.User); } public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, @@ -603,6 +623,13 @@ namespace OpenSim.Tests.Common.Mock CapsSeedUrl = capsURL; + // We don't do this here so that the source region can complete processing first in a single-threaded + // regression test scenario. The test itself will have to call CompleteTeleportClientSide() after a teleport + // CompleteTeleportClientSide(); + } + + public void CompleteTeleportClientSide() + { TeleportSceneClient.CompleteMovement(); //TeleportTargetScene.AgentCrossing(newAgent.AgentID, new Vector3(90, 90, 90), false); } diff --git a/OpenSim/Tests/Common/TestHelpers.cs b/OpenSim/Tests/Common/TestHelpers.cs index 5030d4bf7f..6744fcac97 100644 --- a/OpenSim/Tests/Common/TestHelpers.cs +++ b/OpenSim/Tests/Common/TestHelpers.cs @@ -46,7 +46,8 @@ namespace OpenSim.Tests.Common - + + @@ -62,9 +63,9 @@ namespace OpenSim.Tests.Common Encoding.UTF8.GetBytes( // ""))); //""))); - //""))); - //""))); - //""))); +// "")); +// ""))); +// "")); "")); public static bool AssertThisDelegateCausesArgumentException(TestDelegate d)