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! --- .../Environment/Scenes/Hypergrid/HGAssetMapper.cs | 377 +++++++++++++++++++++ .../Scenes/Hypergrid/HGScene.Inventory.cs | 152 +++++++++ .../Region/Environment/Scenes/Hypergrid/HGScene.cs | 78 +++++ .../Hypergrid/HGSceneCommunicationService.cs | 263 ++++++++++++++ 4 files changed, 870 insertions(+) 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/Scenes') 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