From e6eb571c1d19972fe7eb4c3f7de113b1b91f5e02 Mon Sep 17 00:00:00 2001
From: Charles Krinke
Date: Sun, 14 Dec 2008 02:17:12 +0000
Subject: Mantis#2725. Thank you kindly, Diva, for a patch that: Adds missing
protocol pieces for EstablishAgentCommunication event which allows the client
to activate CAPS and the EQ for child agents.
---
.../Scenes/SceneCommunicationService.cs | 266 ++++++++++++++++-----
1 file changed, 200 insertions(+), 66 deletions(-)
(limited to 'OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs')
diff --git a/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs
index 2b638e3..b89f753 100644
--- a/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs
+++ b/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs
@@ -255,7 +255,7 @@ namespace OpenSim.Region.Environment.Scenes
#region Inform Client of Neighbours
private delegate void InformClientOfNeighbourDelegate(
- ScenePresence avatar, AgentCircuitData a, ulong regionHandle, IPEndPoint endPoint);
+ ScenePresence avatar, AgentCircuitData a, SimpleRegionInfo reg, IPEndPoint endPoint);
private void InformClientOfNeighbourCompleted(IAsyncResult iar)
{
@@ -273,28 +273,40 @@ namespace OpenSim.Region.Environment.Scenes
///
///
///
- private void InformClientOfNeighbourAsync(ScenePresence avatar, AgentCircuitData a, ulong regionHandle,
+ private void InformClientOfNeighbourAsync(ScenePresence avatar, AgentCircuitData a, SimpleRegionInfo reg,
IPEndPoint endPoint)
{
- m_log.Info("[INTERGRID]: Starting to inform client about neighbours");
- bool regionAccepted = m_commsProvider.InterRegion.InformRegionOfChildAgent(regionHandle, a);
+ uint x, y;
+ Utils.LongToUInts(reg.RegionHandle, out x, out y);
+ x = x / Constants.RegionSize;
+ y = y / Constants.RegionSize;
+ m_log.Info("[INTERGRID]: Starting to inform client about neighbour " + x + ", " + y + "(" + endPoint.ToString() + ")");
+
+ string capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort
+ + "/CAPS/" + a.CapsPath + "0000/";
+
+ bool regionAccepted = m_commsProvider.InterRegion.InformRegionOfChildAgent(reg.RegionHandle, a);
if (regionAccepted)
{
IEventQueue eq = avatar.Scene.RequestModuleInterface();
if (eq != null)
{
- OSD Item = EventQueueHelper.EnableSimulator(regionHandle, endPoint);
+ OSD Item = EventQueueHelper.EnableSimulator(reg.RegionHandle, endPoint);
eq.Enqueue(Item, avatar.UUID);
+
+ Item = EventQueueHelper.EstablishAgentCommunication(avatar.UUID, endPoint.ToString(), capsPath);
+ eq.Enqueue(Item, avatar.UUID);
+
+ m_log.DebugFormat("[CAPS]: Sending new CAPS seed url {0} to client {1} in region {2}", capsPath, avatar.UUID, avatar.Scene.RegionInfo.RegionName);
}
else
{
- avatar.ControllingClient.InformClientOfNeighbour(regionHandle, endPoint);
+ avatar.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint);
// TODO: make Event Queue disablable!
}
-
- avatar.AddNeighbourRegion(regionHandle);
- m_log.Info("[INTERGRID]: Completed inform client about neighbours");
+
+ m_log.Info("[INTERGRID]: Completed inform client about neighbour " + endPoint.ToString());
}
}
@@ -330,21 +342,72 @@ namespace OpenSim.Region.Environment.Scenes
neighbours =
m_commsProvider.GridService.RequestNeighbours(m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
- if (neighbours != null)
+ m_log.Debug("[SCM]: EnableChildAgents from " + avatar.Scene.RegionInfo.RegionName);
+
+ /// We need to find the difference between the new regions where there are no child agents
+ /// and the regions where there are already child agents. We only send notification to the former.
+ List neighbourHandles = NeighbourHandles(neighbours); // on this region
+ neighbourHandles.Add(avatar.Scene.RegionInfo.RegionHandle); // add this region too
+ List previousRegionNeighbourHandles = new List(avatar.Scene.GetChildrenSeeds(avatar.UUID).Keys);
+ List newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles);
+ List oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles);
+
+ //Dump("Current Neighbors", neighbourHandles);
+ //Dump("Previous Neighbours", previousRegionNeighbourHandles);
+ //Dump("New Neighbours", newRegions);
+ //Dump("Old Neighbours", oldRegions);
+
+ /// Update the scene presence's known regions here on this region
+ avatar.DropOldNeighbours(oldRegions);
+
+ /// Collect as many seeds as possible
+ Dictionary seeds = new Dictionary(avatar.Scene.GetChildrenSeeds(avatar.UUID));
+ if (!seeds.ContainsKey(avatar.Scene.RegionInfo.RegionHandle))
+ seeds.Add(avatar.Scene.RegionInfo.RegionHandle, avatar.ControllingClient.RequestClientInfo().CapsPath);
+
+ /// Create the necessary child agents
+ List cagents = new List();
+ foreach (SimpleRegionInfo neighbour in neighbours)
{
- for (int i = 0; i < neighbours.Count; i++)
+ AgentCircuitData agent = avatar.ControllingClient.RequestClientInfo();
+ agent.BaseFolder = UUID.Zero;
+ agent.InventoryFolder = UUID.Zero;
+ agent.startpos = new Vector3(128, 128, 70);
+ agent.child = true;
+
+ if (newRegions.Contains(neighbour.RegionHandle))
{
- AgentCircuitData agent = avatar.ControllingClient.RequestClientInfo();
- agent.BaseFolder = UUID.Zero;
- agent.InventoryFolder = UUID.Zero;
- agent.startpos = new Vector3(128, 128, 70);
- agent.child = true;
+ agent.CapsPath = Util.GetRandomCapsPath();
+ avatar.AddNeighbourRegion(neighbour.RegionHandle, agent.CapsPath);
+ seeds.Add(neighbour.RegionHandle, agent.CapsPath);
+ }
+ else
+ agent.CapsPath = avatar.Scene.GetChildSeed(avatar.UUID, neighbour.RegionHandle);
- InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
+ cagents.Add(agent);
+ }
+ /// Update all child agent with everyone's seeds
+ foreach (AgentCircuitData a in cagents)
+ {
+ a.ChildrenCapSeeds = new Dictionary(seeds);
+ }
+ // These two are the same thing!
+ avatar.Scene.SetChildrenSeed(avatar.UUID, seeds);
+ avatar.KnownRegions = seeds;
+ //avatar.Scene.DumpChildrenSeeds(avatar.UUID);
+ //avatar.DumpKnownRegions();
+
+ int count = 0;
+ foreach (SimpleRegionInfo neighbour in neighbours)
+ {
+ // Don't do it if there's already an agent in that region
+ if (newRegions.Contains(neighbour.RegionHandle))
+ {
+ InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
try
{
- d.BeginInvoke(avatar, agent, neighbours[i].RegionHandle, neighbours[i].ExternalEndPoint,
+ d.BeginInvoke(avatar, cagents[count], neighbour, neighbour.ExternalEndPoint,
InformClientOfNeighbourCompleted,
d);
}
@@ -352,10 +415,10 @@ namespace OpenSim.Region.Environment.Scenes
{
m_log.ErrorFormat(
"[REGIONINFO]: Could not resolve external hostname {0} for region {1} ({2}, {3}). {4}",
- neighbours[i].ExternalHostName,
- neighbours[i].RegionHandle,
- neighbours[i].RegionLocX,
- neighbours[i].RegionLocY,
+ neighbour.ExternalHostName,
+ neighbour.RegionHandle,
+ neighbour.RegionLocX,
+ neighbour.RegionLocY,
e);
// FIXME: Okay, even though we've failed, we're still going to throw the exception on,
@@ -366,6 +429,11 @@ namespace OpenSim.Region.Environment.Scenes
}
}
+ else
+ m_log.Debug("[SCM]: Skipping common neighbor " + neighbour.RegionLocX + ", " + neighbour.RegionLocY);
+
+ count++;
+
}
}
@@ -373,7 +441,7 @@ namespace OpenSim.Region.Environment.Scenes
/// This informs a single neighboring region about agent "avatar".
/// Calls an asynchronous method to do so.. so it doesn't lag the sim.
///
- public void InformNeighborChildAgent(ScenePresence avatar, RegionInfo region, List neighbours)
+ public void InformNeighborChildAgent(ScenePresence avatar, SimpleRegionInfo region, List neighbours)
{
AgentCircuitData agent = avatar.ControllingClient.RequestClientInfo();
agent.BaseFolder = UUID.Zero;
@@ -382,7 +450,7 @@ namespace OpenSim.Region.Environment.Scenes
agent.child = true;
InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync;
- d.BeginInvoke(avatar, agent, region.RegionHandle, region.ExternalEndPoint,
+ d.BeginInvoke(avatar, agent, region, region.ExternalEndPoint,
InformClientOfNeighbourCompleted,
d);
}
@@ -463,10 +531,10 @@ namespace OpenSim.Region.Environment.Scenes
///
private void SendChildAgentDataUpdateAsync(ChildAgentDataUpdate cAgentData, ScenePresence presence)
{
- //m_log.Info("[INTERGRID]: Informing neighbors about my agent.");
+ m_log.Info("[INTERGRID]: Informing neighbors about my agent in " + presence.Scene.RegionInfo.RegionName);
try
{
- foreach (ulong regionHandle in presence.KnownChildRegions)
+ foreach (ulong regionHandle in presence.KnownChildRegionHandles)
{
bool regionAccepted = m_commsProvider.InterRegion.ChildAgentUpdate(regionHandle, cAgentData);
@@ -508,11 +576,12 @@ namespace OpenSim.Region.Environment.Scenes
/// This Closes child agents on neighboring regions
/// Calls an asynchronous method to do so.. so it doesn't lag the sim.
///
- private void SendCloseChildAgentAsync(UUID agentID, List regionlst)
+ protected void SendCloseChildAgentAsync(UUID agentID, List regionlst)
{
foreach (ulong regionHandle in regionlst)
{
+ m_log.Debug("[INTERGRID]: Sending close agent to " + regionHandle);
bool regionAccepted = m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID);
if (regionAccepted)
@@ -527,14 +596,14 @@ namespace OpenSim.Region.Environment.Scenes
}
}
- // We remove the list of known regions from the agent's known region list through an event
- // to scene, because, if an agent logged of, it's likely that there will be no scene presence
- // by the time we get to this part of the method.
- handlerRemoveKnownRegionFromAvatar = OnRemoveKnownRegionFromAvatar;
- if (handlerRemoveKnownRegionFromAvatar != null)
- {
- handlerRemoveKnownRegionFromAvatar(agentID, regionlst);
- }
+ //// We remove the list of known regions from the agent's known region list through an event
+ //// to scene, because, if an agent logged of, it's likely that there will be no scene presence
+ //// by the time we get to this part of the method.
+ //handlerRemoveKnownRegionFromAvatar = OnRemoveKnownRegionFromAvatar;
+ //if (handlerRemoveKnownRegionFromAvatar != null)
+ //{
+ // handlerRemoveKnownRegionFromAvatar(agentID, regionlst);
+ //}
}
private void SendCloseChildAgentCompleted(IAsyncResult iar)
@@ -643,12 +712,6 @@ namespace OpenSim.Region.Environment.Scenes
if (eq == null)
avatar.ControllingClient.SendTeleportLocationStart();
- AgentCircuitData agent = avatar.ControllingClient.RequestClientInfo();
- agent.BaseFolder = UUID.Zero;
- agent.InventoryFolder = UUID.Zero;
- agent.startpos = position;
- agent.child = true;
-
if (reg.RemotingAddress != "" && reg.RemotingPort != 0)
{
// region is remote. see if it is up
@@ -662,6 +725,10 @@ namespace OpenSim.Region.Environment.Scenes
if (destRegionUp)
{
+ uint newRegionX = (uint)(reg.RegionHandle >> 40);
+ uint newRegionY = (((uint)(reg.RegionHandle)) >> 8);
+ uint oldRegionX = (uint)(m_regionInfo.RegionHandle >> 40);
+ uint oldRegionY = (((uint)(m_regionInfo.RegionHandle)) >> 8);
// Fixing a bug where teleporting while sitting results in the avatar ending up removed from
// both regions
@@ -675,33 +742,64 @@ namespace OpenSim.Region.Environment.Scenes
// the avatar.Close below will clear the child region list. We need this below for (possibly)
// closing the child agents, so save it here (we need a copy as it is Clear()-ed).
- List childRegions = new List(avatar.GetKnownRegionList());
+ //List childRegions = new List(avatar.GetKnownRegionList());
// Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport
// failure at this point (unlike a border crossing failure). So perhaps this can never fail
// once we reach here...
- avatar.Scene.RemoveCapsHandler(avatar.UUID);
- agent.child = false;
- m_commsProvider.InterRegion.InformRegionOfChildAgent(reg.RegionHandle, agent);
+ //avatar.Scene.RemoveCapsHandler(avatar.UUID);
+
+ AgentCircuitData agent = avatar.ControllingClient.RequestClientInfo();
+ agent.BaseFolder = UUID.Zero;
+ agent.InventoryFolder = UUID.Zero;
+ agent.startpos = position;
+ agent.child = true;
+ if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY))
+ {
+ // brand new agent
+ agent.CapsPath = Util.GetRandomCapsPath();
+ }
+ else
+ {
+ // child agent already there
+ agent.CapsPath = avatar.Scene.GetChildSeed(avatar.UUID, reg.RegionHandle);
+ }
+
+ if (!m_commsProvider.InterRegion.InformRegionOfChildAgent(reg.RegionHandle, agent))
+ {
+ avatar.ControllingClient.SendTeleportFailed("Destination is not accepting teleports.");
+ return;
+ }
+
+ // TODO Should construct this behind a method
+ string capsPath =
+ "http://" + reg.ExternalHostName + ":" + reg.HttpPort
+ + "/CAPS/" + agent.CapsPath + "0000/";
if (eq != null)
{
OSD Item = EventQueueHelper.EnableSimulator(reg.RegionHandle, reg.ExternalEndPoint);
eq.Enqueue(Item, avatar.UUID);
+
+ Item = EventQueueHelper.EstablishAgentCommunication(avatar.UUID, reg.ExternalEndPoint.ToString(), capsPath);
+ eq.Enqueue(Item, avatar.UUID);
}
else
{
avatar.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, reg.ExternalEndPoint);
}
-
- m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId,
- position, false);
- Thread.Sleep(2000);
- AgentCircuitData circuitdata = avatar.ControllingClient.RequestClientInfo();
- // TODO Should construct this behind a method
- string capsPath =
- "http://" + reg.ExternalHostName + ":" + reg.HttpPort
- + "/CAPS/" + circuitdata.CapsPath + "0000/";
+ if (!m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId,
+ position, false))
+ {
+ avatar.ControllingClient.SendTeleportFailed("Problem with destination.");
+ // We should close that agent we just created over at destination...
+ List lst = new List();
+ lst.Add(reg.RegionHandle);
+ SendCloseChildAgentAsync(avatar.UUID, lst);
+ return;
+ }
+
+ Thread.Sleep(2000);
m_log.DebugFormat(
"[CAPS]: Sending new CAPS seed url {0} to client {1}", capsPath, avatar.UUID);
@@ -720,26 +818,25 @@ namespace OpenSim.Region.Environment.Scenes
}
avatar.MakeChildAgent();
- Thread.Sleep(7000);
+ Thread.Sleep(5000);
avatar.CrossAttachmentsIntoNewRegion(reg.RegionHandle, true);
if (KiPrimitive != null)
{
KiPrimitive(avatar.LocalId);
}
- avatar.Close();
- uint newRegionX = (uint)(reg.RegionHandle >> 40);
- uint newRegionY = (((uint)(reg.RegionHandle)) >> 8);
- uint oldRegionX = (uint)(m_regionInfo.RegionHandle >> 40);
- uint oldRegionY = (((uint)(m_regionInfo.RegionHandle)) >> 8);
+ // Let's close some children agents
+ avatar.CloseChildAgents(newRegionX, newRegionY);
+ // Close this ScenePresence too
+ //avatar.Close();
- if (Util.fast_distance2d((int)(newRegionX - oldRegionX), (int)(newRegionY - oldRegionY)) > 3)
- {
- //SendCloseChildAgentConnections(avatar.UUID,avatar.GetKnownRegionList());
- SendCloseChildAgentConnections(avatar.UUID, childRegions);
- CloseConnection(avatar.UUID);
- }
+ // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone
+
+ //if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY))
+ //{
+ // CloseConnection(avatar.UUID);
+ //}
// if (teleport success) // seems to be always success here
// the user may change their profile information in other region,
@@ -775,6 +872,30 @@ namespace OpenSim.Region.Environment.Scenes
}
}
+ private List NeighbourHandles(List neighbours)
+ {
+ List handles = new List();
+ foreach (SimpleRegionInfo reg in neighbours)
+ {
+ handles.Add(reg.RegionHandle);
+ }
+ return handles;
+ }
+
+ private List NewNeighbours(List currentNeighbours, List previousNeighbours)
+ {
+ return currentNeighbours.FindAll(delegate(ulong handle) { return !previousNeighbours.Contains(handle); });
+ }
+
+ private List CommonNeighbours(List currentNeighbours, List previousNeighbours)
+ {
+ return currentNeighbours.FindAll(delegate(ulong handle) { return previousNeighbours.Contains(handle); });
+ }
+
+ private List OldNeighbours(List currentNeighbours, List previousNeighbours)
+ {
+ return previousNeighbours.FindAll(delegate(ulong handle) { return !currentNeighbours.Contains(handle); });
+ }
///
/// Inform a neighbouring region that an avatar is about to cross into it.
///
@@ -846,5 +967,18 @@ namespace OpenSim.Region.Environment.Scenes
{
return m_commsProvider.GridService.RequestNamedRegions(name, maxNumber);
}
+
+ private void Dump(string msg, List handles)
+ {
+ Console.WriteLine("-------------- HANDLE DUMP ({0}) ---------", msg);
+ foreach (ulong handle in handles)
+ {
+ uint x, y;
+ Utils.LongToUInts(handle, out x, out y);
+ x = x / Constants.RegionSize;
+ y = y / Constants.RegionSize;
+ Console.WriteLine("({0}, {1})", x, y);
+ }
+ }
}
}
--
cgit v1.1