diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 30132770e8..b1c34525a1 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -143,7 +143,11 @@ what it is today. * sempuki * SignpostMarv * SpotOn3D +* Stefan_Boom / stoehr * Strawberry Fride +* Talun +* TechplexEngineer (Blake Bourque) +* TBG Renfold * tglion * tlaukkan/Tommil (Tommi S. E. Laukkanen, Bubble Cloud) * tyre @@ -202,3 +206,4 @@ In addition, we would like to thank: * The Mono Project * The NANT Developers * Microsoft (.NET, MSSQL-Adapters) +*x diff --git a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs index 45b8d6f4b9..00657028e4 100644 --- a/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs +++ b/OpenSim/ApplicationPlugins/LoadRegions/LoadRegionsPlugin.cs @@ -122,9 +122,10 @@ namespace OpenSim.ApplicationPlugins.LoadRegions Thread.CurrentThread.ManagedThreadId.ToString() + ")"); - m_openSim.PopulateRegionEstateInfo(regionsToLoad[i]); + bool changed = m_openSim.PopulateRegionEstateInfo(regionsToLoad[i]); m_openSim.CreateRegion(regionsToLoad[i], true, out scene); - regionsToLoad[i].EstateSettings.Save(); + if (changed) + regionsToLoad[i].EstateSettings.Save(); if (scene != null) { diff --git a/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs b/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs index db62d52438..cb88695600 100644 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs +++ b/OpenSim/ApplicationPlugins/Rest/Inventory/RestHandler.cs @@ -539,7 +539,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory /// path has not already been registered, the method is added to the active /// handler table. /// - public void AddStreamHandler(string httpMethod, string path, RestMethod method) { if (!IsEnabled) diff --git a/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs b/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs index 717a097c70..c0ca1e1896 100644 --- a/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs +++ b/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2Handler.cs @@ -101,18 +101,8 @@ namespace OpenSim.Capabilities.Handlers llsdItem.item_id = invItem.ID; llsdItem.name = invItem.Name; llsdItem.parent_id = invItem.Folder; - - try - { - llsdItem.type = Utils.AssetTypeToString((AssetType)invItem.AssetType); - llsdItem.inv_type = Utils.InventoryTypeToString((InventoryType)invItem.InvType); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[WEB FETCH INV DESC HANDLER]: Problem setting asset {0} inventory {1} types while converting inventory item {2}: {3}", - invItem.AssetType, invItem.InvType, invItem.Name, e.Message); - } + llsdItem.type = invItem.AssetType; + llsdItem.inv_type = invItem.InvType; llsdItem.permissions = new LLSDPermissions(); llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid; @@ -126,21 +116,7 @@ namespace OpenSim.Capabilities.Handlers llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions; llsdItem.sale_info = new LLSDSaleInfo(); llsdItem.sale_info.sale_price = invItem.SalePrice; - switch (invItem.SaleType) - { - default: - llsdItem.sale_info.sale_type = "not"; - break; - case 1: - llsdItem.sale_info.sale_type = "original"; - break; - case 2: - llsdItem.sale_info.sale_type = "copy"; - break; - case 3: - llsdItem.sale_info.sale_type = "contents"; - break; - } + llsdItem.sale_info.sale_type = invItem.SaleType; return llsdItem; } diff --git a/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2ServerConnector.cs b/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2ServerConnector.cs index 0ba89315e1..5bab52fe94 100644 --- a/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2ServerConnector.cs +++ b/OpenSim/Capabilities/Handlers/FetchInventory2/FetchInventory2ServerConnector.cs @@ -63,7 +63,8 @@ namespace OpenSim.Capabilities.Handlers FetchInventory2Handler fiHandler = new FetchInventory2Handler(m_InventoryService); IRequestHandler reqHandler - = new RestStreamHandler("POST", "/CAPS/FetchInventory/", fiHandler.FetchInventoryRequest); + = new RestStreamHandler( + "POST", "/CAPS/FetchInventory/", fiHandler.FetchInventoryRequest, "FetchInventory", null); server.AddStreamHandler(reqHandler); } } diff --git a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshServerConnector.cs b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshServerConnector.cs index 2ecfa3c23b..8a275f3f5e 100644 --- a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshServerConnector.cs +++ b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshServerConnector.cs @@ -66,13 +66,14 @@ namespace OpenSim.Capabilities.Handlers throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName)); GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService); - IRequestHandler reqHandler = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), - delegate(Hashtable m_dhttpMethod) - { - return gmeshHandler.ProcessGetMesh(m_dhttpMethod, UUID.Zero, null); - }); + IRequestHandler reqHandler + = new RestHTTPHandler( + "GET", + "/CAPS/" + UUID.Random(), + httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null), + "GetMesh", + null); server.AddStreamHandler(reqHandler); } - } -} +} \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs index 0797215b77..f040ff78e0 100644 --- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs +++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs @@ -58,8 +58,8 @@ namespace OpenSim.Capabilities.Handlers // TODO: Change this to a config option const string REDIRECT_URL = null; - public GetTextureHandler(string path, IAssetService assService) : - base("GET", path) + public GetTextureHandler(string path, IAssetService assService, string name, string description) + : base("GET", path, name, description) { m_assetService = assService; } @@ -77,7 +77,6 @@ namespace OpenSim.Capabilities.Handlers { m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service"); httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound; - return null; } UUID textureID; @@ -115,7 +114,6 @@ namespace OpenSim.Capabilities.Handlers // "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}", // textureID, httpResponse.StatusCode, httpResponse.ContentLength); - httpResponse.Send(); return null; } diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureServerConnector.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureServerConnector.cs index 0d072f71ff..71cf033437 100644 --- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureServerConnector.cs +++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureServerConnector.cs @@ -62,8 +62,8 @@ namespace OpenSim.Capabilities.Handlers if (m_AssetService == null) throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName)); - server.AddStreamHandler(new GetTextureHandler("/CAPS/GetTexture/" /*+ UUID.Random() */, m_AssetService)); + server.AddStreamHandler( + new GetTextureHandler("/CAPS/GetTexture/" /*+ UUID.Random() */, m_AssetService, "GetTexture", null)); } - } -} +} \ No newline at end of file diff --git a/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs b/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs index fd152c35d2..761e4e7564 100644 --- a/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs +++ b/OpenSim/Capabilities/Handlers/GetTexture/Tests/GetTextureHandlerTests.cs @@ -50,9 +50,9 @@ namespace OpenSim.Capabilities.Handlers.GetTexture.Tests TestHelpers.InMethod(); // Overkill - we only really need the asset service, not a whole scene. - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); - GetTextureHandler handler = new GetTextureHandler(null, scene.AssetService); + GetTextureHandler handler = new GetTextureHandler(null, scene.AssetService, "TestGetTexture", null); TestOSHttpRequest req = new TestOSHttpRequest(); TestOSHttpResponse resp = new TestOSHttpResponse(); req.Url = new Uri("http://localhost/?texture_id=00000000-0000-1111-9999-000000000012"); diff --git a/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureHandler.cs b/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureHandler.cs index 594ce9dad9..8849a59ce3 100644 --- a/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureHandler.cs +++ b/OpenSim/Capabilities/Handlers/UploadBakedTexture/UploadBakedTextureHandler.cs @@ -85,8 +85,8 @@ namespace OpenSim.Capabilities.Handlers uploader.OnUpLoad += BakedTextureUploaded; m_HostCapsObj.HttpListener.AddStreamHandler( - new BinaryStreamHandler("POST", capsBase + uploaderPath, - uploader.uploaderCaps)); + new BinaryStreamHandler( + "POST", capsBase + uploaderPath, uploader.uploaderCaps, "UploadBakedTexture", null)); string protocol = "http://"; diff --git a/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs index d5c062b831..9a6ca8640a 100644 --- a/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs +++ b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescHandler.cs @@ -156,11 +156,12 @@ namespace OpenSim.Capabilities.Handlers inv.Folders = new List(); inv.Items = new List(); int version = 0; + int descendents = 0; inv = Fetch( invFetch.owner_id, invFetch.folder_id, invFetch.owner_id, - invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version); + invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version, out descendents); if (inv != null && inv.Folders != null) { @@ -168,6 +169,8 @@ namespace OpenSim.Capabilities.Handlers { contents.categories.Array.Add(ConvertInventoryFolder(invFolder)); } + + descendents += inv.Folders.Count; } if (inv != null && inv.Items != null) @@ -178,7 +181,7 @@ namespace OpenSim.Capabilities.Handlers } } - contents.descendents = contents.items.Array.Count + contents.categories.Array.Count; + contents.descendents = descendents; contents.version = version; // m_log.DebugFormat( @@ -206,7 +209,7 @@ namespace OpenSim.Capabilities.Handlers /// An empty InventoryCollection if the inventory look up failed private InventoryCollection Fetch( UUID agentID, UUID folderID, UUID ownerID, - bool fetchFolders, bool fetchItems, int sortOrder, out int version) + bool fetchFolders, bool fetchItems, int sortOrder, out int version, out int descendents) { // m_log.DebugFormat( // "[WEB FETCH INV DESC HANDLER]: Fetching folders ({0}), items ({1}) from {2} for agent {3}", @@ -215,6 +218,8 @@ namespace OpenSim.Capabilities.Handlers // FIXME MAYBE: We're not handling sortOrder! version = 0; + descendents = 0; + InventoryFolderImpl fold; if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null && agentID == m_LibraryService.LibraryRootFolder.Owner) { @@ -223,6 +228,7 @@ namespace OpenSim.Capabilities.Handlers InventoryCollection ret = new InventoryCollection(); ret.Folders = new List(); ret.Items = fold.RequestListOfItems(); + descendents = ret.Folders.Count + ret.Items.Count; return ret; } @@ -246,24 +252,72 @@ namespace OpenSim.Capabilities.Handlers version = containingFolder.Version; -// if (fetchItems) + if (fetchItems) + { + List itemsToReturn = contents.Items; + List originalItems = new List(itemsToReturn); + + // descendents must only include the links, not the linked items we add + descendents = originalItems.Count; + + // Add target items for links in this folder before the links themselves. + foreach (InventoryItemBase item in originalItems) + { + if (item.AssetType == (int)AssetType.Link) + { + InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID)); + + // Take care of genuinely broken links where the target doesn't exist + // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, + // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles + // rather than having to keep track of every folder requested in the recursion. + if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) + itemsToReturn.Insert(0, linkedItem); + } + } + + // Now scan for folder links and insert the items they target and those links at the head of the return data + foreach (InventoryItemBase item in originalItems) + { + if (item.AssetType == (int)AssetType.LinkFolder) + { + InventoryCollection linkedFolderContents = m_InventoryService.GetFolderContent(ownerID, item.AssetID); + List links = linkedFolderContents.Items; + + itemsToReturn.InsertRange(0, links); + + foreach (InventoryItemBase link in linkedFolderContents.Items) + { + // Take care of genuinely broken links where the target doesn't exist + // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, + // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles + // rather than having to keep track of every folder requested in the recursion. + if (link != null) + { +// m_log.DebugFormat( +// "[WEB FETCH INV DESC HANDLER]: Adding item {0} {1} from folder {2} linked from {3}", +// link.Name, (AssetType)link.AssetType, item.AssetID, containingFolder.Name); + + InventoryItemBase linkedItem + = m_InventoryService.GetItem(new InventoryItemBase(link.AssetID)); + + if (linkedItem != null) + itemsToReturn.Insert(0, linkedItem); + } + } + } + } + } + +// foreach (InventoryItemBase item in contents.Items) // { -// List linkedItemsToAdd = new List(); -// -// foreach (InventoryItemBase item in contents.Items) -// { -// if (item.AssetType == (int)AssetType.Link) -// { -// InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID)); -// -// // Take care of genuinely broken links where the target doesn't exist -// // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate, -// // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles -// // rather than having to keep track of every folder requested in the recursion. -// if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link) -// linkedItemsToAdd.Insert(0, linkedItem); -// } -// } +// m_log.DebugFormat( +// "[WEB FETCH INV DESC HANDLER]: Returning item {0}, type {1}, parent {2} in {3} {4}", +// item.Name, (AssetType)item.AssetType, item.Folder, containingFolder.Name, containingFolder.ID); +// } + + // ===== + // // foreach (InventoryItemBase linkedItem in linkedItemsToAdd) // { @@ -340,12 +394,8 @@ namespace OpenSim.Capabilities.Handlers llsdFolder.folder_id = invFolder.ID; llsdFolder.parent_id = invFolder.ParentID; llsdFolder.name = invFolder.Name; - - if (invFolder.Type == (short)AssetType.Unknown || !Enum.IsDefined(typeof(AssetType), (sbyte)invFolder.Type)) - llsdFolder.type = "-1"; - else - llsdFolder.type = Utils.AssetTypeToString((AssetType)invFolder.Type); - llsdFolder.preferred_type = "-1"; + llsdFolder.type = invFolder.Type; + llsdFolder.preferred_type = -1; return llsdFolder; } @@ -365,18 +415,8 @@ namespace OpenSim.Capabilities.Handlers llsdItem.item_id = invItem.ID; llsdItem.name = invItem.Name; llsdItem.parent_id = invItem.Folder; - - try - { - llsdItem.type = Utils.AssetTypeToString((AssetType)invItem.AssetType); - llsdItem.inv_type = Utils.InventoryTypeToString((InventoryType)invItem.InvType); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[WEB FETCH INV DESC HANDLER]: Problem setting asset {0} inventory {1} types while converting inventory item {2}: {3}", - invItem.AssetType, invItem.InvType, invItem.Name, e.Message); - } + llsdItem.type = invItem.AssetType; + llsdItem.inv_type = invItem.InvType; llsdItem.permissions = new LLSDPermissions(); llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid; @@ -390,21 +430,7 @@ namespace OpenSim.Capabilities.Handlers llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions; llsdItem.sale_info = new LLSDSaleInfo(); llsdItem.sale_info.sale_price = invItem.SalePrice; - switch (invItem.SaleType) - { - default: - llsdItem.sale_info.sale_type = "not"; - break; - case 1: - llsdItem.sale_info.sale_type = "original"; - break; - case 2: - llsdItem.sale_info.sale_type = "copy"; - break; - case 3: - llsdItem.sale_info.sale_type = "contents"; - break; - } + llsdItem.sale_info.sale_type = invItem.SaleType; return llsdItem; } diff --git a/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescServerConnector.cs b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescServerConnector.cs index 92eeb140d0..5d86557dc3 100644 --- a/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescServerConnector.cs +++ b/OpenSim/Capabilities/Handlers/WebFetchInventoryDescendents/WebFetchInvDescServerConnector.cs @@ -68,7 +68,13 @@ namespace OpenSim.Capabilities.Handlers ServerUtils.LoadPlugin(libService, args); WebFetchInvDescHandler webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService); - IRequestHandler reqHandler = new RestStreamHandler("POST", "/CAPS/WebFetchInvDesc/" /*+ UUID.Random()*/, webFetchHandler.FetchInventoryDescendentsRequest); + IRequestHandler reqHandler + = new RestStreamHandler( + "POST", + "/CAPS/WebFetchInvDesc/" /*+ UUID.Random()*/, + webFetchHandler.FetchInventoryDescendentsRequest, + "WebFetchInvDesc", + null); server.AddStreamHandler(reqHandler); } diff --git a/OpenSim/Capabilities/LLSDEnvironmentSettings.cs b/OpenSim/Capabilities/LLSDEnvironmentSettings.cs new file mode 100644 index 0000000000..39019af22c --- /dev/null +++ b/OpenSim/Capabilities/LLSDEnvironmentSettings.cs @@ -0,0 +1,68 @@ +/* + * 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 OpenMetaverse; + +namespace OpenSim.Framework.Capabilities +{ + [OSDMap] + public class LLSDEnvironmentRequest + { + public UUID messageID; + public UUID regionID; + } + + [OSDMap] + public class LLSDEnvironmentSetResponse + { + public UUID regionID; + public UUID messageID; + public Boolean success; + public String fail_reason; + } + + public class EnvironmentSettings + { + /// + /// generates a empty llsd settings response for viewer + /// + /// the message UUID + /// the region UUID + public static string EmptySettings(UUID messageID, UUID regionID) + { + OSDArray arr = new OSDArray(); + LLSDEnvironmentRequest msg = new LLSDEnvironmentRequest(); + msg.messageID = messageID; + msg.regionID = regionID; + arr.Array.Add(msg); + return LLSDHelpers.SerialiseLLSDReply(arr); + } + } + +} diff --git a/OpenSim/Capabilities/LLSDInventoryFolder.cs b/OpenSim/Capabilities/LLSDInventoryFolder.cs index 3c216e9c15..d085430e8a 100644 --- a/OpenSim/Capabilities/LLSDInventoryFolder.cs +++ b/OpenSim/Capabilities/LLSDInventoryFolder.cs @@ -35,7 +35,7 @@ namespace OpenSim.Framework.Capabilities public UUID folder_id; public UUID parent_id; public string name; - public string type; - public string preferred_type; + public int type; + public int preferred_type; } } diff --git a/OpenSim/Capabilities/LLSDInventoryItem.cs b/OpenSim/Capabilities/LLSDInventoryItem.cs index 426a6cbaf5..958e8079b4 100644 --- a/OpenSim/Capabilities/LLSDInventoryItem.cs +++ b/OpenSim/Capabilities/LLSDInventoryItem.cs @@ -37,8 +37,8 @@ namespace OpenSim.Framework.Capabilities public UUID asset_id; public UUID item_id; public LLSDPermissions permissions; - public string type; - public string inv_type; + public int type; + public int inv_type; public int flags; public LLSDSaleInfo sale_info; @@ -65,7 +65,7 @@ namespace OpenSim.Framework.Capabilities public class LLSDSaleInfo { public int sale_price; - public string sale_type; + public int sale_type; } [OSDMap] diff --git a/OpenSim/Capabilities/LLSDStreamHandler.cs b/OpenSim/Capabilities/LLSDStreamHandler.cs index c7c1fc93db..5df24b2cc1 100644 --- a/OpenSim/Capabilities/LLSDStreamHandler.cs +++ b/OpenSim/Capabilities/LLSDStreamHandler.cs @@ -39,7 +39,11 @@ namespace OpenSim.Framework.Capabilities private LLSDMethod m_method; public LLSDStreamhandler(string httpMethod, string path, LLSDMethod method) - : base(httpMethod, path) + : this(httpMethod, path, method, null, null) {} + + public LLSDStreamhandler( + string httpMethod, string path, LLSDMethod method, string name, string description) + : base(httpMethod, path, name, description) { m_method = method; } @@ -62,9 +66,7 @@ namespace OpenSim.Framework.Capabilities TResponse response = m_method(llsdRequest); - Encoding encoding = new UTF8Encoding(false); - - return encoding.GetBytes(LLSDHelpers.SerialiseLLSDReply(response)); + return Util.UTF8NoBomEncoding.GetBytes(LLSDHelpers.SerialiseLLSDReply(response)); } } } diff --git a/OpenSim/ConsoleClient/Requester.cs b/OpenSim/ConsoleClient/Requester.cs index fefe9690f1..aabb02cbb3 100644 --- a/OpenSim/ConsoleClient/Requester.cs +++ b/OpenSim/ConsoleClient/Requester.cs @@ -50,7 +50,7 @@ namespace OpenSim.ConsoleClient request.ContentType = "application/x-www-form-urlencoded"; - byte[] buffer = new System.Text.ASCIIEncoding().GetBytes(data); + byte[] buffer = Encoding.ASCII.GetBytes(data); int length = (int) buffer.Length; request.ContentLength = length; diff --git a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs index df496a74f4..47fb6d7317 100644 --- a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs +++ b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs @@ -1181,6 +1181,72 @@ VALUES // } #endregion } + + #region Environment Settings + public string LoadRegionEnvironmentSettings(UUID regionUUID) + { + string sql = "select * from [regionenvironment] where region_id = @region_id"; + using (SqlConnection conn = new SqlConnection(m_connectionString)) + using (SqlCommand cmd = new SqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("@region_id", regionUUID)); + conn.Open(); + using (SqlDataReader result = cmd.ExecuteReader()) + { + if (!result.Read()) + { + return String.Empty; + } + else + { + return Convert.ToString(result["llsd_settings"]); + } + } + } + } + + public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) + { + { + string sql = "DELETE FROM [regionenvironment] WHERE region_id = @region_id"; + using (SqlConnection conn = new SqlConnection(m_connectionString)) + + using (SqlCommand cmd = new SqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("@region_id", regionUUID)); + conn.Open(); + cmd.ExecuteNonQuery(); + } + + sql = "INSERT INTO [regionenvironment] (region_id, llsd_settings) VALUES (@region_id, @llsd_settings)"; + + using (SqlConnection conn = new SqlConnection(m_connectionString)) + + using (SqlCommand cmd = new SqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("@region_id", regionUUID)); + cmd.Parameters.Add(_Database.CreateParameter("@llsd_settings", settings)); + + conn.Open(); + cmd.ExecuteNonQuery(); + } + } + } + + public void RemoveRegionEnvironmentSettings(UUID regionUUID) + { + string sql = "delete from [regionenvironment] where region_id = @region_id"; + using (SqlConnection conn = new SqlConnection(m_connectionString)) + using (SqlCommand cmd = new SqlCommand(sql, conn)) + { + cmd.Parameters.Add(_Database.CreateParameter("@region_id", regionUUID)); + + conn.Open(); + cmd.ExecuteNonQuery(); + } + } + #endregion + /// /// Loads the settings of a region. /// diff --git a/OpenSim/Data/MSSQL/Resources/RegionStore.migrations b/OpenSim/Data/MSSQL/Resources/RegionStore.migrations index d6a3be9282..350e548a0a 100644 --- a/OpenSim/Data/MSSQL/Resources/RegionStore.migrations +++ b/OpenSim/Data/MSSQL/Resources/RegionStore.migrations @@ -1134,3 +1134,17 @@ ALTER TABLE landaccesslist ADD Expires integer NOT NULL DEFAULT 0; COMMIT +:VERSION 37 #---------------- Environment Settings + +BEGIN TRANSACTION + +CREATE TABLE [dbo].[regionenvironment]( + [region_id] [uniqueidentifier] NOT NULL, + [llsd_settings] [varchar](max) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, + PRIMARY KEY CLUSTERED +( + [region_id] ASC +)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] + +COMMIT diff --git a/OpenSim/Data/MySQL/MySQLAssetData.cs b/OpenSim/Data/MySQL/MySQLAssetData.cs index a22dc0acb9..20df234d5d 100644 --- a/OpenSim/Data/MySQL/MySQLAssetData.cs +++ b/OpenSim/Data/MySQL/MySQLAssetData.cs @@ -163,54 +163,53 @@ namespace OpenSim.Data.MySQL { dbcon.Open(); - MySqlCommand cmd = + using (MySqlCommand cmd = new MySqlCommand( "replace INTO assets(id, name, description, assetType, local, temporary, create_time, access_time, asset_flags, CreatorID, data)" + "VALUES(?id, ?name, ?description, ?assetType, ?local, ?temporary, ?create_time, ?access_time, ?asset_flags, ?CreatorID, ?data)", - dbcon); - - string assetName = asset.Name; - if (asset.Name.Length > 64) + dbcon)) { - assetName = asset.Name.Substring(0, 64); - m_log.Warn("[ASSET DB]: Name field truncated from " + asset.Name.Length + " to " + assetName.Length + " characters on add"); - } - - string assetDescription = asset.Description; - if (asset.Description.Length > 64) - { - assetDescription = asset.Description.Substring(0, 64); - m_log.Warn("[ASSET DB]: Description field truncated from " + asset.Description.Length + " to " + assetDescription.Length + " characters on add"); - } - - // need to ensure we dispose - try - { - using (cmd) + string assetName = asset.Name; + if (asset.Name.Length > 64) { - // create unix epoch time - int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); - cmd.Parameters.AddWithValue("?id", asset.ID); - cmd.Parameters.AddWithValue("?name", assetName); - cmd.Parameters.AddWithValue("?description", assetDescription); - cmd.Parameters.AddWithValue("?assetType", asset.Type); - cmd.Parameters.AddWithValue("?local", asset.Local); - cmd.Parameters.AddWithValue("?temporary", asset.Temporary); - cmd.Parameters.AddWithValue("?create_time", now); - cmd.Parameters.AddWithValue("?access_time", now); - cmd.Parameters.AddWithValue("?CreatorID", asset.Metadata.CreatorID); - cmd.Parameters.AddWithValue("?asset_flags", (int)asset.Flags); - cmd.Parameters.AddWithValue("?data", asset.Data); - cmd.ExecuteNonQuery(); - cmd.Dispose(); - return true; + assetName = asset.Name.Substring(0, 64); + m_log.Warn("[ASSET DB]: Name field truncated from " + asset.Name.Length + " to " + assetName.Length + " characters on add"); + } + + string assetDescription = asset.Description; + if (asset.Description.Length > 64) + { + assetDescription = asset.Description.Substring(0, 64); + m_log.Warn("[ASSET DB]: Description field truncated from " + asset.Description.Length + " to " + assetDescription.Length + " characters on add"); + } + + try + { + using (cmd) + { + // create unix epoch time + int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); + cmd.Parameters.AddWithValue("?id", asset.ID); + cmd.Parameters.AddWithValue("?name", assetName); + cmd.Parameters.AddWithValue("?description", assetDescription); + cmd.Parameters.AddWithValue("?assetType", asset.Type); + cmd.Parameters.AddWithValue("?local", asset.Local); + cmd.Parameters.AddWithValue("?temporary", asset.Temporary); + cmd.Parameters.AddWithValue("?create_time", now); + cmd.Parameters.AddWithValue("?access_time", now); + cmd.Parameters.AddWithValue("?CreatorID", asset.Metadata.CreatorID); + cmd.Parameters.AddWithValue("?asset_flags", (int)asset.Flags); + cmd.Parameters.AddWithValue("?data", asset.Data); + cmd.ExecuteNonQuery(); + return true; + } + } + catch (Exception e) + { + m_log.ErrorFormat("[ASSET DB]: MySQL failure creating asset {0} with name \"{1}\". Error: {2}", + asset.FullID, asset.Name, e.Message); + return false; } - } - catch (Exception e) - { - m_log.ErrorFormat("[ASSET DB]: MySQL failure creating asset {0} with name \"{1}\". Error: {2}", - asset.FullID, asset.Name, e.Message); - return false; } } } @@ -223,33 +222,31 @@ namespace OpenSim.Data.MySQL using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { dbcon.Open(); - MySqlCommand cmd = - new MySqlCommand("update assets set access_time=?access_time where id=?id", - dbcon); - // need to ensure we dispose - try + using (MySqlCommand cmd + = new MySqlCommand("update assets set access_time=?access_time where id=?id", dbcon)) { - using (cmd) + try { - // create unix epoch time - int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); - cmd.Parameters.AddWithValue("?id", asset.ID); - cmd.Parameters.AddWithValue("?access_time", now); - cmd.ExecuteNonQuery(); - cmd.Dispose(); + using (cmd) + { + // create unix epoch time + int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow); + cmd.Parameters.AddWithValue("?id", asset.ID); + cmd.Parameters.AddWithValue("?access_time", now); + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.ErrorFormat( + "[ASSETS DB]: " + + "MySql failure updating access_time for asset {0} with name {1}" + Environment.NewLine + e.ToString() + + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name); } - } - catch (Exception e) - { - m_log.ErrorFormat( - "[ASSETS DB]: " + - "MySql failure updating access_time for asset {0} with name {1}" + Environment.NewLine + e.ToString() - + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name); } } } - } /// @@ -312,35 +309,41 @@ namespace OpenSim.Data.MySQL using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { dbcon.Open(); - MySqlCommand cmd = new MySqlCommand("SELECT name,description,assetType,temporary,id,asset_flags,CreatorID FROM assets LIMIT ?start, ?count", dbcon); - cmd.Parameters.AddWithValue("?start", start); - cmd.Parameters.AddWithValue("?count", count); - try + using (MySqlCommand cmd + = new MySqlCommand( + "SELECT name,description,assetType,temporary,id,asset_flags,CreatorID FROM assets LIMIT ?start, ?count", + dbcon)) { - using (MySqlDataReader dbReader = cmd.ExecuteReader()) + cmd.Parameters.AddWithValue("?start", start); + cmd.Parameters.AddWithValue("?count", count); + + try { - while (dbReader.Read()) + using (MySqlDataReader dbReader = cmd.ExecuteReader()) { - AssetMetadata metadata = new AssetMetadata(); - metadata.Name = (string)dbReader["name"]; - metadata.Description = (string)dbReader["description"]; - metadata.Type = (sbyte)dbReader["assetType"]; - metadata.Temporary = Convert.ToBoolean(dbReader["temporary"]); // Not sure if this is correct. - metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]); - metadata.FullID = DBGuid.FromDB(dbReader["id"]); - metadata.CreatorID = dbReader["CreatorID"].ToString(); - - // Current SHA1s are not stored/computed. - metadata.SHA1 = new byte[] { }; - - retList.Add(metadata); + while (dbReader.Read()) + { + AssetMetadata metadata = new AssetMetadata(); + metadata.Name = (string)dbReader["name"]; + metadata.Description = (string)dbReader["description"]; + metadata.Type = (sbyte)dbReader["assetType"]; + metadata.Temporary = Convert.ToBoolean(dbReader["temporary"]); // Not sure if this is correct. + metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]); + metadata.FullID = DBGuid.FromDB(dbReader["id"]); + metadata.CreatorID = dbReader["CreatorID"].ToString(); + + // Current SHA1s are not stored/computed. + metadata.SHA1 = new byte[] { }; + + retList.Add(metadata); + } } } - } - catch (Exception e) - { - m_log.Error("[ASSETS DB]: MySql failure fetching asset set" + Environment.NewLine + e.ToString()); + catch (Exception e) + { + m_log.Error("[ASSETS DB]: MySql failure fetching asset set" + Environment.NewLine + e.ToString()); + } } } } @@ -355,11 +358,12 @@ namespace OpenSim.Data.MySQL using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { dbcon.Open(); - MySqlCommand cmd = new MySqlCommand("delete from assets where id=?id", dbcon); - cmd.Parameters.AddWithValue("?id", id); - cmd.ExecuteNonQuery(); - cmd.Dispose(); + using (MySqlCommand cmd = new MySqlCommand("delete from assets where id=?id", dbcon)) + { + cmd.Parameters.AddWithValue("?id", id); + cmd.ExecuteNonQuery(); + } } } diff --git a/OpenSim/Data/MySQL/MySQLAuthenticationData.cs b/OpenSim/Data/MySQL/MySQLAuthenticationData.cs index 8d82f61bda..76274972a8 100644 --- a/OpenSim/Data/MySQL/MySQLAuthenticationData.cs +++ b/OpenSim/Data/MySQL/MySQLAuthenticationData.cs @@ -70,41 +70,52 @@ namespace OpenSim.Data.MySQL using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { dbcon.Open(); - MySqlCommand cmd = new MySqlCommand("select * from `" + m_Realm + "` where UUID = ?principalID", dbcon); - cmd.Parameters.AddWithValue("?principalID", principalID.ToString()); - IDataReader result = cmd.ExecuteReader(); - - if (result.Read()) + using (MySqlCommand cmd + = new MySqlCommand("select * from `" + m_Realm + "` where UUID = ?principalID", dbcon)) { - ret.PrincipalID = principalID; + cmd.Parameters.AddWithValue("?principalID", principalID.ToString()); - if (m_ColumnNames == null) + IDataReader result = cmd.ExecuteReader(); + + if (result.Read()) { - m_ColumnNames = new List(); - - DataTable schemaTable = result.GetSchemaTable(); - foreach (DataRow row in schemaTable.Rows) - m_ColumnNames.Add(row["ColumnName"].ToString()); + ret.PrincipalID = principalID; + + CheckColumnNames(result); + + foreach (string s in m_ColumnNames) + { + if (s == "UUID") + continue; + + ret.Data[s] = result[s].ToString(); + } + + return ret; } - - foreach (string s in m_ColumnNames) + else { - if (s == "UUID") - continue; - - ret.Data[s] = result[s].ToString(); + return null; } - - return ret; - } - else - { - return null; } } } + private void CheckColumnNames(IDataReader result) + { + if (m_ColumnNames != null) + return; + + List columnNames = new List(); + + DataTable schemaTable = result.GetSchemaTable(); + foreach (DataRow row in schemaTable.Rows) + columnNames.Add(row["ColumnName"].ToString()); + + m_ColumnNames = columnNames; + } + public bool Store(AuthenticationData data) { if (data.Data.ContainsKey("UUID")) @@ -112,57 +123,53 @@ namespace OpenSim.Data.MySQL string[] fields = new List(data.Data.Keys).ToArray(); - MySqlCommand cmd = new MySqlCommand(); - - string update = "update `"+m_Realm+"` set "; - bool first = true; - foreach (string field in fields) + using (MySqlCommand cmd = new MySqlCommand()) { - if (!first) - update += ", "; - update += "`" + field + "` = ?"+field; - - first = false; - - cmd.Parameters.AddWithValue("?"+field, data.Data[field]); - } - - update += " where UUID = ?principalID"; - - cmd.CommandText = update; - cmd.Parameters.AddWithValue("?principalID", data.PrincipalID.ToString()); - - if (ExecuteNonQuery(cmd) < 1) - { - string insert = "insert into `" + m_Realm + "` (`UUID`, `" + - String.Join("`, `", fields) + - "`) values (?principalID, ?" + String.Join(", ?", fields) + ")"; - - cmd.CommandText = insert; - + string update = "update `"+m_Realm+"` set "; + bool first = true; + foreach (string field in fields) + { + if (!first) + update += ", "; + update += "`" + field + "` = ?"+field; + + first = false; + + cmd.Parameters.AddWithValue("?"+field, data.Data[field]); + } + + update += " where UUID = ?principalID"; + + cmd.CommandText = update; + cmd.Parameters.AddWithValue("?principalID", data.PrincipalID.ToString()); + if (ExecuteNonQuery(cmd) < 1) { - cmd.Dispose(); - return false; + string insert = "insert into `" + m_Realm + "` (`UUID`, `" + + String.Join("`, `", fields) + + "`) values (?principalID, ?" + String.Join(", ?", fields) + ")"; + + cmd.CommandText = insert; + + if (ExecuteNonQuery(cmd) < 1) + return false; } } - cmd.Dispose(); - return true; } public bool SetDataItem(UUID principalID, string item, string value) { - MySqlCommand cmd = new MySqlCommand("update `" + m_Realm + - "` set `" + item + "` = ?" + item + " where UUID = ?UUID"); - - - cmd.Parameters.AddWithValue("?"+item, value); - cmd.Parameters.AddWithValue("?UUID", principalID.ToString()); - - if (ExecuteNonQuery(cmd) > 0) - return true; + using (MySqlCommand cmd + = new MySqlCommand("update `" + m_Realm + "` set `" + item + "` = ?" + item + " where UUID = ?UUID")) + { + cmd.Parameters.AddWithValue("?"+item, value); + cmd.Parameters.AddWithValue("?UUID", principalID.ToString()); + + if (ExecuteNonQuery(cmd) > 0) + return true; + } return false; } @@ -172,18 +179,18 @@ namespace OpenSim.Data.MySQL if (System.Environment.TickCount - m_LastExpire > 30000) DoExpire(); - MySqlCommand cmd = new MySqlCommand("insert into tokens (UUID, token, validity) values (?principalID, ?token, date_add(now(), interval ?lifetime minute))"); - cmd.Parameters.AddWithValue("?principalID", principalID.ToString()); - cmd.Parameters.AddWithValue("?token", token); - cmd.Parameters.AddWithValue("?lifetime", lifetime.ToString()); - - if (ExecuteNonQuery(cmd) > 0) + using (MySqlCommand cmd + = new MySqlCommand( + "insert into tokens (UUID, token, validity) values (?principalID, ?token, date_add(now(), interval ?lifetime minute))")) { - cmd.Dispose(); - return true; + cmd.Parameters.AddWithValue("?principalID", principalID.ToString()); + cmd.Parameters.AddWithValue("?token", token); + cmd.Parameters.AddWithValue("?lifetime", lifetime.ToString()); + + if (ExecuteNonQuery(cmd) > 0) + return true; } - cmd.Dispose(); return false; } @@ -192,30 +199,29 @@ namespace OpenSim.Data.MySQL if (System.Environment.TickCount - m_LastExpire > 30000) DoExpire(); - MySqlCommand cmd = new MySqlCommand("update tokens set validity = date_add(now(), interval ?lifetime minute) where UUID = ?principalID and token = ?token and validity > now()"); - cmd.Parameters.AddWithValue("?principalID", principalID.ToString()); - cmd.Parameters.AddWithValue("?token", token); - cmd.Parameters.AddWithValue("?lifetime", lifetime.ToString()); - - if (ExecuteNonQuery(cmd) > 0) + using (MySqlCommand cmd + = new MySqlCommand( + "update tokens set validity = date_add(now(), interval ?lifetime minute) where UUID = ?principalID and token = ?token and validity > now()")) { - cmd.Dispose(); - return true; - } + cmd.Parameters.AddWithValue("?principalID", principalID.ToString()); + cmd.Parameters.AddWithValue("?token", token); + cmd.Parameters.AddWithValue("?lifetime", lifetime.ToString()); - cmd.Dispose(); + if (ExecuteNonQuery(cmd) > 0) + return true; + } return false; } private void DoExpire() { - MySqlCommand cmd = new MySqlCommand("delete from tokens where validity < now()"); - ExecuteNonQuery(cmd); - - cmd.Dispose(); + using (MySqlCommand cmd = new MySqlCommand("delete from tokens where validity < now()")) + { + ExecuteNonQuery(cmd); + } m_LastExpire = System.Environment.TickCount; } } -} +} \ No newline at end of file diff --git a/OpenSim/Data/MySQL/MySQLAvatarData.cs b/OpenSim/Data/MySQL/MySQLAvatarData.cs index 8c841abc06..6a2f5d814d 100644 --- a/OpenSim/Data/MySQL/MySQLAvatarData.cs +++ b/OpenSim/Data/MySQL/MySQLAvatarData.cs @@ -52,14 +52,15 @@ namespace OpenSim.Data.MySQL public bool Delete(UUID principalID, string name) { - MySqlCommand cmd = new MySqlCommand(); - - cmd.CommandText = String.Format("delete from {0} where `PrincipalID` = ?PrincipalID and `Name` = ?Name", m_Realm); - cmd.Parameters.AddWithValue("?PrincipalID", principalID.ToString()); - cmd.Parameters.AddWithValue("?Name", name); - - if (ExecuteNonQuery(cmd) > 0) - return true; + using (MySqlCommand cmd = new MySqlCommand()) + { + cmd.CommandText = String.Format("delete from {0} where `PrincipalID` = ?PrincipalID and `Name` = ?Name", m_Realm); + cmd.Parameters.AddWithValue("?PrincipalID", principalID.ToString()); + cmd.Parameters.AddWithValue("?Name", name); + + if (ExecuteNonQuery(cmd) > 0) + return true; + } return false; } diff --git a/OpenSim/Data/MySQL/MySQLFriendsData.cs b/OpenSim/Data/MySQL/MySQLFriendsData.cs index 130ba5e9c2..3cd6b8f68b 100644 --- a/OpenSim/Data/MySQL/MySQLFriendsData.cs +++ b/OpenSim/Data/MySQL/MySQLFriendsData.cs @@ -49,34 +49,38 @@ namespace OpenSim.Data.MySQL public bool Delete(string principalID, string friend) { - MySqlCommand cmd = new MySqlCommand(); + using (MySqlCommand cmd = new MySqlCommand()) + { + cmd.CommandText = String.Format("delete from {0} where PrincipalID = ?PrincipalID and Friend = ?Friend", m_Realm); + cmd.Parameters.AddWithValue("?PrincipalID", principalID.ToString()); + cmd.Parameters.AddWithValue("?Friend", friend); - cmd.CommandText = String.Format("delete from {0} where PrincipalID = ?PrincipalID and Friend = ?Friend", m_Realm); - cmd.Parameters.AddWithValue("?PrincipalID", principalID.ToString()); - cmd.Parameters.AddWithValue("?Friend", friend); - - ExecuteNonQuery(cmd); + ExecuteNonQuery(cmd); + } return true; } public FriendsData[] GetFriends(UUID principalID) { - MySqlCommand cmd = new MySqlCommand(); + using (MySqlCommand cmd = new MySqlCommand()) + { + cmd.CommandText = String.Format("select a.*,case when b.Flags is null then -1 else b.Flags end as TheirFlags from {0} as a left join {0} as b on a.PrincipalID = b.Friend and a.Friend = b.PrincipalID where a.PrincipalID = ?PrincipalID", m_Realm); + cmd.Parameters.AddWithValue("?PrincipalID", principalID.ToString()); - cmd.CommandText = String.Format("select a.*,case when b.Flags is null then -1 else b.Flags end as TheirFlags from {0} as a left join {0} as b on a.PrincipalID = b.Friend and a.Friend = b.PrincipalID where a.PrincipalID = ?PrincipalID", m_Realm); - cmd.Parameters.AddWithValue("?PrincipalID", principalID.ToString()); - - return DoQuery(cmd); + return DoQuery(cmd); + } } public FriendsData[] GetFriends(string principalID) { - MySqlCommand cmd = new MySqlCommand(); + using (MySqlCommand cmd = new MySqlCommand()) + { + cmd.CommandText = String.Format("select a.*,case when b.Flags is null then -1 else b.Flags end as TheirFlags from {0} as a left join {0} as b on a.PrincipalID = b.Friend and a.Friend = b.PrincipalID where a.PrincipalID LIKE ?PrincipalID", m_Realm); + cmd.Parameters.AddWithValue("?PrincipalID", principalID.ToString() + '%'); - cmd.CommandText = String.Format("select a.*,case when b.Flags is null then -1 else b.Flags end as TheirFlags from {0} as a left join {0} as b on a.PrincipalID = b.Friend and a.Friend = b.PrincipalID where a.PrincipalID LIKE ?PrincipalID", m_Realm); - cmd.Parameters.AddWithValue("?PrincipalID", principalID.ToString() + '%'); - return DoQuery(cmd); + return DoQuery(cmd); + } } } -} +} \ No newline at end of file diff --git a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs index 786b955708..86367a130a 100644 --- a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs +++ b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs @@ -91,15 +91,17 @@ namespace OpenSim.Data.MySQL if (m_ColumnNames != null) return; - m_ColumnNames = new List(); + List columnNames = new List(); DataTable schemaTable = reader.GetSchemaTable(); foreach (DataRow row in schemaTable.Rows) { if (row["ColumnName"] != null && (!m_Fields.ContainsKey(row["ColumnName"].ToString()))) - m_ColumnNames.Add(row["ColumnName"].ToString()); + columnNames.Add(row["ColumnName"].ToString()); } + + m_ColumnNames = columnNames; } public virtual T[] Get(string field, string key) diff --git a/OpenSim/Data/MySQL/MySQLInventoryData.cs b/OpenSim/Data/MySQL/MySQLInventoryData.cs index 1a634e5eb6..e9b10f3cdf 100644 --- a/OpenSim/Data/MySQL/MySQLInventoryData.cs +++ b/OpenSim/Data/MySQL/MySQLInventoryData.cs @@ -467,43 +467,43 @@ namespace OpenSim.Data.MySQL { dbcon.Open(); - MySqlCommand result = new MySqlCommand(sql, dbcon); - result.Parameters.AddWithValue("?inventoryID", item.ID.ToString()); - result.Parameters.AddWithValue("?assetID", item.AssetID.ToString()); - result.Parameters.AddWithValue("?assetType", item.AssetType.ToString()); - result.Parameters.AddWithValue("?parentFolderID", item.Folder.ToString()); - result.Parameters.AddWithValue("?avatarID", item.Owner.ToString()); - result.Parameters.AddWithValue("?inventoryName", itemName); - result.Parameters.AddWithValue("?inventoryDescription", itemDesc); - result.Parameters.AddWithValue("?inventoryNextPermissions", item.NextPermissions.ToString()); - result.Parameters.AddWithValue("?inventoryCurrentPermissions", - item.CurrentPermissions.ToString()); - result.Parameters.AddWithValue("?invType", item.InvType); - result.Parameters.AddWithValue("?creatorID", item.CreatorId); - result.Parameters.AddWithValue("?inventoryBasePermissions", item.BasePermissions); - result.Parameters.AddWithValue("?inventoryEveryOnePermissions", item.EveryOnePermissions); - result.Parameters.AddWithValue("?inventoryGroupPermissions", item.GroupPermissions); - result.Parameters.AddWithValue("?salePrice", item.SalePrice); - result.Parameters.AddWithValue("?saleType", unchecked((sbyte)item.SaleType)); - result.Parameters.AddWithValue("?creationDate", item.CreationDate); - result.Parameters.AddWithValue("?groupID", item.GroupID); - result.Parameters.AddWithValue("?groupOwned", item.GroupOwned); - result.Parameters.AddWithValue("?flags", item.Flags); - - lock (m_dbLock) + using (MySqlCommand result = new MySqlCommand(sql, dbcon)) { - result.ExecuteNonQuery(); + result.Parameters.AddWithValue("?inventoryID", item.ID.ToString()); + result.Parameters.AddWithValue("?assetID", item.AssetID.ToString()); + result.Parameters.AddWithValue("?assetType", item.AssetType.ToString()); + result.Parameters.AddWithValue("?parentFolderID", item.Folder.ToString()); + result.Parameters.AddWithValue("?avatarID", item.Owner.ToString()); + result.Parameters.AddWithValue("?inventoryName", itemName); + result.Parameters.AddWithValue("?inventoryDescription", itemDesc); + result.Parameters.AddWithValue("?inventoryNextPermissions", item.NextPermissions.ToString()); + result.Parameters.AddWithValue("?inventoryCurrentPermissions", + item.CurrentPermissions.ToString()); + result.Parameters.AddWithValue("?invType", item.InvType); + result.Parameters.AddWithValue("?creatorID", item.CreatorId); + result.Parameters.AddWithValue("?inventoryBasePermissions", item.BasePermissions); + result.Parameters.AddWithValue("?inventoryEveryOnePermissions", item.EveryOnePermissions); + result.Parameters.AddWithValue("?inventoryGroupPermissions", item.GroupPermissions); + result.Parameters.AddWithValue("?salePrice", item.SalePrice); + result.Parameters.AddWithValue("?saleType", unchecked((sbyte)item.SaleType)); + result.Parameters.AddWithValue("?creationDate", item.CreationDate); + result.Parameters.AddWithValue("?groupID", item.GroupID); + result.Parameters.AddWithValue("?groupOwned", item.GroupOwned); + result.Parameters.AddWithValue("?flags", item.Flags); + + lock (m_dbLock) + result.ExecuteNonQuery(); + + result.Dispose(); } - result.Dispose(); - - result = new MySqlCommand("update inventoryfolders set version=version+1 where folderID = ?folderID", dbcon); - result.Parameters.AddWithValue("?folderID", item.Folder.ToString()); - lock (m_dbLock) + using (MySqlCommand result = new MySqlCommand("update inventoryfolders set version=version+1 where folderID = ?folderID", dbcon)) { - result.ExecuteNonQuery(); + result.Parameters.AddWithValue("?folderID", item.Folder.ToString()); + + lock (m_dbLock) + result.ExecuteNonQuery(); } - result.Dispose(); } } catch (MySqlException e) @@ -533,12 +533,12 @@ namespace OpenSim.Data.MySQL { dbcon.Open(); - MySqlCommand cmd = new MySqlCommand("DELETE FROM inventoryitems WHERE inventoryID=?uuid", dbcon); - cmd.Parameters.AddWithValue("?uuid", itemID.ToString()); - - lock (m_dbLock) + using (MySqlCommand cmd = new MySqlCommand("DELETE FROM inventoryitems WHERE inventoryID=?uuid", dbcon)) { - cmd.ExecuteNonQuery(); + cmd.Parameters.AddWithValue("?uuid", itemID.ToString()); + + lock (m_dbLock) + cmd.ExecuteNonQuery(); } } } @@ -579,24 +579,26 @@ namespace OpenSim.Data.MySQL { dbcon.Open(); - MySqlCommand cmd = new MySqlCommand(sql, dbcon); - cmd.Parameters.AddWithValue("?folderID", folder.ID.ToString()); - cmd.Parameters.AddWithValue("?agentID", folder.Owner.ToString()); - cmd.Parameters.AddWithValue("?parentFolderID", folder.ParentID.ToString()); - cmd.Parameters.AddWithValue("?folderName", folderName); - cmd.Parameters.AddWithValue("?type", folder.Type); - cmd.Parameters.AddWithValue("?version", folder.Version); + using (MySqlCommand cmd = new MySqlCommand(sql, dbcon)) + { + cmd.Parameters.AddWithValue("?folderID", folder.ID.ToString()); + cmd.Parameters.AddWithValue("?agentID", folder.Owner.ToString()); + cmd.Parameters.AddWithValue("?parentFolderID", folder.ParentID.ToString()); + cmd.Parameters.AddWithValue("?folderName", folderName); + cmd.Parameters.AddWithValue("?type", folder.Type); + cmd.Parameters.AddWithValue("?version", folder.Version); - try - { - lock (m_dbLock) + try { - cmd.ExecuteNonQuery(); + lock (m_dbLock) + { + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.Error(e.ToString()); } - } - catch (Exception e) - { - m_log.Error(e.ToString()); } } } @@ -624,20 +626,22 @@ namespace OpenSim.Data.MySQL { dbcon.Open(); - MySqlCommand cmd = new MySqlCommand(sql, dbcon); - cmd.Parameters.AddWithValue("?folderID", folder.ID.ToString()); - cmd.Parameters.AddWithValue("?parentFolderID", folder.ParentID.ToString()); - - try + using (MySqlCommand cmd = new MySqlCommand(sql, dbcon)) { - lock (m_dbLock) + cmd.Parameters.AddWithValue("?folderID", folder.ID.ToString()); + cmd.Parameters.AddWithValue("?parentFolderID", folder.ParentID.ToString()); + + try { - cmd.ExecuteNonQuery(); + lock (m_dbLock) + { + cmd.ExecuteNonQuery(); + } + } + catch (Exception e) + { + m_log.Error(e.ToString()); } - } - catch (Exception e) - { - m_log.Error(e.ToString()); } } } diff --git a/OpenSim/Data/MySQL/MySQLPresenceData.cs b/OpenSim/Data/MySQL/MySQLPresenceData.cs index fc625f0057..780806087f 100644 --- a/OpenSim/Data/MySQL/MySQLPresenceData.cs +++ b/OpenSim/Data/MySQL/MySQLPresenceData.cs @@ -63,13 +63,14 @@ namespace OpenSim.Data.MySQL public void LogoutRegionAgents(UUID regionID) { - MySqlCommand cmd = new MySqlCommand(); - - cmd.CommandText = String.Format("delete from {0} where `RegionID`=?RegionID", m_Realm); - - cmd.Parameters.AddWithValue("?RegionID", regionID.ToString()); - - ExecuteNonQuery(cmd); + using (MySqlCommand cmd = new MySqlCommand()) + { + cmd.CommandText = String.Format("delete from {0} where `RegionID`=?RegionID", m_Realm); + + cmd.Parameters.AddWithValue("?RegionID", regionID.ToString()); + + ExecuteNonQuery(cmd); + } } public bool ReportAgent(UUID sessionID, UUID regionID) @@ -81,17 +82,18 @@ namespace OpenSim.Data.MySQL if (regionID == UUID.Zero) return false; - MySqlCommand cmd = new MySqlCommand(); - - cmd.CommandText = String.Format("update {0} set RegionID=?RegionID, LastSeen=NOW() where `SessionID`=?SessionID", m_Realm); - - cmd.Parameters.AddWithValue("?SessionID", sessionID.ToString()); - cmd.Parameters.AddWithValue("?RegionID", regionID.ToString()); - - if (ExecuteNonQuery(cmd) == 0) - return false; + using (MySqlCommand cmd = new MySqlCommand()) + { + cmd.CommandText = String.Format("update {0} set RegionID=?RegionID, LastSeen=NOW() where `SessionID`=?SessionID", m_Realm); + + cmd.Parameters.AddWithValue("?SessionID", sessionID.ToString()); + cmd.Parameters.AddWithValue("?RegionID", regionID.ToString()); + + if (ExecuteNonQuery(cmd) == 0) + return false; + } return true; } } -} +} \ No newline at end of file diff --git a/OpenSim/Data/MySQL/MySQLRegionData.cs b/OpenSim/Data/MySQL/MySQLRegionData.cs index c20c39263a..0614879061 100644 --- a/OpenSim/Data/MySQL/MySQLRegionData.cs +++ b/OpenSim/Data/MySQL/MySQLRegionData.cs @@ -162,17 +162,7 @@ namespace OpenSim.Data.MySQL ret.sizeX = Convert.ToInt32(result["sizeX"]); ret.sizeY = Convert.ToInt32(result["sizeY"]); - if (m_ColumnNames == null) - { - m_ColumnNames = new List(); - - DataTable schemaTable = result.GetSchemaTable(); - foreach (DataRow row in schemaTable.Rows) - { - if (row["ColumnName"] != null) - m_ColumnNames.Add(row["ColumnName"].ToString()); - } - } + CheckColumnNames(result); foreach (string s in m_ColumnNames) { @@ -187,7 +177,11 @@ namespace OpenSim.Data.MySQL if (s == "locY") continue; - ret.Data[s] = result[s].ToString(); + object value = result[s]; + if (value is DBNull) + ret.Data[s] = null; + else + ret.Data[s] = result[s].ToString(); } retList.Add(ret); @@ -198,6 +192,23 @@ namespace OpenSim.Data.MySQL return retList; } + private void CheckColumnNames(IDataReader result) + { + if (m_ColumnNames != null) + return; + + List columnNames = new List(); + + DataTable schemaTable = result.GetSchemaTable(); + foreach (DataRow row in schemaTable.Rows) + { + if (row["ColumnName"] != null) + columnNames.Add(row["ColumnName"].ToString()); + } + + m_ColumnNames = columnNames; + } + public bool Store(RegionData data) { if (data.Data.ContainsKey("uuid")) @@ -318,11 +329,12 @@ namespace OpenSim.Data.MySQL if (scopeID != UUID.Zero) command += " and ScopeID = ?scopeID"; - MySqlCommand cmd = new MySqlCommand(command); - - cmd.Parameters.AddWithValue("?scopeID", scopeID.ToString()); - - return RunCommand(cmd); + using (MySqlCommand cmd = new MySqlCommand(command)) + { + cmd.Parameters.AddWithValue("?scopeID", scopeID.ToString()); + + return RunCommand(cmd); + } } } -} +} \ No newline at end of file diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs index 7df5a8106d..29bd6b634a 100644 --- a/OpenSim/Data/MySQL/MySQLSimulationData.cs +++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs @@ -131,121 +131,121 @@ namespace OpenSim.Data.MySQL using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { dbcon.Open(); - MySqlCommand cmd = dbcon.CreateCommand(); - foreach (SceneObjectPart prim in obj.Parts) + using (MySqlCommand cmd = dbcon.CreateCommand()) { - cmd.Parameters.Clear(); + foreach (SceneObjectPart prim in obj.Parts) + { + cmd.Parameters.Clear(); - cmd.CommandText = "replace into prims (" + - "UUID, CreationDate, " + - "Name, Text, Description, " + - "SitName, TouchName, ObjectFlags, " + - "OwnerMask, NextOwnerMask, GroupMask, " + - "EveryoneMask, BaseMask, PositionX, " + - "PositionY, PositionZ, GroupPositionX, " + - "GroupPositionY, GroupPositionZ, VelocityX, " + - "VelocityY, VelocityZ, AngularVelocityX, " + - "AngularVelocityY, AngularVelocityZ, " + - "AccelerationX, AccelerationY, " + - "AccelerationZ, RotationX, " + - "RotationY, RotationZ, " + - "RotationW, SitTargetOffsetX, " + - "SitTargetOffsetY, SitTargetOffsetZ, " + - "SitTargetOrientW, SitTargetOrientX, " + - "SitTargetOrientY, SitTargetOrientZ, " + - "RegionUUID, CreatorID, " + - "OwnerID, GroupID, " + - "LastOwnerID, SceneGroupID, " + - "PayPrice, PayButton1, " + - "PayButton2, PayButton3, " + - "PayButton4, LoopedSound, " + - "LoopedSoundGain, TextureAnimation, " + - "OmegaX, OmegaY, OmegaZ, " + - "CameraEyeOffsetX, CameraEyeOffsetY, " + - "CameraEyeOffsetZ, CameraAtOffsetX, " + - "CameraAtOffsetY, CameraAtOffsetZ, " + - "ForceMouselook, ScriptAccessPin, " + - "AllowedDrop, DieAtEdge, " + - "SalePrice, SaleType, " + - "ColorR, ColorG, ColorB, ColorA, " + - "ParticleSystem, ClickAction, Material, " + - "CollisionSound, CollisionSoundVolume, " + - "PassTouches, " + - "PassCollisions, " + - "LinkNumber, MediaURL, KeyframeMotion, " + - "PhysicsShapeType, Density, GravityModifier, " + - "Friction, Restitution, Vehicle " + - ") values (" + "?UUID, " + - "?CreationDate, ?Name, ?Text, " + - "?Description, ?SitName, ?TouchName, " + - "?ObjectFlags, ?OwnerMask, ?NextOwnerMask, " + - "?GroupMask, ?EveryoneMask, ?BaseMask, " + - "?PositionX, ?PositionY, ?PositionZ, " + - "?GroupPositionX, ?GroupPositionY, " + - "?GroupPositionZ, ?VelocityX, " + - "?VelocityY, ?VelocityZ, ?AngularVelocityX, " + - "?AngularVelocityY, ?AngularVelocityZ, " + - "?AccelerationX, ?AccelerationY, " + - "?AccelerationZ, ?RotationX, " + - "?RotationY, ?RotationZ, " + - "?RotationW, ?SitTargetOffsetX, " + - "?SitTargetOffsetY, ?SitTargetOffsetZ, " + - "?SitTargetOrientW, ?SitTargetOrientX, " + - "?SitTargetOrientY, ?SitTargetOrientZ, " + - "?RegionUUID, ?CreatorID, ?OwnerID, " + - "?GroupID, ?LastOwnerID, ?SceneGroupID, " + - "?PayPrice, ?PayButton1, ?PayButton2, " + - "?PayButton3, ?PayButton4, ?LoopedSound, " + - "?LoopedSoundGain, ?TextureAnimation, " + - "?OmegaX, ?OmegaY, ?OmegaZ, " + - "?CameraEyeOffsetX, ?CameraEyeOffsetY, " + - "?CameraEyeOffsetZ, ?CameraAtOffsetX, " + - "?CameraAtOffsetY, ?CameraAtOffsetZ, " + - "?ForceMouselook, ?ScriptAccessPin, " + - "?AllowedDrop, ?DieAtEdge, ?SalePrice, " + - "?SaleType, ?ColorR, ?ColorG, " + - "?ColorB, ?ColorA, ?ParticleSystem, " + - "?ClickAction, ?Material, ?CollisionSound, " + - "?CollisionSoundVolume, ?PassTouches, ?PassCollisions, " + - "?LinkNumber, ?MediaURL, ?KeyframeMotion, " + - "?PhysicsShapeType, ?Density, ?GravityModifier, " + - "?Friction, ?Restitution, ?Vehicle)"; + cmd.CommandText = "replace into prims (" + + "UUID, CreationDate, " + + "Name, Text, Description, " + + "SitName, TouchName, ObjectFlags, " + + "OwnerMask, NextOwnerMask, GroupMask, " + + "EveryoneMask, BaseMask, PositionX, " + + "PositionY, PositionZ, GroupPositionX, " + + "GroupPositionY, GroupPositionZ, VelocityX, " + + "VelocityY, VelocityZ, AngularVelocityX, " + + "AngularVelocityY, AngularVelocityZ, " + + "AccelerationX, AccelerationY, " + + "AccelerationZ, RotationX, " + + "RotationY, RotationZ, " + + "RotationW, SitTargetOffsetX, " + + "SitTargetOffsetY, SitTargetOffsetZ, " + + "SitTargetOrientW, SitTargetOrientX, " + + "SitTargetOrientY, SitTargetOrientZ, " + + "RegionUUID, CreatorID, " + + "OwnerID, GroupID, " + + "LastOwnerID, SceneGroupID, " + + "PayPrice, PayButton1, " + + "PayButton2, PayButton3, " + + "PayButton4, LoopedSound, " + + "LoopedSoundGain, TextureAnimation, " + + "OmegaX, OmegaY, OmegaZ, " + + "CameraEyeOffsetX, CameraEyeOffsetY, " + + "CameraEyeOffsetZ, CameraAtOffsetX, " + + "CameraAtOffsetY, CameraAtOffsetZ, " + + "ForceMouselook, ScriptAccessPin, " + + "AllowedDrop, DieAtEdge, " + + "SalePrice, SaleType, " + + "ColorR, ColorG, ColorB, ColorA, " + + "ParticleSystem, ClickAction, Material, " + + "CollisionSound, CollisionSoundVolume, " + + "PassTouches, " + + "PassCollisions, " + + "LinkNumber, MediaURL, KeyframeMotion, " + + "PhysicsShapeType, Density, GravityModifier, " + + "Friction, Restitution, Vehicle " + + ") values (" + "?UUID, " + + "?CreationDate, ?Name, ?Text, " + + "?Description, ?SitName, ?TouchName, " + + "?ObjectFlags, ?OwnerMask, ?NextOwnerMask, " + + "?GroupMask, ?EveryoneMask, ?BaseMask, " + + "?PositionX, ?PositionY, ?PositionZ, " + + "?GroupPositionX, ?GroupPositionY, " + + "?GroupPositionZ, ?VelocityX, " + + "?VelocityY, ?VelocityZ, ?AngularVelocityX, " + + "?AngularVelocityY, ?AngularVelocityZ, " + + "?AccelerationX, ?AccelerationY, " + + "?AccelerationZ, ?RotationX, " + + "?RotationY, ?RotationZ, " + + "?RotationW, ?SitTargetOffsetX, " + + "?SitTargetOffsetY, ?SitTargetOffsetZ, " + + "?SitTargetOrientW, ?SitTargetOrientX, " + + "?SitTargetOrientY, ?SitTargetOrientZ, " + + "?RegionUUID, ?CreatorID, ?OwnerID, " + + "?GroupID, ?LastOwnerID, ?SceneGroupID, " + + "?PayPrice, ?PayButton1, ?PayButton2, " + + "?PayButton3, ?PayButton4, ?LoopedSound, " + + "?LoopedSoundGain, ?TextureAnimation, " + + "?OmegaX, ?OmegaY, ?OmegaZ, " + + "?CameraEyeOffsetX, ?CameraEyeOffsetY, " + + "?CameraEyeOffsetZ, ?CameraAtOffsetX, " + + "?CameraAtOffsetY, ?CameraAtOffsetZ, " + + "?ForceMouselook, ?ScriptAccessPin, " + + "?AllowedDrop, ?DieAtEdge, ?SalePrice, " + + "?SaleType, ?ColorR, ?ColorG, " + + "?ColorB, ?ColorA, ?ParticleSystem, " + + "?ClickAction, ?Material, ?CollisionSound, " + + "?CollisionSoundVolume, ?PassTouches, ?PassCollisions, " + + "?LinkNumber, ?MediaURL, ?KeyframeMotion, " + + "?PhysicsShapeType, ?Density, ?GravityModifier, " + + "?Friction, ?Restitution, ?Vehicle)"; - FillPrimCommand(cmd, prim, obj.UUID, regionUUID); + FillPrimCommand(cmd, prim, obj.UUID, regionUUID); - ExecuteNonQuery(cmd); + ExecuteNonQuery(cmd); - cmd.Parameters.Clear(); + cmd.Parameters.Clear(); - cmd.CommandText = "replace into primshapes (" + - "UUID, Shape, ScaleX, ScaleY, " + - "ScaleZ, PCode, PathBegin, PathEnd, " + - "PathScaleX, PathScaleY, PathShearX, " + - "PathShearY, PathSkew, PathCurve, " + - "PathRadiusOffset, PathRevolutions, " + - "PathTaperX, PathTaperY, PathTwist, " + - "PathTwistBegin, ProfileBegin, ProfileEnd, " + - "ProfileCurve, ProfileHollow, Texture, " + - "ExtraParams, State, Media) values (?UUID, " + - "?Shape, ?ScaleX, ?ScaleY, ?ScaleZ, " + - "?PCode, ?PathBegin, ?PathEnd, " + - "?PathScaleX, ?PathScaleY, " + - "?PathShearX, ?PathShearY, " + - "?PathSkew, ?PathCurve, ?PathRadiusOffset, " + - "?PathRevolutions, ?PathTaperX, " + - "?PathTaperY, ?PathTwist, " + - "?PathTwistBegin, ?ProfileBegin, " + - "?ProfileEnd, ?ProfileCurve, " + - "?ProfileHollow, ?Texture, ?ExtraParams, " + - "?State, ?Media)"; + cmd.CommandText = "replace into primshapes (" + + "UUID, Shape, ScaleX, ScaleY, " + + "ScaleZ, PCode, PathBegin, PathEnd, " + + "PathScaleX, PathScaleY, PathShearX, " + + "PathShearY, PathSkew, PathCurve, " + + "PathRadiusOffset, PathRevolutions, " + + "PathTaperX, PathTaperY, PathTwist, " + + "PathTwistBegin, ProfileBegin, ProfileEnd, " + + "ProfileCurve, ProfileHollow, Texture, " + + "ExtraParams, State, Media) values (?UUID, " + + "?Shape, ?ScaleX, ?ScaleY, ?ScaleZ, " + + "?PCode, ?PathBegin, ?PathEnd, " + + "?PathScaleX, ?PathScaleY, " + + "?PathShearX, ?PathShearY, " + + "?PathSkew, ?PathCurve, ?PathRadiusOffset, " + + "?PathRevolutions, ?PathTaperX, " + + "?PathTaperY, ?PathTwist, " + + "?PathTwistBegin, ?ProfileBegin, " + + "?ProfileEnd, ?ProfileCurve, " + + "?ProfileHollow, ?Texture, ?ExtraParams, " + + "?State, ?Media)"; - FillShapeCommand(cmd, prim); + FillShapeCommand(cmd, prim); - ExecuteNonQuery(cmd); + ExecuteNonQuery(cmd); + } } - - cmd.Dispose(); } } } @@ -997,6 +997,68 @@ namespace OpenSim.Data.MySQL } } + #region RegionEnvironmentSettings + public string LoadRegionEnvironmentSettings(UUID regionUUID) + { + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + { + dbcon.Open(); + + string command = "select * from `regionenvironment` where region_id = ?region_id"; + + using (MySqlCommand cmd = new MySqlCommand(command)) + { + cmd.Connection = dbcon; + + cmd.Parameters.AddWithValue("?region_id", regionUUID.ToString()); + + IDataReader result = ExecuteReader(cmd); + if (!result.Read()) + { + return String.Empty; + } + else + { + return Convert.ToString(result["llsd_settings"]); + } + } + } + } + + public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) + { + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + { + dbcon.Open(); + + using (MySqlCommand cmd = dbcon.CreateCommand()) + { + cmd.CommandText = "REPLACE INTO `regionenvironment` (`region_id`, `llsd_settings`) VALUES (?region_id, ?llsd_settings)"; + + cmd.Parameters.AddWithValue("region_id", regionUUID); + cmd.Parameters.AddWithValue("llsd_settings", settings); + + ExecuteNonQuery(cmd); + } + } + } + + public void RemoveRegionEnvironmentSettings(UUID regionUUID) + { + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) + { + dbcon.Open(); + + using (MySqlCommand cmd = dbcon.CreateCommand()) + { + cmd.CommandText = "delete from `regionenvironment` where region_id = ?region_id"; + cmd.Parameters.AddWithValue("?region_id", regionUUID.ToString()); + ExecuteNonQuery(cmd); + } + } + } + #endregion + public virtual void StoreRegionSettings(RegionSettings rs) { lock (m_dbLock) @@ -1897,41 +1959,40 @@ namespace OpenSim.Data.MySQL { RemoveItems(primID); + if (items.Count == 0) + return; + using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) { dbcon.Open(); - MySqlCommand cmd = dbcon.CreateCommand(); - - if (items.Count == 0) - return; - - cmd.CommandText = "insert into primitems (" + - "invType, assetType, name, " + - "description, creationDate, nextPermissions, " + - "currentPermissions, basePermissions, " + - "everyonePermissions, groupPermissions, " + - "flags, itemID, primID, assetID, " + - "parentFolderID, creatorID, ownerID, " + - "groupID, lastOwnerID) values (?invType, " + - "?assetType, ?name, ?description, " + - "?creationDate, ?nextPermissions, " + - "?currentPermissions, ?basePermissions, " + - "?everyonePermissions, ?groupPermissions, " + - "?flags, ?itemID, ?primID, ?assetID, " + - "?parentFolderID, ?creatorID, ?ownerID, " + - "?groupID, ?lastOwnerID)"; - - foreach (TaskInventoryItem item in items) + using (MySqlCommand cmd = dbcon.CreateCommand()) { - cmd.Parameters.Clear(); - - FillItemCommand(cmd, item); - - ExecuteNonQuery(cmd); + cmd.CommandText = "insert into primitems (" + + "invType, assetType, name, " + + "description, creationDate, nextPermissions, " + + "currentPermissions, basePermissions, " + + "everyonePermissions, groupPermissions, " + + "flags, itemID, primID, assetID, " + + "parentFolderID, creatorID, ownerID, " + + "groupID, lastOwnerID) values (?invType, " + + "?assetType, ?name, ?description, " + + "?creationDate, ?nextPermissions, " + + "?currentPermissions, ?basePermissions, " + + "?everyonePermissions, ?groupPermissions, " + + "?flags, ?itemID, ?primID, ?assetID, " + + "?parentFolderID, ?creatorID, ?ownerID, " + + "?groupID, ?lastOwnerID)"; + + foreach (TaskInventoryItem item in items) + { + cmd.Parameters.Clear(); + + FillItemCommand(cmd, item); + + ExecuteNonQuery(cmd); + } } - - cmd.Dispose(); } } } diff --git a/OpenSim/Data/MySQL/MySQLUserAccountData.cs b/OpenSim/Data/MySQL/MySQLUserAccountData.cs index a18ac66ef6..4ff3175e09 100644 --- a/OpenSim/Data/MySQL/MySQLUserAccountData.cs +++ b/OpenSim/Data/MySQL/MySQLUserAccountData.cs @@ -66,38 +66,40 @@ namespace OpenSim.Data.MySQL if (words.Length > 2) return new UserAccountData[0]; - MySqlCommand cmd = new MySqlCommand(); - - if (words.Length == 1) + using (MySqlCommand cmd = new MySqlCommand()) { - cmd.CommandText = String.Format("select * from {0} where (ScopeID=?ScopeID or ScopeID='00000000-0000-0000-0000-000000000000') and (FirstName like ?search or LastName like ?search) and active=1", m_Realm); - cmd.Parameters.AddWithValue("?search", words[0] + "%"); - cmd.Parameters.AddWithValue("?ScopeID", scopeID.ToString()); - } - else - { - cmd.CommandText = String.Format("select * from {0} where (ScopeID=?ScopeID or ScopeID='00000000-0000-0000-0000-000000000000') and (FirstName like ?searchFirst and LastName like ?searchLast) and active=1", m_Realm); - cmd.Parameters.AddWithValue("?searchFirst", words[0] + "%"); - cmd.Parameters.AddWithValue("?searchLast", words[1] + "%"); - cmd.Parameters.AddWithValue("?ScopeID", scopeID.ToString()); - } + if (words.Length == 1) + { + cmd.CommandText = String.Format("select * from {0} where (ScopeID=?ScopeID or ScopeID='00000000-0000-0000-0000-000000000000') and (FirstName like ?search or LastName like ?search) and active=1", m_Realm); + cmd.Parameters.AddWithValue("?search", words[0] + "%"); + cmd.Parameters.AddWithValue("?ScopeID", scopeID.ToString()); + } + else + { + cmd.CommandText = String.Format("select * from {0} where (ScopeID=?ScopeID or ScopeID='00000000-0000-0000-0000-000000000000') and (FirstName like ?searchFirst and LastName like ?searchLast) and active=1", m_Realm); + cmd.Parameters.AddWithValue("?searchFirst", words[0] + "%"); + cmd.Parameters.AddWithValue("?searchLast", words[1] + "%"); + cmd.Parameters.AddWithValue("?ScopeID", scopeID.ToString()); + } - return DoQuery(cmd); + return DoQuery(cmd); + } } public UserAccountData[] GetUsersWhere(UUID scopeID, string where) { - MySqlCommand cmd = new MySqlCommand(); - - if (scopeID != UUID.Zero) + using (MySqlCommand cmd = new MySqlCommand()) { - where = "(ScopeID=?ScopeID or ScopeID='00000000-0000-0000-0000-000000000000') and (" + where + ")"; - cmd.Parameters.AddWithValue("?ScopeID", scopeID.ToString()); + if (scopeID != UUID.Zero) + { + where = "(ScopeID=?ScopeID or ScopeID='00000000-0000-0000-0000-000000000000') and (" + where + ")"; + cmd.Parameters.AddWithValue("?ScopeID", scopeID.ToString()); + } + + cmd.CommandText = String.Format("select * from {0} where " + where, m_Realm); + + return DoQuery(cmd); } - - cmd.CommandText = String.Format("select * from {0} where " + where, m_Realm); - - return DoQuery(cmd); } } } diff --git a/OpenSim/Data/MySQL/Resources/RegionStore.migrations b/OpenSim/Data/MySQL/Resources/RegionStore.migrations index ef99ef8d7c..db0d0ec399 100644 --- a/OpenSim/Data/MySQL/Resources/RegionStore.migrations +++ b/OpenSim/Data/MySQL/Resources/RegionStore.migrations @@ -883,3 +883,15 @@ ALTER TABLE `regionsettings` MODIFY COLUMN `TelehubObject` VARCHAR(36) NOT NULL COMMIT; +:VERSION 44 #--------------------- Environment Settings + +BEGIN; + +CREATE TABLE `regionenvironment` ( + `region_id` varchar(36) NOT NULL, + `llsd_settings` TEXT NOT NULL, + PRIMARY KEY (`region_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +COMMIT; + diff --git a/OpenSim/Data/Null/NullSimulationData.cs b/OpenSim/Data/Null/NullSimulationData.cs index 24b4511cf7..a39ef0b5fe 100644 --- a/OpenSim/Data/Null/NullSimulationData.cs +++ b/OpenSim/Data/Null/NullSimulationData.cs @@ -76,9 +76,27 @@ namespace OpenSim.Data.Null //This connector doesn't support the windlight module yet } + #region Environment Settings + public string LoadRegionEnvironmentSettings(UUID regionUUID) + { + //This connector doesn't support the Environment module yet + return string.Empty; + } + + public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) + { + //This connector doesn't support the Environment module yet + } + + public void RemoveRegionEnvironmentSettings(UUID regionUUID) + { + //This connector doesn't support the Environment module yet + } + #endregion + public RegionSettings LoadRegionSettings(UUID regionUUID) - { - RegionSettings rs = new RegionSettings(); + { + RegionSettings rs = new RegionSettings(); rs.RegionUUID = regionUUID; return rs; } diff --git a/OpenSim/Data/SQLite/Resources/RegionStore.migrations b/OpenSim/Data/SQLite/Resources/RegionStore.migrations index 1ceddf98a1..e872977634 100644 --- a/OpenSim/Data/SQLite/Resources/RegionStore.migrations +++ b/OpenSim/Data/SQLite/Resources/RegionStore.migrations @@ -564,3 +564,14 @@ COMMIT; BEGIN; ALTER TABLE `regionsettings` ADD COLUMN `parcel_tile_ID` char(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'; COMMIT; + +:VERSION 26 + +BEGIN; + +CREATE TABLE `regionenvironment` ( + `region_id` varchar(36) NOT NULL DEFAULT '000000-0000-0000-0000-000000000000' PRIMARY KEY, + `llsd_settings` TEXT NOT NULL +); + +COMMIT; diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs index 9ec285c979..9175a8fa8c 100644 --- a/OpenSim/Data/SQLite/SQLiteSimulationData.cs +++ b/OpenSim/Data/SQLite/SQLiteSimulationData.cs @@ -61,6 +61,7 @@ namespace OpenSim.Data.SQLite private const string regionbanListSelect = "select * from regionban"; private const string regionSettingsSelect = "select * from regionsettings"; private const string regionWindlightSelect = "select * from regionwindlight"; + private const string regionEnvironmentSelect = "select * from regionenvironment"; private const string regionSpawnPointsSelect = "select * from spawn_points"; private DataSet ds; @@ -72,6 +73,7 @@ namespace OpenSim.Data.SQLite private SqliteDataAdapter landAccessListDa; private SqliteDataAdapter regionSettingsDa; private SqliteDataAdapter regionWindlightDa; + private SqliteDataAdapter regionEnvironmentDa; private SqliteDataAdapter regionSpawnPointsDa; private SqliteConnection m_conn; @@ -146,6 +148,9 @@ namespace OpenSim.Data.SQLite SqliteCommand regionWindlightSelectCmd = new SqliteCommand(regionWindlightSelect, m_conn); regionWindlightDa = new SqliteDataAdapter(regionWindlightSelectCmd); + SqliteCommand regionEnvironmentSelectCmd = new SqliteCommand(regionEnvironmentSelect, m_conn); + regionEnvironmentDa = new SqliteDataAdapter(regionEnvironmentSelectCmd); + SqliteCommand regionSpawnPointsSelectCmd = new SqliteCommand(regionSpawnPointsSelect, m_conn); regionSpawnPointsDa = new SqliteDataAdapter(regionSpawnPointsSelectCmd); @@ -179,6 +184,9 @@ namespace OpenSim.Data.SQLite ds.Tables.Add(createRegionWindlightTable()); setupRegionWindlightCommands(regionWindlightDa, m_conn); + ds.Tables.Add(createRegionEnvironmentTable()); + setupRegionEnvironmentCommands(regionEnvironmentDa, m_conn); + ds.Tables.Add(createRegionSpawnPointsTable()); setupRegionSpawnPointsCommands(regionSpawnPointsDa, m_conn); @@ -258,6 +266,15 @@ namespace OpenSim.Data.SQLite m_log.ErrorFormat("[SQLITE REGION DB]: Caught fill error on regionwindlight table :{0}", e.Message); } + try + { + regionEnvironmentDa.Fill(ds.Tables["regionenvironment"]); + } + catch (Exception e) + { + m_log.ErrorFormat("[SQLITE REGION DB]: Caught fill error on regionenvironment table :{0}", e.Message); + } + try { regionSpawnPointsDa.Fill(ds.Tables["spawn_points"]); @@ -278,12 +295,13 @@ namespace OpenSim.Data.SQLite CreateDataSetMapping(landAccessListDa, "landaccesslist"); CreateDataSetMapping(regionSettingsDa, "regionsettings"); CreateDataSetMapping(regionWindlightDa, "regionwindlight"); + CreateDataSetMapping(regionEnvironmentDa, "regionenvironment"); CreateDataSetMapping(regionSpawnPointsDa, "spawn_points"); } } catch (Exception e) { - m_log.ErrorFormat("[SQLITE REGION DB]: ", e); + m_log.ErrorFormat("[SQLITE REGION DB]: {0} - {1}", e.Message, e.StackTrace); Environment.Exit(23); } return; @@ -341,6 +359,11 @@ namespace OpenSim.Data.SQLite regionWindlightDa.Dispose(); regionWindlightDa = null; } + if (regionEnvironmentDa != null) + { + regionEnvironmentDa.Dispose(); + regionEnvironmentDa = null; + } if (regionSpawnPointsDa != null) { regionSpawnPointsDa.Dispose(); @@ -474,6 +497,63 @@ namespace OpenSim.Data.SQLite } } + #region Region Environment Settings + public string LoadRegionEnvironmentSettings(UUID regionUUID) + { + lock (ds) + { + DataTable environmentTable = ds.Tables["regionenvironment"]; + DataRow row = environmentTable.Rows.Find(regionUUID.ToString()); + if (row == null) + { + return String.Empty; + } + + return (String)row["llsd_settings"]; + } + } + + public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) + { + lock (ds) + { + DataTable environmentTable = ds.Tables["regionenvironment"]; + DataRow row = environmentTable.Rows.Find(regionUUID.ToString()); + + if (row == null) + { + row = environmentTable.NewRow(); + row["region_id"] = regionUUID.ToString(); + row["llsd_settings"] = settings; + environmentTable.Rows.Add(row); + } + else + { + row["llsd_settings"] = settings; + } + + regionEnvironmentDa.Update(ds, "regionenvironment"); + } + } + + public void RemoveRegionEnvironmentSettings(UUID regionUUID) + { + lock (ds) + { + DataTable environmentTable = ds.Tables["regionenvironment"]; + DataRow row = environmentTable.Rows.Find(regionUUID.ToString()); + + if (row != null) + { + row.Delete(); + } + + regionEnvironmentDa.Update(ds, "regionenvironment"); + } + } + + #endregion + public RegionSettings LoadRegionSettings(UUID regionUUID) { lock (ds) @@ -1430,6 +1510,17 @@ namespace OpenSim.Data.SQLite return regionwindlight; } + private static DataTable createRegionEnvironmentTable() + { + DataTable regionEnvironment = new DataTable("regionenvironment"); + createCol(regionEnvironment, "region_id", typeof(String)); + createCol(regionEnvironment, "llsd_settings", typeof(String)); + + regionEnvironment.PrimaryKey = new DataColumn[] { regionEnvironment.Columns["region_id"] }; + + return regionEnvironment; + } + private static DataTable createRegionSpawnPointsTable() { DataTable spawn_points = new DataTable("spawn_points"); @@ -2691,6 +2782,14 @@ namespace OpenSim.Data.SQLite da.UpdateCommand.Connection = conn; } + private void setupRegionEnvironmentCommands(SqliteDataAdapter da, SqliteConnection conn) + { + da.InsertCommand = createInsertCommand("regionenvironment", ds.Tables["regionenvironment"]); + da.InsertCommand.Connection = conn; + da.UpdateCommand = createUpdateCommand("regionenvironment", "region_id=:region_id", ds.Tables["regionenvironment"]); + da.UpdateCommand.Connection = conn; + } + private void setupRegionSpawnPointsCommands(SqliteDataAdapter da, SqliteConnection conn) { da.InsertCommand = createInsertCommand("spawn_points", ds.Tables["spawn_points"]); diff --git a/OpenSim/Data/Tests/RegionTests.cs b/OpenSim/Data/Tests/RegionTests.cs index 474609bb08..dbed8f65d7 100644 --- a/OpenSim/Data/Tests/RegionTests.cs +++ b/OpenSim/Data/Tests/RegionTests.cs @@ -1069,8 +1069,6 @@ namespace OpenSim.Data.Tests regionInfo.RegionLocX = 0; regionInfo.RegionLocY = 0; - Scene scene = new Scene(regionInfo); - SceneObjectPart sop = new SceneObjectPart(); sop.Name = name; sop.Description = name; @@ -1081,7 +1079,7 @@ namespace OpenSim.Data.Tests sop.Shape = PrimitiveBaseShape.Default; SceneObjectGroup sog = new SceneObjectGroup(sop); - sog.SetScene(scene); +// sog.SetScene(scene); return sog; } diff --git a/OpenSim/Framework/AgentCircuitData.cs b/OpenSim/Framework/AgentCircuitData.cs index 57fb808dc1..ffcc5840e8 100644 --- a/OpenSim/Framework/AgentCircuitData.cs +++ b/OpenSim/Framework/AgentCircuitData.cs @@ -98,6 +98,11 @@ namespace OpenSim.Framework /// public string lastname; + /// + /// Agent's full name. + /// + public string Name { get { return string.Format("{0} {1}", firstname, lastname); } } + /// /// Random Unique GUID for this session. Client gets this at login and it's /// only supposed to be disclosed over secure channels diff --git a/OpenSim/Framework/Console/CommandConsole.cs b/OpenSim/Framework/Console/CommandConsole.cs index c5d6b78686..87bdacd2da 100644 --- a/OpenSim/Framework/Console/CommandConsole.cs +++ b/OpenSim/Framework/Console/CommandConsole.cs @@ -79,7 +79,11 @@ namespace OpenSim.Framework.Console public List fn; } - public const string GeneralHelpText = "For more information, type 'help ' where is one of the following categories:"; + public const string GeneralHelpText + = "To enter an argument that contains spaces, surround the argument with double quotes.\nFor example, show object name \"My long object name\"\n"; + + public const string ItemHelpText + = "For more information, type 'help ' where is one of the following:"; /// /// Commands organized by keyword in a tree @@ -108,7 +112,9 @@ namespace OpenSim.Framework.Console // General help if (helpParts.Count == 0) { + help.Add(""); // Will become a newline. help.Add(GeneralHelpText); + help.Add(ItemHelpText); help.AddRange(CollectModulesHelp(tree)); } else @@ -132,7 +138,7 @@ namespace OpenSim.Framework.Console // Check modules first to see if we just need to display a list of those commands if (TryCollectModuleHelp(originalHelpRequest, help)) { - help.Insert(0, GeneralHelpText); + help.Insert(0, ItemHelpText); return help; } diff --git a/OpenSim/Framework/Console/ConsoleDisplayList.cs b/OpenSim/Framework/Console/ConsoleDisplayList.cs new file mode 100644 index 0000000000..68855091d4 --- /dev/null +++ b/OpenSim/Framework/Console/ConsoleDisplayList.cs @@ -0,0 +1,112 @@ +/* + * 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 System.Text; + +namespace OpenSim.Framework.Console +{ + /// + /// Used to generated a formatted table for the console. + /// + /// + /// Currently subject to change. If you use this, be prepared to change your code when this class changes. + /// + public class ConsoleDisplayList + { + /// + /// The default divider between key and value for a list item. + /// + public const string DefaultKeyValueDivider = " : "; + + /// + /// The divider used between key and value for a list item. + /// + public string KeyValueDivider { get; set; } + + /// + /// Table rows + /// + public List> Rows { get; private set; } + + /// + /// Number of spaces to indent the list. + /// + public int Indent { get; set; } + + public ConsoleDisplayList() + { + Rows = new List>(); + KeyValueDivider = DefaultKeyValueDivider; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + AddToStringBuilder(sb); + return sb.ToString(); + } + + public void AddToStringBuilder(StringBuilder sb) + { + string formatString = GetFormatString(); +// System.Console.WriteLine("FORMAT STRING [{0}]", formatString); + + // rows + foreach (KeyValuePair row in Rows) + sb.AppendFormat(formatString, row.Key, row.Value); + } + + /// + /// Gets the format string for the table. + /// + private string GetFormatString() + { + StringBuilder formatSb = new StringBuilder(); + + int longestKey = -1; + + foreach (KeyValuePair row in Rows) + if (row.Key.Length > longestKey) + longestKey = row.Key.Length; + + formatSb.Append(' ', Indent); + + // Can only do left formatting for now + formatSb.AppendFormat("{{0,-{0}}}{1}{{1}}\n", longestKey, KeyValueDivider); + + return formatSb.ToString(); + } + + public void AddRow(object key, object value) + { + Rows.Add(new KeyValuePair(key.ToString(), value.ToString())); + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/Console/ConsoleDisplayTable.cs b/OpenSim/Framework/Console/ConsoleDisplayTable.cs new file mode 100644 index 0000000000..c620dfe10c --- /dev/null +++ b/OpenSim/Framework/Console/ConsoleDisplayTable.cs @@ -0,0 +1,154 @@ +/* + * 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 System.Text; + +namespace OpenSim.Framework.Console +{ + /// + /// Used to generated a formatted table for the console. + /// + /// + /// Currently subject to change. If you use this, be prepared to change your code when this class changes. + /// + public class ConsoleDisplayTable + { + /// + /// Default number of spaces between table columns. + /// + public const int DefaultTableSpacing = 2; + + /// + /// Table columns. + /// + public List Columns { get; private set; } + + /// + /// Table rows + /// + public List Rows { get; private set; } + + /// + /// Number of spaces to indent the table. + /// + public int Indent { get; set; } + + /// + /// Spacing between table columns + /// + public int TableSpacing { get; set; } + + public ConsoleDisplayTable() + { + TableSpacing = DefaultTableSpacing; + Columns = new List(); + Rows = new List(); + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + AddToStringBuilder(sb); + return sb.ToString(); + } + + public void AddColumn(string name, int width) + { + Columns.Add(new ConsoleDisplayTableColumn(name, width)); + } + + public void AddRow(params string[] cells) + { + Rows.Add(new ConsoleDisplayTableRow(cells)); + } + + public void AddToStringBuilder(StringBuilder sb) + { + string formatString = GetFormatString(); +// System.Console.WriteLine("FORMAT STRING [{0}]", formatString); + + // columns + sb.AppendFormat(formatString, Columns.ConvertAll(c => c.Header).ToArray()); + + // rows + foreach (ConsoleDisplayTableRow row in Rows) + sb.AppendFormat(formatString, row.Cells.ToArray()); + } + + /// + /// Gets the format string for the table. + /// + private string GetFormatString() + { + StringBuilder formatSb = new StringBuilder(); + + formatSb.Append(' ', Indent); + + for (int i = 0; i < Columns.Count; i++) + { + formatSb.Append(' ', TableSpacing); + + // Can only do left formatting for now + formatSb.AppendFormat("{{{0},-{1}}}", i, Columns[i].Width); + } + + formatSb.Append('\n'); + + return formatSb.ToString(); + } + } + + public struct ConsoleDisplayTableColumn + { + public string Header { get; set; } + public int Width { get; set; } + + public ConsoleDisplayTableColumn(string header, int width) : this() + { + Header = header; + Width = width; + } + } + + public struct ConsoleDisplayTableRow + { + public List Cells { get; private set; } + + public ConsoleDisplayTableRow(List cells) : this() + { + Cells = cells; + } + + public ConsoleDisplayTableRow(params string[] cells) : this() + { + Cells = new List(cells); + } + } +} \ No newline at end of file diff --git a/OpenSim/Framework/Console/LocalConsole.cs b/OpenSim/Framework/Console/LocalConsole.cs index 7c8626dac0..f65813b9ee 100644 --- a/OpenSim/Framework/Console/LocalConsole.cs +++ b/OpenSim/Framework/Console/LocalConsole.cs @@ -296,6 +296,10 @@ namespace OpenSim.Framework.Console matches[0].Groups["Category"].Value); System.Console.Write("]:"); } + else + { + outText = outText.Trim(); + } } if (level == "error") diff --git a/OpenSim/Framework/EstateSettings.cs b/OpenSim/Framework/EstateSettings.cs index 142b78393b..9020761cad 100644 --- a/OpenSim/Framework/EstateSettings.cs +++ b/OpenSim/Framework/EstateSettings.cs @@ -346,7 +346,7 @@ namespace OpenSim.Framework l_EstateManagers.Remove(avatarID); } - public bool IsEstateManager(UUID avatarID) + public bool IsEstateManagerOrOwner(UUID avatarID) { if (IsEstateOwner(avatarID)) return true; @@ -368,7 +368,7 @@ namespace OpenSim.Framework if (ban.BannedUserID == avatarID) return true; - if (!IsEstateManager(avatarID) && !HasAccess(avatarID)) + if (!IsEstateManagerOrOwner(avatarID) && !HasAccess(avatarID)) { if (DenyMinors) { @@ -411,7 +411,7 @@ namespace OpenSim.Framework public bool HasAccess(UUID user) { - if (IsEstateManager(user)) + if (IsEstateManagerOrOwner(user)) return true; return l_EstateAccess.Contains(user); diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index c1bd07886d..58a65de0c7 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -749,14 +749,21 @@ namespace OpenSim.Framework /// string Name { get; } - /// - /// Determines whether the client thread is doing anything or not. - /// + /// + /// True if the client is active (sending and receiving new UDP messages). False if the client is being closed. + /// bool IsActive { get; set; } - /// - /// Determines whether the client is or has been removed from a given scene - /// + /// + /// Set if the client is closing due to a logout request + /// + /// + /// Do not use this flag if you want to know if the client is closing, since it will not be set in other + /// circumstances (e.g. if a child agent is closed or the agent is kicked off the simulator). Use IsActive + /// instead with a IClientAPI.SceneAgent.IsChildAgent check if necessary. + /// + /// Only set for root agents. + /// bool IsLoggingOut { get; set; } bool SendLogoutPacketWhenClosing { set; } @@ -1362,7 +1369,6 @@ namespace OpenSim.Framework void SendBlueBoxMessage(UUID FromAvatarID, String FromAvatarName, String Message); void SendLogoutPacket(); - EndPoint GetClientEP(); // WARNING WARNING WARNING // @@ -1423,8 +1429,6 @@ namespace OpenSim.Framework void SendGroupVoteHistory(UUID groupID, UUID transactionID, GroupVoteHistory[] Votes); - void KillEndDone(); - bool AddGenericPacketHandler(string MethodName, GenericMessage handler); void SendRebakeAvatarTextures(UUID textureID); diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs index b2604f4a39..a9432c2df3 100644 --- a/OpenSim/Framework/IScene.cs +++ b/OpenSim/Framework/IScene.cs @@ -56,6 +56,11 @@ namespace OpenSim.Framework public interface IScene { + /// + /// The name of this scene. + /// + string Name { get; } + RegionInfo RegionInfo { get; } RegionStatus RegionStatus { get; set; } diff --git a/OpenSim/Framework/ISceneAgent.cs b/OpenSim/Framework/ISceneAgent.cs index 824172d58a..563d906b7f 100644 --- a/OpenSim/Framework/ISceneAgent.cs +++ b/OpenSim/Framework/ISceneAgent.cs @@ -26,6 +26,7 @@ */ using System; +using OpenMetaverse; namespace OpenSim.Framework { @@ -71,5 +72,11 @@ namespace OpenSim.Framework /// This includes scene object data and the appearance data of other avatars. /// void SendInitialDataToMe(); + + /// + /// Direction in which the scene presence is looking. + /// + /// Will be Vector3.Zero for a child agent. + Vector3 Lookat { get; } } } \ No newline at end of file diff --git a/OpenSim/Framework/PrimitiveBaseShape.cs b/OpenSim/Framework/PrimitiveBaseShape.cs index c6ccc9e5eb..fcc9873441 100644 --- a/OpenSim/Framework/PrimitiveBaseShape.cs +++ b/OpenSim/Framework/PrimitiveBaseShape.cs @@ -241,10 +241,14 @@ namespace OpenSim.Framework m_textureEntry = prim.Textures.GetBytes(); - SculptEntry = (prim.Sculpt.Type != OpenMetaverse.SculptType.None); - SculptData = prim.Sculpt.GetBytes(); - SculptTexture = prim.Sculpt.SculptTexture; - SculptType = (byte)prim.Sculpt.Type; + if (prim.Sculpt != null) + { + SculptEntry = (prim.Sculpt.Type != OpenMetaverse.SculptType.None); + SculptData = prim.Sculpt.GetBytes(); + SculptTexture = prim.Sculpt.SculptTexture; + SculptType = (byte)prim.Sculpt.Type; + } + else SculptType = (byte)OpenMetaverse.SculptType.None; } [XmlIgnore] diff --git a/OpenSim/Framework/RegionSettings.cs b/OpenSim/Framework/RegionSettings.cs index c142bd9ae0..47a27807b2 100644 --- a/OpenSim/Framework/RegionSettings.cs +++ b/OpenSim/Framework/RegionSettings.cs @@ -29,6 +29,7 @@ using System; using System.Collections.Generic; using System.IO; using OpenMetaverse; +using System.Runtime.Serialization; namespace OpenSim.Framework { @@ -71,6 +72,32 @@ namespace OpenSim.Framework return pos + offset; } + + /// + /// Returns a string representation of this SpawnPoint. + /// + /// + public override string ToString() + { + return string.Format("{0},{1},{2}", Yaw, Pitch, Distance); + } + + /// + /// Generate a SpawnPoint from a string + /// + /// + public static SpawnPoint Parse(string str) + { + string[] parts = str.Split(','); + if (parts.Length != 3) + throw new ArgumentException("Invalid string: " + str); + + SpawnPoint sp = new SpawnPoint(); + sp.Yaw = float.Parse(parts[0]); + sp.Pitch = float.Parse(parts[1]); + sp.Distance = float.Parse(parts[2]); + return sp; + } } public class RegionSettings @@ -478,7 +505,7 @@ namespace OpenSim.Framework } // Connected Telehub object - private UUID m_TelehubObject; + private UUID m_TelehubObject = UUID.Zero; public UUID TelehubObject { get diff --git a/OpenSim/Framework/SLUtil.cs b/OpenSim/Framework/SLUtil.cs index db4541ef1a..537de7ab15 100644 --- a/OpenSim/Framework/SLUtil.cs +++ b/OpenSim/Framework/SLUtil.cs @@ -38,239 +38,189 @@ namespace OpenSim.Framework public static class SLUtil { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + #region SL / file extension / content-type conversions + private class TypeMapping + { + private sbyte assetType; + private InventoryType inventoryType; + private string contentType; + private string contentType2; + private string extension; + + public sbyte AssetTypeCode + { + get { return assetType; } + } + + public object AssetType + { + get { + if (Enum.IsDefined(typeof(OpenMetaverse.AssetType), assetType)) + return (OpenMetaverse.AssetType)assetType; + else + return OpenMetaverse.AssetType.Unknown; + } + } + + public InventoryType InventoryType + { + get { return inventoryType; } + } + + public string ContentType + { + get { return contentType; } + } + + public string ContentType2 + { + get { return contentType2; } + } + + public string Extension + { + get { return extension; } + } + + private TypeMapping(sbyte assetType, InventoryType inventoryType, string contentType, string contentType2, string extension) + { + this.assetType = assetType; + this.inventoryType = inventoryType; + this.contentType = contentType; + this.contentType2 = contentType2; + this.extension = extension; + } + + public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string contentType2, string extension) + : this((sbyte)assetType, inventoryType, contentType, contentType2, extension) + { + } + + public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string extension) + : this((sbyte)assetType, inventoryType, contentType, null, extension) + { + } + } + + /// + /// Maps between AssetType, InventoryType and Content-Type. + /// Where more than one possibility exists, the first one takes precedence. E.g.: + /// AssetType "AssetType.Texture" -> Content-Type "image-xj2c" + /// Content-Type "image/x-j2c" -> InventoryType "InventoryType.Texture" + /// + private static TypeMapping[] MAPPINGS = new TypeMapping[] { + new TypeMapping(AssetType.Unknown, InventoryType.Unknown, "application/octet-stream", "bin"), + new TypeMapping(AssetType.Texture, InventoryType.Texture, "image/x-j2c", "image/jp2", "j2c"), + new TypeMapping(AssetType.Texture, InventoryType.Snapshot, "image/x-j2c", "image/jp2", "j2c"), + new TypeMapping(AssetType.TextureTGA, InventoryType.Texture, "image/tga", "tga"), + new TypeMapping(AssetType.ImageTGA, InventoryType.Texture, "image/tga", "tga"), + new TypeMapping(AssetType.ImageJPEG, InventoryType.Texture, "image/jpeg", "jpg"), + new TypeMapping(AssetType.Sound, InventoryType.Sound, "audio/ogg", "application/ogg", "ogg"), + new TypeMapping(AssetType.SoundWAV, InventoryType.Sound, "audio/x-wav", "wav"), + new TypeMapping(AssetType.CallingCard, InventoryType.CallingCard, "application/vnd.ll.callingcard", "application/x-metaverse-callingcard", "callingcard"), + new TypeMapping(AssetType.Landmark, InventoryType.Landmark, "application/vnd.ll.landmark", "application/x-metaverse-landmark", "landmark"), + new TypeMapping(AssetType.Clothing, InventoryType.Wearable, "application/vnd.ll.clothing", "application/x-metaverse-clothing", "clothing"), + new TypeMapping(AssetType.Object, InventoryType.Object, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"), + new TypeMapping(AssetType.Object, InventoryType.Attachment, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"), + new TypeMapping(AssetType.Notecard, InventoryType.Notecard, "application/vnd.ll.notecard", "application/x-metaverse-notecard", "notecard"), + new TypeMapping(AssetType.Folder, InventoryType.Folder, "application/vnd.ll.folder", "folder"), + new TypeMapping(AssetType.RootFolder, InventoryType.RootCategory, "application/vnd.ll.rootfolder", "rootfolder"), + new TypeMapping(AssetType.LSLText, InventoryType.LSL, "application/vnd.ll.lsltext", "application/x-metaverse-lsl", "lsl"), + new TypeMapping(AssetType.LSLBytecode, InventoryType.LSL, "application/vnd.ll.lslbyte", "application/x-metaverse-lso", "lso"), + new TypeMapping(AssetType.Bodypart, InventoryType.Wearable, "application/vnd.ll.bodypart", "application/x-metaverse-bodypart", "bodypart"), + new TypeMapping(AssetType.TrashFolder, InventoryType.Folder, "application/vnd.ll.trashfolder", "trashfolder"), + new TypeMapping(AssetType.SnapshotFolder, InventoryType.Folder, "application/vnd.ll.snapshotfolder", "snapshotfolder"), + new TypeMapping(AssetType.LostAndFoundFolder, InventoryType.Folder, "application/vnd.ll.lostandfoundfolder", "lostandfoundfolder"), + new TypeMapping(AssetType.Animation, InventoryType.Animation, "application/vnd.ll.animation", "application/x-metaverse-animation", "animation"), + new TypeMapping(AssetType.Gesture, InventoryType.Gesture, "application/vnd.ll.gesture", "application/x-metaverse-gesture", "gesture"), + new TypeMapping(AssetType.Simstate, InventoryType.Snapshot, "application/x-metaverse-simstate", "simstate"), + new TypeMapping(AssetType.FavoriteFolder, InventoryType.Unknown, "application/vnd.ll.favoritefolder", "favoritefolder"), + new TypeMapping(AssetType.Link, InventoryType.Unknown, "application/vnd.ll.link", "link"), + new TypeMapping(AssetType.LinkFolder, InventoryType.Unknown, "application/vnd.ll.linkfolder", "linkfolder"), + new TypeMapping(AssetType.CurrentOutfitFolder, InventoryType.Unknown, "application/vnd.ll.currentoutfitfolder", "currentoutfitfolder"), + new TypeMapping(AssetType.OutfitFolder, InventoryType.Unknown, "application/vnd.ll.outfitfolder", "outfitfolder"), + new TypeMapping(AssetType.MyOutfitsFolder, InventoryType.Unknown, "application/vnd.ll.myoutfitsfolder", "myoutfitsfolder"), + new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm") + }; + + private static Dictionary asset2Content; + private static Dictionary asset2Extension; + private static Dictionary inventory2Content; + private static Dictionary content2Asset; + private static Dictionary content2Inventory; + + static SLUtil() + { + asset2Content = new Dictionary(); + asset2Extension = new Dictionary(); + inventory2Content = new Dictionary(); + content2Asset = new Dictionary(); + content2Inventory = new Dictionary(); + + foreach (TypeMapping mapping in MAPPINGS) + { + sbyte assetType = mapping.AssetTypeCode; + if (!asset2Content.ContainsKey(assetType)) + asset2Content.Add(assetType, mapping.ContentType); + if (!asset2Extension.ContainsKey(assetType)) + asset2Extension.Add(assetType, mapping.Extension); + if (!inventory2Content.ContainsKey(mapping.InventoryType)) + inventory2Content.Add(mapping.InventoryType, mapping.ContentType); + if (!content2Asset.ContainsKey(mapping.ContentType)) + content2Asset.Add(mapping.ContentType, assetType); + if (!content2Inventory.ContainsKey(mapping.ContentType)) + content2Inventory.Add(mapping.ContentType, mapping.InventoryType); + + if (mapping.ContentType2 != null) + { + if (!content2Asset.ContainsKey(mapping.ContentType2)) + content2Asset.Add(mapping.ContentType2, assetType); + if (!content2Inventory.ContainsKey(mapping.ContentType2)) + content2Inventory.Add(mapping.ContentType2, mapping.InventoryType); + } + } + } + public static string SLAssetTypeToContentType(int assetType) { - switch ((AssetType)assetType) - { - case AssetType.Texture: - return "image/x-j2c"; - case AssetType.Sound: - return "audio/ogg"; - case AssetType.CallingCard: - return "application/vnd.ll.callingcard"; - case AssetType.Landmark: - return "application/vnd.ll.landmark"; - case AssetType.Clothing: - return "application/vnd.ll.clothing"; - case AssetType.Object: - return "application/vnd.ll.primitive"; - case AssetType.Notecard: - return "application/vnd.ll.notecard"; - case AssetType.Folder: - return "application/vnd.ll.folder"; - case AssetType.RootFolder: - return "application/vnd.ll.rootfolder"; - case AssetType.LSLText: - return "application/vnd.ll.lsltext"; - case AssetType.LSLBytecode: - return "application/vnd.ll.lslbyte"; - case AssetType.TextureTGA: - case AssetType.ImageTGA: - return "image/tga"; - case AssetType.Bodypart: - return "application/vnd.ll.bodypart"; - case AssetType.TrashFolder: - return "application/vnd.ll.trashfolder"; - case AssetType.SnapshotFolder: - return "application/vnd.ll.snapshotfolder"; - case AssetType.LostAndFoundFolder: - return "application/vnd.ll.lostandfoundfolder"; - case AssetType.SoundWAV: - return "audio/x-wav"; - case AssetType.ImageJPEG: - return "image/jpeg"; - case AssetType.Animation: - return "application/vnd.ll.animation"; - case AssetType.Gesture: - return "application/vnd.ll.gesture"; - case AssetType.Simstate: - return "application/x-metaverse-simstate"; - case AssetType.FavoriteFolder: - return "application/vnd.ll.favoritefolder"; - case AssetType.Link: - return "application/vnd.ll.link"; - case AssetType.LinkFolder: - return "application/vnd.ll.linkfolder"; - case AssetType.CurrentOutfitFolder: - return "application/vnd.ll.currentoutfitfolder"; - case AssetType.OutfitFolder: - return "application/vnd.ll.outfitfolder"; - case AssetType.MyOutfitsFolder: - return "application/vnd.ll.myoutfitsfolder"; - case AssetType.Unknown: - default: - return "application/octet-stream"; - } + string contentType; + if (!asset2Content.TryGetValue((sbyte)assetType, out contentType)) + contentType = asset2Content[(sbyte)AssetType.Unknown]; + return contentType; } public static string SLInvTypeToContentType(int invType) { - switch ((InventoryType)invType) - { - case InventoryType.Animation: - return "application/vnd.ll.animation"; - case InventoryType.CallingCard: - return "application/vnd.ll.callingcard"; - case InventoryType.Folder: - return "application/vnd.ll.folder"; - case InventoryType.Gesture: - return "application/vnd.ll.gesture"; - case InventoryType.Landmark: - return "application/vnd.ll.landmark"; - case InventoryType.LSL: - return "application/vnd.ll.lsltext"; - case InventoryType.Notecard: - return "application/vnd.ll.notecard"; - case InventoryType.Attachment: - case InventoryType.Object: - return "application/vnd.ll.primitive"; - case InventoryType.Sound: - return "audio/ogg"; - case InventoryType.Snapshot: - case InventoryType.Texture: - return "image/x-j2c"; - case InventoryType.Wearable: - return "application/vnd.ll.clothing"; - default: - return "application/octet-stream"; - } + string contentType; + if (!inventory2Content.TryGetValue((InventoryType)invType, out contentType)) + contentType = inventory2Content[InventoryType.Unknown]; + return contentType; } public static sbyte ContentTypeToSLAssetType(string contentType) { - switch (contentType) - { - case "image/x-j2c": - case "image/jp2": - return (sbyte)AssetType.Texture; - case "application/ogg": - case "audio/ogg": - return (sbyte)AssetType.Sound; - case "application/vnd.ll.callingcard": - case "application/x-metaverse-callingcard": - return (sbyte)AssetType.CallingCard; - case "application/vnd.ll.landmark": - case "application/x-metaverse-landmark": - return (sbyte)AssetType.Landmark; - case "application/vnd.ll.clothing": - case "application/x-metaverse-clothing": - return (sbyte)AssetType.Clothing; - case "application/vnd.ll.primitive": - case "application/x-metaverse-primitive": - return (sbyte)AssetType.Object; - case "application/vnd.ll.notecard": - case "application/x-metaverse-notecard": - return (sbyte)AssetType.Notecard; - case "application/vnd.ll.folder": - return (sbyte)AssetType.Folder; - case "application/vnd.ll.rootfolder": - return (sbyte)AssetType.RootFolder; - case "application/vnd.ll.lsltext": - case "application/x-metaverse-lsl": - return (sbyte)AssetType.LSLText; - case "application/vnd.ll.lslbyte": - case "application/x-metaverse-lso": - return (sbyte)AssetType.LSLBytecode; - case "image/tga": - // Note that AssetType.TextureTGA will be converted to AssetType.ImageTGA - return (sbyte)AssetType.ImageTGA; - case "application/vnd.ll.bodypart": - case "application/x-metaverse-bodypart": - return (sbyte)AssetType.Bodypart; - case "application/vnd.ll.trashfolder": - return (sbyte)AssetType.TrashFolder; - case "application/vnd.ll.snapshotfolder": - return (sbyte)AssetType.SnapshotFolder; - case "application/vnd.ll.lostandfoundfolder": - return (sbyte)AssetType.LostAndFoundFolder; - case "audio/x-wav": - return (sbyte)AssetType.SoundWAV; - case "image/jpeg": - return (sbyte)AssetType.ImageJPEG; - case "application/vnd.ll.animation": - case "application/x-metaverse-animation": - return (sbyte)AssetType.Animation; - case "application/vnd.ll.gesture": - case "application/x-metaverse-gesture": - return (sbyte)AssetType.Gesture; - case "application/x-metaverse-simstate": - return (sbyte)AssetType.Simstate; - case "application/vnd.ll.favoritefolder": - return (sbyte)AssetType.FavoriteFolder; - case "application/vnd.ll.link": - return (sbyte)AssetType.Link; - case "application/vnd.ll.linkfolder": - return (sbyte)AssetType.LinkFolder; - case "application/vnd.ll.currentoutfitfolder": - return (sbyte)AssetType.CurrentOutfitFolder; - case "application/vnd.ll.outfitfolder": - return (sbyte)AssetType.OutfitFolder; - case "application/vnd.ll.myoutfitsfolder": - return (sbyte)AssetType.MyOutfitsFolder; - case "application/octet-stream": - default: - return (sbyte)AssetType.Unknown; - } + sbyte assetType; + if (!content2Asset.TryGetValue(contentType, out assetType)) + assetType = (sbyte)AssetType.Unknown; + return (sbyte)assetType; } public static sbyte ContentTypeToSLInvType(string contentType) { - switch (contentType) - { - case "image/x-j2c": - case "image/jp2": - case "image/tga": - case "image/jpeg": - return (sbyte)InventoryType.Texture; - case "application/ogg": - case "audio/ogg": - case "audio/x-wav": - return (sbyte)InventoryType.Sound; - case "application/vnd.ll.callingcard": - case "application/x-metaverse-callingcard": - return (sbyte)InventoryType.CallingCard; - case "application/vnd.ll.landmark": - case "application/x-metaverse-landmark": - return (sbyte)InventoryType.Landmark; - case "application/vnd.ll.clothing": - case "application/x-metaverse-clothing": - case "application/vnd.ll.bodypart": - case "application/x-metaverse-bodypart": - return (sbyte)InventoryType.Wearable; - case "application/vnd.ll.primitive": - case "application/x-metaverse-primitive": - return (sbyte)InventoryType.Object; - case "application/vnd.ll.notecard": - case "application/x-metaverse-notecard": - return (sbyte)InventoryType.Notecard; - case "application/vnd.ll.folder": - return (sbyte)InventoryType.Folder; - case "application/vnd.ll.rootfolder": - return (sbyte)InventoryType.RootCategory; - case "application/vnd.ll.lsltext": - case "application/x-metaverse-lsl": - case "application/vnd.ll.lslbyte": - case "application/x-metaverse-lso": - return (sbyte)InventoryType.LSL; - case "application/vnd.ll.trashfolder": - case "application/vnd.ll.snapshotfolder": - case "application/vnd.ll.lostandfoundfolder": - return (sbyte)InventoryType.Folder; - case "application/vnd.ll.animation": - case "application/x-metaverse-animation": - return (sbyte)InventoryType.Animation; - case "application/vnd.ll.gesture": - case "application/x-metaverse-gesture": - return (sbyte)InventoryType.Gesture; - case "application/x-metaverse-simstate": - return (sbyte)InventoryType.Snapshot; - case "application/octet-stream": - default: - return (sbyte)InventoryType.Unknown; - } + InventoryType invType; + if (!content2Inventory.TryGetValue(contentType, out invType)) + invType = InventoryType.Unknown; + return (sbyte)invType; + } + + public static string SLAssetTypeToExtension(int assetType) + { + string extension; + if (!asset2Extension.TryGetValue((sbyte)assetType, out extension)) + extension = asset2Extension[(sbyte)AssetType.Unknown]; + return extension; } #endregion SL / file extension / content-type conversions @@ -377,4 +327,4 @@ namespace OpenSim.Framework return output; } } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/Serialization/External/LandDataSerializer.cs b/OpenSim/Framework/Serialization/External/LandDataSerializer.cs index a12877a692..a64f01ce71 100644 --- a/OpenSim/Framework/Serialization/External/LandDataSerializer.cs +++ b/OpenSim/Framework/Serialization/External/LandDataSerializer.cs @@ -42,9 +42,7 @@ namespace OpenSim.Framework.Serialization.External /// public class LandDataSerializer { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - protected static UTF8Encoding m_utf8Encoding = new UTF8Encoding(); +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static Dictionary> m_ldProcessors = new Dictionary>(); @@ -163,7 +161,7 @@ namespace OpenSim.Framework.Serialization.External /// public static LandData Deserialize(byte[] serializedLandData) { - return Deserialize(m_utf8Encoding.GetString(serializedLandData, 0, serializedLandData.Length)); + return Deserialize(Encoding.UTF8.GetString(serializedLandData, 0, serializedLandData.Length)); } /// diff --git a/OpenSim/Framework/Serialization/External/RegionSettingsSerializer.cs b/OpenSim/Framework/Serialization/External/RegionSettingsSerializer.cs index 931898ce10..19468c3b2a 100644 --- a/OpenSim/Framework/Serialization/External/RegionSettingsSerializer.cs +++ b/OpenSim/Framework/Serialization/External/RegionSettingsSerializer.cs @@ -30,6 +30,8 @@ using System.Text; using System.Xml; using OpenMetaverse; using OpenSim.Framework; +using log4net; +using System.Reflection; namespace OpenSim.Framework.Serialization.External { @@ -38,8 +40,6 @@ namespace OpenSim.Framework.Serialization.External /// public class RegionSettingsSerializer { - protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding(); - /// /// Deserialize settings /// @@ -48,7 +48,7 @@ namespace OpenSim.Framework.Serialization.External /// public static RegionSettings Deserialize(byte[] serializedSettings) { - return Deserialize(m_asciiEncoding.GetString(serializedSettings, 0, serializedSettings.Length)); + return Deserialize(Encoding.ASCII.GetString(serializedSettings, 0, serializedSettings.Length)); } /// @@ -187,7 +187,29 @@ namespace OpenSim.Framework.Serialization.External break; } } - + + xtr.ReadEndElement(); + + if (xtr.IsStartElement("Telehub")) + { + xtr.ReadStartElement("Telehub"); + + while (xtr.Read() && xtr.NodeType != XmlNodeType.EndElement) + { + switch (xtr.Name) + { + case "TelehubObject": + settings.TelehubObject = UUID.Parse(xtr.ReadElementContentAsString()); + break; + case "SpawnPoint": + string str = xtr.ReadElementContentAsString(); + SpawnPoint sp = SpawnPoint.Parse(str); + settings.AddSpawnPoint(sp); + break; + } + } + } + xtr.Close(); sr.Close(); @@ -243,7 +265,16 @@ namespace OpenSim.Framework.Serialization.External xtw.WriteElementString("SunPosition", settings.SunPosition.ToString()); // Note: 'SunVector' isn't saved because this value is owned by the Sun Module, which // calculates it automatically according to the date and other factors. - xtw.WriteEndElement(); + xtw.WriteEndElement(); + + xtw.WriteStartElement("Telehub"); + if (settings.TelehubObject != UUID.Zero) + { + xtw.WriteElementString("TelehubObject", settings.TelehubObject.ToString()); + foreach (SpawnPoint sp in settings.SpawnPoints()) + xtw.WriteElementString("SpawnPoint", sp.ToString()); + } + xtw.WriteEndElement(); xtw.WriteEndElement(); diff --git a/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs b/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs index 57da7ca0e4..88f9581afd 100644 --- a/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs +++ b/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs @@ -44,7 +44,7 @@ namespace OpenSim.Framework.Serialization.External /// public class UserInventoryItemSerializer { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static Dictionary> m_InventoryItemXmlProcessors = new Dictionary>(); diff --git a/OpenSim/Framework/Serialization/TarArchiveReader.cs b/OpenSim/Framework/Serialization/TarArchiveReader.cs index 77c29f8cac..339a37ad11 100644 --- a/OpenSim/Framework/Serialization/TarArchiveReader.cs +++ b/OpenSim/Framework/Serialization/TarArchiveReader.cs @@ -53,8 +53,6 @@ namespace OpenSim.Framework.Serialization TYPE_CONTIGUOUS_FILE = 8, } - protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding(); - /// /// Binary reader for the underlying stream /// @@ -120,13 +118,13 @@ namespace OpenSim.Framework.Serialization if (header[156] == (byte)'L') { int longNameLength = ConvertOctalBytesToDecimal(header, 124, 11); - tarHeader.FilePath = m_asciiEncoding.GetString(ReadData(longNameLength)); + tarHeader.FilePath = Encoding.ASCII.GetString(ReadData(longNameLength)); //m_log.DebugFormat("[TAR ARCHIVE READER]: Got long file name {0}", tarHeader.FilePath); header = m_br.ReadBytes(512); } else { - tarHeader.FilePath = m_asciiEncoding.GetString(header, 0, 100); + tarHeader.FilePath = Encoding.ASCII.GetString(header, 0, 100); tarHeader.FilePath = tarHeader.FilePath.Trim(m_nullCharArray); //m_log.DebugFormat("[TAR ARCHIVE READER]: Got short file name {0}", tarHeader.FilePath); } @@ -205,7 +203,7 @@ namespace OpenSim.Framework.Serialization { // Trim leading white space: ancient tars do that instead // of leading 0s :-( don't ask. really. - string oString = m_asciiEncoding.GetString(bytes, startIndex, count).TrimStart(m_spaceCharArray); + string oString = Encoding.ASCII.GetString(bytes, startIndex, count).TrimStart(m_spaceCharArray); int d = 0; diff --git a/OpenSim/Framework/Serialization/TarArchiveWriter.cs b/OpenSim/Framework/Serialization/TarArchiveWriter.cs index fca909f2d8..2a3bc4805d 100644 --- a/OpenSim/Framework/Serialization/TarArchiveWriter.cs +++ b/OpenSim/Framework/Serialization/TarArchiveWriter.cs @@ -41,9 +41,6 @@ namespace OpenSim.Framework.Serialization { // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding(); - protected static UTF8Encoding m_utf8Encoding = new UTF8Encoding(); - /// /// Binary writer for the underlying stream /// @@ -74,7 +71,7 @@ namespace OpenSim.Framework.Serialization /// public void WriteFile(string filePath, string data) { - WriteFile(filePath, m_utf8Encoding.GetBytes(data)); + WriteFile(filePath, Util.UTF8NoBomEncoding.GetBytes(data)); } /// @@ -85,7 +82,7 @@ namespace OpenSim.Framework.Serialization public void WriteFile(string filePath, byte[] data) { if (filePath.Length > 100) - WriteEntry("././@LongLink", m_asciiEncoding.GetBytes(filePath), 'L'); + WriteEntry("././@LongLink", Encoding.ASCII.GetBytes(filePath), 'L'); char fileType; @@ -137,7 +134,7 @@ namespace OpenSim.Framework.Serialization oString = "0" + oString; } - byte[] oBytes = m_asciiEncoding.GetBytes(oString); + byte[] oBytes = Encoding.ASCII.GetBytes(oString); return oBytes; } @@ -156,20 +153,20 @@ namespace OpenSim.Framework.Serialization byte[] header = new byte[512]; // file path field (100) - byte[] nameBytes = m_asciiEncoding.GetBytes(filePath); + byte[] nameBytes = Encoding.ASCII.GetBytes(filePath); int nameSize = (nameBytes.Length >= 100) ? 100 : nameBytes.Length; Array.Copy(nameBytes, header, nameSize); // file mode (8) - byte[] modeBytes = m_asciiEncoding.GetBytes("0000777"); + byte[] modeBytes = Encoding.ASCII.GetBytes("0000777"); Array.Copy(modeBytes, 0, header, 100, 7); // owner user id (8) - byte[] ownerIdBytes = m_asciiEncoding.GetBytes("0000764"); + byte[] ownerIdBytes = Encoding.ASCII.GetBytes("0000764"); Array.Copy(ownerIdBytes, 0, header, 108, 7); // group user id (8) - byte[] groupIdBytes = m_asciiEncoding.GetBytes("0000764"); + byte[] groupIdBytes = Encoding.ASCII.GetBytes("0000764"); Array.Copy(groupIdBytes, 0, header, 116, 7); // file size in bytes (12) @@ -181,17 +178,17 @@ namespace OpenSim.Framework.Serialization Array.Copy(fileSizeBytes, 0, header, 124, 11); // last modification time (12) - byte[] lastModTimeBytes = m_asciiEncoding.GetBytes("11017037332"); + byte[] lastModTimeBytes = Encoding.ASCII.GetBytes("11017037332"); Array.Copy(lastModTimeBytes, 0, header, 136, 11); // entry type indicator (1) - header[156] = m_asciiEncoding.GetBytes(new char[] { fileType })[0]; + header[156] = Encoding.ASCII.GetBytes(new char[] { fileType })[0]; - Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 329, 7); - Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 337, 7); + Array.Copy(Encoding.ASCII.GetBytes("0000000"), 0, header, 329, 7); + Array.Copy(Encoding.ASCII.GetBytes("0000000"), 0, header, 337, 7); // check sum for header block (8) [calculated last] - Array.Copy(m_asciiEncoding.GetBytes(" "), 0, header, 148, 8); + Array.Copy(Encoding.ASCII.GetBytes(" "), 0, header, 148, 8); int checksum = 0; foreach (byte b in header) diff --git a/OpenSim/Framework/Serialization/Tests/RegionSettingsSerializerTests.cs b/OpenSim/Framework/Serialization/Tests/RegionSettingsSerializerTests.cs index a61e4af65d..09b6f6ddad 100644 --- a/OpenSim/Framework/Serialization/Tests/RegionSettingsSerializerTests.cs +++ b/OpenSim/Framework/Serialization/Tests/RegionSettingsSerializerTests.cs @@ -78,6 +78,10 @@ namespace OpenSim.Framework.Serialization.Tests true 12 + + 00000000-0000-0000-0000-111111111111 + 1,-2,0.33 + "; private RegionSettings m_rs; @@ -116,6 +120,8 @@ namespace OpenSim.Framework.Serialization.Tests m_rs.TerrainTexture4 = UUID.Parse("00000000-0000-0000-0000-000000000080"); m_rs.UseEstateSun = true; m_rs.WaterHeight = 23; + m_rs.TelehubObject = UUID.Parse("00000000-0000-0000-0000-111111111111"); + m_rs.AddSpawnPoint(SpawnPoint.Parse("1,-2,0.33")); } [Test] @@ -129,6 +135,8 @@ namespace OpenSim.Framework.Serialization.Tests Assert.That(deserRs.TerrainTexture2, Is.EqualTo(m_rs.TerrainTexture2)); Assert.That(deserRs.DisablePhysics, Is.EqualTo(m_rs.DisablePhysics)); Assert.That(deserRs.TerrainLowerLimit, Is.EqualTo(m_rs.TerrainLowerLimit)); + Assert.That(deserRs.TelehubObject, Is.EqualTo(m_rs.TelehubObject)); + Assert.That(deserRs.SpawnPoints()[0].ToString(), Is.EqualTo(m_rs.SpawnPoints()[0].ToString())); } } } diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index 87d04f8c1e..9a2cd0e56c 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs @@ -320,7 +320,9 @@ namespace OpenSim.Framework.Servers TimeSpan timeTaken = DateTime.Now - m_startuptime; - m_log.InfoFormat("[STARTUP]: Startup took {0}m {1}s", timeTaken.Minutes, timeTaken.Seconds); + m_log.InfoFormat( + "[STARTUP]: Non-script portion of startup took {0}m {1}s. PLEASE WAIT FOR LOGINS TO BE ENABLED ON REGIONS ONCE SCRIPTS HAVE STARTED.", + timeTaken.Minutes, timeTaken.Seconds); } /// @@ -589,8 +591,8 @@ namespace OpenSim.Framework.Servers { string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); FileStream fs = File.Create(path); - System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); - Byte[] buf = enc.GetBytes(pidstring); + + Byte[] buf = Encoding.ASCII.GetBytes(pidstring); fs.Write(buf, 0, buf.Length); fs.Close(); m_pidFile = path; diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHTTPHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseHTTPHandler.cs index 2fe9769b0f..9f8f4a8674 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHTTPHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHTTPHandler.cs @@ -33,9 +33,9 @@ namespace OpenSim.Framework.Servers.HttpServer { public abstract Hashtable Handle(string path, Hashtable Request); - protected BaseHTTPHandler(string httpMethod, string path) - : base(httpMethod, path) - { - } + protected BaseHTTPHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} + + protected BaseHTTPHandler(string httpMethod, string path, string name, string description) + : base(httpMethod, path, name, description) {} } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index a3a5029532..24f986a756 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs @@ -53,6 +53,8 @@ namespace OpenSim.Framework.Servers.HttpServer private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); + public int DebugLevel { get; set; } + private volatile int NotSocketErrors = 0; public volatile bool HTTPDRunning = false; @@ -79,11 +81,6 @@ namespace OpenSim.Framework.Servers.HttpServer private PollServiceRequestManager m_PollServiceManager; - /// - /// Control the printing of certain debug messages. - /// - public int DebugLevel { get; set; } - public uint SSLPort { get { return m_sslport; } @@ -156,7 +153,7 @@ namespace OpenSim.Framework.Servers.HttpServer } } - public List GetStreamHandlerKeys() + public List GetStreamHandlerKeys() { lock (m_streamHandlers) return new List(m_streamHandlers.Keys); @@ -356,7 +353,7 @@ namespace OpenSim.Framework.Servers.HttpServer } catch (Exception e) { - m_log.ErrorFormat("[BASE HTTP SERVER]: OnRequest() failed with {0}{1}", e.Message, e.StackTrace); + m_log.Error(String.Format("[BASE HTTP SERVER]: OnRequest() failed: {0} ", e.Message), e); } } @@ -408,7 +405,12 @@ namespace OpenSim.Framework.Servers.HttpServer string uriString = request.RawUrl; // string reqnum = "unknown"; - int tickstart = Environment.TickCount; + int requestStartTick = Environment.TickCount; + + // Will be adjusted later on. + int requestEndTick = requestStartTick; + + IRequestHandler requestHandler = null; try { @@ -431,6 +433,7 @@ namespace OpenSim.Framework.Servers.HttpServer { if (HandleAgentRequest(agentHandler, request, response)) { + requestEndTick = Environment.TickCount; return; } } @@ -438,20 +441,16 @@ namespace OpenSim.Framework.Servers.HttpServer //response.KeepAlive = true; response.SendChunked = false; - IRequestHandler requestHandler; - string path = request.RawUrl; string handlerKey = GetHandlerKey(request.HttpMethod, path); + byte[] buffer = null; if (TryGetStreamHandler(handlerKey, out requestHandler)) { - if (DebugLevel >= 1) + if (DebugLevel >= 3) m_log.DebugFormat( - "[BASE HTTP SERVER]: Found stream handler for {0} {1}", - request.HttpMethod, request.Url.PathAndQuery); - - // Okay, so this is bad, but should be considered temporary until everything is IStreamHandler. - byte[] buffer = null; + "[BASE HTTP SERVER]: Found stream handler for {0} {1} {2} {3}", + request.HttpMethod, request.Url.PathAndQuery, requestHandler.Name, requestHandler.Description); response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. @@ -507,8 +506,8 @@ namespace OpenSim.Framework.Servers.HttpServer //m_log.Warn("[HTTP]: " + requestBody); } - DoHTTPGruntWork(HTTPRequestHandler.Handle(path, keysvals), response); - return; + + buffer = DoHTTPGruntWork(HTTPRequestHandler.Handle(path, keysvals), response); } else { @@ -521,133 +520,99 @@ namespace OpenSim.Framework.Servers.HttpServer buffer = memoryStream.ToArray(); } } + } + else + { + switch (request.ContentType) + { + case null: + case "text/html": + + if (DebugLevel >= 3) + m_log.DebugFormat( + "[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}", + request.ContentType, request.HttpMethod, request.Url.PathAndQuery); + + buffer = HandleHTTPRequest(request, response); + break; + + case "application/llsd+xml": + case "application/xml+llsd": + case "application/llsd+json": + + if (DebugLevel >= 3) + m_log.DebugFormat( + "[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}", + request.ContentType, request.HttpMethod, request.Url.PathAndQuery); + + buffer = HandleLLSDRequests(request, response); + break; + + case "text/xml": + case "application/xml": + case "application/json": + default: + //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); + // Point of note.. the DoWeHaveA methods check for an EXACT path + // if (request.RawUrl.Contains("/CAPS/EQG")) + // { + // int i = 1; + // } + //m_log.Info("[Debug BASE HTTP SERVER]: Checking for LLSD Handler"); + if (DoWeHaveALLSDHandler(request.RawUrl)) + { + if (DebugLevel >= 3) + m_log.DebugFormat( + "[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}", + request.ContentType, request.HttpMethod, request.Url.PathAndQuery); + + buffer = HandleLLSDRequests(request, response); + } + // m_log.DebugFormat("[BASE HTTP SERVER]: Checking for HTTP Handler for request {0}", request.RawUrl); + else if (DoWeHaveAHTTPHandler(request.RawUrl)) + { + if (DebugLevel >= 3) + m_log.DebugFormat( + "[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}", + request.ContentType, request.HttpMethod, request.Url.PathAndQuery); + + buffer = HandleHTTPRequest(request, response); + } + else + { + if (DebugLevel >= 3) + m_log.DebugFormat( + "[BASE HTTP SERVER]: Assuming a generic XMLRPC request for {0} {1}", + request.HttpMethod, request.Url.PathAndQuery); + + // generic login request. + buffer = HandleXmlRpcRequests(request, response); + } + + break; + } + } - request.InputStream.Close(); - - // HTTP IN support. The script engine takes it from here - // Nothing to worry about for us. - // - if (buffer == null) - return; + request.InputStream.Close(); + if (buffer != null) + { if (!response.SendChunked) response.ContentLength64 = buffer.LongLength; - try - { - response.OutputStream.Write(buffer, 0, buffer.Length); - //response.OutputStream.Close(); - } - catch (HttpListenerException) - { - m_log.WarnFormat("[BASE HTTP SERVER]: HTTP request abnormally terminated."); - } - //response.OutputStream.Close(); - try - { - response.Send(); - //response.FreeContext(); - } - catch (SocketException e) - { - // This has to be here to prevent a Linux/Mono crash - m_log.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); - } - catch (IOException e) - { - m_log.Warn("[BASE HTTP SERVER]: XmlRpcRequest issue: " + e.Message); - } - - return; + response.OutputStream.Write(buffer, 0, buffer.Length); } - if (request.AcceptTypes != null && request.AcceptTypes.Length > 0) - { - foreach (string strAccept in request.AcceptTypes) - { - if (strAccept.Contains("application/llsd+xml") || - strAccept.Contains("application/llsd+json")) - { - if (DebugLevel >= 1) - m_log.DebugFormat( - "[BASE HTTP SERVER]: Found application/llsd+xml accept header handler for {0} {1}", - request.HttpMethod, request.Url.PathAndQuery); + // Do not include the time taken to actually send the response to the caller in the measurement + // time. This is to avoid logging when it's the client that is slow to process rather than the + // server + requestEndTick = Environment.TickCount; - HandleLLSDRequests(request, response); - return; - } - } - } + response.Send(); - switch (request.ContentType) - { - case null: - case "text/html": + //response.OutputStream.Close(); - if (DebugLevel >= 1) - m_log.DebugFormat( - "[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}", - request.ContentType, request.HttpMethod, request.Url.PathAndQuery); - - HandleHTTPRequest(request, response); - return; - - case "application/llsd+xml": - case "application/xml+llsd": - case "application/llsd+json": - - if (DebugLevel >= 1) - m_log.DebugFormat( - "[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}", - request.ContentType, request.HttpMethod, request.Url.PathAndQuery); - - HandleLLSDRequests(request, response); - return; - - case "text/xml": - case "application/xml": - case "application/json": - default: - //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); - // Point of note.. the DoWeHaveA methods check for an EXACT path - // if (request.RawUrl.Contains("/CAPS/EQG")) - // { - // int i = 1; - // } - //m_log.Info("[Debug BASE HTTP SERVER]: Checking for LLSD Handler"); - if (DoWeHaveALLSDHandler(request.RawUrl)) - { - if (DebugLevel >= 1) - m_log.DebugFormat( - "[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}", - request.ContentType, request.HttpMethod, request.Url.PathAndQuery); - - HandleLLSDRequests(request, response); - return; - } - -// m_log.DebugFormat("[BASE HTTP SERVER]: Checking for HTTP Handler for request {0}", request.RawUrl); - if (DoWeHaveAHTTPHandler(request.RawUrl)) - { - if (DebugLevel >= 1) - m_log.DebugFormat( - "[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}", - request.ContentType, request.HttpMethod, request.Url.PathAndQuery); - - HandleHTTPRequest(request, response); - return; - } - - if (DebugLevel >= 1) - m_log.DebugFormat( - "[BASE HTTP SERVER]: Assuming a generic XMLRPC request for {0} {1}", - request.HttpMethod, request.Url.PathAndQuery); - - // generic login request. - HandleXmlRpcRequests(request, response); - - return; - } + //response.FreeContext(); } catch (SocketException e) { @@ -658,25 +623,33 @@ namespace OpenSim.Framework.Servers.HttpServer // // An alternative may be to turn off all response write exceptions on the HttpListener, but let's go // with the minimum first - m_log.WarnFormat("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux", e); + m_log.Warn(String.Format("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux ", e.Message), e); } catch (IOException e) { - m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e); + m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.Message), e); } catch (Exception e) { - m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw {0}", e.StackTrace); + m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.Message), e); SendHTML500(response); } finally { // Every month or so this will wrap and give bad numbers, not really a problem - // since its just for reporting, tickdiff limit can be adjusted - int tickdiff = Environment.TickCount - tickstart; + // since its just for reporting + int tickdiff = requestEndTick - requestStartTick; if (tickdiff > 3000) + { m_log.InfoFormat( - "[BASE HTTP SERVER]: slow {0} request for {1} from {2} took {3} ms", requestMethod, uriString, request.RemoteIPEndPoint.ToString(), tickdiff); + "[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} from {4} took {5}ms", + requestMethod, + uriString, + requestHandler != null ? requestHandler.Name : "", + requestHandler != null ? requestHandler.Description : "", + request.RemoteIPEndPoint.ToString(), + tickdiff); + } } } @@ -797,7 +770,7 @@ namespace OpenSim.Framework.Servers.HttpServer /// /// /// - private void HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response) + private byte[] HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response) { Stream requestStream = request.InputStream; @@ -816,8 +789,23 @@ namespace OpenSim.Framework.Servers.HttpServer { xmlRprcRequest = (XmlRpcRequest) (new XmlRpcRequestDeserializer()).Deserialize(requestBody); } - catch (XmlException) + catch (XmlException e) { + if (DebugLevel >= 1) + { + if (DebugLevel >= 2) + m_log.Warn( + string.Format( + "[BASE HTTP SERVER]: Got XMLRPC request with invalid XML from {0}. XML was '{1}'. Sending blank response. Exception ", + request.RemoteIPEndPoint, requestBody), + e); + else + { + m_log.WarnFormat( + "[BASE HTTP SERVER]: Got XMLRPC request with invalid XML from {0}, length {1}. Sending blank response.", + request.RemoteIPEndPoint, requestBody.Length); + } + } } if (xmlRprcRequest != null) @@ -887,6 +875,7 @@ namespace OpenSim.Framework.Servers.HttpServer String.Format("Requested method [{0}] not found", methodName)); } + response.ContentType = "text/xml"; responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse); } else @@ -896,82 +885,25 @@ namespace OpenSim.Framework.Servers.HttpServer response.StatusCode = 404; response.StatusDescription = "Not Found"; response.ProtocolVersion = "HTTP/1.0"; - byte[] buf = Encoding.UTF8.GetBytes("Not found"); + responseString = "Not found"; response.KeepAlive = false; m_log.ErrorFormat( "[BASE HTTP SERVER]: Handler not found for http request {0} {1}", request.HttpMethod, request.Url.PathAndQuery); - - response.SendChunked = false; - response.ContentLength64 = buf.Length; - response.ContentEncoding = Encoding.UTF8; - - try - { - response.OutputStream.Write(buf, 0, buf.Length); - } - catch (Exception ex) - { - m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message); - } - finally - { - try - { - response.Send(); - //response.FreeContext(); - } - catch (SocketException e) - { - // This has to be here to prevent a Linux/Mono crash - m_log.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); - } - catch (IOException e) - { - m_log.Warn("[BASE HTTP SERVER]: XmlRpcRequest issue: " + e.Message); - } - } - return; - //responseString = "Error"; } } - response.ContentType = "text/xml"; - byte[] buffer = Encoding.UTF8.GetBytes(responseString); response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; - try - { - response.OutputStream.Write(buffer, 0, buffer.Length); - } - catch (Exception ex) - { - m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message); - } - finally - { - try - { - response.Send(); - //response.FreeContext(); - } - catch (SocketException e) - { - // This has to be here to prevent a Linux/Mono crash - m_log.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); - } - catch (IOException e) - { - m_log.Warn("[BASE HTTP SERVER]: XmlRpcRequest issue: " + e.Message); - } - } + + return buffer; } - private void HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response) + private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response) { //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request"); Stream requestStream = request.InputStream; @@ -1057,34 +989,7 @@ namespace OpenSim.Framework.Servers.HttpServer response.ContentEncoding = Encoding.UTF8; response.KeepAlive = true; - try - { - response.OutputStream.Write(buffer, 0, buffer.Length); - } - catch (Exception ex) - { - m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message); - } - finally - { - //response.OutputStream.Close(); - try - { - response.Send(); - response.OutputStream.Flush(); - //response.FreeContext(); - //response.OutputStream.Close(); - } - catch (IOException e) - { - m_log.WarnFormat("[BASE HTTP SERVER]: LLSD IOException {0}.", e); - } - catch (SocketException e) - { - // This has to be here to prevent a Linux/Mono crash - m_log.WarnFormat("[BASE HTTP SERVER]: LLSD issue {0}.\nNOTE: this may be spurious on Linux.", e); - } - } + return buffer; } private byte[] BuildLLSDResponse(OSHttpRequest request, OSHttpResponse response, OSD llsdResponse) @@ -1334,8 +1239,8 @@ namespace OpenSim.Framework.Servers.HttpServer catch (SocketException f) { // This has to be here to prevent a Linux/Mono crash - m_log.WarnFormat( - "[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", f); + m_log.Warn( + String.Format("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux. ", f.Message), f); } } catch(Exception) @@ -1349,7 +1254,7 @@ namespace OpenSim.Framework.Servers.HttpServer } - public void HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) + public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response) { // m_log.DebugFormat( // "[BASE HTTP SERVER]: HandleHTTPRequest for request to {0}, method {1}", @@ -1359,15 +1264,14 @@ namespace OpenSim.Framework.Servers.HttpServer { case "OPTIONS": response.StatusCode = (int)OSHttpStatusCode.SuccessOk; - return; + return null; default: - HandleContentVerbs(request, response); - return; + return HandleContentVerbs(request, response); } } - private void HandleContentVerbs(OSHttpRequest request, OSHttpResponse response) + private byte[] HandleContentVerbs(OSHttpRequest request, OSHttpResponse response) { // m_log.DebugFormat("[BASE HTTP SERVER]: HandleContentVerbs for request to {0}", request.RawUrl); @@ -1383,6 +1287,8 @@ namespace OpenSim.Framework.Servers.HttpServer // to display the form, or process it. // a better way would be nifty. + byte[] buffer; + Stream requestStream = request.InputStream; Encoding encoding = Encoding.UTF8; @@ -1443,14 +1349,14 @@ namespace OpenSim.Framework.Servers.HttpServer if (foundHandler) { Hashtable responsedata1 = requestprocessor(keysvals); - DoHTTPGruntWork(responsedata1,response); + buffer = DoHTTPGruntWork(responsedata1,response); //SendHTML500(response); } else { // m_log.Warn("[BASE HTTP SERVER]: Handler Not Found"); - SendHTML404(response, host); + buffer = SendHTML404(response, host); } } else @@ -1460,16 +1366,18 @@ namespace OpenSim.Framework.Servers.HttpServer if (foundHandler) { Hashtable responsedata2 = requestprocessor(keysvals); - DoHTTPGruntWork(responsedata2, response); + buffer = DoHTTPGruntWork(responsedata2, response); //SendHTML500(response); } else { // m_log.Warn("[BASE HTTP SERVER]: Handler Not Found2"); - SendHTML404(response, host); + buffer = SendHTML404(response, host); } } + + return buffer; } private bool TryGetHTTPHandlerPathBased(string path, out GenericHTTPMethod httpHandler) @@ -1537,7 +1445,7 @@ namespace OpenSim.Framework.Servers.HttpServer } } - internal void DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response) + internal byte[] DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response) { int responsecode; string responseString; @@ -1631,38 +1539,10 @@ namespace OpenSim.Framework.Servers.HttpServer response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; - try - { - response.OutputStream.Write(buffer, 0, buffer.Length); - } - catch (Exception ex) - { - m_log.Warn("[HTTPD]: Error - " + ex.Message); - } - finally - { - //response.OutputStream.Close(); - try - { - response.OutputStream.Flush(); - response.Send(); - - //if (!response.KeepAlive && response.ReuseContext) - // response.FreeContext(); - } - catch (SocketException e) - { - // This has to be here to prevent a Linux/Mono crash - m_log.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); - } - catch (IOException e) - { - m_log.Warn("[BASE HTTP SERVER]: XmlRpcRequest issue: " + e.Message); - } - } + return buffer; } - public void SendHTML404(OSHttpResponse response, string host) + public byte[] SendHTML404(OSHttpResponse response, string host) { // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s response.StatusCode = 404; @@ -1675,31 +1555,10 @@ namespace OpenSim.Framework.Servers.HttpServer response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; - try - { - response.OutputStream.Write(buffer, 0, buffer.Length); - } - catch (Exception ex) - { - m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message); - } - finally - { - //response.OutputStream.Close(); - try - { - response.Send(); - //response.FreeContext(); - } - catch (SocketException e) - { - // This has to be here to prevent a Linux/Mono crash - m_log.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); - } - } + return buffer; } - public void SendHTML500(OSHttpResponse response) + public byte[] SendHTML500(OSHttpResponse response) { // I know this statuscode is dumb, but the client doesn't respond to 404s and 500s response.StatusCode = (int)OSHttpStatusCode.SuccessOk; @@ -1711,28 +1570,8 @@ namespace OpenSim.Framework.Servers.HttpServer response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; - try - { - response.OutputStream.Write(buffer, 0, buffer.Length); - } - catch (Exception ex) - { - m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message); - } - finally - { - //response.OutputStream.Close(); - try - { - response.Send(); - //response.FreeContext(); - } - catch (SocketException e) - { - // This has to be here to prevent a Linux/Mono crash - m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e); - } - } + + return buffer; } public void Start() @@ -1742,6 +1581,9 @@ namespace OpenSim.Framework.Servers.HttpServer private void StartHTTP() { + m_log.InfoFormat( + "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port); + try { //m_httpListener = new HttpListener(); diff --git a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs index a2135a381f..ae7aaf2e3e 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs @@ -45,8 +45,16 @@ namespace OpenSim.Framework.Servers.HttpServer private readonly string m_path; - protected BaseRequestHandler(string httpMethod, string path) + public string Name { get; private set; } + + public string Description { get; private set; } + + protected BaseRequestHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} + + protected BaseRequestHandler(string httpMethod, string path, string name, string description) { + Name = name; + Description = description; m_httpMethod = httpMethod; m_path = path; } diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs index f1cde747fc..6342983a55 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs @@ -34,8 +34,9 @@ namespace OpenSim.Framework.Servers.HttpServer public abstract byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse); - protected BaseStreamHandler(string httpMethod, string path) : base(httpMethod, path) - { - } + protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} + + protected BaseStreamHandler(string httpMethod, string path, string name, string description) + : base(httpMethod, path, name, description) {} } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs index 1699233375..b94bfb4311 100644 --- a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs @@ -36,6 +36,15 @@ namespace OpenSim.Framework.Servers.HttpServer { private BinaryMethod m_method; + public BinaryStreamHandler(string httpMethod, string path, BinaryMethod binaryMethod) + : this(httpMethod, path, binaryMethod, null, null) {} + + public BinaryStreamHandler(string httpMethod, string path, BinaryMethod binaryMethod, string name, string description) + : base(httpMethod, path, name, description) + { + m_method = binaryMethod; + } + public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { byte[] data = ReadFully(request); @@ -45,12 +54,6 @@ namespace OpenSim.Framework.Servers.HttpServer return Encoding.UTF8.GetBytes(responseString); } - public BinaryStreamHandler(string httpMethod, string path, BinaryMethod binaryMethod) - : base(httpMethod, path) - { - m_method = binaryMethod; - } - private static byte[] ReadFully(Stream stream) { byte[] buffer = new byte[1024]; @@ -70,4 +73,4 @@ namespace OpenSim.Framework.Servers.HttpServer } } } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IOSHttpResponse.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IOSHttpResponse.cs index 33a1663358..f61b090be4 100644 --- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IOSHttpResponse.cs +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IOSHttpResponse.cs @@ -128,11 +128,5 @@ namespace OpenSim.Framework.Servers.HttpServer /// string containing the header field /// value void AddHeader(string key, string value); - - /// - /// Send the response back to the remote client - /// - void Send(); } -} - +} \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs index a449c2daa8..cb5cce5f79 100644 --- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs @@ -32,6 +32,25 @@ namespace OpenSim.Framework.Servers.HttpServer { public interface IRequestHandler { + + /// + /// Name for this handler. + /// + /// + /// Used for diagnostics. The path doesn't always describe what the handler does. Can be null if none + /// specified. + /// + string Name { get; } + + /// + /// Description for this handler. + /// + /// + /// Used for diagnostics. The path doesn't always describe what the handler does. Can be null if none + /// specified. + /// + string Description { get; } + // Return response content type string ContentType { get; } @@ -58,4 +77,4 @@ namespace OpenSim.Framework.Servers.HttpServer { Hashtable Handle(string path, Hashtable request); } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs index fc8daf3732..3171759aa3 100644 --- a/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs @@ -107,7 +107,7 @@ namespace OpenSim.Framework.Servers.HttpServer public bool IsSecured { - get { return _context.Secured; } + get { return _context.IsSecured; } } public bool KeepAlive diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs index f9227ace62..89fb5d4562 100644 --- a/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpResponse.cs @@ -321,13 +321,12 @@ namespace OpenSim.Framework.Servers.HttpServer { _httpResponse.Body.Flush(); _httpResponse.Send(); - } + public void FreeContext() { if (_httpClientContext != null) _httpClientContext.Close(); } - } } \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpStatusCodes.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpStatusCodes.cs index 5625227340..a736c8b753 100644 --- a/OpenSim/Framework/Servers/HttpServer/OSHttpStatusCodes.cs +++ b/OpenSim/Framework/Servers/HttpServer/OSHttpStatusCodes.cs @@ -28,143 +28,252 @@ namespace OpenSim.Framework.Servers.HttpServer { /// - /// HTTP status codes (almost) as defined by W3C in - /// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + /// HTTP status codes (almost) as defined by W3C in http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html and IETF in http://tools.ietf.org/html/rfc6585 /// - public enum OSHttpStatusCode: int + public enum OSHttpStatusCode : int { - // 1xx Informational status codes providing a provisional - // response. - // 100 Tells client that to keep on going sending its request - InfoContinue = 100, - // 101 Server understands request, proposes to switch to different - // application level protocol - InfoSwitchingProtocols = 101, + #region 1xx Informational status codes providing a provisional response. + /// + /// 100 Tells client that to keep on going sending its request + /// + InfoContinue = 100, - // 2xx Success codes - // 200 Request successful - SuccessOk = 200, - // 201 Request successful, new resource created - SuccessOkCreated = 201, - // 202 Request accepted, processing still on-going - SuccessOkAccepted = 202, - // 203 Request successful, meta information not authoritative - SuccessOkNonAuthoritativeInformation = 203, - // 204 Request successful, nothing to return in the body - SuccessOkNoContent = 204, - // 205 Request successful, reset displayed content - SuccessOkResetContent = 205, - // 206 Request successful, partial content returned - SuccessOkPartialContent = 206, + /// + /// 101 Server understands request, proposes to switch to different application level protocol + /// + InfoSwitchingProtocols = 101, - // 3xx Redirect code: user agent needs to go somewhere else - // 300 Redirect: different presentation forms available, take - // a pick - RedirectMultipleChoices = 300, - // 301 Redirect: requested resource has moved and now lives - // somewhere else - RedirectMovedPermanently = 301, - // 302 Redirect: Resource temporarily somewhere else, location - // might change - RedirectFound = 302, - // 303 Redirect: See other as result of a POST - RedirectSeeOther = 303, - // 304 Redirect: Resource still the same as before - RedirectNotModified = 304, - // 305 Redirect: Resource must be accessed via proxy provided - // in location field - RedirectUseProxy = 305, - // 307 Redirect: Resource temporarily somewhere else, location - // might change - RedirectMovedTemporarily = 307, + #endregion - // 4xx Client error: the client borked the request - // 400 Client error: bad request, server does not grok what - // the client wants - ClientErrorBadRequest = 400, - // 401 Client error: the client is not authorized, response - // provides WWW-Authenticate header field with a challenge - ClientErrorUnauthorized = 401, - // 402 Client error: Payment required (reserved for future use) - ClientErrorPaymentRequired = 402, - // 403 Client error: Server understood request, will not - // deliver, do not try again. - ClientErrorForbidden = 403, - // 404 Client error: Server cannot find anything matching the - // client request. - ClientErrorNotFound = 404, - // 405 Client error: The method specified by the client in the - // request is not allowed for the resource requested - ClientErrorMethodNotAllowed = 405, - // 406 Client error: Server cannot generate suitable response - // for the resource and content characteristics requested by - // the client - ClientErrorNotAcceptable = 406, - // 407 Client error: Similar to 401, Server requests that - // client authenticate itself with the proxy first - ClientErrorProxyAuthRequired = 407, - // 408 Client error: Server got impatient with client and - // decided to give up waiting for the client's request to - // arrive - ClientErrorRequestTimeout = 408, - // 409 Client error: Server could not fulfill the request for - // a resource as there is a conflict with the current state of - // the resource but thinks client can do something about this - ClientErrorConflict = 409, - // 410 Client error: The resource has moved somewhere else, - // but server has no clue where. - ClientErrorGone = 410, - // 411 Client error: The server is picky again and insists on - // having a content-length header field in the request - ClientErrorLengthRequired = 411, - // 412 Client error: one or more preconditions supplied in the - // client's request is false - ClientErrorPreconditionFailed = 412, - // 413 Client error: For fear of reflux, the server refuses to - // swallow that much data. - ClientErrorRequestEntityToLarge = 413, - // 414 Client error: The server considers the Request-URI to - // be indecently long and refuses to even look at it. - ClientErrorRequestURITooLong = 414, - // 415 Client error: The server has no clue about the media - // type requested by the client (contrary to popular belief it - // is not a warez server) - ClientErrorUnsupportedMediaType = 415, - // 416 Client error: The requested range cannot be delivered - // by the server. + #region 2xx Success codes + + /// + /// 200 Request successful + /// + SuccessOk = 200, + + /// + /// 201 Request successful, new resource created + /// + SuccessOkCreated = 201, + + /// + /// 202 Request accepted, processing still on-going + /// + SuccessOkAccepted = 202, + + /// + /// 203 Request successful, meta information not authoritative + /// + SuccessOkNonAuthoritativeInformation = 203, + + /// + /// 204 Request successful, nothing to return in the body + /// + SuccessOkNoContent = 204, + + /// + /// 205 Request successful, reset displayed content + /// + SuccessOkResetContent = 205, + + /// + /// 206 Request successful, partial content returned + /// + SuccessOkPartialContent = 206, + + #endregion + + #region 3xx Redirect code: user agent needs to go somewhere else + + /// + /// 300 Redirect: different presentation forms available, take a pick + /// + RedirectMultipleChoices = 300, + + /// + /// 301 Redirect: requested resource has moved and now lives somewhere else + /// + RedirectMovedPermanently = 301, + + /// + /// 302 Redirect: Resource temporarily somewhere else, location might change + /// + RedirectFound = 302, + + /// + /// 303 Redirect: See other as result of a POST + /// + RedirectSeeOther = 303, + + /// + /// 304 Redirect: Resource still the same as before + /// + RedirectNotModified = 304, + + /// + /// 305 Redirect: Resource must be accessed via proxy provided in location field + /// + RedirectUseProxy = 305, + + /// + /// 307 Redirect: Resource temporarily somewhere else, location might change + /// + RedirectMovedTemporarily = 307, + + #endregion + + #region 4xx Client error: the client borked the request + + /// + /// 400 Client error: bad request, server does not grok what the client wants + /// + ClientErrorBadRequest = 400, + + /// + /// 401 Client error: the client is not authorized, response provides WWW-Authenticate header field with a challenge + /// + ClientErrorUnauthorized = 401, + + /// + /// 402 Client error: Payment required (reserved for future use) + /// + ClientErrorPaymentRequired = 402, + + /// + /// 403 Client error: Server understood request, will not deliver, do not try again. + ClientErrorForbidden = 403, + + /// + /// 404 Client error: Server cannot find anything matching the client request. + /// + ClientErrorNotFound = 404, + + /// + /// 405 Client error: The method specified by the client in the request is not allowed for the resource requested + /// + ClientErrorMethodNotAllowed = 405, + + /// + /// 406 Client error: Server cannot generate suitable response for the resource and content characteristics requested by the client + /// + ClientErrorNotAcceptable = 406, + + /// + /// 407 Client error: Similar to 401, Server requests that client authenticate itself with the proxy first + /// + ClientErrorProxyAuthRequired = 407, + + /// + /// 408 Client error: Server got impatient with client and decided to give up waiting for the client's request to arrive + /// + ClientErrorRequestTimeout = 408, + + /// + /// 409 Client error: Server could not fulfill the request for a resource as there is a conflict with the current state of the resource but thinks client can do something about this + /// + ClientErrorConflict = 409, + + /// + /// 410 Client error: The resource has moved somewhere else, but server has no clue where. + /// + ClientErrorGone = 410, + + /// + /// 411 Client error: The server is picky again and insists on having a content-length header field in the request + /// + ClientErrorLengthRequired = 411, + + /// + /// 412 Client error: one or more preconditions supplied in the client's request is false + /// + ClientErrorPreconditionFailed = 412, + + /// + /// 413 Client error: For fear of reflux, the server refuses to swallow that much data. + /// + ClientErrorRequestEntityToLarge = 413, + + /// + /// 414 Client error: The server considers the Request-URI to be indecently long and refuses to even look at it. + /// + ClientErrorRequestURITooLong = 414, + + /// + /// 415 Client error: The server has no clue about the media type requested by the client (contrary to popular belief it is not a warez server) + /// + ClientErrorUnsupportedMediaType = 415, + + /// + /// 416 Client error: The requested range cannot be delivered by the server. + /// ClientErrorRequestRangeNotSatisfiable = 416, - // 417 Client error: The expectations of the client as - // expressed in one or more Expect header fields cannot be met - // by the server, the server is awfully sorry about this. - ClientErrorExpectationFailed = 417, - // 499 Client error: Wildcard error. - ClientErrorJoker = 499, - // 5xx Server errors (rare) - // 500 Server error: something really strange and unexpected - // happened - ServerErrorInternalError = 500, - // 501 Server error: The server does not do the functionality - // required to carry out the client request. not at - // all. certainly not before breakfast. but also not after - // breakfast. - ServerErrorNotImplemented = 501, - // 502 Server error: While acting as a proxy or a gateway, the - // server got ditched by the upstream server and as a - // consequence regretfully cannot fulfill the client's request - ServerErrorBadGateway = 502, - // 503 Server error: Due to unforseen circumstances the server - // cannot currently deliver the service requested. Retry-After - // header might indicate when to try again. - ServerErrorServiceUnavailable = 503, - // 504 Server error: The server blames the upstream server - // for not being able to deliver the service requested and - // claims that the upstream server is too slow delivering the - // goods. - ServerErrorGatewayTimeout = 504, - // 505 Server error: The server does not support the HTTP - // version conveyed in the client's request. - ServerErrorHttpVersionNotSupported = 505, + /// + /// 417 Client error: The expectations of the client as expressed in one or more Expect header fields cannot be met by the server, the server is awfully sorry about this. + /// + ClientErrorExpectationFailed = 417, + + /// + /// 428 Client error :The 428 status code indicates that the origin server requires the request to be conditional. + /// + ClientErrorPreconditionRequired = 428, + + /// + /// 429 Client error: The 429 status code indicates that the user has sent too many requests in a given amount of time ("rate limiting"). + /// + ClientErrorTooManyRequests = 429, + + /// + /// 431 Client error: The 431 status code indicates that the server is unwilling to process the request because its header fields are too large. The request MAY be resubmitted after reducing the size of the request header fields. + /// + ClientErrorRequestHeaderFieldsTooLarge = 431, + + /// + /// 499 Client error: Wildcard error. + /// + ClientErrorJoker = 499, + + #endregion + + #region 5xx Server errors (rare) + + /// + /// 500 Server error: something really strange and unexpected happened + /// + ServerErrorInternalError = 500, + + /// + /// 501 Server error: The server does not do the functionality required to carry out the client request. not at all. certainly not before breakfast. but also not after breakfast. + /// + ServerErrorNotImplemented = 501, + + /// + /// 502 Server error: While acting as a proxy or a gateway, the server got ditched by the upstream server and as a consequence regretfully cannot fulfill the client's request + /// + ServerErrorBadGateway = 502, + + /// + /// 503 Server error: Due to unforseen circumstances the server cannot currently deliver the service requested. Retry-After header might indicate when to try again. + /// + ServerErrorServiceUnavailable = 503, + + /// + /// 504 Server error: The server blames the upstream server for not being able to deliver the service requested and claims that the upstream server is too slow delivering the goods. + /// + ServerErrorGatewayTimeout = 504, + + /// + /// 505 Server error: The server does not support the HTTP version conveyed in the client's request. + /// + ServerErrorHttpVersionNotSupported = 505, + + /// + /// 511 Server error: The 511 status code indicates that the client needs to authenticate to gain network access. + /// + ServerErrorNetworkAuthenticationRequired = 511, + + #endregion } } diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index 7c92a50155..bb43cd2d62 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -28,6 +28,7 @@ using System; using System.Collections; using OpenMetaverse; + namespace OpenSim.Framework.Servers.HttpServer { public delegate void RequestMethod(UUID requestID, Hashtable request); @@ -53,7 +54,10 @@ namespace OpenSim.Framework.Servers.HttpServer LslHttp = 1 } - public PollServiceEventArgs(RequestMethod pRequest, HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents, UUID pId, int pTimeOutms) + public PollServiceEventArgs( + RequestMethod pRequest, + HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents, + UUID pId, int pTimeOutms) { Request = pRequest; HasEvents = pHasEvents; diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs index 553a7eb123..723530ae15 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs @@ -31,7 +31,6 @@ using OpenMetaverse; namespace OpenSim.Framework.Servers.HttpServer { - public class PollServiceHttpRequest { public readonly PollServiceEventArgs PollServiceArgs; @@ -39,7 +38,9 @@ namespace OpenSim.Framework.Servers.HttpServer public readonly IHttpRequest Request; public readonly int RequestTime; public readonly UUID RequestID; - public PollServiceHttpRequest(PollServiceEventArgs pPollServiceArgs, IHttpClientContext pHttpContext, IHttpRequest pRequest) + + public PollServiceHttpRequest( + PollServiceEventArgs pPollServiceArgs, IHttpClientContext pHttpContext, IHttpRequest pRequest) { PollServiceArgs = pPollServiceArgs; HttpContext = pHttpContext; @@ -48,4 +49,4 @@ namespace OpenSim.Framework.Servers.HttpServer RequestID = UUID.Random(); } } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 6f87c85b8d..3a14b6fe9b 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs @@ -70,6 +70,7 @@ namespace OpenSim.Framework.Servers.HttpServer ThreadPriority.Normal, false, true, + null, int.MaxValue); } @@ -79,6 +80,7 @@ namespace OpenSim.Framework.Servers.HttpServer ThreadPriority.Normal, false, true, + null, 1000 * 60 * 10); } @@ -144,9 +146,8 @@ namespace OpenSim.Framework.Servers.HttpServer foreach (object o in m_requests) { PollServiceHttpRequest req = (PollServiceHttpRequest) o; - m_server.DoHTTPGruntWork( - req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id), - new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request), req.HttpContext)); + PollServiceWorkerThread.DoHTTPGruntWork( + m_server, req, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); } m_requests.Clear(); @@ -155,6 +156,7 @@ namespace OpenSim.Framework.Servers.HttpServer { t.Abort(); } + m_running = false; } } @@ -184,7 +186,7 @@ namespace OpenSim.Framework.Servers.HttpServer private bool m_running = true; private int slowCount = 0; -// private int m_timeout = 1000; // increase timeout 250; now use the event one + // private int m_timeout = 250; // increase timeout 250; now use the event one public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout) { @@ -202,6 +204,7 @@ namespace OpenSim.Framework.Servers.HttpServer ThreadPriority.Normal, false, true, + null, int.MaxValue); } @@ -211,6 +214,7 @@ namespace OpenSim.Framework.Servers.HttpServer ThreadPriority.Normal, false, true, + null, 1000 * 60 * 10); } @@ -368,8 +372,7 @@ namespace OpenSim.Framework.Servers.HttpServer } else { -// if ((Environment.TickCount - req.RequestTime) > m_timeout) - + // if ((Environment.TickCount - req.RequestTime) > m_timeout) if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) { m_server.DoHTTPGruntWork(req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id), diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs index 7cd27e5290..1e3fbf0db5 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs @@ -94,8 +94,7 @@ namespace OpenSim.Framework.Servers.HttpServer try { Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id, str.ReadToEnd()); - m_server.DoHTTPGruntWork(responsedata, - new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request),req.HttpContext)); + DoHTTPGruntWork(m_server, req, responsedata); } catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream { @@ -106,8 +105,10 @@ namespace OpenSim.Framework.Servers.HttpServer { if ((Environment.TickCount - req.RequestTime) > m_timeout) { - m_server.DoHTTPGruntWork(req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id), - new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request),req.HttpContext)); + DoHTTPGruntWork( + m_server, + req, + req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); } else { @@ -128,6 +129,46 @@ namespace OpenSim.Framework.Servers.HttpServer { m_request.Enqueue(pPollServiceHttpRequest); } + + /// + /// FIXME: This should be part of BaseHttpServer + /// + internal static void DoHTTPGruntWork(BaseHttpServer server, PollServiceHttpRequest req, Hashtable responsedata) + { + OSHttpResponse response + = new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request), req.HttpContext); + + byte[] buffer = server.DoHTTPGruntWork(responsedata, response); + + response.SendChunked = false; + response.ContentLength64 = buffer.Length; + response.ContentEncoding = Encoding.UTF8; + + try + { + response.OutputStream.Write(buffer, 0, buffer.Length); + } + catch (Exception ex) + { + m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex)); + } + finally + { + //response.OutputStream.Close(); + try + { + response.OutputStream.Flush(); + response.Send(); + + //if (!response.KeepAlive && response.ReuseContext) + // response.FreeContext(); + } + catch (Exception e) + { + m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e)); + } + } + } } } */ \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs index a467a83073..07082a8ebb 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs @@ -39,7 +39,11 @@ namespace OpenSim.Framework.Servers.HttpServer private RestDeserialiseMethod m_method; public RestDeserialiseHandler(string httpMethod, string path, RestDeserialiseMethod method) - : base(httpMethod, path) + : this(httpMethod, path, method, null, null) {} + + public RestDeserialiseHandler( + string httpMethod, string path, RestDeserialiseMethod method, string name, string description) + : base(httpMethod, path, name, description) { m_method = method; } diff --git a/OpenSim/Framework/Servers/HttpServer/RestHTTPHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestHTTPHandler.cs index 1f23cacc08..7f898394fd 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestHTTPHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestHTTPHandler.cs @@ -38,19 +38,25 @@ namespace OpenSim.Framework.Servers.HttpServer get { return m_dhttpMethod; } } - public override Hashtable Handle(string path, Hashtable request) - { - - string param = GetParam(path); - request.Add("param", param); - request.Add("path", path); - return m_dhttpMethod(request); - } - public RestHTTPHandler(string httpMethod, string path, GenericHTTPMethod dhttpMethod) : base(httpMethod, path) { m_dhttpMethod = dhttpMethod; } + + public RestHTTPHandler( + string httpMethod, string path, GenericHTTPMethod dhttpMethod, string name, string description) + : base(httpMethod, path, name, description) + { + m_dhttpMethod = dhttpMethod; + } + + public override Hashtable Handle(string path, Hashtable request) + { + string param = GetParam(path); + request.Add("param", param); + request.Add("path", path); + return m_dhttpMethod(request); + } } } diff --git a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs index d2c4002cd5..1f17fee0d0 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs @@ -39,6 +39,15 @@ namespace OpenSim.Framework.Servers.HttpServer get { return m_restMethod; } } + public RestStreamHandler(string httpMethod, string path, RestMethod restMethod) + : this(httpMethod, path, restMethod, null, null) {} + + public RestStreamHandler(string httpMethod, string path, RestMethod restMethod, string name, string description) + : base(httpMethod, path, name, description) + { + m_restMethod = restMethod; + } + public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) { Encoding encoding = Encoding.UTF8; @@ -52,10 +61,5 @@ namespace OpenSim.Framework.Servers.HttpServer return Encoding.UTF8.GetBytes(responseString); } - - public RestStreamHandler(string httpMethod, string path, RestMethod restMethod) : base(httpMethod, path) - { - m_restMethod = restMethod; - } } } diff --git a/OpenSim/Framework/Servers/MainServer.cs b/OpenSim/Framework/Servers/MainServer.cs index b8ab8d9b26..8dc0e3a71d 100644 --- a/OpenSim/Framework/Servers/MainServer.cs +++ b/OpenSim/Framework/Servers/MainServer.cs @@ -25,57 +25,209 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System; using System.Collections.Generic; using System.Reflection; using System.Net; using log4net; +using OpenSim.Framework; +using OpenSim.Framework.Console; using OpenSim.Framework.Servers.HttpServer; namespace OpenSim.Framework.Servers { public class MainServer { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static BaseHttpServer instance = null; - private static Dictionary m_Servers = - new Dictionary(); + private static Dictionary m_Servers = new Dictionary(); + /// + /// Control the printing of certain debug messages. + /// + /// + /// If DebugLevel >= 1, then short warnings are logged when receiving bad input data. + /// If DebugLevel >= 2, then long warnings are logged when receiving bad input data. + /// If DebugLevel >= 3, then short notices about all incoming non-poll HTTP requests are logged. + /// + public static int DebugLevel + { + get { return s_debugLevel; } + set + { + s_debugLevel = value; + + lock (m_Servers) + foreach (BaseHttpServer server in m_Servers.Values) + server.DebugLevel = s_debugLevel; + } + } + + private static int s_debugLevel; + + /// + /// Set the main HTTP server instance. + /// + /// + /// This will be used to register all handlers that listen to the default port. + /// + /// + /// Thrown if the HTTP server has not already been registered via AddHttpServer() + /// public static BaseHttpServer Instance { get { return instance; } - set { instance = value; } + + set + { + lock (m_Servers) + if (!m_Servers.ContainsValue(value)) + throw new Exception("HTTP server must already have been registered to be set as the main instance"); + + instance = value; + } } - public static IHttpServer GetHttpServer(uint port) + /// + /// Get all the registered servers. + /// + /// + /// Returns a copy of the dictionary so this can be iterated through without locking. + /// + /// + public static Dictionary Servers { - return GetHttpServer(port,null); + get { return new Dictionary(m_Servers); } } + + public static void RegisterHttpConsoleCommands(ICommandConsole console) + { + console.Commands.AddCommand( + "Debug", false, "debug http", "debug http []", + "Turn on inbound non-poll http request debugging.", + "If level <= 0, then no extra logging is done.\n" + + "If level >= 1, then short warnings are logged when receiving bad input data.\n" + + "If level >= 2, then long warnings are logged when receiving bad input data.\n" + + "If level >= 3, then short notices about all incoming non-poll HTTP requests are logged.\n" + + "If no level is specified then the current level is returned.", + HandleDebugHttpCommand); + } + + /// + /// Turn on some debugging values for OpenSim. + /// + /// + private static void HandleDebugHttpCommand(string module, string[] args) + { + if (args.Length == 3) + { + int newDebug; + if (int.TryParse(args[2], out newDebug)) + { + MainServer.DebugLevel = newDebug; + MainConsole.Instance.OutputFormat("Debug http level set to {0}", newDebug); + } + } + else if (args.Length == 2) + { + MainConsole.Instance.OutputFormat("Current debug http level is {0}", MainServer.DebugLevel); + } + else + { + MainConsole.Instance.Output("Usage: debug http 0..3"); + } + } + + /// + /// Register an already started HTTP server to the collection of known servers. + /// + /// public static void AddHttpServer(BaseHttpServer server) { - m_Servers.Add(server.Port, server); + lock (m_Servers) + { + if (m_Servers.ContainsKey(server.Port)) + throw new Exception(string.Format("HTTP server for port {0} already exists.", server.Port)); + + m_Servers.Add(server.Port, server); + } } + /// + /// Removes the http server listening on the given port. + /// + /// + /// It is the responsibility of the caller to do clean up. + /// + /// + /// + public static bool RemoveHttpServer(uint port) + { + lock (m_Servers) + return m_Servers.Remove(port); + } + + /// + /// Does this collection of servers contain one with the given port? + /// + /// + /// Unlike GetHttpServer, this will not instantiate a server if one does not exist on that port. + /// + /// + /// true if a server with the given port is registered, false otherwise. + public static bool ContainsHttpServer(uint port) + { + lock (m_Servers) + return m_Servers.ContainsKey(port); + } + + /// + /// Get the default http server or an http server for a specific port. + /// + /// + /// If the requested HTTP server doesn't already exist then a new one is instantiated and started. + /// + /// + /// If 0 then the default HTTP server is returned. + public static IHttpServer GetHttpServer(uint port) + { + return GetHttpServer(port, null); + } + + /// + /// Get the default http server, an http server for a specific port + /// and/or an http server bound to a specific address + /// + /// + /// If the requested HTTP server doesn't already exist then a new one is instantiated and started. + /// + /// + /// If 0 then the default HTTP server is returned. + /// A specific IP address to bind to. If null then the default IP address is used. public static IHttpServer GetHttpServer(uint port, IPAddress ipaddr) { if (port == 0) return Instance; + if (instance != null && port == Instance.Port) return Instance; - if (m_Servers.ContainsKey(port)) + lock (m_Servers) + { + if (m_Servers.ContainsKey(port)) + return m_Servers[port]; + + m_Servers[port] = new BaseHttpServer(port); + + if (ipaddr != null) + m_Servers[port].ListenIPAddress = ipaddr; + + m_Servers[port].Start(); + return m_Servers[port]; - - m_Servers[port] = new BaseHttpServer(port); - - if (ipaddr != null) - m_Servers[port].ListenIPAddress = ipaddr; - - m_log.InfoFormat("[MAIN HTTP SERVER]: Starting main http server on port {0}", port); - m_Servers[port].Start(); - - return m_Servers[port]; + } } } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/Statistics/StatsManager.cs b/OpenSim/Framework/Statistics/StatsManager.cs index 43159ef235..436ce2fa04 100644 --- a/OpenSim/Framework/Statistics/StatsManager.cs +++ b/OpenSim/Framework/Statistics/StatsManager.cs @@ -34,14 +34,12 @@ namespace OpenSim.Framework.Statistics { private static AssetStatsCollector assetStats; private static UserStatsCollector userStats; - private static SimExtraStatsCollector simExtraStats; + private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector(); public static AssetStatsCollector AssetStats { get { return assetStats; } } public static UserStatsCollector UserStats { get { return userStats; } } public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } } - private StatsManager() {} - /// /// Start collecting statistics related to assets. /// Should only be called once. @@ -63,16 +61,5 @@ namespace OpenSim.Framework.Statistics return userStats; } - - /// - /// Start collecting extra sim statistics apart from those collected for the client. - /// Should only be called once. - /// - public static SimExtraStatsCollector StartCollectingSimExtraStats() - { - simExtraStats = new SimExtraStatsCollector(); - - return simExtraStats; - } } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/TaskInventoryDictionary.cs b/OpenSim/Framework/TaskInventoryDictionary.cs index 814758ae54..4d07746d2a 100644 --- a/OpenSim/Framework/TaskInventoryDictionary.cs +++ b/OpenSim/Framework/TaskInventoryDictionary.cs @@ -52,10 +52,10 @@ namespace OpenSim.Framework private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private Thread LockedByThread; - private string WriterStack; +// private string WriterStack; - private Dictionary ReadLockers = - new Dictionary(); +// private Dictionary ReadLockers = +// new Dictionary(); /// /// An advanced lock for inventory data @@ -98,14 +98,25 @@ namespace OpenSim.Framework m_log.Error("[TaskInventoryDictionary] Recursive read lock requested. This should not happen and means something needs to be fixed. For now though, it's safe to continue."); try { - StackTrace stackTrace = new StackTrace(); // get call stack - StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) + // That call stack is useful for end users only. RealProgrammers need a full dump. Commented. + // StackTrace stackTrace = new StackTrace(); // get call stack + // StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) + // + // // write call stack method names + // foreach (StackFrame stackFrame in stackFrames) + // { + // m_log.Error("[SceneObjectGroup.m_parts] "+(stackFrame.GetMethod().Name)); // write method name + // } - // write call stack method names - foreach (StackFrame stackFrame in stackFrames) - { - m_log.Error("[SceneObjectGroup.m_parts] "+(stackFrame.GetMethod().Name)); // write method name - } + // The below is far more useful +// System.Console.WriteLine("------------------------------------------"); +// System.Console.WriteLine("My call stack:\n" + Environment.StackTrace); +// System.Console.WriteLine("------------------------------------------"); +// foreach (KeyValuePair kvp in ReadLockers) +// { +// System.Console.WriteLine("Locker name {0} call stack:\n" + kvp.Value, kvp.Key.Name); +// System.Console.WriteLine("------------------------------------------"); +// } } catch {} @@ -114,6 +125,16 @@ namespace OpenSim.Framework if (m_itemLock.RecursiveWriteCount > 0) { m_log.Error("[TaskInventoryDictionary] Recursive write lock requested. This should not happen and means something needs to be fixed."); +// try +// { +// System.Console.WriteLine("------------------------------------------"); +// System.Console.WriteLine("My call stack:\n" + Environment.StackTrace); +// System.Console.WriteLine("------------------------------------------"); +// System.Console.WriteLine("Locker's call stack:\n" + WriterStack); +// System.Console.WriteLine("------------------------------------------"); +// } +// catch +// {} m_itemLock.ExitWriteLock(); } @@ -123,15 +144,16 @@ namespace OpenSim.Framework if (m_itemLock.IsWriteLockHeld) { m_itemLock = new System.Threading.ReaderWriterLockSlim(); - System.Console.WriteLine("------------------------------------------"); - System.Console.WriteLine("My call stack:\n" + Environment.StackTrace); - System.Console.WriteLine("------------------------------------------"); - System.Console.WriteLine("Locker's call stack:\n" + WriterStack); - System.Console.WriteLine("------------------------------------------"); - LockedByThread = null; - ReadLockers.Clear(); +// System.Console.WriteLine("------------------------------------------"); +// System.Console.WriteLine("My call stack:\n" + Environment.StackTrace); +// System.Console.WriteLine("------------------------------------------"); +// System.Console.WriteLine("Locker's call stack:\n" + WriterStack); +// System.Console.WriteLine("------------------------------------------"); +// LockedByThread = null; +// ReadLockers.Clear(); } } +// ReadLockers[Thread.CurrentThread] = Environment.StackTrace; } else { @@ -139,6 +161,8 @@ namespace OpenSim.Framework { m_itemLock.ExitReadLock(); } +// if (m_itemLock.RecursiveReadCount == 0) +// ReadLockers.Remove(Thread.CurrentThread); } } @@ -158,6 +182,7 @@ namespace OpenSim.Framework if (m_itemLock.RecursiveWriteCount > 0) { m_log.Error("[TaskInventoryDictionary] Recursive write lock requested. This should not happen and means something needs to be fixed."); + m_itemLock.ExitWriteLock(); } while (!m_itemLock.TryEnterWriteLock(60000)) @@ -165,30 +190,30 @@ namespace OpenSim.Framework if (m_itemLock.IsWriteLockHeld) { m_log.Error("Thread lock detected while trying to aquire WRITE lock in TaskInventoryDictionary. Locked by thread " + LockedByThread.Name + ". I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed."); - System.Console.WriteLine("------------------------------------------"); - System.Console.WriteLine("My call stack:\n" + Environment.StackTrace); - System.Console.WriteLine("------------------------------------------"); - System.Console.WriteLine("Locker's call stack:\n" + WriterStack); - System.Console.WriteLine("------------------------------------------"); +// System.Console.WriteLine("------------------------------------------"); +// System.Console.WriteLine("My call stack:\n" + Environment.StackTrace); +// System.Console.WriteLine("------------------------------------------"); +// System.Console.WriteLine("Locker's call stack:\n" + WriterStack); +// System.Console.WriteLine("------------------------------------------"); } else { m_log.Error("Thread lock detected while trying to aquire WRITE lock in TaskInventoryDictionary. Locked by a reader. I'm going to try to solve the thread lock automatically to preserve region stability, but this needs to be fixed."); - System.Console.WriteLine("------------------------------------------"); - System.Console.WriteLine("My call stack:\n" + Environment.StackTrace); - System.Console.WriteLine("------------------------------------------"); - foreach (KeyValuePair kvp in ReadLockers) - { - System.Console.WriteLine("Locker name {0} call stack:\n" + kvp.Value, kvp.Key.Name); - System.Console.WriteLine("------------------------------------------"); - } +// System.Console.WriteLine("------------------------------------------"); +// System.Console.WriteLine("My call stack:\n" + Environment.StackTrace); +// System.Console.WriteLine("------------------------------------------"); +// foreach (KeyValuePair kvp in ReadLockers) +// { +// System.Console.WriteLine("Locker name {0} call stack:\n" + kvp.Value, kvp.Key.Name); +// System.Console.WriteLine("------------------------------------------"); +// } } m_itemLock = new System.Threading.ReaderWriterLockSlim(); - ReadLockers.Clear(); +// ReadLockers.Clear(); } LockedByThread = Thread.CurrentThread; - WriterStack = Environment.StackTrace; +// WriterStack = Environment.StackTrace; } else { diff --git a/OpenSim/Framework/TaskInventoryItem.cs b/OpenSim/Framework/TaskInventoryItem.cs index 7ef8bf788a..fb818ee74b 100644 --- a/OpenSim/Framework/TaskInventoryItem.cs +++ b/OpenSim/Framework/TaskInventoryItem.cs @@ -26,6 +26,8 @@ */ using System; +using System.Reflection; +using log4net; using OpenMetaverse; namespace OpenSim.Framework @@ -35,6 +37,8 @@ namespace OpenSim.Framework /// public class TaskInventoryItem : ICloneable { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// /// XXX This should really be factored out into some constants class. /// @@ -334,12 +338,18 @@ namespace OpenSim.Framework } } - public bool OwnerChanged { - get { + public bool OwnerChanged + { + get + { return _ownerChanged; } - set { + set + { _ownerChanged = value; +// m_log.DebugFormat( +// "[TASK INVENTORY ITEM]: Owner changed set {0} for {1} {2} owned by {3}", +// _ownerChanged, Name, ItemID, OwnerID); } } diff --git a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs index 34a3f1560a..6fde488f36 100644 --- a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs +++ b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs @@ -227,10 +227,10 @@ namespace OpenSim.Framework.Tests es.AddEstateManager(UUID.Zero); es.AddEstateManager(bannedUserId); - Assert.IsTrue(es.IsEstateManager(bannedUserId), "bannedUserId should be EstateManager but isn't."); + Assert.IsTrue(es.IsEstateManagerOrOwner(bannedUserId), "bannedUserId should be EstateManager but isn't."); es.RemoveEstateManager(bannedUserId); - Assert.IsFalse(es.IsEstateManager(bannedUserId), "bannedUserID is estateManager but shouldn't be"); + Assert.IsFalse(es.IsEstateManagerOrOwner(bannedUserId), "bannedUserID is estateManager but shouldn't be"); Assert.IsFalse(es.HasAccess(bannedUserId), "bannedUserID has access but shouldn't"); diff --git a/OpenSim/Framework/Tests/UtilTest.cs b/OpenSim/Framework/Tests/UtilTest.cs index 1ca35dfcb5..f0d2a3f7a7 100644 --- a/OpenSim/Framework/Tests/UtilTest.cs +++ b/OpenSim/Framework/Tests/UtilTest.cs @@ -214,16 +214,13 @@ namespace OpenSim.Framework.Tests for (int i = 0; i < contenttypes.Length; i++) { - if (SLUtil.ContentTypeToSLAssetType(contenttypes[i]) == 18) - { - Assert.That(contenttypes[i] == "image/tga"); - } + int expected; + if (contenttypes[i] == "image/tga") + expected = 12; // if we know only the content-type "image/tga", then we assume the asset type is TextureTGA; not ImageTGA else - { - Assert.That(SLUtil.ContentTypeToSLAssetType(contenttypes[i]) == assettypes[i], - "Expecting {0} but got {1}", assettypes[i], - SLUtil.ContentTypeToSLAssetType(contenttypes[i])); - } + expected = assettypes[i]; + Assert.AreEqual(expected, SLUtil.ContentTypeToSLAssetType(contenttypes[i]), + String.Format("Incorrect AssetType mapped from Content-Type {0}", contenttypes[i])); } int[] inventorytypes = new int[] {-1,0,1,2,3,6,7,8,9,10,15,17,18,20}; @@ -237,7 +234,7 @@ namespace OpenSim.Framework.Tests "application/vnd.ll.primitive", "application/vnd.ll.notecard", "application/vnd.ll.folder", - "application/octet-stream", + "application/vnd.ll.rootfolder", "application/vnd.ll.lsltext", "image/x-j2c", "application/vnd.ll.primitive", @@ -247,7 +244,8 @@ namespace OpenSim.Framework.Tests for (int i=0;i /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards) @@ -1248,8 +1249,7 @@ namespace OpenSim.Framework public static string Base64ToString(string str) { - UTF8Encoding encoder = new UTF8Encoding(); - Decoder utf8Decode = encoder.GetDecoder(); + Decoder utf8Decode = Encoding.UTF8.GetDecoder(); byte[] todecode_byte = Convert.FromBase64String(str); int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length); diff --git a/OpenSim/Framework/Watchdog.cs b/OpenSim/Framework/Watchdog.cs index 881b6aadaa..449d014590 100644 --- a/OpenSim/Framework/Watchdog.cs +++ b/OpenSim/Framework/Watchdog.cs @@ -41,8 +41,8 @@ namespace OpenSim.Framework /// Timer interval in milliseconds for the watchdog timer const double WATCHDOG_INTERVAL_MS = 2500.0d; - /// Maximum timeout in milliseconds before a thread is considered dead - const int WATCHDOG_TIMEOUT_MS = 5000; + /// Default timeout in milliseconds before a thread is considered dead + public const int DEFAULT_WATCHDOG_TIMEOUT_MS = 5000; [System.Diagnostics.DebuggerDisplay("{Thread.Name}")] public class ThreadWatchdogInfo @@ -58,7 +58,7 @@ namespace OpenSim.Framework public int FirstTick { get; private set; } /// - /// First time this heartbeat update was invoked + /// Last time this heartbeat update was invoked /// public int LastTick { get; set; } @@ -77,6 +77,11 @@ namespace OpenSim.Framework /// public bool AlarmIfTimeout { get; set; } + /// + /// Method execute if alarm goes off. If null then no alarm method is fired. + /// + public Func AlarmMethod { get; set; } + public ThreadWatchdogInfo(Thread thread, int timeout) { Thread = thread; @@ -87,27 +92,33 @@ namespace OpenSim.Framework } /// - /// This event is called whenever a tracked thread is stopped or - /// has not called UpdateThread() in time - /// - /// The thread that has been identified as dead - /// The last time this thread called UpdateThread() - public delegate void WatchdogTimeout(Thread thread, int lastTick); - - /// This event is called whenever a tracked thread is - /// stopped or has not called UpdateThread() in time - public static event WatchdogTimeout OnWatchdogTimeout; + /// This event is called whenever a tracked thread is + /// stopped or has not called UpdateThread() in time< + /// /summary> + public static event Action OnWatchdogTimeout; private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private static Dictionary m_threads; private static System.Timers.Timer m_watchdogTimer; + /// + /// Last time the watchdog thread ran. + /// + /// + /// Should run every WATCHDOG_INTERVAL_MS + /// + public static int LastWatchdogThreadTick { get; private set; } + static Watchdog() { m_threads = new Dictionary(); m_watchdogTimer = new System.Timers.Timer(WATCHDOG_INTERVAL_MS); m_watchdogTimer.AutoReset = false; m_watchdogTimer.Elapsed += WatchdogTimerElapsed; + + // Set now so we don't get alerted on the first run + LastWatchdogThreadTick = Environment.TickCount & Int32.MaxValue; + m_watchdogTimer.Start(); } @@ -123,7 +134,7 @@ namespace OpenSim.Framework public static Thread StartThread( ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout) { - return StartThread(start, name, priority, isBackground, alarmIfTimeout, WATCHDOG_TIMEOUT_MS); + return StartThread(start, name, priority, isBackground, alarmIfTimeout, null, DEFAULT_WATCHDOG_TIMEOUT_MS); } /// @@ -135,17 +146,24 @@ namespace OpenSim.Framework /// True to run this thread as a background /// thread, otherwise false /// Trigger an alarm function is we have timed out + /// + /// Alarm method to call if alarmIfTimeout is true and there is a timeout. + /// Normally, this will just return some useful debugging information. + /// /// Number of milliseconds to wait until we issue a warning about timeout. /// The newly created Thread object public static Thread StartThread( - ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout, int timeout) + ThreadStart start, string name, ThreadPriority priority, bool isBackground, + bool alarmIfTimeout, Func alarmMethod, int timeout) { Thread thread = new Thread(start); thread.Name = name; thread.Priority = priority; thread.IsBackground = isBackground; - ThreadWatchdogInfo twi = new ThreadWatchdogInfo(thread, timeout) { AlarmIfTimeout = alarmIfTimeout }; + ThreadWatchdogInfo twi + = new ThreadWatchdogInfo(thread, timeout) + { AlarmIfTimeout = alarmIfTimeout, AlarmMethod = alarmMethod }; m_log.DebugFormat( "[WATCHDOG]: Started tracking thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId); @@ -258,7 +276,17 @@ namespace OpenSim.Framework /// private static void WatchdogTimerElapsed(object sender, System.Timers.ElapsedEventArgs e) { - WatchdogTimeout callback = OnWatchdogTimeout; + int now = Environment.TickCount & Int32.MaxValue; + int msElapsed = now - LastWatchdogThreadTick; + + if (msElapsed > WATCHDOG_INTERVAL_MS * 2) + m_log.WarnFormat( + "[WATCHDOG]: {0} ms since Watchdog last ran. Interval should be approximately {1} ms", + msElapsed, WATCHDOG_INTERVAL_MS); + + LastWatchdogThreadTick = Environment.TickCount & Int32.MaxValue; + + Action callback = OnWatchdogTimeout; if (callback != null) { @@ -266,8 +294,6 @@ namespace OpenSim.Framework lock (m_threads) { - int now = Environment.TickCount; - foreach (ThreadWatchdogInfo threadInfo in m_threads.Values) { if (threadInfo.Thread.ThreadState == ThreadState.Stopped) @@ -296,7 +322,7 @@ namespace OpenSim.Framework if (callbackInfos != null) foreach (ThreadWatchdogInfo callbackInfo in callbackInfos) - callback(callbackInfo.Thread, callbackInfo.LastTick); + callback(callbackInfo); } m_watchdogTimer.Start(); diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index aac575cb5c..6a40cd540d 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -53,19 +53,36 @@ namespace OpenSim.Framework LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - private static int m_requestNumber = 0; + /// + /// Request number for diagnostic purposes. + /// + public static int RequestNumber = 0; - // this is the header field used to communicate the local request id - // used for performance and debugging + /// + /// this is the header field used to communicate the local request id + /// used for performance and debugging + /// public const string OSHeaderRequestID = "opensim-request-id"; - // number of milliseconds a call can take before it is considered - // a "long" call for warning & debugging purposes - public const int LongCallTime = 500; + /// + /// Number of milliseconds a call can take before it is considered + /// a "long" call for warning & debugging purposes + /// + public const int LongCallTime = 3000; - // dictionary of end points + /// + /// The maximum length of any data logged because of a long request time. + /// + /// + /// This is to truncate any really large post data, such as an asset. In theory, the first section should + /// give us useful information about the call (which agent it relates to if applicable, etc.). + /// + public const int MaxRequestDiagLength = 100; + + /// + /// Dictionary of end points + /// private static Dictionary m_endpointSerializer = new Dictionary(); - private static object EndPointLock(string url) { @@ -86,8 +103,7 @@ namespace OpenSim.Framework return eplock; } } - - + #region JSONRequest /// @@ -129,12 +145,13 @@ namespace OpenSim.Framework private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed) { - int reqnum = m_requestNumber++; + int reqnum = RequestNumber++; // m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method); string errorMessage = "unknown error"; int tickstart = Util.EnvironmentTickCount(); int tickdata = 0; + string strBuffer = null; try { @@ -149,7 +166,7 @@ namespace OpenSim.Framework // If there is some input, write it into the request if (data != null) { - string strBuffer = OSDParser.SerializeJsonString(data); + strBuffer = OSDParser.SerializeJsonString(data); byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer); if (compressed) @@ -210,14 +227,23 @@ namespace OpenSim.Framework } finally { - // This just dumps a warning for any operation that takes more than 100 ms int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); if (tickdiff > LongCallTime) - m_log.DebugFormat("[WEB UTIL]: osd request <{0}> (URI:{1}, METHOD:{2}) took {3}ms overall, {4}ms writing", - reqnum,url,method,tickdiff,tickdata); + m_log.InfoFormat( + "[OSD REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", + reqnum, + method, + url, + tickdiff, + tickdata, + strBuffer != null + ? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer) + : ""); } - m_log.DebugFormat("[WEB UTIL]: <{0}> osd request for {1}, method {2} FAILED: {3}", reqnum, url, method, errorMessage); + m_log.DebugFormat( + "[WEB UTIL]: <{0}> osd request for {1}, method {2} FAILED: {3}", reqnum, url, method, errorMessage); + return ErrorResponseMap(errorMessage); } @@ -290,17 +316,17 @@ namespace OpenSim.Framework private static OSDMap ServiceFormRequestWorker(string url, NameValueCollection data, int timeout) { - int reqnum = m_requestNumber++; + int reqnum = RequestNumber++; string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown"; // m_log.DebugFormat("[WEB UTIL]: <{0}> start form request for {1}, method {2}",reqnum,url,method); string errorMessage = "unknown error"; int tickstart = Util.EnvironmentTickCount(); int tickdata = 0; + string queryString = null; try { - HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); request.Method = "POST"; request.Timeout = timeout; @@ -311,7 +337,7 @@ namespace OpenSim.Framework if (data != null) { - string queryString = BuildQueryString(data); + queryString = BuildQueryString(data); byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString); request.ContentLength = buffer.Length; @@ -354,11 +380,20 @@ namespace OpenSim.Framework { int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); if (tickdiff > LongCallTime) - m_log.InfoFormat("[WEB UTIL]: form request <{0}> (URI:{1}, METHOD:{2}) took {3}ms overall, {4}ms writing", - reqnum,url,method,tickdiff,tickdata); + m_log.InfoFormat( + "[SERVICE FORM]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", + reqnum, + method, + url, + tickdiff, + tickdata, + queryString != null + ? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString + : ""); } - m_log.WarnFormat("[WEB UTIL]: <{0}> form request failed: {1}",reqnum,errorMessage); + m_log.WarnFormat("[SERVICE FORM]: <{0}> form request to {1} failed: {2}", reqnum, url, errorMessage); + return ErrorResponseMap(errorMessage); } @@ -638,8 +673,6 @@ namespace OpenSim.Framework return new string[0]; } - - } public static class AsynchronousRestObjectRequester @@ -662,6 +695,12 @@ namespace OpenSim.Framework public static void MakeRequest(string verb, string requestUrl, TRequest obj, Action action) { + int reqnum = WebUtil.RequestNumber++; + // m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method); + + int tickstart = Util.EnvironmentTickCount(); + int tickdata = 0; + // m_log.DebugFormat("[ASYNC REQUEST]: Starting {0} {1}", verb, requestUrl); Type type = typeof(TRequest); @@ -672,12 +711,13 @@ namespace OpenSim.Framework XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); request.Method = verb; + MemoryStream buffer = null; if (verb == "POST") { request.ContentType = "text/xml"; - MemoryStream buffer = new MemoryStream(); + buffer = new MemoryStream(); XmlWriterSettings settings = new XmlWriterSettings(); settings.Encoding = Encoding.UTF8; @@ -699,6 +739,9 @@ namespace OpenSim.Framework requestStream.Write(buffer.ToArray(), 0, length); requestStream.Close(); + // capture how much time was spent writing + tickdata = Util.EnvironmentTickCountSubtract(tickstart); + request.BeginGetResponse(delegate(IAsyncResult ar) { response = request.EndGetResponse(ar); @@ -724,83 +767,108 @@ namespace OpenSim.Framework }, null); }, null); - - - return; } - - request.BeginGetResponse(delegate(IAsyncResult res2) + else { - try + request.BeginGetResponse(delegate(IAsyncResult res2) { - // 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) + // 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 { - 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); - } + respStream = response.GetResponseStream(); + deserial = (TResponse)deserializer.Deserialize(respStream); + } + catch (System.InvalidOperationException) + { + } + finally + { + respStream.Close(); + response.Close(); } } - else + catch (WebException e) { - m_log.ErrorFormat("[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}", verb, requestUrl, e.Status, e.Message); + 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) + catch (Exception e) + { + m_log.ErrorFormat( + "[ASYNC REQUEST]: Request {0} {1} failed with exception {2}{3}", + verb, requestUrl, e.Message, e.StackTrace); + } + + // 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}{3}", + verb, requestUrl, e.Message, e.StackTrace); + } + + }, null); + } + + int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); + if (tickdiff > WebUtil.LongCallTime) + { + string originalRequest = null; + + if (buffer != null) { - m_log.ErrorFormat("[ASYNC REQUEST]: Request {0} {1} failed with exception {2}", verb, requestUrl, e); + originalRequest = Encoding.UTF8.GetString(buffer.ToArray()); + + if (originalRequest.Length > WebUtil.MaxRequestDiagLength) + originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength); } - // 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); + m_log.InfoFormat( + "[ASYNC REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", + reqnum, + verb, + requestUrl, + tickdiff, + tickdata, + originalRequest); + } } } public static class SynchronousRestFormsRequester { - private static readonly ILog m_log = - LogManager.GetLogger( - MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// /// Perform a synchronous REST request. @@ -814,6 +882,12 @@ namespace OpenSim.Framework /// 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) { + int reqnum = WebUtil.RequestNumber++; + // m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method); + + int tickstart = Util.EnvironmentTickCount(); + int tickdata = 0; + WebRequest request = WebRequest.Create(requestUrl); request.Method = verb; string respstring = String.Empty; @@ -842,12 +916,16 @@ namespace OpenSim.Framework } catch (Exception e) { - m_log.DebugFormat("[FORMS]: exception occured on sending request to {0}: " + e.ToString(), requestUrl); + m_log.DebugFormat( + "[FORMS]: exception occured {0} {1}: {2}{3}", verb, requestUrl, e.Message, e.StackTrace); } finally { if (requestStream != null) requestStream.Close(); + + // capture how much time was spent writing + tickdata = Util.EnvironmentTickCountSubtract(tickstart); } } @@ -868,7 +946,9 @@ namespace OpenSim.Framework } catch (Exception e) { - m_log.DebugFormat("[FORMS]: exception occured on receiving reply " + e.ToString()); + m_log.DebugFormat( + "[FORMS]: Exception occured on receiving {0} {1}: {2}{3}", + verb, requestUrl, e.Message, e.StackTrace); } finally { @@ -881,9 +961,21 @@ namespace OpenSim.Framework catch (System.InvalidOperationException) { // This is what happens when there is invalid XML - m_log.DebugFormat("[FORMS]: InvalidOperationException on receiving request"); + m_log.DebugFormat("[FORMS]: InvalidOperationException on receiving {0} {1}", verb, requestUrl); } } + + int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); + if (tickdiff > WebUtil.LongCallTime) + m_log.InfoFormat( + "[FORMS]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", + reqnum, + verb, + requestUrl, + tickdiff, + tickdata, + obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); + return respstring; } } @@ -911,6 +1003,12 @@ namespace OpenSim.Framework public static TResponse MakeRequest(string verb, string requestUrl, TRequest obj, int pTimeout) { + int reqnum = WebUtil.RequestNumber++; + // m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method); + + int tickstart = Util.EnvironmentTickCount(); + int tickdata = 0; + Type type = typeof(TRequest); TResponse deserial = default(TResponse); @@ -918,12 +1016,13 @@ namespace OpenSim.Framework request.Method = verb; if (pTimeout != 0) request.Timeout = pTimeout * 1000; + MemoryStream buffer = null; if ((verb == "POST") || (verb == "PUT")) { request.ContentType = "text/xml"; - MemoryStream buffer = new MemoryStream(); + buffer = new MemoryStream(); XmlWriterSettings settings = new XmlWriterSettings(); settings.Encoding = Encoding.UTF8; @@ -946,13 +1045,19 @@ namespace OpenSim.Framework } catch (Exception e) { - m_log.DebugFormat("[SynchronousRestObjectRequester]: exception in sending data to {0}: {1}", requestUrl, e); + m_log.DebugFormat( + "[SynchronousRestObjectRequester]: Exception in making request {0} {1}: {2}{3}", + verb, requestUrl, e.Message, e.StackTrace); + return deserial; } finally { if (requestStream != null) requestStream.Close(); + + // capture how much time was spent writing + tickdata = Util.EnvironmentTickCountSubtract(tickstart); } } @@ -968,7 +1073,11 @@ namespace OpenSim.Framework respStream.Close(); } else - m_log.DebugFormat("[SynchronousRestObjectRequester]: Oops! no content found in response stream from {0} {1}", requestUrl, verb); + { + m_log.DebugFormat( + "[SynchronousRestObjectRequester]: Oops! no content found in response stream from {0} {1}", + verb, requestUrl); + } } } catch (WebException e) @@ -979,17 +1088,44 @@ namespace OpenSim.Framework return deserial; else m_log.ErrorFormat( - "[SynchronousRestObjectRequester]: WebException {0} {1} {2} {3}", - requestUrl, typeof(TResponse).ToString(), e.Message, e.StackTrace); + "[SynchronousRestObjectRequester]: WebException for {0} {1} {2}: {3} {4}", + verb, requestUrl, typeof(TResponse).ToString(), e.Message, e.StackTrace); } catch (System.InvalidOperationException) { // This is what happens when there is invalid XML - m_log.DebugFormat("[SynchronousRestObjectRequester]: Invalid XML {0} {1}", requestUrl, typeof(TResponse).ToString()); + m_log.DebugFormat( + "[SynchronousRestObjectRequester]: Invalid XML from {0} {1} {2}", + verb, requestUrl, typeof(TResponse).ToString()); } catch (Exception e) { - m_log.DebugFormat("[SynchronousRestObjectRequester]: Exception on response from {0} {1}", requestUrl, e); + m_log.DebugFormat( + "[SynchronousRestObjectRequester]: Exception on response from {0} {1}: {2}{3}", + verb, requestUrl, e.Message, e.StackTrace); + } + + int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); + if (tickdiff > WebUtil.LongCallTime) + { + string originalRequest = null; + + if (buffer != null) + { + originalRequest = Encoding.UTF8.GetString(buffer.ToArray()); + + if (originalRequest.Length > WebUtil.MaxRequestDiagLength) + originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength); + } + + m_log.InfoFormat( + "[SynchronousRestObjectRequester]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}", + reqnum, + verb, + requestUrl, + tickdiff, + tickdata, + originalRequest); } return deserial; diff --git a/OpenSim/Region/Application/Application.cs b/OpenSim/Region/Application/Application.cs index c1300380cf..ebfebc4443 100644 --- a/OpenSim/Region/Application/Application.cs +++ b/OpenSim/Region/Application/Application.cs @@ -92,9 +92,14 @@ namespace OpenSim m_log.Info("[OPENSIM MAIN]: configured log4net using default OpenSim.exe.config"); } - m_log.DebugFormat( + m_log.InfoFormat( "[OPENSIM MAIN]: System Locale is {0}", System.Threading.Thread.CurrentThread.CurrentCulture); + string monoThreadsPerCpu = System.Environment.GetEnvironmentVariable("MONO_THREADS_PER_CPU"); + + m_log.InfoFormat( + "[OPENSIM MAIN]: Environment variable MONO_THREADS_PER_CPU is {0}", monoThreadsPerCpu ?? "unset"); + // Increase the number of IOCP threads available. Mono defaults to a tragically low number int workerThreads, iocpThreads; System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); @@ -109,7 +114,6 @@ namespace OpenSim // Check if the system is compatible with OpenSimulator. // Ensures that the minimum system requirements are met - m_log.Info("Performing compatibility checks... \n"); string supported = String.Empty; if (Util.IsEnvironmentSupported(ref supported)) { diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index fb1e8316ef..e6b57c2ecc 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -28,6 +28,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Reflection; using System.Text; @@ -69,6 +70,7 @@ namespace OpenSim private Regex m_consolePromptRegex = new Regex(@"([^\\])\\(\w)", RegexOptions.Compiled); private string m_timedScript = "disabled"; + private int m_timeInterval = 1200; private Timer m_scriptTimer; public OpenSim(IConfigSource configSource) : base(configSource) @@ -98,6 +100,10 @@ namespace OpenSim m_consolePort = (uint)networkConfig.GetInt("console_port", 0); m_timedScript = startupConfig.GetString("timer_Script", "disabled"); + if (m_timedScript != "disabled") + { + m_timeInterval = startupConfig.GetInt("timer_Interval", 1200); + } if (m_logFileAppender != null) { @@ -138,7 +144,7 @@ namespace OpenSim m_log.Info("===================================================================="); m_log.Info("========================= STARTING OPENSIM ========================="); m_log.Info("===================================================================="); - + //m_log.InfoFormat("[OPENSIM MAIN]: GC Is Server GC: {0}", GCSettings.IsServerGC.ToString()); // http://msdn.microsoft.com/en-us/library/bb384202.aspx //GCSettings.LatencyMode = GCLatencyMode.Batch; @@ -215,7 +221,7 @@ namespace OpenSim { m_scriptTimer = new Timer(); m_scriptTimer.Enabled = true; - m_scriptTimer.Interval = 1200*1000; + m_scriptTimer.Interval = m_timeInterval*1000; m_scriptTimer.Elapsed += RunAutoTimerScript; } } @@ -225,12 +231,14 @@ namespace OpenSim /// private void RegisterConsoleCommands() { - m_console.Commands.AddCommand("Regions", false, "force update", + MainServer.RegisterHttpConsoleCommands(m_console); + + m_console.Commands.AddCommand("Objects", false, "force update", "force update", "Force the update of all objects on clients", HandleForceUpdate); - m_console.Commands.AddCommand("Comms", false, "debug packet", + m_console.Commands.AddCommand("Debug", false, "debug packet", "debug packet [ ]", "Turn on packet debugging", "If level > 255 then all incoming and outgoing packets are logged.\n" @@ -242,17 +250,9 @@ namespace OpenSim + "If an avatar name is given then only packets from that avatar are logged", Debug); - m_console.Commands.AddCommand("Comms", false, "debug http", - "debug http ", - "Turn on inbound http request debugging for everything except the event queue (see debug eq).", - "If level >= 2 then the handler used to service the request is logged.\n" - + "If level >= 1 then incoming HTTP requests are logged.\n" - + "If level <= 0 then no extra http logging is done.\n", - Debug); + m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug); - m_console.Commands.AddCommand("Comms", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug); - - m_console.Commands.AddCommand("Regions", false, "debug scene", + m_console.Commands.AddCommand("Debug", false, "debug scene", "debug scene ", "Turn on scene debugging", Debug); @@ -306,7 +306,7 @@ namespace OpenSim + " If this is not given then the oar is saved to region.oar in the current directory.", SaveOar); - m_console.Commands.AddCommand("Regions", false, "edit scale", + m_console.Commands.AddCommand("Objects", false, "edit scale", "edit scale ", "Change the scale of a named prim", HandleEditScale); @@ -349,7 +349,7 @@ namespace OpenSim "show ratings", "Show rating data", HandleShow); - m_console.Commands.AddCommand("Regions", false, "backup", + m_console.Commands.AddCommand("Objects", false, "backup", "backup", "Persist currently unsaved object changes immediately instead of waiting for the normal persistence call.", RunCommand); @@ -409,10 +409,6 @@ namespace OpenSim m_console.Commands.AddCommand("General", false, "modules unload", "modules unload ", "Unload a module", HandleModules); - - m_console.Commands.AddCommand("Regions", false, "kill uuid", - "kill uuid ", - "Kill an object by UUID", KillUUID); } public override void ShutdownSpecific() @@ -437,12 +433,16 @@ namespace OpenSim } } - private void WatchdogTimeoutHandler(System.Threading.Thread thread, int lastTick) + private void WatchdogTimeoutHandler(Watchdog.ThreadWatchdogInfo twi) { int now = Environment.TickCount & Int32.MaxValue; - m_log.ErrorFormat("[WATCHDOG]: Timeout detected for thread \"{0}\". ThreadState={1}. Last tick was {2}ms ago", - thread.Name, thread.ThreadState, now - lastTick); + m_log.ErrorFormat( + "[WATCHDOG]: Timeout detected for thread \"{0}\". ThreadState={1}. Last tick was {2}ms ago. {3}", + twi.Thread.Name, + twi.Thread.ThreadState, + now - twi.LastTick, + twi.AlarmMethod != null ? string.Format("Data: {0}", twi.AlarmMethod()) : ""); } #region Console Commands @@ -481,10 +481,10 @@ namespace OpenSim else presence.ControllingClient.Kick("\nYou have been logged out by an administrator.\n"); - // ...and close on our side presence.Scene.IncomingCloseAgent(presence.UUID); } } + MainConsole.Instance.Output(""); } @@ -618,10 +618,11 @@ namespace OpenSim return; } - PopulateRegionEstateInfo(regInfo); + bool changed = PopulateRegionEstateInfo(regInfo); IScene scene; CreateRegion(regInfo, true, out scene); - regInfo.EstateSettings.Save(); + if (changed) + regInfo.EstateSettings.Save(); } /// @@ -903,21 +904,6 @@ namespace OpenSim break; - case "http": - if (args.Length == 3) - { - int newDebug; - if (int.TryParse(args[2], out newDebug)) - { - MainServer.Instance.DebugLevel = newDebug; - MainConsole.Instance.OutputFormat("Debug http level set to {0}", newDebug); - break; - } - } - - MainConsole.Instance.Output("Usage: debug http 0..2"); - break; - case "scene": if (args.Length == 4) { @@ -969,8 +955,7 @@ namespace OpenSim if (showParams.Length > 1 && showParams[1] == "full") { agents = m_sceneManager.GetCurrentScenePresences(); - } - else + } else { agents = m_sceneManager.GetCurrentSceneAvatars(); } @@ -979,7 +964,8 @@ namespace OpenSim MainConsole.Instance.Output( String.Format("{0,-16} {1,-16} {2,-37} {3,-11} {4,-16} {5,-30}", "Firstname", "Lastname", - "Agent ID", "Root/Child", "Region", "Position")); + "Agent ID", "Root/Child", "Region", "Position") + ); foreach (ScenePresence presence in agents) { @@ -989,8 +975,7 @@ namespace OpenSim if (regionInfo == null) { regionName = "Unresolvable"; - } - else + } else { regionName = regionInfo.RegionName; } @@ -1003,43 +988,19 @@ namespace OpenSim presence.UUID, presence.IsChildAgent ? "Child" : "Root", regionName, - presence.AbsolutePosition.ToString())); + presence.AbsolutePosition.ToString()) + ); } MainConsole.Instance.Output(String.Empty); break; case "connections": - System.Text.StringBuilder connections = new System.Text.StringBuilder("Connections:\n"); - m_sceneManager.ForEachScene( - delegate(Scene scene) - { - scene.ForEachClient( - delegate(IClientAPI client) - { - connections.AppendFormat("{0}: {1} ({2}) from {3} on circuit {4}\n", - scene.RegionInfo.RegionName, client.Name, client.AgentId, client.RemoteEndPoint, client.CircuitCode); - } - ); - } - ); - - MainConsole.Instance.Output(connections.ToString()); + HandleShowConnections(); break; case "circuits": - System.Text.StringBuilder acd = new System.Text.StringBuilder("Agent Circuits:\n"); - m_sceneManager.ForEachScene( - delegate(Scene scene) - { - //this.HttpServer. - acd.AppendFormat("{0}:\n", scene.RegionInfo.RegionName); - foreach (AgentCircuitData aCircuit in scene.AuthenticateHandler.GetAgentCircuits().Values) - acd.AppendFormat("\t{0} {1} ({2})\n", aCircuit.firstname, aCircuit.lastname, (aCircuit.child ? "Child" : "Root")); - } - ); - - MainConsole.Instance.Output(acd.ToString()); + HandleShowCircuits(); break; case "http-handlers": @@ -1077,17 +1038,29 @@ namespace OpenSim } m_sceneManager.ForEachScene( - delegate(Scene scene) + delegate(Scene scene) { + m_log.Error("The currently loaded modules in " + scene.RegionInfo.RegionName + " are:"); + foreach (IRegionModule module in scene.Modules.Values) { - m_log.Error("The currently loaded modules in " + scene.RegionInfo.RegionName + " are:"); - foreach (IRegionModule module in scene.Modules.Values) + if (!module.IsSharedModule) { - if (!module.IsSharedModule) - { - m_log.Error("Region Module: " + module.Name); - } + m_log.Error("Region Module: " + module.Name); } - }); + } + } + ); + + m_sceneManager.ForEachScene( + delegate(Scene scene) { + MainConsole.Instance.Output("Loaded new region modules in" + scene.RegionInfo.RegionName + " are:"); + foreach (IRegionModuleBase module in scene.RegionModules.Values) + { + Type type = module.GetType().GetInterface("ISharedRegionModule"); + string module_type = type != null ? "Shared" : "Non-Shared"; + MainConsole.Instance.OutputFormat("New Region Module ({0}): {1}", module_type, module.Name); + } + } + ); MainConsole.Instance.Output(""); break; @@ -1132,6 +1105,53 @@ namespace OpenSim } } + private void HandleShowCircuits() + { + ConsoleDisplayTable cdt = new ConsoleDisplayTable(); + cdt.AddColumn("Region", 20); + cdt.AddColumn("Avatar name", 24); + cdt.AddColumn("Type", 5); + cdt.AddColumn("Code", 10); + cdt.AddColumn("IP", 16); + cdt.AddColumn("Viewer Name", 24); + + m_sceneManager.ForEachScene( + s => + { + foreach (AgentCircuitData aCircuit in s.AuthenticateHandler.GetAgentCircuits().Values) + cdt.AddRow( + s.Name, + aCircuit.Name, + aCircuit.child ? "child" : "root", + aCircuit.circuitcode.ToString(), + aCircuit.IPAddress.ToString(), + aCircuit.Viewer); + }); + + MainConsole.Instance.Output(cdt.ToString()); + } + + private void HandleShowConnections() + { + ConsoleDisplayTable cdt = new ConsoleDisplayTable(); + cdt.AddColumn("Region", 20); + cdt.AddColumn("Avatar name", 24); + cdt.AddColumn("Circuit code", 12); + cdt.AddColumn("Endpoint", 23); + cdt.AddColumn("Active?", 7); + + m_sceneManager.ForEachScene( + s => s.ForEachClient( + c => cdt.AddRow( + s.Name, + c.Name, + c.RemoteEndPoint.ToString(), + c.CircuitCode.ToString(), + c.IsActive.ToString()))); + + MainConsole.Instance.Output(cdt.ToString()); + } + /// /// Use XML2 format to serialize data to a file /// @@ -1299,58 +1319,6 @@ namespace OpenSim return result; } - /// - /// Kill an object given its UUID. - /// - /// - protected void KillUUID(string module, string[] cmdparams) - { - if (cmdparams.Length > 2) - { - UUID id = UUID.Zero; - SceneObjectGroup grp = null; - Scene sc = null; - - if (!UUID.TryParse(cmdparams[2], out id)) - { - MainConsole.Instance.Output("[KillUUID]: Error bad UUID format!"); - return; - } - - m_sceneManager.ForEachScene( - delegate(Scene scene) - { - SceneObjectPart part = scene.GetSceneObjectPart(id); - if (part == null) - return; - - grp = part.ParentGroup; - sc = scene; - }); - - if (grp == null) - { - MainConsole.Instance.Output(String.Format("[KillUUID]: Given UUID {0} not found!", id)); - } - else - { - MainConsole.Instance.Output(String.Format("[KillUUID]: Found UUID {0} in scene {1}", id, sc.RegionInfo.RegionName)); - try - { - sc.DeleteSceneObject(grp, false); - } - catch (Exception e) - { - m_log.ErrorFormat("[KillUUID]: Error while removing objects from scene: " + e); - } - } - } - else - { - MainConsole.Instance.Output("[KillUUID]: Usage: kill uuid "); - } - } - #endregion } } diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index ddc7f105eb..76ac246caa 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -232,7 +232,7 @@ namespace OpenSim base.StartupSpecific(); - m_stats = StatsManager.StartCollectingSimExtraStats(); + m_stats = StatsManager.SimExtraStats; // Create a ModuleLoader instance m_moduleLoader = new ModuleLoader(m_config.Source); @@ -437,7 +437,7 @@ namespace OpenSim scene.LoadPrimsFromStorage(regionInfo.originRegionID); // TODO : Try setting resource for region xstats here on scene - MainServer.Instance.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(regionInfo)); + MainServer.Instance.AddStreamHandler(new RegionStatsHandler(regionInfo)); scene.loadAllLandObjectsFromStorage(regionInfo.originRegionID); scene.EventManager.TriggerParcelPrimCountUpdate(); @@ -856,6 +856,9 @@ namespace OpenSim return Util.UTF8.GetBytes("OK"); } + public string Name { get { return "SimStatus"; } } + public string Description { get { return "Simulator Status"; } } + public string ContentType { get { return "text/plain"; } @@ -880,6 +883,9 @@ namespace OpenSim { OpenSimBase m_opensim; string osXStatsURI = String.Empty; + + public string Name { get { return "XSimStatus"; } } + public string Description { get { return "Simulator XStatus"; } } public XSimStatusHandler(OpenSimBase sim) { @@ -920,6 +926,9 @@ namespace OpenSim { OpenSimBase m_opensim; string osUXStatsURI = String.Empty; + + public string Name { get { return "UXSimStatus"; } } + public string Description { get { return "Simulator UXStatus"; } } public UXSimStatusHandler(OpenSimBase sim) { @@ -1051,13 +1060,13 @@ namespace OpenSim /// Load the estate information for the provided RegionInfo object. /// /// - public void PopulateRegionEstateInfo(RegionInfo regInfo) + public bool PopulateRegionEstateInfo(RegionInfo regInfo) { if (EstateDataService != null) regInfo.EstateSettings = EstateDataService.LoadEstateSettings(regInfo.RegionID, false); if (regInfo.EstateSettings.EstateID != 0) - return; + return false; // estate info in the database did not change m_log.WarnFormat("[ESTATE] Region {0} is not part of an estate.", regInfo.RegionName); @@ -1092,7 +1101,7 @@ namespace OpenSim } if (defaultEstateJoined) - return; + return true; // need to update the database else m_log.ErrorFormat( "[OPENSIM BASE]: Joining default estate {0} failed", defaultEstateName); @@ -1154,8 +1163,10 @@ namespace OpenSim MainConsole.Instance.Output("Joining the estate failed. Please try again."); } } - } - } + } + + return true; // need to update the database + } } public class OpenSimConfigSource diff --git a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs index ef6dedb261..d397893aa2 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/BunchOfCaps/BunchOfCaps.cs @@ -158,7 +158,9 @@ namespace OpenSim.Region.ClientStack.Linden try { // the root of all evil - m_HostCapsObj.RegisterHandler("SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest)); + m_HostCapsObj.RegisterHandler( + "SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null)); + m_log.DebugFormat( "[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID); @@ -166,7 +168,10 @@ namespace OpenSim.Region.ClientStack.Linden // new LLSDStreamhandler("POST", // capsBase + m_mapLayerPath, // GetMapLayer); - IRequestHandler req = new RestStreamHandler("POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory); + IRequestHandler req + = new RestStreamHandler( + "POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory, "UpdateScript", null); + m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req); m_HostCapsObj.RegisterHandler("UpdateScriptTask", req); } @@ -181,14 +186,22 @@ namespace OpenSim.Region.ClientStack.Linden try { // I don't think this one works... - m_HostCapsObj.RegisterHandler("NewFileAgentInventory", new LLSDStreamhandler("POST", - capsBase + m_newInventory, - NewAgentInventoryRequest)); - IRequestHandler req = new RestStreamHandler("POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory); + m_HostCapsObj.RegisterHandler( + "NewFileAgentInventory", + new LLSDStreamhandler( + "POST", + capsBase + m_newInventory, + NewAgentInventoryRequest, + "NewFileAgentInventory", + null)); + + IRequestHandler req + = new RestStreamHandler( + "POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory, "Update*", null); + m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req); m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req); m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req); - m_HostCapsObj.RegisterHandler("CopyInventoryFromNotecard", new RestStreamHandler("POST", capsBase + m_copyFromNotecardPath, CopyInventoryFromNotecard)); IRequestHandler getObjectPhysicsDataHandler = new RestStreamHandler("POST", capsBase + m_getObjectPhysicsDataPath, GetObjectPhysicsData); m_HostCapsObj.RegisterHandler("GetObjectPhysicsData", getObjectPhysicsDataHandler); IRequestHandler getObjectCostHandler = new RestStreamHandler("POST", capsBase + m_getObjectCostPath, GetObjectCost); @@ -197,6 +210,12 @@ namespace OpenSim.Region.ClientStack.Linden m_HostCapsObj.RegisterHandler("ResourceCostSelected", ResourceCostSelectedHandler); + + m_HostCapsObj.RegisterHandler( + "CopyInventoryFromNotecard", + new RestStreamHandler( + "POST", capsBase + m_copyFromNotecardPath, CopyInventoryFromNotecard, "CopyInventoryFromNotecard", null)); + // As of RC 1.22.9 of the Linden client this is // supported @@ -245,7 +264,10 @@ namespace OpenSim.Region.ClientStack.Linden if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint)) { - m_log.DebugFormat("[CAPS]: Unauthorized CAPS client"); + m_log.DebugFormat( + "[CAPS]: Unauthorized CAPS client {0} from {1}", + m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint); + return string.Empty; } @@ -296,7 +318,9 @@ namespace OpenSim.Region.ClientStack.Linden m_dumpAssetsToFile); uploader.OnUpLoad += TaskScriptUpdated; - m_HostCapsObj.HttpListener.AddStreamHandler(new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); + m_HostCapsObj.HttpListener.AddStreamHandler( + new BinaryStreamHandler( + "POST", capsBase + uploaderPath, uploader.uploaderCaps, "TaskInventoryScriptUpdater", null)); string protocol = "http://"; @@ -423,8 +447,14 @@ namespace OpenSim.Region.ClientStack.Linden AssetUploader uploader = new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile); + m_HostCapsObj.HttpListener.AddStreamHandler( - new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); + new BinaryStreamHandler( + "POST", + capsBase + uploaderPath, + uploader.uploaderCaps, + "NewAgentInventoryRequest", + m_HostCapsObj.AgentID.ToString())); string protocol = "http://"; @@ -740,7 +770,8 @@ namespace OpenSim.Region.ClientStack.Linden uploader.OnUpLoad += ItemUpdated; m_HostCapsObj.HttpListener.AddStreamHandler( - new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); + new BinaryStreamHandler( + "POST", capsBase + uploaderPath, uploader.uploaderCaps, "NoteCardAgentInventory", null)); string protocol = "http://"; diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index 016ed9757c..ebfe68721e 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs @@ -106,13 +106,14 @@ namespace OpenSim.Region.ClientStack.Linden scene.EventManager.OnRegisterCaps += OnRegisterCaps; MainConsole.Instance.Commands.AddCommand( - "Comms", + "Debug", false, "debug eq", - "debug eq [0|1]", - "Turn on event queue debugging", - "debug eq 1 will turn on event queue debugging. This will log all outgoing event queue messages to clients.\n" - + "debug eq 0 will turn off event queue debugging.", + "debug eq [0|1|2]", + "Turn on event queue debugging" + + "<= 0 - turns off all event queue logging" + + ">= 1 - turns on outgoing event logging" + + ">= 2 - turns on poll notification", HandleDebugEq); } else @@ -235,19 +236,19 @@ namespace OpenSim.Region.ClientStack.Linden // ClientClosed(client.AgentId); // } - private void ClientClosed(UUID AgentID, Scene scene) + private void ClientClosed(UUID agentID, Scene scene) { -// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", AgentID, m_scene.RegionInfo.RegionName); +// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); int count = 0; - while (queues.ContainsKey(AgentID) && queues[AgentID].Count > 0 && count++ < 5) + while (queues.ContainsKey(agentID) && queues[agentID].Count > 0 && count++ < 5) { Thread.Sleep(1000); } lock (queues) { - queues.Remove(AgentID); + queues.Remove(agentID); } List removeitems = new List(); @@ -256,7 +257,7 @@ namespace OpenSim.Region.ClientStack.Linden foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys) { // m_log.DebugFormat("[EVENTQUEUE]: Found key {0} in m_AvatarQueueUUIDMapping while looking for {1}", ky, AgentID); - if (ky == AgentID) + if (ky == agentID) { removeitems.Add(ky); } @@ -267,7 +268,12 @@ namespace OpenSim.Region.ClientStack.Linden UUID eventQueueGetUuid = m_AvatarQueueUUIDMapping[ky]; m_AvatarQueueUUIDMapping.Remove(ky); - MainServer.Instance.RemovePollServiceHTTPHandler("","/CAPS/EQG/" + eventQueueGetUuid.ToString() + "/"); + string eqgPath = GenerateEqgCapPath(eventQueueGetUuid); + MainServer.Instance.RemovePollServiceHTTPHandler("", eqgPath); + +// m_log.DebugFormat( +// "[EVENT QUEUE GET MODULE]: Removed EQG handler {0} for {1} in {2}", +// eqgPath, agentID, m_scene.RegionInfo.RegionName); } } @@ -281,7 +287,7 @@ namespace OpenSim.Region.ClientStack.Linden { searchval = m_QueueUUIDAvatarMapping[ky]; - if (searchval == AgentID) + if (searchval == agentID) { removeitems.Add(ky); } @@ -305,6 +311,15 @@ namespace OpenSim.Region.ClientStack.Linden //} } + /// + /// Generate an Event Queue Get handler path for the given eqg uuid. + /// + /// + private string GenerateEqgCapPath(UUID eqgUuid) + { + return string.Format("/CAPS/EQG/{0}/", eqgUuid); + } + public void OnRegisterCaps(UUID agentID, Caps caps) { // Register an event queue for the client @@ -316,8 +331,7 @@ namespace OpenSim.Region.ClientStack.Linden // Let's instantiate a Queue for this agent right now TryGetQueue(agentID); - string capsBase = "/CAPS/EQG/"; - UUID EventQueueGetUUID = UUID.Zero; + UUID eventQueueGetUUID; lock (m_AvatarQueueUUIDMapping) { @@ -325,43 +339,49 @@ namespace OpenSim.Region.ClientStack.Linden if (m_AvatarQueueUUIDMapping.ContainsKey(agentID)) { //m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!"); - EventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; + eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID]; } else { - EventQueueGetUUID = UUID.Random(); + eventQueueGetUUID = UUID.Random(); //m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!"); } } lock (m_QueueUUIDAvatarMapping) { - if (!m_QueueUUIDAvatarMapping.ContainsKey(EventQueueGetUUID)) - m_QueueUUIDAvatarMapping.Add(EventQueueGetUUID, agentID); + if (!m_QueueUUIDAvatarMapping.ContainsKey(eventQueueGetUUID)) + m_QueueUUIDAvatarMapping.Add(eventQueueGetUUID, agentID); } lock (m_AvatarQueueUUIDMapping) { if (!m_AvatarQueueUUIDMapping.ContainsKey(agentID)) - m_AvatarQueueUUIDMapping.Add(agentID, EventQueueGetUUID); + m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID); } + string eventQueueGetPath = GenerateEqgCapPath(eventQueueGetUUID); + // Register this as a caps handler // FIXME: Confusingly, we need to register separate as a capability so that the client is told about // EventQueueGet when it receive capability information, but then we replace the rest handler immediately // afterwards with the poll service. So for now, we'll pass a null instead to simplify code reading, but // really it should be possible to directly register the poll handler as a capability. - caps.RegisterHandler("EventQueueGet", - new RestHTTPHandler("POST", capsBase + EventQueueGetUUID.ToString() + "/", null)); + caps.RegisterHandler("EventQueueGet", new RestHTTPHandler("POST", eventQueueGetPath, null)); // delegate(Hashtable m_dhttpMethod) // { // return ProcessQueue(m_dhttpMethod, agentID, caps); // })); // This will persist this beyond the expiry of the caps handlers + // TODO: Add EventQueueGet name/description for diagnostics MainServer.Instance.AddPollServiceHTTPHandler( - capsBase + EventQueueGetUUID.ToString() + "/", - new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID,1000)); // 1 sec timeout + eventQueueGetPath, + new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID, 1000)); + +// m_log.DebugFormat( +// "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}", +// eventQueueGetPath, agentID, m_scene.RegionInfo.RegionName); Random rnd = new Random(Environment.TickCount); lock (m_ids) @@ -384,9 +404,25 @@ namespace OpenSim.Region.ClientStack.Linden return false; } + /// + /// Logs a debug line for an outbound event queue message if appropriate. + /// + /// Element containing message + private void LogOutboundDebugMessage(OSD element, UUID agentId) + { + if (element is OSDMap) + { + OSDMap ev = (OSDMap)element; + m_log.DebugFormat( + "Eq OUT {0,-30} to {1,-20} {2,-20}", + ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.RegionInfo.RegionName); + } + } + public Hashtable GetEvents(UUID requestID, UUID pAgentId, string request) { -// m_log.DebugFormat("[EVENT QUEUE GET MODULE]: Invoked GetEvents() for {0}", pAgentId); + if (DebugLevel >= 2) + m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName); Queue queue = TryGetQueue(pAgentId); OSD element; @@ -410,13 +446,8 @@ namespace OpenSim.Region.ClientStack.Linden } else { - if (DebugLevel > 0 && element is OSDMap) - { - OSDMap ev = (OSDMap)element; - m_log.DebugFormat( - "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}", - ev["message"], m_scene.GetScenePresence(pAgentId).Name); - } + if (DebugLevel > 0) + LogOutboundDebugMessage(element, pAgentId); array.Add(element); @@ -426,13 +457,8 @@ namespace OpenSim.Region.ClientStack.Linden { element = queue.Dequeue(); - if (DebugLevel > 0 && element is OSDMap) - { - OSDMap ev = (OSDMap)element; - m_log.DebugFormat( - "[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}", - ev["message"], m_scene.GetScenePresence(pAgentId).Name); - } + if (DebugLevel > 0) + LogOutboundDebugMessage(element, pAgentId); array.Add(element); thisID++; diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs index a5209b7aec..cd70410680 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs @@ -51,7 +51,16 @@ namespace OpenSim.Region.ClientStack.Linden.Tests [SetUp] public void SetUp() { - MainServer.Instance = new BaseHttpServer(9999, false, 9998, ""); + uint port = 9999; + uint sslPort = 9998; + + // This is an unfortunate bit of clean up we have to do because MainServer manages things through static + // variables and the VM is not restarted between tests. + MainServer.RemoveHttpServer(port); + + BaseHttpServer server = new BaseHttpServer(port, false, sslPort, ""); + MainServer.AddHttpServer(server); + MainServer.Instance = server; IConfigSource config = new IniConfigSource(); config.AddConfig("Startup"); @@ -60,7 +69,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests CapabilitiesModule capsModule = new CapabilitiesModule(); EventQueueGetModule eqgModule = new EventQueueGetModule(); - m_scene = SceneHelpers.SetupScene(); + m_scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(m_scene, config, capsModule, eqgModule); } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/FetchInventory2Module.cs b/OpenSim/Region/ClientStack/Linden/Caps/FetchInventory2Module.cs index 14501c7314..cb5afcc38f 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/FetchInventory2Module.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/FetchInventory2Module.cs @@ -132,7 +132,8 @@ namespace OpenSim.Region.ClientStack.Linden capUrl = "/CAPS/" + UUID.Random(); IRequestHandler reqHandler - = new RestStreamHandler("POST", capUrl, m_fetchHandler.FetchInventoryRequest); + = new RestStreamHandler( + "POST", capUrl, m_fetchHandler.FetchInventoryRequest, capName, agentID.ToString()); caps.RegisterHandler(capName, reqHandler); } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs index e7bd2e764a..0d7b1fc6e6 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs @@ -120,11 +120,13 @@ namespace OpenSim.Region.ClientStack.Linden { // m_log.DebugFormat("[GETMESH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService); - IRequestHandler reqHandler = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), - delegate(Hashtable m_dhttpMethod) - { - return gmeshHandler.ProcessGetMesh(m_dhttpMethod, UUID.Zero, null); - }); + IRequestHandler reqHandler + = new RestHTTPHandler( + "GET", + "/CAPS/" + UUID.Random(), + httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null), + "GetMesh", + agentID.ToString()); caps.RegisterHandler("GetMesh", reqHandler); } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs index fffcee2b7e..5ae9cc3307 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs @@ -130,7 +130,9 @@ namespace OpenSim.Region.ClientStack.Linden if (m_URL == "localhost") { // m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); - caps.RegisterHandler("GetTexture", new GetTextureHandler("/CAPS/" + capID + "/", m_assetService)); + caps.RegisterHandler( + "GetTexture", + new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString())); } else { diff --git a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs index 18c7eaeb59..44a68839ca 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/MeshUploadFlagModule.cs @@ -117,7 +117,9 @@ namespace OpenSim.Region.ClientStack.Linden public void RegisterCaps(UUID agentID, Caps caps) { - IRequestHandler reqHandler = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), MeshUploadFlag); + IRequestHandler reqHandler + = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), MeshUploadFlag, "MeshUploadFlag", agentID.ToString()); + caps.RegisterHandler("MeshUploadFlag", reqHandler); m_agentID = agentID; } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs index 91872c5a34..52c4f44c8c 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/NewFileAgentInventoryVariablePriceModule.cs @@ -115,67 +115,66 @@ namespace OpenSim.Region.ClientStack.Linden UUID capID = UUID.Random(); // m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID); - caps.RegisterHandler("NewFileAgentInventoryVariablePrice", - - new LLSDStreamhandler("POST", - "/CAPS/" + capID.ToString(), - delegate(LLSDAssetUploadRequest req) - { - return NewAgentInventoryRequest(req,agentID); - })); - + caps.RegisterHandler( + "NewFileAgentInventoryVariablePrice", + new LLSDStreamhandler( + "POST", + "/CAPS/" + capID.ToString(), + req => NewAgentInventoryRequest(req, agentID), + "NewFileAgentInventoryVariablePrice", + agentID.ToString())); } #endregion public LLSDNewFileAngentInventoryVariablePriceReplyResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest, UUID agentID) { - //TODO: The Mesh uploader uploads many types of content. If you're going to implement a Money based limit - // You need to be aware of this and - + // you need to be aware of this //if (llsdRequest.asset_type == "texture" || // llsdRequest.asset_type == "animation" || // llsdRequest.asset_type == "sound") // { // check user level - ScenePresence avatar = null; - IClientAPI client = null; - m_scene.TryGetScenePresence(agentID, out avatar); - if (avatar != null) + ScenePresence avatar = null; + IClientAPI client = null; + m_scene.TryGetScenePresence(agentID, out avatar); + + if (avatar != null) + { + client = avatar.ControllingClient; + + if (avatar.UserLevel < m_levelUpload) { - client = avatar.ControllingClient; + if (client != null) + client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); - if (avatar.UserLevel < m_levelUpload) - { - if (client != null) - client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false); - - LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse(); - errorResponse.rsvp = ""; - errorResponse.state = "error"; - return errorResponse; - } + LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse(); + errorResponse.rsvp = ""; + errorResponse.state = "error"; + return errorResponse; } + } - // check funds - IMoneyModule mm = m_scene.RequestModuleInterface(); + // check funds + IMoneyModule mm = m_scene.RequestModuleInterface(); - if (mm != null) + if (mm != null) + { + if (!mm.UploadCovered(agentID, mm.UploadCharge)) { - if (!mm.UploadCovered(agentID, mm.UploadCharge)) - { - if (client != null) - client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); + if (client != null) + client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false); - LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse(); - errorResponse.rsvp = ""; - errorResponse.state = "error"; - return errorResponse; - } + LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse(); + errorResponse.rsvp = ""; + errorResponse.state = "error"; + return errorResponse; } + } + // } string assetName = llsdRequest.name; @@ -189,8 +188,14 @@ namespace OpenSim.Region.ClientStack.Linden AssetUploader uploader = new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type, llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile); + MainServer.Instance.AddStreamHandler( - new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps)); + new BinaryStreamHandler( + "POST", + capsBase + uploaderPath, + uploader.uploaderCaps, + "NewFileAgentInventoryVariablePrice", + agentID.ToString())); string protocol = "http://"; @@ -199,10 +204,9 @@ namespace OpenSim.Region.ClientStack.Linden string uploaderURL = protocol + m_scene.RegionInfo.ExternalHostName + ":" + MainServer.Instance.Port.ToString() + capsBase + uploaderPath; - + LLSDNewFileAngentInventoryVariablePriceReplyResponse uploadResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse(); - uploadResponse.rsvp = uploaderURL; uploadResponse.state = "upload"; @@ -220,6 +224,7 @@ namespace OpenSim.Region.ClientStack.Linden pinventoryItem, pparentFolder, pdata, pinventoryType, passetType,agentID); }; + return uploadResponse; } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs index 1c47f0ef80..4ccfc434a6 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/ObjectAdd.cs @@ -66,12 +66,14 @@ namespace OpenSim.Region.ClientStack.Linden // m_log.InfoFormat("[OBJECTADD]: {0}", "/CAPS/OA/" + capuuid + "/"); - caps.RegisterHandler("ObjectAdd", - new RestHTTPHandler("POST", "/CAPS/OA/" + capuuid + "/", - delegate(Hashtable m_dhttpMethod) - { - return ProcessAdd(m_dhttpMethod, agentID, caps); - })); + caps.RegisterHandler( + "ObjectAdd", + new RestHTTPHandler( + "POST", + "/CAPS/OA/" + capuuid + "/", + httpMethod => ProcessAdd(httpMethod, agentID, caps), + "ObjectAdd", + agentID.ToString()));; } public Hashtable ProcessAdd(Hashtable request, UUID AgentId, Caps cap) diff --git a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs index 7a3d97e5d3..ba902b2a3b 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/ObjectCaps/UploadObjectAssetModule.cs @@ -106,12 +106,15 @@ namespace OpenSim.Region.ClientStack.Linden UUID capID = UUID.Random(); // m_log.Debug("[UPLOAD OBJECT ASSET MODULE]: /CAPS/" + capID); - caps.RegisterHandler("UploadObjectAsset", - new RestHTTPHandler("POST", "/CAPS/OA/" + capID + "/", - delegate(Hashtable m_dhttpMethod) - { - return ProcessAdd(m_dhttpMethod, agentID, caps); - })); + caps.RegisterHandler( + "UploadObjectAsset", + new RestHTTPHandler( + "POST", + "/CAPS/OA/" + capID + "/", + httpMethod => ProcessAdd(httpMethod, agentID, caps), + "UploadObjectAsset", + agentID.ToString())); + /* caps.RegisterHandler("NewFileAgentInventoryVariablePrice", @@ -330,7 +333,6 @@ namespace OpenSim.Region.ClientStack.Linden grp.AbsolutePosition = obj.Position; prim.RotationOffset = obj.Rotation; - grp.IsAttachment = false; // Required for linking grp.RootPart.ClearUpdateSchedule(); diff --git a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs index 1dd8938fb0..8ed0fb3e1f 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/SimulatorFeaturesModule.cs @@ -154,7 +154,9 @@ namespace OpenSim.Region.ClientStack.Linden public void RegisterCaps(UUID agentID, Caps caps) { IRequestHandler reqHandler - = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), HandleSimulatorFeaturesRequest); + = new RestHTTPHandler( + "GET", "/CAPS/" + UUID.Random(), + HandleSimulatorFeaturesRequest, "SimulatorFeatures", agentID.ToString()); caps.RegisterHandler("SimulatorFeatures", reqHandler); } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs index 45d6071c24..b3d61a8be0 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/UploadBakedTextureModule.cs @@ -106,7 +106,9 @@ namespace OpenSim.Region.ClientStack.Linden "POST", "/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath, new UploadBakedTextureHandler( - caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture)); + caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture, + "UploadBakedTexture", + agentID.ToString())); } } } \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs index 10f43d192d..2359bd6683 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs @@ -144,7 +144,12 @@ namespace OpenSim.Region.ClientStack.Linden capUrl = "/CAPS/" + UUID.Random(); IRequestHandler reqHandler - = new RestStreamHandler("POST", capUrl, m_webFetchHandler.FetchInventoryDescendentsRequest); + = new RestStreamHandler( + "POST", + capUrl, + m_webFetchHandler.FetchInventoryDescendentsRequest, + "FetchInventoryDescendents2", + agentID.ToString()); caps.RegisterHandler(capName, reqHandler); } @@ -160,4 +165,4 @@ namespace OpenSim.Region.ClientStack.Linden // capName, capUrl, m_scene.RegionInfo.RegionName, agentID); } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs index 90b3ede57c..1b8535cacb 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/IncomingPacket.cs @@ -39,7 +39,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP public sealed class IncomingPacket { /// Client this packet came from - public LLUDPClient Client; + public LLClientView Client; + /// Packet data that has been received public Packet Packet; @@ -48,7 +49,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// /// Reference to the client this packet came from /// Packet data - public IncomingPacket(LLUDPClient client, Packet packet) + public IncomingPacket(LLClientView client, Packet packet) { Client = client; Packet = packet; diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 9c96b52f62..e6289bd96c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -59,7 +59,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Handles new client connections /// Constructor takes a single Packet and authenticates everything /// - public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientInventory, IClientIPEndpoint, IStatsCollector + public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientInventory, IStatsCollector { /// /// Debug packet level. See OpenSim.RegisterConsoleCommands() for more details. @@ -365,7 +365,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected string m_lastName; protected Thread m_clientThread; protected Vector3 m_startpos; - protected EndPoint m_userEndPoint; protected UUID m_activeGroupID; protected string m_activeGroupName = String.Empty; protected ulong m_activeGroupPowers; @@ -458,7 +457,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// /// Constructor /// - public LLClientView(EndPoint remoteEP, Scene scene, LLUDPServer udpServer, LLUDPClient udpClient, AuthenticateResponse sessionInfo, + public LLClientView(Scene scene, LLUDPServer udpServer, LLUDPClient udpClient, AuthenticateResponse sessionInfo, UUID agentId, UUID sessionId, uint circuitCode) { // DebugPacketLevel = 1; @@ -466,7 +465,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP RegisterInterface(this); RegisterInterface(this); RegisterInterface(this); - RegisterInterface(this); m_scene = scene; m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); @@ -483,7 +481,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_sessionId = sessionId; m_secureSessionId = sessionInfo.LoginInfo.SecureSession; m_circuitCode = circuitCode; - m_userEndPoint = remoteEP; m_firstName = sessionInfo.LoginInfo.First; m_lastName = sessionInfo.LoginInfo.Last; m_startpos = sessionInfo.LoginInfo.StartPos; @@ -515,6 +512,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// public void Close(bool sendStop) { + IsActive = false; + m_log.DebugFormat( "[CLIENT]: Close has been called for {0} attached to scene {1}", Name, m_scene.RegionInfo.RegionName); @@ -3902,7 +3901,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP canUseImproved = false; } } - + #endregion UpdateFlags to packet type conversion #region Block Construction @@ -11866,7 +11865,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (DebugPacketLevel <= 100 && (packet.Type == PacketType.AvatarAnimation || packet.Type == PacketType.ViewerEffect)) logPacket = false; - if (DebugPacketLevel <= 50 && packet.Type == PacketType.ImprovedTerseObjectUpdate) + if (DebugPacketLevel <= 50 + & (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate)) logPacket = false; if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily) @@ -11979,7 +11979,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP { ClientInfo info = m_udpClient.GetClientInfo(); - info.userEP = m_userEndPoint; info.proxyEP = null; info.agentcircuit = RequestClientInfo(); @@ -11991,11 +11990,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_udpClient.SetClientInfo(info); } - public EndPoint GetClientEP() - { - return m_userEndPoint; - } - #region Media Parcel Members public void SendParcelMediaCommand(uint flags, ParcelMediaCommandEnum command, float time) @@ -12076,10 +12070,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP return string.Empty; } - public void KillEndDone() - { - } - #region IClientCore private readonly Dictionary m_clientInterfaces = new Dictionary(); @@ -12167,21 +12157,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected void MakeAssetRequest(TransferRequestPacket transferRequest, UUID taskID) { UUID requestID = UUID.Zero; - if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset) + int sourceType = transferRequest.TransferInfo.SourceType; + + if (sourceType == (int)SourceType.Asset) { requestID = new UUID(transferRequest.TransferInfo.Params, 0); } - else if (transferRequest.TransferInfo.SourceType == (int)SourceType.SimInventoryItem) + else if (sourceType == (int)SourceType.SimInventoryItem) { requestID = new UUID(transferRequest.TransferInfo.Params, 80); } - else if (transferRequest.TransferInfo.SourceType == (int)SourceType.SimEstate) + else if (sourceType == (int)SourceType.SimEstate) { requestID = taskID; } - -// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID); +// m_log.DebugFormat( +// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}", +// requestID, taskID, (SourceType)sourceType, Name); //Note, the bool returned from the below function is useless since it is always false. @@ -12270,24 +12263,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP return numPackets; } - #region IClientIPEndpoint Members - - public IPAddress EndPoint - { - get - { - if (m_userEndPoint is IPEndPoint) - { - IPEndPoint ep = (IPEndPoint)m_userEndPoint; - - return ep.Address; - } - return null; - } - } - - #endregion - public void SendRebakeAvatarTextures(UUID textureID) { RebakeAvatarTexturesPacket pack = diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 0831946ada..6e7a6a8192 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -147,23 +147,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP private int m_elapsed500MSOutgoingPacketHandler; /// Flag to signal when clients should check for resends - private bool m_resendUnacked; + protected bool m_resendUnacked; + /// Flag to signal when clients should send ACKs - private bool m_sendAcks; + protected bool m_sendAcks; + /// Flag to signal when clients should send pings - private bool m_sendPing; + protected bool m_sendPing; private ExpiringCache> m_pendingCache = new ExpiringCache>(); private int m_defaultRTO = 0; private int m_maxRTO = 0; - + private int m_ackTimeout = 0; + private int m_pausedAckTimeout = 0; private bool m_disableFacelights = false; public Socket Server { get { return null; } } private int m_malformedCount = 0; // Guard against a spamming attack + /// + /// Record current outgoing client for monitoring purposes. + /// + private IClientAPI m_currentOutgoingClient; + + /// + /// Recording current incoming client for monitoring purposes. + /// + private IClientAPI m_currentIncomingClient; + public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) : base(listenIP, (int)port) { @@ -200,11 +213,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_defaultRTO = config.GetInt("DefaultRTO", 0); m_maxRTO = config.GetInt("MaxRTO", 0); m_disableFacelights = config.GetBoolean("DisableFacelights", false); + m_ackTimeout = 1000 * config.GetInt("AckTimeout", 60); + m_pausedAckTimeout = 1000 * config.GetInt("PausedAckTimeout", 300); } else { PrimUpdatesPerCallback = 100; TextureSendLimit = 20; + m_ackTimeout = 1000 * 60; // 1 minute + m_pausedAckTimeout = 1000 * 300; // 5 minutes } #region BinaryStats @@ -241,19 +258,56 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (m_scene == null) throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); - m_log.Info("[LLUDPSERVER]: Starting the LLUDP server in " + (m_asyncPacketHandling ? "asynchronous" : "synchronous") + " mode"); + m_log.InfoFormat( + "[LLUDPSERVER]: Starting the LLUDP server in {0} mode", + m_asyncPacketHandling ? "asynchronous" : "synchronous"); base.Start(m_recvBufferSize, m_asyncPacketHandling); // Start the packet processing threads Watchdog.StartThread( - IncomingPacketHandler, "Incoming Packets (" + m_scene.RegionInfo.RegionName + ")", ThreadPriority.Normal, false, true); + IncomingPacketHandler, + string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName), + ThreadPriority.Normal, + false, + true, + GetWatchdogIncomingAlarmData, + Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); + Watchdog.StartThread( - OutgoingPacketHandler, "Outgoing Packets (" + m_scene.RegionInfo.RegionName + ")", ThreadPriority.Normal, false, true); + OutgoingPacketHandler, + string.Format("Outgoing Packets ({0})", m_scene.RegionInfo.RegionName), + ThreadPriority.Normal, + false, + true, + GetWatchdogOutgoingAlarmData, + Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); m_elapsedMSSinceLastStatReport = Environment.TickCount; } + /// + /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging. + /// + /// + private string GetWatchdogIncomingAlarmData() + { + return string.Format( + "Client is {0}", + m_currentIncomingClient != null ? m_currentIncomingClient.Name : "none"); + } + + /// + /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging. + /// + /// + private string GetWatchdogOutgoingAlarmData() + { + return string.Format( + "Client is {0}", + m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none"); + } + public new void Stop() { m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName); @@ -487,19 +541,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null); } - public void HandleUnacked(LLUDPClient udpClient) + public void HandleUnacked(LLClientView client) { + LLUDPClient udpClient = client.UDPClient; + if (!udpClient.IsConnected) return; // Disconnect an agent if no packets are received for some time - //FIXME: Make 60 an .ini setting - if ((Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > 1000 * 60) - { - m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); - StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); + int timeoutTicks = m_ackTimeout; + + // Allow more slack if the client is "paused" eg file upload dialogue is open + // Some sort of limit is needed in case the client crashes, loses its network connection + // or some other disaster prevents it from sendung the AgentResume + if (udpClient.IsPaused) + timeoutTicks = m_pausedAckTimeout; + + if (client.IsActive && + (Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > timeoutTicks) + { + // We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even + // though it's set later on by LLClientView.Close() + client.IsActive = false; + + // Fire this out on a different thread so that we don't hold up outgoing packet processing for + // everybody else if this is being called due to an ack timeout. + // This is the same as processing as the async process of a logout request. + Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); - RemoveClient(udpClient); return; } @@ -850,7 +919,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion Ping Check Handling // Inbox insertion - packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); + packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet)); } #region BinaryStats @@ -946,7 +1015,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP UDPPacketBuffer buffer = (UDPPacketBuffer)array[0]; UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; - m_log.DebugFormat("[LLUDPSERVER]: Handling UseCircuitCode request from {0}", buffer.RemoteEndPoint); + m_log.DebugFormat( + "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", + uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, buffer.RemoteEndPoint); remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint; @@ -1001,8 +1072,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP { // Don't create clients for unauthorized requesters. m_log.WarnFormat( - "[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}", - uccp.CircuitCode.ID, uccp.CircuitCode.Code, remoteEndPoint); + "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", + uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); lock (m_pendingCache) m_pendingCache.Remove(remoteEndPoint); } @@ -1090,7 +1161,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); - client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); + client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); client.OnLogout += LogoutHandler; ((LLClientView)client).DisableFacelights = m_disableFacelights; @@ -1102,15 +1173,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP return client; } - private void RemoveClient(LLUDPClient udpClient) + /// + /// Deactivates the client if we don't receive any packets within a certain amount of time (default 60 seconds). + /// + /// + /// If a connection is active then we will always receive packets even if nothing else is happening, due to + /// regular client pings. + /// + /// + private void DeactivateClientDueToTimeout(IClientAPI client) { - // Remove this client from the scene - IClientAPI client; - if (m_scene.TryGetClient(udpClient.AgentID, out client)) - { - client.IsLoggingOut = true; - client.Close(false); - } + // We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even + // though it's set later on by LLClientView.Close() + client.IsActive = false; + + m_log.WarnFormat( + "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", + client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName); + + StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); + + if (!client.SceneAgent.IsChildAgent) + client.Kick("Simulator logged you out due to connection timeout"); + + Util.FireAndForget(o => client.Close()); } private void IncomingPacketHandler() @@ -1219,6 +1305,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP // client. m_packetSent will be set to true if a packet is sent m_scene.ForEachClient(clientPacketHandler); + m_currentOutgoingClient = null; + // If nothing was sent, sleep for the minimum amount of time before a // token bucket could get more tokens if (!m_packetSent) @@ -1235,18 +1323,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP Watchdog.RemoveThread(); } - private void ClientOutgoingPacketHandler(IClientAPI client) + protected void ClientOutgoingPacketHandler(IClientAPI client) { + m_currentOutgoingClient = client; + try { if (client is LLClientView) { - LLUDPClient udpClient = ((LLClientView)client).UDPClient; + LLClientView llClient = (LLClientView)client; + LLUDPClient udpClient = llClient.UDPClient; if (udpClient.IsConnected) { if (m_resendUnacked) - HandleUnacked(udpClient); + HandleUnacked(llClient); if (m_sendAcks) SendAcks(udpClient); @@ -1262,8 +1353,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP } catch (Exception ex) { - m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + - " threw an exception: " + ex.Message, ex); + m_log.Error( + string.Format("[LLUDPSERVER]: OutgoingPacketHandler iteration for {0} threw ", client.Name), ex); } } @@ -1289,11 +1380,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP { nticks++; watch1.Start(); + m_currentOutgoingClient = client; + try { if (client is LLClientView) { - LLUDPClient udpClient = ((LLClientView)client).UDPClient; + LLClientView llClient = (LLClientView)client; + LLUDPClient udpClient = llClient.UDPClient; if (udpClient.IsConnected) { @@ -1302,7 +1396,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP nticksUnack++; watch2.Start(); - HandleUnacked(udpClient); + HandleUnacked(llClient); watch2.Stop(); avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack); @@ -1373,23 +1467,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP #endregion - private void ProcessInPacket(object state) + private void ProcessInPacket(IncomingPacket incomingPacket) { - IncomingPacket incomingPacket = (IncomingPacket)state; Packet packet = incomingPacket.Packet; - LLUDPClient udpClient = incomingPacket.Client; - IClientAPI client; + LLClientView client = incomingPacket.Client; - // Sanity check - if (packet == null || udpClient == null) + if (client.IsActive) { - m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"", - packet, udpClient); - } + m_currentIncomingClient = client; - // Make sure this client is still alive - if (m_scene.TryGetClient(udpClient.AgentID, out client)) - { try { // Process this packet @@ -1404,21 +1490,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP catch (Exception e) { // Don't let a failure in an individual client thread crash the whole sim. - m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type); - m_log.Error(e.Message, e); + m_log.Error( + string.Format( + "[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw ", + client.Name, packet.Type), + e); + } + finally + { + m_currentIncomingClient = null; } } else { - m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID); + m_log.DebugFormat( + "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", + packet.Type, client.Name, m_scene.RegionInfo.RegionName); } } protected void LogoutHandler(IClientAPI client) { client.SendLogoutPacket(); - if (client.IsActive) - RemoveClient(((LLClientView)client).UDPClient); + + if (!client.IsLoggingOut) + { + client.IsLoggingOut = true; + client.Close(); + } } } } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs index a575e3616d..109a8e1914 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs @@ -45,6 +45,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests [TestFixture] public class BasicCircuitTests { + private Scene m_scene; + private TestLLUDPServer m_udpServer; + [TestFixtureSetUp] public void FixtureInit() { @@ -61,83 +64,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; } -// /// -// /// Add a client for testing -// /// -// /// -// /// -// /// -// /// Agent circuit manager used in setting up the stack -// protected void SetupStack( -// IScene scene, out TestLLUDPServer testLLUDPServer, out TestLLPacketServer testPacketServer, -// out AgentCircuitManager acm) -// { -// IConfigSource configSource = new IniConfigSource(); -// ClientStackUserSettings userSettings = new ClientStackUserSettings(); -// testLLUDPServer = new TestLLUDPServer(); -// acm = new AgentCircuitManager(); -// -// uint port = 666; -// testLLUDPServer.Initialise(null, ref port, 0, false, configSource, acm); -// testPacketServer = new TestLLPacketServer(testLLUDPServer, userSettings); -// testLLUDPServer.LocalScene = scene; -// } - -// /// -// /// Set up a client for tests which aren't concerned with this process itself and where only one client is being -// /// tested -// /// -// /// -// /// -// /// -// /// -// protected void AddClient( -// uint circuitCode, EndPoint epSender, TestLLUDPServer testLLUDPServer, AgentCircuitManager acm) -// { -// UUID myAgentUuid = UUID.Parse("00000000-0000-0000-0000-000000000001"); -// UUID mySessionUuid = UUID.Parse("00000000-0000-0000-0000-000000000002"); -// -// AddClient(circuitCode, epSender, myAgentUuid, mySessionUuid, testLLUDPServer, acm); -// } - -// /// -// /// Set up a client for tests which aren't concerned with this process itself -// /// -// /// -// /// -// /// -// /// -// /// -// /// -// protected void AddClient( -// uint circuitCode, EndPoint epSender, UUID agentId, UUID sessionId, -// TestLLUDPServer testLLUDPServer, AgentCircuitManager acm) -// { -// AgentCircuitData acd = new AgentCircuitData(); -// acd.AgentID = agentId; -// acd.SessionID = sessionId; -// -// UseCircuitCodePacket uccp = new UseCircuitCodePacket(); -// -// UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock -// = new UseCircuitCodePacket.CircuitCodeBlock(); -// uccpCcBlock.Code = circuitCode; -// uccpCcBlock.ID = agentId; -// uccpCcBlock.SessionID = sessionId; -// uccp.CircuitCode = uccpCcBlock; -// -// acm.AddNewCircuit(circuitCode, acd); -// -// testLLUDPServer.LoadReceive(uccp, epSender); -// testLLUDPServer.ReceiveData(null); -// } + [SetUp] + public void SetUp() + { + m_scene = new SceneHelpers().SetupScene(); + } /// /// Build an object name packet for test purposes /// /// /// - protected ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName) + private ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName) { ObjectNamePacket onp = new ObjectNamePacket(); ObjectNamePacket.ObjectDataBlock odb = new ObjectNamePacket.ObjectDataBlock(); @@ -148,29 +86,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests return onp; } - - /// - /// Test adding a client to the stack - /// - [Test] - public void TestAddClient() - { - TestHelpers.InMethod(); -// XmlConfigurator.Configure(); - TestScene scene = SceneHelpers.SetupScene(); - uint myCircuitCode = 123456; + private void AddUdpServer() + { + AddUdpServer(new IniConfigSource()); + } + + private void AddUdpServer(IniConfigSource configSource) + { + uint port = 0; + AgentCircuitManager acm = m_scene.AuthenticateHandler; + + m_udpServer = new TestLLUDPServer(IPAddress.Any, ref port, 0, false, configSource, acm); + m_udpServer.AddScene(m_scene); + } + + /// + /// Used by tests that aren't testing this stage. + /// + private ScenePresence AddClient() + { UUID myAgentUuid = TestHelpers.ParseTail(0x1); UUID mySessionUuid = TestHelpers.ParseTail(0x2); + uint myCircuitCode = 123456; IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999); - uint port = 0; - AgentCircuitManager acm = scene.AuthenticateHandler; - - TestLLUDPServer llUdpServer - = new TestLLUDPServer(IPAddress.Any, ref port, 0, false, new IniConfigSource(), acm); - llUdpServer.AddScene(scene); - UseCircuitCodePacket uccp = new UseCircuitCodePacket(); UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock @@ -185,26 +125,67 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor. Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length); - llUdpServer.PacketReceived(upb); + AgentCircuitData acd = new AgentCircuitData(); + acd.AgentID = myAgentUuid; + acd.SessionID = mySessionUuid; + + m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd); + + m_udpServer.PacketReceived(upb); + + return m_scene.GetScenePresence(myAgentUuid); + } + + /// + /// Test adding a client to the stack + /// + [Test] + public void TestAddClient() + { + TestHelpers.InMethod(); +// XmlConfigurator.Configure(); + + AddUdpServer(); + + UUID myAgentUuid = TestHelpers.ParseTail(0x1); + UUID mySessionUuid = TestHelpers.ParseTail(0x2); + uint myCircuitCode = 123456; + IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999); + + UseCircuitCodePacket uccp = new UseCircuitCodePacket(); + + UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock + = new UseCircuitCodePacket.CircuitCodeBlock(); + uccpCcBlock.Code = myCircuitCode; + uccpCcBlock.ID = myAgentUuid; + uccpCcBlock.SessionID = mySessionUuid; + uccp.CircuitCode = uccpCcBlock; + + byte[] uccpBytes = uccp.ToBytes(); + UDPPacketBuffer upb = new UDPPacketBuffer(testEp, uccpBytes.Length); + upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor. + Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length); + + m_udpServer.PacketReceived(upb); // Presence shouldn't exist since the circuit manager doesn't know about this circuit for authentication yet - Assert.That(scene.GetScenePresence(myAgentUuid), Is.Null); + Assert.That(m_scene.GetScenePresence(myAgentUuid), Is.Null); AgentCircuitData acd = new AgentCircuitData(); acd.AgentID = myAgentUuid; acd.SessionID = mySessionUuid; - acm.AddNewCircuit(myCircuitCode, acd); + m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd); - llUdpServer.PacketReceived(upb); + m_udpServer.PacketReceived(upb); // Should succeed now - ScenePresence sp = scene.GetScenePresence(myAgentUuid); + ScenePresence sp = m_scene.GetScenePresence(myAgentUuid); Assert.That(sp.UUID, Is.EqualTo(myAgentUuid)); - Assert.That(llUdpServer.PacketsSent.Count, Is.EqualTo(1)); + Assert.That(m_udpServer.PacketsSent.Count, Is.EqualTo(1)); - Packet packet = llUdpServer.PacketsSent[0]; + Packet packet = m_udpServer.PacketsSent[0]; Assert.That(packet, Is.InstanceOf(typeof(PacketAckPacket))); PacketAckPacket ackPacket = packet as PacketAckPacket; @@ -212,6 +193,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests Assert.That(ackPacket.Packets[0].ID, Is.EqualTo(0)); } + [Test] + public void TestLogoutClientDueToAck() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + IniConfigSource ics = new IniConfigSource(); + IConfig config = ics.AddConfig("ClientStack.LindenUDP"); + config.Set("AckTimeout", -1); + AddUdpServer(ics); + + ScenePresence sp = AddClient(); + m_udpServer.ClientOutgoingPacketHandler(sp.ControllingClient, true, false, false); + + ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); + Assert.That(spAfterAckTimeout, Is.Null); + +// TestHelpers.DisableLogging(); + } + // /// // /// Test removing a client from the stack // /// diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs index 1b68d68765..5fcf376b84 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/LLImageManagerTests.cs @@ -79,7 +79,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests J2KDecoderModule j2kdm = new J2KDecoderModule(); - scene = SceneHelpers.SetupScene(); + SceneHelpers sceneHelpers = new SceneHelpers(); + scene = sceneHelpers.SetupScene(); SceneHelpers.SetupSceneModules(scene, j2kdm); tc = new TestClient(SceneHelpers.GenerateAgentData(userId), scene); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs index d76927be9f..119a677f80 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/MockScene.cs @@ -44,9 +44,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests } protected int m_objectNameCallsReceived; - public MockScene() + public MockScene() : base(new RegionInfo(1000, 1000, null, null)) { - m_regInfo = new RegionInfo(1000, 1000, null, null); m_regStatus = RegionStatus.Up; } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs index 0302385ad2..27b9e5b3f3 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/TestLLUDPServer.cs @@ -59,6 +59,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests PacketsSent.Add(packet); } + public void ClientOutgoingPacketHandler(IClientAPI client, bool resendUnacked, bool sendAcks, bool sendPing) + { + m_resendUnacked = resendUnacked; + m_sendAcks = sendAcks; + m_sendPing = sendPing; + + ClientOutgoingPacketHandler(client); + } + //// /// //// /// The chunks of data to pass to the LLUDPServer when it calls EndReceive //// /// diff --git a/OpenSim/Region/ClientStack/RegionApplicationBase.cs b/OpenSim/Region/ClientStack/RegionApplicationBase.cs index 6e3a58e63a..c4324e8592 100644 --- a/OpenSim/Region/ClientStack/RegionApplicationBase.cs +++ b/OpenSim/Region/ClientStack/RegionApplicationBase.cs @@ -94,24 +94,21 @@ namespace OpenSim.Region.ClientStack m_log.InfoFormat("[REGION SERVER]: Starting HTTP server on port {0}", m_httpServerPort); m_httpServer.Start(); + MainServer.AddHttpServer(m_httpServer); MainServer.Instance = m_httpServer; // "OOB" Server if (m_networkServersInfo.ssl_listener) { - BaseHttpServer server = null; - server = new BaseHttpServer( + BaseHttpServer server = new BaseHttpServer( m_networkServersInfo.https_port, m_networkServersInfo.ssl_listener, m_networkServersInfo.cert_path, m_networkServersInfo.cert_pass); - // Add the server to m_Servers - if(server != null) - { - m_log.InfoFormat("[REGION SERVER]: Starting HTTPS server on port {0}", server.Port); - MainServer.AddHttpServer(server); - server.Start(); - } - } + m_log.InfoFormat("[REGION SERVER]: Starting HTTPS server on port {0}", server.Port); + MainServer.AddHttpServer(server); + server.Start(); + } + base.StartupSpecific(); } diff --git a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs index 874693e8ea..708198923a 100644 --- a/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs +++ b/OpenSim/Region/CoreModules/Agent/AssetTransaction/AssetTransactionModule.cs @@ -42,8 +42,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction public class AssetTransactionModule : INonSharedRegionModule, IAgentAssetTransactions { -// private static readonly ILog m_log = LogManager.GetLogger( -// MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected Scene m_Scene; private bool m_dumpAssetsToFile = false; @@ -209,15 +208,15 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction /// and comes through this method. /// /// + /// /// /// - public void HandleTaskItemUpdateFromTransaction(IClientAPI remoteClient, - SceneObjectPart part, UUID transactionID, - TaskInventoryItem item) + public void HandleTaskItemUpdateFromTransaction( + IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item) { -// m_log.DebugFormat( -// "[TRANSACTIONS MANAGER] Called HandleTaskItemUpdateFromTransaction with item {0}", -// item.Name); + m_log.DebugFormat( + "[TRANSACTIONS MANAGER] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}", + item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName); AgentAssetTransactions transactions = GetUserTransactions(remoteClient.AgentId); diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index 127ca1d794..7d7176fc07 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -83,7 +83,7 @@ namespace Flotsam.RegionModules.AssetCache private Dictionary m_CurrentlyWriting = new Dictionary(); private int m_WaitOnInprogressTimeout = 3000; #else - private List m_CurrentlyWriting = new List(); + private HashSet m_CurrentlyWriting = new HashSet(); #endif private bool m_FileCacheEnabled = true; @@ -143,7 +143,7 @@ namespace Flotsam.RegionModules.AssetCache IConfig assetConfig = source.Configs["AssetCache"]; if (assetConfig == null) { - m_log.Warn( + m_log.Debug( "[FLOTSAM ASSET CACHE]: AssetCache section missing from config (not copied config-include/FlotsamCache.ini.example? Using defaults."); } else @@ -272,7 +272,11 @@ namespace Flotsam.RegionModules.AssetCache // the other thread has updated the time for us. try { - File.SetLastAccessTime(filename, DateTime.Now); + lock (m_CurrentlyWriting) + { + if (!m_CurrentlyWriting.Contains(filename)) + File.SetLastAccessTime(filename, DateTime.Now); + } } catch { diff --git a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs index 5adb84596c..c91b25fac2 100644 --- a/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs +++ b/OpenSim/Region/CoreModules/Asset/Tests/FlotsamAssetCacheTests.cs @@ -65,7 +65,7 @@ namespace OpenSim.Region.CoreModules.Asset.Tests config.Configs["AssetCache"].Set("MemoryCacheEnabled", "true"); m_cache = new FlotsamAssetCache(); - m_scene = SceneHelpers.SetupScene(); + m_scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(m_scene, config, m_cache); } diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index fd7cad255b..394b90a691 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -50,7 +50,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private Scene m_scene; - private IDialogModule m_dialogModule; + private IInventoryAccessModule m_invAccessModule; /// /// Are attachments enabled? @@ -72,7 +72,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public void AddRegion(Scene scene) { m_scene = scene; - m_dialogModule = m_scene.RequestModuleInterface(); m_scene.RegisterModuleInterface(this); if (Enabled) @@ -89,7 +88,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments m_scene.EventManager.OnNewClient -= SubscribeToClientEvents; } - public void RegionLoaded(Scene scene) {} + public void RegionLoaded(Scene scene) + { + m_invAccessModule = m_scene.RequestModuleInterface(); + } public void Close() { @@ -100,6 +102,56 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments #region IAttachmentsModule + public void CopyAttachments(IScenePresence sp, AgentData ad) + { + lock (sp.AttachmentsSyncLock) + { + // Attachment objects + List attachments = sp.GetAttachments(); + if (attachments.Count > 0) + { + ad.AttachmentObjects = new List(); + ad.AttachmentObjectStates = new List(); + // IScriptModule se = m_scene.RequestModuleInterface(); + sp.InTransitScriptStates.Clear(); + + foreach (SceneObjectGroup sog in attachments) + { + // We need to make a copy and pass that copy + // because of transfers withn the same sim + ISceneObject clone = sog.CloneForNewScene(); + // Attachment module assumes that GroupPosition holds the offsets...! + ((SceneObjectGroup)clone).RootPart.GroupPosition = sog.RootPart.AttachedPos; + ((SceneObjectGroup)clone).IsAttachment = false; + ad.AttachmentObjects.Add(clone); + string state = sog.GetStateSnapshot(); + ad.AttachmentObjectStates.Add(state); + sp.InTransitScriptStates.Add(state); + // Let's remove the scripts of the original object here + sog.RemoveScriptInstances(true); + } + } + } + } + + public void CopyAttachments(AgentData ad, IScenePresence sp) + { + if (ad.AttachmentObjects != null && ad.AttachmentObjects.Count > 0) + { + lock (sp.AttachmentsSyncLock) + sp.ClearAttachments(); + + int i = 0; + foreach (ISceneObject so in ad.AttachmentObjects) + { + ((SceneObjectGroup)so).LocalId = 0; + ((SceneObjectGroup)so).RootPart.ClearUpdateSchedule(); + so.SetState(ad.AttachmentObjectStates[i++], m_scene); + m_scene.IncomingCreateObject(Vector3.Zero, so); + } + } + } + /// /// RezAttachments. This should only be called upon login on the first region. /// Attachment rezzings on crossings and TPs are done in a different way. @@ -185,40 +237,55 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (sp.PresenceType == PresenceType.Npc) RezSingleAttachmentFromInventoryInternal(sp, UUID.Zero, attach.AssetID, p, null); else - RezSingleAttachmentFromInventory(sp, attach.ItemID, p, true, d); + RezSingleAttachmentFromInventory(sp, attach.ItemID, p, d); } catch (Exception e) { - m_log.ErrorFormat("[ATTACHMENTS MODULE]: Unable to rez attachment: {0}{1}", e.Message, e.StackTrace); + UUID agentId = (sp.ControllingClient == null) ? (UUID)null : sp.ControllingClient.AgentId; + m_log.ErrorFormat("[ATTACHMENTS MODULE]: Unable to rez attachment with itemID {0}, assetID {1}, point {2} for {3}: {4}\n{5}", + attach.ItemID, attach.AssetID, p, agentId, e.Message, e.StackTrace); } } } - public void SaveChangedAttachments(IScenePresence sp, bool saveAllScripted) + public void DeRezAttachments(IScenePresence sp, bool saveChanged, bool saveAllScripted) { -// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name); - if (!Enabled) return; - foreach (SceneObjectGroup grp in sp.GetAttachments()) +// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name); + + lock (sp.AttachmentsSyncLock) { - grp.IsAttachment = false; - grp.AbsolutePosition = grp.RootPart.AttachedPos; - UpdateKnownItem(sp, grp, saveAllScripted); - grp.IsAttachment = true; + foreach (SceneObjectGroup so in sp.GetAttachments()) + { + // We can only remove the script instances from the script engine after we've retrieved their xml state + // when we update the attachment item. + m_scene.DeleteSceneObject(so, false, false); + + if (saveChanged || saveAllScripted) + { + so.IsAttachment = false; + so.AbsolutePosition = so.RootPart.AttachedPos; + UpdateKnownItem(sp, so, saveAllScripted); + } + + so.RemoveScriptInstances(true); + } + + sp.ClearAttachments(); } } public void DeleteAttachmentsFromScene(IScenePresence sp, bool silent) { -// m_log.DebugFormat( -// "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}", -// m_scene.RegionInfo.RegionName, sp.Name, silent); - if (!Enabled) return; +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}", +// m_scene.RegionInfo.RegionName, sp.Name, silent); + foreach (SceneObjectGroup sop in sp.GetAttachments()) { sop.Scene.DeleteSceneObject(sop, silent); @@ -234,6 +301,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})", // group.Name, group.LocalId, sp.Name, attachmentPt, silent); + + if (group.GetSittingAvatarsCount() != 0) + { +// m_log.WarnFormat( +// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it", +// group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount()); + + return false; + } if (sp.GetAttachments(attachmentPt).Contains(group)) { @@ -294,32 +370,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments group.AttachmentPoint = attachmentPt; group.AbsolutePosition = attachPos; - // We also don't want to do any of the inventory operations for an NPC. if (sp.PresenceType != PresenceType.Npc) - { - // Remove any previous attachments - List attachments = sp.GetAttachments(attachmentPt); - - // At the moment we can only deal with a single attachment - if (attachments.Count != 0) - { - UUID oldAttachmentItemID = attachments[0].FromItemID; - - if (oldAttachmentItemID != UUID.Zero) - DetachSingleAttachmentToInvInternal(sp, oldAttachmentItemID); - else - m_log.WarnFormat( - "[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!", - attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name); - } - - // Add the new attachment to inventory if we don't already have it. - UUID newAttachmentItemID = group.FromItemID; - if (newAttachmentItemID == UUID.Zero) - newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID; - - ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group); - } + UpdateUserInventoryWithAttachment(sp, group, attachmentPt); AttachToAgent(sp, group, attachmentPt, attachPos, silent); } @@ -327,12 +379,36 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return true; } + private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt) + { + // Remove any previous attachments + List attachments = sp.GetAttachments(attachmentPt); + + // At the moment we can only deal with a single attachment + if (attachments.Count != 0) + { + if (attachments[0].FromItemID != UUID.Zero) + DetachSingleAttachmentToInvInternal(sp, attachments[0]); + else + m_log.WarnFormat( + "[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!", + attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name); + } + + // Add the new attachment to inventory if we don't already have it. + UUID newAttachmentItemID = group.FromItemID; + if (newAttachmentItemID == UUID.Zero) + newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID; + + ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group); + } + public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt) { - return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt, true, null); + return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt, null); } - public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc) + public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt, XmlDocument doc) { if (!Enabled) return null; @@ -371,12 +447,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return null; } - SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, doc); - - if (att == null) - DetachSingleAttachmentToInv(sp, itemID); - - return att; + return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, doc); } public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List> rezlist) @@ -453,18 +524,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); } - public void DetachSingleAttachmentToInv(IScenePresence sp, UUID itemID) + public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so) { lock (sp.AttachmentsSyncLock) { // Save avatar attachment information - m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID); +// m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID); - bool changed = sp.Appearance.DetachAttachment(itemID); + if (so.AttachedAvatar != sp.UUID) + { + m_log.WarnFormat( + "[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}", + so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName); + + return; + } + + bool changed = sp.Appearance.DetachAttachment(so.FromItemID); if (changed && m_scene.AvatarFactory != null) m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); - DetachSingleAttachmentToInvInternal(sp, itemID); + DetachSingleAttachmentToInvInternal(sp, so); } } @@ -473,17 +553,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (!Enabled) return; - // First we save the - // attachment point information, then we update the relative - // positioning. Then we have to mark the object as NOT an - // attachment. This is necessary in order to correctly save - // and retrieve GroupPosition information for the attachment. - // Finally, we restore the object's attachment status. - uint attachmentPoint = sog.AttachmentPoint; sog.UpdateGroupPosition(pos); - sog.IsAttachment = false; - sog.AbsolutePosition = sog.RootPart.AttachedPos; - sog.AttachmentPoint = attachmentPoint; sog.HasGroupChanged = true; } @@ -526,6 +596,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// /// /// + /// private void UpdateKnownItem(IScenePresence sp, SceneObjectGroup grp, bool saveAllScripted) { // Saving attachments for NPCs messes them up for the real owner! @@ -538,9 +609,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (grp.HasGroupChanged || (saveAllScripted && grp.ContainsScripts())) { - m_log.DebugFormat( - "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}", - grp.UUID, grp.AttachmentPoint); +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}", +// grp.UUID, grp.AttachmentPoint); string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); @@ -571,12 +642,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } grp.HasGroupChanged = false; // Prevent it being saved over and over } - else - { - m_log.DebugFormat( - "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", - grp.UUID, grp.AttachmentPoint); - } +// else +// { +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", +// grp.UUID, grp.AttachmentPoint); +// } } /// @@ -594,9 +665,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments private void AttachToAgent( IScenePresence sp, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent) { - // m_log.DebugFormat( - // "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", - // so.Name, avatar.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: Adding attachment {0} to avatar {1} in pt {2} pos {3} {4}", +// so.Name, sp.Name, attachmentpoint, attachOffset, so.RootPart.AttachedPos); so.DetachFromBackup(); @@ -627,6 +698,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { m_scene.SendKillObject(new List { so.RootPart.LocalId }); } + else if (so.HasPrivateAttachmentPoint) + { +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}", +// so.Name, sp.Name, so.AttachmentPoint); + + // As this scene object can now only be seen by the attaching avatar, tell everybody else in the + // scene that it's no longer in their awareness. + m_scene.ForEachClient( + client => + { if (client.AgentId != so.AttachedAvatar) + client.SendKillObject(m_scene.RegionInfo.RegionHandle, new List() { so.LocalId }); + }); + } so.IsSelected = false; // fudge.... so.ScheduleGroupForFullUpdate(); @@ -645,210 +730,124 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// The user inventory item created that holds the attachment. private InventoryItemBase AddSceneObjectAsNewAttachmentInInv(IScenePresence sp, SceneObjectGroup grp) { + if (m_invAccessModule == null) + return null; + // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}", // grp.Name, grp.LocalId, remoteClient.Name); -// Vector3 inventoryStoredPosition = new Vector3 -// (((grp.AbsolutePosition.X > (int)Constants.RegionSize) -// ? (float)Constants.RegionSize - 6 -// : grp.AbsolutePosition.X) -// , -// (grp.AbsolutePosition.Y > (int)Constants.RegionSize) -// ? (float)Constants.RegionSize - 6 -// : grp.AbsolutePosition.Y, -// grp.AbsolutePosition.Z); -// -// Vector3 originalPosition = grp.AbsolutePosition; -// -// grp.AbsolutePosition = inventoryStoredPosition; - - // If we're being called from a script, then trying to serialize that same script's state will not complete - // in any reasonable time period. Therefore, we'll avoid it. The worst that can happen is that if - // the client/server crashes rather than logging out normally, the attachment's scripts will resume - // without state on relog. Arguably, this is what we want anyway. - string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp, false); - -// grp.AbsolutePosition = originalPosition; - - AssetBase asset = m_scene.CreateAsset( - grp.GetPartName(grp.LocalId), - grp.GetPartDescription(grp.LocalId), - (sbyte)AssetType.Object, - Utils.StringToBytes(sceneObjectXml), - sp.UUID); - - m_scene.AssetService.Store(asset); - - InventoryItemBase item = new InventoryItemBase(); - item.CreatorId = grp.RootPart.CreatorID.ToString(); - item.CreatorData = grp.RootPart.CreatorData; - item.Owner = sp.UUID; - item.ID = UUID.Random(); - item.AssetID = asset.FullID; - item.Description = asset.Description; - item.Name = asset.Name; - item.AssetType = asset.Type; - item.InvType = (int)InventoryType.Object; - - InventoryFolderBase folder = m_scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object); - if (folder != null) - item.Folder = folder.ID; - else // oopsies - item.Folder = UUID.Zero; - - // Nix the special bits we used to use for slam and the folded perms - uint allowablePermissionsMask = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move); - - if ((sp.UUID != grp.RootPart.OwnerID) && m_scene.Permissions.PropagatePermissions()) - { - item.BasePermissions = grp.RootPart.BaseMask & grp.RootPart.NextOwnerMask & allowablePermissionsMask; - item.CurrentPermissions = grp.RootPart.BaseMask & grp.RootPart.NextOwnerMask & allowablePermissionsMask; - item.NextPermissions = grp.RootPart.NextOwnerMask & allowablePermissionsMask; - item.EveryOnePermissions = grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask & allowablePermissionsMask; - item.GroupPermissions = grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask & allowablePermissionsMask; - } - else - { - item.BasePermissions = grp.RootPart.BaseMask & allowablePermissionsMask; - item.CurrentPermissions = grp.RootPart.OwnerMask & allowablePermissionsMask; - item.NextPermissions = grp.RootPart.NextOwnerMask & allowablePermissionsMask; - item.EveryOnePermissions = grp.RootPart.EveryoneMask & allowablePermissionsMask; - item.GroupPermissions = grp.RootPart.GroupMask & allowablePermissionsMask; - } - item.CreationDate = Util.UnixTimeSinceEpoch(); + InventoryItemBase newItem + = m_invAccessModule.CopyToInventory( + DeRezAction.TakeCopy, + m_scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object).ID, + new List { grp }, + sp.ControllingClient, true)[0]; // sets itemID so client can show item as 'attached' in inventory - grp.FromItemID = item.ID; + grp.FromItemID = newItem.ID; - if (m_scene.AddInventoryItem(item)) - { - sp.ControllingClient.SendInventoryItemCreateUpdate(item, 0); - } - else - { - if (m_dialogModule != null) - m_dialogModule.SendAlertToUser(sp.ControllingClient, "Operation failed"); - } - - return item; + return newItem; } - // What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards. - // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? - private void DetachSingleAttachmentToInvInternal(IScenePresence sp, UUID itemID) + private void DetachSingleAttachmentToInvInternal(IScenePresence sp, SceneObjectGroup so) { // m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name); - if (itemID == UUID.Zero) // If this happened, someone made a mistake.... - return; + m_scene.EventManager.TriggerOnAttach(so.LocalId, so.FromItemID, UUID.Zero); + sp.RemoveAttachment(so); - // We can NOT use the dictionries here, as we are looking - // for an entity by the fromAssetID, which is NOT the prim UUID - EntityBase[] detachEntities = m_scene.GetEntities(); - SceneObjectGroup group; + // We can only remove the script instances from the script engine after we've retrieved their xml state + // when we update the attachment item. + m_scene.DeleteSceneObject(so, false, false); - lock (sp.AttachmentsSyncLock) - { - foreach (EntityBase entity in detachEntities) - { - if (entity is SceneObjectGroup) - { - group = (SceneObjectGroup)entity; - if (group.FromItemID == itemID) - { - m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); - sp.RemoveAttachment(group); + // Prepare sog for storage + so.AttachedAvatar = UUID.Zero; + so.RootPart.SetParentLocalId(0); + so.IsAttachment = false; + so.AbsolutePosition = so.RootPart.AttachedPos; - // Prepare sog for storage - group.AttachedAvatar = UUID.Zero; - group.RootPart.SetParentLocalId(0); - group.IsAttachment = false; - group.AbsolutePosition = group.RootPart.AttachedPos; - - UpdateKnownItem(sp, group, true); - m_scene.DeleteSceneObject(group, false); - - return; - } - } - } - } + UpdateKnownItem(sp, so, true); + so.RemoveScriptInstances(true); } protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal( IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt, XmlDocument doc) { - IInventoryAccessModule invAccess = m_scene.RequestModuleInterface(); - if (invAccess != null) + if (m_invAccessModule == null) + return null; + + lock (sp.AttachmentsSyncLock) { - lock (sp.AttachmentsSyncLock) + SceneObjectGroup objatt; + + if (itemID != UUID.Zero) + objatt = m_invAccessModule.RezObject(sp.ControllingClient, + itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, + false, false, sp.UUID, true); + else + objatt = m_invAccessModule.RezObject(sp.ControllingClient, + null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, + false, false, sp.UUID, true); + + if (objatt != null) { - SceneObjectGroup objatt; - - if (itemID != UUID.Zero) - objatt = invAccess.RezObject(sp.ControllingClient, - itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, - false, false, sp.UUID, true); - else - objatt = invAccess.RezObject(sp.ControllingClient, - null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true, - false, false, sp.UUID, true); - - // m_log.DebugFormat( - // "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}", - // objatt.Name, remoteClient.Name, AttachmentPt); +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}", +// objatt.Name, sp.Name, attachmentPt, m_scene.Name); + + // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. + objatt.HasGroupChanged = false; + bool tainted = false; + if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) + tainted = true; + + // FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal + // course of events. If not, then it's probably not worth trying to recover the situation + // since this is more likely to trigger further exceptions and confuse later debugging. If + // exceptions can be thrown in expected error conditions (not NREs) then make this consistent + // since other normal error conditions will simply return false instead. + // This will throw if the attachment fails + try + { + AttachObject(sp, objatt, attachmentPt, false, false); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", + objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); + + // Make sure the object doesn't stick around and bail + sp.RemoveAttachment(objatt); + m_scene.DeleteSceneObject(objatt, false); + return null; + } - if (objatt != null) - { - // HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller. - objatt.HasGroupChanged = false; - bool tainted = false; - if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint) - tainted = true; - - // This will throw if the attachment fails - try - { - AttachObject(sp, objatt, attachmentPt, false, false); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}", - objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace); - - // Make sure the object doesn't stick around and bail - sp.RemoveAttachment(objatt); - m_scene.DeleteSceneObject(objatt, false); - return null; - } - - if (tainted) - objatt.HasGroupChanged = true; - - if (doc != null) - { - objatt.LoadScriptState(doc); - objatt.ResetOwnerChangeFlag(); - } + if (tainted) + objatt.HasGroupChanged = true; - // Fire after attach, so we don't get messy perms dialogs - // 4 == AttachedRez - objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); - objatt.ResumeScripts(); - - // Do this last so that event listeners have access to all the effects of the attachment - m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); - - return objatt; - } - else + if (doc != null) { - m_log.WarnFormat( - "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", - itemID, sp.Name, attachmentPt); + objatt.LoadScriptState(doc); + objatt.ResetOwnerChangeFlag(); } + + // Fire after attach, so we don't get messy perms dialogs + // 4 == AttachedRez + objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4); + objatt.ResumeScripts(); + + // Do this last so that event listeners have access to all the effects of the attachment + m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID); + + return objatt; + } + else + { + m_log.WarnFormat( + "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", + itemID, sp.Name, attachmentPt); } } @@ -864,9 +863,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// private void ShowAttachInUserInventory(IScenePresence sp, uint AttachmentPt, UUID itemID, SceneObjectGroup att) { - // m_log.DebugFormat( - // "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", - // att.Name, sp.Name, AttachmentPt, itemID); +// m_log.DebugFormat( +// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", +// att.Name, sp.Name, AttachmentPt, itemID); if (UUID.Zero == itemID) { @@ -884,7 +883,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments item = m_scene.InventoryService.GetItem(item); bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); if (changed && m_scene.AvatarFactory != null) + { +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: Queueing appearance save for {0}, attachment {1} point {2} in ShowAttachInUserInventory()", +// sp.Name, att.Name, AttachmentPt); + m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); + } } #endregion @@ -929,9 +934,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments private void Client_OnObjectAttach(IClientAPI remoteClient, uint objectLocalID, uint AttachmentPt, bool silent) { - // m_log.DebugFormat( - // "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", - // objectLocalID, remoteClient.Name, AttachmentPt, silent); +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: Attaching object local id {0} to {1} point {2} from ground (silent = {3})", +// objectLocalID, remoteClient.Name, AttachmentPt, silent); if (!Enabled) return; @@ -967,13 +972,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // Calls attach with a Zero position if (AttachObject(sp, part.ParentGroup, AttachmentPt, false, true)) { - m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId); +// m_log.Debug( +// "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId +// + ", AttachmentPoint: " + AttachmentPt); // Save avatar attachment information - m_log.Debug( - "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId - + ", AttachmentPoint: " + AttachmentPt); - + m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId); } } catch (Exception e) @@ -989,8 +993,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID); + if (sp != null && group != null) - DetachSingleAttachmentToInv(sp, group.FromItemID); + DetachSingleAttachmentToInv(sp, group); } private void Client_OnDetachAttachmentIntoInv(UUID itemID, IClientAPI remoteClient) @@ -1000,7 +1005,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); if (sp != null) - DetachSingleAttachmentToInv(sp, itemID); + { + lock (sp.AttachmentsSyncLock) + { + List attachments = sp.GetAttachments(); + + foreach (SceneObjectGroup group in attachments) + { + if (group.FromItemID == itemID) + { + DetachSingleAttachmentToInv(sp, group); + return; + } + } + } + } } private void Client_OnObjectDrop(uint soLocalId, IClientAPI remoteClient) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 7119ad2319..cd1e1c19d7 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -31,6 +31,7 @@ using System.Reflection; using System.Text; using System.Threading; using System.Timers; +using System.Xml; using Timer=System.Timers.Timer; using Nini.Config; using NUnit.Framework; @@ -38,11 +39,16 @@ using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Communications; using OpenSim.Region.CoreModules.Avatar.Attachments; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; using OpenSim.Region.CoreModules.Framework.InventoryAccess; -using OpenSim.Region.CoreModules.World.Serialiser; +using OpenSim.Region.CoreModules.Scripting.WorldComm; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.CoreModules.World.Serialiser; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.ScriptEngine.XEngine; +using OpenSim.Services.Interfaces; using OpenSim.Tests.Common; using OpenSim.Tests.Common.Mock; @@ -52,11 +58,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests /// Attachment tests /// [TestFixture] - public class AttachmentsModuleTests + public class AttachmentsModuleTests : OpenSimTestCase { - private Scene scene; - private AttachmentsModule m_attMod; - private ScenePresence m_presence; + private AutoResetEvent m_chatEvent = new AutoResetEvent(false); + private OSChatMessage m_osChatMessageReceived; [TestFixtureSetUp] public void FixtureInit() @@ -65,18 +70,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Util.FireAndForgetMethod = FireAndForgetMethod.None; } - [SetUp] - public void Init() - { - IConfigSource config = new IniConfigSource(); - config.AddConfig("Modules"); - config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); - - scene = SceneHelpers.SetupScene(); - m_attMod = new AttachmentsModule(); - SceneHelpers.SetupSceneModules(scene, config, m_attMod, new BasicInventoryAccessModule()); - } - [TestFixtureTearDown] public void TearDown() { @@ -85,32 +78,121 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; } - /// - /// Add the standard presence for a test. - /// - private void AddPresence() + private void OnChatFromWorld(object sender, OSChatMessage oscm) { - UUID userId = TestHelpers.ParseTail(0x1); - UserAccountHelpers.CreateUserWithInventory(scene, userId); - m_presence = SceneHelpers.AddScenePresence(scene, userId); +// Console.WriteLine("Got chat [{0}]", oscm.Message); + + m_osChatMessageReceived = oscm; + m_chatEvent.Set(); + } + + private Scene CreateTestScene() + { + IConfigSource config = new IniConfigSource(); + List modules = new List(); + + AddCommonConfig(config, modules); + + Scene scene + = new SceneHelpers().SetupScene( + "attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config); + SceneHelpers.SetupSceneModules(scene, config, modules.ToArray()); + + return scene; + } + + private Scene CreateScriptingEnabledTestScene() + { + IConfigSource config = new IniConfigSource(); + List modules = new List(); + + AddCommonConfig(config, modules); + AddScriptingConfig(config, modules); + + Scene scene + = new SceneHelpers().SetupScene( + "attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config); + SceneHelpers.SetupSceneModules(scene, config, modules.ToArray()); + + scene.StartScripts(); + + return scene; + } + + private void AddCommonConfig(IConfigSource config, List modules) + { + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + modules.Add(new AttachmentsModule()); + modules.Add(new BasicInventoryAccessModule()); + } + + private void AddScriptingConfig(IConfigSource config, List modules) + { + IConfig startupConfig = config.AddConfig("Startup"); + startupConfig.Set("DefaultScriptEngine", "XEngine"); + + IConfig xEngineConfig = config.AddConfig("XEngine"); + xEngineConfig.Set("Enabled", "true"); + xEngineConfig.Set("StartDelay", "0"); + + // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call + // to AssemblyResolver.OnAssemblyResolve fails. + xEngineConfig.Set("AppDomainLoading", "false"); + + modules.Add(new XEngine()); + + // Necessary to stop serialization complaining + // FIXME: Stop this being necessary if at all possible +// modules.Add(new WorldCommModule()); + } + + /// + /// Creates an attachment item in the given user's inventory. Does not attach. + /// + /// + /// A user with the given ID and an inventory must already exist. + /// + /// + /// The attachment item. + /// + /// + /// + /// + /// + /// + private InventoryItemBase CreateAttachmentItem( + Scene scene, UUID userId, string attName, int rawItemId, int rawAssetId) + { + return UserInventoryHelpers.CreateInventoryItem( + scene, + attName, + TestHelpers.ParseTail(rawItemId), + TestHelpers.ParseTail(rawAssetId), + userId, + InventoryType.Object); } [Test] public void TestAddAttachmentFromGround() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); +// TestHelpers.EnableLogging(); + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); - AddPresence(); string attName = "att"; - SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName).ParentGroup; + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID); - m_attMod.AttachObject(m_presence, so, (uint)AttachmentPoint.Chest, false, false); + scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false); // Check status on scene presence - Assert.That(m_presence.HasAttachments(), Is.True); - List attachments = m_presence.GetAttachments(); + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); Assert.That(attachments.Count, Is.EqualTo(1)); SceneObjectGroup attSo = attachments[0]; Assert.That(attSo.Name, Is.EqualTo(attName)); @@ -121,42 +203,107 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests // Check item status Assert.That( - m_presence.Appearance.GetAttachpoint(attSo.FromItemID), + sp.Appearance.GetAttachpoint(attSo.FromItemID), Is.EqualTo((int)AttachmentPoint.Chest)); + + InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID)); + Assert.That(attachmentItem, Is.Not.Null); + Assert.That(attachmentItem.Name, Is.EqualTo(attName)); + + InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object); + Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID)); + + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + +// TestHelpers.DisableLogging(); + } + + /// + /// Test that we do not attempt to attach an in-world object that someone else is sitting on. + /// + [Test] + public void TestAddSatOnAttachmentFromGround() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); + + string attName = "att"; + + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID); + + UserAccount ua2 = UserAccountHelpers.CreateUserWithInventory(scene, 0x2); + ScenePresence sp2 = SceneHelpers.AddScenePresence(scene, ua2); + + // Put avatar within 10m of the prim so that sit doesn't fail. + sp2.AbsolutePosition = new Vector3(0, 0, 0); + sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero); + + scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false, false); + + Assert.That(sp.HasAttachments(), Is.False); + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); } [Test] - public void TestAddAttachmentFromInventory() + public void TestRezAttachmentFromInventory() { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - AddPresence(); + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID); - UUID attItemId = TestHelpers.ParseTail(0x2); - UUID attAssetId = TestHelpers.ParseTail(0x3); - string attName = "att"; + InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); - UserInventoryHelpers.CreateInventoryItem( - scene, attName, attItemId, attAssetId, m_presence.UUID, InventoryType.Object); - - m_attMod.RezSingleAttachmentFromInventory( - m_presence, attItemId, (uint)AttachmentPoint.Chest); + scene.AttachmentsModule.RezSingleAttachmentFromInventory( + sp, attItem.ID, (uint)AttachmentPoint.Chest); // Check scene presence status - Assert.That(m_presence.HasAttachments(), Is.True); - List attachments = m_presence.GetAttachments(); + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); Assert.That(attachments.Count, Is.EqualTo(1)); SceneObjectGroup attSo = attachments[0]; - Assert.That(attSo.Name, Is.EqualTo(attName)); + Assert.That(attSo.Name, Is.EqualTo(attItem.Name)); Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); Assert.That(attSo.IsAttachment); Assert.That(attSo.UsesPhysics, Is.False); Assert.That(attSo.IsTemporary, Is.False); // Check appearance status - Assert.That(m_presence.Appearance.GetAttachments().Count, Is.EqualTo(1)); - Assert.That(m_presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo((int)AttachmentPoint.Chest)); + Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1)); + Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); + + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + } + + /// + /// Test specific conditions associated with rezzing a scripted attachment from inventory. + /// + [Test] + public void TestRezScriptedAttachmentFromInventory() + { + TestHelpers.InMethod(); + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID); + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10); + TaskInventoryHelpers.AddScript(scene, so.RootPart); + InventoryItemBase userItem = UserInventoryHelpers.AddInventoryItem(scene, so, 0x100, 0x1000); + + scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest); + + // TODO: Need to have a test that checks the script is actually started but this involves a lot more + // plumbing of the script engine and either pausing for events or more infrastructure to turn off various + // script engine delays/asychronicity that isn't helpful in an automated regression testing context. + SceneObjectGroup attSo = scene.GetSceneObjectGroup(so.Name); + Assert.That(attSo.ContainsScripts(), Is.True); } [Test] @@ -165,29 +312,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - AddPresence(); + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID); - UUID attItemId = TestHelpers.ParseTail(0x2); - UUID attAssetId = TestHelpers.ParseTail(0x3); - string attName = "att"; + InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); - UserInventoryHelpers.CreateInventoryItem( - scene, attName, attItemId, attAssetId, m_presence.UUID, InventoryType.Object); - - ISceneEntity so = m_attMod.RezSingleAttachmentFromInventory( - m_presence, attItemId, (uint)AttachmentPoint.Chest); - m_attMod.DetachSingleAttachmentToGround(m_presence, so.LocalId); + ISceneEntity so + = scene.AttachmentsModule.RezSingleAttachmentFromInventory( + sp, attItem.ID, (uint)AttachmentPoint.Chest); + scene.AttachmentsModule.DetachSingleAttachmentToGround(sp, so.LocalId); // Check scene presence status - Assert.That(m_presence.HasAttachments(), Is.False); - List attachments = m_presence.GetAttachments(); + Assert.That(sp.HasAttachments(), Is.False); + List attachments = sp.GetAttachments(); Assert.That(attachments.Count, Is.EqualTo(0)); // Check appearance status - Assert.That(m_presence.Appearance.GetAttachments().Count, Is.EqualTo(0)); + Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(0)); // Check item status - Assert.That(scene.InventoryService.GetItem(new InventoryItemBase(attItemId)), Is.Null); + Assert.That(scene.InventoryService.GetItem(new InventoryItemBase(attItem.ID)), Is.Null); // Check object in scene Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null); @@ -197,28 +342,66 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests public void TestDetachAttachmentToInventory() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); - AddPresence(); + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID); - UUID attItemId = TestHelpers.ParseTail(0x2); - UUID attAssetId = TestHelpers.ParseTail(0x3); - string attName = "att"; + InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); - UserInventoryHelpers.CreateInventoryItem( - scene, attName, attItemId, attAssetId, m_presence.UUID, InventoryType.Object); - - m_attMod.RezSingleAttachmentFromInventory( - m_presence, attItemId, (uint)AttachmentPoint.Chest); - m_attMod.DetachSingleAttachmentToInv(m_presence, attItemId); + SceneObjectGroup so + = (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory( + sp, attItem.ID, (uint)AttachmentPoint.Chest); + scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, so); // Check status on scene presence - Assert.That(m_presence.HasAttachments(), Is.False); - List attachments = m_presence.GetAttachments(); + Assert.That(sp.HasAttachments(), Is.False); + List attachments = sp.GetAttachments(); Assert.That(attachments.Count, Is.EqualTo(0)); // Check item status - Assert.That(m_presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo(0)); + Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0)); + + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(0)); + } + + /// + /// Test specific conditions associated with detaching a scripted attachment from inventory. + /// + [Test] + public void TestDetachScriptedAttachmentToInventory() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + Scene scene = CreateScriptingEnabledTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1); + + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10); + TaskInventoryHelpers.AddScript(scene, so.RootPart); + InventoryItemBase userItem = UserInventoryHelpers.AddInventoryItem(scene, so, 0x100, 0x1000); + + // FIXME: Right now, we have to do a tricksy chat listen to make sure we know when the script is running. + // In the future, we need to be able to do this programatically more predicably. + scene.EventManager.OnChatFromWorld += OnChatFromWorld; + + SceneObjectGroup soRezzed + = (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest); + + // Wait for chat to signal rezzed script has been started. + m_chatEvent.WaitOne(60000); + + scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, soRezzed); + + InventoryItemBase userItemUpdated = scene.InventoryService.GetItem(userItem); + AssetBase asset = scene.AssetService.Get(userItemUpdated.AssetID.ToString()); + + XmlDocument soXml = new XmlDocument(); + soXml.LoadXml(Encoding.UTF8.GetString(asset.Data)); + + XmlNodeList scriptStateNodes = soXml.GetElementsByTagName("ScriptState"); + Assert.That(scriptStateNodes.Count, Is.EqualTo(1)); } /// @@ -230,17 +413,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - UUID userId = TestHelpers.ParseTail(0x1); - UUID attItemId = TestHelpers.ParseTail(0x2); - UUID attAssetId = TestHelpers.ParseTail(0x3); - string attName = "att"; + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); - UserAccountHelpers.CreateUserWithInventory(scene, userId); - InventoryItemBase attItem - = UserInventoryHelpers.CreateInventoryItem( - scene, attName, attItemId, attAssetId, userId, InventoryType.Object); - - AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); + AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); acd.Appearance = new AvatarAppearance(); acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID); ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd); @@ -259,17 +436,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - UUID userId = TestHelpers.ParseTail(0x1); - UUID attItemId = TestHelpers.ParseTail(0x2); - UUID attAssetId = TestHelpers.ParseTail(0x3); - string attName = "att"; + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); - UserAccountHelpers.CreateUserWithInventory(scene, userId); - InventoryItemBase attItem - = UserInventoryHelpers.CreateInventoryItem( - scene, attName, attItemId, attAssetId, userId, InventoryType.Object); - - AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); + AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); acd.Appearance = new AvatarAppearance(); acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID); ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd); @@ -279,7 +450,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(attachments.Count, Is.EqualTo(1)); SceneObjectGroup attSo = attachments[0]; - Assert.That(attSo.Name, Is.EqualTo(attName)); + Assert.That(attSo.Name, Is.EqualTo(attItem.Name)); Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); Assert.That(attSo.IsAttachment); Assert.That(attSo.UsesPhysics, Is.False); @@ -289,9 +460,125 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests List retreivedAttachments = presence.Appearance.GetAttachments(); Assert.That(retreivedAttachments.Count, Is.EqualTo(1)); Assert.That(retreivedAttachments[0].AttachPoint, Is.EqualTo((int)AttachmentPoint.Chest)); - Assert.That(retreivedAttachments[0].ItemID, Is.EqualTo(attItemId)); - Assert.That(retreivedAttachments[0].AssetID, Is.EqualTo(attAssetId)); - Assert.That(presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo((int)AttachmentPoint.Chest)); + Assert.That(retreivedAttachments[0].ItemID, Is.EqualTo(attItem.ID)); + Assert.That(retreivedAttachments[0].AssetID, Is.EqualTo(attItem.AssetID)); + Assert.That(presence.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); + + Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1)); + } + + [Test] + public void TestUpdateAttachmentPosition() + { + TestHelpers.InMethod(); + + Scene scene = CreateTestScene(); + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1); + InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID); + acd.Appearance = new AvatarAppearance(); + acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, acd); + + SceneObjectGroup attSo = sp.GetAttachments()[0]; + + Vector3 newPosition = new Vector3(1, 2, 4); + + scene.SceneGraph.UpdatePrimGroupPosition(attSo.LocalId, newPosition, sp.ControllingClient); + + Assert.That(attSo.AbsolutePosition, Is.EqualTo(sp.AbsolutePosition)); + Assert.That(attSo.RootPart.AttachedPos, Is.EqualTo(newPosition)); + } + + [Test] + public void TestSameSimulatorNeighbouringRegionsTeleport() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + AttachmentsModule attModA = new AttachmentsModule(); + AttachmentsModule attModB = new AttachmentsModule(); + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + entityTransferConfig.Set("wait_for_callback", false); + + modulesConfig.Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1001, 1000); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules( + sceneA, config, new CapabilitiesModule(), etmA, attModA, new BasicInventoryAccessModule()); + SceneHelpers.SetupSceneModules( + sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule()); + + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1); + ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, ua1.PrincipalID, sh.SceneManager); + beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32); + + InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20); + + sceneA.AttachmentsModule.RezSingleAttachmentFromInventory( + beforeTeleportSp, attItem.ID, (uint)AttachmentPoint.Chest); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + sceneA.RequestTeleportLocation( + beforeTeleportSp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + ((TestClient)beforeTeleportSp.ControllingClient).CompleteTeleportClientSide(); + + // Check attachments have made it into sceneB + ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID); + + // This is appearance data, as opposed to actually rezzed attachments + List sceneBAttachments = afterTeleportSceneBSp.Appearance.GetAttachments(); + Assert.That(sceneBAttachments.Count, Is.EqualTo(1)); + Assert.That(sceneBAttachments[0].AttachPoint, Is.EqualTo((int)AttachmentPoint.Chest)); + Assert.That(sceneBAttachments[0].ItemID, Is.EqualTo(attItem.ID)); + Assert.That(sceneBAttachments[0].AssetID, Is.EqualTo(attItem.AssetID)); + Assert.That(afterTeleportSceneBSp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); + + // This is the actual attachment + List actualSceneBAttachments = afterTeleportSceneBSp.GetAttachments(); + Assert.That(actualSceneBAttachments.Count, Is.EqualTo(1)); + SceneObjectGroup actualSceneBAtt = actualSceneBAttachments[0]; + Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name)); + Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest)); + + Assert.That(sceneB.GetSceneObjectGroups().Count, Is.EqualTo(1)); + + // Check attachments have been removed from sceneA + ScenePresence afterTeleportSceneASp = sceneA.GetScenePresence(ua1.PrincipalID); + + // Since this is appearance data, it is still present on the child avatar! + List sceneAAttachments = afterTeleportSceneASp.Appearance.GetAttachments(); + Assert.That(sceneAAttachments.Count, Is.EqualTo(1)); + Assert.That(afterTeleportSceneASp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest)); + + // This is the actual attachment, which should no longer exist + List actualSceneAAttachments = afterTeleportSceneASp.GetAttachments(); + Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0)); + + Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0)); } // I'm commenting this test because scene setup NEEDS InventoryService to diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index 2bebd30299..89cc4f674f 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -128,7 +128,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory /// public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams) { - // m_log.InfoFormat("[AVFACTORY]: start SetAppearance for {0}", client.AgentId); +// m_log.DebugFormat( +// "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}", +// sp.Name, textureEntry, visualParams); // TODO: This is probably not necessary any longer, just assume the // textureEntry set implies that the appearance transaction is complete @@ -158,7 +160,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // Process the baked texture array if (textureEntry != null) { - m_log.InfoFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID); +// m_log.DebugFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID); // WriteBakedTexturesReport(sp, m_log.DebugFormat); @@ -208,7 +210,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory ScenePresence sp = m_scene.GetScenePresence(agentId); if (sp == null) { - m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId); + // This is expected if the user has gone away. +// m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId); return false; } @@ -248,10 +251,10 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (bakedTextureFace == null) { - m_log.WarnFormat( - "[AV FACTORY]: No texture ID set for {0} for {1} in {2} not found when trying to save permanently", - bakeType, sp.Name, m_scene.RegionInfo.RegionName); - + // This can happen legitimately, since some baked textures might not exist + //m_log.WarnFormat( + // "[AV FACTORY]: No texture ID set for {0} for {1} in {2} not found when trying to save permanently", + // bakeType, sp.Name, m_scene.RegionInfo.RegionName); continue; } @@ -337,7 +340,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory return false; } - m_log.DebugFormat("[AVFACTORY]: Completed texture check for {0} {1}", sp.Name, sp.UUID); +// m_log.DebugFormat("[AVFACTORY]: Completed texture check for {0} {1}", sp.Name, sp.UUID); // If we only found default textures, then the appearance is not cached return (defonly ? false : true); @@ -370,11 +373,21 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory if (missingTexturesOnly) { if (m_scene.AssetService.Get(face.TextureID.ToString()) != null) + { continue; + } else + { + // On inter-simulator teleports, this occurs if baked textures are not being stored by the + // grid asset service (which means that they are not available to the new region and so have + // to be re-requested from the client). + // + // The only available core OpenSimulator behaviour right now + // is not to store these textures, temporarily or otherwise. m_log.DebugFormat( "[AVFACTORY]: Missing baked texture {0} ({1}) for {2}, requesting rebake.", face.TextureID, idx, sp.Name); + } } else { @@ -417,7 +430,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // acd.AgentID, i, acd.Appearance.Texture.FaceTextures[i]); int ftIndex = (int)AppearanceManager.BakeTypeToAgentTextureIndex(bakeType); - bakedTextures[bakeType] = faceTextures[ftIndex]; + Primitive.TextureEntryFace texture = faceTextures[ftIndex]; // this will be null if there's no such baked texture + bakedTextures[bakeType] = texture; } return bakedTextures; @@ -482,7 +496,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory ScenePresence sp = m_scene.GetScenePresence(agentid); if (sp == null) { - m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid); + // This is expected if the user has gone away. +// m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid); return; } diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs index 11a0a86bde..848b3bfc08 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/Tests/AvatarFactoryModuleTests.cs @@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory UUID userId = TestHelpers.ParseTail(0x1); AvatarFactoryModule afm = new AvatarFactoryModule(); - TestScene scene = SceneHelpers.SetupScene(); + TestScene scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(scene, afm); ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId); @@ -81,7 +81,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory CoreAssetCache assetCache = new CoreAssetCache(); AvatarFactoryModule afm = new AvatarFactoryModule(); - TestScene scene = SceneHelpers.SetupScene(assetCache); + TestScene scene = new SceneHelpers(assetCache).SetupScene(); SceneHelpers.SetupSceneModules(scene, afm); ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId); diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs index 6215526794..dbbb0aec7d 100644 --- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs @@ -266,7 +266,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat receiverIDs.Add(presence.UUID); } } - } ); } diff --git a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs index 0babeb5140..3a9146557d 100644 --- a/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Combat/CombatModule.cs @@ -96,6 +96,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Combat.CombatModule ScenePresence killingAvatar = null; // string killingAvatarMessage; + // check to see if it is an NPC and just remove it + INPCModule NPCmodule = deadAvatar.Scene.RequestModuleInterface(); + if (NPCmodule != null && NPCmodule.DeleteNPC(deadAvatar.UUID, deadAvatar.Scene)) + { + return; + } + if (killerObjectLocalID == 0) deadAvatarMessage = "You committed suicide!"; else @@ -145,7 +152,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Combat.CombatModule catch (InvalidOperationException) { } - deadAvatar.Health = 100; + deadAvatar.setHealthWithUpdate(100.0f); deadAvatar.Scene.TeleportClientHome(deadAvatar.UUID, deadAvatar.ControllingClient); } @@ -154,14 +161,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Combat.CombatModule try { ILandObject obj = avatar.Scene.LandChannel.GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); - - if ((obj.LandData.Flags & (uint)ParcelFlags.AllowDamage) != 0) + if ((obj.LandData.Flags & (uint)ParcelFlags.AllowDamage) != 0 + || avatar.Scene.RegionInfo.RegionSettings.AllowDamage) { avatar.Invulnerable = false; } else { avatar.Invulnerable = true; + if (avatar.Health < 100.0f) + { + avatar.setHealthWithUpdate(100.0f); + } } } catch (Exception) diff --git a/OpenSim/Region/CoreModules/Avatar/Commands/UserCommandsModule.cs b/OpenSim/Region/CoreModules/Avatar/Commands/UserCommandsModule.cs new file mode 100644 index 0000000000..4bcd2ac499 --- /dev/null +++ b/OpenSim/Region/CoreModules/Avatar/Commands/UserCommandsModule.cs @@ -0,0 +1,189 @@ +/* + * 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.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using log4net; +using Mono.Addins; +using NDesk.Options; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Statistics; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.CoreModules.Avatars.Commands +{ + /// + /// A module that holds commands for manipulating objects in the scene. + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserCommandsModule")] + public class UserCommandsModule : ISharedRegionModule + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public const string TeleportUserCommandSyntax = "teleport user "; + + public static Regex InterRegionDestinationRegex + = new Regex(@"^(?.+)/(?\d+)/(?\d+)/(?\d+)$", RegexOptions.Compiled); + + public static Regex WithinRegionDestinationRegex + = new Regex(@"^(?\d+)/(?\d+)/(?\d+)$", RegexOptions.Compiled); + + private Dictionary m_scenes = new Dictionary(); + + public string Name { get { return "User Commands Module"; } } + + public Type ReplaceableInterface { get { return null; } } + + public void Initialise(IConfigSource source) + { +// m_log.DebugFormat("[USER COMMANDS MODULE]: INITIALIZED MODULE"); + } + + public void PostInitialise() + { +// m_log.DebugFormat("[USER COMMANDS MODULE]: POST INITIALIZED MODULE"); + } + + public void Close() + { +// m_log.DebugFormat("[USER COMMANDS MODULE]: CLOSED MODULE"); + } + + public void AddRegion(Scene scene) + { +// m_log.DebugFormat("[USER COMMANDS MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName); + + lock (m_scenes) + m_scenes[scene.RegionInfo.RegionID] = scene; + + scene.AddCommand( + "Users", + this, + "teleport user", + TeleportUserCommandSyntax, + "Teleport a user in this simulator to the given destination", + " is in format []///, e.g. regionone/20/30/40 or just 20/30/40 to teleport within same region." + + "\nIf the region contains a space then the whole destination must be in quotes, e.g. \"region one/20/30/40\"", + HandleTeleportUser); + } + + public void RemoveRegion(Scene scene) + { +// m_log.DebugFormat("[USER COMMANDS MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName); + + lock (m_scenes) + m_scenes.Remove(scene.RegionInfo.RegionID); + } + + public void RegionLoaded(Scene scene) + { +// m_log.DebugFormat("[USER COMMANDS MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); + } + + private ScenePresence GetUser(string firstName, string lastName) + { + ScenePresence userFound = null; + + lock (m_scenes) + { + foreach (Scene scene in m_scenes.Values) + { + ScenePresence user = scene.GetScenePresence(firstName, lastName); + if (user != null && !user.IsChildAgent) + { + userFound = user; + break; + } + } + } + + return userFound; + } + + private void HandleTeleportUser(string module, string[] cmd) + { + if (cmd.Length < 5) + { + MainConsole.Instance.OutputFormat("Usage: " + TeleportUserCommandSyntax); + return; + } + + string firstName = cmd[2]; + string lastName = cmd[3]; + string rawDestination = cmd[4]; + + ScenePresence user = GetUser(firstName, lastName); + + if (user == null) + { + MainConsole.Instance.OutputFormat("No user found with name {0} {1}", firstName, lastName); + return; + } + +// MainConsole.Instance.OutputFormat("rawDestination [{0}]", rawDestination); + + Match m = WithinRegionDestinationRegex.Match(rawDestination); + + if (!m.Success) + { + m = InterRegionDestinationRegex.Match(rawDestination); + + if (!m.Success) + { + MainConsole.Instance.OutputFormat("Invalid destination {0}", rawDestination); + return; + } + } + + string regionName + = m.Groups["regionName"].Success ? m.Groups["regionName"].Value : user.Scene.RegionInfo.RegionName; + + MainConsole.Instance.OutputFormat( + "Teleporting {0} to {1},{2},{3} in {4}", + user.Name, + m.Groups["x"], m.Groups["y"], m.Groups["z"], + regionName); + + user.Scene.RequestTeleportLocation( + user.ControllingClient, + regionName, + new Vector3( + float.Parse(m.Groups["x"].Value), + float.Parse(m.Groups["y"].Value), + float.Parse(m.Groups["z"].Value)), + user.Lookat, + (uint)TeleportFlags.ViaLocation); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs index f64c161271..24ec435d17 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/FriendsModule.cs @@ -162,7 +162,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends } } - protected void InitModule(IConfigSource config) + protected virtual void InitModule(IConfigSource config) { IConfig friendsConfig = config.Configs["Friends"]; if (friendsConfig != null) @@ -448,30 +448,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends /// Find the client for a ID /// public IClientAPI LocateClientObject(UUID agentID) - { - Scene scene = GetClientScene(agentID); - if (scene != null) - { - ScenePresence presence = scene.GetScenePresence(agentID); - if (presence != null) - return presence.ControllingClient; - } - - return null; - } - - /// - /// Find the scene for an agent - /// - private Scene GetClientScene(UUID agentId) { lock (m_Scenes) { foreach (Scene scene in m_Scenes) { - ScenePresence presence = scene.GetScenePresence(agentId); + ScenePresence presence = scene.GetScenePresence(agentID); if (presence != null && !presence.IsChildAgent) - return scene; + return presence.ControllingClient; } } @@ -498,7 +482,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends Util.FireAndForget( delegate { - m_log.DebugFormat("[FRIENDS MODULE]: Notifying {0} friends", friendList.Count); + m_log.DebugFormat( + "[FRIENDS MODULE]: Notifying {0} friends of {1} of online status {2}", + friendList.Count, agentID, online); + // Notify about this user status StatusNotify(friendList, agentID, online); } @@ -515,7 +502,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends { // Try local if (LocalStatusNotification(userID, friendID, online)) - return; + continue; // The friend is not here [as root]. Let's forward. PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() }); @@ -523,11 +510,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends { PresenceInfo friendSession = null; foreach (PresenceInfo pinfo in friendSessions) + { if (pinfo.RegionID != UUID.Zero) // let's guard against sessions-gone-bad { friendSession = pinfo; break; } + } if (friendSession != null) { @@ -546,7 +535,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends } } - private void OnInstantMessage(IClientAPI client, GridInstantMessage im) + protected virtual void OnInstantMessage(IClientAPI client, GridInstantMessage im) { if ((InstantMessageDialog)im.dialog == InstantMessageDialog.FriendshipOffered) { diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs index 9a6d277252..06f27e23df 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/HGFriendsModule.cs @@ -50,6 +50,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private int m_levelHGFriends = 0; + IUserManagement m_uMan; public IUserManagement UserManagementModule { @@ -87,6 +89,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends m_StatusNotifier = new HGStatusNotifier(this); } + protected override void InitModule(IConfigSource config) + { + base.InitModule(config); + + // Additionally to the base method + IConfig friendsConfig = config.Configs["HGFriendsModule"]; + if (friendsConfig != null) + { + m_levelHGFriends = friendsConfig.GetInt("LevelHGFriends", 0); + + // TODO: read in all config variables pertaining to + // HG friendship permissions + } + } + #endregion #region IFriendsSimConnector @@ -105,6 +122,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends #endregion + protected override void OnInstantMessage(IClientAPI client, GridInstantMessage im) + { + if ((InstantMessageDialog)im.dialog == InstantMessageDialog.FriendshipOffered) + { + // we got a friendship offer + UUID principalID = new UUID(im.fromAgentID); + UUID friendID = new UUID(im.toAgentID); + + // Check if friendID is foreigner and if principalID has the permission + // to request friendships with foreigners. If not, return immediately. + if (!UserManagementModule.IsLocalGridUser(friendID)) + { + ScenePresence avatar = null; + ((Scene)client.Scene).TryGetScenePresence(principalID, out avatar); + + if (avatar == null) + return; + + if (avatar.UserLevel < m_levelHGFriends) + { + client.SendAgentAlertMessage("Unable to send friendship invitation to foreigner. Insufficient permissions.", false); + return; + } + } + } + + base.OnInstantMessage(client, im); + } + protected override void OnApproveFriendRequest(IClientAPI client, UUID friendID, List callingCardFolders) { // Update the local cache. Yes, we need to do it right here @@ -369,12 +415,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends protected override void StoreBackwards(UUID friendID, UUID agentID) { - Boolean agentIsLocal = true; - Boolean friendIsLocal = true; + bool agentIsLocal = true; +// bool friendIsLocal = true; + if (UserManagementModule != null) { agentIsLocal = UserManagementModule.IsLocalGridUser(agentID); - friendIsLocal = UserManagementModule.IsLocalGridUser(friendID); +// friendIsLocal = UserManagementModule.IsLocalGridUser(friendID); } // Is the requester a local user? @@ -461,7 +508,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends { friendUUI = finfo.Friend; theFriendUUID = friendUUI; - UUID utmp = UUID.Zero; String url = String.Empty; String first = String.Empty, last = String.Empty, tmp = String.Empty; + UUID utmp = UUID.Zero; + string url = String.Empty; + string first = String.Empty; + string last = String.Empty; + // If it's confirming the friendship, we already have the full UUI with the secret if (Util.ParseUniversalUserIdentifier(theFriendUUID, out utmp, out url, out first, out last, out secret)) { diff --git a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs index 45b4264c91..7a197f7cd5 100644 --- a/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Friends/Tests/FriendModuleTests.cs @@ -78,7 +78,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests config.AddConfig("FriendsService"); config.Configs["FriendsService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); - m_scene = SceneHelpers.SetupScene(); + m_scene = new SceneHelpers().SetupScene(); m_fm = new FriendsModule(); SceneHelpers.SetupSceneModules(m_scene, config, m_fm); } diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs index 8560c73d6b..6587eadf57 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveWriteRequest.cs @@ -39,6 +39,9 @@ using OpenSim.Framework.Serialization.External; using OpenSim.Region.CoreModules.World.Archiver; using OpenSim.Region.Framework.Scenes; using OpenSim.Services.Interfaces; +using Ionic.Zlib; +using GZipStream = Ionic.Zlib.GZipStream; +using CompressionMode = Ionic.Zlib.CompressionMode; namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver { @@ -91,7 +94,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// Constructor /// public InventoryArchiveWriteRequest( - Guid id, InventoryArchiverModule module, Scene scene, + Guid id, InventoryArchiverModule module, Scene scene, UserAccount userInfo, string invPath, string savePath) : this( id, @@ -99,7 +102,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver scene, userInfo, invPath, - new GZipStream(new FileStream(savePath, FileMode.Create), CompressionMode.Compress)) + new GZipStream(new FileStream(savePath, FileMode.Create), CompressionMode.Compress, CompressionLevel.BestCompression)) { } @@ -107,7 +110,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// Constructor /// public InventoryArchiveWriteRequest( - Guid id, InventoryArchiverModule module, Scene scene, + Guid id, InventoryArchiverModule module, Scene scene, UserAccount userInfo, string invPath, Stream saveStream) { m_id = id; @@ -125,7 +128,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver { Exception reportedException = null; bool succeeded = true; - + try { m_archiveWriter.Close(); @@ -146,6 +149,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver protected void SaveInvItem(InventoryItemBase inventoryItem, string path, Dictionary options, IUserAccountService userAccountService) { + if (options.ContainsKey("exclude")) + { + if (((List)options["exclude"]).Contains(inventoryItem.Name) || + ((List)options["exclude"]).Contains(inventoryItem.ID.ToString())) + { + if (options.ContainsKey("verbose")) + { + m_log.InfoFormat( + "[INVENTORY ARCHIVER]: Skipping inventory item {0} {1} at {2}", + inventoryItem.Name, inventoryItem.ID, path); + } + return; + } + } + if (options.ContainsKey("verbose")) m_log.InfoFormat( "[INVENTORY ARCHIVER]: Saving item {0} {1} with asset {2}", @@ -175,9 +193,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// /// protected void SaveInvFolder( - InventoryFolderBase inventoryFolder, string path, bool saveThisFolderItself, + InventoryFolderBase inventoryFolder, string path, bool saveThisFolderItself, Dictionary options, IUserAccountService userAccountService) { + if (options.ContainsKey("excludefolders")) + { + if (((List)options["excludefolders"]).Contains(inventoryFolder.Name) || + ((List)options["excludefolders"]).Contains(inventoryFolder.ID.ToString())) + { + if (options.ContainsKey("verbose")) + { + m_log.InfoFormat( + "[INVENTORY ARCHIVER]: Skipping folder {0} at {1}", + inventoryFolder.Name, path); + } + return; + } + } + + if (options.ContainsKey("verbose")) + m_log.InfoFormat("[INVENTORY ARCHIVER]: Saving folder {0}", inventoryFolder.Name); + if (saveThisFolderItself) { path += CreateArchiveFolderName(inventoryFolder); @@ -186,7 +222,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver m_archiveWriter.WriteDir(path); } - InventoryCollection contents + InventoryCollection contents = m_scene.InventoryService.GetFolderContent(inventoryFolder.Owner, inventoryFolder.ID); foreach (InventoryFolderBase childFolder in contents.Folders) @@ -213,16 +249,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver InventoryFolderBase inventoryFolder = null; InventoryItemBase inventoryItem = null; InventoryFolderBase rootFolder = m_scene.InventoryService.GetRootFolder(m_userInfo.PrincipalID); - + bool saveFolderContentsOnly = false; - + // Eliminate double slashes and any leading / on the path. string[] components = m_invPath.Split( new string[] { InventoryFolderImpl.PATH_DELIMITER }, StringSplitOptions.RemoveEmptyEntries); - + int maxComponentIndex = components.Length - 1; - + // If the path terminates with a STAR then later on we want to archive all nodes in the folder but not the // folder itself. This may get more sophisicated later on if (maxComponentIndex >= 0 && components[maxComponentIndex] == STAR_WILDCARD) @@ -230,13 +266,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver saveFolderContentsOnly = true; maxComponentIndex--; } - + m_invPath = String.Empty; for (int i = 0; i <= maxComponentIndex; i++) { m_invPath += components[i] + InventoryFolderImpl.PATH_DELIMITER; } - + // Annoyingly Split actually returns the original string if the input string consists only of delimiters // Therefore if we still start with a / after the split, then we need the root folder if (m_invPath.Length == 0) @@ -246,25 +282,25 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver else { m_invPath = m_invPath.Remove(m_invPath.LastIndexOf(InventoryFolderImpl.PATH_DELIMITER)); - List candidateFolders + List candidateFolders = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, rootFolder, m_invPath); if (candidateFolders.Count > 0) inventoryFolder = candidateFolders[0]; } - + // The path may point to an item instead if (inventoryFolder == null) inventoryItem = InventoryArchiveUtils.FindItemByPath(m_scene.InventoryService, rootFolder, m_invPath); - + if (null == inventoryFolder && null == inventoryItem) { - // We couldn't find the path indicated + // We couldn't find the path indicated string errorMessage = string.Format("Aborted save. Could not find inventory path {0}", m_invPath); Exception e = new InventoryArchiverException(errorMessage); m_module.TriggerInventoryArchiveSaved(m_id, false, m_userInfo, m_invPath, m_saveStream, e); throw e; } - + m_archiveWriter = new TarArchiveWriter(m_saveStream); m_log.InfoFormat("[INVENTORY ARCHIVER]: Adding control file to archive."); @@ -278,10 +314,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver { m_log.DebugFormat( "[INVENTORY ARCHIVER]: Found folder {0} {1} at {2}", - inventoryFolder.Name, - inventoryFolder.ID, + inventoryFolder.Name, + inventoryFolder.ID, m_invPath == String.Empty ? InventoryFolderImpl.PATH_DELIMITER : m_invPath); - + //recurse through all dirs getting dirs and files SaveInvFolder(inventoryFolder, ArchiveConstants.INVENTORY_PATH, !saveFolderContentsOnly, options, userAccountService); } @@ -290,10 +326,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver m_log.DebugFormat( "[INVENTORY ARCHIVER]: Found item {0} {1} at {2}", inventoryItem.Name, inventoryItem.ID, m_invPath); - + SaveInvItem(inventoryItem, ArchiveConstants.INVENTORY_PATH, options, userAccountService); } - + // Don't put all this profile information into the archive right now. //SaveUsers(); @@ -352,7 +388,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// /// These names are prepended with an inventory folder's UUID so that more than one folder can have the /// same name - /// + /// /// /// public static string CreateArchiveFolderName(InventoryFolderBase folder) @@ -366,7 +402,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// /// These names are prepended with an inventory item's UUID so that more than one item can have the /// same name - /// + /// /// /// public static string CreateArchiveItemName(InventoryItemBase item) @@ -412,7 +448,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver public string CreateControlFile(Dictionary options) { int majorVersion, minorVersion; - + if (options.ContainsKey("home")) { majorVersion = 1; @@ -422,10 +458,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver { majorVersion = 0; minorVersion = 3; - } - + } + m_log.InfoFormat("[INVENTORY ARCHIVER]: Creating version {0}.{1} IAR", majorVersion, minorVersion); - + StringWriter sw = new StringWriter(); XmlTextWriter xtw = new XmlTextWriter(sw); xtw.Formatting = Formatting.Indented; diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs index ac22c3f079..cf870100a4 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs @@ -47,18 +47,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver public class InventoryArchiverModule : IRegionModule, IInventoryArchiverModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + public string Name { get { return "Inventory Archiver Module"; } } - + public bool IsSharedModule { get { return true; } } /// - /// Enable or disable checking whether the iar user is actually logged in + /// Enable or disable checking whether the iar user is actually logged in /// // public bool DisablePresenceChecks { get; set; } - + public event InventoryArchiveSaved OnInventoryArchiveSaved; - + /// /// The file to load and save inventory if no filename has been specified /// @@ -68,7 +68,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// Pending save completions initiated from the console /// protected List m_pendingConsoleSaves = new List(); - + /// /// All scenes that this module knows about /// @@ -106,7 +106,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver { scene.RegisterModuleInterface(this); OnInventoryArchiveSaved += SaveInvConsoleCommandCompleted; - + scene.AddCommand( "Archiving", this, "load iar", "load iar [-m|--merge] []", @@ -119,11 +119,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver + " is the filesystem path or URI from which to load the IAR." + string.Format(" If this is not given then the filename {0} in the current directory is used", DEFAULT_INV_BACKUP_FILENAME), HandleLoadInvConsoleCommand); - + scene.AddCommand( "Archiving", this, "save iar", - "save iar [-h|--home=] [--noassets] [] [-c|--creators] [-v|--verbose]", - "Save user inventory archive (IAR).", + "save iar [-h|--home=] [--noassets] [] [-c|--creators] [-e|--exclude=] [-f|--excludefolder=] [-v|--verbose]", + "Save user inventory archive (IAR).", " is the user's first name.\n" + " is the user's last name.\n" + " is the path inside the user's inventory for the folder/item to be saved.\n" @@ -131,32 +131,34 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver + string.Format(" If this is not given then the filename {0} in the current directory is used.\n", DEFAULT_INV_BACKUP_FILENAME) + "-h|--home= adds the url of the profile service to the saved user information.\n" + "-c|--creators preserves information about foreign creators.\n" + + "-e|--exclude= don't save the inventory item in archive" + Environment.NewLine + + "-f|--excludefolder= don't save contents of the folder in archive" + Environment.NewLine + "-v|--verbose extra debug messages.\n" + "--noassets stops assets being saved to the IAR.", HandleSaveInvConsoleCommand); m_aScene = scene; } - + m_scenes[scene.RegionInfo.RegionID] = scene; } public void PostInitialise() {} public void Close() {} - + /// /// Trigger the inventory archive saved event. /// protected internal void TriggerInventoryArchiveSaved( - Guid id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream, + Guid id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream, Exception reportedException) { InventoryArchiveSaved handlerInventoryArchiveSaved = OnInventoryArchiveSaved; if (handlerInventoryArchiveSaved != null) handlerInventoryArchiveSaved(id, succeeded, userInfo, invPath, saveStream, reportedException); } - + public bool ArchiveInventory( Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream) { @@ -164,7 +166,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver } public bool ArchiveInventory( - Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream, + Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream, Dictionary options) { if (m_scenes.Count > 0) @@ -188,7 +190,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver return false; } - + return true; // } // else @@ -202,15 +204,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver return false; } - + public bool ArchiveInventory( - Guid id, string firstName, string lastName, string invPath, string pass, string savePath, + Guid id, string firstName, string lastName, string invPath, string pass, string savePath, Dictionary options) { if (m_scenes.Count > 0) { UserAccount userInfo = GetUserInfo(firstName, lastName, pass); - + if (userInfo != null) { // if (CheckPresence(userInfo.PrincipalID)) @@ -228,7 +230,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver return false; } - + return true; // } // else @@ -239,7 +241,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver // } } } - + return false; } @@ -247,9 +249,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver { return DearchiveInventory(firstName, lastName, invPath, pass, loadStream, new Dictionary()); } - + public bool DearchiveInventory( - string firstName, string lastName, string invPath, string pass, Stream loadStream, + string firstName, string lastName, string invPath, string pass, Stream loadStream, Dictionary options) { if (m_scenes.Count > 0) @@ -295,22 +297,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver return false; } - + public bool DearchiveInventory( - string firstName, string lastName, string invPath, string pass, string loadPath, + string firstName, string lastName, string invPath, string pass, string loadPath, Dictionary options) { if (m_scenes.Count > 0) { UserAccount userInfo = GetUserInfo(firstName, lastName, pass); - + if (userInfo != null) { // if (CheckPresence(userInfo.PrincipalID)) // { InventoryArchiveReadRequest request; bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false); - + try { request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadPath, merge); @@ -324,7 +326,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver return false; } - + UpdateClientWithLoadedNodes(userInfo, request.Execute()); return true; @@ -340,7 +342,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver return false; } - + /// /// Load inventory from an inventory file archive /// @@ -351,26 +353,26 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver { Dictionary options = new Dictionary(); OptionSet optionSet = new OptionSet().Add("m|merge", delegate (string v) { options["merge"] = v != null; }); - + List mainParams = optionSet.Parse(cmdparams); - + if (mainParams.Count < 6) { m_log.Error( - "[INVENTORY ARCHIVER]: usage is load iar [-m|--merge] []"); + "[INVENTORY ARCHIVER]: usage is load iar [-m|--merge] []"); return; } - + string firstName = mainParams[2]; string lastName = mainParams[3]; string invPath = mainParams[4]; string pass = mainParams[5]; string loadPath = (mainParams.Count > 6 ? mainParams[6] : DEFAULT_INV_BACKUP_FILENAME); - + m_log.InfoFormat( "[INVENTORY ARCHIVER]: Loading archive {0} to inventory path {1} for {2} {3}", loadPath, invPath, firstName, lastName); - + if (DearchiveInventory(firstName, lastName, invPath, pass, loadPath, options)) m_log.InfoFormat( "[INVENTORY ARCHIVER]: Loaded archive {0} for {1} {2}", @@ -381,7 +383,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver m_log.ErrorFormat("[INVENTORY ARCHIVER]: {0}", e.Message); } } - + /// /// Save inventory to a file archive /// @@ -398,6 +400,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver ops.Add("v|verbose", delegate(string v) { options["verbose"] = v; }); ops.Add("c|creators", delegate(string v) { options["creators"] = v; }); ops.Add("noassets", delegate(string v) { options["noassets"] = v != null; }); + ops.Add("e|exclude=", delegate(string v) + { + if (!options.ContainsKey("exclude")) + options["exclude"] = new List(); + ((List)options["exclude"]).Add(v); + }); + ops.Add("f|excludefolder=", delegate(string v) + { + if (!options.ContainsKey("excludefolders")) + options["excludefolders"] = new List(); + ((List)options["excludefolders"]).Add(v); + }); List mainParams = ops.Parse(cmdparams); @@ -406,10 +420,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver if (mainParams.Count < 6) { m_log.Error( - "[INVENTORY ARCHIVER]: usage is save iar [-h|--home=] [--noassets] [] [-c|--creators] [-v|--verbose]"); + "[INVENTORY ARCHIVER]: save iar [-h|--home=] [--noassets] [] [-c|--creators] [-e|--exclude=] [-f|--excludefolder=] [-v|--verbose]"); return; } - + if (options.ContainsKey("home")) m_log.WarnFormat("[INVENTORY ARCHIVER]: Please be aware that inventory archives with creator information are not compatible with OpenSim 0.7.0.2 and earlier. Do not use the -home option if you want to produce a compatible IAR"); @@ -418,7 +432,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver string invPath = mainParams[4]; string pass = mainParams[5]; string savePath = (mainParams.Count > 6 ? mainParams[6] : DEFAULT_INV_BACKUP_FILENAME); - + m_log.InfoFormat( "[INVENTORY ARCHIVER]: Saving archive {0} using inventory path {1} for {2} {3}", savePath, invPath, firstName, lastName); @@ -433,9 +447,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver m_log.ErrorFormat("[INVENTORY ARCHIVER]: {0}", e.Message); } } - + private void SaveInvConsoleCommandCompleted( - Guid id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream, + Guid id, bool succeeded, UserAccount userInfo, string invPath, Stream saveStream, Exception reportedException) { lock (m_pendingConsoleSaves) @@ -445,7 +459,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver else return; } - + if (succeeded) { m_log.InfoFormat("[INVENTORY ARCHIVER]: Saved archive for {0} {1}", userInfo.FirstName, userInfo.LastName); @@ -453,11 +467,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver else { m_log.ErrorFormat( - "[INVENTORY ARCHIVER]: Archive save for {0} {1} failed - {2}", + "[INVENTORY ARCHIVER]: Archive save for {0} {1} failed - {2}", userInfo.FirstName, userInfo.LastName, reportedException.Message); } } - + /// /// Get user information for the given name. /// @@ -467,13 +481,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver /// protected UserAccount GetUserInfo(string firstName, string lastName, string pass) { - UserAccount account + UserAccount account = m_aScene.UserAccountService.GetUserAccount(m_aScene.RegionInfo.ScopeID, firstName, lastName); - + if (null == account) { m_log.ErrorFormat( - "[INVENTORY ARCHIVER]: Failed to find user info for {0} {1}", + "[INVENTORY ARCHIVER]: Failed to find user info for {0} {1}", firstName, lastName); return null; } @@ -488,7 +502,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver else { m_log.ErrorFormat( - "[INVENTORY ARCHIVER]: Password for user {0} {1} incorrect. Please try again.", + "[INVENTORY ARCHIVER]: Password for user {0} {1} incorrect. Please try again.", firstName, lastName); return null; } @@ -499,7 +513,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver return null; } } - + /// /// Notify the client of loaded nodes if they are logged in /// @@ -508,22 +522,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver { if (loadedNodes.Count == 0) return; - + foreach (Scene scene in m_scenes.Values) { ScenePresence user = scene.GetScenePresence(userInfo.PrincipalID); - + if (user != null && !user.IsChildAgent) { foreach (InventoryNodeBase node in loadedNodes) { // m_log.DebugFormat( -// "[INVENTORY ARCHIVER]: Notifying {0} of loaded inventory node {1}", +// "[INVENTORY ARCHIVER]: Notifying {0} of loaded inventory node {1}", // user.Name, node.Name); - + user.ControllingClient.SendBulkUpdateInventory(node); } - + break; } } @@ -538,7 +552,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver // { // if (DisablePresenceChecks) // return true; -// +// // foreach (Scene scene in m_scenes.Values) // { // ScenePresence p; diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs index 19ef571e7e..1056865590 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiveTestCase.cs @@ -48,7 +48,7 @@ using OpenSim.Tests.Common.Mock; namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests { [TestFixture] - public class InventoryArchiveTestCase + public class InventoryArchiveTestCase : OpenSimTestCase { protected ManualResetEvent mre = new ManualResetEvent(false); @@ -84,8 +84,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests protected string m_coaItemName = "Coalesced Item"; [SetUp] - public virtual void SetUp() + public override void SetUp() { + base.SetUp(); m_iarStream = new MemoryStream(m_iarStreamBytes); } @@ -100,7 +101,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests // log4net.Config.XmlConfigurator.Configure(); InventoryArchiverModule archiverModule = new InventoryArchiverModule(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(scene, archiverModule); UserAccountHelpers.CreateUserWithInventory(scene, m_uaLL1, "hampshire"); diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs index e409c8e051..b112b6db52 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs @@ -61,7 +61,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests SerialiserModule serialiserModule = new SerialiserModule(); m_archiverModule = new InventoryArchiverModule(); - m_scene = SceneHelpers.SetupScene(); + m_scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule); } diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs index 417c20c097..6eb3605235 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/PathTests.cs @@ -62,7 +62,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests InventoryArchiverModule archiverModule = new InventoryArchiverModule(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(scene, archiverModule); // Create user @@ -179,7 +179,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests InventoryArchiverModule archiverModule = new InventoryArchiverModule(); // Annoyingly, we have to set up a scene even though inventory loading has nothing to do with a scene - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); @@ -222,7 +222,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests SerialiserModule serialiserModule = new SerialiserModule(); InventoryArchiverModule archiverModule = new InventoryArchiverModule(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "password"); @@ -247,7 +247,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests InventoryArchiverModule archiverModule = new InventoryArchiverModule(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(scene, archiverModule); // Create user @@ -326,7 +326,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene); Dictionary foldersCreated = new Dictionary(); @@ -393,7 +393,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests TestHelpers.InMethod(); //log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene); string folder1ExistingName = "a"; @@ -444,7 +444,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene); string folder1ExistingName = "a"; diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs index bc5c1ff2c2..92cf9d1616 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/HGLureModule.cs @@ -240,13 +240,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure { ScenePresence sp = scene.GetScenePresence(client.AgentId); IEntityTransferModule transferMod = scene.RequestModuleInterface(); - IEventQueue eq = sp.Scene.RequestModuleInterface(); - if (transferMod != null && sp != null && eq != null) - transferMod.DoTeleport(sp, gatekeeper, finalDestination, im.Position + new Vector3(0.5f, 0.5f, 0f), Vector3.UnitX, teleportflags, eq); + + if (transferMod != null && sp != null) + transferMod.DoTeleport( + sp, gatekeeper, finalDestination, im.Position + new Vector3(0.5f, 0.5f, 0f), + Vector3.UnitX, teleportflags); } } } } } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs index dcfdf8f02b..a889984daf 100644 --- a/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Lure/LureModule.cs @@ -151,6 +151,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure Scene scene = (Scene)(client.Scene); ScenePresence presence = scene.GetScenePresence(client.AgentId); + // Round up Z co-ordinate rather than round-down by casting. This stops tall avatars from being given + // a teleport Z co-ordinate by short avatars that drops them through or embeds them in thin floors on + // arrival. + // + // Ideally we would give the exact float position adjusting for the relative height of the two avatars + // but it looks like a float component isn't possible with a parcel ID. UUID dest = Util.BuildFakeParcelID( scene.RegionInfo.RegionHandle, (uint)presence.AbsolutePosition.X, diff --git a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs index 8101ca21c3..87ca3277be 100644 --- a/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Profile/BasicProfileModule.cs @@ -57,14 +57,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Profile public void Initialise(IConfigSource config) { - // This can be reduced later as the loader will determine - // whether we are needed - if (config.Configs["Profile"] != null) - { - if (config.Configs["Profile"].GetString("Module", string.Empty) != "BasicProfileModule") - return; - } - m_log.DebugFormat("[PROFILE MODULE]: Basic Profile Module enabled"); m_Enabled = true; } diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 2b790f45c5..560f807167 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -30,7 +30,6 @@ using System.Collections.Generic; using System.Net; using System.Reflection; using System.Threading; - using OpenSim.Framework; using OpenSim.Framework.Capabilities; using OpenSim.Framework.Client; @@ -47,29 +46,39 @@ using Nini.Config; namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { - public class EntityTransferModule : ISharedRegionModule, IEntityTransferModule + public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public const int DefaultMaxTransferDistance = 4095; + public const bool WaitForAgentArrivedAtDestinationDefault = true; + /// /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer. /// - private int m_MaxTransferDistance = 4095; - public int MaxTransferDistance - { - get { return m_MaxTransferDistance; } - set { m_MaxTransferDistance = value; } - } + public int MaxTransferDistance { get; set; } - private int m_levelHGTeleport = 0; + /// + /// If true then on a teleport, the source region waits for a callback from the destination region. If + /// a callback fails to arrive within a set time then the user is pulled back into the source region. + /// + public bool WaitForAgentArrivedAtDestination { get; set; } protected bool m_Enabled = false; - protected Scene m_aScene; - protected List m_Scenes = new List(); - protected List m_agentsInTransit; + + public Scene Scene { get; private set; } + + /// + /// Handles recording and manipulation of state for entities that are in transfer within or between regions + /// (cross or teleport). + /// + private EntityTransferStateMachine m_entityTransferStateMachine; + private ExpiringCache> m_bannedRegions = new ExpiringCache>(); + private IEventQueue m_eqModule; + #region ISharedRegionModule public Type ReplaceableInterface @@ -105,11 +114,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer IConfig transferConfig = source.Configs["EntityTransfer"]; if (transferConfig != null) { - MaxTransferDistance = transferConfig.GetInt("max_distance", 4095); - m_levelHGTeleport = transferConfig.GetInt("LevelHGTeleport", 0); + WaitForAgentArrivedAtDestination + = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); + + MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance); + } + else + { + MaxTransferDistance = DefaultMaxTransferDistance; } - m_agentsInTransit = new List(); + m_entityTransferStateMachine = new EntityTransferStateMachine(this); + m_Enabled = true; } @@ -122,10 +138,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (!m_Enabled) return; - if (m_aScene == null) - m_aScene = scene; + Scene = scene; - m_Scenes.Add(scene); scene.RegisterModuleInterface(this); scene.EventManager.OnNewClient += OnNewClient; } @@ -136,26 +150,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer client.OnTeleportLandmarkRequest += RequestTeleportLandmark; } - public virtual void Close() - { - if (!m_Enabled) - return; - } + public virtual void Close() {} - public virtual void RemoveRegion(Scene scene) - { - if (!m_Enabled) - return; - if (scene == m_aScene) - m_aScene = null; - - m_Scenes.Remove(scene); - } + public virtual void RemoveRegion(Scene scene) {} public virtual void RegionLoaded(Scene scene) { if (!m_Enabled) return; + + m_eqModule = Scene.RequestModuleInterface(); } #endregion @@ -164,170 +168,257 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) { + if (sp.Scene.Permissions.IsGridGod(sp.UUID)) + { + // This user will be a God in the destination scene, too + teleportFlags |= (uint)TeleportFlags.Godlike; + } + if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) return; - IEventQueue eq = sp.Scene.RequestModuleInterface(); - // Reset animations; the viewer does that in teleports. sp.Animator.ResetAnimations(); + string destinationRegionName = "(not found)"; + try { if (regionHandle == sp.Scene.RegionInfo.RegionHandle) { - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation {0} within {1}", - position, sp.Scene.RegionInfo.RegionName); + destinationRegionName = sp.Scene.RegionInfo.RegionName; - // Teleport within the same region - if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) - { - Vector3 emergencyPos = new Vector3(128, 128, 128); - - m_log.WarnFormat( - "[ENTITY TRANSFER MODULE]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", - position, sp.Name, sp.UUID, emergencyPos); - position = emergencyPos; - } - - // TODO: Get proper AVG Height - float localAVHeight = 1.56f; - float posZLimit = 22; - - // TODO: Check other Scene HeightField - if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) - { - posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; - } - - float newPosZ = posZLimit + localAVHeight; - if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) - { - position.Z = newPosZ; - } - - sp.ControllingClient.SendTeleportStart(teleportFlags); - - sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); - sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags; - sp.Teleport(position); - - foreach (SceneObjectGroup grp in sp.GetAttachments()) - { - sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT); - } + TeleportAgentWithinRegion(sp, position, lookAt, teleportFlags); } else // Another region possibly in another simulator { - uint x = 0, y = 0; - Utils.LongToUInts(regionHandle, out x, out y); - GridRegion reg = m_aScene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); + GridRegion finalDestination; + TeleportAgentToDifferentRegion( + sp, regionHandle, position, lookAt, teleportFlags, out finalDestination); - if (reg != null) - { - GridRegion finalDestination = GetFinalDestination(reg); - if (finalDestination == null) - { - m_log.WarnFormat("[ENTITY TRANSFER MODULE]: Final destination is having problems. Unable to teleport agent."); - sp.ControllingClient.SendTeleportFailed("Problem at destination"); - return; - } + if (finalDestination != null) + destinationRegionName = finalDestination.RegionName; + } + } + catch (Exception e) + { + m_log.ErrorFormat( + "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}", + sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName, + e.Message, e.StackTrace); - // check if HyperGrid teleport is allowed, based on user level - int flags = m_aScene.GridService.GetRegionFlags(sp.Scene.RegionInfo.ScopeID, reg.RegionID); + // Make sure that we clear the in-transit flag so that future teleport attempts don't always fail. + m_entityTransferStateMachine.ResetFromTransit(sp.UUID); - if (((flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) && (sp.UserLevel < m_levelHGTeleport)) - { - m_log.WarnFormat("[ENTITY TRANSFER MODULE]: Final destination link is non permitted hypergrid region. Unable to teleport agent."); - sp.ControllingClient.SendTeleportFailed("HyperGrid teleport not permitted"); - return; - } + sp.ControllingClient.SendTeleportFailed("Internal error"); + } + } - uint curX = 0, curY = 0; - Utils.LongToUInts(sp.Scene.RegionInfo.RegionHandle, out curX, out curY); - int curCellX = (int)(curX / Constants.RegionSize); - int curCellY = (int)(curY / Constants.RegionSize); - int destCellX = (int)(finalDestination.RegionLocX / Constants.RegionSize); - int destCellY = (int)(finalDestination.RegionLocY / Constants.RegionSize); + /// + /// Teleports the agent within its current region. + /// + /// + /// + /// + /// 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) + { + posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; + } + + float newPosZ = posZLimit + localAVHeight; + if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) + { + position.Z = newPosZ; + } + + m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); + + sp.ControllingClient.SendTeleportStart(teleportFlags); + + sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); + sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags; + sp.Velocity = Vector3.Zero; + sp.Teleport(position); + + m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.ReceivedAtDestination); + + foreach (SceneObjectGroup grp in sp.GetAttachments()) + { + sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT); + } + + m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); + m_entityTransferStateMachine.ResetFromTransit(sp.UUID); + } + + /// + /// Teleports the agent to a different region. + /// + /// + /// /param> + /// + /// + /// + /// + private void TeleportAgentToDifferentRegion( + ScenePresence sp, ulong regionHandle, Vector3 position, + Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination) + { + uint x = 0, y = 0; + Utils.LongToUInts(regionHandle, out x, out y); + GridRegion reg = Scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); + + if (reg != null) + { + finalDestination = GetFinalDestination(reg); + + if (finalDestination == null) + { + m_log.WarnFormat( + "[ENTITY TRANSFER MODULE]: Final destination is having problems. Unable to teleport {0} {1}", + sp.Name, sp.UUID); + + sp.ControllingClient.SendTeleportFailed("Problem at destination"); + return; + } + + // Check that these are not the same coordinates + if (finalDestination.RegionLocX == sp.Scene.RegionInfo.RegionLocX && + finalDestination.RegionLocY == sp.Scene.RegionInfo.RegionLocY) + { + // Can't do. Viewer crashes + sp.ControllingClient.SendTeleportFailed("Space warp! You would crash. Move to a different region and try again."); + return; + } + + // + // This is it + // + DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags); + // + // + // + } + else + { + finalDestination = null; + + // TP to a place that doesn't exist (anymore) + // Inform the viewer about that + sp.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); + + // and set the map-tile to '(Offline)' + uint regX, regY; + Utils.LongToUInts(regionHandle, out regX, out regY); + + MapBlockData block = new MapBlockData(); + block.X = (ushort)(regX / Constants.RegionSize); + block.Y = (ushort)(regY / Constants.RegionSize); + block.Access = 254; // == not there + + List blocks = new List(); + blocks.Add(block); + sp.ControllingClient.SendMapBlock(blocks, 0); + } + } + + /// + /// Determines whether this instance is within the max transfer distance. + /// + /// + /// + /// + /// true if this instance is within max transfer distance; otherwise, false. + /// + private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion) + { // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY); // // m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}", // destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI); - // Check that these are not the same coordinates - if (finalDestination.RegionLocX == sp.Scene.RegionInfo.RegionLocX && - finalDestination.RegionLocY == sp.Scene.RegionInfo.RegionLocY) - { - // Can't do. Viewer crashes - sp.ControllingClient.SendTeleportFailed("Space warp! You would crash. Move to a different region and try again."); - return; - } - - if (Math.Abs(curCellX - destCellX) > MaxTransferDistance || Math.Abs(curCellY - destCellY) > MaxTransferDistance) - { - sp.ControllingClient.SendTeleportFailed( - string.Format( - "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way", - finalDestination.RegionName, destCellX, destCellY, - sp.Scene.RegionInfo.RegionName, curCellX, curCellY, - MaxTransferDistance)); - - return; - } - - // - // This is it - // - DoTeleport(sp, reg, finalDestination, position, lookAt, teleportFlags, eq); - // - // - // - } - else - { - // TP to a place that doesn't exist (anymore) - // Inform the viewer about that - sp.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); - - // and set the map-tile to '(Offline)' - uint regX, regY; - Utils.LongToUInts(regionHandle, out regX, out regY); - - MapBlockData block = new MapBlockData(); - block.X = (ushort)(regX / Constants.RegionSize); - block.Y = (ushort)(regY / Constants.RegionSize); - block.Access = 254; // == not there - - List blocks = new List(); - blocks.Add(block); - sp.ControllingClient.SendMapBlock(blocks, 0); - } - } - } - catch (Exception e) - { - m_log.WarnFormat("[ENTITY TRANSFER MODULE]: Exception on teleport: {0} {1}", e.Message, e.StackTrace); - sp.ControllingClient.SendTeleportFailed("Internal error"); - } + // Insanely, RegionLoc on RegionInfo is the 256m map co-ord whilst GridRegion.RegionLoc is the raw meters position. + return Math.Abs(sourceRegion.RegionLocX - destRegion.RegionCoordX) <= MaxTransferDistance + && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance; } - public void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination, Vector3 position, Vector3 lookAt, uint teleportFlags, IEventQueue eq) + public void DoTeleport( + ScenePresence sp, GridRegion reg, GridRegion finalDestination, + Vector3 position, Vector3 lookAt, uint teleportFlags) { + // Record that this agent is in transit so that we can prevent simultaneous requests and do later detection + // of whether the destination region completes the teleport. + if (!m_entityTransferStateMachine.SetInTransit(sp.UUID)) + { + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Ignoring teleport request of {0} {1} to {2} ({3}) {4}/{5} - agent is already in transit.", + sp.Name, sp.UUID, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position); + + return; + } + if (reg == null || finalDestination == null) { sp.ControllingClient.SendTeleportFailed("Unable to locate destination"); + m_entityTransferStateMachine.ResetFromTransit(sp.UUID); + return; } - if (IsInTransit(sp.UUID)) // Avie is already on the way. Caller shouldn't do this. - return; - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Request Teleport to {0} ({1}) {2}/{3}", + "[ENTITY TRANSFER MODULE]: Teleporting {0} {1} from {2} to {3} ({4}) {5}/{6}", + sp.Name, sp.UUID, sp.Scene.RegionInfo.RegionName, reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position); + RegionInfo sourceRegion = sp.Scene.RegionInfo; + + if (!IsWithinMaxTeleportDistance(sourceRegion, finalDestination)) + { + sp.ControllingClient.SendTeleportFailed( + string.Format( + "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way", + finalDestination.RegionName, finalDestination.RegionCoordX, finalDestination.RegionCoordY, + sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, + MaxTransferDistance)); + + m_entityTransferStateMachine.ResetFromTransit(sp.UUID); + + return; + } + uint newRegionX = (uint)(reg.RegionHandle >> 40); uint newRegionY = (((uint)(reg.RegionHandle)) >> 8); uint oldRegionX = (uint)(sp.Scene.RegionInfo.RegionHandle >> 40); @@ -339,17 +430,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, // it's actually doing a lot of work. IPEndPoint endPoint = finalDestination.ExternalEndPoint; - if (endPoint != null && endPoint.Address != null) + if (endPoint == null || endPoint.Address == null) { - // Fixing a bug where teleporting while sitting results in the avatar ending up removed from - // both regions - if (sp.ParentID != (uint)0) - sp.StandUp(); + sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); + m_entityTransferStateMachine.ResetFromTransit(sp.UUID); - if (!sp.ValidateAttachments()) - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", - sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); + return; + } + + if (!sp.ValidateAttachments()) + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", + sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); // if (!sp.ValidateAttachments()) // { @@ -357,218 +449,245 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // return; // } - string reason; - string version; - if (!m_aScene.SimulationService.QueryAccess(finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) - { - sp.ControllingClient.SendTeleportFailed("Teleport failed: " + reason); - return; - } - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); - - sp.ControllingClient.SendTeleportStart(teleportFlags); - - // the avatar.Close below will clear the child region list. We need this below for (possibly) - // closing the child agents, so save it here (we need a copy as it is Clear()-ed). - //List childRegions = avatar.KnownRegionHandles; - // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport - // failure at this point (unlike a border crossing failure). So perhaps this can never fail - // once we reach here... - //avatar.Scene.RemoveCapsHandler(avatar.UUID); - - string capsPath = String.Empty; - - AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); - AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo(); - agentCircuit.startpos = position; - agentCircuit.child = true; - agentCircuit.Appearance = sp.Appearance; - if (currentAgentCircuit != null) - { - agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; - agentCircuit.IPAddress = currentAgentCircuit.IPAddress; - agentCircuit.Viewer = currentAgentCircuit.Viewer; - agentCircuit.Channel = currentAgentCircuit.Channel; - agentCircuit.Mac = currentAgentCircuit.Mac; - agentCircuit.Id0 = currentAgentCircuit.Id0; - } - - if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) - { - // brand new agent, let's create a new caps seed - agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); - } - - // Let's create an agent there if one doesn't exist yet. - bool logout = false; - if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) - { - sp.ControllingClient.SendTeleportFailed(String.Format("Destination refused: {0}", - reason)); - return; - } - - // OK, it got this agent. Let's close some child agents - sp.CloseChildAgents(newRegionX, newRegionY); - IClientIPEndpoint ipepClient; - if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) - { - //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); - #region IP Translation for NAT - // Uses ipepClient above - if (sp.ClientView.TryGet(out ipepClient)) - { - endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); - } - #endregion - capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); - - if (eq != null) - { - eq.EnableSimulator(destinationHandle, endPoint, sp.UUID); - - // ES makes the client send a UseCircuitCode message to the destination, - // which triggers a bunch of things there. - // So let's wait - Thread.Sleep(200); - - eq.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); - - } - else - { - sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); - } - } - else - { - agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); - capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); - } - - - SetInTransit(sp.UUID); - - // Let's send a full update of the agent. This is a synchronous call. - AgentData agent = new AgentData(); - sp.CopyTo(agent); - agent.Position = position; - SetCallbackURL(agent, sp.Scene.RegionInfo); - - //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); - - if (!UpdateAgent(reg, finalDestination, agent)) - { - // Region doesn't take it - m_log.WarnFormat( - "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Returning avatar to source region.", - sp.Name, finalDestination.RegionName); - - Fail(sp, finalDestination, logout); - return; - } - - sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest"); + string reason; + string version; + if (!Scene.SimulationService.QueryAccess( + finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) + { + sp.ControllingClient.SendTeleportFailed(reason); + m_entityTransferStateMachine.ResetFromTransit(sp.UUID); m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, sp.UUID); + "[ENTITY TRANSFER MODULE]: {0} was stopped from teleporting from {1} to {2} because {3}", + sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); - if (eq != null) + return; + } + + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); + + // Fixing a bug where teleporting while sitting results in the avatar ending up removed from + // both regions + if (sp.ParentID != (uint)0) + sp.StandUp(); + + sp.ControllingClient.SendTeleportStart(teleportFlags); + + // the avatar.Close below will clear the child region list. We need this below for (possibly) + // closing the child agents, so save it here (we need a copy as it is Clear()-ed). + //List childRegions = avatar.KnownRegionHandles; + // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport + // failure at this point (unlike a border crossing failure). So perhaps this can never fail + // once we reach here... + //avatar.Scene.RemoveCapsHandler(avatar.UUID); + + string capsPath = String.Empty; + + AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); + AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo(); + agentCircuit.startpos = position; + agentCircuit.child = true; + agentCircuit.Appearance = sp.Appearance; + if (currentAgentCircuit != null) + { + agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; + agentCircuit.IPAddress = currentAgentCircuit.IPAddress; + agentCircuit.Viewer = currentAgentCircuit.Viewer; + agentCircuit.Channel = currentAgentCircuit.Channel; + agentCircuit.Mac = currentAgentCircuit.Mac; + agentCircuit.Id0 = currentAgentCircuit.Id0; + } + + if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) + { + // brand new agent, let's create a new caps seed + agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); + } + + // Let's create an agent there if one doesn't exist yet. + bool logout = false; + if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) + { + sp.ControllingClient.SendTeleportFailed(String.Format("Teleport refused: {0}", reason)); + m_entityTransferStateMachine.ResetFromTransit(sp.UUID); + + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Teleport of {0} from {1} to {2} was refused because {3}", + sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); + + return; + } + + // Past this point we have to attempt clean up if the teleport fails, so update transfer state. + m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); + + // OK, it got this agent. Let's close some child agents + sp.CloseChildAgents(newRegionX, newRegionY); + + IClientIPEndpoint ipepClient; + if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) + { + //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); + #region IP Translation for NAT + // Uses ipepClient above + if (sp.ClientView.TryGet(out ipepClient)) { - eq.TeleportFinishEvent(destinationHandle, 13, endPoint, - 0, teleportFlags, capsPath, sp.UUID); + endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); + } + #endregion + capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); + + if (m_eqModule != null) + { + m_eqModule.EnableSimulator(destinationHandle, endPoint, sp.UUID); + + // ES makes the client send a UseCircuitCode message to the destination, + // which triggers a bunch of things there. + // So let's wait + Thread.Sleep(200); + + m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); + } else { - sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, - teleportFlags, capsPath); - } - - // Let's set this to true tentatively. This does not trigger OnChildAgent - sp.IsChildAgent = true; - - // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which - // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation - // that the client contacted the destination before we close things here. - if (!WaitForCallback(sp.UUID)) - { - m_log.WarnFormat( - "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} failed due to no callback from destination region. Returning avatar to source region.", - sp.Name, finalDestination.RegionName); - - Fail(sp, finalDestination, logout); - return; - } - - // For backwards compatibility - if (version == "Unknown" || version == string.Empty) - { - // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Old simulator, sending attachments one by one..."); - CrossAttachmentsIntoNewRegion(finalDestination, sp, true); - } - - // May need to logout or other cleanup - AgentHasMovedAway(sp, logout); - - // Well, this is it. The agent is over there. - KillEntity(sp.Scene, sp.LocalId); - - // Now let's make it officially a child agent - sp.MakeChildAgent(); - -// sp.Scene.CleanDroppedAttachments(); - - // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone - - if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) - { - Thread.Sleep(5000); - sp.Close(); - sp.Scene.IncomingCloseAgent(sp.UUID); - } - else - { - // now we have a child agent in this region. - sp.Reset(); - } - - // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! - if (sp.Scene.NeedSceneCacheClear(sp.UUID)) - { - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed", - sp.UUID); + sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); } } else { - sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); + agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); + capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); } + + // Let's send a full update of the agent. This is a synchronous call. + AgentData agent = new AgentData(); + sp.CopyTo(agent); + agent.Position = position; + SetCallbackURL(agent, sp.Scene.RegionInfo); + + //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); + + if (!UpdateAgent(reg, finalDestination, agent)) + { + // Region doesn't take it + m_log.WarnFormat( + "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Returning avatar to source region.", + sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); + + Fail(sp, finalDestination, logout); + return; + } + + sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest"); + + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", + capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); + + if (m_eqModule != null) + { + m_eqModule.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); + } + else + { + sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, + teleportFlags, capsPath); + } + + // Let's set this to true tentatively. This does not trigger OnChildAgent + sp.IsChildAgent = true; + + // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which + // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation + // that the client contacted the destination before we close things here. + if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) + { + m_log.WarnFormat( + "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", + sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); + + Fail(sp, finalDestination, logout); + return; + } + + m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); + + // For backwards compatibility + if (version == "Unknown" || version == string.Empty) + { + // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Old simulator, sending attachments one by one..."); + CrossAttachmentsIntoNewRegion(finalDestination, sp, true); + } + + // May need to logout or other cleanup + AgentHasMovedAway(sp, logout); + + // Well, this is it. The agent is over there. + KillEntity(sp.Scene, sp.LocalId); + + // Now let's make it officially a child agent + sp.MakeChildAgent(); + +// sp.Scene.CleanDroppedAttachments(); + + // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone + + if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) + { + // We need to delay here because Imprudence viewers, unlike v1 or v3, have a short (<200ms, <500ms) delay before + // they regard the new region as the current region after receiving the AgentMovementComplete + // response. If close is sent before then, it will cause the viewer to quit instead. + // + // This sleep can be increased if necessary. However, whilst it's active, + // an agent cannot teleport back to this region if it has teleported away. + Thread.Sleep(2000); + + sp.Scene.IncomingCloseAgent(sp.UUID); + } + else + { + // now we have a child agent in this region. + sp.Reset(); + } + + // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! + if (sp.Scene.NeedSceneCacheClear(sp.UUID)) + { + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed", + sp.UUID); + } + + m_entityTransferStateMachine.ResetFromTransit(sp.UUID); } protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout) { + m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); + // Client never contacted destination. Let's restore everything back sp.ControllingClient.SendTeleportFailed("Problems connecting to destination."); // Fail. Reset it back sp.IsChildAgent = false; ReInstantiateScripts(sp); - ResetFromTransit(sp.UUID); EnableChildAgents(sp); // Finally, kill the agent we just created at the destination. - m_aScene.SimulationService.CloseAgent(finalDestination, sp.UUID); + Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); + + m_entityTransferStateMachine.ResetFromTransit(sp.UUID); } protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) { logout = false; - bool success = m_aScene.SimulationService.CreateAgent(finalDestination, agentCircuit, teleportFlags, out reason); + bool success = Scene.SimulationService.CreateAgent(finalDestination, agentCircuit, teleportFlags, out reason); if (success) sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout); @@ -578,19 +697,27 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent) { - return m_aScene.SimulationService.UpdateAgent(finalDestination, agent); + return Scene.SimulationService.UpdateAgent(finalDestination, agent); } protected virtual void SetCallbackURL(AgentData agent, RegionInfo region) { agent.CallbackURI = region.ServerURI + "agent/" + agent.AgentID.ToString() + "/" + region.RegionID.ToString() + "/release/"; - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Set callback URL to {0}", agent.CallbackURI); + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Set release callback URL to {0} in {1}", + agent.CallbackURI, region.RegionName); } + /// + /// Clean up operations once an agent has moved away through cross or teleport. + /// + /// + /// protected virtual void AgentHasMovedAway(ScenePresence sp, bool logout) { - sp.Scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, true); + if (sp.Scene.AttachmentsModule != null) + sp.Scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, true); } protected void KillEntity(Scene scene, uint localID) @@ -615,7 +742,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer protected virtual bool IsOutsideRegion(Scene s, Vector3 pos) { - if (s.TestBorderCross(pos, Cardinals.N)) return true; if (s.TestBorderCross(pos, Cardinals.S)) @@ -628,7 +754,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return false; } - #endregion #region Landmark Teleport @@ -640,7 +765,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// public virtual void RequestTeleportLandmark(IClientAPI remoteClient, AssetLandmark lm) { - GridRegion info = m_aScene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID); + GridRegion info = Scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID); if (info == null) { @@ -663,10 +788,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer public virtual bool TeleportHome(UUID id, IClientAPI client) { - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName); + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); - //OpenSim.Services.Interfaces.PresenceInfo pinfo = m_aScene.PresenceService.GetAgent(client.SessionId); - GridUserInfo uinfo = m_aScene.GridUserService.GetGridUserInfo(client.AgentId.ToString()); + //OpenSim.Services.Interfaces.PresenceInfo pinfo = Scene.PresenceService.GetAgent(client.SessionId); + GridUserInfo uinfo = Scene.GridUserService.GetGridUserInfo(client.AgentId.ToString()); if (uinfo != null) { @@ -676,7 +802,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer client.SendTeleportFailed("You don't have a home position set."); return false; } - GridRegion regionInfo = m_aScene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID); + GridRegion regionInfo = Scene.GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID); if (regionInfo == null) { // can't find the Home region: Tell viewer and abort @@ -684,8 +810,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return false; } - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: User's home region is {0} {1} ({2}-{3})", - regionInfo.RegionName, regionInfo.RegionID, regionInfo.RegionLocX / Constants.RegionSize, regionInfo.RegionLocY / Constants.RegionSize); + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Home region of {0} is {1} ({2}-{3})", + client.Name, regionInfo.RegionName, regionInfo.RegionCoordX, regionInfo.RegionCoordY); // a little eekie that this goes back to Scene and with a forced cast, will fix that at some point... ((Scene)(client.Scene)).RequestTeleportLocation( @@ -736,7 +862,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer neighbourx--; newpos.X = Constants.RegionSize - enterDistance; - } else if (scene.TestBorderCross(pos + eastCross, Cardinals.E)) { @@ -922,107 +1047,123 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, GridRegion neighbourRegion, bool isFlying, string version) { + if (neighbourRegion == null) + return agent; + try { + m_entityTransferStateMachine.SetInTransit(agent.UUID); + ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize)); - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} to {2}-{3} running version {4}", agent.Firstname, agent.Lastname, neighbourx, neighboury, version); + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} to {2}-{3} running version {4}", + agent.Firstname, agent.Lastname, neighbourx, neighboury, version); Scene m_scene = agent.Scene; - - if (neighbourRegion != null) + + if (!agent.ValidateAttachments()) + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for region crossing of {0} from {1} to {2}. Continuing.", + agent.Name, agent.Scene.RegionInfo.RegionName, neighbourRegion.RegionName); + + pos = pos + agent.Velocity; + Vector3 vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0); + + agent.RemoveFromPhysicalScene(); + + AgentData cAgent = new AgentData(); + agent.CopyTo(cAgent); + cAgent.Position = pos; + if (isFlying) + cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; + + // We don't need the callback anymnore + cAgent.CallbackURI = String.Empty; + + // Beyond this point, extra cleanup is needed beyond removing transit state + m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring); + + if (!m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent)) { - if (!agent.ValidateAttachments()) - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for region crossing of {0} from {1} to {2}. Continuing.", - agent.Name, agent.Scene.RegionInfo.RegionName, neighbourRegion.RegionName); + // region doesn't take it + m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); - pos = pos + agent.Velocity; - Vector3 vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0); + ReInstantiateScripts(agent); + agent.AddToPhysicalScene(isFlying); + m_entityTransferStateMachine.ResetFromTransit(agent.UUID); - agent.RemoveFromPhysicalScene(); - SetInTransit(agent.UUID); + return agent; + } - AgentData cAgent = new AgentData(); - agent.CopyTo(cAgent); - cAgent.Position = pos; - if (isFlying) - cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; + //AgentCircuitData circuitdata = m_controllingClient.RequestClientInfo(); + agent.ControllingClient.RequestClientInfo(); - // We don't need the callback anymnore - cAgent.CallbackURI = String.Empty; + //m_log.Debug("BEFORE CROSS"); + //Scene.DumpChildrenSeeds(UUID); + //DumpKnownRegions(); + string agentcaps; + if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps)) + { + m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: No ENTITY TRANSFER MODULE information for region handle {0}, exiting CrossToNewRegion.", + neighbourRegion.RegionHandle); + return agent; + } + // No turning back + agent.IsChildAgent = true; - if (!m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent)) - { - // region doesn't take it - ReInstantiateScripts(agent); - agent.AddToPhysicalScene(isFlying); - ResetFromTransit(agent.UUID); - return agent; - } - - //AgentCircuitData circuitdata = m_controllingClient.RequestClientInfo(); - agent.ControllingClient.RequestClientInfo(); - - //m_log.Debug("BEFORE CROSS"); - //Scene.DumpChildrenSeeds(UUID); - //DumpKnownRegions(); - string agentcaps; - if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps)) - { - m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: No ENTITY TRANSFER MODULE information for region handle {0}, exiting CrossToNewRegion.", - neighbourRegion.RegionHandle); - return agent; - } - // No turning back - agent.IsChildAgent = true; + string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentcaps); - string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentcaps); - - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID); + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID); - IEventQueue eq = agent.Scene.RequestModuleInterface(); - if (eq != null) - { - eq.CrossRegion(neighbourHandle, pos, vel2 /* agent.Velocity */, neighbourRegion.ExternalEndPoint, - capsPath, agent.UUID, agent.ControllingClient.SessionId); - } - else - { - agent.ControllingClient.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint, - capsPath); - } + if (m_eqModule != null) + { + m_eqModule.CrossRegion( + neighbourHandle, pos, vel2 /* agent.Velocity */, neighbourRegion.ExternalEndPoint, + capsPath, agent.UUID, agent.ControllingClient.SessionId); + } + else + { + agent.ControllingClient.CrossRegion(neighbourHandle, pos, agent.Velocity, neighbourRegion.ExternalEndPoint, + capsPath); + } - // SUCCESS! - agent.MakeChildAgent(); - ResetFromTransit(agent.UUID); + // SUCCESS! + m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.ReceivedAtDestination); - // now we have a child agent in this region. Request all interesting data about other (root) agents - agent.SendOtherAgentsAvatarDataToMe(); - agent.SendOtherAgentsAppearanceToMe(); + // Unlike a teleport, here we do not wait for the destination region to confirm the receipt. + m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); - // Backwards compatibility. Best effort - if (version == "Unknown" || version == string.Empty) - { - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: neighbor with old version, passing attachments one by one..."); - Thread.Sleep(3000); // wait a little now that we're not waiting for the callback - CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true); - } + agent.MakeChildAgent(); + // FIXME: Possibly this should occur lower down after other commands to close other agents, + // but not sure yet what the side effects would be. + m_entityTransferStateMachine.ResetFromTransit(agent.UUID); - // Next, let's close the child agent connections that are too far away. - agent.CloseChildAgents(neighbourx, neighboury); - - AgentHasMovedAway(agent, false); - - // the user may change their profile information in other region, - // so the userinfo in UserProfileCache is not reliable any more, delete it - // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! - if (agent.Scene.NeedSceneCacheClear(agent.UUID)) - { - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID); - } + // now we have a child agent in this region. Request all interesting data about other (root) agents + agent.SendOtherAgentsAvatarDataToMe(); + agent.SendOtherAgentsAppearanceToMe(); + + // Backwards compatibility. Best effort + if (version == "Unknown" || version == string.Empty) + { + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: neighbor with old version, passing attachments one by one..."); + Thread.Sleep(3000); // wait a little now that we're not waiting for the callback + CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true); + } + + // Next, let's close the child agent connections that are too far away. + agent.CloseChildAgents(neighbourx, neighboury); + + AgentHasMovedAway(agent, false); + + // the user may change their profile information in other region, + // so the userinfo in UserProfileCache is not reliable any more, delete it + // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! + if (agent.Scene.NeedSceneCacheClear(agent.UUID)) + { + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID); } //m_log.Debug("AFTER CROSS"); @@ -1034,11 +1175,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.ErrorFormat( "[ENTITY TRANSFER MODULE]: Problem crossing user {0} to new region {1} from {2}. Exception {3}{4}", agent.Name, neighbourRegion.RegionName, agent.Scene.RegionInfo.RegionName, e.Message, e.StackTrace); + + // TODO: Might be worth attempting other restoration here such as reinstantiation of scripts, etc. } return agent; } - + private void CrossAgentToNewRegionCompleted(IAsyncResult iar) { CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState; @@ -1186,7 +1329,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) { - AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); AgentCircuitData agent = sp.ControllingClient.RequestClientInfo(); agent.BaseFolder = UUID.Zero; @@ -1211,7 +1353,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer seeds.Add(neighbour.RegionHandle, agent.CapsPath); } else + { agent.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, neighbour.RegionHandle); + } cagents.Add(agent); } @@ -1322,24 +1466,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // after a cross here Thread.Sleep(500); - Scene m_scene = sp.Scene; + Scene scene = sp.Scene; - uint x, y; - Utils.LongToUInts(reg.RegionHandle, out x, out y); - x = x / Constants.RegionSize; - y = y / Constants.RegionSize; - m_log.Debug("[ENTITY TRANSFER MODULE]: Starting to inform client about neighbour " + x + ", " + y + "(" + endPoint + ")"); + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})", + sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY); string capsPath = reg.ServerURI + CapsUtil.GetCapsSeedPath(a.CapsPath); string reason = String.Empty; - bool regionAccepted = m_scene.SimulationService.CreateAgent(reg, a, (uint)TeleportFlags.Default, out reason); + bool regionAccepted = scene.SimulationService.CreateAgent(reg, a, (uint)TeleportFlags.Default, out reason); if (regionAccepted && newAgent) { - IEventQueue eq = sp.Scene.RequestModuleInterface(); - if (eq != null) + if (m_eqModule != null) { #region IP Translation for NAT IClientIPEndpoint ipepClient; @@ -1351,10 +1492,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat("[ENTITY TRANSFER MODULE]: {0} is sending {1} EnableSimulator for neighbour region {2} @ {3} " + "and EstablishAgentCommunication with seed cap {4}", - m_scene.RegionInfo.RegionName, sp.Name, reg.RegionName, reg.RegionHandle, capsPath); + scene.RegionInfo.RegionName, sp.Name, reg.RegionName, reg.RegionHandle, capsPath); - eq.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID); - eq.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); + m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID); + m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); } else { @@ -1362,8 +1503,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // TODO: make Event Queue disablable! } - m_log.Debug("[ENTITY TRANSFER MODULE]: Completed inform client about neighbour " + endPoint.ToString()); + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Completed inform {0} {1} about neighbour {2}", sp.Name, sp.UUID, endPoint); } + + if (!regionAccepted) + m_log.WarnFormat( + "[ENTITY TRANSFER MODULE]: Region {0} did not accept {1} {2}: {3}", + reg.RegionName, sp.Name, sp.UUID, reason); } /// @@ -1471,17 +1617,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer #endregion - #region Agent Arrived + public void AgentArrivedAtDestination(UUID id) { - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Agent {0} released", id); - ResetFromTransit(id); + m_entityTransferStateMachine.SetAgentArrivedAtDestination(id); } #endregion #region Object Transfers + /// /// Move the given scene object into a new region depending on which region its absolute position has moved /// into. @@ -1747,8 +1893,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer //// And the new channel... //if (m_interregionCommsOut != null) // successYN = m_interregionCommsOut.SendCreateObject(newRegionHandle, grp, true); - if (m_aScene.SimulationService != null) - successYN = m_aScene.SimulationService.CreateObject(destination, newPosition, grp, true); + if (Scene.SimulationService != null) + successYN = Scene.SimulationService.CreateObject(destination, newPosition, grp, true); if (successYN) { @@ -1792,86 +1938,52 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return successYN; } - protected bool CrossAttachmentsIntoNewRegion(GridRegion destination, ScenePresence sp, bool silent) + /// + /// Cross the attachments for an avatar into the destination region. + /// + /// + /// This is only invoked for simulators released prior to April 2011. Versions of OpenSimulator since then + /// transfer attachments in one go as part of the ChildAgentDataUpdate data passed in the update agent call. + /// + /// + /// + /// + protected void CrossAttachmentsIntoNewRegion(GridRegion destination, ScenePresence sp, bool silent) { - List m_attachments = sp.GetAttachments(); + List attachments = sp.GetAttachments(); - // Validate -// foreach (SceneObjectGroup gobj in m_attachments) -// { -// if (gobj == null || gobj.IsDeleted) -// return false; -// } +// m_log.DebugFormat( +// "[ENTITY TRANSFER MODULE]: Crossing {0} attachments into {1} for {2}", +// m_attachments.Count, destination.RegionName, sp.Name); - foreach (SceneObjectGroup gobj in m_attachments) + foreach (SceneObjectGroup gobj in attachments) { // If the prim group is null then something must have happened to it! if (gobj != null && !gobj.IsDeleted) { - // Set the parent localID to 0 so it transfers over properly. - gobj.RootPart.SetParentLocalId(0); - gobj.AbsolutePosition = gobj.RootPart.AttachedPos; - gobj.IsAttachment = false; + SceneObjectGroup clone = (SceneObjectGroup)gobj.CloneForNewScene(); + clone.RootPart.GroupPosition = gobj.RootPart.AttachedPos; + clone.IsAttachment = false; + //gobj.RootPart.LastOwnerID = gobj.GetFromAssetID(); - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending attachment {0} to region {1}", gobj.UUID, destination.RegionName); - CrossPrimGroupIntoNewRegion(destination, Vector3.Zero, gobj, silent); + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Sending attachment {0} to region {1}", + clone.UUID, destination.RegionName); + + CrossPrimGroupIntoNewRegion(destination, Vector3.Zero, clone, silent); } } sp.ClearAttachments(); - - return true; } #endregion #region Misc - protected bool WaitForCallback(UUID id) + public bool IsInTransit(UUID id) { - int count = 200; - while (m_agentsInTransit.Contains(id) && count-- > 0) - { - //m_log.Debug(" >>> Waiting... " + count); - Thread.Sleep(100); - } - - if (count > 0) - return true; - else - return false; - } - - protected void SetInTransit(UUID id) - { - lock (m_agentsInTransit) - { - if (!m_agentsInTransit.Contains(id)) - m_agentsInTransit.Add(id); - } - } - - protected bool IsInTransit(UUID id) - { - lock (m_agentsInTransit) - { - if (m_agentsInTransit.Contains(id)) - return true; - } - return false; - } - - protected bool ResetFromTransit(UUID id) - { - lock (m_agentsInTransit) - { - if (m_agentsInTransit.Contains(id)) - { - m_agentsInTransit.Remove(id); - return true; - } - } - return false; + return m_entityTransferStateMachine.IsInTransit(id); } protected void ReInstantiateScripts(ScenePresence sp) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs new file mode 100644 index 0000000000..d0cab49563 --- /dev/null +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs @@ -0,0 +1,269 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; +using System.Net; +using System.Reflection; +using System.Threading; +using OpenMetaverse; +using log4net; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Client; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Physics.Manager; +using OpenSim.Services.Interfaces; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; + +namespace OpenSim.Region.CoreModules.Framework.EntityTransfer +{ + /// + /// The possible states that an agent can be in when its being transferred between regions. + /// + /// + /// This is a state machine. + /// + /// [Entry] => Preparing + /// Preparing => { Transferring || CleaningUp || [Exit] } + /// Transferring => { ReceivedAtDestination || CleaningUp } + /// ReceivedAtDestination => CleaningUp + /// CleaningUp => [Exit] + /// + /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp + /// However, any state can transition to CleaningUp if the teleport has failed. + /// + enum AgentTransferState + { + Preparing, // The agent is being prepared for transfer + Transferring, // The agent is in the process of being transferred to a destination + ReceivedAtDestination, // The destination has notified us that the agent has been successfully received + CleaningUp // The agent is being changed to child/removed after a transfer + } + + /// + /// Records the state of entities when they are in transfer within or between regions (cross or teleport). + /// + public class EntityTransferStateMachine + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + /// + /// If true then on a teleport, the source region waits for a callback from the destination region. If + /// a callback fails to arrive within a set time then the user is pulled back into the source region. + /// + public bool EnableWaitForAgentArrivedAtDestination { get; set; } + + private EntityTransferModule m_mod; + + private Dictionary m_agentsInTransit = new Dictionary(); + + public EntityTransferStateMachine(EntityTransferModule module) + { + m_mod = module; + } + + /// + /// Set that an agent is in transit. + /// + /// The ID of the agent being teleported + /// true if the agent was not already in transit, false if it was + internal bool SetInTransit(UUID id) + { + lock (m_agentsInTransit) + { + if (!m_agentsInTransit.ContainsKey(id)) + { + m_agentsInTransit[id] = AgentTransferState.Preparing; + return true; + } + } + + return false; + } + + /// + /// Updates the state of an agent that is already in transit. + /// + /// + /// + /// + /// Illegal transitions will throw an Exception + internal void UpdateInTransit(UUID id, AgentTransferState newState) + { + lock (m_agentsInTransit) + { + // Illegal to try and update an agent that's not actually in transit. + if (!m_agentsInTransit.ContainsKey(id)) + throw new Exception( + string.Format( + "Agent with ID {0} is not registered as in transit in {1}", + id, m_mod.Scene.RegionInfo.RegionName)); + + AgentTransferState oldState = m_agentsInTransit[id]; + + bool transitionOkay = false; + + if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) + transitionOkay = true; + else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) + transitionOkay = true; + else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) + transitionOkay = true; + + if (transitionOkay) + m_agentsInTransit[id] = newState; + else + throw new Exception( + string.Format( + "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", + id, oldState, newState, m_mod.Scene.RegionInfo.RegionName)); + } + } + + internal bool IsInTransit(UUID id) + { + lock (m_agentsInTransit) + return m_agentsInTransit.ContainsKey(id); + } + + /// + /// Removes an agent from the transit state machine. + /// + /// + /// true if the agent was flagged as being teleported when this method was called, false otherwise + internal bool ResetFromTransit(UUID id) + { + lock (m_agentsInTransit) + { + if (m_agentsInTransit.ContainsKey(id)) + { + AgentTransferState state = m_agentsInTransit[id]; + + if (state == AgentTransferState.Transferring || state == AgentTransferState.ReceivedAtDestination) + { + // FIXME: For now, we allow exit from any state since a thrown exception in teleport is now guranteed + // to be handled properly - ResetFromTransit() could be invoked at any step along the process + m_log.WarnFormat( + "[ENTITY TRANSFER STATE MACHINE]: Agent with ID {0} should not exit directly from state {1}, should go to {2} state first in {3}", + id, state, AgentTransferState.CleaningUp, m_mod.Scene.RegionInfo.RegionName); + +// throw new Exception( +// "Agent with ID {0} cannot exit directly from state {1}, it must go to {2} state first", +// state, AgentTransferState.CleaningUp); + } + + m_agentsInTransit.Remove(id); + + m_log.DebugFormat( + "[ENTITY TRANSFER STATE MACHINE]: Agent {0} cleared from transit in {1}", + id, m_mod.Scene.RegionInfo.RegionName); + + return true; + } + } + + m_log.WarnFormat( + "[ENTITY TRANSFER STATE MACHINE]: Agent {0} requested to clear from transit in {1} but was already cleared", + id, m_mod.Scene.RegionInfo.RegionName); + + return false; + } + + internal bool WaitForAgentArrivedAtDestination(UUID id) + { + if (!m_mod.WaitForAgentArrivedAtDestination) + return true; + + lock (m_agentsInTransit) + { + if (!IsInTransit(id)) + throw new Exception( + string.Format( + "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit", + id, m_mod.Scene.RegionInfo.RegionName)); + + AgentTransferState currentState = m_agentsInTransit[id]; + + if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) + throw new Exception( + string.Format( + "Asked to wait for destination callback for agent with ID {0} in {1} but agent is in state {2}", + id, m_mod.Scene.RegionInfo.RegionName, currentState)); + } + + int count = 200; + + // There should be no race condition here since no other code should be removing the agent transfer or + // changing the state to another other than Transferring => ReceivedAtDestination. + while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0) + { +// m_log.Debug(" >>> Waiting... " + count); + Thread.Sleep(100); + } + + return count > 0; + } + + internal void SetAgentArrivedAtDestination(UUID id) + { + lock (m_agentsInTransit) + { + if (!m_agentsInTransit.ContainsKey(id)) + { + m_log.WarnFormat( + "[ENTITY TRANSFER STATE MACHINE]: Region {0} received notification of arrival in destination of agent {1} but no teleport request is active", + m_mod.Scene.RegionInfo.RegionName, id); + + return; + } + + AgentTransferState currentState = m_agentsInTransit[id]; + + if (currentState == AgentTransferState.ReceivedAtDestination) + { + // An anomoly but don't make this an outright failure - destination region could be overzealous in sending notification. + m_log.WarnFormat( + "[ENTITY TRANSFER STATE MACHINE]: Region {0} received notification of arrival in destination of agent {1} but notification has already previously been received", + m_mod.Scene.RegionInfo.RegionName, id); + } + else if (currentState != AgentTransferState.Transferring) + { + m_log.ErrorFormat( + "[ENTITY TRANSFER STATE MACHINE]: Region {0} received notification of arrival in destination of agent {1} but agent is in state {2}", + m_mod.Scene.RegionInfo.RegionName, id, currentState); + + return; + } + + m_agentsInTransit[id] = AgentTransferState.ReceivedAtDestination; + } + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index 8b5ad237f2..3010b59f13 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -45,11 +45,12 @@ using Nini.Config; namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { - public class HGEntityTransferModule : EntityTransferModule, ISharedRegionModule, IEntityTransferModule, IUserAgentVerificationModule + public class HGEntityTransferModule + : EntityTransferModule, INonSharedRegionModule, IEntityTransferModule, IUserAgentVerificationModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private bool m_Initialized = false; + private int m_levelHGTeleport = 0; private GatekeeperServiceConnector m_GatekeeperConnector; @@ -63,11 +64,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer public override void Initialise(IConfigSource source) { IConfig moduleConfig = source.Configs["Modules"]; + if (moduleConfig != null) { string name = moduleConfig.GetString("EntityTransferModule", ""); if (name == Name) { + IConfig transferConfig = source.Configs["EntityTransfer"]; + if (transferConfig != null) + m_levelHGTeleport = transferConfig.GetInt("LevelHGTeleport", 0); + InitialiseCommon(source); m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name); } @@ -77,10 +83,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer public override void AddRegion(Scene scene) { base.AddRegion(scene); + if (m_Enabled) - { scene.RegisterModuleInterface(this); - } } protected override void OnNewClient(IClientAPI client) @@ -93,24 +98,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer public override void RegionLoaded(Scene scene) { base.RegionLoaded(scene); + if (m_Enabled) - if (!m_Initialized) - { - m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService); - m_Initialized = true; - - } - + m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService); } + public override void RemoveRegion(Scene scene) { base.AddRegion(scene); - if (m_Enabled) - { - scene.UnregisterModuleInterface(this); - } - } + if (m_Enabled) + scene.UnregisterModuleInterface(this); + } #endregion @@ -118,8 +117,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer protected override GridRegion GetFinalDestination(GridRegion region) { - int flags = m_aScene.GridService.GetRegionFlags(m_aScene.RegionInfo.ScopeID, region.RegionID); + int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, region.RegionID); m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: region {0} flags: {1}", region.RegionID, flags); + if ((flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) { m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Destination region {0} is hyperlink", region.RegionID); @@ -130,6 +130,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: GetHyperlinkRegion to Gatekeeper {0} failed", region.ServerURI); return real_destination; } + return region; } @@ -138,7 +139,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (base.NeedsClosing(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) return true; - int flags = m_aScene.GridService.GetRegionFlags(m_aScene.RegionInfo.ScopeID, reg.RegionID); + int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) return true; @@ -151,7 +152,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (logout) { // Log them out of this grid - m_aScene.PresenceService.LogoutAgent(sp.ControllingClient.SessionId); + Scene.PresenceService.LogoutAgent(sp.ControllingClient.SessionId); } } @@ -160,10 +161,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: CreateAgent {0} {1}", reg.ServerURI, finalDestination.ServerURI); reason = string.Empty; logout = false; - int flags = m_aScene.GridService.GetRegionFlags(m_aScene.RegionInfo.ScopeID, reg.RegionID); + int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Data.RegionFlags.Hyperlink) != 0) { // this user is going to another grid + // check if HyperGrid teleport is allowed, based on user level + if (sp.UserLevel < m_levelHGTeleport) + { + m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Unable to HG teleport agent due to insufficient UserLevel."); + reason = "Hypergrid teleport not allowed"; + return false; + } + if (agentCircuit.ServiceURLs.ContainsKey("HomeURI")) { string userAgentDriver = agentCircuit.ServiceURLs["HomeURI"].ToString(); @@ -193,10 +202,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer public override bool TeleportHome(UUID id, IClientAPI client) { - m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.FirstName, client.LastName); + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Request to teleport {0} {1} home", client.Name, client.AgentId); // Let's find out if this is a foreign user or a local user - IUserManagement uMan = m_aScene.RequestModuleInterface(); + IUserManagement uMan = Scene.RequestModuleInterface(); if (uMan != null && uMan.IsLocalGridUser(id)) { // local grid user @@ -232,13 +242,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return false; } - IEventQueue eq = sp.Scene.RequestModuleInterface(); GridRegion homeGatekeeper = MakeRegion(aCircuit); m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: teleporting user {0} {1} home to {2} via {3}:{4}", aCircuit.firstname, aCircuit.lastname, finalDestination.RegionName, homeGatekeeper.ServerURI, homeGatekeeper.RegionName); - DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome), eq); + DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); return true; } @@ -252,19 +261,21 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Teleporting agent via landmark to {0} region {1} position {2}", (lm.Gatekeeper == string.Empty) ? "local" : lm.Gatekeeper, lm.RegionID, lm.Position); + if (lm.Gatekeeper == string.Empty) { base.RequestTeleportLandmark(remoteClient, lm); return; } - GridRegion info = m_aScene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID); + GridRegion info = Scene.GridService.GetRegionByUUID(UUID.Zero, lm.RegionID); // Local region? if (info != null) { ((Scene)(remoteClient.Scene)).RequestTeleportLocation(remoteClient, info.RegionHandle, lm.Position, Vector3.Zero, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); + return; } else @@ -275,21 +286,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer GridRegion gatekeeper = new GridRegion(); gatekeeper.ServerURI = lm.Gatekeeper; GridRegion finalDestination = gConn.GetHyperlinkRegion(gatekeeper, new UUID(lm.RegionID)); + if (finalDestination != null) { ScenePresence sp = scene.GetScenePresence(remoteClient.AgentId); IEntityTransferModule transferMod = scene.RequestModuleInterface(); - IEventQueue eq = sp.Scene.RequestModuleInterface(); - if (transferMod != null && sp != null && eq != null) - transferMod.DoTeleport(sp, gatekeeper, finalDestination, lm.Position, - Vector3.UnitX, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark), eq); + + if (transferMod != null && sp != null) + transferMod.DoTeleport( + sp, gatekeeper, finalDestination, lm.Position, Vector3.UnitX, + (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); } } // can't find the region: Tell viewer and abort remoteClient.SendTeleportFailed("The teleport destination could not be found."); - } #endregion @@ -304,49 +316,48 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer IUserAgentService security = new UserAgentServiceConnector(url); return security.VerifyClient(aCircuit.SessionID, token); } - else - m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Agent {0} {1} does not have a HomeURI OH NO!", aCircuit.firstname, aCircuit.lastname); + else + { + m_log.DebugFormat( + "[HG ENTITY TRANSFER MODULE]: Agent {0} {1} does not have a HomeURI OH NO!", + aCircuit.firstname, aCircuit.lastname); + } return false; } void OnConnectionClosed(IClientAPI obj) { - if (obj.IsLoggingOut) + if (obj.SceneAgent.IsChildAgent) + return; + + // Let's find out if this is a foreign user or a local user + IUserManagement uMan = Scene.RequestModuleInterface(); +// UserAccount account = Scene.UserAccountService.GetUserAccount(Scene.RegionInfo.ScopeID, obj.AgentId); + + if (uMan != null && uMan.IsLocalGridUser(obj.AgentId)) { - object sp = null; - if (obj.Scene.TryGetScenePresence(obj.AgentId, out sp)) - { - if (((ScenePresence)sp).IsChildAgent) - return; - } + // local grid user + return; + } - // Let's find out if this is a foreign user or a local user - IUserManagement uMan = m_aScene.RequestModuleInterface(); - UserAccount account = m_aScene.UserAccountService.GetUserAccount(m_aScene.RegionInfo.ScopeID, obj.AgentId); - if (uMan != null && uMan.IsLocalGridUser(obj.AgentId)) - { - // local grid user - return; - } + AgentCircuitData aCircuit = ((Scene)(obj.Scene)).AuthenticateHandler.GetAgentCircuitData(obj.CircuitCode); - AgentCircuitData aCircuit = ((Scene)(obj.Scene)).AuthenticateHandler.GetAgentCircuitData(obj.CircuitCode); - - if (aCircuit.ServiceURLs.ContainsKey("HomeURI")) - { - string url = aCircuit.ServiceURLs["HomeURI"].ToString(); - IUserAgentService security = new UserAgentServiceConnector(url); - security.LogoutAgent(obj.AgentId, obj.SessionId); - //m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Sent logout call to UserAgentService @ {0}", url); - } - else + if (aCircuit.ServiceURLs.ContainsKey("HomeURI")) + { + string url = aCircuit.ServiceURLs["HomeURI"].ToString(); + IUserAgentService security = new UserAgentServiceConnector(url); + security.LogoutAgent(obj.AgentId, obj.SessionId); + //m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Sent logout call to UserAgentService @ {0}", url); + } + else + { m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: HomeURI not found for agent {0} logout", obj.AgentId); } } #endregion - private GridRegion MakeRegion(AgentCircuitData aCircuit) { GridRegion region = new GridRegion(); @@ -363,6 +374,5 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer region.InternalEndPoint = new System.Net.IPEndPoint(System.Net.IPAddress.Parse("0.0.0.0"), (int)0); return region; } - } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index a71584a91b..cf72b58832 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -364,8 +364,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { m_log.DebugFormat("[HG INVENTORY ACCESS MODULE]: Changing root inventory for user {0}", client.Name); InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID); - List fids = new List(); - List iids = new List(); + List keep = new List(); foreach (InventoryFolderBase f in content.Folders) @@ -395,4 +394,4 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess #endregion } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index ee9961f831..d30c2e2d4c 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -175,7 +175,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess sbyte assetType, byte wearableType, uint nextOwnerMask, int creationDate) { - m_log.DebugFormat("[AGENT INVENTORY]: Received request to create inventory item {0} in folder {1}", name, folderID); + m_log.DebugFormat("[INVENTORY ACCESS MODULE]: Received request to create inventory item {0} in folder {1}", name, folderID); if (!m_Scene.Permissions.CanCreateUserInventory(invType, remoteClient.AgentId)) return; @@ -210,13 +210,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess else { m_log.ErrorFormat( - "ScenePresence for agent uuid {0} unexpectedly not found in CreateNewInventoryItem", + "[INVENTORY ACCESS MODULE]: ScenePresence for agent uuid {0} unexpectedly not found in CreateNewInventoryItem", remoteClient.AgentId); } } else { - IAgentAssetTransactions agentTransactions = m_Scene.RequestModuleInterface(); + IAgentAssetTransactions agentTransactions = m_Scene.AgentTransactionsModule; if (agentTransactions != null) { agentTransactions.HandleItemCreationFromTransaction( @@ -288,16 +288,19 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess else { m_log.ErrorFormat( - "[AGENT INVENTORY]: Could not find item {0} for caps inventory update", + "[INVENTORY ACCESS MODULE]: Could not find item {0} for caps inventory update", itemID); } return UUID.Zero; } - public virtual UUID CopyToInventory(DeRezAction action, UUID folderID, - List objectGroups, IClientAPI remoteClient) + public virtual List CopyToInventory( + DeRezAction action, UUID folderID, + List objectGroups, IClientAPI remoteClient, bool asAttachment) { + List copiedItems = new List(); + Dictionary> bundlesToCopy = new Dictionary>(); if (CoalesceMultipleObjectsToInventory) @@ -324,16 +327,16 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } } - // This is method scoped and will be returned. It will be the - // last created asset id - UUID assetID = UUID.Zero; +// m_log.DebugFormat( +// "[INVENTORY ACCESS MODULE]: Copying {0} object bundles to folder {1} action {2} for {3}", +// bundlesToCopy.Count, folderID, action, remoteClient.Name); // Each iteration is really a separate asset being created, // with distinct destinations as well. foreach (List bundle in bundlesToCopy.Values) - assetID = CopyBundleToInventory(action, folderID, bundle, remoteClient); + copiedItems.Add(CopyBundleToInventory(action, folderID, bundle, remoteClient, asAttachment)); - return assetID; + return copiedItems; } /// @@ -344,12 +347,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess /// /// /// - /// - protected UUID CopyBundleToInventory( - DeRezAction action, UUID folderID, List objlist, IClientAPI remoteClient) + /// Should be true if the bundle is being copied as an attachment. This prevents + /// attempted serialization of any script state which would abort any operating scripts. + /// The inventory item created by the copy + protected InventoryItemBase CopyBundleToInventory( + DeRezAction action, UUID folderID, List objlist, IClientAPI remoteClient, + bool asAttachment) { - UUID assetID = UUID.Zero; - CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); Dictionary originalPositions = new Dictionary(); @@ -401,18 +405,27 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess string itemXml; + // If we're being called from a script, then trying to serialize that same script's state will not complete + // in any reasonable time period. Therefore, we'll avoid it. The worst that can happen is that if + // the client/server crashes rather than logging out normally, the attachment's scripts will resume + // without state on relog. Arguably, this is what we want anyway. if (objlist.Count > 1) - itemXml = CoalescedSceneObjectsSerializer.ToXml(coa); + itemXml = CoalescedSceneObjectsSerializer.ToXml(coa, !asAttachment); else - itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0]); + itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment); // Restore the position of each group now that it has been stored to inventory. foreach (SceneObjectGroup objectGroup in objlist) objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); + +// m_log.DebugFormat( +// "[INVENTORY ACCESS MODULE]: Created item is {0}", +// item != null ? item.ID.ToString() : "NULL"); + if (item == null) - return UUID.Zero; + return null; // Can't know creator is the same, so null it in inventory if (objlist.Count > 1) @@ -422,7 +435,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } else { - item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); + item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); + item.CreatorData = objlist[0].RootPart.CreatorData; item.SaleType = objlist[0].RootPart.ObjectSaleType; item.SalePrice = objlist[0].RootPart.SalePrice; } @@ -435,8 +449,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess objlist[0].OwnerID.ToString()); m_Scene.AssetService.Store(asset); - item.AssetID = asset.FullID; - assetID = asset.FullID; + item.AssetID = asset.FullID; if (DeRezAction.SaveToExistingUserInventoryItem == action) { @@ -469,9 +482,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // This is a hook to do some per-asset post-processing for subclasses that need that if (remoteClient != null) - ExportAsset(remoteClient.AgentId, assetID); + ExportAsset(remoteClient.AgentId, asset.FullID); - return assetID; + return item; } protected virtual void ExportAsset(UUID agentID, UUID assetID) @@ -617,7 +630,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (null == item) { m_log.DebugFormat( - "[AGENT INVENTORY]: Object {0} {1} scheduled for save to inventory has already been deleted.", + "[INVENTORY ACCESS MODULE]: Object {0} {1} scheduled for save to inventory has already been deleted.", so.Name, so.UUID); return null; @@ -668,7 +681,6 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { // Catch all. Use lost & found // - folder = m_Scene.InventoryService.GetFolderForType(userID, AssetType.LostAndFoundFolder); } } @@ -718,7 +730,6 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (item == null) { - return null; } @@ -748,7 +759,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess else { m_log.WarnFormat( - "[InventoryAccessModule]: Could not find asset {0} for {1} in RezObject()", + "[INVENTORY ACCESS MODULE]: Could not find asset {0} for {1} in RezObject()", assetID, remoteClient.Name); } @@ -859,7 +870,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess SceneObjectPart rootPart = group.RootPart; // m_log.DebugFormat( -// "[InventoryAccessModule]: Preparing to rez {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}", +// "[INVENTORY ACCESS MODULE]: Preparing to rez {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}", // group.Name, group.LocalId, group.UUID, // group.RootPart.OwnerMask, group.RootPart.NextOwnerMask, group.RootPart.GroupMask, group.RootPart.EveryoneMask, // remoteClient.Name); @@ -867,7 +878,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // Vector3 storedPosition = group.AbsolutePosition; if (group.UUID == UUID.Zero) { - m_log.Debug("[InventoryAccessModule]: Object has UUID.Zero! Position 3"); + m_log.Debug("[INVENTORY ACCESS MODULE]: Object has UUID.Zero! Position 3"); } foreach (SceneObjectPart part in group.Parts) @@ -928,7 +939,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } // m_log.DebugFormat( -// "[InventoryAccessModule]: Rezzed {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}", +// "[INVENTORY ACCESS MODULE]: Rezzed {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}", // group.Name, group.LocalId, group.UUID, // group.RootPart.OwnerMask, group.RootPart.NextOwnerMask, group.RootPart.GroupMask, group.RootPart.EveryoneMask, // remoteClient.Name); @@ -1023,8 +1034,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess so.FromFolderID = item.Folder; -// Console.WriteLine("rootPart.OwnedID {0}, item.Owner {1}, item.CurrentPermissions {2:X}", -// rootPart.OwnerID, item.Owner, item.CurrentPermissions); +// m_log.DebugFormat( +// "[INVENTORY ACCESS MODULE]: rootPart.OwnedID {0}, item.Owner {1}, item.CurrentPermissions {2:X}", +// rootPart.OwnerID, item.Owner, item.CurrentPermissions); if ((rootPart.OwnerID != item.Owner) || (item.CurrentPermissions & 16) != 0 || @@ -1160,7 +1172,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (assetRequestItem.AssetID != requestID) { m_log.WarnFormat( - "[CLIENT]: {0} requested asset {1} from item {2} but this does not match item's asset {3}", + "[INVENTORY ACCESS MODULE]: {0} requested asset {1} from item {2} but this does not match item's asset {3}", Name, requestID, itemID, assetRequestItem.AssetID); return false; diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index e74310c849..21d8bd77a9 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -64,8 +64,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests IConfigSource config = new IniConfigSource(); config.AddConfig("Modules"); config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); - - m_scene = SceneHelpers.SetupScene(); + + SceneHelpers sceneHelpers = new SceneHelpers(); + m_scene = sceneHelpers.SetupScene(); SceneHelpers.SetupSceneModules(m_scene, config, m_iam); // Create user @@ -76,7 +77,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests AgentCircuitData acd = new AgentCircuitData(); acd.AgentID = m_userId; - m_tc = new TestClient(acd, m_scene); + m_tc = new TestClient(acd, m_scene); } [Test] diff --git a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs index 7f8271d401..e135c21b79 100644 --- a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs @@ -49,7 +49,16 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring public bool Enabled { get; private set; } private Scene m_scene; - private readonly List m_monitors = new List(); + + /// + /// These are monitors where we know the static details in advance. + /// + /// + /// Dynamic monitors also exist (we don't know any of the details of what stats we get back here) + /// but these are currently hardcoded. + /// + private readonly List m_staticMonitors = new List(); + private readonly List m_alerts = new List(); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -84,9 +93,18 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring public void DebugMonitors(string module, string[] args) { - foreach (IMonitor monitor in m_monitors) + foreach (IMonitor monitor in m_staticMonitors) { - m_log.Info("[MonitorModule]: " + m_scene.RegionInfo.RegionName + " reports " + monitor.GetFriendlyName() + " = " + monitor.GetFriendlyValue()); + m_log.InfoFormat( + "[MONITOR MODULE]: {0} reports {1} = {2}", + m_scene.RegionInfo.RegionName, monitor.GetFriendlyName(), monitor.GetFriendlyValue()); + } + + foreach (KeyValuePair tuple in m_scene.StatsReporter.GetExtraSimStats()) + { + m_log.InfoFormat( + "[MONITOR MODULE]: {0} reports {1} = {2}", + m_scene.RegionInfo.RegionName, tuple.Key, tuple.Value); } } @@ -106,11 +124,12 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring { string monID = (string) request["monitor"]; - foreach (IMonitor monitor in m_monitors) + foreach (IMonitor monitor in m_staticMonitors) { string elemName = monitor.ToString(); if (elemName.StartsWith(monitor.GetType().Namespace)) elemName = elemName.Substring(monitor.GetType().Namespace.Length + 1); + if (elemName == monID || monitor.ToString() == monID) { Hashtable ereply3 = new Hashtable(); @@ -123,6 +142,9 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring } } + // FIXME: Arguably this should also be done with dynamic monitors but I'm not sure what the above code + // is even doing. Why are we inspecting the type of the monitor??? + // No monitor with that name Hashtable ereply2 = new Hashtable(); @@ -134,12 +156,18 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring } string xml = ""; - foreach (IMonitor monitor in m_monitors) + foreach (IMonitor monitor in m_staticMonitors) { string elemName = monitor.GetName(); xml += "<" + elemName + ">" + monitor.GetValue().ToString() + ""; // m_log.DebugFormat("[MONITOR MODULE]: {0} = {1}", elemName, monitor.GetValue()); } + + foreach (KeyValuePair tuple in m_scene.StatsReporter.GetExtraSimStats()) + { + xml += "<" + tuple.Key + ">" + tuple.Value + ""; + } + xml += ""; Hashtable ereply = new Hashtable(); @@ -156,20 +184,20 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring if (!Enabled) return; - m_monitors.Add(new AgentCountMonitor(m_scene)); - m_monitors.Add(new ChildAgentCountMonitor(m_scene)); - m_monitors.Add(new GCMemoryMonitor()); - m_monitors.Add(new ObjectCountMonitor(m_scene)); - m_monitors.Add(new PhysicsFrameMonitor(m_scene)); - m_monitors.Add(new PhysicsUpdateFrameMonitor(m_scene)); - m_monitors.Add(new PWSMemoryMonitor()); - m_monitors.Add(new ThreadCountMonitor()); - m_monitors.Add(new TotalFrameMonitor(m_scene)); - m_monitors.Add(new EventFrameMonitor(m_scene)); - m_monitors.Add(new LandFrameMonitor(m_scene)); - m_monitors.Add(new LastFrameTimeMonitor(m_scene)); + m_staticMonitors.Add(new AgentCountMonitor(m_scene)); + m_staticMonitors.Add(new ChildAgentCountMonitor(m_scene)); + m_staticMonitors.Add(new GCMemoryMonitor()); + m_staticMonitors.Add(new ObjectCountMonitor(m_scene)); + m_staticMonitors.Add(new PhysicsFrameMonitor(m_scene)); + m_staticMonitors.Add(new PhysicsUpdateFrameMonitor(m_scene)); + m_staticMonitors.Add(new PWSMemoryMonitor()); + m_staticMonitors.Add(new ThreadCountMonitor()); + m_staticMonitors.Add(new TotalFrameMonitor(m_scene)); + m_staticMonitors.Add(new EventFrameMonitor(m_scene)); + m_staticMonitors.Add(new LandFrameMonitor(m_scene)); + m_staticMonitors.Add(new LastFrameTimeMonitor(m_scene)); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "TimeDilationMonitor", @@ -177,7 +205,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[0], m => m.GetValue().ToString())); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "SimFPSMonitor", @@ -185,7 +213,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[1], m => string.Format("{0}", m.GetValue()))); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "PhysicsFPSMonitor", @@ -193,7 +221,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[2], m => string.Format("{0}", m.GetValue()))); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "AgentUpdatesPerSecondMonitor", @@ -201,15 +229,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[3], m => string.Format("{0} per second", m.GetValue()))); - m_monitors.Add( - new GenericMonitor( - m_scene, - "ObjectUpdatesPerSecondMonitor", - "Object Updates", - m => m.Scene.StatsReporter.LastReportedObjectUpdates, - m => string.Format("{0} per second", m.GetValue()))); - - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "ActiveObjectCountMonitor", @@ -217,7 +237,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[7], m => string.Format("{0}", m.GetValue()))); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "ActiveScriptsMonitor", @@ -225,7 +245,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[19], m => string.Format("{0}", m.GetValue()))); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "ScriptEventsPerSecondMonitor", @@ -233,7 +253,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[20], m => string.Format("{0} per second", m.GetValue()))); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "InPacketsPerSecondMonitor", @@ -241,7 +261,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[13], m => string.Format("{0} per second", m.GetValue()))); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "OutPacketsPerSecondMonitor", @@ -249,7 +269,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[14], m => string.Format("{0} per second", m.GetValue()))); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "UnackedBytesMonitor", @@ -257,7 +277,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[15], m => string.Format("{0}", m.GetValue()))); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "PendingDownloadsMonitor", @@ -265,7 +285,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[17], m => string.Format("{0}", m.GetValue()))); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "PendingUploadsMonitor", @@ -273,7 +293,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[18], m => string.Format("{0}", m.GetValue()))); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "TotalFrameTimeMonitor", @@ -281,7 +301,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[8], m => string.Format("{0} ms", m.GetValue()))); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "NetFrameTimeMonitor", @@ -289,7 +309,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[9], m => string.Format("{0} ms", m.GetValue()))); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "PhysicsFrameTimeMonitor", @@ -297,7 +317,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[10], m => string.Format("{0} ms", m.GetValue()))); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "SimulationFrameTimeMonitor", @@ -305,7 +325,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[12], m => string.Format("{0} ms", m.GetValue()))); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "AgentFrameTimeMonitor", @@ -313,7 +333,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[16], m => string.Format("{0} ms", m.GetValue()))); - m_monitors.Add( + m_staticMonitors.Add( new GenericMonitor( m_scene, "ImagesFrameTimeMonitor", @@ -321,7 +341,15 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m => m.Scene.StatsReporter.LastReportedSimStats[11], m => string.Format("{0} ms", m.GetValue()))); - m_alerts.Add(new DeadlockAlert(m_monitors.Find(x => x is LastFrameTimeMonitor) as LastFrameTimeMonitor)); + m_staticMonitors.Add( + new GenericMonitor( + m_scene, + "SpareFrameTimeMonitor", + "Spare Frame Time", + m => m.Scene.StatsReporter.LastReportedSimStats[21], + m => string.Format("{0} ms", m.GetValue()))); + + m_alerts.Add(new DeadlockAlert(m_staticMonitors.Find(x => x is LastFrameTimeMonitor) as LastFrameTimeMonitor)); foreach (IAlert alert in m_alerts) { diff --git a/OpenSim/Region/CoreModules/LightShare/EnvironmentModule.cs b/OpenSim/Region/CoreModules/LightShare/EnvironmentModule.cs new file mode 100644 index 0000000000..1526886d7a --- /dev/null +++ b/OpenSim/Region/CoreModules/LightShare/EnvironmentModule.cs @@ -0,0 +1,224 @@ +/* + * 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.Reflection; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using log4net; +using Nini.Config; +using Mono.Addins; + +using Caps = OpenSim.Framework.Capabilities.Caps; + + +namespace OpenSim.Region.CoreModules.World.LightShare +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "EnvironmentModule")] + + public class EnvironmentModule : INonSharedRegionModule, IEnvironmentModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private Scene m_scene = null; + private UUID regionID = UUID.Zero; + private static bool Enabled = false; + + private static readonly string capsName = "EnvironmentSettings"; + private static readonly string capsBase = "/CAPS/0020/"; + + private LLSDEnvironmentSetResponse setResponse = null; + + #region INonSharedRegionModule + public void Initialise(IConfigSource source) + { + IConfig config = source.Configs["ClientStack.LindenCaps"]; + + if (null == config) + return; + + if (config.GetString("Cap_EnvironmentSettings", String.Empty) != "localhost") + { + m_log.InfoFormat("[{0}]: Module is disabled.", Name); + return; + } + + Enabled = true; + + m_log.InfoFormat("[{0}]: Module is enabled.", Name); + } + + public void Close() + { + } + + public string Name + { + get { return "EnvironmentModule"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void AddRegion(Scene scene) + { + if (!Enabled) + return; + + scene.RegisterModuleInterface(this); + m_scene = scene; + regionID = scene.RegionInfo.RegionID; + } + + public void RegionLoaded(Scene scene) + { + if (!Enabled) + return; + + setResponse = new LLSDEnvironmentSetResponse(); + scene.EventManager.OnRegisterCaps += OnRegisterCaps; + } + + public void RemoveRegion(Scene scene) + { + if (Enabled) + return; + + scene.EventManager.OnRegisterCaps -= OnRegisterCaps; + m_scene = null; + } + #endregion + + #region IEnvironmentModule + public void ResetEnvironmentSettings(UUID regionUUID) + { + if (!Enabled) + return; + + m_scene.SimulationDataService.RemoveRegionEnvironmentSettings(regionUUID); + } + #endregion + + #region Events + private void OnRegisterCaps(UUID agentID, Caps caps) + { +// m_log.DebugFormat("[{0}]: Register capability for agentID {1} in region {2}", +// Name, agentID, caps.RegionName); + + string capsPath = capsBase + UUID.Random(); + + // Get handler + caps.RegisterHandler( + capsName, + new RestStreamHandler( + "GET", + capsPath, + (request, path, param, httpRequest, httpResponse) + => GetEnvironmentSettings(request, path, param, agentID, caps), + capsName, + agentID.ToString())); + + // Set handler + caps.HttpListener.AddStreamHandler( + new RestStreamHandler( + "POST", + capsPath, + (request, path, param, httpRequest, httpResponse) + => SetEnvironmentSettings(request, path, param, agentID, caps), + capsName, + agentID.ToString())); + } + #endregion + + private string GetEnvironmentSettings(string request, string path, string param, + UUID agentID, Caps caps) + { +// m_log.DebugFormat("[{0}]: Environment GET handle for agentID {1} in region {2}", +// Name, agentID, caps.RegionName); + + string env = String.Empty; + + try + { + env = m_scene.SimulationDataService.LoadRegionEnvironmentSettings(regionID); + } + catch (Exception e) + { + m_log.ErrorFormat("[{0}]: Unable to load environment settings for region {1}, Exception: {2} - {3}", + Name, caps.RegionName, e.Message, e.StackTrace); + } + + if (String.IsNullOrEmpty(env)) + env = EnvironmentSettings.EmptySettings(UUID.Zero, regionID); + + return env; + } + + private string SetEnvironmentSettings(string request, string path, string param, + UUID agentID, Caps caps) + { + +// m_log.DebugFormat("[{0}]: Environment SET handle from agentID {1} in region {2}", +// Name, agentID, caps.RegionName); + + setResponse.regionID = regionID; + setResponse.success = false; + + if (!m_scene.Permissions.CanIssueEstateCommand(agentID, false)) + { + setResponse.fail_reason = "Insufficient estate permissions, settings has not been saved."; + return LLSDHelpers.SerialiseLLSDReply(setResponse); + } + + try + { + m_scene.SimulationDataService.StoreRegionEnvironmentSettings(regionID, request); + setResponse.success = true; + + m_log.InfoFormat("[{0}]: New Environment settings has been saved from agentID {1} in region {2}", + Name, agentID, caps.RegionName); + } + catch (Exception e) + { + m_log.ErrorFormat("[{0}]: Environment settings has not been saved for region {1}, Exception: {2} - {3}", + Name, caps.RegionName, e.Message, e.StackTrace); + + setResponse.success = false; + setResponse.fail_reason = String.Format("Environment Set for region {0} has failed, settings has not been saved.", caps.RegionName); + } + + return LLSDHelpers.SerialiseLLSDReply(setResponse); + } + } +} + diff --git a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml index dc6efed1e1..424e0ab384 100644 --- a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml +++ b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml @@ -79,7 +79,6 @@ \ \ - \ diff --git a/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs b/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs index 9255791c76..e91e8b9f45 100644 --- a/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs @@ -64,6 +64,8 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules private TimeSpan m_QueueTimeout = new TimeSpan(2, 0, 0); // 2 hours without llGetNextEmail drops the queue private string m_InterObjectHostname = "lsl.opensim.local"; + private int m_MaxEmailSize = 4096; // largest email allowed by default, as per lsl docs. + // Scenes by Region Handle private Dictionary m_Scenes = new Dictionary(); @@ -127,6 +129,7 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules SMTP_SERVER_PORT = SMTPConfig.GetInt("SMTP_SERVER_PORT", SMTP_SERVER_PORT); SMTP_SERVER_LOGIN = SMTPConfig.GetString("SMTP_SERVER_LOGIN", SMTP_SERVER_LOGIN); SMTP_SERVER_PASSWORD = SMTPConfig.GetString("SMTP_SERVER_PASSWORD", SMTP_SERVER_PASSWORD); + m_MaxEmailSize = SMTPConfig.GetInt("email_max_size", m_MaxEmailSize); } catch (Exception e) { @@ -176,18 +179,6 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules get { return true; } } - /// - /// Delay function using thread in seconds - /// - /// - private void DelayInSeconds(int delay) - { - delay = (int)((float)delay * 1000); - if (delay == 0) - return; - System.Threading.Thread.Sleep(delay); - } - private bool IsLocal(UUID objectID) { string unused; @@ -267,10 +258,9 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules m_log.Error("[EMAIL] REGEX Problem in EMail Address: "+address); return; } - //FIXME:Check if subject + body = 4096 Byte - if ((subject.Length + body.Length) > 1024) + if ((subject.Length + body.Length) > m_MaxEmailSize) { - m_log.Error("[EMAIL] subject + body > 1024 Byte"); + m_log.Error("[EMAIL] subject + body larger than limit of " + m_MaxEmailSize + " bytes"); return; } @@ -345,10 +335,6 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules // TODO FIX } } - - //DONE: Message as Second Life style - //20 second delay - AntiSpam System - for now only 10 seconds - DelayInSeconds(10); } /// diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index dcf49a7651..f4a89bd4f2 100644 --- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs @@ -77,7 +77,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp private Dictionary m_UrlMap = new Dictionary(); - + /// + /// Maximum number of external urls that can be set up by this module. + /// private int m_TotalUrls = 5000; private uint https_port = 0; @@ -85,6 +87,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp private IHttpServer m_HttpsServer = null; private string m_ExternalHostNameForLSL = ""; + public string ExternalHostNameForLSL + { + get { return m_ExternalHostNameForLSL; } + } public Type ReplaceableInterface { @@ -104,6 +110,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp { https_port = (uint) config.Configs["Network"].GetInt("https_port",0); } + + IConfig llFunctionsConfig = config.Configs["LL-Functions"]; + + if (llFunctionsConfig != null) + m_TotalUrls = llFunctionsConfig.GetInt("max_external_urls_per_simulator", m_TotalUrls); } public void PostInitialise() @@ -147,6 +158,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp public void Close() { } + public UUID RequestURL(IScriptModule engine, SceneObjectPart host, UUID itemID) { UUID urlcode = UUID.Random(); @@ -176,6 +188,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp args.Type = PollServiceEventArgs.EventType.LslHttp; m_HttpServer.AddPollServiceHTTPHandler(uri, args); + m_log.DebugFormat( + "[URL MODULE]: Set up incoming request url {0} for {1} in {2} {3}", + uri, itemID, host.Name, host.LocalId); + engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_GRANTED", url }); } @@ -218,6 +234,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp args.Type = PollServiceEventArgs.EventType.LslHttp; m_HttpsServer.AddPollServiceHTTPHandler(uri, args); + m_log.DebugFormat( + "[URL MODULE]: Set up incoming secure request url {0} for {1} in {2} {3}", + uri, itemID, host.Name, host.LocalId); + engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_GRANTED", url }); } @@ -241,6 +261,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp m_RequestMap.Remove(req); } +// m_log.DebugFormat( +// "[URL MODULE]: Releasing url {0} for {1} in {2}", +// url, data.itemID, data.hostID); + RemoveUrl(data); m_UrlMap.Remove(url); } diff --git a/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs index 40ffcb4a70..0003af2cc9 100644 --- a/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/XMLRPC/XMLRPCModule.cs @@ -131,11 +131,12 @@ namespace OpenSim.Region.CoreModules.Scripting.XMLRPC { // Start http server // Attach xmlrpc handlers - m_log.Info("[XML RPC MODULE]: " + - "Starting up XMLRPC Server on port " + m_remoteDataPort + " for llRemoteData commands."); - BaseHttpServer httpServer = new BaseHttpServer((uint) m_remoteDataPort); +// m_log.InfoFormat( +// "[XML RPC MODULE]: Starting up XMLRPC Server on port {0} for llRemoteData commands.", +// m_remoteDataPort); + + IHttpServer httpServer = MainServer.GetHttpServer((uint)m_remoteDataPort); httpServer.AddXmlRPCHandler("llRemoteData", XmlRpcRemoteData); - httpServer.Start(); } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs index 8df1c7b49c..a7dd0dd4dd 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Hypergrid/HypergridServiceInConnectorModule.cs @@ -122,7 +122,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Hypergrid ISimulationService simService = scene.RequestModuleInterface(); IFriendsSimConnector friendsConn = scene.RequestModuleInterface(); Object[] args = new Object[] { m_Config }; - IFriendsService friendsService = ServerUtils.LoadPlugin(m_LocalServiceDll, args); +// IFriendsService friendsService = ServerUtils.LoadPlugin(m_LocalServiceDll, args) + ServerUtils.LoadPlugin(m_LocalServiceDll, args); m_HypergridHandler = new GatekeeperServiceInConnector(m_Config, MainServer.Instance, simService); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs index c8f45f69b9..2f3c350c52 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Land/LandServiceInConnectorModule.cs @@ -75,7 +75,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Land if (!m_Enabled) return; - m_log.Info("[LAND IN CONNECTOR]: Starting..."); +// m_log.Info("[LAND IN CONNECTOR]: Starting..."); } public void Close() diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs index 3fd89b9b24..b544ab3be5 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsIn/Neighbour/NeighbourServiceInConnectorModule.cs @@ -74,7 +74,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsIn.Neighbour if (!m_Enabled) return; - m_log.Info("[NEIGHBOUR IN CONNECTOR]: Starting..."); +// m_log.Info("[NEIGHBOUR IN CONNECTOR]: Starting..."); } public void Close() diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs index 8395f8321d..008465fcc9 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/HGAssetBroker.cs @@ -149,7 +149,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset m_aScene = scene; - scene.RegisterModuleInterface(this); + m_aScene.RegisterModuleInterface(this); } public void RemoveRegion(Scene scene) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs index f0d21e67db..4470799f79 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Authorization/AuthorizationService.cs @@ -55,7 +55,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization MethodBase.GetCurrentMethod().DeclaringType); private IUserManagement m_UserManagement; - private IGridService m_GridService; +// private IGridService m_GridService; private Scene m_Scene; AccessFlags m_accessValue = AccessFlags.None; @@ -65,7 +65,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Authorization { m_Scene = scene; m_UserManagement = scene.RequestModuleInterface(); - m_GridService = scene.GridService; +// m_GridService = scene.GridService; if (config != null) { diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs index 540f33a9c0..3c6e38127f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs @@ -41,8 +41,7 @@ using OpenMetaverse; namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid { - public class LocalGridServicesConnector : - ISharedRegionModule, IGridService + public class LocalGridServicesConnector : ISharedRegionModule, IGridService { private static readonly ILog m_log = LogManager.GetLogger( @@ -51,7 +50,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid private IGridService m_GridService; private Dictionary m_LocalCache = new Dictionary(); - private bool m_Enabled = false; + private bool m_Enabled; public LocalGridServicesConnector() { @@ -59,7 +58,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid public LocalGridServicesConnector(IConfigSource source) { - m_log.Debug("[LOCAL GRID CONNECTOR]: LocalGridServicesConnector instantiated"); + m_log.Debug("[LOCAL GRID SERVICE CONNECTOR]: LocalGridServicesConnector instantiated directly."); InitialiseService(source); } @@ -84,8 +83,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid if (name == Name) { InitialiseService(source); - m_Enabled = true; - m_log.Info("[LOCAL GRID CONNECTOR]: Local grid connector enabled"); + m_log.Info("[LOCAL GRID SERVICE CONNECTOR]: Local grid connector enabled"); } } } @@ -95,7 +93,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid IConfig assetConfig = source.Configs["GridService"]; if (assetConfig == null) { - m_log.Error("[LOCAL GRID CONNECTOR]: GridService missing from OpenSim.ini"); + m_log.Error("[LOCAL GRID SERVICE CONNECTOR]: GridService missing from OpenSim.ini"); return; } @@ -104,7 +102,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid if (serviceDll == String.Empty) { - m_log.Error("[LOCAL GRID CONNECTOR]: No LocalServiceModule named in section GridService"); + m_log.Error("[LOCAL GRID SERVICE CONNECTOR]: No LocalServiceModule named in section GridService"); return; } @@ -115,16 +113,20 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid if (m_GridService == null) { - m_log.Error("[LOCAL GRID CONNECTOR]: Can't load grid service"); + m_log.Error("[LOCAL GRID SERVICE CONNECTOR]: Can't load grid service"); return; } + + m_Enabled = true; } public void PostInitialise() { + // FIXME: We will still add this command even if we aren't enabled since RemoteGridServiceConnector + // will have instantiated us directly. MainConsole.Instance.Commands.AddCommand("Regions", false, "show neighbours", "show neighbours", - "Shows the local regions' neighbours", NeighboursCommand); + "Shows the local regions' neighbours", HandleShowNeighboursCommand); } public void Close() @@ -133,17 +135,22 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid public void AddRegion(Scene scene) { - if (m_Enabled) - scene.RegisterModuleInterface(this); + if (!m_Enabled) + return; + + scene.RegisterModuleInterface(this); if (m_LocalCache.ContainsKey(scene.RegionInfo.RegionID)) - m_log.ErrorFormat("[LOCAL GRID CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!"); + m_log.ErrorFormat("[LOCAL GRID SERVICE CONNECTOR]: simulator seems to have more than one region with the same UUID. Please correct this!"); else m_LocalCache.Add(scene.RegionInfo.RegionID, new RegionCache(scene)); } public void RemoveRegion(Scene scene) { + if (!m_Enabled) + return; + m_LocalCache[scene.RegionInfo.RegionID].Clear(); m_LocalCache.Remove(scene.RegionInfo.RegionID); } @@ -232,7 +239,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid #endregion - public void NeighboursCommand(string module, string[] cmdparams) + public void HandleShowNeighboursCommand(string module, string[] cmdparams) { System.Text.StringBuilder caps = new System.Text.StringBuilder(); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs index 4cf62eca54..b0edce7a91 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/GridUser/ActivityDetector.cs @@ -79,29 +79,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.GridUser public void OnConnectionClose(IClientAPI client) { - if (client.IsLoggingOut) - { - object sp = null; - Vector3 position = new Vector3(128, 128, 0); - Vector3 lookat = new Vector3(0, 1, 0); - - if (client.Scene.TryGetScenePresence(client.AgentId, out sp)) - { - if (sp is ScenePresence) - { - if (((ScenePresence)sp).IsChildAgent) - return; - - position = ((ScenePresence)sp).AbsolutePosition; - lookat = ((ScenePresence)sp).Lookat; - } - } - -// m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); - m_GridUserService.LoggedOut(client.AgentId.ToString(), client.SessionId, client.Scene.RegionInfo.RegionID, position, lookat); - } + if (client.SceneAgent.IsChildAgent) + return; +// m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); + m_GridUserService.LoggedOut( + client.AgentId.ToString(), client.SessionId, client.Scene.RegionInfo.RegionID, + client.SceneAgent.AbsolutePosition, client.SceneAgent.Lookat); } - } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs index 3b862daa2f..6cd077a47a 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs @@ -149,9 +149,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage lock (m_scenes) m_scenes[scene.RegionInfo.RegionID] = scene; - scene.EventManager.OnPrimsLoaded += new EventManager.PrimsLoaded(EventManager_OnPrimsLoaded); + scene.EventManager.OnLoginsEnabled += OnLoginsEnabled; } + /// /// /// @@ -166,9 +167,17 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage #endregion ISharedRegionModule - void EventManager_OnPrimsLoaded(Scene s) + void OnLoginsEnabled(string regionName) { - UploadMapTile(s); + Scene scene = null; + foreach (Scene s in m_scenes.Values) + if (s.RegionInfo.RegionName == regionName) + { + scene = s; + break; + } + if (scene != null) + UploadMapTile(scene); } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs index 40cc536916..7a90686839 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs @@ -125,13 +125,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Neighbour uint x, y; Utils.LongToUInts(regionHandle, out x, out y); - m_log.DebugFormat("[NEIGHBOUR CONNECTOR]: HelloNeighbour from region {0} to region at {1}-{2}", - thisRegion.RegionName, x / Constants.RegionSize, y / Constants.RegionSize); - foreach (Scene s in m_Scenes) { if (s.RegionInfo.RegionHandle == regionHandle) { + m_log.DebugFormat("[LOCAL NEIGHBOUR SERVICE CONNECTOR]: HelloNeighbour from region {0} to neighbour {1} at {2}-{3}", + thisRegion.RegionName, s.Name, x / Constants.RegionSize, y / Constants.RegionSize); + //m_log.Debug("[NEIGHBOUR CONNECTOR]: Found region to SendHelloNeighbour"); return s.IncomingHelloNeighbour(thisRegion); } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs index ccfbf78a29..172bea10e3 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Presence/PresenceDetector.cs @@ -64,7 +64,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence scene.EventManager.OnNewClient -= OnNewClient; m_PresenceService.LogoutRegionAgents(scene.RegionInfo.RegionID); - } public void OnMakeRootAgent(ScenePresence sp) @@ -80,18 +79,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Presence public void OnConnectionClose(IClientAPI client) { - if (client.IsLoggingOut) + if (!client.SceneAgent.IsChildAgent) { - object sp = null; - if (client.Scene.TryGetScenePresence(client.AgentId, out sp)) - { - if (sp is ScenePresence) - { - if (((ScenePresence)sp).IsChildAgent) - return; - } - } - // m_log.DebugFormat("[PRESENCE DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); m_PresenceService.LogoutAgent(client.SessionId); } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index 6e75692942..6eb99ea710 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -26,6 +26,7 @@ */ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; using log4net; using Nini.Config; @@ -41,22 +42,20 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation public class LocalSimulationConnectorModule : ISharedRegionModule, ISimulationService { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - // Version of this service + + /// + /// Version of this service + /// private const string m_Version = "SIMULATION/0.1"; - private List m_sceneList = new List(); - - private IEntityTransferModule m_AgentTransferModule; - protected IEntityTransferModule AgentTransferModule - { - get - { - if (m_AgentTransferModule == null) - m_AgentTransferModule = m_sceneList[0].RequestModuleInterface(); - return m_AgentTransferModule; - } - } + /// + /// Map region ID to scene. + /// + private Dictionary m_scenes = new Dictionary(); + /// + /// Is this module enabled? + /// private bool m_ModuleEnabled = false; #region IRegionModule @@ -129,12 +128,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation /// public void RemoveScene(Scene scene) { - lock (m_sceneList) + lock (m_scenes) { - if (m_sceneList.Contains(scene)) - { - m_sceneList.Remove(scene); - } + if (m_scenes.ContainsKey(scene.RegionInfo.RegionID)) + m_scenes.Remove(scene.RegionInfo.RegionID); + else + m_log.WarnFormat( + "[LOCAL SIMULATION CONNECTOR]: Tried to remove region {0} but it was not present", + scene.RegionInfo.RegionName); } } @@ -144,13 +145,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation /// public void Init(Scene scene) { - if (!m_sceneList.Contains(scene)) + lock (m_scenes) { - lock (m_sceneList) - { - m_sceneList.Add(scene); - } - + if (!m_scenes.ContainsKey(scene.RegionInfo.RegionID)) + m_scenes[scene.RegionInfo.RegionID] = scene; + else + m_log.WarnFormat( + "[LOCAL SIMULATION CONNECTOR]: Tried to add region {0} but it is already present", + scene.RegionInfo.RegionName); } } @@ -158,15 +160,24 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation #region ISimulation - public IScene GetScene(ulong regionhandle) + public IScene GetScene(UUID regionId) { - foreach (Scene s in m_sceneList) + if (m_scenes.ContainsKey(regionId)) { - if (s.RegionInfo.RegionHandle == regionhandle) - return s; + return m_scenes[regionId]; + } + else + { + // FIXME: This was pre-existing behaviour but possibly not a good idea, since it hides an error rather + // than making it obvious and fixable. Need to see if the error message comes up in practice. + Scene s = m_scenes.Values.ToArray()[0]; + + m_log.ErrorFormat( + "[LOCAL SIMULATION CONNECTOR]: Region with id {0} not found. Returning {1} {2} instead", + regionId, s.RegionInfo.RegionName, s.RegionInfo.RegionID); + + return s; } - // ? weird. should not happen - return m_sceneList[0]; } public ISimulationService GetInnerService() @@ -187,13 +198,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return false; } - foreach (Scene s in m_sceneList) + if (m_scenes.ContainsKey(destination.RegionID)) { - if (s.RegionInfo.RegionHandle == destination.RegionHandle) - { - m_log.DebugFormat("[LOCAL SIMULATION CONNECTOR]: Found region {0} to send SendCreateChildAgent", destination.RegionName); - return s.NewUserConnection(aCircuit, teleportFlags, out reason); - } +// m_log.DebugFormat("[LOCAL SIMULATION CONNECTOR]: Found region {0} to send SendCreateChildAgent", destination.RegionName); + return m_scenes[destination.RegionID].NewUserConnection(aCircuit, teleportFlags, out reason); } reason = "Did not find region " + destination.RegionName; @@ -205,17 +213,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation if (destination == null) return false; - foreach (Scene s in m_sceneList) + if (m_scenes.ContainsKey(destination.RegionID)) { - if (s.RegionInfo.RegionHandle == destination.RegionHandle) - { - m_log.DebugFormat( - "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", - s.RegionInfo.RegionName, destination.RegionHandle); +// m_log.DebugFormat( +// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", +// s.RegionInfo.RegionName, destination.RegionHandle); - s.IncomingChildAgentDataUpdate(cAgentData); - return true; - } + return m_scenes[destination.RegionID].IncomingChildAgentDataUpdate(cAgentData); } // m_log.DebugFormat("[LOCAL COMMS]: Did not find region {0} for ChildAgentUpdate", regionHandle); @@ -231,11 +235,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation // simulator so when we receive the update we need to hand it to each of the // scenes; scenes each check to see if the is a scene presence for the avatar // note that we really don't need the GridRegion for this call - foreach (Scene s in m_sceneList) + foreach (Scene s in m_scenes.Values) { //m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate"); s.IncomingChildAgentDataUpdate(cAgentData); } + //m_log.Debug("[LOCAL COMMS]: region not found for ChildAgentUpdate"); return true; } @@ -247,14 +252,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation if (destination == null) return false; - foreach (Scene s in m_sceneList) + if (m_scenes.ContainsKey(destination.RegionID)) { - if (s.RegionInfo.RegionHandle == destination.RegionHandle) - { - //m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate"); - return s.IncomingRetrieveRootAgent(id, out agent); - } +// m_log.DebugFormat( +// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", +// s.RegionInfo.RegionName, destination.RegionHandle); + + return m_scenes[destination.RegionID].IncomingRetrieveRootAgent(id, out agent); } + //m_log.Debug("[LOCAL COMMS]: region not found for ChildAgentUpdate"); return false; } @@ -266,59 +272,49 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation if (destination == null) return false; - foreach (Scene s in m_sceneList) + if (m_scenes.ContainsKey(destination.RegionID)) { - if (s.RegionInfo.RegionID == destination.RegionID) - return s.QueryAccess(id, position, out reason); +// m_log.DebugFormat( +// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", +// s.RegionInfo.RegionName, destination.RegionHandle); + + return m_scenes[destination.RegionID].QueryAccess(id, position, out reason); } + + //m_log.Debug("[LOCAL COMMS]: region not found for QueryAccess"); return false; } - public bool ReleaseAgent(UUID origin, UUID id, string uri) + public bool ReleaseAgent(UUID originId, UUID agentId, string uri) { - foreach (Scene s in m_sceneList) + if (m_scenes.ContainsKey(originId)) { - if (s.RegionInfo.RegionID == origin) - { - m_log.Debug("[LOCAL COMMS]: Found region to SendReleaseAgent"); - AgentTransferModule.AgentArrivedAtDestination(id); - return true; -// return s.IncomingReleaseAgent(id); - } +// m_log.DebugFormat( +// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", +// s.RegionInfo.RegionName, destination.RegionHandle); + + m_scenes[originId].EntityTransferModule.AgentArrivedAtDestination(agentId); + return true; } + //m_log.Debug("[LOCAL COMMS]: region not found in SendReleaseAgent " + origin); return false; } + public bool CloseChildAgent(GridRegion destination, UUID id) + { + return CloseAgent(destination, id); + } + public bool CloseAgent(GridRegion destination, UUID id) { if (destination == null) return false; - foreach (Scene s in m_sceneList) + if (m_scenes.ContainsKey(destination.RegionID)) { - if (s.RegionInfo.RegionID == destination.RegionID) - { - //m_log.Debug("[LOCAL COMMS]: Found region to SendCloseAgent"); - return s.IncomingCloseAgent(id); - } - } - //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent"); - return false; - } - - public bool CloseChildAgent(GridRegion destination, UUID id) - { - if (destination == null) - return false; - - foreach (Scene s in m_sceneList) - { - if (s.RegionInfo.RegionID == destination.RegionID) - { - //m_log.Debug("[LOCAL COMMS]: Found region to SendCloseAgent"); - return s.IncomingCloseChildAgent(id); - } + Util.FireAndForget(delegate { m_scenes[destination.RegionID].IncomingCloseAgent(id); }); + return true; } //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent"); return false; @@ -333,62 +329,47 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation if (destination == null) return false; - foreach (Scene s in m_sceneList) + if (m_scenes.ContainsKey(destination.RegionID)) { - if (s.RegionInfo.RegionHandle == destination.RegionHandle) +// m_log.DebugFormat( +// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", +// s.RegionInfo.RegionName, destination.RegionHandle); + + Scene s = m_scenes[destination.RegionID]; + + if (isLocalCall) { - //m_log.Debug("[LOCAL COMMS]: Found region to SendCreateObject"); - if (isLocalCall) - { - // We need to make a local copy of the object - ISceneObject sogClone = sog.CloneForNewScene(); - sogClone.SetState(sog.GetStateSnapshot(), s); - return s.IncomingCreateObject(newPosition, sogClone); - } - else - { - // Use the object as it came through the wire - return s.IncomingCreateObject(newPosition, sog); - } + // We need to make a local copy of the object + ISceneObject sogClone = sog.CloneForNewScene(); + sogClone.SetState(sog.GetStateSnapshot(), s); + return s.IncomingCreateObject(newPosition, sogClone); + } + else + { + // Use the object as it came through the wire + return s.IncomingCreateObject(newPosition, sog); } } + return false; } - public bool CreateObject(GridRegion destination, UUID userID, UUID itemID) - { - if (destination == null) - return false; - - foreach (Scene s in m_sceneList) - { - if (s.RegionInfo.RegionHandle == destination.RegionHandle) - { - return s.IncomingCreateObject(userID, itemID); - } - } - return false; - } - - #endregion /* IInterregionComms */ #region Misc public bool IsLocalRegion(ulong regionhandle) { - foreach (Scene s in m_sceneList) + foreach (Scene s in m_scenes.Values) if (s.RegionInfo.RegionHandle == regionhandle) return true; + return false; } public bool IsLocalRegion(UUID id) { - foreach (Scene s in m_sceneList) - if (s.RegionInfo.RegionID == id) - return true; - return false; + return m_scenes.ContainsKey(id); } #endregion diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs index 4b70692e78..68be552eb3 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs @@ -151,9 +151,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation #region IInterregionComms - public IScene GetScene(ulong handle) + public IScene GetScene(UUID regionId) { - return m_localBackend.GetScene(handle); + return m_localBackend.GetScene(regionId); } public ISimulationService GetInnerService() @@ -226,13 +226,13 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return m_remoteConnector.RetrieveAgent(destination, id, out agent); return false; - } public bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string version, out string reason) { reason = "Communications failure"; version = "Unknown"; + if (destination == null) return false; @@ -245,7 +245,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return m_remoteConnector.QueryAccess(destination, id, position, out version, out reason); return false; - } public bool ReleaseAgent(UUID origin, UUID id, string uri) @@ -316,13 +315,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return false; } - public bool CreateObject(GridRegion destination, UUID userID, UUID itemID) - { - // Not Implemented - return false; - } - #endregion /* IInterregionComms */ - } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index 38db23924f..619550c1c5 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs @@ -41,6 +41,7 @@ using OpenSim.Framework.Serialization.External; using OpenSim.Region.CoreModules.World.Terrain; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.World.Archiver @@ -245,6 +246,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver // Reload serialized prims m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); + UUID oldTelehubUUID = m_scene.RegionInfo.RegionSettings.TelehubObject; + IRegionSerialiserModule serialiser = m_scene.RequestModuleInterface(); int sceneObjectsLoadedCount = 0; @@ -266,11 +269,21 @@ namespace OpenSim.Region.CoreModules.World.Archiver SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject); + bool isTelehub = (sceneObject.UUID == oldTelehubUUID); + // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned // on the same region server and multiple examples a single object archive to be imported // to the same scene (when this is possible). sceneObject.ResetIDs(); + if (isTelehub) + { + // Change the Telehub Object to the new UUID + m_scene.RegionInfo.RegionSettings.TelehubObject = sceneObject.UUID; + m_scene.RegionInfo.RegionSettings.Save(); + oldTelehubUUID = UUID.Zero; + } + // Try to retain the original creator/owner/lastowner if their uuid is present on this grid // or creator data is present. Otherwise, use the estate owner instead. foreach (SceneObjectPart part in sceneObject.Parts) @@ -347,7 +360,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver int ignoredObjects = serialisedSceneObjects.Count - sceneObjectsLoadedCount; if (ignoredObjects > 0) - m_log.WarnFormat("[ARCHIVER]: Ignored {0} scene objects that already existed in the scene", ignoredObjects); + m_log.WarnFormat("[ARCHIVER]: Ignored {0} scene objects that already existed in the scene", ignoredObjects); + + if (oldTelehubUUID != UUID.Zero) + { + m_log.WarnFormat("Telehub object not found: {0}", oldTelehubUUID); + m_scene.RegionInfo.RegionSettings.TelehubObject = UUID.Zero; + m_scene.RegionInfo.RegionSettings.ClearSpawnPoints(); + } } /// @@ -523,6 +543,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver currentRegionSettings.TerrainTexture4 = loadedRegionSettings.TerrainTexture4; currentRegionSettings.UseEstateSun = loadedRegionSettings.UseEstateSun; currentRegionSettings.WaterHeight = loadedRegionSettings.WaterHeight; + currentRegionSettings.TelehubObject = loadedRegionSettings.TelehubObject; + currentRegionSettings.ClearSpawnPoints(); + foreach (SpawnPoint sp in loadedRegionSettings.SpawnPoints()) + currentRegionSettings.AddSpawnPoint(sp); currentRegionSettings.Save(); diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs index 4d459bf2d6..4edaaca594 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs @@ -40,6 +40,9 @@ using OpenSim.Framework.Serialization; using OpenSim.Region.CoreModules.World.Terrain; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using Ionic.Zlib; +using GZipStream = Ionic.Zlib.GZipStream; +using CompressionMode = Ionic.Zlib.CompressionMode; namespace OpenSim.Region.CoreModules.World.Archiver { @@ -64,7 +67,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// Determine whether this archive will save assets. Default is true. /// public bool SaveAssets { get; set; } - + + protected ArchiverModule m_module; protected Scene m_scene; protected Stream m_saveStream; protected Guid m_requestId; @@ -72,17 +76,17 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// /// Constructor /// - /// + /// Calling module /// The path to which to save data. /// The id associated with this request /// /// If there was a problem opening a stream for the file specified by the savePath /// - public ArchiveWriteRequestPreparation(Scene scene, string savePath, Guid requestId) : this(scene, requestId) + public ArchiveWriteRequestPreparation(ArchiverModule module, string savePath, Guid requestId) : this(module, requestId) { try { - m_saveStream = new GZipStream(new FileStream(savePath, FileMode.Create), CompressionMode.Compress); + m_saveStream = new GZipStream(new FileStream(savePath, FileMode.Create), CompressionMode.Compress, CompressionLevel.BestCompression); } catch (EntryPointNotFoundException e) { @@ -96,17 +100,23 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// /// Constructor. /// - /// + /// Calling module /// The stream to which to save data. /// The id associated with this request - public ArchiveWriteRequestPreparation(Scene scene, Stream saveStream, Guid requestId) : this(scene, requestId) + public ArchiveWriteRequestPreparation(ArchiverModule module, Stream saveStream, Guid requestId) : this(module, requestId) { m_saveStream = saveStream; } - protected ArchiveWriteRequestPreparation(Scene scene, Guid requestId) + protected ArchiveWriteRequestPreparation(ArchiverModule module, Guid requestId) { - m_scene = scene; + m_module = module; + + // FIXME: This is only here for regression test purposes since they do not supply a module. Need to fix + // this. + if (m_module != null) + m_scene = m_module.Scene; + m_requestId = requestId; SaveAssets = true; @@ -297,10 +307,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver if (checkPermissions.Contains("T") && !canTransfer) partPermitted = false; + // If the user is the Creator of the object then it can always be included in the OAR + bool creator = (obj.CreatorID.Guid == user.Guid); + if (creator) + partPermitted = true; + //string name = (objGroup.PrimCount == 1) ? objGroup.Name : string.Format("{0} ({1}/{2})", obj.Name, primNumber, objGroup.PrimCount); - //m_log.DebugFormat("[ARCHIVER]: Object permissions: {0}: Base={1:X4}, Owner={2:X4}, Everyone={3:X4}, permissionClass={4}, checkPermissions={5}, canCopy={6}, canTransfer={7}, permitted={8}", + //m_log.DebugFormat("[ARCHIVER]: Object permissions: {0}: Base={1:X4}, Owner={2:X4}, Everyone={3:X4}, permissionClass={4}, checkPermissions={5}, canCopy={6}, canTransfer={7}, creator={8}, permitted={9}", // name, obj.BaseMask, obj.OwnerMask, obj.EveryoneMask, - // permissionClass, checkPermissions, canCopy, canTransfer, permitted); + // permissionClass, checkPermissions, canCopy, canTransfer, creator, partPermitted); if (!partPermitted) { @@ -320,7 +335,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// public string CreateControlFile(Dictionary options) { - int majorVersion = MAX_MAJOR_VERSION, minorVersion = 7; + int majorVersion = MAX_MAJOR_VERSION, minorVersion = 8; // // if (options.ContainsKey("version")) // { @@ -356,32 +371,66 @@ namespace OpenSim.Region.CoreModules.World.Archiver //if (majorVersion == 1) //{ // m_log.WarnFormat("[ARCHIVER]: Please be aware that version 1.0 OARs are not compatible with OpenSim 0.7.0.2 and earlier. Please use the --version=0 option if you want to produce a compatible OAR"); - //} + //} + + String s; - StringWriter sw = new StringWriter(); - XmlTextWriter xtw = new XmlTextWriter(sw); - xtw.Formatting = Formatting.Indented; - xtw.WriteStartDocument(); - xtw.WriteStartElement("archive"); - xtw.WriteAttributeString("major_version", majorVersion.ToString()); - xtw.WriteAttributeString("minor_version", minorVersion.ToString()); + using (StringWriter sw = new StringWriter()) + { + using (XmlTextWriter xtw = new XmlTextWriter(sw)) + { + xtw.Formatting = Formatting.Indented; + xtw.WriteStartDocument(); + xtw.WriteStartElement("archive"); + xtw.WriteAttributeString("major_version", majorVersion.ToString()); + xtw.WriteAttributeString("minor_version", minorVersion.ToString()); + + xtw.WriteStartElement("creation_info"); + DateTime now = DateTime.UtcNow; + TimeSpan t = now - new DateTime(1970, 1, 1); + xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString()); + xtw.WriteElementString("id", UUID.Random().ToString()); + xtw.WriteEndElement(); - xtw.WriteStartElement("creation_info"); - DateTime now = DateTime.UtcNow; - TimeSpan t = now - new DateTime(1970, 1, 1); - xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString()); - xtw.WriteElementString("id", UUID.Random().ToString()); - xtw.WriteEndElement(); + xtw.WriteStartElement("region_info"); - xtw.WriteElementString("assets_included", SaveAssets.ToString()); + bool isMegaregion; + Vector2 size; + IRegionCombinerModule rcMod = null; - xtw.WriteEndElement(); + // FIXME: This is only here for regression test purposes since they do not supply a module. Need to fix + // this, possibly by doing control file creation somewhere else. + if (m_module != null) + rcMod = m_module.RegionCombinerModule; - xtw.Flush(); - xtw.Close(); + if (rcMod != null) + isMegaregion = rcMod.IsRootForMegaregion(m_scene.RegionInfo.RegionID); + else + isMegaregion = false; - String s = sw.ToString(); - sw.Close(); + if (isMegaregion) + size = rcMod.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID); + else + size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize); + + xtw.WriteElementString("is_megaregion", isMegaregion.ToString()); + xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); + + xtw.WriteEndElement(); + + xtw.WriteElementString("assets_included", SaveAssets.ToString()); + + xtw.WriteEndElement(); + + xtw.Flush(); + } + + s = sw.ToString(); + } + +// if (m_scene != null) +// Console.WriteLine( +// "[ARCHIVE WRITE REQUEST PREPARATION]: Control file for {0} is: {1}", m_scene.RegionInfo.RegionName, s); return s; } diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs index f5a5a8d1be..bf3b1240a4 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs @@ -45,7 +45,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private Scene m_scene; + public Scene Scene { get; private set; } + public IRegionCombinerModule RegionCombinerModule { get; private set; } /// /// The file used to load and save an opensimulator archive if no filename has been specified @@ -70,13 +71,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver public void AddRegion(Scene scene) { - m_scene = scene; - m_scene.RegisterModuleInterface(this); + Scene = scene; + Scene.RegisterModuleInterface(this); //m_log.DebugFormat("[ARCHIVER]: Enabled for region {0}", scene.RegionInfo.RegionName); } public void RegionLoaded(Scene scene) { + RegionCombinerModule = scene.RequestModuleInterface(); } public void RemoveRegion(Scene scene) @@ -165,9 +167,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver public void ArchiveRegion(string savePath, Guid requestId, Dictionary options) { m_log.InfoFormat( - "[ARCHIVER]: Writing archive for region {0} to {1}", m_scene.RegionInfo.RegionName, savePath); + "[ARCHIVER]: Writing archive for region {0} to {1}", Scene.RegionInfo.RegionName, savePath); - new ArchiveWriteRequestPreparation(m_scene, savePath, requestId).ArchiveRegion(options); + new ArchiveWriteRequestPreparation(this, savePath, requestId).ArchiveRegion(options); } public void ArchiveRegion(Stream saveStream) @@ -182,7 +184,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver public void ArchiveRegion(Stream saveStream, Guid requestId, Dictionary options) { - new ArchiveWriteRequestPreparation(m_scene, saveStream, requestId).ArchiveRegion(options); + new ArchiveWriteRequestPreparation(this, saveStream, requestId).ArchiveRegion(options); } public void DearchiveRegion(string loadPath) @@ -193,9 +195,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver public void DearchiveRegion(string loadPath, bool merge, bool skipAssets, Guid requestId) { m_log.InfoFormat( - "[ARCHIVER]: Loading archive to region {0} from {1}", m_scene.RegionInfo.RegionName, loadPath); + "[ARCHIVER]: Loading archive to region {0} from {1}", Scene.RegionInfo.RegionName, loadPath); - new ArchiveReadRequest(m_scene, loadPath, merge, skipAssets, requestId).DearchiveRegion(); + new ArchiveReadRequest(Scene, loadPath, merge, skipAssets, requestId).DearchiveRegion(); } public void DearchiveRegion(Stream loadStream) @@ -205,7 +207,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver public void DearchiveRegion(Stream loadStream, bool merge, bool skipAssets, Guid requestId) { - new ArchiveReadRequest(m_scene, loadStream, merge, skipAssets, requestId).DearchiveRegion(); + new ArchiveReadRequest(Scene, loadStream, merge, skipAssets, requestId).DearchiveRegion(); } } } diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsDearchiver.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsDearchiver.cs index 2c040081e0..8c0ef880d4 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/AssetsDearchiver.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsDearchiver.cs @@ -46,8 +46,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding(); - /// /// Store for asset data we received before we get the metadata /// diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs index 63f1363729..5deaf5264b 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs @@ -68,7 +68,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests SerialiserModule serialiserModule = new SerialiserModule(); TerrainModule terrainModule = new TerrainModule(); - m_scene = SceneHelpers.SetupScene(); + m_scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(m_scene, m_archiverModule, serialiserModule, terrainModule); } @@ -102,9 +102,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests 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); +// Vector3 offsetPosition = new Vector3(5, 10, 15); - return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition) { Name = partName }; + return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, Vector3.Zero) { Name = partName }; } protected SceneObjectPart CreateSceneObjectPart2() @@ -291,6 +291,59 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests // TODO: Test presence of more files and contents of files. } + /// + /// Test loading an OpenSim Region Archive where the scene object parts are not ordered by link number (e.g. + /// 2 can come after 3). + /// + [Test] + public void TestLoadOarUnorderedParts() + { + TestHelpers.InMethod(); + + UUID ownerId = TestHelpers.ParseTail(0xaaaa); + + MemoryStream archiveWriteStream = new MemoryStream(); + TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); + + tar.WriteFile( + ArchiveConstants.CONTROL_FILE_PATH, + new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary())); + + SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11); + SceneObjectPart sop2 + = SceneHelpers.CreateSceneObjectPart("obj1-Part2", TestHelpers.ParseTail(0x12), ownerId); + SceneObjectPart sop3 + = SceneHelpers.CreateSceneObjectPart("obj1-Part3", TestHelpers.ParseTail(0x13), ownerId); + + // Add the parts so they will be written out in reverse order to the oar + sog1.AddPart(sop3); + sop3.LinkNum = 3; + sog1.AddPart(sop2); + sop2.LinkNum = 2; + + tar.WriteFile( + ArchiveConstants.CreateOarObjectPath(sog1.Name, sog1.UUID, sog1.AbsolutePosition), + SceneObjectSerializer.ToXml2Format(sog1)); + + tar.Close(); + + MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); + + lock (this) + { + m_scene.EventManager.OnOarFileLoaded += LoadCompleted; + m_archiverModule.DearchiveRegion(archiveReadStream); + } + + Assert.That(m_lastErrorMessage, Is.Null); + + SceneObjectPart part2 = m_scene.GetSceneObjectPart("obj1-Part2"); + Assert.That(part2.LinkNum, Is.EqualTo(2)); + + SceneObjectPart part3 = m_scene.GetSceneObjectPart("obj1-Part3"); + Assert.That(part3.LinkNum, Is.EqualTo(3)); + } + /// /// Test loading an OpenSim Region Archive. /// @@ -463,7 +516,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests SerialiserModule serialiserModule = new SerialiserModule(); TerrainModule terrainModule = new TerrainModule(); - TestScene scene2 = SceneHelpers.SetupScene(); + TestScene scene2 = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule); // Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is @@ -534,6 +587,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests rs.TerrainTexture4 = UUID.Parse("00000000-0000-0000-0000-000000000080"); rs.UseEstateSun = true; rs.WaterHeight = 23; + rs.TelehubObject = UUID.Parse("00000000-0000-0000-0000-111111111111"); + rs.AddSpawnPoint(SpawnPoint.Parse("1,-2,0.33")); tar.WriteFile(ArchiveConstants.SETTINGS_PATH + "region1.xml", RegionSettingsSerializer.Serialize(rs)); @@ -580,6 +635,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests Assert.That(loadedRs.TerrainTexture4, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000080"))); Assert.That(loadedRs.UseEstateSun, Is.True); Assert.That(loadedRs.WaterHeight, Is.EqualTo(23)); + Assert.AreEqual(UUID.Zero, loadedRs.TelehubObject); // because no object was found with the original UUID + Assert.AreEqual(0, loadedRs.SpawnPoints().Count); } /// @@ -607,7 +664,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests SerialiserModule serialiserModule = new SerialiserModule(); TerrainModule terrainModule = new TerrainModule(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(scene, archiverModule, serialiserModule, terrainModule); m_scene.AddNewSceneObject(new SceneObjectGroup(part2), false); diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs index d2bbea34b8..3b84d5728f 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementCommands.cs @@ -73,7 +73,7 @@ namespace OpenSim.Region.CoreModules.World.Estate "set terrain heights [] []", "Sets the terrain texture heights on corner # to /, if or are specified, it will only " + "set it on regions with a matching coordinate. Specify -1 in or to wildcard" + - " that coordinate. Corner # SW = 0, NW = 1, SE = 2, NE = 3.", + " that coordinate. Corner # SW = 0, NW = 1, SE = 2, NE = 3, all corners = -1.", consoleSetTerrainHeights); m_module.Scene.AddCommand( @@ -143,6 +143,16 @@ namespace OpenSim.Region.CoreModules.World.Estate switch (corner) { + case -1: + m_module.Scene.RegionInfo.RegionSettings.Elevation1SW = lowValue; + m_module.Scene.RegionInfo.RegionSettings.Elevation2SW = highValue; + m_module.Scene.RegionInfo.RegionSettings.Elevation1NW = lowValue; + m_module.Scene.RegionInfo.RegionSettings.Elevation2NW = highValue; + m_module.Scene.RegionInfo.RegionSettings.Elevation1SE = lowValue; + m_module.Scene.RegionInfo.RegionSettings.Elevation2SE = highValue; + m_module.Scene.RegionInfo.RegionSettings.Elevation1NE = lowValue; + m_module.Scene.RegionInfo.RegionSettings.Elevation2NE = highValue; + break; case 0: m_module.Scene.RegionInfo.RegionSettings.Elevation1SW = lowValue; m_module.Scene.RegionInfo.RegionSettings.Elevation2SW = highValue; diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index 97a2f4a6f7..fdef9d842f 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -170,12 +170,18 @@ namespace OpenSim.Region.CoreModules.World.Estate sendRegionInfoPacketToAll(); } - public void setEstateTerrainBaseTexture(IClientAPI remoteClient, int corner, UUID texture) + public void setEstateTerrainBaseTexture(int level, UUID texture) + { + setEstateTerrainBaseTexture(null, level, texture); + sendRegionHandshakeToAll(); + } + + public void setEstateTerrainBaseTexture(IClientAPI remoteClient, int level, UUID texture) { if (texture == UUID.Zero) return; - switch (corner) + switch (level) { case 0: Scene.RegionInfo.RegionSettings.TerrainTexture1 = texture; @@ -195,6 +201,11 @@ namespace OpenSim.Region.CoreModules.World.Estate sendRegionInfoPacketToAll(); } + public void setEstateTerrainTextureHeights(int corner, float lowValue, float highValue) + { + setEstateTerrainTextureHeights(null, corner, lowValue, highValue); + } + public void setEstateTerrainTextureHeights(IClientAPI client, int corner, float lowValue, float highValue) { switch (corner) @@ -993,7 +1004,7 @@ namespace OpenSim.Region.CoreModules.World.Estate { RegionHandshakeArgs args = new RegionHandshakeArgs(); - args.isEstateManager = Scene.RegionInfo.EstateSettings.IsEstateManager(remoteClient.AgentId); + args.isEstateManager = Scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(remoteClient.AgentId); if (Scene.RegionInfo.EstateSettings.EstateOwner != UUID.Zero && Scene.RegionInfo.EstateSettings.EstateOwner == remoteClient.AgentId) args.isEstateManager = true; diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index add1551ab4..51dcb67fb7 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -1395,21 +1395,26 @@ namespace OpenSim.Region.CoreModules.World.Land private void EventManagerOnRegisterCaps(UUID agentID, Caps caps) { string capsBase = "/CAPS/" + caps.CapsObjectPath; - caps.RegisterHandler("RemoteParcelRequest", - new RestStreamHandler("POST", capsBase + remoteParcelRequestPath, - delegate(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - return RemoteParcelRequest(request, path, param, agentID, caps); - })); + caps.RegisterHandler( + "RemoteParcelRequest", + new RestStreamHandler( + "POST", + capsBase + remoteParcelRequestPath, + (request, path, param, httpRequest, httpResponse) + => RemoteParcelRequest(request, path, param, agentID, caps), + "RemoteParcelRequest", + agentID.ToString())); + UUID parcelCapID = UUID.Random(); - caps.RegisterHandler("ParcelPropertiesUpdate", - new RestStreamHandler("POST", "/CAPS/" + parcelCapID, - delegate(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - return ProcessPropertiesUpdate(request, path, param, agentID, caps); - })); + caps.RegisterHandler( + "ParcelPropertiesUpdate", + new RestStreamHandler( + "POST", + "/CAPS/" + parcelCapID, + (request, path, param, httpRequest, httpResponse) + => ProcessPropertiesUpdate(request, path, param, agentID, caps), + "ParcelPropertiesUpdate", + agentID.ToString())); } private string ProcessPropertiesUpdate(string request, string path, string param, UUID agentID, Caps caps) { @@ -1774,7 +1779,7 @@ namespace OpenSim.Region.CoreModules.World.Land Vector3 pos = m_scene.GetNearestAllowedPosition(targetAvatar, land); - targetAvatar.TeleportWithMomentum(pos); + targetAvatar.TeleportWithMomentum(pos, null); targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname); parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected."); diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index 5974112b4b..4f067374d2 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs @@ -450,7 +450,10 @@ namespace OpenSim.Region.CoreModules.World.Land { bool isMember; if (m_groupMemberCache.TryGetValue(avatar, out isMember)) + { + m_groupMemberCache.Update(avatar, isMember, m_groupMemberCacheTimeout); return isMember; + } IGroupsModule groupsModule = m_scene.RequestModuleInterface(); if (groupsModule == null) @@ -487,7 +490,7 @@ namespace OpenSim.Region.CoreModules.World.Land if (m_scene.Permissions.IsAdministrator(avatar)) return false; - if (m_scene.RegionInfo.EstateSettings.IsEstateManager(avatar)) + if (m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(avatar)) return false; if (avatar == LandData.OwnerID) @@ -517,7 +520,7 @@ namespace OpenSim.Region.CoreModules.World.Land if (m_scene.Permissions.IsAdministrator(avatar)) return false; - if (m_scene.RegionInfo.EstateSettings.IsEstateManager(avatar)) + if (m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(avatar)) return false; if (avatar == LandData.OwnerID) @@ -1230,7 +1233,7 @@ namespace OpenSim.Region.CoreModules.World.Land if (land.LandData.LocalID == LandData.LocalID) { Vector3 pos = m_scene.GetNearestAllowedPosition(presence, land); - presence.TeleportWithMomentum(pos); + presence.TeleportWithMomentum(pos, null); presence.ControllingClient.SendAlertMessage("You have been ejected from this land"); } } diff --git a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs index 5122734c98..102b4d7550 100644 --- a/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/PrimCountModule.cs @@ -126,7 +126,6 @@ namespace OpenSim.Region.CoreModules.World.Land // m_log.DebugFormat( // "[PRIM COUNT MODULE]: Ignoring OnParcelPrimCountAdd() for {0} on {1} since count is tainted", // obj.Name, m_Scene.RegionInfo.RegionName); - } } diff --git a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs index e553ffa571..b5ee4d2cae 100644 --- a/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs +++ b/OpenSim/Region/CoreModules/World/Land/Tests/PrimCountModuleTests.cs @@ -64,7 +64,7 @@ namespace OpenSim.Region.CoreModules.World.Land.Tests { m_pcm = new PrimCountModule(); LandManagementModule lmm = new LandManagementModule(); - m_scene = SceneHelpers.SetupScene(); + m_scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(m_scene, lmm, m_pcm); int xParcelDivider = (int)Constants.RegionSize - 1; diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs index f86c7906a4..aa306c7db5 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs @@ -225,7 +225,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap int tc = 0; double[,] hm = whichScene.Heightmap.GetDoubles(); tc = Environment.TickCount; - m_log.Info("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile"); + m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile"); EntityBase[] objs = whichScene.GetEntities(); Dictionary z_sort = new Dictionary(); //SortedList z_sort = new SortedList(); @@ -541,7 +541,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap g.Dispose(); } // lock entities objs - m_log.Info("[MAPTILE]: Generating Maptile Step 2: Done in " + (Environment.TickCount - tc) + " ms"); + m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Done in " + (Environment.TickCount - tc) + " ms"); return mapbmp; } diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs index eb1a27f9ec..992bff3290 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs @@ -54,7 +54,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap public void TerrainToBitmap(Bitmap mapbmp) { int tc = Environment.TickCount; - m_log.Info("[MAPTILE]: Generating Maptile Step 1: Terrain"); + m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Terrain"); double[,] hm = m_scene.Heightmap.GetDoubles(); bool ShadowDebugContinue = true; @@ -238,7 +238,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap } } } - m_log.Info("[MAPTILE]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms"); + m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms"); } } } diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs index 1d2141e5e1..d13c2ef91d 100644 --- a/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs +++ b/OpenSim/Region/CoreModules/World/LegacyMap/TexturedMapTileRenderer.cs @@ -278,7 +278,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap public void TerrainToBitmap(Bitmap mapbmp) { int tc = Environment.TickCount; - m_log.Info("[MAPTILE]: Generating Maptile Step 1: Terrain"); + m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Terrain"); // These textures should be in the AssetCache anyway, as every client conneting to this // region needs them. Except on start, when the map is recreated (before anyone connected), @@ -412,7 +412,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap } } } - m_log.Info("[MAPTILE]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms"); + m_log.Debug("[MAPTILE]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms"); } } } diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs index 5239f50e78..601e81e587 100644 --- a/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs +++ b/OpenSim/Region/CoreModules/World/Media/Moap/MoapModule.cs @@ -145,7 +145,9 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap // Even though we're registering for POST we're going to get GETS and UPDATES too caps.RegisterHandler( - "ObjectMedia", new RestStreamHandler("POST", omCapUrl, HandleObjectMediaMessage)); + "ObjectMedia", + new RestStreamHandler( + "POST", omCapUrl, HandleObjectMediaMessage, "ObjectMedia", agentID.ToString())); } string omuCapUrl = "/CAPS/" + UUID.Random(); @@ -157,7 +159,9 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap // Even though we're registering for POST we're going to get GETS and UPDATES too caps.RegisterHandler( - "ObjectMediaNavigate", new RestStreamHandler("POST", omuCapUrl, HandleObjectMediaNavigateMessage)); + "ObjectMediaNavigate", + new RestStreamHandler( + "POST", omuCapUrl, HandleObjectMediaNavigateMessage, "ObjectMediaNavigate", agentID.ToString())); } } diff --git a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs index 4326606d5a..396095afe5 100644 --- a/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs +++ b/OpenSim/Region/CoreModules/World/Media/Moap/Tests/MoapTests.cs @@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests public void SetUp() { m_module = new MoapModule(); - m_scene = SceneHelpers.SetupScene(); + m_scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(m_scene, m_module); } @@ -63,7 +63,7 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene); + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; MediaEntry me = new MediaEntry(); m_module.SetMediaEntry(part, 1, me); @@ -88,7 +88,7 @@ namespace OpenSim.Region.CoreModules.World.Media.Moap.Tests string homeUrl = "opensimulator.org"; - SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene); + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; MediaEntry me = new MediaEntry() { HomeURL = homeUrl }; m_module.SetMediaEntry(part, 1, me); diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs index f5a5c92c4a..e5cd3e2133 100644 --- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs @@ -29,8 +29,10 @@ using System; using System.Collections.Generic; using System.Reflection; using System.Text; +using System.Text.RegularExpressions; using log4net; using Mono.Addins; +using NDesk.Options; using Nini.Config; using OpenMetaverse; using OpenSim.Framework; @@ -78,49 +80,64 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands m_scene = scene; m_console = MainConsole.Instance; - m_console.Commands.AddCommand("Regions", false, "delete object owner", - "delete object owner ", - "Delete a scene object by owner", HandleDeleteObject); - m_console.Commands.AddCommand("Regions", false, "delete object creator", - "delete object creator ", - "Delete a scene object by creator", HandleDeleteObject); - m_console.Commands.AddCommand("Regions", false, "delete object uuid", - "delete object uuid ", - "Delete a scene object by uuid", HandleDeleteObject); - m_console.Commands.AddCommand("Regions", false, "delete object name", - "delete object name ", - "Delete a scene object by name", HandleDeleteObject); - m_console.Commands.AddCommand("Regions", false, "delete object outside", - "delete object outside", - "Delete all scene objects outside region boundaries", HandleDeleteObject); + m_console.Commands.AddCommand( + "Objects", false, "delete object owner", + "delete object owner ", + "Delete a scene object by owner", HandleDeleteObject); m_console.Commands.AddCommand( - "Regions", + "Objects", false, "delete object creator", + "delete object creator ", + "Delete a scene object by creator", HandleDeleteObject); + + m_console.Commands.AddCommand( + "Objects", false, "delete object uuid", + "delete object uuid ", + "Delete a scene object by uuid", HandleDeleteObject); + + m_console.Commands.AddCommand( + "Objects", false, "delete object name", + "delete object name [--regex] ", + "Delete a scene object by name.", + "If --regex is specified then the name is treatead as a regular expression", + HandleDeleteObject); + + m_console.Commands.AddCommand( + "Objects", false, "delete object outside", + "delete object outside", + "Delete all scene objects outside region boundaries", HandleDeleteObject); + + m_console.Commands.AddCommand( + "Objects", false, "show object uuid", "show object uuid ", "Show details of a scene object with the given UUID", HandleShowObjectByUuid); m_console.Commands.AddCommand( - "Regions", + "Objects", false, "show object name", - "show object name ", - "Show details of scene objects with the given name", HandleShowObjectByName); + "show object name [--regex] ", + "Show details of scene objects with the given name.", + "If --regex is specified then the name is treatead as a regular expression", + HandleShowObjectByName); m_console.Commands.AddCommand( - "Regions", + "Objects", false, "show part uuid", "show part uuid ", "Show details of a scene object parts with the given UUID", HandleShowPartByUuid); m_console.Commands.AddCommand( - "Regions", + "Objects", false, "show part name", - "show part name ", - "Show details of scene object parts with the given name", HandleShowPartByName); + "show part name [--regex] ", + "Show details of scene object parts with the given name.", + "If --regex is specified then the name is treatead as a regular expression", + HandleShowPartByName); } public void RemoveRegion(Scene scene) @@ -165,22 +182,38 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands m_console.OutputFormat(sb.ToString()); } - private void HandleShowObjectByName(string module, string[] cmd) + private void HandleShowObjectByName(string module, string[] cmdparams) { if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) return; - if (cmd.Length < 4) + bool useRegex = false; + OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null ); + + List mainParams = options.Parse(cmdparams); + + if (mainParams.Count < 4) { - m_console.OutputFormat("Usage: show object name "); + m_console.OutputFormat("Usage: show object name [--regex] "); return; } - string name = cmd[3]; + string name = mainParams[3]; List sceneObjects = new List(); + Action searchAction; - m_scene.ForEachSOG(so => { if (so.Name == name) { sceneObjects.Add(so); }}); + if (useRegex) + { + Regex nameRegex = new Regex(name); + searchAction = so => { if (nameRegex.IsMatch(so.Name)) { sceneObjects.Add(so); }}; + } + else + { + searchAction = so => { if (so.Name == name) { sceneObjects.Add(so); }}; + } + + m_scene.ForEachSOG(searchAction); if (sceneObjects.Count == 0) { @@ -231,22 +264,39 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands m_console.OutputFormat(sb.ToString()); } - private void HandleShowPartByName(string module, string[] cmd) + private void HandleShowPartByName(string module, string[] cmdparams) { if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) return; - if (cmd.Length < 4) + bool useRegex = false; + OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null ); + + List mainParams = options.Parse(cmdparams); + + if (mainParams.Count < 4) { - m_console.OutputFormat("Usage: show part name "); + m_console.OutputFormat("Usage: show part name [--regex] "); return; } - string name = cmd[3]; + string name = mainParams[3]; List parts = new List(); - m_scene.ForEachSOG(so => so.ForEachPart(sop => { if (sop.Name == name) { parts.Add(sop); } })); + Action searchAction; + + if (useRegex) + { + Regex nameRegex = new Regex(name); + searchAction = so => so.ForEachPart(sop => { if (nameRegex.IsMatch(sop.Name)) { parts.Add(sop); } }); + } + else + { + searchAction = so => so.ForEachPart(sop => { if (sop.Name == name) { parts.Add(sop); } }); + } + + m_scene.ForEachSOG(searchAction); if (parts.Count == 0) { @@ -271,6 +321,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands sb.AppendFormat("Description: {0}\n", so.Description); sb.AppendFormat("Location: {0} @ {1}\n", so.AbsolutePosition, so.Scene.RegionInfo.RegionName); sb.AppendFormat("Parts: {0}\n", so.PrimCount); + sb.AppendFormat("Flags: {0}\n", so.RootPart.Flags); return sb; } @@ -282,7 +333,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands sb.AppendFormat("Location: {0} @ {1}\n", sop.AbsolutePosition, sop.ParentGroup.Scene.RegionInfo.RegionName); sb.AppendFormat("Parent: {0}", sop.IsRoot ? "Is Root\n" : string.Format("{0} {1}\n", sop.ParentGroup.Name, sop.ParentGroup.UUID)); - sb.AppendFormat("Parts: {0}\n", !sop.IsRoot ? "1" : sop.ParentGroup.PrimCount.ToString());; + sb.AppendFormat("Link number: {0}\n", sop.LinkNum); + sb.AppendFormat("Flags: {0}\n", sop.Flags); return sb; } @@ -306,96 +358,121 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands o = cmd[3]; } - List deletes = new List(); - + List deletes = null; UUID match; + bool requireConfirmation = true; switch (mode) { - case "owner": - if (!UUID.TryParse(o, out match)) - return; + case "owner": + if (!UUID.TryParse(o, out match)) + return; - m_scene.ForEachSOG(delegate (SceneObjectGroup g) - { - if (g.OwnerID == match && !g.IsAttachment) - deletes.Add(g); - }); + deletes = new List(); -// if (deletes.Count == 0) -// m_console.OutputFormat("No objects were found with owner {0}", match); - - break; - - case "creator": - if (!UUID.TryParse(o, out match)) - return; - - m_scene.ForEachSOG(delegate (SceneObjectGroup g) - { - if (g.RootPart.CreatorID == match && !g.IsAttachment) - deletes.Add(g); - }); - -// if (deletes.Count == 0) -// m_console.OutputFormat("No objects were found with creator {0}", match); - - break; - - case "uuid": - if (!UUID.TryParse(o, out match)) - return; - - m_scene.ForEachSOG(delegate (SceneObjectGroup g) - { - if (g.UUID == match && !g.IsAttachment) - deletes.Add(g); - }); - -// if (deletes.Count == 0) -// m_console.OutputFormat("No objects were found with uuid {0}", match); - - break; - - case "name": - m_scene.ForEachSOG(delegate (SceneObjectGroup g) - { - if (g.RootPart.Name == o && !g.IsAttachment) - deletes.Add(g); - }); - -// if (deletes.Count == 0) -// m_console.OutputFormat("No objects were found with name {0}", o); - - break; - - case "outside": - m_scene.ForEachSOG(delegate (SceneObjectGroup g) - { - SceneObjectPart rootPart = g.RootPart; - bool delete = false; - - if (rootPart.GroupPosition.Z < 0.0 || rootPart.GroupPosition.Z > 10000.0) + m_scene.ForEachSOG(delegate (SceneObjectGroup g) { - delete = true; - } - else - { - ILandObject parcel - = m_scene.LandChannel.GetLandObject(rootPart.GroupPosition.X, rootPart.GroupPosition.Y); + if (g.OwnerID == match && !g.IsAttachment) + deletes.Add(g); + }); + + // if (deletes.Count == 0) + // m_console.OutputFormat("No objects were found with owner {0}", match); + + break; + + case "creator": + if (!UUID.TryParse(o, out match)) + return; - if (parcel == null || parcel.LandData.Name == "NO LAND") + deletes = new List(); + + m_scene.ForEachSOG(delegate (SceneObjectGroup g) + { + if (g.RootPart.CreatorID == match && !g.IsAttachment) + deletes.Add(g); + }); + + // if (deletes.Count == 0) + // m_console.OutputFormat("No objects were found with creator {0}", match); + + break; + + case "uuid": + if (!UUID.TryParse(o, out match)) + return; + + requireConfirmation = false; + deletes = new List(); + + m_scene.ForEachSOG(delegate (SceneObjectGroup g) + { + if (g.UUID == match && !g.IsAttachment) + deletes.Add(g); + }); + + // if (deletes.Count == 0) + // m_console.OutputFormat("No objects were found with uuid {0}", match); + + break; + + case "name": + deletes = GetDeleteCandidatesByName(module, cmd); + break; + + case "outside": + deletes = new List(); + + m_scene.ForEachSOG(delegate (SceneObjectGroup g) + { + SceneObjectPart rootPart = g.RootPart; + bool delete = false; + + if (rootPart.GroupPosition.Z < 0.0 || rootPart.GroupPosition.Z > 10000.0) + { delete = true; - } + } + else + { + ILandObject parcel + = m_scene.LandChannel.GetLandObject(rootPart.GroupPosition.X, rootPart.GroupPosition.Y); + + if (parcel == null || parcel.LandData.Name == "NO LAND") + delete = true; + } + + if (delete && !g.IsAttachment && !deletes.Contains(g)) + deletes.Add(g); + }); + + if (deletes.Count == 0) + m_console.OutputFormat("No objects were found outside region bounds"); + + break; - if (delete && !g.IsAttachment && !deletes.Contains(g)) - deletes.Add(g); - }); + default: + m_console.OutputFormat("Unrecognized mode {0}", mode); + return; + } -// if (deletes.Count == 0) -// m_console.OutputFormat("No objects were found outside region bounds"); + if (deletes == null || deletes.Count <= 0) + return; - break; + if (requireConfirmation) + { + string response = MainConsole.Instance.CmdPrompt( + string.Format( + "Are you sure that you want to delete {0} objects from {1}", + deletes.Count, m_scene.RegionInfo.RegionName), + "n"); + + if (response.ToLower() != "y") + { + MainConsole.Instance.OutputFormat( + "Aborting delete of {0} objects from {1}", deletes.Count, m_scene.RegionInfo.RegionName); + + return; + } } m_console.OutputFormat("Deleting {0} objects in {1}", deletes.Count, m_scene.RegionInfo.RegionName); @@ -406,5 +483,44 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands m_scene.DeleteSceneObject(g, false); } } + + private List GetDeleteCandidatesByName(string module, string[] cmdparams) + { + if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) + return null; + + bool useRegex = false; + OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null ); + + List mainParams = options.Parse(cmdparams); + + if (mainParams.Count < 4) + { + m_console.OutputFormat("Usage: delete object name [--regex] "); + return null; + } + + string name = mainParams[3]; + + List sceneObjects = new List(); + Action searchAction; + + if (useRegex) + { + Regex nameRegex = new Regex(name); + searchAction = so => { if (nameRegex.IsMatch(so.Name)) { sceneObjects.Add(so); }}; + } + else + { + searchAction = so => { if (so.Name == name) { sceneObjects.Add(so); }}; + } + + m_scene.ForEachSOG(searchAction); + + if (sceneObjects.Count == 0) + m_console.OutputFormat("No objects with name {0} found in {1}", name, m_scene.RegionInfo.RegionName); + + return sceneObjects; + } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index 82ccaf8264..f3d38bc04f 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs @@ -166,6 +166,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions m_scene.Permissions.OnDeedParcel += CanDeedParcel; m_scene.Permissions.OnDeedObject += CanDeedObject; m_scene.Permissions.OnIsGod += IsGod; + m_scene.Permissions.OnIsGridGod += IsGridGod; m_scene.Permissions.OnIsAdministrator += IsAdministrator; m_scene.Permissions.OnDuplicateObject += CanDuplicateObject; m_scene.Permissions.OnDeleteObject += CanDeleteObject; //MAYBE FULLY IMPLEMENTED @@ -220,7 +221,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions "Force permissions on or off", HandleForcePermissions); - m_scene.AddCommand("Users", this, "debug permissions", + m_scene.AddCommand("Debug", this, "debug permissions", "debug permissions ", "Turn on permissions debugging", HandleDebugPermissions); @@ -347,12 +348,12 @@ namespace OpenSim.Region.CoreModules.World.Permissions m_friendsModule = m_scene.RequestModuleInterface(); if (m_friendsModule == null) - m_log.Warn("[PERMISSIONS]: Friends module not found, friend permissions will not work"); + m_log.Debug("[PERMISSIONS]: Friends module not found, friend permissions will not work"); m_groupsModule = m_scene.RequestModuleInterface(); if (m_groupsModule == null) - m_log.Warn("[PERMISSIONS]: Groups module not found, group permissions will not work"); + m_log.Debug("[PERMISSIONS]: Groups module not found, group permissions will not work"); m_moapModule = m_scene.RequestModuleInterface(); @@ -449,39 +450,49 @@ namespace OpenSim.Region.CoreModules.World.Permissions } /// - /// Is the given user an administrator (in other words, a god)? + /// Is the user regarded as an administrator? /// /// /// protected bool IsAdministrator(UUID user) { - if (user == UUID.Zero) return false; - - if (m_scene.RegionInfo.EstateSettings.EstateOwner != UUID.Zero) - { - if (m_scene.RegionInfo.EstateSettings.EstateOwner == user && m_RegionOwnerIsGod) - return true; - } + if (user == UUID.Zero) + return false; + + if (m_scene.RegionInfo.EstateSettings.EstateOwner == user && m_RegionOwnerIsGod) + return true; if (IsEstateManager(user) && m_RegionManagerIsGod) return true; + if (IsGridGod(user, null)) + return true; + + return false; + } + + /// + /// Is the given user a God throughout the grid (not just in the current scene)? + /// + /// The user + /// Unused, can be null + /// + protected bool IsGridGod(UUID user, Scene scene) + { + DebugPermissionInformation(MethodInfo.GetCurrentMethod().Name); + if (m_bypassPermissions) return m_bypassPermissionsValue; + + if (user == UUID.Zero) return false; + if (m_allowGridGods) { ScenePresence sp = m_scene.GetScenePresence(user); if (sp != null) - { - if (sp.UserLevel >= 200) - return true; - return false; - } + return (sp.UserLevel >= 200); UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, user); if (account != null) - { - if (account.UserLevel >= 200) - return true; - } + return (account.UserLevel >= 200); } return false; @@ -503,7 +514,7 @@ namespace OpenSim.Region.CoreModules.World.Permissions { if (user == UUID.Zero) return false; - return m_scene.RegionInfo.EstateSettings.IsEstateManager(user); + return m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(user); } #endregion diff --git a/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs b/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs new file mode 100644 index 0000000000..2838e0c356 --- /dev/null +++ b/OpenSim/Region/CoreModules/World/Region/RegionCommandsModule.cs @@ -0,0 +1,155 @@ +/* + * 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.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using log4net; +using Mono.Addins; +using NDesk.Options; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Statistics; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.CoreModules.World.Objects.Commands +{ + /// + /// A module that holds commands for manipulating objects in the scene. + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "RegionCommandsModule")] + public class RegionCommandsModule : INonSharedRegionModule + { + private Scene m_scene; + private ICommandConsole m_console; + + public string Name { get { return "Region Commands Module"; } } + + public Type ReplaceableInterface { get { return null; } } + + public void Initialise(IConfigSource source) + { +// m_log.DebugFormat("[REGION COMMANDS MODULE]: INITIALIZED MODULE"); + } + + public void PostInitialise() + { +// m_log.DebugFormat("[REGION COMMANDS MODULE]: POST INITIALIZED MODULE"); + } + + public void Close() + { +// m_log.DebugFormat("[REGION COMMANDS MODULE]: CLOSED MODULE"); + } + + public void AddRegion(Scene scene) + { +// m_log.DebugFormat("[REGION COMMANDS MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName); + + m_scene = scene; + m_console = MainConsole.Instance; + + m_console.Commands.AddCommand( + "Regions", false, "show scene", + "show scene", + "Show live scene information for the currently selected region.", HandleShowScene); + } + + public void RemoveRegion(Scene scene) + { +// m_log.DebugFormat("[REGION COMMANDS MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName); + } + + public void RegionLoaded(Scene scene) + { +// m_log.DebugFormat("[REGION COMMANDS MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); + } + + private void HandleShowScene(string module, string[] cmd) + { + if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene)) + return; + + SimStatsReporter r = m_scene.StatsReporter; + float[] stats = r.LastReportedSimStats; + + float timeDilation = stats[0]; + float simFps = stats[1]; + float physicsFps = stats[2]; + float agentUpdates = stats[3]; + float rootAgents = stats[4]; + float childAgents = stats[5]; + float totalPrims = stats[6]; + float activePrims = stats[7]; + float totalFrameTime = stats[8]; +// float netFrameTime = stats.StatsBlock[9].StatValue; // Ignored - not used by OpenSimulator + float physicsFrameTime = stats[10]; + float otherFrameTime = stats[11]; +// float imageFrameTime = stats.StatsBlock[12].StatValue; // Ignored + float inPacketsPerSecond = stats[13]; + float outPacketsPerSecond = stats[14]; + float unackedBytes = stats[15]; +// float agentFrameTime = stats.StatsBlock[16].StatValue; // Not really used + float pendingDownloads = stats[17]; + float pendingUploads = stats[18]; + float activeScripts = stats[19]; + float scriptLinesPerSecond = stats[20]; + + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("Scene statistics for {0}\n", m_scene.RegionInfo.RegionName); + + ConsoleDisplayList dispList = new ConsoleDisplayList(); + dispList.AddRow("Time Dilation", timeDilation); + dispList.AddRow("Sim FPS", simFps); + dispList.AddRow("Physics FPS", physicsFps); + dispList.AddRow("Avatars", rootAgents); + dispList.AddRow("Child agents", childAgents); + dispList.AddRow("Total prims", totalPrims); + dispList.AddRow("Scripts", activeScripts); + dispList.AddRow("Script lines processed per second", scriptLinesPerSecond); + dispList.AddRow("Physics enabled prims", activePrims); + dispList.AddRow("Total frame time", totalFrameTime); + dispList.AddRow("Physics frame time", physicsFrameTime); + dispList.AddRow("Other frame time", otherFrameTime); + dispList.AddRow("Agent Updates per second", agentUpdates); + dispList.AddRow("Packets processed from clients per second", inPacketsPerSecond); + dispList.AddRow("Packets sent to clients per second", outPacketsPerSecond); + dispList.AddRow("Bytes unacknowledged by clients", unackedBytes); + dispList.AddRow("Pending asset downloads to clients", pendingDownloads); + dispList.AddRow("Pending asset uploads from clients", pendingUploads); + + dispList.AddToStringBuilder(sb); + + MainConsole.Instance.Output(sb.ToString()); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs index d1d2020587..7825e3e7c7 100644 --- a/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs +++ b/OpenSim/Region/CoreModules/World/Serialiser/Tests/SerialiserTests.cs @@ -343,7 +343,7 @@ namespace OpenSim.Region.CoreModules.World.Serialiser.Tests public void Init() { m_serialiserModule = new SerialiserModule(); - m_scene = SceneHelpers.SetupScene(); + m_scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(m_scene, m_serialiserModule); } diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs index 93b10052fc..d768a1ac16 100644 --- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs +++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs @@ -78,11 +78,8 @@ namespace OpenSim.Region.CoreModules.World.Sound if (grp.IsAttachment) { - if (grp.AttachmentPoint > 30) // HUD - { - if (sp.ControllingClient.AgentId != grp.OwnerID) - return; - } + if (grp.HasPrivateAttachmentPoint && sp.ControllingClient.AgentId != grp.OwnerID) + return; if (sp.ControllingClient.AgentId == grp.OwnerID) dis = 0; diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs index da81dc16a9..d78ade5fa7 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs @@ -59,28 +59,32 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders /// A terrain channel generated from the image. public virtual ITerrainChannel LoadFile(string filename) { - return LoadBitmap(new Bitmap(filename)); + using (Bitmap b = new Bitmap(filename)) + return LoadBitmap(b); } public virtual ITerrainChannel LoadFile(string filename, int offsetX, int offsetY, int fileWidth, int fileHeight, int w, int h) { - Bitmap bitmap = new Bitmap(filename); - ITerrainChannel retval = new TerrainChannel(true); - - for (int x = 0; x < retval.Width; x++) + using (Bitmap bitmap = new Bitmap(filename)) { - for (int y = 0; y < retval.Height; y++) - { - retval[x, y] = bitmap.GetPixel(offsetX * retval.Width + x, (bitmap.Height - (retval.Height * (offsetY + 1))) + retval.Height - y - 1).GetBrightness() * 128; - } - } + ITerrainChannel retval = new TerrainChannel(true); - return retval; + for (int x = 0; x < retval.Width; x++) + { + for (int y = 0; y < retval.Height; y++) + { + retval[x, y] = bitmap.GetPixel(offsetX * retval.Width + x, (bitmap.Height - (retval.Height * (offsetY + 1))) + retval.Height - y - 1).GetBrightness() * 128; + } + } + + return retval; + } } public virtual ITerrainChannel LoadStream(Stream stream) { - return LoadBitmap(new Bitmap(stream)); + using (Bitmap b = new Bitmap(stream)) + return LoadBitmap(b); } protected virtual ITerrainChannel LoadBitmap(Bitmap bitmap) @@ -134,35 +138,53 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders // "Saving the image to the same file it was constructed from is not allowed and throws an exception." string tempName = Path.GetTempFileName(); - Bitmap entireBitmap = null; + Bitmap existingBitmap = null; Bitmap thisBitmap = null; - if (File.Exists(filename)) + Bitmap newBitmap = null; + + try { - File.Copy(filename, tempName, true); - entireBitmap = new Bitmap(tempName); - if (entireBitmap.Width != fileWidth * regionSizeX || entireBitmap.Height != fileHeight * regionSizeY) + if (File.Exists(filename)) { - // old file, let's overwrite it - entireBitmap = new Bitmap(fileWidth * regionSizeX, fileHeight * regionSizeY); + File.Copy(filename, tempName, true); + existingBitmap = new Bitmap(tempName); + if (existingBitmap.Width != fileWidth * regionSizeX || existingBitmap.Height != fileHeight * regionSizeY) + { + // old file, let's overwrite it + newBitmap = new Bitmap(fileWidth * regionSizeX, fileHeight * regionSizeY); + } + else + { + newBitmap = existingBitmap; + } } + else + { + newBitmap = 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++) + newBitmap.SetPixel(x + offsetX * regionSizeX, y + (fileHeight - 1 - offsetY) * regionSizeY, thisBitmap.GetPixel(x, y)); + + Save(newBitmap, filename); } - else + finally { - entireBitmap = new Bitmap(fileWidth * regionSizeX, fileHeight * regionSizeY); + if (existingBitmap != null) + existingBitmap.Dispose(); + + if (thisBitmap != null) + thisBitmap.Dispose(); + + if (newBitmap != null) + newBitmap.Dispose(); + + if (File.Exists(tempName)) + File.Delete(tempName); } - - 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) @@ -226,16 +248,21 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders /// A System.Drawing.Bitmap containing a coloured image protected static Bitmap CreateBitmapFromMap(ITerrainChannel map) { - Bitmap gradientmapLd = new Bitmap("defaultstripe.png"); + int pallete; + Bitmap bmp; + Color[] colours; - int pallete = gradientmapLd.Height; - - Bitmap bmp = new Bitmap(map.Width, map.Height); - Color[] colours = new Color[pallete]; - - for (int i = 0; i < pallete; i++) + using (Bitmap gradientmapLd = new Bitmap("defaultstripe.png")) { - colours[i] = gradientmapLd.GetPixel(0, i); + pallete = gradientmapLd.Height; + + bmp = new Bitmap(map.Width, map.Height); + colours = new Color[pallete]; + + for (int i = 0; i < pallete; i++) + { + colours[i] = gradientmapLd.GetPixel(0, i); + } } for (int y = 0; y < map.Height; y++) diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs index 699d67a440..9cc767a43e 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/JPEG.cs @@ -99,16 +99,21 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders private static Bitmap CreateBitmapFromMap(ITerrainChannel map) { - Bitmap gradientmapLd = new Bitmap("defaultstripe.png"); + int pallete; + Bitmap bmp; + Color[] colours; - int pallete = gradientmapLd.Height; - - Bitmap bmp = new Bitmap(map.Width, map.Height); - Color[] colours = new Color[pallete]; - - for (int i = 0; i < pallete; i++) + using (Bitmap gradientmapLd = new Bitmap("defaultstripe.png")) { - colours[i] = gradientmapLd.GetPixel(0, i); + pallete = gradientmapLd.Height; + + bmp = new Bitmap(map.Width, map.Height); + colours = new Color[pallete]; + + for (int i = 0; i < pallete; i++) + { + colours[i] = gradientmapLd.GetPixel(0, i); + } } for (int y = 0; y < map.Height; y++) diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/TIFF.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/TIFF.cs index 5d2f8937b4..b416b82a17 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/TIFF.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/TIFF.cs @@ -59,7 +59,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders } //Returns true if this extension is supported for terrain save-tile - public bool SupportsTileSave() + public override bool SupportsTileSave() { return false; } diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs index 1ebf91654c..b5c7d336cb 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs @@ -65,7 +65,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders bool eof = false; int fileXPoints = 0; - int fileYPoints = 0; +// int fileYPoints = 0; // Terragen file while (eof == false) @@ -75,7 +75,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders { case "SIZE": fileXPoints = bs.ReadInt16() + 1; - fileYPoints = fileXPoints; +// fileYPoints = fileXPoints; bs.ReadInt16(); break; case "XPTS": @@ -83,7 +83,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders bs.ReadInt16(); break; case "YPTS": - fileYPoints = bs.ReadInt16(); +// fileYPoints = bs.ReadInt16(); + bs.ReadInt16(); bs.ReadInt16(); break; case "ALTW": @@ -164,10 +165,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders bool eof = false; if (Encoding.ASCII.GetString(bs.ReadBytes(16)) == "TERRAGENTERRAIN ") { - - int fileWidth = w; - int fileHeight = h; - +// int fileWidth = w; +// int fileHeight = h; // Terragen file while (eof == false) @@ -176,17 +175,20 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders switch (tmp) { case "SIZE": - int sztmp = bs.ReadInt16() + 1; - fileWidth = sztmp; - fileHeight = sztmp; +// int sztmp = bs.ReadInt16() + 1; +// fileWidth = sztmp; +// fileHeight = sztmp; + bs.ReadInt16(); bs.ReadInt16(); break; case "XPTS": - fileWidth = bs.ReadInt16(); +// fileWidth = bs.ReadInt16(); + bs.ReadInt16(); bs.ReadInt16(); break; case "YPTS": - fileHeight = bs.ReadInt16(); +// fileHeight = bs.ReadInt16(); + bs.ReadInt16(); bs.ReadInt16(); break; case "ALTW": @@ -250,7 +252,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders if (horizontalScale < 0.01d) horizontalScale = 0.01d; - System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + Encoding enc = Encoding.ASCII; bs.Write(enc.GetBytes("TERRAGENTERRAIN ")); diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index e2bd7697fa..402b9fb0fe 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -724,6 +724,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain } if (shouldTaint) { + m_scene.EventManager.TriggerTerrainTainted(); m_tainted = true; } } @@ -1109,6 +1110,32 @@ namespace OpenSim.Region.CoreModules.World.Terrain CheckForTerrainUpdates(); } + private void InterfaceMinTerrain(Object[] args) + { + int x, y; + for (x = 0; x < m_channel.Width; x++) + { + for (y = 0; y < m_channel.Height; y++) + { + m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]); + } + } + CheckForTerrainUpdates(); + } + + private void InterfaceMaxTerrain(Object[] args) + { + int x, y; + for (x = 0; x < m_channel.Width; x++) + { + for (y = 0; y < m_channel.Height; y++) + { + m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]); + } + } + CheckForTerrainUpdates(); + } + private void InterfaceShowDebugStats(Object[] args) { double max = Double.MinValue; @@ -1249,6 +1276,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain rescaleCommand.AddArgument("min", "min terrain height after rescaling", "Double"); rescaleCommand.AddArgument("max", "max terrain height after rescaling", "Double"); + Command minCommand = new Command("min", CommandIntentions.COMMAND_HAZARDOUS, InterfaceMinTerrain, "Sets the minimum terrain height to the specified value."); + minCommand.AddArgument("min", "terrain height to use as minimum", "Double"); + + Command maxCommand = new Command("max", CommandIntentions.COMMAND_HAZARDOUS, InterfaceMaxTerrain, "Sets the maximum terrain height to the specified value."); + maxCommand.AddArgument("min", "terrain height to use as maximum", "Double"); + // Debug Command showDebugStatsCommand = @@ -1280,6 +1313,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_commander.RegisterCommand("effect", pluginRunCommand); m_commander.RegisterCommand("flip", flipCommand); m_commander.RegisterCommand("rescale", rescaleCommand); + m_commander.RegisterCommand("min", minCommand); + m_commander.RegisterCommand("max", maxCommand); // Add this to our scene so scripts can call these functions m_scene.RegisterModuleCommander(m_commander); diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs index 7bf675daff..df5ac92bb4 100644 --- a/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs +++ b/OpenSim/Region/CoreModules/World/Warp3DMap/TerrainSplat.cs @@ -84,218 +84,241 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap Debug.Assert(heightRanges.Length == 4); Bitmap[] detailTexture = new Bitmap[4]; + Bitmap output = null; + BitmapData outputData = null; - if (textureTerrain) + try { - // Swap empty terrain textureIDs with default IDs - for (int i = 0; i < textureIDs.Length; i++) + if (textureTerrain) { - if (textureIDs[i] == UUID.Zero) - textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i]; - } - - #region Texture Fetching - - if (assetService != null) - { - for (int i = 0; i < 4; i++) + // Swap empty terrain textureIDs with default IDs + for (int i = 0; i < textureIDs.Length; i++) { - AssetBase asset; - UUID cacheID = UUID.Combine(TERRAIN_CACHE_MAGIC, textureIDs[i]); - - // Try to fetch a cached copy of the decoded/resized version of this texture - asset = assetService.GetCached(cacheID.ToString()); - if (asset != null) + if (textureIDs[i] == UUID.Zero) + textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i]; + } + + #region Texture Fetching + + if (assetService != null) + { + for (int i = 0; i < 4; i++) { - try - { - using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data)) - detailTexture[i] = (Bitmap)Image.FromStream(stream); - } - catch (Exception ex) - { - m_log.Warn("Failed to decode cached terrain texture " + cacheID + - " (textureID: " + textureIDs[i] + "): " + ex.Message); - } - } - - if (detailTexture[i] == null) - { - // Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG - asset = assetService.Get(textureIDs[i].ToString()); + AssetBase asset; + UUID cacheID = UUID.Combine(TERRAIN_CACHE_MAGIC, textureIDs[i]); + + // Try to fetch a cached copy of the decoded/resized version of this texture + asset = assetService.GetCached(cacheID.ToString()); if (asset != null) { - try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); } +// m_log.DebugFormat( +// "[TERRAIN SPLAT]: Got asset service cached terrain texture {0} {1}", i, asset.ID); + + try + { + using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data)) + detailTexture[i] = (Bitmap)Image.FromStream(stream); + } catch (Exception ex) { - m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message); + m_log.Warn("Failed to decode cached terrain texture " + cacheID + + " (textureID: " + textureIDs[i] + "): " + ex.Message); } } - - if (detailTexture[i] != null) + + if (detailTexture[i] == null) { - Bitmap bitmap = detailTexture[i]; - - // Make sure this texture is the correct size, otherwise resize - if (bitmap.Width != 256 || bitmap.Height != 256) - bitmap = ImageUtils.ResizeImage(bitmap, 256, 256); - - // Save the decoded and resized texture to the cache - byte[] data; - using (System.IO.MemoryStream stream = new System.IO.MemoryStream()) + // Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG + asset = assetService.Get(textureIDs[i].ToString()); + if (asset != null) { - bitmap.Save(stream, ImageFormat.Png); - data = stream.ToArray(); +// m_log.DebugFormat( +// "[TERRAIN SPLAT]: Got cached original JPEG2000 terrain texture {0} {1}", i, asset.ID); + + try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); } + catch (Exception ex) + { + m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message); + } + } + + if (detailTexture[i] != null) + { + // Make sure this texture is the correct size, otherwise resize + if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256) + { + using (Bitmap origBitmap = detailTexture[i]) + { + detailTexture[i] = ImageUtils.ResizeImage(origBitmap, 256, 256); + } + } + + // Save the decoded and resized texture to the cache + byte[] data; + using (System.IO.MemoryStream stream = new System.IO.MemoryStream()) + { + detailTexture[i].Save(stream, ImageFormat.Png); + data = stream.ToArray(); + } + + // Cache a PNG copy of this terrain texture + AssetBase newAsset = new AssetBase + { + Data = data, + Description = "PNG", + Flags = AssetFlags.Collectable, + FullID = cacheID, + ID = cacheID.ToString(), + Local = true, + Name = String.Empty, + Temporary = true, + Type = (sbyte)AssetType.Unknown + }; + newAsset.Metadata.ContentType = "image/png"; + assetService.Store(newAsset); } - - // Cache a PNG copy of this terrain texture - AssetBase newAsset = new AssetBase - { - Data = data, - Description = "PNG", - Flags = AssetFlags.Collectable, - FullID = cacheID, - ID = cacheID.ToString(), - Local = true, - Name = String.Empty, - Temporary = true, - Type = (sbyte)AssetType.Unknown - }; - newAsset.Metadata.ContentType = "image/png"; - assetService.Store(newAsset); } } } + + #endregion Texture Fetching } - - #endregion Texture Fetching - } - - // Fill in any missing textures with a solid color - for (int i = 0; i < 4; i++) - { - if (detailTexture[i] == null) + + // Fill in any missing textures with a solid color + for (int i = 0; i < 4; i++) { - // Create a solid color texture for this layer - detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb); - using (Graphics gfx = Graphics.FromImage(detailTexture[i])) + if (detailTexture[i] == null) { - using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i])) - gfx.FillRectangle(brush, 0, 0, 256, 256); +// m_log.DebugFormat( +// "[TERRAIN SPLAT]: Generating solid colour for missing texture {0}", i); + + // Create a solid color texture for this layer + detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb); + using (Graphics gfx = Graphics.FromImage(detailTexture[i])) + { + using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i])) + gfx.FillRectangle(brush, 0, 0, 256, 256); + } } } - } - - #region Layer Map - - float[] layermap = new float[256 * 256]; - - for (int y = 0; y < 256; y++) - { - for (int x = 0; x < 256; x++) - { - float height = heightmap[y * 256 + x]; - - float pctX = (float)x / 255f; - float pctY = (float)y / 255f; - - // Use bilinear interpolation between the four corners of start height and - // height range to select the current values at this position - float startHeight = ImageUtils.Bilinear( - startHeights[0], - startHeights[2], - startHeights[1], - startHeights[3], - pctX, pctY); - startHeight = Utils.Clamp(startHeight, 0f, 255f); - - float heightRange = ImageUtils.Bilinear( - heightRanges[0], - heightRanges[2], - heightRanges[1], - heightRanges[3], - pctX, pctY); - heightRange = Utils.Clamp(heightRange, 0f, 255f); - - // Generate two frequencies of perlin noise based on our global position - // The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting - Vector3 vec = new Vector3 - ( - ((float)regionPosition.X + x) * 0.20319f, - ((float)regionPosition.Y + y) * 0.20319f, - height * 0.25f - ); - - float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f; - float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f; - float noise = (lowFreq + highFreq) * 2f; - - // Combine the current height, generated noise, start height, and height range parameters, then scale all of it - float layer = ((height + noise - startHeight) / heightRange) * 4f; - if (Single.IsNaN(layer)) layer = 0f; - layermap[y * 256 + x] = Utils.Clamp(layer, 0f, 3f); - } - } - - #endregion Layer Map - - #region Texture Compositing - - Bitmap output = new Bitmap(256, 256, PixelFormat.Format24bppRgb); - BitmapData outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); - - unsafe - { - // Get handles to all of the texture data arrays - BitmapData[] datas = new BitmapData[] - { - detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat), - detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat), - detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat), - detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat) - }; - - int[] comps = new int[] - { - (datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, - (datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, - (datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, - (datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3 - }; - + + #region Layer Map + + float[] layermap = new float[256 * 256]; + for (int y = 0; y < 256; y++) { for (int x = 0; x < 256; x++) { - float layer = layermap[y * 256 + x]; - - // Select two textures - int l0 = (int)Math.Floor(layer); - int l1 = Math.Min(l0 + 1, 3); - - byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0]; - byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1]; - byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3; - - float aB = *(ptrA + 0); - float aG = *(ptrA + 1); - float aR = *(ptrA + 2); - - float bB = *(ptrB + 0); - float bG = *(ptrB + 1); - float bR = *(ptrB + 2); - - float layerDiff = layer - l0; - - // Interpolate between the two selected textures - *(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB)); - *(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG)); - *(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR)); + float height = heightmap[y * 256 + x]; + + float pctX = (float)x / 255f; + float pctY = (float)y / 255f; + + // Use bilinear interpolation between the four corners of start height and + // height range to select the current values at this position + float startHeight = ImageUtils.Bilinear( + startHeights[0], + startHeights[2], + startHeights[1], + startHeights[3], + pctX, pctY); + startHeight = Utils.Clamp(startHeight, 0f, 255f); + + float heightRange = ImageUtils.Bilinear( + heightRanges[0], + heightRanges[2], + heightRanges[1], + heightRanges[3], + pctX, pctY); + heightRange = Utils.Clamp(heightRange, 0f, 255f); + + // Generate two frequencies of perlin noise based on our global position + // The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting + Vector3 vec = new Vector3 + ( + ((float)regionPosition.X + x) * 0.20319f, + ((float)regionPosition.Y + y) * 0.20319f, + height * 0.25f + ); + + float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f; + float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f; + float noise = (lowFreq + highFreq) * 2f; + + // Combine the current height, generated noise, start height, and height range parameters, then scale all of it + float layer = ((height + noise - startHeight) / heightRange) * 4f; + if (Single.IsNaN(layer)) layer = 0f; + layermap[y * 256 + x] = Utils.Clamp(layer, 0f, 3f); } } - + + #endregion Layer Map + + #region Texture Compositing + + output = new Bitmap(256, 256, PixelFormat.Format24bppRgb); + outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); + + unsafe + { + // Get handles to all of the texture data arrays + BitmapData[] datas = new BitmapData[] + { + detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat), + detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat), + detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat), + detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat) + }; + + int[] comps = new int[] + { + (datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, + (datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, + (datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3, + (datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3 + }; + + for (int y = 0; y < 256; y++) + { + for (int x = 0; x < 256; x++) + { + float layer = layermap[y * 256 + x]; + + // Select two textures + int l0 = (int)Math.Floor(layer); + int l1 = Math.Min(l0 + 1, 3); + + byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0]; + byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1]; + byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3; + + float aB = *(ptrA + 0); + float aG = *(ptrA + 1); + float aR = *(ptrA + 2); + + float bB = *(ptrB + 0); + float bG = *(ptrB + 1); + float bR = *(ptrB + 2); + + float layerDiff = layer - l0; + + // Interpolate between the two selected textures + *(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB)); + *(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG)); + *(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR)); + } + } + + for (int i = 0; i < 4; i++) + detailTexture[i].UnlockBits(datas[i]); + } + } + finally + { for (int i = 0; i < 4; i++) - detailTexture[i].UnlockBits(datas[i]); + if (detailTexture[i] != null) + detailTexture[i].Dispose(); } output.UnlockBits(outputData); diff --git a/OpenSim/Region/CoreModules/World/Warp3DMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs similarity index 89% rename from OpenSim/Region/CoreModules/World/Warp3DMap/MapImageModule.cs rename to OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs index e6f2855b25..3c48d07bb6 100644 --- a/OpenSim/Region/CoreModules/World/Warp3DMap/MapImageModule.cs +++ b/OpenSim/Region/CoreModules/World/Warp3DMap/Warp3DImageModule.cs @@ -54,8 +54,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap private static readonly UUID TEXTURE_METADATA_MAGIC = new UUID("802dc0e0-f080-4931-8b57-d1be8611c4f3"); private static readonly Color4 WATER_COLOR = new Color4(29, 72, 96, 216); - private static readonly ILog m_log = - LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private Scene m_scene; private IRendering m_primMesher; @@ -164,7 +163,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap } catch { - m_log.Warn("[MAPTILE]: Failed to load StartupConfig"); + m_log.Warn("[WARP 3D IMAGE MODULE]: Failed to load StartupConfig"); } m_colors.Clear(); @@ -218,7 +217,10 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap Bitmap bitmap = renderer.Scene.getImage(); if (m_useAntiAliasing) - bitmap = ImageUtils.ResizeImage(bitmap, viewport.Width, viewport.Height); + { + using (Bitmap origBitmap = bitmap) + bitmap = ImageUtils.ResizeImage(origBitmap, viewport.Width, viewport.Height); + } return bitmap; } @@ -233,7 +235,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap catch (Exception e) { // JPEG2000 encoder failed - m_log.Error("[MAPTILE]: Failed generating terrain map: " + e); + m_log.Error("[WARP 3D IMAGE MODULE]: Failed generating terrain map: ", e); } return null; @@ -332,8 +334,17 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap uint globalX, globalY; Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out globalX, out globalY); - Bitmap image = TerrainSplat.Splat(heightmap, textureIDs, startHeights, heightRanges, new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain); - warp_Texture texture = new warp_Texture(image); + warp_Texture texture; + + using ( + Bitmap image + = TerrainSplat.Splat( + heightmap, textureIDs, startHeights, heightRanges, + new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain)) + { + texture = new warp_Texture(image); + } + warp_Material material = new warp_Material(texture); material.setReflectivity(50); renderer.Scene.addMaterial("TerrainColor", material); @@ -560,42 +571,46 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap { try { - Bitmap bitmap = (Bitmap)J2kImage.FromStream(stream); - width = bitmap.Width; - height = bitmap.Height; + int pixelBytes; - BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bitmap.PixelFormat); - int pixelBytes = (bitmap.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4; - - // Sum up the individual channels - unsafe + using (Bitmap bitmap = (Bitmap)J2kImage.FromStream(stream)) { - if (pixelBytes == 4) + width = bitmap.Width; + height = bitmap.Height; + + BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, bitmap.PixelFormat); + pixelBytes = (bitmap.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4; + + // Sum up the individual channels + unsafe { - for (int y = 0; y < height; y++) + if (pixelBytes == 4) { - byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride); - - for (int x = 0; x < width; x++) + for (int y = 0; y < height; y++) { - b += row[x * pixelBytes + 0]; - g += row[x * pixelBytes + 1]; - r += row[x * pixelBytes + 2]; - a += row[x * pixelBytes + 3]; + byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride); + + for (int x = 0; x < width; x++) + { + b += row[x * pixelBytes + 0]; + g += row[x * pixelBytes + 1]; + r += row[x * pixelBytes + 2]; + a += row[x * pixelBytes + 3]; + } } } - } - else - { - for (int y = 0; y < height; y++) + else { - byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride); - - for (int x = 0; x < width; x++) + for (int y = 0; y < height; y++) { - b += row[x * pixelBytes + 0]; - g += row[x * pixelBytes + 1]; - r += row[x * pixelBytes + 2]; + byte* row = (byte*)bitmapData.Scan0 + (y * bitmapData.Stride); + + for (int x = 0; x < width; x++) + { + b += row[x * pixelBytes + 0]; + g += row[x * pixelBytes + 1]; + r += row[x * pixelBytes + 2]; + } } } } @@ -617,7 +632,10 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap } catch (Exception ex) { - m_log.WarnFormat("[MAPTILE]: Error decoding JPEG2000 texture {0} ({1} bytes): {2}", textureID, j2kData.Length, ex.Message); + m_log.WarnFormat( + "[WARP 3D IMAGE MODULE]: Error decoding JPEG2000 texture {0} ({1} bytes): {2}", + textureID, j2kData.Length, ex.Message); + width = 0; height = 0; return new Color4(0.5f, 0.5f, 0.5f, 1.0f); diff --git a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs index 1dedcce893..309856f542 100644 --- a/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs +++ b/OpenSim/Region/CoreModules/World/WorldMap/WorldMapModule.cs @@ -193,14 +193,15 @@ namespace OpenSim.Region.CoreModules.World.WorldMap { //m_log.DebugFormat("[WORLD MAP]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps); string capsBase = "/CAPS/" + caps.CapsObjectPath; - caps.RegisterHandler("MapLayer", - new RestStreamHandler("POST", capsBase + m_mapLayerPath, - delegate(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - return MapLayerRequest(request, path, param, - agentID, caps); - })); + caps.RegisterHandler( + "MapLayer", + new RestStreamHandler( + "POST", + capsBase + m_mapLayerPath, + (request, path, param, httpRequest, httpResponse) + => MapLayerRequest(request, path, param, agentID, caps), + "MapLayer", + agentID.ToString())); } /// @@ -675,7 +676,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap { if (Environment.TickCount > (m_blacklistedregions[regionhandle] + blacklistTimeout)) { - m_log.DebugFormat("[WORLDMAP]: Unblock blacklisted region {0}", regionhandle); + m_log.DebugFormat("[WORLD MAP]: Unblock blacklisted region {0}", regionhandle); m_blacklistedregions.Remove(regionhandle); } @@ -730,7 +731,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap { if (Environment.TickCount > (m_blacklistedurls[httpserver] + blacklistTimeout)) { - m_log.DebugFormat("[WORLDMAP]: Unblock blacklisted URL {0}", httpserver); + m_log.DebugFormat("[WORLD MAP]: Unblock blacklisted URL {0}", httpserver); m_blacklistedurls.Remove(httpserver); } @@ -1427,14 +1428,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap if (terrain == null) return; + m_log.DebugFormat("[WORLD MAP]: Generating map image for {0}", m_scene.RegionInfo.RegionName); + byte[] data = terrain.WriteJpeg2000Image(); if (data == null) return; byte[] overlay = GenerateOverlay(); - m_log.Debug("[WORLDMAP]: STORING MAPTILE IMAGE"); - UUID terrainImageID = UUID.Random(); UUID parcelImageID = UUID.Zero; @@ -1449,7 +1450,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap asset.Flags = AssetFlags.Maptile; // Store the new one - m_log.DebugFormat("[WORLDMAP]: Storing map tile {0}", asset.ID); + m_log.DebugFormat("[WORLD MAP]: Storing map tile {0} for {1}", asset.ID, m_scene.RegionInfo.RegionName); + m_scene.AssetService.Store(asset); if (overlay != null) diff --git a/OpenSim/Region/DataSnapshot/DataRequestHandler.cs b/OpenSim/Region/DataSnapshot/DataRequestHandler.cs index 2f2b3e6743..32e93b4057 100644 --- a/OpenSim/Region/DataSnapshot/DataRequestHandler.cs +++ b/OpenSim/Region/DataSnapshot/DataRequestHandler.cs @@ -42,13 +42,13 @@ namespace OpenSim.Region.DataSnapshot { public class DataRequestHandler { - private Scene m_scene = null; +// private Scene m_scene = null; private DataSnapshotManager m_externalData = null; private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); public DataRequestHandler(Scene scene, DataSnapshotManager externalData) { - m_scene = scene; +// m_scene = scene; m_externalData = externalData; //Register HTTP handler diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index 0516cb134a..410eda05fa 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -36,6 +36,20 @@ namespace OpenSim.Region.Framework.Interfaces { public interface IAttachmentsModule { + /// + /// Copy attachment data from a ScenePresence into the AgentData structure for transmission to another simulator + /// + /// + /// + void CopyAttachments(IScenePresence sp, AgentData ad); + + /// + /// Copy attachment data from an AgentData structure into a ScenePresence. + /// + /// + /// + void CopyAttachments(AgentData ad, IScenePresence sp); + /// /// RezAttachments. This should only be called upon login on the first region. /// Attachment rezzings on crossings and TPs are done in a different way. @@ -44,10 +58,15 @@ namespace OpenSim.Region.Framework.Interfaces void RezAttachments(IScenePresence sp); /// - /// Save the attachments that have change on this presence. + /// Derez the attachements for a scene presence that is closing. /// - /// - void SaveChangedAttachments(IScenePresence sp, bool saveAllScripted); + /// + /// Attachment changes are saved. + /// + /// The presence closing + /// Save changed attachments. + /// Save attachments with scripts even if they haven't changed. + void DeRezAttachments(IScenePresence sp, bool saveChanged, bool saveAllScripted); /// /// Delete all the presence's attachments from the scene @@ -78,7 +97,7 @@ namespace OpenSim.Region.Framework.Interfaces // Same as above, but also load script states from a separate doc ISceneEntity RezSingleAttachmentFromInventory( - IScenePresence presence, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc); + IScenePresence presence, UUID itemID, uint AttachmentPt, XmlDocument doc); /// /// Rez multiple attachments from a user's inventory @@ -95,11 +114,11 @@ namespace OpenSim.Region.Framework.Interfaces void DetachSingleAttachmentToGround(IScenePresence sp, uint objectLocalID); /// - /// Detach the given item so that it remains in the user's inventory. + /// Detach the given attachment so that it remains in the user's inventory. /// /// /param> - /// - void DetachSingleAttachmentToInv(IScenePresence sp, UUID itemID); + /// The attachment to detach. + void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup grp); /// Update the position of an attachment. /// diff --git a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs index 32f4eeaf0a..4274cbe8bd 100644 --- a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs +++ b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs @@ -81,13 +81,18 @@ namespace OpenSim.Region.Framework.Interfaces /// /// Start all the scripts contained in this entity's inventory /// - void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource); + /// + /// + /// + /// + /// Number of scripts started. + int CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource); ArrayList GetScriptErrors(UUID itemID); void ResumeScripts(); /// - /// Stop all the scripts in this entity. + /// Stop and remove all the scripts in this entity from the scene. /// /// /// Should be true if these scripts are being removed because the scene @@ -95,6 +100,11 @@ namespace OpenSim.Region.Framework.Interfaces /// void RemoveScriptInstances(bool sceneObjectBeingDeleted); + /// + /// Stop all the scripts in this entity. + /// + void StopScriptInstances(); + /// /// Start a script which is in this entity's inventory. /// @@ -102,7 +112,11 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// - void CreateScriptInstance( + /// + /// true if the script instance was valid for starting, false otherwise. This does not guarantee + /// that the script was actually started, just that the script was valid (i.e. its asset data could be found, etc.) + /// + bool CreateScriptInstance( TaskInventoryItem item, int startParam, bool postOnRez, string engine, int stateSource); /// @@ -113,12 +127,16 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// - void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource); + /// + /// true if the script instance was valid for starting, false otherwise. This does not guarantee + /// that the script was actually started, just that the script was valid (i.e. its asset data could be found, etc.) + /// + bool CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource); ArrayList CreateScriptInstanceEr(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource); /// - /// Stop a script which is in this prim's inventory. + /// Stop and remove a script which is in this prim's inventory from the scene. /// /// /// @@ -127,6 +145,12 @@ namespace OpenSim.Region.Framework.Interfaces /// void RemoveScriptInstance(UUID itemId, bool sceneObjectBeingDeleted); + /// + /// Stop a script which is in this prim's inventory. + /// + /// + void StopScriptInstance(UUID itemId); + /// /// Add an item to this entity's inventory. If an item with the same name already exists, then an alternative /// name is chosen. @@ -165,6 +189,19 @@ namespace OpenSim.Region.Framework.Interfaces /// List GetInventoryItems(); + /// + /// Gets an inventory item by name + /// + /// + /// This method returns the first inventory item that matches the given name. In SL this is all you need + /// since each item in a prim inventory must have a unique name. + /// + /// + /// + /// The inventory item. Null if no such item was found. + /// + TaskInventoryItem GetInventoryItem(string name); + /// /// Get inventory items by name. /// @@ -174,7 +211,17 @@ namespace OpenSim.Region.Framework.Interfaces /// If no inventory item has that name then an empty list is returned. /// List GetInventoryItems(string name); - + + /// + /// Get inventory items by type. + /// + /// + /// + /// A list of inventory items of that type. + /// If no inventory items of that type then an empty list is returned. + /// + List GetInventoryItems(InventoryType type); + /// /// Get the scene object referenced by an inventory item. /// @@ -227,6 +274,16 @@ namespace OpenSim.Region.Framework.Interfaces /// bool ContainsScripts(); + /// + /// Returns the count of scripts contained + /// + int ScriptCount(); + + /// + /// Returns the count of running scripts contained + /// + int RunningScriptCount(); + /// /// Get the uuids of all items in this inventory /// diff --git a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs index 76f1641a92..5bc8e51759 100644 --- a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs @@ -39,13 +39,30 @@ namespace OpenSim.Region.Framework.Interfaces public interface IEntityTransferModule { - void Teleport(ScenePresence agent, ulong regionHandle, Vector3 position, - Vector3 lookAt, uint teleportFlags); + /// + /// Teleport an agent within the same or to a different region. + /// + /// + /// + /// The handle of the destination region. If it's the same as the region currently + /// occupied by the agent then the teleport will be within that region. + /// + /// + /// + /// + void Teleport(ScenePresence agent, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags); bool TeleportHome(UUID id, IClientAPI client); void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination, - Vector3 position, Vector3 lookAt, uint teleportFlags, IEventQueue eq); + Vector3 position, Vector3 lookAt, uint teleportFlags); + + /// + /// Show whether the given agent is being teleported. + /// + /// The agent ID + /// true if the agent is in the process of being teleported, false otherwise. + bool IsInTransit(UUID id); bool Cross(ScenePresence agent, bool isFlying); diff --git a/OpenSim/Region/Framework/Interfaces/IEnvironmentModule.cs b/OpenSim/Region/Framework/Interfaces/IEnvironmentModule.cs new file mode 100644 index 0000000000..7a7b78202d --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/IEnvironmentModule.cs @@ -0,0 +1,36 @@ +/* + * 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 OpenMetaverse; + +namespace OpenSim.Region.Framework.Interfaces +{ + public interface IEnvironmentModule + { + void ResetEnvironmentSettings(UUID regionUUID); + } +} diff --git a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs index 72e79ed497..ca2ad94592 100644 --- a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs @@ -47,5 +47,8 @@ namespace OpenSim.Region.Framework.Interfaces void sendRegionHandshakeToAll(); void TriggerEstateInfoChange(); void TriggerRegionInfoChange(); + + void setEstateTerrainBaseTexture(int level, UUID texture); + void setEstateTerrainTextureHeights(int corner, float lowValue, float highValue); } } diff --git a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs index 1904011b17..3576e35798 100644 --- a/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IInventoryAccessModule.cs @@ -49,11 +49,15 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// + /// + /// Should be true if the object(s) are begin taken as attachments. False otherwise. + /// /// - /// Returns the UUID of the newly created item asset (not the item itself). - /// FIXME: This is not very useful. It would be far more useful to return a list of items instead. + /// A list of the items created. If there was more than one object and objects are not being coaleseced in + /// inventory, then the order of items is in the same order as the input objects. /// - UUID CopyToInventory(DeRezAction action, UUID folderID, List objectGroups, IClientAPI remoteClient); + List CopyToInventory( + DeRezAction action, UUID folderID, List objectGroups, IClientAPI remoteClient, bool asAttachment); /// /// Rez an object into the scene from the user's inventory diff --git a/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs new file mode 100644 index 0000000000..baac6e827f --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/IJsonStoreModule.cs @@ -0,0 +1,48 @@ +/* + * Copyright (c) Contributors + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using OpenMetaverse; + +namespace OpenSim.Region.Framework.Interfaces +{ + public delegate void TakeValueCallback(string s); + + public interface IJsonStoreModule + { + bool CreateStore(string value, out UUID result); + bool DestroyStore(UUID storeID); + bool TestPath(UUID storeID, string path, bool useJson); + bool SetValue(UUID storeID, string path, string value, bool useJson); + bool RemoveValue(UUID storeID, string path); + bool GetValue(UUID storeID, string path, bool useJson, out string value); + + void TakeValue(UUID storeID, string path, bool useJson, TakeValueCallback cback); + void ReadValue(UUID storeID, string path, bool useJson, TakeValueCallback cback); + } +} diff --git a/OpenSim/Region/Framework/Interfaces/INPCModule.cs b/OpenSim/Region/Framework/Interfaces/INPCModule.cs index dc3ff89303..d582149d57 100644 --- a/OpenSim/Region/Framework/Interfaces/INPCModule.cs +++ b/OpenSim/Region/Framework/Interfaces/INPCModule.cs @@ -113,9 +113,11 @@ namespace OpenSim.Region.Framework.Interfaces /// /// /// If true and the avatar is flying when it reaches the target, land. - /// + /// name="running"> + /// If true, NPC moves with running speed. /// True if the operation succeeded, false if there was no such agent or the agent was not an NPC - bool MoveToTarget(UUID agentID, Scene scene, Vector3 pos, bool noFly, bool landAtTarget); + /// + bool MoveToTarget(UUID agentID, Scene scene, Vector3 pos, bool noFly, bool landAtTarget, bool running); /// /// Stop the NPC's current movement. @@ -134,6 +136,36 @@ namespace OpenSim.Region.Framework.Interfaces /// True if the operation succeeded, false if there was no such agent or the agent was not an NPC bool Say(UUID agentID, Scene scene, string text); + /// + /// Get the NPC to say something. + /// + /// The UUID of the NPC + /// + /// + /// + /// True if the operation succeeded, false if there was no such agent or the agent was not an NPC + bool Say(UUID agentID, Scene scene, string text, int channel); + + /// + /// Get the NPC to shout something. + /// + /// The UUID of the NPC + /// + /// + /// + /// True if the operation succeeded, false if there was no such agent or the agent was not an NPC + bool Shout(UUID agentID, Scene scene, string text, int channel); + + /// + /// Get the NPC to whisper something. + /// + /// The UUID of the NPC + /// + /// + /// + /// True if the operation succeeded, false if there was no such agent or the agent was not an NPC + bool Whisper(UUID agentID, Scene scene, string text, int channel); + /// /// Sit the NPC. /// @@ -151,6 +183,14 @@ namespace OpenSim.Region.Framework.Interfaces /// true if the stand succeeded, false if not bool Stand(UUID agentID, Scene scene); + /// + /// Get the NPC to touch an object. + /// + /// + /// + /// true if the touch is actually attempted, false if not + bool Touch(UUID agentID, UUID partID); + /// /// Delete an NPC. /// diff --git a/OpenSim/Region/Framework/Interfaces/IRegionCombinerModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionCombinerModule.cs new file mode 100644 index 0000000000..e03ac5a26f --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/IRegionCombinerModule.cs @@ -0,0 +1,59 @@ +/* + * 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 System.Text; +using OpenSim.Region.Framework.Scenes; +using System.IO; +using OpenMetaverse; + +namespace OpenSim.Region.Framework.Interfaces +{ + public interface IRegionCombinerModule + { + /// + /// Does the given id belong to the root region of a megaregion? + /// + bool IsRootForMegaregion(UUID regionId); + + /// + /// Gets the size of megaregion. + /// + /// + /// Returns size in meters. + /// Do not rely on this method remaining the same - this area is actively under development. + /// + /// + /// The id of the root region for a megaregion. + /// This may change in the future to allow any region id that makes up a megaregion. + /// Currently, will throw an exception if this does not match a root region. + /// + Vector2 GetSizeOfMegaregion(UUID regionId); + } +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs index 5e43843faf..e6b926ce8c 100644 --- a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs +++ b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs @@ -40,6 +40,12 @@ namespace OpenSim.Region.Framework.Interfaces /// public interface IScenePresence : ISceneAgent { + /// + /// Copy of the script states while the agent is in transit. This state may + /// need to be placed back in case of transfer fail. + /// + List InTransitScriptStates { get; } + /// /// The AttachmentsModule synchronizes on this to avoid race conditions between commands to add and remove attachments. /// @@ -66,6 +72,10 @@ namespace OpenSim.Region.Framework.Interfaces /// List GetAttachments(uint attachmentPoint); + /// + /// Does this avatar have any attachments? + /// + /// bool HasAttachments(); // Don't use these methods directly. Instead, use the AttachmentsModule diff --git a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs index ce66100a65..42dbedcd56 100644 --- a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs @@ -71,6 +71,14 @@ namespace OpenSim.Region.Framework.Interfaces bool HasScript(UUID itemID, out bool running); + /// + /// Returns true if a script is running. + /// + /// The item ID of the script. + bool GetScriptState(UUID itemID); + + void SetRunEnable(UUID instanceID, bool enable); + void SaveAllState(); /// @@ -78,6 +86,14 @@ namespace OpenSim.Region.Framework.Interfaces /// void StartProcessing(); + /// + /// Get the execution times of all scripts in the given array if they are currently running. + /// + /// + /// A float the value is a representative execution time in milliseconds of all scripts in that Array. + /// + float GetScriptExecutionTime(List itemIDs); + /// /// Get the execution times of all scripts in each object. /// @@ -87,4 +103,4 @@ namespace OpenSim.Region.Framework.Interfaces /// Dictionary GetObjectScriptsExecutionTimes(); } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs b/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs index 5b696160b3..ccb583daa9 100644 --- a/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs +++ b/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs @@ -96,6 +96,26 @@ namespace OpenSim.Region.Framework.Interfaces void StoreRegionWindlightSettings(RegionLightShareData wl); void RemoveRegionWindlightSettings(UUID regionID); + /// + /// Load Environment settings from region storage + /// + /// the region UUID + /// LLSD string for viewer + string LoadRegionEnvironmentSettings(UUID regionUUID); + + /// + /// Store Environment settings into region storage + /// + /// the region UUID + /// LLSD string from viewer + void StoreRegionEnvironmentSettings(UUID regionUUID, string settings); + + /// + /// Delete Environment settings from region storage + /// + /// the region UUID + void RemoveRegionEnvironmentSettings(UUID regionUUID); + UUID[] GetObjectIDs(UUID regionID); } } diff --git a/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs b/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs index b7d9cfaf8b..d7c80f79ca 100644 --- a/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs +++ b/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs @@ -108,6 +108,26 @@ namespace OpenSim.Region.Framework.Interfaces void RemoveRegionWindlightSettings(UUID regionID); UUID[] GetObjectIDs(UUID regionID); + /// + /// Load Environment settings from region storage + /// + /// the region UUID + /// LLSD string for viewer + string LoadRegionEnvironmentSettings(UUID regionUUID); + + /// + /// Store Environment settings into region storage + /// + /// the region UUID + /// LLSD string from viewer + void StoreRegionEnvironmentSettings(UUID regionUUID, string settings); + + /// + /// Delete Environment settings from region storage + /// + /// the region UUID + void RemoveRegionEnvironmentSettings(UUID regionUUID); + void Shutdown(); } } diff --git a/OpenSim/Region/Framework/Interfaces/IUrlModule.cs b/OpenSim/Region/Framework/Interfaces/IUrlModule.cs index 1b911666e4..457444cd83 100644 --- a/OpenSim/Region/Framework/Interfaces/IUrlModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IUrlModule.cs @@ -34,6 +34,7 @@ namespace OpenSim.Region.Framework.Interfaces { public interface IUrlModule { + string ExternalHostNameForLSL { get; } UUID RequestURL(IScriptModule engine, SceneObjectPart host, UUID itemID); UUID RequestSecureURL(IScriptModule engine, SceneObjectPart host, UUID itemID); void ReleaseURL(string url); diff --git a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs index e577958839..9ddac1950a 100644 --- a/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs +++ b/OpenSim/Region/Framework/Scenes/Animation/ScenePresenceAnimator.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -294,6 +294,10 @@ namespace OpenSim.Region.Framework.Scenes.Animation return "FALLDOWN"; } + // Check if the user has stopped walking just now + if (CurrentMovementAnimation == "WALK" && (move == Vector3.Zero)) + return "STAND"; + return CurrentMovementAnimation; } @@ -418,13 +422,16 @@ namespace OpenSim.Region.Framework.Scenes.Animation /// public void UpdateMovementAnimations() { - CurrentMovementAnimation = DetermineMovementAnimation(); + lock (m_animations) + { + CurrentMovementAnimation = DetermineMovementAnimation(); -// m_log.DebugFormat( -// "[SCENE PRESENCE ANIMATOR]: Determined animation {0} for {1} in UpdateMovementAnimations()", -// CurrentMovementAnimation, m_scenePresence.Name); +// m_log.DebugFormat( +// "[SCENE PRESENCE ANIMATOR]: Determined animation {0} for {1} in UpdateMovementAnimations()", +// CurrentMovementAnimation, m_scenePresence.Name); - TrySetMovementAnimation(CurrentMovementAnimation); + TrySetMovementAnimation(CurrentMovementAnimation); + } } public UUID[] GetAnimationArray() diff --git a/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs b/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs index 9cb567430b..d9d2e64d87 100644 --- a/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs +++ b/OpenSim/Region/Framework/Scenes/AsyncInventorySender.cs @@ -137,7 +137,7 @@ namespace OpenSim.Region.Framework.Scenes } } - if (fh.Client.IsLoggingOut) + if (!fh.Client.IsActive) continue; // m_log.DebugFormat( diff --git a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs index f678d07805..f555b49f58 100644 --- a/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs +++ b/OpenSim/Region/Framework/Scenes/AsyncSceneObjectGroupDeleter.cs @@ -117,7 +117,7 @@ namespace OpenSim.Region.Framework.Scenes private void InventoryRunDeleteTimer(object sender, ElapsedEventArgs e) { - m_log.Debug("[ASYNC DELETER]: Starting send to inventory loop"); +// m_log.Debug("[ASYNC DELETER]: Starting send to inventory loop"); // We must set appearance parameters in the en_US culture in order to avoid issues where values are saved // in a culture where decimal points are commas and then reloaded in a culture which just treats them as @@ -147,15 +147,15 @@ namespace OpenSim.Region.Framework.Scenes { x = m_inventoryDeletes.Dequeue(); - m_log.DebugFormat( - "[ASYNC DELETER]: Sending object to user's inventory, action {1}, count {2}, {0} item(s) remaining.", - left, x.action, x.objectGroups.Count); +// m_log.DebugFormat( +// "[ASYNC DELETER]: Sending object to user's inventory, action {1}, count {2}, {0} item(s) remaining.", +// left, x.action, x.objectGroups.Count); try { IInventoryAccessModule invAccess = m_scene.RequestModuleInterface(); if (invAccess != null) - invAccess.CopyToInventory(x.action, x.folderID, x.objectGroups, x.remoteClient); + invAccess.CopyToInventory(x.action, x.folderID, x.objectGroups, x.remoteClient, false); if (x.permissionToDelete) { @@ -185,7 +185,7 @@ namespace OpenSim.Region.Framework.Scenes e.StackTrace); } - m_log.Debug("[ASYNC DELETER]: No objects left in inventory send queue."); +// m_log.Debug("[ASYNC DELETER]: No objects left in inventory send queue."); return false; } diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index 2365cfe3f7..76a952b6c2 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs @@ -53,6 +53,10 @@ namespace OpenSim.Region.Framework.Scenes public event ClientMovement OnClientMovement; + public delegate void OnTerrainTaintedDelegate(); + + public event OnTerrainTaintedDelegate OnTerrainTainted; + public delegate void OnTerrainTickDelegate(); public delegate void OnTerrainUpdateDelegate(); @@ -484,6 +488,9 @@ namespace OpenSim.Region.Framework.Scenes public delegate void SceneObjectPartUpdated(SceneObjectPart sop); public event SceneObjectPartUpdated OnSceneObjectPartUpdated; + public delegate void ScenePresenceUpdated(ScenePresence sp); + public event ScenePresenceUpdated OnScenePresenceUpdated; + public delegate void RegionUp(GridRegion region); public event RegionUp OnRegionUp; @@ -935,6 +942,27 @@ namespace OpenSim.Region.Framework.Scenes } } + public void TriggerTerrainTainted() + { + OnTerrainTaintedDelegate handlerTerrainTainted = OnTerrainTainted; + if (handlerTerrainTainted != null) + { + foreach (OnTerrainTaintedDelegate d in handlerTerrainTainted.GetInvocationList()) + { + try + { + d(); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[EVENT MANAGER]: Delegate for TriggerTerrainTainted failed - continuing. {0} {1}", + e.Message, e.StackTrace); + } + } + } + } + public void TriggerParcelPrimCountAdd(SceneObjectGroup obj) { OnParcelPrimCountAddDelegate handlerParcelPrimCountAdd = OnParcelPrimCountAdd; @@ -2367,6 +2395,27 @@ namespace OpenSim.Region.Framework.Scenes } } + public void TriggerScenePresenceUpdated(ScenePresence sp) + { + ScenePresenceUpdated handler = OnScenePresenceUpdated; + if (handler != null) + { + foreach (ScenePresenceUpdated d in handler.GetInvocationList()) + { + try + { + d(sp); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[EVENT MANAGER]: Delegate for TriggerScenePresenceUpdated failed - continuing. {0} {1}", + e.Message, e.StackTrace); + } + } + } + } + public void TriggerOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int local_id, IClientAPI remote_client) { diff --git a/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs b/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs index 6c5685c928..1365831779 100644 --- a/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs +++ b/OpenSim/Region/Framework/Scenes/RegionStatsHandler.cs @@ -48,16 +48,19 @@ namespace OpenSim.Region.Framework.Scenes { public class RegionStatsHandler : IStreamedRequestHandler { + //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private string osRXStatsURI = String.Empty; private string osXStatsURI = String.Empty; //private string osSecret = String.Empty; private OpenSim.Framework.RegionInfo regionInfo; public string localZone = TimeZone.CurrentTimeZone.StandardName; public TimeSpan utcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(DateTime.Now); - - //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - public RegionStatsHandler(OpenSim.Framework.RegionInfo region_info) + public string Name { get { return "RegionStats"; } } + public string Description { get { return "Region Statistics"; } } + + public RegionStatsHandler(RegionInfo region_info) { regionInfo = region_info; osRXStatsURI = Util.SHA1Hash(regionInfo.regionSecret); diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 29465c042d..9776a82403 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -60,19 +60,32 @@ namespace OpenSim.Region.Framework.Scenes /// /// Creates all the scripts in the scene which should be started. /// - public void CreateScriptInstances() + /// + /// Number of scripts that were valid for starting. This does not guarantee that all these scripts + /// were actually started, but just that the start could be attempt (e.g. the asset data for the script could be found) + /// + public int CreateScriptInstances() { - m_log.Info("[PRIM INVENTORY]: Creating scripts in scene"); + m_log.InfoFormat("[SCENE]: Initializing script instances in {0}", RegionInfo.RegionName); + + int scriptsValidForStarting = 0; EntityBase[] entities = Entities.GetEntities(); foreach (EntityBase group in entities) { if (group is SceneObjectGroup) { - ((SceneObjectGroup) group).CreateScriptInstances(0, false, DefaultScriptEngine, 0); + scriptsValidForStarting + += ((SceneObjectGroup) group).CreateScriptInstances(0, false, DefaultScriptEngine, 0); ((SceneObjectGroup) group).ResumeScripts(); } } + + m_log.InfoFormat( + "[SCENE]: Initialized {0} script instances in {1}", + scriptsValidForStarting, RegionInfo.RegionName); + + return scriptsValidForStarting; } /// @@ -80,7 +93,7 @@ namespace OpenSim.Region.Framework.Scenes /// public void StartScripts() { - m_log.Info("[PRIM INVENTORY]: Starting scripts in scene"); + m_log.InfoFormat("[SCENE]: Starting scripts in {0}, please wait.", RegionInfo.RegionName); IScriptModule[] engines = RequestModuleInterfaces(); @@ -300,6 +313,10 @@ namespace OpenSim.Region.Framework.Scenes AssetBase asset = CreateAsset(item.Name, item.Description, (sbyte)AssetType.LSLText, data, remoteClient.AgentId); AssetService.Store(asset); +// m_log.DebugFormat( +// "[PRIM INVENTORY]: Stored asset {0} when updating item {1} in prim {2} for {3}", +// asset.ID, item.Name, part.Name, remoteClient.Name); + if (isScriptRunning) { part.Inventory.RemoveScriptInstance(item.ItemID, false); @@ -431,10 +448,9 @@ namespace OpenSim.Region.Framework.Scenes } else { - IAgentAssetTransactions agentTransactions = this.RequestModuleInterface(); - if (agentTransactions != null) + if (AgentTransactionsModule != null) { - agentTransactions.HandleItemUpdateFromTransaction(remoteClient, transactionID, item); + AgentTransactionsModule.HandleItemUpdateFromTransaction(remoteClient, transactionID, item); } } } @@ -950,8 +966,8 @@ namespace OpenSim.Region.Framework.Scenes sbyte invType, sbyte type, UUID olditemID) { // m_log.DebugFormat( -// "[AGENT INVENTORY]: Received request from {0} to create inventory item link {1} in folder {2} pointing to {3}", -// remoteClient.Name, name, folderID, olditemID); +// "[AGENT INVENTORY]: Received request from {0} to create inventory item link {1} in folder {2} pointing to {3}, assetType {4}, inventoryType {5}", +// remoteClient.Name, name, folderID, olditemID, (AssetType)type, (InventoryType)invType); if (!Permissions.CanCreateUserInventory(invType, remoteClient.AgentId)) return; @@ -984,10 +1000,10 @@ namespace OpenSim.Region.Framework.Scenes asset.Type = type; asset.Name = name; asset.Description = description; - + CreateNewInventoryItem( - remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID, name, 0, callbackID, asset, invType, - (uint)PermissionMask.All, (uint)PermissionMask.All, (uint)PermissionMask.All, + remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID, name, 0, callbackID, asset, invType, + (uint)PermissionMask.All, (uint)PermissionMask.All, (uint)PermissionMask.All, (uint)PermissionMask.All, (uint)PermissionMask.All, Util.UnixTimeSinceEpoch()); } else @@ -1562,21 +1578,17 @@ namespace OpenSim.Region.Framework.Scenes // Only look for an uploaded updated asset if we are passed a transaction ID. This is only the // case for updates uploded through UDP. Updates uploaded via a capability (e.g. a script update) // will not pass in a transaction ID in the update message. - if (transactionID != UUID.Zero) + if (transactionID != UUID.Zero && AgentTransactionsModule != null) { - IAgentAssetTransactions agentTransactions = this.RequestModuleInterface(); - if (agentTransactions != null) - { - agentTransactions.HandleTaskItemUpdateFromTransaction( - remoteClient, part, transactionID, currentItem); - -// if ((InventoryType)itemInfo.InvType == InventoryType.Notecard) -// remoteClient.SendAgentAlertMessage("Notecard saved", false); -// else if ((InventoryType)itemInfo.InvType == InventoryType.LSL) -// remoteClient.SendAgentAlertMessage("Script saved", false); -// else -// remoteClient.SendAgentAlertMessage("Item saved", false); - } + AgentTransactionsModule.HandleTaskItemUpdateFromTransaction( + remoteClient, part, transactionID, currentItem); + +// if ((InventoryType)itemInfo.InvType == InventoryType.Notecard) +// remoteClient.SendAgentAlertMessage("Notecard saved", false); +// else if ((InventoryType)itemInfo.InvType == InventoryType.LSL) +// remoteClient.SendAgentAlertMessage("Script saved", false); +// else +// remoteClient.SendAgentAlertMessage("Item saved", false); } // Base ALWAYS has move @@ -2286,10 +2298,24 @@ namespace OpenSim.Region.Framework.Scenes if (part == null) return; + IScriptModule[] engines = RequestModuleInterfaces(); + if (running) + { + foreach (IScriptModule engine in engines) + { + engine.SetRunEnable(itemID, true); + } EventManager.TriggerStartScript(part.LocalId, itemID); + } else + { + foreach (IScriptModule engine in engines) + { + engine.SetRunEnable(itemID, false); + } EventManager.TriggerStopScript(part.LocalId, itemID); + } } public void GetScriptRunning(IClientAPI controllingClient, UUID objectID, UUID itemID) diff --git a/OpenSim/Region/Framework/Scenes/Scene.Permissions.cs b/OpenSim/Region/Framework/Scenes/Scene.Permissions.cs index e1fedf4bd0..535d87a341 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Permissions.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Permissions.cs @@ -67,6 +67,7 @@ namespace OpenSim.Region.Framework.Scenes public delegate bool RunConsoleCommandHandler(UUID user, Scene requestFromScene); public delegate bool IssueEstateCommandHandler(UUID user, Scene requestFromScene, bool ownerCommand); public delegate bool IsGodHandler(UUID user, Scene requestFromScene); + public delegate bool IsGridGodHandler(UUID user, Scene requestFromScene); public delegate bool IsAdministratorHandler(UUID user); public delegate bool EditParcelHandler(UUID user, ILandObject parcel, Scene scene); public delegate bool EditParcelPropertiesHandler(UUID user, ILandObject parcel, GroupPowers p, Scene scene); @@ -134,6 +135,7 @@ namespace OpenSim.Region.Framework.Scenes public event RunConsoleCommandHandler OnRunConsoleCommand; public event IssueEstateCommandHandler OnIssueEstateCommand; public event IsGodHandler OnIsGod; + public event IsGridGodHandler OnIsGridGod; public event IsAdministratorHandler OnIsAdministrator; // public event EditParcelHandler OnEditParcel; public event EditParcelPropertiesHandler OnEditParcelProperties; @@ -728,6 +730,21 @@ namespace OpenSim.Region.Framework.Scenes return true; } + public bool IsGridGod(UUID user) + { + IsGridGodHandler handler = OnIsGridGod; + if (handler != null) + { + Delegate[] list = handler.GetInvocationList(); + foreach (IsGridGodHandler h in list) + { + if (h(user, m_scene) == false) + return false; + } + } + return true; + } + public bool IsAdministrator(UUID user) { IsAdministratorHandler handler = OnIsAdministrator; diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 48aca98d1a..f437bc832f 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -77,7 +77,12 @@ namespace OpenSim.Region.Framework.Scenes public bool DebugUpdates { get; private set; } public SynchronizeSceneHandler SynchronizeScene; - public SimStatsReporter StatsReporter; + + /// + /// Statistical information for this scene. + /// + public SimStatsReporter StatsReporter { get; private set; } + public List NorthBorders = new List(); public List EastBorders = new List(); public List SouthBorders = new List(); @@ -103,6 +108,7 @@ namespace OpenSim.Region.Framework.Scenes public bool m_trustBinaries; public bool m_allowScriptCrossings; public bool m_useFlySlow; + public bool m_useTrashOnDelete = true; /// /// Temporarily setting to trigger appearance resends at 60 second intervals. @@ -114,6 +120,9 @@ namespace OpenSim.Region.Framework.Scenes { get { return m_defaultDrawDistance; } } + + private List m_AllowedViewers = new List(); + private List m_BannedViewers = new List(); // TODO: need to figure out how allow client agents but deny // root agents when ACL denies access to root agent @@ -163,7 +172,6 @@ namespace OpenSim.Region.Framework.Scenes protected IConfigSource m_config; protected IRegionSerialiserModule m_serialiser; protected IDialogModule m_dialogModule; - protected IEntityTransferModule m_teleportModule; protected ICapabilitiesModule m_capsModule; protected IGroupsModule m_groupsModule; @@ -217,6 +225,7 @@ namespace OpenSim.Region.Framework.Scenes private int backupMS; private int terrainMS; private int landMS; + private int spareMS; /// /// Tick at which the last frame was processed. @@ -458,6 +467,7 @@ namespace OpenSim.Region.Framework.Scenes { if (m_simulationService == null) m_simulationService = RequestModuleInterface(); + return m_simulationService; } } @@ -513,6 +523,9 @@ namespace OpenSim.Region.Framework.Scenes } public IAttachmentsModule AttachmentsModule { get; set; } + public IEntityTransferModule EntityTransferModule { get; private set; } + public IAgentAssetTransactions AgentTransactionsModule { get; private set; } + public IUserManagement UserManagementModule { get; private set; } public IAvatarFactoryModule AvatarFactory { @@ -589,6 +602,20 @@ namespace OpenSim.Region.Framework.Scenes get { return m_sceneGraph.Entities; } } + + // used in sequence see: SpawnPoint() + private int m_SpawnPoint; + // can be closest/random/sequence + public string SpawnPointRouting + { + get; private set; + } + // allow landmarks to pass + public bool TelehubAllowLandmarks + { + get; private set; + } + #endregion Properties #region Constructors @@ -606,14 +633,13 @@ namespace OpenSim.Region.Framework.Scenes Random random = new Random(); - m_lastAllocatedLocalId = (uint)(random.NextDouble() * (double)(uint.MaxValue/2))+(uint)(uint.MaxValue/4); + m_lastAllocatedLocalId = (uint)(random.NextDouble() * (double)(uint.MaxValue / 2)) + (uint)(uint.MaxValue / 4); m_moduleLoader = moduleLoader; m_authenticateHandler = authen; m_sceneGridService = sceneGridService; m_SimulationDataService = simDataService; m_EstateDataService = estateDataService; m_regionHandle = m_regInfo.RegionHandle; - m_regionName = m_regInfo.RegionName; m_lastIncoming = 0; m_lastOutgoing = 0; @@ -630,7 +656,7 @@ namespace OpenSim.Region.Framework.Scenes // resave. // FIXME: It shouldn't be up to the database plugins to create this data - we should do it when a new // region is set up and avoid these gyrations. - RegionSettings rs = simDataService.LoadRegionSettings(m_regInfo.RegionID); + RegionSettings rs = simDataService.LoadRegionSettings(RegionInfo.RegionID); bool updatedTerrainTextures = false; if (rs.TerrainTexture1 == UUID.Zero) { @@ -659,10 +685,10 @@ namespace OpenSim.Region.Framework.Scenes if (updatedTerrainTextures) rs.Save(); - m_regInfo.RegionSettings = rs; + RegionInfo.RegionSettings = rs; if (estateDataService != null) - m_regInfo.EstateSettings = estateDataService.LoadEstateSettings(m_regInfo.RegionID, false); + RegionInfo.EstateSettings = estateDataService.LoadEstateSettings(RegionInfo.RegionID, false); #endregion Region Settings @@ -726,6 +752,9 @@ namespace OpenSim.Region.Framework.Scenes m_maxPhys = RegionInfo.PhysPrimMax; } + SpawnPointRouting = startupConfig.GetString("SpawnPointRouting", "closest"); + TelehubAllowLandmarks = startupConfig.GetBoolean("TelehubAllowLandmark", false); + // Here, if clamping is requested in either global or // local config, it will be used // @@ -735,6 +764,7 @@ namespace OpenSim.Region.Framework.Scenes m_clampPrimSize = true; } + m_useTrashOnDelete = startupConfig.GetBoolean("UseTrashOnDelete",m_useTrashOnDelete); m_trustBinaries = startupConfig.GetBoolean("TrustBinaries", m_trustBinaries); m_allowScriptCrossings = startupConfig.GetBoolean("AllowScriptCrossing", m_allowScriptCrossings); m_dontPersistBefore = @@ -781,6 +811,24 @@ namespace OpenSim.Region.Framework.Scenes } } + string grant = startupConfig.GetString("AllowedClients", String.Empty); + if (grant.Length > 0) + { + foreach (string viewer in grant.Split(',')) + { + m_AllowedViewers.Add(viewer.Trim().ToLower()); + } + } + + grant = startupConfig.GetString("BannedClients", String.Empty); + if (grant.Length > 0) + { + foreach (string viewer in grant.Split(',')) + { + m_BannedViewers.Add(viewer.Trim().ToLower()); + } + } + MinFrameTime = startupConfig.GetFloat( "MinFrameTime", MinFrameTime); m_update_backup = startupConfig.GetInt( "UpdateStorageEveryNFrames", m_update_backup); m_update_coarse_locations = startupConfig.GetInt( "UpdateCoarseLocationsEveryNFrames", m_update_coarse_locations); @@ -835,13 +883,11 @@ namespace OpenSim.Region.Framework.Scenes MainConsole.Instance.Commands.AddCommand("scene", false, "gc collect", "gc collect", "gc collect", "Cause the garbage collector to make a single pass", HandleGcCollect); } - /// - /// Mock constructor for scene group persistency unit tests. - /// SceneObjectGroup RegionId property is delegated to Scene. - /// - /// - public Scene(RegionInfo regInfo) + public Scene(RegionInfo regInfo) : base(regInfo) { + PhysicalPrims = true; + CollidablePrims = true; + BordersLocked = true; Border northBorder = new Border(); northBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, (int)Constants.RegionSize); //<--- @@ -864,12 +910,9 @@ namespace OpenSim.Region.Framework.Scenes WestBorders.Add(westBorder); BordersLocked = false; - m_regInfo = regInfo; m_eventManager = new EventManager(); m_permissions = new ScenePermissions(this); - -// m_lastUpdate = Util.EnvironmentTickCount(); } #endregion @@ -938,8 +981,8 @@ namespace OpenSim.Region.Framework.Scenes List old = new List(); old.Add(otherRegion.RegionHandle); agent.DropOldNeighbours(old); - if (m_teleportModule != null && agent.PresenceType != PresenceType.Npc) - m_teleportModule.EnableChildAgent(agent, otherRegion); + if (EntityTransferModule != null && agent.PresenceType != PresenceType.Npc) + EntityTransferModule.EnableChildAgent(agent, otherRegion); }); } catch (NullReferenceException) @@ -952,7 +995,7 @@ namespace OpenSim.Region.Framework.Scenes else { m_log.InfoFormat( - "[INTERGRID]: Got notice about far away Region: {0} at ({1}, {2})", + "[SCENE]: Got notice about far away Region: {0} at ({1}, {2})", otherRegion.RegionName, otherRegion.RegionLocX, otherRegion.RegionLocY); } } @@ -1046,13 +1089,13 @@ namespace OpenSim.Region.Framework.Scenes } } + m_log.Error("[REGION]: Closing"); + Close(); + if (PhysicsScene != null) { PhysicsScene.Dispose(); - } - - m_log.Error("[REGION]: Closing"); - Close(); + } m_log.Error("[REGION]: Firing Region Restart Message"); @@ -1076,8 +1119,8 @@ namespace OpenSim.Region.Framework.Scenes { ForEachRootScenePresence(delegate(ScenePresence agent) { - if (m_teleportModule != null && agent.PresenceType != PresenceType.Npc) - m_teleportModule.EnableChildAgent(agent, r); + if (EntityTransferModule != null && agent.PresenceType != PresenceType.Npc) + EntityTransferModule.EnableChildAgent(agent, r); }); } catch (NullReferenceException) @@ -1210,8 +1253,8 @@ namespace OpenSim.Region.Framework.Scenes m_sceneGraph.Close(); - if (!GridService.DeregisterRegion(m_regInfo.RegionID)) - m_log.WarnFormat("[SCENE]: Deregister from grid failed for region {0}", m_regInfo.RegionName); + if (!GridService.DeregisterRegion(RegionInfo.RegionID)) + m_log.WarnFormat("[SCENE]: Deregister from grid failed for region {0}", Name); // call the base class Close method. base.Close(); @@ -1267,8 +1310,10 @@ namespace OpenSim.Region.Framework.Scenes m_serialiser = RequestModuleInterface(); m_dialogModule = RequestModuleInterface(); m_capsModule = RequestModuleInterface(); - m_teleportModule = RequestModuleInterface(); + EntityTransferModule = RequestModuleInterface(); m_groupsModule = RequestModuleInterface(); + AgentTransactionsModule = RequestModuleInterface(); + UserManagementModule = RequestModuleInterface(); } #endregion @@ -1389,37 +1434,41 @@ namespace OpenSim.Region.Framework.Scenes endFrame = Frame + frames; float physicsFPS = 0f; - int tmpPhysicsMS, tmpPhysicsMS2, tmpAgentMS, tmpTempOnRezMS, evMS, backMS, terMS; - int previousFrameTick; - int maintc; - int sleepMS; - int framestart; + int previousFrameTick, tmpMS; + int maintc = Util.EnvironmentTickCount(); while (!m_shuttingDown && (endFrame == null || Frame < endFrame)) { - framestart = Util.EnvironmentTickCount(); ++Frame; // m_log.DebugFormat("[SCENE]: Processing frame {0} in {1}", Frame, RegionInfo.RegionName); - agentMS = tempOnRezMS = eventMS = backupMS = terrainMS = landMS = 0; + agentMS = tempOnRezMS = eventMS = backupMS = terrainMS = landMS = spareMS = 0; try { - tmpPhysicsMS2 = Util.EnvironmentTickCount(); + // Apply taints in terrain module to terrain in physics scene + if (Frame % m_update_terrain == 0) + { + tmpMS = Util.EnvironmentTickCount(); + UpdateTerrain(); + terrainMS = Util.EnvironmentTickCountSubtract(tmpMS); + } + + tmpMS = Util.EnvironmentTickCount(); if ((Frame % m_update_physics == 0) && m_physics_enabled) m_sceneGraph.UpdatePreparePhysics(); - physicsMS2 = Util.EnvironmentTickCountSubtract(tmpPhysicsMS2); + physicsMS2 = Util.EnvironmentTickCountSubtract(tmpMS); // Apply any pending avatar force input to the avatar's velocity - tmpAgentMS = Util.EnvironmentTickCount(); + tmpMS = Util.EnvironmentTickCount(); if (Frame % m_update_entitymovement == 0) m_sceneGraph.UpdateScenePresenceMovement(); - agentMS = Util.EnvironmentTickCountSubtract(tmpAgentMS); + agentMS = Util.EnvironmentTickCountSubtract(tmpMS); // Perform the main physics update. This will do the actual work of moving objects and avatars according to their // velocity - tmpPhysicsMS = Util.EnvironmentTickCount(); + tmpMS = Util.EnvironmentTickCount(); if (Frame % m_update_physics == 0) { if (m_physics_enabled) @@ -1428,9 +1477,9 @@ namespace OpenSim.Region.Framework.Scenes if (SynchronizeScene != null) SynchronizeScene(this); } - physicsMS = Util.EnvironmentTickCountSubtract(tmpPhysicsMS); + physicsMS = Util.EnvironmentTickCountSubtract(tmpMS); - tmpAgentMS = Util.EnvironmentTickCount(); + tmpMS = Util.EnvironmentTickCount(); // Check if any objects have reached their targets CheckAtTargets(); @@ -1445,36 +1494,29 @@ namespace OpenSim.Region.Framework.Scenes if (Frame % m_update_presences == 0) m_sceneGraph.UpdatePresences(); - agentMS += Util.EnvironmentTickCountSubtract(tmpAgentMS); + agentMS += Util.EnvironmentTickCountSubtract(tmpMS); // Delete temp-on-rez stuff if (Frame % m_update_temp_cleaning == 0 && !m_cleaningTemps) { - tmpTempOnRezMS = Util.EnvironmentTickCount(); + tmpMS = Util.EnvironmentTickCount(); m_cleaningTemps = true; Util.FireAndForget(delegate { CleanTempObjects(); m_cleaningTemps = false; }); - tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpTempOnRezMS); + tempOnRezMS = Util.EnvironmentTickCountSubtract(tmpMS); } if (Frame % m_update_events == 0) { - evMS = Util.EnvironmentTickCount(); + tmpMS = Util.EnvironmentTickCount(); UpdateEvents(); - eventMS = Util.EnvironmentTickCountSubtract(evMS); + eventMS = Util.EnvironmentTickCountSubtract(tmpMS); } if (Frame % m_update_backup == 0) { - backMS = Util.EnvironmentTickCount(); + tmpMS = Util.EnvironmentTickCount(); UpdateStorageBackup(); - backupMS = Util.EnvironmentTickCountSubtract(backMS); - } - - if (Frame % m_update_terrain == 0) - { - terMS = Util.EnvironmentTickCount(); - UpdateTerrain(); - terrainMS = Util.EnvironmentTickCountSubtract(terMS); + backupMS = Util.EnvironmentTickCountSubtract(tmpMS); } //if (Frame % m_update_land == 0) @@ -1483,29 +1525,6 @@ namespace OpenSim.Region.Framework.Scenes // UpdateLand(); // landMS = Util.EnvironmentTickCountSubtract(ldMS); //} - - // frameMS = Util.EnvironmentTickCountSubtract(maintc); - otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS; - - // if (Frame%m_update_avatars == 0) - // UpdateInWorldTime(); - StatsReporter.AddPhysicsFPS(physicsFPS); - StatsReporter.AddTimeDilation(TimeDilation); - StatsReporter.AddFPS(1); - StatsReporter.SetRootAgents(m_sceneGraph.GetRootAgentCount()); - StatsReporter.SetChildAgents(m_sceneGraph.GetChildAgentCount()); - StatsReporter.SetObjects(m_sceneGraph.GetTotalObjectsCount()); - StatsReporter.SetActiveObjects(m_sceneGraph.GetActiveObjectsCount()); - - // frameMS currently records work frame times, not total frame times (work + any required sleep to - // reach min frame time. - // StatsReporter.addFrameMS(frameMS); - - StatsReporter.addAgentMS(agentMS); - StatsReporter.addPhysicsMS(physicsMS + physicsMS2); - StatsReporter.addOtherMS(otherMS); - StatsReporter.SetActiveScripts(m_sceneGraph.GetActiveScriptsCount()); - StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS()); if (LoginsDisabled && Frame == 20) { @@ -1526,11 +1545,11 @@ namespace OpenSim.Region.Framework.Scenes LoginLock = false; EventManager.TriggerLoginsEnabled(RegionInfo.RegionName); } - m_log.DebugFormat("[REGION]: Enabling logins for {0}", RegionInfo.RegionName); // For RegionReady lockouts - if(LoginLock == false) + if (!LoginLock) { + m_log.InfoFormat("[REGION]: Enabling logins for {0}", RegionInfo.RegionName); LoginsDisabled = false; } @@ -1556,23 +1575,36 @@ namespace OpenSim.Region.Framework.Scenes previousFrameTick = m_lastFrameTick; m_lastFrameTick = Util.EnvironmentTickCount(); - maintc = Util.EnvironmentTickCountSubtract(m_lastFrameTick, framestart); - maintc = (int)(MinFrameTime * 1000) - maintc; + tmpMS = Util.EnvironmentTickCountSubtract(m_lastFrameTick, maintc); + tmpMS = (int)(MinFrameTime * 1000) - tmpMS; m_firstHeartbeat = false; + if (tmpMS > 0) + { + Thread.Sleep(tmpMS); + spareMS += tmpMS; + } - sleepMS = Util.EnvironmentTickCount(); + frameMS = Util.EnvironmentTickCountSubtract(maintc); + maintc = Util.EnvironmentTickCount(); - if (maintc > 0) - Thread.Sleep(maintc); + otherMS = tempOnRezMS + eventMS + backupMS + terrainMS + landMS; + + // if (Frame%m_update_avatars == 0) + // UpdateInWorldTime(); + StatsReporter.AddPhysicsFPS(physicsFPS); + StatsReporter.AddTimeDilation(TimeDilation); + StatsReporter.AddFPS(1); - sleepMS = Util.EnvironmentTickCountSubtract(sleepMS); - frameMS = Util.EnvironmentTickCountSubtract(framestart); - StatsReporter.addSleepMS(sleepMS); StatsReporter.addFrameMS(frameMS); - - // Optionally warn if a frame takes double the amount of time that it should. + StatsReporter.addAgentMS(agentMS); + StatsReporter.addPhysicsMS(physicsMS + physicsMS2); + StatsReporter.addOtherMS(otherMS); + StatsReporter.AddSpareMS(spareMS); + StatsReporter.addScriptLines(m_sceneGraph.GetScriptLPS()); + + // Optionally warn if a frame takes double the amount of time that it should. if (DebugUpdates && Util.EnvironmentTickCountSubtract( m_lastFrameTick, previousFrameTick) > (int)(MinFrameTime * 1000 * 2)) @@ -1759,14 +1791,14 @@ namespace OpenSim.Region.Framework.Scenes public void StoreWindlightProfile(RegionLightShareData wl) { - m_regInfo.WindlightSettings = wl; + RegionInfo.WindlightSettings = wl; SimulationDataService.StoreRegionWindlightSettings(wl); m_eventManager.TriggerOnSaveNewWindlightProfile(); } public void LoadWindlightProfile() { - m_regInfo.WindlightSettings = SimulationDataService.LoadRegionWindlightSettings(RegionInfo.RegionID); + RegionInfo.WindlightSettings = SimulationDataService.LoadRegionWindlightSettings(RegionInfo.RegionID); m_eventManager.TriggerOnSaveNewWindlightProfile(); } @@ -2085,9 +2117,8 @@ namespace OpenSim.Region.Framework.Scenes sceneObject.SetGroup(groupID, null); } - IUserManagement uman = RequestModuleInterface(); - if (uman != null) - sceneObject.RootPart.CreatorIdentification = uman.GetUserUUI(ownerID); + if (UserManagementModule != null) + sceneObject.RootPart.CreatorIdentification = UserManagementModule.GetUserUUI(ownerID); sceneObject.ScheduleGroupForFullUpdate(); @@ -2252,13 +2283,30 @@ namespace OpenSim.Region.Framework.Scenes /// /// Synchronously delete the given object from the scene. /// + /// + /// Scripts are also removed. + /// /// Object Id /// Suppress broadcasting changes to other clients. public void DeleteSceneObject(SceneObjectGroup group, bool silent) + { + DeleteSceneObject(group, silent, true); + } + + /// + /// Synchronously delete the given object from the scene. + /// + /// Object Id + /// Suppress broadcasting changes to other clients. + /// If true, then scripts are removed. If false, then they are only stopped. + public void DeleteSceneObject(SceneObjectGroup group, bool silent, bool removeScripts) { // m_log.DebugFormat("[SCENE]: Deleting scene object {0} {1}", group.Name, group.UUID); - group.RemoveScriptInstances(true); + if (removeScripts) + group.RemoveScriptInstances(true); + else + group.StopScriptInstances(); SceneObjectPart[] partList = group.Parts; @@ -2308,7 +2356,7 @@ namespace OpenSim.Region.Framework.Scenes ForceSceneObjectBackup(so); so.DetachFromBackup(); - SimulationDataService.RemoveObject(so.UUID, m_regInfo.RegionID); + SimulationDataService.RemoveObject(so.UUID, RegionInfo.RegionID); } // We need to keep track of this state in case this group is still queued for further backup. @@ -2365,8 +2413,8 @@ namespace OpenSim.Region.Framework.Scenes return; } - if (m_teleportModule != null) - m_teleportModule.Cross(grp, attemptedPosition, silent); + if (EntityTransferModule != null) + EntityTransferModule.Cross(grp, attemptedPosition, silent); } public Border GetCrossedBorder(Vector3 position, Cardinals gridline) @@ -2566,7 +2614,16 @@ namespace OpenSim.Region.Framework.Scenes } catch (Exception e) { - m_log.WarnFormat("[SCENE]: Problem casting object, exception {0}{1}", e.Message, e.StackTrace); + m_log.WarnFormat("[INTERREGION]: Problem casting object, exception {0}{1}", e.Message, e.StackTrace); + return false; + } + + // If the user is banned, we won't let any of their objects + // enter. Period. + // + if (RegionInfo.EstateSettings.IsBanned(newObject.OwnerID, 36)) + { + m_log.InfoFormat("[INTERREGION]: Denied prim crossing for banned avatar {0}", newObject.OwnerID); return false; } @@ -2577,33 +2634,31 @@ namespace OpenSim.Region.Framework.Scenes if (!AddSceneObject(newObject)) { - m_log.DebugFormat("[SCENE]: Problem adding scene object {0} in {1} ", sog.UUID, RegionInfo.RegionName); + m_log.DebugFormat( + "[INTERREGION]: Problem adding scene object {0} in {1} ", newObject.UUID, RegionInfo.RegionName); return false; } - // For attachments, we need to wait until the agent is root - // before we restart the scripts, or else some functions won't work. if (!newObject.IsAttachment) { + // FIXME: It would be better to never add the scene object at all rather than add it and then delete + // it + if (!Permissions.CanObjectEntry(newObject.UUID, true, newObject.AbsolutePosition)) + { + // Deny non attachments based on parcel settings + // + m_log.Info("[INTERREGION]: Denied prim crossing because of parcel settings"); + + DeleteSceneObject(newObject, false); + + return false; + } + + // For attachments, we need to wait until the agent is root + // before we restart the scripts, or else some functions won't work. newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject)); newObject.ResumeScripts(); } - else - { - ScenePresence sp; - if (TryGetScenePresence(newObject.OwnerID, out sp)) - { - // If the scene presence is here and already a root - // agent, we came from a ;egacy region. Start the scripts - // here as they used to start. - // TODO: Remove in 0.7.3 - if (!sp.IsChildAgent) - { - newObject.RootPart.ParentGroup.CreateScriptInstances(0, false, DefaultScriptEngine, GetStateSource(newObject)); - newObject.ResumeScripts(); - } - } - } // Do this as late as possible so that listeners have full access to the incoming object EventManager.TriggerOnIncomingSceneObject(newObject); @@ -2611,28 +2666,6 @@ namespace OpenSim.Region.Framework.Scenes return true; } - /// - /// Attachment rezzing - /// - /// Agent Unique ID - /// Object ID - /// False - public virtual bool IncomingCreateObject(UUID userID, UUID itemID) - { - m_log.DebugFormat(" >>> IncomingCreateObject(userID, itemID) <<< {0} {1}", userID, itemID); - - // Commented out since this is as yet unused and is arguably not the appropriate place to do this, as - // attachments are being rezzed elsewhere in AddNewClient() -// ScenePresence sp = GetScenePresence(userID); -// if (sp != null && AttachmentsModule != null) -// { -// uint attPt = (uint)sp.Appearance.GetAttachpoint(itemID); -// AttachmentsModule.RezSingleAttachmentFromInventory(sp.ControllingClient, itemID, attPt); -// } - - return false; - } - /// /// Adds a Scene Object group to the Scene. /// Verifies that the creator of the object is not banned from the simulator. @@ -2652,15 +2685,13 @@ namespace OpenSim.Region.Framework.Scenes // enter. Period. // int flags = GetUserFlags(sceneObject.OwnerID); - if (m_regInfo.EstateSettings.IsBanned(sceneObject.OwnerID, flags)) + if (RegionInfo.EstateSettings.IsBanned(sceneObject.OwnerID, flags)) { m_log.InfoFormat("[INTERREGION]: Denied prim crossing for banned avatar {0}", sceneObject.OwnerID); return false; } - sceneObject.SetScene(this); - // Force allocation of new LocalId // SceneObjectPart[] parts = sceneObject.Parts; @@ -2686,10 +2717,10 @@ namespace OpenSim.Region.Framework.Scenes { SceneObjectGroup grp = sceneObject; - m_log.DebugFormat( - "[ATTACHMENT]: Received attachment {0}, inworld asset id {1}", grp.FromItemID, grp.UUID); - m_log.DebugFormat( - "[ATTACHMENT]: Attach to avatar {0} at position {1}", sp.UUID, grp.AbsolutePosition); +// m_log.DebugFormat( +// "[ATTACHMENT]: Received attachment {0}, inworld asset id {1}", grp.FromItemID, grp.UUID); +// m_log.DebugFormat( +// "[ATTACHMENT]: Attach to avatar {0} at position {1}", sp.UUID, grp.AbsolutePosition); RootPrim.RemFlag(PrimFlags.TemporaryOnRez); @@ -2716,18 +2747,6 @@ namespace OpenSim.Region.Framework.Scenes return false; } AddRestoredSceneObject(sceneObject, true, false); - - if (!Permissions.CanObjectEntry(sceneObject.UUID, - true, sceneObject.AbsolutePosition)) - { - // Deny non attachments based on parcel settings - // - m_log.Info("[INTERREGION]: Denied prim crossing because of parcel settings"); - - DeleteSceneObject(sceneObject, false); - - return false; - } } return true; @@ -2785,7 +2804,8 @@ namespace OpenSim.Region.Framework.Scenes if (sp == null) { m_log.DebugFormat( - "[SCENE]: Adding new child scene presence {0} to scene {1} at pos {2}", client.Name, RegionInfo.RegionName, client.StartPos); + "[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}", + client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos); m_clientManager.Add(client); SubscribeToClientEvents(client); @@ -2845,14 +2865,13 @@ namespace OpenSim.Region.Framework.Scenes /// private void CacheUserName(ScenePresence sp, AgentCircuitData aCircuit) { - IUserManagement uMan = RequestModuleInterface(); - if (uMan != null) + if (UserManagementModule != null) { string first = aCircuit.firstname, last = aCircuit.lastname; if (sp.PresenceType == PresenceType.Npc) { - uMan.AddUser(aCircuit.AgentID, first, last); + UserManagementModule.AddUser(aCircuit.AgentID, first, last); } else { @@ -2871,7 +2890,7 @@ namespace OpenSim.Region.Framework.Scenes } } - uMan.AddUser(aCircuit.AgentID, first, last, homeURL); + UserManagementModule.AddUser(aCircuit.AgentID, first, last, homeURL); } } } @@ -3209,8 +3228,10 @@ namespace OpenSim.Region.Framework.Scenes /// The IClientAPI for the client public virtual bool TeleportClientHome(UUID agentId, IClientAPI client) { - if (m_teleportModule != null) - return m_teleportModule.TeleportHome(agentId, client); + if (EntityTransferModule != null) + { + EntityTransferModule.TeleportHome(agentId, client); + } else { m_log.DebugFormat("[SCENE]: Unable to teleport user home: no AgentTransferModule is active"); @@ -3372,65 +3393,82 @@ namespace OpenSim.Region.Framework.Scenes // CheckHeartbeat(); bool isChildAgent = false; ScenePresence avatar = GetScenePresence(agentID); - if (avatar != null) + + if (avatar == null) + { + m_log.WarnFormat( + "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID); + + return; + } + + try { isChildAgent = avatar.IsChildAgent; + m_log.DebugFormat( + "[SCENE]: Removing {0} agent {1} {2} from {3}", + (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName); + + // Don't do this to root agents, it's not nice for the viewer + if (closeChildAgents && isChildAgent) + { + // Tell a single agent to disconnect from the region. + IEventQueue eq = RequestModuleInterface(); + if (eq != null) + { + eq.DisableSimulator(RegionInfo.RegionHandle, avatar.UUID); + } + else + { + avatar.ControllingClient.SendShutdownConnectionNotice(); + } + } + + // Only applies to root agents. if (avatar.ParentID != 0) { avatar.StandUp(); } - try + m_sceneGraph.removeUserCount(!isChildAgent); + + // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop + // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI + if (closeChildAgents && CapsModule != null) + CapsModule.RemoveCaps(agentID); + + // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever + // this method is doing is HORRIBLE!!! + avatar.Scene.NeedSceneCacheClear(avatar.UUID); + + if (closeChildAgents && !isChildAgent) { - m_log.DebugFormat( - "[SCENE]: Removing {0} agent {1} from region {2}", - (isChildAgent ? "child" : "root"), agentID, RegionInfo.RegionName); - - m_sceneGraph.removeUserCount(!isChildAgent); - - // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop - // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI - if (closeChildAgents && CapsModule != null) - CapsModule.RemoveCaps(agentID); - - // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever - // this method is doing is HORRIBLE!!! - avatar.Scene.NeedSceneCacheClear(avatar.UUID); - - if (closeChildAgents && !avatar.IsChildAgent) - { - List regions = avatar.KnownRegionHandles; - regions.Remove(RegionInfo.RegionHandle); - m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); - } - m_log.Debug("[Scene] Beginning ClientClosed"); - m_eventManager.TriggerClientClosed(agentID, this); - m_log.Debug("[Scene] Finished ClientClosed"); - } - catch (NullReferenceException) - { - // We don't know which count to remove it from - // Avatar is already disposed :/ + List regions = avatar.KnownRegionHandles; + regions.Remove(RegionInfo.RegionHandle); + m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); } - try + m_eventManager.TriggerClientClosed(agentID, this); + m_eventManager.TriggerOnRemovePresence(agentID); + + if (!isChildAgent) { - m_eventManager.TriggerOnRemovePresence(agentID); - - if (AttachmentsModule != null && !isChildAgent && avatar.PresenceType != PresenceType.Npc) + if (AttachmentsModule != null) { - IUserManagement uMan = RequestModuleInterface(); // Don't save attachments for HG visitors, it // messes up their inventory. When a HG visitor logs // out on a foreign grid, their attachments will be // reloaded in the state they were in when they left // the home grid. This is best anyway as the visited // grid may use an incompatible script engine. - if (uMan == null || uMan.IsLocalGridUser(avatar.UUID)) - AttachmentsModule.SaveChangedAttachments(avatar, false); + bool saveChanged + = avatar.PresenceType != PresenceType.Npc + && (UserManagementModule == null || UserManagementModule.IsLocalGridUser(avatar.UUID)); + + AttachmentsModule.DeRezAttachments(avatar, saveChanged, false); } - + ForEachClient( delegate(IClientAPI client) { @@ -3438,43 +3476,35 @@ namespace OpenSim.Region.Framework.Scenes try { client.SendKillObject(avatar.RegionHandle, new List { avatar.LocalId }); } catch (NullReferenceException) { } }); - - IAgentAssetTransactions agentTransactions = this.RequestModuleInterface(); - if (agentTransactions != null) - { - agentTransactions.RemoveAgentAssetTransactions(agentID); - } - } - finally - { - // Always clean these structures up so that any failure above doesn't cause them to remain in the - // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering - // the same cleanup exception continually. - // TODO: This should probably extend to the whole method, but we don't want to also catch the NRE - // since this would hide the underlying failure and other associated problems. - m_sceneGraph.RemoveScenePresence(agentID); - m_clientManager.Remove(agentID); } - try - { - avatar.Close(); - } - catch (NullReferenceException) - { - //We can safely ignore null reference exceptions. It means the avatar are dead and cleaned up anyway. - } - catch (Exception e) - { - m_log.ErrorFormat("[SCENE] Scene.cs:RemoveClient exception {0}{1}", e.Message, e.StackTrace); - } - m_log.Debug("[Scene] Done. Firing RemoveCircuit"); + // It's possible for child agents to have transactions if changes are being made cross-border. + if (AgentTransactionsModule != null) + AgentTransactionsModule.RemoveAgentAssetTransactions(agentID); + + avatar.Close(); + m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode); -// CleanDroppedAttachments(); m_log.Debug("[Scene] The avatar has left the building"); - //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false)); - //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true)); } + catch (Exception e) + { + m_log.Error( + string.Format("[SCENE]: Exception removing {0} from {1}, ", avatar.Name, RegionInfo.RegionName), e); + } + finally + { + // Always clean these structures up so that any failure above doesn't cause them to remain in the + // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering + // the same cleanup exception continually. + // TODO: This should probably extend to the whole method, but we don't want to also catch the NRE + // since this would hide the underlying failure and other associated problems. + m_sceneGraph.RemoveScenePresence(agentID); + m_clientManager.Remove(agentID); + } + + //m_log.InfoFormat("[SCENE] Memory pre GC {0}", System.GC.GetTotalMemory(false)); + //m_log.InfoFormat("[SCENE] Memory post GC {0}", System.GC.GetTotalMemory(true)); } /// @@ -3556,7 +3586,7 @@ namespace OpenSim.Region.Framework.Scenes public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, out string reason, bool requirePresenceLookup) { bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 || - (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0); + (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0); bool viahome = ((teleportFlags & (uint)TPFlags.ViaHome) != 0); bool godlike = ((teleportFlags & (uint)TPFlags.Godlike) != 0); @@ -3572,8 +3602,17 @@ namespace OpenSim.Region.Framework.Scenes // Don't disable this log message - it's too helpful m_log.DebugFormat( "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})", - RegionInfo.RegionName, (agent.child ? "child" : "root"),agent.firstname, agent.lastname, - agent.AgentID, agent.circuitcode, agent.IPAddress, agent.Viewer, ((TPFlags)teleportFlags).ToString(), agent.startpos); + RegionInfo.RegionName, + (agent.child ? "child" : "root"), + agent.firstname, + agent.lastname, + agent.AgentID, + agent.circuitcode, + agent.IPAddress, + agent.Viewer, + ((TPFlags)teleportFlags).ToString(), + agent.startpos + ); if (LoginsDisabled) { @@ -3581,6 +3620,50 @@ namespace OpenSim.Region.Framework.Scenes return false; } + //Check if the viewer is banned or in the viewer access list + //We check if the substring is listed for higher flexebility + bool ViewerDenied = true; + + //Check if the specific viewer is listed in the allowed viewer list + if (m_AllowedViewers.Count > 0) + { + foreach (string viewer in m_AllowedViewers) + { + if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) + { + ViewerDenied = false; + break; + } + } + } + else + { + ViewerDenied = false; + } + + //Check if the viewer is in the banned list + if (m_BannedViewers.Count > 0) + { + foreach (string viewer in m_BannedViewers) + { + if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) + { + ViewerDenied = true; + break; + } + } + } + + if (ViewerDenied) + { + m_log.DebugFormat( + "[SCENE]: Access denied for {0} {1} using {2}", + agent.firstname, agent.lastname, agent.Viewer); + reason = "Access denied, your viewer is banned by the region owner"; + return false; + } + + ScenePresence sp = GetScenePresence(agent.AgentID); if (sp != null && !sp.IsChildAgent) @@ -3588,7 +3671,10 @@ namespace OpenSim.Region.Framework.Scenes // We have a zombie from a crashed session. // Or the same user is trying to be root twice here, won't work. // Kill it. - m_log.DebugFormat("[SCENE]: Zombie scene presence detected for {0} in {1}", agent.AgentID, RegionInfo.RegionName); + m_log.DebugFormat( + "[SCENE]: Zombie scene presence detected for {0} {1} in {2}", + sp.Name, sp.UUID, RegionInfo.RegionName); + sp.ControllingClient.Close(); sp = null; } @@ -3615,8 +3701,7 @@ namespace OpenSim.Region.Framework.Scenes { if (!VerifyUserPresence(agent, out reason)) return false; - } - catch (Exception e) + } catch (Exception e) { m_log.ErrorFormat( "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); @@ -3651,8 +3736,7 @@ namespace OpenSim.Region.Framework.Scenes CapsModule.SetAgentCapsSeeds(agent); CapsModule.CreateCaps(agent.AgentID); } - } - else + } else { // Let the SP know how we got here. This has a lot of interesting // uses down the line. @@ -3675,7 +3759,7 @@ namespace OpenSim.Region.Framework.Scenes agent.teleportFlags = teleportFlags; m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); - if (vialogin) + if (vialogin) { // CleanDroppedAttachments(); @@ -3716,8 +3800,7 @@ namespace OpenSim.Region.Framework.Scenes agent.startpos.Z = 720; } } - } - else + } else { if (agent.startpos.X > EastBorders[0].BorderLine.Z) { @@ -3743,10 +3826,19 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectGroup telehub = GetSceneObjectGroup(RegionInfo.RegionSettings.TelehubObject); // Can have multiple SpawnPoints List spawnpoints = RegionInfo.RegionSettings.SpawnPoints(); - if ( spawnpoints.Count > 1) + if (spawnpoints.Count > 1) { - // We have multiple SpawnPoints, Route the agent to a random one - agent.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count)].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); + // We have multiple SpawnPoints, Route the agent to a random or sequential one + if (SpawnPointRouting == "random") + agent.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation( + telehub.AbsolutePosition, + telehub.GroupRotation + ); + else + agent.startpos = spawnpoints[SpawnPoint()].GetLocation( + telehub.AbsolutePosition, + telehub.GroupRotation + ); } else { @@ -3869,9 +3961,9 @@ namespace OpenSim.Region.Framework.Scenes } } - if (m_regInfo.EstateSettings != null) + if (RegionInfo.EstateSettings != null) { - if (m_regInfo.EstateSettings.IsBanned(agent.AgentID,0)) + if (RegionInfo.EstateSettings.IsBanned(agent.AgentID, 0)) { m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user is on the banlist", agent.AgentID, agent.firstname, agent.lastname, RegionInfo.RegionName); @@ -3903,7 +3995,7 @@ namespace OpenSim.Region.Framework.Scenes } bool groupAccess = false; - UUID[] estateGroups = m_regInfo.EstateSettings.EstateGroups; + UUID[] estateGroups = RegionInfo.EstateSettings.EstateGroups; if (estateGroups != null) { @@ -3921,8 +4013,8 @@ namespace OpenSim.Region.Framework.Scenes m_log.ErrorFormat("[CONNECTION BEGIN]: EstateGroups is null!"); } - if (!m_regInfo.EstateSettings.PublicAccess && - !m_regInfo.EstateSettings.HasAccess(agent.AgentID) && + if (!RegionInfo.EstateSettings.PublicAccess && + !RegionInfo.EstateSettings.HasAccess(agent.AgentID) && !groupAccess) { m_log.WarnFormat("[CONNECTION BEGIN]: Denied access to: {0} ({1} {2}) at {3} because the user does not have access to the estate", @@ -3983,41 +4075,41 @@ namespace OpenSim.Region.Framework.Scenes return m_authenticateHandler.TryChangeCiruitCode(oldcc, newcc); } - /// - /// The Grid has requested that we log-off a user. Log them off. - /// - /// Unique ID of the avatar to log-off - /// SecureSessionID of the user, or the RegionSecret text when logging on to the grid - /// message to display to the user. Reason for being logged off - public void HandleLogOffUserFromGrid(UUID AvatarID, UUID RegionSecret, string message) - { - ScenePresence loggingOffUser = GetScenePresence(AvatarID); - if (loggingOffUser != null) - { - UUID localRegionSecret = UUID.Zero; - bool parsedsecret = UUID.TryParse(m_regInfo.regionSecret, out localRegionSecret); - - // Region Secret is used here in case a new sessionid overwrites an old one on the user server. - // Will update the user server in a few revisions to use it. - - if (RegionSecret == loggingOffUser.ControllingClient.SecureSessionId || (parsedsecret && RegionSecret == localRegionSecret)) - { - m_sceneGridService.SendCloseChildAgentConnections(loggingOffUser.UUID, loggingOffUser.KnownRegionHandles); - loggingOffUser.ControllingClient.Kick(message); - // Give them a second to receive the message! - Thread.Sleep(1000); - loggingOffUser.ControllingClient.Close(); - } - else - { - m_log.Info("[USERLOGOFF]: System sending the LogOff user message failed to sucessfully authenticate"); - } - } - else - { - m_log.InfoFormat("[USERLOGOFF]: Got a logoff request for {0} but the user isn't here. The user might already have been logged out", AvatarID.ToString()); - } - } +// /// +// /// The Grid has requested that we log-off a user. Log them off. +// /// +// /// Unique ID of the avatar to log-off +// /// SecureSessionID of the user, or the RegionSecret text when logging on to the grid +// /// message to display to the user. Reason for being logged off +// public void HandleLogOffUserFromGrid(UUID AvatarID, UUID RegionSecret, string message) +// { +// ScenePresence loggingOffUser = GetScenePresence(AvatarID); +// if (loggingOffUser != null) +// { +// UUID localRegionSecret = UUID.Zero; +// bool parsedsecret = UUID.TryParse(RegionInfo.regionSecret, out localRegionSecret); +// +// // Region Secret is used here in case a new sessionid overwrites an old one on the user server. +// // Will update the user server in a few revisions to use it. +// +// if (RegionSecret == loggingOffUser.ControllingClient.SecureSessionId || (parsedsecret && RegionSecret == localRegionSecret)) +// { +// m_sceneGridService.SendCloseChildAgentConnections(loggingOffUser.UUID, loggingOffUser.KnownRegionHandles); +// loggingOffUser.ControllingClient.Kick(message); +// // Give them a second to receive the message! +// Thread.Sleep(1000); +// loggingOffUser.ControllingClient.Close(); +// } +// else +// { +// m_log.Info("[USERLOGOFF]: System sending the LogOff user message failed to sucessfully authenticate"); +// } +// } +// else +// { +// m_log.InfoFormat("[USERLOGOFF]: Got a logoff request for {0} but the user isn't here. The user might already have been logged out", AvatarID.ToString()); +// } +// } /// /// Triggered when an agent crosses into this sim. Also happens on initial login. @@ -4070,21 +4162,19 @@ namespace OpenSim.Region.Framework.Scenes return false; } + // TODO: This check should probably be in QueryAccess(). ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2); if (nearestParcel == null) { - m_log.DebugFormat("[SCENE]: Denying root agent entry to {0}: no allowed parcel", cAgentData.AgentID); + m_log.DebugFormat( + "[SCENE]: Denying root agent entry to {0} in {1}: no allowed parcel", + cAgentData.AgentID, RegionInfo.RegionName); + return false; } - int num = m_sceneGraph.GetNumberOfScenePresences(); - - if (num >= RegionInfo.RegionSettings.AgentLimit) - { - if (!Permissions.IsAdministrator(cAgentData.AgentID)) - return false; - } - + // We have to wait until the viewer contacts this region after receiving EAC. + // That calls AddNewClient, which finally creates the ScenePresence ScenePresence childAgentUpdate = WaitGetScenePresence(cAgentData.AgentID); if (childAgentUpdate != null) @@ -4128,14 +4218,28 @@ namespace OpenSim.Region.Framework.Scenes return false; } + /// + /// Poll until the requested ScenePresence appears or we timeout. + /// + /// The scene presence is found, else null. + /// protected virtual ScenePresence WaitGetScenePresence(UUID agentID) { int ntimes = 10; - ScenePresence childAgentUpdate = null; - while ((childAgentUpdate = GetScenePresence(agentID)) == null && (ntimes-- > 0)) + ScenePresence sp = null; + while ((sp = GetScenePresence(agentID)) == null && (ntimes-- > 0)) Thread.Sleep(1000); - return childAgentUpdate; + if (sp == null) + m_log.WarnFormat( + "[SCENE PRESENCE]: Did not find presence with id {0} in {1} before timeout", + agentID, RegionInfo.RegionName); +// else +// m_log.DebugFormat( +// "[SCENE PRESENCE]: Found presence {0} {1} {2} in {3} after {4} waits", +// sp.Name, sp.UUID, sp.IsChildAgent ? "child" : "root", RegionInfo.RegionName, 10 - ntimes); + + return sp; } public virtual bool IncomingRetrieveRootAgent(UUID id, out IAgentData agent) @@ -4173,33 +4277,7 @@ namespace OpenSim.Region.Framework.Scenes ScenePresence presence = m_sceneGraph.GetScenePresence(agentID); if (presence != null) { - // Nothing is removed here, so down count it as such - if (presence.IsChildAgent) - { - m_sceneGraph.removeUserCount(false); - } - else if (!childOnly) - { - m_sceneGraph.removeUserCount(true); - } - - // Don't do this to root agents on logout, it's not nice for the viewer - if (presence.IsChildAgent) - { - // Tell a single agent to disconnect from the region. - IEventQueue eq = RequestModuleInterface(); - if (eq != null) - { - eq.DisableSimulator(RegionInfo.RegionHandle, agentID); - } - else - presence.ControllingClient.SendShutdownConnectionNotice(); - presence.ControllingClient.Close(false); - } - else if (!childOnly) - { - presence.ControllingClient.Close(true); - } + presence.ControllingClient.Close(); return true; } @@ -4247,13 +4325,13 @@ namespace OpenSim.Region.Framework.Scenes ScenePresence sp = GetScenePresence(remoteClient.AgentId); if (sp != null) { - uint regionX = m_regInfo.RegionLocX; - uint regionY = m_regInfo.RegionLocY; + uint regionX = RegionInfo.RegionLocX; + uint regionY = RegionInfo.RegionLocY; Utils.LongToUInts(regionHandle, out regionX, out regionY); - int shiftx = (int) regionX - (int) m_regInfo.RegionLocX * (int)Constants.RegionSize; - int shifty = (int) regionY - (int) m_regInfo.RegionLocY * (int)Constants.RegionSize; + int shiftx = (int) regionX - (int) RegionInfo.RegionLocX * (int)Constants.RegionSize; + int shifty = (int) regionY - (int) RegionInfo.RegionLocY * (int)Constants.RegionSize; position.X += shiftx; position.Y += shifty; @@ -4276,7 +4354,7 @@ namespace OpenSim.Region.Framework.Scenes if (!result) { - regionHandle = m_regInfo.RegionHandle; + regionHandle = RegionInfo.RegionHandle; } else { @@ -4285,8 +4363,10 @@ namespace OpenSim.Region.Framework.Scenes position.Y -= shifty; } - if (m_teleportModule != null) - m_teleportModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags); + if (EntityTransferModule != null) + { + EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags); + } else { m_log.DebugFormat("[SCENE]: Unable to perform teleports: no AgentTransferModule is active"); @@ -4297,8 +4377,10 @@ namespace OpenSim.Region.Framework.Scenes public bool CrossAgentToNewRegion(ScenePresence agent, bool isFlying) { - if (m_teleportModule != null) - return m_teleportModule.Cross(agent, isFlying); + if (EntityTransferModule != null) + { + return EntityTransferModule.Cross(agent, isFlying); + } else { m_log.DebugFormat("[SCENE]: Unable to cross agent to neighbouring region, because there is no AgentTransferModule"); @@ -4599,6 +4681,17 @@ namespace OpenSim.Region.Framework.Scenes m_sceneGraph.ForEachScenePresence(action); } + /// + /// Get all the scene object groups. + /// + /// + /// The scene object groups. If the scene is empty then an empty list is returned. + /// + public List GetSceneObjectGroups() + { + return m_sceneGraph.GetSceneObjectGroups(); + } + /// /// Get a group via its UUID /// @@ -4778,7 +4871,7 @@ namespace OpenSim.Region.Framework.Scenes public void DeleteFromStorage(UUID uuid) { - SimulationDataService.RemoveObject(uuid, m_regInfo.RegionID); + SimulationDataService.RemoveObject(uuid, RegionInfo.RegionID); } public int GetHealth(out int flags, out string message) @@ -5259,7 +5352,7 @@ Environment.Exit(1); IEstateDataService estateDataService = EstateDataService; if (estateDataService != null) { - m_regInfo.EstateSettings = estateDataService.LoadEstateSettings(m_regInfo.RegionID, false); + RegionInfo.EstateSettings = estateDataService.LoadEstateSettings(RegionInfo.RegionID, false); TriggerEstateSunUpdate(); } } @@ -5446,29 +5539,58 @@ Environment.Exit(1); throw new Exception(error); } - // This method is called across the simulation connector to - // determine if a given agent is allowed in this region - // AS A ROOT AGENT. Returning false here will prevent them - // from logging into the region, teleporting into the region - // or corssing the broder walking, but will NOT prevent - // child agent creation, thereby emulating the SL behavior. + /// + /// This method is called across the simulation connector to + /// determine if a given agent is allowed in this region + /// AS A ROOT AGENT + /// + /// + /// Returning false here will prevent them + /// from logging into the region, teleporting into the region + /// or corssing the broder walking, but will NOT prevent + /// child agent creation, thereby emulating the SL behavior. + /// + /// + /// + /// + /// public bool QueryAccess(UUID agentID, Vector3 position, out string reason) { reason = "You are banned from the region"; + if (EntityTransferModule.IsInTransit(agentID)) + { + reason = "Agent is still in transit from this region"; + + m_log.WarnFormat( + "[SCENE]: Denying agent {0} entry into {1} since region still has them registered as in transit", + agentID, RegionInfo.RegionName); + + return false; + } + if (Permissions.IsGod(agentID)) { reason = String.Empty; return true; } - int num = m_sceneGraph.GetNumberOfScenePresences(); + // FIXME: Root agent count is currently known to be inaccurate. This forces a recount before we check. + // However, the long term fix is to make sure root agent count is always accurate. + m_sceneGraph.RecalculateStats(); + + int num = m_sceneGraph.GetRootAgentCount(); if (num >= RegionInfo.RegionSettings.AgentLimit) { if (!Permissions.IsAdministrator(agentID)) { reason = "The region is full"; + + m_log.DebugFormat( + "[SCENE]: Denying presence with id {0} entry into {1} since region is at agent limit of {2}", + agentID, RegionInfo.RegionName, RegionInfo.RegionSettings.AgentLimit); + return false; } } @@ -5640,6 +5762,20 @@ Environment.Exit(1); } } + // manage and select spawn points in sequence + public int SpawnPoint() + { + int spawnpoints = RegionInfo.RegionSettings.SpawnPoints().Count; + + if (spawnpoints == 0) + return 0; + + m_SpawnPoint++; + if (m_SpawnPoint > spawnpoints) + m_SpawnPoint = 1; + return m_SpawnPoint - 1; + } + private void HandleGcCollect(string module, string[] args) { GC.Collect(); diff --git a/OpenSim/Region/Framework/Scenes/SceneBase.cs b/OpenSim/Region/Framework/Scenes/SceneBase.cs index 9b8a3ae3c9..e8134cd866 100644 --- a/OpenSim/Region/Framework/Scenes/SceneBase.cs +++ b/OpenSim/Region/Framework/Scenes/SceneBase.cs @@ -51,6 +51,8 @@ namespace OpenSim.Region.Framework.Scenes #endregion #region Fields + + public string Name { get { return RegionInfo.RegionName; } } public IConfigSource Config { @@ -148,6 +150,11 @@ namespace OpenSim.Region.Framework.Scenes #endregion + public SceneBase(RegionInfo regInfo) + { + RegionInfo = regInfo; + } + #region Update Methods /// @@ -211,10 +218,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// - public virtual RegionInfo RegionInfo - { - get { return m_regInfo; } - } + public virtual RegionInfo RegionInfo { get; private set; } #region admin stuff diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs index b806d9174b..5d8447bddb 100644 --- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs +++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs @@ -84,16 +84,23 @@ namespace OpenSim.Region.Framework.Scenes if (neighbourService != null) neighbour = neighbourService.HelloNeighbour(regionhandle, region); else - m_log.DebugFormat("[SCS]: No neighbour service provided for informing neigbhours of this region"); + m_log.DebugFormat( + "[SCENE COMMUNICATION SERVICE]: No neighbour service provided for region {0} to inform neigbhours of status", + m_scene.Name); if (neighbour != null) { - // m_log.DebugFormat("[INTERGRID]: Successfully informed neighbour {0}-{1} that I'm here", x / Constants.RegionSize, y / Constants.RegionSize); + m_log.DebugFormat( + "[SCENE COMMUNICATION SERVICE]: Region {0} successfully informed neighbour {1} at {2}-{3} that it is up", + m_scene.Name, neighbour.RegionName, x / Constants.RegionSize, y / Constants.RegionSize); + m_scene.EventManager.TriggerOnRegionUp(neighbour); } else { - m_log.InfoFormat("[INTERGRID]: Failed to inform neighbour {0}-{1} that I'm here.", x / Constants.RegionSize, y / Constants.RegionSize); + m_log.WarnFormat( + "[SCENE COMMUNICATION SERVICE]: Region {0} failed to inform neighbour at {1}-{2} that it is up.", + x / Constants.RegionSize, y / Constants.RegionSize); } } @@ -101,8 +108,13 @@ namespace OpenSim.Region.Framework.Scenes { //m_log.Info("[INTER]: " + debugRegionName + ": SceneCommunicationService: Sending InterRegion Notification that region is up " + region.RegionName); - List neighbours = m_scene.GridService.GetNeighbours(m_scene.RegionInfo.ScopeID, m_scene.RegionInfo.RegionID); - //m_log.DebugFormat("[INTERGRID]: Informing {0} neighbours that this region is up", neighbours.Count); + List neighbours + = m_scene.GridService.GetNeighbours(m_scene.RegionInfo.ScopeID, m_scene.RegionInfo.RegionID); + + m_log.DebugFormat( + "[SCENE COMMUNICATION SERVICE]: Informing {0} neighbours that region {1} is up", + neighbours.Count, m_scene.Name); + foreach (GridRegion n in neighbours) { InformNeighbourThatRegionUpDelegate d = InformNeighboursThatRegionIsUpAsync; @@ -156,7 +168,9 @@ namespace OpenSim.Region.Framework.Scenes // that the region position is cached or performance will degrade Utils.LongToUInts(regionHandle, out x, out y); GridRegion dest = m_scene.GridService.GetRegionByPosition(UUID.Zero, (int)x, (int)y); -// bool v = true; + if (dest == null) + continue; + if (!simulatorList.Contains(dest.ServerURI)) { // we havent seen this simulator before, add it to the list diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 058784694f..c3d66eb466 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -101,6 +101,13 @@ namespace OpenSim.Region.Framework.Scenes /// protected internal Dictionary SceneObjectGroupsByLocalPartID = new Dictionary(); + /// + /// Lock to prevent object group update, linking, delinking and duplication operations from running concurrently. + /// + /// + /// These operations rely on the parts composition of the object. If allowed to run concurrently then race + /// conditions can occur. + /// private Object m_updateLock = new Object(); #endregion @@ -394,9 +401,9 @@ namespace OpenSim.Region.Framework.Scenes if (Entities.ContainsKey(sceneObject.UUID)) { -// m_log.DebugFormat( -// "[SCENEGRAPH]: Scene graph for {0} already contains object {1} in AddSceneObject()", -// m_parentScene.RegionInfo.RegionName, sceneObject.UUID); + m_log.DebugFormat( + "[SCENEGRAPH]: Scene graph for {0} already contains object {1} in AddSceneObject()", + m_parentScene.RegionInfo.RegionName, sceneObject.UUID); return false; } @@ -775,12 +782,6 @@ namespace OpenSim.Region.Framework.Scenes public int GetChildAgentCount() { - // some network situations come in where child agents get closed twice. - if (m_numChildAgents < 0) - { - m_numChildAgents = 0; - } - return m_numChildAgents; } @@ -852,11 +853,6 @@ namespace OpenSim.Region.Framework.Scenes return m_scenePresenceArray; } - public int GetNumberOfScenePresences() - { - return m_scenePresenceArray.Count; - } - /// /// Request a scene presence by UUID. Fast, indexed lookup. /// @@ -1041,6 +1037,18 @@ namespace OpenSim.Region.Framework.Scenes return result; } + /// + /// Get all the scene object groups. + /// + /// + /// The scene object groups. If the scene is empty then an empty list is returned. + /// + protected internal List GetSceneObjectGroups() + { + lock (SceneObjectGroupsByFullID) + return new List(SceneObjectGroupsByFullID.Values); + } + /// /// Get a group in the scene /// @@ -1184,11 +1192,7 @@ namespace OpenSim.Region.Framework.Scenes /// protected internal void ForEachSOG(Action action) { - List objlist; - lock (SceneObjectGroupsByFullID) - objlist = new List(SceneObjectGroupsByFullID.Values); - - foreach (SceneObjectGroup obj in objlist) + foreach (SceneObjectGroup obj in GetSceneObjectGroups()) { try { @@ -2065,12 +2069,14 @@ namespace OpenSim.Region.Framework.Scenes /// /// /// + /// null if duplication fails, otherwise the duplicated object + /// public SceneObjectGroup DuplicateObject(uint originalPrimID, Vector3 offset, uint flags, UUID AgentID, UUID GroupID, Quaternion rot) { // m_log.DebugFormat( // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}", // originalPrimID, offset, AgentID); - + SceneObjectGroup original = GetGroupByPrim(originalPrimID); if (original != null) { @@ -2100,25 +2106,25 @@ namespace OpenSim.Region.Framework.Scenes // FIXME: This section needs to be refactored so that it just calls AddSceneObject() Entities.Add(copy); - + lock (SceneObjectGroupsByFullID) SceneObjectGroupsByFullID[copy.UUID] = copy; - + SceneObjectPart[] children = copy.Parts; - + lock (SceneObjectGroupsByFullPartID) { SceneObjectGroupsByFullPartID[copy.UUID] = copy; foreach (SceneObjectPart part in children) SceneObjectGroupsByFullPartID[part.UUID] = copy; } - + lock (SceneObjectGroupsByLocalPartID) { SceneObjectGroupsByLocalPartID[copy.LocalId] = copy; foreach (SceneObjectPart part in children) SceneObjectGroupsByLocalPartID[part.LocalId] = copy; - } + } // PROBABLE END OF FIXME // Since we copy from a source group that is in selected @@ -2150,11 +2156,10 @@ namespace OpenSim.Region.Framework.Scenes { m_log.WarnFormat("[SCENE]: Attempted to duplicate nonexistant prim id {0}", GroupID); } - + return null; } - - /// + /// Calculates the distance between two Vector3s /// /// diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs index 2effa251c7..26524fb7b8 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs @@ -54,20 +54,32 @@ namespace OpenSim.Region.Framework.Scenes /// /// Start the scripts contained in all the prims in this group. /// - public void CreateScriptInstances(int startParam, bool postOnRez, - string engine, int stateSource) + /// + /// + /// + /// + /// + /// Number of scripts that were valid for starting. This does not guarantee that all these scripts + /// were actually started, but just that the start could be attempt (e.g. the asset data for the script could be found) + /// + public int CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource) { + int scriptsStarted = 0; + // Don't start scripts if they're turned off in the region! if (!m_scene.RegionInfo.RegionSettings.DisableScripts) { SceneObjectPart[] parts = m_parts.GetArray(); for (int i = 0; i < parts.Length; i++) - parts[i].Inventory.CreateScriptInstances(startParam, postOnRez, engine, stateSource); + scriptsStarted + += parts[i].Inventory.CreateScriptInstances(startParam, postOnRez, engine, stateSource); } + + return scriptsStarted; } /// - /// Stop the scripts contained in all the prims in this group + /// Stop and remove the scripts contained in all the prims in this group /// public void RemoveScriptInstances(bool sceneObjectBeingDeleted) { @@ -76,6 +88,14 @@ namespace OpenSim.Region.Framework.Scenes parts[i].Inventory.RemoveScriptInstances(sceneObjectBeingDeleted); } + /// + /// Stop the scripts contained in all the prims in this group + /// + public void StopScriptInstances() + { + Array.ForEach(m_parts.GetArray(), p => p.Inventory.StopScriptInstances()); + } + /// /// Add an inventory item from a user's inventory to a prim in this scene object. /// diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 1734ab7be2..f1f94a78bf 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -131,6 +131,15 @@ namespace OpenSim.Region.Framework.Scenes } } + /// + /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage + /// (the database). + /// + /// + /// Ultimately, this should be managed such that region modules can change it at the end of a set of operations + /// so that either all changes are preserved or none at all. However, currently, a large amount of internal + /// code will set this anyway when some object properties are changed. + /// public bool HasGroupChanged { set @@ -244,6 +253,22 @@ namespace OpenSim.Region.Framework.Scenes } } + /// + /// If this scene object has an attachment point then indicate whether there is a point where + /// attachments are perceivable by avatars other than the avatar to which this object is attached. + /// + /// + /// HUDs are not perceivable by other avatars. + /// + public bool HasPrivateAttachmentPoint + { + get + { + return AttachmentPoint >= (uint)OpenMetaverse.AttachmentPoint.HUDCenter2 + && AttachmentPoint <= (uint)OpenMetaverse.AttachmentPoint.HUDBottomRight; + } + } + public void ClearPartAttachmentData() { AttachmentPoint = 0; @@ -621,6 +646,9 @@ namespace OpenSim.Region.Framework.Scenes return; } } + + // Restuff the new GroupPosition into each SOP of the linkset. + // This has the affect of resetting and tainting the physics actors. SceneObjectPart[] parts = m_parts.GetArray(); bool triggerScriptEvent = m_rootPart.GroupPosition != val; if (m_dupeInProgress) @@ -1649,16 +1677,6 @@ namespace OpenSim.Region.Framework.Scenes { return Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); } - - /// - /// Added as a way for the storage provider to reset the scene, - /// most likely a better way to do this sort of thing but for now... - /// - /// - public void SetScene(Scene scene) - { - m_scene = scene; - } /// /// Set a part to act as the root part for this scene object @@ -1740,6 +1758,9 @@ namespace OpenSim.Region.Framework.Scenes public void ResetChildPrimPhysicsPositions() { + // Setting this SOG's absolute position also loops through and sets the positions + // of the SOP's in this SOG's linkset. This has the side affect of making sure + // the physics world matches the simulated world. AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works? // teravus: AbsolutePosition is NOT a normal property! @@ -1816,8 +1837,9 @@ namespace OpenSim.Region.Framework.Scenes part.ClearUpdateSchedule(); if (part == m_rootPart) { - if (!IsAttachment || (AttachedAvatar == avatar.ControllingClient.AgentId) || - (AttachmentPoint < 31) || (AttachmentPoint > 38)) + if (!IsAttachment + || AttachedAvatar == avatar.ControllingClient.AgentId + || !HasPrivateAttachmentPoint) avatar.ControllingClient.SendKillObject(m_regionHandle, new List { part.LocalId }); } } @@ -2531,8 +2553,13 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Schedule a full update for this scene object + /// Schedule a full update for this scene object to all interested viewers. /// + /// + /// Ultimately, this should be managed such that region modules can invoke it at the end of a set of operations + /// so that either all changes are sent at once. However, currently, a large amount of internal + /// code will set this anyway when some object properties are changed. + /// public void ScheduleGroupForFullUpdate() { // if (IsAttachment) @@ -2551,8 +2578,13 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Schedule a terse update for this scene object + /// Schedule a terse update for this scene object to all interested viewers. /// + /// + /// Ultimately, this should be managed such that region modules can invoke it at the end of a set of operations + /// so that either all changes are sent at once. However, currently, a large amount of internal + /// code will set this anyway when some object properties are changed. + /// public void ScheduleGroupForTerseUpdate() { // m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID); @@ -2682,12 +2714,18 @@ namespace OpenSim.Region.Framework.Scenes /// /// Link the prims in a given group to this group /// + /// + /// Do not call this method directly - use Scene.LinkObjects() instead to avoid races between threads. + /// FIXME: There are places where scripts call these methods directly without locking. This is a potential race condition. + /// /// The group of prims which should be linked to this group public void LinkToGroup(SceneObjectGroup objectGroup) { LinkToGroup(objectGroup, false); } + // Link an existing group to this group. + // The group being linked need not be a linkset -- it can have just one prim. public void LinkToGroup(SceneObjectGroup objectGroup, bool insert) { // m_log.DebugFormat( @@ -2698,6 +2736,7 @@ namespace OpenSim.Region.Framework.Scenes if (objectGroup == this) return; + // 'linkPart' == the root of the group being linked into this group SceneObjectPart linkPart = objectGroup.m_rootPart; if (m_rootPart.PhysActor != null) @@ -2709,31 +2748,44 @@ namespace OpenSim.Region.Framework.Scenes bool grpusephys = UsesPhysics; bool grptemporary = IsTemporary; + // Remember where the group being linked thought it was Vector3 oldGroupPosition = linkPart.GroupPosition; Quaternion oldRootRotation = linkPart.RotationOffset; - linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; + // A linked SOP remembers its location and rotation relative to the root of a group. + // Convert the root of the group being linked to be relative to the + // root of the group being linked to. + // Note: Some of the assignments have complex side effects. + // First move the new group's root SOP's position to be relative to ours + // (radams1: Not sure if the multiple setting of OffsetPosition is required. If not, + // this code can be reordered to have a more logical flow.) + linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; + // Assign the new parent to the root of the old group linkPart.ParentID = m_rootPart.LocalId; - - linkPart.GroupPosition = AbsolutePosition; + // Now that it's a child, it's group position is our root position + linkPart.GroupPosition = AbsolutePosition; Vector3 axPos = linkPart.OffsetPosition; + // Rotate the linking root SOP's position to be relative to the new root prim Quaternion parentRot = m_rootPart.RotationOffset; axPos *= Quaternion.Conjugate(parentRot); linkPart.OffsetPosition = axPos; + // Make the linking root SOP's rotation relative to the new root prim Quaternion oldRot = linkPart.RotationOffset; Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot; linkPart.RotationOffset = newRot; -// linkPart.ParentID = m_rootPart.LocalId; done above - + // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. + // Now that we know this SOG has at least two SOPs in it, the new root + // SOP becomes the first in the linkset. if (m_rootPart.LinkNum == 0) m_rootPart.LinkNum = 1; lock (m_parts.SyncRoot) { + // Calculate the new link number for the old root SOP int linkNum; if (insert) { @@ -2749,6 +2801,7 @@ namespace OpenSim.Region.Framework.Scenes linkNum = PrimCount + 1; } + // Add the old root SOP as a part in our group's list m_parts.Add(linkPart.UUID, linkPart); linkPart.SetParent(this); @@ -2756,6 +2809,8 @@ namespace OpenSim.Region.Framework.Scenes // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true); + + // If the added SOP is physical, also tell the physics engine about the link relationship. if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) { linkPart.PhysActor.link(m_rootPart.PhysActor); @@ -2763,21 +2818,28 @@ namespace OpenSim.Region.Framework.Scenes } linkPart.LinkNum = linkNum++; + linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false); + // Get a list of the SOP's in the old group in order of their linknum's. SceneObjectPart[] ogParts = objectGroup.Parts; Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) { return a.LinkNum - b.LinkNum; }); + // Add each of the SOP's from the old linkset to our linkset for (int i = 0; i < ogParts.Length; i++) { SceneObjectPart part = ogParts[i]; if (part.UUID != objectGroup.m_rootPart.UUID) { LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); - // let physics know + + // Update the physics flags for the newly added SOP + // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true); + + // If the added SOP is physical, also tell the physics engine about the link relationship. if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) { part.PhysActor.link(m_rootPart.PhysActor); @@ -2788,6 +2850,7 @@ namespace OpenSim.Region.Framework.Scenes } } + // Now that we've aquired all of the old SOG's parts, remove the old SOG from the scene. m_scene.UnlinkSceneObject(objectGroup, true); objectGroup.IsDeleted = true; @@ -2814,6 +2877,11 @@ namespace OpenSim.Region.Framework.Scenes /// Delink the given prim from this group. The delinked prim is established as /// an independent SceneObjectGroup. /// + /// + /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race + /// condition. But currently there is no + /// alternative method that does take a lonk to delink a single prim. + /// /// /// The object group of the newly delinked prim. Null if part could not be found public SceneObjectGroup DelinkFromGroup(uint partID) @@ -2825,6 +2893,11 @@ namespace OpenSim.Region.Framework.Scenes /// Delink the given prim from this group. The delinked prim is established as /// an independent SceneObjectGroup. /// + /// + /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race + /// condition. But currently there is no + /// alternative method that does take a lonk to delink a single prim. + /// /// /// /// The object group of the newly delinked prim. Null if part could not be found @@ -2850,6 +2923,11 @@ namespace OpenSim.Region.Framework.Scenes /// Delink the given prim from this group. The delinked prim is established as /// an independent SceneObjectGroup. /// + /// + /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race + /// condition. But currently there is no + /// alternative method that does take a lock to delink a single prim. + /// /// /// /// The object group of the newly delinked prim. @@ -2864,6 +2942,7 @@ namespace OpenSim.Region.Framework.Scenes linkPart.ClearUndoState(); + Vector3 worldPos = linkPart.GetWorldPosition(); Quaternion worldRot = linkPart.GetWorldRotation(); // Remove the part from this object @@ -2873,6 +2952,7 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart[] parts = m_parts.GetArray(); + // Rejigger the linknum's of the remaining SOP's to fill any gap if (parts.Length == 1 && RootPart != null) { // Single prim left @@ -2894,22 +2974,31 @@ namespace OpenSim.Region.Framework.Scenes PhysicsActor linkPartPa = linkPart.PhysActor; + // Remove the SOP from the physical scene. + // If the new SOG is physical, it is re-created later. + // (There is a problem here in that we have not yet told the physics + // engine about the delink. Someday, linksets should be made first + // class objects in the physics engine interface). if (linkPartPa != null) m_scene.PhysicsScene.RemovePrim(linkPartPa); // We need to reset the child part's position // ready for life as a separate object after being a part of another object + + /* This commented out code seems to recompute what GetWorldPosition already does. + * Replace with a call to GetWorldPosition (before unlinking) Quaternion parentRot = m_rootPart.RotationOffset; - Vector3 axPos = linkPart.OffsetPosition; - axPos *= parentRot; linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; linkPart.OffsetPosition = new Vector3(0, 0, 0); - + */ + linkPart.GroupPosition = worldPos; + linkPart.OffsetPosition = Vector3.Zero; linkPart.RotationOffset = worldRot; + // Create a new SOG to go around this unlinked and unattached SOP SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); m_scene.AddNewSceneObject(objectGroup, true); @@ -2947,42 +3036,58 @@ namespace OpenSim.Region.Framework.Scenes m_isBackedUp = false; } + // This links an SOP from a previous linkset into my linkset. + // The trick is that the SOP's position and rotation are relative to the old root SOP's + // so we are passed in the position and rotation of the old linkset so this can + // unjigger this SOP's position and rotation from the previous linkset and + // then make them relative to my linkset root. private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation, int linkNum) { Quaternion parentRot = oldGroupRotation; Quaternion oldRot = part.RotationOffset; - Quaternion worldRot = parentRot * oldRot; - - parentRot = oldGroupRotation; + // Move our position to not be relative to the old parent Vector3 axPos = part.OffsetPosition; - axPos *= parentRot; part.OffsetPosition = axPos; Vector3 newPos = oldGroupPosition + part.OffsetPosition; part.GroupPosition = newPos; part.OffsetPosition = Vector3.Zero; + + // Compution our rotation to be not relative to the old parent + Quaternion worldRot = parentRot * oldRot; part.RotationOffset = worldRot; + // Add this SOP to our linkset part.SetParent(this); part.ParentID = m_rootPart.LocalId; - m_parts.Add(part.UUID, part); part.LinkNum = linkNum; - part.OffsetPosition = newPos - AbsolutePosition; + // Compute the new position of this SOP relative to the group position + part.OffsetPosition = part.GroupPosition - AbsolutePosition; + // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. + // It would have the affect of setting the physics engine position multiple + // times. In theory, that is not necessary but I don't have a good linkset + // test to know that cleaning up this code wouldn't break things.) + + // Rotate the relative position by the rotation of the group Quaternion rootRotation = m_rootPart.RotationOffset; - Vector3 pos = part.OffsetPosition; pos *= Quaternion.Conjugate(rootRotation); part.OffsetPosition = pos; + // Compute the SOP's rotation relative to the rotation of the group. parentRot = m_rootPart.RotationOffset; oldRot = part.RotationOffset; Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot; part.RotationOffset = newRot; + + // Since this SOP's state has changed, push those changes into the physics engine + // and the simulator. + part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false); } /// @@ -3498,7 +3603,7 @@ namespace OpenSim.Region.Framework.Scenes //we need to do a terse update even if the move wasn't allowed // so that the position is reset in the client (the object snaps back) - ScheduleGroupForTerseUpdate(); + RootPart.ScheduleTerseUpdate(); } /// @@ -3613,6 +3718,11 @@ namespace OpenSim.Region.Framework.Scenes m_scene.PhysicsScene.AddPhysicsActorTaint(actor); } + if (IsAttachment) + { + m_rootPart.AttachedPos = pos; + } + AbsolutePosition = pos; HasGroupChanged = true; @@ -4199,7 +4309,86 @@ namespace OpenSim.Region.Framework.Scenes for (int i = 0; i < parts.Length; i++) parts[i].TriggerScriptChangedEvent(val); } - + + /// + /// Returns a count of the number of scripts in this groups parts. + /// + public int ScriptCount() + { + int count = 0; + SceneObjectPart[] parts = m_parts.GetArray(); + for (int i = 0; i < parts.Length; i++) + count += parts[i].Inventory.ScriptCount(); + + return count; + } + + /// + /// A float the value is a representative execution time in milliseconds of all scripts in the link set. + /// + public float ScriptExecutionTime() + { + IScriptModule[] engines = Scene.RequestModuleInterfaces(); + + if (engines.Length == 0) // No engine at all + return 0.0f; + + float time = 0.0f; + + // get all the scripts in all parts + SceneObjectPart[] parts = m_parts.GetArray(); + List scripts = new List(); + for (int i = 0; i < parts.Length; i++) + { + scripts.AddRange(parts[i].Inventory.GetInventoryItems(InventoryType.LSL)); + } + // extract the UUIDs + List ids = new List(scripts.Count); + foreach (TaskInventoryItem script in scripts) + { + if (!ids.Contains(script.ItemID)) + { + ids.Add(script.ItemID); + } + } + // Offer the list of script UUIDs to each engine found and accumulate the time + foreach (IScriptModule e in engines) + { + if (e != null) + { + time += e.GetScriptExecutionTime(ids); + } + } + return time; + } + + /// + /// Returns a count of the number of running scripts in this groups parts. + /// + public int RunningScriptCount() + { + int count = 0; + SceneObjectPart[] parts = m_parts.GetArray(); + for (int i = 0; i < parts.Length; i++) + count += parts[i].Inventory.RunningScriptCount(); + + return count; + } + + /// + /// Gets the number of sitting avatars. + /// + /// This applies to all sitting avatars whether there is a sit target set or not. + /// + public int GetSittingAvatarsCount() + { + int count = 0; + + Array.ForEach(m_parts.GetArray(), p => count += p.GetSittingAvatarsCount()); + + return count; + } + public override string ToString() { return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition); diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 735bd32671..bd11cde97b 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -147,6 +147,21 @@ namespace OpenSim.Region.Framework.Scenes get { return ParentGroup.RootPart == this; } } + /// + /// Is an explicit sit target set for this part? + /// + public bool IsSitTargetSet + { + get + { + return + !(SitTargetPosition == Vector3.Zero + && (SitTargetOrientation == Quaternion.Identity // Valid Zero Rotation quaternion + || SitTargetOrientation.X == 0f && SitTargetOrientation.Y == 0f && SitTargetOrientation.Z == 1f && SitTargetOrientation.W == 0f // W-Z Mapping was invalid at one point + || SitTargetOrientation.X == 0f && SitTargetOrientation.Y == 0f && SitTargetOrientation.Z == 0f && SitTargetOrientation.W == 0f)); // Invalid Quaternion + } + } + #region Fields public bool AllowedDrop; @@ -426,7 +441,6 @@ namespace OpenSim.Region.Framework.Scenes private uint _category; private Int32 _creationDate; private uint _parentID = 0; - private UUID m_sitTargetAvatar = UUID.Zero; private uint _baseMask = (uint)PermissionMask.All; private uint _ownerMask = (uint)PermissionMask.All; private uint _groupMask = (uint)PermissionMask.None; @@ -738,6 +752,7 @@ namespace OpenSim.Region.Framework.Scenes return m_groupPosition; } + // If I'm an attachment, my position is reported as the position of who I'm attached to if (ParentGroup.IsAttachment) { ScenePresence sp = ParentGroup.Scene.GetScenePresence(ParentGroup.AttachedAvatar); @@ -765,7 +780,7 @@ namespace OpenSim.Region.Framework.Scenes } else { - // To move the child prim in respect to the group position and rotation we have to calculate + // The physics engine always sees all objects (root or linked) in world coordinates. actor.Position = GetWorldPosition(); actor.Orientation = GetWorldRotation(); } @@ -844,6 +859,8 @@ namespace OpenSim.Region.Framework.Scenes { // We don't want the physics engine mucking up the rotations in a linkset PhysicsActor actor = PhysActor; + // If this is a root of a linkset, the real rotation is what the physics engine thinks. + // If not a root prim, the offset rotation is computed by SOG and is relative to the root. if (ParentID == 0 && (Shape.PCode != 9 || Shape.State == 0) && actor != null) { if (actor.Orientation.X != 0f || actor.Orientation.Y != 0f @@ -1024,7 +1041,18 @@ namespace OpenSim.Region.Framework.Scenes public int LinkNum { get { return m_linkNum; } - set { m_linkNum = value; } + set + { +// if (ParentGroup != null) +// { +// m_log.DebugFormat( +// "[SCENE OBJECT PART]: Setting linknum of {0}@{1} to {2} from {3}", +// Name, AbsolutePosition, value, m_linkNum); +// Util.PrintCallStack(); +// } + + m_linkNum = value; + } } public byte ClickAction @@ -1309,13 +1337,20 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// ID of the avatar that is sat on us. If there is no such avatar then is UUID.Zero + /// ID of the avatar that is sat on us if we have a sit target. If there is no such avatar then is UUID.Zero /// - public UUID SitTargetAvatar - { - get { return m_sitTargetAvatar; } - set { m_sitTargetAvatar = value; } - } + public UUID SitTargetAvatar { get; set; } + + /// + /// IDs of all avatars start on this object part. + /// + /// + /// We need to track this so that we can stop sat upon prims from being attached. + /// + /// + /// null if there are no sitting avatars. This is to save us create a hashset for every prim in a scene. + /// + private HashSet m_sittingAvatars; public virtual UUID RegionID { @@ -2111,7 +2146,7 @@ namespace OpenSim.Region.Framework.Scenes else m_log.WarnFormat( "[SCENE OBJECT PART]: Part {0} {1} requested mesh/sculpt data for asset id {2} from asset service but received no data", - Name, LocalId, id); + Name, UUID, id); } /// @@ -2216,6 +2251,9 @@ namespace OpenSim.Region.Framework.Scenes /// public void DoPhysicsPropertyUpdate(bool UsePhysics, bool isNew) { + if (ParentGroup.Scene == null) + return; + if (!ParentGroup.Scene.PhysicalPrims && UsePhysics) return; @@ -2494,14 +2532,20 @@ namespace OpenSim.Region.Framework.Scenes /// A Linked Child Prim objects position in world public Vector3 GetWorldPosition() { - Quaternion parentRot = ParentGroup.RootPart.RotationOffset; - Vector3 axPos = OffsetPosition; - axPos *= parentRot; - Vector3 translationOffsetPosition = axPos; - if(_parentID == 0) - return GroupPosition; + Vector3 ret; + if (_parentID == 0) + // if a root SOP, my position is what it is + ret = GroupPosition; else - return ParentGroup.AbsolutePosition + translationOffsetPosition; + { + // If a child SOP, my position is relative to the root SOP so take + // my info and add the root's position and rotation to + // get my world position. + Quaternion parentRot = ParentGroup.RootPart.RotationOffset; + Vector3 translationOffsetPosition = OffsetPosition * parentRot; + ret = ParentGroup.AbsolutePosition + translationOffsetPosition; + } + return ret; } /// @@ -2518,6 +2562,8 @@ namespace OpenSim.Region.Framework.Scenes } else { + // A child SOP's rotation is relative to the root SOP's rotation. + // Combine them to get my absolute rotation. Quaternion parentRot = ParentGroup.RootPart.RotationOffset; Quaternion oldRot = RotationOffset; newRot = parentRot * oldRot; @@ -3174,8 +3220,9 @@ namespace OpenSim.Region.Framework.Scenes if (ParentGroup.IsDeleted) return; - if (ParentGroup.IsAttachment && (ParentGroup.AttachedAvatar != remoteClient.AgentId) && - (ParentGroup.AttachmentPoint >= 31) && (ParentGroup.AttachmentPoint <= 38)) + if (ParentGroup.IsAttachment + && ParentGroup.AttachedAvatar != remoteClient.AgentId + && ParentGroup.HasPrivateAttachmentPoint) return; if (remoteClient.AgentId == OwnerID) @@ -3694,7 +3741,6 @@ namespace OpenSim.Region.Framework.Scenes hasProfileCut = hasDimple; // is it the same thing? } - public void SetGroup(UUID groupID, IClientAPI client) { // Scene.AddNewPrims() calls with client == null so can't use this. @@ -3724,10 +3770,12 @@ namespace OpenSim.Region.Framework.Scenes public void SetPhysicsAxisRotation() { - if (PhysActor != null) + PhysicsActor pa = PhysActor; + + if (pa != null) { - PhysActor.LockAngularMotion(RotationAxis); - ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); + pa.LockAngularMotion(RotationAxis); + ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa); } } @@ -4444,7 +4492,7 @@ namespace OpenSim.Region.Framework.Scenes // For now, we use the NINJA naming scheme for identifying joints. // In the future, we can support other joint specification schemes such as a // custom checkbox in the viewer GUI. - if (ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) + if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) { string hingeString = "hingejoint"; return (Name.Length >= hingeString.Length && Name.Substring(0, hingeString.Length) == hingeString); @@ -4460,7 +4508,7 @@ namespace OpenSim.Region.Framework.Scenes // For now, we use the NINJA naming scheme for identifying joints. // In the future, we can support other joint specification schemes such as a // custom checkbox in the viewer GUI. - if (ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) + if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) { string ballString = "balljoint"; return (Name.Length >= ballString.Length && Name.Substring(0, ballString.Length) == ballString); @@ -4476,7 +4524,7 @@ namespace OpenSim.Region.Framework.Scenes // For now, we use the NINJA naming scheme for identifying joints. // In the future, we can support other joint specification schemes such as a // custom checkbox in the viewer GUI. - if (ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) + if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints) { return IsHingeJoint() || IsBallJoint(); } @@ -4598,7 +4646,6 @@ namespace OpenSim.Region.Framework.Scenes } */ } - else // it already has a physical representation { DoPhysicsPropertyUpdate(UsePhysics, false); // Update physical status. @@ -5074,8 +5121,9 @@ namespace OpenSim.Region.Framework.Scenes if (ParentGroup.IsDeleted) return; - if (ParentGroup.IsAttachment && ((ParentGroup.RootPart != this) || - ((ParentGroup.AttachedAvatar != remoteClient.AgentId) && (ParentGroup.AttachmentPoint >= 31) && (ParentGroup.AttachmentPoint <= 38)))) + if (ParentGroup.IsAttachment + && (ParentGroup.RootPart != this + || ParentGroup.AttachedAvatar != remoteClient.AgentId && ParentGroup.HasPrivateAttachmentPoint)) return; // Causes this thread to dig into the Client Thread Data. @@ -5147,5 +5195,99 @@ namespace OpenSim.Region.Framework.Scenes Inventory.UpdateInventoryItem(item, false, false); } } + + /// + /// Record an avatar sitting on this part. + /// + /// This is called for all the sitting avatars whether there is a sit target set or not. + /// + /// true if the avatar was not already recorded, false otherwise. + /// + /// + protected internal bool AddSittingAvatar(UUID avatarId) + { + if (IsSitTargetSet && SitTargetAvatar == UUID.Zero) + SitTargetAvatar = avatarId; + + HashSet sittingAvatars = m_sittingAvatars; + + if (sittingAvatars == null) + sittingAvatars = new HashSet(); + + lock (sittingAvatars) + { + m_sittingAvatars = sittingAvatars; + return m_sittingAvatars.Add(avatarId); + } + } + + /// + /// Remove an avatar recorded as sitting on this part. + /// + /// This applies to all sitting avatars whether there is a sit target set or not. + /// + /// true if the avatar was present and removed, false if it was not present. + /// + /// + protected internal bool RemoveSittingAvatar(UUID avatarId) + { + if (SitTargetAvatar == avatarId) + SitTargetAvatar = UUID.Zero; + + HashSet sittingAvatars = m_sittingAvatars; + + // This can occur under a race condition where another thread + if (sittingAvatars == null) + return false; + + lock (sittingAvatars) + { + if (sittingAvatars.Remove(avatarId)) + { + if (sittingAvatars.Count == 0) + m_sittingAvatars = null; + + return true; + } + } + + return false; + } + + /// + /// Get a copy of the list of sitting avatars. + /// + /// This applies to all sitting avatars whether there is a sit target set or not. + /// A hashset of the sitting avatars. Returns null if there are no sitting avatars. + public HashSet GetSittingAvatars() + { + HashSet sittingAvatars = m_sittingAvatars; + + if (sittingAvatars == null) + { + return null; + } + else + { + lock (sittingAvatars) + return new HashSet(sittingAvatars); + } + } + + /// + /// Gets the number of sitting avatars. + /// + /// This applies to all sitting avatars whether there is a sit target set or not. + /// + public int GetSittingAvatarsCount() + { + HashSet sittingAvatars = m_sittingAvatars; + + if (sittingAvatars == null) + return 0; + + lock (sittingAvatars) + return sittingAvatars.Count; + } } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 959046ac05..1c9a17ef9e 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -176,16 +176,14 @@ namespace OpenSim.Region.Framework.Scenes /// public void ChangeInventoryOwner(UUID ownerId) { - m_items.LockItemsForWrite(true); - if (0 == Items.Count) - { - m_items.LockItemsForWrite(false); - return; - } + List items = GetInventoryItems(); + if (items.Count == 0) + return; + + m_items.LockItemsForWrite(true); HasInventoryChanged = true; m_part.ParentGroup.HasGroupChanged = true; - List items = GetInventoryItems(); foreach (TaskInventoryItem item in items) { if (ownerId != item.OwnerID) @@ -234,7 +232,7 @@ namespace OpenSim.Region.Framework.Scenes private void QueryScriptStates() { - if (m_part == null || m_part.ParentGroup == null) + if (m_part == null || m_part.ParentGroup == null || m_part.ParentGroup.Scene == null) return; IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces(); @@ -262,19 +260,16 @@ namespace OpenSim.Region.Framework.Scenes Items.LockItemsForRead(false); } - /// - /// Start all the scripts contained in this prim's inventory - /// - public void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource) + public int CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource) { - Items.LockItemsForRead(true); - IList items = new List(Items.Values); - Items.LockItemsForRead(false); - foreach (TaskInventoryItem item in items) - { - if ((int)InventoryType.LSL == item.InvType) - CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); - } + int scriptsValidForStarting = 0; + + List scripts = GetInventoryItems(InventoryType.LSL); + foreach (TaskInventoryItem item in scripts) + if (CreateScriptInstance(item, startParam, postOnRez, engine, stateSource)) + scriptsValidForStarting++; + + return scriptsValidForStarting; } public ArrayList GetScriptErrors(UUID itemID) @@ -297,7 +292,7 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Stop all the scripts in this prim. + /// Stop and remove all the scripts in this prim. /// /// /// Should be true if these scripts are being removed because the scene @@ -305,26 +300,28 @@ namespace OpenSim.Region.Framework.Scenes /// public void RemoveScriptInstances(bool sceneObjectBeingDeleted) { - Items.LockItemsForRead(true); - IList items = new List(Items.Values); - Items.LockItemsForRead(false); - - foreach (TaskInventoryItem item in items) + List scripts = GetInventoryItems(InventoryType.LSL); + foreach (TaskInventoryItem item in scripts) { - if ((int)InventoryType.LSL == item.InvType) - { - RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted); - m_part.RemoveScriptEvents(item.ItemID); - } + RemoveScriptInstance(item.ItemID, sceneObjectBeingDeleted); + m_part.RemoveScriptEvents(item.ItemID); } } + /// + /// Stop all the scripts in this prim. + /// + public void StopScriptInstances() + { + GetInventoryItems(InventoryType.LSL).ForEach(i => StopScriptInstance(i)); + } + /// /// Start a script which is in this prim's inventory. /// /// - /// - public void CreateScriptInstance(TaskInventoryItem item, int startParam, bool postOnRez, string engine, int stateSource) + /// true if the script instance was created, false otherwise + public bool CreateScriptInstance(TaskInventoryItem item, int startParam, bool postOnRez, string engine, int stateSource) { // m_log.DebugFormat("[PRIM INVENTORY]: Starting script {0} {1} in prim {2} {3} in {4}", // item.Name, item.ItemID, m_part.Name, m_part.UUID, m_part.ParentGroup.Scene.RegionInfo.RegionName); @@ -332,61 +329,70 @@ namespace OpenSim.Region.Framework.Scenes if (!m_part.ParentGroup.Scene.Permissions.CanRunScript(item.ItemID, m_part.UUID, item.OwnerID)) { StoreScriptError(item.ItemID, "no permission"); - return; + return false; } m_part.AddFlag(PrimFlags.Scripted); - if (!m_part.ParentGroup.Scene.RegionInfo.RegionSettings.DisableScripts) - { - if (stateSource == 2 && // Prim crossing - m_part.ParentGroup.Scene.m_trustBinaries) - { - m_items.LockItemsForWrite(true); - m_items[item.ItemID].PermsMask = 0; - m_items[item.ItemID].PermsGranter = UUID.Zero; - m_items.LockItemsForWrite(false); - m_part.ParentGroup.Scene.EventManager.TriggerRezScript( - m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource); - StoreScriptErrors(item.ItemID, null); - m_part.ParentGroup.AddActiveScriptCount(1); - m_part.ScheduleFullUpdate(); - return; - } + if (m_part.ParentGroup.Scene.RegionInfo.RegionSettings.DisableScripts) + return false; - AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString()); - if (null == asset) - { - string msg = String.Format("asset ID {0} could not be found", item.AssetID); - StoreScriptError(item.ItemID, msg); - m_log.ErrorFormat( + if (stateSource == 2 && // Prim crossing + m_part.ParentGroup.Scene.m_trustBinaries) + { + m_items.LockItemsForWrite(true); + m_items[item.ItemID].PermsMask = 0; + m_items[item.ItemID].PermsGranter = UUID.Zero; + m_items.LockItemsForWrite(false); + m_part.ParentGroup.Scene.EventManager.TriggerRezScript( + m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource); + StoreScriptErrors(item.ItemID, null); + m_part.ParentGroup.AddActiveScriptCount(1); + m_part.ScheduleFullUpdate(); + return true; + } + + AssetBase asset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString()); + if (null == asset) + { + m_log.ErrorFormat( + "[PRIM INVENTORY]: Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found", + item.Name, item.ItemID, m_part.AbsolutePosition, + m_part.ParentGroup.Scene.RegionInfo.RegionName, item.AssetID); + + return false; + } + else + { + if (m_part.ParentGroup.m_savedScriptState != null) + item.OldItemID = RestoreSavedScriptState(item.LoadedItemID, item.OldItemID, item.ItemID); + + string msg = String.Format("asset ID {0} could not be found", item.AssetID); + StoreScriptError(item.ItemID, msg); + m_log.ErrorFormat( "[PRIM INVENTORY]: Couldn't start script {0}, {1} at {2} in {3} since asset ID {4} could not be found", item.Name, item.ItemID, m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName, item.AssetID); - } - else - { - if (m_part.ParentGroup.m_savedScriptState != null) - item.OldItemID = RestoreSavedScriptState(item.LoadedItemID, item.OldItemID, item.ItemID); - m_items.LockItemsForWrite(true); + m_items.LockItemsForWrite(true); - m_items[item.ItemID].OldItemID = item.OldItemID; - m_items[item.ItemID].PermsMask = 0; - m_items[item.ItemID].PermsGranter = UUID.Zero; + m_items[item.ItemID].OldItemID = item.OldItemID; + m_items[item.ItemID].PermsMask = 0; + m_items[item.ItemID].PermsGranter = UUID.Zero; - m_items.LockItemsForWrite(false); + m_items.LockItemsForWrite(false); - string script = Utils.BytesToString(asset.Data); - m_part.ParentGroup.Scene.EventManager.TriggerRezScript( - m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource); - StoreScriptErrors(item.ItemID, null); - if (!item.ScriptRunning) - m_part.ParentGroup.Scene.EventManager.TriggerStopScript( - m_part.LocalId, item.ItemID); - m_part.ParentGroup.AddActiveScriptCount(1); - m_part.ScheduleFullUpdate(); - } + string script = Utils.BytesToString(asset.Data); + m_part.ParentGroup.Scene.EventManager.TriggerRezScript( + m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource); + StoreScriptErrors(item.ItemID, null); + if (!item.ScriptRunning) + m_part.ParentGroup.Scene.EventManager.TriggerStopScript( + m_part.LocalId, item.ItemID); + m_part.ParentGroup.AddActiveScriptCount(1); + m_part.ScheduleFullUpdate(); + + return true; } } @@ -459,7 +465,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// A /// - public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) + public bool CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) { lock (m_scriptErrors) { @@ -467,6 +473,7 @@ namespace OpenSim.Region.Framework.Scenes m_scriptErrors.Remove(itemId); } CreateScriptInstanceInternal(itemId, startParam, postOnRez, engine, stateSource); + return true; } private void CreateScriptInstanceInternal(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) @@ -597,7 +604,7 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// Stop a script which is in this prim's inventory. + /// Stop and remove a script which is in this prim's inventory. /// /// /// @@ -616,7 +623,7 @@ namespace OpenSim.Region.Framework.Scenes } else { - m_log.ErrorFormat( + m_log.WarnFormat( "[PRIM INVENTORY]: " + "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", itemId, m_part.Name, m_part.UUID, @@ -624,6 +631,51 @@ namespace OpenSim.Region.Framework.Scenes } } + /// + /// Stop a script which is in this prim's inventory. + /// + /// + /// + /// Should be true if this script is being removed because the scene + /// object is being deleted. This will prevent spurious updates to the client. + /// + public void StopScriptInstance(UUID itemId) + { + TaskInventoryItem scriptItem; + + lock (m_items) + m_items.TryGetValue(itemId, out scriptItem); + + if (scriptItem != null) + { + StopScriptInstance(scriptItem); + } + else + { + m_log.WarnFormat( + "[PRIM INVENTORY]: " + + "Couldn't stop script with ID {0} since it couldn't be found for prim {1}, {2} at {3} in {4}", + itemId, m_part.Name, m_part.UUID, + m_part.AbsolutePosition, m_part.ParentGroup.Scene.RegionInfo.RegionName); + } + } + + /// + /// Stop a script which is in this prim's inventory. + /// + /// + /// + /// Should be true if this script is being removed because the scene + /// object is being deleted. This will prevent spurious updates to the client. + /// + public void StopScriptInstance(TaskInventoryItem item) + { + m_part.ParentGroup.Scene.EventManager.TriggerStopScript(m_part.LocalId, item.ItemID); + + // At the moment, even stopped scripts are counted as active, which is probably wrong. +// m_part.ParentGroup.AddActiveScriptCount(-1); + } + /// /// Check if the inventory holds an item with a given name. /// @@ -770,14 +822,22 @@ namespace OpenSim.Region.Framework.Scenes return item; } - /// - /// Get inventory items by name. - /// - /// - /// - /// A list of inventory items with that name. - /// If no inventory item has that name then an empty list is returned. - /// + public TaskInventoryItem GetInventoryItem(string name) + { + m_items.LockItemsForRead(true); + foreach (TaskInventoryItem item in m_items.Values) + { + if (item.Name == name) + { + m_items.LockItemsForRead(false); + return item; + } + } + m_items.LockItemsForRead(false); + + return null; + } + public List GetInventoryItems(string name) { List items = new List(); @@ -1247,10 +1307,10 @@ namespace OpenSim.Region.Framework.Scenes if ((item.CurrentPermissions & ((uint)PermissionMask.Modify >> 13)) == 0) item.CurrentPermissions &= ~(uint)PermissionMask.Modify; } - item.OwnerChanged = true; item.CurrentPermissions &= item.NextPermissions; item.BasePermissions &= item.NextPermissions; item.EveryonePermissions &= item.NextPermissions; + item.OwnerChanged = true; item.PermsMask = 0; item.PermsGranter = UUID.Zero; } @@ -1281,9 +1341,57 @@ namespace OpenSim.Region.Framework.Scenes return true; } } + return false; } + /// + /// Returns the count of scripts in this parts inventory. + /// + /// + public int ScriptCount() + { + int count = 0; + Items.LockItemsForRead(true); + foreach (TaskInventoryItem item in m_items.Values) + { + if (item.InvType == (int)InventoryType.LSL) + { + count++; + } + } + Items.LockItemsForRead(false); + return count; + } + /// + /// Returns the count of running scripts in this parts inventory. + /// + /// + public int RunningScriptCount() + { + IScriptModule[] engines = m_part.ParentGroup.Scene.RequestModuleInterfaces(); + if (engines.Length == 0) + return 0; + + int count = 0; + List scripts = GetInventoryItems(InventoryType.LSL); + + foreach (TaskInventoryItem item in scripts) + { + foreach (IScriptModule engine in engines) + { + if (engine != null) + { + if (engine.GetScriptState(item.ItemID)) + { + count++; + } + } + } + } + return count; + } + public List GetInventoryList() { List ret = new List(); @@ -1298,22 +1406,24 @@ namespace OpenSim.Region.Framework.Scenes { List ret = new List(); - lock (m_items) - ret = new List(m_items.Values); + Items.LockItemsForRead(true); + ret = new List(m_items.Values); + Items.LockItemsForRead(false); return ret; } - public List GetInventoryScripts() + public List GetInventoryItems(InventoryType type) { List ret = new List(); - lock (m_items) - { - foreach (TaskInventoryItem item in m_items.Values) - if (item.InvType == (int)InventoryType.LSL) - ret.Add(item); - } + Items.LockItemsForRead(true); + + foreach (TaskInventoryItem item in m_items.Values) + if (item.InvType == (int)type) + ret.Add(item); + + Items.LockItemsForRead(false); return ret; } @@ -1335,35 +1445,36 @@ namespace OpenSim.Region.Framework.Scenes if (engines.Length == 0) // No engine at all return ret; - Items.LockItemsForRead(true); - foreach (TaskInventoryItem item in m_items.Values) + List scripts = GetInventoryItems(InventoryType.LSL); + + foreach (TaskInventoryItem item in scripts) { - if (item.InvType == (int)InventoryType.LSL) + foreach (IScriptModule e in engines) { - foreach (IScriptModule e in engines) + if (e != null) { - if (e != null) +// m_log.DebugFormat( +// "[PRIM INVENTORY]: Getting script state from engine {0} for {1} in part {2} in group {3} in {4}", +// e.Name, item.Name, m_part.Name, m_part.ParentGroup.Name, m_part.ParentGroup.Scene.Name); + + string n = e.GetXMLState(item.ItemID); + if (n != String.Empty) { - string n = e.GetXMLState(item.ItemID); - if (n != String.Empty) + if (oldIDs) { - if (oldIDs) - { - if (!ret.ContainsKey(item.OldItemID)) - ret[item.OldItemID] = n; - } - else - { - if (!ret.ContainsKey(item.ItemID)) - ret[item.ItemID] = n; - } - break; + if (!ret.ContainsKey(item.OldItemID)) + ret[item.OldItemID] = n; } + else + { + if (!ret.ContainsKey(item.ItemID)) + ret[item.ItemID] = n; + } + break; } } } } - Items.LockItemsForRead(false); return ret; } @@ -1373,27 +1484,27 @@ namespace OpenSim.Region.Framework.Scenes if (engines.Length == 0) return; + List scripts = GetInventoryItems(InventoryType.LSL); - Items.LockItemsForRead(true); - - foreach (TaskInventoryItem item in m_items.Values) + foreach (TaskInventoryItem item in scripts) { - if (item.InvType == (int)InventoryType.LSL) + foreach (IScriptModule engine in engines) { - foreach (IScriptModule engine in engines) + if (engine != null) { - if (engine != null) - { - if (item.OwnerChanged) - engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER }); - item.OwnerChanged = false; - engine.ResumeScript(item.ItemID); - } +// m_log.DebugFormat( +// "[PRIM INVENTORY]: Resuming script {0} {1} for {2}, OwnerChanged {3}", +// item.Name, item.ItemID, item.OwnerID, item.OwnerChanged); + + engine.ResumeScript(item.ItemID); + + if (item.OwnerChanged) + engine.PostScriptEvent(item.ItemID, "changed", new Object[] { (int)Changed.OWNER }); + + item.OwnerChanged = false; } } } - - Items.LockItemsForRead(false); } } } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 4940063ead..e27d3096b0 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -45,6 +45,7 @@ using TeleportFlags = OpenSim.Framework.Constants.TeleportFlags; namespace OpenSim.Region.Framework.Scenes { + [Flags] enum ScriptControlled : uint { CONTROL_ZERO = 0, @@ -76,6 +77,11 @@ namespace OpenSim.Region.Framework.Scenes // { // m_log.Debug("[SCENE PRESENCE] Destructor called"); // } + private void TriggerScenePresenceUpdated() + { + if (m_scene != null) + m_scene.EventManager.TriggerScenePresenceUpdated(this); + } private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -497,6 +503,7 @@ namespace OpenSim.Region.Framework.Scenes //m_log.DebugFormat( // "[ENTITY BASE]: In {0} set AbsolutePosition of {1} to {2}", // Scene.RegionInfo.RegionName, Name, m_pos); + TriggerScenePresenceUpdated(); } } @@ -516,6 +523,7 @@ namespace OpenSim.Region.Framework.Scenes return; m_pos = value; + TriggerScenePresenceUpdated(); } } @@ -585,6 +593,12 @@ namespace OpenSim.Region.Framework.Scenes } private UUID m_parentUUID = UUID.Zero; + /// + /// Are we sitting on an object? + /// + /// A more readable way of testing presence sit status than ParentID == 0 + public bool IsSatOnObject { get { return ParentID != 0; } } + /// /// If the avatar is sitting, the prim that it's sitting on. If not sitting then null. /// @@ -1087,23 +1101,13 @@ namespace OpenSim.Region.Framework.Scenes /// public void Teleport(Vector3 pos) { - bool isFlying = Flying; - RemoveFromPhysicalScene(); - Velocity = Vector3.Zero; - CheckLandingPoint(ref pos); - AbsolutePosition = pos; - AddToPhysicalScene(isFlying); - - SendTerseUpdateToAllClients(); - } - - public void TeleportWithMomentum(Vector3 pos) - { - TeleportWithMomentum(pos, null); + TeleportWithMomentum(pos, Vector3.Zero); } public void TeleportWithMomentum(Vector3 pos, Vector3? v) { + if (ParentID != (uint)0) + StandUp(); bool isFlying = Flying; Vector3 vel = Velocity; RemoveFromPhysicalScene(); @@ -1283,17 +1287,33 @@ namespace OpenSim.Region.Framework.Scenes bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); MakeRootAgent(AbsolutePosition, flying); - - if ((m_callbackURI != null) && !m_callbackURI.Equals("")) - { - m_log.DebugFormat("[SCENE PRESENCE]: Releasing agent in URI {0}", m_callbackURI); - Scene.SimulationService.ReleaseAgent(m_originRegionID, UUID, m_callbackURI); - m_callbackURI = null; - } + ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); // m_log.DebugFormat("[SCENE PRESENCE] Completed movement"); - ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); + if ((m_callbackURI != null) && !m_callbackURI.Equals("")) + { + // We cannot sleep here since this would hold up the inbound packet processing thread, as + // CompleteMovement() is executed synchronously. However, it might be better to delay the release + // here until we know for sure that the agent is active in this region. Sending AgentMovementComplete + // is not enough for Imprudence clients - there appears to be a small delay (<200ms, <500ms) until they regard this + // region as the current region, meaning that a close sent before then will fail the teleport. +// System.Threading.Thread.Sleep(2000); + + m_log.DebugFormat( + "[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}", + client.Name, client.AgentId, m_callbackURI); + + Scene.SimulationService.ReleaseAgent(m_originRegionID, UUID, m_callbackURI); + m_callbackURI = null; + } +// else +// { +// m_log.DebugFormat( +// "[SCENE PRESENCE]: No callback provided on CompleteMovement of {0} {1} to {2}", +// client.Name, client.AgentId, m_scene.RegionInfo.RegionName); +// } + ValidateAndSendAppearanceAndAgentData(); // Create child agents in neighbouring regions @@ -1308,7 +1328,6 @@ namespace OpenSim.Region.Framework.Scenes friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); } - // m_log.DebugFormat( // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); @@ -1361,7 +1380,7 @@ namespace OpenSim.Region.Framework.Scenes { // m_log.DebugFormat( // "[SCENE PRESENCE]: In {0} received agent update from {1}, flags {2}", -// Scene.RegionInfo.RegionName, remoteClient.Name, agentData.ControlFlags); +// Scene.RegionInfo.RegionName, remoteClient.Name, (AgentManager.ControlFlags)agentData.ControlFlags); if (IsChildAgent) { @@ -1471,14 +1490,8 @@ namespace OpenSim.Region.Framework.Scenes } } - lock (scriptedcontrols) - { - if (scriptedcontrols.Count > 0) - { - SendControlToScripts((uint)flags); - flags = RemoveIgnoredControls(flags, IgnoredControls); - } - } + uint flagsForScripts = (uint)flags; + flags = RemoveIgnoredControls(flags, IgnoredControls); if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) HandleAgentSitOnGround(); @@ -1492,6 +1505,7 @@ namespace OpenSim.Region.Framework.Scenes PhysicsActor actor = PhysicsActor; if (actor == null) { + SendControlsToScripts(flagsForScripts); return; } @@ -1571,7 +1585,7 @@ namespace OpenSim.Region.Framework.Scenes MovementFlag |= (byte)nudgehack; } -// m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with {1}", Name, DCF); + //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with {1}", Name, DCF); MovementFlag += (byte)(uint)DCF; update_movementflag = true; } @@ -1584,7 +1598,7 @@ namespace OpenSim.Region.Framework.Scenes && ((MovementFlag & (byte)nudgehack) == nudgehack)) ) // This or is for Nudge forward { -// m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with lack of {1}", Name, DCF); + //m_log.DebugFormat("[SCENE PRESENCE]: Updating MovementFlag for {0} with lack of {1}", Name, DCF); MovementFlag -= ((byte)(uint)DCF); update_movementflag = true; @@ -1665,11 +1679,14 @@ namespace OpenSim.Region.Framework.Scenes // } // } -// if (update_movementflag && ParentID == 0) -// Animator.UpdateMovementAnimations(); + if (update_movementflag && ParentID == 0) + Animator.UpdateMovementAnimations(); + + SendControlsToScripts(flagsForScripts); } m_scene.EventManager.TriggerOnClientMovement(this); + TriggerScenePresenceUpdated(); } /// @@ -1929,10 +1946,6 @@ namespace OpenSim.Region.Framework.Scenes } } - // Reset sit target. - if (part.SitTargetAvatar == UUID) - part.SitTargetAvatar = UUID.Zero; - part.ParentGroup.DeleteAvatar(UUID); // ParentPosition = part.GetWorldPosition(); ControllingClient.SendClearFollowCamProperties(part.ParentUUID); @@ -1950,6 +1963,8 @@ namespace OpenSim.Region.Framework.Scenes SendAvatarDataToAllAgents(); m_requestedSitTargetID = 0; + part.RemoveSittingAvatar(UUID); + if (part != null) part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); } @@ -1983,15 +1998,7 @@ namespace OpenSim.Region.Framework.Scenes //look for prims with explicit sit targets that are available foreach (SceneObjectPart part in partArray) { - // Is a sit target available? - Vector3 avSitOffset = part.SitTargetPosition; - Quaternion avSitOrientation = part.SitTargetOrientation; - UUID avOnTargetAlready = part.SitTargetAvatar; - - bool SitTargetUnOccupied = avOnTargetAlready == UUID.Zero; - bool SitTargetisSet = avSitOffset != Vector3.Zero || avSitOrientation != Quaternion.Identity; - - if (SitTargetisSet && SitTargetUnOccupied) + if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero) { //switch the target to this prim return part; @@ -2002,10 +2009,8 @@ namespace OpenSim.Region.Framework.Scenes return targetPart; } - private void SendSitResponse(UUID targetID, Vector3 offset, Quaternion pSitOrientation) + private void SendSitResponse(UUID targetID, Vector3 offset, Quaternion sitOrientation) { - Vector3 pos = new Vector3(); - Quaternion sitOrientation = pSitOrientation; Vector3 cameraEyeOffset = Vector3.Zero; Vector3 cameraAtOffset = Vector3.Zero; bool forceMouselook = false; @@ -2017,54 +2022,39 @@ namespace OpenSim.Region.Framework.Scenes // TODO: determine position to sit at based on scene geometry; don't trust offset from client // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it - // Is a sit target available? - Vector3 avSitOffSet = part.SitTargetPosition; - Quaternion avSitOrientation = part.SitTargetOrientation; - UUID avOnTargetAlready = part.SitTargetAvatar; - - bool SitTargetUnOccupied = (!(avOnTargetAlready != UUID.Zero)); - bool SitTargetisSet = - (!(avSitOffSet == Vector3.Zero && - ( - avSitOrientation == Quaternion.Identity // Valid Zero Rotation quaternion - || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 1f && avSitOrientation.W == 0f // W-Z Mapping was invalid at one point - || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f && avSitOrientation.W == 0f // Invalid Quaternion - ) - )); - -// m_log.DebugFormat("[SCENE PRESENCE]: {0} {1}", SitTargetisSet, SitTargetUnOccupied); - if (PhysicsActor != null) m_sitAvatarHeight = PhysicsActor.Size.Z * 0.5f; bool canSit = false; - pos = part.AbsolutePosition + offset; + Vector3 pos = part.AbsolutePosition + offset; - if (SitTargetisSet) + if (part.IsSitTargetSet && part.SitTargetAvatar == UUID.Zero) { - if (SitTargetUnOccupied) - { - m_log.DebugFormat( - "[SCENE PRESENCE]: Sitting {0} on {1} {2} because sit target is set and unoccupied", - Name, part.Name, part.LocalId); +// m_log.DebugFormat( +// "[SCENE PRESENCE]: Sitting {0} on {1} {2} because sit target is set and unoccupied", +// Name, part.Name, part.LocalId); - part.SitTargetAvatar = UUID; - offset = new Vector3(avSitOffSet.X, avSitOffSet.Y, avSitOffSet.Z); - sitOrientation = avSitOrientation; - canSit = true; - } + offset = part.SitTargetPosition; + sitOrientation = part.SitTargetOrientation; + canSit = true; } else { if (Util.GetDistanceTo(AbsolutePosition, pos) <= 10) { - m_log.DebugFormat( - "[SCENE PRESENCE]: Sitting {0} on {1} {2} because sit target is unset and within 10m", - Name, part.Name, part.LocalId); +// m_log.DebugFormat( +// "[SCENE PRESENCE]: Sitting {0} on {1} {2} because sit target is unset and within 10m", +// Name, part.Name, part.LocalId); AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight); canSit = true; } +// else +// { +// m_log.DebugFormat( +// "[SCENE PRESENCE]: Ignoring sit request of {0} on {1} {2} because sit target is unset and outside 10m", +// Name, part.Name, part.LocalId); +// } } if (canSit) @@ -2075,6 +2065,8 @@ namespace OpenSim.Region.Framework.Scenes RemoveFromPhysicalScene(); } + part.AddSittingAvatar(UUID); + cameraAtOffset = part.GetCameraAtOffset(); cameraEyeOffset = part.GetCameraEyeOffset(); forceMouselook = part.GetForceMouselook(); @@ -2351,6 +2343,15 @@ namespace OpenSim.Region.Framework.Scenes if (part != null) { + if (part.ParentGroup.IsAttachment) + { + m_log.WarnFormat( + "[SCENE PRESENCE]: Avatar {0} tried to sit on part {1} from object {2} in {3} but this is an attachment for avatar id {4}", + Name, part.Name, part.ParentGroup.Name, Scene.Name, part.ParentGroup.AttachedAvatar); + + return; + } + if (part.SitTargetAvatar == UUID) { Vector3 sitTargetPos = part.SitTargetPosition; @@ -2616,6 +2617,7 @@ namespace OpenSim.Region.Framework.Scenes m_scene.ForEachClient(SendTerseUpdateToClient); } + TriggerScenePresenceUpdated(); } public void SendCoarseLocations(List coarseLocations, List avatarUUIDs) @@ -2694,7 +2696,7 @@ namespace OpenSim.Region.Framework.Scenes // If we are using the the cached appearance then send it out to everyone if (cachedappearance) { - m_log.DebugFormat("[SCENEPRESENCE]: baked textures are in the cache for {0}", Name); + m_log.DebugFormat("[SCENE PRESENCE]: baked textures are in the cache for {0}", Name); // If the avatars baked textures are all in the cache, then we have a // complete appearance... send it out, if not, then we'll send it when @@ -3099,8 +3101,8 @@ namespace OpenSim.Region.Framework.Scenes x = x / Constants.RegionSize; y = y / Constants.RegionSize; - //m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX))); - //m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY))); +// m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX))); +// m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY))); if (Util.IsOutsideView(DrawDistance, x, newRegionX, y, newRegionY)) { byebyeRegions.Add(handle); @@ -3157,7 +3159,7 @@ namespace OpenSim.Region.Framework.Scenes public void ChildAgentDataUpdate(AgentData cAgentData) { - //m_log.Debug(" >>> ChildAgentDataUpdate <<< " + Scene.RegionInfo.RegionName); +// m_log.Debug(" >>> ChildAgentDataUpdate <<< " + Scene.RegionInfo.RegionName); if (!IsChildAgent) return; @@ -3269,31 +3271,8 @@ namespace OpenSim.Region.Framework.Scenes catch { } cAgent.DefaultAnim = Animator.Animations.DefaultAnimation; - // Attachment objects - List attachments = GetAttachments(); - if (attachments.Count > 0) - { - cAgent.AttachmentObjects = new List(); - cAgent.AttachmentObjectStates = new List(); -// IScriptModule se = m_scene.RequestModuleInterface(); - InTransitScriptStates.Clear(); - - foreach (SceneObjectGroup sog in attachments) - { - // We need to make a copy and pass that copy - // because of transfers withn the same sim - ISceneObject clone = sog.CloneForNewScene(); - // Attachment module assumes that GroupPosition holds the offsets...! - ((SceneObjectGroup)clone).RootPart.GroupPosition = sog.RootPart.AttachedPos; - ((SceneObjectGroup)clone).IsAttachment = false; - cAgent.AttachmentObjects.Add(clone); - string state = sog.GetStateSnapshot(); - cAgent.AttachmentObjectStates.Add(state); - InTransitScriptStates.Add(state); - // Let's remove the scripts of the original object here - sog.RemoveScriptInstances(true); - } - } + if (Scene.AttachmentsModule != null) + Scene.AttachmentsModule.CopyAttachments(this, cAgent); } private void CopyFrom(AgentData cAgent) @@ -3301,6 +3280,9 @@ namespace OpenSim.Region.Framework.Scenes m_originRegionID = cAgent.RegionID; m_callbackURI = cAgent.CallbackURI; +// m_log.DebugFormat( +// "[SCENE PRESENCE]: Set callback for {0} in {1} to {2} in CopyFrom()", +// Name, m_scene.RegionInfo.RegionName, m_callbackURI); m_pos = cAgent.Position; m_velocity = cAgent.Velocity; @@ -3365,18 +3347,8 @@ namespace OpenSim.Region.Framework.Scenes if (cAgent.DefaultAnim != null) Animator.Animations.SetDefaultAnimation(cAgent.DefaultAnim.AnimID, cAgent.DefaultAnim.SequenceNum, UUID.Zero); - if (cAgent.AttachmentObjects != null && cAgent.AttachmentObjects.Count > 0) - { - m_attachments = new List(); - int i = 0; - foreach (ISceneObject so in cAgent.AttachmentObjects) - { - ((SceneObjectGroup)so).LocalId = 0; - ((SceneObjectGroup)so).RootPart.ClearUpdateSchedule(); - so.SetState(cAgent.AttachmentObjectStates[i++], m_scene); - m_scene.IncomingCreateObject(Vector3.Zero, so); - } - } + if (Scene.AttachmentsModule != null) + Scene.AttachmentsModule.CopyAttachments(cAgent, this); } public bool CopyAgent(out IAgentData agent) @@ -3402,6 +3374,7 @@ namespace OpenSim.Region.Framework.Scenes Velocity = force; m_forceToApply = null; + TriggerScenePresenceUpdated(); } } @@ -3509,23 +3482,53 @@ namespace OpenSim.Region.Framework.Scenes RaiseCollisionScriptEvents(coldata); - if (Invulnerable || GodLevel >= 200) + // Gods do not take damage and Invulnerable is set depending on parcel/region flags + if (Invulnerable || GodLevel > 0) return; - + + // The following may be better in the ICombatModule + // probably tweaking of the values for ground and normal prim collisions will be needed float starthealth = Health; uint killerObj = 0; + SceneObjectPart part = null; foreach (uint localid in coldata.Keys) { - SceneObjectPart part = Scene.GetSceneObjectPart(localid); - - if (part != null && part.ParentGroup.Damage != -1.0f) - Health -= part.ParentGroup.Damage; + if (localid == 0) + { + part = null; + } else { - if (coldata[localid].PenetrationDepth >= 0.10f) + part = Scene.GetSceneObjectPart(localid); + } + if (part != null) + { + // Ignore if it has been deleted or volume detect + if (!part.ParentGroup.IsDeleted && !part.ParentGroup.IsVolumeDetect) + { + if (part.ParentGroup.Damage > 0.0f) + { + // Something with damage... + Health -= part.ParentGroup.Damage; + part.ParentGroup.Scene.DeleteSceneObject(part.ParentGroup, false); + } + else + { + // An ordinary prim + if (coldata[localid].PenetrationDepth >= 0.10f) + Health -= coldata[localid].PenetrationDepth * 5.0f; + } + } + } + else + { + // 0 is the ground + // what about collisions with other avatars? + if (localid == 0 && coldata[localid].PenetrationDepth >= 0.10f) Health -= coldata[localid].PenetrationDepth * 5.0f; } + if (Health <= 0.0f) { if (localid != 0) @@ -3541,7 +3544,16 @@ namespace OpenSim.Region.Framework.Scenes ControllingClient.SendHealth(Health); } if (Health <= 0) + { m_scene.EventManager.TriggerAvatarKill(killerObj, this); + } + if (starthealth == Health && Health < 100.0f) + { + Health += 0.03f; + if (Health > 100.0f) + Health = 100.0f; + ControllingClient.SendHealth(Health); + } } } @@ -3553,9 +3565,6 @@ namespace OpenSim.Region.Framework.Scenes public void Close() { - if (!IsChildAgent) - m_scene.AttachmentsModule.DeleteAttachmentsFromScene(this, false); - // Clear known regions KnownRegions = new Dictionary(); @@ -3624,6 +3633,63 @@ namespace OpenSim.Region.Framework.Scenes return m_attachments.Count > 0; } + /// + /// Returns the total count of scripts in all parts inventories. + /// + public int ScriptCount() + { + int count = 0; + lock (m_attachments) + { + foreach (SceneObjectGroup gobj in m_attachments) + { + if (gobj != null) + { + count += gobj.ScriptCount(); + } + } + } + return count; + } + + /// + /// A float the value is a representative execution time in milliseconds of all scripts in all attachments. + /// + public float ScriptExecutionTime() + { + float time = 0.0f; + lock (m_attachments) + { + foreach (SceneObjectGroup gobj in m_attachments) + { + if (gobj != null) + { + time += gobj.ScriptExecutionTime(); + } + } + } + return time; + } + + /// + /// Returns the total count of running scripts in all parts. + /// + public int RunningScriptCount() + { + int count = 0; + lock (m_attachments) + { + foreach (SceneObjectGroup gobj in m_attachments) + { + if (gobj != null) + { + count += gobj.RunningScriptCount(); + } + } + } + return count; + } + public bool HasScriptedAttachments() { lock (m_attachments) @@ -3841,77 +3907,92 @@ namespace OpenSim.Region.Framework.Scenes } } - internal void SendControlToScripts(uint flags) + private void SendControlsToScripts(uint flags) { - ScriptControlled allflags = ScriptControlled.CONTROL_ZERO; - - if (MouseDown) + // Notify the scripts only after calling UpdateMovementAnimations(), so that if a script + // (e.g., a walking script) checks which animation is active it will be the correct animation. + lock (scriptedcontrols) { - allflags = LastCommands & (ScriptControlled.CONTROL_ML_LBUTTON | ScriptControlled.CONTROL_LBUTTON); - if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP) != 0 || (flags & unchecked((uint)AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP)) != 0) + if (scriptedcontrols.Count <= 0) + return; + + ScriptControlled allflags = ScriptControlled.CONTROL_ZERO; + + if (MouseDown) { - allflags = ScriptControlled.CONTROL_ZERO; + allflags = LastCommands & (ScriptControlled.CONTROL_ML_LBUTTON | ScriptControlled.CONTROL_LBUTTON); + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_UP) != 0 || (flags & unchecked((uint)AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_UP)) != 0) + { + allflags = ScriptControlled.CONTROL_ZERO; + MouseDown = true; + } + } + + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN) != 0) + { + allflags |= ScriptControlled.CONTROL_ML_LBUTTON; MouseDown = true; } - } + + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0) + { + allflags |= ScriptControlled.CONTROL_LBUTTON; + MouseDown = true; + } + + // find all activated controls, whether the scripts are interested in them or not + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS) != 0) + { + allflags |= ScriptControlled.CONTROL_FWD; + } + + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG) != 0) + { + allflags |= ScriptControlled.CONTROL_BACK; + } + + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS) != 0) + { + allflags |= ScriptControlled.CONTROL_UP; + } + + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0) + { + allflags |= ScriptControlled.CONTROL_DOWN; + } - if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_ML_LBUTTON_DOWN) != 0) - { - allflags |= ScriptControlled.CONTROL_ML_LBUTTON; - MouseDown = true; - } - if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LBUTTON_DOWN) != 0) - { - allflags |= ScriptControlled.CONTROL_LBUTTON; - MouseDown = true; - } + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS) != 0) + { + allflags |= ScriptControlled.CONTROL_LEFT; + } + + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG) != 0) + { + allflags |= ScriptControlled.CONTROL_RIGHT; + } + + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0) + { + allflags |= ScriptControlled.CONTROL_ROT_RIGHT; + } + + if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0) + { + allflags |= ScriptControlled.CONTROL_ROT_LEFT; + } - // find all activated controls, whether the scripts are interested in them or not - if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_POS) != 0) - { - allflags |= ScriptControlled.CONTROL_FWD; - } - if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_AT_NEG) != 0) - { - allflags |= ScriptControlled.CONTROL_BACK; - } - if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_POS) != 0) - { - allflags |= ScriptControlled.CONTROL_UP; - } - if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0) - { - allflags |= ScriptControlled.CONTROL_DOWN; - } - if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LEFT_POS) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_POS) != 0) - { - allflags |= ScriptControlled.CONTROL_LEFT; - } - if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_LEFT_NEG) != 0 || (flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_LEFT_NEG) != 0) - { - allflags |= ScriptControlled.CONTROL_RIGHT; - } - if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0) - { - allflags |= ScriptControlled.CONTROL_ROT_RIGHT; - } - if ((flags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0) - { - allflags |= ScriptControlled.CONTROL_ROT_LEFT; - } - // optimization; we have to check per script, but if nothing is pressed and nothing changed, we can skip that - if (allflags != ScriptControlled.CONTROL_ZERO || allflags != LastCommands) - { - lock (scriptedcontrols) + // optimization; we have to check per script, but if nothing is pressed and nothing changed, we can skip that + if (allflags != ScriptControlled.CONTROL_ZERO || allflags != LastCommands) { foreach (KeyValuePair kvp in scriptedcontrols) { UUID scriptUUID = kvp.Key; ScriptControllers scriptControlData = kvp.Value; - + ScriptControlled localHeld = allflags & scriptControlData.eventControls; // the flags interesting for us ScriptControlled localLast = LastCommands & scriptControlData.eventControls; // the activated controls in the last cycle ScriptControlled localChange = localHeld ^ localLast; // the changed bits + if (localHeld != ScriptControlled.CONTROL_ZERO || localChange != ScriptControlled.CONTROL_ZERO) { // only send if still pressed or just changed @@ -3919,9 +4000,9 @@ namespace OpenSim.Region.Framework.Scenes } } } + + LastCommands = allflags; } - - LastCommands = allflags; } internal static AgentManager.ControlFlags RemoveIgnoredControls(AgentManager.ControlFlags flags, ScriptControlled ignored) @@ -4001,7 +4082,7 @@ namespace OpenSim.Region.Framework.Scenes land.LandData.UserLocation != Vector3.Zero && land.LandData.OwnerID != m_uuid && (!m_scene.Permissions.IsGod(m_uuid)) && - (!m_scene.RegionInfo.EstateSettings.IsEstateManager(m_uuid))) + (!m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid))) { float curr = Vector3.Distance(AbsolutePosition, pos); if (Vector3.Distance(land.LandData.UserLocation, pos) < curr) @@ -4015,13 +4096,13 @@ namespace OpenSim.Region.Framework.Scenes { if ((m_teleportFlags & (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID)) == (TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID) || - (m_teleportFlags & TeleportFlags.ViaLandmark) != 0 || + (m_scene.TelehubAllowLandmarks == true ? false : ((m_teleportFlags & TeleportFlags.ViaLandmark) != 0 )) || (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0) { if (GodLevel < 200 && ((!m_scene.Permissions.IsGod(m_uuid) && - !m_scene.RegionInfo.EstateSettings.IsEstateManager(m_uuid)) || + !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) || (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0)) { @@ -4029,28 +4110,92 @@ namespace OpenSim.Region.Framework.Scenes if (spawnPoints.Length == 0) return; - float distance = 9999; - int closest = -1; + int index; + bool selected = false; - for (int i = 0 ; i < spawnPoints.Length ; i++) + switch (m_scene.SpawnPointRouting) { - Vector3 spawnPosition = spawnPoints[i].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); - Vector3 offset = spawnPosition - pos; - float d = Vector3.Mag(offset); - if (d >= distance) - continue; - ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); - if (land == null) - continue; - if (land.IsEitherBannedOrRestricted(UUID)) - continue; - distance = d; - closest = i; - } - if (closest == -1) - return; + case "random": - pos = spawnPoints[closest].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); + do + { + index = Util.RandomClass.Next(spawnPoints.Length - 1); + + Vector3 spawnPosition = spawnPoints[index].GetLocation( + telehub.AbsolutePosition, + telehub.GroupRotation + ); + // SpawnPoint sp = spawnPoints[index]; + + ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); + if (land == null || land.IsEitherBannedOrRestricted(UUID)) + selected = false; + else + selected = true; + + } while ( selected == false); + + pos = spawnPoints[index].GetLocation( + telehub.AbsolutePosition, + telehub.GroupRotation + ); + return; + + case "sequence": + + do + { + index = m_scene.SpawnPoint(); + + Vector3 spawnPosition = spawnPoints[index].GetLocation( + telehub.AbsolutePosition, + telehub.GroupRotation + ); + // SpawnPoint sp = spawnPoints[index]; + + ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); + if (land == null || land.IsEitherBannedOrRestricted(UUID)) + selected = false; + else + selected = true; + + } while (selected == false); + + pos = spawnPoints[index].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); + ; + return; + + default: + case "closest": + + float distance = 9999; + int closest = -1; + + for (int i = 0; i < spawnPoints.Length; i++) + { + Vector3 spawnPosition = spawnPoints[i].GetLocation( + telehub.AbsolutePosition, + telehub.GroupRotation + ); + Vector3 offset = spawnPosition - pos; + float d = Vector3.Mag(offset); + if (d >= distance) + continue; + ILandObject land = m_scene.LandChannel.GetLandObject(spawnPosition.X, spawnPosition.Y); + if (land == null) + continue; + if (land.IsEitherBannedOrRestricted(UUID)) + continue; + distance = d; + closest = i; + } + if (closest == -1) + return; + + pos = spawnPoints[closest].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); + return; + + } } } } @@ -4095,7 +4240,7 @@ namespace OpenSim.Region.Framework.Scenes GodLevel < 200 && ((land.LandData.OwnerID != m_uuid && !m_scene.Permissions.IsGod(m_uuid) && - !m_scene.RegionInfo.EstateSettings.IsEstateManager(m_uuid)) || + !m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_uuid)) || (m_teleportFlags & TeleportFlags.ViaLocation) != 0 || (m_teleportFlags & Constants.TeleportFlags.ViaHGLogin) != 0)) { diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs index 55455cc434..a4f730d375 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs @@ -47,14 +47,30 @@ namespace OpenSim.Region.Framework.Scenes.Serialization /// public class CoalescedSceneObjectsSerializer { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// /// Serialize coalesced objects to Xml /// /// + /// + /// If true then serialize script states. This will halt any running scripts + /// /// public static string ToXml(CoalescedSceneObjects coa) + { + return ToXml(coa, true); + } + + /// + /// Serialize coalesced objects to Xml + /// + /// + /// + /// If true then serialize script states. This will halt any running scripts + /// + /// + public static string ToXml(CoalescedSceneObjects coa, bool doScriptStates) { using (StringWriter sw = new StringWriter()) { @@ -91,7 +107,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization writer.WriteAttributeString("offsety", offsets[i].Y.ToString()); writer.WriteAttributeString("offsetz", offsets[i].Z.ToString()); - SceneObjectSerializer.ToOriginalXmlFormat(obj, writer, true); + SceneObjectSerializer.ToOriginalXmlFormat(obj, writer, doScriptStates); writer.WriteEndElement(); // SceneObjectGroup } diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index abca14f314..2372d6ba93 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -1537,51 +1537,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization } } - //////// Read ///////// - public static bool Xml2ToSOG(XmlTextReader reader, SceneObjectGroup sog) - { - reader.Read(); - reader.ReadStartElement("SceneObjectGroup"); - SceneObjectPart root = Xml2ToSOP(reader); - if (root != null) - sog.SetRootPart(root); - else - { - return false; - } - - if (sog.UUID == UUID.Zero) - sog.UUID = sog.RootPart.UUID; - - reader.Read(); // OtherParts - - while (!reader.EOF) - { - switch (reader.NodeType) - { - case XmlNodeType.Element: - if (reader.Name == "SceneObjectPart") - { - SceneObjectPart child = Xml2ToSOP(reader); - if (child != null) - sog.AddPart(child); - } - else - { - //Logger.Log("Found unexpected prim XML element " + reader.Name, Helpers.LogLevel.Debug); - reader.Read(); - } - break; - case XmlNodeType.EndElement: - default: - reader.Read(); - break; - } - - } - return true; - } - public static SceneObjectPart Xml2ToSOP(XmlTextReader reader) { SceneObjectPart obj = new SceneObjectPart(); diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs index d214eba1fc..a3485d29e6 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs @@ -223,50 +223,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization public static SceneObjectGroup DeserializeGroupFromXml2(string xmlString) { - XmlDocument doc = new XmlDocument(); - XmlNode rootNode; - - XmlTextReader reader = new XmlTextReader(new StringReader(xmlString)); - reader.WhitespaceHandling = WhitespaceHandling.None; - doc.Load(reader); - reader.Close(); - rootNode = doc.FirstChild; - - // This is to deal with neighbouring regions that are still surrounding the group xml with the - // tag. It should be possible to remove the first part of this if statement once we go past 0.5.9 (or - // when some other changes forces all regions to upgrade). - // This might seem rather pointless since prim crossing from this revision to an earlier revision remains - // broken. But it isn't much work to accomodate the old format here. - if (rootNode.LocalName.Equals("scene")) - { - foreach (XmlNode aPrimNode in rootNode.ChildNodes) - { - // There is only ever one prim. This oddity should be removeable post 0.5.9 - //return SceneObjectSerializer.FromXml2Format(aPrimNode.OuterXml); - using (reader = new XmlTextReader(new StringReader(aPrimNode.OuterXml))) - { - SceneObjectGroup obj = new SceneObjectGroup(); - if (SceneObjectSerializer.Xml2ToSOG(reader, obj)) - return obj; - - return null; - } - } - - return null; - } - else - { - //return SceneObjectSerializer.FromXml2Format(rootNode.OuterXml); - using (reader = new XmlTextReader(new StringReader(rootNode.OuterXml))) - { - SceneObjectGroup obj = new SceneObjectGroup(); - if (SceneObjectSerializer.Xml2ToSOG(reader, obj)) - return obj; - - return null; - } - } + return SceneObjectSerializer.FromXml2Format(xmlString); } /// @@ -307,8 +264,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization ICollection sceneObjects = new List(); foreach (XmlNode aPrimNode in rootNode.ChildNodes) { - SceneObjectGroup obj = CreatePrimFromXml2(scene, aPrimNode.OuterXml); - if (obj != null && startScripts) + SceneObjectGroup obj = DeserializeGroupFromXml2(aPrimNode.OuterXml); + if (startScripts) sceneObjects.Add(obj); } @@ -319,27 +276,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization } } - /// - /// Create a prim from the xml2 representation. - /// - /// - /// - /// The scene object created. null if the scene object already existed - protected static SceneObjectGroup CreatePrimFromXml2(Scene scene, string xmlData) - { - //SceneObjectGroup obj = SceneObjectSerializer.FromXml2Format(xmlData); - using (XmlTextReader reader = new XmlTextReader(new StringReader(xmlData))) - { - SceneObjectGroup obj = new SceneObjectGroup(); - SceneObjectSerializer.Xml2ToSOG(reader, obj); - - if (scene.AddRestoredSceneObject(obj, true, false)) - return obj; - else - return null; - } - } - #endregion } -} +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs index a4afd4705f..18e6ecec41 100644 --- a/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs +++ b/OpenSim/Region/Framework/Scenes/SimStatsReporter.cs @@ -26,7 +26,7 @@ */ using System; -//using System.Collections.Generic; +using System.Collections.Generic; using System.Timers; using OpenMetaverse.Packets; using OpenSim.Framework; @@ -35,10 +35,18 @@ using OpenSim.Region.Framework.Interfaces; namespace OpenSim.Region.Framework.Scenes { + /// + /// Collect statistics from the scene to send to the client and for access by other monitoring tools. + /// + /// + /// FIXME: This should be a monitoring region module + /// public class SimStatsReporter { -// private static readonly log4net.ILog m_log -// = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private static readonly log4net.ILog m_log + = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + + public const string LastReportedObjectUpdateStatName = "LastReportedObjectUpdates"; public delegate void SendStatResult(SimStats stats); @@ -48,10 +56,17 @@ namespace OpenSim.Region.Framework.Scenes public event YourStatsAreWrong OnStatsIncorrect; - private SendStatResult handlerSendStatResult = null; + private SendStatResult handlerSendStatResult; - private YourStatsAreWrong handlerStatsIncorrect = null; + private YourStatsAreWrong handlerStatsIncorrect; + /// + /// These are the IDs of stats sent in the StatsPacket to the viewer. + /// + /// + /// Some of these are not relevant to OpenSimulator since it is architected differently to other simulators + /// (e.g. script instructions aren't executed as part of the frame loop so 'script time' is tricky). + /// public enum Stats : uint { TimeDilation = 0, @@ -75,20 +90,20 @@ namespace OpenSim.Region.Framework.Scenes OutPacketsPerSecond = 18, PendingDownloads = 19, PendingUploads = 20, - VirtualSizeKB = 21, - ResidentSizeKB = 22, + VirtualSizeKb = 21, + ResidentSizeKb = 22, PendingLocalUploads = 23, UnAckedBytes = 24, PhysicsPinnedTasks = 25, - PhysicsLODTasks = 26, - PhysicsStepMS = 27, - PhysicsShapeMS = 28, - PhysicsOtherMS = 29, - PhysicsMemory = 30, - ScriptEPS = 31, - SimSpareTime = 32, - SimSleepTime = 33, - IOPumpTime = 34 + PhysicsLodTasks = 26, + SimPhysicsStepMs = 27, + SimPhysicsShapeMs = 28, + SimPhysicsOtherMs = 29, + SimPhysicsMemory = 30, + ScriptEps = 31, + SimSpareMs = 32, + SimSleepMs = 33, + SimIoPumpTime = 34 } /// @@ -113,11 +128,24 @@ namespace OpenSim.Region.Framework.Scenes get { return lastReportedSimStats; } } + /// + /// Extra sim statistics that are used by monitors but not sent to the client. + /// + /// + /// The keys are the stat names. + /// + private Dictionary m_lastReportedExtraSimStats = new Dictionary(); + // Sending a stats update every 3 seconds- - private int statsUpdatesEveryMS = 3000; - private float statsUpdateFactor = 0; - private float m_timeDilation = 0; - private int m_fps = 0; + private int m_statsUpdatesEveryMS = 3000; + private float m_statsUpdateFactor; + private float m_timeDilation; + private int m_fps; + + /// + /// Number of the last frame on which we processed a stats udpate. + /// + private uint m_lastUpdateFrame; /// /// Our nominal fps target, as expected in fps stats when a sim is running normally. @@ -135,43 +163,42 @@ namespace OpenSim.Region.Framework.Scenes private float m_reportedFpsCorrectionFactor = 5; // saved last reported value so there is something available for llGetRegionFPS - private float lastReportedSimFPS = 0; - private float[] lastReportedSimStats = new float[23]; - private float m_pfps = 0; + private float lastReportedSimFPS; + private float[] lastReportedSimStats = new float[22]; + private float m_pfps; /// /// Number of agent updates requested in this stats cycle /// - private int m_agentUpdates = 0; + private int m_agentUpdates; /// /// Number of object updates requested in this stats cycle /// private int m_objectUpdates; - private int m_frameMS = 0; - private int m_netMS = 0; - private int m_agentMS = 0; - private int m_physicsMS = 0; - private int m_imageMS = 0; - private int m_otherMS = 0; - private int m_sleeptimeMS = 0; - + private int m_frameMS; + private int m_spareMS; + private int m_netMS; + private int m_agentMS; + private int m_physicsMS; + private int m_imageMS; + private int m_otherMS; //Ckrinke: (3-21-08) Comment out to remove a compiler warning. Bring back into play when needed. //Ckrinke private int m_scriptMS = 0; - private int m_rootAgents = 0; - private int m_childAgents = 0; - private int m_numPrim = 0; - private int m_inPacketsPerSecond = 0; - private int m_outPacketsPerSecond = 0; - private int m_activePrim = 0; - private int m_unAckedBytes = 0; - private int m_pendingDownloads = 0; - private int m_pendingUploads = 0; - private int m_activeScripts = 0; - private int m_scriptLinesPerSecond = 0; + private int m_rootAgents; + private int m_childAgents; + private int m_numPrim; + private int m_inPacketsPerSecond; + private int m_outPacketsPerSecond; + private int m_activePrim; + private int m_unAckedBytes; + private int m_pendingDownloads; + private int m_pendingUploads = 0; // FIXME: Not currently filled in + private int m_activeScripts; + private int m_scriptLinesPerSecond; private int m_objectCapacity = 45000; @@ -187,13 +214,13 @@ namespace OpenSim.Region.Framework.Scenes { m_scene = scene; m_reportedFpsCorrectionFactor = scene.MinFrameTime * m_nominalReportedFps; - statsUpdateFactor = (float)(statsUpdatesEveryMS / 1000); + m_statsUpdateFactor = (float)(m_statsUpdatesEveryMS / 1000); ReportingRegion = scene.RegionInfo; m_objectCapacity = scene.RegionInfo.ObjectCapacity; m_report.AutoReset = true; - m_report.Interval = statsUpdatesEveryMS; - m_report.Elapsed += statsHeartBeat; + m_report.Interval = m_statsUpdatesEveryMS; + m_report.Elapsed += TriggerStatsHeartbeat; m_report.Enabled = true; if (StatsManager.SimExtraStats != null) @@ -202,20 +229,38 @@ namespace OpenSim.Region.Framework.Scenes public void Close() { - m_report.Elapsed -= statsHeartBeat; + m_report.Elapsed -= TriggerStatsHeartbeat; m_report.Close(); } + /// + /// Sets the number of milliseconds between stat updates. + /// + /// public void SetUpdateMS(int ms) { - statsUpdatesEveryMS = ms; - statsUpdateFactor = (float)(statsUpdatesEveryMS / 1000); - m_report.Interval = statsUpdatesEveryMS; + m_statsUpdatesEveryMS = ms; + m_statsUpdateFactor = (float)(m_statsUpdatesEveryMS / 1000); + m_report.Interval = m_statsUpdatesEveryMS; + } + + private void TriggerStatsHeartbeat(object sender, EventArgs args) + { + try + { + statsHeartBeat(sender, args); + } + catch (Exception e) + { + m_log.Warn(string.Format( + "[SIM STATS REPORTER] Update for {0} failed with exception ", + m_scene.RegionInfo.RegionName), e); + } } private void statsHeartBeat(object sender, EventArgs e) { - SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[23]; + SimStatsPacket.StatBlock[] sb = new SimStatsPacket.StatBlock[22]; SimStatsPacket.RegionBlock rb = new SimStatsPacket.RegionBlock(); // Know what's not thread safe in Mono... modifying timers. @@ -242,7 +287,7 @@ namespace OpenSim.Region.Framework.Scenes int reportedFPS = (int)(m_fps * m_reportedFpsCorrectionFactor); // save the reported value so there is something available for llGetRegionFPS - lastReportedSimFPS = reportedFPS / statsUpdateFactor; + lastReportedSimFPS = reportedFPS / m_statsUpdateFactor; float physfps = ((m_pfps / 1000)); @@ -253,7 +298,6 @@ namespace OpenSim.Region.Framework.Scenes physfps = 0; #endregion - float factor = 1 / statsUpdateFactor; if (reportedFPS <= 0) reportedFPS = 1; @@ -264,32 +308,38 @@ namespace OpenSim.Region.Framework.Scenes float targetframetime = 1100.0f / (float)m_nominalReportedFps; float sparetime; - float sleeptime; if (TotalFrameTime > targetframetime) { sparetime = 0; - sleeptime = 0; - } - else - { - sparetime = m_frameMS - m_physicsMS - m_agentMS; - sparetime *= perframe; - if (sparetime < 0) - sparetime = 0; - else if (sparetime > TotalFrameTime) - sparetime = TotalFrameTime; - sleeptime = m_sleeptimeMS * perframe; } + + m_rootAgents = m_scene.SceneGraph.GetRootAgentCount(); + m_childAgents = m_scene.SceneGraph.GetChildAgentCount(); + m_numPrim = m_scene.SceneGraph.GetTotalObjectsCount(); + m_activePrim = m_scene.SceneGraph.GetActiveObjectsCount(); + m_activeScripts = m_scene.SceneGraph.GetActiveScriptsCount(); + + // FIXME: Checking for stat sanity is a complex approach. What we really need to do is fix the code + // so that stat numbers are always consistent. + CheckStatSanity(); // other MS is actually simulation time // m_otherMS = m_frameMS - m_physicsMS - m_imageMS - m_netMS - m_agentMS; // m_imageMS m_netMS are not included in m_frameMS - m_otherMS = m_frameMS - m_physicsMS - m_agentMS - m_sleeptimeMS; + m_otherMS = m_frameMS - m_physicsMS - m_agentMS; if (m_otherMS < 0) m_otherMS = 0; - for (int i = 0; i < 23; i++) + uint thisFrame = m_scene.Frame; + float framesUpdated = (float)(thisFrame - m_lastUpdateFrame) * m_reportedFpsCorrectionFactor; + m_lastUpdateFrame = thisFrame; + + // Avoid div-by-zero if somehow we've not updated any frames. + if (framesUpdated == 0) + framesUpdated = 1; + + for (int i = 0; i < 22; i++) { sb[i] = new SimStatsPacket.StatBlock(); } @@ -298,13 +348,13 @@ namespace OpenSim.Region.Framework.Scenes sb[0].StatValue = (Single.IsNaN(m_timeDilation)) ? 0.1f : m_timeDilation ; //((((m_timeDilation + (0.10f * statsUpdateFactor)) /10) / statsUpdateFactor)); sb[1].StatID = (uint) Stats.SimFPS; - sb[1].StatValue = reportedFPS / statsUpdateFactor; + sb[1].StatValue = reportedFPS / m_statsUpdateFactor; sb[2].StatID = (uint) Stats.PhysicsFPS; - sb[2].StatValue = physfps / statsUpdateFactor; + sb[2].StatValue = physfps / m_statsUpdateFactor; sb[3].StatID = (uint) Stats.AgentUpdates; - sb[3].StatValue = (m_agentUpdates / statsUpdateFactor); + sb[3].StatValue = (m_agentUpdates / m_statsUpdateFactor); sb[4].StatID = (uint) Stats.Agents; sb[4].StatValue = m_rootAgents; @@ -319,38 +369,31 @@ namespace OpenSim.Region.Framework.Scenes sb[7].StatValue = m_activePrim; sb[8].StatID = (uint)Stats.FrameMS; - // sb[8].StatValue = m_frameMS / statsUpdateFactor; - sb[8].StatValue = TotalFrameTime; + sb[8].StatValue = m_frameMS / framesUpdated; sb[9].StatID = (uint)Stats.NetMS; - // sb[9].StatValue = m_netMS / statsUpdateFactor; - sb[9].StatValue = m_netMS * perframe; + sb[9].StatValue = m_netMS / framesUpdated; sb[10].StatID = (uint)Stats.PhysicsMS; - // sb[10].StatValue = m_physicsMS / statsUpdateFactor; - sb[10].StatValue = m_physicsMS * perframe; + sb[10].StatValue = m_physicsMS / framesUpdated; sb[11].StatID = (uint)Stats.ImageMS ; - // sb[11].StatValue = m_imageMS / statsUpdateFactor; - sb[11].StatValue = m_imageMS * perframe; + sb[11].StatValue = m_imageMS / framesUpdated; sb[12].StatID = (uint)Stats.OtherMS; - // sb[12].StatValue = m_otherMS / statsUpdateFactor; - sb[12].StatValue = m_otherMS * perframe; - + sb[12].StatValue = m_otherMS / framesUpdated; sb[13].StatID = (uint)Stats.InPacketsPerSecond; - sb[13].StatValue = (m_inPacketsPerSecond / statsUpdateFactor); + sb[13].StatValue = (m_inPacketsPerSecond / m_statsUpdateFactor); sb[14].StatID = (uint)Stats.OutPacketsPerSecond; - sb[14].StatValue = (m_outPacketsPerSecond / statsUpdateFactor); + sb[14].StatValue = (m_outPacketsPerSecond / m_statsUpdateFactor); sb[15].StatID = (uint)Stats.UnAckedBytes; sb[15].StatValue = m_unAckedBytes; sb[16].StatID = (uint)Stats.AgentMS; -// sb[16].StatValue = m_agentMS / statsUpdateFactor; - sb[16].StatValue = m_agentMS * perframe; + sb[16].StatValue = m_agentMS / framesUpdated; sb[17].StatID = (uint)Stats.PendingDownloads; sb[17].StatValue = m_pendingDownloads; @@ -362,15 +405,12 @@ namespace OpenSim.Region.Framework.Scenes sb[19].StatValue = m_activeScripts; sb[20].StatID = (uint)Stats.ScriptLinesPerSecond; - sb[20].StatValue = m_scriptLinesPerSecond / statsUpdateFactor; + sb[20].StatValue = m_scriptLinesPerSecond / m_statsUpdateFactor; - sb[21].StatID = (uint)Stats.SimSpareTime; - sb[21].StatValue = sparetime; + sb[21].StatID = (uint)Stats.SimSpareMs; + sb[21].StatValue = m_spareMS / framesUpdated; - sb[22].StatID = (uint)Stats.SimSleepTime; - sb[22].StatValue = sleeptime; - - for (int i = 0; i < 23; i++) + for (int i = 0; i < 22; i++) { lastReportedSimStats[i] = sb[i].StatValue; } @@ -387,13 +427,32 @@ namespace OpenSim.Region.Framework.Scenes } // Extra statistics that aren't currently sent to clients - LastReportedObjectUpdates = m_objectUpdates / statsUpdateFactor; + lock (m_lastReportedExtraSimStats) + { + m_lastReportedExtraSimStats[LastReportedObjectUpdateStatName] = m_objectUpdates / m_statsUpdateFactor; - resetvalues(); + Dictionary physicsStats = m_scene.PhysicsScene.GetStats(); + + if (physicsStats != null) + { + foreach (KeyValuePair tuple in physicsStats) + { + // FIXME: An extremely dirty hack to divide MS stats per frame rather than per second + // Need to change things so that stats source can indicate whether they are per second or + // per frame. + if (tuple.Key.EndsWith("MS")) + m_lastReportedExtraSimStats[tuple.Key] = tuple.Value / framesUpdated; + else + m_lastReportedExtraSimStats[tuple.Key] = tuple.Value / m_statsUpdateFactor; + } + } + } + + ResetValues(); } } - private void resetvalues() + private void ResetValues() { m_timeDilation = 0; m_fps = 0; @@ -411,7 +470,7 @@ namespace OpenSim.Region.Framework.Scenes m_physicsMS = 0; m_imageMS = 0; m_otherMS = 0; - m_sleeptimeMS = 0; + m_spareMS = 0; //Ckrinke This variable is not used, so comment to remove compiler warning until it is used. //Ckrinke m_scriptMS = 0; @@ -433,13 +492,6 @@ namespace OpenSim.Region.Framework.Scenes m_timeDilation = td; } - public void SetRootAgents(int rootAgents) - { - m_rootAgents = rootAgents; - CheckStatSanity(); - - } - internal void CheckStatSanity() { if (m_rootAgents < 0 || m_childAgents < 0) @@ -456,22 +508,6 @@ namespace OpenSim.Region.Framework.Scenes } } - public void SetChildAgents(int childAgents) - { - m_childAgents = childAgents; - CheckStatSanity(); - } - - public void SetObjects(int objects) - { - m_numPrim = objects; - } - - public void SetActiveObjects(int objects) - { - m_activePrim = objects; - } - public void AddFPS(int frames) { m_fps += frames; @@ -513,6 +549,11 @@ namespace OpenSim.Region.Framework.Scenes m_frameMS += ms; } + public void AddSpareMS(int ms) + { + m_spareMS += ms; + } + public void addNetMS(int ms) { m_netMS += ms; @@ -538,15 +579,13 @@ namespace OpenSim.Region.Framework.Scenes m_otherMS += ms; } - public void addSleepMS(int ms) - { - m_sleeptimeMS += ms; - } - public void AddPendingDownloads(int count) { m_pendingDownloads += count; - if (m_pendingDownloads < 0) m_pendingDownloads = 0; + + if (m_pendingDownloads < 0) + m_pendingDownloads = 0; + //m_log.InfoFormat("[stats]: Adding {0} to pending downloads to make {1}", count, m_pendingDownloads); } @@ -555,11 +594,6 @@ namespace OpenSim.Region.Framework.Scenes m_scriptLinesPerSecond += count; } - public void SetActiveScripts(int count) - { - m_activeScripts = count; - } - public void AddPacketsStats(int inPackets, int outPackets, int unAckedBytes) { AddInPackets(inPackets); @@ -568,5 +602,11 @@ namespace OpenSim.Region.Framework.Scenes } #endregion + + public Dictionary GetExtraSimStats() + { + lock (m_lastReportedExtraSimStats) + return new Dictionary(m_lastReportedExtraSimStats); + } } } diff --git a/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs b/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs index ab6311b520..4a21dc9730 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/BorderTests.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Text; using NUnit.Framework; using OpenMetaverse; @@ -68,11 +69,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests Vector3 position = new Vector3(200,200,21); foreach (Border b in testborders) - { Assert.That(!b.TestCross(position)); - } - position = new Vector3(200,280,21); Assert.That(NorthBorder.TestCross(position)); diff --git a/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs index a5d2b2304a..ea9fc9386e 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/EntityManagerTests.cs @@ -45,7 +45,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests { static public Random random; SceneObjectGroup found; - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); [Test] public void T010_AddObjects() diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs index 9a60e50eb9..d23c96511c 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneGraphTests.cs @@ -26,7 +26,9 @@ */ using System; +using System.IO; using System.Reflection; +using System.Text; using NUnit.Framework; using OpenMetaverse; using OpenSim.Framework; @@ -44,7 +46,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void TestDuplicateObject() { TestHelpers.InMethod(); - Scene scene = SceneHelpers.SetupScene(); +// TestHelpers.EnableLogging(); + + Scene scene = new SceneHelpers().SetupScene(); UUID ownerId = new UUID("00000000-0000-0000-0000-000000000010"); string part1Name = "part1"; @@ -82,6 +86,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(dupePart1.PhysActor, Is.Not.Null); Assert.That(dupePart2.PhysActor, Is.Not.Null); */ + +// TestHelpers.DisableLogging(); } } } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs index 7737d8ea83..3398a53fb8 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs @@ -88,7 +88,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests { TestHelpers.InMethod(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); int partsToTestCount = 3; SceneObjectGroup so @@ -118,7 +118,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests { TestHelpers.InMethod(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); string obj1Name = "Alfred"; string obj2Name = "Betty"; @@ -152,7 +152,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests { TestHelpers.InMethod(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); int partsToTestCount = 3; SceneObjectGroup so @@ -185,11 +185,16 @@ namespace OpenSim.Region.Framework.Scenes.Tests { TestHelpers.InMethod(); - TestScene scene = SceneHelpers.SetupScene(); - SceneObjectPart part = SceneHelpers.AddSceneObject(scene); - scene.DeleteSceneObject(part.ParentGroup, false); + TestScene scene = new SceneHelpers().SetupScene(); + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene); - SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); + Assert.That(so.IsDeleted, Is.False); + + scene.DeleteSceneObject(so, false); + + Assert.That(so.IsDeleted, Is.True); + + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); Assert.That(retrievedPart, Is.Null); } @@ -204,24 +209,28 @@ namespace OpenSim.Region.Framework.Scenes.Tests UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000001"); - TestScene scene = SceneHelpers.SetupScene(); + TestScene scene = new SceneHelpers().SetupScene(); // Turn off the timer on the async sog deleter - we'll crank it by hand for this test. AsyncSceneObjectGroupDeleter sogd = scene.SceneObjectGroupDeleter; sogd.Enabled = false; - SceneObjectPart part = SceneHelpers.AddSceneObject(scene); + SceneObjectGroup so = SceneHelpers.AddSceneObject(scene); IClientAPI client = SceneHelpers.AddScenePresence(scene, agentId).ControllingClient; - scene.DeRezObjects(client, new System.Collections.Generic.List() { part.LocalId }, UUID.Zero, DeRezAction.Delete, UUID.Zero); + scene.DeRezObjects(client, new System.Collections.Generic.List() { so.LocalId }, UUID.Zero, DeRezAction.Delete, UUID.Zero); - SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(so.LocalId); Assert.That(retrievedPart, Is.Not.Null); + Assert.That(so.IsDeleted, Is.False); + sogd.InventoryDeQueueAndDelete(); - SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(part.LocalId); + Assert.That(so.IsDeleted, Is.True); + + SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(so.LocalId); Assert.That(retrievedPart2, Is.Null); } diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs index 654b1a2cc6..0076f41225 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectDeRezTests.cs @@ -61,7 +61,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); - TestScene scene = SceneHelpers.SetupScene(); + TestScene scene = new SceneHelpers().SetupScene(); IConfigSource configSource = new IniConfigSource(); IConfig config = configSource.AddConfig("Startup"); config.Set("serverside_object_permissions", true); @@ -100,7 +100,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); UUID objectOwnerId = UUID.Parse("20000000-0000-0000-0000-000000000001"); - TestScene scene = SceneHelpers.SetupScene(); + TestScene scene = new SceneHelpers().SetupScene(); IConfigSource configSource = new IniConfigSource(); IConfig config = configSource.AddConfig("Startup"); config.Set("serverside_object_permissions", true); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs index be5b4a8986..0e525c92de 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs @@ -55,7 +55,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests UUID ownerId = TestHelpers.ParseTail(0x1); int nParts = 3; - TestScene scene = SceneHelpers.SetupScene(); + TestScene scene = new SceneHelpers().SetupScene(); SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(nParts, ownerId, "TestLinkToSelf_", 0x10); scene.AddSceneObject(sog1); scene.LinkObjects(ownerId, sog1.LocalId, new List() { sog1.Parts[1].LocalId }); @@ -71,11 +71,11 @@ namespace OpenSim.Region.Framework.Scenes.Tests bool debugtest = false; - Scene scene = SceneHelpers.SetupScene(); - SceneObjectPart part1 = SceneHelpers.AddSceneObject(scene); - SceneObjectGroup grp1 = part1.ParentGroup; - SceneObjectPart part2 = SceneHelpers.AddSceneObject(scene); - SceneObjectGroup grp2 = part2.ParentGroup; + Scene scene = new SceneHelpers().SetupScene(); + SceneObjectGroup grp1 = SceneHelpers.AddSceneObject(scene); + SceneObjectPart part1 = grp1.RootPart; + SceneObjectGroup grp2 = SceneHelpers.AddSceneObject(scene); + SceneObjectPart part2 = grp2.RootPart; grp1.AbsolutePosition = new Vector3(10, 10, 10); grp2.AbsolutePosition = Vector3.Zero; @@ -153,15 +153,15 @@ namespace OpenSim.Region.Framework.Scenes.Tests bool debugtest = false; - Scene scene = SceneHelpers.SetupScene(); - SceneObjectPart part1 = SceneHelpers.AddSceneObject(scene); - SceneObjectGroup grp1 = part1.ParentGroup; - SceneObjectPart part2 = SceneHelpers.AddSceneObject(scene); - SceneObjectGroup grp2 = part2.ParentGroup; - SceneObjectPart part3 = SceneHelpers.AddSceneObject(scene); - SceneObjectGroup grp3 = part3.ParentGroup; - SceneObjectPart part4 = SceneHelpers.AddSceneObject(scene); - SceneObjectGroup grp4 = part4.ParentGroup; + Scene scene = new SceneHelpers().SetupScene(); + SceneObjectGroup grp1 = SceneHelpers.AddSceneObject(scene); + SceneObjectPart part1 = grp1.RootPart; + SceneObjectGroup grp2 = SceneHelpers.AddSceneObject(scene); + SceneObjectPart part2 = grp2.RootPart; + SceneObjectGroup grp3 = SceneHelpers.AddSceneObject(scene); + SceneObjectPart part3 = grp3.RootPart; + SceneObjectGroup grp4 = SceneHelpers.AddSceneObject(scene); + SceneObjectPart part4 = grp4.RootPart; grp1.AbsolutePosition = new Vector3(10, 10, 10); grp2.AbsolutePosition = Vector3.Zero; @@ -286,7 +286,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests TestHelpers.InMethod(); //log4net.Config.XmlConfigurator.Configure(); - TestScene scene = SceneHelpers.SetupScene(); + TestScene scene = new SceneHelpers().SetupScene(); string rootPartName = "rootpart"; UUID rootPartUuid = new UUID("00000000-0000-0000-0000-000000000001"); @@ -325,7 +325,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests TestHelpers.InMethod(); //log4net.Config.XmlConfigurator.Configure(); - TestScene scene = SceneHelpers.SetupScene(); + TestScene scene = new SceneHelpers().SetupScene(); string rootPartName = "rootpart"; UUID rootPartUuid = new UUID("00000000-0000-0000-0000-000000000001"); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs index b49c6e7a98..e9318594ce 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectResizeTests.cs @@ -52,8 +52,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneHelpers.SetupScene(); - SceneObjectGroup g1 = SceneHelpers.AddSceneObject(scene).ParentGroup; + Scene scene = new SceneHelpers().SetupScene(); + SceneObjectGroup g1 = SceneHelpers.AddSceneObject(scene); g1.GroupResize(new Vector3(2, 3, 4)); @@ -75,7 +75,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests TestHelpers.InMethod(); //log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); SceneObjectGroup g1 = SceneHelpers.CreateSceneObject(2, UUID.Zero); g1.RootPart.Scale = new Vector3(2, 3, 4); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs index c582cf66fb..d2361f8667 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectScriptTests.cs @@ -52,7 +52,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // UUID itemId = TestHelpers.ParseTail(0x2); string itemName = "Test Script Item"; - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); scene.AddNewSceneObject(so, true); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs new file mode 100644 index 0000000000..6d255aa2d9 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectSpatialTests.cs @@ -0,0 +1,154 @@ +/* + * 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.Reflection; +using System.Threading; +using NUnit.Framework; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Communications; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Region.Framework.Scenes.Tests +{ + /// + /// Spatial scene object tests (will eventually cover root and child part position, rotation properties, etc.) + /// + [TestFixture] + public class SceneObjectSpatialTests + { + TestScene m_scene; + UUID m_ownerId = TestHelpers.ParseTail(0x1); + + [SetUp] + public void SetUp() + { + m_scene = new SceneHelpers().SetupScene(); + } + + [Test] + public void TestGetSceneObjectGroupPosition() + { + TestHelpers.InMethod(); + + Vector3 position = new Vector3(10, 20, 30); + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(1, m_ownerId, "obj1", 0x10); + so.AbsolutePosition = position; + m_scene.AddNewSceneObject(so, false); + + Assert.That(so.AbsolutePosition, Is.EqualTo(position)); + } + + [Test] + public void TestGetRootPartPosition() + { + TestHelpers.InMethod(); + + Vector3 partPosition = new Vector3(10, 20, 30); + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(1, m_ownerId, "obj1", 0x10); + so.AbsolutePosition = partPosition; + m_scene.AddNewSceneObject(so, false); + + Assert.That(so.RootPart.AbsolutePosition, Is.EqualTo(partPosition)); + Assert.That(so.RootPart.GroupPosition, Is.EqualTo(partPosition)); + Assert.That(so.RootPart.GetWorldPosition(), Is.EqualTo(partPosition)); + Assert.That(so.RootPart.RelativePosition, Is.EqualTo(partPosition)); + Assert.That(so.RootPart.OffsetPosition, Is.EqualTo(Vector3.Zero)); + } + + [Test] + public void TestGetChildPartPosition() + { + TestHelpers.InMethod(); + + Vector3 rootPartPosition = new Vector3(10, 20, 30); + Vector3 childOffsetPosition = new Vector3(2, 3, 4); + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(2, m_ownerId, "obj1", 0x10); + so.AbsolutePosition = rootPartPosition; + so.Parts[1].OffsetPosition = childOffsetPosition; + + m_scene.AddNewSceneObject(so, false); + + // Calculate child absolute position. + Vector3 childPosition = new Vector3(rootPartPosition + childOffsetPosition); + + SceneObjectPart childPart = so.Parts[1]; + Assert.That(childPart.AbsolutePosition, Is.EqualTo(childPosition)); + Assert.That(childPart.GroupPosition, Is.EqualTo(rootPartPosition)); + Assert.That(childPart.GetWorldPosition(), Is.EqualTo(childPosition)); + Assert.That(childPart.RelativePosition, Is.EqualTo(childOffsetPosition)); + Assert.That(childPart.OffsetPosition, Is.EqualTo(childOffsetPosition)); + } + + [Test] + public void TestGetChildPartPositionAfterObjectRotation() + { + TestHelpers.InMethod(); + + Vector3 rootPartPosition = new Vector3(10, 20, 30); + Vector3 childOffsetPosition = new Vector3(2, 3, 4); + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(2, m_ownerId, "obj1", 0x10); + so.AbsolutePosition = rootPartPosition; + so.Parts[1].OffsetPosition = childOffsetPosition; + + m_scene.AddNewSceneObject(so, false); + + so.UpdateGroupRotationR(Quaternion.CreateFromEulers(0, 0, -90 * Utils.DEG_TO_RAD)); + + // Calculate child absolute position. + Vector3 rotatedChildOffsetPosition + = new Vector3(childOffsetPosition.Y, -childOffsetPosition.X, childOffsetPosition.Z); + + Vector3 childPosition = new Vector3(rootPartPosition + rotatedChildOffsetPosition); + + SceneObjectPart childPart = so.Parts[1]; + + // FIXME: Should be childPosition after rotation? + Assert.That(childPart.AbsolutePosition, Is.EqualTo(rootPartPosition + childOffsetPosition)); + + Assert.That(childPart.GroupPosition, Is.EqualTo(rootPartPosition)); + Assert.That(childPart.GetWorldPosition(), Is.EqualTo(childPosition)); + + // Relative to root part as (0, 0, 0) + Assert.That(childPart.RelativePosition, Is.EqualTo(childOffsetPosition)); + + // Relative to root part as (0, 0, 0) + Assert.That(childPart.OffsetPosition, Is.EqualTo(childOffsetPosition)); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs index 2a342d50c8..742c7691e9 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectStatusTests.cs @@ -26,6 +26,7 @@ */ using System; +using System.Collections.Generic; using System.Reflection; using NUnit.Framework; using OpenMetaverse; @@ -43,24 +44,141 @@ namespace OpenSim.Region.Framework.Scenes.Tests [TestFixture] public class SceneObjectStatusTests { + private TestScene m_scene; + private UUID m_ownerId = TestHelpers.ParseTail(0x1); + private SceneObjectGroup m_so1; + private SceneObjectGroup m_so2; + + [SetUp] + public void Init() + { + m_scene = new SceneHelpers().SetupScene(); + m_so1 = SceneHelpers.CreateSceneObject(1, m_ownerId, "so1", 0x10); + m_so2 = SceneHelpers.CreateSceneObject(1, m_ownerId, "so2", 0x20); + } + [Test] - public void TestSetPhantom() + public void TestSetPhantomSinglePrim() { TestHelpers.InMethod(); -// Scene scene = SceneSetupHelpers.SetupScene(); - SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, UUID.Zero); - SceneObjectPart rootPart = so.RootPart; + m_scene.AddSceneObject(m_so1); + + SceneObjectPart rootPart = m_so1.RootPart; Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); - so.ScriptSetPhantomStatus(true); + m_so1.ScriptSetPhantomStatus(true); // Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags); Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Phantom)); - so.ScriptSetPhantomStatus(false); + m_so1.ScriptSetPhantomStatus(false); Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); } + + [Test] + public void TestSetPhysicsSinglePrim() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + + SceneObjectPart rootPart = m_so1.RootPart; + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); + + m_so1.ScriptSetPhysicsStatus(true); + +// Console.WriteLine("so.RootPart.Flags [{0}]", so.RootPart.Flags); + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + + m_so1.ScriptSetPhysicsStatus(false); + + Assert.That(rootPart.Flags, Is.EqualTo(PrimFlags.None)); + } + + [Test] + public void TestSetPhysicsLinkset() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + m_scene.AddSceneObject(m_so2); + + m_scene.LinkObjects(m_ownerId, m_so1.LocalId, new List() { m_so2.LocalId }); + + m_so1.ScriptSetPhysicsStatus(true); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.Physics)); + + m_so1.ScriptSetPhysicsStatus(false); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.None)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.None)); + + m_so1.ScriptSetPhysicsStatus(true); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.Physics)); + } + + /// + /// Test that linking results in the correct physical status for all linkees. + /// + [Test] + public void TestLinkPhysicsBothPhysical() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + m_scene.AddSceneObject(m_so2); + + m_so1.ScriptSetPhysicsStatus(true); + m_so2.ScriptSetPhysicsStatus(true); + + m_scene.LinkObjects(m_ownerId, m_so1.LocalId, new List() { m_so2.LocalId }); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.Physics)); + } + + /// + /// Test that linking results in the correct physical status for all linkees. + /// + [Test] + public void TestLinkPhysicsRootPhysicalOnly() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + m_scene.AddSceneObject(m_so2); + + m_so1.ScriptSetPhysicsStatus(true); + + m_scene.LinkObjects(m_ownerId, m_so1.LocalId, new List() { m_so2.LocalId }); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.Physics)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.Physics)); + } + + /// + /// Test that linking results in the correct physical status for all linkees. + /// + [Test] + public void TestLinkPhysicsChildPhysicalOnly() + { + TestHelpers.InMethod(); + + m_scene.AddSceneObject(m_so1); + m_scene.AddSceneObject(m_so2); + + m_so2.ScriptSetPhysicsStatus(true); + + m_scene.LinkObjects(m_ownerId, m_so1.LocalId, new List() { m_so2.LocalId }); + + Assert.That(m_so1.RootPart.Flags, Is.EqualTo(PrimFlags.None)); + Assert.That(m_so1.Parts[1].Flags, Is.EqualTo(PrimFlags.None)); + } } } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs index c13d82e16d..c7eaff9d00 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectUserGroupTests.cs @@ -58,7 +58,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests UUID userId = UUID.Parse("10000000-0000-0000-0000-000000000001"); - TestScene scene = SceneHelpers.SetupScene(); + TestScene scene = new SceneHelpers().SetupScene(); IConfigSource configSource = new IniConfigSource(); IConfig startupConfig = configSource.AddConfig("Startup"); diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs index ed9b179286..02c45ef11c 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs @@ -67,10 +67,12 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void Init() { TestHelpers.InMethod(); - - scene = SceneHelpers.SetupScene("Neighbour x", UUID.Random(), 1000, 1000); - scene2 = SceneHelpers.SetupScene("Neighbour x+1", UUID.Random(), 1001, 1000); - scene3 = SceneHelpers.SetupScene("Neighbour x-1", UUID.Random(), 999, 1000); + + SceneHelpers sh = new SceneHelpers(); + + scene = sh.SetupScene("Neighbour x", UUID.Random(), 1000, 1000); + scene2 = sh.SetupScene("Neighbour x+1", UUID.Random(), 1001, 1000); + scene3 = sh.SetupScene("Neighbour x-1", UUID.Random(), 999, 1000); ISharedRegionModule interregionComms = new LocalSimulationConnectorModule(); interregionComms.Initialise(new IniConfigSource()); @@ -99,9 +101,9 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void TestCloseAgent() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); +// TestHelpers.EnableLogging(); - TestScene scene = SceneHelpers.SetupScene(); + TestScene scene = new SceneHelpers().SetupScene(); ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(sp.UUID), Is.Not.Null); @@ -112,6 +114,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(scene.GetScenePresence(sp.UUID), Is.Null); Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(sp.UUID), Is.Null); Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(0)); + +// TestHelpers.DisableLogging(); } [Test] @@ -126,7 +130,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests IConfig config = configSource.AddConfig("Modules"); config.Set("SimulationServices", "LocalSimulationConnectorModule"); - TestScene scene = SceneHelpers.SetupScene(); + SceneHelpers sceneHelpers = new SceneHelpers(); + TestScene scene = sceneHelpers.SetupScene(); SceneHelpers.SetupSceneModules(scene, configSource, lsc); UUID agentId = TestHelpers.ParseTail(0x01); @@ -176,8 +181,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests // UUID agent1Id = UUID.Parse("00000000-0000-0000-0000-000000000001"); - TestScene myScene1 = SceneHelpers.SetupScene("Neighbour y", UUID.Random(), 1000, 1000); - TestScene myScene2 = SceneHelpers.SetupScene("Neighbour y + 1", UUID.Random(), 1001, 1000); + TestScene myScene1 = new SceneHelpers().SetupScene("Neighbour y", UUID.Random(), 1000, 1000); + TestScene myScene2 = new SceneHelpers().SetupScene("Neighbour y + 1", UUID.Random(), 1001, 1000); IConfigSource configSource = new IniConfigSource(); IConfig config = configSource.AddConfig("Startup"); diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs index 89f8007d0f..646e5fa61a 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAnimationTests.cs @@ -59,7 +59,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - TestScene scene = SceneHelpers.SetupScene(); + TestScene scene = new SceneHelpers().SetupScene(); ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); sp.Flying = true; sp.PhysicsCollisionUpdate(new CollisionEventUpdate()); diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs index cfea10d710..1d1ff88420 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAutopilotTests.cs @@ -64,7 +64,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests [SetUp] public void Init() { - m_scene = SceneHelpers.SetupScene(); + m_scene = new SceneHelpers().SetupScene(); } [Test] diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs index b7b8db445e..493ab70883 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs @@ -26,6 +26,7 @@ */ using System; +using System.Collections.Generic; using System.Reflection; using Nini.Config; using NUnit.Framework; @@ -50,7 +51,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests [SetUp] public void Init() { - m_scene = SceneHelpers.SetupScene(); + m_scene = new SceneHelpers().SetupScene(); m_sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); } @@ -64,11 +65,13 @@ namespace OpenSim.Region.Framework.Scenes.Tests Vector3 startPos = new Vector3(10.1f, 0, 0); m_sp.AbsolutePosition = startPos; - SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene); + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); + Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(0)); + Assert.That(part.GetSittingAvatars(), Is.Null); Assert.That(m_sp.ParentID, Is.EqualTo(0)); } @@ -82,11 +85,17 @@ namespace OpenSim.Region.Framework.Scenes.Tests Vector3 startPos = new Vector3(9.9f, 0, 0); m_sp.AbsolutePosition = startPos; - SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene); + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); + Assert.That(m_sp.PhysicsActor, Is.Null); + Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); + Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(1)); + HashSet sittingAvatars = part.GetSittingAvatars(); + Assert.That(sittingAvatars.Count, Is.EqualTo(1)); + Assert.That(sittingAvatars.Contains(m_sp.UUID)); Assert.That(m_sp.ParentID, Is.EqualTo(part.LocalId)); } @@ -100,14 +109,10 @@ namespace OpenSim.Region.Framework.Scenes.Tests Vector3 startPos = new Vector3(1, 1, 1); m_sp.AbsolutePosition = startPos; - SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene); + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); - Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); - Assert.That(m_sp.ParentID, Is.EqualTo(part.LocalId)); - Assert.That(m_sp.PhysicsActor, Is.Null); - // FIXME: This is different for live avatars - z position is adjusted. This is half the height of the // default avatar. // Curiously, Vector3.ToString() will not display the last two places of the float. For example, @@ -119,6 +124,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests m_sp.StandUp(); Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); + Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(0)); + Assert.That(part.GetSittingAvatars(), Is.Null); Assert.That(m_sp.ParentID, Is.EqualTo(0)); Assert.That(m_sp.PhysicsActor, Is.Not.Null); } @@ -133,7 +140,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests Vector3 startPos = new Vector3(128, 128, 30); m_sp.AbsolutePosition = startPos; - SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene); + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; part.SitTargetPosition = new Vector3(0, 0, 1); m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); @@ -145,11 +152,20 @@ namespace OpenSim.Region.Framework.Scenes.Tests Is.EqualTo(part.AbsolutePosition + part.SitTargetPosition + ScenePresence.SIT_TARGET_ADJUSTMENT)); Assert.That(m_sp.PhysicsActor, Is.Null); + Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(1)); + HashSet sittingAvatars = part.GetSittingAvatars(); + Assert.That(sittingAvatars.Count, Is.EqualTo(1)); + Assert.That(sittingAvatars.Contains(m_sp.UUID)); + m_sp.StandUp(); Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); Assert.That(m_sp.ParentID, Is.EqualTo(0)); Assert.That(m_sp.PhysicsActor, Is.Not.Null); + + Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); + Assert.That(part.GetSittingAvatarsCount(), Is.EqualTo(0)); + Assert.That(part.GetSittingAvatars(), Is.Null); } [Test] diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs index bebc10ca25..a407f01d63 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceTeleportTests.cs @@ -34,10 +34,14 @@ using OpenSim.Framework; using OpenSim.Framework.Communications; using OpenSim.Framework.Servers; using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.CoreModules.Framework; +using OpenSim.Region.CoreModules.Framework.EntityTransfer; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; +using OpenSim.Region.CoreModules.World.Permissions; using OpenSim.Tests.Common; using OpenSim.Tests.Common.Mock; -using System.Threading; +using System.IO; +using System.Text; namespace OpenSim.Region.Framework.Scenes.Tests { @@ -47,145 +51,367 @@ namespace OpenSim.Region.Framework.Scenes.Tests [TestFixture] public class ScenePresenceTeleportTests { - /// - /// Test a teleport between two regions that are not neighbours and do not share any neighbours in common. - /// - /// Does not yet do what is says on the tin. - /// Commenting for now - //[Test, LongRunning] - public void TestSimpleNotNeighboursTeleport() + [TestFixtureSetUp] + public void FixtureInit() { - TestHelpers.InMethod(); - ThreadRunResults results = new ThreadRunResults(); - results.Result = false; - results.Message = "Test did not run"; - TestRunning testClass = new TestRunning(results); - - Thread testThread = new Thread(testClass.run); - - // Seems kind of redundant to start a thread and then join it, however.. We need to protect against - // A thread abort exception in the simulator code. - testThread.Start(); - testThread.Join(); - - Assert.That(testClass.results.Result, Is.EqualTo(true), testClass.results.Message); - // Console.WriteLine("Beginning test {0}", MethodBase.GetCurrentMethod()); + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest; } - [TearDown] + [TestFixtureTearDown] public void TearDown() { - try - { - if (MainServer.Instance != null) MainServer.Instance.Stop(); - } - catch (NullReferenceException) - { } + // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple + // threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression + // tests really shouldn't). + Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; } - } - - public class ThreadRunResults - { - public bool Result = false; - public string Message = string.Empty; - } - - public class TestRunning - { - public ThreadRunResults results; - public TestRunning(ThreadRunResults t) + [Test] + public void TestSameRegionTeleport() { - results = t; + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + EntityTransferModule etm = new EntityTransferModule(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + // Not strictly necessary since FriendsModule assumes it is the default (!) + config.Configs["Modules"].Set("EntityTransferModule", etm.Name); + + TestScene scene = new SceneHelpers().SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + SceneHelpers.SetupSceneModules(scene, config, etm); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); + sp.AbsolutePosition = new Vector3(30, 31, 32); + scene.RequestTeleportLocation( + sp.ControllingClient, + scene.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + Assert.That(sp.AbsolutePosition, Is.EqualTo(teleportPosition)); + + Assert.That(scene.GetRootAgentCount(), Is.EqualTo(1)); + Assert.That(scene.GetChildAgentCount(), Is.EqualTo(0)); + + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). +// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); } - public void run(object o) + + [Test] + public void TestSameSimulatorSeparatedRegionsTeleport() { - - //results.Result = true; - log4net.Config.XmlConfigurator.Configure(); + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); - UUID sceneAId = UUID.Parse("00000000-0000-0000-0000-000000000100"); - UUID sceneBId = UUID.Parse("00000000-0000-0000-0000-000000000200"); + UUID userId = TestHelpers.ParseTail(0x1); - // shared module - ISharedRegionModule interregionComms = new LocalSimulationConnectorModule(); + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); - Scene sceneB = SceneHelpers.SetupScene("sceneB", sceneBId, 1010, 1010); - SceneHelpers.SetupSceneModules(sceneB, new IniConfigSource(), interregionComms); - sceneB.RegisterRegionWithGrid(); + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + entityTransferConfig.Set("wait_for_callback", false); - Scene sceneA = SceneHelpers.SetupScene("sceneA", sceneAId, 1000, 1000); - SceneHelpers.SetupSceneModules(sceneA, new IniConfigSource(), interregionComms); - sceneA.RegisterRegionWithGrid(); + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1002, 1000); - UUID agentId = UUID.Parse("00000000-0000-0000-0000-000000000041"); - TestClient client = (TestClient)SceneHelpers.AddScenePresence(sceneA, agentId).ControllingClient; + SceneHelpers.SetupSceneModules(sceneA, config, etmA); + SceneHelpers.SetupSceneModules(sceneB, config, etmB); + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); - ICapabilitiesModule sceneACapsModule = sceneA.RequestModuleInterface(); + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); - results.Result = (sceneACapsModule.GetCapsPath(agentId) == client.CapsSeedUrl); - - if (!results.Result) - { - results.Message = "Incorrect caps object path set up in sceneA"; - return; - } + ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); + sp.AbsolutePosition = new Vector3(30, 31, 32); - /* - Assert.That( - sceneACapsModule.GetCapsPath(agentId), - Is.EqualTo(client.CapsSeedUrl), - "Incorrect caps object path set up in sceneA"); - */ - // FIXME: This is a hack to get the test working - really the normal OpenSim mechanisms should be used. - + // XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole + // UDP stack (?) +// ((TestClient)sp.ControllingClient).TeleportTargetScene = sceneB; - client.TeleportTargetScene = sceneB; - client.Teleport(sceneB.RegionInfo.RegionHandle, new Vector3(100, 100, 100), new Vector3(40, 40, 40)); + sceneA.RequestTeleportLocation( + sp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); - results.Result = (sceneB.GetScenePresence(agentId) != null); - if (!results.Result) - { - results.Message = "Client does not have an agent in sceneB"; - return; - } + ((TestClient)sp.ControllingClient).CompleteTeleportClientSide(); - //Assert.That(sceneB.GetScenePresence(agentId), Is.Not.Null, "Client does not have an agent in sceneB"); - - //Assert.That(sceneA.GetScenePresence(agentId), Is.Null, "Client still had an agent in sceneA"); + Assert.That(sceneA.GetScenePresence(userId), Is.Null); - results.Result = (sceneA.GetScenePresence(agentId) == null); - if (!results.Result) - { - results.Message = "Client still had an agent in sceneA"; - return; - } + ScenePresence sceneBSp = sceneB.GetScenePresence(userId); + Assert.That(sceneBSp, Is.Not.Null); + Assert.That(sceneBSp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneB.RegionInfo.RegionName)); + Assert.That(sceneBSp.AbsolutePosition, Is.EqualTo(teleportPosition)); - ICapabilitiesModule sceneBCapsModule = sceneB.RequestModuleInterface(); + Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(0)); + Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0)); + Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(1)); + Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0)); + // TODO: Add assertions to check correct circuit details in both scenes. - results.Result = ("http://" + sceneB.RegionInfo.ExternalHostName + ":" + sceneB.RegionInfo.HttpPort + - "/CAPS/" + sceneBCapsModule.GetCapsPath(agentId) + "0000/" == client.CapsSeedUrl); - if (!results.Result) - { - results.Message = "Incorrect caps object path set up in sceneB"; - return; - } + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). +// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + } - // Temporary assertion - caps url construction should at least be doable through a method. - /* - Assert.That( - "http://" + sceneB.RegionInfo.ExternalHostName + ":" + sceneB.RegionInfo.HttpPort + "/CAPS/" + sceneBCapsModule.GetCapsPath(agentId) + "0000/", - Is.EqualTo(client.CapsSeedUrl), - "Incorrect caps object path set up in sceneB"); - */ - // This assertion will currently fail since we don't remove the caps paths when no longer needed - //Assert.That(sceneACapsModule.GetCapsPath(agentId), Is.Null, "sceneA still had a caps object path"); + /// + /// Test teleport procedures when the target simulator returns false when queried about access. + /// + [Test] + public void TestSameSimulatorSeparatedRegionsQueryAccessFails() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); - // TODO: Check that more of everything is as it should be + UUID userId = TestHelpers.ParseTail(0x1); + Vector3 preTeleportPosition = new Vector3(30, 31, 32); - // TODO: test what happens if we try to teleport to a region that doesn't exist + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("EntityTransferModule", etmA.Name); + config.Configs["Modules"].Set("SimulationServices", lscm.Name); + + config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + config.Configs["EntityTransfer"].Set("wait_for_callback", false); + + config.AddConfig("Startup"); + config.Configs["Startup"].Set("serverside_object_permissions", true); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1002, 1000); + + SceneHelpers.SetupSceneModules(sceneA, config, etmA ); + + // We need to set up the permisions module on scene B so that our later use of agent limit to deny + // QueryAccess won't succeed anyway because administrators are always allowed in and the default + // IsAdministrator if no permissions module is present is true. + SceneHelpers.SetupSceneModules(sceneB, config, new object[] { new PermissionsModule(), etmB }); + + // Shared scene modules + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); + sp.AbsolutePosition = preTeleportPosition; + + // Make sceneB return false on query access + sceneB.RegionInfo.RegionSettings.AgentLimit = 0; + + sceneA.RequestTeleportLocation( + sp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + +// ((TestClient)sp.ControllingClient).CompleteTeleportClientSide(); + + Assert.That(sceneB.GetScenePresence(userId), Is.Null); + + ScenePresence sceneASp = sceneA.GetScenePresence(userId); + Assert.That(sceneASp, Is.Not.Null); + Assert.That(sceneASp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneA.RegionInfo.RegionName)); + Assert.That(sceneASp.AbsolutePosition, Is.EqualTo(preTeleportPosition)); + + Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(1)); + Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0)); + Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(0)); + Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0)); + + // TODO: Add assertions to check correct circuit details in both scenes. + + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). +// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + +// TestHelpers.DisableLogging(); + } + + /// + /// Test teleport procedures when the target simulator create agent step is refused. + /// + [Test] + public void TestSameSimulatorSeparatedRegionsCreateAgentFails() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + Vector3 preTeleportPosition = new Vector3(30, 31, 32); + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("EntityTransferModule", etmA.Name); + config.Configs["Modules"].Set("SimulationServices", lscm.Name); + + config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + config.Configs["EntityTransfer"].Set("wait_for_callback", false); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1002, 1000); + + SceneHelpers.SetupSceneModules(sceneA, config, etmA); + SceneHelpers.SetupSceneModules(sceneB, config, etmB); + + // Shared scene modules + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + ScenePresence sp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); + sp.AbsolutePosition = preTeleportPosition; + + // Make sceneB refuse CreateAgent + sceneB.LoginsDisabled = true; + + sceneA.RequestTeleportLocation( + sp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + +// ((TestClient)sp.ControllingClient).CompleteTeleportClientSide(); + + Assert.That(sceneB.GetScenePresence(userId), Is.Null); + + ScenePresence sceneASp = sceneA.GetScenePresence(userId); + Assert.That(sceneASp, Is.Not.Null); + Assert.That(sceneASp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneA.RegionInfo.RegionName)); + Assert.That(sceneASp.AbsolutePosition, Is.EqualTo(preTeleportPosition)); + + Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(1)); + Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(0)); + Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(0)); + Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0)); + + // TODO: Add assertions to check correct circuit details in both scenes. + + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). +// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + +// TestHelpers.DisableLogging(); + } + + [Test] + public void TestSameSimulatorNeighbouringRegionsTeleport() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID userId = TestHelpers.ParseTail(0x1); + + EntityTransferModule etmA = new EntityTransferModule(); + EntityTransferModule etmB = new EntityTransferModule(); + LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule(); + + IConfigSource config = new IniConfigSource(); + IConfig modulesConfig = config.AddConfig("Modules"); + modulesConfig.Set("EntityTransferModule", etmA.Name); + modulesConfig.Set("SimulationServices", lscm.Name); + IConfig entityTransferConfig = config.AddConfig("EntityTransfer"); + + // In order to run a single threaded regression test we do not want the entity transfer module waiting + // for a callback from the destination scene before removing its avatar data. + entityTransferConfig.Set("wait_for_callback", false); + + SceneHelpers sh = new SceneHelpers(); + TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000); + TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1001, 1000); + + SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm); + SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA); + SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB); + + Vector3 teleportPosition = new Vector3(10, 11, 12); + Vector3 teleportLookAt = new Vector3(20, 21, 22); + + ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager); + originalSp.AbsolutePosition = new Vector3(30, 31, 32); + + ScenePresence beforeSceneASp = sceneA.GetScenePresence(userId); + Assert.That(beforeSceneASp, Is.Not.Null); + Assert.That(beforeSceneASp.IsChildAgent, Is.False); + + ScenePresence beforeSceneBSp = sceneB.GetScenePresence(userId); + Assert.That(beforeSceneBSp, Is.Not.Null); + Assert.That(beforeSceneBSp.IsChildAgent, Is.True); + + // XXX: A very nasty hack to tell the client about the destination scene without having to crank the whole + // UDP stack (?) +// ((TestClient)beforeSceneASp.ControllingClient).TeleportTargetScene = sceneB; + + sceneA.RequestTeleportLocation( + beforeSceneASp.ControllingClient, + sceneB.RegionInfo.RegionHandle, + teleportPosition, + teleportLookAt, + (uint)TeleportFlags.ViaLocation); + + ((TestClient)beforeSceneASp.ControllingClient).CompleteTeleportClientSide(); + + ScenePresence afterSceneASp = sceneA.GetScenePresence(userId); + Assert.That(afterSceneASp, Is.Not.Null); + Assert.That(afterSceneASp.IsChildAgent, Is.True); + + ScenePresence afterSceneBSp = sceneB.GetScenePresence(userId); + Assert.That(afterSceneBSp, Is.Not.Null); + Assert.That(afterSceneBSp.IsChildAgent, Is.False); + Assert.That(afterSceneBSp.Scene.RegionInfo.RegionName, Is.EqualTo(sceneB.RegionInfo.RegionName)); + Assert.That(afterSceneBSp.AbsolutePosition, Is.EqualTo(teleportPosition)); + + Assert.That(sceneA.GetRootAgentCount(), Is.EqualTo(0)); + Assert.That(sceneA.GetChildAgentCount(), Is.EqualTo(1)); + Assert.That(sceneB.GetRootAgentCount(), Is.EqualTo(1)); + Assert.That(sceneB.GetChildAgentCount(), Is.EqualTo(0)); + + // TODO: Add assertions to check correct circuit details in both scenes. + + // Lookat is sent to the client only - sp.Lookat does not yield the same thing (calculation from camera + // position instead). +// Assert.That(sp.Lookat, Is.EqualTo(teleportLookAt)); + +// TestHelpers.DisableLogging(); } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs index 5c9a77db67..d722a0990a 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneTests.cs @@ -60,7 +60,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests { TestHelpers.InMethod(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); scene.Update(1); Assert.That(scene.Frame, Is.EqualTo(1)); diff --git a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs index 55c80f5af1..a51e4e377b 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/TaskInventoryTests.cs @@ -58,7 +58,7 @@ namespace OpenSim.Region.Framework.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, user1.PrincipalID); SceneObjectPart sop1 = sog1.RootPart; @@ -81,7 +81,7 @@ namespace OpenSim.Region.Framework.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, user1.PrincipalID); SceneObjectPart sop1 = sog1.RootPart; @@ -124,11 +124,13 @@ namespace OpenSim.Region.Framework.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, user1.PrincipalID); SceneObjectPart sop1 = sog1.RootPart; - TaskInventoryItem sopItem1 = TaskInventoryHelpers.AddNotecard(scene, sop1); + TaskInventoryItem sopItem1 + = TaskInventoryHelpers.AddNotecard( + scene, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); InventoryFolderBase folder = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, user1.PrincipalID, "Objects")[0]; @@ -153,11 +155,14 @@ namespace OpenSim.Region.Framework.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene); SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, user1.PrincipalID); + SceneObjectPart sop1 = sog1.RootPart; - TaskInventoryItem sopItem1 = TaskInventoryHelpers.AddNotecard(scene, sop1); + TaskInventoryItem sopItem1 + = TaskInventoryHelpers.AddNotecard( + scene, sop1, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); // Perform test scene.MoveTaskInventoryItem(user1.PrincipalID, UUID.Zero, sop1, sopItem1.ItemID); diff --git a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs index 55fc1e73f8..44d2d452d5 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/UserInventoryTests.cs @@ -58,7 +58,7 @@ namespace OpenSim.Region.Framework.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002)); InventoryItemBase item1 = UserInventoryHelpers.CreateInventoryItem(scene, "item1", user1.PrincipalID); @@ -85,7 +85,7 @@ namespace OpenSim.Region.Framework.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); UserAccount user1 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1001)); UserAccount user2 = UserAccountHelpers.CreateUserWithInventory(scene, TestHelpers.ParseTail(1002)); InventoryFolderBase folder1 diff --git a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs index d9fe87c0bf..198e487d1b 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/UuidGathererTests.cs @@ -47,7 +47,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests public void Init() { // FIXME: We don't need a full scene here - it would be enough to set up the asset service. - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); m_assetService = scene.AssetService; m_uuidGatherer = new UuidGatherer(m_assetService); } diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index eac8e8460e..17a210bd25 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -44,7 +44,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server { public delegate void OnIRCClientReadyDelegate(IRCClientView cv); - public class IRCClientView : IClientAPI, IClientCore, IClientIPEndpoint + public class IRCClientView : IClientAPI, IClientCore { public event OnIRCClientReadyDelegate OnIRCReady; @@ -1440,11 +1440,6 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server Disconnect(); } - public EndPoint GetClientEP() - { - return null; - } - public ClientInfo GetClientInfo() { return new ClientInfo(); @@ -1635,11 +1630,6 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server } - public void KillEndDone() - { - - } - public bool AddGenericPacketHandler(string MethodName, GenericMessage handler) { return true; @@ -1647,15 +1637,6 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server #endregion - #region Implementation of IClientIPEndpoint - - public IPAddress EndPoint - { - get { return ((IPEndPoint) m_client.Client.RemoteEndPoint).Address; } - } - - #endregion - public void SendRebakeAvatarTextures(UUID textureID) { } diff --git a/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs new file mode 100644 index 0000000000..1b9e3ace5c --- /dev/null +++ b/OpenSim/Region/OptionalModules/Avatar/Attachments/AttachmentsCommandModule.cs @@ -0,0 +1,195 @@ +/* + * 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 System.Reflection; +using System.Text; +using log4net; +using Mono.Addins; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Console; +using OpenSim.Framework.Statistics; +using OpenSim.Region.ClientStack.LindenUDP; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.OptionalModules.Avatar.Attachments +{ + /// + /// A module that just holds commands for inspecting avatar appearance. + /// + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsCommandModule")] + public class AttachmentsCommandModule : ISharedRegionModule + { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private List m_scenes = new List(); +// private IAvatarFactoryModule m_avatarFactory; + + public string Name { get { return "Attachments Command Module"; } } + + public Type ReplaceableInterface { get { return null; } } + + public void Initialise(IConfigSource source) + { +// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: INITIALIZED MODULE"); + } + + public void PostInitialise() + { +// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: POST INITIALIZED MODULE"); + } + + public void Close() + { +// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: CLOSED MODULE"); + } + + public void AddRegion(Scene scene) + { +// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName); + } + + public void RemoveRegion(Scene scene) + { +// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName); + + lock (m_scenes) + m_scenes.Remove(scene); + } + + public void RegionLoaded(Scene scene) + { +// m_log.DebugFormat("[ATTACHMENTS COMMAND MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); + + lock (m_scenes) + m_scenes.Add(scene); + + scene.AddCommand( + "Users", this, "attachments show", + "attachments show [ ]", + "Show attachment information for avatars in this simulator.", + HandleShowAttachmentsCommand); + } + + protected void HandleShowAttachmentsCommand(string module, string[] cmd) + { + if (cmd.Length != 2 && cmd.Length < 4) + { + MainConsole.Instance.OutputFormat("Usage: attachments show [ ]"); + return; + } + + bool targetNameSupplied = false; + string optionalTargetFirstName = null; + string optionalTargetLastName = null; + + if (cmd.Length >= 4) + { + targetNameSupplied = true; + optionalTargetFirstName = cmd[2]; + optionalTargetLastName = cmd[3]; + } + + StringBuilder sb = new StringBuilder(); + + lock (m_scenes) + { + foreach (Scene scene in m_scenes) + { + if (targetNameSupplied) + { + ScenePresence sp = scene.GetScenePresence(optionalTargetFirstName, optionalTargetLastName); + if (sp != null && !sp.IsChildAgent) + GetAttachmentsReport(sp, sb); + } + else + { + scene.ForEachRootScenePresence(sp => GetAttachmentsReport(sp, sb)); + } + } + } + + MainConsole.Instance.Output(sb.ToString()); + } + + private void GetAttachmentsReport(ScenePresence sp, StringBuilder sb) + { + sb.AppendFormat("Attachments for {0}\n", sp.Name); + + ConsoleDisplayTable ct = new ConsoleDisplayTable() { Indent = 2 }; + ct.Columns.Add(new ConsoleDisplayTableColumn("Attachment Name", 36)); + ct.Columns.Add(new ConsoleDisplayTableColumn("Local ID", 10)); + ct.Columns.Add(new ConsoleDisplayTableColumn("Item ID", 36)); + ct.Columns.Add(new ConsoleDisplayTableColumn("Attach Point", 14)); + ct.Columns.Add(new ConsoleDisplayTableColumn("Position", 15)); + +// sb.AppendFormat( +// " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n", +// "Attachment Name", "Local ID", "Item ID", "Attach Point", "Position"); + + List attachmentObjects = sp.GetAttachments(); + foreach (SceneObjectGroup attachmentObject in attachmentObjects) + { +// InventoryItemBase attachmentItem +// = m_scenes[0].InventoryService.GetItem(new InventoryItemBase(attachmentObject.FromItemID)); + +// if (attachmentItem == null) +// { +// sb.AppendFormat( +// "WARNING: Couldn't find attachment for item {0} at point {1}\n", +// attachmentData.ItemID, (AttachmentPoint)attachmentData.AttachPoint); +// continue; +// } +// else +// { +// sb.AppendFormat( +// " {0,-36} {1,-10} {2,-36} {3,-14} {4,-15}\n", +// attachmentObject.Name, attachmentObject.LocalId, attachmentObject.FromItemID, +// (AttachmentPoint)attachmentObject.AttachmentPoint, attachmentObject.RootPart.AttachedPos); + ct.Rows.Add( + new ConsoleDisplayTableRow( + new List() + { + attachmentObject.Name, + attachmentObject.LocalId.ToString(), + attachmentObject.FromItemID.ToString(), + ((AttachmentPoint)attachmentObject.AttachmentPoint).ToString(), + attachmentObject.RootPart.AttachedPos.ToString() + })); +// } + } + + ct.AddToStringBuilder(sb); + sb.Append("\n"); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/OptionalModules/Avatar/Friends/FriendsCommandsModule.cs b/OpenSim/Region/OptionalModules/Avatar/Friends/FriendsCommandsModule.cs index e68f9d07a3..2602050de4 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Friends/FriendsCommandsModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Friends/FriendsCommandsModule.cs @@ -58,6 +58,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.Friends private Scene m_scene; private IFriendsModule m_friendsModule; private IUserManagement m_userManagementModule; + private IPresenceService m_presenceService; // private IAvatarFactoryModule m_avatarFactory; @@ -99,8 +100,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Friends m_friendsModule = m_scene.RequestModuleInterface(); m_userManagementModule = m_scene.RequestModuleInterface(); + m_presenceService = m_scene.RequestModuleInterface(); - if (m_friendsModule != null && m_userManagementModule != null) + if (m_friendsModule != null && m_userManagementModule != null && m_presenceService != null) { m_scene.AddCommand( "Friends", this, "friends show", @@ -162,7 +164,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Friends MainConsole.Instance.OutputFormat("Friends for {0} {1} {2}:", firstName, lastName, userId); - MainConsole.Instance.OutputFormat("UUID, Name, MyFlags, TheirFlags"); + MainConsole.Instance.OutputFormat( + "{0,-36} {1,-36} {2,-7} {3,7} {4,10}", "UUID", "Name", "Status", "MyFlags", "TheirFlags"); foreach (FriendInfo friend in friends) { @@ -175,14 +178,22 @@ namespace OpenSim.Region.OptionalModules.Avatar.Friends UUID friendId; string friendName; + string onlineText; if (UUID.TryParse(friend.Friend, out friendId)) friendName = m_userManagementModule.GetUserName(friendId); else friendName = friend.Friend; + OpenSim.Services.Interfaces.PresenceInfo[] pi = m_presenceService.GetAgents(new string[] { friend.Friend }); + if (pi.Length > 0) + onlineText = "online"; + else + onlineText = "offline"; + MainConsole.Instance.OutputFormat( - "{0} {1} {2} {3}", friend.Friend, friendName, friend.MyFlags, friend.TheirFlags); + "{0,-36} {1,-36} {2,-7} {3,-7} {4,-10}", + friend.Friend, friendName, onlineText, friend.MyFlags, friend.TheirFlags); } } } diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs index 8af3652b20..7b20446856 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs @@ -306,30 +306,35 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice agentID, caps, scene.RegionInfo.RegionName); string capsBase = "/CAPS/" + caps.CapsObjectPath; - caps.RegisterHandler("ProvisionVoiceAccountRequest", - new RestStreamHandler("POST", capsBase + m_provisionVoiceAccountRequestPath, - delegate(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - return ProvisionVoiceAccountRequest(scene, request, path, param, - agentID, caps); - })); - caps.RegisterHandler("ParcelVoiceInfoRequest", - new RestStreamHandler("POST", capsBase + m_parcelVoiceInfoRequestPath, - delegate(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - return ParcelVoiceInfoRequest(scene, request, path, param, - agentID, caps); - })); - caps.RegisterHandler("ChatSessionRequest", - new RestStreamHandler("POST", capsBase + m_chatSessionRequestPath, - delegate(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - return ChatSessionRequest(scene, request, path, param, - agentID, caps); - })); + caps.RegisterHandler( + "ProvisionVoiceAccountRequest", + new RestStreamHandler( + "POST", + capsBase + m_provisionVoiceAccountRequestPath, + (request, path, param, httpRequest, httpResponse) + => ProvisionVoiceAccountRequest(scene, request, path, param, agentID, caps), + "ProvisionVoiceAccountRequest", + agentID.ToString())); + + caps.RegisterHandler( + "ParcelVoiceInfoRequest", + new RestStreamHandler( + "POST", + capsBase + m_parcelVoiceInfoRequestPath, + (request, path, param, httpRequest, httpResponse) + => ParcelVoiceInfoRequest(scene, request, path, param, agentID, caps), + "ParcelVoiceInfoRequest", + agentID.ToString())); + + caps.RegisterHandler( + "ChatSessionRequest", + new RestStreamHandler( + "POST", + capsBase + m_chatSessionRequestPath, + (request, path, param, httpRequest, httpResponse) + => ChatSessionRequest(scene, request, path, param, agentID, caps), + "ChatSessionRequest", + agentID.ToString())); } /// @@ -818,11 +823,10 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice m_log.DebugFormat("[FreeSwitchVoice]: Region:Parcel \"{0}\": parcel id {1}: using channel name {2}", landName, land.LocalID, landUUID); } - System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding(); // slvoice handles the sip address differently if it begins with confctl, hiding it from the user in the friends list. however it also disables // the personal speech indicators as well unless some siren14-3d codec magic happens. we dont have siren143d so we'll settle for the personal speech indicator. - channelUri = String.Format("sip:conf-{0}@{1}", "x" + Convert.ToBase64String(encoding.GetBytes(landUUID)), m_freeSwitchRealm); + channelUri = String.Format("sip:conf-{0}@{1}", "x" + Convert.ToBase64String(Encoding.ASCII.GetBytes(landUUID)), m_freeSwitchRealm); lock (m_ParcelAddress) { diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs index 4dbac1dd97..396d4c5d78 100644 --- a/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/Voice/VivoxVoice/VivoxVoiceModule.cs @@ -406,30 +406,36 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice m_log.DebugFormat("[VivoxVoice] OnRegisterCaps: agentID {0} caps {1}", agentID, caps); string capsBase = "/CAPS/" + caps.CapsObjectPath; - caps.RegisterHandler("ProvisionVoiceAccountRequest", - new RestStreamHandler("POST", capsBase + m_provisionVoiceAccountRequestPath, - delegate(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - return ProvisionVoiceAccountRequest(scene, request, path, param, - agentID, caps); - })); - caps.RegisterHandler("ParcelVoiceInfoRequest", - new RestStreamHandler("POST", capsBase + m_parcelVoiceInfoRequestPath, - delegate(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - return ParcelVoiceInfoRequest(scene, request, path, param, - agentID, caps); - })); - caps.RegisterHandler("ChatSessionRequest", - new RestStreamHandler("POST", capsBase + m_chatSessionRequestPath, - delegate(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - return ChatSessionRequest(scene, request, path, param, - agentID, caps); - })); + + caps.RegisterHandler( + "ProvisionVoiceAccountRequest", + new RestStreamHandler( + "POST", + capsBase + m_provisionVoiceAccountRequestPath, + (request, path, param, httpRequest, httpResponse) + => ProvisionVoiceAccountRequest(scene, request, path, param, agentID, caps), + "ProvisionVoiceAccountRequest", + agentID.ToString())); + + caps.RegisterHandler( + "ParcelVoiceInfoRequest", + new RestStreamHandler( + "POST", + capsBase + m_parcelVoiceInfoRequestPath, + (request, path, param, httpRequest, httpResponse) + => ParcelVoiceInfoRequest(scene, request, path, param, agentID, caps), + "ParcelVoiceInfoRequest", + agentID.ToString())); + + caps.RegisterHandler( + "ChatSessionRequest", + new RestStreamHandler( + "POST", + capsBase + m_chatSessionRequestPath, + (request, path, param, httpRequest, httpResponse) + => ChatSessionRequest(scene, request, path, param, agentID, caps), + "ChatSessionRequest", + agentID.ToString())); } /// diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs index 130513d4c0..5d57f70733 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs @@ -1401,9 +1401,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups { response = WebUtil.PostToService(m_groupsServerURI, requestArgs); } - catch (Exception e) + catch (Exception) { - m_log.InfoFormat("[SIMIAN GROUPS CONNECTOR] request failed {0}",CacheKey); + m_log.ErrorFormat("[SIMIAN GROUPS CONNECTOR]: request failed {0}", CacheKey); } // and cache the response diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs index d2f63272bd..ac638f1053 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/Tests/GroupsModuleTests.cs @@ -50,7 +50,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - TestScene scene = SceneHelpers.SetupScene(); + TestScene scene = new SceneHelpers().SetupScene(); IConfigSource configSource = new IniConfigSource(); IConfig config = configSource.AddConfig("Groups"); config.Set("Enabled", true); diff --git a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs index 52fc27dcf5..61aaf04bd2 100644 --- a/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs +++ b/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/XmlRpcGroupsServicesConnectorModule.cs @@ -1120,7 +1120,6 @@ namespace Nwc.XmlRpc /// Class supporting the request side of an XML-RPC transaction. public class ConfigurableKeepAliveXmlRpcRequest : XmlRpcRequest { - private Encoding _encoding = new ASCIIEncoding(); private XmlRpcRequestSerializer _serializer = new XmlRpcRequestSerializer(); private XmlRpcResponseDeserializer _deserializer = new XmlRpcResponseDeserializer(); private bool _disableKeepAlive = true; @@ -1153,7 +1152,7 @@ namespace Nwc.XmlRpc request.KeepAlive = !_disableKeepAlive; Stream stream = request.GetRequestStream(); - XmlTextWriter xml = new XmlTextWriter(stream, _encoding); + XmlTextWriter xml = new XmlTextWriter(stream, Encoding.ASCII); _serializer.Serialize(xml, this); xml.Flush(); xml.Close(); diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs new file mode 100644 index 0000000000..34894badf7 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStore.cs @@ -0,0 +1,500 @@ +/* + * Copyright (c) Contributors + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using Mono.Addins; + +using System; +using System.Reflection; +using System.Threading; +using System.Text; +using System.Net; +using System.Net.Sockets; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace OpenSim.Region.OptionalModules.Scripting.JsonStore +{ + public class JsonStore + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private OSD m_ValueStore; + + protected class TakeValueCallbackClass + { + public string Path { get; set; } + public bool UseJson { get; set; } + public TakeValueCallback Callback { get; set; } + + public TakeValueCallbackClass(string spath, bool usejson, TakeValueCallback cback) + { + Path = spath; + UseJson = usejson; + Callback = cback; + } + } + + protected List m_TakeStore; + protected List m_ReadStore; + + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public JsonStore() : this("") {} + + public JsonStore(string value) + { + m_TakeStore = new List(); + m_ReadStore = new List(); + + if (String.IsNullOrEmpty(value)) + m_ValueStore = new OSDMap(); + else + m_ValueStore = OSDParser.DeserializeJson(value); + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public bool TestPath(string expr, bool useJson) + { + Stack path = ParsePathExpression(expr); + OSD result = ProcessPathExpression(m_ValueStore,path); + + if (result == null) + return false; + + if (useJson || result.Type == OSDType.String) + return true; + + return false; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public bool GetValue(string expr, out string value, bool useJson) + { + Stack path = ParsePathExpression(expr); + OSD result = ProcessPathExpression(m_ValueStore,path); + return ConvertOutputValue(result,out value,useJson); + } + + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public bool RemoveValue(string expr) + { + return SetValueFromExpression(expr,null); + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public bool SetValue(string expr, string value, bool useJson) + { + OSD ovalue = useJson ? OSDParser.DeserializeJson(value) : new OSDString(value); + return SetValueFromExpression(expr,ovalue); + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public bool TakeValue(string expr, bool useJson, TakeValueCallback cback) + { + Stack path = ParsePathExpression(expr); + string pexpr = PathExpressionToKey(path); + + OSD result = ProcessPathExpression(m_ValueStore,path); + if (result == null) + { + m_TakeStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback)); + return false; + } + + string value = String.Empty; + if (! ConvertOutputValue(result,out value,useJson)) + { + // the structure does not match the request so i guess we'll wait + m_TakeStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback)); + return false; + } + + SetValueFromExpression(expr,null); + cback(value); + + return true; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public bool ReadValue(string expr, bool useJson, TakeValueCallback cback) + { + Stack path = ParsePathExpression(expr); + string pexpr = PathExpressionToKey(path); + + OSD result = ProcessPathExpression(m_ValueStore,path); + if (result == null) + { + m_ReadStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback)); + return false; + } + + string value = String.Empty; + if (! ConvertOutputValue(result,out value,useJson)) + { + // the structure does not match the request so i guess we'll wait + m_ReadStore.Add(new TakeValueCallbackClass(pexpr,useJson,cback)); + return false; + } + + cback(value); + + return true; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected bool SetValueFromExpression(string expr, OSD ovalue) + { + Stack path = ParsePathExpression(expr); + if (path.Count == 0) + { + m_ValueStore = ovalue; + return true; + } + + string pkey = path.Pop(); + string pexpr = PathExpressionToKey(path); + if (pexpr != "") + pexpr += "."; + + OSD result = ProcessPathExpression(m_ValueStore,path); + if (result == null) + return false; + + Regex aPattern = new Regex("\\[([0-9]+|\\+)\\]"); + MatchCollection amatches = aPattern.Matches(pkey,0); + + if (amatches.Count > 0) + { + if (result.Type != OSDType.Array) + return false; + + OSDArray amap = result as OSDArray; + + Match match = amatches[0]; + GroupCollection groups = match.Groups; + string akey = groups[1].Value; + + if (akey == "+") + { + string npkey = String.Format("[{0}]",amap.Count); + + amap.Add(ovalue); + InvokeNextCallback(pexpr + npkey); + return true; + } + + int aval = Convert.ToInt32(akey); + if (0 <= aval && aval < amap.Count) + { + if (ovalue == null) + amap.RemoveAt(aval); + else + { + amap[aval] = ovalue; + InvokeNextCallback(pexpr + pkey); + } + return true; + } + + return false; + } + + Regex hPattern = new Regex("{([^}]+)}"); + MatchCollection hmatches = hPattern.Matches(pkey,0); + + if (hmatches.Count > 0) + { + Match match = hmatches[0]; + GroupCollection groups = match.Groups; + string hkey = groups[1].Value; + + if (result is OSDMap) + { + OSDMap hmap = result as OSDMap; + if (ovalue != null) + { + hmap[hkey] = ovalue; + InvokeNextCallback(pexpr + pkey); + } + else if (hmap.ContainsKey(hkey)) + hmap.Remove(hkey); + + return true; + } + + return false; + } + + // Shouldn't get here if the path was checked correctly + m_log.WarnFormat("[JsonStore] invalid path expression"); + return false; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected bool InvokeNextCallback(string pexpr) + { + // Process all of the reads that match the expression first + List reads = + m_ReadStore.FindAll(delegate(TakeValueCallbackClass tb) { return pexpr.StartsWith(tb.Path); }); + + foreach (TakeValueCallbackClass readcb in reads) + { + m_ReadStore.Remove(readcb); + ReadValue(readcb.Path,readcb.UseJson,readcb.Callback); + } + + // Process one take next + TakeValueCallbackClass takecb = + m_TakeStore.Find(delegate(TakeValueCallbackClass tb) { return pexpr.StartsWith(tb.Path); }); + + if (takecb != null) + { + m_TakeStore.Remove(takecb); + TakeValue(takecb.Path,takecb.UseJson,takecb.Callback); + + return true; + } + + return false; + } + + // ----------------------------------------------------------------- + /// + /// Parse the path expression and put the components into a stack. We + /// use a stack because we process the path in inverse order later + /// + // ----------------------------------------------------------------- + protected static Stack ParsePathExpression(string path) + { + Stack m_path = new Stack(); + + // add front and rear separators + path = "." + path + "."; + + // add separators for quoted paths + Regex pass1 = new Regex("{[^}]+}"); + path = pass1.Replace(path,".$0.",-1,0); + + // add separators for array references + Regex pass2 = new Regex("(\\[[0-9]+\\]|\\[\\+\\])"); + path = pass2.Replace(path,".$0.",-1,0); + + // add quotes to bare identifier + Regex pass3 = new Regex("\\.([a-zA-Z]+)"); + path = pass3.Replace(path,".{$1}",-1,0); + + // remove extra separators + Regex pass4 = new Regex("\\.+"); + path = pass4.Replace(path,".",-1,0); + + Regex validate = new Regex("^\\.(({[^}]+}|\\[[0-9]+\\]|\\[\\+\\])\\.)+$"); + if (validate.IsMatch(path)) + { + Regex parser = new Regex("\\.({[^}]+}|\\[[0-9]+\\]|\\[\\+\\]+)"); + MatchCollection matches = parser.Matches(path,0); + foreach (Match match in matches) + m_path.Push(match.Groups[1].Value); + } + + return m_path; + } + + // ----------------------------------------------------------------- + /// + /// + /// + /// path is a stack where the top level of the path is at the bottom of the stack + // ----------------------------------------------------------------- + protected static OSD ProcessPathExpression(OSD map, Stack path) + { + if (path.Count == 0) + return map; + + string pkey = path.Pop(); + + OSD rmap = ProcessPathExpression(map,path); + if (rmap == null) + return null; + + // ---------- Check for an array index ---------- + Regex aPattern = new Regex("\\[([0-9]+)\\]"); + MatchCollection amatches = aPattern.Matches(pkey,0); + + if (amatches.Count > 0) + { + if (rmap.Type != OSDType.Array) + { + m_log.WarnFormat("[JsonStore] wrong type for key {2}, expecting {0}, got {1}",OSDType.Array,rmap.Type,pkey); + return null; + } + + OSDArray amap = rmap as OSDArray; + + Match match = amatches[0]; + GroupCollection groups = match.Groups; + string akey = groups[1].Value; + int aval = Convert.ToInt32(akey); + + if (aval < amap.Count) + return (OSD) amap[aval]; + + return null; + } + + // ---------- Check for a hash index ---------- + Regex hPattern = new Regex("{([^}]+)}"); + MatchCollection hmatches = hPattern.Matches(pkey,0); + + if (hmatches.Count > 0) + { + if (rmap.Type != OSDType.Map) + { + m_log.WarnFormat("[JsonStore] wrong type for key {2}, expecting {0}, got {1}",OSDType.Map,rmap.Type,pkey); + return null; + } + + OSDMap hmap = rmap as OSDMap; + + Match match = hmatches[0]; + GroupCollection groups = match.Groups; + string hkey = groups[1].Value; + + if (hmap.ContainsKey(hkey)) + return (OSD) hmap[hkey]; + + return null; + } + + // Shouldn't get here if the path was checked correctly + m_log.WarnFormat("[JsonStore] Path type (unknown) does not match the structure"); + return null; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected static bool ConvertOutputValue(OSD result, out string value, bool useJson) + { + value = String.Empty; + + // If we couldn't process the path + if (result == null) + return false; + + if (useJson) + { + // The path pointed to an intermediate hash structure + if (result.Type == OSDType.Map) + { + value = OSDParser.SerializeJsonString(result as OSDMap); + return true; + } + + // The path pointed to an intermediate hash structure + if (result.Type == OSDType.Array) + { + value = OSDParser.SerializeJsonString(result as OSDArray); + return true; + } + + value = "'" + result.AsString() + "'"; + return true; + } + + if (result.Type == OSDType.String) + { + value = result.AsString(); + return true; + } + + return false; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected static string PathExpressionToKey(Stack path) + { + if (path.Count == 0) + return ""; + + string pkey = ""; + foreach (string k in path) + pkey = (pkey == "") ? k : (k + "." + pkey); + + return pkey; + } + } +} diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs new file mode 100644 index 0000000000..311531c8d4 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreModule.cs @@ -0,0 +1,430 @@ +/* + * Copyright (c) Contributors + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using Mono.Addins; + +using System; +using System.Reflection; +using System.Threading; +using System.Text; +using System.Net; +using System.Net.Sockets; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using System.Collections.Generic; +using System.Text.RegularExpressions; + + +namespace OpenSim.Region.OptionalModules.Scripting.JsonStore +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "JsonStoreModule")] + + public class JsonStoreModule : INonSharedRegionModule, IJsonStoreModule + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IConfig m_config = null; + private bool m_enabled = false; + private Scene m_scene = null; + + private Dictionary m_JsonValueStore; + private UUID m_sharedStore; + +#region IRegionModule Members + + // ----------------------------------------------------------------- + /// + /// Name of this shared module is it's class name + /// + // ----------------------------------------------------------------- + public string Name + { + get { return this.GetType().Name; } + } + + // ----------------------------------------------------------------- + /// + /// Initialise this shared module + /// + /// this region is getting initialised + /// nini config, we are not using this + // ----------------------------------------------------------------- + public void Initialise(IConfigSource config) + { + try + { + if ((m_config = config.Configs["JsonStore"]) == null) + { + // There is no configuration, the module is disabled + // m_log.InfoFormat("[JsonStore] no configuration info"); + return; + } + + m_enabled = m_config.GetBoolean("Enabled", m_enabled); + } + catch (Exception e) + { + m_log.ErrorFormat("[JsonStore] initialization error: {0}",e.Message); + return; + } + + if (m_enabled) + m_log.DebugFormat("[JsonStore] module is enabled"); + } + + // ----------------------------------------------------------------- + /// + /// everything is loaded, perform post load configuration + /// + // ----------------------------------------------------------------- + public void PostInitialise() + { + } + + // ----------------------------------------------------------------- + /// + /// Nothing to do on close + /// + // ----------------------------------------------------------------- + public void Close() + { + } + + // ----------------------------------------------------------------- + /// + /// + // ----------------------------------------------------------------- + public void AddRegion(Scene scene) + { + if (m_enabled) + { + m_scene = scene; + m_scene.RegisterModuleInterface(this); + + m_sharedStore = UUID.Zero; + m_JsonValueStore = new Dictionary(); + m_JsonValueStore.Add(m_sharedStore,new JsonStore("")); + } + } + + // ----------------------------------------------------------------- + /// + /// + // ----------------------------------------------------------------- + public void RemoveRegion(Scene scene) + { + // need to remove all references to the scene in the subscription + // list to enable full garbage collection of the scene object + } + + // ----------------------------------------------------------------- + /// + /// Called when all modules have been added for a region. This is + /// where we hook up events + /// + // ----------------------------------------------------------------- + public void RegionLoaded(Scene scene) + { + if (m_enabled) {} + } + + /// ----------------------------------------------------------------- + /// + /// + // ----------------------------------------------------------------- + public Type ReplaceableInterface + { + get { return null; } + } + +#endregion + +#region ScriptInvocationInteface + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public bool CreateStore(string value, out UUID result) + { + result = UUID.Zero; + + if (! m_enabled) return false; + + UUID uuid = UUID.Random(); + JsonStore map = null; + + try + { + map = new JsonStore(value); + } + catch (Exception e) + { + m_log.InfoFormat("[JsonStore] Unable to initialize store from {0}; {1}",value,e.Message); + return false; + } + + lock (m_JsonValueStore) + m_JsonValueStore.Add(uuid,map); + + result = uuid; + return true; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public bool DestroyStore(UUID storeID) + { + if (! m_enabled) return false; + + lock (m_JsonValueStore) + m_JsonValueStore.Remove(storeID); + + return true; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public bool TestPath(UUID storeID, string path, bool useJson) + { + if (! m_enabled) return false; + + JsonStore map = null; + lock (m_JsonValueStore) + { + if (! m_JsonValueStore.TryGetValue(storeID,out map)) + { + m_log.InfoFormat("[JsonStore] Missing store {0}",storeID); + return true; + } + } + + try + { + lock (map) + return map.TestPath(path,useJson); + } + catch (Exception e) + { + m_log.InfoFormat("[JsonStore] Path test failed for {0} in {1}; {2}",path,storeID,e.Message); + } + + return false; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public bool SetValue(UUID storeID, string path, string value, bool useJson) + { + if (! m_enabled) return false; + + JsonStore map = null; + lock (m_JsonValueStore) + { + if (! m_JsonValueStore.TryGetValue(storeID,out map)) + { + m_log.InfoFormat("[JsonStore] Missing store {0}",storeID); + return false; + } + } + + try + { + lock (map) + if (map.SetValue(path,value,useJson)) + return true; + } + catch (Exception e) + { + m_log.InfoFormat("[JsonStore] Unable to assign {0} to {1} in {2}; {3}",value,path,storeID,e.Message); + } + + return false; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public bool RemoveValue(UUID storeID, string path) + { + if (! m_enabled) return false; + + JsonStore map = null; + lock (m_JsonValueStore) + { + if (! m_JsonValueStore.TryGetValue(storeID,out map)) + { + m_log.InfoFormat("[JsonStore] Missing store {0}",storeID); + return false; + } + } + + try + { + lock (map) + if (map.RemoveValue(path)) + return true; + } + catch (Exception e) + { + m_log.InfoFormat("[JsonStore] Unable to remove {0} in {1}; {2}",path,storeID,e.Message); + } + + return false; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public bool GetValue(UUID storeID, string path, bool useJson, out string value) + { + value = String.Empty; + + if (! m_enabled) return false; + + JsonStore map = null; + lock (m_JsonValueStore) + { + if (! m_JsonValueStore.TryGetValue(storeID,out map)) + return false; + } + + try + { + lock (map) + { + return map.GetValue(path, out value, useJson); + } + } + catch (Exception e) + { + m_log.InfoFormat("[JsonStore] unable to retrieve value; {0}",e.Message); + } + + return false; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public void TakeValue(UUID storeID, string path, bool useJson, TakeValueCallback cback) + { + if (! m_enabled) + { + cback(String.Empty); + return; + } + + JsonStore map = null; + lock (m_JsonValueStore) + { + if (! m_JsonValueStore.TryGetValue(storeID,out map)) + { + cback(String.Empty); + return; + } + } + + try + { + lock (map) + { + map.TakeValue(path, useJson, cback); + return; + } + } + catch (Exception e) + { + m_log.InfoFormat("[JsonStore] unable to retrieve value; {0}",e.ToString()); + } + + cback(String.Empty); + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + public void ReadValue(UUID storeID, string path, bool useJson, TakeValueCallback cback) + { + if (! m_enabled) + { + cback(String.Empty); + return; + } + + JsonStore map = null; + lock (m_JsonValueStore) + { + if (! m_JsonValueStore.TryGetValue(storeID,out map)) + { + cback(String.Empty); + return; + } + } + + try + { + lock (map) + { + map.ReadValue(path, useJson, cback); + return; + } + } + catch (Exception e) + { + m_log.InfoFormat("[JsonStore] unable to retrieve value; {0}",e.ToString()); + } + + cback(String.Empty); + } + +#endregion + } +} diff --git a/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs new file mode 100644 index 0000000000..eaba816179 --- /dev/null +++ b/OpenSim/Region/OptionalModules/Scripting/JsonStore/JsonStoreScriptModule.cs @@ -0,0 +1,498 @@ +/* + * Copyright (c) Contributors + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using Mono.Addins; + +using System; +using System.Reflection; +using System.Threading; +using System.Text; +using System.Net; +using System.Net.Sockets; +using log4net; +using Nini.Config; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace OpenSim.Region.OptionalModules.Scripting.JsonStore +{ + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "JsonStoreScriptModule")] + + public class JsonStoreScriptModule : INonSharedRegionModule + { + private static readonly ILog m_log = + LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IConfig m_config = null; + private bool m_enabled = false; + private Scene m_scene = null; + + private IScriptModuleComms m_comms; + private IJsonStoreModule m_store; + +#region IRegionModule Members + + // ----------------------------------------------------------------- + /// + /// Name of this shared module is it's class name + /// + // ----------------------------------------------------------------- + public string Name + { + get { return this.GetType().Name; } + } + + // ----------------------------------------------------------------- + /// + /// Initialise this shared module + /// + /// this region is getting initialised + /// nini config, we are not using this + // ----------------------------------------------------------------- + public void Initialise(IConfigSource config) + { + try + { + if ((m_config = config.Configs["JsonStore"]) == null) + { + // There is no configuration, the module is disabled + // m_log.InfoFormat("[JsonStoreScripts] no configuration info"); + return; + } + + m_enabled = m_config.GetBoolean("Enabled", m_enabled); + } + catch (Exception e) + { + m_log.ErrorFormat("[JsonStoreScripts] initialization error: {0}",e.Message); + return; + } + + if (m_enabled) + m_log.DebugFormat("[JsonStoreScripts] module is enabled"); + } + + // ----------------------------------------------------------------- + /// + /// everything is loaded, perform post load configuration + /// + // ----------------------------------------------------------------- + public void PostInitialise() + { + } + + // ----------------------------------------------------------------- + /// + /// Nothing to do on close + /// + // ----------------------------------------------------------------- + public void Close() + { + } + + // ----------------------------------------------------------------- + /// + /// + // ----------------------------------------------------------------- + public void AddRegion(Scene scene) + { + } + + // ----------------------------------------------------------------- + /// + /// + // ----------------------------------------------------------------- + public void RemoveRegion(Scene scene) + { + // need to remove all references to the scene in the subscription + // list to enable full garbage collection of the scene object + } + + // ----------------------------------------------------------------- + /// + /// Called when all modules have been added for a region. This is + /// where we hook up events + /// + // ----------------------------------------------------------------- + public void RegionLoaded(Scene scene) + { + if (m_enabled) + { + m_scene = scene; + m_comms = m_scene.RequestModuleInterface(); + if (m_comms == null) + { + m_log.ErrorFormat("[JsonStoreScripts] ScriptModuleComms interface not defined"); + m_enabled = false; + return; + } + + m_store = m_scene.RequestModuleInterface(); + if (m_store == null) + { + m_log.ErrorFormat("[JsonStoreScripts] JsonModule interface not defined"); + m_enabled = false; + return; + } + + try + { + m_comms.RegisterScriptInvocation(this,"JsonCreateStore"); + m_comms.RegisterScriptInvocation(this,"JsonDestroyStore"); + + m_comms.RegisterScriptInvocation(this,"JsonReadNotecard"); + m_comms.RegisterScriptInvocation(this,"JsonWriteNotecard"); + + m_comms.RegisterScriptInvocation(this,"JsonTestPath"); + m_comms.RegisterScriptInvocation(this,"JsonTestPathJson"); + + m_comms.RegisterScriptInvocation(this,"JsonGetValue"); + m_comms.RegisterScriptInvocation(this,"JsonGetValueJson"); + + m_comms.RegisterScriptInvocation(this,"JsonTakeValue"); + m_comms.RegisterScriptInvocation(this,"JsonTakeValueJson"); + + m_comms.RegisterScriptInvocation(this,"JsonReadValue"); + m_comms.RegisterScriptInvocation(this,"JsonReadValueJson"); + + m_comms.RegisterScriptInvocation(this,"JsonSetValue"); + m_comms.RegisterScriptInvocation(this,"JsonSetValueJson"); + + m_comms.RegisterScriptInvocation(this,"JsonRemoveValue"); + } + catch (Exception e) + { + // See http://opensimulator.org/mantis/view.php?id=5971 for more information + m_log.WarnFormat("[JsonStroreScripts] script method registration failed; {0}",e.Message); + m_enabled = false; + } + } + } + + /// ----------------------------------------------------------------- + /// + /// + // ----------------------------------------------------------------- + public Type ReplaceableInterface + { + get { return null; } + } + +#endregion + +#region ScriptInvocationInteface + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected void GenerateRuntimeError(string msg) + { + throw new Exception("JsonStore Runtime Error: " + msg); + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected UUID JsonCreateStore(UUID hostID, UUID scriptID, string value) + { + UUID uuid = UUID.Zero; + if (! m_store.CreateStore(value, out uuid)) + GenerateRuntimeError("Failed to create Json store"); + + return uuid; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected int JsonDestroyStore(UUID hostID, UUID scriptID, UUID storeID) + { + return m_store.DestroyStore(storeID) ? 1 : 0; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected UUID JsonReadNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, UUID assetID) + { + UUID reqID = UUID.Random(); + Util.FireAndForget(delegate(object o) { DoJsonReadNotecard(reqID,hostID,scriptID,storeID,path,assetID); }); + return reqID; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected UUID JsonWriteNotecard(UUID hostID, UUID scriptID, UUID storeID, string path, string name) + { + UUID reqID = UUID.Random(); + Util.FireAndForget(delegate(object o) { DoJsonWriteNotecard(reqID,hostID,scriptID,storeID,path,name); }); + return reqID; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected int JsonTestPath(UUID hostID, UUID scriptID, UUID storeID, string path) + { + return m_store.TestPath(storeID,path,false) ? 1 : 0; + } + + protected int JsonTestPathJson(UUID hostID, UUID scriptID, UUID storeID, string path) + { + return m_store.TestPath(storeID,path,true) ? 1 : 0; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected int JsonSetValue(UUID hostID, UUID scriptID, UUID storeID, string path, string value) + { + return m_store.SetValue(storeID,path,value,false) ? 1 : 0; + } + + protected int JsonSetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path, string value) + { + return m_store.SetValue(storeID,path,value,true) ? 1 : 0; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected int JsonRemoveValue(UUID hostID, UUID scriptID, UUID storeID, string path) + { + return m_store.RemoveValue(storeID,path) ? 1 : 0; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected string JsonGetValue(UUID hostID, UUID scriptID, UUID storeID, string path) + { + string value = String.Empty; + m_store.GetValue(storeID,path,false,out value); + return value; + } + + protected string JsonGetValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) + { + string value = String.Empty; + m_store.GetValue(storeID,path,true, out value); + return value; + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected UUID JsonTakeValue(UUID hostID, UUID scriptID, UUID storeID, string path) + { + UUID reqID = UUID.Random(); + Util.FireAndForget(delegate(object o) { DoJsonTakeValue(scriptID,reqID,storeID,path,false); }); + return reqID; + } + + protected UUID JsonTakeValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) + { + UUID reqID = UUID.Random(); + Util.FireAndForget(delegate(object o) { DoJsonTakeValue(scriptID,reqID,storeID,path,true); }); + return reqID; + } + + private void DoJsonTakeValue(UUID scriptID, UUID reqID, UUID storeID, string path, bool useJson) + { + try + { + m_store.TakeValue(storeID,path,useJson,delegate(string value) { DispatchValue(scriptID,reqID,value); }); + return; + } + catch (Exception e) + { + m_log.InfoFormat("[JsonStoreScripts] unable to retrieve value; {0}",e.ToString()); + } + + DispatchValue(scriptID,reqID,String.Empty); + } + + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected UUID JsonReadValue(UUID hostID, UUID scriptID, UUID storeID, string path) + { + UUID reqID = UUID.Random(); + Util.FireAndForget(delegate(object o) { DoJsonReadValue(scriptID,reqID,storeID,path,false); }); + return reqID; + } + + protected UUID JsonReadValueJson(UUID hostID, UUID scriptID, UUID storeID, string path) + { + UUID reqID = UUID.Random(); + Util.FireAndForget(delegate(object o) { DoJsonReadValue(scriptID,reqID,storeID,path,true); }); + return reqID; + } + + private void DoJsonReadValue(UUID scriptID, UUID reqID, UUID storeID, string path, bool useJson) + { + try + { + m_store.ReadValue(storeID,path,useJson,delegate(string value) { DispatchValue(scriptID,reqID,value); }); + return; + } + catch (Exception e) + { + m_log.InfoFormat("[JsonStoreScripts] unable to retrieve value; {0}",e.ToString()); + } + + DispatchValue(scriptID,reqID,String.Empty); + } + +#endregion + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + protected void DispatchValue(UUID scriptID, UUID reqID, string value) + { + m_comms.DispatchReply(scriptID,1,value,reqID.ToString()); + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + private void DoJsonReadNotecard(UUID reqID, UUID hostID, UUID scriptID, UUID storeID, string path, UUID assetID) + { + AssetBase a = m_scene.AssetService.Get(assetID.ToString()); + if (a == null) + GenerateRuntimeError(String.Format("Unable to find notecard asset {0}",assetID)); + + if (a.Type != (sbyte)AssetType.Notecard) + GenerateRuntimeError(String.Format("Invalid notecard asset {0}",assetID)); + + m_log.DebugFormat("[JsonStoreScripts] read notecard in context {0}",storeID); + + try + { + string jsondata = SLUtil.ParseNotecardToString(Encoding.UTF8.GetString(a.Data)); + int result = m_store.SetValue(storeID, path, jsondata,true) ? 1 : 0; + m_comms.DispatchReply(scriptID,result, "", reqID.ToString()); + return; + } + catch (Exception e) + { + m_log.WarnFormat("[JsonStoreScripts] Json parsing failed; {0}",e.Message); + } + + GenerateRuntimeError(String.Format("Json parsing failed for {0}",assetID.ToString())); + m_comms.DispatchReply(scriptID,0,"",reqID.ToString()); + } + + // ----------------------------------------------------------------- + /// + /// + /// + // ----------------------------------------------------------------- + private void DoJsonWriteNotecard(UUID reqID, UUID hostID, UUID scriptID, UUID storeID, string path, string name) + { + string data; + if (! m_store.GetValue(storeID,path,true, out data)) + { + m_comms.DispatchReply(scriptID,0,UUID.Zero.ToString(),reqID.ToString()); + return; + } + + SceneObjectPart host = m_scene.GetSceneObjectPart(hostID); + + // Create new asset + UUID assetID = UUID.Random(); + AssetBase asset = new AssetBase(assetID, name, (sbyte)AssetType.Notecard, host.OwnerID.ToString()); + asset.Description = "Json store"; + + int textLength = data.Length; + data = "Linden text version 2\n{\nLLEmbeddedItems version 1\n{\ncount 0\n}\nText length " + + textLength.ToString() + "\n" + data + "}\n"; + + asset.Data = Util.UTF8.GetBytes(data); + m_scene.AssetService.Store(asset); + + // Create Task Entry + TaskInventoryItem taskItem = new TaskInventoryItem(); + + taskItem.ResetIDs(host.UUID); + taskItem.ParentID = host.UUID; + taskItem.CreationDate = (uint)Util.UnixTimeSinceEpoch(); + taskItem.Name = asset.Name; + taskItem.Description = asset.Description; + taskItem.Type = (int)AssetType.Notecard; + taskItem.InvType = (int)InventoryType.Notecard; + taskItem.OwnerID = host.OwnerID; + taskItem.CreatorID = host.OwnerID; + taskItem.BasePermissions = (uint)PermissionMask.All; + taskItem.CurrentPermissions = (uint)PermissionMask.All; + taskItem.EveryonePermissions = 0; + taskItem.NextPermissions = (uint)PermissionMask.All; + taskItem.GroupID = host.GroupID; + taskItem.GroupPermissions = 0; + taskItem.Flags = 0; + taskItem.PermsGranter = UUID.Zero; + taskItem.PermsMask = 0; + taskItem.AssetID = asset.FullID; + + host.Inventory.AddInventoryItem(taskItem, false); + + m_comms.DispatchReply(scriptID,1,assetID.ToString(),reqID.ToString()); + } + } +} diff --git a/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs b/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs index 74f52087fe..03481d2d29 100644 --- a/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/Minimodule/MRMModule.cs @@ -482,10 +482,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule // Convert to base64 // string filetext = Convert.ToBase64String(data); - - ASCIIEncoding enc = new ASCIIEncoding(); - - Byte[] buf = enc.GetBytes(filetext); + Byte[] buf = Encoding.ASCII.GetBytes(filetext); m_log.Info("MRM 9"); diff --git a/OpenSim/Region/OptionalModules/Scripting/Minimodule/SPAvatar.cs b/OpenSim/Region/OptionalModules/Scripting/Minimodule/SPAvatar.cs index 922eaafeda..d192309dea 100644 --- a/OpenSim/Region/OptionalModules/Scripting/Minimodule/SPAvatar.cs +++ b/OpenSim/Region/OptionalModules/Scripting/Minimodule/SPAvatar.cs @@ -68,7 +68,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.Minimodule public Vector3 WorldPosition { get { return GetSP().AbsolutePosition; } - set { GetSP().TeleportWithMomentum(value); } + set { GetSP().Teleport(value); } } public bool IsChildAgent diff --git a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs index 0b9f875e89..600cafb7c4 100644 --- a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs @@ -228,9 +228,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady // m_log.InfoFormat("[RegionReady]: Logins enabled for {0}, Oar {1}", // m_scene.RegionInfo.RegionName, m_oarFileLoading.ToString()); - m_log.InfoFormat("[RegionReady]: Initialization complete - logins enabled for {0}", m_scene.RegionInfo.RegionName); + m_log.InfoFormat( + "[RegionReady]: INITIALIZATION COMPLETE FOR {0} - LOGINS ENABLED", m_scene.Name); - if ( m_uri != string.Empty ) + if (m_uri != string.Empty) { RRAlert("enabled"); } diff --git a/OpenSim/Region/OptionalModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs b/OpenSim/Region/OptionalModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs index cab30dec25..74a85e2cd5 100644 --- a/OpenSim/Region/OptionalModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs +++ b/OpenSim/Region/OptionalModules/Scripting/ScriptModuleComms/ScriptModuleCommsModule.cs @@ -38,7 +38,7 @@ using OpenMetaverse; using System.Linq; using System.Linq.Expressions; -namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms +namespace OpenSim.Region.OptionalModules.Scripting.ScriptModuleComms { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ScriptModuleCommsModule")] class ScriptModuleCommsModule : INonSharedRegionModule, IScriptModuleComms diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 89968654cf..97db7e1e79 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -76,22 +76,27 @@ namespace OpenSim.Region.OptionalModules.World.NPC public void Say(string message) { - SendOnChatFromClient(message, ChatTypeEnum.Say); + SendOnChatFromClient(0, message, ChatTypeEnum.Say); } - public void Shout(string message) + public void Say(int channel, string message) { - SendOnChatFromClient(message, ChatTypeEnum.Shout); + SendOnChatFromClient(channel, message, ChatTypeEnum.Say); } - public void Whisper(string message) + public void Shout(int channel, string message) { - SendOnChatFromClient(message, ChatTypeEnum.Whisper); + SendOnChatFromClient(channel, message, ChatTypeEnum.Shout); + } + + public void Whisper(int channel, string message) + { + SendOnChatFromClient(channel, message, ChatTypeEnum.Whisper); } public void Broadcast(string message) { - SendOnChatFromClient(message, ChatTypeEnum.Broadcast); + SendOnChatFromClient(0, message, ChatTypeEnum.Broadcast); } public void GiveMoney(UUID target, int amount) @@ -99,6 +104,45 @@ namespace OpenSim.Region.OptionalModules.World.NPC OnMoneyTransferRequest(m_uuid, target, amount, 1, "Payment"); } + public bool Touch(UUID target) + { + SceneObjectPart part = m_scene.GetSceneObjectPart(target); + if (part == null) + return false; + bool objectTouchable = hasTouchEvents(part); // Only touch an object that is scripted to respond + if (!objectTouchable && !part.IsRoot) + objectTouchable = hasTouchEvents(part.ParentGroup.RootPart); + if (!objectTouchable) + return false; + // Set up the surface args as if the touch is from a client that does not support this + SurfaceTouchEventArgs surfaceArgs = new SurfaceTouchEventArgs(); + surfaceArgs.FaceIndex = -1; // TOUCH_INVALID_FACE + surfaceArgs.Binormal = Vector3.Zero; // TOUCH_INVALID_VECTOR + surfaceArgs.Normal = Vector3.Zero; // TOUCH_INVALID_VECTOR + surfaceArgs.STCoord = new Vector3(-1.0f, -1.0f, 0.0f); // TOUCH_INVALID_TEXCOORD + surfaceArgs.UVCoord = surfaceArgs.STCoord; // TOUCH_INVALID_TEXCOORD + List touchArgs = new List(); + touchArgs.Add(surfaceArgs); + Vector3 offset = part.OffsetPosition * -1.0f; + if (OnGrabObject == null) + return false; + OnGrabObject(part.LocalId, offset, this, touchArgs); + if (OnGrabUpdate != null) + OnGrabUpdate(part.UUID, offset, part.ParentGroup.RootPart.GroupPosition, this, touchArgs); + if (OnDeGrabObject != null) + OnDeGrabObject(part.LocalId, this, touchArgs); + return true; + } + + private bool hasTouchEvents(SceneObjectPart part) + { + if ((part.ScriptEvents & scriptEvents.touch) != 0 || + (part.ScriptEvents & scriptEvents.touch_start) != 0 || + (part.ScriptEvents & scriptEvents.touch_end) != 0) + return true; + return false; + } + public void InstantMessage(UUID target, string message) { OnInstantMessage(this, new GridInstantMessage(m_scene, @@ -146,10 +190,18 @@ namespace OpenSim.Region.OptionalModules.World.NPC #region Internal Functions - private void SendOnChatFromClient(string message, ChatTypeEnum chatType) + private void SendOnChatFromClient(int channel, string message, ChatTypeEnum chatType) { + if (channel == 0) + { + message = message.Trim(); + if (string.IsNullOrEmpty(message)) + { + return; + } + } OSChatMessage chatFromClient = new OSChatMessage(); - chatFromClient.Channel = 0; + chatFromClient.Channel = channel; chatFromClient.From = Name; chatFromClient.Message = message; chatFromClient.Position = StartPos; @@ -900,11 +952,6 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public EndPoint GetClientEP() - { - return null; - } - public ClientInfo GetClientInfo() { return null; @@ -1046,10 +1093,6 @@ namespace OpenSim.Region.OptionalModules.World.NPC { } - public void KillEndDone() - { - } - public void SendEventInfoReply (EventData info) { } diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs index ebf5e8463d..b37aba394e 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCModule.cs @@ -155,18 +155,10 @@ namespace OpenSim.Region.OptionalModules.World.NPC ScenePresence sp; if (scene.TryGetScenePresence(npcAvatar.AgentId, out sp)) { - m_log.DebugFormat( - "[NPC MODULE]: Successfully retrieved scene presence for NPC {0} {1}", sp.Name, sp.UUID); - sp.CompleteMovement(npcAvatar, false); m_avatars.Add(npcAvatar.AgentId, npcAvatar); + m_log.DebugFormat("[NPC MODULE]: Created NPC {0} {1}", npcAvatar.AgentId, sp.Name); } - else - { - m_log.WarnFormat("[NPC MODULE]: Could not find scene presence for NPC {0} {1}", sp.Name, sp.UUID); - npcAvatar.AgentId = UUID.Zero; - } - } ev.Set(); }); @@ -178,7 +170,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC return npcAvatar.AgentId; } - public bool MoveToTarget(UUID agentID, Scene scene, Vector3 pos, bool noFly, bool landAtTarget) + public bool MoveToTarget(UUID agentID, Scene scene, Vector3 pos, bool noFly, bool landAtTarget, bool running) { lock (m_avatars) { @@ -192,6 +184,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC sp.Name, pos, scene.RegionInfo.RegionName, noFly, landAtTarget); sp.MoveToTarget(pos, noFly, landAtTarget); + sp.SetAlwaysRun = running; return true; } @@ -220,6 +213,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC } public bool Say(UUID agentID, Scene scene, string text) + { + return Say(agentID, scene, text, 0); + } + + public bool Say(UUID agentID, Scene scene, string text, int channel) { lock (m_avatars) { @@ -228,7 +226,25 @@ namespace OpenSim.Region.OptionalModules.World.NPC ScenePresence sp; scene.TryGetScenePresence(agentID, out sp); - m_avatars[agentID].Say(text); + m_avatars[agentID].Say(channel, text); + + return true; + } + } + + return false; + } + + public bool Shout(UUID agentID, Scene scene, string text, int channel) + { + lock (m_avatars) + { + if (m_avatars.ContainsKey(agentID)) + { + ScenePresence sp; + scene.TryGetScenePresence(agentID, out sp); + + m_avatars[agentID].Shout(channel, text); return true; } @@ -255,6 +271,24 @@ namespace OpenSim.Region.OptionalModules.World.NPC return false; } + public bool Whisper(UUID agentID, Scene scene, string text, int channel) + { + lock (m_avatars) + { + if (m_avatars.ContainsKey(agentID)) + { + ScenePresence sp; + scene.TryGetScenePresence(agentID, out sp); + + m_avatars[agentID].Whisper(channel, text); + + return true; + } + } + + return false; + } + public bool Stand(UUID agentID, Scene scene) { lock (m_avatars) @@ -272,6 +306,16 @@ namespace OpenSim.Region.OptionalModules.World.NPC return false; } + public bool Touch(UUID agentID, UUID objectID) + { + lock (m_avatars) + { + if (m_avatars.ContainsKey(agentID)) + return m_avatars[agentID].Touch(objectID); + return false; + } + } + public UUID GetOwner(UUID agentID) { lock (m_avatars) @@ -308,7 +352,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC scene.RemoveClient(agentID, false); m_avatars.Remove(agentID); -// m_log.DebugFormat("[NPC MODULE]: Removed {0} {1}", agentID, av.Name); + m_log.DebugFormat("[NPC MODULE]: Removed NPC {0} {1}", agentID, av.Name); return true; } } diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs index eea0b2e6ad..91799667ab 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs @@ -85,7 +85,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests m_attMod = new AttachmentsModule(); m_npcMod = new NPCModule(); - m_scene = SceneHelpers.SetupScene(); + m_scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(m_scene, config, m_afMod, m_umMod, m_attMod, m_npcMod, new BasicInventoryAccessModule()); } @@ -242,7 +242,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); Vector3 targetPos = startPos + new Vector3(0, 10, 0); - m_npcMod.MoveToTarget(npc.UUID, m_scene, targetPos, false, false); + m_npcMod.MoveToTarget(npc.UUID, m_scene, targetPos, false, false, false); Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); //Assert.That(npc.Rotation, Is.EqualTo(new Quaternion(0, 0, 0.7071068f, 0.7071068f))); @@ -267,7 +267,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests // Try a second movement startPos = npc.AbsolutePosition; targetPos = startPos + new Vector3(10, 0, 0); - m_npcMod.MoveToTarget(npc.UUID, m_scene, targetPos, false, false); + m_npcMod.MoveToTarget(npc.UUID, m_scene, targetPos, false, false, false); Assert.That(npc.AbsolutePosition, Is.EqualTo(startPos)); // Assert.That(npc.Rotation, Is.EqualTo(new Quaternion(0, 0, 0, 1))); @@ -301,7 +301,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests UUID npcId = m_npcMod.CreateNPC("John", "Smith", startPos, UUID.Zero, true, m_scene, sp.Appearance); ScenePresence npc = m_scene.GetScenePresence(npcId); - SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene); + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; part.SitTargetPosition = new Vector3(0, 0, 1); m_npcMod.Sit(npc.UUID, part.UUID, m_scene); @@ -333,7 +333,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests UUID npcId = m_npcMod.CreateNPC("John", "Smith", startPos, UUID.Zero, true, m_scene, sp.Appearance); ScenePresence npc = m_scene.GetScenePresence(npcId); - SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene); + SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene).RootPart; m_npcMod.Sit(npc.UUID, part.UUID, m_scene); diff --git a/OpenSim/Region/OptionalModules/World/WorldView/WorldViewModule.cs b/OpenSim/Region/OptionalModules/World/WorldView/WorldViewModule.cs index 48c242db51..1aee39a5b9 100644 --- a/OpenSim/Region/OptionalModules/World/WorldView/WorldViewModule.cs +++ b/OpenSim/Region/OptionalModules/World/WorldView/WorldViewModule.cs @@ -113,14 +113,15 @@ namespace OpenSim.Region.OptionalModules.World.WorldView if (!m_Enabled) return new Byte[0]; - Bitmap bmp = m_Generator.CreateViewImage(pos, rot, fov, width, - height, usetex); + using (Bitmap bmp = m_Generator.CreateViewImage(pos, rot, fov, width, height, usetex)) + { + using (MemoryStream str = new MemoryStream()) + { + bmp.Save(str, ImageFormat.Jpeg); - MemoryStream str = new MemoryStream(); - - bmp.Save(str, ImageFormat.Jpeg); - - return str.ToArray(); + return str.ToArray(); + } + } } } } diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs index b1a3ff9df5..e43136a258 100644 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs +++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsActor.cs @@ -36,13 +36,7 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin { public class BasicActor : PhysicsActor { - private Vector3 _position; - private Vector3 _velocity; - private Vector3 _acceleration; private Vector3 _size; - private Vector3 m_rotationalVelocity; - private bool flying; - private bool iscolliding; public BasicActor(Vector3 size) { @@ -55,11 +49,7 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin set { return; } } - public override Vector3 RotationalVelocity - { - get { return m_rotationalVelocity; } - set { m_rotationalVelocity = value; } - } + public override Vector3 RotationalVelocity { get; set; } public override bool SetAlwaysRun { @@ -105,17 +95,9 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin set { return; } } - public override bool Flying - { - get { return flying; } - set { flying = value; } - } + public override bool Flying { get; set; } - public override bool IsColliding - { - get { return iscolliding; } - set { iscolliding = value; } - } + public override bool IsColliding { get; set; } public override bool CollidingGround { @@ -134,11 +116,7 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin get { return false; } } - public override Vector3 Position - { - get { return _position; } - set { _position = value; } - } + public override Vector3 Position { get; set; } public override Vector3 Size { @@ -206,11 +184,7 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin get { return Vector3.Zero; } } - public override Vector3 Velocity - { - get { return _velocity; } - set { _velocity = value; } - } + public override Vector3 Velocity { get; set; } public override Vector3 Torque { @@ -230,11 +204,7 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin set { } } - public override Vector3 Acceleration - { - get { return _acceleration; } - set { _acceleration = value; } - } + public override Vector3 Acceleration { get; set; } public override bool Kinematic { diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPrim.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPrim.cs new file mode 100644 index 0000000000..47d7df3cc1 --- /dev/null +++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsPrim.cs @@ -0,0 +1,315 @@ +/* + * 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 Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Region.Physics.Manager; + +namespace OpenSim.Region.Physics.BasicPhysicsPlugin +{ + public class BasicPhysicsPrim : PhysicsActor + { + private Vector3 _size; +// private PrimitiveBaseShape _shape; + + public BasicPhysicsPrim( + string name, uint localId, Vector3 position, Vector3 size, Quaternion orientation, PrimitiveBaseShape shape) + { + Name = name; + LocalID = localId; + Position = position; + Size = size; + Orientation = orientation; + Shape = shape; + } + + public override int PhysicsActorType + { + get { return (int) ActorTypes.Agent; } + set { return; } + } + + public override Vector3 RotationalVelocity { get; set; } + + public override bool SetAlwaysRun + { + get { return false; } + set { return; } + } + + public override uint LocalID + { + set { return; } + } + + public override bool Grabbed + { + set { return; } + } + + public override bool Selected + { + set { return; } + } + + public override float Buoyancy + { + get { return 0f; } + set { return; } + } + + public override bool FloatOnWater + { + set { return; } + } + + public override bool IsPhysical + { + get { return false; } + set { return; } + } + + public override bool ThrottleUpdates + { + get { return false; } + set { return; } + } + + public override bool Flying { get; set; } + + public override bool IsColliding { get; set; } + + public override bool CollidingGround + { + get { return false; } + set { return; } + } + + public override bool CollidingObj + { + get { return false; } + set { return; } + } + + public override bool Stopped + { + get { return false; } + } + + public override Vector3 Position { get; set; } + + public override Vector3 Size + { + get { return _size; } + set { + _size = value; + _size.Z = _size.Z / 2.0f; + } + } + + public override PrimitiveBaseShape Shape + { +// set { _shape = value; } + set {} + } + + public override float Mass + { + get { return 0f; } + } + + public override Vector3 Force + { + get { return Vector3.Zero; } + set { return; } + } + + public override int VehicleType + { + get { return 0; } + set { return; } + } + + public override void VehicleFloatParam(int param, float value) + { + + } + + public override void VehicleVectorParam(int param, Vector3 value) + { + + } + + public override void VehicleRotationParam(int param, Quaternion rotation) + { + + } + + public override void VehicleFlags(int param, bool remove) + { + + } + + public override void SetVolumeDetect(int param) + { + + } + + public override Vector3 CenterOfMass + { + get { return Vector3.Zero; } + } + + public override Vector3 GeometricCenter + { + get { return Vector3.Zero; } + } + + public override Vector3 Velocity { get; set; } + + public override Vector3 Torque + { + get { return Vector3.Zero; } + set { return; } + } + + public override float CollisionScore + { + get { return 0f; } + set { } + } + + public override Quaternion Orientation { get; set; } + + public override Vector3 Acceleration { get; set; } + + public override bool Kinematic + { + get { return true; } + set { } + } + + public override void link(PhysicsActor obj) + { + } + + public override void delink() + { + } + + public override void LockAngularMotion(Vector3 axis) + { + } + + public override void AddForce(Vector3 force, bool pushforce) + { + } + + public override void AddAngularForce(Vector3 force, bool pushforce) + { + } + + public override void SetMomentum(Vector3 momentum) + { + } + + public override void CrossingFailure() + { + } + + public override Vector3 PIDTarget + { + set { return; } + } + + public override bool PIDActive + { + set { return; } + } + + public override float PIDTau + { + set { return; } + } + + public override float PIDHoverHeight + { + set { return; } + } + + public override bool PIDHoverActive + { + set { return; } + } + + public override PIDHoverType PIDHoverType + { + set { return; } + } + + public override float PIDHoverTau + { + set { return; } + } + + public override Quaternion APIDTarget + { + set { return; } + } + + public override bool APIDActive + { + set { return; } + } + + public override float APIDStrength + { + set { return; } + } + + public override float APIDDamping + { + set { return; } + } + + public override void SubscribeEvents(int ms) + { + } + + public override void UnSubscribeEvents() + { + } + + public override bool SubscribedEvents() + { + return false; + } + } +} diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs index 2e1421649f..f5826edd2c 100644 --- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs +++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs @@ -34,9 +34,17 @@ using OpenSim.Region.Physics.Manager; namespace OpenSim.Region.Physics.BasicPhysicsPlugin { + /// + /// This is an incomplete extremely basic physics implementation + /// + /// + /// Not useful for anything at the moment apart from some regression testing in other components where some form + /// of physics plugin is needed. + /// public class BasicScene : PhysicsScene { private List _actors = new List(); + private List _prims = new List(); private float[] _heightMap; //protected internal string sceneIdentifier; @@ -50,10 +58,19 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin { } - public override void Dispose() - { + public override void Dispose() {} + public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, + Vector3 size, Quaternion rotation, bool isPhysical, uint localid) + { + BasicPhysicsPrim prim = new BasicPhysicsPrim(primName, localid, position, size, rotation, pbs); + prim.IsPhysical = isPhysical; + + _prims.Add(prim); + + return prim; } + public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) { BasicActor act = new BasicActor(size); @@ -63,30 +80,18 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin return act; } - public override void RemovePrim(PhysicsActor prim) + public override void RemovePrim(PhysicsActor actor) { + BasicPhysicsPrim prim = (BasicPhysicsPrim)actor; + if (_prims.Contains(prim)) + _prims.Remove(prim); } public override void RemoveAvatar(PhysicsActor actor) { - BasicActor act = (BasicActor) actor; + BasicActor act = (BasicActor)actor; if (_actors.Contains(act)) - { _actors.Remove(act); - } - } - -/* - public override PhysicsActor AddPrim(Vector3 position, Vector3 size, Quaternion rotation) - { - return null; - } -*/ - - public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, Vector3 position, - Vector3 size, Quaternion rotation, bool isPhysical, uint localid) - { - return null; } public override void AddPhysicsActorTaint(PhysicsActor prim) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index b08d5dba4d..dc0c0083f8 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -74,7 +74,7 @@ public class BSCharacter : PhysicsActor private float _buoyancy; private int _subscribedEventsMs = 0; - private int _lastCollisionTime = 0; + private int _nextCollisionOkTime = 0; private Vector3 _PIDTarget; private bool _usePID; @@ -360,17 +360,22 @@ public class BSCharacter : PhysicsActor } //m_lastUpdateSent = false; } + public override void AddAngularForce(Vector3 force, bool pushforce) { } public override void SetMomentum(Vector3 momentum) { } + + // Turn on collision events at a rate no faster than one every the given milliseconds public override void SubscribeEvents(int ms) { _subscribedEventsMs = ms; - _lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen + _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen } + // Stop collision events public override void UnSubscribeEvents() { _subscribedEventsMs = 0; } + // Return 'true' if someone has subscribed to events public override bool SubscribedEvents() { return (_subscribedEventsMs > 0); } @@ -386,47 +391,57 @@ public class BSCharacter : PhysicsActor _mass = _density * _avatarVolume; } + // Set to 'true' if the individual changed items should be checked + // (someday RequestPhysicsTerseUpdate() will take a bitmap of changed properties) + const bool SHOULD_CHECK_FOR_INDIVIDUAL_CHANGES = false; + // The physics engine says that properties have updated. Update same and inform // the world that things have changed. public void UpdateProperties(EntityProperties entprop) { bool changed = false; - // we assign to the local variables so the normal set action does not happen - if (_position != entprop.Position) - { + if (SHOULD_CHECK_FOR_INDIVIDUAL_CHANGES) { + // we assign to the local variables so the normal set action does not happen + if (_position != entprop.Position) { + _position = entprop.Position; + changed = true; + } + if (_orientation != entprop.Rotation) { + _orientation = entprop.Rotation; + changed = true; + } + if (_velocity != entprop.Velocity) { + _velocity = entprop.Velocity; + changed = true; + } + if (_acceleration != entprop.Acceleration) { + _acceleration = entprop.Acceleration; + changed = true; + } + if (_rotationalVelocity != entprop.RotationalVelocity) { + _rotationalVelocity = entprop.RotationalVelocity; + changed = true; + } + if (changed) { + // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); + // Avatar movement is not done by generating this event. There is code in the heartbeat + // loop that updates avatars. + // base.RequestPhysicsterseUpdate(); + } + } + else { _position = entprop.Position; - changed = true; - } - if (_orientation != entprop.Rotation) - { _orientation = entprop.Rotation; - changed = true; - } - if (_velocity != entprop.Velocity) - { _velocity = entprop.Velocity; - changed = true; - } - if (_acceleration != entprop.Acceleration) - { _acceleration = entprop.Acceleration; - changed = true; - } - if (_rotationalVelocity != entprop.RotationalVelocity) - { _rotationalVelocity = entprop.RotationalVelocity; - changed = true; - } - if (changed) - { - // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); - // Avatar movement is not done by generating this event. There is a system that - // checks for avatar updates each heartbeat loop. // base.RequestPhysicsterseUpdate(); } } // Called by the scene when a collision with this object is reported + // The collision, if it should be reported to the character, is placed in a collection + // that will later be sent to the simulator when SendCollisions() is called. CollisionEventUpdate collisionCollection = null; public void Collide(uint collidingWith, ActorTypes type, Vector3 contactPoint, Vector3 contactNormal, float pentrationDepth) { @@ -440,29 +455,34 @@ public class BSCharacter : PhysicsActor } // throttle collisions to the rate specified in the subscription - if (_subscribedEventsMs == 0) return; // don't want collisions - int nowTime = _scene.SimulationNowTime; - if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return; - _lastCollisionTime = nowTime; + if (_subscribedEventsMs != 0) { + int nowTime = _scene.SimulationNowTime; + if (nowTime >= _nextCollisionOkTime) { + _nextCollisionOkTime = nowTime + _subscribedEventsMs; - if (collisionCollection == null) - collisionCollection = new CollisionEventUpdate(); - collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); + if (collisionCollection == null) + collisionCollection = new CollisionEventUpdate(); + collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); + } + } } public void SendCollisions() { - // if (collisionCollection != null) - // { - // base.SendCollisionUpdate(collisionCollection); - // collisionCollection = null; - // } + /* + if (collisionCollection != null && collisionCollection.Count > 0) + { + base.SendCollisionUpdate(collisionCollection); + collisionCollection = null; + } + */ // Kludge to make a collision call even if there are no collisions. // This causes the avatar animation to get updated. if (collisionCollection == null) collisionCollection = new CollisionEventUpdate(); base.SendCollisionUpdate(collisionCollection); - collisionCollection = null; + collisionCollection.Clear(); + // End kludge } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs index 0730824ce1..0f027b8d6a 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs @@ -32,6 +32,14 @@ using OpenMetaverse; namespace OpenSim.Region.Physics.BulletSPlugin { + /// + /// Entry for a port of Bullet (http://bulletphysics.org/) to OpenSim. + /// This module interfaces to an unmanaged C++ library which makes the + /// actual calls into the Bullet physics engine. + /// The unmanaged library is found in opensim-libs::trunk/unmanaged/BulletSim/. + /// The unmanaged library is compiled and linked statically with Bullet + /// to create BulletSim.dll and libBulletSim.so (for both 32 and 64 bit). + /// public class BSPlugin : IPhysicsPlugin { //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); @@ -53,6 +61,9 @@ public class BSPlugin : IPhysicsPlugin { if (Util.IsWindows()) Util.LoadArchSpecificWindowsDll("BulletSim.dll"); + // If not Windows, loading is performed by the + // Mono loader as specified in + // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config". _mScene = new BSScene(sceneIdentifier); } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 248d1f2786..130f1ca145 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -90,7 +90,7 @@ public sealed class BSPrim : PhysicsActor private BSPrim _parentPrim; private int _subscribedEventsMs = 0; - private int _lastCollisionTime = 0; + private int _nextCollisionOkTime = 0; long _collidingStep; long _collidingGroundStep; @@ -597,7 +597,8 @@ public sealed class BSPrim : PhysicsActor } public override void SubscribeEvents(int ms) { _subscribedEventsMs = ms; - _lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen + // make sure first collision happens + _nextCollisionOkTime = Util.EnvironmentTickCount() - _subscribedEventsMs; } public override void UnSubscribeEvents() { _subscribedEventsMs = 0; @@ -1338,23 +1339,27 @@ public sealed class BSPrim : PhysicsActor _collidingGroundStep = _scene.SimulationStep; } - if (_subscribedEventsMs == 0) return; // nothing in the object is waiting for collision events - // throttle the collisions to the number of milliseconds specified in the subscription - int nowTime = _scene.SimulationNowTime; - if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return; - _lastCollisionTime = nowTime; + // if someone is subscribed to collision events.... + if (_subscribedEventsMs != 0) { + // throttle the collisions to the number of milliseconds specified in the subscription + int nowTime = _scene.SimulationNowTime; + if (nowTime >= _nextCollisionOkTime) { + _nextCollisionOkTime = nowTime + _subscribedEventsMs; - if (collisionCollection == null) - collisionCollection = new CollisionEventUpdate(); - collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); + if (collisionCollection == null) + collisionCollection = new CollisionEventUpdate(); + collisionCollection.AddCollider(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth)); + } + } } + // The scene is telling us it's time to pass our collected collisions into the simulator public void SendCollisions() { - if (collisionCollection != null) + if (collisionCollection != null && collisionCollection.Count > 0) { base.SendCollisionUpdate(collisionCollection); - collisionCollection = null; + collisionCollection.Clear(); } } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 94a0ccf276..417cb5f3f0 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -52,6 +52,7 @@ using OpenSim.Region.Framework; // Should prim.link() and prim.delink() membership checking happen at taint time? // Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect +// Use collision masks for collision with terrain and phantom objects // Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions) // Implement LockAngularMotion // Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) @@ -62,9 +63,6 @@ using OpenSim.Region.Framework; // Multiple contact points on collision? // See code in ode::near... calls to collision_accounting_events() // (This might not be a problem. ODE collects all the collisions with one object in one tick.) -// Use collision masks for collision with terrain and phantom objects -// Figure out how to not allocate a new Dictionary and List for every collision -// in BSPrim.Collide() and BSCharacter.Collide(). Can the same ones be reused? // Raycast // namespace OpenSim.Region.Physics.BulletSPlugin @@ -405,6 +403,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters // prevent simulation until we've been initialized if (!m_initialized) return 10.0f; + long simulateStartTime = Util.EnvironmentTickCount(); + // update the prim states while we know the physics engine is not busy ProcessTaints(); @@ -437,13 +437,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters } } - // The SendCollision's batch up the collisions on the objects. Now push the collisions into the simulator. + // The above SendCollision's batch up the collisions on the objects. + // Now push the collisions into the simulator. foreach (BSPrim bsp in m_primsWithCollisions) bsp.SendCollisions(); m_primsWithCollisions.Clear(); + + // This is a kludge to get avatar movement updated. + // Don't send collisions only if there were collisions -- send everytime. + // ODE sends collisions even if there are none and this is used to update + // avatar animations and stuff. // foreach (BSCharacter bsc in m_avatarsWithCollisions) // bsc.SendCollisions(); - // This is a kludge to get avatar movement updated. ODE sends collisions even if there isn't any foreach (KeyValuePair kvp in m_avatars) kvp.Value.SendCollisions(); m_avatarsWithCollisions.Clear(); @@ -465,10 +470,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters if (m_avatars.TryGetValue(entprop.ID, out actor)) { actor.UpdateProperties(entprop); + continue; } } } + // If enabled, call into the physics engine to dump statistics if (m_detailedStatsStep > 0) { if ((m_simulationStep % m_detailedStatsStep) == 0) @@ -477,6 +484,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters } } + // this is a waste since the outside routine also calcuates the physics simulation + // period. TODO: There should be a way of computing physics frames from simulator computation. + // long simulateTotalTime = Util.EnvironmentTickCountSubtract(simulateStartTime); + // return (timeStep * (float)simulateTotalTime); + // TODO: FIX THIS: fps calculation wrong. This calculation always returns about 1 in normal operation. return timeStep / (numSubSteps * m_fixedTimeStep) * 1000f; } @@ -528,6 +540,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters public override void SetWaterLevel(float baseheight) { m_waterLevel = baseheight; + // TODO: pass to physics engine so things will float? } public float GetWaterLevel() { diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs index d10a2aa29d..cfede557fc 100644 --- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs +++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs @@ -241,8 +241,22 @@ namespace OpenSim.Region.Physics.Manager public abstract void AddPhysicsActorTaint(PhysicsActor prim); + /// + /// Perform a simulation of the current physics scene over the given timestep. + /// + /// + /// The number of frames simulated over that period. public abstract float Simulate(float timeStep); + /// + /// Get statistics about this scene. + /// + /// This facility is currently experimental and subject to change. + /// + /// A dictionary where the key is the statistic name. If no statistics are supplied then returns null. + /// + public virtual Dictionary GetStats() { return null; } + public abstract void GetResults(); public abstract void SetTerrain(float[] heightMap); diff --git a/OpenSim/Region/Physics/Meshing/PrimMesher.cs b/OpenSim/Region/Physics/Meshing/PrimMesher.cs index 53022ad6b4..4049ee1598 100644 --- a/OpenSim/Region/Physics/Meshing/PrimMesher.cs +++ b/OpenSim/Region/Physics/Meshing/PrimMesher.cs @@ -236,6 +236,13 @@ namespace PrimMesher this.U = u; this.V = v; } + + public UVCoord Flip() + { + this.U = 1.0f - this.U; + this.V = 1.0f - this.V; + return this; + } } public struct Face @@ -603,40 +610,40 @@ namespace PrimMesher /// /// generates a profile for extrusion /// - internal class Profile + public class Profile { private const float twoPi = 2.0f * (float)Math.PI; - internal string errorMessage = null; + public string errorMessage = null; - internal List coords; - internal List faces; - internal List vertexNormals; - internal List us; - internal List faceUVs; - internal List faceNumbers; + public List coords; + public List faces; + public List vertexNormals; + public List us; + public List faceUVs; + public List faceNumbers; // use these for making individual meshes for each prim face - internal List outerCoordIndices = null; - internal List hollowCoordIndices = null; - internal List cut1CoordIndices = null; - internal List cut2CoordIndices = null; + public List outerCoordIndices = null; + public List hollowCoordIndices = null; + public List cut1CoordIndices = null; + public List cut2CoordIndices = null; - internal Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f); - internal Coord cutNormal1 = new Coord(); - internal Coord cutNormal2 = new Coord(); + public Coord faceNormal = new Coord(0.0f, 0.0f, 1.0f); + public Coord cutNormal1 = new Coord(); + public Coord cutNormal2 = new Coord(); - internal int numOuterVerts = 0; - internal int numHollowVerts = 0; + public int numOuterVerts = 0; + public int numHollowVerts = 0; - internal int outerFaceNumber = -1; - internal int hollowFaceNumber = -1; + public int outerFaceNumber = -1; + public int hollowFaceNumber = -1; - internal bool calcVertexNormals = false; - internal int bottomFaceNumber = 0; - internal int numPrimFaces = 0; + public bool calcVertexNormals = false; + public int bottomFaceNumber = 0; + public int numPrimFaces = 0; - internal Profile() + public Profile() { this.coords = new List(); this.faces = new List(); @@ -646,7 +653,7 @@ namespace PrimMesher this.faceNumbers = new List(); } - internal Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals) + public Profile(int sides, float profileStart, float profileEnd, float hollow, int hollowSides, bool createFaces, bool calcVertexNormals) { this.calcVertexNormals = calcVertexNormals; this.coords = new List(); @@ -657,7 +664,6 @@ namespace PrimMesher this.faceNumbers = new List(); Coord center = new Coord(0.0f, 0.0f, 0.0f); - //bool hasCenter = false; List hollowCoords = new List(); List hollowNormals = new List(); @@ -682,8 +688,8 @@ namespace PrimMesher float yScale = 0.5f; if (sides == 4) // corners of a square are sqrt(2) from center { - xScale = 0.707f; - yScale = 0.707f; + xScale = 0.707107f; + yScale = 0.707107f; } float startAngle = profileStart * twoPi; @@ -724,7 +730,6 @@ namespace PrimMesher else if (!simpleFace) { this.coords.Add(center); - //hasCenter = true; if (this.calcVertexNormals) this.vertexNormals.Add(new Coord(0.0f, 0.0f, 1.0f)); this.us.Add(0.0f); @@ -752,7 +757,10 @@ namespace PrimMesher else hollowNormals.Add(new Coord(-angle.X, -angle.Y, 0.0f)); - hollowUs.Add(angle.angle * hollow); + if (hollowSides == 4) + hollowUs.Add(angle.angle * hollow * 0.707107f); + else + hollowUs.Add(angle.angle * hollow); } } } @@ -829,9 +837,6 @@ namespace PrimMesher if (createFaces) { - //int numOuterVerts = this.coords.Count; - //numOuterVerts = this.coords.Count; - //int numHollowVerts = hollowCoords.Count; int numTotalVerts = this.numOuterVerts + this.numHollowVerts; if (this.numOuterVerts == this.numHollowVerts) @@ -993,11 +998,7 @@ namespace PrimMesher if (startVert > 0) this.faceNumbers.Add(-1); for (int i = 0; i < this.numOuterVerts - 1; i++) - //this.faceNumbers.Add(sides < 5 ? faceNum++ : faceNum); - this.faceNumbers.Add(sides < 5 && i < sides ? faceNum++ : faceNum); - - //if (!hasHollow && !hasProfileCut) - // this.bottomFaceNumber = faceNum++; + this.faceNumbers.Add(sides < 5 && i <= sides ? faceNum++ : faceNum); this.faceNumbers.Add(hasProfileCut ? -1 : faceNum++); @@ -1014,8 +1015,7 @@ namespace PrimMesher this.hollowFaceNumber = faceNum++; } - //if (hasProfileCut || hasHollow) - // this.bottomFaceNumber = faceNum++; + this.bottomFaceNumber = faceNum++; if (hasHollow && hasProfileCut) @@ -1030,19 +1030,19 @@ namespace PrimMesher } - internal void MakeFaceUVs() + public void MakeFaceUVs() { this.faceUVs = new List(); foreach (Coord c in this.coords) - this.faceUVs.Add(new UVCoord(0.5f + c.X, 0.5f - c.Y)); + this.faceUVs.Add(new UVCoord(1.0f - (0.5f + c.X), 1.0f - (0.5f - c.Y))); } - internal Profile Copy() + public Profile Copy() { return this.Copy(true); } - internal Profile Copy(bool needFaces) + public Profile Copy(bool needFaces) { Profile copy = new Profile(); @@ -1071,12 +1071,12 @@ namespace PrimMesher return copy; } - internal void AddPos(Coord v) + public void AddPos(Coord v) { this.AddPos(v.X, v.Y, v.Z); } - internal void AddPos(float x, float y, float z) + public void AddPos(float x, float y, float z) { int i; int numVerts = this.coords.Count; @@ -1092,7 +1092,7 @@ namespace PrimMesher } } - internal void AddRot(Quat q) + public void AddRot(Quat q) { int i; int numVerts = this.coords.Count; @@ -1113,7 +1113,7 @@ namespace PrimMesher } } - internal void Scale(float x, float y) + public void Scale(float x, float y) { int i; int numVerts = this.coords.Count; @@ -1131,7 +1131,7 @@ namespace PrimMesher /// /// Changes order of the vertex indices and negates the center vertex normal. Does not alter vertex normals of radial vertices /// - internal void FlipNormals() + public void FlipNormals() { int i; int numFaces = this.faces.Count; @@ -1171,7 +1171,7 @@ namespace PrimMesher } } - internal void AddValue2FaceVertexIndices(int num) + public void AddValue2FaceVertexIndices(int num) { int numFaces = this.faces.Count; Face tmpFace; @@ -1186,7 +1186,7 @@ namespace PrimMesher } } - internal void AddValue2FaceNormalIndices(int num) + public void AddValue2FaceNormalIndices(int num) { if (this.calcVertexNormals) { @@ -1204,7 +1204,7 @@ namespace PrimMesher } } - internal void DumpRaw(String path, String name, String title) + public void DumpRaw(String path, String name, String title) { if (path == null) return; @@ -1261,6 +1261,15 @@ namespace PrimMesher public void Create(PathType pathType, int steps) { + if (this.taperX > 0.999f) + this.taperX = 0.999f; + if (this.taperX < -0.999f) + this.taperX = -0.999f; + if (this.taperY > 0.999f) + this.taperY = 0.999f; + if (this.taperY < -0.999f) + this.taperY = -0.999f; + if (pathType == PathType.Linear || pathType == PathType.Flexible) { int step = 0; @@ -1273,12 +1282,12 @@ namespace PrimMesher float start = -0.5f; float stepSize = length / (float)steps; - float percentOfPathMultiplier = stepSize; - float xOffset = 0.0f; - float yOffset = 0.0f; + float percentOfPathMultiplier = stepSize * 0.999999f; + float xOffset = this.topShearX * this.pathCutBegin; + float yOffset = this.topShearY * this.pathCutBegin; float zOffset = start; - float xOffsetStepIncrement = this.topShearX / steps; - float yOffsetStepIncrement = this.topShearY / steps; + float xOffsetStepIncrement = this.topShearX * length / steps; + float yOffsetStepIncrement = this.topShearY * length / steps; float percentOfPath = this.pathCutBegin; zOffset += percentOfPath; @@ -1573,13 +1582,6 @@ namespace PrimMesher this.hollow = 0.99f; if (hollow < 0.0f) this.hollow = 0.0f; - - //if (sphereMode) - // this.hasProfileCut = this.profileEnd - this.profileStart < 0.4999f; - //else - // //this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f); - // this.hasProfileCut = this.profileEnd - this.profileStart < 0.9999f; - //this.hasHollow = (this.hollow > 0.001f); } /// @@ -1614,10 +1616,9 @@ namespace PrimMesher steps = (int)(steps * 4.5 * length); } - if (sphereMode) + if (this.sphereMode) this.hasProfileCut = this.profileEnd - this.profileStart < 0.4999f; else - //this.hasProfileCut = (this.profileStart > 0.0f || this.profileEnd < 1.0f); this.hasProfileCut = this.profileEnd - this.profileStart < 0.9999f; this.hasHollow = (this.hollow > 0.001f); @@ -1630,6 +1631,22 @@ namespace PrimMesher float hollow = this.hollow; + if (pathType == PathType.Circular) + { + needEndFaces = false; + if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f) + needEndFaces = true; + else if (this.taperX != 0.0f || this.taperY != 0.0f) + needEndFaces = true; + else if (this.skew != 0.0f) + needEndFaces = true; + else if (twistTotal != 0.0f) + needEndFaces = true; + else if (this.radius != 0.0f) + needEndFaces = true; + } + else needEndFaces = true; + // sanity checks float initialProfileRot = 0.0f; if (pathType == PathType.Circular) @@ -1689,20 +1706,13 @@ namespace PrimMesher this.numPrimFaces = profile.numPrimFaces; - //profileOuterFaceNumber = profile.faceNumbers[0]; - //if (!needEndFaces) - // profileOuterFaceNumber--; - //profileOuterFaceNumber = needEndFaces ? 1 : 0; - - - //if (hasHollow) - //{ - // if (needEndFaces) - // profileHollowFaceNumber = profile.faceNumbers[profile.numOuterVerts + 1]; - // else - // profileHollowFaceNumber = profile.faceNumbers[profile.numOuterVerts] - 1; - //} - + int cut1FaceNumber = profile.bottomFaceNumber + 1; + int cut2FaceNumber = cut1FaceNumber + 1; + if (!needEndFaces) + { + cut1FaceNumber -= 2; + cut2FaceNumber -= 2; + } profileOuterFaceNumber = profile.outerFaceNumber; if (!needEndFaces) @@ -1732,7 +1742,8 @@ namespace PrimMesher Coord lastCutNormal1 = new Coord(); Coord lastCutNormal2 = new Coord(); - float lastV = 1.0f; + float thisV = 0.0f; + float lastV = 0.0f; Path path = new Path(); path.twistBegin = twistBegin; @@ -1754,23 +1765,6 @@ namespace PrimMesher path.Create(pathType, steps); - - if (pathType == PathType.Circular) - { - needEndFaces = false; - if (this.pathCutBegin != 0.0f || this.pathCutEnd != 1.0f) - needEndFaces = true; - else if (this.taperX != 0.0f || this.taperY != 0.0f) - needEndFaces = true; - else if (this.skew != 0.0f) - needEndFaces = true; - else if (twistTotal != 0.0f) - needEndFaces = true; - else if (this.radius != 0.0f) - needEndFaces = true; - } - else needEndFaces = true; - for (int nodeIndex = 0; nodeIndex < path.pathNodes.Count; nodeIndex++) { PathNode node = path.pathNodes[nodeIndex]; @@ -1784,7 +1778,7 @@ namespace PrimMesher { newLayer.FlipNormals(); - // add the top faces to the viewerFaces list here + // add the bottom faces to the viewerFaces list if (this.viewerMode) { Coord faceNormal = newLayer.faceNormal; @@ -1811,6 +1805,13 @@ namespace PrimMesher newViewerFace.uv2 = newLayer.faceUVs[face.v2]; newViewerFace.uv3 = newLayer.faceUVs[face.v3]; + if (pathType == PathType.Linear) + { + newViewerFace.uv1.Flip(); + newViewerFace.uv2.Flip(); + newViewerFace.uv3.Flip(); + } + this.viewerFaces.Add(newViewerFace); } } @@ -1835,7 +1836,10 @@ namespace PrimMesher // fill faces between layers int numVerts = newLayer.coords.Count; - Face newFace = new Face(); + Face newFace1 = new Face(); + Face newFace2 = new Face(); + + thisV = 1.0f - node.percentOfPath; if (nodeIndex > 0) { @@ -1853,14 +1857,23 @@ namespace PrimMesher int whichVert = i - startVert; - newFace.v1 = i; - newFace.v2 = i - numVerts; - newFace.v3 = iNext - numVerts; - this.faces.Add(newFace); + newFace1.v1 = i; + newFace1.v2 = i - numVerts; + newFace1.v3 = iNext; - newFace.v2 = iNext - numVerts; - newFace.v3 = iNext; - this.faces.Add(newFace); + newFace1.n1 = newFace1.v1; + newFace1.n2 = newFace1.v2; + newFace1.n3 = newFace1.v3; + this.faces.Add(newFace1); + + newFace2.v1 = iNext; + newFace2.v2 = i - numVerts; + newFace2.v3 = iNext - numVerts; + + newFace2.n1 = newFace2.v1; + newFace2.n2 = newFace2.v2; + newFace2.n3 = newFace2.v3; + this.faces.Add(newFace2); if (this.viewerMode) { @@ -1873,10 +1886,16 @@ namespace PrimMesher ViewerFace newViewerFace1 = new ViewerFace(primFaceNum); ViewerFace newViewerFace2 = new ViewerFace(primFaceNum); - float u1 = newLayer.us[whichVert]; + int uIndex = whichVert; + if (!hasHollow && sides > 4 && uIndex < newLayer.us.Count - 1) + { + uIndex++; + } + + float u1 = newLayer.us[uIndex]; float u2 = 1.0f; - if (whichVert < newLayer.us.Count - 1) - u2 = newLayer.us[whichVert + 1]; + if (uIndex < (int)newLayer.us.Count - 1) + u2 = newLayer.us[uIndex + 1]; if (whichVert == cut1Vert || whichVert == cut2Vert) { @@ -1894,13 +1913,22 @@ namespace PrimMesher u1 -= (int)u1; if (u2 < 0.1f) u2 = 1.0f; - //this.profileOuterFaceNumber = primFaceNum; } - else if (whichVert > profile.coords.Count - profile.numHollowVerts - 1) + } + + if (this.sphereMode) + { + if (whichVert != cut1Vert && whichVert != cut2Vert) { - u1 *= 2.0f; - u2 *= 2.0f; - //this.profileHollowFaceNumber = primFaceNum; + u1 = u1 * 2.0f - 1.0f; + u2 = u2 * 2.0f - 1.0f; + + if (whichVert >= newLayer.numOuterVerts) + { + u1 -= hollow; + u2 -= hollow; + } + } } @@ -1908,37 +1936,39 @@ namespace PrimMesher newViewerFace1.uv2.U = u1; newViewerFace1.uv3.U = u2; - newViewerFace1.uv1.V = 1.0f - node.percentOfPath; + newViewerFace1.uv1.V = thisV; newViewerFace1.uv2.V = lastV; - newViewerFace1.uv3.V = lastV; + newViewerFace1.uv3.V = thisV; - newViewerFace2.uv1.U = u1; - newViewerFace2.uv2.U = u2; + newViewerFace2.uv1.U = u2; + newViewerFace2.uv2.U = u1; newViewerFace2.uv3.U = u2; - newViewerFace2.uv1.V = 1.0f - node.percentOfPath; + newViewerFace2.uv1.V = thisV; newViewerFace2.uv2.V = lastV; - newViewerFace2.uv3.V = 1.0f - node.percentOfPath; + newViewerFace2.uv3.V = lastV; - newViewerFace1.v1 = this.coords[i]; - newViewerFace1.v2 = this.coords[i - numVerts]; - newViewerFace1.v3 = this.coords[iNext - numVerts]; + newViewerFace1.v1 = this.coords[newFace1.v1]; + newViewerFace1.v2 = this.coords[newFace1.v2]; + newViewerFace1.v3 = this.coords[newFace1.v3]; - newViewerFace2.v1 = this.coords[i]; - newViewerFace2.v2 = this.coords[iNext - numVerts]; - newViewerFace2.v3 = this.coords[iNext]; + newViewerFace2.v1 = this.coords[newFace2.v1]; + newViewerFace2.v2 = this.coords[newFace2.v2]; + newViewerFace2.v3 = this.coords[newFace2.v3]; - newViewerFace1.coordIndex1 = i; - newViewerFace1.coordIndex2 = i - numVerts; - newViewerFace1.coordIndex3 = iNext - numVerts; + newViewerFace1.coordIndex1 = newFace1.v1; + newViewerFace1.coordIndex2 = newFace1.v2; + newViewerFace1.coordIndex3 = newFace1.v3; - newViewerFace2.coordIndex1 = i; - newViewerFace2.coordIndex2 = iNext - numVerts; - newViewerFace2.coordIndex3 = iNext; + newViewerFace2.coordIndex1 = newFace2.v1; + newViewerFace2.coordIndex2 = newFace2.v2; + newViewerFace2.coordIndex3 = newFace2.v3; // profile cut faces if (whichVert == cut1Vert) { + newViewerFace1.primFaceNumber = cut1FaceNumber; + newViewerFace2.primFaceNumber = cut1FaceNumber; newViewerFace1.n1 = newLayer.cutNormal1; newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal1; @@ -1947,10 +1977,14 @@ namespace PrimMesher } else if (whichVert == cut2Vert) { + newViewerFace1.primFaceNumber = cut2FaceNumber; + newViewerFace2.primFaceNumber = cut2FaceNumber; newViewerFace1.n1 = newLayer.cutNormal2; - newViewerFace1.n2 = newViewerFace1.n3 = lastCutNormal2; + newViewerFace1.n2 = lastCutNormal2; + newViewerFace1.n3 = lastCutNormal2; - newViewerFace2.n1 = newViewerFace2.n3 = newLayer.cutNormal2; + newViewerFace2.n1 = newLayer.cutNormal2; + newViewerFace2.n3 = newLayer.cutNormal2; newViewerFace2.n2 = lastCutNormal2; } @@ -1963,13 +1997,13 @@ namespace PrimMesher } else { - newViewerFace1.n1 = this.normals[i]; - newViewerFace1.n2 = this.normals[i - numVerts]; - newViewerFace1.n3 = this.normals[iNext - numVerts]; + newViewerFace1.n1 = this.normals[newFace1.n1]; + newViewerFace1.n2 = this.normals[newFace1.n2]; + newViewerFace1.n3 = this.normals[newFace1.n3]; - newViewerFace2.n1 = this.normals[i]; - newViewerFace2.n2 = this.normals[iNext - numVerts]; - newViewerFace2.n3 = this.normals[iNext]; + newViewerFace2.n1 = this.normals[newFace2.n1]; + newViewerFace2.n2 = this.normals[newFace2.n2]; + newViewerFace2.n3 = this.normals[newFace2.n3]; } } @@ -1982,14 +2016,13 @@ namespace PrimMesher lastCutNormal1 = newLayer.cutNormal1; lastCutNormal2 = newLayer.cutNormal2; - lastV = 1.0f - node.percentOfPath; + lastV = thisV; if (needEndFaces && nodeIndex == path.pathNodes.Count - 1 && viewerMode) { // add the top faces to the viewerFaces list here Coord faceNormal = newLayer.faceNormal; - ViewerFace newViewerFace = new ViewerFace(); - newViewerFace.primFaceNumber = 0; + ViewerFace newViewerFace = new ViewerFace(0); int numFaces = newLayer.faces.Count; List faces = newLayer.faces; @@ -2012,6 +2045,13 @@ namespace PrimMesher newViewerFace.uv2 = newLayer.faceUVs[face.v2 - coordsLen]; newViewerFace.uv3 = newLayer.faceUVs[face.v3 - coordsLen]; + if (pathType == PathType.Linear) + { + newViewerFace.uv1.Flip(); + newViewerFace.uv2.Flip(); + newViewerFace.uv3.Flip(); + } + this.viewerFaces.Add(newViewerFace); } } diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index 8397eb4331..f3b0630843 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs @@ -1261,14 +1261,20 @@ namespace OpenSim.Region.Physics.OdePlugin { m_requestedUpdateFrequency = ms; m_eventsubscription = ms; - CollisionEventsThisFrame.Clear(); + + // Don't clear collision event reporting here. This is called directly from scene code and so can lead + // to a race condition with the simulate loop + _parent_scene.AddCollisionEventReporting(this); } public override void UnSubscribeEvents() { - CollisionEventsThisFrame.Clear(); _parent_scene.RemoveCollisionEventReporting(this); + + // Don't clear collision event reporting here. This is called directly from scene code and so can lead + // to a race condition with the simulate loop + m_requestedUpdateFrequency = 0; m_eventsubscription = 0; } diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 6f37347781..a41c8565b9 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs @@ -156,7 +156,15 @@ namespace OpenSim.Region.Physics.OdePlugin /// public IntPtr m_targetSpace = IntPtr.Zero; + /// + /// The prim geometry, used for collision detection. + /// + /// + /// This is never null except for a brief period when the geometry needs to be replaced (due to resizing or + /// mesh change) or when the physical prim is being removed from the scene. + /// public IntPtr prim_geom { get; private set; } + public IntPtr _triMeshData { get; private set; } private IntPtr _linkJointGroup = IntPtr.Zero; @@ -325,14 +333,12 @@ namespace OpenSim.Region.Physics.OdePlugin { prim_geom = geom; //Console.WriteLine("SetGeom to " + prim_geom + " for " + Name); - if (prim_geom != IntPtr.Zero) - { - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - _parent_scene.geom_name_map[prim_geom] = Name; - _parent_scene.actor_name_map[prim_geom] = this; - } + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); + + _parent_scene.geom_name_map[prim_geom] = Name; + _parent_scene.actor_name_map[prim_geom] = this; if (childPrim) { @@ -765,11 +771,8 @@ namespace OpenSim.Region.Physics.OdePlugin m_collisionCategories &= ~CollisionCategories.Body; m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land); - if (prim_geom != IntPtr.Zero) - { - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - } + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); d.BodyDestroy(Body); lock (childrenPrim) @@ -793,11 +796,8 @@ namespace OpenSim.Region.Physics.OdePlugin m_collisionCategories &= ~CollisionCategories.Body; m_collisionFlags &= ~(CollisionCategories.Wind | CollisionCategories.Land); - if (prim_geom != IntPtr.Zero) - { - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - } + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); Body = IntPtr.Zero; } @@ -864,10 +864,7 @@ namespace OpenSim.Region.Physics.OdePlugin // _parent_scene.waitForSpaceUnlock(m_targetSpace); try { - if (prim_geom == IntPtr.Zero) - { - SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null)); - } + SetGeom(d.CreateTriMesh(m_targetSpace, _triMeshData, parent_scene.triCallback, null, null)); } catch (AccessViolationException) { @@ -890,73 +887,67 @@ namespace OpenSim.Region.Physics.OdePlugin #if SPAM Console.WriteLine("ZProcessTaints for " + Name); #endif + + // This must be processed as the very first taint so that later operations have a prim_geom to work with + // if this is a new prim. if (m_taintadd) - { changeadd(); - } - - if (prim_geom != IntPtr.Zero) - { - if (!_position.ApproxEquals(m_taintposition, 0f)) - changemove(); - if (m_taintrot != _orientation) - { - if (childPrim && IsPhysical) // For physical child prim... - { - rotate(); - // KF: ODE will also rotate the parent prim! - // so rotate the root back to where it was - OdePrim parent = (OdePrim)_parent; - parent.rotate(); - } - else - { - //Just rotate the prim - rotate(); - } + if (!_position.ApproxEquals(m_taintposition, 0f)) + changemove(); + + if (m_taintrot != _orientation) + { + if (childPrim && IsPhysical) // For physical child prim... + { + rotate(); + // KF: ODE will also rotate the parent prim! + // so rotate the root back to where it was + OdePrim parent = (OdePrim)_parent; + parent.rotate(); + } + else + { + //Just rotate the prim + rotate(); } - - if (m_taintPhysics != IsPhysical && !(m_taintparent != _parent)) - changePhysicsStatus(); - - if (!_size.ApproxEquals(m_taintsize, 0f)) - changesize(); - - if (m_taintshape) - changeshape(); - - if (m_taintforce) - changeAddForce(); - - if (m_taintaddangularforce) - changeAddAngularForce(); - - if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f)) - changeSetTorque(); - - if (m_taintdisable) - changedisable(); - - if (m_taintselected != m_isSelected) - changeSelectedStatus(); - - if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f)) - changevelocity(); - - if (m_taintparent != _parent) - changelink(); - - if (m_taintCollidesWater != m_collidesWater) - changefloatonwater(); - - if (!m_angularlock.ApproxEquals(m_taintAngularLock,0f)) - changeAngularLock(); - } - else - { - m_log.ErrorFormat("[PHYSICS]: The scene reused a disposed PhysActor for {0}! *waves finger*, Don't be evil. A couple of things can cause this. An improper prim breakdown(be sure to set prim_geom to zero after d.GeomDestroy! An improper buildup (creating the geom failed). Or, the Scene Reused a physics actor after disposing it.)", Name); } + + if (m_taintPhysics != IsPhysical && !(m_taintparent != _parent)) + changePhysicsStatus(); + + if (!_size.ApproxEquals(m_taintsize, 0f)) + changesize(); + + if (m_taintshape) + changeshape(); + + if (m_taintforce) + changeAddForce(); + + if (m_taintaddangularforce) + changeAddAngularForce(); + + if (!m_taintTorque.ApproxEquals(Vector3.Zero, 0.001f)) + changeSetTorque(); + + if (m_taintdisable) + changedisable(); + + if (m_taintselected != m_isSelected) + changeSelectedStatus(); + + if (!m_taintVelocity.ApproxEquals(Vector3.Zero, 0.001f)) + changevelocity(); + + if (m_taintparent != _parent) + changelink(); + + if (m_taintCollidesWater != m_collidesWater) + changefloatonwater(); + + if (!m_angularlock.ApproxEquals(m_taintAngularLock,0f)) + changeAngularLock(); } /// @@ -1052,150 +1043,146 @@ Console.WriteLine("ZProcessTaints for " + Name); /// Child prim private void AddChildPrim(OdePrim prim) { -//Console.WriteLine("AddChildPrim " + Name); - if (LocalID != prim.LocalID) + if (LocalID == prim.LocalID) + return; + + if (Body == IntPtr.Zero) { - if (Body == IntPtr.Zero) + Body = d.BodyCreate(_parent_scene.world); + setMass(); + } + + lock (childrenPrim) + { + if (childrenPrim.Contains(prim)) + return; + +// m_log.DebugFormat( +// "[ODE PRIM]: Linking prim {0} {1} to {2} {3}", prim.Name, prim.LocalID, Name, LocalID); + + childrenPrim.Add(prim); + + foreach (OdePrim prm in childrenPrim) { - Body = d.BodyCreate(_parent_scene.world); - setMass(); + d.Mass m2; + d.MassSetZero(out m2); + d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z); + + d.Quaternion quat = new d.Quaternion(); + quat.W = prm._orientation.W; + quat.X = prm._orientation.X; + quat.Y = prm._orientation.Y; + quat.Z = prm._orientation.Z; + + d.Matrix3 mat = new d.Matrix3(); + d.RfromQ(out mat, ref quat); + d.MassRotate(ref m2, ref mat); + d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z); + d.MassAdd(ref pMass, ref m2); } - if (Body != IntPtr.Zero) + + foreach (OdePrim prm in childrenPrim) { - lock (childrenPrim) - { - if (!childrenPrim.Contains(prim)) - { -//Console.WriteLine("childrenPrim.Add " + prim); - childrenPrim.Add(prim); - - foreach (OdePrim prm in childrenPrim) - { - d.Mass m2; - d.MassSetZero(out m2); - d.MassSetBoxTotal(out m2, prim.CalculateMass(), prm._size.X, prm._size.Y, prm._size.Z); + prm.m_collisionCategories |= CollisionCategories.Body; + prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); - d.Quaternion quat = new d.Quaternion(); - quat.W = prm._orientation.W; - quat.X = prm._orientation.X; - quat.Y = prm._orientation.Y; - quat.Z = prm._orientation.Z; - - d.Matrix3 mat = new d.Matrix3(); - d.RfromQ(out mat, ref quat); - d.MassRotate(ref m2, ref mat); - d.MassTranslate(ref m2, Position.X - prm.Position.X, Position.Y - prm.Position.Y, Position.Z - prm.Position.Z); - d.MassAdd(ref pMass, ref m2); - } - - foreach (OdePrim prm in childrenPrim) - { - prm.m_collisionCategories |= CollisionCategories.Body; - prm.m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); - - if (prm.prim_geom == IntPtr.Zero) - { - m_log.WarnFormat( - "[PHYSICS]: Unable to link one of the linkset elements {0} for parent {1}. No geom yet", - prm.Name, prim.Name); - continue; - } //Console.WriteLine(" GeomSetCategoryBits 1: " + prm.prim_geom + " - " + (int)prm.m_collisionCategories + " for " + Name); - d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories); - d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags); + d.GeomSetCategoryBits(prm.prim_geom, (int)prm.m_collisionCategories); + d.GeomSetCollideBits(prm.prim_geom, (int)prm.m_collisionFlags); + d.Quaternion quat = new d.Quaternion(); + quat.W = prm._orientation.W; + quat.X = prm._orientation.X; + quat.Y = prm._orientation.Y; + quat.Z = prm._orientation.Z; - d.Quaternion quat = new d.Quaternion(); - quat.W = prm._orientation.W; - quat.X = prm._orientation.X; - quat.Y = prm._orientation.Y; - quat.Z = prm._orientation.Z; + d.Matrix3 mat = new d.Matrix3(); + d.RfromQ(out mat, ref quat); + if (Body != IntPtr.Zero) + { + d.GeomSetBody(prm.prim_geom, Body); + prm.childPrim = true; + d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z); + //d.GeomSetOffsetPosition(prim.prim_geom, + // (Position.X - prm.Position.X) - pMass.c.X, + // (Position.Y - prm.Position.Y) - pMass.c.Y, + // (Position.Z - prm.Position.Z) - pMass.c.Z); + d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat); + //d.GeomSetOffsetRotation(prm.prim_geom, ref mat); + d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); + d.BodySetMass(Body, ref pMass); + } + else + { + m_log.DebugFormat("[PHYSICS]: {0} ain't got no boooooooooddy, no body", Name); + } - d.Matrix3 mat = new d.Matrix3(); - d.RfromQ(out mat, ref quat); - if (Body != IntPtr.Zero) - { - d.GeomSetBody(prm.prim_geom, Body); - prm.childPrim = true; - d.GeomSetOffsetWorldPosition(prm.prim_geom, prm.Position.X , prm.Position.Y, prm.Position.Z); - //d.GeomSetOffsetPosition(prim.prim_geom, - // (Position.X - prm.Position.X) - pMass.c.X, - // (Position.Y - prm.Position.Y) - pMass.c.Y, - // (Position.Z - prm.Position.Z) - pMass.c.Z); - d.GeomSetOffsetWorldRotation(prm.prim_geom, ref mat); - //d.GeomSetOffsetRotation(prm.prim_geom, ref mat); - d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); - d.BodySetMass(Body, ref pMass); - } - else - { - m_log.DebugFormat("[PHYSICS]: {0} ain't got no boooooooooddy, no body", Name); - } + prm.m_interpenetrationcount = 0; + prm.m_collisionscore = 0; + prm.m_disabled = false; - prm.m_interpenetrationcount = 0; - prm.m_collisionscore = 0; - prm.m_disabled = false; + // The body doesn't already have a finite rotation mode set here + if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null) + { + prm.createAMotor(m_angularlock); + } + prm.Body = Body; + _parent_scene.ActivatePrim(prm); + } - // The body doesn't already have a finite rotation mode set here - if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null) - { - prm.createAMotor(m_angularlock); - } - prm.Body = Body; - _parent_scene.ActivatePrim(prm); - } - - m_collisionCategories |= CollisionCategories.Body; - m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); + m_collisionCategories |= CollisionCategories.Body; + m_collisionFlags |= (CollisionCategories.Land | CollisionCategories.Wind); //Console.WriteLine("GeomSetCategoryBits 2: " + prim_geom + " - " + (int)m_collisionCategories + " for " + Name); - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); //Console.WriteLine(" Post GeomSetCategoryBits 2"); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - d.Quaternion quat2 = new d.Quaternion(); - quat2.W = _orientation.W; - quat2.X = _orientation.X; - quat2.Y = _orientation.Y; - quat2.Z = _orientation.Z; + d.Quaternion quat2 = new d.Quaternion(); + quat2.W = _orientation.W; + quat2.X = _orientation.X; + quat2.Y = _orientation.Y; + quat2.Z = _orientation.Z; - d.Matrix3 mat2 = new d.Matrix3(); - d.RfromQ(out mat2, ref quat2); - d.GeomSetBody(prim_geom, Body); - d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z); - //d.GeomSetOffsetPosition(prim.prim_geom, - // (Position.X - prm.Position.X) - pMass.c.X, - // (Position.Y - prm.Position.Y) - pMass.c.Y, - // (Position.Z - prm.Position.Z) - pMass.c.Z); - //d.GeomSetOffsetRotation(prim_geom, ref mat2); - d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); - d.BodySetMass(Body, ref pMass); + d.Matrix3 mat2 = new d.Matrix3(); + d.RfromQ(out mat2, ref quat2); + d.GeomSetBody(prim_geom, Body); + d.GeomSetOffsetWorldPosition(prim_geom, Position.X - pMass.c.X, Position.Y - pMass.c.Y, Position.Z - pMass.c.Z); + //d.GeomSetOffsetPosition(prim.prim_geom, + // (Position.X - prm.Position.X) - pMass.c.X, + // (Position.Y - prm.Position.Y) - pMass.c.Y, + // (Position.Z - prm.Position.Z) - pMass.c.Z); + //d.GeomSetOffsetRotation(prim_geom, ref mat2); + d.MassTranslate(ref pMass, -pMass.c.X, -pMass.c.Y, -pMass.c.Z); + d.BodySetMass(Body, ref pMass); - d.BodySetAutoDisableFlag(Body, true); - d.BodySetAutoDisableSteps(Body, body_autodisable_frames); + d.BodySetAutoDisableFlag(Body, true); + d.BodySetAutoDisableSteps(Body, body_autodisable_frames); - m_interpenetrationcount = 0; - m_collisionscore = 0; - m_disabled = false; + m_interpenetrationcount = 0; + m_collisionscore = 0; + m_disabled = false; - // The body doesn't already have a finite rotation mode set here - if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null) - { - createAMotor(m_angularlock); - } - d.BodySetPosition(Body, Position.X, Position.Y, Position.Z); - if (m_vehicle.Type != Vehicle.TYPE_NONE) - m_vehicle.Enable(Body, _parent_scene); - - _parent_scene.ActivatePrim(this); - } - } + // The body doesn't already have a finite rotation mode set here + if ((!m_angularlock.ApproxEquals(Vector3.Zero, 0f)) && _parent == null) + { + createAMotor(m_angularlock); } + + d.BodySetPosition(Body, Position.X, Position.Y, Position.Z); + + if (m_vehicle.Type != Vehicle.TYPE_NONE) + m_vehicle.Enable(Body, _parent_scene); + + _parent_scene.ActivatePrim(this); } } private void ChildSetGeom(OdePrim odePrim) { +// m_log.DebugFormat( +// "[ODE PRIM]: ChildSetGeom {0} {1} for {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID); + //if (IsPhysical && Body != IntPtr.Zero) lock (childrenPrim) { @@ -1210,12 +1197,14 @@ Console.WriteLine("ZProcessTaints for " + Name); //prm.childPrim = false; } } + disableBody(); - if (Body != IntPtr.Zero) - { - _parent_scene.DeactivatePrim(this); - } + // Spurious - Body == IntPtr.Zero after disableBody() +// if (Body != IntPtr.Zero) +// { +// _parent_scene.DeactivatePrim(this); +// } lock (childrenPrim) { @@ -1229,6 +1218,9 @@ Console.WriteLine("ZProcessTaints for " + Name); private void ChildDelink(OdePrim odePrim) { +// m_log.DebugFormat( +// "[ODE PRIM]: Delinking prim {0} {1} from {2} {3}", odePrim.Name, odePrim.LocalID, Name, LocalID); + // Okay, we have a delinked child.. need to rebuild the body. lock (childrenPrim) { @@ -1243,6 +1235,7 @@ Console.WriteLine("ZProcessTaints for " + Name); //prm.childPrim = false; } } + disableBody(); lock (childrenPrim) @@ -1251,10 +1244,11 @@ Console.WriteLine("ZProcessTaints for " + Name); childrenPrim.Remove(odePrim); } - if (Body != IntPtr.Zero) - { - _parent_scene.DeactivatePrim(this); - } + // Spurious - Body == IntPtr.Zero after disableBody() +// if (Body != IntPtr.Zero) +// { +// _parent_scene.DeactivatePrim(this); +// } lock (childrenPrim) { @@ -1303,11 +1297,8 @@ Console.WriteLine("ZProcessTaints for " + Name); disableBodySoft(); } - if (prim_geom != IntPtr.Zero) - { - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - } + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); if (IsPhysical) { @@ -1328,11 +1319,8 @@ Console.WriteLine("ZProcessTaints for " + Name); if (m_collidesWater) m_collisionFlags |= CollisionCategories.Water; - if (prim_geom != IntPtr.Zero) - { - d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); - } + d.GeomSetCategoryBits(prim_geom, (int)m_collisionCategories); + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); if (IsPhysical) { @@ -1472,6 +1460,9 @@ Console.WriteLine("CreateGeom:"); } else { + m_log.WarnFormat( + "[ODE PRIM]: Called RemoveGeom() on {0} {1} where geometry was already null.", Name, LocalID); + return false; } } @@ -1505,16 +1496,13 @@ Console.WriteLine("changeadd 1"); #endif CreateGeom(m_targetSpace, mesh); - if (prim_geom != IntPtr.Zero) - { - d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); - d.Quaternion myrot = new d.Quaternion(); - myrot.X = _orientation.X; - myrot.Y = _orientation.Y; - myrot.Z = _orientation.Z; - myrot.W = _orientation.W; - d.GeomSetQuaternion(prim_geom, ref myrot); - } + d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); + d.Quaternion myrot = new d.Quaternion(); + myrot.X = _orientation.X; + myrot.Y = _orientation.Y; + myrot.Z = _orientation.Z; + myrot.W = _orientation.W; + d.GeomSetQuaternion(prim_geom, ref myrot); if (IsPhysical && Body == IntPtr.Zero) enableBody(); @@ -1579,24 +1567,20 @@ Console.WriteLine(" JointCreateFixed"); //m_log.Debug("[BUG]: race!"); //} } - else - { - // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position); - // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position); -// _parent_scene.waitForSpaceUnlock(m_targetSpace); - IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace); - m_targetSpace = tempspace; + // string primScenAvatarIn = _parent_scene.whichspaceamIin(_position); + // int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position); +// _parent_scene.waitForSpaceUnlock(m_targetSpace); + + IntPtr tempspace = _parent_scene.recalculateSpaceForGeom(prim_geom, _position, m_targetSpace); + m_targetSpace = tempspace; // _parent_scene.waitForSpaceUnlock(m_targetSpace); - if (prim_geom != IntPtr.Zero) - { - d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); + + d.GeomSetPosition(prim_geom, _position.X, _position.Y, _position.Z); // _parent_scene.waitForSpaceUnlock(m_targetSpace); - d.SpaceAdd(m_targetSpace, prim_geom); - } - } + d.SpaceAdd(m_targetSpace, prim_geom); changeSelectedStatus(); @@ -2047,18 +2031,16 @@ Console.WriteLine(" JointCreateFixed"); { m_collidesWater = m_taintCollidesWater; - if (prim_geom != IntPtr.Zero) + if (m_collidesWater) { - if (m_collidesWater) - { - m_collisionFlags |= CollisionCategories.Water; - } - else - { - m_collisionFlags &= ~CollisionCategories.Water; - } - d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); + m_collisionFlags |= CollisionCategories.Water; } + else + { + m_collisionFlags &= ~CollisionCategories.Water; + } + + d.GeomSetCollideBits(prim_geom, (int)m_collisionFlags); } /// diff --git a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs index 842ff916dc..32e81e2ea1 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdeScene.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdeScene.cs @@ -30,20 +30,21 @@ using System; using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Threading; -using System.IO; -using System.Diagnostics; using log4net; using Nini.Config; using Ode.NET; +using OpenMetaverse; #if USE_DRAWSTUFF using Drawstuff.NET; #endif using OpenSim.Framework; using OpenSim.Region.Physics.Manager; -using OpenMetaverse; namespace OpenSim.Region.Physics.OdePlugin { @@ -54,15 +55,15 @@ namespace OpenSim.Region.Physics.OdePlugin End = 2 } - public struct sCollisionData - { - public uint ColliderLocalId; - public uint CollidedWithLocalId; - public int NumberOfCollisions; - public int CollisionType; - public int StatusIndicator; - public int lastframe; - } +// public struct sCollisionData +// { +// public uint ColliderLocalId; +// public uint CollidedWithLocalId; +// public int NumberOfCollisions; +// public int CollisionType; +// public int StatusIndicator; +// public int lastframe; +// } [Flags] public enum CollisionCategories : int @@ -131,6 +132,135 @@ namespace OpenSim.Region.Physics.OdePlugin /// internal static Object UniversalColliderSyncObject = new Object(); + /// + /// Is stats collecting enabled for this ODE scene? + /// + public bool CollectStats { get; set; } + + /// + /// Statistics for this scene. + /// + private Dictionary m_stats = new Dictionary(); + + /// + /// Stat name for total number of avatars in this ODE scene. + /// + public const string ODETotalAvatarsStatName = "ODETotalAvatars"; + + /// + /// Stat name for total number of prims in this ODE scene. + /// + public const string ODETotalPrimsStatName = "ODETotalPrims"; + + /// + /// Stat name for total number of prims with active physics in this ODE scene. + /// + public const string ODEActivePrimsStatName = "ODEActivePrims"; + + /// + /// Stat name for the total time spent in ODE frame processing. + /// + /// + /// A sanity check for the main scene loop physics time. + /// + public const string ODETotalFrameMsStatName = "ODETotalFrameMS"; + + /// + /// Stat name for time spent processing avatar taints per frame + /// + public const string ODEAvatarTaintMsStatName = "ODEAvatarTaintFrameMS"; + + /// + /// Stat name for time spent processing prim taints per frame + /// + public const string ODEPrimTaintMsStatName = "ODEPrimTaintFrameMS"; + + /// + /// Stat name for time spent calculating avatar forces per frame. + /// + public const string ODEAvatarForcesFrameMsStatName = "ODEAvatarForcesFrameMS"; + + /// + /// Stat name for time spent calculating prim forces per frame + /// + public const string ODEPrimForcesFrameMsStatName = "ODEPrimForcesFrameMS"; + + /// + /// Stat name for time spent fulfilling raycasting requests per frame + /// + public const string ODERaycastingFrameMsStatName = "ODERaycastingFrameMS"; + + /// + /// Stat name for time spent in native code that actually steps through the simulation. + /// + public const string ODENativeStepFrameMsStatName = "ODENativeStepFrameMS"; + + /// + /// Stat name for the number of milliseconds that ODE spends in native space collision code. + /// + public const string ODENativeSpaceCollisionFrameMsStatName = "ODENativeSpaceCollisionFrameMS"; + + /// + /// Stat name for milliseconds that ODE spends in native geom collision code. + /// + public const string ODENativeGeomCollisionFrameMsStatName = "ODENativeGeomCollisionFrameMS"; + + /// + /// Time spent in collision processing that is not spent in native space or geom collision code. + /// + public const string ODEOtherCollisionFrameMsStatName = "ODEOtherCollisionFrameMS"; + + /// + /// Stat name for time spent notifying listeners of collisions + /// + public const string ODECollisionNotificationFrameMsStatName = "ODECollisionNotificationFrameMS"; + + /// + /// Stat name for milliseconds spent updating avatar position and velocity + /// + public const string ODEAvatarUpdateFrameMsStatName = "ODEAvatarUpdateFrameMS"; + + /// + /// Stat name for the milliseconds spent updating prim position and velocity + /// + public const string ODEPrimUpdateFrameMsStatName = "ODEPrimUpdateFrameMS"; + + /// + /// Stat name for avatar collisions with another entity. + /// + public const string ODEAvatarContactsStatsName = "ODEAvatarContacts"; + + /// + /// Stat name for prim collisions with another entity. + /// + public const string ODEPrimContactsStatName = "ODEPrimContacts"; + + /// + /// Used to hold tick numbers for stat collection purposes. + /// + private int m_nativeCollisionStartTick; + + /// + /// A messy way to tell if we need to avoid adding a collision time because this was already done in the callback. + /// + private bool m_inCollisionTiming; + + /// + /// A temporary holder for the number of avatar collisions in a frame, so we can work out how many object + /// collisions occured using the _perloopcontact if stats collection is enabled. + /// + private int m_tempAvatarCollisionsThisFrame; + + /// + /// Used in calculating physics frame time dilation + /// + private int tickCountFrameRun; + + /// + /// Used in calculating physics frame time dilation + /// + private int latertickcount; + private Random fluidRandomizer = new Random(Environment.TickCount); private const uint m_regionWidth = Constants.RegionSize; @@ -257,12 +387,12 @@ namespace OpenSim.Region.Physics.OdePlugin /// /// A dictionary of actors that should receive collision events. /// - private readonly Dictionary _collisionEventPrim = new Dictionary(); + private readonly Dictionary m_collisionEventActors = new Dictionary(); /// /// A dictionary of collision event changes that are waiting to be processed. /// - private readonly Dictionary _collisionEventPrimChanges = new Dictionary(); + private readonly Dictionary m_collisionEventActorsChanges = new Dictionary(); /// /// Maps a unique geometry id (a memory location) to a physics actor name. @@ -345,9 +475,6 @@ namespace OpenSim.Region.Physics.OdePlugin private OdePrim cp1; private OdeCharacter cc2; private OdePrim cp2; - private int tickCountFrameRun; - - private int latertickcount=0; //private int cStartStop = 0; //private string cDictKey = ""; @@ -440,6 +567,8 @@ namespace OpenSim.Region.Physics.OdePlugin // Initialize the mesh plugin public override void Initialise(IMesher meshmerizer, IConfigSource config) { + InitializeExtraStats(); + mesher = meshmerizer; m_config = config; // Defaults @@ -464,6 +593,8 @@ namespace OpenSim.Region.Physics.OdePlugin IConfig physicsconfig = m_config.Configs["ODEPhysicsSettings"]; if (physicsconfig != null) { + CollectStats = physicsconfig.GetBoolean("collect_stats", false); + gravityx = physicsconfig.GetFloat("world_gravityx", 0f); gravityy = physicsconfig.GetFloat("world_gravityy", 0f); gravityz = physicsconfig.GetFloat("world_gravityz", -9.8f); @@ -764,6 +895,62 @@ namespace OpenSim.Region.Physics.OdePlugin #region Collision Detection + /// + /// Collides two geometries. + /// + /// + /// + /// /param> + /// + /// + /// + private int CollideGeoms( + IntPtr geom1, IntPtr geom2, int maxContacts, Ode.NET.d.ContactGeom[] contactsArray, int contactGeomSize) + { + int count; + + lock (OdeScene.UniversalColliderSyncObject) + { + // We do this inside the lock so that we don't count any delay in acquiring it + if (CollectStats) + m_nativeCollisionStartTick = Util.EnvironmentTickCount(); + + count = d.Collide(geom1, geom2, maxContacts, contactsArray, contactGeomSize); + } + + // We do this outside the lock so that any waiting threads aren't held up, though the effect is probably + // negligable + if (CollectStats) + m_stats[ODENativeGeomCollisionFrameMsStatName] + += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); + + return count; + } + + /// + /// Collide two spaces or a space and a geometry. + /// + /// + /// /param> + /// + private void CollideSpaces(IntPtr space1, IntPtr space2, IntPtr data) + { + if (CollectStats) + { + m_inCollisionTiming = true; + m_nativeCollisionStartTick = Util.EnvironmentTickCount(); + } + + d.SpaceCollide2(space1, space2, data, nearCallback); + + if (CollectStats && m_inCollisionTiming) + { + m_stats[ODENativeSpaceCollisionFrameMsStatName] + += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); + m_inCollisionTiming = false; + } + } + /// /// This is our near callback. A geometry is near a body /// @@ -772,6 +959,13 @@ namespace OpenSim.Region.Physics.OdePlugin /// another geometry or space private void near(IntPtr space, IntPtr g1, IntPtr g2) { + if (CollectStats && m_inCollisionTiming) + { + m_stats[ODENativeSpaceCollisionFrameMsStatName] + += Util.EnvironmentTickCountSubtract(m_nativeCollisionStartTick); + m_inCollisionTiming = false; + } + // m_log.DebugFormat("[PHYSICS]: Colliding {0} and {1} in {2}", g1, g2, space); // no lock here! It's invoked from within Simulate(), which is thread-locked @@ -789,7 +983,7 @@ namespace OpenSim.Region.Physics.OdePlugin // contact points in the space try { - d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback); + CollideSpaces(g1, g2, IntPtr.Zero); } catch (AccessViolationException) { @@ -832,6 +1026,7 @@ namespace OpenSim.Region.Physics.OdePlugin // Figure out how many contact points we have int count = 0; + try { // Colliding Geom To Geom @@ -843,8 +1038,11 @@ namespace OpenSim.Region.Physics.OdePlugin if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact)) return; - lock (OdeScene.UniversalColliderSyncObject) - count = d.Collide(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf); + count = CollideGeoms(g1, g2, contacts.Length, contacts, d.ContactGeom.SizeOf); + + // All code after this is only relevant if we have any collisions + if (count <= 0) + return; if (count > contacts.Length) m_log.Error("[ODE SCENE]: Got " + count + " contacts when we asked for a maximum of " + contacts.Length); @@ -1113,14 +1311,12 @@ namespace OpenSim.Region.Physics.OdePlugin { _perloopContact.Add(curContact); - // If we're colliding against terrain if (name1 == "Terrain" || name2 == "Terrain") { - // If we're moving if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) { - // Use the movement terrain contact + // Avatar is moving on terrain, use the movement terrain contact AvatarMovementTerrainContact.geom = curContact; if (m_global_contactcount < maxContactsbeforedeath) @@ -1133,7 +1329,7 @@ namespace OpenSim.Region.Physics.OdePlugin { if (p2.PhysicsActorType == (int)ActorTypes.Agent) { - // Use the non moving terrain contact + // Avatar is standing on terrain, use the non moving terrain contact TerrainContact.geom = curContact; if (m_global_contactcount < maxContactsbeforedeath) @@ -1228,13 +1424,11 @@ namespace OpenSim.Region.Physics.OdePlugin } else { - // we're colliding with prim or avatar - // check if we're moving if ((p2.PhysicsActorType == (int)ActorTypes.Agent)) { if ((Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) { - // Use the Movement prim contact + // Avatar is moving on a prim, use the Movement prim contact AvatarMovementprimContact.geom = curContact; if (m_global_contactcount < maxContactsbeforedeath) @@ -1245,9 +1439,8 @@ namespace OpenSim.Region.Physics.OdePlugin } else { - // Use the non movement contact + // Avatar is standing still on a prim, use the non movement contact contact.geom = curContact; - _perloopContact.Add(curContact); if (m_global_contactcount < maxContactsbeforedeath) { @@ -1355,7 +1548,7 @@ namespace OpenSim.Region.Physics.OdePlugin break; } } - //m_log.DebugFormat("[Collsion]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); + //m_log.DebugFormat("[Collision]: Depth {0}", Math.Abs(contact.depth - contactGeom.depth)); //m_log.DebugFormat("[Collision]: <{0},{1},{2}>", Math.Abs(contactGeom.normal.X - contact.normal.X), Math.Abs(contactGeom.normal.Y - contact.normal.Y), Math.Abs(contactGeom.normal.Z - contact.normal.Z)); } } @@ -1578,7 +1771,7 @@ namespace OpenSim.Region.Physics.OdePlugin // and we'll run it again on all of them. try { - d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback); + CollideSpaces(space, chr.Shell, IntPtr.Zero); } catch (AccessViolationException) { @@ -1593,6 +1786,12 @@ namespace OpenSim.Region.Physics.OdePlugin //} } + if (CollectStats) + { + m_tempAvatarCollisionsThisFrame = _perloopContact.Count; + m_stats[ODEAvatarContactsStatsName] += m_tempAvatarCollisionsThisFrame; + } + List removeprims = null; foreach (OdePrim chr in _activeprims) { @@ -1604,7 +1803,7 @@ namespace OpenSim.Region.Physics.OdePlugin { if (space != IntPtr.Zero && chr.prim_geom != IntPtr.Zero && chr.m_taintremove == false) { - d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback); + CollideSpaces(space, chr.prim_geom, IntPtr.Zero); } else { @@ -1625,6 +1824,9 @@ namespace OpenSim.Region.Physics.OdePlugin } } + if (CollectStats) + m_stats[ODEPrimContactsStatName] += _perloopContact.Count - m_tempAvatarCollisionsThisFrame; + if (removeprims != null) { foreach (OdePrim chr in removeprims) @@ -1706,8 +1908,8 @@ namespace OpenSim.Region.Physics.OdePlugin { // m_log.DebugFormat("[PHYSICS]: Adding {0} {1} to collision event reporting", obj.SOPName, obj.LocalID); - lock (_collisionEventPrimChanges) - _collisionEventPrimChanges[obj.LocalID] = obj; + lock (m_collisionEventActorsChanges) + m_collisionEventActorsChanges[obj.LocalID] = obj; } /// @@ -1718,8 +1920,8 @@ namespace OpenSim.Region.Physics.OdePlugin { // m_log.DebugFormat("[PHYSICS]: Removing {0} {1} from collision event reporting", obj.SOPName, obj.LocalID); - lock (_collisionEventPrimChanges) - _collisionEventPrimChanges[obj.LocalID] = null; + lock (m_collisionEventActorsChanges) + m_collisionEventActorsChanges[obj.LocalID] = null; } #region Add/Remove Entities @@ -2226,7 +2428,8 @@ namespace OpenSim.Region.Physics.OdePlugin /// internal void RemovePrimThreadLocked(OdePrim prim) { -//Console.WriteLine("RemovePrimThreadLocked " + prim.m_primName); +// m_log.DebugFormat("[ODE SCENE]: Removing physical prim {0} {1}", prim.Name, prim.LocalID); + lock (prim) { RemoveCollisionEventReporting(prim); @@ -2682,21 +2885,23 @@ namespace OpenSim.Region.Physics.OdePlugin /// /// This is our main simulate loop + /// + /// /// It's thread locked by a Mutex in the scene. /// It holds Collisions, it instructs ODE to step through the physical reactions /// It moves the objects around in memory /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup) - /// + /// /// - /// + /// The number of frames simulated over that period. public override float Simulate(float timeStep) { + int startFrameTick = CollectStats ? Util.EnvironmentTickCount() : 0; + int tempTick = 0, tempTick2 = 0; + if (framecount >= int.MaxValue) framecount = 0; - //if (m_worldOffset != Vector3.Zero) - // return 0; - framecount++; float fps = 0; @@ -2704,7 +2909,7 @@ namespace OpenSim.Region.Physics.OdePlugin float timeLeft = timeStep; //m_log.Info(timeStep.ToString()); -// step_time += timeStep; +// step_time += timeSte // // // If We're loaded down by something else, // // or debugging with the Visual Studio project on pause @@ -2725,17 +2930,17 @@ namespace OpenSim.Region.Physics.OdePlugin // We change _collisionEventPrimChanges to avoid locking _collisionEventPrim itself and causing potential // deadlock if the collision event tries to lock something else later on which is already locked by a // caller that is adding or removing the collision event. - lock (_collisionEventPrimChanges) + lock (m_collisionEventActorsChanges) { - foreach (KeyValuePair kvp in _collisionEventPrimChanges) + foreach (KeyValuePair kvp in m_collisionEventActorsChanges) { if (kvp.Value == null) - _collisionEventPrim.Remove(kvp.Key); + m_collisionEventActors.Remove(kvp.Key); else - _collisionEventPrim[kvp.Key] = kvp.Value; + m_collisionEventActors[kvp.Key] = kvp.Value; } - _collisionEventPrimChanges.Clear(); + m_collisionEventActorsChanges.Clear(); } if (SupportsNINJAJoints) @@ -2770,6 +2975,9 @@ namespace OpenSim.Region.Physics.OdePlugin { try { + if (CollectStats) + tempTick = Util.EnvironmentTickCount(); + lock (_taintedActors) { foreach (OdeCharacter character in _taintedActors) @@ -2778,6 +2986,13 @@ namespace OpenSim.Region.Physics.OdePlugin _taintedActors.Clear(); } + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEAvatarTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + lock (_taintedPrims) { foreach (OdePrim prim in _taintedPrims) @@ -2808,6 +3023,13 @@ namespace OpenSim.Region.Physics.OdePlugin _taintedPrims.Clear(); } + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEPrimTaintMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + // Move characters foreach (OdeCharacter actor in _characters) actor.Move(defects); @@ -2827,6 +3049,13 @@ namespace OpenSim.Region.Physics.OdePlugin defects.Clear(); } + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEAvatarForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + // Move other active objects foreach (OdePrim prim in _activeprims) { @@ -2834,15 +3063,36 @@ namespace OpenSim.Region.Physics.OdePlugin prim.Move(timeStep); } + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEPrimForcesFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + //if ((framecount % m_randomizeWater) == 0) // randomizeWater(waterlevel); //int RayCastTimeMS = m_rayCastManager.ProcessQueuedRequests(); m_rayCastManager.ProcessQueuedRequests(); + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODERaycastingFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + collision_optimized(); - foreach (PhysicsActor obj in _collisionEventPrim.Values) + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEOtherCollisionFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + + foreach (PhysicsActor obj in m_collisionEventActors.Values) { // m_log.DebugFormat("[PHYSICS]: Assessing {0} {1} for collision events", obj.SOPName, obj.LocalID); @@ -2866,9 +3116,19 @@ namespace OpenSim.Region.Physics.OdePlugin // "[PHYSICS]: Collision contacts to process this frame = {0}", m_global_contactcount); m_global_contactcount = 0; - + + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODECollisionNotificationFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + d.WorldQuickStep(world, ODE_STEPSIZE); + if (CollectStats) + m_stats[ODENativeStepFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); + d.JointGroupEmpty(contactgroup); } catch (Exception e) @@ -2879,6 +3139,9 @@ namespace OpenSim.Region.Physics.OdePlugin timeLeft -= ODE_STEPSIZE; } + if (CollectStats) + tempTick = Util.EnvironmentTickCount(); + foreach (OdeCharacter actor in _characters) { if (actor.bad) @@ -2902,6 +3165,13 @@ namespace OpenSim.Region.Physics.OdePlugin defects.Clear(); } + if (CollectStats) + { + tempTick2 = Util.EnvironmentTickCount(); + m_stats[ODEAvatarUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick2, tempTick); + tempTick = tempTick2; + } + //if (timeStep < 0.2f) foreach (OdePrim prim in _activeprims) @@ -2915,6 +3185,9 @@ namespace OpenSim.Region.Physics.OdePlugin } } + if (CollectStats) + m_stats[ODEPrimUpdateFrameMsStatName] += Util.EnvironmentTickCountSubtract(tempTick); + //DumpJointInfo(); // Finished with all sim stepping. If requested, dump world state to file for debugging. @@ -2936,7 +3209,7 @@ namespace OpenSim.Region.Physics.OdePlugin d.WorldExportDIF(world, fname, physics_logging_append_existing_logfile, prefix); } - latertickcount = Util.EnvironmentTickCount() - tickCountFrameRun; + latertickcount = Util.EnvironmentTickCountSubtract(tickCountFrameRun); // OpenSimulator above does 10 fps. 10 fps = means that the main thread loop and physics // has a max of 100 ms to run theoretically. @@ -2954,6 +3227,9 @@ namespace OpenSim.Region.Physics.OdePlugin } tickCountFrameRun = Util.EnvironmentTickCount(); + + if (CollectStats) + m_stats[ODETotalFrameMsStatName] += Util.EnvironmentTickCountSubtract(startFrameTick); } return fps; @@ -3189,7 +3465,7 @@ namespace OpenSim.Region.Physics.OdePlugin public override bool IsThreaded { // for now we won't be multithreaded - get { return (false); } + get { return false; } } #region ODE Specific Terrain Fixes @@ -3765,26 +4041,19 @@ namespace OpenSim.Region.Physics.OdePlugin public override Dictionary GetTopColliders() { - Dictionary returncolliders = new Dictionary(); - int cnt = 0; + Dictionary topColliders; + lock (_prims) { - foreach (OdePrim prm in _prims) - { - if (prm.CollisionScore > 0) - { - returncolliders.Add(prm.LocalID, prm.CollisionScore); - cnt++; - prm.CollisionScore = 0f; - if (cnt > 25) - { - break; - } - } - } + List orderedPrims = new List(_prims); + orderedPrims.OrderByDescending(p => p.CollisionScore).Take(25); + topColliders = orderedPrims.ToDictionary(p => p.LocalID, p => p.CollisionScore); + + foreach (OdePrim p in _prims) + p.CollisionScore = 0; } - return returncolliders; + return topColliders; } public override bool SupportsRayCast() @@ -3954,5 +4223,52 @@ namespace OpenSim.Region.Physics.OdePlugin ds.SetViewpoint(ref xyz, ref hpr); } #endif + + public override Dictionary GetStats() + { + if (!CollectStats) + return null; + + Dictionary returnStats; + + lock (OdeLock) + { + returnStats = new Dictionary(m_stats); + + // FIXME: This is a SUPER DUMB HACK until we can establish stats that aren't subject to a division by + // 3 from the SimStatsReporter. + returnStats[ODETotalAvatarsStatName] = _characters.Count * 3; + returnStats[ODETotalPrimsStatName] = _prims.Count * 3; + returnStats[ODEActivePrimsStatName] = _activeprims.Count * 3; + + InitializeExtraStats(); + } + + returnStats[ODEOtherCollisionFrameMsStatName] + = returnStats[ODEOtherCollisionFrameMsStatName] + - returnStats[ODENativeSpaceCollisionFrameMsStatName] + - returnStats[ODENativeGeomCollisionFrameMsStatName]; + + return returnStats; + } + + private void InitializeExtraStats() + { + m_stats[ODETotalFrameMsStatName] = 0; + m_stats[ODEAvatarTaintMsStatName] = 0; + m_stats[ODEPrimTaintMsStatName] = 0; + m_stats[ODEAvatarForcesFrameMsStatName] = 0; + m_stats[ODEPrimForcesFrameMsStatName] = 0; + m_stats[ODERaycastingFrameMsStatName] = 0; + m_stats[ODENativeStepFrameMsStatName] = 0; + m_stats[ODENativeSpaceCollisionFrameMsStatName] = 0; + m_stats[ODENativeGeomCollisionFrameMsStatName] = 0; + m_stats[ODEOtherCollisionFrameMsStatName] = 0; + m_stats[ODECollisionNotificationFrameMsStatName] = 0; + m_stats[ODEAvatarContactsStatsName] = 0; + m_stats[ODEPrimContactsStatName] = 0; + m_stats[ODEAvatarUpdateFrameMsStatName] = 0; + m_stats[ODEPrimUpdateFrameMsStatName] = 0; + } } } \ No newline at end of file diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs index d8d955439c..204c4ff5fb 100644 --- a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs +++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs @@ -43,9 +43,8 @@ using Mono.Addins; [assembly: AddinDependency("OpenSim", "0.5")] namespace OpenSim.Region.RegionCombinerModule { - [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] - public class RegionCombinerModule : ISharedRegionModule + public class RegionCombinerModule : ISharedRegionModule, IRegionCombinerModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -59,19 +58,33 @@ namespace OpenSim.Region.RegionCombinerModule get { return null; } } + /// + /// Is this module enabled? + /// + private bool m_combineContiguousRegions = false; + + /// + /// This holds the root regions for the megaregions. + /// + /// + /// Usually there is only ever one megaregion (and hence only one entry here). + /// private Dictionary m_regions = new Dictionary(); - private bool enabledYN = false; + + /// + /// The scenes that comprise the megaregion. + /// private Dictionary m_startingScenes = new Dictionary(); public void Initialise(IConfigSource source) { IConfig myConfig = source.Configs["Startup"]; - enabledYN = myConfig.GetBoolean("CombineContiguousRegions", false); + m_combineContiguousRegions = myConfig.GetBoolean("CombineContiguousRegions", false); - if (enabledYN) - MainConsole.Instance.Commands.AddCommand( - "RegionCombinerModule", false, "fix-phantoms", "fix-phantoms", - "Fixes phantom objects after an import to megaregions", FixPhantoms); + MainConsole.Instance.Commands.AddCommand( + "RegionCombinerModule", false, "fix-phantoms", "fix-phantoms", + "Fixes phantom objects after an import to a megaregion or a change from a megaregion back to normal regions", + FixPhantoms); } public void Close() @@ -80,6 +93,8 @@ namespace OpenSim.Region.RegionCombinerModule public void AddRegion(Scene scene) { + if (m_combineContiguousRegions) + scene.RegisterModuleInterface(this); } public void RemoveRegion(Scene scene) @@ -88,8 +103,113 @@ namespace OpenSim.Region.RegionCombinerModule public void RegionLoaded(Scene scene) { - if (enabledYN) + lock (m_startingScenes) + m_startingScenes.Add(scene.RegionInfo.originRegionID, scene); + + if (m_combineContiguousRegions) + { RegionLoadedDoWork(scene); + + scene.EventManager.OnNewPresence += NewPresence; + } + } + + public bool IsRootForMegaregion(UUID regionId) + { + lock (m_regions) + return m_regions.ContainsKey(regionId); + } + + public Vector2 GetSizeOfMegaregion(UUID regionId) + { + lock (m_regions) + { + if (m_regions.ContainsKey(regionId)) + { + RegionConnections rootConn = m_regions[regionId]; + + return new Vector2((float)rootConn.XEnd, (float)rootConn.YEnd); + } + } + + throw new Exception(string.Format("Region with id {0} not found", regionId)); + } + + private void NewPresence(ScenePresence presence) + { + if (presence.IsChildAgent) + { + byte[] throttleData; + + try + { + throttleData = presence.ControllingClient.GetThrottlesPacked(1); + } + catch (NotImplementedException) + { + return; + } + + if (throttleData == null) + return; + + if (throttleData.Length == 0) + return; + + if (throttleData.Length != 28) + return; + + byte[] adjData; + int pos = 0; + + if (!BitConverter.IsLittleEndian) + { + byte[] newData = new byte[7 * 4]; + Buffer.BlockCopy(throttleData, 0, newData, 0, 7 * 4); + + for (int i = 0; i < 7; i++) + Array.Reverse(newData, i * 4, 4); + + adjData = newData; + } + else + { + adjData = throttleData; + } + + // 0.125f converts from bits to bytes + int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; + int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; + int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; + int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; + int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; + 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 total = resend + land + wind + cloud + task + texture + asset; + + byte[] data = new byte[7 * 4]; + int ii = 0; + + Buffer.BlockCopy(Utils.FloatToBytes(resend), 0, data, ii, 4); ii += 4; + Buffer.BlockCopy(Utils.FloatToBytes(land * 50), 0, data, ii, 4); ii += 4; + Buffer.BlockCopy(Utils.FloatToBytes(wind), 0, data, ii, 4); ii += 4; + Buffer.BlockCopy(Utils.FloatToBytes(cloud), 0, data, ii, 4); ii += 4; + Buffer.BlockCopy(Utils.FloatToBytes(task), 0, data, ii, 4); ii += 4; + Buffer.BlockCopy(Utils.FloatToBytes(texture), 0, data, ii, 4); ii += 4; + Buffer.BlockCopy(Utils.FloatToBytes(asset), 0, data, ii, 4); + + try + { + presence.ControllingClient.SetChildAgentThrottle(data); + } + catch (NotImplementedException) + { + return; + } + } } private void RegionLoadedDoWork(Scene scene) @@ -100,8 +220,6 @@ namespace OpenSim.Region.RegionCombinerModule return; // */ - lock (m_startingScenes) - m_startingScenes.Add(scene.RegionInfo.originRegionID, scene); // Give each region a standard set of non-infinite borders Border northBorder = new Border(); @@ -124,24 +242,21 @@ namespace OpenSim.Region.RegionCombinerModule westBorder.CrossDirection = Cardinals.W; scene.WestBorders[0] = westBorder; - - - RegionConnections regionConnections = new RegionConnections(); - regionConnections.ConnectedRegions = new List(); - regionConnections.RegionScene = scene; - regionConnections.RegionLandChannel = scene.LandChannel; - regionConnections.RegionId = scene.RegionInfo.originRegionID; - regionConnections.X = scene.RegionInfo.RegionLocX; - regionConnections.Y = scene.RegionInfo.RegionLocY; - regionConnections.XEnd = (int)Constants.RegionSize; - regionConnections.YEnd = (int)Constants.RegionSize; - + RegionConnections newConn = new RegionConnections(); + newConn.ConnectedRegions = new List(); + newConn.RegionScene = scene; + newConn.RegionLandChannel = scene.LandChannel; + newConn.RegionId = scene.RegionInfo.originRegionID; + newConn.X = scene.RegionInfo.RegionLocX; + newConn.Y = scene.RegionInfo.RegionLocY; + newConn.XEnd = (int)Constants.RegionSize; + newConn.YEnd = (int)Constants.RegionSize; lock (m_regions) { bool connectedYN = false; - foreach (RegionConnections conn in m_regions.Values) + foreach (RegionConnections rootConn in m_regions.Values) { #region commented /* @@ -306,13 +421,9 @@ namespace OpenSim.Region.RegionCombinerModule //xxy //xxx - - if ((((int)conn.X * (int)Constants.RegionSize) + conn.XEnd - >= (regionConnections.X * (int)Constants.RegionSize)) - && (((int)conn.Y * (int)Constants.RegionSize) - >= (regionConnections.Y * (int)Constants.RegionSize))) + if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY >= newConn.PosY) { - connectedYN = DoWorkForOneRegionOverPlusXY(conn, regionConnections, scene); + connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene); break; } @@ -320,12 +431,9 @@ namespace OpenSim.Region.RegionCombinerModule //xyx //xxx //xxx - if ((((int)conn.X * (int)Constants.RegionSize) - >= (regionConnections.X * (int)Constants.RegionSize)) - && (((int)conn.Y * (int)Constants.RegionSize) + conn.YEnd - >= (regionConnections.Y * (int)Constants.RegionSize))) + if (rootConn.PosX >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY) { - connectedYN = DoWorkForOneRegionOverXPlusY(conn, regionConnections, scene); + connectedYN = DoWorkForOneRegionOverXPlusY(rootConn, newConn, scene); break; } @@ -333,12 +441,9 @@ namespace OpenSim.Region.RegionCombinerModule //xxy //xxx //xxx - if ((((int)conn.X * (int)Constants.RegionSize) + conn.XEnd - >= (regionConnections.X * (int)Constants.RegionSize)) - && (((int)conn.Y * (int)Constants.RegionSize) + conn.YEnd - >= (regionConnections.Y * (int)Constants.RegionSize))) + if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY) { - connectedYN = DoWorkForOneRegionOverPlusXPlusY(conn, regionConnections, scene); + connectedYN = DoWorkForOneRegionOverPlusXPlusY(rootConn, newConn, scene); break; } @@ -347,66 +452,63 @@ namespace OpenSim.Region.RegionCombinerModule // If !connectYN means that this region is a root region if (!connectedYN) { - DoWorkForRootRegion(regionConnections, scene); - + DoWorkForRootRegion(newConn, scene); } } + // Set up infinite borders around the entire AABB of the combined ConnectedRegions AdjustLargeRegionBounds(); } - private bool DoWorkForOneRegionOverPlusXY(RegionConnections conn, RegionConnections regionConnections, Scene scene) + private bool DoWorkForOneRegionOverPlusXY(RegionConnections rootConn, RegionConnections newConn, Scene scene) { Vector3 offset = Vector3.Zero; - offset.X = (((regionConnections.X * (int)Constants.RegionSize)) - - ((conn.X * (int)Constants.RegionSize))); - offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) - - ((conn.Y * (int)Constants.RegionSize))); + offset.X = newConn.PosX - rootConn.PosX; + offset.Y = newConn.PosY - rootConn.PosY; Vector3 extents = Vector3.Zero; - extents.Y = conn.YEnd; - extents.X = conn.XEnd + regionConnections.XEnd; + extents.Y = rootConn.YEnd; + extents.X = rootConn.XEnd + newConn.XEnd; - conn.UpdateExtents(extents); + rootConn.UpdateExtents(extents); - m_log.DebugFormat("Scene: {0} to the west of Scene{1} Offset: {2}. Extents:{3}", - conn.RegionScene.RegionInfo.RegionName, - regionConnections.RegionScene.RegionInfo.RegionName, offset, extents); + m_log.DebugFormat( + "[REGION COMBINER MODULE]: Root region {0} is to the west of region {1}, Offset: {2}, Extents: {3}", + rootConn.RegionScene.RegionInfo.RegionName, + newConn.RegionScene.RegionInfo.RegionName, offset, extents); scene.BordersLocked = true; - conn.RegionScene.BordersLocked = true; + rootConn.RegionScene.BordersLocked = true; RegionData ConnectedRegion = new RegionData(); ConnectedRegion.Offset = offset; ConnectedRegion.RegionId = scene.RegionInfo.originRegionID; ConnectedRegion.RegionScene = scene; - conn.ConnectedRegions.Add(ConnectedRegion); + rootConn.ConnectedRegions.Add(ConnectedRegion); // Inform root region Physics about the extents of this region - conn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); + rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); // Inform Child region that it needs to forward it's terrain to the root region - scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, Vector3.Zero); + scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero); // Extend the borders as appropriate - lock (conn.RegionScene.EastBorders) - conn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize; + lock (rootConn.RegionScene.EastBorders) + rootConn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize; - lock (conn.RegionScene.NorthBorders) - conn.RegionScene.NorthBorders[0].BorderLine.Y += (int)Constants.RegionSize; + lock (rootConn.RegionScene.NorthBorders) + rootConn.RegionScene.NorthBorders[0].BorderLine.Y += (int)Constants.RegionSize; - lock (conn.RegionScene.SouthBorders) - conn.RegionScene.SouthBorders[0].BorderLine.Y += (int)Constants.RegionSize; + lock (rootConn.RegionScene.SouthBorders) + rootConn.RegionScene.SouthBorders[0].BorderLine.Y += (int)Constants.RegionSize; lock (scene.WestBorders) { - - - scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - conn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West + scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - rootConn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West // Trigger auto teleport to root region - scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; - scene.WestBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY; + scene.WestBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX; + scene.WestBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY; } // Reset Terrain.. since terrain loads before we get here, we need to load @@ -415,56 +517,58 @@ namespace OpenSim.Region.RegionCombinerModule scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised()); // Unlock borders - conn.RegionScene.BordersLocked = false; + rootConn.RegionScene.BordersLocked = false; scene.BordersLocked = false; // Create a client event forwarder and add this region's events to the root region. - if (conn.ClientEventForwarder != null) - conn.ClientEventForwarder.AddSceneToEventForwarding(scene); + if (rootConn.ClientEventForwarder != null) + rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene); return true; } - private bool DoWorkForOneRegionOverXPlusY(RegionConnections conn, RegionConnections regionConnections, Scene scene) + private bool DoWorkForOneRegionOverXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene) { Vector3 offset = Vector3.Zero; - offset.X = (((regionConnections.X * (int)Constants.RegionSize)) - - ((conn.X * (int)Constants.RegionSize))); - offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) - - ((conn.Y * (int)Constants.RegionSize))); + offset.X = newConn.PosX - rootConn.PosX; + offset.Y = newConn.PosY - rootConn.PosY; Vector3 extents = Vector3.Zero; - extents.Y = regionConnections.YEnd + conn.YEnd; - extents.X = conn.XEnd; - conn.UpdateExtents(extents); + extents.Y = newConn.YEnd + rootConn.YEnd; + extents.X = rootConn.XEnd; + rootConn.UpdateExtents(extents); scene.BordersLocked = true; - conn.RegionScene.BordersLocked = true; + rootConn.RegionScene.BordersLocked = true; RegionData ConnectedRegion = new RegionData(); ConnectedRegion.Offset = offset; ConnectedRegion.RegionId = scene.RegionInfo.originRegionID; ConnectedRegion.RegionScene = scene; - conn.ConnectedRegions.Add(ConnectedRegion); + rootConn.ConnectedRegions.Add(ConnectedRegion); - m_log.DebugFormat("Scene: {0} to the northeast of Scene{1} Offset: {2}. Extents:{3}", - conn.RegionScene.RegionInfo.RegionName, - regionConnections.RegionScene.RegionInfo.RegionName, offset, extents); + m_log.DebugFormat( + "[REGION COMBINER MODULE]: Root region {0} is to the south of region {1}, Offset: {2}, Extents: {3}", + rootConn.RegionScene.RegionInfo.RegionName, + newConn.RegionScene.RegionInfo.RegionName, offset, extents); - conn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); - scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, Vector3.Zero); + rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); + scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero); + + lock (rootConn.RegionScene.NorthBorders) + rootConn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize; + + lock (rootConn.RegionScene.EastBorders) + rootConn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize; + + lock (rootConn.RegionScene.WestBorders) + rootConn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize; - lock (conn.RegionScene.NorthBorders) - conn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize; - lock (conn.RegionScene.EastBorders) - conn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize; - lock (conn.RegionScene.WestBorders) - conn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize; lock (scene.SouthBorders) { - scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - conn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south - scene.SouthBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; - scene.SouthBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY; + scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - rootConn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south + scene.SouthBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX; + scene.SouthBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY; } // Reset Terrain.. since terrain normally loads first. @@ -473,83 +577,92 @@ namespace OpenSim.Region.RegionCombinerModule //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); scene.BordersLocked = false; - conn.RegionScene.BordersLocked = false; - if (conn.ClientEventForwarder != null) - conn.ClientEventForwarder.AddSceneToEventForwarding(scene); + rootConn.RegionScene.BordersLocked = false; + + if (rootConn.ClientEventForwarder != null) + rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene); + return true; } - private bool DoWorkForOneRegionOverPlusXPlusY(RegionConnections conn, RegionConnections regionConnections, Scene scene) + private bool DoWorkForOneRegionOverPlusXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene) { Vector3 offset = Vector3.Zero; - offset.X = (((regionConnections.X * (int)Constants.RegionSize)) - - ((conn.X * (int)Constants.RegionSize))); - offset.Y = (((regionConnections.Y * (int)Constants.RegionSize)) - - ((conn.Y * (int)Constants.RegionSize))); + offset.X = newConn.PosX - rootConn.PosX; + offset.Y = newConn.PosY - rootConn.PosY; Vector3 extents = Vector3.Zero; - extents.Y = regionConnections.YEnd + conn.YEnd; - extents.X = regionConnections.XEnd + conn.XEnd; - conn.UpdateExtents(extents); + + // We do not want to inflate the extents for regions strictly to the NE of the root region, since this + // would double count regions strictly to the north and east that have already been added. +// extents.Y = regionConnections.YEnd + conn.YEnd; +// extents.X = regionConnections.XEnd + conn.XEnd; +// conn.UpdateExtents(extents); + + extents.Y = rootConn.YEnd; + extents.X = rootConn.XEnd; scene.BordersLocked = true; - conn.RegionScene.BordersLocked = true; + rootConn.RegionScene.BordersLocked = true; RegionData ConnectedRegion = new RegionData(); ConnectedRegion.Offset = offset; ConnectedRegion.RegionId = scene.RegionInfo.originRegionID; ConnectedRegion.RegionScene = scene; - conn.ConnectedRegions.Add(ConnectedRegion); + rootConn.ConnectedRegions.Add(ConnectedRegion); - m_log.DebugFormat("Scene: {0} to the NorthEast of Scene{1} Offset: {2}. Extents:{3}", - conn.RegionScene.RegionInfo.RegionName, - regionConnections.RegionScene.RegionInfo.RegionName, offset, extents); + m_log.DebugFormat( + "[REGION COMBINER MODULE]: Region {0} is to the southwest of Scene {1}, Offset: {2}, Extents: {3}", + rootConn.RegionScene.RegionInfo.RegionName, + newConn.RegionScene.RegionInfo.RegionName, offset, extents); - conn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); - scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset, Vector3.Zero); - lock (conn.RegionScene.NorthBorders) + rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); + scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero); + + lock (rootConn.RegionScene.NorthBorders) { - if (conn.RegionScene.NorthBorders.Count == 1)// && 2) + if (rootConn.RegionScene.NorthBorders.Count == 1)// && 2) { //compound border // already locked above - conn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize; + rootConn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize; - lock (conn.RegionScene.EastBorders) - conn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize; - lock (conn.RegionScene.WestBorders) - conn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize; + lock (rootConn.RegionScene.EastBorders) + rootConn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize; + + lock (rootConn.RegionScene.WestBorders) + rootConn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize; } } lock (scene.SouthBorders) { - scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - conn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south - scene.SouthBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; - scene.SouthBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY; + scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - rootConn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south + scene.SouthBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX; + scene.SouthBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY; } - lock (conn.RegionScene.EastBorders) + lock (rootConn.RegionScene.EastBorders) { - if (conn.RegionScene.EastBorders.Count == 1)// && conn.RegionScene.EastBorders.Count == 2) + if (rootConn.RegionScene.EastBorders.Count == 1)// && conn.RegionScene.EastBorders.Count == 2) { - conn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize; - lock (conn.RegionScene.NorthBorders) - conn.RegionScene.NorthBorders[0].BorderLine.Y += (int)Constants.RegionSize; - lock (conn.RegionScene.SouthBorders) - conn.RegionScene.SouthBorders[0].BorderLine.Y += (int)Constants.RegionSize; + rootConn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize; + lock (rootConn.RegionScene.NorthBorders) + rootConn.RegionScene.NorthBorders[0].BorderLine.Y += (int)Constants.RegionSize; + lock (rootConn.RegionScene.SouthBorders) + rootConn.RegionScene.SouthBorders[0].BorderLine.Y += (int)Constants.RegionSize; } } lock (scene.WestBorders) { - scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - conn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West - scene.WestBorders[0].TriggerRegionX = conn.RegionScene.RegionInfo.RegionLocX; - scene.WestBorders[0].TriggerRegionY = conn.RegionScene.RegionInfo.RegionLocY; + scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - rootConn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West + scene.WestBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX; + scene.WestBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY; } /* @@ -568,46 +681,50 @@ namespace OpenSim.Region.RegionCombinerModule scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised()); //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); scene.BordersLocked = false; - conn.RegionScene.BordersLocked = false; + rootConn.RegionScene.BordersLocked = false; - if (conn.ClientEventForwarder != null) - conn.ClientEventForwarder.AddSceneToEventForwarding(scene); + if (rootConn.ClientEventForwarder != null) + rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene); return true; //scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset,extents); - } - private void DoWorkForRootRegion(RegionConnections regionConnections, Scene scene) + private void DoWorkForRootRegion(RegionConnections rootConn, Scene scene) { + m_log.DebugFormat("[REGION COMBINER MODULE]: Adding root region {0}", scene.RegionInfo.RegionName); + RegionData rdata = new RegionData(); rdata.Offset = Vector3.Zero; rdata.RegionId = scene.RegionInfo.originRegionID; rdata.RegionScene = scene; // save it's land channel - regionConnections.RegionLandChannel = scene.LandChannel; + rootConn.RegionLandChannel = scene.LandChannel; // Substitue our landchannel RegionCombinerLargeLandChannel lnd = new RegionCombinerLargeLandChannel(rdata, scene.LandChannel, - regionConnections.ConnectedRegions); + rootConn.ConnectedRegions); + scene.LandChannel = lnd; + // Forward the permissions modules of each of the connected regions to the root region lock (m_regions) { - foreach (RegionData r in regionConnections.ConnectedRegions) + foreach (RegionData r in rootConn.ConnectedRegions) { - ForwardPermissionRequests(regionConnections, r.RegionScene); + ForwardPermissionRequests(rootConn, r.RegionScene); } + + // Create the root region's Client Event Forwarder + rootConn.ClientEventForwarder = new RegionCombinerClientEventForwarder(rootConn); + + // Sets up the CoarseLocationUpdate forwarder for this root region + scene.EventManager.OnNewPresence += SetCourseLocationDelegate; + + // Adds this root region to a dictionary of regions that are connectable + m_regions.Add(scene.RegionInfo.originRegionID, rootConn); } - // Create the root region's Client Event Forwarder - regionConnections.ClientEventForwarder = new RegionCombinerClientEventForwarder(regionConnections); - - // Sets up the CoarseLocationUpdate forwarder for this root region - scene.EventManager.OnNewPresence += SetCourseLocationDelegate; - - // Adds this root region to a dictionary of regions that are connectable - m_regions.Add(scene.RegionInfo.originRegionID, regionConnections); } private void SetCourseLocationDelegate(ScenePresence presence) @@ -864,6 +981,7 @@ namespace OpenSim.Region.RegionCombinerModule return true; } } + oborder = null; return false; } @@ -873,14 +991,19 @@ namespace OpenSim.Region.RegionCombinerModule pPosition = pPosition/(int) Constants.RegionSize; int OffsetX = (int) pPosition.X; int OffsetY = (int) pPosition.Y; - foreach (RegionConnections regConn in m_regions.Values) + + lock (m_regions) { - foreach (RegionData reg in regConn.ConnectedRegions) + foreach (RegionConnections regConn in m_regions.Values) { - if (reg.Offset.X == OffsetX && reg.Offset.Y == OffsetY) - return reg; + foreach (RegionData reg in regConn.ConnectedRegions) + { + if (reg.Offset.X == OffsetX && reg.Offset.Y == OffsetY) + return reg; + } } } + return new RegionData(); } @@ -936,18 +1059,19 @@ namespace OpenSim.Region.RegionCombinerModule } #region console commands + public void FixPhantoms(string module, string[] cmdparams) { - List scenes = new List(m_startingScenes.Values); + List scenes = new List(m_startingScenes.Values); + foreach (Scene s in scenes) { - s.ForEachSOG(delegate(SceneObjectGroup e) - { - e.AbsolutePosition = e.AbsolutePosition; - } - ); + MainConsole.Instance.OutputFormat("Fixing phantoms for {0}", s.RegionInfo.RegionName); + + s.ForEachSOG(so => so.AbsolutePosition = so.AbsolutePosition); } } + #endregion } } diff --git a/OpenSim/Region/RegionCombinerModule/RegionConnections.cs b/OpenSim/Region/RegionCombinerModule/RegionConnections.cs index 3aa9f20f1a..fba51d2efa 100644 --- a/OpenSim/Region/RegionCombinerModule/RegionConnections.cs +++ b/OpenSim/Region/RegionCombinerModule/RegionConnections.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using OpenMetaverse; +using OpenSim.Framework; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; @@ -49,17 +50,45 @@ namespace OpenSim.Region.RegionCombinerModule /// LargeLandChannel for combined region /// public ILandChannel RegionLandChannel; + + /// + /// The x map co-ordinate for this region (where each co-ordinate is a Constants.RegionSize block). + /// public uint X; + + /// + /// The y co-ordinate for this region (where each cor-odinate is a Constants.RegionSize block). + /// public uint Y; - public int XEnd; - public int YEnd; + + /// + /// The X meters position of this connection. + /// + public uint PosX { get { return X * Constants.RegionSize; } } + + /// + /// The Y meters co-ordinate of this connection. + /// + public uint PosY { get { return Y * Constants.RegionSize; } } + + /// + /// The size of the megaregion in meters. + /// + public uint XEnd; + + /// + /// The size of the megaregion in meters. + /// + public uint YEnd; + public List ConnectedRegions; public RegionCombinerPermissionModule PermissionModule; public RegionCombinerClientEventForwarder ClientEventForwarder; + public void UpdateExtents(Vector3 extents) { - XEnd = (int)extents.X; - YEnd = (int)extents.Y; + XEnd = (uint)extents.X; + YEnd = (uint)extents.Y; } } } \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs index bb5baccfd4..2027ca6491 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptApi.cs @@ -27,17 +27,22 @@ using System; using OpenMetaverse; +using OpenSim.Framework; using OpenSim.Region.Framework.Scenes; - namespace OpenSim.Region.ScriptEngine.Interfaces { public interface IScriptApi { - // - // Each API has an identifier, which is used to load the - // proper runtime assembly at load time. - // - void Initialize(IScriptEngine engine, SceneObjectPart part, uint localID, UUID item); + /// + /// Initialize the API + /// + /// + /// Each API has an identifier, which is used to load the + /// proper runtime assembly at load time. + /// /param> + /// + /// + void Initialize(IScriptEngine engine, SceneObjectPart part, TaskInventoryItem item); } -} +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index b04f6b6624..ec13b6cc01 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs @@ -63,6 +63,16 @@ namespace OpenSim.Region.ScriptEngine.Interfaces /// bool Running { get; set; } + /// + /// Gets or sets a value indicating whether this + /// is run. + /// For viewer script editor control + /// + /// + /// true if run; otherwise, false. + /// + bool Run { get; set; } + /// /// Is the script suspended? /// diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/ApiManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/ApiManager.cs index 47ed6ba42a..684138f79c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/ApiManager.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/ApiManager.cs @@ -29,42 +29,43 @@ using System; using System.Collections; using System.Collections.Generic; using System.Reflection; +using log4net; using OpenSim.Region.ScriptEngine.Interfaces; namespace OpenSim.Region.ScriptEngine.Shared.Api { public class ApiManager { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private Dictionary m_Apis = new Dictionary(); public string[] GetApis() { - if (m_Apis.Count > 0) + if (m_Apis.Count <= 0) { - List l = new List(m_Apis.Keys); - return l.ToArray(); - } + Assembly a = Assembly.GetExecutingAssembly(); - Assembly a = Assembly.GetExecutingAssembly(); + Type[] types = a.GetExportedTypes(); - Type[] types = a.GetExportedTypes(); - - foreach (Type t in types) - { - string name = t.ToString(); - int idx = name.LastIndexOf('.'); - if (idx != -1) - name = name.Substring(idx+1); - - if (name.EndsWith("_Api")) + foreach (Type t in types) { - name = name.Substring(0, name.Length - 4); - m_Apis[name] = t; + string name = t.ToString(); + int idx = name.LastIndexOf('.'); + if (idx != -1) + name = name.Substring(idx+1); + + if (name.EndsWith("_Api")) + { + name = name.Substring(0, name.Length - 4); + m_Apis[name] = t; + } } } - List ret = new List(m_Apis.Keys); - return ret.ToArray(); +// m_log.DebugFormat("[API MANAGER]: Found {0} apis", m_Apis.Keys.Count); + + return new List(m_Apis.Keys).ToArray(); } public IScriptApi CreateApi(string api) @@ -76,4 +77,4 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return ret; } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs index 3cbdde5897..693992afe4 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs @@ -233,17 +233,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_Timer[engine].UnSetTimerEvents(localID, itemID); // Remove from: HttpRequest - IHttpRequestModule iHttpReq = - engine.World.RequestModuleInterface(); - iHttpReq.StopHttpRequest(localID, itemID); + IHttpRequestModule iHttpReq = engine.World.RequestModuleInterface(); + if (iHttpReq != null) + iHttpReq.StopHttpRequest(localID, itemID); IWorldComm comms = engine.World.RequestModuleInterface(); if (comms != null) comms.DeleteListener(itemID); IXMLRPC xmlrpc = engine.World.RequestModuleInterface(); - xmlrpc.DeleteChannels(itemID); - xmlrpc.CancelSRDRequests(itemID); + if (xmlrpc != null) + { + xmlrpc.DeleteChannels(itemID); + xmlrpc.CancelSRDRequests(itemID); + } // Remove Sensors m_SensorRepeat[engine].UnSetSenseRepeaterEvents(localID, itemID); @@ -325,7 +328,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { List data = new List(); - Object[] listeners=m_Listener[engine].GetSerializationData(itemID); + Object[] listeners = m_Listener[engine].GetSerializationData(itemID); if (listeners.Length > 0) { data.Add("listener"); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs index 489c1c6e21..b5fa6de298 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/CM_Api.cs @@ -59,16 +59,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { internal IScriptEngine m_ScriptEngine; internal SceneObjectPart m_host; - internal uint m_localID; - internal UUID m_itemID; + internal TaskInventoryItem m_item; internal bool m_CMFunctionsEnabled = false; - public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID) + public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) { m_ScriptEngine = ScriptEngine; m_host = host; - m_localID = localID; - m_itemID = itemID; + m_item = item; if (m_ScriptEngine.Config.GetBoolean("AllowCareminsterFunctions", false)) m_CMFunctionsEnabled = true; @@ -95,7 +93,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public string cmDetectedCountry(int number) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, number); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number); if (detectedParams == null) return String.Empty; return detectedParams.Country; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 595dd8a3bf..6ec3081e05 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -88,8 +88,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected IScriptEngine m_ScriptEngine; protected SceneObjectPart m_host; - protected uint m_localID; - protected UUID m_itemID; + + /// + /// The item that hosts this script + /// + protected TaskInventoryItem m_item; + protected bool throwErrorOnNotImplemented = true; protected AsyncCommandManager AsyncCommands = null; protected float m_ScriptDelayFactor = 1.0f; @@ -107,6 +111,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected IUrlModule m_UrlModule = null; protected Dictionary m_userInfoCache = new Dictionary(); + protected int EMAIL_PAUSE_TIME = 20; // documented delay value for smtp. // protected Timer m_ShoutSayTimer; protected int m_SayShoutCount = 0; @@ -134,7 +139,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api {"TURNRIGHT", "Turning Right"} }; - public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID) + public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) { /* m_ShoutSayTimer = new Timer(1000); @@ -146,10 +151,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_ScriptEngine = ScriptEngine; m_host = host; - m_localID = localID; - m_itemID = itemID; + m_item = item; m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false); + LoadLimits(); // read script limits from config. + + m_TransferModule = + m_ScriptEngine.World.RequestModuleInterface(); + m_UrlModule = m_ScriptEngine.World.RequestModuleInterface(); + + AsyncCommands = new AsyncCommandManager(ScriptEngine); + } + + /* load configuration items that affect script, object and run-time behavior. */ + private void LoadLimits() + { m_ScriptDelayFactor = m_ScriptEngine.Config.GetFloat("ScriptDelayFactor", 1.0f); m_ScriptDistanceFactor = @@ -162,12 +178,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_ScriptEngine.Config.GetInt("NotecardLineReadCharsMax", 255); if (m_notecardLineReadCharsMax > 65535) m_notecardLineReadCharsMax = 65535; - - m_TransferModule = - m_ScriptEngine.World.RequestModuleInterface(); - m_UrlModule = m_ScriptEngine.World.RequestModuleInterface(); - - AsyncCommands = new AsyncCommandManager(ScriptEngine); + // load limits for particular subsystems. + IConfig SMTPConfig; + if ((SMTPConfig = m_ScriptEngine.ConfigSource.Configs["SMTP"]) != null) { + // there's an smtp config, so load in the snooze time. + EMAIL_PAUSE_TIME = SMTPConfig.GetInt("email_pause_time", EMAIL_PAUSE_TIME); + } } public override Object InitializeLifetimeService() @@ -199,7 +215,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api [DebuggerNonUserCode] public void state(string newState) { - m_ScriptEngine.SetState(m_itemID, newState); + m_ScriptEngine.SetState(m_item.ItemID, newState); } /// @@ -210,7 +226,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llResetScript() { m_host.AddScriptLPS(1); - m_ScriptEngine.ApiResetScript(m_itemID); + m_ScriptEngine.ApiResetScript(m_item.ItemID); } public void llResetOtherScript(string name) @@ -219,7 +235,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); - if ((item = ScriptByName(name)) != UUID.Zero) + if ((item = GetScriptByName(name)) != UUID.Zero) m_ScriptEngine.ResetScript(item); else ShoutError("llResetOtherScript: script "+name+" not found"); @@ -231,7 +247,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); - if ((item = ScriptByName(name)) != UUID.Zero) + if ((item = GetScriptByName(name)) != UUID.Zero) { return m_ScriptEngine.GetScriptState(item) ?1:0; } @@ -253,7 +269,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // These functions are supposed to be robust, // so get the state one step at a time. - if ((item = ScriptByName(name)) != UUID.Zero) + if ((item = GetScriptByName(name)) != UUID.Zero) { m_ScriptEngine.SetScriptState(item, run == 0 ? false : true); } @@ -362,77 +378,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - protected UUID InventorySelf() - { - UUID invItemID = new UUID(); - bool unlock = false; - if (!m_host.TaskInventory.IsReadLockedByMe()) - { - m_host.TaskInventory.LockItemsForRead(true); - unlock = true; - } - foreach (KeyValuePair inv in m_host.TaskInventory) - { - if (inv.Value.Type == 10 && inv.Value.ItemID == m_itemID) - { - invItemID = inv.Key; - break; - } - } - if (unlock) - { - m_host.TaskInventory.LockItemsForRead(false); - } - return invItemID; - } - protected UUID InventoryKey(string name, int type) { - m_host.AddScriptLPS(1); - m_host.TaskInventory.LockItemsForRead(true); - - foreach (KeyValuePair inv in m_host.TaskInventory) - { - if (inv.Value.Name == name) - { - m_host.TaskInventory.LockItemsForRead(false); - - if (inv.Value.Type != type) - { - return UUID.Zero; - } + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name); - return inv.Value.AssetID; - } - } - - m_host.TaskInventory.LockItemsForRead(false); - return UUID.Zero; + if (item != null && item.Type == type) + return item.AssetID; + else + return UUID.Zero; } - protected UUID InventoryKey(string name) - { - m_host.AddScriptLPS(1); - - - m_host.TaskInventory.LockItemsForRead(true); - - foreach (KeyValuePair inv in m_host.TaskInventory) - { - if (inv.Value.Name == name) - { - m_host.TaskInventory.LockItemsForRead(false); - return inv.Value.AssetID; - } - } - - m_host.TaskInventory.LockItemsForRead(false); - - - return UUID.Zero; - } - - /// /// accepts a valid UUID, -or- a name of an inventory item. /// Returns a valid UUID or UUID.Zero if key invalid and item not found @@ -442,19 +397,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// protected UUID KeyOrName(string k) { - UUID key = UUID.Zero; + UUID key; // if we can parse the string as a key, use it. - if (UUID.TryParse(k, out key)) - { - return key; - } // else try to locate the name in inventory of object. found returns key, - // not found returns UUID.Zero which will translate to the default particle texture - else + // not found returns UUID.Zero + if (!UUID.TryParse(k, out key)) { - return InventoryKey(k); + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(k); + + if (item != null) + key = item.AssetID; + else + key = UUID.Zero; } + + return key; } // convert a LSL_Rotation to a Quaternion @@ -559,15 +517,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return LSL_Vector.Norm(v); } - public LSL_Float llVecDist(LSL_Vector a, LSL_Vector b) + private double VecDist(LSL_Vector a, LSL_Vector b) { - m_host.AddScriptLPS(1); double dx = a.x - b.x; double dy = a.y - b.y; double dz = a.z - b.z; return Math.Sqrt(dx * dx + dy * dy + dz * dz); } + public LSL_Float llVecDist(LSL_Vector a, LSL_Vector b) + { + m_host.AddScriptLPS(1); + return VecDist(a, b); + } + //Now we start getting into quaternions which means sin/cos, matrices and vectors. ckrinke // Utility function for llRot2Euler @@ -1010,7 +973,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID.TryParse(ID, out keyID); IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface(); if (wComm != null) - return wComm.Listen(m_localID, m_itemID, m_host.UUID, channelID, name, keyID, msg); + return wComm.Listen(m_host.LocalId, m_item.ItemID, m_host.UUID, channelID, name, keyID, msg); else return -1; } @@ -1020,7 +983,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface(); if (wComm != null) - wComm.ListenControl(m_itemID, number, active); + wComm.ListenControl(m_item.ItemID, number, active); } public void llListenRemove(int number) @@ -1028,7 +991,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface(); if (wComm != null) - wComm.ListenRemove(m_itemID, number); + wComm.ListenRemove(m_item.ItemID, number); } public void llSensor(string name, string id, int type, double range, double arc) @@ -1037,7 +1000,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID keyID = UUID.Zero; UUID.TryParse(id, out keyID); - AsyncCommands.SensorRepeatPlugin.SenseOnce(m_localID, m_itemID, name, keyID, type, range, arc, m_host); + AsyncCommands.SensorRepeatPlugin.SenseOnce(m_host.LocalId, m_item.ItemID, name, keyID, type, range, arc, m_host); } public void llSensorRepeat(string name, string id, int type, double range, double arc, double rate) @@ -1046,13 +1009,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID keyID = UUID.Zero; UUID.TryParse(id, out keyID); - AsyncCommands.SensorRepeatPlugin.SetSenseRepeatEvent(m_localID, m_itemID, name, keyID, type, range, arc, rate, m_host); + AsyncCommands.SensorRepeatPlugin.SetSenseRepeatEvent(m_host.LocalId, m_item.ItemID, name, keyID, type, range, arc, rate, m_host); } public void llSensorRemove() { m_host.AddScriptLPS(1); - AsyncCommands.SensorRepeatPlugin.UnSetSenseRepeaterEvents(m_localID, m_itemID); + AsyncCommands.SensorRepeatPlugin.UnSetSenseRepeaterEvents(m_host.LocalId, m_item.ItemID); } public string resolveName(UUID objecUUID) @@ -1093,7 +1056,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String llDetectedName(int number) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, number); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number); if (detectedParams == null) return String.Empty; return detectedParams.Name; @@ -1102,7 +1065,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String llDetectedKey(int number) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, number); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number); if (detectedParams == null) return String.Empty; return detectedParams.Key.ToString(); @@ -1111,7 +1074,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String llDetectedOwner(int number) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, number); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number); if (detectedParams == null) return String.Empty; return detectedParams.Owner.ToString(); @@ -1120,7 +1083,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer llDetectedType(int number) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, number); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number); if (detectedParams == null) return 0; return new LSL_Integer(detectedParams.Type); @@ -1129,7 +1092,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llDetectedPos(int number) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, number); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number); if (detectedParams == null) return new LSL_Vector(); return detectedParams.Position; @@ -1138,7 +1101,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llDetectedVel(int number) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, number); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number); if (detectedParams == null) return new LSL_Vector(); return detectedParams.Velocity; @@ -1147,7 +1110,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llDetectedGrab(int number) { m_host.AddScriptLPS(1); - DetectParams parms = m_ScriptEngine.GetDetectParams(m_itemID, number); + DetectParams parms = m_ScriptEngine.GetDetectParams(m_item.ItemID, number); if (parms == null) return new LSL_Vector(0, 0, 0); @@ -1157,7 +1120,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Rotation llDetectedRot(int number) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, number); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number); if (detectedParams == null) return new LSL_Rotation(); return detectedParams.Rotation; @@ -1166,7 +1129,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer llDetectedGroup(int number) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, number); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, number); if (detectedParams == null) return new LSL_Integer(0); if (m_host.GroupID == detectedParams.Group) @@ -1177,7 +1140,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer llDetectedLinkNumber(int number) { m_host.AddScriptLPS(1); - DetectParams parms = m_ScriptEngine.GetDetectParams(m_itemID, number); + DetectParams parms = m_ScriptEngine.GetDetectParams(m_item.ItemID, number); if (parms == null) return new LSL_Integer(0); @@ -1190,7 +1153,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llDetectedTouchBinormal(int index) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, index); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index); if (detectedParams == null) return new LSL_Vector(); return detectedParams.TouchBinormal; @@ -1202,7 +1165,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer llDetectedTouchFace(int index) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, index); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index); if (detectedParams == null) return new LSL_Integer(-1); return new LSL_Integer(detectedParams.TouchFace); @@ -1214,7 +1177,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llDetectedTouchNormal(int index) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, index); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index); if (detectedParams == null) return new LSL_Vector(); return detectedParams.TouchNormal; @@ -1226,7 +1189,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llDetectedTouchPos(int index) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, index); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index); if (detectedParams == null) return new LSL_Vector(); return detectedParams.TouchPos; @@ -1238,7 +1201,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llDetectedTouchST(int index) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, index); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index); if (detectedParams == null) return new LSL_Vector(-1.0, -1.0, 0.0); return detectedParams.TouchST; @@ -1250,7 +1213,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llDetectedTouchUV(int index) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, index); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, index); if (detectedParams == null) return new LSL_Vector(-1.0, -1.0, 0.0); return detectedParams.TouchUV; @@ -1433,6 +1396,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + private bool IsPhysical() + { + return ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) == (uint)PrimFlags.Physics); + } + public LSL_Integer llGetStatus(int status) { m_host.AddScriptLPS(1); @@ -1440,11 +1408,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api switch (status) { case ScriptBaseClass.STATUS_PHYSICS: - if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Physics) == (uint)PrimFlags.Physics) - { - return 1; - } - return 0; + return IsPhysical() ? 1 : 0; case ScriptBaseClass.STATUS_PHANTOM: if ((m_host.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) == (uint)PrimFlags.Phantom) @@ -1962,6 +1926,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api rgb.x = texcolor.R; rgb.y = texcolor.G; rgb.z = texcolor.B; + return rgb; } else @@ -2196,11 +2161,68 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - SetPos(m_host, pos); + SetPos(m_host, pos, true); ScriptSleep(200); } + /// + /// Tries to move the entire object so that the root prim is within 0.1m of position. http://wiki.secondlife.com/wiki/LlSetRegionPos + /// Documentation indicates that the use of x/y coordinates up to 10 meters outside the bounds of a region will work but do not specify what happens if there is no adjacent region for the object to move into. + /// Uses the RegionSize constant here rather than hard-coding 266.0 to alert any developer modifying OpenSim to support variable-sized regions that this method will need tweaking. + /// + /// + /// 1 if successful, 0 otherwise. + public LSL_Integer llSetRegionPos(LSL_Vector pos) + { + m_host.AddScriptLPS(1); + + // BEGIN WORKAROUND + // IF YOU GET REGION CROSSINGS WORKING WITH THIS FUNCTION, REPLACE THE WORKAROUND. + // + // This workaround is to prevent silent failure of this function. + // According to the specification on the SL Wiki, providing a position outside of the + if (pos.x < 0 || pos.x > Constants.RegionSize || pos.y < 0 || pos.y > Constants.RegionSize) + { + return 0; + } + // END WORK AROUND + else if ( // this is not part of the workaround if-block because it's not related to the workaround. + IsPhysical() || + m_host.ParentGroup.IsAttachment || // return FALSE if attachment + ( + pos.x < -10.0 || // return FALSE if more than 10 meters into a west-adjacent region. + pos.x > (Constants.RegionSize + 10) || // return FALSE if more than 10 meters into a east-adjacent region. + pos.y < -10.0 || // return FALSE if more than 10 meters into a south-adjacent region. + pos.y > (Constants.RegionSize + 10) || // return FALSE if more than 10 meters into a north-adjacent region. + pos.z > 4096 // return FALSE if altitude than 4096m + ) + ) + { + return 0; + } + + // if we reach this point, then the object is not physical, it's not an attachment, and the destination is within the valid range. + // this could possibly be done in the above else-if block, but we're doing the check here to keep the code easier to read. + + Vector3 objectPos = m_host.ParentGroup.RootPart.AbsolutePosition; + LandData here = World.GetLandData((float)objectPos.X, (float)objectPos.Y); + LandData there = World.GetLandData((float)pos.x, (float)pos.y); + + // we're only checking prim limits if it's moving to a different parcel under the assumption that if the object got onto the parcel without exceeding the prim limits. + + bool sameParcel = here.GlobalID == there.GlobalID; + + if (!sameParcel && !World.Permissions.CanObjectEntry(m_host.UUID, false, new Vector3((float)pos.x, (float)pos.y, (float)pos.z))) + { + return 0; + } + + SetPos(m_host.ParentGroup.RootPart, pos, false); + + return VecDist(pos, llGetRootPosition()) <= 0.1 ? 1 : 0; + } + // Capped movemment if distance > 10m (http://wiki.secondlife.com/wiki/LlSetPos) // note linked setpos is capped "differently" private LSL_Vector SetPosAdjust(LSL_Vector start, LSL_Vector end) @@ -2232,55 +2254,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return real_vec; } - public LSL_Integer llSetRegionPos(LSL_Vector pos) - { - return new LSL_Integer(SetRegionPos(m_host, pos)); - } - - protected int SetRegionPos(SceneObjectPart part, LSL_Vector targetPos) - { - if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) - return 0; - - SceneObjectGroup grp = part.ParentGroup; - - if (grp.IsAttachment) - return 0; - - if (grp.RootPart.PhysActor != null && grp.RootPart.PhysActor.IsPhysical) - return 0; - - if (targetPos.x < -10.0f || targetPos.x >= (float)Constants.RegionSize || targetPos.y < -10.0f || targetPos.y >= (float)Constants.RegionSize || targetPos.z < 0 || targetPos.z >= 4096.0f) - return 0; - - float constrainedX = (float)targetPos.x; - float constrainedY = (float)targetPos.y; - - if (constrainedX < 0.0f) - constrainedX = 0.0f; - if (constrainedY < 0.0f) - constrainedY = 0.0f; - if (constrainedX >= (float)Constants.RegionSize) - constrainedX = (float)Constants.RegionSize - 0.1f; - if (constrainedY >= (float)Constants.RegionSize) - constrainedY = (float)Constants.RegionSize -0.1f; - - float ground = World.GetGroundHeight(constrainedX, constrainedY); - - if (targetPos.z < ground) - targetPos.z = ground; - - Vector3 dest = new Vector3((float)targetPos.x, (float)targetPos.y, (float)targetPos.z); - - if (!World.Permissions.CanObjectEntry(grp.UUID, false, dest)) - return 0; - - grp.UpdateGroupPosition(dest); - - return 1; - } - - protected void SetPos(SceneObjectPart part, LSL_Vector targetPos) + /// + /// set object position, optionally capping the distance. + /// + /// + /// + /// if TRUE, will cap the distance to 10m. + protected void SetPos(SceneObjectPart part, LSL_Vector targetPos, bool adjust) { if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) return; @@ -3044,20 +3024,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer llGiveMoney(string destination, int amount) { - UUID invItemID=InventorySelf(); - if (invItemID == UUID.Zero) - return 0; - m_host.AddScriptLPS(1); - m_host.TaskInventory.LockItemsForRead(true); - TaskInventoryItem item = m_host.TaskInventory[invItemID]; - m_host.TaskInventory.LockItemsForRead(false); - - if (item.PermsGranter == UUID.Zero) + if (m_item.PermsGranter == UUID.Zero) return 0; - if ((item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0) + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_DEBIT) == 0) { LSLError("No permissions to give money"); return 0; @@ -3120,74 +3092,72 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - Util.FireAndForget(delegate (object x) + Util.FireAndForget(x => { if (Double.IsNaN(rot.x) || Double.IsNaN(rot.y) || Double.IsNaN(rot.z) || Double.IsNaN(rot.s)) return; + float dist = (float)llVecDist(llGetPos(), pos); if (dist > m_ScriptDistanceFactor * 10.0f) return; - //Clone is thread-safe - TaskInventoryDictionary partInventory = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(inventory); - foreach (KeyValuePair inv in partInventory) + if (item == null) { - if (inv.Value.Name == inventory) - { - // make sure we're an object. - if (inv.Value.InvType != (int)InventoryType.Object) - { - llSay(0, "Unable to create requested object. Object is missing from database."); - return; - } - - Vector3 llpos = new Vector3((float)pos.x, (float)pos.y, (float)pos.z); - Vector3 llvel = new Vector3((float)vel.x, (float)vel.y, (float)vel.z); - - // need the magnitude later - // float velmag = (float)Util.GetMagnitude(llvel); - - SceneObjectGroup new_group = World.RezObject(m_host, inv.Value, llpos, Rot2Quaternion(rot), llvel, param); - - // If either of these are null, then there was an unknown error. - if (new_group == null) - continue; - - // objects rezzed with this method are die_at_edge by default. - new_group.RootPart.SetDieAtEdge(true); - - new_group.ResumeScripts(); - - m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams( - "object_rez", new Object[] { - new LSL_String( - new_group.RootPart.UUID.ToString()) }, - new DetectParams[0])); - - // do recoil - SceneObjectGroup hostgrp = m_host.ParentGroup; - if (hostgrp == null) - return; - - if (hostgrp.IsAttachment) // don't recoil avatars - return; - - PhysicsActor pa = new_group.RootPart.PhysActor; - - if (pa != null && pa.IsPhysical && llvel != Vector3.Zero) - { - float groupmass = new_group.GetMass(); - llvel *= -groupmass; - llApplyImpulse(new LSL_Vector(llvel.X, llvel.Y,llvel.Z), 0); - } - // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) - return; - } + llSay(0, "Could not find object " + inventory); + return; } - llSay(0, "Could not find object " + inventory); + if (item.InvType != (int)InventoryType.Object) + { + llSay(0, "Unable to create requested object. Object is missing from database."); + return; + } + + Vector3 llpos = new Vector3((float)pos.x, (float)pos.y, (float)pos.z); + Vector3 llvel = new Vector3((float)vel.x, (float)vel.y, (float)vel.z); + + // need the magnitude later + // float velmag = (float)Util.GetMagnitude(llvel); + + SceneObjectGroup new_group = World.RezObject(m_host, item, llpos, Rot2Quaternion(rot), llvel, param); + + // If either of these are null, then there was an unknown error. + if (new_group == null) + return; + + // objects rezzed with this method are die_at_edge by default. + new_group.RootPart.SetDieAtEdge(true); + + new_group.ResumeScripts(); + + m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams( + "object_rez", new Object[] { + new LSL_String( + new_group.RootPart.UUID.ToString()) }, + new DetectParams[0])); + + // do recoil + SceneObjectGroup hostgrp = m_host.ParentGroup; + if (hostgrp == null) + return; + + if (hostgrp.IsAttachment) // don't recoil avatars + return; + + PhysicsActor pa = new_group.RootPart.PhysActor; + + if (pa != null && pa.IsPhysical && llvel != Vector3.Zero) + { + float groupmass = new_group.GetMass(); + llvel *= -groupmass; + llApplyImpulse(new LSL_Vector(llvel.X, llvel.Y,llvel.Z), 0); + } + // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) + return; + }); //ScriptSleep((int)((groupmass * velmag) / 10)); @@ -3251,11 +3221,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api sec = m_MinTimerInterval; m_host.AddScriptLPS(1); // Setting timer repeat - AsyncCommands.TimerPlugin.SetTimerEvent(m_localID, m_itemID, sec); + AsyncCommands.TimerPlugin.SetTimerEvent(m_host.LocalId, m_item.ItemID, sec); } public virtual void llSleep(double sec) { +// m_log.Info("llSleep snoozing " + sec + "s."); m_host.AddScriptLPS(1); Thread.Sleep((int)(sec * 1000)); } @@ -3314,29 +3285,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llTakeControls(int controls, int accept, int pass_on) { - TaskInventoryItem item; - - m_host.TaskInventory.LockItemsForRead(true); - if (!m_host.TaskInventory.ContainsKey(InventorySelf())) + if (m_item.PermsGranter != UUID.Zero) { - m_host.TaskInventory.LockItemsForRead(false); - return; - } - else - { - item = m_host.TaskInventory[InventorySelf()]; - } - m_host.TaskInventory.LockItemsForRead(false); - - if (item.PermsGranter != UUID.Zero) - { - ScenePresence presence = World.GetScenePresence(item.PermsGranter); + ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); if (presence != null) { - if ((item.PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0) + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0) { - presence.RegisterControlEventsToScript(controls, accept, pass_on, m_localID, m_itemID); + presence.RegisterControlEventsToScript(controls, accept, pass_on, m_host.LocalId, m_item.ItemID); } } } @@ -3346,38 +3303,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llReleaseControls() { - TaskInventoryItem item; - - m_host.TaskInventory.LockItemsForRead(true); - lock (m_host.TaskInventory) - { - - if (!m_host.TaskInventory.ContainsKey(InventorySelf())) - { - m_host.TaskInventory.LockItemsForRead(false); - return; - } - else - { - item = m_host.TaskInventory[InventorySelf()]; - } - } - m_host.TaskInventory.LockItemsForRead(false); - m_host.AddScriptLPS(1); - if (item.PermsGranter != UUID.Zero) + if (m_item.PermsGranter != UUID.Zero) { - ScenePresence presence = World.GetScenePresence(item.PermsGranter); + ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); if (presence != null) { - if ((item.PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0) + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0) { // Unregister controls from Presence - presence.UnRegisterControlEventsToScript(m_localID, m_itemID); + presence.UnRegisterControlEventsToScript(m_host.LocalId, m_item.ItemID); // Remove Take Control permission. - item.PermsMask &= ~ScriptBaseClass.PERMISSION_TAKE_CONTROLS; + m_item.PermsMask &= ~ScriptBaseClass.PERMISSION_TAKE_CONTROLS; } } } @@ -3390,39 +3329,54 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_UrlModule.ReleaseURL(url); } - public void llAttachToAvatar(int attachment) + /// + /// Attach the object containing this script to the avatar that owns it. + /// + /// The attachment point (e.g. ATTACH_CHEST) + /// true if the attach suceeded, false if it did not + public bool AttachToAvatar(int attachmentPoint) + { + SceneObjectGroup grp = m_host.ParentGroup; + ScenePresence presence = World.GetScenePresence(m_host.OwnerID); + + IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; + + if (attachmentsModule != null) + return attachmentsModule.AttachObject(presence, grp, (uint)attachmentPoint, false, true); + else + return false; + } + + /// + /// Detach the object containing this script from the avatar it is attached to. + /// + /// + /// Nothing happens if the object is not attached. + /// + public void DetachFromAvatar() + { + Util.FireAndForget(DetachWrapper, m_host); + } + + private void DetachWrapper(object o) + { + if (World.AttachmentsModule != null) + { + SceneObjectPart host = (SceneObjectPart)o; + ScenePresence presence = World.GetScenePresence(host.OwnerID); + World.AttachmentsModule.DetachSingleAttachmentToInv(presence, host.ParentGroup); + } + } + + public void llAttachToAvatar(int attachmentPoint) { m_host.AddScriptLPS(1); - TaskInventoryItem item; - - m_host.TaskInventory.LockItemsForRead(true); - - if (!m_host.TaskInventory.ContainsKey(InventorySelf())) - { - m_host.TaskInventory.LockItemsForRead(false); - return; - } - else - { - item = m_host.TaskInventory[InventorySelf()]; - } - - m_host.TaskInventory.LockItemsForRead(false); - - if (item.PermsGranter != m_host.OwnerID) + if (m_item.PermsGranter != m_host.OwnerID) return; - if ((item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) != 0) - { - SceneObjectGroup grp = m_host.ParentGroup; - - ScenePresence presence = World.GetScenePresence(m_host.OwnerID); - - IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; - if (attachmentsModule != null) - attachmentsModule.AttachObject(presence, grp, (uint)attachment, false, true); - } + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) != 0) + AttachToAvatar(attachmentPoint); } public void llDetachFromAvatar() @@ -3432,44 +3386,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (m_host.ParentGroup.AttachmentPoint == 0) return; - TaskInventoryItem item; - - m_host.TaskInventory.LockItemsForRead(true); - - if (!m_host.TaskInventory.ContainsKey(InventorySelf())) - { - m_host.TaskInventory.LockItemsForRead(false); - return; - } - else - { - item = m_host.TaskInventory[InventorySelf()]; - } - m_host.TaskInventory.LockItemsForRead(false); - - - if (item.PermsGranter != m_host.OwnerID) + if (m_item.PermsGranter != m_host.OwnerID) return; - if ((item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) != 0) - { - IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; - if (attachmentsModule != null) - Util.FireAndForget(DetachWrapper, m_host); - } - } - - private void DetachWrapper(object o) - { - SceneObjectPart host = (SceneObjectPart)o; - - SceneObjectGroup grp = host.ParentGroup; - UUID itemID = grp.FromItemID; - ScenePresence presence = World.GetScenePresence(host.OwnerID); - - IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; - if (attachmentsModule != null) - attachmentsModule.DetachSingleAttachmentToInv(presence, itemID); + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_ATTACH) != 0) + DetachFromAvatar(); } public void llTakeCamera(string avatar) @@ -3590,7 +3511,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } emailModule.SendEmail(m_host.UUID, address, subject, message); - ScriptSleep(15000); + ScriptSleep(EMAIL_PAUSE_TIME * 1000); } public void llGetNextEmail(string address, string subject) @@ -3627,6 +3548,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return m_host.UUID.ToString(); } + public LSL_Key llGenerateKey() + { + m_host.AddScriptLPS(1); + return UUID.Random().ToString(); + } + public void llSetBuoyancy(double buoyancy) { m_host.AddScriptLPS(1); @@ -3673,7 +3600,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); try { - m_ScriptEngine.SetMinEventDelay(m_itemID, delay); + m_ScriptEngine.SetMinEventDelay(m_item.ItemID, delay); } catch (NotImplementedException) { @@ -3726,29 +3653,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - UUID invItemID = InventorySelf(); - if (invItemID == UUID.Zero) + if (m_item.PermsGranter == UUID.Zero) return; - TaskInventoryItem item; - - m_host.TaskInventory.LockItemsForRead(true); - if (!m_host.TaskInventory.ContainsKey(InventorySelf())) + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0) { - m_host.TaskInventory.LockItemsForRead(false); - return; - } - else - { - item = m_host.TaskInventory[InventorySelf()]; - } - m_host.TaskInventory.LockItemsForRead(false); - if (item.PermsGranter == UUID.Zero) - return; - - if ((item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0) - { - ScenePresence presence = World.GetScenePresence(item.PermsGranter); + ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); if (presence != null) { @@ -3766,41 +3676,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - UUID invItemID=InventorySelf(); - if (invItemID == UUID.Zero) + if (m_item.PermsGranter == UUID.Zero) return; - TaskInventoryItem item; - - m_host.TaskInventory.LockItemsForRead(true); - if (!m_host.TaskInventory.ContainsKey(InventorySelf())) + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0) { - m_host.TaskInventory.LockItemsForRead(false); - return; - } - else - { - item = m_host.TaskInventory[InventorySelf()]; - } - m_host.TaskInventory.LockItemsForRead(false); - - - if (item.PermsGranter == UUID.Zero) - return; - - if ((item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) != 0) - { - UUID animID = new UUID(); - - if (!UUID.TryParse(anim, out animID)) - { - animID=InventoryKey(anim); - } - - ScenePresence presence = World.GetScenePresence(item.PermsGranter); + ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); if (presence != null) { + UUID animID = KeyOrName(anim); + if (animID == UUID.Zero) presence.Animator.RemoveAnimation(anim); else @@ -3833,44 +3719,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Integer llGetStartParameter() { m_host.AddScriptLPS(1); - return m_ScriptEngine.GetStartParameter(m_itemID); + return m_ScriptEngine.GetStartParameter(m_item.ItemID); } public void llRequestPermissions(string agent, int perm) { - UUID agentID = new UUID(); + UUID agentID; if (!UUID.TryParse(agent, out agentID)) return; - UUID invItemID = InventorySelf(); - - if (invItemID == UUID.Zero) - return; // Not in a prim? How?? - - TaskInventoryItem item; - - - m_host.TaskInventory.LockItemsForRead(true); - if (!m_host.TaskInventory.ContainsKey(invItemID)) - { - m_host.TaskInventory.LockItemsForRead(false); - return; - } - else - { - item = m_host.TaskInventory[invItemID]; - } - m_host.TaskInventory.LockItemsForRead(false); - if (agentID == UUID.Zero || perm == 0) // Releasing permissions { llReleaseControls(); - item.PermsGranter = UUID.Zero; - item.PermsMask = 0; + m_item.PermsGranter = UUID.Zero; + m_item.PermsMask = 0; - m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( + m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams( "run_time_permissions", new Object[] { new LSL_Integer(0) }, new DetectParams[0])); @@ -3878,7 +3744,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } - if (item.PermsGranter != agentID || (perm & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0) + if (m_item.PermsGranter != agentID || (perm & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0) llReleaseControls(); m_host.AddScriptLPS(1); @@ -3895,11 +3761,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms { m_host.TaskInventory.LockItemsForWrite(true); - m_host.TaskInventory[invItemID].PermsGranter = agentID; - m_host.TaskInventory[invItemID].PermsMask = perm; + m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID; + m_host.TaskInventory[m_item.ItemID].PermsMask = perm; m_host.TaskInventory.LockItemsForWrite(false); - m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( + m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams( "run_time_permissions", new Object[] { new LSL_Integer(perm) }, new DetectParams[0])); @@ -3934,11 +3800,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms { m_host.TaskInventory.LockItemsForWrite(true); - m_host.TaskInventory[invItemID].PermsGranter = agentID; - m_host.TaskInventory[invItemID].PermsMask = perm; + m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID; + m_host.TaskInventory[m_item.ItemID].PermsMask = perm; m_host.TaskInventory.LockItemsForWrite(false); - m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( + m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams( "run_time_permissions", new Object[] { new LSL_Integer(perm) }, new DetectParams[0])); @@ -3949,9 +3815,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } ScenePresence presence = World.GetScenePresence(agentID); - if (presence != null) { + // If permissions are being requested from an NPC and were not implicitly granted above then + // auto grant all reuqested permissions if the script is owned by the NPC or the NPCs owner + INPCModule npcModule = World.RequestModuleInterface(); + if (npcModule != null && npcModule.IsNPC(agentID, World)) + { + if (agentID == m_host.ParentGroup.OwnerID || npcModule.GetOwner(agentID) == m_host.ParentGroup.OwnerID) + { + lock (m_host.TaskInventory) + { + m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID; + m_host.TaskInventory[m_item.ItemID].PermsMask = perm; + } + + m_ScriptEngine.PostScriptEvent( + m_item.ItemID, + new EventParams( + "run_time_permissions", new Object[] { new LSL_Integer(perm) }, new DetectParams[0])); + } + + // it is an NPC, exit even if the permissions werent granted above, they are not going to answer + // the question! + return; + } + string ownerName = resolveName(m_host.ParentGroup.RootPart.OwnerID); if (ownerName == String.Empty) ownerName = "(hippos)"; @@ -3959,8 +3848,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (!m_waitingForScriptAnswer) { m_host.TaskInventory.LockItemsForWrite(true); - m_host.TaskInventory[invItemID].PermsGranter = agentID; - m_host.TaskInventory[invItemID].PermsMask = 0; + m_host.TaskInventory[m_item.ItemID].PermsGranter = agentID; + m_host.TaskInventory[m_item.ItemID].PermsMask = 0; m_host.TaskInventory.LockItemsForWrite(false); presence.ControllingClient.OnScriptAnswer += handleScriptAnswer; @@ -3968,16 +3857,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } presence.ControllingClient.SendScriptQuestion( - m_host.UUID, m_host.ParentGroup.RootPart.Name, ownerName, invItemID, perm); + m_host.UUID, m_host.ParentGroup.RootPart.Name, ownerName, m_item.ItemID, perm); return; } // Requested agent is not in range, refuse perms - m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( - "run_time_permissions", new Object[] { - new LSL_Integer(0) }, - new DetectParams[0])); + m_ScriptEngine.PostScriptEvent( + m_item.ItemID, + new EventParams("run_time_permissions", new Object[] { new LSL_Integer(0) }, new DetectParams[0])); } void handleScriptAnswer(IClientAPI client, UUID taskID, UUID itemID, int answer) @@ -3985,24 +3873,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (taskID != m_host.UUID) return; - UUID invItemID = InventorySelf(); - - if (invItemID == UUID.Zero) - return; - - client.OnScriptAnswer-=handleScriptAnswer; - m_waitingForScriptAnswer=false; + client.OnScriptAnswer -= handleScriptAnswer; + m_waitingForScriptAnswer = false; if ((answer & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) == 0) llReleaseControls(); - m_host.TaskInventory.LockItemsForWrite(true); - m_host.TaskInventory[invItemID].PermsMask = answer; + m_host.TaskInventory[m_item.ItemID].PermsMask = answer; m_host.TaskInventory.LockItemsForWrite(false); - - m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( + m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams( "run_time_permissions", new Object[] { new LSL_Integer(answer) }, new DetectParams[0])); @@ -4012,41 +3893,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - m_host.TaskInventory.LockItemsForRead(true); - - foreach (TaskInventoryItem item in m_host.TaskInventory.Values) - { - if (item.Type == 10 && item.ItemID == m_itemID) - { - m_host.TaskInventory.LockItemsForRead(false); - return item.PermsGranter.ToString(); - } - } - m_host.TaskInventory.LockItemsForRead(false); - - return UUID.Zero.ToString(); + return m_item.PermsGranter.ToString(); } public LSL_Integer llGetPermissions() { m_host.AddScriptLPS(1); - m_host.TaskInventory.LockItemsForRead(true); + int perms = m_item.PermsMask; - foreach (TaskInventoryItem item in m_host.TaskInventory.Values) - { - if (item.Type == 10 && item.ItemID == m_itemID) - { - int perms = item.PermsMask; - if (m_automaticLinkPermission) - perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; - m_host.TaskInventory.LockItemsForRead(false); - return perms; - } - } - m_host.TaskInventory.LockItemsForRead(false); + if (m_automaticLinkPermission) + perms |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; - return 0; + return perms; } public LSL_Integer llGetLinkNumber() @@ -4084,18 +3943,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llCreateLink(string target, int parent) { m_host.AddScriptLPS(1); - UUID invItemID = InventorySelf(); + UUID targetID; if (!UUID.TryParse(target, out targetID)) return; - TaskInventoryItem item; - m_host.TaskInventory.LockItemsForRead(true); - item = m_host.TaskInventory[invItemID]; - m_host.TaskInventory.LockItemsForRead(false); - - if ((item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 && !m_automaticLinkPermission) { ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!"); @@ -4103,7 +3957,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } IClientAPI client = null; - ScenePresence sp = World.GetScenePresence(item.PermsGranter); + ScenePresence sp = World.GetScenePresence(m_item.PermsGranter); if (sp != null) client = sp.ControllingClient; @@ -4149,18 +4003,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llBreakLink(int linknum) { m_host.AddScriptLPS(1); - UUID invItemID = InventorySelf(); - m_host.TaskInventory.LockItemsForRead(true); - if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 - && !m_automaticLinkPermission) - { - ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!"); - m_host.TaskInventory.LockItemsForRead(false); - return; - } - m_host.TaskInventory.LockItemsForRead(false); - + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 + && !m_automaticLinkPermission) + { + ShoutError("Script trying to link but PERMISSION_CHANGE_LINKS permission not set!"); + return; + } + if (linknum < ScriptBaseClass.LINK_THIS) return; @@ -4259,12 +4109,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - UUID invItemID = InventorySelf(); - - TaskInventoryItem item; - m_host.TaskInventory.LockItemsForRead(true); - item = m_host.TaskInventory[invItemID]; - m_host.TaskInventory.LockItemsForRead(false); + TaskInventoryItem item = m_item; if ((item.PermsMask & ScriptBaseClass.PERMISSION_CHANGE_LINKS) == 0 && !m_automaticLinkPermission) @@ -4461,11 +4306,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llGiveInventory(string destination, string inventory) { m_host.AddScriptLPS(1); - bool found = false; + UUID destId = UUID.Zero; - UUID objId = UUID.Zero; - int assetType = 0; - string objName = String.Empty; if (!UUID.TryParse(destination, out destId)) { @@ -4473,28 +4315,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } - // move the first object found with this inventory name - m_host.TaskInventory.LockItemsForRead(true); - foreach (KeyValuePair inv in m_host.TaskInventory) - { - if (inv.Value.Name == inventory) - { - found = true; - objId = inv.Key; - assetType = inv.Value.Type; - objName = inv.Value.Name; - break; - } - } - m_host.TaskInventory.LockItemsForRead(false); + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(inventory); - if (!found) + if (item == null) { llSay(0, String.Format("Could not find object '{0}'", inventory)); return; // throw new Exception(String.Format("The inventory object '{0}' could not be found", inventory)); } + UUID objId = item.ItemID; + // check if destination is an object if (World.GetSceneObjectPart(destId) != null) { @@ -4526,14 +4357,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; byte[] bucket = new byte[1]; - bucket[0] = (byte)assetType; + bucket[0] = (byte)item.Type; //byte[] objBytes = agentItem.ID.GetBytes(); //Array.Copy(objBytes, 0, bucket, 1, 16); GridInstantMessage msg = new GridInstantMessage(World, m_host.OwnerID, m_host.Name, destId, (byte)InstantMessageDialog.TaskInventoryOffered, - false, objName+". "+m_host.Name+" is located at "+ + false, item.Name+". "+m_host.Name+" is located at "+ World.RegionInfo.RegionName+" "+ m_host.AbsolutePosition.ToString(), agentItem.ID, true, m_host.AbsolutePosition, @@ -4561,27 +4392,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - List inv; - try - { - m_host.TaskInventory.LockItemsForRead(true); - inv = new List(m_host.TaskInventory.Values); - } - finally - { - m_host.TaskInventory.LockItemsForRead(false); - } - foreach (TaskInventoryItem item in inv) - { - if (item.Name == name) - { - if (item.ItemID == m_itemID) - throw new ScriptDeleteException(); - else - m_host.Inventory.RemoveInventoryItem(item.ItemID); - return; - } - } + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name); + + if (item == null) + return; + + if (item.ItemID == m_item.ItemID) + throw new ScriptDeleteException(); + else + m_host.Inventory.RemoveInventoryItem(item.ItemID); } public void llSetText(string text, LSL_Vector color, double alpha) @@ -4709,8 +4528,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID rq = UUID.Random(); UUID tid = AsyncCommands. - DataserverPlugin.RegisterRequest(m_localID, - m_itemID, rq.ToString()); + DataserverPlugin.RegisterRequest(m_host.LocalId, + m_item.ItemID, rq.ToString()); AsyncCommands. DataserverPlugin.DataserverReply(rq.ToString(), reply); @@ -4729,16 +4548,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - //Clone is thread safe - TaskInventoryDictionary itemDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); - - foreach (TaskInventoryItem item in itemDictionary.Values) + foreach (TaskInventoryItem item in m_host.Inventory.GetInventoryItems()) { if (item.Type == 3 && item.Name == name) { UUID tid = AsyncCommands. - DataserverPlugin.RegisterRequest(m_localID, - m_itemID, item.AssetID.ToString()); + DataserverPlugin.RegisterRequest(m_host.LocalId, + m_item.ItemID, item.AssetID.ToString()); Vector3 region = new Vector3( World.RegionInfo.RegionLocX * Constants.RegionSize, @@ -4764,6 +4580,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return tid.ToString(); } } + ScriptSleep(1000); return String.Empty; } @@ -4956,19 +4773,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID soundId = UUID.Zero; if (!UUID.TryParse(impact_sound, out soundId)) { - m_host.TaskInventory.LockItemsForRead(true); - foreach (TaskInventoryItem item in m_host.TaskInventory.Values) - { - if (item.Type == (int)AssetType.Sound && item.Name == impact_sound) - { - soundId = item.AssetID; - break; - } - } - m_host.TaskInventory.LockItemsForRead(false); + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(impact_sound); + + if (item != null && item.Type == (int)AssetType.Sound) + soundId = item.AssetID; } - m_host.CollisionSoundVolume = (float)impact_volume; + m_host.CollisionSound = soundId; + m_host.CollisionSoundVolume = (float)impact_volume; m_host.CollisionSoundType = 1; } @@ -5010,10 +4822,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID partItemID; foreach (SceneObjectPart part in parts) { - //Clone is thread safe - TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)part.TaskInventory.Clone(); - - foreach (TaskInventoryItem item in itemsDictionary.Values) + foreach (TaskInventoryItem item in part.Inventory.GetInventoryItems()) { if (item.Type == ScriptBaseClass.INVENTORY_SCRIPT) { @@ -5211,22 +5020,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String llGetScriptName() { - string result = String.Empty; - m_host.AddScriptLPS(1); - m_host.TaskInventory.LockItemsForRead(true); - foreach (TaskInventoryItem item in m_host.TaskInventory.Values) - { - if (item.Type == 10 && item.ItemID == m_itemID) - { - result = item.Name!=null?item.Name:String.Empty; - break; - } - } - m_host.TaskInventory.LockItemsForRead(false); - - return result; + return m_item.Name != null ? m_item.Name : String.Empty; } public LSL_Integer llGetLinkNumberOfSides(int link) @@ -5397,22 +5193,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - m_host.TaskInventory.LockItemsForRead(true); - foreach (KeyValuePair inv in m_host.TaskInventory) + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name); + + if (item == null) + return UUID.Zero.ToString(); + + if ((item.CurrentPermissions + & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) + == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) { - if (inv.Value.Name == name) - { - if ((inv.Value.CurrentPermissions & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) - { - m_host.TaskInventory.LockItemsForRead(false); - return inv.Value.AssetID.ToString(); - } - else - { - m_host.TaskInventory.LockItemsForRead(false); - return UUID.Zero.ToString(); - } - } + return item.AssetID.ToString(); } m_host.TaskInventory.LockItemsForRead(false); @@ -6360,7 +6150,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } } - List presenceIds = new List(); World.ForEachRootScenePresence( delegate (ScenePresence ssp) @@ -6511,7 +6300,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (m_host.OwnerID == land.LandData.OwnerID) { Vector3 pos = World.GetNearestAllowedPosition(presence, land); - presence.TeleportWithMomentum(pos); + presence.TeleportWithMomentum(pos, null); presence.ControllingClient.SendAlertMessage("You have been ejected from this land"); } } @@ -7036,22 +6825,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - protected UUID GetTaskInventoryItem(string name) - { - m_host.TaskInventory.LockItemsForRead(true); - foreach (KeyValuePair inv in m_host.TaskInventory) - { - if (inv.Value.Name == name) - { - m_host.TaskInventory.LockItemsForRead(false); - return inv.Key; - } - } - m_host.TaskInventory.LockItemsForRead(false); - - return UUID.Zero; - } - public void llGiveInventoryList(string destination, string category, LSL_List inventory) { m_host.AddScriptLPS(1); @@ -7064,16 +6837,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api foreach (Object item in inventory.Data) { + string rawItemString = item.ToString(); + UUID itemID; - if (UUID.TryParse(item.ToString(), out itemID)) + if (UUID.TryParse(rawItemString, out itemID)) { itemList.Add(itemID); } else { - itemID = GetTaskInventoryItem(item.ToString()); - if (itemID != UUID.Zero) - itemList.Add(itemID); + TaskInventoryItem taskItem = m_host.Inventory.GetInventoryItem(rawItemString); + + if (taskItem != null) + itemList.Add(taskItem.ItemID); } } @@ -7395,9 +7171,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llRemoteLoadScriptPin(string target, string name, int pin, int running, int start_param) { m_host.AddScriptLPS(1); - bool found = false; + UUID destId = UUID.Zero; - UUID srcId = UUID.Zero; if (!UUID.TryParse(target, out destId)) { @@ -7412,25 +7187,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } // copy the first script found with this inventory name - TaskInventoryItem scriptItem = null; - m_host.TaskInventory.LockItemsForRead(true); - foreach (KeyValuePair inv in m_host.TaskInventory) - { - if (inv.Value.Name == name) - { - // make sure the object is a script - if (10 == inv.Value.Type) - { - found = true; - srcId = inv.Key; - scriptItem = inv.Value; - break; - } - } - } - m_host.TaskInventory.LockItemsForRead(false); + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name); - if (!found) + // make sure the object is a script + if (item == null || item.Type != 10) { llSay(0, "Could not find script " + name); return; @@ -7439,13 +7199,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api SceneObjectPart dest = World.GetSceneObjectPart(destId); if (dest != null) { - if ((scriptItem.BasePermissions & (uint)PermissionMask.Transfer) != 0 || dest.ParentGroup.RootPart.OwnerID == m_host.ParentGroup.RootPart.OwnerID) + if ((item.BasePermissions & (uint)PermissionMask.Transfer) != 0 || dest.ParentGroup.RootPart.OwnerID == m_host.ParentGroup.RootPart.OwnerID) { // the rest of the permission checks are done in RezScript, so check the pin there as well - World.RezScriptFromPrim(srcId, m_host, destId, pin, running, start_param); + World.RezScriptFromPrim(item.ItemID, m_host, destId, pin, running, start_param); - if ((scriptItem.BasePermissions & (uint)PermissionMask.Copy) == 0) - m_host.Inventory.RemoveInventoryItem(srcId); + if ((item.BasePermissions & (uint)PermissionMask.Copy) == 0) + m_host.Inventory.RemoveInventoryItem(item.ItemID); } } // this will cause the delay even if the script pin or permissions were wrong - seems ok @@ -7458,14 +7218,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface(); if (xmlrpcMod.IsEnabled()) { - UUID channelID = xmlrpcMod.OpenXMLRPCChannel(m_localID, m_itemID, UUID.Zero); + UUID channelID = xmlrpcMod.OpenXMLRPCChannel(m_host.LocalId, m_item.ItemID, UUID.Zero); IXmlRpcRouter xmlRpcRouter = m_ScriptEngine.World.RequestModuleInterface(); if (xmlRpcRouter != null) { string ExternalHostName = m_ScriptEngine.World.RegionInfo.ExternalHostName; xmlRpcRouter.RegisterNewReceiver(m_ScriptEngine.ScriptModule, channelID, m_host.UUID, - m_itemID, String.Format("http://{0}:{1}/", ExternalHostName, + m_item.ItemID, String.Format("http://{0}:{1}/", ExternalHostName, xmlrpcMod.Port.ToString())); } object[] resobj = new object[] @@ -7477,7 +7237,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api new LSL_Integer(0), new LSL_String(String.Empty) }; - m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams("remote_data", resobj, + m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams("remote_data", resobj, new DetectParams[0])); } ScriptSleep(1000); @@ -7488,7 +7248,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface(); ScriptSleep(3000); - return (xmlrpcMod.SendRemoteData(m_localID, m_itemID, channel, dest, idata, sdata)).ToString(); + return (xmlrpcMod.SendRemoteData(m_host.LocalId, m_item.ItemID, channel, dest, idata, sdata)).ToString(); } public void llRemoteDataReply(string channel, string message_id, string sdata, int idata) @@ -8475,7 +8235,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; face = (int)rules.GetLSLIntegerItem(idx++); int shiny = (int)rules.GetLSLIntegerItem(idx++); - Bumpiness bump = (Bumpiness)Convert.ToByte((int)rules.GetLSLIntegerItem(idx++)); + Bumpiness bump = (Bumpiness)(int)rules.GetLSLIntegerItem(idx++); SetShiny(part, face, shiny, bump); @@ -10317,7 +10077,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String llGetSimulatorHostname() { m_host.AddScriptLPS(1); - return System.Environment.MachineName; + IUrlModule UrlModule = World.RequestModuleInterface(); + return UrlModule.ExternalHostNameForLSL; } // @@ -10554,92 +10315,82 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - public LSL_Integer llGetInventoryPermMask(string item, int mask) + public LSL_Integer llGetInventoryPermMask(string itemName, int mask) { m_host.AddScriptLPS(1); - m_host.TaskInventory.LockItemsForRead(true); - foreach (KeyValuePair inv in m_host.TaskInventory) + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName); + + if (item == null) + return -1; + + switch (mask) { - if (inv.Value.Name == item) - { - m_host.TaskInventory.LockItemsForRead(false); - switch (mask) - { - case 0: - return (int)inv.Value.BasePermissions; - case 1: - return (int)inv.Value.CurrentPermissions; - case 2: - return (int)inv.Value.GroupPermissions; - case 3: - return (int)inv.Value.EveryonePermissions; - case 4: - return (int)inv.Value.NextPermissions; - } - } + case 0: + return (int)item.BasePermissions; + case 1: + return (int)item.CurrentPermissions; + case 2: + return (int)item.GroupPermissions; + case 3: + return (int)item.EveryonePermissions; + case 4: + return (int)item.NextPermissions; } m_host.TaskInventory.LockItemsForRead(false); return -1; } - public void llSetInventoryPermMask(string item, int mask, int value) + public void llSetInventoryPermMask(string itemName, int mask, int value) { m_host.AddScriptLPS(1); + if (m_ScriptEngine.Config.GetBoolean("AllowGodFunctions", false)) { if (World.Permissions.CanRunConsoleCommand(m_host.OwnerID)) { - lock (m_host.TaskInventory) + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName); + + if (item != null) { - foreach (KeyValuePair inv in m_host.TaskInventory) + switch (mask) { - if (inv.Value.Name == item) - { - switch (mask) - { - case 0: - inv.Value.BasePermissions = (uint)value; - break; - case 1: - inv.Value.CurrentPermissions = (uint)value; - break; - case 2: - inv.Value.GroupPermissions = (uint)value; - break; - case 3: - inv.Value.EveryonePermissions = (uint)value; - break; - case 4: - inv.Value.NextPermissions = (uint)value; - break; - } - } + case 0: + item.BasePermissions = (uint)value; + break; + case 1: + item.CurrentPermissions = (uint)value; + break; + case 2: + item.GroupPermissions = (uint)value; + break; + case 3: + item.EveryonePermissions = (uint)value; + break; + case 4: + item.NextPermissions = (uint)value; + break; } } } } } - public LSL_String llGetInventoryCreator(string item) + public LSL_String llGetInventoryCreator(string itemName) { m_host.AddScriptLPS(1); - m_host.TaskInventory.LockItemsForRead(true); - foreach (KeyValuePair inv in m_host.TaskInventory) + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName); + + if (item == null) { - if (inv.Value.Name == item) - { - m_host.TaskInventory.LockItemsForRead(false); - return inv.Value.CreatorID.ToString(); - } + llSay(0, "No item name '" + item + "'"); + + return String.Empty; } - m_host.TaskInventory.LockItemsForRead(false); - llSay(0, "No item name '" + item + "'"); - - return String.Empty; + return item.CreatorID.ToString(); } public void llOwnerSay(string msg) @@ -10656,13 +10407,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); if (m_UrlModule != null) - return m_UrlModule.RequestSecureURL(m_ScriptEngine.ScriptModule, m_host, m_itemID).ToString(); + return m_UrlModule.RequestSecureURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID).ToString(); return UUID.Zero.ToString(); } public LSL_String llRequestSimulatorData(string simulator, int data) { - IOSSL_Api ossl = (IOSSL_Api)m_ScriptEngine.GetApi(m_itemID, "OSSL"); + IOSSL_Api ossl = (IOSSL_Api)m_ScriptEngine.GetApi(m_item.ItemID, "OSSL"); try { @@ -10672,7 +10423,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api GridRegion info; - if (m_ScriptEngine.World.RegionInfo.RegionName == simulator) + if (m_ScriptEngine.World.RegionInfo.RegionName == simulator) //Det data for this simulator? + info = new GridRegion(m_ScriptEngine.World.RegionInfo); else info = m_ScriptEngine.World.GridService.GetRegionByName(m_ScriptEngine.World.RegionInfo.ScopeID, simulator); @@ -10685,10 +10437,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api ScriptSleep(1000); return UUID.Zero.ToString(); } - reply = new LSL_Vector( - info.RegionLocX, - info.RegionLocY, - 0).ToString(); + if (m_ScriptEngine.World.RegionInfo.RegionName != simulator) + { + //Hypergrid Region co-ordinates + uint rx = 0, ry = 0; + Utils.LongToUInts(Convert.ToUInt64(info.RegionSecret), out rx, out ry); + + reply = new LSL_Vector( + rx, + ry, + 0).ToString(); + } + else + { + //Local-cooridnates + reply = new LSL_Vector( + info.RegionLocX, + info.RegionLocY, + 0).ToString(); + } break; case ScriptBaseClass.DATA_SIM_STATUS: if (info != null) @@ -10724,7 +10491,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID rq = UUID.Random(); UUID tid = AsyncCommands. - DataserverPlugin.RegisterRequest(m_localID, m_itemID, rq.ToString()); + DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, rq.ToString()); AsyncCommands. DataserverPlugin.DataserverReply(rq.ToString(), reply); @@ -10743,7 +10510,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); if (m_UrlModule != null) - return m_UrlModule.RequestURL(m_ScriptEngine.ScriptModule, m_host, m_itemID).ToString(); + return m_UrlModule.RequestURL(m_ScriptEngine.ScriptModule, m_host, m_item.ItemID).ToString(); return UUID.Zero.ToString(); } @@ -10779,7 +10546,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // child agents have a mass of 1.0 return 1; else - return avatar.GetMass(); + return (double)avatar.GetMass(); } catch (KeyNotFoundException) { @@ -11183,18 +10950,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - m_host.TaskInventory.LockItemsForRead(true); - foreach (KeyValuePair inv in m_host.TaskInventory) - { - if (inv.Value.Name == name) - { - m_host.TaskInventory.LockItemsForRead(false); - return inv.Value.Type; - } - } - m_host.TaskInventory.LockItemsForRead(false); + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name); - return -1; + if (item == null) + return -1; + + return item.Type; } public void llSetPayPrice(int price, LSL_List quick_pay_buttons) @@ -11222,32 +10983,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Vector llGetCameraPos() { m_host.AddScriptLPS(1); - UUID invItemID = InventorySelf(); - if (invItemID == UUID.Zero) - return new LSL_Vector(); + if (m_item.PermsGranter == UUID.Zero) + return new LSL_Vector(); - m_host.TaskInventory.LockItemsForRead(true); - - UUID agentID = m_host.TaskInventory[invItemID].PermsGranter; - -// if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero) - if (agentID == UUID.Zero) - { - m_host.TaskInventory.LockItemsForRead(false); - return new LSL_Vector(); - } - - if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) { ShoutError("No permissions to track the camera"); - m_host.TaskInventory.LockItemsForRead(false); return new LSL_Vector(); } - m_host.TaskInventory.LockItemsForRead(false); // ScenePresence presence = World.GetScenePresence(m_host.OwnerID); - ScenePresence presence = World.GetScenePresence(agentID); + ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); if (presence != null) { LSL_Vector pos = new LSL_Vector(presence.CameraPosition.X, presence.CameraPosition.Y, presence.CameraPosition.Z); @@ -11259,30 +11006,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_Rotation llGetCameraRot() { m_host.AddScriptLPS(1); - UUID invItemID = InventorySelf(); - if (invItemID == UUID.Zero) - return new LSL_Rotation(); - m_host.TaskInventory.LockItemsForRead(true); + if (m_item.PermsGranter == UUID.Zero) + return new LSL_Rotation(); - UUID agentID = m_host.TaskInventory[invItemID].PermsGranter; - -// if (m_host.TaskInventory[invItemID].PermsGranter == UUID.Zero) - if (agentID == UUID.Zero) - { - m_host.TaskInventory.LockItemsForRead(false); - return new LSL_Rotation(); - } - if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0) { ShoutError("No permissions to track the camera"); - m_host.TaskInventory.LockItemsForRead(false); return new LSL_Rotation(); } - m_host.TaskInventory.LockItemsForRead(false); // ScenePresence presence = World.GetScenePresence(m_host.OwnerID); - ScenePresence presence = World.GetScenePresence(agentID); + ScenePresence presence = World.GetScenePresence(m_item.PermsGranter); if (presence != null) { return new LSL_Rotation(presence.CameraRotation.X, presence.CameraRotation.Y, presence.CameraRotation.Z, presence.CameraRotation.W); @@ -11341,7 +11076,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void llMapDestination(string simname, LSL_Vector pos, LSL_Vector lookAt) { m_host.AddScriptLPS(1); - DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_itemID, 0); + DetectParams detectedParams = m_ScriptEngine.GetDetectParams(m_item.ItemID, 0); if (detectedParams == null) { if (m_host.ParentGroup.IsAttachment == true) @@ -11465,30 +11200,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - // our key in the object we are in - UUID invItemID = InventorySelf(); - if (invItemID == UUID.Zero) return; - // the object we are in UUID objectID = m_host.ParentUUID; - if (objectID == UUID.Zero) return; + if (objectID == UUID.Zero) + return; - UUID agentID; - m_host.TaskInventory.LockItemsForRead(true); // we need the permission first, to know which avatar we want to set the camera for - agentID = m_host.TaskInventory[invItemID].PermsGranter; + UUID agentID = m_item.PermsGranter; if (agentID == UUID.Zero) - { - m_host.TaskInventory.LockItemsForRead(false); return; - } - if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) - { - m_host.TaskInventory.LockItemsForRead(false); + + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return; - } - m_host.TaskInventory.LockItemsForRead(false); ScenePresence presence = World.GetScenePresence(agentID); @@ -11530,34 +11254,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - // our key in the object we are in - UUID invItemID=InventorySelf(); - if (invItemID == UUID.Zero) return; - // the object we are in UUID objectID = m_host.ParentUUID; - if (objectID == UUID.Zero) return; + if (objectID == UUID.Zero) + return; // we need the permission first, to know which avatar we want to clear the camera for - UUID agentID; - m_host.TaskInventory.LockItemsForRead(true); - agentID = m_host.TaskInventory[invItemID].PermsGranter; + UUID agentID = m_item.PermsGranter; + if (agentID == UUID.Zero) - { - m_host.TaskInventory.LockItemsForRead(false); return; - } - if ((m_host.TaskInventory[invItemID].PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) - { - m_host.TaskInventory.LockItemsForRead(false); + + if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_CONTROL_CAMERA) == 0) return; - } - m_host.TaskInventory.LockItemsForRead(false); ScenePresence presence = World.GetScenePresence(agentID); // we are not interested in child-agents - if (presence.IsChildAgent) return; + if (presence.IsChildAgent) + return; presence.ControllingClient.SendClearFollowCamProperties(objectID); } @@ -11748,8 +11463,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - UUID reqID = httpScriptMod. - StartHttpRequest(m_localID, m_itemID, url, param, httpHeaders, body); + UUID reqID + = httpScriptMod.StartHttpRequest(m_host.LocalId, m_item.ItemID, url, param, httpHeaders, body); if (reqID != UUID.Zero) return reqID.ToString(); @@ -12003,19 +11718,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api break; // For the following 8 see the Object version below case ScriptBaseClass.OBJECT_RUNNING_SCRIPT_COUNT: - ret.Add(new LSL_Integer(0)); + ret.Add(new LSL_Integer(av.RunningScriptCount())); break; case ScriptBaseClass.OBJECT_TOTAL_SCRIPT_COUNT: - ret.Add(new LSL_Integer(0)); + ret.Add(new LSL_Integer(av.ScriptCount())); break; case ScriptBaseClass.OBJECT_SCRIPT_MEMORY: - ret.Add(new LSL_Integer(0)); + ret.Add(new LSL_Integer(av.RunningScriptCount() * 16384)); break; case ScriptBaseClass.OBJECT_SCRIPT_TIME: - ret.Add(new LSL_Float(0)); + ret.Add(new LSL_Float(av.ScriptExecutionTime() / 1000.0f)); break; case ScriptBaseClass.OBJECT_PRIM_EQUIVALENCE: - ret.Add(new LSL_Integer(0)); + ret.Add(new LSL_Integer(1)); break; case ScriptBaseClass.OBJECT_SERVER_COST: ret.Add(new LSL_Float(0)); @@ -12073,37 +11788,35 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api case ScriptBaseClass.OBJECT_CREATOR: ret.Add(new LSL_String(obj.CreatorID.ToString())); break; - // The following 8 I have intentionaly coded to return zero. They are part of - // "Land Impact" calculations. These calculations are probably not applicable - // to OpenSim, required figures (cpu/memory usage) are not currently tracked - // I have intentionally left these all at zero rather than return possibly - // missleading numbers case ScriptBaseClass.OBJECT_RUNNING_SCRIPT_COUNT: - // in SL this currently includes crashed scripts - ret.Add(new LSL_Integer(0)); + ret.Add(new LSL_Integer(obj.ParentGroup.RunningScriptCount())); break; case ScriptBaseClass.OBJECT_TOTAL_SCRIPT_COUNT: - ret.Add(new LSL_Integer(0)); + ret.Add(new LSL_Integer(obj.ParentGroup.ScriptCount())); break; case ScriptBaseClass.OBJECT_SCRIPT_MEMORY: // The value returned in SL for mono scripts is 65536 * number of active scripts - ret.Add(new LSL_Integer(0)); + // and 16384 * number of active scripts for LSO. since llGetFreememory + // is coded to give the LSO value use it here + ret.Add(new LSL_Integer(obj.ParentGroup.RunningScriptCount() * 16384)); break; case ScriptBaseClass.OBJECT_SCRIPT_TIME: - // Average cpu time per simulator frame expended on all scripts in the objetc - ret.Add(new LSL_Float(0)); + // Average cpu time in seconds per simulator frame expended on all scripts in the object + ret.Add(new LSL_Float(obj.ParentGroup.ScriptExecutionTime() / 1000.0f)); break; case ScriptBaseClass.OBJECT_PRIM_EQUIVALENCE: // according to the SL wiki A prim or linkset will have prim // equivalent of the number of prims in a linkset if it does not // contain a mesh anywhere in the link set or is not a normal prim // The value returned in SL for normal prims is prim count - ret.Add(new LSL_Integer(0)); + ret.Add(new LSL_Integer(obj.ParentGroup.PrimCount)); break; // costs below may need to be diferent for root parts, need to check case ScriptBaseClass.OBJECT_SERVER_COST: - // The value returned in SL for normal prims is prim count + // The linden calculation is here + // http://wiki.secondlife.com/wiki/Mesh/Mesh_Server_Weight + // The value returned in SL for normal prims looks like the prim count ret.Add(new LSL_Float(0)); break; case ScriptBaseClass.OBJECT_STREAMING_COST: @@ -12128,22 +11841,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return new LSL_List(); } - internal UUID ScriptByName(string name) + internal UUID GetScriptByName(string name) { - m_host.TaskInventory.LockItemsForRead(true); + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name); - foreach (TaskInventoryItem item in m_host.TaskInventory.Values) - { - if (item.Type == 10 && item.Name == name) - { - m_host.TaskInventory.LockItemsForRead(false); - return item.ItemID; - } - } + if (item == null || item.Type != 10) + return UUID.Zero; - m_host.TaskInventory.LockItemsForRead(false); - - return UUID.Zero; + return item.ItemID; } internal void ShoutError(string msg) @@ -12183,21 +11888,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - //Clone is thread safe - TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); - UUID assetID = UUID.Zero; if (!UUID.TryParse(name, out assetID)) { - foreach (TaskInventoryItem item in itemsDictionary.Values) - { - if (item.Type == 7 && item.Name == name) - { - assetID = item.AssetID; - break; - } - } + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name); + + if (item != null && item.Type == 7) + assetID = item.AssetID; } if (assetID == UUID.Zero) @@ -12209,7 +11907,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } // was: UUID tid = tid = AsyncCommands. - UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_localID, m_itemID, assetID.ToString()); + UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, assetID.ToString()); if (NotecardCache.IsCached(assetID)) { @@ -12228,9 +11926,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } - System.Text.UTF8Encoding enc = - new System.Text.UTF8Encoding(); - string data = enc.GetString(a.Data); + string data = Encoding.UTF8.GetString(a.Data); //m_log.Debug(data); NotecardCache.Cache(id, data); AsyncCommands. @@ -12246,21 +11942,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { m_host.AddScriptLPS(1); - //Clone is thread safe - TaskInventoryDictionary itemsDictionary = (TaskInventoryDictionary)m_host.TaskInventory.Clone(); - UUID assetID = UUID.Zero; if (!UUID.TryParse(name, out assetID)) { - foreach (TaskInventoryItem item in itemsDictionary.Values) - { - if (item.Type == 7 && item.Name == name) - { - assetID = item.AssetID; - break; - } - } + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(name); + + if (item != null && item.Type == 7) + assetID = item.AssetID; } if (assetID == UUID.Zero) @@ -12272,7 +11961,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } // was: UUID tid = tid = AsyncCommands. - UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_localID, m_itemID, assetID.ToString()); + UUID tid = AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, assetID.ToString()); if (NotecardCache.IsCached(assetID)) { @@ -12290,9 +11979,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } - System.Text.UTF8Encoding enc = - new System.Text.UTF8Encoding(); - string data = enc.GetString(a.Data); + string data = Encoding.UTF8.GetString(a.Data); //m_log.Debug(data); NotecardCache.Cache(id, data); AsyncCommands.DataserverPlugin.DataserverReply(id.ToString(), @@ -12356,7 +12043,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { UUID rq = UUID.Random(); - AsyncCommands.DataserverPlugin.RegisterRequest(m_localID, m_itemID, rq.ToString()); + AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, rq.ToString()); AsyncCommands.DataserverPlugin.DataserverReply(rq.ToString(), Name2Username(llKey2Name(id))); @@ -12372,7 +12059,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { UUID rq = UUID.Random(); - AsyncCommands.DataserverPlugin.RegisterRequest(m_localID, m_itemID, rq.ToString()); + AsyncCommands.DataserverPlugin.RegisterRequest(m_host.LocalId, m_item.ItemID, rq.ToString()); AsyncCommands.DataserverPlugin.DataserverReply(rq.ToString(), llKey2Name(id)); @@ -12574,7 +12261,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { Tri t1 = new Tri(); Tri t2 = new Tri(); - + Vector3 p1 = new Vector3(x-1, y-1, (float)heightfield[x-1, y-1]); Vector3 p2 = new Vector3(x, y-1, (float)heightfield[x, y-1]); Vector3 p3 = new Vector3(x, y, (float)heightfield[x, y]); @@ -12615,7 +12302,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // sometimes if (Math.Abs(b) < 0.000001) continue; - + double r = a / b; // ray points away from plane @@ -12875,7 +12562,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api bool isAccount = false; bool isGroup = false; - if (!estate.IsEstateOwner(m_host.OwnerID) || !estate.IsEstateManager(m_host.OwnerID)) + if (!estate.IsEstateOwner(m_host.OwnerID) || !estate.IsEstateManagerOrOwner(m_host.OwnerID)) return 0; UUID id = new UUID(); @@ -12937,6 +12624,40 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return 1; } + public LSL_Integer llGetMemoryLimit() + { + m_host.AddScriptLPS(1); + // The value returned for LSO scripts in SL + return 16384; + } + + public LSL_Integer llSetMemoryLimit(LSL_Integer limit) + { + m_host.AddScriptLPS(1); + // Treat as an LSO script + return ScriptBaseClass.FALSE; + } + + public LSL_Integer llGetSPMaxMemory() + { + m_host.AddScriptLPS(1); + // The value returned for LSO scripts in SL + return 16384; + } + + public virtual LSL_Integer llGetUsedMemory() + { + m_host.AddScriptLPS(1); + // The value returned for LSO scripts in SL + return 16384; + } + + public void llScriptProfiler(LSL_Integer flags) + { + m_host.AddScriptLPS(1); + // This does nothing for LSO scripts in SL + } + #region Not Implemented // // Listing the unimplemented lsl functions here, please move @@ -12949,25 +12670,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api NotImplemented("llGetEnv"); } - public void llGetSPMaxMemory() - { - m_host.AddScriptLPS(1); - NotImplemented("llGetSPMaxMemory"); - } - - public virtual LSL_Integer llGetUsedMemory() - { - m_host.AddScriptLPS(1); - NotImplemented("llGetUsedMemory"); - return 0; - } - - public void llScriptProfiler(LSL_Integer flags) - { - m_host.AddScriptLPS(1); - //NotImplemented("llScriptProfiler"); - } - public void llSetSoundQueueing(int queue) { m_host.AddScriptLPS(1); @@ -13045,8 +12747,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api try { - UUID invItemID=InventorySelf(); - if (invItemID == UUID.Zero) + TaskInventoryItem item = m_item; + if (item == null) { replydata = "SERVICE_ERROR"; return; @@ -13054,10 +12756,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); - m_host.TaskInventory.LockItemsForRead(true); - TaskInventoryItem item = m_host.TaskInventory[invItemID]; - m_host.TaskInventory.LockItemsForRead(false); - if (item.PermsGranter == UUID.Zero) { replydata = "MISSING_PERMISSION_DEBIT"; @@ -13099,7 +12797,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } finally { - m_ScriptEngine.PostScriptEvent(m_itemID, new EventParams( + m_ScriptEngine.PostScriptEvent(m_item.ItemID, new EventParams( "transaction_result", new Object[] { new LSL_String(txn.ToString()), new LSL_Integer(replycode), diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs index 77a784d077..795de802bb 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs @@ -58,17 +58,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { internal IScriptEngine m_ScriptEngine; internal SceneObjectPart m_host; - internal uint m_localID; - internal UUID m_itemID; internal bool m_LSFunctionsEnabled = false; internal IScriptModuleComms m_comms = null; - public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID) + public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) { m_ScriptEngine = ScriptEngine; m_host = host; - m_localID = localID; - m_itemID = itemID; if (m_ScriptEngine.Config.GetBoolean("AllowLightShareFunctions", false)) m_LSFunctionsEnabled = true; @@ -449,7 +445,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSShoutError("LightShare functions are not enabled."); return 0; } - if (!World.RegionInfo.EstateSettings.IsEstateManager(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200) + if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200) { LSShoutError("lsSetWindlightScene can only be used by estate managers or owners."); return 0; @@ -477,7 +473,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSShoutError("LightShare functions are not enabled."); return; } - if (!World.RegionInfo.EstateSettings.IsEstateManager(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200) + if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200) { LSShoutError("lsSetWindlightScene can only be used by estate managers or owners."); return; @@ -500,7 +496,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSShoutError("LightShare functions are not enabled."); return 0; } - if (!World.RegionInfo.EstateSettings.IsEstateManager(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200) + if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200) { LSShoutError("lsSetWindlightSceneTargeted can only be used by estate managers or owners."); return 0; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs index 7c07e15fa3..4bd3dffd30 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/MOD_Api.cs @@ -57,17 +57,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { internal IScriptEngine m_ScriptEngine; internal SceneObjectPart m_host; - internal uint m_localID; - internal UUID m_itemID; + internal TaskInventoryItem m_item; internal bool m_MODFunctionsEnabled = false; internal IScriptModuleComms m_comms = null; - public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID) + public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) { m_ScriptEngine = ScriptEngine; m_host = host; - m_localID = localID; - m_itemID = itemID; + m_item = item; if (m_ScriptEngine.Config.GetBoolean("AllowMODFunctions", false)) m_MODFunctionsEnabled = true; @@ -252,7 +250,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // non-null but don't trust it completely try { - object result = m_comms.InvokeOperation(m_host.UUID, m_itemID, fname, convertedParms); + object result = m_comms.InvokeOperation(m_host.UUID, m_item.ItemID, fname, convertedParms); if (result != null) return result; @@ -279,7 +277,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID req = UUID.Random(); - m_comms.RaiseEvent(m_itemID, req.ToString(), module, command, k); + m_comms.RaiseEvent(m_item.ItemID, req.ToString(), module, command, k); return req.ToString(); } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 0dc2aa2b95..29d0342d60 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -126,13 +126,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api [Serializable] public class OSSL_Api : MarshalByRefObject, IOSSL_Api, IScriptApi { -// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public const string GridInfoServiceConfigSectionName = "GridInfoService"; internal IScriptEngine m_ScriptEngine; internal ILSL_Api m_LSL_Api = null; // get a reference to the LSL API so we can call methods housed there internal SceneObjectPart m_host; - internal uint m_localID; - internal UUID m_itemID; + internal TaskInventoryItem m_item; internal bool m_OSFunctionsEnabled = false; internal ThreatLevel m_MaxThreatLevel = ThreatLevel.VeryLow; internal float m_ScriptDelayFactor = 1.0f; @@ -140,12 +141,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api internal bool m_debuggerSafe = false; internal Dictionary m_FunctionPerms = new Dictionary(); - public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, uint localID, UUID itemID) + public void Initialize(IScriptEngine ScriptEngine, SceneObjectPart host, TaskInventoryItem item) { m_ScriptEngine = ScriptEngine; m_host = host; - m_localID = localID; - m_itemID = itemID; + m_item = item; m_debuggerSafe = m_ScriptEngine.Config.GetBoolean("DebuggerSafe", false); if (m_ScriptEngine.Config.GetBoolean("AllowOSFunctions", false)) @@ -218,12 +218,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + /// + /// Initialize the LSL interface. + /// + /// + /// FIXME: This is an abomination. We should be able to set this up earlier but currently we have no + /// guarantee the interface is present on Initialize(). There needs to be another post initialize call from + /// ScriptInstance. + /// private void InitLSL() { if (m_LSL_Api != null) return; - m_LSL_Api = (ILSL_Api)m_ScriptEngine.GetApi(m_itemID, "LSL"); + m_LSL_Api = (ILSL_Api)m_ScriptEngine.GetApi(m_item.ItemID, "LSL"); } // @@ -342,22 +350,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; } - TaskInventoryItem ti = m_host.Inventory.GetInventoryItem(m_itemID); - if (ti == null) - { - OSSLError( - String.Format("{0} permission error. Can't find script in prim inventory.", - function)); - } + UUID ownerID = m_item.OwnerID; - UUID ownerID = ti.OwnerID; - - //OSSL only may be used if objet is in the same group as the parcel + //OSSL only may be used if object is in the same group as the parcel if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_GROUP_MEMBER")) { ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y); - if (land.LandData.GroupID == ti.GroupID && land.LandData.GroupID != UUID.Zero) + if (land.LandData.GroupID == m_item.GroupID && land.LandData.GroupID != UUID.Zero) { return; } @@ -378,7 +378,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("ESTATE_MANAGER")) { //Only Estate Managers may use the function - if (World.RegionInfo.EstateSettings.IsEstateManager(ownerID) && World.RegionInfo.EstateSettings.EstateOwner != ownerID) + if (World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(ownerID) && World.RegionInfo.EstateSettings.EstateOwner != ownerID) { return; } @@ -393,13 +393,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } - if (!m_FunctionPerms[function].AllowedCreators.Contains(ti.CreatorID)) + if (!m_FunctionPerms[function].AllowedCreators.Contains(m_item.CreatorID)) OSSLError( String.Format("{0} permission denied. Script creator is not in the list of users allowed to execute this function and prim owner also has no permission.", function)); - if (ti.CreatorID != ownerID) + + if (m_item.CreatorID != ownerID) { - if ((ti.CurrentPermissions & (uint)PermissionMask.Modify) != 0) + if ((m_item.CurrentPermissions & (uint)PermissionMask.Modify) != 0) OSSLError( String.Format("{0} permission denied. Script permissions error.", function)); @@ -730,11 +731,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api m_host.AddScriptLPS(1); + // For safety, we add another permission check here, and don't rely only on the standard OSSL permissions if (World.Permissions.CanRunConsoleCommand(m_host.OwnerID)) { MainConsole.Instance.RunCommand(command); return true; } + return false; } @@ -880,13 +883,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (World.Entities.ContainsKey((UUID)agent) && World.Entities[avatarID] is ScenePresence) { ScenePresence target = (ScenePresence)World.Entities[avatarID]; - EndPoint ep = target.ControllingClient.GetClientEP(); - if (ep is IPEndPoint) - { - IPEndPoint ip = (IPEndPoint)ep; - return ip.Address.ToString(); - } + return target.ControllingClient.RemoteEndPoint.Address.ToString(); } + // fall through case, just return nothing return ""; } @@ -957,21 +956,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api UUID avatarID = (UUID)avatar; m_host.AddScriptLPS(1); + + // FIXME: What we really want to do here is factor out the similar code in llStopAnimation() to a common + // method (though see that doesn't do the is animation check, which is probably a bug) and have both + // these functions call that common code. However, this does mean navigating the brain-dead requirement + // of calling InitLSL() if (World.Entities.ContainsKey(avatarID) && World.Entities[avatarID] is ScenePresence) { ScenePresence target = (ScenePresence)World.Entities[avatarID]; if (target != null) { - UUID animID = UUID.Zero; - m_host.TaskInventory.LockItemsForRead(true); - foreach (KeyValuePair inv in m_host.TaskInventory) + UUID animID; + + if (!UUID.TryParse(animation, out animID)) { - if (inv.Value.Name == animation) - { - if (inv.Value.Type == (int)AssetType.Animation) - animID = inv.Value.AssetID; - continue; - } + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(animation); + if (item != null && item.Type == (int)AssetType.Animation) + animID = item.AssetID; + else + animID = UUID.Zero; } m_host.TaskInventory.LockItemsForRead(false); @@ -1178,7 +1181,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api CheckThreatLevel(ThreatLevel.High, "osSetStateEvents"); m_host.AddScriptLPS(1); - m_host.SetScriptEvents(m_itemID, events); + m_host.SetScriptEvents(m_item.ItemID, events); } public void osSetRegionWaterHeight(double height) @@ -1186,12 +1189,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api CheckThreatLevel(ThreatLevel.High, "osSetRegionWaterHeight"); m_host.AddScriptLPS(1); - //Check to make sure that the script's owner is the estate manager/master - //World.Permissions.GenericEstatePermission( - if (World.Permissions.IsGod(m_host.OwnerID)) - { - World.EventManager.TriggerRequestChangeWaterHeight((float)height); - } + + World.EventManager.TriggerRequestChangeWaterHeight((float)height); } /// @@ -1202,27 +1201,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// The "Sun Hour" that is desired, 0...24, with 0 just after SunRise public void osSetRegionSunSettings(bool useEstateSun, bool sunFixed, double sunHour) { - CheckThreatLevel(ThreatLevel.Nuisance, "osSetRegionSunSettings"); + CheckThreatLevel(ThreatLevel.High, "osSetRegionSunSettings"); m_host.AddScriptLPS(1); - //Check to make sure that the script's owner is the estate manager/master - //World.Permissions.GenericEstatePermission( - if (World.Permissions.IsGod(m_host.OwnerID)) - { - while (sunHour > 24.0) - sunHour -= 24.0; - while (sunHour < 0) - sunHour += 24.0; + while (sunHour > 24.0) + sunHour -= 24.0; + while (sunHour < 0) + sunHour += 24.0; - World.RegionInfo.RegionSettings.UseEstateSun = useEstateSun; - World.RegionInfo.RegionSettings.SunPosition = sunHour + 6; // LL Region Sun Hour is 6 to 30 - World.RegionInfo.RegionSettings.FixedSun = sunFixed; - World.RegionInfo.RegionSettings.Save(); + World.RegionInfo.RegionSettings.UseEstateSun = useEstateSun; + World.RegionInfo.RegionSettings.SunPosition = sunHour + 6; // LL Region Sun Hour is 6 to 30 + World.RegionInfo.RegionSettings.FixedSun = sunFixed; + World.RegionInfo.RegionSettings.Save(); - World.EventManager.TriggerEstateToolsSunUpdate(World.RegionInfo.RegionHandle, sunFixed, useEstateSun, (float)sunHour); - } + World.EventManager.TriggerEstateToolsSunUpdate( + World.RegionInfo.RegionHandle, sunFixed, useEstateSun, (float)sunHour); } /// @@ -1232,26 +1227,23 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api /// The "Sun Hour" that is desired, 0...24, with 0 just after SunRise public void osSetEstateSunSettings(bool sunFixed, double sunHour) { - CheckThreatLevel(ThreatLevel.Nuisance, "osSetEstateSunSettings"); + CheckThreatLevel(ThreatLevel.High, "osSetEstateSunSettings"); m_host.AddScriptLPS(1); - //Check to make sure that the script's owner is the estate manager/master - //World.Permissions.GenericEstatePermission( - if (World.Permissions.IsGod(m_host.OwnerID)) - { - while (sunHour > 24.0) - sunHour -= 24.0; - while (sunHour < 0) - sunHour += 24.0; + while (sunHour > 24.0) + sunHour -= 24.0; - World.RegionInfo.EstateSettings.UseGlobalTime = !sunFixed; - World.RegionInfo.EstateSettings.SunPosition = sunHour; - World.RegionInfo.EstateSettings.FixedSun = sunFixed; - World.RegionInfo.EstateSettings.Save(); + while (sunHour < 0) + sunHour += 24.0; - World.EventManager.TriggerEstateToolsSunUpdate(World.RegionInfo.RegionHandle, sunFixed, World.RegionInfo.RegionSettings.UseEstateSun, (float)sunHour); - } + World.RegionInfo.EstateSettings.UseGlobalTime = !sunFixed; + World.RegionInfo.EstateSettings.SunPosition = sunHour; + World.RegionInfo.EstateSettings.FixedSun = sunFixed; + World.RegionInfo.EstateSettings.Save(); + + World.EventManager.TriggerEstateToolsSunUpdate( + World.RegionInfo.RegionHandle, sunFixed, World.RegionInfo.RegionSettings.UseEstateSun, (float)sunHour); } /// @@ -1627,7 +1619,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public Object osParseJSONNew(string JSON) { - CheckThreatLevel(ThreatLevel.None, "osParseJSON"); + CheckThreatLevel(ThreatLevel.None, "osParseJSONNew"); m_host.AddScriptLPS(1); @@ -1681,9 +1673,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api CheckThreatLevel(ThreatLevel.Low, "osMessageObject"); m_host.AddScriptLPS(1); + UUID objUUID; + if (!UUID.TryParse(objectUUID, out objUUID)) // prior to patching, a thrown exception regarding invalid GUID format would be shouted instead. + { + OSSLShoutError("osMessageObject() cannot send messages to objects with invalid UUIDs"); + return; + } + object[] resobj = new object[] { new LSL_Types.LSLString(m_host.UUID.ToString()), new LSL_Types.LSLString(message) }; - SceneObjectPart sceneOP = World.GetSceneObjectPart(new UUID(objectUUID)); + SceneObjectPart sceneOP = World.GetSceneObjectPart(objUUID); + + if (sceneOP == null) // prior to patching, PostObjectEvent() would cause a throw exception to be shouted instead. + { + OSSLShoutError("osMessageObject() cannot send message to " + objUUID.ToString() + ", object was not found in scene."); + return; + } m_ScriptEngine.PostObjectEvent( sceneOP.LocalId, new EventParams( @@ -1826,8 +1831,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (a == null) return UUID.Zero; - System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding(); - string data = enc.GetString(a.Data); + string data = Encoding.UTF8.GetString(a.Data); NotecardCache.Cache(assetID, data); }; @@ -1980,7 +1984,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { string retval = String.Empty; IConfigSource config = m_ScriptEngine.ConfigSource; - string url = config.Configs["GridInfo"].GetString("GridInfoURI", String.Empty); + string url = null; + + IConfig gridInfoConfig = config.Configs["GridInfo"]; + + if (gridInfoConfig != null) + url = gridInfoConfig.GetString("GridInfoURI", String.Empty); if (String.IsNullOrEmpty(url)) return "Configuration Error!"; @@ -2042,8 +2051,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api string nick = String.Empty; IConfigSource config = m_ScriptEngine.ConfigSource; - if (config.Configs["GridInfo"] != null) - nick = config.Configs["GridInfo"].GetString("gridnick", nick); + if (config.Configs[GridInfoServiceConfigSectionName] != null) + nick = config.Configs[GridInfoServiceConfigSectionName].GetString("gridnick", nick); if (String.IsNullOrEmpty(nick)) nick = GridUserInfo(InfoType.Nick); @@ -2059,8 +2068,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api string name = String.Empty; IConfigSource config = m_ScriptEngine.ConfigSource; - if (config.Configs["GridInfo"] != null) - name = config.Configs["GridInfo"].GetString("gridname", name); + if (config.Configs[GridInfoServiceConfigSectionName] != null) + name = config.Configs[GridInfoServiceConfigSectionName].GetString("gridname", name); if (String.IsNullOrEmpty(name)) name = GridUserInfo(InfoType.Name); @@ -2076,8 +2085,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api string loginURI = String.Empty; IConfigSource config = m_ScriptEngine.ConfigSource; - if (config.Configs["GridInfo"] != null) - loginURI = config.Configs["GridInfo"].GetString("login", loginURI); + if (config.Configs[GridInfoServiceConfigSectionName] != null) + loginURI = config.Configs[GridInfoServiceConfigSectionName].GetString("login", loginURI); if (String.IsNullOrEmpty(loginURI)) loginURI = GridUserInfo(InfoType.Login); @@ -2124,8 +2133,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api string retval = String.Empty; IConfigSource config = m_ScriptEngine.ConfigSource; - if (config.Configs["GridInfo"] != null) - retval = config.Configs["GridInfo"].GetString(key, retval); + if (config.Configs[GridInfoServiceConfigSectionName] != null) + retval = config.Configs[GridInfoServiceConfigSectionName].GetString(key, retval); if (String.IsNullOrEmpty(retval)) retval = GridUserInfo(InfoType.Custom, key); @@ -2135,7 +2144,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String osFormatString(string str, LSL_List strings) { - CheckThreatLevel(ThreatLevel.Low, "osFormatString"); + CheckThreatLevel(ThreatLevel.VeryLow, "osFormatString"); m_host.AddScriptLPS(1); return String.Format(str, strings.Data); @@ -2143,7 +2152,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_List osMatchString(string src, string pattern, int start) { - CheckThreatLevel(ThreatLevel.High, "osMatchString"); + CheckThreatLevel(ThreatLevel.VeryLow, "osMatchString"); m_host.AddScriptLPS(1); LSL_List result = new LSL_List(); @@ -2185,7 +2194,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public LSL_String osReplaceString(string src, string pattern, string replace, int count, int start) { - CheckThreatLevel(ThreatLevel.High, "osReplaceString"); + CheckThreatLevel(ThreatLevel.VeryLow, "osReplaceString"); m_host.AddScriptLPS(1); // Normalize indices (if negative). @@ -2480,7 +2489,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return; Vector3 pos = new Vector3((float) position.x, (float) position.y, (float) position.z); - module.MoveToTarget(npcId, World, pos, false, true); + module.MoveToTarget(npcId, World, pos, false, true, false); } } @@ -2505,7 +2514,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api World, pos, (options & ScriptBaseClass.OS_NPC_NO_FLY) != 0, - (options & ScriptBaseClass.OS_NPC_LAND_AT_TARGET) != 0); + (options & ScriptBaseClass.OS_NPC_LAND_AT_TARGET) != 0, + (options & ScriptBaseClass.OS_NPC_RUNNING) != 0); } } @@ -2555,7 +2565,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api public void osNpcStopMoveToTarget(LSL_Key npc) { - CheckThreatLevel(ThreatLevel.VeryLow, "osNpcStopMoveTo"); + CheckThreatLevel(ThreatLevel.High, "osNpcStopMoveToTarget"); m_host.AddScriptLPS(1); INPCModule module = World.RequestModuleInterface(); @@ -2571,6 +2581,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } public void osNpcSay(LSL_Key npc, string message) + { + osNpcSay(npc, 0, message); + } + + public void osNpcSay(LSL_Key npc, int channel, string message) { CheckThreatLevel(ThreatLevel.High, "osNpcSay"); m_host.AddScriptLPS(1); @@ -2583,7 +2598,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (!module.CheckPermissions(npcId, m_host.OwnerID)) return; - module.Say(npcId, World, message); + module.Say(npcId, World, message, channel); + } + } + + public void osNpcShout(LSL_Key npc, int channel, string message) + { + CheckThreatLevel(ThreatLevel.High, "osNpcShout"); + m_host.AddScriptLPS(1); + + INPCModule module = World.RequestModuleInterface(); + if (module != null) + { + UUID npcId = new UUID(npc.m_string); + + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; + + module.Shout(npcId, World, message, channel); } } @@ -2684,6 +2716,58 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } } + public void osNpcWhisper(LSL_Key npc, int channel, string message) + { + CheckThreatLevel(ThreatLevel.High, "osNpcWhisper"); + m_host.AddScriptLPS(1); + + INPCModule module = World.RequestModuleInterface(); + if (module != null) + { + UUID npcId = new UUID(npc.m_string); + + if (!module.CheckPermissions(npcId, m_host.OwnerID)) + return; + + module.Whisper(npcId, World, message, channel); + } + } + + public void osNpcTouch(LSL_Key npcLSL_Key, LSL_Key object_key, LSL_Integer link_num) + { + CheckThreatLevel(ThreatLevel.High, "osNpcTouch"); + m_host.AddScriptLPS(1); + INPCModule module = World.RequestModuleInterface(); + int linkNum = link_num.value; + if (module != null || (linkNum < 0 && linkNum != ScriptBaseClass.LINK_THIS)) + { + UUID npcId; + if (!UUID.TryParse(npcLSL_Key, out npcId) || !module.CheckPermissions(npcId, m_host.OwnerID)) + return; + SceneObjectPart part = null; + UUID objectId; + if (UUID.TryParse(LSL_String.ToString(object_key), out objectId)) + part = World.GetSceneObjectPart(objectId); + if (part == null) + return; + if (linkNum != ScriptBaseClass.LINK_THIS) + { + if (linkNum == 0 || linkNum == ScriptBaseClass.LINK_ROOT) + { // 0 and 1 are treated as root, find the root if the current part isnt it + if (!part.IsRoot) + part = part.ParentGroup.RootPart; + } + else + { // Find the prim with the given link number if not found then fail silently + part = part.ParentGroup.GetLinkNumPart(linkNum); + if (part == null) + return; + } + } + module.Touch(npcId, part.UUID); + } + } + /// /// Save the current appearance of the script owner permanently to the named notecard. /// @@ -2835,21 +2919,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api CheckThreatLevel(ThreatLevel.Severe, "osKickAvatar"); m_host.AddScriptLPS(1); - if (World.Permissions.CanRunConsoleCommand(m_host.OwnerID)) + World.ForEachRootScenePresence(delegate(ScenePresence sp) { - World.ForEachRootScenePresence(delegate(ScenePresence sp) + if (sp.Firstname == FirstName && sp.Lastname == SurName) { - if (sp.Firstname == FirstName && sp.Lastname == SurName) - { - // kick client... - if (alert != null) - sp.ControllingClient.Kick(alert); + // kick client... + if (alert != null) + sp.ControllingClient.Kick(alert); - // ...and close on our side - sp.Scene.IncomingCloseAgent(sp.UUID); - } - }); - } + // ...and close on our side + sp.Scene.IncomingCloseAgent(sp.UUID); + } + }); } public void osCauseDamage(string avatar, double damage) @@ -3095,5 +3176,151 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api return ScriptBaseClass.TRUE; } + + /// + /// Sets terrain estate texture + /// + /// + /// + /// + public void osSetTerrainTexture(int level, LSL_Key texture) + { + CheckThreatLevel(ThreatLevel.High, "osSetTerrainTexture"); + + m_host.AddScriptLPS(1); + //Check to make sure that the script's owner is the estate manager/master + //World.Permissions.GenericEstatePermission( + if (World.Permissions.IsGod(m_host.OwnerID)) + { + if (level < 0 || level > 3) + return; + + UUID textureID = new UUID(); + if (!UUID.TryParse(texture, out textureID)) + return; + + // estate module is required + IEstateModule estate = World.RequestModuleInterface(); + if (estate != null) + estate.setEstateTerrainBaseTexture(level, textureID); + } + } + + /// + /// Sets terrain heights of estate + /// + /// + /// + /// + /// + public void osSetTerrainTextureHeight(int corner, double low, double high) + { + CheckThreatLevel(ThreatLevel.High, "osSetTerrainTextureHeight"); + + m_host.AddScriptLPS(1); + //Check to make sure that the script's owner is the estate manager/master + //World.Permissions.GenericEstatePermission( + if (World.Permissions.IsGod(m_host.OwnerID)) + { + if (corner < 0 || corner > 3) + return; + + // estate module is required + IEstateModule estate = World.RequestModuleInterface(); + if (estate != null) + estate.setEstateTerrainTextureHeights(corner, (float)low, (float)high); + } + } + + public void osForceAttachToAvatar(int attachmentPoint) + { + CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatar"); + + m_host.AddScriptLPS(1); + + InitLSL(); + ((LSL_Api)m_LSL_Api).AttachToAvatar(attachmentPoint); + } + + public void osForceAttachToAvatarFromInventory(string itemName, int attachmentPoint) + { + CheckThreatLevel(ThreatLevel.High, "osForceAttachToAvatarFromInventory"); + + m_host.AddScriptLPS(1); + + ForceAttachToAvatarFromInventory(m_host.OwnerID, itemName, attachmentPoint); + } + + public void osForceAttachToOtherAvatarFromInventory(string rawAvatarId, string itemName, int attachmentPoint) + { + CheckThreatLevel(ThreatLevel.Severe, "osForceAttachToOtherAvatarFromInventory"); + + m_host.AddScriptLPS(1); + + UUID avatarId; + + if (!UUID.TryParse(rawAvatarId, out avatarId)) + return; + + ForceAttachToAvatarFromInventory(avatarId, itemName, attachmentPoint); + } + + public void ForceAttachToAvatarFromInventory(UUID avatarId, string itemName, int attachmentPoint) + { + IAttachmentsModule attachmentsModule = m_ScriptEngine.World.AttachmentsModule; + + if (attachmentsModule == null) + return; + + InitLSL(); + + TaskInventoryItem item = m_host.Inventory.GetInventoryItem(itemName); + + if (item == null) + { + ((LSL_Api)m_LSL_Api).llSay(0, string.Format("Could not find object '{0}'", itemName)); + throw new Exception(String.Format("The inventory item '{0}' could not be found", itemName)); + } + + if (item.InvType != (int)InventoryType.Object) + { + // FIXME: Temporary null check for regression tests since they dont' have the infrastructure to set + // up the api reference. + if (m_LSL_Api != null) + ((LSL_Api)m_LSL_Api).llSay(0, string.Format("Unable to attach, item '{0}' is not an object.", itemName)); + + throw new Exception(String.Format("The inventory item '{0}' is not an object", itemName)); + + return; + } + + ScenePresence sp = World.GetScenePresence(avatarId); + + if (sp == null) + return; + + InventoryItemBase newItem = World.MoveTaskInventoryItem(sp.UUID, UUID.Zero, m_host, item.ItemID); + + if (newItem == null) + { + m_log.ErrorFormat( + "[OSSL API]: Could not create user inventory item {0} for {1}, attach point {2} in {3}", + itemName, m_host.Name, attachmentPoint, World.Name); + + return; + } + + attachmentsModule.RezSingleAttachmentFromInventory(sp, newItem.ID, (uint)attachmentPoint); + } + + public void osForceDetachFromAvatar() + { + CheckThreatLevel(ThreatLevel.High, "osForceDetachFromAvatar"); + + m_host.AddScriptLPS(1); + + InitLSL(); + ((LSL_Api)m_LSL_Api).DetachFromAvatar(); + } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Listener.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Listener.cs index 93e0261da6..efa86fc0e0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Listener.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/Listener.cs @@ -88,13 +88,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins public Object[] GetSerializationData(UUID itemID) { - return m_commsPlugin.GetSerializationData(itemID); + if (m_commsPlugin != null) + return m_commsPlugin.GetSerializationData(itemID); + else + return new Object[]{}; } public void CreateFromData(uint localID, UUID itemID, UUID hostID, Object[] data) { - m_commsPlugin.CreateFromData(localID, itemID, hostID, data); + if (m_commsPlugin != null) + m_commsPlugin.CreateFromData(localID, itemID, hostID, data); } } } \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs index 1373971fe1..19f3ce191c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/Plugins/SensorRepeat.cs @@ -308,7 +308,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins } SceneObjectPart SensePoint = ts.host; - Vector3 fromRegionPos = SensePoint.AbsolutePosition; + Vector3 fromRegionPos = SensePoint.GetWorldPosition(); // pre define some things to avoid repeated definitions in the loop body Vector3 toRegionPos; @@ -323,13 +323,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins Quaternion q = SensePoint.GetWorldRotation(); // non-attached prim Sensor *always* uses World rotation! if (SensePoint.ParentGroup.IsAttachment) { - // In attachments, the sensor cone always orients with the + // In attachments, rotate the sensor cone with the // avatar rotation. This may include a nonzero elevation if // in mouselook. + // This will not include the rotation and position of the + // attachment point (e.g. your head when a sensor is in your + // hair attached to your scull. Your hair will turn with + // your head but the sensor will stay with your (global) + // avatar rotation and position. + // Position of a sensor in a child prim attached to an avatar + // will be still wrong. ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); fromRegionPos = avatar.AbsolutePosition; q = avatar.Rotation; } + LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W); LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r); double mag_fwd = LSL_Types.Vector3.Mag(forward_dir); @@ -441,14 +449,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins return sensedEntities; SceneObjectPart SensePoint = ts.host; - Vector3 fromRegionPos = SensePoint.AbsolutePosition; + Vector3 fromRegionPos = SensePoint.GetWorldPosition(); - Quaternion q = SensePoint.RotationOffset; + Quaternion q = SensePoint.GetWorldRotation(); if (SensePoint.ParentGroup.IsAttachment) { - // In attachments, the sensor cone always orients with the + // In attachments, rotate the sensor cone with the // avatar rotation. This may include a nonzero elevation if // in mouselook. + // This will not include the rotation and position of the + // attachment point (e.g. your head when a sensor is in your + // hair attached to your scull. Your hair will turn with + // your head but the sensor will stay with your (global) + // avatar rotation and position. + // Position of a sensor in a child prim attached to an avatar + // will be still wrong. ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar); if (avatar == null) return sensedEntities; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs index 40ae495613..af352589ff 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/ILSL_Api.cs @@ -105,6 +105,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_Integer llFloor(double f); void llForceMouselook(int mouselook); LSL_Float llFrand(double mag); + LSL_Key llGenerateKey(); LSL_Vector llGetAccel(); LSL_Integer llGetAgentInfo(string id); LSL_String llGetAgentLanguage(string id); @@ -150,7 +151,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_Rotation llGetLocalRot(); LSL_Float llGetMass(); LSL_Float llGetMassMKS(); - void llGetNextEmail(string address, string subject); + LSL_Integer llGetMemoryLimit(); + void llGetNextEmail(string address, string subject); LSL_String llGetNotecardLine(string name, int line); LSL_Key llGetNumberOfNotecardLines(string name); LSL_Integer llGetNumberOfPrims(); @@ -188,6 +190,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_String llGetScriptName(); LSL_Integer llGetScriptState(string name); LSL_String llGetSimulatorHostname(); + LSL_Integer llGetSPMaxMemory(); LSL_Integer llGetStartParameter(); LSL_Integer llGetStatus(int status); LSL_String llGetSubString(string src, int start, int end); @@ -323,6 +326,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void llSay(int channelID, string text); void llScaleTexture(double u, double v, int face); LSL_Integer llScriptDanger(LSL_Vector pos); + void llScriptProfiler(LSL_Integer flag); LSL_Key llSendRemoteData(string channel, string dest, int idata, string sdata); void llSensor(string name, string id, int type, double range, double arc); void llSensorRemove(); @@ -347,6 +351,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void llSetLinkTexture(int linknumber, string texture, int face); void llSetLinkTextureAnim(int linknum, int mode, int face, int sizex, int sizey, double start, double length, double rate); void llSetLocalRot(LSL_Rotation rot); + LSL_Integer llSetMemoryLimit(LSL_Integer limit); void llSetObjectDesc(string desc); void llSetObjectName(string name); void llSetObjectPermMask(int mask, int value); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs index 444a681b55..1facc96d0c 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Interface/IOSSL_Api.cs @@ -98,6 +98,41 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void osAvatarPlayAnimation(string avatar, string animation); void osAvatarStopAnimation(string avatar, string animation); + // Attachment commands + + /// + /// Attach the object containing this script to the avatar that owns it without asking for PERMISSION_ATTACH + /// + /// The attachment point. For example, ATTACH_CHEST + void osForceAttachToAvatar(int attachment); + + /// + /// Attach an inventory item in the object containing this script to the avatar that owns it without asking for PERMISSION_ATTACH + /// + /// + /// Nothing happens if the owner is not in the region. + /// + /// Tha name of the item. If this is not found then a warning is said to the owner + /// The attachment point. For example, ATTACH_CHEST + void osForceAttachToAvatarFromInventory(string itemName, int attachment); + + /// + /// Attach an inventory item in the object containing this script to any avatar in the region without asking for PERMISSION_ATTACH + /// + /// + /// Nothing happens if the avatar is not in the region. + /// + /// The UUID of the avatar to which to attach. Nothing happens if this is not a UUID + /// The name of the item. If this is not found then a warning is said to the owner + /// The attachment point. For example, ATTACH_CHEST + void osForceAttachToOtherAvatarFromInventory(string rawAvatarId, string itemName, int attachmentPoint); + + /// + /// Detach the object containing this script from the avatar it is attached to without checking for PERMISSION_ATTACH + /// + /// Nothing happens if the object is not attached. + void osForceDetachFromAvatar(); + //texture draw functions string osMovePen(string drawList, int x, int y); string osDrawLine(string drawList, int startX, int startY, int endX, int endY); @@ -203,11 +238,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces void osNpcSetRot(LSL_Key npc, rotation rot); void osNpcStopMoveToTarget(LSL_Key npc); void osNpcSay(key npc, string message); + void osNpcSay(key npc, int channel, string message); + void osNpcShout(key npc, int channel, string message); void osNpcSit(key npc, key target, int options); void osNpcStand(LSL_Key npc); void osNpcRemove(key npc); void osNpcPlayAnimation(LSL_Key npc, string animation); void osNpcStopAnimation(LSL_Key npc, string animation); + void osNpcTouch(LSL_Key npcLSL_Key, LSL_Key object_key, LSL_Integer link_num); + void osNpcWhisper(key npc, int channel, string message); LSL_Key osOwnerSaveAppearance(string notecard); LSL_Key osAgentSaveAppearance(key agentId, string notecard); @@ -234,5 +273,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Interfaces LSL_Integer osInviteToGroup(LSL_Key agentId); LSL_Integer osEjectFromGroup(LSL_Key agentId); + + void osSetTerrainTexture(int level, LSL_Key texture); + void osSetTerrainTextureHeight(int corner, double low, double high); } } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs index ad4f70c21b..a08cc421cf 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Constants.cs @@ -383,6 +383,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int PRIM_SCULPT_FLAG_INVERT = 64; public const int PRIM_SCULPT_FLAG_MIRROR = 128; + public const int PROFILE_NONE = 0; + public const int PROFILE_SCRIPT_MEMORY = 1; + public const int MASK_BASE = 0; public const int MASK_OWNER = 1; public const int MASK_GROUP = 2; @@ -641,6 +644,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase public const int OS_NPC_FLY = 0; public const int OS_NPC_NO_FLY = 1; public const int OS_NPC_LAND_AT_TARGET = 2; + public const int OS_NPC_RUNNING = 4; public const int OS_NPC_SIT_NOW = 0; diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs index 2f8e1692ef..89b6eff417 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/LSL_Stub.cs @@ -165,11 +165,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_LSL_Functions.llBreakLink(linknum); } - public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) - { - return m_LSL_Functions.llCastRay(start, end, options); - } - public LSL_Integer llCeil(double f) { return m_LSL_Functions.llCeil(f); @@ -376,6 +371,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llFrand(mag); } + public LSL_Key llGenerateKey() + { + return m_LSL_Functions.llGenerateKey(); + } + public LSL_Vector llGetAccel() { return m_LSL_Functions.llGetAccel(); @@ -591,6 +591,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llGetMassMKS(); } + public LSL_Integer llGetMemoryLimit() + { + return m_LSL_Functions.llGetMemoryLimit(); + } + public void llGetNextEmail(string address, string subject) { m_LSL_Functions.llGetNextEmail(address, subject); @@ -781,6 +786,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llGetSimulatorHostname(); } + public LSL_Integer llGetSPMaxMemory() + { + return m_LSL_Functions.llGetSPMaxMemory(); + } + public LSL_Integer llGetStartParameter() { return m_LSL_Functions.llGetStartParameter(); @@ -956,6 +966,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llRequestDisplayName(id); } + public LSL_List llCastRay(LSL_Vector start, LSL_Vector end, LSL_List options) + { + return m_LSL_Functions.llCastRay(start, end, options); + } + public void llLinkParticleSystem(int linknum, LSL_List rules) { m_LSL_Functions.llLinkParticleSystem(linknum, rules); @@ -1450,6 +1465,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase return m_LSL_Functions.llScriptDanger(pos); } + public void llScriptProfiler(LSL_Integer flags) + { + m_LSL_Functions.llScriptProfiler(flags); + } + public LSL_Key llSendRemoteData(string channel, string dest, int idata, string sdata) { return m_LSL_Functions.llSendRemoteData(channel, dest, idata, sdata); @@ -1565,6 +1585,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_LSL_Functions.llSetLocalRot(rot); } + public LSL_Integer llSetMemoryLimit(LSL_Integer limit) + { + return m_LSL_Functions.llSetMemoryLimit(limit); + } + public void llSetObjectDesc(string desc) { m_LSL_Functions.llSetObjectDesc(desc); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs index 680cefb4e0..b40bdf0b17 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs @@ -289,8 +289,29 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_OSSL_Functions.osAvatarStopAnimation(avatar, animation); } + // Avatar functions - //Texture Draw functions + public void osForceAttachToAvatar(int attachmentPoint) + { + m_OSSL_Functions.osForceAttachToAvatar(attachmentPoint); + } + + public void osForceAttachToAvatarFromInventory(string itemName, int attachmentPoint) + { + m_OSSL_Functions.osForceAttachToAvatarFromInventory(itemName, attachmentPoint); + } + + public void osForceAttachToOtherAvatarFromInventory(string rawAvatarId, string itemName, int attachmentPoint) + { + m_OSSL_Functions.osForceAttachToOtherAvatarFromInventory(rawAvatarId, itemName, attachmentPoint); + } + + public void osForceDetachFromAvatar() + { + m_OSSL_Functions.osForceDetachFromAvatar(); + } + + // Texture Draw functions public string osMovePen(string drawList, int x, int y) { @@ -569,6 +590,17 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_OSSL_Functions.osNpcSay(npc, message); } + public void osNpcSay(key npc, int channel, string message) + { + m_OSSL_Functions.osNpcSay(npc, channel, message); + } + + + public void osNpcShout(key npc, int channel, string message) + { + m_OSSL_Functions.osNpcShout(npc, channel, message); + } + public void osNpcSit(LSL_Key npc, LSL_Key target, int options) { m_OSSL_Functions.osNpcSit(npc, target, options); @@ -594,6 +626,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase m_OSSL_Functions.osNpcStopAnimation(npc, animation); } + public void osNpcWhisper(key npc, int channel, string message) + { + m_OSSL_Functions.osNpcWhisper(npc, channel, message); + } + + public void osNpcTouch(LSL_Key npcLSL_Key, LSL_Key object_key, LSL_Integer link_num) + { + m_OSSL_Functions.osNpcTouch(npcLSL_Key, object_key, link_num); + } + public LSL_Key osOwnerSaveAppearance(string notecard) { return m_OSSL_Functions.osOwnerSaveAppearance(notecard); @@ -878,5 +920,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase { return m_OSSL_Functions.osEjectFromGroup(agentId); } + + public void osSetTerrainTexture(int level, LSL_Key texture) + { + m_OSSL_Functions.osSetTerrainTexture(level, texture); + } + + public void osSetTerrainTextureHeight(int corner, double low, double high) + { + m_OSSL_Functions.osSetTerrainTextureHeight(corner, low, high); + } } } diff --git a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs index 8f2ec49cf4..17a0d69838 100644 --- a/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs @@ -31,6 +31,7 @@ using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.IO; +using System.Text; using Microsoft.CSharp; //using Microsoft.JScript; using Microsoft.VisualBasic; @@ -711,9 +712,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools // string filetext = System.Convert.ToBase64String(data); - System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); - - Byte[] buf = enc.GetBytes(filetext); + Byte[] buf = Encoding.ASCII.GetBytes(filetext); FileStream sfs = File.Create(assembly + ".text"); sfs.Write(buf, 0, buf.Length); @@ -804,8 +803,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools mapstring += String.Format("{0},{1},{2},{3}\n", k.Key, k.Value, v.Key, v.Value); } - System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); - Byte[] mapbytes = enc.GetBytes(mapstring); + Byte[] mapbytes = Encoding.ASCII.GetBytes(mapstring); FileStream mfs = File.Create(filename); mfs.Write(mapbytes, 0, mapbytes.Length); mfs.Close(); diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 5e68d698e2..8d92ba56b7 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -26,16 +26,17 @@ */ using System; -using System.IO; -using System.Diagnostics; //for [DebuggerNonUserCode] -using System.Runtime.Remoting; -using System.Runtime.Remoting.Lifetime; -using System.Threading; using System.Collections; using System.Collections.Generic; -using System.Security.Policy; -using System.Reflection; using System.Globalization; +using System.IO; +using System.Diagnostics; //for [DebuggerNonUserCode] +using System.Reflection; +using System.Runtime.Remoting; +using System.Runtime.Remoting.Lifetime; +using System.Security.Policy; +using System.Text; +using System.Threading; using System.Xml; using OpenMetaverse; using log4net; @@ -121,6 +122,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public bool Running { get; set; } + public bool Run { get; set; } + public bool Suspended { get { return m_Suspended; } @@ -216,6 +219,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_postOnRez = postOnRez; m_AttachedAvatar = part.ParentGroup.AttachedAvatar; m_RegionID = part.ParentGroup.Scene.RegionInfo.RegionID; + Run = true; if (part != null) { @@ -232,7 +236,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance foreach (string api in am.GetApis()) { m_Apis[api] = am.CreateApi(api); - m_Apis[api].Initialize(engine, part, LocalID, itemID); + m_Apis[api].Initialize(engine, part, ScriptTask); } try @@ -295,13 +299,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance using (FileStream fs = File.Open(savedState, FileMode.Open, FileAccess.Read, FileShare.None)) { - System.Text.UTF8Encoding enc = - new System.Text.UTF8Encoding(); - Byte[] data = new Byte[size]; fs.Read(data, 0, size); - xml = enc.GetString(data); + xml = Encoding.UTF8.GetString(data); ScriptSerializer.Deserialize(xml, this); @@ -330,16 +331,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance } else { - m_log.ErrorFormat( - "[SCRIPT INSTANCE]: Unable to load script state from assembly {0}: Memory limit exceeded", - assembly); + m_log.WarnFormat( + "[SCRIPT INSTANCE]: Unable to load script state file {0} for script {1} {2} in {3} {4} (assembly {5}). Memory limit exceeded", + savedState, ScriptName, ItemID, PrimName, ObjectID, assembly); } } catch (Exception e) { m_log.ErrorFormat( - "[SCRIPT INSTANCE]: Unable to load script state from assembly {0}. XML is {1}. Exception {2}{3}", - assembly, xml, e.Message, e.StackTrace); + "[SCRIPT INSTANCE]: Unable to load script state file {0} for script {1} {2} in {3} {4} (assembly {5}). XML is {6}. Exception {7}{8}", + savedState, ScriptName, ItemID, PrimName, ObjectID, assembly, xml, e.Message, e.StackTrace); } } // else @@ -354,10 +355,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public void Init() { - if (!m_startOnInit) return; + if (!m_startOnInit) + return; if (m_startedFromSavedState) { + if (!Run) + return; + Start(); if (m_postOnRez) { @@ -390,6 +395,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance } else { + if (!Run) + return; + Start(); PostEvent(new EventParams("state_entry", new Object[0], new DetectParams[0])); @@ -946,8 +954,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance try { FileStream fs = File.Create(Path.Combine(Path.GetDirectoryName(assembly), ItemID.ToString() + ".state")); - System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding(); - Byte[] buf = enc.GetBytes(xml); + Byte[] buf = Util.UTF8NoBomEncoding.GetBytes(xml); fs.Write(buf, 0, buf.Length); fs.Close(); } @@ -966,7 +973,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public IScriptApi GetApi(string name) { if (m_Apis.ContainsKey(name)) + { +// m_log.DebugFormat("[SCRIPT INSTANCE]: Found api {0} in {1}@{2}", name, ScriptName, PrimName); + return m_Apis[name]; + } + +// m_log.DebugFormat("[SCRIPT INSTANCE]: Did not find api {0} in {1}@{2}", name, ScriptName, PrimName); + return null; } diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptSerializer.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptSerializer.cs index bcdc7bf5dd..797bce3ce1 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptSerializer.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptSerializer.cs @@ -55,6 +55,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public static string Serialize(ScriptInstance instance) { bool running = instance.Running; + bool enabled = instance.Run; XmlDocument xmldoc = new XmlDocument(); @@ -77,6 +78,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance rootElement.AppendChild(run); + XmlElement run_enable = xmldoc.CreateElement("", "Run", ""); + run_enable.AppendChild(xmldoc.CreateTextNode( + enabled.ToString())); + + rootElement.AppendChild(run_enable); + Dictionary vars = instance.GetVars(); XmlElement variables = xmldoc.CreateElement("", "Variables", ""); @@ -225,6 +232,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance { object varValue; XmlNodeList partL = rootNode.ChildNodes; + instance.Run = true; foreach (XmlNode part in partL) { @@ -236,6 +244,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance case "Running": instance.Running=bool.Parse(part.InnerText); break; + case "Run": + instance.Run = bool.Parse(part.InnerText); + break; case "Variables": XmlNodeList varL = part.ChildNodes; foreach (XmlNode var in varL) diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs index e2d0db267f..c73e22ffdb 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiInventoryTests.cs @@ -63,7 +63,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests IConfig config = initConfigSource.AddConfig("XEngine"); config.Set("Enabled", "true"); - m_scene = SceneHelpers.SetupScene(); + m_scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(m_scene, initConfigSource); m_engine = new XEngine.XEngine(); @@ -91,7 +91,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests TaskInventoryHelpers.AddSceneObject(m_scene, so1.RootPart, inventoryItemName, itemId, userId); LSL_Api api = new LSL_Api(); - api.Initialize(m_engine, so1.RootPart, so1.RootPart.LocalId, so1.RootPart.UUID); + api.Initialize(m_engine, so1.RootPart, null); // Create a second object SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, userId, "so2", 0x100); @@ -124,7 +124,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests SceneObjectGroup so1 = SceneHelpers.CreateSceneObject(1, user1Id, "so1", 0x10); m_scene.AddSceneObject(so1); LSL_Api api = new LSL_Api(); - api.Initialize(m_engine, so1.RootPart, so1.RootPart.LocalId, so1.RootPart.UUID); + api.Initialize(m_engine, so1.RootPart, null); // Create an object embedded inside the first UUID itemId = TestHelpers.ParseTail(0x20); @@ -134,7 +134,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests SceneObjectGroup so2 = SceneHelpers.CreateSceneObject(1, user2Id, "so2", 0x100); m_scene.AddSceneObject(so2); LSL_Api api2 = new LSL_Api(); - api2.Initialize(m_engine, so2.RootPart, so2.RootPart.LocalId, so2.RootPart.UUID); + api2.Initialize(m_engine, so2.RootPart, null); // *** Firstly, we test where llAllowInventoryDrop() has not been called. *** api.llGiveInventory(so2.UUID.ToString(), inventoryItemName); diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs new file mode 100644 index 0000000000..2565ae7136 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiLinkingTests.cs @@ -0,0 +1,142 @@ +/* + * 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.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.AvatarFactory; +using OpenSim.Region.OptionalModules.World.NPC; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests for linking functions in LSL + /// + /// + /// This relates to LSL. Actual linking functionality should be tested in the main + /// OpenSim.Region.Framework.Scenes.Tests.SceneObjectLinkingTests. + /// + [TestFixture] + public class LSL_ApiLinkingTests + { + protected Scene m_scene; + protected XEngine.XEngine m_engine; + + [SetUp] + public void SetUp() + { + IConfigSource initConfigSource = new IniConfigSource(); + IConfig config = initConfigSource.AddConfig("XEngine"); + config.Set("Enabled", "true"); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules(m_scene, initConfigSource); + + m_engine = new XEngine.XEngine(); + m_engine.Initialise(initConfigSource); + m_engine.AddRegion(m_scene); + } + + [Test] + public void TestllCreateLink() + { + TestHelpers.InMethod(); + + UUID ownerId = TestHelpers.ParseTail(0x1); + + SceneObjectGroup grp1 = SceneHelpers.CreateSceneObject(2, ownerId, "grp1-", 0x10); + grp1.AbsolutePosition = new Vector3(10, 10, 10); + m_scene.AddSceneObject(grp1); + + // FIXME: This should really be a script item (with accompanying script) + TaskInventoryItem grp1Item + = TaskInventoryHelpers.AddNotecard( + m_scene, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); + grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; + + SceneObjectGroup grp2 = SceneHelpers.CreateSceneObject(2, ownerId, "grp2-", 0x20); + grp2.AbsolutePosition = new Vector3(20, 20, 20); + + // <180,0,0> + grp2.UpdateGroupRotationR(Quaternion.CreateFromEulers(180 * Utils.DEG_TO_RAD, 0, 0)); + + m_scene.AddSceneObject(grp2); + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item); + + apiGrp1.llCreateLink(grp2.UUID.ToString(), ScriptBaseClass.TRUE); + + Assert.That(grp1.Parts.Length, Is.EqualTo(4)); + Assert.That(grp2.IsDeleted, Is.True); + } + + [Test] + public void TestllBreakLink() + { + TestHelpers.InMethod(); + + UUID ownerId = TestHelpers.ParseTail(0x1); + + SceneObjectGroup grp1 = SceneHelpers.CreateSceneObject(2, ownerId, "grp1-", 0x10); + grp1.AbsolutePosition = new Vector3(10, 10, 10); + m_scene.AddSceneObject(grp1); + + // FIXME: This should really be a script item (with accompanying script) + TaskInventoryItem grp1Item + = TaskInventoryHelpers.AddNotecard( + m_scene, grp1.RootPart, "ncItem", TestHelpers.ParseTail(0x800), TestHelpers.ParseTail(0x900)); + + grp1Item.PermsMask |= ScriptBaseClass.PERMISSION_CHANGE_LINKS; + + LSL_Api apiGrp1 = new LSL_Api(); + apiGrp1.Initialize(m_engine, grp1.RootPart, grp1Item); + + apiGrp1.llBreakLink(2); + + Assert.That(grp1.Parts.Length, Is.EqualTo(1)); + + SceneObjectGroup grp2 = m_scene.GetSceneObjectGroup("grp1-Part1"); + Assert.That(grp2, Is.Not.Null); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs index 9cf9258571..c41d1e7acf 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs @@ -58,16 +58,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests IConfig config = initConfigSource.AddConfig("XEngine"); config.Set("Enabled", "true"); - Scene scene = SceneHelpers.SetupScene(); - SceneObjectPart part = SceneHelpers.AddSceneObject(scene); + Scene scene = new SceneHelpers().SetupScene(); + SceneObjectPart part = SceneHelpers.AddSceneObject(scene).RootPart; XEngine.XEngine engine = new XEngine.XEngine(); engine.Initialise(initConfigSource); engine.AddRegion(scene); m_lslApi = new LSL_Api(); - m_lslApi.Initialize(engine, part, part.LocalId, part.UUID); - + m_lslApi.Initialize(engine, part, null); } [Test] @@ -261,7 +260,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests TestHelpers.InMethod(); // Create Prim1. - Scene scene = SceneHelpers.SetupScene(); + Scene scene = new SceneHelpers().SetupScene(); string obj1Name = "Prim1"; UUID objUuid = new UUID("00000000-0000-0000-0000-000000000001"); SceneObjectPart part1 = diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs index 7573dfff5f..c8718d9603 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAppearanceTest.cs @@ -67,7 +67,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests config = initConfigSource.AddConfig("NPC"); config.Set("Enabled", "true"); - m_scene = SceneHelpers.SetupScene(); + m_scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(m_scene, initConfigSource, new AvatarFactoryModule(), new NPCModule()); m_engine = new XEngine.XEngine(); @@ -79,7 +79,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests /// Test creation of an NPC where the appearance data comes from a notecard /// [Test] - public void TestOsNpcCreateFromNotecard() + public void TestOsNpcCreateUsingAppearanceFromNotecard() { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); @@ -90,12 +90,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); sp.Appearance.AvatarHeight = newHeight; - SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10); SceneObjectPart part = so.RootPart; m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, part, part.LocalId, part.UUID); + osslApi.Initialize(m_engine, part, null); string notecardName = "appearanceNc"; osslApi.osOwnerSaveAppearance(notecardName); @@ -114,10 +114,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests /// Test creation of an NPC where the appearance data comes from an avatar already in the region. /// [Test] - public void TestOsNpcCreateFromAvatar() + public void TestOsNpcCreateUsingAppearanceFromAvatar() { TestHelpers.InMethod(); -// log4net.Config.XmlConfigurator.Configure(); +// TestHelpers.EnableLogging(); // Store an avatar with a different height from default in a notecard. UUID userId = TestHelpers.ParseTail(0x1); @@ -125,12 +125,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); sp.Appearance.AvatarHeight = newHeight; - SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10); SceneObjectPart part = so.RootPart; m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, part, part.LocalId, part.UUID); + osslApi.Initialize(m_engine, part, null); string notecardName = "appearanceNc"; osslApi.osOwnerSaveAppearance(notecardName); @@ -156,12 +156,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); sp.Appearance.AvatarHeight = newHeight; - SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10); SceneObjectPart part = so.RootPart; m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, part, part.LocalId, part.UUID); + osslApi.Initialize(m_engine, part, null); string notecardName = "appearanceNc"; @@ -197,12 +197,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, nonOwnerId); sp.Appearance.AvatarHeight = newHeight; - SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, ownerId); + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, ownerId, 0x10); SceneObjectPart part = so.RootPart; m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, part, part.LocalId, part.UUID); + osslApi.Initialize(m_engine, part, null); string notecardName = "appearanceNc"; diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs new file mode 100644 index 0000000000..5ed1f3d2cf --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiAttachmentTests.cs @@ -0,0 +1,231 @@ +/* + * 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.Reflection; +using System.Text; +using log4net; +using Nini.Config; +using NUnit.Framework; +using OpenMetaverse; +using OpenMetaverse.Assets; +using OpenMetaverse.StructuredData; +using OpenSim.Framework; +using OpenSim.Region.CoreModules.Avatar.Attachments; +using OpenSim.Region.CoreModules.Framework.InventoryAccess; +using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Services.Interfaces; +using OpenSim.Tests.Common; +using OpenSim.Tests.Common.Mock; + +namespace OpenSim.Region.ScriptEngine.Shared.Tests +{ + /// + /// Tests for OSSL attachment functions + /// + /// + /// TODO: Add tests for all functions + /// + [TestFixture] + public class OSSL_ApiAttachmentTests : OpenSimTestCase + { + protected Scene m_scene; + protected XEngine.XEngine m_engine; + + [SetUp] + public override void SetUp() + { + base.SetUp(); + + IConfigSource initConfigSource = new IniConfigSource(); + + IConfig xengineConfig = initConfigSource.AddConfig("XEngine"); + xengineConfig.Set("Enabled", "true"); + xengineConfig.Set("AllowOSFunctions", "true"); + xengineConfig.Set("OSFunctionThreatLevel", "Severe"); + + IConfig modulesConfig = initConfigSource.AddConfig("Modules"); + modulesConfig.Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + m_scene = new SceneHelpers().SetupScene(); + SceneHelpers.SetupSceneModules( + m_scene, initConfigSource, new AttachmentsModule(), new BasicInventoryAccessModule()); + + m_engine = new XEngine.XEngine(); + m_engine.Initialise(initConfigSource); + m_engine.AddRegion(m_scene); + } + + [Test] + public void TestOsForceAttachToAvatarFromInventory() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string taskInvObjItemName = "sphere"; + UUID taskInvObjItemId = UUID.Parse("00000000-0000-0000-0000-100000000000"); + AttachmentPoint attachPoint = AttachmentPoint.Chin; + + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, ua1.PrincipalID); + SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); + TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); + + new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); + +// SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ua1.PrincipalID); + + // Create an object embedded inside the first + TaskInventoryHelpers.AddSceneObject(m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID); + + osslApi.osForceAttachToAvatarFromInventory(taskInvObjItemName, (int)attachPoint); + + // Check scene presence status + Assert.That(sp.HasAttachments(), Is.True); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + Assert.That(attSo.Name, Is.EqualTo(taskInvObjItemName)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((uint)attachPoint)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + + // Check appearance status + List attachmentsInAppearance = sp.Appearance.GetAttachments(); + Assert.That(attachmentsInAppearance.Count, Is.EqualTo(1)); + Assert.That(sp.Appearance.GetAttachpoint(attachmentsInAppearance[0].ItemID), Is.EqualTo((uint)attachPoint)); + } + + /// + /// Make sure we can't force attach anything other than objects. + /// + [Test] + public void TestOsForceAttachToAvatarFromInventoryNotObject() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string taskInvObjItemName = "sphere"; + UUID taskInvObjItemId = UUID.Parse("00000000-0000-0000-0000-100000000000"); + AttachmentPoint attachPoint = AttachmentPoint.Chin; + + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, 0x1); + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, ua1.PrincipalID); + SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); + TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); + + new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); + + // Create an object embedded inside the first + TaskInventoryHelpers.AddNotecard( + m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, TestHelpers.ParseTail(0x900)); + + bool exceptionCaught = false; + + try + { + osslApi.osForceAttachToAvatarFromInventory(taskInvObjItemName, (int)attachPoint); + } + catch (Exception) + { + exceptionCaught = true; + } + + Assert.That(exceptionCaught, Is.True); + + // Check scene presence status + Assert.That(sp.HasAttachments(), Is.False); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(0)); + + // Check appearance status + List attachmentsInAppearance = sp.Appearance.GetAttachments(); + Assert.That(attachmentsInAppearance.Count, Is.EqualTo(0)); + } + + [Test] + public void TestOsForceAttachToOtherAvatarFromInventory() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + string taskInvObjItemName = "sphere"; + UUID taskInvObjItemId = UUID.Parse("00000000-0000-0000-0000-100000000000"); + AttachmentPoint attachPoint = AttachmentPoint.Chin; + + UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(m_scene, "user", "one", 0x1, "pass"); + UserAccount ua2 = UserAccountHelpers.CreateUserWithInventory(m_scene, "user", "two", 0x2, "pass"); + + ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, ua1); + SceneObjectGroup inWorldObj = SceneHelpers.AddSceneObject(m_scene, "inWorldObj", ua1.PrincipalID); + TaskInventoryItem scriptItem = TaskInventoryHelpers.AddScript(m_scene, inWorldObj.RootPart); + + new LSL_Api().Initialize(m_engine, inWorldObj.RootPart, scriptItem); + OSSL_Api osslApi = new OSSL_Api(); + osslApi.Initialize(m_engine, inWorldObj.RootPart, scriptItem); + + // Create an object embedded inside the first + TaskInventoryHelpers.AddSceneObject(m_scene, inWorldObj.RootPart, taskInvObjItemName, taskInvObjItemId, ua1.PrincipalID); + + ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, ua2); + + osslApi.osForceAttachToOtherAvatarFromInventory(sp2.UUID.ToString(), taskInvObjItemName, (int)attachPoint); + + // Check scene presence status + Assert.That(sp.HasAttachments(), Is.False); + List attachments = sp.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(0)); + + Assert.That(sp2.HasAttachments(), Is.True); + List attachments2 = sp2.GetAttachments(); + Assert.That(attachments2.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments2[0]; + Assert.That(attSo.Name, Is.EqualTo(taskInvObjItemName)); + Assert.That(attSo.OwnerID, Is.EqualTo(ua2.PrincipalID)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((uint)attachPoint)); + Assert.That(attSo.IsAttachment); + Assert.That(attSo.UsesPhysics, Is.False); + Assert.That(attSo.IsTemporary, Is.False); + + // Check appearance status + List attachmentsInAppearance = sp.Appearance.GetAttachments(); + Assert.That(attachmentsInAppearance.Count, Is.EqualTo(0)); + + List attachmentsInAppearance2 = sp2.Appearance.GetAttachments(); + Assert.That(attachmentsInAppearance2.Count, Is.EqualTo(1)); + Assert.That(sp2.Appearance.GetAttachpoint(attachmentsInAppearance2[0].ItemID), Is.EqualTo((uint)attachPoint)); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs index 9d9fc514a3..25679a65c0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/OSSL_ApiNpcTests.cs @@ -52,14 +52,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests /// Tests for OSSL NPC API /// [TestFixture] - public class OSSL_NpcApiAppearanceTest + public class OSSL_NpcApiAppearanceTest : OpenSimTestCase { protected Scene m_scene; protected XEngine.XEngine m_engine; [SetUp] - public void SetUp() + public override void SetUp() { + base.SetUp(); + IConfigSource initConfigSource = new IniConfigSource(); IConfig config = initConfigSource.AddConfig("XEngine"); config.Set("Enabled", "true"); @@ -68,7 +70,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests config = initConfigSource.AddConfig("NPC"); config.Set("Enabled", "true"); - m_scene = SceneHelpers.SetupScene(); + m_scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(m_scene, initConfigSource, new AvatarFactoryModule(), new NPCModule()); m_engine = new XEngine.XEngine(); @@ -95,19 +97,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); sp.Appearance.AvatarHeight = newHeight; - SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10); SceneObjectPart part = so.RootPart; m_scene.AddSceneObject(so); - SceneObjectGroup otherSo = SceneHelpers.CreateSceneObject(1, otherUserId); + SceneObjectGroup otherSo = SceneHelpers.CreateSceneObject(1, otherUserId, 0x20); SceneObjectPart otherPart = otherSo.RootPart; m_scene.AddSceneObject(otherSo); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, part, part.LocalId, part.UUID); + osslApi.Initialize(m_engine, part, null); OSSL_Api otherOsslApi = new OSSL_Api(); - otherOsslApi.Initialize(m_engine, otherPart, otherPart.LocalId, otherPart.UUID); + otherOsslApi.Initialize(m_engine, otherPart, null); string notecardName = "appearanceNc"; osslApi.osOwnerSaveAppearance(notecardName); @@ -146,12 +148,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, userId); sp.Appearance.AvatarHeight = newHeight; - SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId); + SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, userId, 0x10); SceneObjectPart part = so.RootPart; m_scene.AddSceneObject(so); OSSL_Api osslApi = new OSSL_Api(); - osslApi.Initialize(m_engine, part, part.LocalId, part.UUID); + osslApi.Initialize(m_engine, part, null); string notecardName = "appearanceNc"; osslApi.osOwnerSaveAppearance(notecardName); diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs index 7d7bd82778..f247a0be42 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEngineTest.cs @@ -58,9 +58,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine.Tests // Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); m_xEngine = new XEngine(); - // Necessary to stop serialization complaining - WorldCommModule wcModule = new WorldCommModule(); - IniConfigSource configSource = new IniConfigSource(); IConfig startupConfig = configSource.AddConfig("Startup"); @@ -68,13 +65,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine.Tests IConfig xEngineConfig = configSource.AddConfig("XEngine"); xEngineConfig.Set("Enabled", "true"); + xEngineConfig.Set("StartDelay", "0"); // These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call // to AssemblyResolver.OnAssemblyResolve fails. xEngineConfig.Set("AppDomainLoading", "false"); - m_scene = SceneHelpers.SetupScene("My Test", UUID.Random(), 1000, 1000, null, configSource); - SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine, wcModule); + m_scene = new SceneHelpers().SetupScene("My Test", UUID.Random(), 1000, 1000, configSource); + SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine); m_scene.StartScripts(); } diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 2a01fc4070..d763063536 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -63,6 +63,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// + /// Control the printing of certain debug messages. + /// + /// + /// If DebugLevel >= 1, then we log every time that a script is started. + /// +// public int DebugLevel { get; set; } + private SmartThreadPool m_ThreadPool; private int m_MaxScriptQueue; private Scene m_Scene; @@ -70,7 +78,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine private IConfigSource m_ConfigSource = null; private ICompiler m_Compiler; private int m_MinThreads; - private int m_MaxThreads ; + private int m_MaxThreads; + + /// + /// Amount of time to delay before starting. + /// + private int m_StartDelay; + private int m_IdleTimeout; private int m_StackSize; private int m_SleepTime; @@ -284,14 +298,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine AppDomain.CurrentDomain.AssemblyResolve += OnAssemblyResolve; - m_log.InfoFormat("[XEngine] Initializing scripts in region {0}", - scene.RegionInfo.RegionName); m_Scene = scene; + m_log.InfoFormat("[XEngine]: Initializing scripts in region {0}", m_Scene.RegionInfo.RegionName); m_MinThreads = m_ScriptConfig.GetInt("MinThreads", 2); m_MaxThreads = m_ScriptConfig.GetInt("MaxThreads", 100); m_IdleTimeout = m_ScriptConfig.GetInt("IdleTimeout", 60); string priority = m_ScriptConfig.GetString("Priority", "BelowNormal"); + m_StartDelay = m_ScriptConfig.GetInt("StartDelay", 15000); m_MaxScriptQueue = m_ScriptConfig.GetInt("MaxScriptEventQueue",300); m_StackSize = m_ScriptConfig.GetInt("ThreadStackSize", 262144); m_SleepTime = m_ScriptConfig.GetInt("MaintenanceInterval", 10) * 1000; @@ -389,8 +403,41 @@ namespace OpenSim.Region.ScriptEngine.XEngine "Starts all stopped scripts." + "If a is given then only that script will be started. Otherwise, all suitable scripts are started.", (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); + +// MainConsole.Instance.Commands.AddCommand( +// "Debug", false, "debug xengine", "debug xengine []", +// "Turn on detailed xengine debugging.", +// "If level <= 0, then no extra logging is done.\n" +// + "If level >= 1, then we log every time that a script is started.", +// HandleDebugLevelCommand); } + /// + /// Change debug level + /// + /// + /// +// private void HandleDebugLevelCommand(string module, string[] args) +// { +// if (args.Length == 3) +// { +// int newDebug; +// if (int.TryParse(args[2], out newDebug)) +// { +// DebugLevel = newDebug; +// MainConsole.Instance.OutputFormat("Debug level set to {0}", newDebug); +// } +// } +// else if (args.Length == 2) +// { +// MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel); +// } +// else +// { +// MainConsole.Instance.Output("Usage: debug xengine 0..1"); +// } +// } + /// /// Parse the raw item id into a script instance from the command params if it's present. /// @@ -799,35 +846,66 @@ namespace OpenSim.Region.ScriptEngine.XEngine int colon = firstline.IndexOf(':'); if (firstline.Length > 2 && firstline.Substring(0, 2) == "//" && colon != -1) { - string engineName = firstline.Substring(2, colon-2); + string engineName = firstline.Substring(2, colon - 2); if (names.Contains(engineName)) { engine = engineName; - script = "//" + script.Substring(script.IndexOf(':')+1); + script = "//" + script.Substring(colon + 1); } else { if (engine == ScriptEngineName) { - SceneObjectPart part = - m_Scene.GetSceneObjectPart( - localID); - - TaskInventoryItem item = - part.Inventory.GetInventoryItem(itemID); + // If we are falling back on XEngine as the default engine, then only complain to the user + // if a script language has been explicitly set and it's one that we recognize or there are + // no non-whitespace characters after the colon. + // + // If the script is + // explicitly not allowed or the script is not in LSL then the user will be informed by a later compiler message. + // + // If the colon ends the line then we'll risk the false positive as this is more likely + // to signal a real scriptengine line where the user wants to use the default compile language. + // + // This avoids the overwhelming number of false positives where we're in this code because + // there's a colon in a comment in the first line of a script for entirely + // unrelated reasons (e.g. vim settings). + // + // TODO: A better fix would be to deprecate simple : detection and look for some less likely + // string to begin the comment (like #! in unix shell scripts). + bool warnRunningInXEngine = false; + string restOfFirstLine = firstline.Substring(colon + 1); - ScenePresence presence = - m_Scene.GetScenePresence( - item.OwnerID); + // FIXME: These are hardcoded because they are currently hardcoded in Compiler.cs + if (restOfFirstLine.StartsWith("c#") + || restOfFirstLine.StartsWith("vb") + || restOfFirstLine.StartsWith("lsl") + || restOfFirstLine.StartsWith("js") + || restOfFirstLine.StartsWith("yp") + || restOfFirstLine.Length == 0) + warnRunningInXEngine = true; - if (presence != null) + if (warnRunningInXEngine) { - presence.ControllingClient.SendAgentAlertMessage( - "Selected engine unavailable. "+ - "Running script on "+ - ScriptEngineName, - false); + SceneObjectPart part = + m_Scene.GetSceneObjectPart( + localID); + + TaskInventoryItem item = + part.Inventory.GetInventoryItem(itemID); + + ScenePresence presence = + m_Scene.GetScenePresence( + item.OwnerID); + + if (presence != null) + { + presence.ControllingClient.SendAgentAlertMessage( + "Selected engine unavailable. "+ + "Running script on "+ + ScriptEngineName, + false); + } } } } @@ -884,20 +962,31 @@ namespace OpenSim.Region.ScriptEngine.XEngine { if (m_InitialStartup) { - m_InitialStartup = false; - System.Threading.Thread.Sleep(15000); - - if (m_CompileQueue.Count == 0) - { - // No scripts on region, so won't get triggered later - // by the queue becoming empty so we trigger it here - m_Scene.EventManager.TriggerEmptyScriptCompileQueue(0, String.Empty); - } + // This delay exists to stop mono problems where script compilation and startup would stop the sim + // working properly for the session. + System.Threading.Thread.Sleep(m_StartDelay); } object[] o; + + int scriptsStarted = 0; + while (m_CompileQueue.Dequeue(out o)) - DoOnRezScript(o); + { + if (DoOnRezScript(o)) + { + scriptsStarted++; + + if (m_InitialStartup) + if (scriptsStarted % 50 == 0) + m_log.InfoFormat( + "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.RegionInfo.RegionName); + } + } + + if (m_InitialStartup) + m_log.InfoFormat( + "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.RegionInfo.RegionName); // NOTE: Despite having a lockless queue, this lock is required // to make sure there is never no compile thread while there @@ -905,12 +994,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine // due to a race condition // lock (m_CompileQueue) - { m_CurrentCompile = null; - } + m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount, m_ScriptErrorMessage); + m_ScriptFailCount = 0; + m_InitialStartup = false; return null; } @@ -1093,11 +1183,18 @@ namespace OpenSim.Region.ScriptEngine.XEngine AppDomain sandbox; if (m_AppDomainLoading) + { sandbox = AppDomain.CreateDomain( m_Scene.RegionInfo.RegionID.ToString(), evidence, appSetup); + m_AppDomains[appDomain].AssemblyResolve += + new ResolveEventHandler( + AssemblyResolver.OnAssemblyResolve); + } else + { sandbox = AppDomain.CurrentDomain; + } //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); @@ -1109,9 +1206,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_AppDomains[appDomain] = sandbox; - m_AppDomains[appDomain].AssemblyResolve += - new ResolveEventHandler( - AssemblyResolver.OnAssemblyResolve); m_DomainScripts[appDomain] = new List(); } catch (Exception e) @@ -1396,24 +1490,23 @@ namespace OpenSim.Region.ScriptEngine.XEngine return false; uuids = m_PrimObjects[localID]; - - foreach (UUID itemID in uuids) - { - IScriptInstance instance = null; - try + foreach (UUID itemID in uuids) { - if (m_Scripts.ContainsKey(itemID)) - instance = m_Scripts[itemID]; + IScriptInstance instance = null; + try + { + if (m_Scripts.ContainsKey(itemID)) + instance = m_Scripts[itemID]; + } + catch { /* ignore race conditions */ } + + if (instance != null) + { + instance.PostEvent(p); + result = true; + } } - catch { /* ignore race conditions */ } - - if (instance != null) - { - instance.PostEvent(p); - result = true; - } - } } return result; @@ -1539,6 +1632,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine } } + public void SetRunEnable(UUID instanceID, bool enable) + { + IScriptInstance instance = GetInstance(instanceID); + if (instance != null) + instance.Run = enable; + } + public bool GetScriptState(UUID itemID) { IScriptInstance instance = GetInstance(itemID); @@ -1573,7 +1673,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine { IScriptInstance instance = GetInstance(itemID); if (instance != null) - instance.Stop(0); + { + // Give the script some time to finish processing its last event. Simply aborting the script thread can + // cause issues on mono 2.6, 2.10 and possibly later where locks are not released properly on abort. + instance.Stop(1000); + } } public DetectParams GetDetectParams(UUID itemID, int idx) @@ -1671,12 +1775,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine public string GetXMLState(UUID itemID) { -// m_log.DebugFormat("[XEngine]: Getting XML state for {0}", itemID); +// m_log.DebugFormat("[XEngine]: Getting XML state for script instance {0}", itemID); IScriptInstance instance = GetInstance(itemID); if (instance == null) { -// m_log.DebugFormat("[XEngine]: Found no script for {0}, returning empty string", itemID); +// m_log.DebugFormat("[XEngine]: Found no script instance for {0}, returning empty string", itemID); return ""; } @@ -1749,14 +1853,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine FileMode.Open, FileAccess.Read)) { tfs.Read(tdata, 0, tdata.Length); - tfs.Close(); } - assem = new System.Text.ASCIIEncoding().GetString(tdata); + assem = Encoding.ASCII.GetString(tdata); } catch (Exception e) { - m_log.DebugFormat("[XEngine]: Unable to open script textfile {0}, reason: {1}", assemName+".text", e.Message); + m_log.ErrorFormat( + "[XEngine]: Unable to open script textfile {0}{1}, reason: {2}", + assemName, ".text", e.Message); } } } @@ -1773,16 +1878,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine using (FileStream fs = File.Open(assemName, FileMode.Open, FileAccess.Read)) { fs.Read(data, 0, data.Length); - fs.Close(); } assem = System.Convert.ToBase64String(data); } catch (Exception e) { - m_log.DebugFormat("[XEngine]: Unable to open script assembly {0}, reason: {1}", assemName, e.Message); + m_log.ErrorFormat( + "[XEngine]: Unable to open script assembly {0}, reason: {1}", assemName, e.Message); } - } } @@ -1795,9 +1899,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine using (StreamReader msr = new StreamReader(mfs)) { map = msr.ReadToEnd(); - msr.Close(); } - mfs.Close(); } } @@ -1833,6 +1935,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine public bool SetXMLState(UUID itemID, string xml) { +// m_log.DebugFormat("[XEngine]: Writing state for script item with ID {0}", itemID); + if (xml == String.Empty) return false; @@ -1893,31 +1997,61 @@ namespace OpenSim.Region.ScriptEngine.XEngine { using (FileStream fs = File.Create(path)) { +// m_log.DebugFormat("[XEngine]: Writing assembly file {0}", path); + fs.Write(filedata, 0, filedata.Length); - fs.Close(); } } catch (IOException ex) { // if there already exists a file at that location, it may be locked. - m_log.ErrorFormat("[XEngine]: File {0} already exists! {1}", path, ex.Message); + m_log.ErrorFormat("[XEngine]: Error whilst writing assembly file {0}, {1}", path, ex.Message); } + + string textpath = path + ".text"; try { - using (FileStream fs = File.Create(path + ".text")) + using (FileStream fs = File.Create(textpath)) { using (StreamWriter sw = new StreamWriter(fs)) { +// m_log.DebugFormat("[XEngine]: Writing .text file {0}", textpath); + sw.Write(base64); - sw.Close(); } - fs.Close(); } } catch (IOException ex) { // if there already exists a file at that location, it may be locked. - m_log.ErrorFormat("[XEngine]: File {0} already exists! {1}", path, ex.Message); + m_log.ErrorFormat("[XEngine]: Error whilst writing .text file {0}, {1}", textpath, ex.Message); + } + } + + XmlNodeList mapL = rootE.GetElementsByTagName("LineMap"); + if (mapL.Count > 0) + { + XmlElement mapE = (XmlElement)mapL[0]; + + string mappath = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString()); + mappath = Path.Combine(mappath, mapE.GetAttribute("Filename")); + + try + { + using (FileStream mfs = File.Create(mappath)) + { + using (StreamWriter msw = new StreamWriter(mfs)) + { + // m_log.DebugFormat("[XEngine]: Writing linemap file {0}", mappath); + + msw.Write(mapE.InnerText); + } + } + } + catch (IOException ex) + { + // if there already exists a file at that location, it may be locked. + m_log.ErrorFormat("[XEngine]: Linemap file {0} already exists! {1}", mappath, ex.Message); } } } @@ -1931,43 +2065,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine { using (StreamWriter ssw = new StreamWriter(sfs)) { +// m_log.DebugFormat("[XEngine]: Writing state file {0}", statepath); + ssw.Write(stateE.OuterXml); - ssw.Close(); } - sfs.Close(); } } catch (IOException ex) { // if there already exists a file at that location, it may be locked. - m_log.ErrorFormat("[XEngine]: File {0} already exists! {1}", statepath, ex.Message); - } - - XmlNodeList mapL = rootE.GetElementsByTagName("LineMap"); - if (mapL.Count > 0) - { - XmlElement mapE = (XmlElement)mapL[0]; - - string mappath = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString()); - mappath = Path.Combine(mappath, mapE.GetAttribute("Filename")); - - try - { - using (FileStream mfs = File.Create(mappath)) - { - using (StreamWriter msw = new StreamWriter(mfs)) - { - msw.Write(mapE.InnerText); - msw.Close(); - } - mfs.Close(); - } - } - catch (IOException ex) - { - // if there already exists a file at that location, it may be locked. - m_log.ErrorFormat("[XEngine]: File {0} already exists! {1}", statepath, ex.Message); - } + m_log.ErrorFormat("[XEngine]: Error whilst writing state file {0}, {1}", statepath, ex.Message); } return true; @@ -2001,47 +2108,61 @@ namespace OpenSim.Region.ScriptEngine.XEngine if (!topScripts.ContainsKey(si.LocalID)) topScripts[si.RootLocalID] = 0; -// long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; -// float framesElapsed = ticksElapsed / (18.1818 * TimeSpan.TicksPerMillisecond); - - // Execution time of the script adjusted by it's measurement period to make scripts started at - // different times comparable. -// float adjustedExecutionTime -// = (float)si.MeasurementPeriodExecutionTime -// / ((float)(tickNow - si.MeasurementPeriodTickStart) / ScriptInstance.MaxMeasurementPeriod) -// / TimeSpan.TicksPerMillisecond; - - long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; - - // Avoid divide by zerp - if (ticksElapsed == 0) - ticksElapsed = 1; - - // Scale execution time to the ideal 55 fps frame time for these reasons. - // - // 1) XEngine does not execute scripts per frame, unlike other script engines. Hence, there is no - // 'script execution time per frame', which is the original purpose of this value. - // - // 2) Giving the raw execution times is misleading since scripts start at different times, making - // it impossible to compare scripts. - // - // 3) Scaling the raw execution time to the time that the script has been running is better but - // is still misleading since a script that has just been rezzed may appear to have been running - // for much longer. - // - // 4) Hence, we scale execution time to an idealised frame time (55 fps). This is also not perfect - // since the figure does not represent actual execution time and very hard running scripts will - // never exceed 18ms (though this is a very high number for script execution so is a warning sign). - float adjustedExecutionTime - = ((float)si.MeasurementPeriodExecutionTime / ticksElapsed) * 18.1818f; - - topScripts[si.RootLocalID] += adjustedExecutionTime; + topScripts[si.RootLocalID] += CalculateAdjustedExectionTime(si, tickNow); } } return topScripts; } + public float GetScriptExecutionTime(List itemIDs) + { + if (itemIDs == null|| itemIDs.Count == 0) + { + return 0.0f; + } + float time = 0.0f; + long tickNow = Util.EnvironmentTickCount(); + IScriptInstance si; + // Calculate the time for all scripts that this engine is executing + // Ignore any others + foreach (UUID id in itemIDs) + { + si = GetInstance(id); + if (si != null && si.Running) + { + time += CalculateAdjustedExectionTime(si, tickNow); + } + } + return time; + } + + private float CalculateAdjustedExectionTime(IScriptInstance si, long tickNow) + { + long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; + + // Avoid divide by zero + if (ticksElapsed == 0) + ticksElapsed = 1; + + // Scale execution time to the ideal 55 fps frame time for these reasons. + // + // 1) XEngine does not execute scripts per frame, unlike other script engines. Hence, there is no + // 'script execution time per frame', which is the original purpose of this value. + // + // 2) Giving the raw execution times is misleading since scripts start at different times, making + // it impossible to compare scripts. + // + // 3) Scaling the raw execution time to the time that the script has been running is better but + // is still misleading since a script that has just been rezzed may appear to have been running + // for much longer. + // + // 4) Hence, we scale execution time to an idealised frame time (55 fps). This is also not perfect + // since the figure does not represent actual execution time and very hard running scripts will + // never exceed 18ms (though this is a very high number for script execution so is a warning sign). + return ((float)si.MeasurementPeriodExecutionTime / ticksElapsed) * 18.1818f; + } + public void SuspendScript(UUID itemID) { // m_log.DebugFormat("[XEngine]: Received request to suspend script with ID {0}", itemID); diff --git a/OpenSim/Region/UserStatistics/WebStatsModule.cs b/OpenSim/Region/UserStatistics/WebStatsModule.cs index b9ba4bc797..faf746fac0 100644 --- a/OpenSim/Region/UserStatistics/WebStatsModule.cs +++ b/OpenSim/Region/UserStatistics/WebStatsModule.cs @@ -90,7 +90,7 @@ namespace OpenSim.Region.UserStatistics dbConn = new SqliteConnection("URI=file:LocalUserStatistics.db,version=3"); dbConn.Open(); - CheckAndUpdateDatabase(dbConn); + CreateTables(dbConn); Prototype_distributor protodep = new Prototype_distributor(); Updater_distributor updatedep = new Updater_distributor(); @@ -131,7 +131,7 @@ namespace OpenSim.Region.UserStatistics } } - public void ReceiveClassicSimStatsPacket(SimStats stats) + private void ReceiveClassicSimStatsPacket(SimStats stats) { if (!enabled) { @@ -163,7 +163,7 @@ namespace OpenSim.Region.UserStatistics } } - public Hashtable HandleUnknownCAPSRequest(Hashtable request) + private Hashtable HandleUnknownCAPSRequest(Hashtable request) { //string regpath = request["uri"].ToString(); int response_code = 200; @@ -178,7 +178,7 @@ namespace OpenSim.Region.UserStatistics return responsedata; } - public Hashtable HandleStatsRequest(Hashtable request) + private Hashtable HandleStatsRequest(Hashtable request) { lastHit = System.Environment.TickCount; Hashtable responsedata = new Hashtable(); @@ -237,36 +237,12 @@ namespace OpenSim.Region.UserStatistics return responsedata; } - - public void CheckAndUpdateDatabase(SqliteConnection db) - { - lock (db) - { - // TODO: FIXME: implement stats migrations - const string SQL = @"SELECT * FROM migrations LIMIT 1"; - using (SqliteCommand cmd = new SqliteCommand(SQL, db)) - { - try - { - cmd.ExecuteNonQuery(); - } - catch (SqliteSyntaxException) - { - CreateTables(db); - } - } - } - } - - public void CreateTables(SqliteConnection db) + private void CreateTables(SqliteConnection db) { using (SqliteCommand createcmd = new SqliteCommand(SQL_STATS_TABLE_CREATE, db)) { createcmd.ExecuteNonQuery(); - - createcmd.CommandText = SQL_MIGRA_TABLE_CREATE; - createcmd.ExecuteNonQuery(); } } @@ -301,22 +277,23 @@ namespace OpenSim.Region.UserStatistics get { return true; } } - public void OnRegisterCaps(UUID agentID, Caps caps) + private void OnRegisterCaps(UUID agentID, Caps caps) { // m_log.DebugFormat("[WEB STATS MODULE]: OnRegisterCaps: agentID {0} caps {1}", agentID, caps); string capsPath = "/CAPS/VS/" + UUID.Random(); - caps.RegisterHandler("ViewerStats", - new RestStreamHandler("POST", capsPath, - delegate(string request, string path, string param, - IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) - { - return ViewerStatsReport(request, path, param, - agentID, caps); - })); + caps.RegisterHandler( + "ViewerStats", + new RestStreamHandler( + "POST", + capsPath, + (request, path, param, httpRequest, httpResponse) + => ViewerStatsReport(request, path, param, agentID, caps), + "ViewerStats", + agentID.ToString())); } - public void OnDeRegisterCaps(UUID agentID, Caps caps) + private void OnDeRegisterCaps(UUID agentID, Caps caps) { } @@ -336,7 +313,7 @@ namespace OpenSim.Region.UserStatistics } } - public void OnMakeRootAgent(ScenePresence agent) + private void OnMakeRootAgent(ScenePresence agent) { UUID regionUUID = GetRegionUUIDFromHandle(agent.RegionHandle); @@ -365,11 +342,11 @@ namespace OpenSim.Region.UserStatistics } } - public void OnMakeChildAgent(ScenePresence agent) + private void OnMakeChildAgent(ScenePresence agent) { } - public void OnClientClosed(UUID agentID, Scene scene) + private void OnClientClosed(UUID agentID, Scene scene) { lock (m_sessions) { @@ -380,7 +357,7 @@ namespace OpenSim.Region.UserStatistics } } - public string readLogLines(int amount) + private string readLogLines(int amount) { Encoding encoding = Encoding.ASCII; int sizeOfChar = encoding.GetByteCount("\n"); @@ -418,7 +395,7 @@ namespace OpenSim.Region.UserStatistics return encoding.GetString(buffer); } - public UUID GetRegionUUIDFromHandle(ulong regionhandle) + private UUID GetRegionUUIDFromHandle(ulong regionhandle) { lock (m_scenes) { @@ -441,17 +418,17 @@ namespace OpenSim.Region.UserStatistics /// /// /// - public string ViewerStatsReport(string request, string path, string param, + private string ViewerStatsReport(string request, string path, string param, UUID agentID, Caps caps) { // m_log.DebugFormat("[WEB STATS MODULE]: Received viewer starts report from {0}", agentID); - UpdateUserStats(ParseViewerStats(request,agentID), dbConn); + UpdateUserStats(ParseViewerStats(request, agentID), dbConn); return String.Empty; } - public UserSessionID ParseViewerStats(string request, UUID agentID) + private UserSessionID ParseViewerStats(string request, UUID agentID) { UserSessionID uid = new UserSessionID(); UserSessionData usd; @@ -592,14 +569,14 @@ namespace OpenSim.Region.UserStatistics return uid; } - public void UpdateUserStats(UserSessionID uid, SqliteConnection db) + private void UpdateUserStats(UserSessionID uid, SqliteConnection db) { if (uid.session_id == UUID.Zero) return; lock (db) { - using (SqliteCommand updatecmd = new SqliteCommand(SQL_STATS_TABLE_UPDATE, db)) + using (SqliteCommand updatecmd = new SqliteCommand(SQL_STATS_TABLE_INSERT, db)) { updatecmd.Parameters.Add(new SqliteParameter(":session_id", uid.session_data.session_id.ToString())); updatecmd.Parameters.Add(new SqliteParameter(":agent_id", uid.session_data.agent_id.ToString())); @@ -648,44 +625,26 @@ namespace OpenSim.Region.UserStatistics updatecmd.Parameters.Add(new SqliteParameter(":f_dropped", uid.session_data.f_dropped)); updatecmd.Parameters.Add(new SqliteParameter(":f_failed_resends", uid.session_data.f_failed_resends)); updatecmd.Parameters.Add(new SqliteParameter(":f_invalid", uid.session_data.f_invalid)); - updatecmd.Parameters.Add(new SqliteParameter(":f_off_circuit", uid.session_data.f_off_circuit)); updatecmd.Parameters.Add(new SqliteParameter(":f_resent", uid.session_data.f_resent)); updatecmd.Parameters.Add(new SqliteParameter(":f_send_packet", uid.session_data.f_send_packet)); - - updatecmd.Parameters.Add(new SqliteParameter(":session_key", uid.session_data.session_id.ToString())); - updatecmd.Parameters.Add(new SqliteParameter(":agent_key", uid.session_data.agent_id.ToString())); - updatecmd.Parameters.Add(new SqliteParameter(":region_key", uid.session_data.region_id.ToString())); + +// StringBuilder parameters = new StringBuilder(); +// SqliteParameterCollection spc = updatecmd.Parameters; +// foreach (SqliteParameter sp in spc) +// parameters.AppendFormat("{0}={1},", sp.ParameterName, sp.Value); +// +// m_log.DebugFormat("[WEB STATS MODULE]: Parameters {0}", parameters); // m_log.DebugFormat("[WEB STATS MODULE]: Database stats update for {0}", uid.session_data.agent_id); - int result = updatecmd.ExecuteNonQuery(); - - if (result == 0) - { -// m_log.DebugFormat("[WEB STATS MODULE]: Database stats insert for {0}", uid.session_data.agent_id); - - updatecmd.CommandText = SQL_STATS_TABLE_INSERT; - - try - { - updatecmd.ExecuteNonQuery(); - } - catch (Exception e) - { - m_log.WarnFormat( - "[WEB STATS MODULE]: failed to write stats for {0}, storage Execution Exception {1}{2}", - uid.session_data.agent_id, e.Message, e.StackTrace); - } - } + updatecmd.ExecuteNonQuery(); } } } #region SQL - private const string SQL_MIGRA_TABLE_CREATE = @"create table migrations(name varchar(100), version int)"; - - private const string SQL_STATS_TABLE_CREATE = @"CREATE TABLE stats_session_data ( + private const string SQL_STATS_TABLE_CREATE = @"CREATE TABLE IF NOT EXISTS stats_session_data ( session_id VARCHAR(36) NOT NULL PRIMARY KEY, agent_id VARCHAR(36) NOT NULL DEFAULT '', region_id VARCHAR(36) NOT NULL DEFAULT '', @@ -735,11 +694,11 @@ namespace OpenSim.Region.UserStatistics f_send_packet INT NOT NULL DEFAULT '0' );"; - private const string SQL_STATS_TABLE_INSERT = @"INSERT INTO stats_session_data ( + private const string SQL_STATS_TABLE_INSERT = @"INSERT OR REPLACE INTO stats_session_data ( session_id, agent_id, region_id, last_updated, remote_ip, name_f, name_l, avg_agents_in_view, min_agents_in_view, max_agents_in_view, mode_agents_in_view, avg_fps, min_fps, max_fps, mode_fps, a_language, mem_use, meters_traveled, avg_ping, min_ping, max_ping, mode_ping, regions_visited, run_time, avg_sim_fps, min_sim_fps, max_sim_fps, mode_sim_fps, start_time, client_version, s_cpu, s_gpu, s_os, s_ram, -d_object_kb, d_texture_kb, n_in_kb, n_in_pk, n_out_kb, n_out_pk, f_dropped, f_failed_resends, f_invalid, f_invalid, f_off_circuit, +d_object_kb, d_texture_kb, d_world_kb, n_in_kb, n_in_pk, n_out_kb, n_out_pk, f_dropped, f_failed_resends, f_invalid, f_off_circuit, f_resent, f_send_packet ) VALUES @@ -747,62 +706,13 @@ VALUES :session_id, :agent_id, :region_id, :last_updated, :remote_ip, :name_f, :name_l, :avg_agents_in_view, :min_agents_in_view, :max_agents_in_view, :mode_agents_in_view, :avg_fps, :min_fps, :max_fps, :mode_fps, :a_language, :mem_use, :meters_traveled, :avg_ping, :min_ping, :max_ping, :mode_ping, :regions_visited, :run_time, :avg_sim_fps, :min_sim_fps, :max_sim_fps, :mode_sim_fps, :start_time, :client_version, :s_cpu, :s_gpu, :s_os, :s_ram, -:d_object_kb, :d_texture_kb, :n_in_kb, :n_in_pk, :n_out_kb, :n_out_pk, :f_dropped, :f_failed_resends, :f_invalid, :f_invalid, :f_off_circuit, +:d_object_kb, :d_texture_kb, :d_world_kb, :n_in_kb, :n_in_pk, :n_out_kb, :n_out_pk, :f_dropped, :f_failed_resends, :f_invalid, :f_off_circuit, :f_resent, :f_send_packet ) "; - private const string SQL_STATS_TABLE_UPDATE = @" -UPDATE stats_session_data -set session_id=:session_id, - agent_id=:agent_id, - region_id=:region_id, - last_updated=:last_updated, - remote_ip=:remote_ip, - name_f=:name_f, - name_l=:name_l, - avg_agents_in_view=:avg_agents_in_view, - min_agents_in_view=:min_agents_in_view, - max_agents_in_view=:max_agents_in_view, - mode_agents_in_view=:mode_agents_in_view, - avg_fps=:avg_fps, - min_fps=:min_fps, - max_fps=:max_fps, - mode_fps=:mode_fps, - a_language=:a_language, - mem_use=:mem_use, - meters_traveled=:meters_traveled, - avg_ping=:avg_ping, - min_ping=:min_ping, - max_ping=:max_ping, - mode_ping=:mode_ping, - regions_visited=:regions_visited, - run_time=:run_time, - avg_sim_fps=:avg_sim_fps, - min_sim_fps=:min_sim_fps, - max_sim_fps=:max_sim_fps, - mode_sim_fps=:mode_sim_fps, - start_time=:start_time, - client_version=:client_version, - s_cpu=:s_cpu, - s_gpu=:s_gpu, - s_os=:s_os, - s_ram=:s_ram, - d_object_kb=:d_object_kb, - d_texture_kb=:d_texture_kb, - d_world_kb=:d_world_kb, - n_in_kb=:n_in_kb, - n_in_pk=:n_in_pk, - n_out_kb=:n_out_kb, - n_out_pk=:n_out_pk, - f_dropped=:f_dropped, - f_failed_resends=:f_failed_resends, - f_invalid=:f_invalid, - f_off_circuit=:f_off_circuit, - f_resent=:f_resent, - f_send_packet=:f_send_packet -WHERE session_id=:session_key AND agent_id=:agent_key AND region_id=:region_key"; - #endregion + #endregion + } public static class UserSessionUtil diff --git a/OpenSim/Server/Base/HttpServerBase.cs b/OpenSim/Server/Base/HttpServerBase.cs index d47155984f..29b1c00822 100644 --- a/OpenSim/Server/Base/HttpServerBase.cs +++ b/OpenSim/Server/Base/HttpServerBase.cs @@ -40,44 +40,9 @@ namespace OpenSim.Server.Base { public class HttpServerBase : ServicesServerBase { - // Logger - // - private static readonly ILog m_Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); +// private static readonly ILog m_Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - // The http server instance - // - protected BaseHttpServer m_HttpServer = null; - protected uint m_Port = 0; - protected Dictionary m_Servers = - new Dictionary(); - protected uint m_consolePort = 0; - - public IHttpServer HttpServer - { - get { return m_HttpServer; } - } - - public uint DefaultPort - { - get { return m_Port; } - } - - public IHttpServer GetHttpServer(uint port) - { - m_Log.InfoFormat("[SERVER]: Requested port {0}", port); - if (port == m_Port) - return HttpServer; - - if (m_Servers.ContainsKey(port)) - return m_Servers[port]; - - m_Servers[port] = new BaseHttpServer(port); - - m_Log.InfoFormat("[SERVER]: Starting new HTTP server on port {0}", port); - m_Servers[port].Start(); - - return m_Servers[port]; - } + private uint m_consolePort; // Handle all the automagical stuff // @@ -94,19 +59,21 @@ namespace OpenSim.Server.Base System.Console.WriteLine("Section 'Network' not found, server can't start"); Thread.CurrentThread.Abort(); } + uint port = (uint)networkConfig.GetInt("port", 0); if (port == 0) { - Thread.CurrentThread.Abort(); } - // + bool ssl_main = networkConfig.GetBoolean("https_main",false); bool ssl_listener = networkConfig.GetBoolean("https_listener",false); m_consolePort = (uint)networkConfig.GetInt("ConsolePort", 0); - m_Port = port; + + BaseHttpServer httpServer = null; + // // This is where to make the servers: // @@ -118,8 +85,7 @@ namespace OpenSim.Server.Base // if ( !ssl_main ) { - m_HttpServer = new BaseHttpServer(port); - + httpServer = new BaseHttpServer(port); } else { @@ -135,10 +101,12 @@ namespace OpenSim.Server.Base System.Console.WriteLine("Password for X509 certificate is missing, server can't start."); Thread.CurrentThread.Abort(); } - m_HttpServer = new BaseHttpServer(port, ssl_main, cert_path, cert_pass); + + httpServer = new BaseHttpServer(port, ssl_main, cert_path, cert_pass); } - MainServer.Instance = m_HttpServer; + MainServer.AddHttpServer(httpServer); + MainServer.Instance = httpServer; // If https_listener = true, then add an ssl listener on the https_port... if ( ssl_listener == true ) { @@ -157,43 +125,24 @@ namespace OpenSim.Server.Base System.Console.WriteLine("Password for X509 certificate is missing, server can't start."); Thread.CurrentThread.Abort(); } - // Add our https_server - BaseHttpServer server = null; - server = new BaseHttpServer(https_port, ssl_listener, cert_path, cert_pass); - if (server != null) - { - m_Log.InfoFormat("[SERVER]: Starting HTTPS server on port {0}", https_port); - m_Servers.Add(https_port,server); - } - else - System.Console.WriteLine(String.Format("Failed to start HTTPS server on port {0}",https_port)); + + MainServer.AddHttpServer(new BaseHttpServer(https_port, ssl_listener, cert_path, cert_pass)); } } protected override void Initialise() { - m_Log.InfoFormat("[SERVER]: Starting HTTP server on port {0}", m_HttpServer.Port); - m_HttpServer.Start(); + foreach (BaseHttpServer s in MainServer.Servers.Values) + s.Start(); - if (m_Servers.Count > 0) - { - foreach (BaseHttpServer s in m_Servers.Values) - { - if (!s.UseSSL) - m_Log.InfoFormat("[SERVER]: Starting HTTP server on port {0}", s.Port); - else - m_Log.InfoFormat("[SERVER]: Starting HTTPS server on port {0}", s.Port); - - s.Start(); - } - } + MainServer.RegisterHttpConsoleCommands(MainConsole.Instance); if (MainConsole.Instance is RemoteConsole) { if (m_consolePort == 0) - ((RemoteConsole)MainConsole.Instance).SetServer(m_HttpServer); + ((RemoteConsole)MainConsole.Instance).SetServer(MainServer.Instance); else - ((RemoteConsole)MainConsole.Instance).SetServer(GetHttpServer(m_consolePort)); + ((RemoteConsole)MainConsole.Instance).SetServer(MainServer.GetHttpServer(m_consolePort)); } } } diff --git a/OpenSim/Server/Base/ServerUtils.cs b/OpenSim/Server/Base/ServerUtils.cs index 8effdd2d1b..42c82cf34c 100644 --- a/OpenSim/Server/Base/ServerUtils.cs +++ b/OpenSim/Server/Base/ServerUtils.cs @@ -117,7 +117,10 @@ namespace OpenSim.Server.Base catch (Exception e) { if (!(e is System.MissingMethodException)) - m_log.ErrorFormat("Error loading plugin from {0}, exception {1}", dllName, e.InnerException); + { + m_log.ErrorFormat("Error loading plugin {0} from {1}. Exception: {2}", + interfaceName, dllName, e.InnerException == null ? e.Message : e.InnerException.Message); + } return null; } @@ -265,7 +268,7 @@ namespace OpenSim.Server.Base continue; XmlElement elem = parent.OwnerDocument.CreateElement("", - kvp.Key, ""); + XmlConvert.EncodeLocalName(kvp.Key), ""); if (kvp.Value is Dictionary) { @@ -320,11 +323,11 @@ namespace OpenSim.Server.Base XmlNode type = part.Attributes.GetNamedItem("type"); if (type == null || type.Value != "List") { - ret[part.Name] = part.InnerText; + ret[XmlConvert.DecodeName(part.Name)] = part.InnerText; } else { - ret[part.Name] = ParseElement(part); + ret[XmlConvert.DecodeName(part.Name)] = ParseElement(part); } } diff --git a/OpenSim/Server/Base/ServicesServerBase.cs b/OpenSim/Server/Base/ServicesServerBase.cs index 36c48e63c1..b137c05889 100644 --- a/OpenSim/Server/Base/ServicesServerBase.cs +++ b/OpenSim/Server/Base/ServicesServerBase.cs @@ -27,9 +27,10 @@ using System; using System.IO; -using System.Xml; -using System.Threading; using System.Reflection; +using System.Threading; +using System.Text; +using System.Xml; using OpenSim.Framework; using OpenSim.Framework.Console; using log4net; @@ -335,8 +336,7 @@ namespace OpenSim.Server.Base { string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); FileStream fs = File.Create(path); - System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); - Byte[] buf = enc.GetBytes(pidstring); + Byte[] buf = Encoding.ASCII.GetBytes(pidstring); fs.Write(buf, 0, buf.Length); fs.Close(); m_pidFile = path; diff --git a/OpenSim/Server/Handlers/Authentication/AuthenticationServerPostHandler.cs b/OpenSim/Server/Handlers/Authentication/AuthenticationServerPostHandler.cs index a19b5993bf..6b93cd9035 100644 --- a/OpenSim/Server/Handlers/Authentication/AuthenticationServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Authentication/AuthenticationServerPostHandler.cs @@ -321,8 +321,7 @@ namespace OpenSim.Server.Handlers.Authentication private byte[] ResultToBytes(Dictionary result) { string xmlString = ServerUtils.BuildXmlResponse(result); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } } } diff --git a/OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs b/OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs index dfed761234..18cef154e5 100644 --- a/OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs +++ b/OpenSim/Server/Handlers/Authentication/OpenIdServerHandler.cs @@ -191,6 +191,8 @@ For more information, see http://openid.net/. #endregion HTML + public string Name { get { return "OpenId"; } } + public string Description { get { return null; } } public string ContentType { get { return m_contentType; } } public string HttpMethod { get { return m_httpMethod; } } public string Path { get { return m_path; } } diff --git a/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs b/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs index 3ee405c509..393584e932 100644 --- a/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Avatar/AvatarServerPostHandler.cs @@ -121,8 +121,7 @@ namespace OpenSim.Server.Handlers.Avatar string xmlString = ServerUtils.BuildXmlResponse(result); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } return FailureResult(); diff --git a/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs b/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs index 59420f5ca5..47a85581af 100644 --- a/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Friends/FriendsServerPostHandler.cs @@ -95,7 +95,8 @@ namespace OpenSim.Server.Handlers.Friends return DeleteFriendString(request); } - m_log.DebugFormat("[FRIENDS HANDLER]: unknown method {0} request {1}", method.Length, method); + + m_log.DebugFormat("[FRIENDS HANDLER]: unknown method request {0}", method); } catch (Exception e) { @@ -103,7 +104,6 @@ namespace OpenSim.Server.Handlers.Friends } return FailureResult(); - } #region Method-specific handlers @@ -152,10 +152,9 @@ namespace OpenSim.Server.Handlers.Friends } string xmlString = ServerUtils.BuildXmlResponse(result); - //m_log.DebugFormat("[FRIENDS HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + //m_log.DebugFormat("[FRIENDS HANDLER]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] StoreFriend(Dictionary request) diff --git a/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs b/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs index bebf48242b..ef5f33e173 100644 --- a/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Grid/GridServerPostHandler.cs @@ -116,7 +116,7 @@ namespace OpenSim.Server.Handlers.Grid return GetRegionFlags(request); } - m_log.DebugFormat("[GRID HANDLER]: unknown method {0} request {1}", method.Length, method); + m_log.DebugFormat("[GRID HANDLER]: unknown method request {0}", method); } catch (Exception e) { @@ -226,10 +226,9 @@ namespace OpenSim.Server.Handlers.Grid } string xmlString = ServerUtils.BuildXmlResponse(result); - //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] GetRegionByUUID(Dictionary request) @@ -256,9 +255,9 @@ namespace OpenSim.Server.Handlers.Grid result["result"] = rinfo.ToKeyValuePairs(); string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] GetRegionByPosition(Dictionary request) @@ -289,9 +288,9 @@ namespace OpenSim.Server.Handlers.Grid result["result"] = rinfo.ToKeyValuePairs(); string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] GetRegionByName(Dictionary request) @@ -318,9 +317,9 @@ namespace OpenSim.Server.Handlers.Grid result["result"] = rinfo.ToKeyValuePairs(); string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] GetRegionsByName(Dictionary request) @@ -361,9 +360,9 @@ namespace OpenSim.Server.Handlers.Grid } string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] GetRegionRange(Dictionary request) @@ -410,9 +409,9 @@ namespace OpenSim.Server.Handlers.Grid } } string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] GetDefaultRegions(Dictionary request) @@ -440,9 +439,9 @@ namespace OpenSim.Server.Handlers.Grid } } string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] GetFallbackRegions(Dictionary request) @@ -481,9 +480,9 @@ namespace OpenSim.Server.Handlers.Grid } } string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] GetHyperlinks(Dictionary request) @@ -511,9 +510,9 @@ namespace OpenSim.Server.Handlers.Grid } } string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] GetRegionFlags(Dictionary request) @@ -537,12 +536,11 @@ namespace OpenSim.Server.Handlers.Grid result["result"] = flags.ToString(); string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } - #endregion #region Misc diff --git a/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs b/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs index bf212554c7..687cf8ddb1 100644 --- a/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs +++ b/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs @@ -117,10 +117,9 @@ namespace OpenSim.Server.Handlers.GridUser result["result"] = guinfo.ToKeyValuePairs(); string xmlString = ServerUtils.BuildXmlResponse(result); - //m_log.DebugFormat("[GRID USER HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + //m_log.DebugFormat("[GRID USER HANDLER]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] LoggedOut(Dictionary request) @@ -189,10 +188,9 @@ namespace OpenSim.Server.Handlers.GridUser result["result"] = guinfo.ToKeyValuePairs(); string xmlString = ServerUtils.BuildXmlResponse(result); - //m_log.DebugFormat("[GRID USER HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + //m_log.DebugFormat("[GRID USER HANDLER]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] GetGridUserInfos(Dictionary request) @@ -231,8 +229,7 @@ namespace OpenSim.Server.Handlers.GridUser } string xmlString = ServerUtils.BuildXmlResponse(result); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } private bool UnpackArgs(Dictionary request, out string user, out UUID region, out Vector3 position, out Vector3 lookAt) diff --git a/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs b/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs index 8ef03e7a71..0aa272973f 100644 --- a/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Hypergrid/HGFriendsServerPostHandler.cs @@ -122,7 +122,8 @@ namespace OpenSim.Server.Handlers.Hypergrid return GrantRights(request); */ } - m_log.DebugFormat("[HGFRIENDS HANDLER]: unknown method {0} request {1}", method.Length, method); + + m_log.DebugFormat("[HGFRIENDS HANDLER]: unknown method {0}", method); } catch (Exception e) { @@ -278,13 +279,11 @@ namespace OpenSim.Server.Handlers.Hypergrid } string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); - + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } - #endregion #region Misc diff --git a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs index cb9b65da77..64127c20af 100644 --- a/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs +++ b/OpenSim/Server/Handlers/Inventory/XInventoryInConnector.cs @@ -217,9 +217,9 @@ namespace OpenSim.Server.Handlers.Asset result["RESULT"] = "False"; string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] HandleGetInventorySkeleton(Dictionary request) @@ -245,9 +245,9 @@ namespace OpenSim.Server.Handlers.Asset result["FOLDERS"] = sfolders; string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] HandleGetUserInventory(Dictionary request) @@ -284,9 +284,9 @@ namespace OpenSim.Server.Handlers.Asset } string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] HandleGetRootFolder(Dictionary request) @@ -300,9 +300,9 @@ namespace OpenSim.Server.Handlers.Asset result["folder"] = EncodeFolder(rfolder); string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] HandleGetFolderForType(Dictionary request) @@ -317,9 +317,9 @@ namespace OpenSim.Server.Handlers.Asset result["folder"] = EncodeFolder(folder); string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] HandleGetFolderContent(Dictionary request) @@ -358,9 +358,9 @@ namespace OpenSim.Server.Handlers.Asset } string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] HandleGetFolderItems(Dictionary request) @@ -386,9 +386,9 @@ namespace OpenSim.Server.Handlers.Asset result["ITEMS"] = sitems; string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] HandleAddFolder(Dictionary request) @@ -550,9 +550,9 @@ namespace OpenSim.Server.Handlers.Asset result["item"] = EncodeItem(item); string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] HandleGetFolder(Dictionary request) @@ -567,9 +567,9 @@ namespace OpenSim.Server.Handlers.Asset result["folder"] = EncodeFolder(folder); string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] HandleGetActiveGestures(Dictionary request) @@ -592,9 +592,9 @@ namespace OpenSim.Server.Handlers.Asset result["ITEMS"] = items; string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] HandleGetAssetPermissions(Dictionary request) @@ -609,11 +609,10 @@ namespace OpenSim.Server.Handlers.Asset result["RESULT"] = perms.ToString(); string xmlString = ServerUtils.BuildXmlResponse(result); - //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); - } + //m_log.DebugFormat("[XXX]: resp string: {0}", xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); + } private Dictionary EncodeFolder(InventoryFolderBase f) { diff --git a/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs b/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs index 75dd711ed2..4a619698bc 100644 --- a/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs +++ b/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs @@ -33,17 +33,24 @@ using System.Xml; using Nini.Config; using log4net; +using OpenMetaverse; +using OpenSim.Framework; using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Server.Handlers.Base; +using GridRegion = OpenSim.Services.Interfaces.GridRegion; + namespace OpenSim.Server.Handlers.MapImage { public class MapAddServiceConnector : ServiceConnector { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private IMapImageService m_MapService; + private IGridService m_GridService; private string m_ConfigName = "MapImageService"; public MapAddServiceConnector(IConfigSource config, IHttpServer server, string configName) : @@ -53,16 +60,27 @@ namespace OpenSim.Server.Handlers.MapImage if (serverConfig == null) throw new Exception(String.Format("No section {0} in config file", m_ConfigName)); - string gridService = serverConfig.GetString("LocalServiceModule", + string mapService = serverConfig.GetString("LocalServiceModule", String.Empty); - if (gridService == String.Empty) + if (mapService == String.Empty) throw new Exception("No LocalServiceModule in config file"); Object[] args = new Object[] { config }; - m_MapService = ServerUtils.LoadPlugin(gridService, args); + m_MapService = ServerUtils.LoadPlugin(mapService, args); + + string gridService = serverConfig.GetString("GridService", String.Empty); + if (gridService != string.Empty) + m_GridService = ServerUtils.LoadPlugin(gridService, args); + + if (m_GridService != null) + m_log.InfoFormat("[MAP IMAGE HANDLER]: GridService check is ON"); + else + m_log.InfoFormat("[MAP IMAGE HANDLER]: GridService check is OFF"); + + bool proxy = serverConfig.GetBoolean("HasProxy", false); + server.AddStreamHandler(new MapServerPostHandler(m_MapService, m_GridService, proxy)); - server.AddStreamHandler(new MapServerPostHandler(m_MapService)); } } @@ -70,11 +88,15 @@ namespace OpenSim.Server.Handlers.MapImage { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private IMapImageService m_MapService; + private IGridService m_GridService; + bool m_Proxy; - public MapServerPostHandler(IMapImageService service) : + public MapServerPostHandler(IMapImageService service, IGridService grid, bool proxy) : base("POST", "/map") { m_MapService = service; + m_GridService = grid; + m_Proxy = proxy; } public override byte[] Handle(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) @@ -105,6 +127,27 @@ namespace OpenSim.Server.Handlers.MapImage // if (request.ContainsKey("TYPE")) // type = request["TYPE"].ToString(); + if (m_GridService != null) + { + System.Net.IPAddress ipAddr = GetCallerIP(httpRequest); + GridRegion r = m_GridService.GetRegionByPosition(UUID.Zero, x * (int)Constants.RegionSize, y * (int)Constants.RegionSize); + if (r != null) + { + if (r.ExternalEndPoint.Address.ToString() != ipAddr.ToString()) + { + m_log.WarnFormat("[MAP IMAGE HANDLER]: IP address {0} may be trying to impersonate region in IP {1}", ipAddr, r.ExternalEndPoint.Address); + return FailureResult("IP address of caller does not match IP address of registered region"); + } + + } + else + { + m_log.WarnFormat("[MAP IMAGE HANDLER]: IP address {0} may be rogue. Region not found at coordinates {1}-{2}", + ipAddr, x, y); + return FailureResult("Region not found at given coordinates"); + } + } + byte[] data = Convert.FromBase64String(request["DATA"].ToString()); string reason = string.Empty; @@ -183,5 +226,31 @@ namespace OpenSim.Server.Handlers.MapImage return ms.ToArray(); } + + private System.Net.IPAddress GetCallerIP(IOSHttpRequest request) + { + if (!m_Proxy) + return request.RemoteIPEndPoint.Address; + + // We're behind a proxy + string xff = "X-Forwarded-For"; + string xffValue = request.Headers[xff.ToLower()]; + if (xffValue == null || (xffValue != null && xffValue == string.Empty)) + xffValue = request.Headers[xff]; + + if (xffValue == null || (xffValue != null && xffValue == string.Empty)) + { + m_log.WarnFormat("[MAP IMAGE HANDLER]: No XFF header"); + return request.RemoteIPEndPoint.Address; + } + + System.Net.IPEndPoint ep = Util.GetClientIPFromXFF(xffValue); + if (ep != null) + return ep.Address; + + // Oops + return request.RemoteIPEndPoint.Address; + } + } } diff --git a/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs b/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs index 6b6a552448..2d67c6db0c 100644 --- a/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs +++ b/OpenSim/Server/Handlers/Presence/PresenceServerPostHandler.cs @@ -199,9 +199,9 @@ namespace OpenSim.Server.Handlers.Presence result["result"] = pinfo.ToKeyValuePairs(); string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] GetAgents(Dictionary request) @@ -240,12 +240,11 @@ namespace OpenSim.Server.Handlers.Presence } string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } - private byte[] SuccessResult() { XmlDocument doc = new XmlDocument(); diff --git a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs index 8f6fa52cfd..d772c391ac 100644 --- a/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs +++ b/OpenSim/Server/Handlers/Simulation/AgentHandlers.cs @@ -149,13 +149,16 @@ namespace OpenSim.Server.Handlers.Simulation responsedata["int_response_code"] = HttpStatusCode.OK; - OSDMap resp = new OSDMap(2); + OSDMap resp = new OSDMap(3); resp["success"] = OSD.FromBoolean(result); resp["reason"] = OSD.FromString(reason); resp["version"] = OSD.FromString(version); - responsedata["str_response_string"] = OSDParser.SerializeJsonString(resp); + // We must preserve defaults here, otherwise a false "success" will not be put into the JSON map! + responsedata["str_response_string"] = OSDParser.SerializeJsonString(resp, true); + +// Console.WriteLine("str_response_string [{0}]", responsedata["str_response_string"]); } protected virtual void DoAgentGet(Hashtable request, Hashtable responsedata, UUID id, UUID regionID) @@ -569,7 +572,7 @@ namespace OpenSim.Server.Handlers.Simulation AgentData agent = new AgentData(); try { - agent.Unpack(args, m_SimulationService.GetScene(destination.RegionHandle)); + agent.Unpack(args, m_SimulationService.GetScene(destination.RegionID)); } catch (Exception ex) { @@ -589,7 +592,7 @@ namespace OpenSim.Server.Handlers.Simulation AgentPosition agent = new AgentPosition(); try { - agent.Unpack(args, m_SimulationService.GetScene(destination.RegionHandle)); + agent.Unpack(args, m_SimulationService.GetScene(destination.RegionID)); } catch (Exception ex) { diff --git a/OpenSim/Server/Handlers/Simulation/ObjectHandlers.cs b/OpenSim/Server/Handlers/Simulation/ObjectHandlers.cs index f0d8f69827..dbb1a15ae7 100644 --- a/OpenSim/Server/Handlers/Simulation/ObjectHandlers.cs +++ b/OpenSim/Server/Handlers/Simulation/ObjectHandlers.cs @@ -93,11 +93,6 @@ namespace OpenSim.Server.Handlers.Simulation DoObjectPost(request, responsedata, regionID); return responsedata; } - else if (method.Equals("PUT")) - { - DoObjectPut(request, responsedata, regionID); - return responsedata; - } //else if (method.Equals("DELETE")) //{ // DoObjectDelete(request, responsedata, agentID, action, regionHandle); @@ -161,7 +156,7 @@ namespace OpenSim.Server.Handlers.Simulation if (args.ContainsKey("extra") && args["extra"] != null) extraStr = args["extra"].AsString(); - IScene s = m_SimulationService.GetScene(destination.RegionHandle); + IScene s = m_SimulationService.GetScene(destination.RegionID); ISceneObject sog = null; try { @@ -219,48 +214,5 @@ namespace OpenSim.Server.Handlers.Simulation { return m_SimulationService.CreateObject(destination, newPosition, sog, false); } - - protected virtual void DoObjectPut(Hashtable request, Hashtable responsedata, UUID regionID) - { - OSDMap args = Utils.GetOSDMap((string)request["body"]); - if (args == null) - { - responsedata["int_response_code"] = 400; - responsedata["str_response_string"] = "false"; - return; - } - - // retrieve the input arguments - int x = 0, y = 0; - UUID uuid = UUID.Zero; - string regionname = string.Empty; - if (args.ContainsKey("destination_x") && args["destination_x"] != null) - Int32.TryParse(args["destination_x"].AsString(), out x); - if (args.ContainsKey("destination_y") && args["destination_y"] != null) - Int32.TryParse(args["destination_y"].AsString(), out y); - if (args.ContainsKey("destination_uuid") && args["destination_uuid"] != null) - UUID.TryParse(args["destination_uuid"].AsString(), out uuid); - if (args.ContainsKey("destination_name") && args["destination_name"] != null) - regionname = args["destination_name"].ToString(); - - GridRegion destination = new GridRegion(); - destination.RegionID = uuid; - destination.RegionLocX = x; - destination.RegionLocY = y; - destination.RegionName = regionname; - - UUID userID = UUID.Zero, itemID = UUID.Zero; - if (args.ContainsKey("userid") && args["userid"] != null) - userID = args["userid"].AsUUID(); - if (args.ContainsKey("itemid") && args["itemid"] != null) - itemID = args["itemid"].AsUUID(); - - // This is the meaning of PUT object - bool result = m_SimulationService.CreateObject(destination, userID, itemID); - - responsedata["int_response_code"] = 200; - responsedata["str_response_string"] = result.ToString(); - } - } } diff --git a/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs b/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs index 3fd69aed50..72551ef404 100644 --- a/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs +++ b/OpenSim/Server/Handlers/UserAccounts/UserAccountServerPostHandler.cs @@ -195,9 +195,9 @@ namespace OpenSim.Server.Handlers.UserAccounts } string xmlString = ServerUtils.BuildXmlResponse(result); + //m_log.DebugFormat("[GRID HANDLER]: resp string: {0}", xmlString); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } byte[] StoreAccount(Dictionary request) @@ -353,8 +353,7 @@ namespace OpenSim.Server.Handlers.UserAccounts private byte[] ResultToBytes(Dictionary result) { string xmlString = ServerUtils.BuildXmlResponse(result); - UTF8Encoding encoding = new UTF8Encoding(); - return encoding.GetBytes(xmlString); + return Util.UTF8NoBomEncoding.GetBytes(xmlString); } } -} +} \ No newline at end of file diff --git a/OpenSim/Server/ServerMain.cs b/OpenSim/Server/ServerMain.cs index 9503c4cff6..21fb6785c3 100644 --- a/OpenSim/Server/ServerMain.cs +++ b/OpenSim/Server/ServerMain.cs @@ -30,6 +30,7 @@ using log4net; using System.Reflection; using System; using System.Collections.Generic; +using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Server.Base; using OpenSim.Server.Handlers.Base; @@ -92,27 +93,24 @@ namespace OpenSim.Server if (parts.Length > 1) friendlyName = parts[1]; - IHttpServer server = m_Server.HttpServer; - if (port != 0) - server = m_Server.GetHttpServer(port); + IHttpServer server; - if (port != m_Server.DefaultPort && port != 0) - m_log.InfoFormat("[SERVER]: Loading {0} on port {1}", friendlyName, port); + if (port != 0) + server = MainServer.GetHttpServer(port); else - m_log.InfoFormat("[SERVER]: Loading {0}", friendlyName); + server = MainServer.Instance; + + m_log.InfoFormat("[SERVER]: Loading {0} on port {1}", friendlyName, server.Port); IServiceConnector connector = null; - Object[] modargs = new Object[] { m_Server.Config, server, - configName }; - connector = ServerUtils.LoadPlugin(conn, - modargs); + Object[] modargs = new Object[] { m_Server.Config, server, configName }; + connector = ServerUtils.LoadPlugin(conn, modargs); + if (connector == null) { modargs = new Object[] { m_Server.Config, server }; - connector = - ServerUtils.LoadPlugin(conn, - modargs); + connector = ServerUtils.LoadPlugin(conn, modargs); } if (connector != null) @@ -132,4 +130,4 @@ namespace OpenSim.Server return 0; } } -} +} \ No newline at end of file diff --git a/OpenSim/Services/AvatarService/AvatarService.cs b/OpenSim/Services/AvatarService/AvatarService.cs index c59a9e0263..423c7818f0 100644 --- a/OpenSim/Services/AvatarService/AvatarService.cs +++ b/OpenSim/Services/AvatarService/AvatarService.cs @@ -93,7 +93,7 @@ namespace OpenSim.Services.AvatarService if (kvp.Key.StartsWith("_")) count++; - m_log.DebugFormat("[AVATAR SERVICE]: SetAvatar for {0}, attachs={1}", principalID, count); +// m_log.DebugFormat("[AVATAR SERVICE]: SetAvatar for {0}, attachs={1}", principalID, count); m_Database.Delete("PrincipalID", principalID.ToString()); AvatarBaseData av = new AvatarBaseData(); diff --git a/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs similarity index 100% rename from OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs rename to OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs diff --git a/OpenSim/Services/Connectors/Authentication/AuthenticationServiceConnector.cs b/OpenSim/Services/Connectors/Authentication/AuthenticationServicesConnector.cs similarity index 100% rename from OpenSim/Services/Connectors/Authentication/AuthenticationServiceConnector.cs rename to OpenSim/Services/Connectors/Authentication/AuthenticationServicesConnector.cs diff --git a/OpenSim/Services/Connectors/Authorization/AuthorizationServiceConnector.cs b/OpenSim/Services/Connectors/Authorization/AuthorizationServicesConnector.cs similarity index 100% rename from OpenSim/Services/Connectors/Authorization/AuthorizationServiceConnector.cs rename to OpenSim/Services/Connectors/Authorization/AuthorizationServicesConnector.cs diff --git a/OpenSim/Services/Connectors/Avatar/AvatarServiceConnector.cs b/OpenSim/Services/Connectors/Avatar/AvatarServicesConnector.cs similarity index 100% rename from OpenSim/Services/Connectors/Avatar/AvatarServiceConnector.cs rename to OpenSim/Services/Connectors/Avatar/AvatarServicesConnector.cs diff --git a/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs b/OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs similarity index 100% rename from OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs rename to OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs diff --git a/OpenSim/Services/Connectors/Grid/GridServiceConnector.cs b/OpenSim/Services/Connectors/Grid/GridServicesConnector.cs similarity index 96% rename from OpenSim/Services/Connectors/Grid/GridServiceConnector.cs rename to OpenSim/Services/Connectors/Grid/GridServicesConnector.cs index 7deaf954c0..f982cc1360 100644 --- a/OpenSim/Services/Connectors/Grid/GridServiceConnector.cs +++ b/OpenSim/Services/Connectors/Grid/GridServicesConnector.cs @@ -116,29 +116,36 @@ namespace OpenSim.Services.Connectors } else if (replyData.ContainsKey("Result")&& (replyData["Result"].ToString().ToLower() == "failure")) { - m_log.DebugFormat("[GRID CONNECTOR]: Registration failed: {0}", replyData["Message"].ToString()); + m_log.ErrorFormat( + "[GRID CONNECTOR]: Registration failed: {0} when contacting {1}", replyData["Message"], uri); + return replyData["Message"].ToString(); } else if (!replyData.ContainsKey("Result")) { - m_log.DebugFormat("[GRID CONNECTOR]: reply data does not contain result field"); + m_log.ErrorFormat( + "[GRID CONNECTOR]: reply data does not contain result field when contacting {0}", uri); } else { - m_log.DebugFormat("[GRID CONNECTOR]: unexpected result {0}", replyData["Result"].ToString()); - return "Unexpected result "+replyData["Result"].ToString(); + m_log.ErrorFormat( + "[GRID CONNECTOR]: unexpected result {0} when contacting {1}", replyData["Result"], uri); + + return "Unexpected result " + replyData["Result"].ToString(); } - } else - m_log.DebugFormat("[GRID CONNECTOR]: RegisterRegion received null reply"); + { + m_log.ErrorFormat( + "[GRID CONNECTOR]: RegisterRegion received null reply when contacting grid server at {0}", uri); + } } catch (Exception e) { - m_log.DebugFormat("[GRID CONNECTOR]: Exception when contacting grid server at {0}: {1}", uri, e.Message); + m_log.ErrorFormat("[GRID CONNECTOR]: Exception when contacting grid server at {0}: {1}", uri, e.Message); } - return "Error communicating with grid service"; + return string.Format("Error communicating with the grid service at {0}", uri); } public bool DeregisterRegion(UUID regionID) diff --git a/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs b/OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs similarity index 100% rename from OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs rename to OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs diff --git a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs index bc0bc54764..4cd933cc15 100644 --- a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs @@ -154,17 +154,32 @@ namespace OpenSim.Services.Connectors.Hypergrid UUID mapTile = m_HGMapImage; string filename = string.Empty; - Bitmap bitmap = null; + try { WebClient c = new WebClient(); //m_log.Debug("JPEG: " + imageURL); string name = regionID.ToString(); filename = Path.Combine(storagePath, name + ".jpg"); - c.DownloadFile(imageURL, filename); - bitmap = new Bitmap(filename); - //m_log.Debug("Size: " + m.PhysicalDimension.Height + "-" + m.PhysicalDimension.Width); - byte[] imageData = OpenJPEG.EncodeFromImage(bitmap, true); + m_log.DebugFormat("[GATEKEEPER SERVICE CONNECTOR]: Map image at {0}, cached at {1}", imageURL, filename); + if (!File.Exists(filename)) + { + m_log.DebugFormat("[GATEKEEPER SERVICE CONNECTOR]: downloading..."); + c.DownloadFile(imageURL, filename); + } + else + { + m_log.DebugFormat("[GATEKEEPER SERVICE CONNECTOR]: using cached image"); + } + + byte[] imageData = null; + + using (Bitmap bitmap = new Bitmap(filename)) + { + //m_log.Debug("Size: " + m.PhysicalDimension.Height + "-" + m.PhysicalDimension.Width); + imageData = OpenJPEG.EncodeFromImage(bitmap, true); + } + AssetBase ass = new AssetBase(UUID.Random(), "region " + name, (sbyte)AssetType.Texture, regionID.ToString()); // !!! for now diff --git a/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/HGFriendsServicesConnector.cs similarity index 100% rename from OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs rename to OpenSim/Services/Connectors/Hypergrid/HGFriendsServicesConnector.cs diff --git a/OpenSim/Services/Connectors/Hypergrid/HeloServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/HeloServicesConnector.cs similarity index 100% rename from OpenSim/Services/Connectors/Hypergrid/HeloServiceConnector.cs rename to OpenSim/Services/Connectors/Hypergrid/HeloServicesConnector.cs diff --git a/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs b/OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs similarity index 100% rename from OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs rename to OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs diff --git a/OpenSim/Services/Connectors/Land/LandServiceConnector.cs b/OpenSim/Services/Connectors/Land/LandServicesConnector.cs similarity index 100% rename from OpenSim/Services/Connectors/Land/LandServiceConnector.cs rename to OpenSim/Services/Connectors/Land/LandServicesConnector.cs diff --git a/OpenSim/Services/Connectors/MapImage/MapImageServiceConnector.cs b/OpenSim/Services/Connectors/MapImage/MapImageServicesConnector.cs similarity index 100% rename from OpenSim/Services/Connectors/MapImage/MapImageServiceConnector.cs rename to OpenSim/Services/Connectors/MapImage/MapImageServicesConnector.cs diff --git a/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs b/OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs similarity index 98% rename from OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs rename to OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs index 888b072013..7429293c3c 100644 --- a/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs +++ b/OpenSim/Services/Connectors/Neighbour/NeighbourServicesConnector.cs @@ -132,8 +132,7 @@ namespace OpenSim.Services.Connectors try { strBuffer = OSDParser.SerializeJsonString(args); - UTF8Encoding str = new UTF8Encoding(); - buffer = str.GetBytes(strBuffer); + buffer = Util.UTF8NoBomEncoding.GetBytes(strBuffer); } catch (Exception e) { diff --git a/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs b/OpenSim/Services/Connectors/Presence/PresenceServicesConnector.cs similarity index 100% rename from OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs rename to OpenSim/Services/Connectors/Presence/PresenceServicesConnector.cs diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianActivityDetector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianActivityDetector.cs index 2267325bdc..95e4bab134 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianActivityDetector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianActivityDetector.cs @@ -79,27 +79,13 @@ namespace OpenSim.Services.Connectors.SimianGrid public void OnConnectionClose(IClientAPI client) { - if (client.IsLoggingOut) - { - object sp = null; - Vector3 position = new Vector3(128, 128, 0); - Vector3 lookat = new Vector3(0, 1, 0); + if (client.SceneAgent.IsChildAgent) + return; - if (client.Scene.TryGetScenePresence(client.AgentId, out sp)) - { - if (sp is ScenePresence) - { - if (((ScenePresence)sp).IsChildAgent) - return; - - position = ((ScenePresence)sp).AbsolutePosition; - lookat = ((ScenePresence)sp).Lookat; - } - } - -// m_log.DebugFormat("[SIMIAN ACTIVITY DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); - m_GridUserService.LoggedOut(client.AgentId.ToString(), client.SessionId, client.Scene.RegionInfo.RegionID, position, lookat); - } +// m_log.DebugFormat("[ACTIVITY DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); + m_GridUserService.LoggedOut( + client.AgentId.ToString(), client.SessionId, client.Scene.RegionInfo.RegionID, + client.SceneAgent.AbsolutePosition, client.SceneAgent.Lookat); } void OnEnteringNewParcel(ScenePresence sp, int localLandID, UUID regionID) @@ -111,4 +97,4 @@ namespace OpenSim.Services.Connectors.SimianGrid }); } } -} +} \ No newline at end of file diff --git a/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs b/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs index 620bb109a9..6db830b184 100644 --- a/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs +++ b/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs @@ -149,6 +149,21 @@ namespace OpenSim.Services.Connectors m_database.RemoveRegionWindlightSettings(regionID); } + public string LoadRegionEnvironmentSettings(UUID regionUUID) + { + return m_database.LoadRegionEnvironmentSettings(regionUUID); + } + + public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) + { + m_database.StoreRegionEnvironmentSettings(regionUUID, settings); + } + + public void RemoveRegionEnvironmentSettings(UUID regionUUID) + { + m_database.RemoveRegionEnvironmentSettings(regionUUID); + } + public UUID[] GetObjectIDs(UUID regionID) { return m_database.GetObjectIDs(regionID); diff --git a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs index 5037543024..cd9338660b 100644 --- a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs @@ -62,7 +62,7 @@ namespace OpenSim.Services.Connectors.Simulation //m_Region = region; } - public IScene GetScene(ulong regionHandle) + public IScene GetScene(UUID regionId) { return null; } @@ -320,29 +320,40 @@ namespace OpenSim.Services.Connectors.Simulation { OSDMap data = (OSDMap)result["_Result"]; + // FIXME: If there is a _Result map then it's the success key here that indicates the true success + // or failure, not the sibling result node. + success = data["success"]; + reason = data["reason"].AsString(); if (data["version"] != null && data["version"].AsString() != string.Empty) version = data["version"].AsString(); - m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: QueryAccess to {0} returned {1} version {2} ({3})", uri, success, version, data["version"].AsString()); + m_log.DebugFormat( + "[REMOTE SIMULATION CONNECTOR]: QueryAccess to {0} returned {1}, reason {2}, version {3} ({4})", + uri, success, reason, version, data["version"].AsString()); } if (!success) { - if (result.ContainsKey("Message")) + // If we don't check this then OpenSimulator 0.7.3.1 and some period before will never see the + // actual failure message + if (!result.ContainsKey("_Result")) { - string message = result["Message"].AsString(); - if (message == "Service request failed: [MethodNotAllowed] MethodNotAllowed") // Old style region + if (result.ContainsKey("Message")) { - m_log.Info("[REMOTE SIMULATION CONNECTOR]: The above web util error was caused by a TP to a sim that doesn't support QUERYACCESS and can be ignored"); - return true; + string message = result["Message"].AsString(); + if (message == "Service request failed: [MethodNotAllowed] MethodNotAllowed") // Old style region + { + m_log.Info("[REMOTE SIMULATION CONNECTOR]: The above web util error was caused by a TP to a sim that doesn't support QUERYACCESS and can be ignored"); + return true; + } + + reason = result["Message"]; + } + else + { + reason = "Communications failure"; } - - reason = result["Message"]; - } - else - { - reason = "Communications failure"; } return false; @@ -356,7 +367,7 @@ namespace OpenSim.Services.Connectors.Simulation } catch (Exception e) { - m_log.WarnFormat("[REMOTE SIMULATION CONNECTOR] QueryAcess failed with exception; {0}",e.ToString()); + m_log.WarnFormat("[REMOTE SIMULATION CONNECTOR] QueryAcesss failed with exception; {0}",e.ToString()); } return false; diff --git a/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs b/OpenSim/Services/Connectors/UserAccounts/UserAccountServicesConnector.cs similarity index 100% rename from OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs rename to OpenSim/Services/Connectors/UserAccounts/UserAccountServicesConnector.cs diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index 3dc87bc5d5..aab403a203 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -85,12 +85,38 @@ namespace OpenSim.Services.GridService if (MainConsole.Instance != null) { MainConsole.Instance.Commands.AddCommand("Regions", true, - "show region", - "show region ", + "deregister region id", + "deregister region id ", + "Deregister a region manually.", + String.Empty, + HandleDeregisterRegion); + + // A messy way of stopping this command being added if we are in standalone (since the simulator + // has an identically named command + // + // XXX: We're relying on the OpenSimulator version being registered first, which is not well defined. + if (MainConsole.Instance.Commands.Resolve(new string[] { "show", "regions" }).Length == 0) + MainConsole.Instance.Commands.AddCommand("Regions", true, + "show regions", + "show regions", + "Show details on all regions", + String.Empty, + HandleShowRegions); + + MainConsole.Instance.Commands.AddCommand("Regions", true, + "show region name", + "show region name ", "Show details on a region", String.Empty, HandleShowRegion); + MainConsole.Instance.Commands.AddCommand("Regions", true, + "show region at", + "show region at ", + "Show details on a region at the given co-ordinate.", + "For example, show region at 1000 1000", + HandleShowRegionAt); + MainConsole.Instance.Commands.AddCommand("Regions", true, "set region flags", "set region flags ", @@ -495,34 +521,151 @@ namespace OpenSim.Services.GridService return -1; } - private void HandleShowRegion(string module, string[] cmd) + private void HandleDeregisterRegion(string module, string[] cmd) { - if (cmd.Length != 3) + if (cmd.Length != 4) { - MainConsole.Instance.Output("Syntax: show region "); - return; - } - List regions = m_Database.Get(cmd[2], UUID.Zero); - if (regions == null || regions.Count < 1) - { - MainConsole.Instance.Output("Region not found"); + MainConsole.Instance.Output("Syntax: degregister region id "); return; } - MainConsole.Instance.Output("Region Name Region UUID"); - MainConsole.Instance.Output("Location URI"); - MainConsole.Instance.Output("Owner ID Flags"); - MainConsole.Instance.Output("-------------------------------------------------------------------------------"); + string rawRegionUuid = cmd[3]; + UUID regionUuid; + + if (!UUID.TryParse(rawRegionUuid, out regionUuid)) + { + MainConsole.Instance.OutputFormat("{0} is not a valid region uuid", rawRegionUuid); + return; + } + + GridRegion region = GetRegionByUUID(UUID.Zero, regionUuid); + + if (region == null) + { + MainConsole.Instance.OutputFormat("No region with UUID {0}", regionUuid); + return; + } + + if (DeregisterRegion(regionUuid)) + { + MainConsole.Instance.OutputFormat("Deregistered {0} {1}", region.RegionName, regionUuid); + } + else + { + // I don't think this can ever occur if we know that the region exists. + MainConsole.Instance.OutputFormat("Error deregistering {0} {1}", region.RegionName, regionUuid); + } + + return; + } + + private void HandleShowRegions(string module, string[] cmd) + { + if (cmd.Length != 2) + { + MainConsole.Instance.Output("Syntax: show regions"); + return; + } + + List regions = m_Database.Get(int.MinValue, int.MinValue, int.MaxValue, int.MaxValue, UUID.Zero); + + OutputRegionsToConsoleSummary(regions); + } + + + private void HandleShowRegion(string module, string[] cmd) + { + if (cmd.Length != 4) + { + MainConsole.Instance.Output("Syntax: show region name "); + return; + } + + string regionName = cmd[3]; + + List regions = m_Database.Get(regionName, UUID.Zero); + if (regions == null || regions.Count < 1) + { + MainConsole.Instance.Output("No region with name {0} found", regionName); + return; + } + + OutputRegionsToConsole(regions); + } + + private void HandleShowRegionAt(string module, string[] cmd) + { + if (cmd.Length != 5) + { + MainConsole.Instance.Output("Syntax: show region at "); + return; + } + + int x, y; + if (!int.TryParse(cmd[3], out x)) + { + MainConsole.Instance.Output("x-coord must be an integer"); + return; + } + + if (!int.TryParse(cmd[4], out y)) + { + MainConsole.Instance.Output("y-coord must be an integer"); + return; + } + + RegionData region = m_Database.Get(x * (int)Constants.RegionSize, y * (int)Constants.RegionSize, UUID.Zero); + if (region == null) + { + MainConsole.Instance.OutputFormat("No region found at {0},{1}", x, y); + return; + } + + OutputRegionToConsole(region); + } + + private void OutputRegionToConsole(RegionData r) + { + OpenSim.Data.RegionFlags flags = (OpenSim.Data.RegionFlags)Convert.ToInt32(r.Data["flags"]); + + ConsoleDisplayList dispList = new ConsoleDisplayList(); + dispList.AddRow("Region Name", r.RegionName); + dispList.AddRow("Region ID", r.RegionID); + dispList.AddRow("Location", string.Format("{0},{1}", r.coordX, r.coordY)); + dispList.AddRow("URI", r.Data["serverURI"]); + dispList.AddRow("Owner ID", r.Data["owner_uuid"]); + dispList.AddRow("Flags", flags); + + MainConsole.Instance.Output(dispList.ToString()); + } + + private void OutputRegionsToConsole(List regions) + { + foreach (RegionData r in regions) + OutputRegionToConsole(r); + } + + private void OutputRegionsToConsoleSummary(List regions) + { + ConsoleDisplayTable dispTable = new ConsoleDisplayTable(); + dispTable.AddColumn("Name", 16); + dispTable.AddColumn("ID", 36); + dispTable.AddColumn("Position", 11); + dispTable.AddColumn("Owner ID", 36); + dispTable.AddColumn("Flags", 60); + foreach (RegionData r in regions) { OpenSim.Data.RegionFlags flags = (OpenSim.Data.RegionFlags)Convert.ToInt32(r.Data["flags"]); - MainConsole.Instance.Output(String.Format("{0,-20} {1}\n{2,-20} {3}\n{4,-39} {5}\n\n", - r.RegionName, r.RegionID, - String.Format("{0},{1}", r.posX / Constants.RegionSize, r.posY / Constants.RegionSize), - r.Data["serverURI"], - r.Data["owner_uuid"], flags)); + dispTable.AddRow( + r.RegionName, + r.RegionID.ToString(), + string.Format("{0},{1}", r.coordX, r.coordY), + r.Data["owner_uuid"].ToString(), + flags.ToString()); } - return; + + MainConsole.Instance.Output(dispTable.ToString()); } private int ParseFlags(int prev, string flags) diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs index 149a0abb4f..47d22b95fd 100644 --- a/OpenSim/Services/HypergridService/GatekeeperService.cs +++ b/OpenSim/Services/HypergridService/GatekeeperService.cs @@ -370,8 +370,6 @@ namespace OpenSim.Services.HypergridService return false; } } - - return false; } // Check that the service token was generated for *this* grid. diff --git a/OpenSim/Services/HypergridService/HGFriendsService.cs b/OpenSim/Services/HypergridService/HGFriendsService.cs index 39524ab93e..98423d765c 100644 --- a/OpenSim/Services/HypergridService/HGFriendsService.cs +++ b/OpenSim/Services/HypergridService/HGFriendsService.cs @@ -276,19 +276,19 @@ namespace OpenSim.Services.HypergridService } } - // Lastly, let's notify the rest who may be online somewhere else - foreach (string user in usersToBeNotified) - { - UUID id = new UUID(user); - //m_UserAgentService.LocateUser(id); - //etc... - //if (m_TravelingAgents.ContainsKey(id) && m_TravelingAgents[id].GridExternalName != m_GridName) - //{ - // string url = m_TravelingAgents[id].GridExternalName; - // // forward - //} - //m_log.WarnFormat("[HGFRIENDS SERVICE]: User {0} is visiting another grid. HG Status notifications still not implemented.", user); - } +// // Lastly, let's notify the rest who may be online somewhere else +// foreach (string user in usersToBeNotified) +// { +// UUID id = new UUID(user); +// //m_UserAgentService.LocateUser(id); +// //etc... +// //if (m_TravelingAgents.ContainsKey(id) && m_TravelingAgents[id].GridExternalName != m_GridName) +// //{ +// // string url = m_TravelingAgents[id].GridExternalName; +// // // forward +// //} +// //m_log.WarnFormat("[HGFRIENDS SERVICE]: User {0} is visiting another grid. HG Status notifications still not implemented.", user); +// } // and finally, let's send the online friends if (online) diff --git a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs index b6ec558b80..6e4b68c8bd 100644 --- a/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs +++ b/OpenSim/Services/HypergridService/HGSuitcaseInventoryService.cs @@ -57,7 +57,7 @@ namespace OpenSim.Services.HypergridService private string m_HomeURL; private IUserAccountService m_UserAccountService; - private UserAccountCache m_Cache; +// private UserAccountCache m_Cache; private ExpiringCache> m_SuitcaseTrees = new ExpiringCache>(); @@ -92,7 +92,7 @@ namespace OpenSim.Services.HypergridService // Preferred m_HomeURL = invConfig.GetString("HomeURI", m_HomeURL); - m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); +// m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); } m_log.Debug("[HG SUITCASE INVENTORY SERVICE]: Starting..."); @@ -107,9 +107,8 @@ namespace OpenSim.Services.HypergridService public override List GetInventorySkeleton(UUID principalID) { XInventoryFolder suitcase = GetSuitcaseXFolder(principalID); - XInventoryFolder root = GetRootXFolder(principalID); - List tree = GetFolderTree(suitcase.folderID); + List tree = GetFolderTree(principalID, suitcase.folderID); if (tree == null || (tree != null && tree.Count == 0)) return null; @@ -119,7 +118,7 @@ namespace OpenSim.Services.HypergridService folders.Add(ConvertToOpenSim(x)); } - SetAsRootFolder(suitcase, root); + SetAsNormalFolder(suitcase); folders.Add(ConvertToOpenSim(suitcase)); return folders; @@ -134,12 +133,11 @@ namespace OpenSim.Services.HypergridService userInventory.Items = new List(); XInventoryFolder suitcase = GetSuitcaseXFolder(userID); - XInventoryFolder root = GetRootXFolder(userID); - List tree = GetFolderTree(suitcase.folderID); + List tree = GetFolderTree(userID, suitcase.folderID); if (tree == null || (tree != null && tree.Count == 0)) { - SetAsRootFolder(suitcase, root); + SetAsNormalFolder(suitcase); userInventory.Folders.Add(ConvertToOpenSim(suitcase)); return userInventory; } @@ -164,7 +162,7 @@ namespace OpenSim.Services.HypergridService userInventory.Items.AddRange(items); } - SetAsRootFolder(suitcase, root); + SetAsNormalFolder(suitcase); userInventory.Folders.Add(ConvertToOpenSim(suitcase)); m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetUserInventory for user {0} returning {1} folders and {2} items", @@ -175,14 +173,13 @@ namespace OpenSim.Services.HypergridService public override InventoryFolderBase GetRootFolder(UUID principalID) { m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: GetRootFolder for {0}", principalID); - if (m_Database == null) - m_log.ErrorFormat("[XXX]: m_Database is NULL!"); // Let's find out the local root folder XInventoryFolder root = GetRootXFolder(principalID); ; if (root == null) { m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: Unable to retrieve local root folder for user {0}", principalID); + return null; } // Warp! Root folder for travelers is the suitcase folder @@ -202,7 +199,7 @@ namespace OpenSim.Services.HypergridService CreateSystemFolders(principalID, suitcase.folderID); } - SetAsRootFolder(suitcase, root); + SetAsNormalFolder(suitcase); return ConvertToOpenSim(suitcase); } @@ -271,9 +268,8 @@ namespace OpenSim.Services.HypergridService public override InventoryCollection GetFolderContent(UUID principalID, UUID folderID) { InventoryCollection coll = null; - XInventoryFolder suitcase = GetSuitcaseXFolder(principalID); - if (!IsWithinSuitcaseTree(folderID, suitcase)) + if (!IsWithinSuitcaseTree(principalID, folderID)) return new InventoryCollection(); coll = base.GetFolderContent(principalID, folderID); @@ -290,9 +286,7 @@ namespace OpenSim.Services.HypergridService { // Let's do a bit of sanity checking, more than the base service does // make sure the given folder exists under the suitcase tree of this user - XInventoryFolder suitcase = GetSuitcaseXFolder(principalID); - - if (!IsWithinSuitcaseTree(folderID, suitcase)) + if (!IsWithinSuitcaseTree(principalID, folderID)) return new List(); return base.GetFolderItems(principalID, folderID); @@ -303,21 +297,27 @@ namespace OpenSim.Services.HypergridService m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: AddFolder {0} {1}", folder.Name, folder.ParentID); // Let's do a bit of sanity checking, more than the base service does // make sure the given folder's parent folder exists under the suitcase tree of this user - XInventoryFolder suitcase = GetSuitcaseXFolder(folder.Owner); - if (!IsWithinSuitcaseTree(folder.ParentID, suitcase)) + if (!IsWithinSuitcaseTree(folder.Owner, folder.ParentID)) return false; // OK, it's legit - return base.AddFolder(folder); + if (base.AddFolder(folder)) + { + List tree; + if (m_SuitcaseTrees.TryGetValue(folder.Owner, out tree)) + tree.Add(ConvertFromOpenSim(folder)); + + return true; + } + + return false; } public override bool UpdateFolder(InventoryFolderBase folder) { - XInventoryFolder suitcase = GetSuitcaseXFolder(folder.Owner); - m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Update folder {0}, version {1}", folder.ID, folder.Version); - if (!IsWithinSuitcaseTree(folder.ID, suitcase)) + if (!IsWithinSuitcaseTree(folder.Owner, folder.ID)) { m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: folder {0} not within Suitcase tree", folder.Name); return false; @@ -329,9 +329,8 @@ namespace OpenSim.Services.HypergridService public override bool MoveFolder(InventoryFolderBase folder) { - XInventoryFolder suitcase = GetSuitcaseXFolder(folder.Owner); - - if (!IsWithinSuitcaseTree(folder.ID, suitcase) || !IsWithinSuitcaseTree(folder.ParentID, suitcase)) + if (!IsWithinSuitcaseTree(folder.Owner, folder.ID) || + !IsWithinSuitcaseTree(folder.Owner, folder.ParentID)) return false; return base.MoveFolder(folder); @@ -353,9 +352,7 @@ namespace OpenSim.Services.HypergridService { // Let's do a bit of sanity checking, more than the base service does // make sure the given folder's parent folder exists under the suitcase tree of this user - XInventoryFolder suitcase = GetSuitcaseXFolder(item.Owner); - - if (!IsWithinSuitcaseTree(item.Folder, suitcase)) + if (!IsWithinSuitcaseTree(item.Owner, item.Folder)) return false; // OK, it's legit @@ -365,9 +362,7 @@ namespace OpenSim.Services.HypergridService public override bool UpdateItem(InventoryItemBase item) { - XInventoryFolder suitcase = GetSuitcaseXFolder(item.Owner); - - if (!IsWithinSuitcaseTree(item.Folder, suitcase)) + if (!IsWithinSuitcaseTree(item.Owner, item.Folder)) return false; return base.UpdateItem(item); @@ -377,9 +372,7 @@ namespace OpenSim.Services.HypergridService { // Principal is b0rked. *sigh* - XInventoryFolder suitcase = GetSuitcaseXFolder(items[0].Owner); - - if (!IsWithinSuitcaseTree(items[0].Folder, suitcase)) + if (!IsWithinSuitcaseTree(items[0].Owner, items[0].Folder)) return false; return base.MoveItems(principalID, items); @@ -400,15 +393,8 @@ namespace OpenSim.Services.HypergridService item.Name, item.ID, item.Folder); return null; } - XInventoryFolder suitcase = GetSuitcaseXFolder(it.Owner); - if (suitcase == null) - { - m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Root or Suitcase are null for user {0}", - it.Owner); - return null; - } - if (!IsWithinSuitcaseTree(it.Folder, suitcase)) + if (!IsWithinSuitcaseTree(it.Owner, it.Folder)) { m_log.DebugFormat("[HG SUITCASE INVENTORY SERVICE]: Item {0} (folder {1}) is not within Suitcase", it.Name, it.Folder); @@ -431,9 +417,7 @@ namespace OpenSim.Services.HypergridService if (f != null) { - XInventoryFolder suitcase = GetSuitcaseXFolder(f.Owner); - - if (!IsWithinSuitcaseTree(f.ID, suitcase)) + if (!IsWithinSuitcaseTree(f.Owner, f.ID)) return null; } @@ -481,22 +465,37 @@ namespace OpenSim.Services.HypergridService if (folders != null && folders.Length > 0) return folders[0]; + + // check to see if we have the old Suitcase folder + folders = m_Database.GetFolders( + new string[] { "agentID", "folderName", "parentFolderID" }, + new string[] { principalID.ToString(), "My Suitcase", UUID.Zero.ToString() }); + if (folders != null && folders.Length > 0) + { + // Move it to under the root folder + XInventoryFolder root = GetRootXFolder(principalID); + folders[0].parentFolderID = root.folderID; + folders[0].type = 100; + m_Database.StoreFolder(folders[0]); + return folders[0]; + } + return null; } - private void SetAsRootFolder(XInventoryFolder suitcase, XInventoryFolder root) + private void SetAsNormalFolder(XInventoryFolder suitcase) { suitcase.type = (short)AssetType.Folder; } - private List GetFolderTree(UUID folder) + private List GetFolderTree(UUID principalID, UUID folder) { List t = null; - if (m_SuitcaseTrees.TryGetValue(folder, out t)) + if (m_SuitcaseTrees.TryGetValue(principalID, out t)) return t; t = GetFolderTreeRecursive(folder); - m_SuitcaseTrees.AddOrUpdate(folder, t, 120); + m_SuitcaseTrees.AddOrUpdate(principalID, t, 5*60); // 5minutes return t; } @@ -528,11 +527,18 @@ namespace OpenSim.Services.HypergridService /// /// /// - private bool IsWithinSuitcaseTree(UUID folderID, XInventoryFolder suitcase) + private bool IsWithinSuitcaseTree(UUID principalID, UUID folderID) { + XInventoryFolder suitcase = GetSuitcaseXFolder(principalID); + if (suitcase == null) + { + m_log.WarnFormat("[HG SUITCASE INVENTORY SERVICE]: User {0} does not have a Suitcase folder", principalID); + return false; + } + List tree = new List(); tree.Add(suitcase); // Warp! the tree is the real root folder plus the children of the suitcase folder - tree.AddRange(GetFolderTree(suitcase.folderID)); + tree.AddRange(GetFolderTree(principalID, suitcase.folderID)); XInventoryFolder f = tree.Find(delegate(XInventoryFolder fl) { if (fl.folderID == folderID) return true; diff --git a/OpenSim/Services/Interfaces/ISimulationService.cs b/OpenSim/Services/Interfaces/ISimulationService.cs index 7940256ab5..a963b8e5b5 100644 --- a/OpenSim/Services/Interfaces/ISimulationService.cs +++ b/OpenSim/Services/Interfaces/ISimulationService.cs @@ -35,7 +35,17 @@ namespace OpenSim.Services.Interfaces { public interface ISimulationService { - IScene GetScene(ulong regionHandle); + /// + /// Retrieve the scene with the given region ID. + /// + /// + /// Region identifier. + /// + /// + /// The scene. + /// + IScene GetScene(UUID regionId); + ISimulationService GetInnerService(); #region Agents @@ -108,16 +118,6 @@ namespace OpenSim.Services.Interfaces /// bool CreateObject(GridRegion destination, Vector3 newPosition, ISceneObject sog, bool isLocalCall); - /// - /// Create an object from the user's inventory in the destination region. - /// This message is used primarily by clients. - /// - /// - /// - /// - /// - bool CreateObject(GridRegion destination, UUID userID, UUID itemID); - #endregion Objects } diff --git a/OpenSim/Services/InventoryService/XInventoryService.cs b/OpenSim/Services/InventoryService/XInventoryService.cs index 0e7a3584e2..7518b86f0b 100644 --- a/OpenSim/Services/InventoryService/XInventoryService.cs +++ b/OpenSim/Services/InventoryService/XInventoryService.cs @@ -52,6 +52,7 @@ namespace OpenSim.Services.InventoryService : this(config, "InventoryService") { } + public XInventoryService(IConfigSource config, string configName) : base(config) { if (configName != string.Empty) @@ -301,46 +302,62 @@ namespace OpenSim.Services.InventoryService public virtual bool AddFolder(InventoryFolderBase folder) { - //m_log.DebugFormat("[XINVENTORY]: Add folder {0} type {1} in parent {2}", folder.Name, folder.Type, folder.ParentID); +// m_log.DebugFormat("[XINVENTORY]: Add folder {0} type {1} in parent {2}", folder.Name, folder.Type, folder.ParentID); + InventoryFolderBase check = GetFolder(folder); if (check != null) return false; - if (folder.Type == (short)AssetType.Folder || folder.Type == (short)AssetType.Unknown || - GetFolderForType(folder.Owner, (AssetType)(folder.Type)) == null) + if (folder.Type == (short)AssetType.Folder + || folder.Type == (short)AssetType.Unknown + || folder.Type == (short)AssetType.OutfitFolder + || GetFolderForType(folder.Owner, (AssetType)(folder.Type)) == null) { XInventoryFolder xFolder = ConvertFromOpenSim(folder); return m_Database.StoreFolder(xFolder); } else - m_log.DebugFormat("[XINVENTORY]: Folder {0} of type {1} already exists", folder.Name, folder.Type); + { + m_log.WarnFormat( + "[XINVENTORY]: Folder of type {0} already exists when tried to add {1} to {2} for {3}", + folder.Type, folder.Name, folder.ParentID, folder.Owner); + } return false; } public virtual bool UpdateFolder(InventoryFolderBase folder) { - //m_log.DebugFormat("[XINVENTORY]: Update folder {0} {1} ({2})", folder.Name, folder.Type, folder.ID); +// m_log.DebugFormat("[XINVENTORY]: Update folder {0} {1} ({2})", folder.Name, folder.Type, folder.ID); + XInventoryFolder xFolder = ConvertFromOpenSim(folder); InventoryFolderBase check = GetFolder(folder); + if (check == null) return AddFolder(folder); - if (check.Type != -1 || xFolder.type != -1) + if ((check.Type != (short)AssetType.Unknown || xFolder.type != (short)AssetType.Unknown) + && (check.Type != (short)AssetType.OutfitFolder || xFolder.type != (short)AssetType.OutfitFolder)) { if (xFolder.version < check.Version) { - //m_log.DebugFormat("[XINVENTORY]: {0} < {1} can't do", xFolder.version, check.Version); +// m_log.DebugFormat("[XINVENTORY]: {0} < {1} can't do", xFolder.version, check.Version); return false; } + check.Version = (ushort)xFolder.version; xFolder = ConvertFromOpenSim(check); - //m_log.DebugFormat("[XINVENTORY]: Storing {0} {1} {2}", xFolder.folderName, xFolder.version, xFolder.type); + +// m_log.DebugFormat( +// "[XINVENTORY]: Storing version only update to system folder {0} {1} {2}", +// xFolder.folderName, xFolder.version, xFolder.type); + return m_Database.StoreFolder(xFolder); } if (xFolder.version < check.Version) xFolder.version = check.Version; + xFolder.folderID = check.ID; return m_Database.StoreFolder(xFolder); @@ -363,6 +380,11 @@ namespace OpenSim.Services.InventoryService // We don't check the principal's ID here // public virtual bool DeleteFolders(UUID principalID, List folderIDs) + { + return DeleteFolders(principalID, folderIDs, true); + } + + public virtual bool DeleteFolders(UUID principalID, List folderIDs, bool onlyIfTrash) { if (!m_AllowDelete) return false; @@ -371,11 +393,12 @@ namespace OpenSim.Services.InventoryService // foreach (UUID id in folderIDs) { - if (!ParentIsTrash(id)) + if (onlyIfTrash && !ParentIsTrash(id)) continue; + //m_log.InfoFormat("[XINVENTORY SERVICE]: Delete folder {0}", id); InventoryFolderBase f = new InventoryFolderBase(); f.ID = id; - PurgeFolder(f); + PurgeFolder(f, onlyIfTrash); m_Database.DeleteFolders("folderID", id.ToString()); } @@ -383,11 +406,16 @@ namespace OpenSim.Services.InventoryService } public virtual bool PurgeFolder(InventoryFolderBase folder) + { + return PurgeFolder(folder, true); + } + + public virtual bool PurgeFolder(InventoryFolderBase folder, bool onlyIfTrash) { if (!m_AllowDelete) return false; - if (!ParentIsTrash(folder.ID)) + if (onlyIfTrash && !ParentIsTrash(folder.ID)) return false; XInventoryFolder[] subFolders = m_Database.GetFolders( @@ -396,7 +424,7 @@ namespace OpenSim.Services.InventoryService foreach (XInventoryFolder x in subFolders) { - PurgeFolder(ConvertToOpenSim(x)); + PurgeFolder(ConvertToOpenSim(x), onlyIfTrash); m_Database.DeleteFolders("folderID", x.folderID.ToString()); } @@ -408,14 +436,13 @@ namespace OpenSim.Services.InventoryService public virtual bool AddItem(InventoryItemBase item) { // m_log.DebugFormat( -// "[XINVENTORY SERVICE]: Adding item {0} to folder {1} for {2}", item.ID, item.Folder, item.Owner); +// "[XINVENTORY SERVICE]: Adding item {0} {1} to folder {2} for {3}", item.Name, item.ID, item.Folder, item.Owner); return m_Database.StoreItem(ConvertFromOpenSim(item)); } public virtual bool UpdateItem(InventoryItemBase item) { -// throw new Exception("urrgh"); if (!m_AllowDelete) if (item.AssetType == (sbyte)AssetType.Link || item.AssetType == (sbyte)AssetType.LinkFolder) return false; diff --git a/OpenSim/Services/LLLoginService/LLLoginResponse.cs b/OpenSim/Services/LLLoginService/LLLoginResponse.cs index 079bcb17ed..a4b3cbd16e 100644 --- a/OpenSim/Services/LLLoginService/LLLoginResponse.cs +++ b/OpenSim/Services/LLLoginService/LLLoginResponse.cs @@ -231,7 +231,8 @@ namespace OpenSim.Services.LLLoginService public LLLoginResponse(UserAccount account, AgentCircuitData aCircuit, GridUserInfo pinfo, GridRegion destination, List invSkel, FriendInfo[] friendsList, ILibraryService libService, string where, string startlocation, Vector3 position, Vector3 lookAt, List gestures, string message, - GridRegion home, IPEndPoint clientIP, string mapTileURL, string profileURL, string openIDURL, string searchURL, string currency) + GridRegion home, IPEndPoint clientIP, string mapTileURL, string profileURL, string openIDURL, string searchURL, string currency, + string DSTZone) : this() { FillOutInventoryData(invSkel, libService); @@ -260,7 +261,45 @@ namespace OpenSim.Services.LLLoginService FillOutRegionData(destination); FillOutSeedCap(aCircuit, destination, clientIP); - + + switch (DSTZone) + { + case "none": + DST = "N"; + break; + case "local": + DST = TimeZone.CurrentTimeZone.IsDaylightSavingTime(DateTime.Now) ? "Y" : "N"; + break; + default: + TimeZoneInfo dstTimeZone = null; + string[] tzList = DSTZone.Split(';'); + + foreach (string tzName in tzList) + { + try + { + dstTimeZone = TimeZoneInfo.FindSystemTimeZoneById(tzName); + } + catch + { + continue; + } + break; + } + + if (dstTimeZone == null) + { + m_log.WarnFormat( + "[LLOGIN RESPONSE]: No valid timezone found for DST in {0}, falling back to system time.", tzList); + DST = TimeZone.CurrentTimeZone.IsDaylightSavingTime(DateTime.Now) ? "Y" : "N"; + } + else + { + DST = dstTimeZone.IsDaylightSavingTime(DateTime.Now) ? "Y" : "N"; + } + + break; + } } private void FillOutInventoryData(List invSkel, ILibraryService libService) @@ -355,7 +394,31 @@ namespace OpenSim.Services.LLLoginService private void SetDefaultValues() { - DST = TimeZone.CurrentTimeZone.IsDaylightSavingTime(DateTime.Now) ? "Y" : "N"; + TimeZoneInfo gridTimeZone; + + // Disabled for now pending making timezone a config value, which can at some point have a default of + // a ; separated list of possible timezones. + // The problem here is that US/Pacific (or even the Olsen America/Los_Angeles) is not universal across + // windows, mac and various distributions of linux, introducing another element of consistency. + // The server operator needs to be able to control this setting +// try +// { +// // First try to fetch DST from Pacific Standard Time, because this is +// // the one expected by the viewer. "US/Pacific" is the string to search +// // on linux and mac, and should work also on Windows (to confirm) +// gridTimeZone = TimeZoneInfo.FindSystemTimeZoneById("US/Pacific"); +// } +// catch (Exception e) +// { +// m_log.WarnFormat( +// "[TIMEZONE]: {0} Falling back to system time. System time should be set to Pacific Standard Time to provide the expected time", +// e.Message); + + gridTimeZone = TimeZoneInfo.Local; +// } + + DST = gridTimeZone.IsDaylightSavingTime(DateTime.Now) ? "Y" : "N"; + StipendSinceLogin = "N"; Gendered = "Y"; EverLoggedIn = "Y"; diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index 891c452b07..ed887d9753 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs @@ -82,6 +82,8 @@ namespace OpenSim.Services.LLLoginService protected string m_AllowedClients; protected string m_DeniedClients; + protected string m_DSTZone; + IConfig m_LoginServerConfig; // IConfig m_ClientsConfig; @@ -118,6 +120,8 @@ namespace OpenSim.Services.LLLoginService m_AllowedClients = m_LoginServerConfig.GetString("AllowedClients", string.Empty); m_DeniedClients = m_LoginServerConfig.GetString("DeniedClients", string.Empty); + m_DSTZone = m_LoginServerConfig.GetString("DSTZone", "America/Los_Angeles;Pacific Standard Time"); + // Clean up some of these vars if (m_MapTileURL != String.Empty) { @@ -241,6 +245,7 @@ namespace OpenSim.Services.LLLoginService m_log.InfoFormat("[LLOGIN SERVICE]: Login request for {0} {1} at {2} using viewer {3}, channel {4}, IP {5}, Mac {6}, Id0 {7}", firstName, lastName, startLocation, clientVersion, channel, clientIP.Address.ToString(), mac, id0); + try { // @@ -253,7 +258,9 @@ namespace OpenSim.Services.LLLoginService if (!am.Success) { - m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: client {0} is not allowed", clientVersion); + m_log.InfoFormat( + "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: client {2} is not allowed", + firstName, lastName, clientVersion); return LLFailedLoginResponse.LoginBlockedProblem; } } @@ -265,7 +272,9 @@ namespace OpenSim.Services.LLLoginService if (dm.Success) { - m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: client {0} is denied", clientVersion); + m_log.InfoFormat( + "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: client {2} is denied", + firstName, lastName, clientVersion); return LLFailedLoginResponse.LoginBlockedProblem; } } @@ -276,7 +285,8 @@ namespace OpenSim.Services.LLLoginService UserAccount account = m_UserAccountService.GetUserAccount(scopeID, firstName, lastName); if (account == null) { - m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: user not found"); + m_log.InfoFormat( + "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: user not found", firstName, lastName); return LLFailedLoginResponse.UserProblem; } @@ -288,7 +298,9 @@ namespace OpenSim.Services.LLLoginService if (account.UserLevel < m_MinLoginLevel) { - m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: login is blocked for user level {0}", account.UserLevel); + m_log.InfoFormat( + "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: user level is {2} but minimum login level is {3}", + firstName, lastName, m_MinLoginLevel, account.UserLevel); return LLFailedLoginResponse.LoginBlockedProblem; } @@ -299,7 +311,8 @@ namespace OpenSim.Services.LLLoginService { if (account.ScopeID != scopeID && account.ScopeID != UUID.Zero) { - m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: user not found"); + m_log.InfoFormat( + "[LLOGIN SERVICE]: Login failed, reason: user {0} {1} not found", firstName, lastName); return LLFailedLoginResponse.UserProblem; } } @@ -318,7 +331,9 @@ namespace OpenSim.Services.LLLoginService UUID secureSession = UUID.Zero; if ((token == string.Empty) || (token != string.Empty && !UUID.TryParse(token, out secureSession))) { - m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: authentication failed"); + m_log.InfoFormat( + "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: authentication failed", + firstName, lastName); return LLFailedLoginResponse.UserProblem; } @@ -327,13 +342,18 @@ namespace OpenSim.Services.LLLoginService // if (m_RequireInventory && m_InventoryService == null) { - m_log.WarnFormat("[LLOGIN SERVICE]: Login failed, reason: inventory service not set up"); + m_log.WarnFormat( + "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: inventory service not set up", + firstName, lastName); return LLFailedLoginResponse.InventoryProblem; } + List inventorySkel = m_InventoryService.GetInventorySkeleton(account.PrincipalID); if (m_RequireInventory && ((inventorySkel == null) || (inventorySkel != null && inventorySkel.Count == 0))) { - m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: unable to retrieve user inventory"); + m_log.InfoFormat( + "[LLOGIN SERVICE]: Login failed, for {0} {1}, reason: unable to retrieve user inventory", + firstName, lastName); return LLFailedLoginResponse.InventoryProblem; } @@ -347,9 +367,12 @@ namespace OpenSim.Services.LLLoginService if (m_PresenceService != null) { success = m_PresenceService.LoginAgent(account.PrincipalID.ToString(), session, secureSession); + if (!success) { - m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: could not login presence"); + m_log.InfoFormat( + "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: could not login presence", + firstName, lastName); return LLFailedLoginResponse.GridProblem; } } @@ -382,9 +405,18 @@ namespace OpenSim.Services.LLLoginService if (destination == null) { m_PresenceService.LogoutAgent(session); - m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: destination not found"); + + m_log.InfoFormat( + "[LLOGIN SERVICE]: Login failed for {0} {1}, reason: destination not found", + firstName, lastName); return LLFailedLoginResponse.GridProblem; } + else + { + m_log.DebugFormat( + "[LLOGIN SERVICE]: Found destination {0}, endpoint {1} for {2} {3}", + destination.RegionName, destination.ExternalEndPoint, firstName, lastName); + } if (account.UserLevel >= 200) flags |= TeleportFlags.Godlike; @@ -408,7 +440,7 @@ namespace OpenSim.Services.LLLoginService if (aCircuit == null) { m_PresenceService.LogoutAgent(session); - m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: {0}", reason); + m_log.InfoFormat("[LLOGIN SERVICE]: Login failed for {0} {1}, reason: {2}", firstName, lastName, reason); return new LLFailedLoginResponse("key", reason, "false"); } @@ -423,10 +455,14 @@ namespace OpenSim.Services.LLLoginService // // Finally, fill out the response and return it // - LLLoginResponse response = new LLLoginResponse(account, aCircuit, guinfo, destination, inventorySkel, friendsList, m_LibraryService, - where, startLocation, position, lookAt, gestures, m_WelcomeMessage, home, clientIP, m_MapTileURL, m_ProfileURL, m_OpenIDURL, m_SearchURL, m_Currency); + LLLoginResponse response + = new LLLoginResponse( + account, aCircuit, guinfo, destination, inventorySkel, friendsList, m_LibraryService, + where, startLocation, position, lookAt, gestures, m_WelcomeMessage, home, clientIP, + m_MapTileURL, m_ProfileURL, m_OpenIDURL, m_SearchURL, m_Currency, m_DSTZone); + + m_log.DebugFormat("[LLOGIN SERVICE]: All clear. Sending login response to {0} {1}", firstName, lastName); - m_log.DebugFormat("[LLOGIN SERVICE]: All clear. Sending login response to client."); return response; } catch (Exception e) @@ -438,11 +474,16 @@ namespace OpenSim.Services.LLLoginService } } - protected GridRegion FindDestination(UserAccount account, UUID scopeID, GridUserInfo pinfo, UUID sessionID, string startLocation, GridRegion home, out GridRegion gatekeeper, out string where, out Vector3 position, out Vector3 lookAt, out TeleportFlags flags) + protected GridRegion FindDestination( + UserAccount account, UUID scopeID, GridUserInfo pinfo, UUID sessionID, string startLocation, + GridRegion home, out GridRegion gatekeeper, + out string where, out Vector3 position, out Vector3 lookAt, out TeleportFlags flags) { flags = TeleportFlags.ViaLogin; - m_log.DebugFormat("[LLOGIN SERVICE]: FindDestination for start location {0}", startLocation); + m_log.DebugFormat( + "[LLOGIN SERVICE]: Finding destination matching start location {0} for {1}", + startLocation, account.Name); gatekeeper = null; where = "home"; diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs index 318758d984..769de83c9c 100644 --- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs @@ -58,57 +58,74 @@ namespace OpenSim.Tests.Common /// public class SceneHelpers { - public static TestScene SetupScene() + /// + /// We need a scene manager so that test clients can retrieve a scene when performing teleport tests. + /// + public SceneManager SceneManager { get; private set; } + + private AgentCircuitManager m_acm = new AgentCircuitManager(); + private ISimulationDataService m_simDataService + = OpenSim.Server.Base.ServerUtils.LoadPlugin("OpenSim.Tests.Common.dll", null); + private IEstateDataService m_estateDataService = null; + + private LocalAssetServicesConnector m_assetService; + private LocalAuthenticationServicesConnector m_authenticationService; + private LocalInventoryServicesConnector m_inventoryService; + private LocalGridServicesConnector m_gridService; + private LocalUserAccountServicesConnector m_userAccountService; + private LocalPresenceServicesConnector m_presenceService; + + private CoreAssetCache m_cache; + + public SceneHelpers() : this(null) {} + + public SceneHelpers(CoreAssetCache cache) { - return SetupScene(null); + SceneManager = new SceneManager(); + + m_assetService = StartAssetService(cache); + m_authenticationService = StartAuthenticationService(); + m_inventoryService = StartInventoryService(); + m_gridService = StartGridService(); + m_userAccountService = StartUserAccountService(); + m_presenceService = StartPresenceService(); + + m_inventoryService.PostInitialise(); + m_assetService.PostInitialise(); + m_userAccountService.PostInitialise(); + m_presenceService.PostInitialise(); + + m_cache = cache; } /// /// Set up a test scene /// /// - /// Automatically starts service threads, as would the normal runtime. + /// Automatically starts services, as would the normal runtime. /// /// - public static TestScene SetupScene(CoreAssetCache cache) + public TestScene SetupScene() { - return SetupScene("Unit test region", UUID.Random(), 1000, 1000, cache); + return SetupScene("Unit test region", UUID.Random(), 1000, 1000); } - public static TestScene SetupScene(string name, UUID id, uint x, uint y) + public TestScene SetupScene(string name, UUID id, uint x, uint y) { - return SetupScene(name, id, x, y, null); + return SetupScene(name, id, x, y, new IniConfigSource()); } /// - /// Set up a scene. If it's more then one scene, use the same CommunicationsManager to link regions - /// or a different, to get a brand new scene with new shared region modules. + /// Set up a scene. /// /// Name of the region /// ID of the region /// X co-ordinate of the region /// Y co-ordinate of the region - /// - /// - public static TestScene SetupScene( - string name, UUID id, uint x, uint y, CoreAssetCache cache) - { - return SetupScene(name, id, x, y, cache, new IniConfigSource()); - } - - /// - /// Set up a scene. If it's more then one scene, use the same CommunicationsManager to link regions - /// or a different, to get a brand new scene with new shared region modules. - /// - /// Name of the region - /// ID of the region - /// X co-ordinate of the region - /// Y co-ordinate of the region - /// /// /// - public static TestScene SetupScene( - string name, UUID id, uint x, uint y, CoreAssetCache cache, IConfigSource configSource) + public TestScene SetupScene( + string name, UUID id, uint x, uint y, IConfigSource configSource) { Console.WriteLine("Setting up test scene {0}", name); @@ -119,30 +136,47 @@ namespace OpenSim.Tests.Common regInfo.RegionName = name; regInfo.RegionID = id; - AgentCircuitManager acm = new AgentCircuitManager(); SceneCommunicationService scs = new SceneCommunicationService(); - ISimulationDataService simDataService = OpenSim.Server.Base.ServerUtils.LoadPlugin("OpenSim.Tests.Common.dll", null); - IEstateDataService estateDataService = null; - TestScene testScene = new TestScene( - regInfo, acm, scs, simDataService, estateDataService, null, false, configSource, null); + regInfo, m_acm, scs, m_simDataService, m_estateDataService, null, false, configSource, null); IRegionModule godsModule = new GodsModule(); godsModule.Initialise(testScene, new IniConfigSource()); testScene.AddModule(godsModule.Name, godsModule); - LocalAssetServicesConnector assetService = StartAssetService(testScene, cache); - StartAuthenticationService(testScene); - LocalInventoryServicesConnector inventoryService = StartInventoryService(testScene); - StartGridService(testScene); - LocalUserAccountServicesConnector userAccountService = StartUserAccountService(testScene); - LocalPresenceServicesConnector presenceService = StartPresenceService(testScene); + // Add scene to services + m_assetService.AddRegion(testScene); - inventoryService.PostInitialise(); - assetService.PostInitialise(); - userAccountService.PostInitialise(); - presenceService.PostInitialise(); + if (m_cache != null) + { + m_cache.AddRegion(testScene); + m_cache.RegionLoaded(testScene); + testScene.AddRegionModule(m_cache.Name, m_cache); + } + + m_assetService.RegionLoaded(testScene); + testScene.AddRegionModule(m_assetService.Name, m_assetService); + + m_authenticationService.AddRegion(testScene); + m_authenticationService.RegionLoaded(testScene); + testScene.AddRegionModule(m_authenticationService.Name, m_authenticationService); + + m_inventoryService.AddRegion(testScene); + m_inventoryService.RegionLoaded(testScene); + testScene.AddRegionModule(m_inventoryService.Name, m_inventoryService); + + m_gridService.AddRegion(testScene); + m_gridService.RegionLoaded(testScene); + testScene.AddRegionModule(m_gridService.Name, m_gridService); + + m_userAccountService.AddRegion(testScene); + m_userAccountService.RegionLoaded(testScene); + testScene.AddRegionModule(m_userAccountService.Name, m_userAccountService); + + m_presenceService.AddRegion(testScene); + m_presenceService.RegionLoaded(testScene); + testScene.AddRegionModule(m_presenceService.Name, m_presenceService); testScene.RegionInfo.EstateSettings.EstateOwner = UUID.Random(); testScene.SetModuleInterfaces(); @@ -153,28 +187,28 @@ namespace OpenSim.Tests.Common PhysicsPluginManager physicsPluginManager = new PhysicsPluginManager(); physicsPluginManager.LoadPluginsFromAssembly("Physics/OpenSim.Region.Physics.BasicPhysicsPlugin.dll"); testScene.PhysicsScene - = physicsPluginManager.GetPhysicsScene("basicphysics", "ZeroMesher", new IniConfigSource(), "test"); + = physicsPluginManager.GetPhysicsScene("basicphysics", "ZeroMesher", new IniConfigSource(), "test"); testScene.RegionInfo.EstateSettings = new EstateSettings(); testScene.LoginsDisabled = false; testScene.RegisterRegionWithGrid(); + SceneManager.Add(testScene); + return testScene; } - private static LocalAssetServicesConnector StartAssetService(Scene testScene, CoreAssetCache cache) + private static LocalAssetServicesConnector StartAssetService(CoreAssetCache cache) { - LocalAssetServicesConnector assetService = new LocalAssetServicesConnector(); IConfigSource config = new IniConfigSource(); - config.AddConfig("Modules"); config.Configs["Modules"].Set("AssetServices", "LocalAssetServicesConnector"); config.AddConfig("AssetService"); config.Configs["AssetService"].Set("LocalServiceModule", "OpenSim.Services.AssetService.dll:AssetService"); config.Configs["AssetService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); - + + LocalAssetServicesConnector assetService = new LocalAssetServicesConnector(); assetService.Initialise(config); - assetService.AddRegion(testScene); if (cache != null) { @@ -184,56 +218,43 @@ namespace OpenSim.Tests.Common cacheConfig.AddConfig("AssetCache"); cache.Initialise(cacheConfig); - cache.AddRegion(testScene); - cache.RegionLoaded(testScene); - testScene.AddRegionModule(cache.Name, cache); } - - assetService.RegionLoaded(testScene); - testScene.AddRegionModule(assetService.Name, assetService); return assetService; } - private static void StartAuthenticationService(Scene testScene) + private static LocalAuthenticationServicesConnector StartAuthenticationService() { - ISharedRegionModule service = new LocalAuthenticationServicesConnector(); IConfigSource config = new IniConfigSource(); - config.AddConfig("Modules"); config.AddConfig("AuthenticationService"); config.Configs["Modules"].Set("AuthenticationServices", "LocalAuthenticationServicesConnector"); config.Configs["AuthenticationService"].Set( "LocalServiceModule", "OpenSim.Services.AuthenticationService.dll:PasswordAuthenticationService"); config.Configs["AuthenticationService"].Set("StorageProvider", "OpenSim.Data.Null.dll"); - + + LocalAuthenticationServicesConnector service = new LocalAuthenticationServicesConnector(); service.Initialise(config); - service.AddRegion(testScene); - service.RegionLoaded(testScene); - testScene.AddRegionModule(service.Name, service); - //m_authenticationService = service; + + return service; } - private static LocalInventoryServicesConnector StartInventoryService(Scene testScene) + private static LocalInventoryServicesConnector StartInventoryService() { - LocalInventoryServicesConnector inventoryService = new LocalInventoryServicesConnector(); - IConfigSource config = new IniConfigSource(); config.AddConfig("Modules"); config.AddConfig("InventoryService"); config.Configs["Modules"].Set("InventoryServices", "LocalInventoryServicesConnector"); config.Configs["InventoryService"].Set("LocalServiceModule", "OpenSim.Services.InventoryService.dll:InventoryService"); config.Configs["InventoryService"].Set("StorageProvider", "OpenSim.Tests.Common.dll"); - + + LocalInventoryServicesConnector inventoryService = new LocalInventoryServicesConnector(); inventoryService.Initialise(config); - inventoryService.AddRegion(testScene); - inventoryService.RegionLoaded(testScene); - testScene.AddRegionModule(inventoryService.Name, inventoryService); return inventoryService; } - private static LocalGridServicesConnector StartGridService(Scene testScene) + private static LocalGridServicesConnector StartGridService() { IConfigSource config = new IniConfigSource(); config.AddConfig("Modules"); @@ -245,8 +266,6 @@ namespace OpenSim.Tests.Common LocalGridServicesConnector gridService = new LocalGridServicesConnector(); gridService.Initialise(config); - gridService.AddRegion(testScene); - gridService.RegionLoaded(testScene); return gridService; } @@ -256,7 +275,7 @@ namespace OpenSim.Tests.Common /// /// /// - private static LocalUserAccountServicesConnector StartUserAccountService(Scene testScene) + private static LocalUserAccountServicesConnector StartUserAccountService() { IConfigSource config = new IniConfigSource(); config.AddConfig("Modules"); @@ -268,10 +287,6 @@ namespace OpenSim.Tests.Common LocalUserAccountServicesConnector userAccountService = new LocalUserAccountServicesConnector(); userAccountService.Initialise(config); - - userAccountService.AddRegion(testScene); - userAccountService.RegionLoaded(testScene); - testScene.AddRegionModule(userAccountService.Name, userAccountService); return userAccountService; } @@ -280,7 +295,7 @@ namespace OpenSim.Tests.Common /// Start a presence service /// /// - private static LocalPresenceServicesConnector StartPresenceService(Scene testScene) + private static LocalPresenceServicesConnector StartPresenceService() { IConfigSource config = new IniConfigSource(); config.AddConfig("Modules"); @@ -292,10 +307,6 @@ namespace OpenSim.Tests.Common LocalPresenceServicesConnector presenceService = new LocalPresenceServicesConnector(); presenceService.Initialise(config); - - presenceService.AddRegion(testScene); - presenceService.RegionLoaded(testScene); - testScene.AddRegionModule(presenceService.Name, presenceService); return presenceService; } @@ -313,19 +324,52 @@ namespace OpenSim.Tests.Common /// /// Setup modules for a scene. /// - /// + /// + /// If called directly, then all the modules must be shared modules. + /// + /// /// /// public static void SetupSceneModules(Scene scene, IConfigSource config, params object[] modules) + { + SetupSceneModules(new Scene[] { scene }, config, modules); + } + + /// + /// Setup modules for a scene using their default settings. + /// + /// + /// + public static void SetupSceneModules(Scene[] scenes, params object[] modules) + { + SetupSceneModules(scenes, new IniConfigSource(), modules); + } + + /// + /// Setup modules for scenes. + /// + /// + /// If called directly, then all the modules must be shared modules. + /// + /// + /// + /// + public static void SetupSceneModules(Scene[] scenes, IConfigSource config, params object[] modules) { List newModules = new List(); foreach (object module in modules) { +// Console.WriteLine("MODULE RAW {0}", module); if (module is IRegionModule) { IRegionModule m = (IRegionModule)module; - m.Initialise(scene, config); - scene.AddModule(m.Name, m); + + foreach (Scene scene in scenes) + { + m.Initialise(scene, config); + scene.AddModule(m.Name, m); + } + m.PostInitialise(); } else if (module is IRegionModuleBase) @@ -333,6 +377,7 @@ namespace OpenSim.Tests.Common // for the new system, everything has to be initialised first, // shared modules have to be post-initialised, then all get an AddRegion with the scene IRegionModuleBase m = (IRegionModuleBase)module; +// Console.WriteLine("MODULE {0}", m.Name); m.Initialise(config); newModules.Add(m); } @@ -345,15 +390,19 @@ namespace OpenSim.Tests.Common foreach (IRegionModuleBase module in newModules) { - module.AddRegion(scene); - scene.AddRegionModule(module.Name, module); + foreach (Scene scene in scenes) + { + module.AddRegion(scene); + scene.AddRegionModule(module.Name, module); + } } // RegionLoaded is fired after all modules have been appropriately added to all scenes foreach (IRegionModuleBase module in newModules) - module.RegionLoaded(scene); + foreach (Scene scene in scenes) + module.RegionLoaded(scene); - scene.SetModuleInterfaces(); + foreach (Scene scene in scenes) { scene.SetModuleInterfaces(); } } /// @@ -363,31 +412,61 @@ namespace OpenSim.Tests.Common /// public static AgentCircuitData GenerateAgentData(UUID agentId) { - string firstName = "testfirstname"; + AgentCircuitData acd = GenerateCommonAgentData(); - AgentCircuitData agentData = new AgentCircuitData(); - agentData.AgentID = agentId; - agentData.firstname = firstName; - agentData.lastname = "testlastname"; + acd.AgentID = agentId; + acd.firstname = "testfirstname"; + acd.lastname = "testlastname"; + acd.ServiceURLs = new Dictionary(); + + return acd; + } + + /// + /// Generate some standard agent connection data. + /// + /// + /// + public static AgentCircuitData GenerateAgentData(UserAccount ua) + { + AgentCircuitData acd = GenerateCommonAgentData(); + + acd.AgentID = ua.PrincipalID; + acd.firstname = ua.FirstName; + acd.lastname = ua.LastName; + acd.ServiceURLs = ua.ServiceURLs; + + return acd; + } + + private static AgentCircuitData GenerateCommonAgentData() + { + AgentCircuitData acd = new AgentCircuitData(); // XXX: Sessions must be unique, otherwise one presence can overwrite another in NullPresenceData. - agentData.SessionID = UUID.Random(); - agentData.SecureSessionID = UUID.Random(); + acd.SessionID = UUID.Random(); + acd.SecureSessionID = UUID.Random(); - agentData.circuitcode = 123; - agentData.BaseFolder = UUID.Zero; - agentData.InventoryFolder = UUID.Zero; - agentData.startpos = Vector3.Zero; - agentData.CapsPath = "http://wibble.com"; - agentData.ServiceURLs = new Dictionary(); - agentData.Appearance = new AvatarAppearance(); + acd.circuitcode = 123; + acd.BaseFolder = UUID.Zero; + acd.InventoryFolder = UUID.Zero; + acd.startpos = Vector3.Zero; + acd.CapsPath = "http://wibble.com"; + acd.Appearance = new AvatarAppearance(); - return agentData; + return acd; } /// /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test /// + /// + /// This can be used for tests where there is only one region or where there are multiple non-neighbour regions + /// and teleport doesn't take place. + /// + /// XXX: Use the version of this method that takes the UserAccount structure wherever possible - this will + /// make the agent circuit data (e.g. first, lastname) consistent with the user account data. + /// /// /// /// @@ -396,6 +475,33 @@ namespace OpenSim.Tests.Common return AddScenePresence(scene, GenerateAgentData(agentId)); } + /// + /// Add a root agent where the details of the agent connection (apart from the id) are unimportant for the test + /// + /// + /// XXX: Use the version of this method that takes the UserAccount structure wherever possible - this will + /// make the agent circuit data (e.g. first, lastname) consistent with the user account data. + /// + /// + /// + /// + /// + public static ScenePresence AddScenePresence(Scene scene, UUID agentId, SceneManager sceneManager) + { + return AddScenePresence(scene, GenerateAgentData(agentId), sceneManager); + } + + /// + /// Add a root agent. + /// + /// + /// + /// + public static ScenePresence AddScenePresence(Scene scene, UserAccount ua) + { + return AddScenePresence(scene, GenerateAgentData(ua)); + } + /// /// Add a root agent. /// @@ -415,6 +521,30 @@ namespace OpenSim.Tests.Common /// /// public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData) + { + return AddScenePresence(scene, agentData, null); + } + + /// + /// Add a root agent. + /// + /// + /// This function + /// + /// 1) Tells the scene that an agent is coming. Normally, the login service (local if standalone, from the + /// userserver if grid) would give initial login data back to the client and separately tell the scene that the + /// agent was coming. + /// + /// 2) Connects the agent with the scene + /// + /// This function performs actions equivalent with notifying the scene that an agent is + /// coming and then actually connecting the agent to the scene. The one step missed out is the very first + /// + /// + /// + /// + /// + public static ScenePresence AddScenePresence(Scene scene, AgentCircuitData agentData, SceneManager sceneManager) { // We emulate the proper login sequence here by doing things in four stages @@ -425,7 +555,7 @@ namespace OpenSim.Tests.Common lpsc.m_PresenceService.LoginAgent(agentData.AgentID.ToString(), agentData.SessionID, agentData.SecureSessionID); // Stages 1 & 2 - ScenePresence sp = IntroduceClientToScene(scene, agentData, TeleportFlags.ViaLogin); + ScenePresence sp = IntroduceClientToScene(scene, sceneManager, agentData, TeleportFlags.ViaLogin); // Stage 3: Complete the entrance into the region. This converts the child agent into a root agent. sp.CompleteMovement(sp.ControllingClient, true); @@ -433,7 +563,20 @@ namespace OpenSim.Tests.Common return sp; } - private static ScenePresence IntroduceClientToScene(Scene scene, AgentCircuitData agentData, TeleportFlags tf) + /// + /// Introduce an agent into the scene by adding a new client. + /// + /// The scene presence added + /// + /// Scene manager. Can be null if there is only one region in the test or multiple regions that are not + /// neighbours and where no teleporting takes place. + /// + /// + /// + /// + private static ScenePresence IntroduceClientToScene( + Scene scene, SceneManager sceneManager, AgentCircuitData agentData, TeleportFlags tf) { string reason; @@ -442,7 +585,7 @@ namespace OpenSim.Tests.Common Console.WriteLine("NewUserConnection failed: " + reason); // Stage 2: add the new client as a child agent to the scene - TestClient client = new TestClient(agentData, scene); + TestClient client = new TestClient(agentData, scene, sceneManager); scene.AddNewClient(client, PresenceType.User); return scene.GetScenePresence(agentData.AgentID); @@ -454,7 +597,7 @@ namespace OpenSim.Tests.Common acd.child = true; // XXX: ViaLogin may not be correct for child agents - return IntroduceClientToScene(scene, acd, TeleportFlags.ViaLogin); + return IntroduceClientToScene(scene, null, acd, TeleportFlags.ViaLogin); } /// @@ -462,9 +605,9 @@ namespace OpenSim.Tests.Common /// /// /// - public static SceneObjectPart AddSceneObject(Scene scene) + public static SceneObjectGroup AddSceneObject(Scene scene) { - return AddSceneObject(scene, "Test Object"); + return AddSceneObject(scene, "Test Object", UUID.Zero); } /// @@ -472,17 +615,18 @@ namespace OpenSim.Tests.Common /// /// /// + /// /// - public static SceneObjectPart AddSceneObject(Scene scene, string name) + public static SceneObjectGroup AddSceneObject(Scene scene, string name, UUID ownerId) { - SceneObjectPart part = CreateSceneObjectPart(name, UUID.Random(), UUID.Zero); + SceneObjectGroup so = new SceneObjectGroup(CreateSceneObjectPart(name, UUID.Random(), ownerId)); //part.UpdatePrimFlags(false, false, true); //part.ObjectFlags |= (uint)PrimFlags.Phantom; - scene.AddNewSceneObject(new SceneObjectGroup(part), false); + scene.AddNewSceneObject(so, false); - return part; + return so; } /// @@ -498,19 +642,36 @@ namespace OpenSim.Tests.Common ownerId, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) { Name = name, UUID = id, Scale = new Vector3(1, 1, 1) }; } - + /// /// Create a scene object but do not add it to the scene. /// /// - /// UUID always starts at 00000000-0000-0000-0000-000000000001 + /// UUID always starts at 00000000-0000-0000-0000-000000000001. For some purposes, (e.g. serializing direct + /// to another object's inventory) we do not need a scene unique ID. So it would be better to add the + /// UUID when we actually add an object to a scene rather than on creation. /// /// The number of parts that should be in the scene object /// /// public static SceneObjectGroup CreateSceneObject(int parts, UUID ownerId) { - return CreateSceneObject(parts, ownerId, "", 0x1); + return CreateSceneObject(parts, ownerId, 0x1); + } + + /// + /// Create a scene object but do not add it to the scene. + /// + /// The number of parts that should be in the scene object + /// + /// + /// The hexadecimal last part of the UUID for parts created. A UUID of the form "00000000-0000-0000-0000-{0:XD12}" + /// will be given to the root part, and incremented for each part thereafter. + /// + /// + public static SceneObjectGroup CreateSceneObject(int parts, UUID ownerId, int uuidTail) + { + return CreateSceneObject(parts, ownerId, "", uuidTail); } /// @@ -522,7 +683,7 @@ namespace OpenSim.Tests.Common /// /// /// The prefix to be given to part names. This will be suffixed with "Part" - /// (e.g. mynamePart0 for the root part) + /// (e.g. mynamePart1 for the root part) /// /// /// The hexadecimal last part of the UUID for parts created. A UUID of the form "00000000-0000-0000-0000-{0:XD12}" @@ -535,14 +696,14 @@ namespace OpenSim.Tests.Common SceneObjectGroup sog = new SceneObjectGroup( - CreateSceneObjectPart(string.Format("{0}Part0", partNamePrefix), new UUID(rawSogId), ownerId)); + CreateSceneObjectPart(string.Format("{0}Part1", partNamePrefix), new UUID(rawSogId), ownerId)); if (parts > 1) - for (int i = 1; i < parts; i++) + for (int i = 2; i <= parts; i++) sog.AddPart( CreateSceneObjectPart( string.Format("{0}Part{1}", partNamePrefix, i), - new UUID(string.Format("00000000-0000-0000-0000-{0:X12}", uuidTail + i)), + new UUID(string.Format("00000000-0000-0000-0000-{0:X12}", uuidTail + i - 1)), ownerId)); return sog; diff --git a/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs b/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs index 7058d1e568..fba03abcf0 100644 --- a/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/TaskInventoryHelpers.cs @@ -45,29 +45,67 @@ namespace OpenSim.Tests.Common /// /// /// + /// + /// + /// /// The item that was added - public static TaskInventoryItem AddNotecard(Scene scene, SceneObjectPart part) + public static TaskInventoryItem AddNotecard(Scene scene, SceneObjectPart part, string itemName, UUID itemID, UUID assetID) { AssetNotecard nc = new AssetNotecard(); nc.BodyText = "Hello World!"; nc.Encode(); - UUID ncAssetUuid = new UUID("00000000-0000-0000-1000-000000000000"); - UUID ncItemUuid = new UUID("00000000-0000-0000-1100-000000000000"); + AssetBase ncAsset - = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero); + = AssetHelpers.CreateAsset(assetID, AssetType.Notecard, nc.AssetData, UUID.Zero); scene.AssetService.Store(ncAsset); + TaskInventoryItem ncItem = new TaskInventoryItem - { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid, + { Name = itemName, AssetID = assetID, ItemID = itemID, Type = (int)AssetType.Notecard, InvType = (int)InventoryType.Notecard }; part.Inventory.AddInventoryItem(ncItem, true); return ncItem; } + /// + /// Add a simple script to the given part. + /// + /// + /// TODO: Accept input for item and asset IDs to avoid mysterious script failures that try to use any of these + /// functions more than once in a test. + /// + /// + /// + /// The item that was added + public static TaskInventoryItem AddScript(Scene scene, SceneObjectPart part) + { + AssetScriptText ast = new AssetScriptText(); + ast.Source = "default { state_entry() { llSay(0, \"Hello World\"); } }"; + ast.Encode(); + + UUID assetUuid = new UUID("00000000-0000-0000-1000-000000000000"); + UUID itemUuid = new UUID("00000000-0000-0000-1100-000000000000"); + AssetBase asset + = AssetHelpers.CreateAsset(assetUuid, AssetType.LSLText, ast.AssetData, UUID.Zero); + scene.AssetService.Store(asset); + TaskInventoryItem item + = new TaskInventoryItem + { Name = "scriptItem", AssetID = assetUuid, ItemID = itemUuid, + Type = (int)AssetType.LSLText, InvType = (int)InventoryType.LSL }; + part.Inventory.AddInventoryItem(item, true); + + return item; + } + /// /// Add a scene object item to the given part. /// + /// + /// TODO: Accept input for item and asset IDs to avoid mysterious script failures that try to use any of these + /// functions more than once in a test. + /// + /// /// /// /// diff --git a/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs b/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs index b73df2ca4c..2fbebc4ea9 100644 --- a/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/UserAccountHelpers.cs @@ -126,6 +126,11 @@ namespace OpenSim.Tests.Common return CreateUserWithInventory(scene, "Bill", "Bailey", userId, "troll"); } + public static UserAccount CreateUserWithInventory(Scene scene, int userId) + { + return CreateUserWithInventory(scene, "Bill", "Bailey", TestHelpers.ParseTail(userId), "troll"); + } + public static UserAccount CreateUserWithInventory( Scene scene, string firstName, string lastName, UUID userId, string pw) { @@ -133,6 +138,15 @@ namespace OpenSim.Tests.Common CreateUserWithInventory(scene, ua, pw); return ua; } + + public static UserAccount CreateUserWithInventory( + Scene scene, string firstName, string lastName, int userId, string pw) + { + UserAccount ua + = new UserAccount(TestHelpers.ParseTail(userId)) { FirstName = firstName, LastName = lastName }; + CreateUserWithInventory(scene, ua, pw); + return ua; + } public static void CreateUserWithInventory(Scene scene, UserAccount ua, string pw) { diff --git a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs index fdc60d8f39..b3a7c9eec3 100644 --- a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs @@ -42,6 +42,57 @@ namespace OpenSim.Tests.Common { public static readonly string PATH_DELIMITER = "/"; + /// + /// Add an existing scene object as an item in the user's inventory. + /// + /// + /// + /// + /// + /// The inventory item created. + public static InventoryItemBase AddInventoryItem( + Scene scene, SceneObjectGroup so, int inventoryIdTail, int assetIdTail) + { + return AddInventoryItem( + scene, + so.Name, + TestHelpers.ParseTail(inventoryIdTail), + InventoryType.Object, + AssetHelpers.CreateAsset(TestHelpers.ParseTail(assetIdTail), so), + so.OwnerID); + } + + /// + /// Creates a notecard in the objects folder and specify an item id. + /// + /// + /// + /// + /// + /// The serialized asset for this item + /// + /// + private static InventoryItemBase AddInventoryItem( + Scene scene, string itemName, UUID itemId, InventoryType itemType, AssetBase asset, UUID userId) + { + scene.AssetService.Store(asset); + + InventoryItemBase item = new InventoryItemBase(); + item.Name = itemName; + item.AssetID = asset.FullID; + item.ID = itemId; + item.Owner = userId; + item.AssetType = asset.Type; + item.InvType = (int)itemType; + + InventoryFolderBase folder = scene.InventoryService.GetFolderForType(userId, (AssetType)asset.Type); + + item.Folder = folder.ID; + scene.AddInventoryItem(item); + + return item; + } + /// /// Creates a notecard in the objects folder and specify an item id. /// @@ -81,42 +132,27 @@ namespace OpenSim.Tests.Common /// Type of item to create /// public static InventoryItemBase CreateInventoryItem( - Scene scene, string itemName, UUID itemId, UUID assetId, UUID userId, InventoryType type) + Scene scene, string itemName, UUID itemId, UUID assetId, UUID userId, InventoryType itemType) { AssetBase asset = null; - if (type == InventoryType.Notecard) + if (itemType == InventoryType.Notecard) { asset = AssetHelpers.CreateNotecardAsset(); asset.CreatorID = userId.ToString(); } - else if (type == InventoryType.Object) + else if (itemType == InventoryType.Object) { asset = AssetHelpers.CreateAsset(assetId, SceneHelpers.CreateSceneObject(1, userId)); } else { - throw new Exception(string.Format("Inventory type {0} not supported", type)); + throw new Exception(string.Format("Inventory type {0} not supported", itemType)); } - scene.AssetService.Store(asset); - - InventoryItemBase item = new InventoryItemBase(); - item.Name = itemName; - item.AssetID = asset.FullID; - item.ID = itemId; - item.Owner = userId; - item.AssetType = asset.Type; - item.InvType = (int)type; - - InventoryFolderBase folder = scene.InventoryService.GetFolderForType(userId, AssetType.Notecard); - - item.Folder = folder.ID; - scene.AddInventoryItem(item); - - return item; + return AddInventoryItem(scene, itemName, itemId, itemType, asset, userId); } - + /// /// Create inventory folders starting from the user's root folder. /// diff --git a/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs b/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs index 38fbbe35a1..3f99a39f84 100644 --- a/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs +++ b/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs @@ -113,6 +113,21 @@ namespace OpenSim.Data.Null m_store.StoreRegionWindlightSettings(wl); } + public string LoadRegionEnvironmentSettings(UUID regionUUID) + { + return m_store.LoadRegionEnvironmentSettings(regionUUID); + } + + public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) + { + m_store.StoreRegionEnvironmentSettings(regionUUID, settings); + } + + public void RemoveRegionEnvironmentSettings(UUID regionUUID) + { + m_store.RemoveRegionEnvironmentSettings(regionUUID); + } + public UUID[] GetObjectIDs(UUID regionID) { return new UUID[0]; @@ -163,7 +178,25 @@ namespace OpenSim.Data.Null { //This connector doesn't support the windlight module yet } - + + #region Environment Settings + public string LoadRegionEnvironmentSettings(UUID regionUUID) + { + //This connector doesn't support the Environment module yet + return string.Empty; + } + + public void StoreRegionEnvironmentSettings(UUID regionUUID, string settings) + { + //This connector doesn't support the Environment module yet + } + + public void RemoveRegionEnvironmentSettings(UUID regionUUID) + { + //This connector doesn't support the Environment module yet + } + #endregion + public RegionSettings LoadRegionSettings(UUID regionUUID) { RegionSettings rs = null; diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index b2c824c81e..e254dd8d5d 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -46,12 +46,10 @@ namespace OpenSim.Tests.Common.Mock EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing"); - // TODO: This is a really nasty (and temporary) means of telling the test client which scene to invoke setup - // methods on when a teleport is requested - public Scene TeleportTargetScene; private TestClient TeleportSceneClient; private Scene m_scene; + private SceneManager m_sceneManager; // Properties so that we can get at received data for test purposes public List ReceivedOfflineNotifications { get; private set; } @@ -435,15 +433,29 @@ namespace OpenSim.Tests.Common.Mock /// /// Constructor /// + /// + /// Can be used for a test where there is only one region or where there are multiple regions that are not + /// neighbours and where no teleporting takes place. In other situations, the constructor that takes in a + /// scene manager should be used. + /// /// /// - public TestClient(AgentCircuitData agentData, Scene scene) + public TestClient(AgentCircuitData agentData, Scene scene) : this(agentData, scene, null) {} + + /// + /// Constructor + /// + /// + /// + /// + public TestClient(AgentCircuitData agentData, Scene scene, SceneManager sceneManager) { m_agentId = agentData.AgentID; m_firstName = agentData.firstname; m_lastName = agentData.lastname; m_circuitCode = agentData.circuitcode; m_scene = scene; + m_sceneManager = sceneManager; SessionId = agentData.SessionID; SecureSessionId = agentData.SecureSessionID; CapsSeedUrl = agentData.CapsPath; @@ -593,8 +605,16 @@ namespace OpenSim.Tests.Common.Mock AgentCircuitData newAgent = RequestClientInfo(); // Stage 2: add the new client as a child agent to the scene - TeleportSceneClient = new TestClient(newAgent, TeleportTargetScene); - TeleportTargetScene.AddNewClient(TeleportSceneClient, PresenceType.User); + uint x, y; + Utils.LongToUInts(neighbourHandle, out x, out y); + x /= Constants.RegionSize; + y /= Constants.RegionSize; + + Scene neighbourScene; + m_sceneManager.TryGetScene(x, y, out neighbourScene); + + TeleportSceneClient = new TestClient(newAgent, neighbourScene, m_sceneManager); + neighbourScene.AddNewClient(TeleportSceneClient, PresenceType.User); } public virtual void SendRegionTeleport(ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, @@ -604,6 +624,13 @@ namespace OpenSim.Tests.Common.Mock CapsSeedUrl = capsURL; + // We don't do this here so that the source region can complete processing first in a single-threaded + // regression test scenario. The test itself will have to call CompleteTeleportClientSide() after a teleport + // CompleteTeleportClientSide(); + } + + public void CompleteTeleportClientSide() + { TeleportSceneClient.CompleteMovement(); //TeleportTargetScene.AgentCrossing(newAgent.AgentID, new Vector3(90, 90, 90), false); } @@ -944,11 +971,6 @@ namespace OpenSim.Tests.Common.Mock { } - public EndPoint GetClientEP() - { - return null; - } - public ClientInfo GetClientInfo() { return null; @@ -1104,10 +1126,6 @@ namespace OpenSim.Tests.Common.Mock { } - public void KillEndDone() - { - } - public void SendEventInfoReply (EventData info) { } diff --git a/OpenSim/Tests/Common/Mock/TestLandChannel.cs b/OpenSim/Tests/Common/Mock/TestLandChannel.cs index 0e4dfb9eee..4b4d52d77e 100644 --- a/OpenSim/Tests/Common/Mock/TestLandChannel.cs +++ b/OpenSim/Tests/Common/Mock/TestLandChannel.cs @@ -46,6 +46,14 @@ namespace OpenSim.Tests.Common.Mock { m_scene = scene; m_parcels = new List(); + SetupDefaultParcel(); + } + + private void SetupDefaultParcel() + { + ILandObject obj = new LandObject(UUID.Zero, false, m_scene); + obj.LandData.Name = "Your Parcel"; + m_parcels.Add(obj); } public List ParcelsNearPoint(Vector3 position) @@ -63,11 +71,7 @@ namespace OpenSim.Tests.Common.Mock m_parcels.Clear(); if (setupDefaultParcel) - { - ILandObject obj = new LandObject(UUID.Zero, false, m_scene); - obj.LandData.Name = "Your Parcel"; - m_parcels.Add(obj); - } + SetupDefaultParcel(); } protected ILandObject GetNoLand() @@ -102,6 +106,5 @@ namespace OpenSim.Tests.Common.Mock public void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id) {} public void Subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id) {} - } -} +} \ No newline at end of file diff --git a/OpenSim/Tests/Common/OpenSimTestCase.cs b/OpenSim/Tests/Common/OpenSimTestCase.cs new file mode 100644 index 0000000000..8c40923017 --- /dev/null +++ b/OpenSim/Tests/Common/OpenSimTestCase.cs @@ -0,0 +1,46 @@ +/* + * 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 NUnit.Framework; + +namespace OpenSim.Tests.Common +{ + [TestFixture] + public class OpenSimTestCase + { + [SetUp] + public virtual void SetUp() + { +// TestHelpers.InMethod(); + // Disable logging for each test so that one where logging is enabled doesn't cause all subsequent tests + // to have logging on if it failed with an exception. + TestHelpers.DisableLogging(); + } + } +} + diff --git a/OpenSim/Tests/Common/TestHelpers.cs b/OpenSim/Tests/Common/TestHelpers.cs index ced06de1ad..30121fef6a 100644 --- a/OpenSim/Tests/Common/TestHelpers.cs +++ b/OpenSim/Tests/Common/TestHelpers.cs @@ -27,6 +27,8 @@ using System; using System.Diagnostics; +using System.IO; +using System.Text; using NUnit.Framework; using OpenMetaverse; @@ -34,6 +36,38 @@ namespace OpenSim.Tests.Common { public class TestHelpers { + private static Stream EnableLoggingConfigStream + = new MemoryStream( + Encoding.UTF8.GetBytes( +@" + + + + + + + + + + + + + + + + +")); + + private static MemoryStream DisableLoggingConfigStream + = new MemoryStream( + Encoding.UTF8.GetBytes( +// "")); + //""))); +// "")); +// ""))); +// "")); + "")); + public static bool AssertThisDelegateCausesArgumentException(TestDelegate d) { try @@ -58,6 +92,26 @@ namespace OpenSim.Tests.Common Console.WriteLine("===> In Test Method : {0} <===", stackTrace.GetFrame(1).GetMethod().Name); } + public static void EnableLogging() + { + log4net.Config.XmlConfigurator.Configure(EnableLoggingConfigStream); + } + + /// + /// Disable logging whilst running the tests. + /// + /// + /// Remember, if a regression test throws an exception before completing this will not be invoked if it's at + /// the end of the test. + /// TODO: Always invoke this after every test - probably need to make all test cases inherit from a common + /// TestCase class where this can be done. + /// + public static void DisableLogging() + { + log4net.Config.XmlConfigurator.Configure(DisableLoggingConfigStream); + DisableLoggingConfigStream.Position = 0; + } + /// /// Parse tail section into full UUID. /// diff --git a/OpenSim/Tests/Torture/NPCTortureTests.cs b/OpenSim/Tests/Torture/NPCTortureTests.cs index 02245056c4..731df6808c 100644 --- a/OpenSim/Tests/Torture/NPCTortureTests.cs +++ b/OpenSim/Tests/Torture/NPCTortureTests.cs @@ -98,7 +98,7 @@ namespace OpenSim.Tests.Torture umm = new UserManagementModule(); am = new AttachmentsModule(); - scene = SceneHelpers.SetupScene(); + scene = new SceneHelpers().SetupScene(); SceneHelpers.SetupSceneModules(scene, config, afm, umm, am, new BasicInventoryAccessModule(), new NPCModule()); } diff --git a/OpenSim/Tests/Torture/ObjectTortureTests.cs b/OpenSim/Tests/Torture/ObjectTortureTests.cs index d0d2199b0c..195d47bd52 100644 --- a/OpenSim/Tests/Torture/ObjectTortureTests.cs +++ b/OpenSim/Tests/Torture/ObjectTortureTests.cs @@ -126,7 +126,7 @@ namespace OpenSim.Tests.Torture // Using a local variable for scene, at least on mono 2.6.7, means that it's much more likely to be garbage // collected when we teardown this test. If it's done in a member variable, even if that is subsequently // nulled out, the garbage collect can be delayed. - TestScene scene = SceneHelpers.SetupScene(); + TestScene scene = new SceneHelpers().SetupScene(); // Process process = Process.GetCurrentProcess(); // long startProcessMemory = process.PrivateMemorySize64; diff --git a/OpenSim/Tests/Torture/ScriptTortureTests.cs b/OpenSim/Tests/Torture/ScriptTortureTests.cs index 2ef55b34b3..24f278f3f8 100644 --- a/OpenSim/Tests/Torture/ScriptTortureTests.cs +++ b/OpenSim/Tests/Torture/ScriptTortureTests.cs @@ -84,7 +84,7 @@ namespace OpenSim.Tests.Torture // to AssemblyResolver.OnAssemblyResolve fails. xEngineConfig.Set("AppDomainLoading", "false"); - m_scene = SceneHelpers.SetupScene("My Test", UUID.Random(), 1000, 1000, null, configSource); + m_scene = new SceneHelpers().SetupScene("My Test", UUID.Random(), 1000, 1000, configSource); SceneHelpers.SetupSceneModules(m_scene, configSource, m_xEngine, wcModule); m_scene.EventManager.OnChatFromWorld += OnChatFromWorld; diff --git a/OpenSim/Tools/Compiler/Program.cs b/OpenSim/Tools/Compiler/Program.cs index 249e18b402..6c59c313a6 100644 --- a/OpenSim/Tools/Compiler/Program.cs +++ b/OpenSim/Tools/Compiler/Program.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Text; using Microsoft.CSharp; using OpenSim.Region.ScriptEngine.Shared.CodeTools; using System.CodeDom.Compiler; @@ -201,12 +202,8 @@ namespace OpenSim.Tools.LSL.Compiler // Convert to base64 // string filetext = System.Convert.ToBase64String(data); - - System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); - - Byte[] buf = enc.GetBytes(filetext); - - FileStream sfs = File.Create(OutFile+".text"); + Byte[] buf = Encoding.ASCII.GetBytes(filetext); + FileStream sfs = File.Create(OutFile + ".text"); sfs.Write(buf, 0, buf.Length); sfs.Close(); @@ -222,9 +219,9 @@ namespace OpenSim.Tools.LSL.Compiler // } // } - buf = enc.GetBytes(posmap); + buf = Encoding.ASCII.GetBytes(posmap); - FileStream mfs = File.Create(OutFile+".map"); + FileStream mfs = File.Create(OutFile + ".map"); mfs.Write(buf, 0, buf.Length); mfs.Close(); diff --git a/OpenSim/Tools/pCampBot/Bot.cs b/OpenSim/Tools/pCampBot/Bot.cs index da090dda64..daaa3c0070 100644 --- a/OpenSim/Tools/pCampBot/Bot.cs +++ b/OpenSim/Tools/pCampBot/Bot.cs @@ -43,6 +43,14 @@ using Timer = System.Timers.Timer; namespace pCampBot { + public enum ConnectionState + { + Disconnected, + Connecting, + Connected, + Disconnecting + } + public class Bot { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -86,7 +94,7 @@ namespace pCampBot /// /// Is this bot connected to the grid? /// - public bool IsConnected { get; private set; } + public ConnectionState ConnectionState { get; private set; } public string FirstName { get; private set; } public string LastName { get; private set; } @@ -130,6 +138,8 @@ namespace pCampBot BotManager bm, List behaviours, string firstName, string lastName, string password, string loginUri) { + ConnectionState = ConnectionState.Disconnected; + behaviours.ForEach(b => b.Initialize(this)); Client = new GridClient(); @@ -157,10 +167,10 @@ namespace pCampBot Behaviours.ForEach( b => { + Thread.Sleep(Random.Next(3000, 10000)); + // m_log.DebugFormat("[pCAMPBOT]: For {0} performing action {1}", Name, b.GetType()); b.Action(); - - Thread.Sleep(Random.Next(1000, 10000)); } ); } @@ -178,6 +188,8 @@ namespace pCampBot /// public void shutdown() { + ConnectionState = ConnectionState.Disconnecting; + if (m_actionThread != null) m_actionThread.Abort(); @@ -209,9 +221,11 @@ namespace pCampBot Client.Network.Disconnected += this.Network_OnDisconnected; Client.Objects.ObjectUpdate += Objects_NewPrim; + ConnectionState = ConnectionState.Connecting; + if (Client.Network.Login(FirstName, LastName, Password, "pCampBot", "Your name")) { - IsConnected = true; + ConnectionState = ConnectionState.Connected; Thread.Sleep(Random.Next(1000, 10000)); m_actionThread = new Thread(Action); @@ -241,6 +255,8 @@ namespace pCampBot } else { + ConnectionState = ConnectionState.Disconnected; + m_log.ErrorFormat( "{0} {1} cannot login: {2}", FirstName, LastName, Client.Network.LoginMessage); @@ -439,6 +455,8 @@ namespace pCampBot public void Network_OnDisconnected(object sender, DisconnectedEventArgs args) { + ConnectionState = ConnectionState.Disconnected; + m_log.DebugFormat( "[BOT]: Bot {0} disconnected reason {1}, message {2}", Name, args.Reason, args.Message); @@ -456,13 +474,15 @@ namespace pCampBot && OnDisconnected != null) // if (OnDisconnected != null) { - IsConnected = false; OnDisconnected(this, EventType.DISCONNECTED); } } public void Objects_NewPrim(object sender, PrimEventArgs args) { +// if (Name.EndsWith("4")) +// throw new Exception("Aaargh"); + Primitive prim = args.Prim; if (prim != null) diff --git a/OpenSim/Tools/pCampBot/BotManager.cs b/OpenSim/Tools/pCampBot/BotManager.cs index 0f501b788b..d615b3fb8a 100644 --- a/OpenSim/Tools/pCampBot/BotManager.cs +++ b/OpenSim/Tools/pCampBot/BotManager.cs @@ -49,6 +49,14 @@ namespace pCampBot { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + public const int DefaultLoginDelay = 5000; + + /// + /// Delay between logins of multiple bots. + /// + /// TODO: This value needs to be configurable by a command line argument. + public int LoginDelay { get; set; } + /// /// Command console /// @@ -84,6 +92,8 @@ namespace pCampBot /// public BotManager() { + LoginDelay = DefaultLoginDelay; + Rng = new Random(Environment.TickCount); AssetsReceived = new Dictionary(); RegionsKnown = new Dictionary(); @@ -151,28 +161,34 @@ namespace pCampBot Array.ForEach( cs.GetString("behaviours", "p").Split(new char[] { ',' }), b => behaviourSwitches.Add(b)); + MainConsole.Instance.OutputFormat( + "[BOT MANAGER]: Starting {0} bots connecting to {1}, named {2} {3}_", + botcount, + loginUri, + firstName, + lastNameStem); + + MainConsole.Instance.OutputFormat("[BOT MANAGER]: Delay between logins is {0}ms", LoginDelay); + for (int i = 0; i < botcount; i++) { string lastName = string.Format("{0}_{1}", lastNameStem, i); + // We must give each bot its own list of instantiated behaviours since they store state. List behaviours = new List(); - + // Hard-coded for now if (behaviourSwitches.Contains("p")) behaviours.Add(new PhysicsBehaviour()); - + if (behaviourSwitches.Contains("g")) behaviours.Add(new GrabbingBehaviour()); - + if (behaviourSwitches.Contains("t")) behaviours.Add(new TeleportBehaviour()); - + if (behaviourSwitches.Contains("c")) behaviours.Add(new CrossBehaviour()); - - MainConsole.Instance.OutputFormat( - "[BOT MANAGER]: Bot {0} {1} configured for behaviours {2}", - firstName, lastName, string.Join(",", behaviours.ConvertAll(b => b.Name).ToArray())); StartBot(this, behaviours, firstName, lastName, password, loginUri); } @@ -211,6 +227,10 @@ namespace pCampBot BotManager bm, List behaviours, string firstName, string lastName, string password, string loginUri) { + MainConsole.Instance.OutputFormat( + "[BOT MANAGER]: Starting bot {0} {1}, behaviours are {2}", + firstName, lastName, string.Join(",", behaviours.ConvertAll(b => b.Name).ToArray())); + Bot pb = new Bot(bm, behaviours, firstName, lastName, password, loginUri); pb.OnConnected += handlebotEvent; @@ -222,7 +242,11 @@ namespace pCampBot Thread pbThread = new Thread(pb.startup); pbThread.Name = pb.Name; pbThread.IsBackground = true; + pbThread.Start(); + + // Stagger logins + Thread.Sleep(LoginDelay); } /// @@ -242,7 +266,7 @@ namespace pCampBot lock (m_lBot) { - if (m_lBot.TrueForAll(b => !b.IsConnected)) + if (m_lBot.TrueForAll(b => b.ConnectionState == ConnectionState.Disconnected)) Environment.Exit(0); break; @@ -251,13 +275,21 @@ namespace pCampBot } /// - /// Shutting down all bots + /// Shut down all bots /// + /// + /// We launch each shutdown on its own thread so that a slow shutting down bot doesn't hold up all the others. + /// public void doBotShutdown() { lock (m_lBot) - foreach (Bot pb in m_lBot) - pb.shutdown(); + { + foreach (Bot bot in m_lBot) + { + Bot thisBot = bot; + Util.FireAndForget(o => thisBot.shutdown()); + } + } } /// @@ -271,11 +303,8 @@ namespace pCampBot private void HandleShutdown(string module, string[] cmd) { - Util.FireAndForget(o => - { - m_log.Warn("[BOTMANAGER]: Shutting down bots"); - doBotShutdown(); - }); + m_log.Info("[BOTMANAGER]: Shutting down bots"); + doBotShutdown(); } private void HandleShowRegions(string module, string[] cmd) @@ -302,9 +331,11 @@ namespace pCampBot { foreach (Bot pb in m_lBot) { + Simulator currentSim = pb.Client.Network.CurrentSim; + MainConsole.Instance.OutputFormat( outputFormat, - pb.Name, pb.Client.Network.CurrentSim.Name, pb.IsConnected ? "Connected" : "Disconnected"); + pb.Name, currentSim != null ? currentSim.Name : "(none)", pb.ConnectionState); } } } diff --git a/OpenSim/Tools/pCampBot/pCampBot.cs b/OpenSim/Tools/pCampBot/pCampBot.cs index ec5ad04fce..9e82577be5 100644 --- a/OpenSim/Tools/pCampBot/pCampBot.cs +++ b/OpenSim/Tools/pCampBot/pCampBot.cs @@ -27,7 +27,9 @@ using System; using System.Reflection; +using System.Threading; using log4net; +using log4net.Config; using Nini.Config; using OpenSim.Framework; using OpenSim.Framework.Console; @@ -51,6 +53,8 @@ namespace pCampBot [STAThread] public static void Main(string[] args) { + XmlConfigurator.Configure(); + IConfig config = ParseConfig(args); if (config.Get("help") != null || config.Get("loginuri") == null) { @@ -67,7 +71,9 @@ namespace pCampBot BotManager bm = new BotManager(); //startup specified number of bots. 1 is the default - bm.dobotStartup(botcount, config); + Thread startBotThread = new Thread(o => bm.dobotStartup(botcount, config)); + startBotThread.Name = "Initial start bots thread"; + startBotThread.Start(); while (true) { diff --git a/ThirdPartyLicenses/DotNetZip-bzip2.txt b/ThirdPartyLicenses/DotNetZip-bzip2.txt new file mode 100644 index 0000000000..f8b4346fe9 --- /dev/null +++ b/ThirdPartyLicenses/DotNetZip-bzip2.txt @@ -0,0 +1,29 @@ + +The managed BZIP2 code included in Ionic.BZip2.dll and Ionic.Zip.dll is +modified code, based on the bzip2 code in the Apache commons compress +library. + +The original BZip2 was created by Julian Seward, and is licensed under +the BSD license. + +The following license applies to the Apache code: +----------------------------------------------------------------------- + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ diff --git a/ThirdPartyLicenses/DotNetZip-zlib.txt b/ThirdPartyLicenses/DotNetZip-zlib.txt new file mode 100644 index 0000000000..801e941903 --- /dev/null +++ b/ThirdPartyLicenses/DotNetZip-zlib.txt @@ -0,0 +1,70 @@ + +The following licenses govern use of the accompanying software, the +DotNetZip library ("the software"). If you use the software, you accept +these licenses. If you do not accept the license, do not use the software. + +The managed ZLIB code included in Ionic.Zlib.dll and Ionic.Zip.dll is +modified code, based on jzlib. + + + +The following notice applies to jzlib: +----------------------------------------------------------------------- + +Copyright (c) 2000,2001,2002,2003 ymnk, JCraft,Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +2. 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. + +3. The names of the authors may not be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 JCRAFT, +INC. OR ANY CONTRIBUTORS TO THIS SOFTWARE 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. + +----------------------------------------------------------------------- + +jzlib is based on zlib-1.1.3. + +The following notice applies to zlib: + +----------------------------------------------------------------------- + +Copyright (C) 1995-2004 Jean-loup Gailly and Mark Adler + + The ZLIB software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly jloup@gzip.org + Mark Adler madler@alumni.caltech.edu + + +----------------------------------------------------------------------- diff --git a/ThirdPartyLicenses/DotNetZip.txt b/ThirdPartyLicenses/DotNetZip.txt new file mode 100644 index 0000000000..c3103fd07d --- /dev/null +++ b/ThirdPartyLicenses/DotNetZip.txt @@ -0,0 +1,33 @@ +Microsoft Public License (Ms-PL) + +This license governs use of the accompanying software, the DotNetZip library ("the software"). If you use the software, you accept this license. If you do not accept the license, do not use the software. + +1. Definitions + +The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. + +A "contribution" is the original software, or any additions or changes to the software. + +A "contributor" is any person that distributes its contribution under this license. + +"Licensed patents" are a contributor's patent claims that read directly on its contribution. + +2. Grant of Rights + +(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. + +(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + +3. Conditions and Limitations + +(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. + +(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. + +(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. + +(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. + +(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. + + diff --git a/bin/Ionic.Zip.dll b/bin/Ionic.Zip.dll new file mode 100644 index 0000000000..95fa928855 Binary files /dev/null and b/bin/Ionic.Zip.dll differ diff --git a/bin/OpenSim.Framework.Serialization.Tests.dll.config b/bin/OpenSim.Framework.Serialization.Tests.dll.config deleted file mode 100644 index a3f681d89e..0000000000 --- a/bin/OpenSim.Framework.Serialization.Tests.dll.config +++ /dev/null @@ -1,33 +0,0 @@ - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bin/OpenSim.Region.ClientStack.LindenCaps.Tests.dll.config b/bin/OpenSim.Region.ClientStack.LindenCaps.Tests.dll.config deleted file mode 100644 index a3f681d89e..0000000000 --- a/bin/OpenSim.Region.ClientStack.LindenCaps.Tests.dll.config +++ /dev/null @@ -1,33 +0,0 @@ - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bin/OpenSim.Region.ClientStack.LindenUDP.Tests.dll.config b/bin/OpenSim.Region.ClientStack.LindenUDP.Tests.dll.config deleted file mode 100644 index a3f681d89e..0000000000 --- a/bin/OpenSim.Region.ClientStack.LindenUDP.Tests.dll.config +++ /dev/null @@ -1,33 +0,0 @@ - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bin/OpenSim.Region.OptionalModules.Tests.dll.config b/bin/OpenSim.Region.OptionalModules.Tests.dll.config deleted file mode 100644 index a3f681d89e..0000000000 --- a/bin/OpenSim.Region.OptionalModules.Tests.dll.config +++ /dev/null @@ -1,33 +0,0 @@ - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bin/OpenSim.Tests.Torture.dll.config b/bin/OpenSim.Tests.Torture.dll.config deleted file mode 100644 index a3f681d89e..0000000000 --- a/bin/OpenSim.Tests.Torture.dll.config +++ /dev/null @@ -1,33 +0,0 @@ - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bin/OpenSim.exe.config b/bin/OpenSim.exe.config index 4a49fc5631..e3107abc87 100755 --- a/bin/OpenSim.exe.config +++ b/bin/OpenSim.exe.config @@ -31,5 +31,10 @@ + + + + + diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example old mode 100755 new mode 100644 index 50366a675d..9c68b6546c --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -61,17 +61,20 @@ ;; Place to create a PID file ; PIDFile = "/tmp/my.pid" + ;# {region_info_source} {} {Where to load region from?} {filesystem web} filesystem ;; Determine where OpenSimulator looks for the files which tell it ;; which regions to server ;; Default is "filesystem" ; region_info_source = "filesystem" ; region_info_source = "web" - + + ;# {regionload_regionsdir} {region_info_source} {Location of file?} {} Regions ;; Determines where the region XML files are stored if you are loading ;; these from the filesystem. ;; Defaults to bin/Regions in your OpenSimulator installation directory ; regionload_regionsdir="C:\somewhere\xmlfiles\" + ;# {regionload_webserver_url} {region_info_source} {URL to load region from?} {} ;; Determines the page from which regions xml is retrieved if you are ;; loading these from the web. ;; The XML here has the same format as it does on the filesystem @@ -92,6 +95,7 @@ ;; Maximum size where a prim can be physical. Affects resizing of existing prims. This can be overriden in the region config file. ; PhysicalPrimMax = 10 + ;# {ClampPrimSize} {} {Clamp viewer rezzed prims to max sizes?} {true false} false ;; If a viewer attempts to rez a prim larger than the non-physical or physical prim max, clamp the dimensions to the appropriate maximum ;; This can be overriden in the region config file. ; ClampPrimSize = false @@ -117,6 +121,7 @@ ;; This will likely break them ; CombineContiguousRegions = false + ;# {InworldRestartShutsDown} {} {Shutdown instance on region restart?} {true false} false ;; If you have only one region in an instance, or to avoid the many bugs ;; that you can trigger in modules by restarting a region, set this to ;; true to make the entire instance exit instead of restarting the region. @@ -131,14 +136,17 @@ ;; If both of these values are set to zero then persistence of all changed ;; objects will happen on every sweep. + ;# {MinimumTimeBeforePersistenceConsidered} {} {Time before un-changed object may be persisted} {} 60 ;; Objects will be considered for persistance in the next sweep when they ;; have not changed for this number of seconds. ; MinimumTimeBeforePersistenceConsidered = 60 + ;# {MaximumTimeBeforePersistenceConsidered} {} {Time before changed objects may be persisted?} {} 600 ;; Objects will always be considered for persistance in the next sweep ;; if the first change occurred this number of seconds ago. ; MaximumTimeBeforePersistenceConsidered = 600 + ;# {see_into_this_sim_from_neighbor} {} {Should avatars in neighbor sims see objects in this sim?} {true false} true ;; Should avatars in neighbor sims see objects in this sim? ; see_into_this_sim_from_neighbor = true @@ -153,6 +161,7 @@ ;; Note that only the ODE physics engine currently deals with meshed ;; prims in a satisfactory way. + ;# {meshing} {} {Select mesher} {Meshmerizer ZeroMesher} Meshmerizer ;; ZeroMesher is faster but leaves the physics engine to model the mesh ;; using the basic shapes that it supports. ;; Usually this is only a box. @@ -161,6 +170,7 @@ ; meshing = ZeroMesher ;; Choose one of the physics engines below + ;# {physics} {} {Select physics engine} {OpenDynamicsEngine BulletSim basicphysics POS} OpenDynamicsEngine ;; OpenDynamicsEngine is by some distance the most developed physics engine ;; BulletSim is incomplete and experimental but in active development ;; basicphysics effectively does not model physics at all, making all objects phantom @@ -184,38 +194,52 @@ ;; If set to true, then all permissions checks are carried out ; serverside_object_permissions = true + ;# {allow_grid_gods} {} {Allow grid gods?} {true false} false ;; This allows users with a UserLevel of 200 or more to assume god ;; powers in the regions in this simulator. ; allow_grid_gods = false ;; This allows some control over permissions ;; please note that this still doesn't duplicate SL, and is not intended to + ;# {region_owner_is_god} {} {Allow region owner gods} {true false} true + ;; Allow region owners to assume god powers in their regions ; region_owner_is_god = true + + ;# {region_manager_is_god} {} {Allow region manager gods} {true false} false + ;; Allow region managers to assume god powers in regions they manage ; region_manager_is_god = false + + ;# {parcel_owner_is_god} {} {Allow parcel owner gods} {true false} true + ;; Allow parcel owners to assume god powers in their parcels ; parcel_owner_is_god = true + ;# {simple_build_permissions} {} {Allow building in parcel by access list (no groups)} {true false} false ;; More control over permissions ;; This is definitely not SL! - ; Provides a simple control for land owners to give build rights to specific avatars - ; in publicly accessible parcels that disallow object creation in general. - ; Owners specific avatars by adding them to the Access List of the parcel - ; without having to use the Groups feature + ;; Provides a simple control for land owners to give build rights to specific avatars + ;; in publicly accessible parcels that disallow object creation in general. + ;; Owners specific avatars by adding them to the Access List of the parcel + ;; without having to use the Groups feature ; simple_build_permissions = false + ;# {DefaultScriptEngine} {} {Default script engine} {XEngine} XEngine ;; Default script engine to use. Currently, we only have XEngine ; DefaultScriptEngine = "XEngine" + ;# {GenerateMaptiles} {} {Generate map tiles?} {true false} true ;; Map tile options. You can choose to generate no map tiles at all, ;; generate normal maptiles, or nominate an uploaded texture to ;; be the map tile ; GenerateMaptiles = true + ;# {MaptileRefresh} {GenerateMaptiles} {Maptile refresh period?} {} 0 ;; If desired, a running region can update the map tiles periodically ;; to reflect building activity. This names no sense of you don't have ;; prims on maptiles. Value is in seconds. ; MaptileRefresh = 0 + ;# {MaptileStaticUUID} {} {Asset ID for static map texture} {} 00000000-0000-0000-0000-000000000000 ;; If not generating maptiles, use this static texture asset ID ; MaptileStaticUUID = "00000000-0000-0000-0000-000000000000" @@ -228,9 +252,11 @@ ;; got a large number of objects, so you can turn it off here if you'd like. ; DrawPrimOnMapTile = true + ;# {HttpProxy} {} {Proxy URL for llHTTPRequest and dynamic texture loading} {} http://proxy.com:8080 ;; Http proxy setting for llHTTPRequest and dynamic texture loading, if required ; HttpProxy = "http://proxy.com:8080" + ;# {HttpProxyExceptions} {HttpProxy} {Set of regular expressions defining URL that should not be proxied} {} ;; If you're using HttpProxy, then you can set HttpProxyExceptions to a list of regular expressions for URLs that you don't want to go through the proxy ;; For example, servers inside your firewall. ;; Separate patterns with a ';' @@ -241,21 +267,67 @@ ;; server to send mail through. ; emailmodule = DefaultEmailModule + ;# {SpawnPointRouting} {} {Set routing method for Telehub Spawnpoints} {closest random sequence} closest + ;; SpawnPointRouting adjusts the landing for incoming avatars. + ;; "closest" will place the avatar at the SpawnPoint located in the closest + ;; available spot to the destination (typically map click/landmark). + ;; "random" will place the avatar on a randomly selected spawnpoint; + ;; "sequence" will place the avatar on the next sequential SpawnPoint + ; SpawnPointRouting = closest + + ;# {TelehubAllowLandmark} {} {Allow users with landmarks to override telehub routing} {true false} false + ;; TelehubAllowLandmark allows users with landmarks to override telehub routing and land at the landmark coordinates when set to true + ;; default is false + ; TelehubAllowLandmark = false + + ;# {AllowedClients} {} {Bar (|) separated list of allowed clients} {} + ;; Bar (|) separated list of viewers which may gain access to the regions. + ;; One can use a substring of the viewer name to enable only certain versions + ;; Example: Agent uses the viewer "Imprudence 1.3.2.0" + ;; - "Imprudence" has access + ;; - "Imprudence 1.3" has access + ;; - "Imprudence 1.3.1" has no access + ; AllowedViewerList = + + ;# {BannedClients} {} {Bar (|) separated list of banned clients} {} + ;# Bar (|) separated list of viewers which may not gain access to the regions. + ;; One can use a Substring of the viewer name to disable only certain versions + ;; Example: Agent uses the viewer "Imprudence 1.3.2.0" + ;; - "Imprudence" has no access + ;; - "Imprudence 1.3" has no access + ;; - "Imprudence 1.3.1" has access + ; BannedViewerList = + + [Estates] ; If these values are commented out then the user will be asked for estate details when required (this is the normal case). ; If these values are uncommented then they will be used to create a default estate as necessary. ; New regions will be automatically assigned to that default estate. + ;# {DefaultEstateName} {} {Default name for estate?} {} My Estate + ;; Name for the default estate ; DefaultEstateName = My Estate - ; DefaultEstateOwnerName = FirstName LastName - - ; The following parameters will only be used on a standalone system to create an estate owner that does not already exist - ; If DefaultEstateOwnerUUID is left at UUID.Zero (as below) then a random UUID will be assigned. - ; This is normally what you want + ;# {DefaultEstateOwnerName} {} {Default estate owner name?} {} FirstName LastName + ;; Name for default estate owner + ; DefaultEstateOwnerName = FirstName LastName + + + ; ** Standalone Estate Settings ** + ; The following parameters will only be used on a standalone system to + ; create an estate owner that does not already exist + + ;# {DefaultEstateOwnerUUID} {} {Default estate owner UUID?} {} 00000000-0000-0000-0000-000000000000 + ;; If DefaultEstateOwnerUUID is left at UUID.Zero (as below) then a random + ;; UUID will be assigned. This is normally what you want ; DefaultEstateOwnerUUID = 00000000-0000-0000-0000-000000000000 + ;# {DefaultEstateOwnerEMail} {} {Default estate owner email?} {} + ;; Email address for the default estate owner ; DefaultEstateOwnerEMail = owner@domain.com + + ;# {DefaultEstateOwnerPassword} {} {Default estate owner password} {} + ;; Password for the default estate owner ; DefaultEstateOwnerPassword = password @@ -273,6 +345,12 @@ ;# {host_domain_header_from} {[Startup]emailmodule:DefaultEmailModule enabled:true} {From address to use in the sent email header?} {} 127.0.0.1 ; host_domain_header_from = "127.0.0.1" + ;# {email_pause_time} {[Startup]emailmodule:DefaultEmailModule enabled:true} {Period in seconds to delay after an email is sent.} {} 20 + ; email_pause_time = 20 + + ;# {email_max_size} {[Startup]emailmodule:DefaultEmailModule enabled:true} {Maximum total size of email in bytes.} {} 4096 + ; email_max_size = 4096 + ;# {SMTP_SERVER_HOSTNAME} {[Startup]emailmodule:DefaultEmailModule enabled:true} {SMTP server name?} {} 127.0.0.1 ; SMTP_SERVER_HOSTNAME = "127.0.0.1" @@ -285,12 +363,15 @@ ;# {SMTP_SERVER_PASSWORD} {[Startup]emailmodule:DefaultEmailModule enabled:true} {SMTP server password} {} ; SMTP_SERVER_PASSWORD = "" - [Network] + + ;# {ConsoleUser} {} {User name for console account} {} ;; Configure the remote console user here. This will not actually be used ;; unless you use -console=rest at startup. ; ConsoleUser = "Test" + ;# {ConsolePass} {} {Password for console account} {} ; ConsolePass = "secret" + ;# {console_port} {} {Port for console connections} {} 0 ; console_port = 0 ;# {http_listener_port} {} {TCP Port for this simulator to listen on? (This must be unique to the simulator!)} {} 9000 @@ -354,11 +435,14 @@ [SimulatorFeatures] + + ;# {MapImageServerURI} {} {URL for the map server} {} ; Experimental new information sent in SimulatorFeatures cap for Kokua viewers ; meant to override the MapImage and search server url given at login, and varying ; on a sim-basis. ; Viewers that don't understand it, will ignore it ;MapImageServerURI = "http://127.0.0.1:9000/" + ;# {SearchServerURI} {} {URL of the search server} {} ;SearchServerURI = "http://127.0.0.1:9000/" @@ -552,6 +636,7 @@ [Economy] + ;# {SellEnabled} {} {Enable selling for 0?} {true false} true ; The default economy module only implements just enough to allow free actions (transfer of objects, etc). ; There is no intention to implement anything further in core OpenSimulator. ; This functionality has to be provided by third party modules. @@ -559,9 +644,11 @@ ;; Enables selling things for $0. Default is true. ; SellEnabled = true + ;# {PriceUpload} {} {Price for uploading?} {} 0 ;; Money Unit fee to upload textures, animations etc. Default is 0. ; PriceUpload = 0 + ;# {PriceGroupCreate} {} {Fee for group creation} {} 0 ;; Money Unit fee to create groups. Default is 0. ; PriceGroupCreate = 0 @@ -638,8 +725,11 @@ ; AllowLightShareFunctions = false ;# {OSFunctionThreatLevel} {Enabled:true AllowOSFunctions:true} {OSFunction threat level? (DANGEROUS!)} {None VeryLow Low Moderate High VeryHigh Severe} VeryLow - ;; Threat level to allow, one of None, VeryLow, Low, Moderate, High, - ;; VeryHigh, Severe + ;; Threat level to allow, one of None, VeryLow, Low, Moderate, High, VeryHigh, Severe + ;; See http://opensimulator.org/wiki/Threat_level for more information on these levels. + ;; We do not recommend that use set a general level above Low unless you have a high level of trust + ;; in all the users that can run scripts in your simulator. It is safer to explicitly + ;; allow certain types of user to run higher threat level OSSL functions, as detailed later on. OSFunctionThreatLevel = VeryLow ; OS Functions enable/disable @@ -656,10 +746,10 @@ ; Allow_osSetRegionWaterHeight = 888760cb-a3cf-43ac-8ea4-8732fd3ee2bb ; Comma separated list of owner classes that allow the function for a particular class of owners. Choices are - ; - PARCEL_GROUP_MEMBER: allow if objectgroup is the same group as the parcel - ; - PARCEL_OWNER: allow if the objectowner is parcelowner - ; - ESTATE_MANAGER: allow if the object owner is a estate manager - ; - ESTATE_OWNER: allow if objectowner is estateowner + ; - PARCEL_GROUP_MEMBER: allow if the object group is the same group as the parcel + ; - PARCEL_OWNER: allow if the object owner is the parcel owner + ; - ESTATE_MANAGER: allow if the object owner is an estate manager + ; - ESTATE_OWNER: allow if the object owner is the estate owner ; Allow_osSetRegionWaterHeight = 888760cb-a3cf-43ac-8ea4-8732fd3ee2bb, PARCEL_OWNER, ESTATE_OWNER>, ... ; You can also use script creators as the uuid @@ -668,32 +758,41 @@ ; If both Allow_ and Creators_ are given, effective permissions ; are the union of the two. + ;# {EventLimit} {} {Amount of time a script can spend in an event handler} {} 30 ;; Time a script can spend in an event handler before it is interrupted ; EventLimit = 30 + ;# {KillTimedOutScripts} {} {Kill script in case of event time overruns?} {true false} false ;; If a script overruns it's event limit, kill the script? ; KillTimedOutScripts = false + ;# {ScriptDelayFactor} {} {Multiplier for scripting delays} {} 1.0 ;; Sets the multiplier for the scripting delays ; ScriptDelayFactor = 1.0 - ;; The factor the 10 m distances llimits are multiplied by + ;# {ScriptDistanceLimitFactor} {} {Multiplier for 10.0m distance limits?} {} + ;; The factor the 10 m distances limits are multiplied by ; ScriptDistanceLimitFactor = 1.0 + ;# {NotecardLineReadCharsMax} {} {Maximum length of notecard line?} {} 255 ;; Maximum length of notecard line read ;; Increasing this to large values potentially opens ;; up the system to malicious scripters ; NotecardLineReadCharsMax = 255 + ;# {SensorMaxRange} {} {Sensor range} {} 96.0 ;; Sensor settings ; SensorMaxRange = 96.0 + ;# {SensorMaxResults} {} {Max sensor results returned?} {} ; SensorMaxResults = 16 + ;# {DisableUndergroundMovement} {} {Disable underground movement of prims} {true false} true ;; Disable underground movement of prims (default true); set to ;; false to allow script controlled underground positioning of ;; prims ; DisableUndergroundMovement = true + ;# {ScriptEnginesPath} {} {Path to script assemblies} {} ScriptEngines ;; Path to script engine assemblies ;; Default is ./bin/ScriptEngines ; ScriptEnginesPath = "ScriptEngines" @@ -780,7 +879,7 @@ ;; groups service if the service is using these keys ; XmlRpcServiceReadKey = 1234 ; XmlRpcServiceWriteKey = 1234 - + [InterestManagement] ;# {UpdatePrioritizationScheme} {} {Update prioritization scheme?} {BestAvatarResponsiveness Time Distance SimpleAngularDistance FrontBack} BestAvatarResponsiveness ;; This section controls how state updates are prioritized for each client diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 6fb97876f2..6d699fd505 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -33,6 +33,10 @@ ; Console commands run every 20 minutes ; timer_Script = "filename" + ; timer_Script time interval (default 20 min) + ; The time is 60 per minute + ; timer_Interval = 1200 + ; ## ; ## SYSTEM ; ## @@ -337,6 +341,13 @@ ; OpenJPEG if false ; UseCSJ2K = true + + ; Use "Trash" folder for items deleted from the scene + ; When set to True (the default) items deleted from the scene will be + ; stored in the user's trash or lost and found folder. When set to + ; False items will be removed from the scene permanently + UseTrashOnDelete = True + ; Persist avatar baked textures ; Persisting baked textures can speed up login and region border ; crossings especially with large numbers of users, though it @@ -527,7 +538,20 @@ ; silly vanity "Facelights" dead. Sorry, head mounted miner's lamps ; will also be affected. ; - ;DisableFacelights = "false(1815) + ;DisableFacelights = false + + ; The time to wait before disconecting an unresponsive client. + ; The time is in seconds. The default is one minute + ; + ;AckTimeout = 60 + + ; The time to wait before disconecting an unresponsive paused client. + ; A client can be paused when the file selection dialog is open during file upload. + ; This gives extra time to find files via the dialog but will still disconnect if + ; the client crashes or loses its network connection + ; The time is in seconds. The default is five minutes. + ; + ;PausedAckTimeout = 300 [ClientStack.LindenCaps] ;; Long list of capabilities taken from @@ -542,6 +566,7 @@ Cap_CopyInventoryFromNotecard = "localhost" Cap_DispatchRegionInfo = "" Cap_EstateChangeInfo = "" + Cap_EnvironmentSettings = "localhost" Cap_EventQueueGet = "localhost" Cap_FetchInventory = "" Cap_ObjectMedia = "localhost" @@ -594,13 +619,12 @@ Cap_ViewerStartAuction = "" Cap_ViewerStats = "" - ; The various fetch inventory caps are supported by OpenSim, but may - ; lead to poor sim performance if served by the simulators, - ; so they are currently disabled by default. + ; Capabilities for fetching inventory over HTTP rather than UDP ; FetchInventoryDescendents2 and FetchInventory2 are the ones used in the latest Linden Lab viewers (from some point in the v2 series and above) + ; It appears that Linden Lab viewer 3.3.1 onwards will not work properly if FetchInventoryDescendents2 and FetchInventory2 are not enabled Cap_WebFetchInventoryDescendents = "" - Cap_FetchInventoryDescendents2 = "" - Cap_FetchInventory2 = "" + Cap_FetchInventoryDescendents2 = "localhost" + Cap_FetchInventory2 = "localhost" [Chat] @@ -668,6 +692,25 @@ [ODEPhysicsSettings] + ; ## + ; ## Physics stats settings + ; + + ; If collect_stats is enabled, then extra stat information is collected which is accessible via the MonitorModule + ; (see http://opensimulator.org/wiki/Monitoring_Module for more details). + collect_stats = false + + ; ## + ; ## Physics logging settings - logfiles are saved to *.DIF files + ; ## + + ; default is false + ;physics_logging = true + ;; every n simulation iterations, the physics snapshot file is updated + ;physics_logging_interval = 50 + ;; append to existing physics logfile, or overwrite existing logfiles? + ;physics_logging_append_existing_logfile = true + ;## ;## World Settings ;## @@ -816,17 +859,6 @@ ; number^2 physical level of detail of the sculpt texture. 16x16 - 256 verticies mesh_physical_lod = 16 - ; ## - ; ## Physics logging settings - logfiles are saved to *.DIF files - ; ## - - ; default is false - ;physics_logging = true - ;; every n simulation iterations, the physics snapshot file is updated - ;physics_logging_interval = 50 - ;; append to existing physics logfile, or overwrite existing logfiles? - ;physics_logging_append_existing_logfile = true - ; ## ; ## Joint support ; ## @@ -1125,16 +1157,20 @@ ; currently unused ; AllowosConsoleCommand=false + ; Are god functions such as llSetObjectPermMask() allowed? If true then gods and only gods have access to these functions. + ; If false then gods cannot execute these functions either. AllowGodFunctions = false ; Maximum number of llListen events we allow over the entire region. ; Set this to 0 to have no limit imposed - max_listeners_per_region = 1000 + max_listens_per_region = 1000 ; Maximum number of llListen events we allow per script ; Set this to 0 to have no limit imposed. max_listens_per_script = 64 - + + ; Maximum number of external urls that scripts can set up in this simulator (e.g. via llRequestURL()) + max_external_urls_per_simulator = 100 [DataSnapshot] ; The following set of configs pertains to search. @@ -1560,6 +1596,12 @@ MaptileURL = "http://www.mygrid.com/Grid/" RefreshTime = 3600 +;; +;; JsonStore module provides structured store for scripts +;; +[JsonStore] +Enabled = False + ;; ;; These are defaults that are overwritten below in [Architecture]. ;; These defaults allow OpenSim to work out of the box with diff --git a/bin/PrimMesher.dll b/bin/PrimMesher.dll index 249e91c0a5..87022b7cfc 100755 Binary files a/bin/PrimMesher.dll and b/bin/PrimMesher.dll differ diff --git a/bin/Robust.HG.ini.example b/bin/Robust.HG.ini.example index 2fd9f11ba6..3eecdd916f 100644 --- a/bin/Robust.HG.ini.example +++ b/bin/Robust.HG.ini.example @@ -185,7 +185,7 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003 ;; This switch creates the minimum set of body parts and avatar entries for a viewer 2 ;; to show a default "Ruth" avatar rather than a cloud for a newly created user. ;; Default is false - ; CreateDefaultAvatarEntries = false + CreateDefaultAvatarEntries = true ;; Allow the service to process HTTP createuser calls. ;; Default is false. @@ -237,12 +237,19 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003 WelcomeMessage = "Welcome, Avatar!" AllowRemoteSetLoginLevel = "false" - + ; For V2 map MapTileURL = "http://127.0.0.1:8002"; - ; For WebProfiles (V3) - ProfileServerURL = "http://127.0.0.1/profiles/[AGENT_NAME]" + ; For V2/3 Web Profiles + ; Work in progress: The ProfileServerURL/OpenIDServerURL are + ; being used in a development viewer as support for webprofiles + ; is being developed across the componets + ; + ; ProfileServerURL = "http://127.0.0.1/profiles/[AGENT_NAME]" + ; + ; For V2/V3 webapp authentication SSO + ; OpenIDServerURL = "http://127.0.0.1/openid/openidserver/" ; If you run this login server behind a proxy, set this to true ; HasProxy = false @@ -275,10 +282,29 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003 ;AllowedClients = "" ;DeniedClients = "" + ;# {DSTZone} {} {Override Daylight Saving Time rules} {* none local} "America/Los_Angeles;Pacific Standard Time" + ;; Viewers do not receive timezone information from the server - almost all (?) default to Pacific Standard Time + ;; However, they do rely on the server to tell them whether it's Daylight Saving Time or not. + ;; Hence, calculating DST based on a different timezone can result in a misleading viewer display and inconsistencies between grids. + ;; By default, this setting uses various timezone names to calculate DST with regards to the viewer's standard PST. + ;; Options are + ;; "none" no DST + ;; "local" use the server's only timezone to calculate DST. This is previous OpenSimulator behaviour. + ;; "America/Los_Angeles;Pacific Standard Time" use these timezone names to look up Daylight savings. + ;; 'America/Los_Angeles' is used on Linux/Mac systems whilst 'Pacific Standard Time' is used on Windows + DSTZone = "America/Los_Angeles;Pacific Standard Time" + [MapImageService] LocalServiceModule = "OpenSim.Services.MapImageService.dll:MapImageService" ; Set this if you want to change the default ; TilesStoragePath = "maptiles" + ; + ; If for some reason you have the AddMapTile service outside the firewall (e.g. 8002), + ; you may want to set this. Otherwise, don't set it, because it's already protected. + ; GridService = "OpenSim.Services.GridService.dll:GridService" + ; + ; Additionally, if you run this server behind a proxy, set this to true + ; HasProxy = false [GridInfoService] ; These settings are used to return information on a get_grid_info call. @@ -318,6 +344,14 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003 ; password help: optional: page providing password assistance for users of your grid ;password = http://127.0.0.1/password + + ; HG address of the gatekeeper, if you have one + ; this is the entry point for all the regions of the world + ; gatekeeper = http://127.0.0.1:8002/ + + ; HG user domain, if you have one + ; this is the entry point for all user-related HG services + ; uas = http://127.0.0.1:8002/ [GatekeeperService] LocalServiceModule = "OpenSim.Services.HypergridService.dll:GatekeeperService" diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example index 69e94a584a..5a9d61341c 100644 --- a/bin/Robust.ini.example +++ b/bin/Robust.ini.example @@ -166,7 +166,7 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003 ;; This switch creates the minimum set of body parts and avatar entries for a viewer 2 ;; to show a default "Ruth" avatar rather than a cloud for a newly created user. ;; Default is false - ; CreateDefaultAvatarEntries = false + CreateDefaultAvatarEntries = true ;; Allow the service to process HTTP createuser calls. ;; Default is false. @@ -225,10 +225,14 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003 MapTileURL = "http://127.0.0.1:8002"; ; For V2/3 Web Profiles - ProfileServerURL = "http://127.0.0.1/profiles/[AGENT_NAME]" - + ; Work in progress: The ProfileServerURL/OpenIDServerURL are + ; being used in a development viewer as support for webprofiles + ; is being developed across the componets + ; + ; ProfileServerURL = "http://127.0.0.1/profiles/[AGENT_NAME]" + ; ; For V2/V3 webapp authentication SSO - OpenIDServerURL = "http://127.0.0.1/openid/openidserver/" + ; OpenIDServerURL = "http://127.0.0.1/openid/openidserver/" ; If you run this login server behind a proxy, set this to true ; HasProxy = false @@ -250,10 +254,39 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003 ;AllowedClients = "" ;DeniedClients = "" + ;# {DSTZone} {} {Override Daylight Saving Time rules} {* none local} "America/Los_Angeles;Pacific Standard Time" + ;; Viewers do not listen to timezone sent by the server. They use Pacific Standard Time instead, + ;; but rely on the server to calculate Daylight Saving Time. Sending another DST than US Pacific + ;; would result in time inconsistencies between grids (during summer and around DST transition period) + ;; default let OpenSim calculate US Pacific DST + ;; "none" disable DST (equivallent to "local" with system set to GMT) + ;; "local" force legacy behaviour (using local system time to calculate DST) + ; DSTZone = "America/Los_Angeles;Pacific Standard Time" + + ;# {DSTZone} {} {Override Daylight Saving Time rules} {* none local} "America/Los_Angeles;Pacific Standard Time" + ;; Viewers do not receive timezone information from the server - almost all (?) default to Pacific Standard Time + ;; However, they do rely on the server to tell them whether it's Daylight Saving Time or not. + ;; Hence, calculating DST based on a different timezone can result in a misleading viewer display and inconsistencies between grids. + ;; By default, this setting uses various timezone names to calculate DST with regards to the viewer's standard PST. + ;; Options are + ;; "none" no DST + ;; "local" use the server's only timezone to calculate DST. This is previous OpenSimulator behaviour. + ;; "America/Los_Angeles;Pacific Standard Time" use these timezone names to look up Daylight savings. + ;; 'America/Los_Angeles' is used on Linux/Mac systems whilst 'Pacific Standard Time' is used on Windows + DSTZone = "America/Los_Angeles;Pacific Standard Time" + [MapImageService] LocalServiceModule = "OpenSim.Services.MapImageService.dll:MapImageService" ; Set this if you want to change the default ; TilesStoragePath = "maptiles" + ; + ; If for some reason you have the AddMapTile service outside the firewall (e.g. 8002), + ; you may want to set this. Otherwise, don't set it, because it's already protected. + ; GridService = "OpenSim.Services.GridService.dll:GridService" + ; + ; Additionally, if you run this server behind a proxy, set this to true + ; HasProxy = false + [GridInfoService] diff --git a/bin/config-include/FlotsamCache.ini.example b/bin/config-include/FlotsamCache.ini.example index cd39f8c740..b9c6d84808 100644 --- a/bin/config-include/FlotsamCache.ini.example +++ b/bin/config-include/FlotsamCache.ini.example @@ -36,7 +36,7 @@ ; How often {in hours} should the disk be checked for expired filed ; Specify 0 to disable expiration checking - FileCleanupTimer = .166 ;roughly every 10 minutes + FileCleanupTimer = 1.0 ;every hour ; If WAIT_ON_INPROGRESS_REQUESTS has been defined then this specifies how ; long (in miliseconds) to block a request thread while trying to complete @@ -60,4 +60,4 @@ ; cache, and request all assets that are found that are not already cached (this ; will cause those assets to be cached) ; - ; DeepScanBeforePurge = false + DeepScanBeforePurge = true diff --git a/bin/config-include/Grid.ini b/bin/config-include/Grid.ini index 95d62649ca..cb3a5c86d6 100644 --- a/bin/config-include/Grid.ini +++ b/bin/config-include/Grid.ini @@ -29,9 +29,6 @@ SimulationServiceInConnector = true LibraryModule = true -[Profile] - Module = "BasicProfileModule" - [SimulationDataStore] LocalServiceModule = "OpenSim.Services.Connectors.dll:SimulationDataService" diff --git a/bin/config-include/GridCommon.ini.example b/bin/config-include/GridCommon.ini.example index fa6f5258c5..8d7f6fc427 100644 --- a/bin/config-include/GridCommon.ini.example +++ b/bin/config-include/GridCommon.ini.example @@ -137,6 +137,10 @@ ;; uncomment the next line. You may want to do this on sims that have licensed content. ; OutboundPermission = False +[HGFriendsModule] + ; User level required to be able to send friendship invitations to foreign users + ;LevelHGFriends = 0; + [UserAgentService] ; ; === HG ONLY === diff --git a/bin/config-include/Standalone.ini b/bin/config-include/Standalone.ini index d307387e85..ba72fe747d 100644 --- a/bin/config-include/Standalone.ini +++ b/bin/config-include/Standalone.ini @@ -25,9 +25,6 @@ GridInfoServiceInConnector = true MapImageServiceInConnector = true -[Profile] - Module = "BasicProfileModule" - [SimulationDataStore] LocalServiceModule = "OpenSim.Services.Connectors.dll:SimulationDataService" @@ -95,6 +92,18 @@ WelcomeMessage = "Welcome, Avatar!" + ;# {DSTZone} {} {Override Daylight Saving Time rules} {* none local} "America/Los_Angeles;Pacific Standard Time" + ;; Viewers do not receive timezone information from the server - almost all (?) default to Pacific Standard Time + ;; However, they do rely on the server to tell them whether it's Daylight Saving Time or not. + ;; Hence, calculating DST based on a different timezone can result in a misleading viewer display and inconsistencies between grids. + ;; By default, this setting uses various timezone names to calculate DST with regards to the viewer's standard PST. + ;; Options are + ;; "none" no DST + ;; "local" use the server's only timezone to calculate DST. This is previous OpenSimulator behaviour. + ;; "America/Los_Angeles;Pacific Standard Time" use these timezone names to look up Daylight savings. + ;; 'America/Los_Angeles' is used on Linux/Mac systems whilst 'Pacific Standard Time' is used on Windows + DSTZone = "America/Los_Angeles;Pacific Standard Time" + [MapImageService] LocalServiceModule = "OpenSim.Services.MapImageService.dll:MapImageService" ; in minutes diff --git a/bin/config-include/StandaloneCommon.ini.example b/bin/config-include/StandaloneCommon.ini.example index 8d9842cc5a..e4bc548967 100644 --- a/bin/config-include/StandaloneCommon.ini.example +++ b/bin/config-include/StandaloneCommon.ini.example @@ -61,6 +61,10 @@ ;; uncomment the next line. You may want to do this on sims that have licensed content. ; OutboundPermission = False +[HGFriendsModule] + ; User level required to be able to send friendship invitations to foreign users + ;LevelHGFriends = 0; + [GridService] ;; For in-memory region storage (default) StorageProvider = "OpenSim.Data.Null.dll:NullRegionData" @@ -231,6 +235,14 @@ ; currently unused ;password = http://127.0.0.1/password + ; HG address of the gatekeeper, if you have one + ; this is the entry point for all the regions of the world + ; gatekeeper = http://127.0.0.1:9000/ + + ; HG user domain, if you have one + ; this is the entry point for all user-related HG services + ; uas = http://127.0.0.1:9000/ + [MapImageService] ; Set this if you want to change the default ; TilesStoragePath = "maptiles" diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll index 2c28063f4c..a3ccb98b88 100755 Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index f40f446213..0b286aa96e 100755 Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll index d9e5e89874..d91dac159e 100755 Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so index 06770a4e69..891c956bc7 100755 Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ diff --git a/bin/pCampBot.exe.config b/bin/pCampBot.exe.config index 3f19ee855d..9cfb7e91e4 100644 --- a/bin/pCampBot.exe.config +++ b/bin/pCampBot.exe.config @@ -8,7 +8,7 @@ - + diff --git a/bin/startuplogo.txt b/bin/startuplogo.txt index 0d11e7725e..e69de29bb2 100644 --- a/bin/startuplogo.txt +++ b/bin/startuplogo.txt @@ -1 +0,0 @@ -STARTUP COMPLETE diff --git a/prebuild.xml b/prebuild.xml index f9b26eff82..cb62aecaea 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -34,7 +34,7 @@ - + ../../bin/ @@ -77,7 +77,7 @@ - + ../../bin/ @@ -112,7 +112,7 @@ - + ../../../../bin/ @@ -126,6 +126,7 @@ ../../../../bin/ + @@ -150,7 +151,7 @@ - + ../../../bin/ @@ -177,7 +178,7 @@ - + ../../../bin/ @@ -205,7 +206,7 @@ - + ../../../bin/ @@ -234,7 +235,7 @@ - + ../../../bin/ @@ -258,7 +259,7 @@ - + ../../bin/ @@ -287,7 +288,7 @@ - + ../../../../bin/ @@ -312,7 +313,7 @@ - + ../../../../bin/ @@ -339,7 +340,7 @@ - + ../../../../bin/ @@ -364,7 +365,7 @@ - + ../../../../bin/ @@ -390,7 +391,7 @@ - + ../../../../bin/ @@ -416,7 +417,7 @@ - + ../../../bin/ @@ -448,7 +449,7 @@ - + ../../../../bin/ @@ -476,7 +477,7 @@ - + ../../../../bin/Physics/ @@ -499,7 +500,7 @@ - + ../../../../bin/Physics/ @@ -522,7 +523,7 @@ - + ../../../../bin/Physics/ @@ -552,7 +553,7 @@ - + ../../../../bin/ @@ -577,7 +578,7 @@ - + ../../../../bin/Physics/ @@ -608,7 +609,7 @@ - + ../../../../bin/Physics/ @@ -639,7 +640,7 @@ - + ../../../../bin/Physics/ @@ -672,7 +673,7 @@ - + ../../../../bin/Physics/ @@ -703,7 +704,7 @@ - + ../../../../bin/Physics/ @@ -735,7 +736,7 @@ - + ../../bin/ @@ -770,7 +771,7 @@ - + ../../../bin/ @@ -811,7 +812,7 @@ - + ../../../bin/ @@ -864,7 +865,7 @@ - + ../../../bin/ @@ -894,7 +895,7 @@ - + ../../../bin/ @@ -921,7 +922,7 @@ - + ../../../bin/ @@ -952,7 +953,7 @@ - + ../../../bin/ @@ -983,7 +984,7 @@ - + ../../../bin/ @@ -1022,7 +1023,7 @@ - + ../../../bin/ @@ -1053,7 +1054,7 @@ - + ../../../bin/ @@ -1084,7 +1085,7 @@ - + ../../../bin/ @@ -1116,7 +1117,7 @@ - + ../../../bin/ @@ -1149,7 +1150,7 @@ - + ../../../bin/ @@ -1183,7 +1184,7 @@ - + ../../../bin/ @@ -1214,7 +1215,7 @@ - + ../../../bin/ @@ -1245,7 +1246,7 @@ - + ../../../bin/ @@ -1278,7 +1279,7 @@ - + ../../../bin/ @@ -1311,7 +1312,7 @@ - + ../../../bin/ @@ -1349,7 +1350,7 @@ - + ../../../bin/ @@ -1379,7 +1380,7 @@ - + ../../../bin/ @@ -1418,7 +1419,7 @@ - + ../../../bin/ @@ -1459,7 +1460,7 @@ - + ../../bin/ @@ -1479,6 +1480,7 @@ + @@ -1492,7 +1494,7 @@ - + ../../bin/ @@ -1524,7 +1526,7 @@ - + ../../../bin/ @@ -1567,6 +1569,7 @@ + @@ -1589,7 +1592,7 @@ - + ../../../bin/ @@ -1627,7 +1630,7 @@ - + ../../../bin/ @@ -1662,7 +1665,7 @@ - + ../../../../../bin/ @@ -1705,7 +1708,7 @@ - + ../../../../../bin/ @@ -1747,7 +1750,7 @@ - + ../../../bin/ @@ -1804,7 +1807,7 @@ - + ../../../bin/ @@ -1832,7 +1835,7 @@ - + ../../../bin/ @@ -1876,7 +1879,7 @@ - + ../../../bin/ @@ -1911,7 +1914,7 @@ - + ../../../bin/ @@ -1941,7 +1944,7 @@ - + ../../../bin/ @@ -1982,7 +1985,7 @@ - + ../../../bin/ @@ -2017,7 +2020,7 @@ - + ../../../../bin/ @@ -2054,7 +2057,7 @@ - + ../../../../bin/ @@ -2098,7 +2101,7 @@ - + ../../../bin/ @@ -2135,7 +2138,7 @@ - + ../../../bin/ @@ -2173,7 +2176,7 @@ - + ../../../bin/ @@ -2207,7 +2210,7 @@ - + ../../../bin/ @@ -2248,7 +2251,7 @@ - + ../../../../bin/ @@ -2286,7 +2289,7 @@ - + ../../../../../../bin/ @@ -2319,7 +2322,7 @@ - + ../../../../../../../bin/ @@ -2351,7 +2354,7 @@ - + ../../../../../../bin/ @@ -2390,7 +2393,7 @@ - + ../../../../../bin/ @@ -2421,7 +2424,7 @@ - + ../../../../../bin/ @@ -2459,7 +2462,7 @@ - + ../../../../bin/ @@ -2502,7 +2505,7 @@ - + ../../../bin/ @@ -2553,7 +2556,7 @@ - + ../../../bin/ @@ -2580,7 +2583,7 @@ - + ../../../bin/ @@ -2607,7 +2610,7 @@ - + ../../../bin/ @@ -2631,7 +2634,7 @@ - + ../../../../bin/ @@ -2658,7 +2661,7 @@ - + ../../../../bin/ @@ -2685,7 +2688,7 @@ - + ../../../../bin/ @@ -2712,7 +2715,7 @@ - + ../../../../bin/ @@ -2740,7 +2743,7 @@ - + ../../../bin/ @@ -2784,7 +2787,7 @@ - + ../../bin/ @@ -2807,7 +2810,7 @@ - + ../../../bin/ @@ -2857,7 +2860,7 @@ - + ../../../bin/ @@ -2899,7 +2902,7 @@ - + ../../../bin/ @@ -2930,7 +2933,7 @@ - + ../../../../bin/ @@ -2961,7 +2964,7 @@ - + ../../../../bin/ @@ -2991,7 +2994,7 @@ - + ../../../bin/ @@ -3022,6 +3025,8 @@ + + @@ -3062,7 +3067,7 @@ - + ../../../bin/ @@ -3121,7 +3126,7 @@ - + ../../../bin/ @@ -3135,6 +3140,7 @@ ../../../bin/ + @@ -3179,7 +3185,7 @@ - + ../../../../../bin/ @@ -3216,7 +3222,7 @@ - + ../../../../../../bin/ @@ -3252,7 +3258,7 @@ - + ../../../bin/ @@ -3306,7 +3312,7 @@ TODO: this is kind of lame, we basically build a duplicate assembly but with tests added in, just because we can't resolve cross-bin-dir-refs. --> - + ../../../../../bin/ @@ -3336,7 +3342,7 @@ - + ../../../bin/