From e187972377c19bdd85093677c4c54034e4f9196e Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Tue, 25 Nov 2008 15:19:00 +0000 Subject: * Apply http://opensimulator.org/mantis/view.php?id=2640 * This is Diva's hypergrid patch, as perviously discussed on the opensim-dev mailing list * Applied some minor prebuild.xml jiggling to resolve a dependency issue * Thanks Diva! --- .../Modules/Hypergrid/HGStandaloneAssetService.cs | 199 +++++++++++ .../Hypergrid/HGStandaloneInventoryService.cs | 315 +++++++++++++++++ .../Modules/Hypergrid/HGWorldMapModule.cs | 178 ++++++++++ .../Environment/Scenes/Hypergrid/HGAssetMapper.cs | 377 +++++++++++++++++++++ .../Scenes/Hypergrid/HGScene.Inventory.cs | 152 +++++++++ .../Region/Environment/Scenes/Hypergrid/HGScene.cs | 78 +++++ .../Hypergrid/HGSceneCommunicationService.cs | 263 ++++++++++++++ 7 files changed, 1562 insertions(+) create mode 100644 OpenSim/Region/Environment/Modules/Hypergrid/HGStandaloneAssetService.cs create mode 100644 OpenSim/Region/Environment/Modules/Hypergrid/HGStandaloneInventoryService.cs create mode 100644 OpenSim/Region/Environment/Modules/Hypergrid/HGWorldMapModule.cs create mode 100644 OpenSim/Region/Environment/Scenes/Hypergrid/HGAssetMapper.cs create mode 100644 OpenSim/Region/Environment/Scenes/Hypergrid/HGScene.Inventory.cs create mode 100644 OpenSim/Region/Environment/Scenes/Hypergrid/HGScene.cs create mode 100644 OpenSim/Region/Environment/Scenes/Hypergrid/HGSceneCommunicationService.cs (limited to 'OpenSim/Region/Environment') diff --git a/OpenSim/Region/Environment/Modules/Hypergrid/HGStandaloneAssetService.cs b/OpenSim/Region/Environment/Modules/Hypergrid/HGStandaloneAssetService.cs new file mode 100644 index 0000000..cfcda42 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/Hypergrid/HGStandaloneAssetService.cs @@ -0,0 +1,199 @@ +/** + * Copyright (c) 2008, Contributors. All rights reserved. + * 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 Organizations nor the names of Individual + * Contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 log4net; +using Nini.Config; + +using OpenMetaverse; + +using OpenSim.Framework; +using OpenSim.Framework.Communications; +using OpenSim.Framework.Communications.Cache; +using OpenSim.Framework.Servers; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; +using OpenSim.Grid.AssetServer; + +namespace OpenSim.Region.Environment.Modules.Hypergrid +{ + public class HGStandaloneAssetService : IRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static bool initialized = false; + private static bool enabled = false; + + Scene m_scene; + AssetService m_assetService; + + #region IRegionModule interface + + public void Initialise(Scene scene, IConfigSource config) + { + if (!initialized) + { + initialized = true; + m_scene = scene; + + // This module is only on for standalones in hypergrid mode + enabled = !config.Configs["Startup"].GetBoolean("gridmode", true) && config.Configs["Startup"].GetBoolean("hypergrid", false); + } + } + + public void PostInitialise() + { + if (enabled) + { + m_log.Info("[HGStandaloneAssetService]: Starting..."); + + m_assetService = new AssetService(m_scene); + } + } + + public void Close() + { + } + + public string Name + { + get { return "HGStandaloneAssetService"; } + } + + public bool IsSharedModule + { + get { return true; } + } + + #endregion + + } + + public class AssetService + { + private IUserService m_userService; + private bool m_doLookup = false; + + public bool DoLookup + { + get { return m_doLookup; } + set { m_doLookup = value; } + } + private static readonly ILog m_log + = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public AssetService(Scene m_scene) + { + AddHttpHandlers(m_scene); + m_userService = m_scene.CommsManager.UserService; + } + + protected void AddHttpHandlers(Scene m_scene) + { + IAssetProviderPlugin m_assetProvider = ((AssetServerBase)m_scene.AssetCache.AssetServer).AssetProviderPlugin; + + m_scene.AddStreamHandler(new GetAssetStreamHandler(m_assetProvider)); + m_scene.AddStreamHandler(new PostAssetStreamHandler(m_assetProvider)); + + } + + + ///// + ///// Check that the source of an inventory request is one that we trust. + ///// + ///// + ///// + //public bool CheckTrustSource(IPEndPoint peer) + //{ + // if (m_doLookup) + // { + // m_log.InfoFormat("[GRID AGENT INVENTORY]: Checking trusted source {0}", peer); + // UriBuilder ub = new UriBuilder(m_userserver_url); + // IPAddress[] uaddrs = Dns.GetHostAddresses(ub.Host); + // foreach (IPAddress uaddr in uaddrs) + // { + // if (uaddr.Equals(peer.Address)) + // { + // return true; + // } + // } + + // m_log.WarnFormat( + // "[GRID AGENT INVENTORY]: Rejecting request since source {0} was not in the list of trusted sources", + // peer); + + // return false; + // } + // else + // { + // return true; + // } + //} + + /// + /// Check that the source of an inventory request for a particular agent is a current session belonging to + /// that agent. + /// + /// + /// + /// + public bool CheckAuthSession(string session_id, string avatar_id) + { + if (m_doLookup) + { + m_log.InfoFormat("[HGStandaloneInvService]: checking authed session {0} {1}", session_id, avatar_id); + UUID userID = UUID.Zero; + UUID sessionID = UUID.Zero; + UUID.TryParse(avatar_id, out userID); + UUID.TryParse(session_id, out sessionID); + if (userID.Equals(UUID.Zero) || sessionID.Equals(UUID.Zero)) + { + m_log.Info("[HGStandaloneInvService]: Invalid user or session id " + avatar_id + "; " + session_id); + return false; + } + UserProfileData userProfile = m_userService.GetUserProfile(userID); + if (userProfile != null && userProfile.CurrentAgent != null && + userProfile.CurrentAgent.SessionID == sessionID) + { + m_log.Info("[HGStandaloneInvService]: user is logged in and session is valid. Authorizing access."); + return true; + } + + m_log.Warn("[HGStandaloneInvService]: unknown user or session_id, request rejected"); + return false; + } + else + { + return true; + } + } + } +} diff --git a/OpenSim/Region/Environment/Modules/Hypergrid/HGStandaloneInventoryService.cs b/OpenSim/Region/Environment/Modules/Hypergrid/HGStandaloneInventoryService.cs new file mode 100644 index 0000000..7203b88 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/Hypergrid/HGStandaloneInventoryService.cs @@ -0,0 +1,315 @@ +/** + * Copyright (c) 2008, Contributors. All rights reserved. + * 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 Organizations nor the names of Individual + * Contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 log4net; +using Nini.Config; + +using OpenMetaverse; + +using OpenSim.Framework; +using OpenSim.Framework.Communications; +using OpenSim.Framework.Communications.Cache; +using OpenSim.Framework.Servers; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Modules.Hypergrid +{ + public class HGStandaloneInventoryService : IRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static bool initialized = false; + private static bool enabled = false; + + Scene m_scene; + InventoryService m_inventoryService; + + #region IRegionModule interface + + public void Initialise(Scene scene, IConfigSource config) + { + if (!initialized) + { + initialized = true; + m_scene = scene; + + // This module is only on for standalones + enabled = !config.Configs["Startup"].GetBoolean("gridmode", true) && config.Configs["Startup"].GetBoolean("hypergrid", false); + } + } + + public void PostInitialise() + { + if (enabled) + { + m_log.Info("[HGStandaloneInvService]: Starting..."); + m_inventoryService = new InventoryService(m_scene); + } + } + + public void Close() + { + } + + public string Name + { + get { return "HGStandaloneInventoryService"; } + } + + public bool IsSharedModule + { + get { return true; } + } + + #endregion + + } + + public class InventoryService + { + private InventoryServiceBase m_inventoryService; + private IUserService m_userService; + private bool m_doLookup = false; + + public bool DoLookup + { + get { return m_doLookup; } + set { m_doLookup = value; } + } + private static readonly ILog m_log + = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public InventoryService(Scene m_scene) + { + m_inventoryService = (InventoryServiceBase)m_scene.CommsManager.SecureInventoryService; + m_userService = m_scene.CommsManager.UserService; + AddHttpHandlers(m_scene); + + } + + protected void AddHttpHandlers(Scene m_scene) + { + m_scene.AddStreamHandler( + new RestDeserialiseSecureHandler( + "POST", "/GetInventory/", GetUserInventory, CheckAuthSession)); + + m_scene.AddStreamHandler( + new RestDeserialiseSecureHandler( + "POST", "/NewFolder/", m_inventoryService.AddFolder, CheckAuthSession)); + + m_scene.AddStreamHandler( + new RestDeserialiseSecureHandler( + "POST", "/UpdateFolder/", m_inventoryService.UpdateFolder, CheckAuthSession)); + + m_scene.AddStreamHandler( + new RestDeserialiseSecureHandler( + "POST", "/MoveFolder/", m_inventoryService.MoveFolder, CheckAuthSession)); + + m_scene.AddStreamHandler( + new RestDeserialiseSecureHandler( + "POST", "/PurgeFolder/", m_inventoryService.PurgeFolder, CheckAuthSession)); + + m_scene.AddStreamHandler( + new RestDeserialiseSecureHandler( + "POST", "/NewItem/", m_inventoryService.AddItem, CheckAuthSession)); + + m_scene.AddStreamHandler( + new RestDeserialiseSecureHandler( + "POST", "/DeleteItem/", m_inventoryService.DeleteItem, CheckAuthSession)); + + //// WARNING: Root folders no longer just delivers the root and immediate child folders (e.g + //// system folders such as Objects, Textures), but it now returns the entire inventory skeleton. + //// It would have been better to rename this request, but complexities in the BaseHttpServer + //// (e.g. any http request not found is automatically treated as an xmlrpc request) make it easier + //// to do this for now. + //m_scene.AddStreamHandler( + // new RestDeserialiseTrustedHandler> + // ("POST", "/RootFolders/", GetInventorySkeleton, CheckTrustSource)); + + //// for persistent active gestures + //m_scene.AddStreamHandler( + // new RestDeserialiseTrustedHandler> + // ("POST", "/ActiveGestures/", GetActiveGestures, CheckTrustSource)); + } + + + ///// + ///// Check that the source of an inventory request is one that we trust. + ///// + ///// + ///// + //public bool CheckTrustSource(IPEndPoint peer) + //{ + // if (m_doLookup) + // { + // m_log.InfoFormat("[GRID AGENT INVENTORY]: Checking trusted source {0}", peer); + // UriBuilder ub = new UriBuilder(m_userserver_url); + // IPAddress[] uaddrs = Dns.GetHostAddresses(ub.Host); + // foreach (IPAddress uaddr in uaddrs) + // { + // if (uaddr.Equals(peer.Address)) + // { + // return true; + // } + // } + + // m_log.WarnFormat( + // "[GRID AGENT INVENTORY]: Rejecting request since source {0} was not in the list of trusted sources", + // peer); + + // return false; + // } + // else + // { + // return true; + // } + //} + + /// + /// Check that the source of an inventory request for a particular agent is a current session belonging to + /// that agent. + /// + /// + /// + /// + public bool CheckAuthSession(string session_id, string avatar_id) + { + if (m_doLookup) + { + m_log.InfoFormat("[HGStandaloneInvService]: checking authed session {0} {1}", session_id, avatar_id); + UUID userID = UUID.Zero; + UUID sessionID = UUID.Zero; + UUID.TryParse(avatar_id, out userID); + UUID.TryParse(session_id, out sessionID); + if (userID.Equals(UUID.Zero) || sessionID.Equals(UUID.Zero)) + { + m_log.Info("[HGStandaloneInvService]: Invalid user or session id " + avatar_id + "; " + session_id); + return false; + } + UserProfileData userProfile = m_userService.GetUserProfile(userID); + if (userProfile != null && userProfile.CurrentAgent != null && + userProfile.CurrentAgent.SessionID == sessionID) + { + m_log.Info("[HGStandaloneInvService]: user is logged in and session is valid. Authorizing access."); + return true; + } + + m_log.Warn("[HGStandaloneInvService]: unknown user or session_id, request rejected"); + return false; + } + else + { + return true; + } + } + + + /// + /// Return a user's entire inventory + /// + /// + /// The user's inventory. If an inventory cannot be found then an empty collection is returned. + public InventoryCollection GetUserInventory(Guid rawUserID) + { + UUID userID = new UUID(rawUserID); + + m_log.Info("[HGStandaloneInvService]: Processing request for inventory of " + userID); + + // Uncomment me to simulate a slow responding inventory server + //Thread.Sleep(16000); + + InventoryCollection invCollection = new InventoryCollection(); + + List allFolders = ((InventoryServiceBase)m_inventoryService).GetInventorySkeleton(userID); + + if (null == allFolders) + { + m_log.WarnFormat("[HGStandaloneInvService]: No inventory found for user {0}", rawUserID); + + return invCollection; + } + + List allItems = new List(); + + foreach (InventoryFolderBase folder in allFolders) + { + List items = ((InventoryServiceBase)m_inventoryService).RequestFolderItems(folder.ID); + + if (items != null) + { + allItems.InsertRange(0, items); + } + } + + invCollection.UserID = userID; + invCollection.Folders = allFolders; + invCollection.Items = allItems; + + // foreach (InventoryFolderBase folder in invCollection.Folders) + // { + // m_log.DebugFormat("[GRID AGENT INVENTORY]: Sending back folder {0} {1}", folder.Name, folder.ID); + // } + // + // foreach (InventoryItemBase item in invCollection.Items) + // { + // m_log.DebugFormat("[GRID AGENT INVENTORY]: Sending back item {0} {1}, folder {2}", item.Name, item.ID, item.Folder); + // } + + m_log.InfoFormat( + "[HGStandaloneInvService]: Sending back inventory response to user {0} containing {1} folders and {2} items", + invCollection.UserID, invCollection.Folders.Count, invCollection.Items.Count); + + return invCollection; + } + + /// + /// Guid to UUID wrapper for same name IInventoryServices method + /// + /// + /// + public List GetInventorySkeleton(Guid rawUserID) + { + UUID userID = new UUID(rawUserID); + return ((InventoryServiceBase)m_inventoryService).GetInventorySkeleton(userID); + } + + public List GetActiveGestures(Guid rawUserID) + { + UUID userID = new UUID(rawUserID); + + m_log.InfoFormat("[HGStandaloneInvService]: fetching active gestures for user {0}", userID); + + return ((InventoryServiceBase)m_inventoryService).GetActiveGestures(userID); + } + } +} diff --git a/OpenSim/Region/Environment/Modules/Hypergrid/HGWorldMapModule.cs b/OpenSim/Region/Environment/Modules/Hypergrid/HGWorldMapModule.cs new file mode 100644 index 0000000..7f8f285 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/Hypergrid/HGWorldMapModule.cs @@ -0,0 +1,178 @@ +/** + * Copyright (c) 2008, Contributors. All rights reserved. + * 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 Organizations nor the names of Individual + * Contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Net; +using System.Reflection; +using System.Threading; +using OpenMetaverse; +using OpenMetaverse.Imaging; +using OpenMetaverse.StructuredData; +using log4net; +using Nini.Config; +using Nwc.XmlRpc; + +using OpenSim.Framework; +using OpenSim.Framework.Communications.Cache; +using OpenSim.Framework.Communications.Capabilities; +using OpenSim.Framework.Servers; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Modules.World.WorldMap; +using OpenSim.Region.Environment.Scenes; +using OpenSim.Region.Environment.Types; +using Caps = OpenSim.Framework.Communications.Capabilities.Caps; + +using OSD = OpenMetaverse.StructuredData.OSD; +using OSDMap = OpenMetaverse.StructuredData.OSDMap; +using OSDArray = OpenMetaverse.StructuredData.OSDArray; + +namespace OpenSim.Region.Environment.Modules.Hypergrid +{ + public class HGWorldMapModule : WorldMapModule, IRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + #region IRegionModule Members + + public override void Initialise(Scene scene, IConfigSource config) + { + IConfig startupConfig = config.Configs["Startup"]; + if (startupConfig.GetString("WorldMapModule", "WorldMap") == "HGWorldMap") + m_Enabled = true; + + if (!m_Enabled) + return; + m_log.Info("[HGMap] Initializing..."); + m_scene = scene; + } + + + public override string Name + { + get { return "HGWorldMap"; } + } + + + #endregion + + /// + /// Requests map blocks in area of minX, maxX, minY, MaxY in world cordinates + /// + /// + /// + /// + /// + public override void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag) + { + // + // WARNING!!! COPY & PASTE FROM SUPERCLASS + // The only difference is at the very end + // + + m_log.Info("[HGMap]: Request map blocks " + minX + "-" + maxX + " " + minY + "-" + maxY); + + //m_scene.ForEachScenePresence(delegate (ScenePresence sp) { + // if (!sp.IsChildAgent && sp.UUID == remoteClient.AgentId) + // { + // Console.WriteLine("XXX Root agent"); + // DoRequestMapBlocks(remoteClient, minX, minY, maxX, maxY, flag); + // } + //}; + + List mapBlocks; + if ((flag & 0x10000) != 0) // user clicked on the map a tile that isn't visible + { + List response = new List(); + + // this should return one mapblock at most. But make sure: Look whether the one we requested is in there + mapBlocks = m_scene.SceneGridService.RequestNeighbourMapBlocks(minX, minY, maxX, maxY); + if (mapBlocks != null) + { + foreach (MapBlockData block in mapBlocks) + { + if (block.X == minX && block.Y == minY) + { + // found it => add it to response + response.Add(block); + break; + } + } + } + response = mapBlocks; + if (response.Count == 0) + { + // response still empty => couldn't find the map-tile the user clicked on => tell the client + MapBlockData block = new MapBlockData(); + block.X = (ushort)minX; + block.Y = (ushort)minY; + block.Access = 254; // == not there + response.Add(block); + } + remoteClient.SendMapBlock(response, 0); + } + else + { + // normal mapblock request. Use the provided values + mapBlocks = m_scene.SceneGridService.RequestNeighbourMapBlocks(minX - 4, minY - 4, maxX + 4, maxY + 4); + + // Different from super + FillInMap(mapBlocks, minX, minY, maxX, maxY); + // + + remoteClient.SendMapBlock(mapBlocks, flag); + } + } + + + private void FillInMap(List mapBlocks, int minX, int minY, int maxX, int maxY) + { + for (int x = minX; x <= maxX; x++) + for (int y = minY; y <= maxY; y++) + { + MapBlockData mblock = mapBlocks.Find(delegate(MapBlockData mb) { return ((mb.X == x) && (mb.Y == y)); }); + if (mblock == null) + { + mblock = new MapBlockData(); + mblock.X = (ushort)x; + mblock.Y = (ushort)y; + mblock.Name = ""; + mblock.Access = 254; // not here??? + mblock.MapImageId = UUID.Zero; + mapBlocks.Add(mblock); + } + } + } + } +} diff --git a/OpenSim/Region/Environment/Scenes/Hypergrid/HGAssetMapper.cs b/OpenSim/Region/Environment/Scenes/Hypergrid/HGAssetMapper.cs new file mode 100644 index 0000000..3e27b7c --- /dev/null +++ b/OpenSim/Region/Environment/Scenes/Hypergrid/HGAssetMapper.cs @@ -0,0 +1,377 @@ +/** + * Copyright (c) 2008, Contributors. All rights reserved. + * 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 Organizations nor the names of Individual + * Contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; + +using log4net; +using Nini.Config; +using OpenMetaverse; + +using OpenSim.Framework; +using OpenSim.Framework.Communications; +using OpenSim.Framework.Communications.Cache; +using OpenSim.Framework.Servers; +using OpenSim.Region.Environment; +using OpenSim.Region.Environment.Scenes; + +//using HyperGrid.Framework; +//using OpenSim.Region.Communications.Hypergrid; + +namespace OpenSim.Region.Environment.Scenes.Hypergrid +{ + public class HGAssetMapper + { + #region Fields + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + // This maps between asset server URLs and asset server clients + private Dictionary m_assetServers = new Dictionary(); + + // This maps between asset UUIDs and asset servers + private Dictionary m_assetMap = new Dictionary(); + + private Scene m_scene; + #endregion + + #region Constructor + + public HGAssetMapper(Scene scene) + { + m_scene = scene; + } + + #endregion + + #region Internal functions + + private string UserAssetURL(UUID userID) + { + CachedUserInfo uinfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(userID); + if (uinfo != null) + return (uinfo.UserProfile.UserAssetURI == "") ? null : uinfo.UserProfile.UserAssetURI; + return null; + } + + private bool IsHomeUser(UUID userID) + { + CachedUserInfo uinfo = m_scene.CommsManager.UserProfileCacheService.GetUserDetails(userID); + + if (uinfo != null) + { + //if ((uinfo.UserProfile.UserAssetURI == null) || (uinfo.UserProfile.UserAssetURI == "") || + // uinfo.UserProfile.UserAssetURI.Equals(m_scene.CommsManager.NetworkServersInfo.AssetURL)) + if (HGNetworkServersInfo.Singleton.IsLocalUser(uinfo.UserProfile.UserAssetURI)) + { + m_log.Debug("[HGScene]: Home user " + uinfo.UserProfile.FirstName + " " + uinfo.UserProfile.SurName); + return true; + } + } + + m_log.Debug("[HGScene]: Foreign user " + uinfo.UserProfile.FirstName + " " + uinfo.UserProfile.SurName); + return false; + } + + private bool IsInAssetMap(UUID uuid) + { + return m_assetMap.ContainsKey(uuid); + } + + private bool FetchAsset(GridAssetClient asscli, UUID assetID, bool isTexture) + { + // I'm not going over 3 seconds since this will be blocking processing of all the other inbound + // packets from the client. + int pollPeriod = 200; + int maxPolls = 15; + + AssetBase asset; + + // Maybe it came late, and it's already here. Check first. + if (m_scene.CommsManager.AssetCache.TryGetCachedAsset(assetID, out asset)) + { + m_log.Debug("[HGScene]: Asset already in asset cache. " + assetID); + return true; + } + + + asscli.RequestAsset(assetID, isTexture); + + do + { + Thread.Sleep(pollPeriod); + + if (m_scene.CommsManager.AssetCache.TryGetCachedAsset(assetID, out asset) && (asset != null)) + { + m_log.Debug("[HGScene]: Asset made it to asset cache. " + asset.Name + " " + assetID); + // I think I need to store it in the asset DB too. + // For now, let me just do it for textures and scripts + if (((AssetType)asset.Type == AssetType.Texture) || + ((AssetType)asset.Type == AssetType.LSLBytecode) || + ((AssetType)asset.Type == AssetType.LSLText)) + { + AssetBase asset1 = new AssetBase(); + Copy(asset, asset1); + m_scene.AssetCache.AssetServer.StoreAsset(asset1); + } + return true; + } + } while (--maxPolls > 0); + + m_log.WarnFormat("[HGScene]: {0} {1} was not received before the retrieval timeout was reached", + isTexture ? "texture" : "asset", assetID.ToString()); + + return false; + } + + private bool PostAsset(GridAssetClient asscli, UUID assetID) + { + AssetBase asset1; + m_scene.CommsManager.AssetCache.TryGetCachedAsset(assetID, out asset1); + + if (asset1 != null) + { + // See long comment in AssetCache.AddAsset + if (!asset1.Temporary || asset1.Local) + { + // The asset cache returns instances of subclasses of AssetBase: + // TextureImage or AssetInfo. So in passing them to the remote + // server we first need to convert this to instances of AssetBase, + // which is the serializable class for assets. + AssetBase asset = new AssetBase(); + Copy(asset1, asset); + + asscli.StoreAsset(asset); + } + return true; + } + else + m_log.Warn("[HGScene]: Tried to post asset to remote server, but asset not in local cache."); + + return false; + } + + private void Copy(AssetBase from, AssetBase to) + { + to.Data = from.Data; + to.Description = from.Description; + to.FullID = from.FullID; + to.ID = from.ID; + to.Local = from.Local; + to.Name = from.Name; + to.Temporary = from.Temporary; + to.Type = from.Type; + + } + + private void _guardedAdd(Dictionary lst, UUID obj, bool val) + { + if (!lst.ContainsKey(obj)) + lst.Add(obj, val); + } + + private void SniffTextureUUIDs(Dictionary uuids, SceneObjectGroup sog) + { + try + { + _guardedAdd(uuids, sog.RootPart.Shape.Textures.DefaultTexture.TextureID, true); + } + catch (Exception) { } + + foreach (Primitive.TextureEntryFace tface in sog.RootPart.Shape.Textures.FaceTextures) + { + try + { + _guardedAdd(uuids, tface.TextureID, true); + } + catch (Exception) { } + } + + foreach (SceneObjectPart sop in sog.Children.Values) + { + try + { + _guardedAdd(uuids, sop.Shape.Textures.DefaultTexture.TextureID, true); + } + catch (Exception) { } + foreach (Primitive.TextureEntryFace tface in sop.Shape.Textures.FaceTextures) + { + try + { + _guardedAdd(uuids, tface.TextureID, true); + } + catch (Exception) { } + } + } + } + + private void SniffTaskInventoryUUIDs(Dictionary uuids, SceneObjectGroup sog) + { + TaskInventoryDictionary tinv = sog.RootPart.TaskInventory; + + foreach (TaskInventoryItem titem in tinv.Values) + { + uuids.Add(titem.AssetID, (InventoryType)titem.Type == InventoryType.Texture); + } + } + + private Dictionary SniffUUIDs(AssetBase asset) + { + Dictionary uuids = new Dictionary(); + if ((asset != null) && ((AssetType)asset.Type == AssetType.Object)) + { + string ass_str = Utils.BytesToString(asset.Data); + SceneObjectGroup sog = new SceneObjectGroup(ass_str, true); + + SniffTextureUUIDs(uuids, sog); + + // We need to sniff further... + SniffTaskInventoryUUIDs(uuids, sog); + + } + + return uuids; + } + + private Dictionary SniffUUIDs(UUID assetID) + { + Dictionary uuids = new Dictionary(); + + AssetBase asset; + m_scene.CommsManager.AssetCache.TryGetCachedAsset(assetID, out asset); + + return SniffUUIDs(asset); + } + + private void Dump(Dictionary lst) + { + m_log.Debug("XXX -------- UUID DUMP ------- XXX"); + foreach (KeyValuePair kvp in lst) + m_log.Debug(" >> " + kvp.Key + " (texture? " + kvp.Value + ")"); + m_log.Debug("XXX -------- UUID DUMP ------- XXX"); + } + + #endregion + + + #region Public interface + + public void Get(UUID itemID, UUID ownerID) + { + if (!IsInAssetMap(itemID) && !IsHomeUser(ownerID)) + { + // Get the item from the remote asset server onto the local AssetCache + // and place an entry in m_assetMap + + GridAssetClient asscli = null; + string userAssetURL = UserAssetURL(ownerID); + if (userAssetURL != null) + { + m_assetServers.TryGetValue(userAssetURL, out asscli); + if (asscli == null) + { + m_log.Debug("[HGScene]: Starting new GridAssetClient for " + userAssetURL); + asscli = new GridAssetClient(userAssetURL); + asscli.SetReceiver(m_scene.CommsManager.AssetCache); // Straight to the asset cache! + m_assetServers.Add(userAssetURL, asscli); + } + + m_log.Debug("[HGScene]: Fetching object " + itemID + " to asset server " + userAssetURL); + bool success = FetchAsset(asscli, itemID, false); // asscli.RequestAsset(item.ItemID, false); + + // OK, now fetch the inside. + Dictionary ids = SniffUUIDs(itemID); + Dump(ids); + foreach (KeyValuePair kvp in ids) + FetchAsset(asscli, kvp.Key, kvp.Value); + + + if (success) + { + m_log.Debug("[HGScene]: Successfully fetched item from remote asset server " + userAssetURL); + m_assetMap.Add(itemID, asscli); + } + else + m_log.Warn("[HGScene]: Could not fetch asset from remote asset server " + userAssetURL); + } + else + m_log.Warn("[HGScene]: Unable to locate foreign user's asset server"); + } + } + + public void Post(UUID itemID, UUID ownerID) + { + if (!IsHomeUser(ownerID)) + { + // Post the item from the local AssetCache ontp the remote asset server + // and place an entry in m_assetMap + + GridAssetClient asscli = null; + string userAssetURL = UserAssetURL(ownerID); + if (userAssetURL != null) + { + m_assetServers.TryGetValue(userAssetURL, out asscli); + if (asscli == null) + { + m_log.Debug("[HGScene]: Starting new GridAssetClient for " + userAssetURL); + asscli = new GridAssetClient(userAssetURL); + asscli.SetReceiver(m_scene.CommsManager.AssetCache); // Straight to the asset cache! + m_assetServers.Add(userAssetURL, asscli); + } + m_log.Debug("[HGScene]: Posting object " + itemID + " to asset server " + userAssetURL); + bool success = PostAsset(asscli, itemID); + + // Now the inside + Dictionary ids = SniffUUIDs(itemID); + Dump(ids); + foreach (KeyValuePair kvp in ids) + PostAsset(asscli, kvp.Key); + + if (success) + { + m_log.Debug("[HGScene]: Successfully posted item to remote asset server " + userAssetURL); + m_assetMap.Add(itemID, asscli); + } + else + m_log.Warn("[HGScene]: Could not post asset to remote asset server " + userAssetURL); + + //if (!m_assetMap.ContainsKey(itemID)) + // m_assetMap.Add(itemID, asscli); + } + else + m_log.Warn("[HGScene]: Unable to locate foreign user's asset server"); + + } + } + + #endregion + + } +} diff --git a/OpenSim/Region/Environment/Scenes/Hypergrid/HGScene.Inventory.cs b/OpenSim/Region/Environment/Scenes/Hypergrid/HGScene.Inventory.cs new file mode 100644 index 0000000..af3c04f --- /dev/null +++ b/OpenSim/Region/Environment/Scenes/Hypergrid/HGScene.Inventory.cs @@ -0,0 +1,152 @@ +/** + * Copyright (c) 2008, Contributors. All rights reserved. + * 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 Organizations nor the names of Individual + * Contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; + +using log4net; +using Nini.Config; +using OpenMetaverse; + +using OpenSim.Framework; +using OpenSim.Framework.Communications; +using OpenSim.Framework.Communications.Cache; +using OpenSim.Framework.Servers; +using OpenSim.Region.Environment; +using OpenSim.Region.Environment.Scenes; + +namespace OpenSim.Region.Environment.Scenes.Hypergrid +{ + public partial class HGScene : Scene + { + #region Fields + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private HGAssetMapper m_assMapper; + + #endregion + + #region Constructors + + public HGScene(RegionInfo regInfo, AgentCircuitManager authen, + CommunicationsManager commsMan, SceneCommunicationService sceneGridService, + AssetCache assetCach, StorageManager storeManager, BaseHttpServer httpServer, + ModuleLoader moduleLoader, bool dumpAssetsToFile, bool physicalPrim, + bool SeeIntoRegionFromNeighbor, IConfigSource config, string simulatorVersion) + : base(regInfo, authen, commsMan, sceneGridService, assetCach, storeManager, httpServer, moduleLoader, + dumpAssetsToFile, physicalPrim, SeeIntoRegionFromNeighbor, config, simulatorVersion) + { + m_log.Info("[HGScene]: Starting HGScene."); + m_assMapper = new HGAssetMapper(this); + + EventManager.OnNewInventoryItemUploadComplete += UploadInventoryItem; + } + + #endregion + + #region Event handlers + + public void UploadInventoryItem(UUID avatarID, UUID assetID, string name, int userlevel) + { + CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(avatarID); + if (userInfo != null) + { + m_assMapper.Post(assetID, avatarID); + } + } + + #endregion + + #region Overrides of Scene.Inventory methods + + /// + /// CapsUpdateInventoryItemAsset + /// + public override UUID CapsUpdateInventoryItemAsset(IClientAPI remoteClient, UUID itemID, byte[] data) + { + UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data); + + UploadInventoryItem(remoteClient.AgentId, newAssetID, "", 0); + + return newAssetID; + } + + /// + /// DeleteToInventory + /// + public override UUID DeleteToInventory(int destination, UUID folderID, SceneObjectGroup objectGroup, IClientAPI remoteClient) + { + UUID assetID = base.DeleteToInventory(destination, folderID, objectGroup, remoteClient); + + if (!assetID.Equals(UUID.Zero)) + { + UploadInventoryItem(remoteClient.AgentId, assetID, "", 0); + } + else + m_log.Debug("[HGScene]: Scene.Inventory did not create asset"); + + return assetID; + } + + /// + /// RezObject + /// + public override SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, + UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, + bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) + { + CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId); + if (userInfo != null) + { + if (userInfo.RootFolder != null) + { + InventoryItemBase item = userInfo.RootFolder.FindItem(itemID); + + if (item != null) + { + m_assMapper.Get(item.AssetID, remoteClient.AgentId); + + } + } + } + + // OK, we're done fetching. Pass it up to the default RezObject + return base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, + RezSelected, RemoveItem, fromTaskID, attachment); + + } + + + #endregion + + } + +} diff --git a/OpenSim/Region/Environment/Scenes/Hypergrid/HGScene.cs b/OpenSim/Region/Environment/Scenes/Hypergrid/HGScene.cs new file mode 100644 index 0000000..a1a6173 --- /dev/null +++ b/OpenSim/Region/Environment/Scenes/Hypergrid/HGScene.cs @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2008, Contributors. All rights reserved. + * 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 Organizations nor the names of Individual + * Contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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 OpenMetaverse; + +using OpenSim.Framework; + +using OpenSim.Framework.Communications.Cache; +using OpenSim.Region.Environment; +using OpenSim.Region.Environment.Scenes; +using TPFlags = OpenSim.Framework.Constants.TeleportFlags; + +namespace OpenSim.Region.Environment.Scenes.Hypergrid +{ + public partial class HGScene : Scene + { + /// + /// Teleport an avatar to their home region + /// + /// + /// + public override void TeleportClientHome(UUID agentId, IClientAPI client) + { + m_log.Debug("[HGScene]: TeleportClientHome " + client.FirstName + " " + client.LastName); + + CachedUserInfo uinfo = CommsManager.UserProfileCacheService.GetUserDetails(agentId); + UserProfileData UserProfile = uinfo.UserProfile; + + if (UserProfile != null) + { + RegionInfo regionInfo = CommsManager.GridService.RequestNeighbourInfo(UserProfile.HomeRegion); + //if (regionInfo != null) + //{ + // UserProfile.HomeRegionID = regionInfo.RegionID; + // //CommsManager.UserService.UpdateUserProfile(UserProfile); + //} + if (regionInfo == null) + { + // can't find the Home region: Tell viewer and abort + client.SendTeleportFailed("Your home-region could not be found."); + return; + } + RequestTeleportLocation( + client, regionInfo.RegionHandle, UserProfile.HomeLocation, UserProfile.HomeLookAt, + (uint)(TPFlags.SetLastToTarget | TPFlags.ViaHome)); + } + } + + } +} diff --git a/OpenSim/Region/Environment/Scenes/Hypergrid/HGSceneCommunicationService.cs b/OpenSim/Region/Environment/Scenes/Hypergrid/HGSceneCommunicationService.cs new file mode 100644 index 0000000..501584a --- /dev/null +++ b/OpenSim/Region/Environment/Scenes/Hypergrid/HGSceneCommunicationService.cs @@ -0,0 +1,263 @@ +/** + * Copyright (c) 2008, Contributors. All rights reserved. + * 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 Organizations nor the names of Individual + * Contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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.Reflection; +using System.Threading; + +using OpenMetaverse; + +using log4net; +using OpenSim.Framework; +using OpenSim.Framework.Communications; +using OpenSim.Framework.Communications.Cache; +using OpenSim.Region.Environment.Scenes; +using OpenSim.Region.Environment; +using OpenSim.Region.Interfaces; +using OSD = OpenMetaverse.StructuredData.OSD; + +namespace OpenSim.Region.Environment.Scenes.Hypergrid +{ + public class HGSceneCommunicationService : SceneCommunicationService + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IHyperlink m_hg; + + public HGSceneCommunicationService(CommunicationsManager commsMan, IHyperlink hg) : base(commsMan) + { + m_hg = hg; + } + + + /// + /// 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 = false; + + IEventQueue eq = avatar.Scene.RequestModuleInterface(); + + if (regionHandle == m_regionInfo.RegionHandle) + { + // Teleport within the same region + if (position.X < 0 || position.X > Constants.RegionSize || position.Y < 0 || position.Y > Constants.RegionSize || 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 = (float)avatar.Scene.GetLandHeight((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 + { + RegionInfo reg = RequestNeighbouringRegionInfo(regionHandle); + if (reg != null) + { + /// + /// Hypergrid mod start + /// + /// + bool isHyperLink = m_hg.IsHyperlinkRegion(reg.RegionHandle); + bool isHomeUser = true; + ulong realHandle = regionHandle; + CachedUserInfo uinfo = m_commsProvider.UserProfileCacheService.GetUserDetails(avatar.UUID); + if (uinfo != null) + { + isHomeUser = HGNetworkServersInfo.Singleton.IsLocalUser(uinfo.UserProfile.UserAssetURI); + realHandle = m_hg.FindRegionHandle(regionHandle); + Console.WriteLine("XXX ---- home user? " + isHomeUser + " --- hyperlink? " + isHyperLink + " --- real handle: " + realHandle.ToString()); + } + /// + /// Hypergrid mod stop + /// + /// + + if (eq == null) + avatar.ControllingClient.SendTeleportLocationStart(); + + AgentCircuitData agent = avatar.ControllingClient.RequestClientInfo(); + agent.BaseFolder = UUID.Zero; + agent.InventoryFolder = UUID.Zero; + agent.startpos = position; + agent.child = true; + + if (reg.RemotingAddress != "" && reg.RemotingPort != 0) + { + // region is remote. see if it is up + destRegionUp = m_commsProvider.InterRegion.CheckRegion(reg.RemotingAddress, reg.RemotingPort); + } + else + { + // assume local regions are always up + destRegionUp = true; + } + + 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); + agent.child = false; + m_commsProvider.InterRegion.InformRegionOfChildAgent(reg.RegionHandle, agent); + + m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId, + position, false); + Thread.Sleep(2000); + AgentCircuitData circuitdata = avatar.ControllingClient.RequestClientInfo(); + + // TODO Should construct this behind a method + string capsPath = + "http://" + reg.ExternalHostName + ":" + reg.HttpPort + + "/CAPS/" + circuitdata.CapsPath + "0000/"; + + 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) + { + OSD Item = EventQueueHelper.TeleportFinishEvent(realHandle, 13, reg.ExternalEndPoint, + 4, teleportFlags, capsPath, avatar.UUID); + eq.Enqueue(Item, avatar.UUID); + } + else + { + avatar.ControllingClient.SendRegionTeleport(realHandle, 13, reg.ExternalEndPoint, 4, + teleportFlags, capsPath); + } + /// + /// Hypergrid mod stop + /// + + avatar.MakeChildAgent(); + Thread.Sleep(7000); + avatar.CrossAttachmentsIntoNewRegion(reg.RegionHandle, true); + if (KiPrimitive != null) + { + KiPrimitive(avatar.LocalId); + } + + avatar.Close(); + + uint newRegionX = (uint)(reg.RegionHandle >> 40); + uint newRegionY = (((uint)(reg.RegionHandle)) >> 8); + uint oldRegionX = (uint)(m_regionInfo.RegionHandle >> 40); + uint oldRegionY = (((uint)(m_regionInfo.RegionHandle)) >> 8); + /// + /// Hypergrid mod: extra check for isHyperLink + /// + if ((Util.fast_distance2d((int)(newRegionX - oldRegionX), (int)(newRegionY - oldRegionY)) > 3) || isHyperLink) + { + //SendCloseChildAgentConnections(avatar.UUID, avatar.GetKnownRegionList()); + SendCloseChildAgentConnections(avatar.UUID, childRegions); + 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)) + m_commsProvider.UserProfileCacheService.RemoveUser(avatar.UUID); + m_log.InfoFormat("[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); + } + } + } + + } +} -- cgit v1.1