From 5c870fce548eeca24ae0491a2261ce4fb330a57b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 12 Apr 2011 19:45:33 -0700 Subject: [PATCH 01/16] Bug fix in object serialization -- sculpt data was wrong. --- .../Framework/Scenes/Serialization/SceneObjectSerializer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 57ae4fd24f..b412e25579 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -1318,7 +1318,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteStartElement("SculptData"); byte[] sd; if (shp.SculptData != null) - sd = shp.ExtraParams; + sd = shp.SculptData; else sd = Utils.EmptyBytes; writer.WriteBase64(sd, 0, sd.Length); From 16c911dcbb883e60d7a49176db8b2cea650cc929 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 12 Apr 2011 19:46:27 -0700 Subject: [PATCH 02/16] Implemented terrain save-tile command. Does the opposite of load-tile. For now, only saves to .png. --- .../FileLoaders/GenericSystemDrawing.cs | 46 ++++++++++++++++ .../World/Terrain/FileLoaders/JPEG.cs | 8 +++ .../World/Terrain/FileLoaders/LLRAW.cs | 8 +++ .../World/Terrain/FileLoaders/RAW32.cs | 7 +++ .../World/Terrain/FileLoaders/Terragen.cs | 8 +++ .../World/Terrain/ITerrainLoader.cs | 1 + .../World/Terrain/TerrainModule.cs | 54 +++++++++++++++++++ 7 files changed, 132 insertions(+) diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs index d6fa0937e5..21a9999ba0 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs @@ -124,6 +124,52 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders colours.Save(stream, ImageFormat.Png); } + public virtual void SaveFile(ITerrainChannel m_channel, string filename, + int offsetX, int offsetY, + int fileWidth, int fileHeight, + int regionSizeX, int regionSizeY) + + { + // We need to do this because: + // "Saving the image to the same file it was constructed from is not allowed and throws an exception." + string tempName = offsetX + "_ " + offsetY + "_" + filename; + + Bitmap entireBitmap = null; + Bitmap thisBitmap = null; + if (File.Exists(filename)) + { + File.Copy(filename, tempName); + entireBitmap = new Bitmap(tempName); + if (entireBitmap.Width != fileWidth * regionSizeX || entireBitmap.Height != fileHeight * regionSizeY) + { + // old file, let's overwrite it + entireBitmap = new Bitmap(fileWidth * regionSizeX, fileHeight * regionSizeY); + } + } + else + { + entireBitmap = new Bitmap(fileWidth * regionSizeX, fileHeight * regionSizeY); + } + + thisBitmap = CreateGrayscaleBitmapFromMap(m_channel); + Console.WriteLine("offsetX=" + offsetX + " offsetY=" + offsetY); + for (int x = 0; x < regionSizeX; x++) + for (int y = 0; y < regionSizeY; y++) + entireBitmap.SetPixel(x + offsetX * regionSizeX, y + (fileHeight - 1 - offsetY) * regionSizeY, thisBitmap.GetPixel(x, y)); + + Save(entireBitmap, filename); + thisBitmap.Dispose(); + entireBitmap.Dispose(); + + if (File.Exists(tempName)) + File.Delete(tempName); + } + + protected virtual void Save(Bitmap bmp, string filename) + { + bmp.Save(filename, ImageFormat.Png); + } + #endregion public override string ToString() diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs index 8667607d0b..1a0d8ecf60 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs @@ -76,6 +76,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders colours.Save(stream, ImageFormat.Jpeg); } + public virtual void SaveFile(ITerrainChannel m_channel, string filename, + int offsetX, int offsetY, + int fileWidth, int fileHeight, + int regionSizeX, int regionSizeY) + { + throw new System.Exception("Not Implemented"); + } + #endregion public override string ToString() diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs index a70ef13ed0..fad7641e42 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/LLRAW.cs @@ -240,6 +240,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders get { return ".raw"; } } + public virtual void SaveFile(ITerrainChannel m_channel, string filename, + int offsetX, int offsetY, + int fileWidth, int fileHeight, + int regionSizeX, int regionSizeY) + { + throw new System.Exception("Not Implemented"); + } + #endregion public override string ToString() diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs index 3c76665d5e..ba073cae5a 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/RAW32.cs @@ -160,6 +160,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders bs.Close(); } + public virtual void SaveFile(ITerrainChannel m_channel, string filename, + int offsetX, int offsetY, + int fileWidth, int fileHeight, + int regionSizeX, int regionSizeY) + { + throw new System.Exception("Not Implemented"); + } #endregion public override string ToString() diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs index 2919897153..2f37d9d7e9 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs @@ -308,6 +308,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders get { return ".ter"; } } + public virtual void SaveFile(ITerrainChannel m_channel, string filename, + int offsetX, int offsetY, + int fileWidth, int fileHeight, + int regionSizeX, int regionSizeY) + { + throw new System.Exception("Not Implemented"); + } + #endregion public override string ToString() diff --git a/OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs index 7403281621..7237f90a38 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainLoader.cs @@ -38,5 +38,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain ITerrainChannel LoadStream(Stream stream); void SaveFile(string filename, ITerrainChannel map); void SaveStream(Stream stream, ITerrainChannel map); + void SaveFile(ITerrainChannel map, string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int regionSizeX, int regionSizeY); } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 8a79d78b22..9c7b2fab9c 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -540,6 +540,39 @@ namespace OpenSim.Region.CoreModules.World.Terrain } } + /// + /// Saves the terrain to a larger terrain file. + /// + /// The terrain file to save + /// The width of the file in units + /// The height of the file in units + /// Where to begin our slice + /// Where to begin our slice + public void SaveToFile(string filename, int fileWidth, int fileHeight, int fileStartX, int fileStartY) + { + int offsetX = (int)m_scene.RegionInfo.RegionLocX - fileStartX; + int offsetY = (int)m_scene.RegionInfo.RegionLocY - fileStartY; + + if (offsetX >= 0 && offsetX < fileWidth && offsetY >= 0 && offsetY < fileHeight) + { + // this region is included in the tile request + foreach (KeyValuePair loader in m_loaders) + { + if (filename.EndsWith(loader.Key)) + { + lock (m_scene) + { + loader.Value.SaveFile(m_channel, filename, offsetX, offsetY, + fileWidth, fileHeight, + (int)Constants.RegionSize, + (int)Constants.RegionSize); + } + return; + } + } + } + } + /// /// Performs updates to the region periodically, synchronising physics and other heightmap aware sections /// @@ -860,6 +893,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain SaveToFile((string) args[0]); } + private void InterfaceSaveTileFile(Object[] args) + { + SaveToFile((string)args[0], + (int)args[1], + (int)args[2], + (int)args[3], + (int)args[4]); + } + private void InterfaceBakeTerrain(Object[] args) { UpdateRevertMap(); @@ -1115,6 +1157,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain loadFromTileCommand.AddArgument("minimum Y tile", "The Y region coordinate of the first section on the file", "Integer"); + Command saveToTileCommand = + new Command("save-tile", CommandIntentions.COMMAND_HAZARDOUS, InterfaceSaveTileFile, "Saves the current heightmap to the larger file."); + saveToTileCommand.AddArgument("filename", + "The file you wish to save to, the file extension determines the loader to be used. Supported extensions include: " + + supportedFileExtensions, "String"); + saveToTileCommand.AddArgument("file width", "The width of the file in tiles", "Integer"); + saveToTileCommand.AddArgument("file height", "The height of the file in tiles", "Integer"); + saveToTileCommand.AddArgument("minimum X tile", "The X region coordinate of the first section on the file", + "Integer"); + saveToTileCommand.AddArgument("minimum Y tile", "The Y region coordinate of the first section on the file", + "Integer"); // Terrain adjustments Command fillRegionCommand = new Command("fill", CommandIntentions.COMMAND_HAZARDOUS, InterfaceFillTerrain, "Fills the current heightmap with a specified value."); @@ -1166,6 +1219,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_commander.RegisterCommand("load", loadFromFileCommand); m_commander.RegisterCommand("load-tile", loadFromTileCommand); m_commander.RegisterCommand("save", saveToFileCommand); + m_commander.RegisterCommand("save-tile", saveToTileCommand); m_commander.RegisterCommand("fill", fillRegionCommand); m_commander.RegisterCommand("elevate", elevateCommand); m_commander.RegisterCommand("lower", lowerCommand); From 7592a033df4f81ba985e1d6f57ad0ef488dc5745 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 12 Apr 2011 20:24:28 -0700 Subject: [PATCH 03/16] Moved 3 request handlers from OpenSim.Framework.Servers.HttpServer up to OpenSim.Framework -- just pasted them in WebUtil. This is so that code that uses the Service connectors don't need to include the HttpServer dll -- that was odd. --- .../AsynchronousRestObjectRequester.cs | 192 ---------- .../SynchronousRestFormsRequester.cs | 131 ------- .../SynchronousRestObjectRequester.cs | 122 ------- OpenSim/Framework/WebUtil.cs | 335 ++++++++++++++++++ .../Avatar/Friends/FriendsModule.cs | 2 +- .../InstantMessage/OfflineMessageModule.cs | 1 - .../Asset/AssetServiceInConnectorModule.cs | 1 - .../AuthenticationServiceInConnectorModule.cs | 1 - .../Grid/GridInfoServiceInConnectorModule.cs | 1 - .../HypergridServiceInConnectorModule.cs | 1 - .../InventoryServiceInConnectorModule.cs | 3 +- .../Land/LandServiceInConnectorModule.cs | 1 - .../Login/LLLoginServiceInConnectorModule.cs | 1 - .../NeighbourServiceInConnectorModule.cs | 1 - .../SimulationServiceInConnectorModule.cs | 1 - .../Connectors/Asset/AssetServiceConnector.cs | 1 - .../AuthenticationServiceConnector.cs | 1 - .../AuthorizationServiceConnector.cs | 1 - .../Avatar/AvatarServiceConnector.cs | 1 - .../Freeswitch/RemoteFreeswitchConnector.cs | 1 - .../Friends/FriendsServiceConnector.cs | 1 - .../Connectors/Friends/FriendsSimConnector.cs | 2 +- .../Connectors/Grid/GridServiceConnector.cs | 1 - .../GridUser/GridUserServiceConnector.cs | 1 - .../Inventory/XInventoryConnector.cs | 1 - .../Connectors/Land/LandServiceConnector.cs | 1 - .../Neighbour/NeighbourServiceConnector.cs | 1 - .../Presence/PresenceServiceConnector.cs | 1 - .../UserAccountServiceConnector.cs | 1 - prebuild.xml | 1 - 30 files changed, 338 insertions(+), 472 deletions(-) delete mode 100644 OpenSim/Framework/Servers/HttpServer/AsynchronousRestObjectRequester.cs delete mode 100644 OpenSim/Framework/Servers/HttpServer/SynchronousRestFormsRequester.cs delete mode 100644 OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectRequester.cs diff --git a/OpenSim/Framework/Servers/HttpServer/AsynchronousRestObjectRequester.cs b/OpenSim/Framework/Servers/HttpServer/AsynchronousRestObjectRequester.cs deleted file mode 100644 index 03c12dd560..0000000000 --- a/OpenSim/Framework/Servers/HttpServer/AsynchronousRestObjectRequester.cs +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using System.Net; -using System.Reflection; -using System.Text; -using System.Xml; -using System.Xml.Serialization; -using log4net; - -namespace OpenSim.Framework.Servers.HttpServer -{ - public class AsynchronousRestObjectRequester - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - /// - /// Perform an asynchronous REST request. - /// - /// GET or POST - /// - /// - /// - /// - /// - /// Thrown if we encounter a - /// network issue while posting the request. You'll want to make - /// sure you deal with this as they're not uncommon - // - public static void MakeRequest(string verb, - string requestUrl, TRequest obj, Action action) - { -// m_log.DebugFormat("[ASYNC REQUEST]: Starting {0} {1}", verb, requestUrl); - - Type type = typeof (TRequest); - - WebRequest request = WebRequest.Create(requestUrl); - WebResponse response = null; - TResponse deserial = default(TResponse); - XmlSerializer deserializer = new XmlSerializer(typeof (TResponse)); - - request.Method = verb; - - if (verb == "POST") - { - request.ContentType = "text/xml"; - - MemoryStream buffer = new MemoryStream(); - - XmlWriterSettings settings = new XmlWriterSettings(); - settings.Encoding = Encoding.UTF8; - - using (XmlWriter writer = XmlWriter.Create(buffer, settings)) - { - XmlSerializer serializer = new XmlSerializer(type); - serializer.Serialize(writer, obj); - writer.Flush(); - } - - int length = (int) buffer.Length; - request.ContentLength = length; - - request.BeginGetRequestStream(delegate(IAsyncResult res) - { - Stream requestStream = request.EndGetRequestStream(res); - - requestStream.Write(buffer.ToArray(), 0, length); - requestStream.Close(); - - request.BeginGetResponse(delegate(IAsyncResult ar) - { - response = request.EndGetResponse(ar); - Stream respStream = null; - try - { - respStream = response.GetResponseStream(); - deserial = (TResponse)deserializer.Deserialize( - respStream); - } - catch (System.InvalidOperationException) - { - } - finally - { - // Let's not close this - //buffer.Close(); - respStream.Close(); - response.Close(); - } - - action(deserial); - - }, null); - }, null); - - - return; - } - - request.BeginGetResponse(delegate(IAsyncResult res2) - { - try - { - // If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't - // documented in MSDN - response = request.EndGetResponse(res2); - - Stream respStream = null; - try - { - respStream = response.GetResponseStream(); - deserial = (TResponse)deserializer.Deserialize(respStream); - } - catch (System.InvalidOperationException) - { - } - finally - { - respStream.Close(); - response.Close(); - } - } - catch (WebException e) - { - if (e.Status == WebExceptionStatus.ProtocolError) - { - if (e.Response is HttpWebResponse) - { - HttpWebResponse httpResponse = (HttpWebResponse)e.Response; - - if (httpResponse.StatusCode != HttpStatusCode.NotFound) - { - // We don't appear to be handling any other status codes, so log these feailures to that - // people don't spend unnecessary hours hunting phantom bugs. - m_log.DebugFormat( - "[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}", - verb, requestUrl, httpResponse.StatusCode); - } - } - } - else - { - m_log.ErrorFormat("[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}", verb, requestUrl, e.Status, e.Message); - } - } - catch (Exception e) - { - m_log.ErrorFormat("[ASYNC REQUEST]: Request {0} {1} failed with exception {2}", verb, requestUrl, e); - } - - // m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString()); - - try - { - action(deserial); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}", verb, requestUrl, e); - } - - }, null); - } - } -} diff --git a/OpenSim/Framework/Servers/HttpServer/SynchronousRestFormsRequester.cs b/OpenSim/Framework/Servers/HttpServer/SynchronousRestFormsRequester.cs deleted file mode 100644 index 41ece86047..0000000000 --- a/OpenSim/Framework/Servers/HttpServer/SynchronousRestFormsRequester.cs +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using System.Net; -using System.Reflection; -using System.Text; -using System.Xml; -using System.Xml.Serialization; - -using log4net; - -namespace OpenSim.Framework.Servers.HttpServer -{ - public class SynchronousRestFormsRequester - { - private static readonly ILog m_log = - LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); - - /// - /// Perform a synchronous REST request. - /// - /// - /// - /// - /// - /// - /// Thrown if we encounter a network issue while posting - /// the request. You'll want to make sure you deal with this as they're not uncommon - public static string MakeRequest(string verb, string requestUrl, string obj) - { - WebRequest request = WebRequest.Create(requestUrl); - request.Method = verb; - string respstring = String.Empty; - - using (MemoryStream buffer = new MemoryStream()) - { - if ((verb == "POST") || (verb == "PUT")) - { - request.ContentType = "text/www-form-urlencoded"; - - int length = 0; - using (StreamWriter writer = new StreamWriter(buffer)) - { - writer.Write(obj); - writer.Flush(); - } - - length = (int)obj.Length; - request.ContentLength = length; - - Stream requestStream = null; - try - { - requestStream = request.GetRequestStream(); - requestStream.Write(buffer.ToArray(), 0, length); - } - catch (Exception e) - { - m_log.DebugFormat("[FORMS]: exception occured on sending request to {0}: " + e.ToString(), requestUrl); - } - finally - { - if (requestStream != null) - requestStream.Close(); - } - } - - try - { - using (WebResponse resp = request.GetResponse()) - { - if (resp.ContentLength != 0) - { - Stream respStream = null; - try - { - respStream = resp.GetResponseStream(); - using (StreamReader reader = new StreamReader(respStream)) - { - respstring = reader.ReadToEnd(); - } - } - catch (Exception e) - { - m_log.DebugFormat("[FORMS]: exception occured on receiving reply " + e.ToString()); - } - finally - { - if (respStream != null) - respStream.Close(); - } - } - } - } - catch (System.InvalidOperationException) - { - // This is what happens when there is invalid XML - m_log.DebugFormat("[FORMS]: InvalidOperationException on receiving request"); - } - } - return respstring; - } - } -} diff --git a/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectRequester.cs b/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectRequester.cs deleted file mode 100644 index eab463cbd8..0000000000 --- a/OpenSim/Framework/Servers/HttpServer/SynchronousRestObjectRequester.cs +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.IO; -using System.Net; -using System.Text; -using System.Xml; -using System.Xml.Serialization; - -namespace OpenSim.Framework.Servers.HttpServer -{ - public class SynchronousRestObjectPoster - { - [Obsolete] - public static TResponse BeginPostObject(string verb, string requestUrl, TRequest obj) - { - return SynchronousRestObjectRequester.MakeRequest(verb, requestUrl, obj); - } - } - - public class SynchronousRestObjectRequester - { - /// - /// Perform a synchronous REST request. - /// - /// - /// - /// - /// - /// - /// Thrown if we encounter a network issue while posting - /// the request. You'll want to make sure you deal with this as they're not uncommon - public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj) - { - Type type = typeof (TRequest); - TResponse deserial = default(TResponse); - - WebRequest request = WebRequest.Create(requestUrl); - request.Method = verb; - - if ((verb == "POST") || (verb == "PUT")) - { - request.ContentType = "text/xml"; - - MemoryStream buffer = new MemoryStream(); - - XmlWriterSettings settings = new XmlWriterSettings(); - settings.Encoding = Encoding.UTF8; - - using (XmlWriter writer = XmlWriter.Create(buffer, settings)) - { - XmlSerializer serializer = new XmlSerializer(type); - serializer.Serialize(writer, obj); - writer.Flush(); - } - - int length = (int) buffer.Length; - request.ContentLength = length; - - Stream requestStream = null; - try - { - requestStream = request.GetRequestStream(); - requestStream.Write(buffer.ToArray(), 0, length); - } - catch (Exception) - { - return deserial; - } - finally - { - if (requestStream != null) - requestStream.Close(); - } - } - - try - { - using (WebResponse resp = request.GetResponse()) - { - if (resp.ContentLength > 0) - { - Stream respStream = resp.GetResponseStream(); - XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); - deserial = (TResponse)deserializer.Deserialize(respStream); - respStream.Close(); - } - } - } - catch (System.InvalidOperationException) - { - // This is what happens when there is invalid XML - } - return deserial; - } - } -} diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index 1feeeb31e5..64cd014f5c 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -36,6 +36,9 @@ using System.Net.Security; using System.Reflection; using System.Text; using System.Web; +using System.Xml; +using System.Xml.Serialization; + using log4net; using OpenSim.Framework.Servers.HttpServer; using OpenMetaverse.StructuredData; @@ -625,4 +628,336 @@ namespace OpenSim.Framework } + + public static class AsynchronousRestObjectRequester + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Perform an asynchronous REST request. + /// + /// GET or POST + /// + /// + /// + /// + /// + /// Thrown if we encounter a + /// network issue while posting the request. You'll want to make + /// sure you deal with this as they're not uncommon + // + public static void MakeRequest(string verb, + string requestUrl, TRequest obj, Action action) + { + // m_log.DebugFormat("[ASYNC REQUEST]: Starting {0} {1}", verb, requestUrl); + + Type type = typeof(TRequest); + + WebRequest request = WebRequest.Create(requestUrl); + WebResponse response = null; + TResponse deserial = default(TResponse); + XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); + + request.Method = verb; + + if (verb == "POST") + { + request.ContentType = "text/xml"; + + MemoryStream buffer = new MemoryStream(); + + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; + + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, obj); + writer.Flush(); + } + + int length = (int)buffer.Length; + request.ContentLength = length; + + request.BeginGetRequestStream(delegate(IAsyncResult res) + { + Stream requestStream = request.EndGetRequestStream(res); + + requestStream.Write(buffer.ToArray(), 0, length); + requestStream.Close(); + + request.BeginGetResponse(delegate(IAsyncResult ar) + { + response = request.EndGetResponse(ar); + Stream respStream = null; + try + { + respStream = response.GetResponseStream(); + deserial = (TResponse)deserializer.Deserialize( + respStream); + } + catch (System.InvalidOperationException) + { + } + finally + { + // Let's not close this + //buffer.Close(); + respStream.Close(); + response.Close(); + } + + action(deserial); + + }, null); + }, null); + + + return; + } + + request.BeginGetResponse(delegate(IAsyncResult res2) + { + try + { + // If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't + // documented in MSDN + response = request.EndGetResponse(res2); + + Stream respStream = null; + try + { + respStream = response.GetResponseStream(); + deserial = (TResponse)deserializer.Deserialize(respStream); + } + catch (System.InvalidOperationException) + { + } + finally + { + respStream.Close(); + response.Close(); + } + } + catch (WebException e) + { + if (e.Status == WebExceptionStatus.ProtocolError) + { + if (e.Response is HttpWebResponse) + { + HttpWebResponse httpResponse = (HttpWebResponse)e.Response; + + if (httpResponse.StatusCode != HttpStatusCode.NotFound) + { + // We don't appear to be handling any other status codes, so log these feailures to that + // people don't spend unnecessary hours hunting phantom bugs. + m_log.DebugFormat( + "[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}", + verb, requestUrl, httpResponse.StatusCode); + } + } + } + else + { + m_log.ErrorFormat("[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}", verb, requestUrl, e.Status, e.Message); + } + } + catch (Exception e) + { + m_log.ErrorFormat("[ASYNC REQUEST]: Request {0} {1} failed with exception {2}", verb, requestUrl, e); + } + + // m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString()); + + try + { + action(deserial); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}", verb, requestUrl, e); + } + + }, null); + } + } + + public static class SynchronousRestFormsRequester + { + private static readonly ILog m_log = + LogManager.GetLogger( + MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Perform a synchronous REST request. + /// + /// + /// + /// + /// + /// + /// Thrown if we encounter a network issue while posting + /// the request. You'll want to make sure you deal with this as they're not uncommon + public static string MakeRequest(string verb, string requestUrl, string obj) + { + WebRequest request = WebRequest.Create(requestUrl); + request.Method = verb; + string respstring = String.Empty; + + using (MemoryStream buffer = new MemoryStream()) + { + if ((verb == "POST") || (verb == "PUT")) + { + request.ContentType = "text/www-form-urlencoded"; + + int length = 0; + using (StreamWriter writer = new StreamWriter(buffer)) + { + writer.Write(obj); + writer.Flush(); + } + + length = (int)obj.Length; + request.ContentLength = length; + + Stream requestStream = null; + try + { + requestStream = request.GetRequestStream(); + requestStream.Write(buffer.ToArray(), 0, length); + } + catch (Exception e) + { + m_log.DebugFormat("[FORMS]: exception occured on sending request to {0}: " + e.ToString(), requestUrl); + } + finally + { + if (requestStream != null) + requestStream.Close(); + } + } + + try + { + using (WebResponse resp = request.GetResponse()) + { + if (resp.ContentLength != 0) + { + Stream respStream = null; + try + { + respStream = resp.GetResponseStream(); + using (StreamReader reader = new StreamReader(respStream)) + { + respstring = reader.ReadToEnd(); + } + } + catch (Exception e) + { + m_log.DebugFormat("[FORMS]: exception occured on receiving reply " + e.ToString()); + } + finally + { + if (respStream != null) + respStream.Close(); + } + } + } + } + catch (System.InvalidOperationException) + { + // This is what happens when there is invalid XML + m_log.DebugFormat("[FORMS]: InvalidOperationException on receiving request"); + } + } + return respstring; + } + } + + public class SynchronousRestObjectPoster + { + [Obsolete] + public static TResponse BeginPostObject(string verb, string requestUrl, TRequest obj) + { + return SynchronousRestObjectRequester.MakeRequest(verb, requestUrl, obj); + } + } + + public class SynchronousRestObjectRequester + { + /// + /// Perform a synchronous REST request. + /// + /// + /// + /// + /// + /// + /// Thrown if we encounter a network issue while posting + /// the request. You'll want to make sure you deal with this as they're not uncommon + public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj) + { + Type type = typeof(TRequest); + TResponse deserial = default(TResponse); + + WebRequest request = WebRequest.Create(requestUrl); + request.Method = verb; + + if ((verb == "POST") || (verb == "PUT")) + { + request.ContentType = "text/xml"; + + MemoryStream buffer = new MemoryStream(); + + XmlWriterSettings settings = new XmlWriterSettings(); + settings.Encoding = Encoding.UTF8; + + using (XmlWriter writer = XmlWriter.Create(buffer, settings)) + { + XmlSerializer serializer = new XmlSerializer(type); + serializer.Serialize(writer, obj); + writer.Flush(); + } + + int length = (int)buffer.Length; + request.ContentLength = length; + + Stream requestStream = null; + try + { + requestStream = request.GetRequestStream(); + requestStream.Write(buffer.ToArray(), 0, length); + } + catch (Exception) + { + return deserial; + } + finally + { + if (requestStream != null) + requestStream.Close(); + } + } + + try + { + using (WebResponse resp = request.GetResponse()) + { + if (resp.ContentLength > 0) + { + Stream respStream = resp.GetResponseStream(); + XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); + deserial = (TResponse)deserializer.Deserialize(respStream); + respStream.Close(); + } + } + } + catch (System.InvalidOperationException) + { + // This is what happens when there is invalid XML + } + return deserial; + } + } } diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index 4d74b2a0a0..5baf0785f4 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -34,13 +34,13 @@ using Nini.Config; using Nwc.XmlRpc; using OpenMetaverse; using OpenSim.Framework; +using OpenSim.Framework.Servers.HttpServer; using OpenSim.Framework.Communications; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; using OpenSim.Services.Connectors.Friends; using OpenSim.Server.Base; -using OpenSim.Framework.Servers.HttpServer; using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; using GridRegion = OpenSim.Services.Interfaces.GridRegion; diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs index fdfcd104c0..919ea338f4 100644 --- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs @@ -33,7 +33,6 @@ using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Communications; using OpenSim.Framework.Servers; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Framework.Client; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs index e25700d1f7..422f394d7a 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Asset/AssetServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Authentication/AuthenticationServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Authentication/AuthenticationServiceInConnectorModule.cs index 02acddc37e..2b5beba374 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Authentication/AuthenticationServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Authentication/AuthenticationServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Grid/GridInfoServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Grid/GridInfoServiceInConnectorModule.cs index 6d975afb14..f29c074206 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Grid/GridInfoServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Grid/GridInfoServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs index 2f96bcb1ab..d2343c994e 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Inventory/InventoryServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Inventory/InventoryServiceInConnectorModule.cs index 209cf0d3c2..53a8ace14c 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Inventory/InventoryServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Inventory/InventoryServiceInConnectorModule.cs @@ -31,9 +31,8 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; using OpenSim.Server.Base; using OpenSim.Server.Handlers.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs index fcc69e949f..fc642032b5 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Login/LLLoginServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Login/LLLoginServiceInConnectorModule.cs index 2a9366c44e..f759470b28 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Login/LLLoginServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Login/LLLoginServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs index 35518d59f8..5c3263260e 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Simulation/SimulationServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Simulation/SimulationServiceInConnectorModule.cs index 5ee1c97e5f..86b4926ac5 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Simulation/SimulationServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Simulation/SimulationServiceInConnectorModule.cs @@ -31,7 +31,6 @@ using System.Collections.Generic; using log4net; using Nini.Config; using OpenSim.Framework; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; using OpenSim.Server.Base; diff --git a/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs index 65b3537041..f1da4fa777 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs @@ -34,7 +34,6 @@ using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using OpenMetaverse; diff --git a/OpenSim/Services/Connectors/Authentication/AuthenticationServiceConnector.cs b/OpenSim/Services/Connectors/Authentication/AuthenticationServiceConnector.cs index 6f77a2d8b3..c04e7a4971 100644 --- a/OpenSim/Services/Connectors/Authentication/AuthenticationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Authentication/AuthenticationServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using OpenSim.Server.Base; using OpenMetaverse; diff --git a/OpenSim/Services/Connectors/Authorization/AuthorizationServiceConnector.cs b/OpenSim/Services/Connectors/Authorization/AuthorizationServiceConnector.cs index 4eb4bd2470..35b7109496 100644 --- a/OpenSim/Services/Connectors/Authorization/AuthorizationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Authorization/AuthorizationServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using OpenMetaverse; diff --git a/OpenSim/Services/Connectors/Avatar/AvatarServiceConnector.cs b/OpenSim/Services/Connectors/Avatar/AvatarServiceConnector.cs index 1cd6bf8e1a..1a93ae71c6 100644 --- a/OpenSim/Services/Connectors/Avatar/AvatarServiceConnector.cs +++ b/OpenSim/Services/Connectors/Avatar/AvatarServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using IAvatarService = OpenSim.Services.Interfaces.IAvatarService; diff --git a/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs b/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs index c9bba0b730..d68829996d 100644 --- a/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs +++ b/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using OpenSim.Server.Base; using OpenMetaverse; diff --git a/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs b/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs index 36b5083860..861c4759a3 100644 --- a/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs +++ b/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; using OpenSim.Server.Base; diff --git a/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs b/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs index 0a7b277e4c..4ffa68c381 100644 --- a/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs +++ b/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs @@ -32,7 +32,7 @@ using System.Reflection; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using OpenSim.Server.Base; -using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Framework; using OpenMetaverse; using log4net; diff --git a/OpenSim/Services/Connectors/Grid/GridServiceConnector.cs b/OpenSim/Services/Connectors/Grid/GridServiceConnector.cs index 5092d741e6..e57f28b44e 100644 --- a/OpenSim/Services/Connectors/Grid/GridServiceConnector.cs +++ b/OpenSim/Services/Connectors/Grid/GridServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using OpenSim.Server.Base; diff --git a/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs b/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs index b3ea865996..738cc06949 100644 --- a/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs +++ b/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using OpenSim.Server.Base; diff --git a/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs b/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs index b3bfcc27df..cd9f2bfcff 100644 --- a/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs +++ b/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs @@ -34,7 +34,6 @@ using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using OpenSim.Server.Base; using OpenMetaverse; diff --git a/OpenSim/Services/Connectors/Land/LandServiceConnector.cs b/OpenSim/Services/Connectors/Land/LandServiceConnector.cs index 252f7a1d16..30a73a471c 100644 --- a/OpenSim/Services/Connectors/Land/LandServiceConnector.cs +++ b/OpenSim/Services/Connectors/Land/LandServiceConnector.cs @@ -34,7 +34,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using OpenMetaverse; using Nwc.XmlRpc; diff --git a/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs b/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs index 9e444c49bc..2cae02d42a 100644 --- a/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs +++ b/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs @@ -36,7 +36,6 @@ using System.Text; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using OpenMetaverse; using OpenMetaverse.StructuredData; diff --git a/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs b/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs index 41ebeaf05e..7238afc613 100644 --- a/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs +++ b/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Services.Interfaces; using GridRegion = OpenSim.Services.Interfaces.GridRegion; using OpenSim.Server.Base; diff --git a/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs b/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs index 2a5df83193..f6835b9f2f 100644 --- a/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs +++ b/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs @@ -33,7 +33,6 @@ using System.Reflection; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Communications; -using OpenSim.Framework.Servers.HttpServer; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenMetaverse; diff --git a/prebuild.xml b/prebuild.xml index 870ebf300c..81716641c6 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -931,7 +931,6 @@ - From 90b810c27ef4fe3da1796842940af13db61fb91d Mon Sep 17 00:00:00 2001 From: dahlia Date: Tue, 12 Apr 2011 22:47:30 -0700 Subject: [PATCH 04/16] force mesh proxy for simple box prims with path cut --- OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs | 3 +++ OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs index 85e34c1e3d..6df213d851 100644 --- a/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs +++ b/OpenSim/Region/Physics/BulletDotNETPlugin/BulletDotNETScene.cs @@ -648,6 +648,9 @@ namespace OpenSim.Region.Physics.BulletDotNETPlugin if (pbs.ProfileHollow != 0) iPropertiesNotSupportedDefault++; + if ((pbs.PathBegin != 0) || pbs.PathEnd != 0) + iPropertiesNotSupportedDefault++; + if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0)) iPropertiesNotSupportedDefault++; diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index eb97f41e3c..a0101af2bb 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs @@ -2528,6 +2528,9 @@ namespace OpenSim.Region.Physics.OdePlugin if (pbs.ProfileHollow != 0) iPropertiesNotSupportedDefault++; + if ((pbs.PathBegin != 0) || pbs.PathEnd != 0) + iPropertiesNotSupportedDefault++; + if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0)) iPropertiesNotSupportedDefault++; From 6613daa82a3bf0d45b0be1b2941646042f9008f4 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 13 Apr 2011 17:46:36 +0100 Subject: [PATCH 05/16] Add a regression test for rezzing a single object into a scene from user inventory --- .../ClientStack/LindenUDP/LLClientView.cs | 9 +- .../Tests/InventoryAccessModuleTests.cs | 133 ++++++++++++++++++ .../World/Estate/EstateManagementModule.cs | 4 + prebuild.xml | 1 + 4 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 8de31d7069..76d7f7964b 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -4290,6 +4290,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SendEstateCovenantInformation(UUID covenant) { +// m_log.DebugFormat("[LLCLIENTVIEW]: Sending estate covenant asset id of {0} to {1}", covenant, Name); + EstateCovenantReplyPacket einfopack = new EstateCovenantReplyPacket(); EstateCovenantReplyPacket.DataBlock edata = new EstateCovenantReplyPacket.DataBlock(); edata.CovenantID = covenant; @@ -4300,8 +4302,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(einfopack, ThrottleOutPacketType.Task); } - public void SendDetailedEstateData(UUID invoice, string estateName, uint estateID, uint parentEstate, uint estateFlags, uint sunPosition, UUID covenant, string abuseEmail, UUID estateOwner) + public void SendDetailedEstateData( + UUID invoice, string estateName, uint estateID, uint parentEstate, uint estateFlags, uint sunPosition, + UUID covenant, string abuseEmail, UUID estateOwner) { +// m_log.DebugFormat( +// "[LLCLIENTVIEW]: Sending detailed estate data to {0} with covenant asset id {1}", Name, covenant); + EstateOwnerMessagePacket packet = new EstateOwnerMessagePacket(); packet.MethodData.Invoice = invoice; packet.AgentData.TransactionID = UUID.Random(); diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs new file mode 100644 index 0000000000..ecf70ac347 --- /dev/null +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -0,0 +1,133 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Threading; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Framework.Serialization; +using OpenSim.Framework.Serialization.External; +using OpenSim.Framework.Communications; +using OpenSim.Region.CoreModules.Avatar.Inventory.Archiver; +using OpenSim.Region.CoreModules.Framework.InventoryAccess; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; +using OpenSim.Tests.Common.Setup; + +namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests +{ + [TestFixture] + public class InventoryAccessModuleTests + { + protected TestScene m_scene; + protected BasicInventoryAccessModule m_iam; + + [SetUp] + public void SetUp() + { + m_iam = new BasicInventoryAccessModule(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + m_scene = SceneSetupHelpers.SetupScene("Inventory"); + SceneSetupHelpers.SetupSceneModules(m_scene, config, m_iam); + } + + [Test] + public void TestRezObject() + { + TestHelper.InMethod(); + log4net.Config.XmlConfigurator.Configure(); + + // Create user + string userFirstName = "Jock"; + string userLastName = "Stirrup"; + string userPassword = "troll"; + UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); + UserProfileTestUtils.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword); + + // Create asset + SceneObjectGroup object1; + SceneObjectPart part1; + { + string partName = "My Little Dog Object"; + UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); + PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); + Vector3 groupPosition = new Vector3(10, 20, 30); + Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); + Vector3 offsetPosition = new Vector3(5, 10, 15); + + part1 + = new SceneObjectPart( + ownerId, shape, groupPosition, rotationOffset, offsetPosition); + part1.Name = partName; + + object1 = new SceneObjectGroup(part1); + } + + UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); + AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); + m_scene.AssetService.Store(asset1); + + // Create item + UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080"); + string item1Name = "My Little Dog"; + InventoryItemBase item1 = new InventoryItemBase(); + item1.Name = item1Name; + item1.AssetID = asset1.FullID; + item1.ID = item1Id; + InventoryFolderBase objsFolder + = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, userId, "Objects")[0]; + item1.Folder = objsFolder.ID; + m_scene.AddInventoryItem(item1); + + AgentCircuitData acd = new AgentCircuitData(); + acd.AgentID = userId; + TestClient tc = new TestClient(acd, m_scene); + + SceneObjectGroup so + = m_iam.RezObject( + tc, item1Id, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); + + Assert.That(so, Is.Not.Null); + + SceneObjectPart retrievedPart = m_scene.GetSceneObjectPart(so.UUID); + Assert.That(retrievedPart, Is.Not.Null); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index b6d64acb80..ab90e90b78 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -259,6 +259,10 @@ namespace OpenSim.Region.CoreModules.World.Estate private void handleChangeEstateCovenantRequest(IClientAPI remoteClient, UUID estateCovenantID) { +// m_log.DebugFormat( +// "[ESTATE MANAGEMENT MODULE]: Handling request from {0} to change estate covenant to {1}", +// remoteClient.Name, estateCovenantID); + Scene.RegionInfo.RegionSettings.Covenant = estateCovenantID; Scene.RegionInfo.RegionSettings.Save(); TriggerRegionInfoChange(); diff --git a/prebuild.xml b/prebuild.xml index 81716641c6..49063daa57 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -2888,6 +2888,7 @@ + From 08fd1d9bbd0878e6ea0ce4abc0a664a70865ea01 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 13 Apr 2011 18:11:04 +0100 Subject: [PATCH 06/16] factor out some test code into the SetUp() --- .../Tests/InventoryAccessModuleTests.cs | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index ecf70ac347..5eca753d03 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -54,6 +54,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests { protected TestScene m_scene; protected BasicInventoryAccessModule m_iam; + protected UUID m_userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); + protected TestClient m_tc; [SetUp] public void SetUp() @@ -66,20 +68,23 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests m_scene = SceneSetupHelpers.SetupScene("Inventory"); SceneSetupHelpers.SetupSceneModules(m_scene, config, m_iam); + + // Create user + string userFirstName = "Jock"; + string userLastName = "Stirrup"; + string userPassword = "troll"; + UserProfileTestUtils.CreateUserWithInventory(m_scene, userFirstName, userLastName, m_userId, userPassword); + + AgentCircuitData acd = new AgentCircuitData(); + acd.AgentID = m_userId; + m_tc = new TestClient(acd, m_scene); } [Test] public void TestRezObject() { TestHelper.InMethod(); - log4net.Config.XmlConfigurator.Configure(); - - // Create user - string userFirstName = "Jock"; - string userLastName = "Stirrup"; - string userPassword = "troll"; - UUID userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); - UserProfileTestUtils.CreateUserWithInventory(m_scene, userFirstName, userLastName, userId, userPassword); +// log4net.Config.XmlConfigurator.Configure(); // Create asset SceneObjectGroup object1; @@ -112,17 +117,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests item1.AssetID = asset1.FullID; item1.ID = item1Id; InventoryFolderBase objsFolder - = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, userId, "Objects")[0]; + = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, m_userId, "Objects")[0]; item1.Folder = objsFolder.ID; m_scene.AddInventoryItem(item1); - AgentCircuitData acd = new AgentCircuitData(); - acd.AgentID = userId; - TestClient tc = new TestClient(acd, m_scene); - SceneObjectGroup so = m_iam.RezObject( - tc, item1Id, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); + m_tc, item1Id, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); Assert.That(so, Is.Not.Null); From 58efd761d13bd4f2617fcb3f94bbe265880589e3 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 13 Apr 2011 21:17:43 +0100 Subject: [PATCH 07/16] Add coalesced scene objects class and serializer. This is currently only used by the TestRezCoalescedObject() regression test. This structure matches the existing one for SceneObjects and will allow code to be reused by the uuid gatherer, other tests, etc. Test is not yet fully implemented due to a bug in rezzing coalesced objects where they all get the same name as the item. Only one object should get the same name as the item, which appears to be the one selected last when the the objects were coalesced in the first place. This bug will be addressed shortly. --- .../InventoryAccess/InventoryAccessModule.cs | 19 ++- .../Tests/InventoryAccessModuleTests.cs | 79 +++++++++++ .../Framework/Scenes/CoalescedSceneObjects.cs | 128 ++++++++++++++++++ OpenSim/Region/Framework/Scenes/Scene.cs | 15 +- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 2 + .../CoalescedSceneObjectsSerializer.cs | 117 ++++++++++++++++ .../Serialization/SceneObjectSerializer.cs | 23 +++- OpenSim/Tests/Common/Setup/AssetHelpers.cs | 15 ++ 8 files changed, 389 insertions(+), 9 deletions(-) create mode 100644 OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs create mode 100644 OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 73b0a35b7c..cfcfc79c11 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -274,7 +274,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess float minX, minY, minZ; float maxX, maxY, maxZ; - Vector3[] offsets = m_Scene.GetCombinedBoundingBox(objlist, + Vector3[] offsets = Scene.GetCombinedBoundingBox(objlist, out minX, out maxX, out minY, out maxY, out minZ, out maxZ); @@ -289,7 +289,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess XmlDocument doc = new XmlDocument(); SceneObjectGroup g = objlist[i]; doc.LoadXml(xmlStrings[g.UUID]); - XmlElement e = (XmlElement)doc.SelectSingleNode("/SceneObjectGroup"); + XmlElement e = (XmlElement)doc.SelectSingleNode("/SceneObjectGroup"); e.SetAttribute("offsetx", offsets[i].X.ToString()); e.SetAttribute("offsety", offsets[i].Y.ToString()); e.SetAttribute("offsetz", offsets[i].Z.ToString()); @@ -659,9 +659,18 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess itemId, n.OuterXml); objlist.Add(g); XmlElement el = (XmlElement)n; - float x = Convert.ToSingle(el.GetAttribute("offsetx")); - float y = Convert.ToSingle(el.GetAttribute("offsety")); - float z = Convert.ToSingle(el.GetAttribute("offsetz")); + + string rawX = el.GetAttribute("offsetx"); + string rawY = el.GetAttribute("offsety"); + string rawZ = el.GetAttribute("offsetz"); +// +// m_log.DebugFormat( +// "[INVENTORY ACCESS MODULE]: Converting coalesced object {0} offset <{1}, {2}, {3}>", +// g.Name, rawX, rawY, rawZ); + + float x = Convert.ToSingle(rawX); + float y = Convert.ToSingle(rawY); + float z = Convert.ToSingle(rawZ); veclist.Add(new Vector3(x, y, z)); } } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index 5eca753d03..f8fa424738 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -80,6 +80,85 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests m_tc = new TestClient(acd, m_scene); } + [Test] + public void TestRezCoalescedObject() + { + TestHelper.InMethod(); + log4net.Config.XmlConfigurator.Configure(); + + // Create asset + SceneObjectGroup object1; + { + string partName = "Object1"; + UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); + PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); + Vector3 groupPosition = new Vector3(10, 20, 30); + Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); + Vector3 offsetPosition = new Vector3(5, 10, 15); + + SceneObjectPart part1 + = new SceneObjectPart( + ownerId, shape, groupPosition, rotationOffset, offsetPosition); + part1.Name = partName; + + object1 = new SceneObjectGroup(part1); + } + + SceneObjectGroup object2; + { + string partName = "Object2"; + UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); + PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); + Vector3 groupPosition = new Vector3(10, 20, 30); + Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); + Vector3 offsetPosition = new Vector3(5, 10, 15); + + SceneObjectPart part1 + = new SceneObjectPart( + ownerId, shape, groupPosition, rotationOffset, offsetPosition); + part1.Name = partName; + + object2 = new SceneObjectGroup(part1); + } + + CoalescedSceneObjects coa = new CoalescedSceneObjects(m_userId, object1, object2); + + UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); + AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, coa); + m_scene.AssetService.Store(asset1); + + // Create item + UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080"); + string item1Name = "My Little Dog"; + InventoryItemBase item1 = new InventoryItemBase(); + item1.Name = item1Name; + item1.AssetID = asset1.FullID; + item1.ID = item1Id; + InventoryFolderBase objsFolder + = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, m_userId, "Objects")[0]; + item1.Folder = objsFolder.ID; + m_scene.AddInventoryItem(item1); + + SceneObjectGroup so + = m_iam.RezObject( + m_tc, item1Id, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); + + Assert.That(so, Is.Not.Null); + + Assert.That(m_scene.SceneGraph.GetTotalObjectsCount(), Is.EqualTo(2)); + + SceneObjectPart retrievedObj1Part = m_scene.GetSceneObjectPart(object1.Name); + Assert.That(retrievedObj1Part, Is.Null); + + retrievedObj1Part = m_scene.GetSceneObjectPart(item1.Name); + Assert.That(retrievedObj1Part, Is.Not.Null); + Assert.That(retrievedObj1Part.Name, Is.EqualTo(item1.Name)); + + // FIXME: Can't test yet due to a bug where objects in coalescence all get the item name when rerezzed. +// SceneObjectPart retrievedObj2Part = m_scene.GetSceneObjectPart(object2.Name); +// Assert.That(retrievedObj2Part, Is.Not.Null); + } + [Test] public void TestRezObject() { diff --git a/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs b/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs new file mode 100644 index 0000000000..51eac5f3f6 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs @@ -0,0 +1,128 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenMetaverse; + +namespace OpenSim.Region.Framework.Scenes +{ + /// + /// Represents a coalescene of scene objects. A coalescence occurs when objects that are not in the same linkset + /// are grouped together. + /// + public class CoalescedSceneObjects + { + /// + /// The creator of this coalesence, though not necessarily the objects within it. + /// + public UUID CreatorId { get; set; } + + /// + /// The number of objects in this coalesence + /// + public int Count + { + get + { + lock (m_memberObjects) + return m_memberObjects.Count; + } + } + + /// + /// Does this coalesence have any member objects? + /// + public bool HasObjects { get { return Count > 0; } } + + /// + /// Get the objects currently in this coalescence + /// + public List Objects + { + get + { + lock (m_memberObjects) + return new List(m_memberObjects); + } + } + + /// + /// Get the scene that contains the objects in this coalescence. If there are no objects then null is returned. + /// + public Scene Scene + { + get + { + if (!HasObjects) + return null; + else + return Objects[0].Scene; + } + } + + /// + /// At this point, we need to preserve the order of objects added to the coalescence, since the first + /// one will end up matching the item name when rerezzed. + /// + protected List m_memberObjects = new List(); + + public CoalescedSceneObjects(UUID creatorId) + { + CreatorId = creatorId; + } + + public CoalescedSceneObjects(UUID creatorId, params SceneObjectGroup[] objs) : this(creatorId) + { + foreach (SceneObjectGroup obj in objs) + Add(obj); + } + + /// + /// Add an object to the coalescence. + /// + /// + /// The offset of the object within the group + public void Add(SceneObjectGroup obj) + { + lock (m_memberObjects) + m_memberObjects.Add(obj); + } + + /// + /// Removes a scene object from the coalescene + /// + /// + /// true if the object was there to be removed, false if not. + public bool Remove(SceneObjectGroup obj) + { + lock (m_memberObjects) + return m_memberObjects.Remove(obj); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index f0acc38820..e6dd48940f 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4839,7 +4839,20 @@ namespace OpenSim.Region.Framework.Scenes } } - public Vector3[] GetCombinedBoundingBox(List objects, out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) + /// + /// Get the volume of space that will encompass all the given objects. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static Vector3[] GetCombinedBoundingBox( + List objects, + out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) { minX = 256; maxX = -256; diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 97af0a0b47..72f040252f 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -997,6 +997,8 @@ namespace OpenSim.Region.Framework.Scenes { foreach (SceneObjectPart p in ((SceneObjectGroup)entity).Parts) { +// m_log.DebugFormat("[SCENE GRAPH]: Part {0} has name {1}", p.UUID, p.Name); + if (p.Name == name) { sop = p; diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs new file mode 100644 index 0000000000..3af2f76340 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs @@ -0,0 +1,117 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Reflection; +using System.Xml; +using log4net; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.Framework.Scenes.Serialization +{ + /// + /// Serialize and deserialize coalesced scene objects. + /// + public class CoalescedSceneObjectsSerializer + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// Serialize coalesced objects to Xml + /// + /// + /// + public static string ToXml(CoalescedSceneObjects coa) + { + // TODO: Should probably return an empty xml serialization rather than a blank string + if (!coa.HasObjects) + return ""; + + using (StringWriter sw = new StringWriter()) + { + using (XmlTextWriter writer = new XmlTextWriter(sw)) + { + List coaObjects = coa.Objects; + +// m_log.DebugFormat( +// "[COALESCED SCENE OBJECTS SERIALIZER]: Writing {0} objects for coalesced object", +// coaObjects.Count); + + float minX, minY, minZ; + float maxX, maxY, maxZ; + + Vector3[] offsets = Scene.GetCombinedBoundingBox(coaObjects, + out minX, out maxX, out minY, out maxY, + out minZ, out maxZ); + + writer.WriteStartElement("CoalescedObject"); + + float sizeX = maxX - minX; + float sizeY = maxY - minY; + float sizeZ = maxZ - minZ; + + writer.WriteAttributeString("x", sizeX.ToString()); + writer.WriteAttributeString("y", sizeY.ToString()); + writer.WriteAttributeString("z", sizeZ.ToString()); + + // Embed the offsets into the group XML + for (int i = 0; i < coaObjects.Count; i++) + { + SceneObjectGroup obj = coaObjects[i]; + +// m_log.DebugFormat( +// "[COALESCED SCENE OBJECTS SERIALIZER]: Writing offset for object {0}, {1}", +// i, obj.Name); + + writer.WriteStartElement("SceneObjectGroup"); + writer.WriteAttributeString("offsetx", offsets[i].X.ToString()); + writer.WriteAttributeString("offsety", offsets[i].Y.ToString()); + writer.WriteAttributeString("offsetz", offsets[i].Z.ToString()); + + SceneObjectSerializer.ToOriginalXmlFormat(obj, writer, true); + + writer.WriteEndElement(); + } + + writer.WriteEndElement(); // CoalescedObject + } + + string output = sw.ToString(); + +// m_log.Debug(output); + + return output; + } + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index b412e25579..bb8a83a1af 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -139,6 +139,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization return sw.ToString(); } } + /// /// Serialize a scene object to the original xml format @@ -146,11 +147,25 @@ namespace OpenSim.Region.Framework.Scenes.Serialization /// /// public static void ToOriginalXmlFormat(SceneObjectGroup sceneObject, XmlTextWriter writer) + { + ToOriginalXmlFormat(sceneObject, writer, false); + } + + /// + /// Serialize a scene object to the original xml format + /// + /// + /// + /// If false, don't write the enclosing SceneObjectGroup element + /// + public static void ToOriginalXmlFormat(SceneObjectGroup sceneObject, XmlTextWriter writer, bool noRootElement) { //m_log.DebugFormat("[SERIALIZER]: Starting serialization of {0}", Name); //int time = System.Environment.TickCount; - writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty); + if (!noRootElement) + writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty); + writer.WriteStartElement(String.Empty, "RootPart", String.Empty); ToXmlFormat(sceneObject.RootPart, writer); writer.WriteEndElement(); @@ -170,10 +185,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteEndElement(); // OtherParts sceneObject.SaveScriptedState(writer); - writer.WriteEndElement(); // SceneObjectGroup + + if (!noRootElement) + writer.WriteEndElement(); // SceneObjectGroup //m_log.DebugFormat("[SERIALIZER]: Finished serialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time); - } + } protected static void ToXmlFormat(SceneObjectPart part, XmlTextWriter writer) { diff --git a/OpenSim/Tests/Common/Setup/AssetHelpers.cs b/OpenSim/Tests/Common/Setup/AssetHelpers.cs index ff4423f7ab..af66d7f0a7 100644 --- a/OpenSim/Tests/Common/Setup/AssetHelpers.cs +++ b/OpenSim/Tests/Common/Setup/AssetHelpers.cs @@ -71,6 +71,21 @@ namespace OpenSim.Tests.Common Encoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(sog)), sog.OwnerID); } + + /// + /// Create an asset from the given scene object. + /// + /// + /// + /// + public static AssetBase CreateAsset(UUID assetUuid, CoalescedSceneObjects coa) + { + return CreateAsset( + assetUuid, + AssetType.Object, + Encoding.ASCII.GetBytes(CoalescedSceneObjectsSerializer.ToXml(coa)), + coa.CreatorId); + } /// /// Create an asset from the given data. From d8d28c37372718aa593ead5c85cd45ced83766a5 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 13 Apr 2011 21:31:45 +0100 Subject: [PATCH 08/16] Fix bug where rezzing coalesced objects would give all objects the same name as the item. This now only happens for the first object (which was the item selected last when the coalesce was originally taken) This matches the expected behaviour of the environment as seen on the Linden Labs grid. --- .../InventoryAccess/InventoryAccessModule.cs | 13 +++++++++---- .../Tests/InventoryAccessModuleTests.cs | 5 ++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index cfcfc79c11..1f8bad1eb5 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -762,10 +762,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // affect the name stored in the serialization, transfer // the correct name from the inventory to the // object itself before we rez. - rootPart.Name = item.Name; - rootPart.Description = item.Description; - rootPart.ObjectSaleType = item.SaleType; - rootPart.SalePrice = item.SalePrice; + // + // Only do these for the first object if we are rezzing a coalescence. + if (i == 0) + { + rootPart.Name = item.Name; + rootPart.Description = item.Description; + rootPart.ObjectSaleType = item.SaleType; + rootPart.SalePrice = item.SalePrice; + } group.SetGroup(remoteClient.ActiveGroupId, remoteClient); if ((rootPart.OwnerID != item.Owner) || diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index f8fa424738..0f2b6108ad 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -154,9 +154,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests Assert.That(retrievedObj1Part, Is.Not.Null); Assert.That(retrievedObj1Part.Name, Is.EqualTo(item1.Name)); - // FIXME: Can't test yet due to a bug where objects in coalescence all get the item name when rerezzed. -// SceneObjectPart retrievedObj2Part = m_scene.GetSceneObjectPart(object2.Name); -// Assert.That(retrievedObj2Part, Is.Not.Null); + SceneObjectPart retrievedObj2Part = m_scene.GetSceneObjectPart(object2.Name); + Assert.That(retrievedObj2Part, Is.Not.Null); } [Test] From 68cc5b46fefdf4db68cae1202086257ce731f8a1 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 13 Apr 2011 21:48:16 +0100 Subject: [PATCH 09/16] refactor: move code to obtain the coalescence size and object offsets into CoalescedSceneObjects from the serializer. --- .../Tests/InventoryAccessModuleTests.cs | 2 +- .../Framework/Scenes/CoalescedSceneObjects.cs | 26 ++++++++++++++++++ .../CoalescedSceneObjectsSerializer.cs | 27 +++++++++---------- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index 0f2b6108ad..c197cb9b1b 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -84,7 +84,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests public void TestRezCoalescedObject() { TestHelper.InMethod(); - log4net.Config.XmlConfigurator.Configure(); +// log4net.Config.XmlConfigurator.Configure(); // Create asset SceneObjectGroup object1; diff --git a/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs b/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs index 51eac5f3f6..af8ccda6c2 100644 --- a/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs +++ b/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs @@ -124,5 +124,31 @@ namespace OpenSim.Region.Framework.Scenes lock (m_memberObjects) return m_memberObjects.Remove(obj); } + + /// + /// Get the total size of the coalescence (the size required to cover all the objects within it) and the + /// offsets of each of those objects. + /// + /// + /// + /// An array of offsets. The order of objects is the same as returned from the Objects property + /// + public Vector3[] GetSizeAndOffsets(out Vector3 size) + { + float minX, minY, minZ; + float maxX, maxY, maxZ; + + Vector3[] offsets + = Scene.GetCombinedBoundingBox( + Objects, out minX, out maxX, out minY, out maxY, out minZ, out maxZ); + + float sizeX = maxX - minX; + float sizeY = maxY - minY; + float sizeZ = maxZ - minZ; + + size = new Vector3(sizeX, sizeY, sizeZ); + + return offsets; + } } } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs index 3af2f76340..a0e120a9ac 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs @@ -42,6 +42,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization /// /// Serialize and deserialize coalesced scene objects. /// + /// + /// Deserialization not yet here. + /// public class CoalescedSceneObjectsSerializer { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -60,29 +63,23 @@ namespace OpenSim.Region.Framework.Scenes.Serialization using (StringWriter sw = new StringWriter()) { using (XmlTextWriter writer = new XmlTextWriter(sw)) - { + { + Vector3 size; + List coaObjects = coa.Objects; // m_log.DebugFormat( // "[COALESCED SCENE OBJECTS SERIALIZER]: Writing {0} objects for coalesced object", // coaObjects.Count); - float minX, minY, minZ; - float maxX, maxY, maxZ; - - Vector3[] offsets = Scene.GetCombinedBoundingBox(coaObjects, - out minX, out maxX, out minY, out maxY, - out minZ, out maxZ); + // This is weak - we're relying on the set of coalesced objects still being identical + Vector3[] offsets = coa.GetSizeAndOffsets(out size); writer.WriteStartElement("CoalescedObject"); - float sizeX = maxX - minX; - float sizeY = maxY - minY; - float sizeZ = maxZ - minZ; - - writer.WriteAttributeString("x", sizeX.ToString()); - writer.WriteAttributeString("y", sizeY.ToString()); - writer.WriteAttributeString("z", sizeZ.ToString()); + writer.WriteAttributeString("x", size.X.ToString()); + writer.WriteAttributeString("y", size.Y.ToString()); + writer.WriteAttributeString("z", size.Z.ToString()); // Embed the offsets into the group XML for (int i = 0; i < coaObjects.Count; i++) @@ -100,7 +97,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization SceneObjectSerializer.ToOriginalXmlFormat(obj, writer, true); - writer.WriteEndElement(); + writer.WriteEndElement(); // SceneObjectGroup } writer.WriteEndElement(); // CoalescedObject From c81f5bfc5c3cb0bac2a89ee846099dcaae1f357b Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 13 Apr 2011 22:29:12 +0100 Subject: [PATCH 10/16] Adjust the quanterions used in the rez coalsced object tests to get sensible bounding box and offset numbers. Extend test to check position of objects in the rezzed coalescence. --- .../Tests/InventoryAccessModuleTests.cs | 16 ++++++++++++---- OpenSim/Region/Framework/Scenes/Scene.cs | 4 ++++ .../Region/Framework/Scenes/SceneObjectPart.cs | 9 ++++++++- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index c197cb9b1b..c76a30af69 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -93,12 +93,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); Vector3 groupPosition = new Vector3(10, 20, 30); - Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); + Quaternion rotationOffset = Quaternion.Identity; Vector3 offsetPosition = new Vector3(5, 10, 15); SceneObjectPart part1 = new SceneObjectPart( ownerId, shape, groupPosition, rotationOffset, offsetPosition); + part1.Scale = new Vector3(1, 1, 1); part1.Name = partName; object1 = new SceneObjectGroup(part1); @@ -109,13 +110,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests string partName = "Object2"; UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040"); PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere(); - Vector3 groupPosition = new Vector3(10, 20, 30); - Quaternion rotationOffset = new Quaternion(20, 30, 40, 50); + Vector3 groupPosition = new Vector3(20, 40, 60); + Quaternion rotationOffset = Quaternion.Identity; Vector3 offsetPosition = new Vector3(5, 10, 15); SceneObjectPart part1 = new SceneObjectPart( ownerId, shape, groupPosition, rotationOffset, offsetPosition); + part1.Scale = new Vector3(1, 1, 1); part1.Name = partName; object2 = new SceneObjectGroup(part1); @@ -141,7 +143,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests SceneObjectGroup so = m_iam.RezObject( - m_tc, item1Id, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); + m_tc, item1Id, new Vector3(100, 100, 100), Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); Assert.That(so, Is.Not.Null); @@ -154,8 +156,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests Assert.That(retrievedObj1Part, Is.Not.Null); Assert.That(retrievedObj1Part.Name, Is.EqualTo(item1.Name)); + // Bottom of coalescence is placed on ground, hence we end up with 100.5 rather than 85 since the bottom + // object is unit square. + Assert.That(retrievedObj1Part.AbsolutePosition, Is.EqualTo(new Vector3(95, 90, 100.5f))); + SceneObjectPart retrievedObj2Part = m_scene.GetSceneObjectPart(object2.Name); Assert.That(retrievedObj2Part, Is.Not.Null); + Assert.That(retrievedObj2Part.Name, Is.EqualTo(object2.Name)); + Assert.That(retrievedObj2Part.AbsolutePosition, Is.EqualTo(new Vector3(105, 110, 130.5f))); } [Test] diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index e6dd48940f..fdd5205de8 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4870,6 +4870,10 @@ namespace OpenSim.Region.Framework.Scenes Vector3 vec = g.AbsolutePosition; g.GetAxisAlignedBoundingBoxRaw(out ominX, out omaxX, out ominY, out omaxY, out ominZ, out omaxZ); + +// m_log.DebugFormat( +// "[SCENE]: For {0} found AxisAlignedBoundingBoxRaw {1}, {2}", +// g.Name, new Vector3(ominX, ominY, ominZ), new Vector3(omaxX, omaxY, omaxZ)); ominX += vec.X; omaxX += vec.X; diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 4d5eedfc95..ce1e6b8614 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2088,7 +2088,14 @@ namespace OpenSim.Region.Framework.Scenes axPos *= parentRot; Vector3 translationOffsetPosition = axPos; - return GroupPosition + translationOffsetPosition; + +// m_log.DebugFormat("[SCENE OBJECT PART]: Found group pos {0} for part {1}", GroupPosition, Name); + + Vector3 worldPos = GroupPosition + translationOffsetPosition; + +// m_log.DebugFormat("[SCENE OBJECT PART]: Found world pos {0} for part {1}", worldPos, Name); + + return worldPos; } /// From c5465414b64d835128827976cc3da32aa462e6a3 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 13 Apr 2011 22:55:26 +0100 Subject: [PATCH 11/16] Use common coalesced serialization code for both tests and the InventoryAccessModule. Continue to restore original absolute positions of stored scene objects, though it's possible that these aren't used again --- .../InventoryAccess/InventoryAccessModule.cs | 67 ++++--------------- 1 file changed, 13 insertions(+), 54 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 1f8bad1eb5..c0946f4d52 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -222,7 +222,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess deletes[g.OwnerID].Add(g); } - // This is pethod scoped and will be returned. It will be the + // This is method scoped and will be returned. It will be the // last created asset id UUID assetID = UUID.Zero; @@ -230,8 +230,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // with distinct destinations as well. foreach (List objlist in deletes.Values) { - Dictionary xmlStrings = - new Dictionary(); + CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); + Dictionary originalPositions = new Dictionary(); foreach (SceneObjectGroup objectGroup in objlist) { @@ -245,7 +245,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess : objectGroup.AbsolutePosition.X, objectGroup.AbsolutePosition.Z); - Vector3 originalPosition = objectGroup.AbsolutePosition; + originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; objectGroup.AbsolutePosition = inventoryStoredPosition; @@ -259,59 +259,20 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess (uint)PermissionMask.Modify); objectGroup.RootPart.NextOwnerMask |= (uint)PermissionMask.Move; - - string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(objectGroup); - - objectGroup.AbsolutePosition = originalPosition; - - xmlStrings[objectGroup.UUID] = sceneObjectXml; + + coa.Add(objectGroup); } string itemXml; if (objlist.Count > 1) - { - float minX, minY, minZ; - float maxX, maxY, maxZ; - - Vector3[] offsets = Scene.GetCombinedBoundingBox(objlist, - out minX, out maxX, out minY, out maxY, - out minZ, out maxZ); - - // CreateWrapper - XmlDocument itemDoc = new XmlDocument(); - XmlElement root = itemDoc.CreateElement("", "CoalescedObject", ""); - itemDoc.AppendChild(root); - - // Embed the offsets into the group XML - for ( int i = 0 ; i < objlist.Count ; i++ ) - { - XmlDocument doc = new XmlDocument(); - SceneObjectGroup g = objlist[i]; - doc.LoadXml(xmlStrings[g.UUID]); - XmlElement e = (XmlElement)doc.SelectSingleNode("/SceneObjectGroup"); - e.SetAttribute("offsetx", offsets[i].X.ToString()); - e.SetAttribute("offsety", offsets[i].Y.ToString()); - e.SetAttribute("offsetz", offsets[i].Z.ToString()); - - XmlNode objectNode = itemDoc.ImportNode(e, true); - root.AppendChild(objectNode); - } - - float sizeX = maxX - minX; - float sizeY = maxY - minY; - float sizeZ = maxZ - minZ; - - root.SetAttribute("x", sizeX.ToString()); - root.SetAttribute("y", sizeY.ToString()); - root.SetAttribute("z", sizeZ.ToString()); - - itemXml = itemDoc.InnerXml; - } + itemXml = CoalescedSceneObjectsSerializer.ToXml(coa); else - { - itemXml = xmlStrings[objlist[0].UUID]; - } + itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0]); + + // Restore the position of each group now that it has been stored to inventory. + foreach (SceneObjectGroup objectGroup in objlist) + objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; // Get the user info of the item destination // @@ -332,7 +293,6 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { // All returns / deletes go to the object owner // - userID = objlist[0].RootPart.OwnerID; } @@ -346,7 +306,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // Delete is treated like return in this case // Deleting your own items makes them go to trash // - + InventoryFolderBase folder = null; InventoryItemBase item = null; @@ -548,7 +508,6 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return assetID; } - /// /// Rez an object into the scene from the user's inventory /// From 5b89c66c9704f2bd219a35f8a70ac60e751d7f49 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 11 Apr 2011 09:06:28 -0700 Subject: [PATCH 12/16] New tokenbucket algorithm. This one provides fair sharing of the queues when client and simulator throttles are set. This algorithm also uses pre-defined burst rate of 150% of the sustained rate for each of the throttles. Removed the "state" queue. The state queue is not a Linden queue and appeared to be used just to get kill packets sent. --- .../ClientStack/LindenUDP/LLClientView.cs | 6 +- .../ClientStack/LindenUDP/LLUDPClient.cs | 96 +++--- .../ClientStack/LindenUDP/LLUDPServer.cs | 2 +- .../ClientStack/LindenUDP/TokenBucket.cs | 314 +++++++++++------- 4 files changed, 266 insertions(+), 152 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 76d7f7964b..5980669651 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -1610,7 +1610,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else { - OutPacket(kill, ThrottleOutPacketType.State); + // OutPacket(kill, ThrottleOutPacketType.State); + OutPacket(kill, ThrottleOutPacketType.Task); } } @@ -2440,7 +2441,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP packet.Effect = effectBlocks; - OutPacket(packet, ThrottleOutPacketType.State); + // OutPacket(packet, ThrottleOutPacketType.State); + OutPacket(packet, ThrottleOutPacketType.Task); } public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 9a8bfd357c..5a69851b3c 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -135,7 +135,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_nextOnQueueEmpty = 1; /// Throttle bucket for this agent's connection - private readonly TokenBucket m_throttle; + private readonly TokenBucket m_throttleClient; + /// Throttle bucket for this agent's connection + private readonly TokenBucket m_throttleCategory; /// Throttle buckets for each packet category private readonly TokenBucket[] m_throttleCategories; /// Outgoing queues for throttled packets @@ -174,7 +176,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_maxRTO = maxRTO; // Create a token bucket throttle for this client that has the scene token bucket as a parent - m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total); + m_throttleClient = new TokenBucket(parentThrottle, rates.TotalLimit); + // Create a token bucket throttle for the total categary with the client bucket as a throttle + m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit); // Create an array of token buckets for this clients different throttle categories m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; @@ -185,7 +189,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Initialize the packet outboxes, where packets sit while they are waiting for tokens m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue(); // Initialize the token buckets that control the throttling for each category - m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type)); + m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetLimit(type)); } // Default the retransmission timeout to three seconds @@ -206,6 +210,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_packetOutboxes[i].Clear(); m_nextPackets[i] = null; } + + // pull the throttle out of the scene throttle + m_throttleClient.Parent.UnregisterRequest(m_throttleClient); OnPacketStats = null; OnQueueEmpty = null; } @@ -216,6 +223,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Information about the client connection public ClientInfo GetClientInfo() { +/// + TokenBucket tb; + + tb = m_throttleClient.Parent; + m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest,"ROOT"); + + tb = m_throttleClient; + m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CLIENT"); + + tb = m_throttleCategory; + m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CATEGORY"); + + for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) + { + tb = m_throttleCategories[i]; + m_log.WarnFormat("[TOKENS] {4} <{0}:{1}>: Actual={2},Requested={3}",AgentID,i,tb.DripRate,tb.RequestedDripRate," BUCKET"); + } + +/// + // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists // of pending and needed ACKs for every client every time some method wants information about // this connection is a recipe for poor performance @@ -223,13 +250,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP info.pendingAcks = new Dictionary(); info.needAck = new Dictionary(); - info.resendThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; - info.landThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; - info.windThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; - info.cloudThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; - info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; - info.assetThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; - info.textureThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; + info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; + info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; + info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; + info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; + // info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; + info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; + info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; + info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + info.taskThrottle + info.assetThrottle + info.textureThrottle; @@ -317,8 +345,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); // State is a subcategory of task that we allocate a percentage to - int state = (int)((float)task * STATE_TASK_PERCENTAGE); - task -= state; + int state = 0; + // int state = (int)((float)task * STATE_TASK_PERCENTAGE); + // task -= state; // Make sure none of the throttles are set below our packet MTU, // otherwise a throttle could become permanently clogged @@ -339,40 +368,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Update the token buckets with new throttle values TokenBucket bucket; - bucket = m_throttle; - bucket.MaxBurst = total; + bucket = m_throttleCategory; + bucket.RequestedDripRate = total; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; - bucket.DripRate = resend; - bucket.MaxBurst = resend; + bucket.RequestedDripRate = resend; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; - bucket.DripRate = land; - bucket.MaxBurst = land; + bucket.RequestedDripRate = land; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; - bucket.DripRate = wind; - bucket.MaxBurst = wind; + bucket.RequestedDripRate = wind; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; - bucket.DripRate = cloud; - bucket.MaxBurst = cloud; + bucket.RequestedDripRate = cloud; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; - bucket.DripRate = asset; - bucket.MaxBurst = asset; + bucket.RequestedDripRate = asset; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; - bucket.DripRate = task + state; - bucket.MaxBurst = task + state; + bucket.RequestedDripRate = task; bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; - bucket.DripRate = state; - bucket.MaxBurst = state; + bucket.RequestedDripRate = state; bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; - bucket.DripRate = texture; - bucket.MaxBurst = texture; + bucket.RequestedDripRate = texture; // Reset the packed throttles cached data m_packedThrottles = null; @@ -387,14 +408,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP data = new byte[7 * 4]; int i = 0; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)(m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) + - m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; - Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate), 0, data, i, 4); i += 4; + Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate), 0, data, i, 4); i += 4; m_packedThrottles = data; } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 583214ca0b..d08b25f79d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -228,7 +228,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } #endregion BinaryStats - m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps); + m_throttle = new TokenBucket(null, sceneThrottleBps); ThrottleRates = new ThrottleRates(configSource); } diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs index 0a8331f32a..e4d59ff829 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs @@ -26,6 +26,10 @@ */ using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; +using log4net; namespace OpenSim.Region.ClientStack.LindenUDP { @@ -35,89 +39,126 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public class TokenBucket { - /// Parent bucket to this bucket, or null if this is a root - /// bucket - TokenBucket parent; - /// Size of the bucket in bytes. If zero, the bucket has - /// infinite capacity - int maxBurst; - /// Rate that the bucket fills, in bytes per millisecond. If - /// zero, the bucket always remains full - int tokensPerMS; - /// Number of tokens currently in the bucket - int content; - /// Time of the last drip, in system ticks - int lastDrip; + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static Int32 m_counter = 0; + + private Int32 m_identifier; + + /// + /// Number of ticks (ms) per quantum, drip rate and max burst + /// are defined over this interval. + /// + private const Int32 m_ticksPerQuantum = 1000; - #region Properties + /// + /// This is the number of quantums worth of packets that can + /// be accommodated during a burst + /// + private const Double m_quantumsPerBurst = 1.5; + + /// + /// + private const Int32 m_minimumDripRate = 1400; + + /// Time of the last drip, in system ticks + private Int32 m_lastDrip; + + /// + /// The number of bytes that can be sent at this moment. This is the + /// current number of tokens in the bucket + /// + private Int64 m_tokenCount; + + /// + /// Map of children buckets and their requested maximum burst rate + /// + private Dictionary m_children = new Dictionary(); + +#region Properties /// /// The parent bucket of this bucket, or null if this bucket has no /// parent. The parent bucket will limit the aggregate bandwidth of all /// of its children buckets /// + private TokenBucket m_parent; public TokenBucket Parent { - get { return parent; } + get { return m_parent; } + set { m_parent = value; } } /// /// Maximum burst rate in bytes per second. This is the maximum number - /// of tokens that can accumulate in the bucket at any one time + /// of tokens that can accumulate in the bucket at any one time. This + /// also sets the total request for leaf nodes /// - public int MaxBurst + private Int64 m_burstRate; + public Int64 RequestedBurstRate { - get { return maxBurst; } - set { maxBurst = (value >= 0 ? value : 0); } + get { return m_burstRate; } + set { m_burstRate = (value < 0 ? 0 : value); } } + public Int64 BurstRate + { + get { + double rate = RequestedBurstRate * BurstRateModifier(); + if (rate < m_minimumDripRate * m_quantumsPerBurst) + rate = m_minimumDripRate * m_quantumsPerBurst; + + return (Int64) rate; + } + } + /// /// The speed limit of this bucket in bytes per second. This is the - /// number of tokens that are added to the bucket per second + /// number of tokens that are added to the bucket per quantum /// /// Tokens are added to the bucket any time /// is called, at the granularity of /// the system tick interval (typically around 15-22ms) - public int DripRate + private Int64 m_dripRate; + public Int64 RequestedDripRate { - get { return tokensPerMS * 1000; } - set - { - if (value == 0) - tokensPerMS = 0; - else - { - int bpms = (int)((float)value / 1000.0f); + get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } + set { + m_dripRate = (value < 0 ? 0 : value); + m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); + m_totalDripRequest = m_dripRate; + if (m_parent != null) + m_parent.RegisterRequest(this,m_dripRate); + } + } - if (bpms <= 0) - tokensPerMS = 1; // 1 byte/ms is the minimum granularity - else - tokensPerMS = bpms; - } + public Int64 DripRate + { + get { + if (m_parent == null) + return Math.Min(RequestedDripRate,TotalDripRequest); + + double rate = (double)RequestedDripRate * m_parent.DripRateModifier(); + if (rate < m_minimumDripRate) + rate = m_minimumDripRate; + + return (Int64)rate; } } /// - /// The speed limit of this bucket in bytes per millisecond + /// The current total of the requested maximum burst rates of + /// this bucket's children buckets. /// - public int DripPerMS - { - get { return tokensPerMS; } - } + private Int64 m_totalDripRequest; + public Int64 TotalDripRequest + { + get { return m_totalDripRequest; } + set { m_totalDripRequest = value; } + } + +#endregion Properties - /// - /// The number of bytes that can be sent at this moment. This is the - /// current number of tokens in the bucket - /// If this bucket has a parent bucket that does not have - /// enough tokens for a request, will - /// return false regardless of the content of this bucket - /// - public int Content - { - get { return content; } - } - - #endregion Properties +#region Constructor /// /// Default constructor @@ -128,56 +169,115 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// zero if this bucket has no maximum capacity /// Rate that the bucket fills, in bytes per /// second. If zero, the bucket always remains full - public TokenBucket(TokenBucket parent, int maxBurst, int dripRate) + public TokenBucket(TokenBucket parent, Int64 dripRate) { - this.parent = parent; - MaxBurst = maxBurst; - DripRate = dripRate; - lastDrip = Environment.TickCount & Int32.MaxValue; + m_identifier = m_counter++; + + Parent = parent; + RequestedDripRate = dripRate; + // TotalDripRequest = dripRate; // this will be overwritten when a child node registers + // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); + m_lastDrip = Environment.TickCount & Int32.MaxValue; } +#endregion Constructor + + /// + /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning + /// no modification if the requested bandwidth is less than the + /// max burst bandwidth all the way to the root of the throttle + /// hierarchy. However, if any of the parents is over-booked, then + /// the modifier will be less than 1. + /// + private double DripRateModifier() + { + Int64 driprate = DripRate; + return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; + } + + /// + /// + private double BurstRateModifier() + { + // for now... burst rate is always m_quantumsPerBurst (constant) + // larger than drip rate so the ratio of burst requests is the + // same as the drip ratio + return DripRateModifier(); + } + + /// + /// Register drip rate requested by a child of this throttle. Pass the + /// changes up the hierarchy. + /// + public void RegisterRequest(TokenBucket child, Int64 request) + { + m_children[child] = request; + // m_totalDripRequest = m_children.Values.Sum(); + + m_totalDripRequest = 0; + foreach (KeyValuePair cref in m_children) + m_totalDripRequest += cref.Value; + + // Pass the new values up to the parent + if (m_parent != null) + m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); + } + + /// + /// Remove the rate requested by a child of this throttle. Pass the + /// changes up the hierarchy. + /// + public void UnregisterRequest(TokenBucket child) + { + m_children.Remove(child); + // m_totalDripRequest = m_children.Values.Sum(); + + m_totalDripRequest = 0; + foreach (KeyValuePair cref in m_children) + m_totalDripRequest += cref.Value; + + // Pass the new values up to the parent + if (m_parent != null) + m_parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); + } + /// /// Remove a given number of tokens from the bucket /// /// Number of tokens to remove from the bucket /// True if the requested number of tokens were removed from /// the bucket, otherwise false - public bool RemoveTokens(int amount) + public bool RemoveTokens(Int64 amount) { - bool dummy; - return RemoveTokens(amount, out dummy); + // Deposit tokens for this interval + Drip(); + + // If we have enough tokens then remove them and return + if (m_tokenCount - amount >= 0) + { + if (m_parent == null || m_parent.RemoveTokens(amount)) + { + m_tokenCount -= amount; + return true; + } + } + + return false; } /// - /// Remove a given number of tokens from the bucket + /// Deposit tokens into the bucket from a child bucket that did + /// not use all of its available tokens /// - /// Number of tokens to remove from the bucket - /// True if tokens were added to the bucket - /// during this call, otherwise false - /// True if the requested number of tokens were removed from - /// the bucket, otherwise false - public bool RemoveTokens(int amount, out bool dripSucceeded) + private void Deposit(Int64 count) { - if (maxBurst == 0) - { - dripSucceeded = true; - return true; - } + m_tokenCount += count; - dripSucceeded = Drip(); - - if (content - amount >= 0) - { - if (parent != null && !parent.RemoveTokens(amount)) - return false; - - content -= amount; - return true; - } - else - { - return false; - } + // Deposit the overflow in the parent bucket, this is how we share + // unused bandwidth + Int64 burstrate = BurstRate; + if (m_tokenCount > burstrate) + m_tokenCount = burstrate; } /// @@ -186,37 +286,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// call to Drip /// /// True if tokens were added to the bucket, otherwise false - public bool Drip() + private void Drip() { - if (tokensPerMS == 0) + // This should never happen... means we are a leaf node and were created + // with no drip rate... + if (DripRate == 0) { - content = maxBurst; - return true; + m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0"); + return; } - else - { - int now = Environment.TickCount & Int32.MaxValue; - int deltaMS = now - lastDrip; + + // Determine the interval over which we are adding tokens, never add + // more than a single quantum of tokens + Int32 now = Environment.TickCount & Int32.MaxValue; + Int32 deltaMS = Math.Min(now - m_lastDrip, m_ticksPerQuantum); - if (deltaMS <= 0) - { - if (deltaMS < 0) - lastDrip = now; - return false; - } + m_lastDrip = now; - int dripAmount = deltaMS * tokensPerMS; + // This can be 0 in the very unusual case that the timer wrapped + // It can be 0 if we try add tokens at a sub-tick rate + if (deltaMS <= 0) + return; - content = Math.Min(content + dripAmount, maxBurst); - lastDrip = now; - - if (dripAmount < 0 || content < 0) - // sim has been idle for too long, integer has overflown - // previous calculation is meaningless, let's put it at correct max - content = maxBurst; - - return true; - } + Deposit(deltaMS * DripRate / m_ticksPerQuantum); } } } From 3fe22126ca3974b2a10365121ee0141fb54806e6 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 12:36:36 -0700 Subject: [PATCH 13/16] First pass at moving object property requests into a queue similar to the entity update queue. The number of property packets can become significant when selecting/deselecting large numbers of objects. This is experimental code. --- .../Client/MXP/ClientStack/MXPClientView.cs | 4 +- .../VWoHTTP/ClientStack/VWHClientView.cs | 4 +- OpenSim/Framework/IClientAPI.cs | 37 +- .../ClientStack/LindenUDP/LLClientView.cs | 367 +++++++++++------- .../ClientStack/LindenUDP/PriorityQueue.cs | 12 +- .../Examples/SimpleModule/MyNpcCharacter.cs | 12 +- .../Framework/Scenes/SceneObjectGroup.cs | 10 +- .../Framework/Scenes/SceneObjectPart.cs | 10 +- .../Server/IRCClientView.cs | 5 +- .../OptionalModules/World/NPC/NPCAvatar.cs | 12 +- OpenSim/Tests/Common/Mock/TestClient.cs | 11 +- 11 files changed, 269 insertions(+), 215 deletions(-) diff --git a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs index d1a0440524..a604a2ee63 100644 --- a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs +++ b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs @@ -1337,12 +1337,12 @@ namespace OpenSim.Client.MXP.ClientStack // Need to translate to MXP somehow } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { //throw new System.NotImplementedException(); } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { //throw new System.NotImplementedException(); } diff --git a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs index fc27f0198b..d8cd0acbd9 100644 --- a/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs +++ b/OpenSim/Client/VWoHTTP/ClientStack/VWHClientView.cs @@ -884,12 +884,12 @@ namespace OpenSim.Client.VWoHTTP.ClientStack throw new System.NotImplementedException(); } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { throw new System.NotImplementedException(); } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { throw new System.NotImplementedException(); } diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 5bf0b7b0a9..c56a756314 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -570,16 +570,30 @@ namespace OpenSim.Framework public float dwell; } - public class EntityUpdate + public class IEntityUpdate { public ISceneEntity Entity; - public PrimUpdateFlags Flags; - public float TimeDilation; + public uint Flags; - public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation) + public IEntityUpdate(ISceneEntity entity, uint flags) { Entity = entity; Flags = flags; + } + } + + + public class EntityUpdate : IEntityUpdate + { + // public ISceneEntity Entity; + // public PrimUpdateFlags Flags; + public float TimeDilation; + + public EntityUpdate(ISceneEntity entity, PrimUpdateFlags flags, float timedilation) + : base(entity,(uint)flags) + { + //Entity = entity; + // Flags = flags; TimeDilation = timedilation; } } @@ -1211,20 +1225,9 @@ namespace OpenSim.Framework /// void SendSimStats(SimStats stats); - void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, - uint Category, - UUID LastOwnerID, string ObjectName, string Description); + void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags); - void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, - UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, - string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, - uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice); + void SendObjectPropertiesReply(ISceneEntity Entity); void SendAgentOffline(UUID[] agentIDs); diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 5980669651..33b99095a2 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -386,6 +386,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_cachedTextureSerial; private PriorityQueue m_entityUpdates; + private PriorityQueue m_entityProps; private Prioritizer m_prioritizer; private bool m_disableFacelights = false; @@ -433,9 +434,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected IAssetService m_assetService; private const bool m_checkPackets = true; - private Timer m_propertiesPacketTimer; - private List m_propertiesBlocks = new List(); - #endregion Class Members #region Properties @@ -511,6 +509,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_scene = scene; m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); + m_entityProps = new PriorityQueue(m_scene.Entities.Count); m_fullUpdateDataBlocksBuilder = new List(); m_killRecord = new HashSet(); // m_attachmentsSent = new HashSet(); @@ -534,9 +533,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_udpClient.OnQueueEmpty += HandleQueueEmpty; m_udpClient.OnPacketStats += PopulateStats; - m_propertiesPacketTimer = new Timer(100); - m_propertiesPacketTimer.Elapsed += ProcessObjectPropertiesPacket; - m_prioritizer = new Prioritizer(m_scene); RegisterLocalPacketHandlers(); @@ -3636,9 +3632,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); } - private Int32 m_LastQueueFill = 0; - private uint m_maxUpdates = 0; - private void ProcessEntityUpdates(int maxUpdates) { OpenSim.Framework.Lazy> objectUpdateBlocks = new OpenSim.Framework.Lazy>(); @@ -3646,46 +3639,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP OpenSim.Framework.Lazy> terseUpdateBlocks = new OpenSim.Framework.Lazy>(); OpenSim.Framework.Lazy> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy>(); + // Check to see if this is a flush if (maxUpdates <= 0) { - m_maxUpdates = Int32.MaxValue; + maxUpdates = Int32.MaxValue; } - else - { - if (m_maxUpdates == 0 || m_LastQueueFill == 0) - { - m_maxUpdates = (uint)maxUpdates; - } - else - { - if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) - m_maxUpdates += 5; - else - m_maxUpdates = m_maxUpdates >> 1; - } - m_maxUpdates = Util.Clamp(m_maxUpdates,10,500); - } - m_LastQueueFill = Util.EnvironmentTickCount(); - + int updatesThisCall = 0; -// -// DEBUGGING CODE... REMOVE -// LogQueueProcessEvent(this.m_agentId,m_entityUpdates,m_maxUpdates); -// // We must lock for both manipulating the kill record and sending the packet, in order to avoid a race // condition where a kill can be processed before an out-of-date update for the same object. lock (m_killRecord) { float avgTimeDilation = 1.0f; - EntityUpdate update; + IEntityUpdate iupdate; Int32 timeinqueue; // this is just debugging code & can be dropped later - while (updatesThisCall < m_maxUpdates) + while (updatesThisCall < maxUpdates) { lock (m_entityUpdates.SyncRoot) - if (!m_entityUpdates.TryDequeue(out update, out timeinqueue)) + if (!m_entityUpdates.TryDequeue(out iupdate, out timeinqueue)) break; + + EntityUpdate update = (EntityUpdate)iupdate; + avgTimeDilation += update.TimeDilation; avgTimeDilation *= 0.5f; @@ -3725,7 +3702,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region UpdateFlags to packet type conversion - PrimUpdateFlags updateFlags = update.Flags; + PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags; bool canUseCompressed = true; bool canUseImproved = true; @@ -3804,6 +3781,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion Block Construction } + #region Packet Sending @@ -3904,12 +3882,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion Primitive Packet/Data Sending Methods + // These are used to implement an adaptive backoff in the number + // of updates converted to packets. Since we don't want packets + // to sit in the queue with old data, only convert enough updates + // to packets that can be sent in 200ms. + private Int32 m_LastQueueFill = 0; + private Int32 m_maxUpdates = 0; + void HandleQueueEmpty(ThrottleOutPacketTypeFlags categories) { if ((categories & ThrottleOutPacketTypeFlags.Task) != 0) { + if (m_maxUpdates == 0 || m_LastQueueFill == 0) + { + m_maxUpdates = m_udpServer.PrimUpdatesPerCallback; + } + else + { + if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200) + m_maxUpdates += 5; + else + m_maxUpdates = m_maxUpdates >> 1; + } + m_maxUpdates = Util.Clamp(m_maxUpdates,10,500); + m_LastQueueFill = Util.EnvironmentTickCount(); + if (m_entityUpdates.Count > 0) - ProcessEntityUpdates(m_udpServer.PrimUpdatesPerCallback); + ProcessEntityUpdates(m_maxUpdates); + + if (m_entityProps.Count > 0) + ProcessEntityPropertyRequests(m_maxUpdates); } if ((categories & ThrottleOutPacketTypeFlags.Texture) != 0) @@ -4023,47 +4025,147 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(pack, ThrottleOutPacketType.Task); } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) +/// ----------------------------------------------------------------- +/// +/// ----------------------------------------------------------------- + + private class ObjectPropertyUpdate : IEntityUpdate { - ObjectPropertiesFamilyPacket objPropFamilyPack = (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); - // TODO: don't create new blocks if recycling an old packet - - ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); - objPropDB.RequestFlags = RequestFlags; - objPropDB.ObjectID = ObjectUUID; - if (OwnerID == GroupID) - objPropDB.OwnerID = UUID.Zero; - else - objPropDB.OwnerID = OwnerID; - objPropDB.GroupID = GroupID; - objPropDB.BaseMask = BaseMask; - objPropDB.OwnerMask = OwnerMask; - objPropDB.GroupMask = GroupMask; - objPropDB.EveryoneMask = EveryoneMask; - objPropDB.NextOwnerMask = NextOwnerMask; - - // TODO: More properties are needed in SceneObjectPart! - objPropDB.OwnershipCost = OwnershipCost; - objPropDB.SaleType = SaleType; - objPropDB.SalePrice = SalePrice; - objPropDB.Category = Category; - objPropDB.LastOwnerID = LastOwnerID; - objPropDB.Name = Util.StringToBytes256(ObjectName); - objPropDB.Description = Util.StringToBytes256(Description); - objPropFamilyPack.ObjectData = objPropDB; - objPropFamilyPack.Header.Zerocoded = true; - OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task); + internal bool SendFamilyProps; + + public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam) + : base(entity,flags) + { + SendFamilyProps = sendfam; + } + } + + public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags) + { + uint priority = m_prioritizer.GetUpdatePriority(this, entity); + lock (m_entityProps.SyncRoot) + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true)); } - public void SendObjectPropertiesReply( - UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) + { + uint priority = m_prioritizer.GetUpdatePriority(this, entity); + lock (m_entityProps.SyncRoot) + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false)); + } + + private void ProcessEntityPropertyRequests(int maxUpdates) + { + OpenSim.Framework.Lazy> objectFamilyBlocks = + new OpenSim.Framework.Lazy>(); + + OpenSim.Framework.Lazy> objectPropertiesBlocks = + new OpenSim.Framework.Lazy>(); + + IEntityUpdate iupdate; + Int32 timeinqueue; // this is just debugging code & can be dropped later + + int updatesThisCall = 0; + while (updatesThisCall < m_maxUpdates) + { + lock (m_entityProps.SyncRoot) + if (!m_entityProps.TryDequeue(out iupdate, out timeinqueue)) + break; + + ObjectPropertyUpdate update = (ObjectPropertyUpdate)iupdate; + if (update.SendFamilyProps) + { + if (update.Entity is SceneObjectPart) + { + SceneObjectPart sop = (SceneObjectPart)update.Entity; + ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); + objectFamilyBlocks.Value.Add(objPropDB); + } + } + else + { + if (update.Entity is SceneObjectPart) + { + SceneObjectPart sop = (SceneObjectPart)update.Entity; + ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); + objectPropertiesBlocks.Value.Add(objPropDB); + } + } + } + + + if (objectPropertiesBlocks.IsValueCreated) + { + List blocks = objectPropertiesBlocks.Value; + + ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); + packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; + for (int i = 0; i < blocks.Count; i++) + packet.ObjectData[i] = blocks[i]; + + packet.Header.Zerocoded = true; + OutPacket(packet, ThrottleOutPacketType.Task, true); + } + + + if (objectFamilyBlocks.IsValueCreated) + { + List blocks = objectFamilyBlocks.Value; + + // ObjectPropertiesFamilyPacket objPropFamilyPack = + // (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); + // + // objPropFamilyPack.ObjectData = new ObjectPropertiesFamilyPacket.ObjectDataBlock[blocks.Count]; + // for (int i = 0; i < blocks.Count; i++) + // objPropFamilyPack.ObjectData[i] = blocks[i]; + // + // OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task, true); + + // one packet per object block... uggh... + for (int i = 0; i < blocks.Count; i++) + { + ObjectPropertiesFamilyPacket packet = + (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); + + packet.ObjectData = blocks[i]; + packet.Header.Zerocoded = true; + OutPacket(packet, ThrottleOutPacketType.Task); + } + + } + + } + + private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) + { + ObjectPropertiesFamilyPacket.ObjectDataBlock block = new ObjectPropertiesFamilyPacket.ObjectDataBlock(); + + block.RequestFlags = requestFlags; + block.ObjectID = sop.UUID; + if (sop.OwnerID == sop.GroupID) + block.OwnerID = UUID.Zero; + else + block.OwnerID = sop.OwnerID; + block.GroupID = sop.GroupID; + block.BaseMask = sop.BaseMask; + block.OwnerMask = sop.OwnerMask; + block.GroupMask = sop.GroupMask; + block.EveryoneMask = sop.EveryoneMask; + block.NextOwnerMask = sop.NextOwnerMask; + + // TODO: More properties are needed in SceneObjectPart! + block.OwnershipCost = sop.OwnershipCost; + block.SaleType = sop.ObjectSaleType; + block.SalePrice = sop.SalePrice; + block.Category = sop.Category; + block.LastOwnerID = sop.CreatorID; // copied from old SOG call... is this right? + block.Name = Util.StringToBytes256(sop.Name); + block.Description = Util.StringToBytes256(sop.Description); + + return block; + } + + private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) { //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); // TODO: don't create new blocks if recycling an old packet @@ -4071,85 +4173,43 @@ namespace OpenSim.Region.ClientStack.LindenUDP ObjectPropertiesPacket.ObjectDataBlock block = new ObjectPropertiesPacket.ObjectDataBlock(); - block.ItemID = ItemID; - block.CreationDate = CreationDate; - block.CreatorID = CreatorUUID; - block.FolderID = FolderUUID; - block.FromTaskID = FromTaskUUID; - block.GroupID = GroupUUID; - block.InventorySerial = InventorySerial; + block.ObjectID = sop.UUID; + block.Name = Util.StringToBytes256(sop.Name); + block.Description = Util.StringToBytes256(sop.Description); - block.LastOwnerID = LastOwnerUUID; - // proper.ObjectData[0].LastOwnerID = UUID.Zero; - - block.ObjectID = ObjectUUID; - if (OwnerUUID == GroupUUID) + block.CreationDate = (ulong)sop.CreationDate * 1000000; // viewer wants date in microseconds + block.CreatorID = sop.CreatorID; + block.GroupID = sop.GroupID; + block.LastOwnerID = sop.LastOwnerID; + if (sop.OwnerID == sop.GroupID) block.OwnerID = UUID.Zero; else - block.OwnerID = OwnerUUID; - block.TouchName = Util.StringToBytes256(TouchTitle); - block.TextureID = TextureID; - block.SitName = Util.StringToBytes256(SitTitle); - block.Name = Util.StringToBytes256(ItemName); - block.Description = Util.StringToBytes256(ItemDescription); - block.OwnerMask = OwnerMask; - block.NextOwnerMask = NextOwnerMask; - block.GroupMask = GroupMask; - block.EveryoneMask = EveryoneMask; - block.BaseMask = BaseMask; - // proper.ObjectData[0].AggregatePerms = 53; - // proper.ObjectData[0].AggregatePermTextures = 0; - // proper.ObjectData[0].AggregatePermTexturesOwner = 0; - block.SaleType = saleType; - block.SalePrice = salePrice; + block.OwnerID = sop.OwnerID; - lock (m_propertiesPacketTimer) - { - m_propertiesBlocks.Add(block); + block.ItemID = sop.FromUserInventoryItemID; + block.FolderID = UUID.Zero; // sop.FromFolderID ?? + block.FromTaskID = UUID.Zero; // ??? + block.InventorySerial = (short)sop.InventorySerial; + + SceneObjectPart root = sop.ParentGroup.RootPart; - int length = 0; - foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks) - { - length += b.Length; - } - if (length > 1100) // FIXME: use real MTU - { - ProcessObjectPropertiesPacket(null, null); - m_propertiesPacketTimer.Stop(); - return; - } + block.TouchName = Util.StringToBytes256(root.TouchName); + block.TextureID = new byte[0]; // TextureID ??? + block.SitName = Util.StringToBytes256(root.SitName); + block.OwnerMask = root.OwnerMask; + block.NextOwnerMask = root.NextOwnerMask; + block.GroupMask = root.GroupMask; + block.EveryoneMask = root.EveryoneMask; + block.BaseMask = root.BaseMask; + block.SaleType = root.ObjectSaleType; + block.SalePrice = root.SalePrice; - m_propertiesPacketTimer.Stop(); - m_propertiesPacketTimer.Start(); - } - - //proper.Header.Zerocoded = true; - //OutPacket(proper, ThrottleOutPacketType.Task); + return block; } - private void ProcessObjectPropertiesPacket(Object sender, ElapsedEventArgs e) - { - ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); - - lock (m_propertiesPacketTimer) - { - m_propertiesPacketTimer.Stop(); - - proper.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[m_propertiesBlocks.Count]; - - int index = 0; - - foreach (ObjectPropertiesPacket.ObjectDataBlock b in m_propertiesBlocks) - { - proper.ObjectData[index++] = b; - } - - m_propertiesBlocks.Clear(); - } - - proper.Header.Zerocoded = true; - OutPacket(proper, ThrottleOutPacketType.Task); - } +/// ----------------------------------------------------------------- +/// +/// ----------------------------------------------------------------- #region Estate Data Sending Methods @@ -4489,6 +4549,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SendForceClientSelectObjects(List ObjectIDs) { + m_log.WarnFormat("[LLCLIENTVIEW] sending select with {0} objects", ObjectIDs.Count); + bool firstCall = true; const int MAX_OBJECTS_PER_PACKET = 251; ForceObjectSelectPacket pack = (ForceObjectSelectPacket)PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect); @@ -11381,6 +11443,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); } + if (throttlePacketType == ThrottleOutPacketType.Task) + { + System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace(); // get call stack + System.Diagnostics.StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) + + string stack = ""; + for (int count = 1; count < stackFrames.Length; count++) + { + stack += (stack == "" ? "" : ",") + stackFrames[count].GetMethod().Name; + if (count > 5) break; + } + + // m_log.WarnFormat("[BADGUY] {0}", stack); + } + m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); } diff --git a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs index 364ce4ba9e..6521a00745 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs @@ -78,7 +78,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } - public bool Enqueue(uint pqueue, EntityUpdate value) + public bool Enqueue(uint pqueue, IEntityUpdate value) { LookupItem lookup; @@ -99,7 +99,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP return true; } - internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue) + internal bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue) { for (int i = 0; i < m_numberOfQueues; ++i) { @@ -122,7 +122,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } timeinqueue = 0; - value = default(EntityUpdate); + value = default(IEntityUpdate); return false; } @@ -175,8 +175,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region MinHeapItem private struct MinHeapItem : IComparable { - private EntityUpdate value; - internal EntityUpdate Value { + private IEntityUpdate value; + internal IEntityUpdate Value { get { return this.value; } @@ -212,7 +212,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP this.pqueue = pqueue; } - internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value) + internal MinHeapItem(uint pqueue, UInt64 entryorder, IEntityUpdate value) { this.entrytime = Util.EnvironmentTickCount(); this.entryorder = entryorder; diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index d939329814..89e9e204bb 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs @@ -702,18 +702,12 @@ namespace OpenSim.Region.Examples.SimpleModule { } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType,int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { + } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index ca7d9d9d57..30563d4232 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -1765,10 +1765,12 @@ namespace OpenSim.Region.Framework.Scenes /// public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) { - remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, - RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, - RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, - RootPart.CreatorID, RootPart.Name, RootPart.Description); + remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags); + +// remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, +// RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, +// RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, +// RootPart.CreatorID, RootPart.Name, RootPart.Description); } public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index ce1e6b8614..8a8a6993cc 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2055,15 +2055,7 @@ namespace OpenSim.Region.Framework.Scenes public void GetProperties(IClientAPI client) { - //Viewer wants date in microseconds so multiply it by 1,000,000. - client.SendObjectPropertiesReply( - m_fromUserInventoryItemID, (ulong)_creationDate*(ulong)1e6, _creatorID, UUID.Zero, UUID.Zero, - _groupID, (short)InventorySerial, _lastOwnerID, UUID, _ownerID, - ParentGroup.RootPart.TouchName, new byte[0], ParentGroup.RootPart.SitName, Name, Description, - ParentGroup.RootPart._ownerMask, ParentGroup.RootPart._nextOwnerMask, ParentGroup.RootPart._groupMask, ParentGroup.RootPart._everyoneMask, - ParentGroup.RootPart._baseMask, - ParentGroup.RootPart.ObjectSaleType, - ParentGroup.RootPart.SalePrice); + client.SendObjectPropertiesReply(this); } public UUID GetRootPartUUID() diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index 821cd4bd33..4b6e52e757 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -1332,14 +1332,13 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { - } public void SendAgentOffline(UUID[] agentIDs) diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 96760a2721..2504e3019c 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -786,18 +786,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType, int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { + } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index d1dc17fc9b..dca562674b 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -816,18 +816,11 @@ namespace OpenSim.Tests.Common.Mock { } - public void SendObjectPropertiesFamilyData(uint RequestFlags, UUID ObjectUUID, UUID OwnerID, UUID GroupID, - uint BaseMask, uint OwnerMask, uint GroupMask, uint EveryoneMask, - uint NextOwnerMask, int OwnershipCost, byte SaleType,int SalePrice, uint Category, - UUID LastOwnerID, string ObjectName, string Description) + public void SendObjectPropertiesFamilyData(ISceneEntity Entity, uint RequestFlags) { } - public void SendObjectPropertiesReply(UUID ItemID, ulong CreationDate, UUID CreatorUUID, UUID FolderUUID, UUID FromTaskUUID, - UUID GroupUUID, short InventorySerial, UUID LastOwnerUUID, UUID ObjectUUID, - UUID OwnerUUID, string TouchTitle, byte[] TextureID, string SitTitle, string ItemName, - string ItemDescription, uint OwnerMask, uint NextOwnerMask, uint GroupMask, uint EveryoneMask, - uint BaseMask, byte saleType, int salePrice) + public void SendObjectPropertiesReply(ISceneEntity entity) { } From 5e7aba4f88a90e266e01b5509c4ba04730815475 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 14:40:57 -0700 Subject: [PATCH 14/16] fixed a couple bugs with the property queues --- .../ClientStack/LindenUDP/LLClientView.cs | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 33b99095a2..f926c3532f 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -4091,9 +4091,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP objectPropertiesBlocks.Value.Add(objPropDB); } } + + updatesThisCall++; } + Int32 ppcnt = 0; + Int32 pbcnt = 0; + if (objectPropertiesBlocks.IsValueCreated) { List blocks = objectPropertiesBlocks.Value; @@ -4105,9 +4110,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP packet.Header.Zerocoded = true; OutPacket(packet, ThrottleOutPacketType.Task, true); + + pbcnt += blocks.Count; + ppcnt++; } + Int32 fpcnt = 0; + Int32 fbcnt = 0; + if (objectFamilyBlocks.IsValueCreated) { List blocks = objectFamilyBlocks.Value; @@ -4130,10 +4141,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP packet.ObjectData = blocks[i]; packet.Header.Zerocoded = true; OutPacket(packet, ThrottleOutPacketType.Task); + + fpcnt++; + fbcnt++; } } + m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); + m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); } private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) @@ -11408,6 +11424,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(packet, throttlePacketType, true); } +/// + Dictionary pktsrc = new Dictionary(); + uint pktcnt = 0; +/// + /// /// This is the starting point for sending a simulator packet out to the client /// @@ -11455,7 +11476,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (count > 5) break; } - // m_log.WarnFormat("[BADGUY] {0}", stack); + lock(pktsrc) + { + if (! pktsrc.ContainsKey(stack)) + pktsrc.Add(stack,0); + pktsrc[stack]++; + + if (++pktcnt > 500) + { + pktcnt = 0; + m_log.WarnFormat("[PACKETCOUNTS] START"); + foreach (KeyValuePair pkt in pktsrc) + m_log.WarnFormat("[PACKETCOUNTS] {0,8}, {1}", pkt.Value, pkt.Key); + pktsrc.Clear(); + m_log.WarnFormat("[PACKETCOUNTS] END"); + } + } } m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); From b33aac737a3e7ae28216cb98de99d9c6eba1d563 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 15:40:57 -0700 Subject: [PATCH 15/16] Fixed the update of items in the priority queue to enable both types of property updates to be specified. Not sure if one form of property update should supercede another. But for now the old OpenSim behavior is preserved by sending both. --- OpenSim/Framework/IClientAPI.cs | 5 +++++ .../ClientStack/LindenUDP/LLClientView.cs | 21 +++++++++++++------ .../ClientStack/LindenUDP/PriorityQueue.cs | 2 +- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index c56a756314..f573c32d07 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -575,6 +575,11 @@ namespace OpenSim.Framework public ISceneEntity Entity; public uint Flags; + public virtual void Update(IEntityUpdate update) + { + this.Flags |= update.Flags; + } + public IEntityUpdate(ISceneEntity entity, uint flags) { Entity = entity; diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index f926c3532f..a6f2d09bb1 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -4032,26 +4032,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP private class ObjectPropertyUpdate : IEntityUpdate { internal bool SendFamilyProps; + internal bool SendObjectProps; - public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam) + public ObjectPropertyUpdate(ISceneEntity entity, uint flags, bool sendfam, bool sendobj) : base(entity,flags) { SendFamilyProps = sendfam; + SendObjectProps = sendobj; + } + public void Update(ObjectPropertyUpdate update) + { + SendFamilyProps = SendFamilyProps || update.SendFamilyProps; + SendObjectProps = SendObjectProps || update.SendObjectProps; + Flags |= update.Flags; } } public void SendObjectPropertiesFamilyData(ISceneEntity entity, uint requestFlags) { - uint priority = m_prioritizer.GetUpdatePriority(this, entity); + uint priority = 0; // time based ordering only lock (m_entityProps.SyncRoot) - m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true)); + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); } public void SendObjectPropertiesReply(ISceneEntity entity) { - uint priority = m_prioritizer.GetUpdatePriority(this, entity); + uint priority = 0; // time based ordering only lock (m_entityProps.SyncRoot) - m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false)); + m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true)); } private void ProcessEntityPropertyRequests(int maxUpdates) @@ -4082,7 +4090,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP objectFamilyBlocks.Value.Add(objPropDB); } } - else + + if (update.SendObjectProps) { if (update.Entity is SceneObjectPart) { diff --git a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs index 6521a00745..b62ec07ed9 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs @@ -87,7 +87,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (m_lookupTable.TryGetValue(localid, out lookup)) { entry = lookup.Heap[lookup.Handle].EntryOrder; - value.Flags |= lookup.Heap[lookup.Handle].Value.Flags; + value.Update(lookup.Heap[lookup.Handle].Value); lookup.Heap.Remove(lookup.Handle); } From bf91d1b07784f3c03744efd2d6dea1b621620cce Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 12 Apr 2011 15:55:21 -0700 Subject: [PATCH 16/16] remove packet monitoring debugging code --- .../ClientStack/LindenUDP/LLClientView.cs | 118 +----------------- 1 file changed, 2 insertions(+), 116 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index a6f2d09bb1..613a921b4d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -300,77 +300,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Used to adjust Sun Orbit values so Linden based viewers properly position sun private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; - // First log file or time has expired, start writing to a new log file -// -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// THIS IS DEBUGGING CODE & SHOULD BE REMOVED -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- - public class QueueLogger - { - public Int32 start = 0; - public StreamWriter Log = null; - private Dictionary m_idMap = new Dictionary(); - - public QueueLogger() - { - DateTime now = DateTime.Now; - String fname = String.Format("queue-{0}.log", now.ToString("yyyyMMddHHmmss")); - Log = new StreamWriter(fname); - - start = Util.EnvironmentTickCount(); - } - - public int LookupID(UUID uuid) - { - int localid; - if (! m_idMap.TryGetValue(uuid,out localid)) - { - localid = m_idMap.Count + 1; - m_idMap[uuid] = localid; - } - - return localid; - } - } - - public static QueueLogger QueueLog = null; - - // ----------------------------------------------------------------- - public void LogAvatarUpdateEvent(UUID client, UUID avatar, Int32 timeinqueue) - { - if (QueueLog == null) - QueueLog = new QueueLogger(); - - Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); - lock(QueueLog) - { - int cid = QueueLog.LookupID(client); - int aid = QueueLog.LookupID(avatar); - QueueLog.Log.WriteLine("{0},AU,AV{1:D4},AV{2:D4},{3}",ticks,cid,aid,timeinqueue); - } - } - - // ----------------------------------------------------------------- - public void LogQueueProcessEvent(UUID client, PriorityQueue queue, uint maxup) - { - if (QueueLog == null) - QueueLog = new QueueLogger(); - - Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start); - lock(QueueLog) - { - int cid = QueueLog.LookupID(client); - QueueLog.Log.WriteLine("{0},PQ,AV{1:D4},{2},{3}",ticks,cid,maxup,queue.ToString()); - } - } -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// ----------------------------------------------------------------- -// - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected static Dictionary PacketHandlers = new Dictionary(); //Global/static handlers for all clients @@ -4025,10 +3954,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(pack, ThrottleOutPacketType.Task); } -/// ----------------------------------------------------------------- -/// -/// ----------------------------------------------------------------- - private class ObjectPropertyUpdate : IEntityUpdate { internal bool SendFamilyProps; @@ -4157,8 +4082,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP } - m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); - m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); + // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); + // m_log.WarnFormat("[PACKETCOUNTS] queued {0} family property packets with {1} blocks",fpcnt,fbcnt); } private ObjectPropertiesFamilyPacket.ObjectDataBlock CreateObjectPropertiesFamilyBlock(SceneObjectPart sop, uint requestFlags) @@ -4232,10 +4157,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP return block; } -/// ----------------------------------------------------------------- -/// -/// ----------------------------------------------------------------- - #region Estate Data Sending Methods private static bool convertParamStringToBool(byte[] field) @@ -11433,11 +11354,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(packet, throttlePacketType, true); } -/// - Dictionary pktsrc = new Dictionary(); - uint pktcnt = 0; -/// - /// /// This is the starting point for sending a simulator packet out to the client /// @@ -11472,36 +11388,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (logPacket) m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); } - - if (throttlePacketType == ThrottleOutPacketType.Task) - { - System.Diagnostics.StackTrace stackTrace = new System.Diagnostics.StackTrace(); // get call stack - System.Diagnostics.StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) - - string stack = ""; - for (int count = 1; count < stackFrames.Length; count++) - { - stack += (stack == "" ? "" : ",") + stackFrames[count].GetMethod().Name; - if (count > 5) break; - } - - lock(pktsrc) - { - if (! pktsrc.ContainsKey(stack)) - pktsrc.Add(stack,0); - pktsrc[stack]++; - - if (++pktcnt > 500) - { - pktcnt = 0; - m_log.WarnFormat("[PACKETCOUNTS] START"); - foreach (KeyValuePair pkt in pktsrc) - m_log.WarnFormat("[PACKETCOUNTS] {0,8}, {1}", pkt.Value, pkt.Key); - pktsrc.Clear(); - m_log.WarnFormat("[PACKETCOUNTS] END"); - } - } - } m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); }