/// <summary> /// This informs all neighbouring regions about agent "avatar". /// Calls an asynchronous method to do so.. so it doesn't lag the sim. /// </summary> /// <param name="sp"></param> public void EnableChildAgents(ScenePresence sp) { List<GridRegion> neighbours = new List<GridRegion>(); RegionInfo m_regionInfo = sp.Scene.RegionInfo; if (m_regionInfo != null) { neighbours = RequestNeighbours(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); } else { m_log.Debug("[ENTITY TRANSFER MODULE]: m_regionInfo was null in EnableChildAgents, is this a NPC?"); } /// 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<ulong> neighbourHandles = NeighbourHandles(neighbours); // on this region neighbourHandles.Add(sp.Scene.RegionInfo.RegionHandle); // add this region too List<ulong> previousRegionNeighbourHandles; if (sp.Scene.CapsModule != null) { previousRegionNeighbourHandles = new List<ulong>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID).Keys); } else { previousRegionNeighbourHandles = new List<ulong>(); } List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles); List<ulong> 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 sp.DropOldNeighbours(oldRegions); /// Collect as many seeds as possible Dictionary<ulong, string> seeds; if (sp.Scene.CapsModule != null) seeds = new Dictionary<ulong, string>(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); else seeds = new Dictionary<ulong, string>(); //m_log.Debug(" !!! No. of seeds: " + seeds.Count); if (!seeds.ContainsKey(sp.Scene.RegionInfo.RegionHandle)) seeds.Add(sp.Scene.RegionInfo.RegionHandle, sp.ControllingClient.RequestClientInfo().CapsPath); /// Create the necessary child agents List<AgentCircuitData> cagents = new List<AgentCircuitData>(); foreach (GridRegion neighbour in neighbours) { 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; agent.InventoryFolder = UUID.Zero; // agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour); agent.startpos = new Vector3(128, 128, 70); agent.child = true; agent.Appearance = sp.Appearance; if (currentAgentCircuit != null) { agent.ServiceURLs = currentAgentCircuit.ServiceURLs; agent.IPAddress = currentAgentCircuit.IPAddress; agent.Viewer = currentAgentCircuit.Viewer; agent.Channel = currentAgentCircuit.Channel; agent.Mac = currentAgentCircuit.Mac; agent.Id0 = currentAgentCircuit.Id0; } if (newRegions.Contains(neighbour.RegionHandle)) { agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); sp.AddNeighbourRegion(neighbour.RegionHandle, agent.CapsPath); seeds.Add(neighbour.RegionHandle, agent.CapsPath); } else agent.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, neighbour.RegionHandle); cagents.Add(agent); } } /// Update all child agent with everyone's seeds foreach (AgentCircuitData a in cagents) { a.ChildrenCapSeeds = new Dictionary<ulong, string>(seeds); } if (sp.Scene.CapsModule != null) { sp.Scene.CapsModule.SetChildrenSeed(sp.UUID, seeds); } sp.KnownRegions = seeds; //avatar.Scene.DumpChildrenSeeds(avatar.UUID); //avatar.DumpKnownRegions(); bool newAgent = false; int count = 0; foreach (GridRegion neighbour in neighbours) { //m_log.WarnFormat("--> Going to send child agent to {0}", neighbour.RegionName); // Don't do it if there's already an agent in that region if (newRegions.Contains(neighbour.RegionHandle)) newAgent = true; else newAgent = false; if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) { InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; try { d.BeginInvoke(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent, InformClientOfNeighbourCompleted, d); } catch (ArgumentOutOfRangeException) { m_log.ErrorFormat( "[ENTITY TRANSFER MODULE]: Neighbour Regions response included the current region in the neighbour list. The following region will not display to the client: {0} for region {1} ({2}, {3}).", neighbour.ExternalHostName, neighbour.RegionHandle, neighbour.RegionLocX, neighbour.RegionLocY); } catch (Exception e) { m_log.ErrorFormat( "[ENTITY TRANSFER MODULE]: Could not resolve external hostname {0} for region {1} ({2}, {3}). {4}", 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, // since I don't know what will happen if we just let the client continue // XXX: Well, decided to swallow the exception instead for now. Let us see how that goes. // throw e; } } count++; } }
/// <summary> /// This informs all neighboring regions about agent "avatar". /// Calls an asynchronous method to do so.. so it doesn't lag the sim. /// </summary> public void EnableNeighbourChildAgents(ScenePresence avatar, List<RegionInfo> lstneighbours) { List<SimpleRegionInfo> neighbours = new List<SimpleRegionInfo>(); //m_commsProvider.GridService.RequestNeighbours(m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); for (int i = 0; i < lstneighbours.Count; i++) { // We don't want to keep sending to regions that consistently fail on comms. if (!(lstneighbours[i].commFailTF)) { neighbours.Add(new SimpleRegionInfo(lstneighbours[i])); } } // we're going to be using the above code once neighbour cache is correct. Currently it doesn't appear to be // So we're temporarily going back to the old method of grabbing it from the Grid Server Every time :/ if (m_regionInfo != null) { neighbours = RequestNeighbors(avatar.Scene,m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); } else { m_log.Debug("[ENABLENEIGHBOURCHILDAGENTS]: m_regionInfo was null in EnableNeighbourChildAgents, is this a NPC?"); } /// 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<ulong> neighbourHandles = NeighbourHandles(neighbours); // on this region neighbourHandles.Add(avatar.Scene.RegionInfo.RegionHandle); // add this region too List<ulong> previousRegionNeighbourHandles ; if (avatar.Scene.CapsModule != null) { previousRegionNeighbourHandles = new List<ulong>(avatar.Scene.CapsModule.GetChildrenSeeds(avatar.UUID).Keys); } else { previousRegionNeighbourHandles = new List<ulong>(); } List<ulong> newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles); List<ulong> 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<ulong, string> seeds; if (avatar.Scene.CapsModule != null) seeds = new Dictionary<ulong, string>(avatar.Scene.CapsModule.GetChildrenSeeds(avatar.UUID)); else seeds = new Dictionary<ulong, string>(); //m_log.Debug(" !!! No. of seeds: " + seeds.Count); if (!seeds.ContainsKey(avatar.Scene.RegionInfo.RegionHandle)) seeds.Add(avatar.Scene.RegionInfo.RegionHandle, avatar.ControllingClient.RequestClientInfo().CapsPath); /// Create the necessary child agents List<AgentCircuitData> cagents = new List<AgentCircuitData>(); foreach (SimpleRegionInfo neighbour in neighbours) { if (neighbour.RegionHandle != avatar.Scene.RegionInfo.RegionHandle) { 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)) { agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); avatar.AddNeighbourRegion(neighbour.RegionHandle, agent.CapsPath); seeds.Add(neighbour.RegionHandle, agent.CapsPath); } else agent.CapsPath = avatar.Scene.CapsModule.GetChildSeed(avatar.UUID, neighbour.RegionHandle); cagents.Add(agent); } } /// Update all child agent with everyone's seeds foreach (AgentCircuitData a in cagents) { a.ChildrenCapSeeds = new Dictionary<ulong, string>(seeds); } if (avatar.Scene.CapsModule != null) { // These two are the same thing! avatar.Scene.CapsModule.SetChildrenSeed(avatar.UUID, seeds); } avatar.KnownRegions = seeds; //avatar.Scene.DumpChildrenSeeds(avatar.UUID); //avatar.DumpKnownRegions(); bool newAgent = false; 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)) newAgent = true; else newAgent = false; if (neighbour.RegionHandle != avatar.Scene.RegionInfo.RegionHandle) { InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; try { d.BeginInvoke(avatar, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent, InformClientOfNeighbourCompleted, d); } catch (ArgumentOutOfRangeException) { m_log.ErrorFormat( "[REGIONINFO]: Neighbour Regions response included the current region in the neighbor list. The following region will not display to the client: {0} for region {1} ({2}, {3}).", neighbour.ExternalHostName, neighbour.RegionHandle, neighbour.RegionLocX, neighbour.RegionLocY); } catch (Exception e) { m_log.ErrorFormat( "[REGIONINFO]: Could not resolve external hostname {0} for region {1} ({2}, {3}). {4}", 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, // since I don't know what will happen if we just let the client continue // XXX: Well, decided to swallow the exception instead for now. Let us see how that goes. // throw e; } } count++; } }