From f1c30784ac767bf5f62e81748984b76d85d71f6a Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 15 Jan 2010 15:11:58 -0800 Subject: [PATCH] * General cleanup of Teleports, Crossings and Child agents. They are now in the new AgentTransferModule, in line with what MW started implementing back in May -- ITeleportModule. This has been renamed IAgentTransferModule, to be more generic. * HGSceneCommunicationService has been deleted * SceneCommunicationService will likely be deleted soon too --- OpenSim/Region/Application/HGCommands.cs | 2 +- OpenSim/Region/Application/OpenSim.cs | 4 +- .../AgentTransfer/AgentTransferModule.cs | 1188 +++++++++++++++++ .../Resources/CoreModulePlugin.addin.xml | 1 + .../Grid/HGGridConnector.cs | 4 +- .../Simulation/LocalSimulationConnector.cs | 17 +- .../World/WorldMap/MapSearchModule.cs | 7 +- ...eportModule.cs => IAgentTransferModule.cs} | 17 +- .../Hypergrid/HGSceneCommunicationService.cs | 387 ------ OpenSim/Region/Framework/Scenes/Scene.cs | 67 +- .../Scenes/SceneCommunicationService.cs | 1149 ---------------- .../Region/Framework/Scenes/SceneManager.cs | 4 +- .../Region/Framework/Scenes/ScenePresence.cs | 25 +- bin/config-include/Grid.ini | 1 + bin/config-include/GridHypergrid.ini | 1 + bin/config-include/Standalone.ini | 1 + bin/config-include/StandaloneHypergrid.ini | 3 +- 17 files changed, 1266 insertions(+), 1612 deletions(-) create mode 100644 OpenSim/Region/CoreModules/Agent/AgentTransfer/AgentTransferModule.cs rename OpenSim/Region/Framework/Interfaces/{ITeleportModule.cs => IAgentTransferModule.cs} (80%) delete mode 100644 OpenSim/Region/Framework/Scenes/Hypergrid/HGSceneCommunicationService.cs diff --git a/OpenSim/Region/Application/HGCommands.cs b/OpenSim/Region/Application/HGCommands.cs index a863697bdb..5b99d7d045 100644 --- a/OpenSim/Region/Application/HGCommands.cs +++ b/OpenSim/Region/Application/HGCommands.cs @@ -47,7 +47,7 @@ namespace OpenSim public static Scene CreateScene(RegionInfo regionInfo, AgentCircuitManager circuitManager, StorageManager storageManager, ModuleLoader m_moduleLoader, ConfigSettings m_configSettings, OpenSimConfigSource m_config, string m_version) { - HGSceneCommunicationService sceneGridService = new HGSceneCommunicationService(); + SceneCommunicationService sceneGridService = new SceneCommunicationService(); return new HGScene( diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 9f5e173fbe..546a1d123b 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -414,7 +414,7 @@ namespace OpenSim foreach (ScenePresence presence in agents) { - RegionInfo regionInfo = m_sceneManager.GetRegionInfo(presence.RegionHandle); + RegionInfo regionInfo = presence.Scene.RegionInfo; if (presence.Firstname.ToLower().Contains(cmdparams[2].ToLower()) && presence.Lastname.ToLower().Contains(cmdparams[3].ToLower())) @@ -908,7 +908,7 @@ namespace OpenSim foreach (ScenePresence presence in agents) { - RegionInfo regionInfo = m_sceneManager.GetRegionInfo(presence.RegionHandle); + RegionInfo regionInfo = presence.Scene.RegionInfo; string regionName; if (regionInfo == null) diff --git a/OpenSim/Region/CoreModules/Agent/AgentTransfer/AgentTransferModule.cs b/OpenSim/Region/CoreModules/Agent/AgentTransfer/AgentTransferModule.cs new file mode 100644 index 0000000000..8e3d041bc0 --- /dev/null +++ b/OpenSim/Region/CoreModules/Agent/AgentTransfer/AgentTransferModule.cs @@ -0,0 +1,1188 @@ +/* + * 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 System.Net; +using System.Reflection; +using System.Threading; + +using OpenSim.Framework; +using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Client; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Services.Interfaces; + +using GridRegion = OpenSim.Services.Interfaces.GridRegion; + +using OpenMetaverse; +using log4net; +using Nini.Config; + +namespace OpenSim.Region.CoreModules.Agent.AgentTransfer +{ + public class AgentTransferModule : ISharedRegionModule, IAgentTransferModule + { + #region ISharedRegionModule + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private bool m_Enabled = false; + protected Scene m_aScene; + protected List m_agentsInTransit; + + public Type ReplaceableInterface + { + get { return null; } + } + + public string Name + { + get { return "AgentTransferModule"; } + } + + public virtual void Initialise(IConfigSource source) + { + IConfig moduleConfig = source.Configs["Modules"]; + if (moduleConfig != null) + { + string name = moduleConfig.GetString("AgentTransferModule", ""); + if (name == Name) + { + m_agentsInTransit = new List(); + m_Enabled = true; + m_log.Info("[AGENT TRANSFER MODULE]: Enabled."); + } + } + } + + public virtual void PostInitialise() + { + } + + public virtual void AddRegion(Scene scene) + { + if (!m_Enabled) + return; + + if (m_aScene == null) + m_aScene = scene; + + scene.RegisterModuleInterface(this); + } + + public virtual void Close() + { + if (!m_Enabled) + return; + } + + + public virtual void RemoveRegion(Scene scene) + { + if (!m_Enabled) + return; + if (scene == m_aScene) + m_aScene = null; + } + + public virtual void RegionLoaded(Scene scene) + { + if (!m_Enabled) + return; + + } + + + #endregion + + #region Teleports + + public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) + { + if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) + return; + + bool destRegionUp = true; + + IEventQueue eq = sp.Scene.RequestModuleInterface(); + + // Reset animations; the viewer does that in teleports. + sp.Animator.ResetAnimations(); + + if (regionHandle == sp.Scene.RegionInfo.RegionHandle) + { + m_log.DebugFormat( + "[AGENT TRANSFER MODULE]: RequestTeleportToLocation {0} within {1}", + position, sp.Scene.RegionInfo.RegionName); + + // Teleport within the same region + if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) + { + Vector3 emergencyPos = new Vector3(128, 128, 128); + + m_log.WarnFormat( + "[AGENT TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", + position, sp.Name, sp.UUID, emergencyPos); + position = emergencyPos; + } + + // TODO: Get proper AVG Height + float localAVHeight = 1.56f; + float posZLimit = 22; + + // TODO: Check other Scene HeightField + if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) + { + posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; + } + + float newPosZ = posZLimit + localAVHeight; + if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) + { + position.Z = newPosZ; + } + + // Only send this if the event queue is null + if (eq == null) + sp.ControllingClient.SendTeleportLocationStart(); + + sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); + sp.Teleport(position); + } + else + { + uint x = 0, y = 0; + Utils.LongToUInts(regionHandle, out x, out y); + GridRegion reg = m_aScene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); + + if (reg != null) + { + m_log.DebugFormat( + "[AGENT TRANSFER MODULE]: RequestTeleportToLocation to {0} in {1}", + position, reg.RegionName); + + uint newRegionX = (uint)(reg.RegionHandle >> 40); + uint newRegionY = (((uint)(reg.RegionHandle)) >> 8); + uint oldRegionX = (uint)(sp.Scene.RegionInfo.RegionHandle >> 40); + uint oldRegionY = (((uint)(sp.Scene.RegionInfo.RegionHandle)) >> 8); + + ulong destinationHandle = GetRegionHandle(reg); + + if (eq == null) + sp.ControllingClient.SendTeleportLocationStart(); + + // Let's do DNS resolution only once in this process, please! + // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, + // it's actually doing a lot of work. + IPEndPoint endPoint = reg.ExternalEndPoint; + if (endPoint.Address == null) + { + // Couldn't resolve the name. Can't TP, because the viewer wants IP addresses. + destRegionUp = false; + } + + if (destRegionUp) + { + // Fixing a bug where teleporting while sitting results in the avatar ending up removed from + // both regions + if (sp.ParentID != (uint)0) + sp.StandUp(); + + if (!sp.ValidateAttachments()) + { + sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state"); + return; + } + + // 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()); + // 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); + + string capsPath = String.Empty; + AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo(); + agentCircuit.BaseFolder = UUID.Zero; + agentCircuit.InventoryFolder = UUID.Zero; + agentCircuit.startpos = position; + agentCircuit.child = true; + agentCircuit.Appearance = sp.Appearance; + + if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY)) + { + // brand new agent, let's create a new caps seed + agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); + } + + string reason = String.Empty; + + // Let's create an agent there if one doesn't exist yet. + //if (!m_commsProvider.InterRegion.InformRegionOfChildAgent(reg.RegionHandle, agentCircuit)) + if (!m_aScene.SimulationService.CreateAgent(reg, agentCircuit, teleportFlags, out reason)) + { + sp.ControllingClient.SendTeleportFailed(String.Format("Destination is not accepting teleports: {0}", + reason)); + return; + } + + // OK, it got this agent. Let's close some child agents + sp.CloseChildAgents(newRegionX, newRegionY); + + if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY)) + { + #region IP Translation for NAT + IClientIPEndpoint ipepClient; + if (sp.ClientView.TryGet(out ipepClient)) + { + capsPath + = "http://" + + NetworkUtil.GetHostFor(ipepClient.EndPoint, reg.ExternalHostName) + + ":" + + reg.HttpPort + + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); + } + else + { + capsPath + = "http://" + + reg.ExternalHostName + + ":" + + reg.HttpPort + + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); + } + #endregion + + if (eq != null) + { + #region IP Translation for NAT + // Uses ipepClient above + if (sp.ClientView.TryGet(out ipepClient)) + { + endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); + } + #endregion + + eq.EnableSimulator(destinationHandle, endPoint, sp.UUID); + + // ES makes the client send a UseCircuitCode message to the destination, + // which triggers a bunch of things there. + // So let's wait + Thread.Sleep(2000); + + eq.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); + + } + else + { + sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); + } + } + else + { + agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); + capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort + + "/CAPS/" + agentCircuit.CapsPath + "0000/"; + } + + // Expect avatar crossing is a heavy-duty function at the destination. + // That is where MakeRoot is called, which fetches appearance and inventory. + // Plus triggers OnMakeRoot, which spawns a series of asynchronous updates. + //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; + //} + + SetInTransit(sp.UUID); + + // Let's send a full update of the agent. This is a synchronous call. + AgentData agent = new AgentData(); + sp.CopyTo(agent); + agent.Position = position; + agent.CallbackURI = "http://" + sp.Scene.RegionInfo.ExternalHostName + ":" + sp.Scene.RegionInfo.HttpPort + + "/agent/" + sp.UUID.ToString() + "/" + sp.Scene.RegionInfo.RegionID.ToString() + "/release/"; + + m_aScene.SimulationService.UpdateAgent(reg, agent); + + m_log.DebugFormat( + "[AGENT TRANSFER MODULE]: Sending new AGENT TRANSFER MODULE seed url {0} to client {1}", capsPath, sp.UUID); + + + if (eq != null) + { + eq.TeleportFinishEvent(destinationHandle, 13, endPoint, + 0, teleportFlags, capsPath, sp.UUID); + } + else + { + sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, + teleportFlags, capsPath); + } + + // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which + // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation + // that the client contacted the destination before we send the attachments and close things here. + if (!WaitForCallback(sp.UUID)) + { + // Client never contacted destination. Let's restore everything back + sp.ControllingClient.SendTeleportFailed("Problems connecting to destination."); + + ResetFromTransit(sp.UUID); + + // Yikes! We should just have a ref to scene here. + //sp.Scene.InformClientOfNeighbours(sp); + EnableChildAgents(sp); + + // Finally, kill the agent we just created at the destination. + m_aScene.SimulationService.CloseAgent(reg, sp.UUID); + + return; + } + + KillEntity(sp.Scene, sp.LocalId); + + sp.MakeChildAgent(); + + // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it + sp.CrossAttachmentsIntoNewRegion(reg, true); + + // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone + + if (NeedsClosing(oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) + { + Thread.Sleep(5000); + sp.Close(); + sp.Scene.IncomingCloseAgent(sp.UUID); + } + else + // now we have a child agent in this region. + sp.Reset(); + + + // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! + if (sp.Scene.NeedSceneCacheClear(sp.UUID)) + { + m_log.DebugFormat( + "[AGENT TRANSFER MODULE]: User {0} is going to another region, profile cache removed", + sp.UUID); + } + } + else + { + sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); + } + } + else + { + // TP to a place that doesn't exist (anymore) + // Inform the viewer about that + sp.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); + + // and set the map-tile to '(Offline)' + uint regX, regY; + Utils.LongToUInts(regionHandle, out regX, out regY); + + MapBlockData block = new MapBlockData(); + block.X = (ushort)(regX / Constants.RegionSize); + block.Y = (ushort)(regY / Constants.RegionSize); + block.Access = 254; // == not there + + List blocks = new List(); + blocks.Add(block); + sp.ControllingClient.SendMapBlock(blocks, 0); + } + } + } + + #endregion + + #region Enable Child Agent + /// + /// 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 EnableChildAgent(ScenePresence sp, GridRegion region) + { + AgentCircuitData agent = sp.ControllingClient.RequestClientInfo(); + agent.BaseFolder = UUID.Zero; + agent.InventoryFolder = UUID.Zero; + agent.startpos = new Vector3(128, 128, 70); + agent.child = true; + agent.Appearance = sp.Appearance; + + InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; + d.BeginInvoke(sp, agent, region, region.ExternalEndPoint, true, + InformClientOfNeighbourCompleted, + d); + } + #endregion + + #region Crossings + + public void Cross(ScenePresence agent, bool isFlying) + { + Scene scene = agent.Scene; + Vector3 pos = agent.AbsolutePosition; + Vector3 newpos = new Vector3(pos.X, pos.Y, pos.Z); + uint neighbourx = scene.RegionInfo.RegionLocX; + uint neighboury = scene.RegionInfo.RegionLocY; + const float boundaryDistance = 1.7f; + Vector3 northCross = new Vector3(0, boundaryDistance, 0); + Vector3 southCross = new Vector3(0, -1 * boundaryDistance, 0); + Vector3 eastCross = new Vector3(boundaryDistance, 0, 0); + Vector3 westCross = new Vector3(-1 * boundaryDistance, 0, 0); + + // distance to edge that will trigger crossing + + + // distance into new region to place avatar + const float enterDistance = 0.5f; + + if (scene.TestBorderCross(pos + westCross, Cardinals.W)) + { + if (scene.TestBorderCross(pos + northCross, Cardinals.N)) + { + Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N); + neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); + } + else if (scene.TestBorderCross(pos + southCross, Cardinals.S)) + { + Border b = scene.GetCrossedBorder(pos + southCross, Cardinals.S); + if (b.TriggerRegionX == 0 && b.TriggerRegionY == 0) + { + neighboury--; + newpos.Y = Constants.RegionSize - enterDistance; + } + else + { + neighboury = b.TriggerRegionY; + neighbourx = b.TriggerRegionX; + + Vector3 newposition = pos; + newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize; + newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize; + agent.ControllingClient.SendAgentAlertMessage( + String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false); + InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene); + return; + } + } + + Border ba = scene.GetCrossedBorder(pos + westCross, Cardinals.W); + if (ba.TriggerRegionX == 0 && ba.TriggerRegionY == 0) + { + neighbourx--; + newpos.X = Constants.RegionSize - enterDistance; + } + else + { + neighboury = ba.TriggerRegionY; + neighbourx = ba.TriggerRegionX; + + + Vector3 newposition = pos; + newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize; + newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize; + agent.ControllingClient.SendAgentAlertMessage( + String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false); + InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene); + + + return; + } + + } + else if (scene.TestBorderCross(pos + eastCross, Cardinals.E)) + { + Border b = scene.GetCrossedBorder(pos + eastCross, Cardinals.E); + neighbourx += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); + newpos.X = enterDistance; + + if (scene.TestBorderCross(pos + southCross, Cardinals.S)) + { + Border ba = scene.GetCrossedBorder(pos + southCross, Cardinals.S); + if (ba.TriggerRegionX == 0 && ba.TriggerRegionY == 0) + { + neighboury--; + newpos.Y = Constants.RegionSize - enterDistance; + } + else + { + neighboury = ba.TriggerRegionY; + neighbourx = ba.TriggerRegionX; + Vector3 newposition = pos; + newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize; + newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize; + agent.ControllingClient.SendAgentAlertMessage( + String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false); + InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene); + return; + } + } + else if (scene.TestBorderCross(pos + northCross, Cardinals.N)) + { + Border c = scene.GetCrossedBorder(pos + northCross, Cardinals.N); + neighboury += (uint)(int)(c.BorderLine.Z / (int)Constants.RegionSize); + newpos.Y = enterDistance; + } + + + } + else if (scene.TestBorderCross(pos + southCross, Cardinals.S)) + { + Border b = scene.GetCrossedBorder(pos + southCross, Cardinals.S); + if (b.TriggerRegionX == 0 && b.TriggerRegionY == 0) + { + neighboury--; + newpos.Y = Constants.RegionSize - enterDistance; + } + else + { + neighboury = b.TriggerRegionY; + neighbourx = b.TriggerRegionX; + Vector3 newposition = pos; + newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize; + newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize; + agent.ControllingClient.SendAgentAlertMessage( + String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false); + InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene); + return; + } + } + else if (scene.TestBorderCross(pos + northCross, Cardinals.N)) + { + + Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N); + neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); + newpos.Y = enterDistance; + } + + /* + + if (pos.X < boundaryDistance) //West + { + neighbourx--; + newpos.X = Constants.RegionSize - enterDistance; + } + else if (pos.X > Constants.RegionSize - boundaryDistance) // East + { + neighbourx++; + newpos.X = enterDistance; + } + + if (pos.Y < boundaryDistance) // South + { + neighboury--; + newpos.Y = Constants.RegionSize - enterDistance; + } + else if (pos.Y > Constants.RegionSize - boundaryDistance) // North + { + neighboury++; + newpos.Y = enterDistance; + } + */ + + CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync; + d.BeginInvoke(agent, newpos, neighbourx, neighboury, isFlying, CrossAgentToNewRegionCompleted, d); + + } + + + public delegate void InformClientToInitateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, + Vector3 position, + Scene initiatingScene); + + private void InformClientToInitateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene) + { + + // This assumes that we know what our neighbors are. + + InformClientToInitateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync; + d.BeginInvoke(agent, regionX, regionY, position, initiatingScene, + InformClientToInitiateTeleportToLocationCompleted, + d); + } + + public void InformClientToInitiateTeleportToLocationAsync(ScenePresence agent, uint regionX, uint regionY, Vector3 position, + Scene initiatingScene) + { + Thread.Sleep(10000); + IMessageTransferModule im = initiatingScene.RequestModuleInterface(); + if (im != null) + { + UUID gotoLocation = Util.BuildFakeParcelID( + Util.UIntsToLong( + (regionX * + (uint)Constants.RegionSize), + (regionY * + (uint)Constants.RegionSize)), + (uint)(int)position.X, + (uint)(int)position.Y, + (uint)(int)position.Z); + GridInstantMessage m = new GridInstantMessage(initiatingScene, UUID.Zero, + "Region", agent.UUID, + (byte)InstantMessageDialog.GodLikeRequestTeleport, false, + "", gotoLocation, false, new Vector3(127, 0, 0), + new Byte[0]); + im.SendInstantMessage(m, delegate(bool success) + { + m_log.DebugFormat("[AGENT TRANSFER MODULE]: Client Initiating Teleport sending IM success = {0}", success); + }); + + } + } + + private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar) + { + InformClientToInitateTeleportToLocationDelegate icon = + (InformClientToInitateTeleportToLocationDelegate)iar.AsyncState; + icon.EndInvoke(iar); + } + + 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("[AGENT TRANSFER MODULE]: Crossing agent {0} {1} to {2}-{3}", agent.Firstname, agent.Lastname, neighbourx, neighboury); + + Scene m_scene = agent.Scene; + ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize)); + + int x = (int)(neighbourx * Constants.RegionSize), y = (int)(neighboury * Constants.RegionSize); + GridRegion neighbourRegion = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); + + if (neighbourRegion != null && agent.ValidateAttachments()) + { + pos = pos + (agent.Velocity); + + SetInTransit(agent.UUID); + AgentData cAgent = new AgentData(); + agent.CopyTo(cAgent); + cAgent.Position = pos; + if (isFlying) + cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; + cAgent.CallbackURI = "http://" + m_scene.RegionInfo.ExternalHostName + ":" + m_scene.RegionInfo.HttpPort + + "/agent/" + agent.UUID.ToString() + "/" + m_scene.RegionInfo.RegionID.ToString() + "/release/"; + + m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent); + + // 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(); + + //m_log.Debug("BEFORE CROSS"); + //Scene.DumpChildrenSeeds(UUID); + //DumpKnownRegions(); + string agentcaps; + if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps)) + { + m_log.ErrorFormat("[AGENT TRANSFER MODULE]: No AGENT TRANSFER MODULE 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("[AGENT TRANSFER MODULE]: Sending new AGENT TRANSFER MODULE 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); + } + + if (!WaitForCallback(agent.UUID)) + { + m_log.Debug("[AGENT TRANSFER MODULE]: Callback never came in crossing agent"); + ResetFromTransit(agent.UUID); + + // Yikes! We should just have a ref to scene here. + //agent.Scene.InformClientOfNeighbours(agent); + EnableChildAgents(agent); + + return agent; + } + + agent.MakeChildAgent(); + // now we have a child agent in this region. Request all interesting data about other (root) agents + agent.SendInitialFullUpdateToAllClients(); + + agent.CrossAttachmentsIntoNewRegion(neighbourRegion, 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 + // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! + if (agent.Scene.NeedSceneCacheClear(agent.UUID)) + { + m_log.DebugFormat( + "[AGENT TRANSFER MODULE]: User {0} is going to another region", agent.UUID); + } + } + + //m_log.Debug("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) + agent.Reset(); + else // Not successful + agent.RestoreInCurrentScene(); + + // In any case + agent.NotInTransit(); + + //m_log.DebugFormat("[AGENT TRANSFER MODULE]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname); + } + + #endregion + + + #region Enable Child Agents + + private delegate void InformClientOfNeighbourDelegate( + ScenePresence avatar, AgentCircuitData a, GridRegion reg, IPEndPoint endPoint, bool newAgent); + + /// + /// This informs all neighboring regions about agent "avatar". + /// Calls an asynchronous method to do so.. so it doesn't lag the sim. + /// + public void EnableChildAgents(ScenePresence sp) + { + List neighbours = new List(); + RegionInfo m_regionInfo = sp.Scene.RegionInfo; + + if (m_regionInfo != null) + { + neighbours = RequestNeighbours(sp.Scene, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); + } + else + { + m_log.Debug("[AGENT 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 neighbourHandles = NeighbourHandles(neighbours); // on this region + neighbourHandles.Add(sp.Scene.RegionInfo.RegionHandle); // add this region too + List previousRegionNeighbourHandles; + + if (sp.Scene.CapsModule != null) + { + previousRegionNeighbourHandles = + new List(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID).Keys); + } + else + { + previousRegionNeighbourHandles = new List(); + } + + 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 + sp.DropOldNeighbours(oldRegions); + + /// Collect as many seeds as possible + Dictionary seeds; + if (sp.Scene.CapsModule != null) + seeds + = new Dictionary(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); + else + seeds = new Dictionary(); + + //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 cagents = new List(); + foreach (GridRegion neighbour in neighbours) + { + if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) + { + + AgentCircuitData agent = sp.ControllingClient.RequestClientInfo(); + agent.BaseFolder = UUID.Zero; + agent.InventoryFolder = UUID.Zero; + agent.startpos = new Vector3(128, 128, 70); + agent.child = true; + agent.Appearance = sp.Appearance; + + 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(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( + "[AGENT TRANSFER MODULE]: 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( + "[AGENT 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++; + } + } + + private void InformClientOfNeighbourCompleted(IAsyncResult iar) + { + InformClientOfNeighbourDelegate icon = (InformClientOfNeighbourDelegate)iar.AsyncState; + icon.EndInvoke(iar); + //m_log.WarnFormat(" --> InformClientOfNeighbourCompleted"); + } + + /// + /// Async component for informing client of which neighbours exist + /// + /// + /// This needs to run asynchronously, as a network timeout may block the thread for a long while + /// + /// + /// + /// + /// + private void InformClientOfNeighbourAsync(ScenePresence sp, AgentCircuitData a, GridRegion reg, + IPEndPoint endPoint, bool newAgent) + { + // Let's wait just a little to give time to originating regions to catch up with closing child agents + // after a cross here + Thread.Sleep(500); + + Scene m_scene = sp.Scene; + + uint x, y; + Utils.LongToUInts(reg.RegionHandle, out x, out y); + x = x / Constants.RegionSize; + y = y / Constants.RegionSize; + m_log.Info("[AGENT TRANSFER MODULE]: Starting to inform client about neighbour " + x + ", " + y + "(" + endPoint.ToString() + ")"); + + string capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort + + "/CAPS/" + a.CapsPath + "0000/"; + + string reason = String.Empty; + + + bool regionAccepted = m_scene.SimulationService.CreateAgent(reg, a, 0, out reason); // m_interregionCommsOut.SendCreateChildAgent(reg.RegionHandle, a, 0, out reason); + + if (regionAccepted && newAgent) + { + IEventQueue eq = sp.Scene.RequestModuleInterface(); + if (eq != null) + { + #region IP Translation for NAT + IClientIPEndpoint ipepClient; + if (sp.ClientView.TryGet(out ipepClient)) + { + endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); + } + #endregion + + eq.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID); + eq.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); + m_log.DebugFormat("[AGENT TRANSFER MODULE]: Sending new AGENT TRANSFER MODULE seed url {0} to client {1} in region {2}", + capsPath, sp.UUID, sp.Scene.RegionInfo.RegionName); + } + else + { + sp.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint); + // TODO: make Event Queue disablable! + } + + m_log.Info("[AGENT TRANSFER MODULE]: Completed inform client about neighbour " + endPoint.ToString()); + + } + + } + + protected List RequestNeighbours(Scene pScene, uint pRegionLocX, uint pRegionLocY) + { + RegionInfo m_regionInfo = pScene.RegionInfo; + + Border[] northBorders = pScene.NorthBorders.ToArray(); + Border[] southBorders = pScene.SouthBorders.ToArray(); + Border[] eastBorders = pScene.EastBorders.ToArray(); + Border[] westBorders = pScene.WestBorders.ToArray(); + + // Legacy one region. Provided for simplicity while testing the all inclusive method in the else statement. + if (northBorders.Length <= 1 && southBorders.Length <= 1 && eastBorders.Length <= 1 && westBorders.Length <= 1) + { + return pScene.GridService.GetNeighbours(m_regionInfo.ScopeID, m_regionInfo.RegionID); + } + else + { + Vector2 extent = Vector2.Zero; + for (int i = 0; i < eastBorders.Length; i++) + { + extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X; + } + for (int i = 0; i < northBorders.Length; i++) + { + extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y; + } + + // Loss of fraction on purpose + extent.X = ((int)extent.X / (int)Constants.RegionSize) + 1; + extent.Y = ((int)extent.Y / (int)Constants.RegionSize) + 1; + + int startX = (int)(pRegionLocX - 1) * (int)Constants.RegionSize; + int startY = (int)(pRegionLocY - 1) * (int)Constants.RegionSize; + + int endX = ((int)pRegionLocX + (int)extent.X) * (int)Constants.RegionSize; + int endY = ((int)pRegionLocY + (int)extent.Y) * (int)Constants.RegionSize; + + List neighbours = pScene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY); + neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); + + return neighbours; + } + } + + 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); }); + } + + private List NeighbourHandles(List neighbours) + { + List handles = new List(); + foreach (GridRegion reg in neighbours) + { + handles.Add(reg.RegionHandle); + } + return handles; + } + + private void Dump(string msg, List handles) + { + m_log.InfoFormat("-------------- 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; + m_log.InfoFormat("({0}, {1})", x, y); + } + } + + #endregion + + + #region Agent Arrived + public void AgentArrivedAtDestination(UUID id) + { + //m_log.Debug(" >>> ReleaseAgent called <<< "); + ResetFromTransit(id); + } + + #endregion + + + #region Misc + protected bool IsOutsideRegion(Scene s, Vector3 pos) + { + + if (s.TestBorderCross(pos, Cardinals.N)) + return true; + if (s.TestBorderCross(pos, Cardinals.S)) + return true; + if (s.TestBorderCross(pos, Cardinals.E)) + return true; + if (s.TestBorderCross(pos, Cardinals.W)) + return true; + + return false; + } + + protected bool WaitForCallback(UUID id) + { + int count = 200; + while (m_agentsInTransit.Contains(id) && count-- > 0) + { + //m_log.Debug(" >>> Waiting... " + count); + Thread.Sleep(100); + } + + if (count > 0) + return true; + else + return false; + } + + protected void SetInTransit(UUID id) + { + lock (m_agentsInTransit) + { + if (!m_agentsInTransit.Contains(id)) + m_agentsInTransit.Add(id); + } + } + + protected bool ResetFromTransit(UUID id) + { + lock (m_agentsInTransit) + { + if (m_agentsInTransit.Contains(id)) + { + m_agentsInTransit.Remove(id); + return true; + } + } + return false; + } + + protected void KillEntity(Scene scene, uint localID) + { + scene.SendKillObject(localID); + } + + protected virtual ulong GetRegionHandle(GridRegion region) + { + return region.RegionHandle; + } + + protected virtual bool NeedsClosing(uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg) + { + return Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY); + } + + #endregion + + } +} diff --git a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml index 1cc8ca935a..f980c24264 100644 --- a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml +++ b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml @@ -8,6 +8,7 @@ + diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs index 592991bcd3..fa705be273 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs @@ -385,7 +385,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid private static Random random = new Random(); - + // From the command line link-region public GridRegion TryLinkRegionToCoords(Scene m_scene, IClientAPI client, string mapName, int xloc, int yloc) { string host = "127.0.0.1"; @@ -441,6 +441,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid return TryLinkRegionToCoords(m_scene, client, mapName, xloc, 0); } + // From the command line and the 2 above public bool TryCreateLink(Scene m_scene, IClientAPI client, int xloc, int yloc, string externalRegionName, uint externalPort, string externalHostName, out GridRegion regInfo) { @@ -572,6 +573,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid return TryLinkRegion((Scene)client.Scene, client, regionDescriptor); } + // From the map and secondlife://blah public GridRegion GetHyperlinkRegion(ulong handle) { foreach (GridRegion r in m_HyperlinkRegions.Values) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index a341f2f2c3..f4383f1cdb 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -43,6 +43,17 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private List m_sceneList = new List(); + private IAgentTransferModule m_AgentTransferModule; + protected IAgentTransferModule AgentTransferModule + { + get + { + if (m_AgentTransferModule == null) + m_AgentTransferModule = m_sceneList[0].RequestModuleInterface(); + return m_AgentTransferModule; + } + } + private bool m_ModuleEnabled = false; #region IRegionModule @@ -247,8 +258,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation { if (s.RegionInfo.RegionID == origin) { - //m_log.Debug("[LOCAL COMMS]: Found region to SendReleaseAgent"); - return s.IncomingReleaseAgent(id); + m_log.Debug("[LOCAL COMMS]: Found region to SendReleaseAgent"); + AgentTransferModule.AgentArrivedAtDestination(id); + return true; +// return s.IncomingReleaseAgent(id); } } //m_log.Debug("[LOCAL COMMS]: region not found in SendReleaseAgent " + origin); diff --git a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs index be46fa55b2..42b463267b 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/MapSearchModule.cs @@ -104,7 +104,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap if (info != null) regionInfos.Add(info); } - if ((regionInfos.Count == 0) && IsHypergridOn()) + if ((regionInfos.Count == 0)) { // OK, we tried but there are no regions matching that name. // Let's check quickly if this is a domain name, and if so link to it @@ -158,11 +158,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap remoteClient.SendMapBlock(blocks, 0); } - private bool IsHypergridOn() - { - return (m_scene.SceneGridService is HGSceneCommunicationService); - } - private Scene GetClientScene(IClientAPI client) { foreach (Scene s in m_scenes) diff --git a/OpenSim/Region/Framework/Interfaces/ITeleportModule.cs b/OpenSim/Region/Framework/Interfaces/IAgentTransferModule.cs similarity index 80% rename from OpenSim/Region/Framework/Interfaces/ITeleportModule.cs rename to OpenSim/Region/Framework/Interfaces/IAgentTransferModule.cs index 5f9129d713..76745d6e20 100644 --- a/OpenSim/Region/Framework/Interfaces/ITeleportModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAgentTransferModule.cs @@ -26,16 +26,25 @@ */ using System; -using System.Collections.Generic; -using System.Text; +using OpenSim.Services.Interfaces; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; + using OpenMetaverse; using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.Framework.Interfaces { - public interface ITeleportModule + public interface IAgentTransferModule { - void RequestTeleportToLocation(ScenePresence avatar, ulong regionHandle, Vector3 position, + void Teleport(ScenePresence agent, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags); + + void Cross(ScenePresence agent, bool isFlying); + + void AgentArrivedAtDestination(UUID agent); + + void EnableChildAgents(ScenePresence agent); + + void EnableChildAgent(ScenePresence agent, GridRegion region); } } diff --git a/OpenSim/Region/Framework/Scenes/Hypergrid/HGSceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/Hypergrid/HGSceneCommunicationService.cs deleted file mode 100644 index b27be80456..0000000000 --- a/OpenSim/Region/Framework/Scenes/Hypergrid/HGSceneCommunicationService.cs +++ /dev/null @@ -1,387 +0,0 @@ -/* - * 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 System.Net; -using System.Reflection; -using System.Threading; -using log4net; -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Framework.Client; -using OpenSim.Framework.Communications; -using OpenSim.Framework.Capabilities; -using OpenSim.Region.Framework.Interfaces; -using OpenSim.Services.Interfaces; -using GridRegion = OpenSim.Services.Interfaces.GridRegion; - -namespace OpenSim.Region.Framework.Scenes.Hypergrid -{ - public class HGSceneCommunicationService : SceneCommunicationService - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private IHyperlinkService m_hg; - IHyperlinkService HyperlinkService - { - get - { - if (m_hg == null) - m_hg = m_scene.RequestModuleInterface(); - return m_hg; - } - } - - public HGSceneCommunicationService() : base() - { - } - - - /// - /// Try to teleport an agent to a new region. - /// - /// - /// - /// - /// - /// - public override void RequestTeleportToLocation(ScenePresence avatar, ulong regionHandle, Vector3 position, - Vector3 lookAt, uint teleportFlags) - { - if (!avatar.Scene.Permissions.CanTeleport(avatar.UUID)) - return; - - bool destRegionUp = true; - - IEventQueue eq = avatar.Scene.RequestModuleInterface(); - - // Reset animations; the viewer does that in teleports. - avatar.Animator.ResetAnimations(); - - if (regionHandle == m_regionInfo.RegionHandle) - { - // Teleport within the same region - if (IsOutsideRegion(avatar.Scene, position) || position.Z < 0) - { - Vector3 emergencyPos = new Vector3(128, 128, 128); - - m_log.WarnFormat( - "[HGSceneCommService]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", - position, avatar.Name, avatar.UUID, emergencyPos); - position = emergencyPos; - } - // TODO: Get proper AVG Height - float localAVHeight = 1.56f; - - float posZLimit = 22; - - if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) - { - posZLimit = (float) avatar.Scene.Heightmap[(int) position.X, (int) position.Y]; - } - - float newPosZ = posZLimit + localAVHeight; - if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) - { - position.Z = newPosZ; - } - - // Only send this if the event queue is null - if (eq == null) - avatar.ControllingClient.SendTeleportLocationStart(); - - - avatar.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); - avatar.Teleport(position); - } - else - { - uint x = 0, y = 0; - Utils.LongToUInts(regionHandle, out x, out y); - GridRegion reg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); - - if (reg != null) - { - - 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); - - /// - /// Hypergrid mod start - /// - /// - bool isHyperLink = (HyperlinkService.GetHyperlinkRegion(reg.RegionHandle) != null); - bool isHomeUser = true; - ulong realHandle = regionHandle; - isHomeUser = HyperlinkService.IsLocalUser(avatar.UUID); - realHandle = m_hg.FindRegionHandle(regionHandle); - m_log.Debug("XXX ---- home user? " + isHomeUser + " --- hyperlink? " + isHyperLink + " --- real handle: " + realHandle.ToString()); - /// - /// Hypergrid mod stop - /// - /// - - if (eq == null) - avatar.ControllingClient.SendTeleportLocationStart(); - - - // Let's do DNS resolution only once in this process, please! - // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, - // it's actually doing a lot of work. - IPEndPoint endPoint = reg.ExternalEndPoint; - if (endPoint.Address == null) - { - // Couldn't resolve the name. Can't TP, because the viewer wants IP addresses. - destRegionUp = false; - } - - if (destRegionUp) - { - // Fixing a bug where teleporting while sitting results in the avatar ending up removed from - // both regions - if (avatar.ParentID != (uint)0) - avatar.StandUp(); - - if (!avatar.ValidateAttachments()) - { - avatar.ControllingClient.SendTeleportFailed("Inconsistent attachment state"); - return; - } - - // 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()); - // 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); - - string capsPath = String.Empty; - AgentCircuitData agentCircuit = avatar.ControllingClient.RequestClientInfo(); - agentCircuit.BaseFolder = UUID.Zero; - agentCircuit.InventoryFolder = UUID.Zero; - agentCircuit.startpos = position; - agentCircuit.child = true; - agentCircuit.Appearance = avatar.Appearance; - - if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY)) - { - // brand new agent, let's create a new caps seed - agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); - } - - string reason = String.Empty; - - if (!m_scene.SimulationService.CreateAgent(reg, agentCircuit, teleportFlags, out reason)) - { - avatar.ControllingClient.SendTeleportFailed(String.Format("Destination is not accepting teleports: {0}", - reason)); - return; - } - - // Let's close some agents - if (isHyperLink) // close them all except this one - { - List regions = new List(avatar.KnownChildRegionHandles); - regions.Remove(avatar.Scene.RegionInfo.RegionHandle); - SendCloseChildAgentConnections(avatar.UUID, regions); - } - else // close just a few - avatar.CloseChildAgents(newRegionX, newRegionY); - - if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY) || isHyperLink) - { - capsPath - = "http://" - + reg.ExternalHostName - + ":" - + reg.HttpPort - + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); - - if (eq != null) - { - #region IP Translation for NAT - IClientIPEndpoint ipepClient; - if (avatar.ClientView.TryGet(out ipepClient)) - { - endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); - } - #endregion - - eq.EnableSimulator(realHandle, endPoint, avatar.UUID); - - // ES makes the client send a UseCircuitCode message to the destination, - // which triggers a bunch of things there. - // So let's wait - Thread.Sleep(2000); - - eq.EstablishAgentCommunication(avatar.UUID, endPoint, capsPath); - } - else - { - avatar.ControllingClient.InformClientOfNeighbour(realHandle, endPoint); - // TODO: make Event Queue disablable! - } - } - else - { - // child agent already there - agentCircuit.CapsPath = avatar.Scene.CapsModule.GetChildSeed(avatar.UUID, reg.RegionHandle); - capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort - + "/CAPS/" + agentCircuit.CapsPath + "0000/"; - } - - //m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId, - // position, false); - - //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(realHandle); - // SendCloseChildAgentAsync(avatar.UUID, lst); - // return; - //} - - SetInTransit(avatar.UUID); - // Let's send a full update of the agent. This is a synchronous call. - AgentData agent = new AgentData(); - avatar.CopyTo(agent); - agent.Position = position; - agent.CallbackURI = "http://" + m_regionInfo.ExternalHostName + ":" + m_regionInfo.HttpPort + - "/agent/" + avatar.UUID.ToString() + "/" + avatar.Scene.RegionInfo.RegionID.ToString() + "/release/"; - - m_scene.SimulationService.UpdateAgent(reg, agent); - - m_log.DebugFormat( - "[CAPS]: Sending new CAPS seed url {0} to client {1}", capsPath, avatar.UUID); - - - /// - /// Hypergrid mod: realHandle instead of reg.RegionHandle - /// - /// - if (eq != null) - { - eq.TeleportFinishEvent(realHandle, 13, endPoint, - 4, teleportFlags, capsPath, avatar.UUID); - } - else - { - avatar.ControllingClient.SendRegionTeleport(realHandle, 13, endPoint, 4, - teleportFlags, capsPath); - } - /// - /// Hypergrid mod stop - /// - - - // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which - // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation - // that the client contacted the destination before we send the attachments and close things here. - if (!WaitForCallback(avatar.UUID)) - { - // Client never contacted destination. Let's restore everything back - avatar.ControllingClient.SendTeleportFailed("Problems connecting to destination."); - - ResetFromTransit(avatar.UUID); - // Yikes! We should just have a ref to scene here. - avatar.Scene.InformClientOfNeighbours(avatar); - - // Finally, kill the agent we just created at the destination. - m_scene.SimulationService.CloseAgent(reg, avatar.UUID); - return; - } - - // Can't go back from here - if (KiPrimitive != null) - { - KiPrimitive(avatar.LocalId); - } - - avatar.MakeChildAgent(); - - // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it - avatar.CrossAttachmentsIntoNewRegion(reg, true); - - - // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone - /// - /// Hypergrid mod: extra check for isHyperLink - /// - if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY) || isHyperLink) - { - Thread.Sleep(5000); - avatar.Close(); - CloseConnection(avatar.UUID); - } - // if (teleport success) // seems to be always success here - // the user may change their profile information in other region, - // so the userinfo in UserProfileCache is not reliable any more, delete it - if (avatar.Scene.NeedSceneCacheClear(avatar.UUID) || isHyperLink) - { - // REFACTORING PROBLEM!!!! - //m_commsProvider.UserProfileCacheService.RemoveUser(avatar.UUID); - m_log.DebugFormat( - "[HGSceneCommService]: User {0} is going to another region, profile cache removed", - avatar.UUID); - } - } - else - { - avatar.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); - } - } - else - { - // TP to a place that doesn't exist (anymore) - // Inform the viewer about that - avatar.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); - - // and set the map-tile to '(Offline)' - uint regX, regY; - Utils.LongToUInts(regionHandle, out regX, out regY); - - MapBlockData block = new MapBlockData(); - block.X = (ushort)(regX / Constants.RegionSize); - block.Y = (ushort)(regY / Constants.RegionSize); - block.Access = 254; // == not there - - List blocks = new List(); - blocks.Add(block); - avatar.ControllingClient.SendMapBlock(blocks, 0); - } - } - } - - } -} diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 48f033128c..dcbbe08979 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -315,7 +315,7 @@ namespace OpenSim.Region.Framework.Scenes protected IConfigSource m_config; protected IRegionSerialiserModule m_serialiser; protected IDialogModule m_dialogModule; - protected ITeleportModule m_teleportModule; + protected IAgentTransferModule m_teleportModule; protected ICapabilitiesModule m_capsModule; public ICapabilitiesModule CapsModule @@ -901,7 +901,7 @@ namespace OpenSim.Region.Framework.Scenes regInfo.RegionName = otherRegion.RegionName; regInfo.ScopeID = otherRegion.ScopeID; regInfo.ExternalHostName = otherRegion.ExternalHostName; - + GridRegion r = new GridRegion(regInfo); try { ForEachScenePresence(delegate(ScenePresence agent) @@ -915,7 +915,8 @@ namespace OpenSim.Region.Framework.Scenes List old = new List(); old.Add(otherRegion.RegionHandle); agent.DropOldNeighbours(old); - InformClientOfNeighbor(agent, regInfo); + if (m_teleportModule != null) + m_teleportModule.EnableChildAgent(agent, r); } } ); @@ -1063,6 +1064,7 @@ namespace OpenSim.Region.Framework.Scenes { foreach (RegionInfo region in m_regionRestartNotifyList) { + GridRegion r = new GridRegion(region); try { ForEachScenePresence(delegate(ScenePresence agent) @@ -1070,9 +1072,8 @@ namespace OpenSim.Region.Framework.Scenes // If agent is a root agent. if (!agent.IsChildAgent) { - //agent.ControllingClient.new - //this.CommsManager.InterRegion.InformRegionOfChildAgent(otherRegion.RegionHandle, agent.ControllingClient.RequestClientInfo()); - InformClientOfNeighbor(agent, region); + if (m_teleportModule != null) + m_teleportModule.EnableChildAgent(agent, r); } } ); @@ -1217,7 +1218,7 @@ namespace OpenSim.Region.Framework.Scenes m_serialiser = RequestModuleInterface(); m_dialogModule = RequestModuleInterface(); m_capsModule = RequestModuleInterface(); - m_teleportModule = RequestModuleInterface(); + m_teleportModule = RequestModuleInterface(); } #endregion @@ -3783,17 +3784,6 @@ namespace OpenSim.Region.Framework.Scenes return false; } - public virtual bool IncomingReleaseAgent(UUID id) - { - return m_sceneGridService.ReleaseAgent(id); - } - - public void SendReleaseAgent(UUID origin, UUID id, string uri) - { - //m_interregionCommsOut.SendReleaseAgent(regionHandle, id, uri); - SimulationService.ReleaseAgent(origin, id, uri); - } - /// /// Tell a single agent to disconnect from the region. /// @@ -3837,30 +3827,6 @@ namespace OpenSim.Region.Framework.Scenes return false; } - /// - /// Tell neighboring regions about this agent - /// When the regions respond with a true value, - /// tell the agents about the region. - /// - /// We have to tell the regions about the agents first otherwise it'll deny them access - /// - /// - /// - public void InformClientOfNeighbours(ScenePresence presence) - { - m_sceneGridService.EnableNeighbourChildAgents(presence, m_neighbours); - } - - /// - /// Tell a neighboring region about this agent - /// - /// - /// - public void InformClientOfNeighbor(ScenePresence presence, RegionInfo region) - { - m_sceneGridService.EnableNeighbourChildAgents(presence, m_neighbours); - } - /// /// Tries to teleport agent to other region. /// @@ -3936,16 +3902,12 @@ namespace OpenSim.Region.Framework.Scenes } if (m_teleportModule != null) - { - m_teleportModule.RequestTeleportToLocation(sp, regionHandle, - position, lookAt, teleportFlags); - } + m_teleportModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags); else { - m_sceneGridService.RequestTeleportToLocation(sp, regionHandle, - position, lookAt, teleportFlags); + m_log.DebugFormat("[SCENE]: Unable to perform teleports: no AgentTransferModule is active"); + sp.ControllingClient.SendTeleportFailed("Unable to perform teleports on this simulator."); } - } } @@ -3971,7 +3933,12 @@ namespace OpenSim.Region.Framework.Scenes public void CrossAgentToNewRegion(ScenePresence agent, bool isFlying) { - m_sceneGridService.CrossAgentToNewRegion(this, agent, isFlying); + if (m_teleportModule != null) + m_teleportModule.Cross(agent, isFlying); + else + { + m_log.DebugFormat("[SCENE]: Unable to cross agent to neighbouring region, because there is no AgentTransferModule"); + } } public void SendOutChildAgentUpdates(AgentPosition cadu, ScenePresence presence) diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs index f99df29e23..a67b42a3da 100644 --- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs +++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs @@ -60,8 +60,6 @@ namespace OpenSim.Region.Framework.Scenes protected RegionCommsListener regionCommsHost; - protected List m_agentsInTransit; - public bool RegionLoginsEnabled { get { return m_regionLoginsEnabled; } @@ -124,7 +122,6 @@ namespace OpenSim.Region.Framework.Scenes public SceneCommunicationService() { - m_agentsInTransit = new List(); } public void SetScene(Scene s) @@ -150,381 +147,6 @@ namespace OpenSim.Region.Framework.Scenes { } - #region CommsManager Event handlers - - /// - /// A New User will arrive shortly, Informs the scene that there's a new user on the way - /// - /// Data we need to ensure that the agent can connect - /// - protected void NewUserConnection(AgentCircuitData agent) - { - handlerExpectUser = OnExpectUser; - if (handlerExpectUser != null) - { - //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: OnExpectUser Fired for User:" + agent.firstname + " " + agent.lastname); - handlerExpectUser(agent); - } - } - - /// - /// The Grid has requested us to log-off the user - /// - /// Unique ID of agent to log-off - /// The secret string that the region establishes with the grid when registering - /// The message to send to the user that tells them why they were logged off - protected void GridLogOffUser(UUID AgentID, UUID RegionSecret, string message) - { - handlerLogOffUser = OnLogOffUser; - if (handlerLogOffUser != null) - { - handlerLogOffUser(AgentID, RegionSecret, message); - } - } - - /// - /// Inform the scene that we've got an update about a child agent that we have - /// - /// - /// - protected bool ChildAgentUpdate(ChildAgentDataUpdate cAgentData) - { - handlerChildAgentUpdate = OnChildAgentUpdate; - if (handlerChildAgentUpdate != null) - handlerChildAgentUpdate(cAgentData); - - - return true; - } - - - protected void AgentCrossing(UUID agentID, Vector3 position, bool isFlying) - { - handlerAvatarCrossingIntoRegion = OnAvatarCrossingIntoRegion; - if (handlerAvatarCrossingIntoRegion != null) - { - handlerAvatarCrossingIntoRegion(agentID, position, isFlying); - } - } - - protected void PrimCrossing(UUID primID, Vector3 position, bool isPhysical) - { - handlerPrimCrossingIntoRegion = OnPrimCrossingIntoRegion; - if (handlerPrimCrossingIntoRegion != null) - { - handlerPrimCrossingIntoRegion(primID, position, isPhysical); - } - } - - protected bool CloseConnection(UUID agentID) - { - m_log.Debug("[INTERREGION]: Incoming Agent Close Request for agent: " + agentID); - - handlerCloseAgentConnection = OnCloseAgentConnection; - if (handlerCloseAgentConnection != null) - { - return handlerCloseAgentConnection(agentID); - } - - return false; - } - - protected LandData FetchLandData(uint x, uint y) - { - handlerGetLandData = OnGetLandData; - if (handlerGetLandData != null) - { - return handlerGetLandData(x, y); - } - return null; - } - - #endregion - - #region Inform Client of Neighbours - - private delegate void InformClientOfNeighbourDelegate( - ScenePresence avatar, AgentCircuitData a, GridRegion reg, IPEndPoint endPoint, bool newAgent); - - private void InformClientOfNeighbourCompleted(IAsyncResult iar) - { - InformClientOfNeighbourDelegate icon = (InformClientOfNeighbourDelegate) iar.AsyncState; - icon.EndInvoke(iar); - //m_log.WarnFormat(" --> InformClientOfNeighbourCompleted"); - } - - /// - /// Async component for informing client of which neighbours exist - /// - /// - /// This needs to run asynchronously, as a network timeout may block the thread for a long while - /// - /// - /// - /// - /// - private void InformClientOfNeighbourAsync(ScenePresence avatar, AgentCircuitData a, GridRegion reg, - IPEndPoint endPoint, bool newAgent) - { - // Let's wait just a little to give time to originating regions to catch up with closing child agents - // after a cross here - Thread.Sleep(500); - - 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/"; - - string reason = String.Empty; - - - bool regionAccepted = m_scene.SimulationService.CreateAgent(reg, a, 0, out reason); // m_interregionCommsOut.SendCreateChildAgent(reg.RegionHandle, a, 0, out reason); - - if (regionAccepted && newAgent) - { - IEventQueue eq = avatar.Scene.RequestModuleInterface(); - if (eq != null) - { - #region IP Translation for NAT - IClientIPEndpoint ipepClient; - if (avatar.ClientView.TryGet(out ipepClient)) - { - endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); - } - #endregion - - eq.EnableSimulator(reg.RegionHandle, endPoint, avatar.UUID); - eq.EstablishAgentCommunication(avatar.UUID, endPoint, capsPath); - 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(reg.RegionHandle, endPoint); - // TODO: make Event Queue disablable! - } - - m_log.Info("[INTERGRID]: Completed inform client about neighbour " + endPoint.ToString()); - - } - - } - - public List RequestNeighbours(Scene pScene, uint pRegionLocX, uint pRegionLocY) - { - Border[] northBorders = pScene.NorthBorders.ToArray(); - Border[] southBorders = pScene.SouthBorders.ToArray(); - Border[] eastBorders = pScene.EastBorders.ToArray(); - Border[] westBorders = pScene.WestBorders.ToArray(); - - // Legacy one region. Provided for simplicity while testing the all inclusive method in the else statement. - if (northBorders.Length <= 1 && southBorders.Length <= 1 && eastBorders.Length <= 1 && westBorders.Length <= 1) - { - return m_scene.GridService.GetNeighbours(m_regionInfo.ScopeID, m_regionInfo.RegionID); - } - else - { - Vector2 extent = Vector2.Zero; - for (int i = 0; i < eastBorders.Length; i++) - { - extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X; - } - for (int i = 0; i < northBorders.Length; i++) - { - extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y; - } - - // Loss of fraction on purpose - extent.X = ((int)extent.X / (int)Constants.RegionSize) + 1; - extent.Y = ((int)extent.Y / (int)Constants.RegionSize) + 1; - - int startX = (int)(pRegionLocX - 1) * (int)Constants.RegionSize; - int startY = (int)(pRegionLocY - 1) * (int)Constants.RegionSize; - - int endX = ((int)pRegionLocX + (int)extent.X) * (int)Constants.RegionSize; - int endY = ((int)pRegionLocY + (int)extent.Y) * (int)Constants.RegionSize; - - List neighbours = m_scene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY); - neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); - - return neighbours; - } - } - - /// - /// This informs all neighboring regions about agent "avatar". - /// Calls an asynchronous method to do so.. so it doesn't lag the sim. - /// - public void EnableNeighbourChildAgents(ScenePresence avatar, List lstneighbours) - { - List neighbours = new List(); - - if (m_regionInfo != null) - { - neighbours = RequestNeighbours(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 neighbourHandles = NeighbourHandles(neighbours); // on this region - neighbourHandles.Add(avatar.Scene.RegionInfo.RegionHandle); // add this region too - List previousRegionNeighbourHandles ; - - if (avatar.Scene.CapsModule != null) - { - previousRegionNeighbourHandles = - new List(avatar.Scene.CapsModule.GetChildrenSeeds(avatar.UUID).Keys); - } - else - { - previousRegionNeighbourHandles = new List(); - } - - 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; - if (avatar.Scene.CapsModule != null) - seeds - = new Dictionary(avatar.Scene.CapsModule.GetChildrenSeeds(avatar.UUID)); - else - seeds = new Dictionary(); - - //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 cagents = new List(); - foreach (GridRegion 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; - agent.Appearance = avatar.Appearance; - - 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(seeds); - } - - if (avatar.Scene.CapsModule != null) - { - avatar.Scene.CapsModule.SetChildrenSeed(avatar.UUID, seeds); - } - avatar.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 != 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++; - } - } - - /// - /// 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, GridRegion region) - { - AgentCircuitData agent = avatar.ControllingClient.RequestClientInfo(); - agent.BaseFolder = UUID.Zero; - agent.InventoryFolder = UUID.Zero; - agent.startpos = new Vector3(128, 128, 70); - agent.child = true; - agent.Appearance = avatar.Appearance; - - InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; - d.BeginInvoke(avatar, agent, region, region.ExternalEndPoint, true, - InformClientOfNeighbourCompleted, - d); - } - - #endregion - public delegate void InformNeighbourThatRegionUpDelegate(INeighbourService nService, RegionInfo region, ulong regionhandle); private void InformNeighborsThatRegionisUpCompleted(IAsyncResult iar) @@ -683,782 +305,11 @@ namespace OpenSim.Region.Framework.Scenes d); } } - - - /// - /// Try to teleport an agent to a new region. - /// - /// - /// - /// - /// - /// - public virtual void RequestTeleportToLocation(ScenePresence avatar, ulong regionHandle, Vector3 position, - Vector3 lookAt, uint teleportFlags) - { - if (!avatar.Scene.Permissions.CanTeleport(avatar.UUID)) - return; - - bool destRegionUp = true; - - IEventQueue eq = avatar.Scene.RequestModuleInterface(); - - // Reset animations; the viewer does that in teleports. - avatar.Animator.ResetAnimations(); - - if (regionHandle == m_regionInfo.RegionHandle) - { - m_log.DebugFormat( - "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation {0} within {1}", - position, m_regionInfo.RegionName); - - // Teleport within the same region - if (IsOutsideRegion(avatar.Scene, position) || position.Z < 0) - { - Vector3 emergencyPos = new Vector3(128, 128, 128); - - m_log.WarnFormat( - "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", - position, avatar.Name, avatar.UUID, emergencyPos); - position = emergencyPos; - } - - // TODO: Get proper AVG Height - float localAVHeight = 1.56f; - float posZLimit = 22; - - // TODO: Check other Scene HeightField - if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <=(int)Constants.RegionSize) - { - posZLimit = (float) avatar.Scene.Heightmap[(int) position.X, (int) position.Y]; - } - - float newPosZ = posZLimit + localAVHeight; - if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) - { - position.Z = newPosZ; - } - - // Only send this if the event queue is null - if (eq == null) - avatar.ControllingClient.SendTeleportLocationStart(); - - avatar.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); - avatar.Teleport(position); - } - else - { - uint x = 0, y = 0; - Utils.LongToUInts(regionHandle, out x, out y); - GridRegion reg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); - - if (reg != null) - { - m_log.DebugFormat( - "[SCENE COMMUNICATION SERVICE]: RequestTeleportToLocation to {0} in {1}", - position, reg.RegionName); - - if (eq == null) - avatar.ControllingClient.SendTeleportLocationStart(); - - // Let's do DNS resolution only once in this process, please! - // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, - // it's actually doing a lot of work. - IPEndPoint endPoint = reg.ExternalEndPoint; - if (endPoint.Address == null) - { - // Couldn't resolve the name. Can't TP, because the viewer wants IP addresses. - destRegionUp = false; - } - - 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 - if (avatar.ParentID != (uint)0) - avatar.StandUp(); - - if (!avatar.ValidateAttachments()) - { - avatar.ControllingClient.SendTeleportFailed("Inconsistent attachment state"); - return; - } - - // 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()); - // 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); - - string capsPath = String.Empty; - AgentCircuitData agentCircuit = avatar.ControllingClient.RequestClientInfo(); - agentCircuit.BaseFolder = UUID.Zero; - agentCircuit.InventoryFolder = UUID.Zero; - agentCircuit.startpos = position; - agentCircuit.child = true; - agentCircuit.Appearance = avatar.Appearance; - - if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY)) - { - // brand new agent, let's create a new caps seed - agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); - } - - string reason = String.Empty; - - // Let's create an agent there if one doesn't exist yet. - //if (!m_commsProvider.InterRegion.InformRegionOfChildAgent(reg.RegionHandle, agentCircuit)) - if (!m_scene.SimulationService.CreateAgent(reg, agentCircuit, teleportFlags, out reason)) - { - avatar.ControllingClient.SendTeleportFailed(String.Format("Destination is not accepting teleports: {0}", - reason)); - return; - } - - // OK, it got this agent. Let's close some child agents - avatar.CloseChildAgents(newRegionX, newRegionY); - - if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY)) - { - #region IP Translation for NAT - IClientIPEndpoint ipepClient; - if (avatar.ClientView.TryGet(out ipepClient)) - { - capsPath - = "http://" - + NetworkUtil.GetHostFor(ipepClient.EndPoint, reg.ExternalHostName) - + ":" - + reg.HttpPort - + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); - } - else - { - capsPath - = "http://" - + reg.ExternalHostName - + ":" - + reg.HttpPort - + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); - } - #endregion - - if (eq != null) - { - #region IP Translation for NAT - // Uses ipepClient above - if (avatar.ClientView.TryGet(out ipepClient)) - { - endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); - } - #endregion - - eq.EnableSimulator(reg.RegionHandle, endPoint, avatar.UUID); - - // ES makes the client send a UseCircuitCode message to the destination, - // which triggers a bunch of things there. - // So let's wait - Thread.Sleep(2000); - - eq.EstablishAgentCommunication(avatar.UUID, endPoint, capsPath); - } - else - { - avatar.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint); - } - } - else - { - agentCircuit.CapsPath = avatar.Scene.CapsModule.GetChildSeed(avatar.UUID, reg.RegionHandle); - capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort - + "/CAPS/" + agentCircuit.CapsPath + "0000/"; - } - - // Expect avatar crossing is a heavy-duty function at the destination. - // That is where MakeRoot is called, which fetches appearance and inventory. - // Plus triggers OnMakeRoot, which spawns a series of asynchronous updates. - //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; - //} - - SetInTransit(avatar.UUID); - // Let's send a full update of the agent. This is a synchronous call. - AgentData agent = new AgentData(); - avatar.CopyTo(agent); - agent.Position = position; - agent.CallbackURI = "http://" + m_regionInfo.ExternalHostName + ":" + m_regionInfo.HttpPort + - "/agent/" + avatar.UUID.ToString() + "/" + avatar.Scene.RegionInfo.RegionID.ToString() + "/release/"; - - m_scene.SimulationService.UpdateAgent(reg, agent); - - m_log.DebugFormat( - "[CAPS]: Sending new CAPS seed url {0} to client {1}", capsPath, avatar.UUID); - - - if (eq != null) - { - eq.TeleportFinishEvent(reg.RegionHandle, 13, endPoint, - 0, teleportFlags, capsPath, avatar.UUID); - } - else - { - avatar.ControllingClient.SendRegionTeleport(reg.RegionHandle, 13, endPoint, 4, - teleportFlags, capsPath); - } - - // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which - // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation - // that the client contacted the destination before we send the attachments and close things here. - if (!WaitForCallback(avatar.UUID)) - { - // Client never contacted destination. Let's restore everything back - avatar.ControllingClient.SendTeleportFailed("Problems connecting to destination."); - - ResetFromTransit(avatar.UUID); - - // Yikes! We should just have a ref to scene here. - avatar.Scene.InformClientOfNeighbours(avatar); - - // Finally, kill the agent we just created at the destination. - m_scene.SimulationService.CloseAgent(reg, avatar.UUID); - - return; - } - - // Can't go back from here - if (KiPrimitive != null) - { - KiPrimitive(avatar.LocalId); - } - - avatar.MakeChildAgent(); - - // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it - avatar.CrossAttachmentsIntoNewRegion(reg, true); - - // 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)) - { - Thread.Sleep(5000); - avatar.Close(); - CloseConnection(avatar.UUID); - } - else - // now we have a child agent in this region. - avatar.Reset(); - - - // if (teleport success) // seems to be always success here - // the user may change their profile information in other region, - // so the userinfo in UserProfileCache is not reliable any more, delete it - - // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! - if (avatar.Scene.NeedSceneCacheClear(avatar.UUID)) - { - m_log.DebugFormat( - "[SCENE COMMUNICATION SERVICE]: User {0} is going to another region, profile cache removed", - avatar.UUID); - } - } - else - { - avatar.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); - } - } - else - { - // TP to a place that doesn't exist (anymore) - // Inform the viewer about that - avatar.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); - - // and set the map-tile to '(Offline)' - uint regX, regY; - Utils.LongToUInts(regionHandle, out regX, out regY); - - MapBlockData block = new MapBlockData(); - block.X = (ushort)(regX / Constants.RegionSize); - block.Y = (ushort)(regY / Constants.RegionSize); - block.Access = 254; // == not there - - List blocks = new List(); - blocks.Add(block); - avatar.ControllingClient.SendMapBlock(blocks, 0); - } - } - } - - protected bool IsOutsideRegion(Scene s, Vector3 pos) - { - - if (s.TestBorderCross(pos,Cardinals.N)) - return true; - if (s.TestBorderCross(pos, Cardinals.S)) - return true; - if (s.TestBorderCross(pos, Cardinals.E)) - return true; - if (s.TestBorderCross(pos, Cardinals.W)) - return true; - - return false; - } - - public bool WaitForCallback(UUID id) - { - int count = 200; - while (m_agentsInTransit.Contains(id) && count-- > 0) - { - //m_log.Debug(" >>> Waiting... " + count); - Thread.Sleep(100); - } - - if (count > 0) - return true; - else - return false; - } - - public bool ReleaseAgent(UUID id) - { - //m_log.Debug(" >>> ReleaseAgent called <<< "); - return ResetFromTransit(id); - } - - public void SetInTransit(UUID id) - { - lock (m_agentsInTransit) - { - if (!m_agentsInTransit.Contains(id)) - m_agentsInTransit.Add(id); - } - } - - protected bool ResetFromTransit(UUID id) - { - lock (m_agentsInTransit) - { - if (m_agentsInTransit.Contains(id)) - { - m_agentsInTransit.Remove(id); - return true; - } - } - return false; - } - - private List NeighbourHandles(List neighbours) - { - List handles = new List(); - foreach (GridRegion 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); }); - } - - 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; - const float boundaryDistance = 1.7f; - Vector3 northCross = new Vector3(0,boundaryDistance, 0); - Vector3 southCross = new Vector3(0, -1 * boundaryDistance, 0); - Vector3 eastCross = new Vector3(boundaryDistance, 0, 0); - Vector3 westCross = new Vector3(-1 * boundaryDistance, 0, 0); - - // distance to edge that will trigger crossing - - - // distance into new region to place avatar - const float enterDistance = 0.5f; - - if (scene.TestBorderCross(pos + westCross, Cardinals.W)) - { - if (scene.TestBorderCross(pos + northCross, Cardinals.N)) - { - Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N); - neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); - } - else if (scene.TestBorderCross(pos + southCross, Cardinals.S)) - { - Border b = scene.GetCrossedBorder(pos + southCross, Cardinals.S); - if (b.TriggerRegionX == 0 && b.TriggerRegionY == 0) - { - neighboury--; - newpos.Y = Constants.RegionSize - enterDistance; - } - else - { - neighboury = b.TriggerRegionY; - neighbourx = b.TriggerRegionX; - - Vector3 newposition = pos; - newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize; - newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize; - agent.ControllingClient.SendAgentAlertMessage( - String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false); - InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene); - return; - } - } - - Border ba = scene.GetCrossedBorder(pos + westCross, Cardinals.W); - if (ba.TriggerRegionX == 0 && ba.TriggerRegionY == 0) - { - neighbourx--; - newpos.X = Constants.RegionSize - enterDistance; - } - else - { - neighboury = ba.TriggerRegionY; - neighbourx = ba.TriggerRegionX; - - - Vector3 newposition = pos; - newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize; - newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize; - agent.ControllingClient.SendAgentAlertMessage( - String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false); - InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene); - - - return; - } - - } - else if (scene.TestBorderCross(pos + eastCross, Cardinals.E)) - { - Border b = scene.GetCrossedBorder(pos + eastCross, Cardinals.E); - neighbourx += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); - newpos.X = enterDistance; - - if (scene.TestBorderCross(pos + southCross, Cardinals.S)) - { - Border ba = scene.GetCrossedBorder(pos + southCross, Cardinals.S); - if (ba.TriggerRegionX == 0 && ba.TriggerRegionY == 0) - { - neighboury--; - newpos.Y = Constants.RegionSize - enterDistance; - } - else - { - neighboury = ba.TriggerRegionY; - neighbourx = ba.TriggerRegionX; - Vector3 newposition = pos; - newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize; - newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize; - agent.ControllingClient.SendAgentAlertMessage( - String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false); - InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene); - return; - } - } - else if (scene.TestBorderCross(pos + northCross, Cardinals.N)) - { - Border c = scene.GetCrossedBorder(pos + northCross, Cardinals.N); - neighboury += (uint)(int)(c.BorderLine.Z / (int)Constants.RegionSize); - newpos.Y = enterDistance; - } - - - } - else if (scene.TestBorderCross(pos + southCross, Cardinals.S)) - { - Border b = scene.GetCrossedBorder(pos + southCross, Cardinals.S); - if (b.TriggerRegionX == 0 && b.TriggerRegionY == 0) - { - neighboury--; - newpos.Y = Constants.RegionSize - enterDistance; - } - else - { - neighboury = b.TriggerRegionY; - neighbourx = b.TriggerRegionX; - Vector3 newposition = pos; - newposition.X += (scene.RegionInfo.RegionLocX - neighbourx) * Constants.RegionSize; - newposition.Y += (scene.RegionInfo.RegionLocY - neighboury) * Constants.RegionSize; - agent.ControllingClient.SendAgentAlertMessage( - String.Format("Moving you to region {0},{1}", neighbourx, neighboury), false); - InformClientToInitateTeleportToLocation(agent, neighbourx, neighboury, newposition, scene); - return; - } - } - else if (scene.TestBorderCross(pos + northCross, Cardinals.N)) - { - - Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N); - neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); - newpos.Y = enterDistance; - } - - /* - - if (pos.X < boundaryDistance) //West - { - neighbourx--; - newpos.X = Constants.RegionSize - enterDistance; - } - else if (pos.X > Constants.RegionSize - boundaryDistance) // East - { - neighbourx++; - newpos.X = enterDistance; - } - - if (pos.Y < boundaryDistance) // South - { - neighboury--; - newpos.Y = Constants.RegionSize - enterDistance; - } - else if (pos.Y > Constants.RegionSize - boundaryDistance) // North - { - neighboury++; - newpos.Y = enterDistance; - } - */ - - CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync; - d.BeginInvoke(agent, newpos, neighbourx, neighboury, isFlying, CrossAgentToNewRegionCompleted, d); - } - - public delegate void InformClientToInitateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, - Vector3 position, - Scene initiatingScene); - - public void InformClientToInitateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, - Scene initiatingScene) - { - - // This assumes that we know what our neighbors are. - - InformClientToInitateTeleportToLocationDelegate d = InformClientToInitiateTeleportToLocationAsync; - d.BeginInvoke(agent,regionX,regionY,position,initiatingScene, - InformClientToInitiateTeleportToLocationCompleted, - d); - } - - public void InformClientToInitiateTeleportToLocationAsync(ScenePresence agent, uint regionX, uint regionY, Vector3 position, - Scene initiatingScene) - { - Thread.Sleep(10000); - IMessageTransferModule im = initiatingScene.RequestModuleInterface(); - if (im != null) - { - UUID gotoLocation = Util.BuildFakeParcelID( - Util.UIntsToLong( - (regionX * - (uint)Constants.RegionSize), - (regionY * - (uint)Constants.RegionSize)), - (uint)(int)position.X, - (uint)(int)position.Y, - (uint)(int)position.Z); - GridInstantMessage m = new GridInstantMessage(initiatingScene, UUID.Zero, - "Region", agent.UUID, - (byte)InstantMessageDialog.GodLikeRequestTeleport, false, - "", gotoLocation, false, new Vector3(127, 0, 0), - new Byte[0]); - im.SendInstantMessage(m, delegate(bool success) - { - m_log.DebugFormat("[CLIENT]: Client Initiating Teleport sending IM success = {0}", success); - }); - - } - } - - private void InformClientToInitiateTeleportToLocationCompleted(IAsyncResult iar) - { - InformClientToInitateTeleportToLocationDelegate icon = - (InformClientToInitateTeleportToLocationDelegate) iar.AsyncState; - icon.EndInvoke(iar); - } - - 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)); - - int x = (int)(neighbourx * Constants.RegionSize), y = (int)(neighboury * Constants.RegionSize); - GridRegion neighbourRegion = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); - - 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); - - SetInTransit(agent.UUID); - AgentData cAgent = new AgentData(); - agent.CopyTo(cAgent); - cAgent.Position = pos; - if (isFlying) - cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; - cAgent.CallbackURI = "http://" + m_regionInfo.ExternalHostName + ":" + m_regionInfo.HttpPort + - "/agent/" + agent.UUID.ToString() + "/" + agent.Scene.RegionInfo.RegionID.ToString() + "/release/"; - - m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent); - - // 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(); - - //m_log.Debug("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); - } - - if (!WaitForCallback(agent.UUID)) - { - ResetFromTransit(agent.UUID); - - // Yikes! We should just have a ref to scene here. - agent.Scene.InformClientOfNeighbours(agent); - - return agent; - } - - agent.MakeChildAgent(); - // now we have a child agent in this region. Request all interesting data about other (root) agents - agent.SendInitialFullUpdateToAllClients(); - - agent.CrossAttachmentsIntoNewRegion(neighbourRegion, 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 - // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! - if (agent.Scene.NeedSceneCacheClear(agent.UUID)) - { - m_log.DebugFormat( - "[SCENE COMM]: User {0} is going to another region", agent.UUID); - } - } - - //m_log.Debug("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) - { - agent.Reset(); - } - else // Not successful - { - //CachedUserInfo userInfo = m_commsProvider.UserProfileCacheService.GetUserDetails(agent.UUID); - //if (userInfo != null) - //{ - // userInfo.FetchInventory(); - //} - agent.RestoreInCurrentScene(); - } - // In any case - agent.NotInTransit(); - - //m_log.DebugFormat("[SCENE COMM]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname); - } public List RequestNamedRegions(string name, int maxNumber) { return m_scene.GridService.GetRegionsByName(UUID.Zero, name, maxNumber); } - private void Dump(string msg, List handles) - { - m_log.InfoFormat("-------------- 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; - m_log.InfoFormat("({0}, {1})", x, y); - } - } } } diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs index c2e3370eb0..6395d9868b 100644 --- a/OpenSim/Region/Framework/Scenes/SceneManager.cs +++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs @@ -468,11 +468,11 @@ namespace OpenSim.Region.Framework.Scenes return presences; } - public RegionInfo GetRegionInfo(ulong regionHandle) + public RegionInfo GetRegionInfo(UUID regionID) { foreach (Scene scene in m_localScenes) { - if (scene.RegionInfo.RegionHandle == regionHandle) + if (scene.RegionInfo.RegionID == regionID) { return scene.RegionInfo; } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 4ead60c2f3..711f9d9994 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1072,6 +1072,8 @@ namespace OpenSim.Region.Framework.Scenes /// public void CompleteMovement() { + //m_log.Debug("[SCENE PRESENCE]: CompleteMovement"); + Vector3 look = Velocity; if ((look.X == 0) && (look.Y == 0) && (look.Z == 0)) { @@ -1096,7 +1098,7 @@ namespace OpenSim.Region.Framework.Scenes if ((m_callbackURI != null) && !m_callbackURI.Equals("")) { m_log.DebugFormat("[SCENE PRESENCE]: Releasing agent in URI {0}", m_callbackURI); - Scene.SendReleaseAgent(m_originRegionID, UUID, m_callbackURI); + Scene.SimulationService.ReleaseAgent(m_originRegionID, UUID, m_callbackURI); m_callbackURI = null; } @@ -1104,6 +1106,17 @@ namespace OpenSim.Region.Framework.Scenes m_controllingClient.MoveAgentIntoRegion(m_regionInfo, AbsolutePosition, look); SendInitialData(); + + // Create child agents in neighbouring regions + if (!m_isChildAgent) + { + IAgentTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); + if (m_agentTransfer != null) + m_agentTransfer.EnableChildAgents(this); + else + m_log.DebugFormat("[SCENE PRESENCE]: Unable to create child agents in neighbours, because AgentTransferModule is not active"); + } + } /// @@ -2156,6 +2169,7 @@ namespace OpenSim.Region.Framework.Scenes { if (m_isChildAgent) { + // WHAT??? m_log.Debug("[SCENEPRESENCE]: AddNewMovement() called on child agent, making root agent!"); // we have to reset the user's child agent connections. @@ -2179,7 +2193,9 @@ namespace OpenSim.Region.Framework.Scenes if (m_scene.SceneGridService != null) { - m_scene.SceneGridService.EnableNeighbourChildAgents(this, new List()); + IAgentTransferModule m_agentTransfer = m_scene.RequestModuleInterface(); + if (m_agentTransfer != null) + m_agentTransfer.EnableChildAgents(this); } return; @@ -2476,11 +2492,6 @@ namespace OpenSim.Region.Framework.Scenes m_controllingClient.SendAvatarData(new SendAvatarData(m_regionInfo.RegionHandle, m_firstname, m_lastname, m_grouptitle, m_uuid, LocalId, pos, m_appearance.Texture.GetBytes(), m_parentID, m_bodyRot)); - if (!m_isChildAgent) - { - m_scene.InformClientOfNeighbours(this); - } - SendInitialFullUpdateToAllClients(); SendAppearanceToAllOtherAgents(); } diff --git a/bin/config-include/Grid.ini b/bin/config-include/Grid.ini index 4892306b8a..1a9ac72d46 100644 --- a/bin/config-include/Grid.ini +++ b/bin/config-include/Grid.ini @@ -17,6 +17,7 @@ PresenceServices = "RemotePresenceServicesConnector" UserAccountServices = "RemoteUserAccountServicesConnector" SimulationServices = "RemoteSimulationConnectorModule" + AgentTransferModule = "AgentTransferModule" LandServiceInConnector = true NeighbourServiceInConnector = true SimulationServiceInConnector = true diff --git a/bin/config-include/GridHypergrid.ini b/bin/config-include/GridHypergrid.ini index 9077e734f5..1275a603aa 100644 --- a/bin/config-include/GridHypergrid.ini +++ b/bin/config-include/GridHypergrid.ini @@ -20,6 +20,7 @@ PresenceServices = "RemotePresenceServicesConnector" UserAccountServices = "RemoteUserAccountServicesConnector" SimulationServices = "RemoteSimulationConnectorModule" + AgentTransferModule = "AgentTransferModule" LandServiceInConnector = true NeighbourServiceInConnector = true HypergridServiceInConnector = true diff --git a/bin/config-include/Standalone.ini b/bin/config-include/Standalone.ini index bf3237bd0f..c9d483bfa0 100644 --- a/bin/config-include/Standalone.ini +++ b/bin/config-include/Standalone.ini @@ -16,6 +16,7 @@ PresenceServices = "LocalPresenceServicesConnector" UserAccountServices = "LocalUserAccountServicesConnector" SimulationServices = "LocalSimulationConnectorModule" + AgentTransferModule = "AgentTransferModule" LibraryModule = true LLLoginServiceInConnector = true diff --git a/bin/config-include/StandaloneHypergrid.ini b/bin/config-include/StandaloneHypergrid.ini index 682170c6fb..20c5d102e6 100644 --- a/bin/config-include/StandaloneHypergrid.ini +++ b/bin/config-include/StandaloneHypergrid.ini @@ -19,7 +19,8 @@ PresenceServices = "LocalPresenceServicesConnector" UserAccountServices = "LocalUserAccountServicesConnector" SimulationServices = "RemoteSimulationConnectorModule" - AvatarServices = "LocalAvatarServicesConnector"; + AvatarServices = "LocalAvatarServicesConnector" + AgentTransferModule = "AgentTransferModule" InventoryServiceInConnector = true AssetServiceInConnector = true HGAuthServiceInConnector = true