diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index e2eb89e566..30b44b15b2 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -3179,6 +3179,11 @@ namespace OpenSim.Region.Framework.Scenes
return m_sceneGridService.CrossToNeighbouringRegion(regionHandle, agentID, position, isFlying);
}
+ public void CrossAgentToNewRegion(ScenePresence agent, bool isFlying)
+ {
+ m_sceneGridService.CrossAgentToNewRegion(this, agent, isFlying);
+ }
+
public void SendOutChildAgentUpdates(AgentPosition cadu, ScenePresence presence)
{
m_sceneGridService.SendChildAgentDataUpdate(cadu, presence);
diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
index bef57a0096..98b0f97f24 100644
--- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
@@ -35,6 +35,7 @@ using OpenMetaverse.StructuredData;
using log4net;
using OpenSim.Framework;
using OpenSim.Framework.Communications;
+using OpenSim.Framework.Communications.Cache;
using OpenSim.Framework.Communications.Capabilities;
using OpenSim.Region.Framework.Interfaces;
using OSD = OpenMetaverse.StructuredData.OSD;
@@ -1018,6 +1019,175 @@ namespace OpenSim.Region.Framework.Scenes
return m_commsProvider.InterRegion.ExpectAvatarCrossing(regionhandle, agentID, position, isFlying);
}
+ public void CrossAgentToNewRegion(Scene scene, ScenePresence agent, bool isFlying)
+ {
+ Vector3 pos = agent.AbsolutePosition;
+ Vector3 newpos = new Vector3(pos.X, pos.Y, pos.Z);
+ uint neighbourx = m_regionInfo.RegionLocX;
+ uint neighboury = m_regionInfo.RegionLocY;
+
+ // distance to edge that will trigger crossing
+ const float boundaryDistance = 1.7f;
+
+ // distance into new region to place avatar
+ const float enterDistance = 0.1f;
+
+ if (pos.X < boundaryDistance)
+ {
+ neighbourx--;
+ newpos.X = Constants.RegionSize - enterDistance;
+ }
+ else if (pos.X > Constants.RegionSize - boundaryDistance)
+ {
+ neighbourx++;
+ newpos.X = enterDistance;
+ }
+
+ if (pos.Y < boundaryDistance)
+ {
+ neighboury--;
+ newpos.Y = Constants.RegionSize - enterDistance;
+ }
+ else if (pos.Y > Constants.RegionSize - boundaryDistance)
+ {
+ neighboury++;
+ newpos.Y = enterDistance;
+ }
+
+ Vector3 vel = agent.Velocity;
+
+ CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync;
+ d.BeginInvoke(agent, newpos, neighbourx, neighboury, isFlying, CrossAgentToNewRegionCompleted, d);
+
+
+ }
+
+ public delegate ScenePresence CrossAgentToNewRegionDelegate(ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, bool isFlying);
+
+ ///
+ /// This Closes child agents on neighboring regions
+ /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
+ ///
+ protected ScenePresence CrossAgentToNewRegionAsync(ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, bool isFlying)
+ {
+ m_log.DebugFormat("[SCENE COMM]: Crossing agent {0} {1} to {2}-{3}", agent.Firstname, agent.Lastname, neighbourx, neighboury);
+
+ ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize));
+ SimpleRegionInfo neighbourRegion = RequestNeighbouringRegionInfo(neighbourHandle);
+ if (neighbourRegion != null && agent.ValidateAttachments())
+ {
+ pos = pos + (agent.Velocity);
+
+ CachedUserInfo userInfo = m_commsProvider.UserProfileCacheService.GetUserDetails(agent.UUID);
+ if (userInfo != null)
+ {
+ userInfo.DropInventory();
+ }
+ else
+ {
+ m_log.WarnFormat("[SCENE COMM]: No cached user info found for {0} {1} on leaving region {2}",
+ agent.Name, agent.UUID, agent.Scene.RegionInfo.RegionName);
+ }
+
+ bool crossingSuccessful =
+ CrossToNeighbouringRegion(neighbourHandle, agent.ControllingClient.AgentId, pos,
+ isFlying);
+ if (crossingSuccessful)
+ {
+ // Next, let's close the child agent connections that are too far away.
+ agent.CloseChildAgents(neighbourx, neighboury);
+
+ //AgentCircuitData circuitdata = m_controllingClient.RequestClientInfo();
+ agent.ControllingClient.RequestClientInfo();
+
+ //Console.WriteLine("BEFORE CROSS");
+ //Scene.DumpChildrenSeeds(UUID);
+ //DumpKnownRegions();
+ string agentcaps;
+ if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps))
+ {
+ m_log.ErrorFormat("[SCENE COMM]: No CAPS information for region handle {0}, exiting CrossToNewRegion.",
+ neighbourRegion.RegionHandle);
+ return agent;
+ }
+ // TODO Should construct this behind a method
+ string capsPath =
+ "http://" + neighbourRegion.ExternalHostName + ":" + neighbourRegion.HttpPort
+ + "/CAPS/" + agentcaps /*circuitdata.CapsPath*/ + "0000/";
+
+ m_log.DebugFormat("[CAPS]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID);
+
+ IEventQueue eq = agent.Scene.RequestModuleInterface();
+ if (eq != null)
+ {
+ eq.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint,
+ capsPath, agent.UUID, agent.ControllingClient.SessionId);
+ }
+ else
+ {
+ agent.ControllingClient.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint,
+ capsPath);
+ }
+
+ agent.MakeChildAgent();
+ // now we have a child agent in this region. Request all interesting data about other (root) agents
+ agent.SendInitialFullUpdateToAllClients();
+
+ agent.CrossAttachmentsIntoNewRegion(neighbourHandle, true);
+
+ // m_scene.SendKillObject(m_localId);
+
+ agent.Scene.NotifyMyCoarseLocationChange();
+ // the user may change their profile information in other region,
+ // so the userinfo in UserProfileCache is not reliable any more, delete it
+ if (agent.Scene.NeedSceneCacheClear(agent.UUID))
+ {
+ agent.Scene.CommsManager.UserProfileCacheService.RemoveUser(agent.UUID);
+ m_log.DebugFormat(
+ "[SCENE COMM]: User {0} is going to another region, profile cache removed", agent.UUID);
+ }
+ }
+ else
+ {
+ //// Restore the user structures that we needed to delete before asking the receiving region
+ //// to complete the crossing
+ //userInfo.FetchInventory();
+ //agent.Scene.CapsModule.AddCapsHandler(agent.UUID);
+ }
+ }
+
+ //Console.WriteLine("AFTER CROSS");
+ //Scene.DumpChildrenSeeds(UUID);
+ //DumpKnownRegions();
+ return agent;
+ }
+
+ private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
+ {
+ CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
+ ScenePresence agent = icon.EndInvoke(iar);
+
+ // If the cross was successful, this agent is a child agent
+ if (agent.IsChildAgent)
+ {
+ // Put the child agent back at the center
+ agent.AbsolutePosition = new Vector3(128, 128, 70);
+ }
+ else // Not successful
+ {
+ CachedUserInfo userInfo = m_commsProvider.UserProfileCacheService.GetUserDetails(agent.UUID);
+ if (userInfo != null)
+ {
+ userInfo.FetchInventory();
+ }
+ agent.RestoreInCurrentScene();
+ }
+ agent.IsInTransit = false;
+
+ //m_log.DebugFormat("[SCENE COMM]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
+ }
+
+
public bool PrimCrossToNeighboringRegion(ulong regionhandle, UUID primID, string objData, int XMLMethod)
{
return m_commsProvider.InterRegion.InformRegionOfPrimCrossing(regionhandle, primID, objData, XMLMethod);
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 2dd305a916..f841707da5 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -547,6 +547,13 @@ namespace OpenSim.Region.Framework.Scenes
get { return m_animations; }
}
+ private bool m_inTransit;
+ public bool IsInTransit
+ {
+ get { return m_inTransit; }
+ set { m_inTransit = value; }
+ }
+
#endregion
#region Constructor(s)
@@ -850,7 +857,7 @@ namespace OpenSim.Region.Framework.Scenes
CachedUserInfo userInfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(m_uuid);
if (userInfo != null)
- userInfo.FetchInventory();
+ userInfo.FetchInventory();
else
m_log.ErrorFormat("[SCENE]: Could not find user info for {0} when making it a root agent", m_uuid);
@@ -2377,15 +2384,31 @@ namespace OpenSim.Region.Framework.Scenes
pos2.Y = pos2.Y + (vel.Y*timeStep);
pos2.Z = pos2.Z + (vel.Z*timeStep);
- if ((pos2.X < 0) || (pos2.X > Constants.RegionSize))
+ if (!IsInTransit)
{
- CrossToNewRegion();
+ if ((pos2.X < 0) || (pos2.X > Constants.RegionSize))
+ {
+ CrossToNewRegion();
+ }
+
+ if ((pos2.Y < 0) || (pos2.Y > Constants.RegionSize))
+ {
+ CrossToNewRegion();
+ }
+ }
+ else
+ {
+ RemoveFromPhysicalScene();
+ // This constant has been inferred from experimentation
+ // I'm not sure what this value should be, so I tried a few values.
+ timeStep = 0.04f;
+ pos2 = AbsolutePosition;
+ pos2.X = pos2.X + (vel.X * timeStep);
+ pos2.Y = pos2.Y + (vel.Y * timeStep);
+ pos2.Z = pos2.Z + (vel.Z * timeStep);
+ m_pos = pos2;
}
- if ((pos2.Y < 0) || (pos2.Y > Constants.RegionSize))
- {
- CrossToNewRegion();
- }
}
///
@@ -2396,130 +2419,13 @@ namespace OpenSim.Region.Framework.Scenes
///
protected void CrossToNewRegion()
{
- Vector3 pos = AbsolutePosition;
- Vector3 newpos = new Vector3(pos.X, pos.Y, pos.Z);
- uint neighbourx = m_regionInfo.RegionLocX;
- uint neighboury = m_regionInfo.RegionLocY;
+ m_inTransit = true;
+ m_scene.CrossAgentToNewRegion(this, m_physicsActor.Flying);
+ }
- // distance to edge that will trigger crossing
- const float boundaryDistance = 1.7f;
-
- // distance into new region to place avatar
- const float enterDistance = 0.1f;
-
- if (pos.X < boundaryDistance)
- {
- neighbourx--;
- newpos.X = Constants.RegionSize - enterDistance;
- }
- else if (pos.X > Constants.RegionSize - boundaryDistance)
- {
- neighbourx++;
- newpos.X = enterDistance;
- }
-
- if (pos.Y < boundaryDistance)
- {
- neighboury--;
- newpos.Y = Constants.RegionSize - enterDistance;
- }
- else if (pos.Y > Constants.RegionSize - boundaryDistance)
- {
- neighboury++;
- newpos.Y = enterDistance;
- }
-
- Vector3 vel = m_velocity;
- ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize));
- SimpleRegionInfo neighbourRegion = m_scene.RequestNeighbouringRegionInfo(neighbourHandle);
- if (neighbourRegion != null && ValidateAttachments())
- {
- // When the neighbour is informed of the border crossing, it will set up CAPS handlers for the avatar
- // This means we need to remove the current caps handler here and possibly compensate later,
- // in case both scenes are being hosted on the same region server. Messy
- //m_scene.RemoveCapsHandler(UUID);
- newpos = newpos + (vel);
-
- CachedUserInfo userInfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(UUID);
- if (userInfo != null)
- {
- userInfo.DropInventory();
- }
- else
- {
- m_log.WarnFormat("[SCENE PRESENCE]: No cached user info found for {0} {1} on leaving region", Name, UUID);
- }
-
- bool crossingSuccessful =
- m_scene.InformNeighbourOfCrossing(neighbourHandle, m_controllingClient.AgentId, newpos,
- m_physicsActor.Flying);
- if (crossingSuccessful)
- {
- // Next, let's close the child agent connections that are too far away.
- CloseChildAgents(neighbourx, neighboury);
-
- //AgentCircuitData circuitdata = m_controllingClient.RequestClientInfo();
- m_controllingClient.RequestClientInfo();
-
- //Console.WriteLine("BEFORE CROSS");
- //Scene.DumpChildrenSeeds(UUID);
- //DumpKnownRegions();
- string agentcaps;
- if (!m_knownChildRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps))
- {
- m_log.ErrorFormat("[SCENE PRESENCE]: No CAPS information for region handle {0}, exiting CrossToNewRegion.",
- neighbourRegion.RegionHandle);
- return;
- }
- // TODO Should construct this behind a method
- string capsPath =
- "http://" + neighbourRegion.ExternalHostName + ":" + neighbourRegion.HttpPort
- + "/CAPS/" + agentcaps /*circuitdata.CapsPath*/ + "0000/";
-
- m_log.DebugFormat("[CAPS]: Sending new CAPS seed url {0} to client {1}", capsPath, m_uuid);
-
- IEventQueue eq = m_scene.RequestModuleInterface();
- if (eq != null)
- {
- eq.CrossRegion(neighbourHandle, newpos, vel, neighbourRegion.ExternalEndPoint,
- capsPath, UUID, ControllingClient.SessionId);
- }
- else
- {
- m_controllingClient.CrossRegion(neighbourHandle, newpos, vel, neighbourRegion.ExternalEndPoint,
- capsPath);
- }
-
- MakeChildAgent();
- // now we have a child agent in this region. Request all interesting data about other (root) agents
- SendInitialFullUpdateToAllClients();
-
- CrossAttachmentsIntoNewRegion(neighbourHandle, true);
-
- // m_scene.SendKillObject(m_localId);
-
- m_scene.NotifyMyCoarseLocationChange();
- // the user may change their profile information in other region,
- // so the userinfo in UserProfileCache is not reliable any more, delete it
- if (m_scene.NeedSceneCacheClear(UUID))
- {
- m_scene.CommsManager.UserProfileCacheService.RemoveUser(UUID);
- m_log.DebugFormat(
- "[SCENE PRESENCE]: User {0} is going to another region, profile cache removed", UUID);
- }
- }
- else
- {
- // Restore the user structures that we needed to delete before asking the receiving region
- // to complete the crossing
- userInfo.FetchInventory();
- m_scene.CapsModule.AddCapsHandler(UUID);
- }
- }
-
- //Console.WriteLine("AFTER CROSS");
- //Scene.DumpChildrenSeeds(UUID);
- //DumpKnownRegions();
+ public void RestoreInCurrentScene()
+ {
+ AddToPhysicalScene();
}
///
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs
index db88878f09..2f2bc19b33 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTests.cs
@@ -66,11 +66,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests
scene2 = SceneSetupHelpers.SetupScene("Neighbour x+1", UUID.Random(), 1001, 1000, cm);
scene3 = SceneSetupHelpers.SetupScene("Neighbour x-1", UUID.Random(), 999, 1000, cm);
- IRegionModule interregionComms = new RESTInterregionComms();
- interregionComms.Initialise(scene, new IniConfigSource());
- interregionComms.Initialise(scene2, new IniConfigSource());
- interregionComms.Initialise(scene3, new IniConfigSource());
- interregionComms.PostInitialise();
+ IRegionModule interregionComms = new RESTInterregionComms();
+ interregionComms.Initialise(scene, new IniConfigSource());
+ interregionComms.Initialise(scene2, new IniConfigSource());
+ interregionComms.Initialise(scene3, new IniConfigSource());
+ interregionComms.PostInitialise();
SceneSetupHelpers.SetupSceneModules(scene, new IniConfigSource(), interregionComms);
SceneSetupHelpers.SetupSceneModules(scene2, new IniConfigSource(), interregionComms);
SceneSetupHelpers.SetupSceneModules(scene3, new IniConfigSource(), interregionComms);
@@ -203,6 +203,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
scene.RegisterRegionWithGrid();
scene2.RegisterRegionWithGrid();
presence.Update();
+ // Crossings are asynchronous
+ while (presence.IsInTransit) { } ;
Assert.That(presence.IsChildAgent, Is.True, "Did not complete region cross as expected.");
Assert.That(presence2.IsChildAgent, Is.False, "Did not receive root status after receiving agent.");
@@ -210,6 +212,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
// Cross Back
presence2.AbsolutePosition = new Vector3(-1, 3, 100);
presence2.Update();
+ // Crossings are asynchronous
+ while (presence.IsInTransit) { };
Assert.That(presence2.IsChildAgent, Is.True, "Did not return from region as expected.");
Assert.That(presence.IsChildAgent, Is.False, "Presence was not made root in old region again.");