From 1b156b7fe84bf132b51ff198d6d730708f5930b7 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 22 May 2014 19:18:24 +0100 Subject: [PATCH 01/18] Add regression test for in-range chat between neighbouring regions from east to west. --- .../Avatar/Chat/Tests/ChatModuleTests.cs | 158 ++++++++++++++++++ OpenSim/Region/Framework/Scenes/Scene.cs | 5 +- .../BasicPhysicsPlugin/BasicPhysicsScene.cs | 1 + OpenSim/Tests/Common/Mock/TestClient.cs | 40 +++++ prebuild.xml | 1 + 5 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs new file mode 100644 index 0000000000..315cc195ca --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs @@ -0,0 +1,158 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using log4net.Config; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.CoreModules.Avatar.Chat; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; +using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests +{ + [TestFixture] + public class ChatModuleTests : OpenSimTestCase + { + [TestFixtureSetUp] + public void FixtureInit() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + // We must do this here so that child agent positions are updated in a predictable manner. + 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; + } + + /// + /// Tests chat between neighbour regions on the east-west axis + /// + /// + /// Really, this is a combination of a child agent position update test and a chat range test. These need + /// to be separated later on. + /// + [Test] + public void TestInterRegionChatDistanceEastWest() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID sp1Uuid = TestHelpers.ParseTail(0x11); + UUID sp2Uuid = TestHelpers.ParseTail(0x12); + + Vector3 sp1Position = new Vector3(6, 128, 20); + Vector3 sp2Position = new Vector3(250, 128, 20); + + // XXX: HTTP server is not (and should not be) necessary for this test, though it's absence makes the + // CapabilitiesModule complain when it can't set up HTTP endpoints. +// BaseHttpServer httpServer = new BaseHttpServer(99999); +// MainServer.AddHttpServer(httpServer); +// MainServer.Instance = httpServer; + + // We need entity transfer modules so that when sp2 logs into the east region, the region calls + // EntityTransferModuleto set up a child agent on the west region. + // XXX: However, this is not an entity transfer so is misleading. + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Chat"); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + + SceneHelpers sh = new SceneHelpers(); + + TestScene sceneWest = sh.SetupScene("sceneWest", TestHelpers.ParseTail(0x1), 1000, 1000); + TestScene sceneEast = sh.SetupScene("sceneEast", TestHelpers.ParseTail(0x2), 1001, 1000); + SceneHelpers.SetupSceneModules(new Scene[] { sceneWest, sceneEast }, config, lscm); + + SceneHelpers.SetupSceneModules(sceneWest, config, new CapabilitiesModule(), etmA, new ChatModule()); + SceneHelpers.SetupSceneModules(sceneEast, config, new CapabilitiesModule(), etmB, new ChatModule()); + + ScenePresence sp1 = SceneHelpers.AddScenePresence(sceneEast, sp1Uuid); + TestClient sp1Client = (TestClient)sp1.ControllingClient; + + // If we don't set agents to flying, test will go wrong as they instantly fall to z = 0. + // TODO: May need to create special complete no-op test physics module rather than basic physics, since + // physics is irrelevant to this test. + sp1.Flying = true; + sp1.AbsolutePosition = sp1Position; + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(sp2Uuid); + TestClient tc = new TestClient(acd, sceneEast); + List destinationTestClients = new List(); + EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); + + ScenePresence sp2 = SceneHelpers.AddScenePresence(sceneWest, tc, acd); + TestClient sp2Client = (TestClient)sp2.ControllingClient; + + sp2.Flying = true; + sp2.AbsolutePosition = sp2Position; + + TestClient sp2ChildClient = destinationTestClients[0]; + + // We must update the scene in order to make the new root agent sp2 in sceneWest trigger a position update to its + // child in sceneEast. + sceneWest.Update(1); + + // Check child position is correct. + Assert.AreEqual( + new Vector3(sp2Position.X - sceneWest.RegionInfo.RegionSizeX, sp2Position.Y, sp2Position.Z), + sp2ChildClient.SceneAgent.AbsolutePosition); + + // Check chat received + string receivedChatMessage = ""; + + sp2ChildClient.OnReceivedChatMessage + += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedChatMessage = message; + + string testMessage = "'ello darling"; + sp1Client.Chat(0, ChatTypeEnum.Say, testMessage); + + Assert.AreEqual(testMessage, receivedChatMessage); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 3b8fbfdd26..7005c0a5ef 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4133,7 +4133,10 @@ namespace OpenSim.Region.Framework.Scenes /// true if we handled it. public virtual bool IncomingUpdateChildAgent(AgentPosition cAgentData) { - //m_log.Debug(" XXX Scene IncomingChildAgentDataUpdate POSITION in " + RegionInfo.RegionName); +// m_log.DebugFormat( +// "[SCENE PRESENCE]: IncomingChildAgentDataUpdate POSITION for {0} in {1}, position {2}", +// cAgentData.AgentID, Name, cAgentData.Position); + ScenePresence childAgentUpdate = GetScenePresence(cAgentData.AgentID); if (childAgentUpdate != null) { diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs index 8e405616fa..f53adcb065 100644 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs +++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs @@ -147,6 +147,7 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin terrainHeight = _heightMap[(int)actor.Position.Y * (int)m_regionExtent.Y + (int)actor.Position.X]; float height = terrainHeight + actor.Size.Z; +// Console.WriteLine("height {0}, actorPosition {1}", height, actorPosition); if (actor.Flying) { diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index c2b0935788..8eeaf99222 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -62,14 +62,23 @@ namespace OpenSim.Tests.Common.Mock public event Action OnReceivedMoveAgentIntoRegion; public event Action OnTestClientInformClientOfNeighbour; public event TestClientOnSendRegionTeleportDelegate OnTestClientSendRegionTeleport; + public event Action OnReceivedEntityUpdate; + + public event OnReceivedChatMessageDelegate OnReceivedChatMessage; public event Action OnReceivedInstantMessage; + public event Action OnReceivedSendRebakeAvatarTextures; public delegate void TestClientOnSendRegionTeleportDelegate( ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, uint locationID, uint flags, string capsURL); + public delegate void OnReceivedChatMessageDelegate( + string message, byte type, Vector3 fromPos, string fromName, + UUID fromAgentID, UUID ownerID, byte source, byte audible); + + // disable warning: public events, part of the public API #pragma warning disable 67 @@ -466,6 +475,34 @@ namespace OpenSim.Tests.Common.Mock SentImageNotInDatabasePackets = new List(); } + /// + /// Trigger chat coming from this connection. + /// + /// + /// + /// + public bool Chat(int channel, ChatTypeEnum type, string message) + { + ChatMessage handlerChatFromClient = OnChatFromClient; + + if (handlerChatFromClient != null) + { + OSChatMessage args = new OSChatMessage(); + args.Channel = channel; + args.From = Name; + args.Message = message; + args.Type = type; + + args.Scene = Scene; + args.Sender = this; + args.SenderUUID = AgentId; + + handlerChatFromClient(this, args); + } + + return true; + } + /// /// Attempt a teleport to the given region. /// @@ -550,6 +587,9 @@ namespace OpenSim.Tests.Common.Mock string message, byte type, Vector3 fromPos, string fromName, UUID fromAgentID, UUID ownerID, byte source, byte audible) { +// Console.WriteLine("mmm {0} {1} {2}", message, Name, AgentId); + if (OnReceivedChatMessage != null) + OnReceivedChatMessage(message, type, fromPos, fromName, fromAgentID, ownerID, source, audible); } public void SendInstantMessage(GridInstantMessage im) diff --git a/prebuild.xml b/prebuild.xml index 9a419eb3c2..196bfd2931 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -3081,6 +3081,7 @@ + From 65a135f4d33fc0be3738f11c51a6c27c344a10aa Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 22 May 2014 19:47:33 +0100 Subject: [PATCH 02/18] Simplify regression TestInterRegionChatDistanceEastWest() by making the child presence connection directly rather than routing through TestClient. This code isn't relevant to this test and is already exercised by other tests. --- .../Avatar/Chat/Tests/ChatModuleTests.cs | 13 ++++++------- OpenSim/Tests/Common/Helpers/SceneHelpers.cs | 6 +++++- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs index 315cc195ca..c5eb2adf99 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs @@ -121,18 +121,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests sp1.Flying = true; sp1.AbsolutePosition = sp1Position; - AgentCircuitData acd = SceneHelpers.GenerateAgentData(sp2Uuid); - TestClient tc = new TestClient(acd, sceneEast); - List destinationTestClients = new List(); - EntityTransferHelpers.SetupInformClientOfNeighbourTriggersNeighbourClientCreate(tc, destinationTestClients); - - ScenePresence sp2 = SceneHelpers.AddScenePresence(sceneWest, tc, acd); + ScenePresence sp2 = SceneHelpers.AddScenePresence(sceneWest, sp2Uuid); TestClient sp2Client = (TestClient)sp2.ControllingClient; + // When sp2 logs in to sceneWest, it sets up a child agent in sceneEast and informs the sp2 client to + // make the connection. For this test, will simplify this chain by making the connection separately here. + ScenePresence sp2Child = SceneHelpers.AddChildScenePresence(sceneEast, sp2Uuid); + sp2.Flying = true; sp2.AbsolutePosition = sp2Position; - TestClient sp2ChildClient = destinationTestClients[0]; + TestClient sp2ChildClient = (TestClient)sp2Child.ControllingClient; // We must update the scene in order to make the new root agent sp2 in sceneWest trigger a position update to its // child in sceneEast. diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs index 874ff625fa..342cd06004 100644 --- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs @@ -574,7 +574,11 @@ namespace OpenSim.Tests.Common public static ScenePresence AddChildScenePresence(Scene scene, UUID agentId) { - AgentCircuitData acd = GenerateAgentData(agentId); + return AddChildScenePresence(scene, GenerateAgentData(agentId)); + } + + public static ScenePresence AddChildScenePresence(Scene scene, AgentCircuitData acd) + { acd.child = true; // XXX: ViaLogin may not be correct for child agents From 15b50ae737cf316cfe9db6843f06f7b3799f139e Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 22 May 2014 19:55:34 +0100 Subject: [PATCH 03/18] Extend regression TestInterRegionChatDistanceEastWest() to test in range chat both ways. --- .../Avatar/Chat/Tests/ChatModuleTests.cs | 57 +++++++++++++------ 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs index c5eb2adf99..fac9bd481e 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs @@ -119,39 +119,60 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests // TODO: May need to create special complete no-op test physics module rather than basic physics, since // physics is irrelevant to this test. sp1.Flying = true; + + // When sp1 logs in to sceneEast, it sets up a child agent in sceneWest and informs the sp2 client to + // make the connection. For this test, will simplify this chain by making the connection directly. + ScenePresence sp1Child = SceneHelpers.AddChildScenePresence(sceneWest, sp1Uuid); + TestClient sp1ChildClient = (TestClient)sp1Child.ControllingClient; + sp1.AbsolutePosition = sp1Position; ScenePresence sp2 = SceneHelpers.AddScenePresence(sceneWest, sp2Uuid); TestClient sp2Client = (TestClient)sp2.ControllingClient; - - // When sp2 logs in to sceneWest, it sets up a child agent in sceneEast and informs the sp2 client to - // make the connection. For this test, will simplify this chain by making the connection separately here. - ScenePresence sp2Child = SceneHelpers.AddChildScenePresence(sceneEast, sp2Uuid); - sp2.Flying = true; - sp2.AbsolutePosition = sp2Position; + ScenePresence sp2Child = SceneHelpers.AddChildScenePresence(sceneEast, sp2Uuid); TestClient sp2ChildClient = (TestClient)sp2Child.ControllingClient; - // We must update the scene in order to make the new root agent sp2 in sceneWest trigger a position update to its - // child in sceneEast. - sceneWest.Update(1); + sp2.AbsolutePosition = sp2Position; + + // We must update the scenes in order to make the root new root agents trigger position updates in their + // children. + sceneWest.Update(1); + sceneEast.Update(1); + + // Check child positions are correct. + Assert.AreEqual( + new Vector3(sp1Position.X + sceneEast.RegionInfo.RegionSizeX, sp1Position.Y, sp1Position.Z), + sp1ChildClient.SceneAgent.AbsolutePosition); - // Check child position is correct. Assert.AreEqual( new Vector3(sp2Position.X - sceneWest.RegionInfo.RegionSizeX, sp2Position.Y, sp2Position.Z), sp2ChildClient.SceneAgent.AbsolutePosition); - // Check chat received - string receivedChatMessage = ""; + // Check chat from sp1 + { + string receivedChatMessage = ""; - sp2ChildClient.OnReceivedChatMessage - += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedChatMessage = message; + sp2ChildClient.OnReceivedChatMessage + += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedChatMessage = message; - string testMessage = "'ello darling"; - sp1Client.Chat(0, ChatTypeEnum.Say, testMessage); - - Assert.AreEqual(testMessage, receivedChatMessage); + string testMessage = "'ello darling"; + sp1Client.Chat(0, ChatTypeEnum.Say, testMessage); + } + + // Check chat from sp2 + { + string receivedChatMessage = ""; + + sp1ChildClient.OnReceivedChatMessage + += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedChatMessage = message; + + string testMessage = "fantastic cats"; + sp2Client.Chat(0, ChatTypeEnum.Say, testMessage); + + Assert.AreEqual(testMessage, receivedChatMessage); + } } } } \ No newline at end of file From bffc9ad18471076360692731597f89d232bb07b9 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 22 May 2014 20:04:32 +0100 Subject: [PATCH 04/18] Extend regression TestInterRegionChatDistanceEastWest() to test out of range chat --- .../Avatar/Chat/Tests/ChatModuleTests.cs | 53 ++++++++++++++----- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs index fac9bd481e..bdaa97b700 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs @@ -150,28 +150,55 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests new Vector3(sp2Position.X - sceneWest.RegionInfo.RegionSizeX, sp2Position.Y, sp2Position.Z), sp2ChildClient.SceneAgent.AbsolutePosition); + string receivedSp1ChatMessage = ""; + string receivedSp2ChatMessage = ""; + + sp1ChildClient.OnReceivedChatMessage + += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp1ChatMessage = message; + sp2ChildClient.OnReceivedChatMessage + += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp2ChatMessage = message; + // Check chat from sp1 - { - string receivedChatMessage = ""; - - sp2ChildClient.OnReceivedChatMessage - += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedChatMessage = message; - + { string testMessage = "'ello darling"; sp1Client.Chat(0, ChatTypeEnum.Say, testMessage); + +// Assert.AreEqual(testMessage, receivedSp1ChatMessage); + Assert.AreEqual(testMessage, receivedSp2ChatMessage); } // Check chat from sp2 - { - string receivedChatMessage = ""; - - sp1ChildClient.OnReceivedChatMessage - += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedChatMessage = message; - + { string testMessage = "fantastic cats"; sp2Client.Chat(0, ChatTypeEnum.Say, testMessage); - Assert.AreEqual(testMessage, receivedChatMessage); + Assert.AreEqual(testMessage, receivedSp1ChatMessage); +// Assert.AreEqual(testMessage, receivedSp2ChatMessage); + } + + sp1Position = new Vector3(30, 128, 20); + sp1.AbsolutePosition = sp1Position; + sceneEast.Update(1); + + // Check child position is correct. + Assert.AreEqual( + new Vector3(sp1Position.X + sceneEast.RegionInfo.RegionSizeX, sp1Position.Y, sp1Position.Z), + sp1ChildClient.SceneAgent.AbsolutePosition); + + // sp2 should now be out of range for chat from sp1 + { + string testMessage = "beef"; + sp1Client.Chat(0, ChatTypeEnum.Say, testMessage); + + Assert.AreNotEqual(testMessage, receivedSp2ChatMessage); + } + + // sp1 should now be out of range for chat from sp2 + { + string testMessage = "lentils"; + sp2Client.Chat(0, ChatTypeEnum.Say, testMessage); + + Assert.AreNotEqual(testMessage, receivedSp1ChatMessage); } } } From f8b824123970418211bbc5ea501ead98a1781084 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 22 May 2014 20:28:26 +0100 Subject: [PATCH 05/18] Add regression test for north-south chat across neighbour regions. --- .../Avatar/Chat/Tests/ChatModuleTests.cs | 185 +++++++++++++----- 1 file changed, 133 insertions(+), 52 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs index bdaa97b700..7b8c418d79 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/Tests/ChatModuleTests.cs @@ -65,6 +65,32 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; } + private void SetupNeighbourRegions(TestScene sceneA, TestScene sceneB) + { + // XXX: HTTP server is not (and should not be) necessary for this test, though it's absence makes the + // CapabilitiesModule complain when it can't set up HTTP endpoints. + // BaseHttpServer httpServer = new BaseHttpServer(99999); + // MainServer.AddHttpServer(httpServer); + // MainServer.Instance = httpServer; + + // We need entity transfer modules so that when sp2 logs into the east region, the region calls + // EntityTransferModuleto set up a child agent on the west region. + // XXX: However, this is not an entity transfer so is misleading. + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Chat"); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, new ChatModule()); + SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB, new ChatModule()); + } + /// /// Tests chat between neighbour regions on the east-west axis /// @@ -84,33 +110,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests Vector3 sp1Position = new Vector3(6, 128, 20); Vector3 sp2Position = new Vector3(250, 128, 20); - // XXX: HTTP server is not (and should not be) necessary for this test, though it's absence makes the - // CapabilitiesModule complain when it can't set up HTTP endpoints. -// BaseHttpServer httpServer = new BaseHttpServer(99999); -// MainServer.AddHttpServer(httpServer); -// MainServer.Instance = httpServer; - - // We need entity transfer modules so that when sp2 logs into the east region, the region calls - // EntityTransferModuleto set up a child agent on the west region. - // XXX: However, this is not an entity transfer so is misleading. - EntityTransferModule etmA = new EntityTransferModule(); - EntityTransferModule etmB = new EntityTransferModule(); - LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); - - IConfigSource config = new IniConfigSource(); - config.AddConfig("Chat"); - IConfig modulesConfig = config.AddConfig("Modules"); - modulesConfig.Set("EntityTransferModule", etmA.Name); - modulesConfig.Set("SimulationServices", lscm.Name); - SceneHelpers sh = new SceneHelpers(); - TestScene sceneWest = sh.SetupScene("sceneWest", TestHelpers.ParseTail(0x1), 1000, 1000); TestScene sceneEast = sh.SetupScene("sceneEast", TestHelpers.ParseTail(0x2), 1001, 1000); - SceneHelpers.SetupSceneModules(new Scene[] { sceneWest, sceneEast }, config, lscm); - SceneHelpers.SetupSceneModules(sceneWest, config, new CapabilitiesModule(), etmA, new ChatModule()); - SceneHelpers.SetupSceneModules(sceneEast, config, new CapabilitiesModule(), etmB, new ChatModule()); + SetupNeighbourRegions(sceneWest, sceneEast); ScenePresence sp1 = SceneHelpers.AddScenePresence(sceneEast, sp1Uuid); TestClient sp1Client = (TestClient)sp1.ControllingClient; @@ -158,23 +162,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests sp2ChildClient.OnReceivedChatMessage += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp2ChatMessage = message; - // Check chat from sp1 - { - string testMessage = "'ello darling"; - sp1Client.Chat(0, ChatTypeEnum.Say, testMessage); - -// Assert.AreEqual(testMessage, receivedSp1ChatMessage); - Assert.AreEqual(testMessage, receivedSp2ChatMessage); - } - - // Check chat from sp2 - { - string testMessage = "fantastic cats"; - sp2Client.Chat(0, ChatTypeEnum.Say, testMessage); - - Assert.AreEqual(testMessage, receivedSp1ChatMessage); -// Assert.AreEqual(testMessage, receivedSp2ChatMessage); - } + TestUserInRange(sp1Client, "ello darling", ref receivedSp2ChatMessage); + TestUserInRange(sp2Client, "fantastic cats", ref receivedSp1ChatMessage); sp1Position = new Vector3(30, 128, 20); sp1.AbsolutePosition = sp1Position; @@ -185,21 +174,113 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat.Tests new Vector3(sp1Position.X + sceneEast.RegionInfo.RegionSizeX, sp1Position.Y, sp1Position.Z), sp1ChildClient.SceneAgent.AbsolutePosition); - // sp2 should now be out of range for chat from sp1 - { - string testMessage = "beef"; - sp1Client.Chat(0, ChatTypeEnum.Say, testMessage); + TestUserOutOfRange(sp1Client, "beef", ref receivedSp2ChatMessage); + TestUserOutOfRange(sp2Client, "lentils", ref receivedSp1ChatMessage); + } - Assert.AreNotEqual(testMessage, receivedSp2ChatMessage); - } + /// + /// Tests chat between neighbour regions on the north-south axis + /// + /// + /// Really, this is a combination of a child agent position update test and a chat range test. These need + /// to be separated later on. + /// + [Test] + public void TestInterRegionChatDistanceNorthSouth() + { + TestHelpers.InMethod(); + // TestHelpers.EnableLogging(); - // sp1 should now be out of range for chat from sp2 - { - string testMessage = "lentils"; - sp2Client.Chat(0, ChatTypeEnum.Say, testMessage); + UUID sp1Uuid = TestHelpers.ParseTail(0x11); + UUID sp2Uuid = TestHelpers.ParseTail(0x12); - Assert.AreNotEqual(testMessage, receivedSp1ChatMessage); - } + Vector3 sp1Position = new Vector3(128, 250, 20); + Vector3 sp2Position = new Vector3(128, 6, 20); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneNorth = sh.SetupScene("sceneNorth", TestHelpers.ParseTail(0x1), 1000, 1000); + TestScene sceneSouth = sh.SetupScene("sceneSouth", TestHelpers.ParseTail(0x2), 1000, 1001); + + SetupNeighbourRegions(sceneNorth, sceneSouth); + + ScenePresence sp1 = SceneHelpers.AddScenePresence(sceneNorth, sp1Uuid); + TestClient sp1Client = (TestClient)sp1.ControllingClient; + + // If we don't set agents to flying, test will go wrong as they instantly fall to z = 0. + // TODO: May need to create special complete no-op test physics module rather than basic physics, since + // physics is irrelevant to this test. + sp1.Flying = true; + + // When sp1 logs in to sceneEast, it sets up a child agent in sceneNorth and informs the sp2 client to + // make the connection. For this test, will simplify this chain by making the connection directly. + ScenePresence sp1Child = SceneHelpers.AddChildScenePresence(sceneSouth, sp1Uuid); + TestClient sp1ChildClient = (TestClient)sp1Child.ControllingClient; + + sp1.AbsolutePosition = sp1Position; + + ScenePresence sp2 = SceneHelpers.AddScenePresence(sceneSouth, sp2Uuid); + TestClient sp2Client = (TestClient)sp2.ControllingClient; + sp2.Flying = true; + + ScenePresence sp2Child = SceneHelpers.AddChildScenePresence(sceneNorth, sp2Uuid); + TestClient sp2ChildClient = (TestClient)sp2Child.ControllingClient; + + sp2.AbsolutePosition = sp2Position; + + // We must update the scenes in order to make the root new root agents trigger position updates in their + // children. + sceneNorth.Update(1); + sceneSouth.Update(1); + + // Check child positions are correct. + Assert.AreEqual( + new Vector3(sp1Position.X, sp1Position.Y - sceneNorth.RegionInfo.RegionSizeY, sp1Position.Z), + sp1ChildClient.SceneAgent.AbsolutePosition); + + Assert.AreEqual( + new Vector3(sp2Position.X, sp2Position.Y + sceneSouth.RegionInfo.RegionSizeY, sp2Position.Z), + sp2ChildClient.SceneAgent.AbsolutePosition); + + string receivedSp1ChatMessage = ""; + string receivedSp2ChatMessage = ""; + + sp1ChildClient.OnReceivedChatMessage + += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp1ChatMessage = message; + sp2ChildClient.OnReceivedChatMessage + += (message, type, fromPos, fromName, fromAgentID, ownerID, source, audible) => receivedSp2ChatMessage = message; + + TestUserInRange(sp1Client, "ello darling", ref receivedSp2ChatMessage); + TestUserInRange(sp2Client, "fantastic cats", ref receivedSp1ChatMessage); + + sp1Position = new Vector3(30, 128, 20); + sp1.AbsolutePosition = sp1Position; + sceneNorth.Update(1); + + // Check child position is correct. + Assert.AreEqual( + new Vector3(sp1Position.X, sp1Position.Y - sceneNorth.RegionInfo.RegionSizeY, sp1Position.Z), + sp1ChildClient.SceneAgent.AbsolutePosition); + + TestUserOutOfRange(sp1Client, "beef", ref receivedSp2ChatMessage); + TestUserOutOfRange(sp2Client, "lentils", ref receivedSp1ChatMessage); + } + + private void TestUserInRange(TestClient speakClient, string testMessage, ref string receivedMessage) + { + receivedMessage = ""; + + speakClient.Chat(0, ChatTypeEnum.Say, testMessage); + + Assert.AreEqual(testMessage, receivedMessage); + } + + private void TestUserOutOfRange(TestClient speakClient, string testMessage, ref string receivedMessage) + { + receivedMessage = ""; + + speakClient.Chat(0, ChatTypeEnum.Say, testMessage); + + Assert.AreNotEqual(testMessage, receivedMessage); } } } \ No newline at end of file From 16bf38e1abd3a6235008a38ba7ca29e836c925c7 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 22 May 2014 23:39:22 +0100 Subject: [PATCH 06/18] Fix issue where llSetCameraAtOffset() and llSetCameraEyeOffset() in non-root prims moved camera/focus to wrong position. For non-root prim, eye offsets now need to be made relative to root prim if either camera-at or camera-eye are set. Probably a regression since November 2013 when all sits were made relative to root prim to match viewer expections (and fix other bugs). Addresses http://opensimulator.org/mantis/view.php?id=7176 --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 398d39498b..ed107e470e 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2755,6 +2755,10 @@ namespace OpenSim.Region.Framework.Scenes cameraAtOffset = part.GetCameraAtOffset(); cameraEyeOffset = part.GetCameraEyeOffset(); + + if (cameraEyeOffset != Vector3.Zero || cameraAtOffset != Vector3.Zero) + cameraEyeOffset += part.OffsetPosition; + forceMouselook = part.GetForceMouselook(); // An viewer expects to specify sit positions as offsets to the root prim, even if a child prim is From 3fbaef9275dbb1767dc734e2d8dbe1d2cabfb566 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 22 May 2014 23:52:28 +0100 Subject: [PATCH 07/18] If the root prim has a camera-at or camera-eye setting and a sat upon child prim does not, use the root prim offsets. This matches behaviour just tested on the Linden Lab grid. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index ed107e470e..026b0b6a4e 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2754,8 +2754,15 @@ namespace OpenSim.Region.Framework.Scenes part.AddSittingAvatar(this); cameraAtOffset = part.GetCameraAtOffset(); + + if (cameraAtOffset == Vector3.Zero) + cameraAtOffset = part.ParentGroup.RootPart.GetCameraAtOffset(); + cameraEyeOffset = part.GetCameraEyeOffset(); + if (cameraEyeOffset == Vector3.Zero) + cameraEyeOffset = part.ParentGroup.RootPart.GetCameraEyeOffset(); + if (cameraEyeOffset != Vector3.Zero || cameraAtOffset != Vector3.Zero) cameraEyeOffset += part.OffsetPosition; From 174df941720bc45c1e73224919c34f059129b9e1 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 22 May 2014 23:58:28 +0100 Subject: [PATCH 08/18] If a script calls llSetCameraAtOffset() or llSetCameraEyeOffset() on a child prim and the root prim has no corresponding value set, then also set the root prim. This matches behaviour just tested on the Linden Lab grid. --- .../ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 5590cd53b7..7d8821cc08 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -6846,12 +6846,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); m_host.SetCameraEyeOffset(offset); + + if (m_host.ParentGroup.RootPart.GetCameraEyeOffset() == Vector3.Zero) + m_host.ParentGroup.RootPart.SetCameraEyeOffset(offset); } public void llSetCameraAtOffset(LSL_Vector offset) { m_host.AddScriptLPS(1); m_host.SetCameraAtOffset(offset); + + if (m_host.ParentGroup.RootPart.GetCameraAtOffset() == Vector3.Zero) + m_host.ParentGroup.RootPart.SetCameraAtOffset(offset); } public void llSetLinkCamera(LSL_Integer link, LSL_Vector eye, LSL_Vector at) From fbed2455965283e7cec92f8cceb89a333e1dca14 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 23 May 2014 01:34:02 +0100 Subject: [PATCH 09/18] Compensate camera-at and camera-eye for child prim rotation when sitting on child prim with camera-eye set --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 026b0b6a4e..eaac71ddc6 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2764,7 +2764,19 @@ namespace OpenSim.Region.Framework.Scenes cameraEyeOffset = part.ParentGroup.RootPart.GetCameraEyeOffset(); if (cameraEyeOffset != Vector3.Zero || cameraAtOffset != Vector3.Zero) + { + if (!part.IsRoot) + { + cameraEyeOffset = cameraEyeOffset * part.RotationOffset; + cameraAtOffset = part.OffsetPosition; + } + cameraEyeOffset += part.OffsetPosition; + } + +// m_log.DebugFormat( +// "[SCENE PRESENCE]: Using cameraAtOffset {0}, cameraEyeOffset {1} for sit on {2} by {3} in {4}", +// cameraAtOffset, cameraEyeOffset, part.Name, Name, Scene.Name); forceMouselook = part.GetForceMouselook(); From c78a8271c44c581e4c939fa6347fd967ffdee847 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 23 May 2014 01:38:05 +0100 Subject: [PATCH 10/18] Add any camera at compensation for sat upon child prims to any existing camera-at value, rather than replace. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index eaac71ddc6..f067f9df0f 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2768,7 +2768,7 @@ namespace OpenSim.Region.Framework.Scenes if (!part.IsRoot) { cameraEyeOffset = cameraEyeOffset * part.RotationOffset; - cameraAtOffset = part.OffsetPosition; + cameraAtOffset += part.OffsetPosition; } cameraEyeOffset += part.OffsetPosition; From 5015b0b485058db5bf1f2b56cf375c23349749ad Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 23 May 2014 01:55:05 +0100 Subject: [PATCH 11/18] If one is sitting on a child with an unset camera-eye and so using one set in a root prim, the focus should remain on the root prim. Matches behaviour just tested on the Linden grid. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index f067f9df0f..17f54c2d79 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -2755,15 +2755,19 @@ namespace OpenSim.Region.Framework.Scenes cameraAtOffset = part.GetCameraAtOffset(); - if (cameraAtOffset == Vector3.Zero) + if (!part.IsRoot && cameraAtOffset == Vector3.Zero) cameraAtOffset = part.ParentGroup.RootPart.GetCameraAtOffset(); + bool cameraEyeOffsetFromRootForChild = false; cameraEyeOffset = part.GetCameraEyeOffset(); - if (cameraEyeOffset == Vector3.Zero) + if (!part.IsRoot && cameraEyeOffset == Vector3.Zero) + { cameraEyeOffset = part.ParentGroup.RootPart.GetCameraEyeOffset(); + cameraEyeOffsetFromRootForChild = true; + } - if (cameraEyeOffset != Vector3.Zero || cameraAtOffset != Vector3.Zero) + if ((cameraEyeOffset != Vector3.Zero && !cameraEyeOffsetFromRootForChild) || cameraAtOffset != Vector3.Zero) { if (!part.IsRoot) { From 72c67c50911e31937826314c825fdf13baa1cc28 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 23 May 2014 20:14:49 +0100 Subject: [PATCH 12/18] Fix possible infinite recursion in MessageTransferModule.SendGridInstantMessageViaXMLRPCAsync() whilst preserving retry lookup behaviour. This is based on heavily mikemig's original patch in http://opensimulator.org/mantis/view.php?id=7149 but instead of exiting after the first IM delivery failure to presence information retrieved from the presence service it will retry the lookup until the result matches the previous lookup. This is to deal with the case where the agent is sent an IM whilst they are teleporting. --- .../InstantMessage/MessageTransferModule.cs | 166 ++++++------------ 1 file changed, 57 insertions(+), 109 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs index 7aa7123144..2462ff837b 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/MessageTransferModule.cs @@ -428,7 +428,7 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage /// /// delegate for sending a grid instant message asynchronously /// - public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID); + public delegate void GridInstantMessageDelegate(GridInstantMessage im, MessageResultNotification result); protected virtual void GridInstantMessageCompleted(IAsyncResult iar) { @@ -442,138 +442,87 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage { GridInstantMessageDelegate d = SendGridInstantMessageViaXMLRPCAsync; - d.BeginInvoke(im, result, UUID.Zero, GridInstantMessageCompleted, d); + d.BeginInvoke(im, result, GridInstantMessageCompleted, d); } /// - /// Recursive SendGridInstantMessage over XMLRPC method. - /// This is called from within a dedicated thread. - /// The first time this is called, prevRegionHandle will be 0 Subsequent times this is called from - /// itself, prevRegionHandle will be the last region handle that we tried to send. - /// If the handles are the same, we look up the user's location using the grid. - /// If the handles are still the same, we end. The send failed. + /// Internal SendGridInstantMessage over XMLRPC method. /// - /// - /// Pass in 0 the first time this method is called. It will be called recursively with the last - /// regionhandle tried - /// - protected virtual void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result, UUID prevRegionID) + /// + /// This is called from within a dedicated thread. + /// + private void SendGridInstantMessageViaXMLRPCAsync(GridInstantMessage im, MessageResultNotification result) { UUID toAgentID = new UUID(im.toAgentID); - - PresenceInfo upd = null; - - bool lookupAgent = false; + UUID regionID; + bool needToLookupAgent; lock (m_UserRegionMap) - { - if (m_UserRegionMap.ContainsKey(toAgentID)) - { - upd = new PresenceInfo(); - upd.RegionID = m_UserRegionMap[toAgentID]; + needToLookupAgent = !m_UserRegionMap.TryGetValue(toAgentID, out regionID); - // We need to compare the current regionhandle with the previous region handle - // or the recursive loop will never end because it will never try to lookup the agent again - if (prevRegionID == upd.RegionID) - { - lookupAgent = true; - } - } - else - { - lookupAgent = true; - } - } - - - // Are we needing to look-up an agent? - if (lookupAgent) + while (true) { - // Non-cached user agent lookup. - PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() }); - if (presences != null && presences.Length > 0) + if (needToLookupAgent) { - foreach (PresenceInfo p in presences) + PresenceInfo[] presences = PresenceService.GetAgents(new string[] { toAgentID.ToString() }); + + UUID foundRegionID = UUID.Zero; + + if (presences != null) { - if (p.RegionID != UUID.Zero) + foreach (PresenceInfo p in presences) { - upd = p; - break; + if (p.RegionID != UUID.Zero) + { + foundRegionID = p.RegionID; + break; + } } } + + // If not found or the found region is the same as the last lookup, then message is undeliverable + if (foundRegionID == UUID.Zero || foundRegionID == regionID) + break; + else + regionID = foundRegionID; } - if (upd != null) + GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, regionID); + if (reginfo == null) { - // check if we've tried this before.. - // This is one way to end the recursive loop - // - if (upd.RegionID == prevRegionID) - { - // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); - HandleUndeliverableMessage(im, result); - return; - } + m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", regionID); + break; } - else + + // Try to send the message to the agent via the retrieved region. + Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); + msgdata["region_handle"] = 0; + bool imresult = doIMSending(reginfo, msgdata); + + // If the message delivery was successful, then cache the entry. + if (imresult) { - // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); - HandleUndeliverableMessage(im, result); + lock (m_UserRegionMap) + { + m_UserRegionMap[toAgentID] = regionID; + } + result(true); return; } + + // If we reach this point in the first iteration of the while, then we may have unsuccessfully tried + // to use a locally cached region ID. All subsequent attempts need to lookup agent details from + // the presence service. + needToLookupAgent = true; } - if (upd != null) - { - GridRegion reginfo = m_Scenes[0].GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, - upd.RegionID); - if (reginfo != null) - { - Hashtable msgdata = ConvertGridInstantMessageToXMLRPC(im); - // Not actually used anymore, left in for compatibility - // Remove at next interface change - // - msgdata["region_handle"] = 0; - bool imresult = doIMSending(reginfo, msgdata); - if (imresult) - { - // IM delivery successful, so store the Agent's location in our local cache. - lock (m_UserRegionMap) - { - if (m_UserRegionMap.ContainsKey(toAgentID)) - { - m_UserRegionMap[toAgentID] = upd.RegionID; - } - else - { - m_UserRegionMap.Add(toAgentID, upd.RegionID); - } - } - result(true); - } - else - { - // try again, but lookup user this time. - // Warning, this must call the Async version - // of this method or we'll be making thousands of threads - // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync - // The version that spawns the thread is SendGridInstantMessageViaXMLRPC + // If we reached this point then the message was not deliverable. Remove the bad cache entry and + // signal the delivery failure. + lock (m_UserRegionMap) + m_UserRegionMap.Remove(toAgentID); - // This is recursive!!!!! - SendGridInstantMessageViaXMLRPCAsync(im, result, - upd.RegionID); - } - } - else - { - m_log.WarnFormat("[GRID INSTANT MESSAGE]: Unable to find region {0}", upd.RegionID); - HandleUndeliverableMessage(im, result); - } - } - else - { - HandleUndeliverableMessage(im, result); - } + // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); + HandleUndeliverableMessage(im, result); } /// @@ -584,7 +533,6 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage /// Bool if the message was successfully delivered at the other side. protected virtual bool doIMSending(GridRegion reginfo, Hashtable xmlrpcdata) { - ArrayList SendParams = new ArrayList(); SendParams.Add(xmlrpcdata); XmlRpcRequest GridReq = new XmlRpcRequest("grid_instant_message", SendParams); From fbcb76383d5083a7a1b4c4ba75d37b247859a87d Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 23 May 2014 20:57:50 +0100 Subject: [PATCH 13/18] Allow console output to be multiline by making colourization regex RegexOptions.SingleLine --- OpenSim/Framework/Console/LocalConsole.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Framework/Console/LocalConsole.cs b/OpenSim/Framework/Console/LocalConsole.cs index a967db6271..b17b8e0f74 100644 --- a/OpenSim/Framework/Console/LocalConsole.cs +++ b/OpenSim/Framework/Console/LocalConsole.cs @@ -283,7 +283,7 @@ namespace OpenSim.Framework.Console { string regex = @"^(?.*?)\[(?[^\]]+)\]:?(?.*)"; - Regex RE = new Regex(regex, RegexOptions.Multiline); + Regex RE = new Regex(regex, RegexOptions.Singleline); MatchCollection matches = RE.Matches(text); if (matches.Count == 1) From f55e15363665ac885b51fa549c9c1566e9ea0cc6 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 23 May 2014 21:09:48 +0100 Subject: [PATCH 14/18] Compile the regex that extract categories for colourization just once rather than on every single log. Compiling every time is unnecessary since Regex is thread-safe. --- OpenSim/Framework/Console/LocalConsole.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/OpenSim/Framework/Console/LocalConsole.cs b/OpenSim/Framework/Console/LocalConsole.cs index b17b8e0f74..260a86fb9a 100644 --- a/OpenSim/Framework/Console/LocalConsole.cs +++ b/OpenSim/Framework/Console/LocalConsole.cs @@ -46,6 +46,11 @@ namespace OpenSim.Framework.Console // private readonly object m_syncRoot = new object(); private const string LOGLEVEL_NONE = "(none)"; + // Used to extract categories for colourization. + private Regex m_categoryRegex + = new Regex( + @"^(?.*?)\[(?[^\]]+)\]:?(?.*)", RegexOptions.Singleline | RegexOptions.Compiled); + private int m_cursorYPosition = -1; private int m_cursorXPosition = 0; private StringBuilder m_commandLine = new StringBuilder(); @@ -280,11 +285,8 @@ namespace OpenSim.Framework.Console string outText = text; if (level != LOGLEVEL_NONE) - { - string regex = @"^(?.*?)\[(?[^\]]+)\]:?(?.*)"; - - Regex RE = new Regex(regex, RegexOptions.Singleline); - MatchCollection matches = RE.Matches(text); + { + MatchCollection matches = m_categoryRegex.Matches(text); if (matches.Count == 1) { From b3a496d6f2fa09659b0109f745632bc80acc756f Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 23 May 2014 21:13:37 +0100 Subject: [PATCH 15/18] Add mikemig to contributors --- CONTRIBUTORS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index fa79ea7d54..1d080ff037 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -134,6 +134,7 @@ what it is today. * Micheil Merlin * Mike Osias (IBM) * Mike Pitman (IBM) +* mikemig * mikkopa/_someone - RealXtend * Misterblue * Mircea Kitsune From 250ea09328253422ff2a0e4877ee9968556328f0 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 23 May 2014 22:12:49 +0100 Subject: [PATCH 16/18] Reactivate regression test TestCastAndConcatString() in CompilerTests. --- .../ScriptEngine/Shared/CodeTools/Compiler.cs | 4 ++-- .../Shared/CodeTools/Tests/CompilerTest.cs | 24 ++++++++++++------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs index b4640eff12..1efe798d2f 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs @@ -444,7 +444,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // return compileScript; // } - private static string CreateCSCompilerScript( + public static string CreateCSCompilerScript( string compileScript, string className, string baseClassName, ParameterInfo[] constructorParameters) { compileScript = string.Format( @@ -472,7 +472,7 @@ namespace SecondLife return compileScript; } - private static string CreateVBCompilerScript(string compileScript, string className, string baseClassName) + public static string CreateVBCompilerScript(string compileScript, string className, string baseClassName) { compileScript = String.Empty + "Imports OpenSim.Region.ScriptEngine.Shared: Imports System.Collections.Generic: " + diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs index 05a8756e6e..29b6006594 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs @@ -31,6 +31,7 @@ using System.Collections.Generic; using Microsoft.CSharp; using NUnit.Framework; using OpenSim.Region.ScriptEngine.Shared.CodeTools; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenSim.Tests.Common; namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests @@ -66,9 +67,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests m_CSCodeProvider = new CSharpCodeProvider(); m_compilerParameters = new CompilerParameters(); - string rootPath = Path.Combine(Path.GetDirectoryName(System.AppDomain.CurrentDomain.BaseDirectory), "bin"); + string rootPath = Path.Combine(Path.GetDirectoryName(System.AppDomain.CurrentDomain.BaseDirectory)); m_compilerParameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.Shared.dll")); m_compilerParameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.Shared.Api.Runtime.dll")); + m_compilerParameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenMetaverseTypes.dll")); m_compilerParameters.GenerateExecutable = false; } @@ -112,6 +114,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests "public Script() { } " + cg.Convert(input) + "} }\n"; + Dictionary, KeyValuePair> positionMap = cg.PositionMap; m_compilerResults = m_CSCodeProvider.CompileAssemblyFromSource(m_compilerParameters, output); @@ -124,7 +127,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests /// Test that a string can be cast to string and another string /// concatenated. /// - //[Test] + [Test] public void TestCastAndConcatString() { TestHelpers.InMethod(); @@ -143,15 +146,20 @@ default } }"; +// System.Console.WriteLine(input); CSCodeGenerator cg = new CSCodeGenerator(); - string output = "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\n" + - "namespace SecondLife { " + - "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass {\n" + - "public Script() { } " + - cg.Convert(input) + - "} }\n"; + string output = cg.Convert(input); + + output = Compiler.CreateCSCompilerScript(output, "script1", typeof(ScriptBaseClass).FullName, null); +// System.Console.WriteLine(output); + m_compilerResults = m_CSCodeProvider.CompileAssemblyFromSource(m_compilerParameters, output); +// foreach (CompilerError compErr in m_compilerResults.Errors) +// { +// System.Console.WriteLine("Error: {0}", compErr); +// } + Assert.AreEqual(0, m_compilerResults.Errors.Count); } } From cf95b65c10c285b297257db492fbeb9dc19d1d4c Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 23 May 2014 22:29:47 +0100 Subject: [PATCH 17/18] Get regression test TestUseUndeclaredVariable() functional again, though not yet enabled. This reveals the position map problems and will make the fix (and subsequent continual checking) easier. --- .../Shared/CodeTools/Tests/CompilerTest.cs | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs index 29b6006594..ab68793252 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs @@ -108,19 +108,30 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests }"; CSCodeGenerator cg = new CSCodeGenerator(); - string output = "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\n" + - "namespace SecondLife { " + - "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass {\n" + - "public Script() { } " + - cg.Convert(input) + - "} }\n"; + string output = cg.Convert(input); + + output = Compiler.CreateCSCompilerScript(output, "script1", typeof(ScriptBaseClass).FullName, null); + System.Console.WriteLine(output); Dictionary, KeyValuePair> positionMap = cg.PositionMap; m_compilerResults = m_CSCodeProvider.CompileAssemblyFromSource(m_compilerParameters, output); - Assert.AreEqual(new KeyValuePair(5, 21), - positionMap[new KeyValuePair(m_compilerResults.Errors[0].Line, m_compilerResults.Errors[0].Column)]); + foreach (KeyValuePair key in positionMap.Keys) + { + KeyValuePair val = positionMap[key]; + + System.Console.WriteLine("{0},{1} => {2},{3}", key.Key, key.Value, val.Key, val.Value); + } + + foreach (CompilerError compErr in m_compilerResults.Errors) + { + System.Console.WriteLine("Error: {0},{1} => {2}", compErr.Line, compErr.Column, compErr); + } + + Assert.AreEqual( + new KeyValuePair(5, 21), + positionMap[new KeyValuePair(m_compilerResults.Errors[0].Line, m_compilerResults.Errors[0].Column)]); } /// From 9bae636ff0dc426e913e26c45b6936f16131f6d5 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 24 May 2014 00:12:23 +0100 Subject: [PATCH 18/18] Fix issues where reported LSL compiler error line numbers do not match the script. This is probably due to changes in the layout of the generated script preamble (using statements etc, ) in c8afc852 (Jan 17 2013). Re-enabled existing regression test that exercises at least one case of this. --- .../Shared/CodeTools/CSCodeGenerator.cs | 2 +- .../Shared/CodeTools/Tests/CompilerTest.cs | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs index 6aa717db03..8b8e038951 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/CSCodeGenerator.cs @@ -162,7 +162,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools m_braceCount++; // line number - m_CSharpLine += 3; + m_CSharpLine += 9; // here's the payload retstr += GenerateLine(); diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs index ab68793252..badf82adc1 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Tests/CompilerTest.cs @@ -92,7 +92,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests /// Test the C# compiler error message can be mapped to the correct /// line/column in the LSL source when an undeclared variable is used. /// - //[Test] + [Test] public void TestUseUndeclaredVariable() { TestHelpers.InMethod(); @@ -110,24 +110,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests CSCodeGenerator cg = new CSCodeGenerator(); string output = cg.Convert(input); - output = Compiler.CreateCSCompilerScript(output, "script1", typeof(ScriptBaseClass).FullName, null); - System.Console.WriteLine(output); + output = Compiler.CreateCSCompilerScript(output, "script1", typeof(ScriptBaseClass).FullName, null); +// System.Console.WriteLine(output); Dictionary, KeyValuePair> positionMap = cg.PositionMap; m_compilerResults = m_CSCodeProvider.CompileAssemblyFromSource(m_compilerParameters, output); - - foreach (KeyValuePair key in positionMap.Keys) - { - KeyValuePair val = positionMap[key]; - - System.Console.WriteLine("{0},{1} => {2},{3}", key.Key, key.Value, val.Key, val.Value); - } - - foreach (CompilerError compErr in m_compilerResults.Errors) - { - System.Console.WriteLine("Error: {0},{1} => {2}", compErr.Line, compErr.Column, compErr); - } +// +// foreach (KeyValuePair key in positionMap.Keys) +// { +// KeyValuePair val = positionMap[key]; +// +// System.Console.WriteLine("{0},{1} => {2},{3}", key.Key, key.Value, val.Key, val.Value); +// } +// +// foreach (CompilerError compErr in m_compilerResults.Errors) +// { +// System.Console.WriteLine("Error: {0},{1} => {2}", compErr.Line, compErr.Column, compErr); +// } Assert.AreEqual( new KeyValuePair(5, 21),