From d9cc908471922a1239bb8a757e07084072852982 Mon Sep 17 00:00:00 2001 From: Charles Krinke Date: Sat, 16 Aug 2008 19:20:14 +0000 Subject: Mantis#1965. Thank you kindly, HomerHorwitz for a patch that: Places touched: - Added two events for in-packets to LLCLientView: RegionHandleRequest and ParcelInfoRequest - Added sending of two out-packets to LLCLientView: RegionIDAndHandleReply and ParcelInfoReply. - Scene handles the RegionHandleRequest, LandManagementModule the ParcelInfoRequest - Added inter-region request for LandData by RegionHandle and local position. This was implemented as XML-RPC request. The returned LandData isn't complete, it only contains the data necessary for answering the ParcelInfoRequest - Added new CAPS (0009) for RemoteParcelRequest and some methods for LandData handling to LandManagementModule - Added methods for fake parcelID creation and parsing to Util - Fixed missing implementation of interface methods. - Added new file: OpenSim/Framework/Communications/Capabilities/LLSDRemoteParcelResponse.cs NOTE: This is part of the patch, too. Due to the many places touched, I would consider this patch as experimental. --- .../Framework/Communications/Capabilities/Caps.cs | 4 +- .../Capabilities/LLSDRemoteParcelResponse.cs | 42 ++++++++ OpenSim/Framework/Communications/IGridServices.cs | 2 + OpenSim/Framework/IClientAPI.cs | 9 ++ OpenSim/Framework/IRegionCommsListener.cs | 5 +- OpenSim/Framework/RegionCommsListener.cs | 15 ++- OpenSim/Framework/Util.cs | 19 ++++ .../Region/ClientStack/LindenUDP/LLClientView.cs | 65 +++++++++++ .../Communications/Local/LocalBackEndServices.cs | 15 +++ .../Region/Communications/OGS1/OGS1GridServices.cs | 101 +++++++++++++++++ .../Modules/World/Land/LandManagementModule.cs | 120 ++++++++++++++++++++- .../Environment/Modules/World/NPC/NPCAvatar.cs | 12 +++ OpenSim/Region/Environment/Scenes/Scene.cs | 18 ++++ .../Scenes/SceneCommunicationService.cs | 16 ++- .../Region/Examples/SimpleModule/MyNpcCharacter.cs | 11 ++ 15 files changed, 448 insertions(+), 6 deletions(-) create mode 100644 OpenSim/Framework/Communications/Capabilities/LLSDRemoteParcelResponse.cs diff --git a/OpenSim/Framework/Communications/Capabilities/Caps.cs b/OpenSim/Framework/Communications/Capabilities/Caps.cs index 7350d4d..1aa8eb0 100644 --- a/OpenSim/Framework/Communications/Capabilities/Caps.cs +++ b/OpenSim/Framework/Communications/Capabilities/Caps.cs @@ -86,11 +86,13 @@ namespace OpenSim.Framework.Communications.Capabilities private static readonly string m_notecardTaskUpdatePath = "0005/"; // private static readonly string m_fetchInventoryPath = "0006/"; - // The following two entries are in a module, however, there also here so that we don't re-assign + // The following entries are in a module, however, they are also here so that we don't re-assign // the path to another cap by mistake. // private static readonly string m_parcelVoiceInfoRequestPath = "0007/"; // This is in a module. // private static readonly string m_provisionVoiceAccountRequestPath = "0008/";// This is in a module. + // private static readonly string m_remoteParcelRequestPath = "0009/";// This is in the LandManagementModule. + //private string eventQueue = "0100/"; private BaseHttpServer m_httpListener; private LLUUID m_agentID; diff --git a/OpenSim/Framework/Communications/Capabilities/LLSDRemoteParcelResponse.cs b/OpenSim/Framework/Communications/Capabilities/LLSDRemoteParcelResponse.cs new file mode 100644 index 0000000..27adea0 --- /dev/null +++ b/OpenSim/Framework/Communications/Capabilities/LLSDRemoteParcelResponse.cs @@ -0,0 +1,42 @@ +/* +* 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 OpenSim 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 libsecondlife; + +namespace OpenSim.Framework.Communications.Capabilities +{ + [LLSDType("MAP")] + public class LLSDRemoteParcelResponse + { + public LLUUID parcel_id; + + public LLSDRemoteParcelResponse() + { + } + } +} diff --git a/OpenSim/Framework/Communications/IGridServices.cs b/OpenSim/Framework/Communications/IGridServices.cs index 3ecda68..509f408 100644 --- a/OpenSim/Framework/Communications/IGridServices.cs +++ b/OpenSim/Framework/Communications/IGridServices.cs @@ -57,5 +57,7 @@ namespace OpenSim.Framework.Communications RegionInfo RequestClosestRegion(string regionName); Dictionary GetGridSettings(); List RequestNeighbourMapBlocks(int minX, int minY, int maxX, int maxY); + // not complete yet, only contains the fields needed for ParcelInfoReqeust + LandData RequestLandData(ulong regionHandle, uint x, uint y); } } diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 36842cc..536050c 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -293,6 +293,9 @@ namespace OpenSim.Framework public delegate void EstateBlueBoxMessageRequest(IClientAPI remoteClient, LLUUID invoice, LLUUID senderID, LLUUID sessionID, string senderName, string message); public delegate void EstateDebugRegionRequest(IClientAPI remoteClient, LLUUID invoice, LLUUID senderID, bool scripted, bool collisionEvents, bool physics); public delegate void EstateTeleportOneUserHomeRequest(IClientAPI remoteClient, LLUUID invoice, LLUUID senderID, LLUUID prey); + public delegate void RegionHandleRequest(IClientAPI remoteClient, LLUUID regionID); + public delegate void ParcelInfoRequest(IClientAPI remoteClient, LLUUID parcelID); + public delegate void ScriptReset(IClientAPI remoteClient, LLUUID objectID, LLUUID itemID); public delegate void GetScriptRunning(IClientAPI remoteClient, LLUUID objectID, LLUUID itemID); public delegate void SetScriptRunning(IClientAPI remoteClient, LLUUID objectID, LLUUID itemID, bool running); @@ -498,6 +501,9 @@ namespace OpenSim.Framework event EstateDebugRegionRequest OnEstateDebugRegionRequest; event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest; event UUIDNameRequest OnUUIDGroupNameRequest; + + event RegionHandleRequest OnRegionHandleRequest; + event ParcelInfoRequest OnParcelInfoRequest; event RequestObjectPropertiesFamily OnObjectGroupRequest; event ScriptReset OnScriptReset; @@ -721,5 +727,8 @@ namespace OpenSim.Framework void SendSetFollowCamProperties(LLUUID objectID, SortedDictionary parameters); void SendClearFollowCamProperties(LLUUID objectID); + + void SendRegionHandle(LLUUID regoinID, ulong handle); + void SendParcelInfo(RegionInfo info, LandData land, LLUUID parcelID, uint x, uint y); } } diff --git a/OpenSim/Framework/IRegionCommsListener.cs b/OpenSim/Framework/IRegionCommsListener.cs index ce84a40..1758508 100644 --- a/OpenSim/Framework/IRegionCommsListener.cs +++ b/OpenSim/Framework/IRegionCommsListener.cs @@ -52,6 +52,8 @@ namespace OpenSim.Framework public delegate void LogOffUser(ulong regionHandle, LLUUID agentID, LLUUID regionSecret, string message); + public delegate LandData GetLandData(uint x, uint y); + public interface IRegionCommsListener { event ExpectUserDelegate OnExpectUser; @@ -66,5 +68,6 @@ namespace OpenSim.Framework event RegionUp OnRegionUp; event ChildAgentUpdate OnChildAgentUpdate; event LogOffUser OnLogOffUser; + event GetLandData OnGetLandData; } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/RegionCommsListener.cs b/OpenSim/Framework/RegionCommsListener.cs index 4045b44..0b50a81 100644 --- a/OpenSim/Framework/RegionCommsListener.cs +++ b/OpenSim/Framework/RegionCommsListener.cs @@ -46,7 +46,8 @@ namespace OpenSim.Framework private PrimCrossing handlerPrimCrossingIntoRegion = null; // OnPrimCrossingIntoRegion; private RegionUp handlerRegionUp = null; // OnRegionUp; private LogOffUser handlerLogOffUser = null; - + private GetLandData handlerGetLandData = null; + #region IRegionCommsListener Members public event ExpectUserDelegate OnExpectUser; @@ -61,6 +62,7 @@ namespace OpenSim.Framework public event RegionUp OnRegionUp; public event ChildAgentUpdate OnChildAgentUpdate; public event LogOffUser OnLogOffUser; + public event GetLandData OnGetLandData; #endregion @@ -226,5 +228,14 @@ namespace OpenSim.Framework return false; } + + public LandData TriggerGetLandData(uint x, uint y) + { + handlerGetLandData = OnGetLandData; + if (handlerGetLandData != null) + return handlerGetLandData(x, y); + + return null; + } } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index d72e03e..bc35fa6 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -716,5 +716,24 @@ namespace OpenSim.Framework XmlRpcRequest client = new XmlRpcRequest(methodName, args); return client.Send(url, 6000); } + + // used for RemoteParcelRequest (for "About Landmark") + public static LLUUID BuildFakeParcelID(ulong regionHandle, uint x, uint y) { + byte[] bytes = { + (byte)(regionHandle >> 56), (byte)(regionHandle >> 48), (byte)(regionHandle >> 40), (byte)(regionHandle >> 32), + (byte)(regionHandle >> 24), (byte)(regionHandle >> 16), (byte)(regionHandle >> 8), (byte)regionHandle, + (byte)(x >> 24), (byte)(x >> 16), (byte)(x >> 8), (byte)x, + (byte)(y >> 24), (byte)(y >> 16), (byte)(y >> 8), (byte)y }; + return new LLUUID(bytes, 0); + } + + public static void ParseFakeParcelID(LLUUID parcelID, out ulong regionHandle, out uint x, out uint y) { + byte[] bytes = parcelID.GetBytes(); + regionHandle = Helpers.BytesToUInt64(bytes); + x = Helpers.BytesToUInt(bytes, 8); + // grrr. I'd like to use that code in the next line, but libsl has an off-by-one bug here and returns 0. + //uint y = Helpers.BytesToUInt(bytes, 12); + y = (uint)((bytes[12] << 24) | (bytes[13] << 16) | (bytes[14] << 8) | bytes[15]); + } } } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 69c1dac..b616acb 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -229,6 +229,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP // private RequestAsset handlerRequestAsset = null; // OnRequestAsset; private UUIDNameRequest handlerTeleportHomeRequest = null; + private RegionHandleRequest handlerRegionHandleRequest = null; // OnRegionHandleRequest + private ParcelInfoRequest handlerParcelInfoRequest = null; // OnParcelInfoRequest + private ScriptAnswer handlerScriptAnswer = null; private RequestPayPrice handlerRequestPayPrice = null; private ObjectDeselect handlerObjectDetach = null; @@ -916,6 +919,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP public event EstateBlueBoxMessageRequest OnEstateBlueBoxMessageRequest; public event EstateDebugRegionRequest OnEstateDebugRegionRequest; public event EstateTeleportOneUserHomeRequest OnEstateTeleportOneUserHomeRequest; + public event RegionHandleRequest OnRegionHandleRequest; + public event ParcelInfoRequest OnParcelInfoRequest; public event ScriptReset OnScriptReset; public event GetScriptRunning OnGetScriptRunning; public event SetScriptRunning OnSetScriptRunning; @@ -5296,6 +5301,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Parcel related packets + case PacketType.RegionHandleRequest: + RegionHandleRequestPacket rhrPack = (RegionHandleRequestPacket)Pack; + + handlerRegionHandleRequest = OnRegionHandleRequest; + if (handlerRegionHandleRequest != null) + { + handlerRegionHandleRequest(this, rhrPack.RequestBlock.RegionID); + } + break; + + case PacketType.ParcelInfoRequest: + ParcelInfoRequestPacket pirPack = (ParcelInfoRequestPacket)Pack; + + handlerParcelInfoRequest = OnParcelInfoRequest; + if (handlerParcelInfoRequest != null) + { + handlerParcelInfoRequest(this, pirPack.Data.ParcelID); + } + break; + case PacketType.ParcelAccessListRequest: ParcelAccessListRequestPacket requestPacket = (ParcelAccessListRequestPacket)Pack; @@ -6294,5 +6319,45 @@ namespace OpenSim.Region.ClientStack.LindenUDP } #endregion + + public void SendRegionHandle(LLUUID regionID, ulong handle) { + RegionIDAndHandleReplyPacket reply = (RegionIDAndHandleReplyPacket)PacketPool.Instance.GetPacket(PacketType.RegionIDAndHandleReply); + reply.ReplyBlock.RegionID = regionID; + reply.ReplyBlock.RegionHandle = handle; + OutPacket(reply, ThrottleOutPacketType.Land); + } + + public void SendParcelInfo(RegionInfo info, LandData land, LLUUID parcelID, uint x, uint y) + { + ParcelInfoReplyPacket reply = (ParcelInfoReplyPacket)PacketPool.Instance.GetPacket(PacketType.ParcelInfoReply); + reply.AgentData.AgentID = m_agentId; + reply.Data.ParcelID = parcelID; + reply.Data.OwnerID = land.OwnerID; + reply.Data.Name = Helpers.StringToField(land.Name); + reply.Data.Desc = Helpers.StringToField(land.Description); + reply.Data.ActualArea = land.Area; + reply.Data.BillableArea = land.Area; // TODO: what is this? + + // Bit 0: Mature, bit 7: on sale, other bits: no idea + reply.Data.Flags = (byte)( + ((land.Flags & (uint)Parcel.ParcelFlags.MaturePublish) != 0 ? (1 << 0) : 0) + + ((land.Flags & (uint)Parcel.ParcelFlags.ForSale) != 0 ? (1 << 7) : 0)); + + LLVector3 pos = land.UserLocation; + if (pos.Equals(LLVector3.Zero)) + { + pos = (land.AABBMax + land.AABBMin) * 0.5f; + } + reply.Data.GlobalX = info.RegionLocX * Constants.RegionSize + x; + reply.Data.GlobalY = info.RegionLocY * Constants.RegionSize + y; + reply.Data.GlobalZ = pos.Z; + reply.Data.SimName = Helpers.StringToField(info.RegionName); + reply.Data.SnapshotID = land.SnapshotID; + reply.Data.Dwell = 0; // TODO: not implemented yet + reply.Data.SalePrice = land.SalePrice; + reply.Data.AuctionID = (int)land.AuctionID; + + OutPacket(reply, ThrottleOutPacketType.Land); + } } } diff --git a/OpenSim/Region/Communications/Local/LocalBackEndServices.cs b/OpenSim/Region/Communications/Local/LocalBackEndServices.cs index 5cf62f3..8149bcc 100644 --- a/OpenSim/Region/Communications/Local/LocalBackEndServices.cs +++ b/OpenSim/Region/Communications/Local/LocalBackEndServices.cs @@ -491,5 +491,20 @@ namespace OpenSim.Region.Communications.Local return false; } + + public LandData RequestLandData (ulong regionHandle, uint x, uint y) + { + m_log.DebugFormat("[INTERREGION STANDALONE] requests land data in {0}, at {1}, {2}", + regionHandle, x, y); + + if (m_regionListeners.ContainsKey(regionHandle)) + { + LandData land = m_regionListeners[regionHandle].TriggerGetLandData(x, y); + return land; + } + + m_log.Debug("[INTERREGION STANDALONE] didn't find land data locally."); + return null; + } } } diff --git a/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs b/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs index 65b8763..9a4c166 100644 --- a/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs +++ b/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs @@ -28,6 +28,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.IO; using System.Net; using System.Net.Sockets; using System.Reflection; @@ -92,6 +93,7 @@ namespace OpenSim.Region.Communications.OGS1 httpServer.AddXmlRPCHandler("expect_user", ExpectUser); httpServer.AddXmlRPCHandler("logoff_user", LogOffUser); httpServer.AddXmlRPCHandler("check", PingCheckReply); + httpServer.AddXmlRPCHandler("land_data", LandData); StartRemoting(); } @@ -1624,5 +1626,104 @@ namespace OpenSim.Region.Communications.OGS1 } } } + + public LandData RequestLandData (ulong regionHandle, uint x, uint y) + { + m_log.DebugFormat("[OGS1 GRID SERVICES] requests land data in {0}, at {1}, {2}", + regionHandle, x, y); + LandData landData = m_localBackend.RequestLandData(regionHandle, x, y); + if (landData == null) + { + Hashtable hash = new Hashtable(); + hash["region_handle"] = regionHandle.ToString(); + hash["x"] = x.ToString(); + hash["y"] = y.ToString(); + + IList paramList = new ArrayList(); + paramList.Add(hash); + + // this might be cached, as we probably requested it just a moment ago... + RegionInfo info = RequestNeighbourInfo(regionHandle); + + try + { + XmlRpcRequest request = new XmlRpcRequest("land_data", paramList); + string uri = "http://" + info.ExternalEndPoint.Address + ":" + info.HttpPort + "/"; + XmlRpcResponse response = request.Send(uri, 10000); + if (response.IsFault) + { + m_log.ErrorFormat("[OGS1 GRID SERVICES] remote call returned an error: {0}", response.FaultString); + } + else + { + hash = (Hashtable)response.Value; + try { + landData = new LandData(); + landData.AABBMax = LLVector3.Parse((string)hash["AABBMax"]); + landData.AABBMin = LLVector3.Parse((string)hash["AABBMin"]); + landData.Area = Convert.ToInt32(hash["Area"]); + landData.AuctionID = Convert.ToUInt32(hash["AuctionID"]); + landData.Description = (string)hash["Description"]; + landData.Flags = Convert.ToUInt32(hash["Flags"]); + landData.GlobalID = new LLUUID((string)hash["GlobalID"]); + landData.Name = (string)hash["Name"]; + landData.OwnerID = new LLUUID((string)hash["OwnerID"]); + landData.SalePrice = Convert.ToInt32(hash["SalePrice"]); + landData.SnapshotID = new LLUUID((string)hash["SnapshotID"]); + landData.UserLocation = LLVector3.Parse((string)hash["UserLocation"]); + m_log.DebugFormat("[OGS1 GRID SERVICES] Got land data for parcel {0}", landData.Name); + } + catch (Exception e) + { + m_log.Error("[OGS1 GRID SERVICES] Got exception while parsing land-data:", e); + } + } + } + catch (Exception e) + { + m_log.ErrorFormat("[OGS1 GRID SERVICES] Couldn't contact region {0}: {1}", regionHandle, e); + } + } + return landData; + } + + // Grid Request Processing + /// + /// Someone asked us about parcel-information + /// + /// + /// + public XmlRpcResponse LandData(XmlRpcRequest request) + { + Hashtable requestData = (Hashtable)request.Params[0]; + ulong regionHandle = Convert.ToUInt64(requestData["region_handle"]); + uint x = Convert.ToUInt32(requestData["x"]); + uint y = Convert.ToUInt32(requestData["y"]); + m_log.DebugFormat("[OGS1 GRID SERVICES]: Got XML reqeuest for land data at {0}, {1} in region {2}", x, y, regionHandle); + + LandData landData = m_localBackend.RequestLandData(regionHandle, x, y); + Hashtable hash = new Hashtable(); + if (landData != null) + { + // for now, only push out the data we need for answering a ParcelInfoReqeust + // FIXME: these Replace calls are necessary as LLVector3.Parse can't parse vectors with spaces in them. Can be removed as soon as we switch to a newer version + hash["AABBMax"] = landData.AABBMax.ToString().Replace(" ", ""); + hash["AABBMin"] = landData.AABBMin.ToString().Replace(" ", ""); + hash["Area"] = landData.Area.ToString(); + hash["AuctionID"] = landData.AuctionID.ToString(); + hash["Description"] = landData.Description; + hash["Flags"] = landData.Flags.ToString(); + hash["GlobalID"] = landData.GlobalID.ToString(); + hash["Name"] = landData.Name; + hash["OwnerID"] = landData.OwnerID.ToString(); + hash["SalePrice"] = landData.SalePrice.ToString(); + hash["SnapshotID"] = landData.SnapshotID.ToString(); + hash["UserLocation"] = landData.UserLocation.ToString().Replace(" ", ""); + } + + XmlRpcResponse response = new XmlRpcResponse(); + response.Value = hash; + return response; + } } } diff --git a/OpenSim/Region/Environment/Modules/World/Land/LandManagementModule.cs b/OpenSim/Region/Environment/Modules/World/Land/LandManagementModule.cs index 92eda80..46f108e 100644 --- a/OpenSim/Region/Environment/Modules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/Environment/Modules/World/Land/LandManagementModule.cs @@ -26,19 +26,30 @@ */ using System; +using System.Collections; using System.Collections.Generic; +using System.Reflection; using libsecondlife; +using log4net; using Nini.Config; using OpenSim.Region.Environment.Interfaces; using OpenSim.Region.Environment.Scenes; using OpenSim.Framework; +using OpenSim.Framework.Servers; +using OpenSim.Framework.Communications.Capabilities; using OpenSim.Region.Physics.Manager; using Axiom.Math; +using Caps = OpenSim.Framework.Communications.Capabilities.Caps; namespace OpenSim.Region.Environment.Modules.World.Land { public class LandManagementModule : IRegionModule { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private static readonly string remoteParcelRequestPath = "0009/"; + private LandChannel landChannel; private Scene m_scene; @@ -75,6 +86,7 @@ namespace OpenSim.Region.Environment.Modules.World.Land m_scene.EventManager.OnSetAllowForcefulBan += this.SetAllowedForcefulBans; m_scene.EventManager.OnRequestParcelPrimCountUpdate += this.PerformParcelPrimCountUpdate; m_scene.EventManager.OnParcelPrimCountTainted += this.SetPrimsTainted; + m_scene.EventManager.OnRegisterCaps += this.OnRegisterCaps; lock (m_scene) { @@ -95,7 +107,7 @@ namespace OpenSim.Region.Environment.Modules.World.Land client.OnParcelAccessListUpdateRequest += new ParcelAccessListUpdateRequest(handleParcelAccessUpdateRequest); client.OnParcelAbandonRequest += new ParcelAbandonRequest(handleParcelAbandonRequest); client.OnParcelReclaim += new ParcelReclaim(handleParcelReclaim); - + client.OnParcelInfoRequest += new ParcelInfoRequest(handleParcelInfo); if (m_scene.Entities.ContainsKey(client.AgentId)) { SendLandUpdate((ScenePresence)m_scene.Entities[client.AgentId], true); @@ -1084,6 +1096,112 @@ namespace OpenSim.Region.Environment.Modules.World.Land public void setSimulatorObjectMaxOverride(overrideSimulatorMaxPrimCountDelegate overrideDel) { } + + #region CAPS handler + private void OnRegisterCaps(LLUUID agentID, Caps caps) + { + string capsBase = "/CAPS/" + caps.CapsObjectPath; + caps.RegisterHandler("RemoteParcelRequest", + new RestStreamHandler("POST", capsBase + remoteParcelRequestPath, + delegate(string request, string path, string param, + OSHttpRequest httpRequest, OSHttpResponse httpResponse) + { + return RemoteParcelRequest(request, path, param, agentID, caps); + })); + } + + // we cheat here: As we don't have (and want) a grid-global parcel-store, we can't return the + // "real" parcelID, because we wouldn't be able to map that to the region the parcel belongs to. + // So, we create a "fake" parcelID by using the regionHandle (64 bit), and the local (integer) x + // and y coordinate (each 8 bit), encoded in a LLUUID (128 bit). + // + // Request format: + // + // + // location + // + // 1.23 + // 45..6 + // 78.9 + // + // region_id + // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + // + // + private string RemoteParcelRequest(string request, string path, string param, LLUUID agentID, Caps caps) + { + LLUUID parcelID = LLUUID.Zero; + try + { + Hashtable hash = new Hashtable(); + hash = (Hashtable)LLSD.LLSDDeserialize(Helpers.StringToField(request)); + if(hash.ContainsKey("region_id") && hash.ContainsKey("location")) + { + LLUUID regionID = (LLUUID)hash["region_id"]; + ArrayList list = (ArrayList)hash["location"]; + uint x = (uint)(double)list[0]; + uint y = (uint)(double)list[1]; + if(hash.ContainsKey("region_handle")) + { + // if you do a "About Landmark" on a landmark a second time, the viewer sends the + // region_handle it got earlier via RegionHandleRequest + ulong regionHandle = Helpers.BytesToUInt64((byte[])hash["region_handle"]); + parcelID = Util.BuildFakeParcelID(regionHandle, x, y); + } + else if(regionID == m_scene.RegionInfo.RegionID) + { + // a parcel request for a local parcel => no need to query the grid + parcelID = Util.BuildFakeParcelID(m_scene.RegionInfo.RegionHandle, x, y); + } + else + { + // a parcel request for a parcel in another region. Ask the grid about the region + RegionInfo info = m_scene.CommsManager.GridService.RequestNeighbourInfo(regionID); + if(info != null) parcelID = Util.BuildFakeParcelID(info.RegionHandle, x, y); + } + } + } + catch (LLSD.LLSDParseException e) + { + m_log.ErrorFormat("[LAND] Fetch error: {0}", e.Message); + m_log.ErrorFormat("[LAND] ... in request {0}", request); + } + catch(InvalidCastException) + { + m_log.ErrorFormat("[LAND] Wrong type in request {0}", request); + } + + LLSDRemoteParcelResponse response = new LLSDRemoteParcelResponse(); + response.parcel_id = parcelID; + m_log.DebugFormat("[LAND] got parcelID {0}", parcelID); + + return LLSDHelpers.SerialiseLLSDReply(response); + } + + #endregion + + private void handleParcelInfo(IClientAPI remoteClient, LLUUID parcelID) + { + if(parcelID == LLUUID.Zero) return; + + // assume we've got the parcelID we just computed in RemoteParcelRequest + ulong regionHandle; + uint x, y; + Util.ParseFakeParcelID(parcelID, out regionHandle, out x, out y); + m_log.DebugFormat("[LAND] got parcelinfo request for regionHandle {0}, x/y {1}/{2}", regionHandle, x, y); + + LandData landData; + if(regionHandle == m_scene.RegionInfo.RegionHandle) landData = this.GetLandObject(x, y).landData; + else landData = m_scene.CommsManager.GridService.RequestLandData(regionHandle, x, y); + + if(landData != null) + { + // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark. + m_log.Debug("[LAND] got parcelinfo; sending"); + remoteClient.SendParcelInfo(m_scene.RegionInfo, landData, parcelID, x, y); + } + else m_log.Debug("[LAND] got no parcelinfo; not sending"); + } } } diff --git a/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs b/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs index 5853b87..7b05027 100644 --- a/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs @@ -302,6 +302,10 @@ namespace OpenSim.Region.Environment.Modules.World.NPC public event UpdateVector OnAutoPilotGo; public event TerrainUnacked OnUnackedTerrain; + + public event RegionHandleRequest OnRegionHandleRequest; + public event ParcelInfoRequest OnParcelInfoRequest; + #pragma warning restore 67 #endregion @@ -832,5 +836,13 @@ namespace OpenSim.Region.Environment.Modules.World.NPC public void SendClearFollowCamProperties (LLUUID objectID) { } + + public void SendRegionHandle (LLUUID regoinID, ulong handle) + { + } + + public void SendParcelInfo (RegionInfo info, LandData land, LLUUID parcelID, uint x, uint y) + { + } } } diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index 2e89e4b..9b0b53a 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs @@ -2170,6 +2170,8 @@ namespace OpenSim.Region.Environment.Scenes client.OnScriptReset += ProcessScriptReset; client.OnGetScriptRunning += GetScriptRunning; client.OnSetScriptRunning += SetScriptRunning; + + client.OnRegionHandleRequest += RegionHandleRequest; client.OnUnackedTerrain += TerrainUnAcked; @@ -2502,6 +2504,7 @@ namespace OpenSim.Region.Environment.Scenes m_sceneGridService.OnRemoveKnownRegionFromAvatar += HandleRemoveKnownRegionsFromAvatar; m_sceneGridService.OnLogOffUser += HandleLogOffUserFromGrid; m_sceneGridService.KillObject += SendKillObject; + m_sceneGridService.OnGetLandData += GetLandData; } /// @@ -2518,6 +2521,7 @@ namespace OpenSim.Region.Environment.Scenes m_sceneGridService.OnExpectUser -= NewUserConnection; m_sceneGridService.OnAvatarCrossingIntoRegion -= AgentCrossing; m_sceneGridService.OnCloseAgentConnection -= CloseConnection; + m_sceneGridService.OnGetLandData -= GetLandData; m_sceneGridService.Close(); } @@ -3436,6 +3440,12 @@ namespace OpenSim.Region.Environment.Scenes return LandChannel.GetLandObject(x, y).landData; } + public LandData GetLandData(uint x, uint y) + { + m_log.DebugFormat("[SCENE] returning land for {0},{1}", x, y); + return LandChannel.GetLandObject((int)x, (int)y).landData; + } + public void SetLandMusicURL(float x, float y, string url) { ILandObject land = LandChannel.GetLandObject(x, y); @@ -3833,6 +3843,14 @@ namespace OpenSim.Region.Environment.Scenes // client.SendParcelMediaCommand((uint)(4), ParcelMediaCommandEnum.Play, 0); // }); } + + public void RegionHandleRequest(IClientAPI client, LLUUID regionID) + { + RegionInfo info; + if(regionID == RegionInfo.RegionID) info = RegionInfo; + else info = CommsManager.GridService.RequestNeighbourInfo(regionID); + if(info != null) client.SendRegionHandle(regionID, info.RegionHandle); + } public void TerrainUnAcked(IClientAPI client, int patchX, int patchY) diff --git a/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs index 008d67a..35a7434 100644 --- a/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs +++ b/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs @@ -59,7 +59,8 @@ namespace OpenSim.Region.Environment.Scenes public event ChildAgentUpdate OnChildAgentUpdate; public event RemoveKnownRegionsFromAvatarList OnRemoveKnownRegionFromAvatar; public event LogOffUser OnLogOffUser; - + public event GetLandData OnGetLandData; + private AgentCrossing handlerAvatarCrossingIntoRegion = null; // OnAvatarCrossingIntoRegion; private ExpectUserDelegate handlerExpectUser = null; // OnExpectUser; private ExpectPrimDelegate handlerExpectPrim = null; // OnExpectPrim; @@ -69,6 +70,7 @@ namespace OpenSim.Region.Environment.Scenes private ChildAgentUpdate handlerChildAgentUpdate = null; // OnChildAgentUpdate; private RemoveKnownRegionsFromAvatarList handlerRemoveKnownRegionFromAvatar = null; // OnRemoveKnownRegionFromAvatar; private LogOffUser handlerLogOffUser = null; + private GetLandData handlerGetLandData = null; // OnGetLandData public KillObjectDelegate KillObject; public string _debugRegionName = String.Empty; @@ -108,6 +110,7 @@ namespace OpenSim.Region.Environment.Scenes regionCommsHost.OnRegionUp += newRegionUp; regionCommsHost.OnChildAgentUpdate += ChildAgentUpdate; regionCommsHost.OnLogOffUser += GridLogOffUser; + regionCommsHost.OnGetLandData += FetchLandData; } else { @@ -131,6 +134,7 @@ namespace OpenSim.Region.Environment.Scenes regionCommsHost.OnExpectPrim -= IncomingPrimCrossing; regionCommsHost.OnAvatarCrossingIntoRegion -= AgentCrossing; regionCommsHost.OnCloseAgentConnection -= CloseConnection; + regionCommsHost.OnGetLandData -= FetchLandData; m_commsProvider.GridService.DeregisterRegion(m_regionInfo); regionCommsHost = null; } @@ -227,6 +231,16 @@ namespace OpenSim.Region.Environment.Scenes 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 diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index a7d2ef3..61ea966 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs @@ -204,6 +204,9 @@ namespace OpenSim.Region.Examples.SimpleModule public event TerrainUnacked OnUnackedTerrain; + public event RegionHandleRequest OnRegionHandleRequest; + public event ParcelInfoRequest OnParcelInfoRequest; + #pragma warning restore 67 private LLUUID myID = LLUUID.Random(); @@ -832,5 +835,13 @@ namespace OpenSim.Region.Examples.SimpleModule public void SendClearFollowCamProperties (LLUUID objectID) { } + + public void SendRegionHandle (LLUUID regoinID, ulong handle) + { + } + + public void SendParcelInfo (RegionInfo info, LandData land, LLUUID parcelID, uint x, uint y) + { + } } } -- cgit v1.1