From 5e579b71fdd51fc840ddbece99322e1f9c9be805 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 5 Sep 2011 22:55:48 +0100 Subject: [PATCH 01/54] Allow the HGInventoryBroker to set the UserManager when it instantiates a RemoteXInventoryServiceConnector for a visiting HG user. Not doing this causes NREs whenever that user tries to access inventory when Hypergrid is turned on since the Remote connector does not have a scene (which is only used to fetch the UserManager) Aims to address http://opensimulator.org/mantis/view.php?id=5669 --- .../Inventory/HGInventoryBroker.cs | 11 +++++++++-- .../Inventory/RemoteXInventoryServiceConnector.cs | 7 ++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs index 72ae336352..f9e4bb9064 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs @@ -572,14 +572,21 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory string connectorType = new HeloServicesConnector(url).Helo(); m_log.DebugFormat("[HG INVENTORY SERVICE]: HELO returned {0}", connectorType); if (connectorType == "opensim-simian") + { connector = new SimianInventoryServiceConnector(url); + } else - connector = new RemoteXInventoryServicesConnector(url); + { + RemoteXInventoryServicesConnector rxisc = new RemoteXInventoryServicesConnector(url); + rxisc.UserManager = UserManagementModule; + connector = rxisc; + } + m_connectors.Add(url, connector); } } + return connector; } - } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs index 8f1f25774a..4a3ccc53fd 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs @@ -50,7 +50,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory private XInventoryServicesConnector m_RemoteConnector; private IUserManagement m_UserManager; - private IUserManagement UserManager + public IUserManagement UserManager { get { @@ -60,6 +60,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory } return m_UserManager; } + + set + { + m_UserManager = value; + } } public Type ReplaceableInterface From cf73afec356eed30e169be3ce71edad89b4fdb37 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 5 Sep 2011 23:42:37 +0100 Subject: [PATCH 02/54] Try disabling the inconsistent attachment state check to see if this actually has an impact. The code in question is over three years old and just be catching an inconsistency rather than being wholly necessary. This commit still carries out the check and prints all the previous log warnings but a 'failure' no longer prevents avatar region crossing or teleport, and it doesn't give the client the error message. This will have some kind of impact on http://opensimulator.org/mantis/view.php?id=5672 --- .../EntityTransfer/EntityTransferModule.cs | 31 +++++++++++-------- .../Scripting/WorldComm/WorldCommModule.cs | 3 +- .../Region/Framework/Scenes/ScenePresence.cs | 16 +++++----- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 45506ed52b..ac13d5ea5f 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -209,7 +209,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Teleport(position); foreach (SceneObjectGroup grp in sp.GetAttachments()) - sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT); + { + if (grp.IsDeleted) + sp.Scene.EventManager.TriggerOnScriptChangedEvent(grp.LocalId, (uint)Changed.TELEPORT); + } } else // Another region possibly in another simulator { @@ -326,11 +329,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (sp.ParentID != (uint)0) sp.StandUp(); - if (!sp.ValidateAttachments()) - { - sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state"); - return; - } +// if (!sp.ValidateAttachments()) +// { +// sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state"); +// return; +// } string reason; string version; @@ -944,8 +947,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer Scene m_scene = agent.Scene; - if (neighbourRegion != null && agent.ValidateAttachments()) + if (neighbourRegion != null) { + agent.ValidateAttachments(); + pos = pos + (agent.Velocity); SetInTransit(agent.UUID); @@ -1763,16 +1768,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer List m_attachments = sp.GetAttachments(); // Validate - foreach (SceneObjectGroup gobj in m_attachments) - { - if (gobj == null || gobj.IsDeleted) - return false; - } +// foreach (SceneObjectGroup gobj in m_attachments) +// { +// if (gobj == null || gobj.IsDeleted) +// return false; +// } foreach (SceneObjectGroup gobj in m_attachments) { // If the prim group is null then something must have happened to it! - if (gobj != null) + if (gobj != null && !gobj.IsDeleted) { // Set the parent localID to 0 so it transfers over properly. gobj.RootPart.SetParentLocalId(0); diff --git a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs index b20a875139..a14a84b42a 100644 --- a/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/WorldComm/WorldCommModule.cs @@ -323,7 +323,8 @@ namespace OpenSim.Region.CoreModules.Scripting.WorldComm List targets = new List(); foreach (SceneObjectGroup sog in attachments) { - targets.Add(sog.UUID); + if (!sog.IsDeleted) + targets.Add(sog.UUID); } // Need to check each attachment diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 1c283c7c2c..f231a390c8 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3498,7 +3498,10 @@ namespace OpenSim.Region.Framework.Scenes m_attachments.Clear(); } - public bool ValidateAttachments() + /// + /// This is currently just being done for information. + /// + public void ValidateAttachments() { lock (m_attachments) { @@ -3508,21 +3511,16 @@ namespace OpenSim.Region.Framework.Scenes if (gobj == null) { m_log.WarnFormat( - "[SCENE PRESENCE]: Failed to validate an attachment for {0} since it was null", Name); - return false; + "[SCENE PRESENCE]: Failed to validate an attachment for {0} since it was null. Continuing", Name); } - - if (gobj.IsDeleted) + else if (gobj.IsDeleted) { m_log.WarnFormat( - "[SCENE PRESENCE]: Failed to validate attachment {0} {1} for {2} since it had been deleted", + "[SCENE PRESENCE]: Failed to validate attachment {0} {1} for {2} since it had been deleted. Continuing", gobj.Name, gobj.UUID, Name); - return false; } } } - - return true; } /// From 0cb0140a1d652c3ba47f1c9000d1ba81c8e786f8 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 6 Sep 2011 00:29:37 +0100 Subject: [PATCH 03/54] Stop the pointless double setting of every attachment in AvatarAppearance. The second was already being filtered out so this has no user level effect --- OpenSim/Framework/AvatarAppearance.cs | 14 ++++++++++---- .../Avatar/Attachments/AttachmentsModule.cs | 8 ++------ .../Attachments/Tests/AttachmentsModuleTests.cs | 1 + 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index aed9087f07..0b0afeb9bf 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs @@ -402,8 +402,13 @@ namespace OpenSim.Framework internal void AppendAttachment(AvatarAttachment attach) { - if (! m_attachments.ContainsKey(attach.AttachPoint)) +// m_log.DebugFormat( +// "[AVATAR APPEARNCE]: Appending itemID={0}, assetID={1} at {2}", +// attach.ItemID, attach.AssetID, attach.AttachPoint); + + if (!m_attachments.ContainsKey(attach.AttachPoint)) m_attachments[attach.AttachPoint] = new List(); + m_attachments[attach.AttachPoint].Add(attach); } @@ -430,13 +435,13 @@ namespace OpenSim.Framework /// public bool SetAttachment(int attachpoint, UUID item, UUID asset) { - if (attachpoint == 0) - return false; - // m_log.DebugFormat( // "[AVATAR APPEARANCE]: Setting attachment at {0} with item ID {1}, asset ID {2}", // attachpoint, item, asset); + if (attachpoint == 0) + return false; + if (item == UUID.Zero) { if (m_attachments.ContainsKey(attachpoint)) @@ -465,6 +470,7 @@ namespace OpenSim.Framework { ReplaceAttachment(new AvatarAttachment(attachpoint,item, asset)); } + return true; } diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 48814990e1..e2e697e771 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -242,7 +242,7 @@ 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); +// group.Name, group.LocalId, sp.Name, attachmentPt, silent); if (sp.GetAttachments(attachmentPt).Contains(group)) { @@ -356,8 +356,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { if (att == null) DetachSingleAttachmentToInv(itemID, sp.ControllingClient); - else - ShowAttachInUserInventory(att, sp, itemID, AttachmentPt); } return att; @@ -386,9 +384,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (objatt != null) { - // Loading the inventory from XML will have set this, but - // there is no way the object could have changed yet, - // since scripts aren't running yet. So, clear it here. + // 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) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 363e2584aa..3f8c01fc1c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -150,6 +150,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests 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)); } From 05a4bedc305a299efaf89c881b7dafbe25ed23a6 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 6 Sep 2011 00:32:52 +0100 Subject: [PATCH 04/54] get rid of the unused AttachmentsModule.ShowAttachInUserInventory() --- .../Avatar/Attachments/AttachmentsModule.cs | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index e2e697e771..dde6ca609b 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -430,34 +430,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return null; } - - /// - /// Update the user inventory to the attachment of an item - /// - /// - /// - /// - /// - /// - private UUID ShowAttachInUserInventory( - SceneObjectGroup att, IScenePresence sp, UUID itemID, uint attachmentPoint) - { -// m_log.DebugFormat( -// "[ATTACHMENTS MODULE]: Updating inventory of {0} to show attachment of {1} {2} (item ID {3}) at {4}", -// sp.Name, att.Name, att.LocalId, itemID, AttachmentPt); - - if (!att.IsDeleted) - attachmentPoint = att.AttachmentPoint; - - InventoryItemBase item = new InventoryItemBase(itemID, sp.UUID); - item = m_scene.InventoryService.GetItem(item); - - bool changed = sp.Appearance.SetAttachment((int)attachmentPoint, itemID, item.AssetID); - if (changed && m_scene.AvatarFactory != null) - m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID); - - return att.UUID; - } /// /// Update the user inventory to reflect an attachment From c6ec573d105b52f65e02077e8603a9b586884ecd Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 6 Sep 2011 00:36:38 +0100 Subject: [PATCH 05/54] Get rid of the confusing version of IAttachmentsModule.RezSingleAttachmentFromInventory() with the updateInventoryStatus switch, since this is never called with false --- .../Avatar/Attachments/AttachmentsModule.cs | 13 ++----------- .../Framework/Interfaces/IAttachmentsModule.cs | 14 -------------- 2 files changed, 2 insertions(+), 25 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index dde6ca609b..67969b7dbb 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -326,12 +326,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public ISceneEntity RezSingleAttachmentFromInventory( IClientAPI remoteClient, UUID itemID, uint AttachmentPt) { - return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true); - } - - public ISceneEntity RezSingleAttachmentFromInventory( - IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus) - { // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", // (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); @@ -352,11 +346,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt); - if (updateInventoryStatus) - { - if (att == null) - DetachSingleAttachmentToInv(itemID, sp.ControllingClient); - } + if (att == null) + DetachSingleAttachmentToInv(itemID, sp.ControllingClient); return att; } diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index dd11ded8a6..73d15a5f50 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -87,20 +87,6 @@ namespace OpenSim.Region.Framework.Interfaces /// The scene object that was attached. Null if the scene object could not be found ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt); - /// - /// Rez an attachment from user inventory - /// - /// - /// - /// - /// - /// If true, we also update the user's inventory to show that the attachment is set. If false, we do not. - /// False is required so that we don't attempt to update information when a user enters a scene with the - /// attachment already correctly set up in inventory. - /// The uuid of the scene object that was attached. Null if the scene object could not be found - ISceneEntity RezSingleAttachmentFromInventory( - IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus); - /// /// Rez multiple attachments from a user's inventory /// From b903d2ca963d5f68803a1cabbd033f89ab72634a Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 6 Sep 2011 01:59:21 +0100 Subject: [PATCH 06/54] In SetAttachment, if the existing attachment has no asset id then carry on rather than abort. When a user logs in, the attachment item ids are pulled from persistence in the Avatars table. However, the asset ids are not saved. When the avatar enters a simulator the attachments are set again. If we simply perform an item check then the asset ids (which are now present) are never set, and NPC attachments later fail unless the attachment is detached and reattached. Hopefully resolves part of http://opensimulator.org/mantis/view.php?id=5653 --- OpenSim/Framework/AvatarAppearance.cs | 36 +++++++++++++++++-- OpenSim/Framework/ChildAgentDataUpdate.cs | 1 + .../Tests/AttachmentsModuleTests.cs | 8 +++++ OpenSim/Services/Interfaces/IAvatarService.cs | 4 +-- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index 0b0afeb9bf..cce44b02b8 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs @@ -414,12 +414,16 @@ namespace OpenSim.Framework internal void ReplaceAttachment(AvatarAttachment attach) { +// m_log.DebugFormat( +// "[AVATAR APPEARANCE]: Replacing itemID={0}, assetID={1} at {2}", +// attach.ItemID, attach.AssetID, attach.AttachPoint); + m_attachments[attach.AttachPoint] = new List(); m_attachments[attach.AttachPoint].Add(attach); } /// - /// Add an attachment + /// Set an attachment /// /// /// If the attachpoint has the @@ -449,11 +453,20 @@ namespace OpenSim.Framework m_attachments.Remove(attachpoint); return true; } + return false; } - // check if the item is already attached at this point - if (GetAttachpoint(item) == (attachpoint & 0x7F)) + // When a user logs in, the attachment item ids are pulled from persistence in the Avatars table. However, + // the asset ids are not saved. When the avatar enters a simulator the attachments are set again. If + // we simply perform an item check here then the asset ids (which are now present) are never set, and NPC attachments + // later fail unless the attachment is detached and reattached. + // + // Therefore, we will carry on with the set if the existing attachment has no asset id. + AvatarAttachment existingAttachment = GetAttachmentForItem(item); + if (existingAttachment != null + && existingAttachment.AssetID != UUID.Zero + && existingAttachment.AttachPoint == (attachpoint & 0x7F)) { // m_log.DebugFormat("[AVATAR APPEARANCE] attempt to attach an already attached item {0}",item); return false; @@ -474,6 +487,23 @@ namespace OpenSim.Framework return true; } + /// + /// If the item is already attached, return it. + /// + /// + /// Returns null if this item is not attached. + public AvatarAttachment GetAttachmentForItem(UUID itemID) + { + foreach (KeyValuePair> kvp in m_attachments) + { + int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; }); + if (index >= 0) + return kvp.Value[index]; + } + + return null; + } + public int GetAttachpoint(UUID itemID) { foreach (KeyValuePair> kvp in m_attachments) diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs index 613db1c55a..53ec166b4e 100644 --- a/OpenSim/Framework/ChildAgentDataUpdate.cs +++ b/OpenSim/Framework/ChildAgentDataUpdate.cs @@ -628,6 +628,7 @@ namespace OpenSim.Framework // We know all of these must end up as attachments so we // append rather than replace to ensure multiple attachments // per point continues to work +// m_log.DebugFormat("[CHILDAGENTDATAUPDATE]: Appending attachments for {0}", AgentID); Appearance.AppendAttachment(new AvatarAttachment((OSDMap)o)); } } diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 3f8c01fc1c..0fa2e00e2b 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -247,6 +247,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(attSo.IsAttachment); Assert.That(attSo.UsesPhysics, Is.False); Assert.That(attSo.IsTemporary, Is.False); + + // Check appearance status + 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)); } // I'm commenting this test because scene setup NEEDS InventoryService to diff --git a/OpenSim/Services/Interfaces/IAvatarService.cs b/OpenSim/Services/Interfaces/IAvatarService.cs index 0d5ab7db2e..cda7113a4f 100644 --- a/OpenSim/Services/Interfaces/IAvatarService.cs +++ b/OpenSim/Services/Interfaces/IAvatarService.cs @@ -262,7 +262,6 @@ namespace OpenSim.Services.Interfaces UUID.Parse(Data["SkirtItem"]), UUID.Parse(Data["SkirtAsset"])); - if (Data.ContainsKey("VisualParams")) { string[] vps = Data["VisualParams"].Split(new char[] {','}); @@ -291,7 +290,6 @@ namespace OpenSim.Services.Interfaces } } - // Attachments Dictionary attchs = new Dictionary(); foreach (KeyValuePair _kvp in Data) @@ -308,7 +306,7 @@ namespace OpenSim.Services.Interfaces UUID uuid = UUID.Zero; UUID.TryParse(_kvp.Value, out uuid); - appearance.SetAttachment(point,uuid,UUID.Zero); + appearance.SetAttachment(point, uuid, UUID.Zero); } if (appearance.Wearables[AvatarWearable.BODY].Count == 0) From 5beee42809ad0fbdf559cb82038a5d3d41e98d9e Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 6 Sep 2011 02:29:22 +0100 Subject: [PATCH 07/54] rename AM.AddSceneObjectAsAttachment() to AddSceneObjectAsNewAttachmentInInv --- .../CoreModules/Avatar/Attachments/AttachmentsModule.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 67969b7dbb..af431f498a 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -302,7 +302,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments itemID = group.GetFromItemID(); if (itemID == UUID.Zero) - itemID = AddSceneObjectAsAttachment(sp.ControllingClient, group).ID; + itemID = AddSceneObjectAsNewAttachmentInInv(sp.ControllingClient, group).ID; ShowAttachInUserInventory(sp, attachmentPt, itemID, group); } @@ -733,12 +733,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } /// - /// Add a scene object that was previously free in the scene as an attachment to an avatar. + /// Add a scene object as a new attachment in the user inventory. /// /// /// /// The user inventory item created that holds the attachment. - private InventoryItemBase AddSceneObjectAsAttachment(IClientAPI remoteClient, SceneObjectGroup grp) + private InventoryItemBase AddSceneObjectAsNewAttachmentInInv(IClientAPI remoteClient, SceneObjectGroup grp) { // m_log.DebugFormat("[SCENE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2} {3} {4}", grp.Name, grp.LocalId, remoteClient.Name, remoteClient.AgentId, AgentId); From 1a8f5b97b968bcb46f31cb1b3458acee4ed7f1db Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 6 Sep 2011 02:40:19 +0100 Subject: [PATCH 08/54] refactor: Make logic in AM.AttachObject() clearer by not reusing existing variables in different contexts --- .../Avatar/Attachments/AttachmentsModule.cs | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index af431f498a..996e2ab159 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -285,26 +285,31 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments group.AttachmentPoint = attachmentPt; group.AbsolutePosition = attachPos; - // Remove any previous attachments - UUID itemID = UUID.Zero; - - List attachments = sp.GetAttachments(attachmentPt); - - // At the moment we can only deal with a single attachment // 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) - itemID = attachments[0].GetFromItemID(); + { + UUID oldAttachmentItemID = attachments[0].GetFromItemID(); - if (itemID != UUID.Zero) - DetachSingleAttachmentToInv(itemID, sp); + if (oldAttachmentItemID != UUID.Zero) + DetachSingleAttachmentToInv(oldAttachmentItemID, sp); + 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.GetFromItemID(); + if (newAttachmentItemID == UUID.Zero) + newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp.ControllingClient, group).ID; - itemID = group.GetFromItemID(); - if (itemID == UUID.Zero) - itemID = AddSceneObjectAsNewAttachmentInInv(sp.ControllingClient, group).ID; - - ShowAttachInUserInventory(sp, attachmentPt, itemID, group); + ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group); } AttachToAgent(sp, group, attachmentPt, attachPos, silent); From 4bf3adffb8d58a7a856307df3460ac3eb4bf6d91 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 6 Sep 2011 22:26:28 +0100 Subject: [PATCH 09/54] In SceneViewer, introduce an IsEnabled flag and perform Close() under an m_pendingObjects lock in order to avoid the race condition seen by danbanner in http://opensimulator.org/mantis/view.php?id=5669 --- .../Framework/Interfaces/ISceneViewer.cs | 11 +++- .../Region/Framework/Scenes/SceneViewer.cs | 59 +++++++++++++------ 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs b/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs index 2397f223b3..a4cc2bee40 100644 --- a/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs +++ b/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs @@ -30,12 +30,21 @@ using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.Framework.Interfaces { + /// + /// Sends scheduled updates to it's associated ScenePresence. + /// public interface ISceneViewer { void Reset(); void Close(); + + /// + /// Add the part to the queue of parts for which we need to send an update to the client + /// + /// void QueuePartForUpdate(SceneObjectPart part); + void SendPrimUpdates(); int GetPendingObjectsCount(); } -} +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/SceneViewer.cs b/OpenSim/Region/Framework/Scenes/SceneViewer.cs index e2ea830ca1..3e0d1dbc77 100644 --- a/OpenSim/Region/Framework/Scenes/SceneViewer.cs +++ b/OpenSim/Region/Framework/Scenes/SceneViewer.cs @@ -38,27 +38,42 @@ namespace OpenSim.Region.Framework.Scenes { public class SceneViewer : ISceneViewer { + /// + /// Is this scene viewer enabled? + /// + private bool IsEnabled { get; set; } + + /// + /// The scene presence serviced by this viewer. + /// protected ScenePresence m_presence; + + /// + /// The queue of parts for which we need to send out updates. + /// protected UpdateQueue m_partsUpdateQueue = new UpdateQueue(); + + /// + /// The queue of objects for which we need to send out updates. + /// protected Queue m_pendingObjects; + /// + /// The last update assocated with a given part update. + /// protected Dictionary m_updateTimes = new Dictionary(); - public SceneViewer() - { - } - public SceneViewer(ScenePresence presence) { m_presence = presence; + IsEnabled = true; } - /// - /// Add the part to the queue of parts for which we need to send an update to the client - /// - /// public void QueuePartForUpdate(SceneObjectPart part) { + if (!IsEnabled) + return; + lock (m_partsUpdateQueue) { m_partsUpdateQueue.Enqueue(part); @@ -87,6 +102,11 @@ namespace OpenSim.Region.Framework.Scenes lock (m_pendingObjects) { + // We must do this under lock so that we don't suffer a race condition if another thread closes the + // viewer + if (!IsEnabled) + return; + while (m_pendingObjects != null && m_pendingObjects.Count > 0) { SceneObjectGroup g = m_pendingObjects.Dequeue(); @@ -119,7 +139,6 @@ namespace OpenSim.Region.Framework.Scenes // We deal with the possibility that two updates occur at // the same unix time at the update point itself. - if ((update.LastFullUpdateTime < part.TimeStampFull) || part.ParentGroup.IsAttachment) { // m_log.DebugFormat( @@ -135,9 +154,7 @@ namespace OpenSim.Region.Framework.Scenes // this update. If this happened, then subsequent // updates which occurred on the same tick or the // next tick of the last update would be ignored. - update.LastFullUpdateTime = part.TimeStampFull; - } else if (update.LastTerseUpdateTime <= part.TimeStampTerse) { @@ -193,15 +210,21 @@ namespace OpenSim.Region.Framework.Scenes public void Close() { - lock (m_updateTimes) + lock (m_pendingObjects) { - m_updateTimes.Clear(); + IsEnabled = false; + + lock (m_updateTimes) + { + m_updateTimes.Clear(); + } + lock (m_partsUpdateQueue) + { + m_partsUpdateQueue.Clear(); + } + + Reset(); } - lock (m_partsUpdateQueue) - { - m_partsUpdateQueue.Clear(); - } - Reset(); } public int GetPendingObjectsCount() From 405a5b097b146eeb0db0f9b59d89a2fc6f352cee Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 6 Sep 2011 22:39:01 +0100 Subject: [PATCH 10/54] Comment out unused ISceneViewer.Reset() to reduce code complexity --- OpenSim/Region/Framework/Interfaces/ISceneViewer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs b/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs index a4cc2bee40..e715e706f2 100644 --- a/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs +++ b/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs @@ -35,7 +35,7 @@ namespace OpenSim.Region.Framework.Interfaces /// public interface ISceneViewer { - void Reset(); +// void Reset(); void Close(); /// From 3d4d3427cd2c61b982b602eeba0ec7105ae9be50 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 6 Sep 2011 22:44:34 +0100 Subject: [PATCH 11/54] Comment out SceneViewer.Reset() and stop calling from Close() since this is useless work as a closed scene object is never reset. Strictly speaking, we could also stop bothering to clear the m_updateTimes and m_partsUpdateQueue if we are sure that the whole SceneViewer is shortly to be garbage collected anyway, but we'll leave them around for now. --- .../Region/Framework/Scenes/SceneViewer.cs | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneViewer.cs b/OpenSim/Region/Framework/Scenes/SceneViewer.cs index 3e0d1dbc77..9ad80b808d 100644 --- a/OpenSim/Region/Framework/Scenes/SceneViewer.cs +++ b/OpenSim/Region/Framework/Scenes/SceneViewer.cs @@ -193,37 +193,38 @@ namespace OpenSim.Region.Framework.Scenes } } - public void Reset() - { - if (m_pendingObjects == null) - return; - - lock (m_pendingObjects) - { - if (m_pendingObjects != null) - { - m_pendingObjects.Clear(); - m_pendingObjects = null; - } - } - } +// public void Reset() +// { +// if (m_pendingObjects == null) +// return; +// +// lock (m_pendingObjects) +// { +// if (m_pendingObjects != null) +// { +// m_pendingObjects.Clear(); +// m_pendingObjects = null; +// } +// } +// } public void Close() { lock (m_pendingObjects) { + // We perform this under the m_pendingObjects lock in order to avoid a race condition with another + // thread on SendPrimUpdates() IsEnabled = false; lock (m_updateTimes) { m_updateTimes.Clear(); } + lock (m_partsUpdateQueue) { m_partsUpdateQueue.Clear(); } - - Reset(); } } From e6cd4defdbee5d6df9cb5809ab66619ac1e51c9b Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 6 Sep 2011 22:48:05 +0100 Subject: [PATCH 12/54] Lock m_pendingObjects when calling GetPendingObjectsCount(). This is only called by a region console command. We should also be locking m_partsUpdateQueue when dequeueing the next part, or locking m_pendingObjects in QueuePartForUpdate(). However, I won't do this now since I don't have time to analyze how this would affect liveness. --- OpenSim/Region/Framework/Scenes/SceneViewer.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneViewer.cs b/OpenSim/Region/Framework/Scenes/SceneViewer.cs index 9ad80b808d..50e1e39afe 100644 --- a/OpenSim/Region/Framework/Scenes/SceneViewer.cs +++ b/OpenSim/Region/Framework/Scenes/SceneViewer.cs @@ -231,7 +231,8 @@ namespace OpenSim.Region.Framework.Scenes public int GetPendingObjectsCount() { if (m_pendingObjects != null) - return m_pendingObjects.Count; + lock (m_pendingObjects) + return m_pendingObjects.Count; return 0; } From d7a516d885b9b39fe70e4e7a8645ebbd1671b110 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 6 Sep 2011 23:16:37 +0100 Subject: [PATCH 13/54] Add temporary debugging in HGInventoryBroker and RemoveXInventoryServiceConnector This is for http://opensimulator.org/mantis/view.php?id=5669 If we can't retrieve an IUserManagement module we complain, and we also warn in the log when its manually set in XISC by HGInventoryBroker --- .../UserManagement/UserManagementModule.cs | 2 -- .../Inventory/HGInventoryBroker.cs | 36 +++++++++++-------- .../RemoteXInventoryServiceConnector.cs | 14 ++++++-- 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index b0b35e4d0d..f7003dbb12 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -87,8 +87,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement "Show the bindings between user UUIDs and user names", String.Empty, HandleShowUsers); - - } public bool IsSharedModule diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs index f9e4bb9064..d9d7318a18 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs @@ -64,7 +64,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory get { if (m_UserManagement == null) + { m_UserManagement = m_Scenes[0].RequestModuleInterface(); + + if (m_UserManagement == null) + m_log.ErrorFormat( + "[HG INVENTORY CONNECTOR]: Could not retrieve IUserManagement module from {0}", + m_Scenes[0].RegionInfo.RegionName); + } + return m_UserManagement; } } @@ -323,7 +331,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory } - public List GetFolderItems(UUID userID, UUID folderID) + public List GetFolderItems(UUID userID, UUID folderID) { //m_log.Debug("[HG INVENTORY CONNECTOR]: GetFolderItems " + folderID); @@ -338,7 +346,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory } - public bool AddFolder(InventoryFolderBase folder) + public bool AddFolder(InventoryFolderBase folder) { if (folder == null) return false; @@ -355,7 +363,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector.AddFolder(folder); } - public bool UpdateFolder(InventoryFolderBase folder) + public bool UpdateFolder(InventoryFolderBase folder) { if (folder == null) return false; @@ -372,7 +380,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector.UpdateFolder(folder); } - public bool DeleteFolders(UUID ownerID, List folderIDs) + public bool DeleteFolders(UUID ownerID, List folderIDs) { if (folderIDs == null) return false; @@ -391,7 +399,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector.DeleteFolders(ownerID, folderIDs); } - public bool MoveFolder(InventoryFolderBase folder) + public bool MoveFolder(InventoryFolderBase folder) { if (folder == null) return false; @@ -408,7 +416,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector.MoveFolder(folder); } - public bool PurgeFolder(InventoryFolderBase folder) + public bool PurgeFolder(InventoryFolderBase folder) { if (folder == null) return false; @@ -442,7 +450,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector.AddItem(item); } - public bool UpdateItem(InventoryItemBase item) + public bool UpdateItem(InventoryItemBase item) { if (item == null) return false; @@ -459,7 +467,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector.UpdateItem(item); } - public bool MoveItems(UUID ownerID, List items) + public bool MoveItems(UUID ownerID, List items) { if (items == null) return false; @@ -478,7 +486,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector.MoveItems(ownerID, items); } - public bool DeleteItems(UUID ownerID, List itemIDs) + public bool DeleteItems(UUID ownerID, List itemIDs) { //m_log.DebugFormat("[HG INVENTORY CONNECTOR]: Delete {0} items for user {1}", itemIDs.Count, ownerID); @@ -497,7 +505,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector.DeleteItems(ownerID, itemIDs); } - public InventoryItemBase GetItem(InventoryItemBase item) + public InventoryItemBase GetItem(InventoryItemBase item) { if (item == null) return null; @@ -513,7 +521,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector.GetItem(item); } - public InventoryFolderBase GetFolder(InventoryFolderBase folder) + public InventoryFolderBase GetFolder(InventoryFolderBase folder) { if (folder == null) return null; @@ -530,17 +538,17 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector.GetFolder(folder); } - public bool HasInventoryForUser(UUID userID) + public bool HasInventoryForUser(UUID userID) { return false; } - public List GetActiveGestures(UUID userId) + public List GetActiveGestures(UUID userId) { return new List(); } - public int GetAssetPermissions(UUID userID, UUID assetID) + public int GetAssetPermissions(UUID userID, UUID assetID) { //m_log.Debug("[HG INVENTORY CONNECTOR]: GetAssetPermissions " + assetID); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs index 4a3ccc53fd..97fdd4e5ad 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs @@ -57,12 +57,21 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory if (m_UserManager == null) { m_UserManager = m_Scene.RequestModuleInterface(); + + if (m_UserManager == null) + m_log.ErrorFormat( + "[XINVENTORY CONNECTOR]: Could not retrieve IUserManagement module from {0}", + m_Scene.RegionInfo.RegionName); } + return m_UserManager; } set { + m_log.WarnFormat( + "[XINVENTORY CONNECTOR]: Manually setting UserManager {0} (scene {1})", value, m_Scene); + m_UserManager = value; } } @@ -91,12 +100,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory Init(source); } - protected void Init(IConfigSource source) + protected void Init(IConfigSource source) { m_RemoteConnector = new XInventoryServicesConnector(source); } - #region ISharedRegionModule public void Initialise(IConfigSource source) @@ -186,7 +194,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return m_RemoteConnector.GetFolderForType(userID, type); } - public InventoryCollection GetFolderContent(UUID userID, UUID folderID) + public InventoryCollection GetFolderContent(UUID userID, UUID folderID) { InventoryCollection invCol = m_RemoteConnector.GetFolderContent(userID, folderID); Util.FireAndForget(delegate From 7cadb89a0f5a298beda619c395c0810ca198a718 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 7 Sep 2011 23:16:19 +0100 Subject: [PATCH 14/54] When a region is added to the HG Inventory Broker, also pass this through to the embedded local inventory connector to prevent an NRE when that connector tries to lookup the UserManager through the scene. This is to address http://opensimulator.org/mantis/view.php?id=5669 However, if this failure was happening I'm kind of surprised that local HG inventory was working at all..... We probably weren't seeing these exceptions previously because we weren't logging them when the reached the top of a FireAndForget thread. --- .../Inventory/HGInventoryBroker.cs | 27 ++++++++++++++++--- .../LocalInventoryServiceConnector.cs | 13 +++++---- .../RemoteXInventoryServiceConnector.cs | 22 +++++++-------- 3 files changed, 41 insertions(+), 21 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs index d9d7318a18..0d121edb97 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs @@ -148,8 +148,29 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory scene.RegisterModuleInterface(this); - scene.EventManager.OnClientClosed += OnClientClosed; + if (m_Scenes.Count == 1) + { + // FIXME: The local connector needs the scene to extract the UserManager. However, it's not enabled so + // we can't just add the region. But this approach is super-messy. + if (m_LocalGridInventoryService is RemoteXInventoryServicesConnector) + { + m_log.DebugFormat( + "[HG INVENTORY BROKER]: Manually setting scene in RemoteXInventoryServicesConnector to {0}", + scene.RegionInfo.RegionName); + ((RemoteXInventoryServicesConnector)m_LocalGridInventoryService).Scene = scene; + } + else if (m_LocalGridInventoryService is LocalInventoryServicesConnector) + { + m_log.DebugFormat( + "[HG INVENTORY BROKER]: Manually setting scene in LocalInventoryServicesConnector to {0}", + scene.RegionInfo.RegionName); + + ((LocalInventoryServicesConnector)m_LocalGridInventoryService).Scene = scene; + } + + scene.EventManager.OnClientClosed += OnClientClosed; + } } public void RemoveRegion(Scene scene) @@ -586,7 +607,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory else { RemoteXInventoryServicesConnector rxisc = new RemoteXInventoryServicesConnector(url); - rxisc.UserManager = UserManagementModule; + rxisc.Scene = m_Scenes[0]; connector = rxisc; } @@ -597,4 +618,4 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory return connector; } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs index 65e39c0c06..d3ef08d4f6 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs @@ -47,9 +47,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - private IInventoryService m_InventoryService; + /// + /// Scene used by this module. This currently needs to be publicly settable for HGInventoryBroker. + /// + public Scene Scene { get; set; } - private Scene m_Scene; + private IInventoryService m_InventoryService; private IUserManagement m_UserManager; private IUserManagement UserManager @@ -58,7 +61,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory { if (m_UserManager == null) { - m_UserManager = m_Scene.RequestModuleInterface(); + m_UserManager = Scene.RequestModuleInterface(); } return m_UserManager; } @@ -131,8 +134,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory scene.RegisterModuleInterface(this); - if (m_Scene == null) - m_Scene = scene; + if (Scene == null) + Scene = scene; } public void RemoveRegion(Scene scene) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs index 97fdd4e5ad..eb907749d9 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs @@ -45,6 +45,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// + /// Scene used by this module. This currently needs to be publicly settable for HGInventoryBroker. + /// + public Scene Scene { get; set; } + private bool m_Enabled = false; private Scene m_Scene; private XInventoryServicesConnector m_RemoteConnector; @@ -56,24 +61,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory { if (m_UserManager == null) { - m_UserManager = m_Scene.RequestModuleInterface(); + m_UserManager = Scene.RequestModuleInterface(); if (m_UserManager == null) m_log.ErrorFormat( "[XINVENTORY CONNECTOR]: Could not retrieve IUserManagement module from {0}", - m_Scene.RegionInfo.RegionName); + Scene.RegionInfo.RegionName); } return m_UserManager; } - - set - { - m_log.WarnFormat( - "[XINVENTORY CONNECTOR]: Manually setting UserManager {0} (scene {1})", value, m_Scene); - - m_UserManager = value; - } } public Type ReplaceableInterface @@ -141,15 +138,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory scene.RegisterModuleInterface(this); - if (m_Scene == null) - m_Scene = scene; + if (Scene == null) + Scene = scene; } public void RemoveRegion(Scene scene) { if (!m_Enabled) return; - } public void RegionLoaded(Scene scene) From 08bd16285d3b9e2be8f76db17ac7cd7a861ae817 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 7 Sep 2011 23:55:41 +0100 Subject: [PATCH 15/54] When invoking any of the OSSL teleport functions, do it on a separate thread rather than the script thread. This is to prevent the aborting of attachment script threads on teleport from aborting the one actually doing the teleport. This allows OSSL teleport functions to work when invoked on scripts in attachments (and huds, I assume) --- .../Shared/Api/Implementation/OSSL_Api.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 3ddd79b283..e1c837e51a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -703,9 +703,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api == World.LandChannel.GetLandObject( presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) { - World.RequestTeleportLocation(presence.ControllingClient, regionName, - new Vector3((float)position.x, (float)position.y, (float)position.z), - new Vector3((float)lookat.x, (float)lookat.y, (float)lookat.z), (uint)TPFlags.ViaLocation); + // We will launch the teleport on a new thread so that when the script threads are terminated + // before teleport in ScriptInstance.GetXMLState(), we don't end up aborting the one doing the teleporting. + Util.FireAndForget( + o => World.RequestTeleportLocation(presence.ControllingClient, regionName, + new Vector3((float)position.x, (float)position.y, (float)position.z), + new Vector3((float)lookat.x, (float)lookat.y, (float)lookat.z), (uint)TPFlags.ViaLocation)); ScriptSleep(5000); } @@ -741,9 +744,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api == World.LandChannel.GetLandObject( presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID) { - World.RequestTeleportLocation(presence.ControllingClient, regionHandle, - new Vector3((float)position.x, (float)position.y, (float)position.z), - new Vector3((float)lookat.x, (float)lookat.y, (float)lookat.z), (uint)TPFlags.ViaLocation); + // We will launch the teleport on a new thread so that when the script threads are terminated + // before teleport in ScriptInstance.GetXMLState(), we don't end up aborting the one doing the teleporting. + Util.FireAndForget( + o => World.RequestTeleportLocation(presence.ControllingClient, regionHandle, + new Vector3((float)position.x, (float)position.y, (float)position.z), + new Vector3((float)lookat.x, (float)lookat.y, (float)lookat.z), (uint)TPFlags.ViaLocation)); + ScriptSleep(5000); } } From 3e7960d161af4157fcd315c2b932a305548ce50d Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 8 Sep 2011 19:52:28 +0100 Subject: [PATCH 16/54] Increase information in logging for UserAgentServiceConnector. Done for http://opensimulator.org/mantis/view.php?id=5669 --- .../Hypergrid/UserAgentServiceConnector.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs index 08a3876676..63aabad04f 100644 --- a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs @@ -441,14 +441,14 @@ namespace OpenSim.Services.Connectors.Hypergrid } catch { - m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0}", m_ServerURL); + m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for StatusNotification", m_ServerURL); // reason = "Exception: " + e.Message; return friendsOnline; } if (response.IsFault) { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} returned an error: {1}", m_ServerURL, response.FaultString); + m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for StatusNotification returned an error: {1}", m_ServerURL, response.FaultString); // reason = "XMLRPC Fault"; return friendsOnline; } @@ -512,14 +512,14 @@ namespace OpenSim.Services.Connectors.Hypergrid } catch { - m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0}", m_ServerURL); + m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetOnlineFriends", m_ServerURL); // reason = "Exception: " + e.Message; return online; } if (response.IsFault) { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} returned an error: {1}", m_ServerURL, response.FaultString); + m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetOnlineFriends returned an error: {1}", m_ServerURL, response.FaultString); // reason = "XMLRPC Fault"; return online; } @@ -577,14 +577,14 @@ namespace OpenSim.Services.Connectors.Hypergrid } catch { - m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0}", m_ServerURL); + m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetServerURLs", m_ServerURL); // reason = "Exception: " + e.Message; return serverURLs; } if (response.IsFault) { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} returned an error: {1}", m_ServerURL, response.FaultString); + m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetServerURLs returned an error: {1}", m_ServerURL, response.FaultString); // reason = "XMLRPC Fault"; return serverURLs; } @@ -641,14 +641,14 @@ namespace OpenSim.Services.Connectors.Hypergrid } catch { - m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0}", m_ServerURL); + m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for LocateUser", m_ServerURL); // reason = "Exception: " + e.Message; return url; } if (response.IsFault) { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} returned an error: {1}", m_ServerURL, response.FaultString); + m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for LocateUser returned an error: {1}", m_ServerURL, response.FaultString); // reason = "XMLRPC Fault"; return url; } @@ -700,14 +700,14 @@ namespace OpenSim.Services.Connectors.Hypergrid } catch { - m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0}", m_ServerURL); + m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetUUI", m_ServerURL); // reason = "Exception: " + e.Message; return uui; } if (response.IsFault) { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} returned an error: {1}", m_ServerURL, response.FaultString); + m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetUUI returned an error: {1}", m_ServerURL, response.FaultString); // reason = "XMLRPC Fault"; return uui; } @@ -748,14 +748,14 @@ namespace OpenSim.Services.Connectors.Hypergrid } catch (Exception e) { - m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0}", m_ServerURL); + m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetBoolResponse", m_ServerURL); reason = "Exception: " + e.Message; return false; } if (response.IsFault) { - m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} returned an error: {1}", m_ServerURL, response.FaultString); + m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetBoolResponse returned an error: {1}", m_ServerURL, response.FaultString); reason = "XMLRPC Fault"; return false; } From bd5d2cb043892399baff85667ee1e6ec6f3b3d2e Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 8 Sep 2011 20:51:52 +0100 Subject: [PATCH 17/54] Use scene presence agent id for rezzed object ownership rather than item owner. These should be identical. However, the item isn't available when rezzing npc attachments. --- .../InventoryAccess/InventoryAccessModule.cs | 19 +++-- .../World/NPC/Tests/NPCModuleTests.cs | 77 +++++++++++++++++++ .../Common/Helpers/UserInventoryHelpers.cs | 3 +- 3 files changed, 90 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 4e8466d786..03238d94c2 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -724,8 +724,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess SceneObjectGroup group = null; string xmlData = Utils.BytesToString(rezAsset.Data); - List objlist = - new List(); + List objlist = new List(); List veclist = new List(); byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0); Vector3 pos; @@ -797,6 +796,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess m_log.Debug("[InventoryAccessModule]: Object has UUID.Zero! Position 3"); } + foreach (SceneObjectPart part in group.Parts) + { + // Make the rezzer the owner, as this is not necessarily set correctly in the serialized asset. + part.LastOwnerID = part.OwnerID; + part.OwnerID = remoteClient.AgentId; + } + if (!attachment) { // If it's rezzed in world, select it. Much easier to @@ -833,13 +839,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess group.AbsolutePosition = pos + veclist[i]; } - SceneObjectPart rootPart = group.RootPart; - group.SetGroup(remoteClient.ActiveGroupId, remoteClient); if (!attachment) { - if (group.RootPart.Shape.PCode == (byte)PCode.Prim) + SceneObjectPart rootPart = group.RootPart; + + if (rootPart.Shape.PCode == (byte)PCode.Prim) group.ClearPartAttachmentData(); // Fire on_rez @@ -963,11 +969,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if ((part.OwnerID != item.Owner) || (item.CurrentPermissions & 16) != 0) { - part.LastOwnerID = part.OwnerID; - part.OwnerID = item.Owner; part.Inventory.ChangeInventoryOwner(item.Owner); part.GroupMask = 0; // DO NOT propagate here } + part.EveryoneMask = item.EveryOnePermissions; part.NextOwnerMask = item.NextPermissions; } diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs index 78296a4e1f..3bd43b4e52 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs @@ -26,6 +26,7 @@ */ using System; +using System.Collections.Generic; using System.Reflection; using log4net; using Nini.Config; @@ -33,7 +34,9 @@ using NUnit.Framework; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Communications; +using OpenSim.Region.CoreModules.Avatar.Attachments; using OpenSim.Region.CoreModules.Avatar.AvatarFactory; +using OpenSim.Region.CoreModules.Framework.InventoryAccess; using OpenSim.Region.CoreModules.Framework.UserManagement; using OpenSim.Region.CoreModules.ServiceConnectorsOut.Avatar; using OpenSim.Region.Framework.Interfaces; @@ -47,6 +50,13 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests [TestFixture] public class NPCModuleTests { + [SetUp] + public void Init() + { + // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. + Util.FireAndForgetMethod = FireAndForgetMethod.None; + } + [Test] public void TestCreate() { @@ -87,6 +97,73 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests Assert.That(umm.GetUserName(npc.UUID), Is.EqualTo(string.Format("{0} {1}", npc.Firstname, npc.Lastname))); } + [Test] + public void TestAttachments() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + IConfigSource config = new IniConfigSource(); + config.AddConfig("NPC"); + config.Configs["NPC"].Set("Enabled", "true"); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + AvatarFactoryModule afm = new AvatarFactoryModule(); + UserManagementModule umm = new UserManagementModule(); + AttachmentsModule am = new AttachmentsModule(); + + TestScene scene = SceneHelpers.SetupScene(); + SceneHelpers.SetupSceneModules(scene, config, afm, umm, am, new BasicInventoryAccessModule(), new NPCModule()); + + UUID userId = TestHelpers.ParseTail(0x1); + UserAccountHelpers.CreateUserWithInventory(scene, userId); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId); +// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); + + // 8 is the index of the first baked texture in AvatarAppearance +// UUID originalFace8TextureId = TestHelpers.ParseTail(0x10); +// Primitive.TextureEntry originalTe = new Primitive.TextureEntry(UUID.Zero); +// Primitive.TextureEntryFace originalTef = originalTe.CreateFace(8); +// originalTef.TextureID = originalFace8TextureId; + + // We also need to add the texture to the asset service, otherwise the AvatarFactoryModule will tell + // ScenePresence.SendInitialData() to reset our entire appearance. +// scene.AssetService.Store(AssetHelpers.CreateAsset(originalFace8TextureId)); +// +// afm.SetAppearanceFromClient(sp.ControllingClient, originalTe, null); + + UUID attItemId = TestHelpers.ParseTail(0x2); + UUID attAssetId = TestHelpers.ParseTail(0x3); + string attName = "att"; + + UserInventoryHelpers.CreateInventoryItem( + scene, attName, attItemId, attAssetId, sp.UUID, InventoryType.Object); + + am.RezSingleAttachmentFromInventory( + sp.ControllingClient, attItemId, (uint)AttachmentPoint.Chest); + + INPCModule npcModule = scene.RequestModuleInterface(); + UUID npcId = npcModule.CreateNPC("John", "Smith", new Vector3(128, 128, 30), scene, sp.Appearance); + + ScenePresence npc = scene.GetScenePresence(npcId); + + // Check scene presence status + Assert.That(npc.HasAttachments(), Is.True); + List attachments = npc.GetAttachments(); + Assert.That(attachments.Count, Is.EqualTo(1)); + SceneObjectGroup attSo = attachments[0]; + + // Just for now, we won't test the name since this is (wrongly) the asset part name rather than the item + // name. TODO: Do need to fix ultimately since the item may be renamed before being passed on to an NPC. +// Assert.That(attSo.Name, Is.EqualTo(attName)); + 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); + Assert.That(attSo.OwnerID, Is.EqualTo(npc.UUID)); + } + [Test] public void TestMove() { diff --git a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs index 4e60ca9ed8..ceb79059cc 100644 --- a/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/UserInventoryHelpers.cs @@ -88,8 +88,7 @@ namespace OpenSim.Tests.Common if (type == InventoryType.Notecard) asset = AssetHelpers.CreateAsset(scene, userId); else if (type == InventoryType.Object) - asset - = AssetHelpers.CreateAsset(assetId, SceneHelpers.CreateSceneObject(1, userId)); + asset = AssetHelpers.CreateAsset(assetId, SceneHelpers.CreateSceneObject(1, userId)); else throw new Exception(string.Format("Inventory type {0} not supported", type)); From 96a3b68086c44dfe35018cc1eaf20be5cba1b0b1 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 8 Sep 2011 20:59:52 +0100 Subject: [PATCH 18/54] Remember to set and unset the fire and forget method at the top of the attachment and npc tests --- .../Attachments/Tests/AttachmentsModuleTests.cs | 10 +++++++--- .../World/NPC/Tests/NPCModuleTests.cs | 12 ++++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 0fa2e00e2b..35183b395a 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -58,12 +58,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests private AttachmentsModule m_attMod; private ScenePresence m_presence; - [SetUp] - public void Init() + [TestFixtureSetUp] + public void FixtureInit() { // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. Util.FireAndForgetMethod = FireAndForgetMethod.None; + } + [SetUp] + public void Init() + { IConfigSource config = new IniConfigSource(); config.AddConfig("Modules"); config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); @@ -73,7 +77,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests SceneHelpers.SetupSceneModules(scene, config, m_attMod, new BasicInventoryAccessModule()); } - [TearDown] + [TestFixtureTearDown] public void TearDown() { // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs index 3bd43b4e52..018cf88485 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs @@ -50,13 +50,21 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests [TestFixture] public class NPCModuleTests { - [SetUp] - public void Init() + [TestFixtureSetUp] + public void FixtureInit() { // Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread. Util.FireAndForgetMethod = FireAndForgetMethod.None; } + [TestFixtureTearDown] + public void TearDown() + { + // We must set this back afterwards, otherwise later tests will fail since they're expecting multiple + // threads. Possibly, later tests should be rewritten not to worry about such things. + Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; + } + [Test] public void TestCreate() { From 9615292133ce937677d10a3acd5f71f9216e3425 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 8 Sep 2011 21:06:10 +0100 Subject: [PATCH 19/54] Centralize module setup for NPC tests. This is overkill for some tests since they dont' need all the modules, but I think the gain in code readability is worth it --- .../World/NPC/Tests/NPCModuleTests.cs | 64 +++++++------------ 1 file changed, 22 insertions(+), 42 deletions(-) diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs index 018cf88485..10d8bfaafe 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs @@ -50,6 +50,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests [TestFixture] public class NPCModuleTests { + private TestScene scene; + private AvatarFactoryModule afm; + private UserManagementModule umm; + private AttachmentsModule am; + [TestFixtureSetUp] public void FixtureInit() { @@ -65,21 +70,28 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; } + public void Init() + { + IConfigSource config = new IniConfigSource(); + config.AddConfig("NPC"); + config.Configs["NPC"].Set("Enabled", "true"); + config.AddConfig("Modules"); + config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); + + afm = new AvatarFactoryModule(); + umm = new UserManagementModule(); + am = new AttachmentsModule(); + + TestScene scene = SceneHelpers.SetupScene(); + SceneHelpers.SetupSceneModules(scene, config, afm, umm, am, new BasicInventoryAccessModule(), new NPCModule()); + } + [Test] public void TestCreate() { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - IConfigSource config = new IniConfigSource(); - config.AddConfig("NPC"); - config.Configs["NPC"].Set("Enabled", "true"); - - AvatarFactoryModule afm = new AvatarFactoryModule(); - UserManagementModule umm = new UserManagementModule(); - - TestScene scene = SceneHelpers.SetupScene(); - SceneHelpers.SetupSceneModules(scene, config, afm, umm, new NPCModule()); ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); // ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); @@ -111,35 +123,9 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - IConfigSource config = new IniConfigSource(); - config.AddConfig("NPC"); - config.Configs["NPC"].Set("Enabled", "true"); - config.AddConfig("Modules"); - config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule"); - - AvatarFactoryModule afm = new AvatarFactoryModule(); - UserManagementModule umm = new UserManagementModule(); - AttachmentsModule am = new AttachmentsModule(); - - TestScene scene = SceneHelpers.SetupScene(); - SceneHelpers.SetupSceneModules(scene, config, afm, umm, am, new BasicInventoryAccessModule(), new NPCModule()); - UUID userId = TestHelpers.ParseTail(0x1); UserAccountHelpers.CreateUserWithInventory(scene, userId); ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId); -// ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); - - // 8 is the index of the first baked texture in AvatarAppearance -// UUID originalFace8TextureId = TestHelpers.ParseTail(0x10); -// Primitive.TextureEntry originalTe = new Primitive.TextureEntry(UUID.Zero); -// Primitive.TextureEntryFace originalTef = originalTe.CreateFace(8); -// originalTef.TextureID = originalFace8TextureId; - - // We also need to add the texture to the asset service, otherwise the AvatarFactoryModule will tell - // ScenePresence.SendInitialData() to reset our entire appearance. -// scene.AssetService.Store(AssetHelpers.CreateAsset(originalFace8TextureId)); -// -// afm.SetAppearanceFromClient(sp.ControllingClient, originalTe, null); UUID attItemId = TestHelpers.ParseTail(0x2); UUID attAssetId = TestHelpers.ParseTail(0x3); @@ -165,6 +151,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests // Just for now, we won't test the name since this is (wrongly) the asset part name rather than the item // name. TODO: Do need to fix ultimately since the item may be renamed before being passed on to an NPC. // Assert.That(attSo.Name, Is.EqualTo(attName)); + Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest)); Assert.That(attSo.IsAttachment); Assert.That(attSo.UsesPhysics, Is.False); @@ -178,13 +165,6 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - IConfigSource config = new IniConfigSource(); - - config.AddConfig("NPC"); - config.Configs["NPC"].Set("Enabled", "true"); - - TestScene scene = SceneHelpers.SetupScene(); - SceneHelpers.SetupSceneModules(scene, config, new NPCModule()); ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); // ScenePresence originalAvatar = scene.GetScenePresence(originalClient.AgentId); From f5eace678124088e29bd8dd2fc7da6e96f8cf60d Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Thu, 8 Sep 2011 21:54:40 +0100 Subject: [PATCH 20/54] Fix test failure. Oversight in setting up the tests themselves. --- .../Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs index 10d8bfaafe..246bc34219 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs @@ -70,6 +70,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod; } + [SetUp] public void Init() { IConfigSource config = new IniConfigSource(); @@ -82,7 +83,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC.Tests umm = new UserManagementModule(); am = new AttachmentsModule(); - TestScene scene = SceneHelpers.SetupScene(); + scene = SceneHelpers.SetupScene(); SceneHelpers.SetupSceneModules(scene, config, afm, umm, am, new BasicInventoryAccessModule(), new NPCModule()); } From 086bf9f15db05ca2be1cf0dda24f8ee7a368988d Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 9 Sep 2011 00:29:59 +0100 Subject: [PATCH 21/54] Save the default terrain texture UUIDs for a new region instead of leaving them as UUID.Zero. Leaving them at UUID.Zero meant that when a viewer 2 logged into a region that had been freshly created, it received UUID.Zero for these textures, and hence display the land as plain white. On a simulator restart, the problem would go away since when the database adapators loaded the new region settings, RegionSettings itself has code to use default textures instead of UUID.Zero. This commit resolves the problem by saving the default texture UUIDs instead of Zero. However, we currently have to do this in a roundabout way by resaving once the RegionSettings have been created by the database for the first time. This needless complexity should be addressed. This change will also have the effect of replacing any existing UUID.Zero terrain textures with the default ones. However, this shouldn't have any effect since the UUID.Zeros were already being replaced in memory with those same UUIDs. --- .../Handlers/GetTexture/GetTextureHandler.cs | 5 +-- OpenSim/Data/MySQL/MySQLSimulationData.cs | 1 - .../World/Estate/EstateManagementModule.cs | 5 +++ OpenSim/Region/Framework/Scenes/Scene.cs | 37 ++++++++++++++++++- 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs index 105a1e028b..e1b4fe756b 100644 --- a/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs +++ b/OpenSim/Capabilities/Handlers/GetTexture/GetTextureHandler.cs @@ -47,7 +47,6 @@ using Caps = OpenSim.Framework.Capabilities.Caps; namespace OpenSim.Capabilities.Handlers { - public class GetTextureHandler : BaseStreamHandler { private static readonly ILog m_log = @@ -67,7 +66,6 @@ namespace OpenSim.Capabilities.Handlers public override byte[] Handle(string path, Stream request, OSHttpRequest httpRequest, OSHttpResponse httpResponse) { - // Try to parse the texture ID from the request URL NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query); string textureStr = query.GetOne("texture_id"); @@ -85,6 +83,8 @@ namespace OpenSim.Capabilities.Handlers UUID textureID; if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID)) { +// m_log.DebugFormat("[GETTEXTURE]: Received request for texture id {0}", textureID); + string[] formats; if (format != null && format != string.Empty) { @@ -105,7 +105,6 @@ namespace OpenSim.Capabilities.Handlers if (FetchTexture(httpRequest, httpResponse, textureID, f)) break; } - } else { diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs index 96ecea6cb6..6d14b82075 100644 --- a/OpenSim/Data/MySQL/MySQLSimulationData.cs +++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs @@ -1209,7 +1209,6 @@ namespace OpenSim.Data.MySQL return prim; } - /// /// Build a prim inventory item from the persisted data. /// diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index d0605e3bc9..94c141793d 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -968,6 +968,11 @@ namespace OpenSim.Region.CoreModules.World.Estate args.terrainDetail2 = Scene.RegionInfo.RegionSettings.TerrainTexture3; args.terrainDetail3 = Scene.RegionInfo.RegionSettings.TerrainTexture4; + m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 1 {0} for region {1}", args.terrainDetail0, Scene.RegionInfo.RegionName); + m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 2 {0} for region {1}", args.terrainDetail1, Scene.RegionInfo.RegionName); + m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 3 {0} for region {1}", args.terrainDetail2, Scene.RegionInfo.RegionName); + m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 4 {0} for region {1}", args.terrainDetail3, Scene.RegionInfo.RegionName); + remoteClient.SendRegionHandshake(Scene.RegionInfo,args); } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index d3de37d361..f86b3b6a04 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -588,7 +588,42 @@ namespace OpenSim.Region.Framework.Scenes #region Region Settings // Load region settings - m_regInfo.RegionSettings = simDataService.LoadRegionSettings(m_regInfo.RegionID); + // LoadRegionSettings creates new region settings in persistence if they don't already exist for this region. + // However, in this case, the default textures are not set in memory properly, so we need to do it here and + // 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); + bool updatedTerrainTextures = false; + if (rs.TerrainTexture1 == UUID.Zero) + { + rs.TerrainTexture1 = RegionSettings.DEFAULT_TERRAIN_TEXTURE_1; + updatedTerrainTextures = true; + } + + if (rs.TerrainTexture2 == UUID.Zero) + { + rs.TerrainTexture2 = RegionSettings.DEFAULT_TERRAIN_TEXTURE_2; + updatedTerrainTextures = true; + } + + if (rs.TerrainTexture3 == UUID.Zero) + { + rs.TerrainTexture3 = RegionSettings.DEFAULT_TERRAIN_TEXTURE_3; + updatedTerrainTextures = true; + } + + if (rs.TerrainTexture4 == UUID.Zero) + { + rs.TerrainTexture4 = RegionSettings.DEFAULT_TERRAIN_TEXTURE_4; + updatedTerrainTextures = true; + } + + if (updatedTerrainTextures) + rs.Save(); + + m_regInfo.RegionSettings = rs; + if (estateDataService != null) m_regInfo.EstateSettings = estateDataService.LoadEstateSettings(m_regInfo.RegionID, false); From 42790f021fd5d69ba10ac02d158681f3d299da80 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 9 Sep 2011 00:47:23 +0100 Subject: [PATCH 22/54] Fix unit tests from RegionSettings commit --- OpenSim/Data/Null/NullSimulationData.cs | 4 ++++ OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/OpenSim/Data/Null/NullSimulationData.cs b/OpenSim/Data/Null/NullSimulationData.cs index e8d733b582..c33a6f2c43 100644 --- a/OpenSim/Data/Null/NullSimulationData.cs +++ b/OpenSim/Data/Null/NullSimulationData.cs @@ -59,19 +59,23 @@ namespace OpenSim.Data.Null public void StoreRegionSettings(RegionSettings rs) { } + public RegionLightShareData LoadRegionWindlightSettings(UUID regionUUID) { //This connector doesn't support the windlight module yet //Return default LL windlight settings return new RegionLightShareData(); } + public void RemoveRegionWindlightSettings(UUID regionID) { } + public void StoreRegionWindlightSettings(RegionLightShareData wl) { //This connector doesn't support the windlight module yet } + public RegionSettings LoadRegionSettings(UUID regionUUID) { return null; diff --git a/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs b/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs index 2ea36da228..79bb9c2ce3 100644 --- a/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs +++ b/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs @@ -163,6 +163,10 @@ namespace OpenSim.Data.Null { RegionSettings rs = null; m_regionSettings.TryGetValue(regionUUID, out rs); + + if (rs == null) + rs = new RegionSettings(); + return rs; } From 655935db49ad3a363426eef52f4aedba990cc9af Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 9 Sep 2011 01:00:41 +0100 Subject: [PATCH 23/54] Use a copy of the inventory items list to register users in the thread started by GetFolderContent(), to protect ourselves against callers modifying lists Hopefully this addresses http://opensimulator.org/mantis/view.php?id=5681 --- .../Inventory/LocalInventoryServiceConnector.cs | 5 ++++- .../Inventory/RemoteXInventoryServiceConnector.cs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs index d3ef08d4f6..1c83f8eb49 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/LocalInventoryServiceConnector.cs @@ -188,8 +188,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory Util.FireAndForget(delegate { if (UserManager != null) - foreach (InventoryItemBase item in invCol.Items) + { + // Protect ourselves against the caller subsequently modifying the items list + foreach (InventoryItemBase item in new List(invCol.Items)) UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData); + } }); return invCol; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs index eb907749d9..c9c716cec7 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs @@ -196,8 +196,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory Util.FireAndForget(delegate { if (UserManager != null) - foreach (InventoryItemBase item in invCol.Items) + { + // Protect ourselves against the caller subsequently modifying the items list + foreach (InventoryItemBase item in new List(invCol.Items)) UserManager.AddUser(item.CreatorIdAsUuid, item.CreatorData); + } }); return invCol; From bea2e0f32bfd49d4ea92dd59c508327354f9c93f Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 9 Sep 2011 22:50:54 +0100 Subject: [PATCH 24/54] Comment out the part of the load oar code that zeroes out prim sit target orientations and positions. The warning about these causing problems is very old and may no longer apply. Hopes to fix http://opensimulator.org/mantis/view.php?id=5680 --- .../Region/CoreModules/World/Archiver/ArchiveReadRequest.cs | 4 ++-- .../CoreModules/World/Archiver/Tests/ArchiverTests.cs | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index 48130e7991..587d260583 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs @@ -284,8 +284,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver part.LastOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; // And zap any troublesome sit target information - part.SitTargetOrientation = new Quaternion(0, 0, 0, 1); - part.SitTargetPosition = new Vector3(0, 0, 0); +// part.SitTargetOrientation = new Quaternion(0, 0, 0, 1); +// part.SitTargetPosition = new Vector3(0, 0, 0); // Fix ownership/creator of inventory items // Not doing so results in inventory items diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs index b185d9b7e6..e798e5e361 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs @@ -318,6 +318,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary())); SceneObjectPart part1 = CreateSceneObjectPart1(); + + part1.SitTargetOrientation = new Quaternion(0.2f, 0.3f, 0.4f, 0.5f); + part1.SitTargetPosition = new Vector3(1, 2, 3); + SceneObjectGroup object1 = new SceneObjectGroup(part1); // Let's put some inventory items into our object @@ -390,6 +394,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests object1PartLoaded.RotationOffset, Is.EqualTo(part1.RotationOffset), "object1 rotation offset not equal"); Assert.That( object1PartLoaded.OffsetPosition, Is.EqualTo(part1.OffsetPosition), "object1 offset position not equal"); + Assert.That(object1PartLoaded.SitTargetOrientation, Is.EqualTo(part1.SitTargetOrientation)); + Assert.That(object1PartLoaded.SitTargetPosition, Is.EqualTo(part1.SitTargetPosition)); TaskInventoryItem loadedSoundItem = object1PartLoaded.Inventory.GetInventoryItems(soundItemName)[0]; Assert.That(loadedSoundItem, Is.Not.Null, "loaded sound item was null"); From 28961dd1cfc21a90510faa33af6d3c1c6f8bc0af Mon Sep 17 00:00:00 2001 From: Micheil Merlin Date: Sun, 4 Sep 2011 12:21:29 -0500 Subject: [PATCH 25/54] llSetPrimitiveParams Prim type params precision errors --- .../Shared/Api/Implementation/LSL_Api.cs | 76 ++++++++++++++----- .../ScriptEngine/Shared/Tests/LSL_ApiTest.cs | 58 ++++++++------ 2 files changed, 90 insertions(+), 44 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 88e884dabc..cf8517d8b0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -6570,6 +6570,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api protected ObjectShapePacket.ObjectDataBlock SetPrimitiveBlockShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, byte profileshape, byte pathcurve) { + float tempFloat; // Use in float expressions below to avoid byte cast precision issues. ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock(); if (holeshape != (int)ScriptBaseClass.PRIM_HOLE_DEFAULT && @@ -6651,8 +6652,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { twist.y = 1.0f; } - shapeBlock.PathTwistBegin = (sbyte)(100 * twist.x); - shapeBlock.PathTwist = (sbyte)(100 * twist.y); + // A fairly large precision error occurs for some calculations, + // if a float or double is directly cast to a byte or sbyte + // variable, in both .Net and Mono. In .Net, coding + // "(sbyte)(float)(some expression)" corrects the precision + // errors. But this does not work for Mono. This longer coding + // form of creating a tempoary float variable from the + // expression first, then casting that variable to a byte or + // sbyte, works for both .Net and Mono. These types of + // assignments occur in SetPrimtiveBlockShapeParams and + // SetPrimitiveShapeParams in support of llSetPrimitiveParams. + tempFloat = (float)(100.0d * twist.x); + shapeBlock.PathTwistBegin = (sbyte)tempFloat; + tempFloat = (float)(100.0d * twist.y); + shapeBlock.PathTwist = (sbyte)tempFloat; shapeBlock.ObjectLocalID = part.LocalId; @@ -6663,6 +6676,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Prim type box, cylinder and prism. protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector taper_b, LSL_Vector topshear, byte profileshape, byte pathcurve) { + float tempFloat; // Use in float expressions below to avoid byte cast precision issues. ObjectShapePacket.ObjectDataBlock shapeBlock; shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve); @@ -6683,8 +6697,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { taper_b.y = 2f; } - shapeBlock.PathScaleX = (byte)(100 * (2.0 - taper_b.x)); - shapeBlock.PathScaleY = (byte)(100 * (2.0 - taper_b.y)); + tempFloat = (float)(100.0d * (2.0d - taper_b.x)); + shapeBlock.PathScaleX = (byte)tempFloat; + tempFloat = (float)(100.0d * (2.0d - taper_b.y)); + shapeBlock.PathScaleY = (byte)tempFloat; if (topshear.x < -0.5f) { topshear.x = -0.5f; @@ -6701,8 +6717,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { topshear.y = 0.5f; } - shapeBlock.PathShearX = (byte)(100 * topshear.x); - shapeBlock.PathShearY = (byte)(100 * topshear.y); + tempFloat = (float)(100.0d * topshear.x); + shapeBlock.PathShearX = (byte)tempFloat; + tempFloat = (float)(100.0d * topshear.y); + shapeBlock.PathShearY = (byte)tempFloat; part.Shape.SculptEntry = false; part.UpdateShape(shapeBlock); @@ -6752,6 +6770,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // Prim type torus, tube and ring. protected void SetPrimitiveShapeParams(SceneObjectPart part, int holeshape, LSL_Vector cut, float hollow, LSL_Vector twist, LSL_Vector holesize, LSL_Vector topshear, LSL_Vector profilecut, LSL_Vector taper_a, float revolutions, float radiusoffset, float skew, byte profileshape, byte pathcurve) { + float tempFloat; // Use in float expressions below to avoid byte cast precision issues. ObjectShapePacket.ObjectDataBlock shapeBlock; shapeBlock = SetPrimitiveBlockShapeParams(part, holeshape, cut, hollow, twist, profileshape, pathcurve); @@ -6776,8 +6795,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { holesize.y = 0.5f; } - shapeBlock.PathScaleX = (byte)(100 * (2 - holesize.x)); - shapeBlock.PathScaleY = (byte)(100 * (2 - holesize.y)); + tempFloat = (float)(100.0d * (2.0d - holesize.x)); + shapeBlock.PathScaleX = (byte)tempFloat; + tempFloat = (float)(100.0d * (2.0d - holesize.y)); + shapeBlock.PathScaleY = (byte)tempFloat; if (topshear.x < -0.5f) { topshear.x = -0.5f; @@ -6794,8 +6815,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { topshear.y = 0.5f; } - shapeBlock.PathShearX = (byte)(100 * topshear.x); - shapeBlock.PathShearY = (byte)(100 * topshear.y); + tempFloat = (float)(100.0d * topshear.x); + shapeBlock.PathShearX = (byte)tempFloat; + tempFloat = (float)(100.0d * topshear.y); + shapeBlock.PathShearY = (byte)tempFloat; if (profilecut.x < 0f) { profilecut.x = 0f; @@ -6839,8 +6862,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { taper_a.y = 1f; } - shapeBlock.PathTaperX = (sbyte)(100 * taper_a.x); - shapeBlock.PathTaperY = (sbyte)(100 * taper_a.y); + tempFloat = (float)(100.0d * taper_a.x); + shapeBlock.PathTaperX = (sbyte)tempFloat; + tempFloat = (float)(100.0d * taper_a.y); + shapeBlock.PathTaperY = (sbyte)tempFloat; if (revolutions < 1f) { revolutions = 1f; @@ -6849,7 +6874,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { revolutions = 4f; } - shapeBlock.PathRevolutions = (byte)(66.666667 * (revolutions - 1.0)); + tempFloat = 66.66667f * (revolutions - 1.0f); + shapeBlock.PathRevolutions = (byte)tempFloat; // limits on radiusoffset depend on revolutions and hole size (how?) seems like the maximum range is 0 to 1 if (radiusoffset < 0f) { @@ -6859,7 +6885,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { radiusoffset = 1f; } - shapeBlock.PathRadiusOffset = (sbyte)(100 * radiusoffset); + tempFloat = 100.0f * radiusoffset; + shapeBlock.PathRadiusOffset = (sbyte)tempFloat; if (skew < -0.95f) { skew = -0.95f; @@ -6868,7 +6895,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api { skew = 0.95f; } - shapeBlock.PathSkew = (sbyte)(100 * skew); + tempFloat = 100.0f * skew; + shapeBlock.PathSkew = (sbyte)tempFloat; part.Shape.SculptEntry = false; part.UpdateShape(shapeBlock); @@ -7681,10 +7709,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api res.Add(new LSL_Vector(Shape.PathTaperX / 100.0, Shape.PathTaperY / 100.0, 0)); // float revolutions - res.Add(new LSL_Float((Shape.PathRevolutions * 0.015) + 1.0)); // Slightly inaccurate, because an unsigned - // byte is being used to represent the entire - // range of floating-point values from 1.0 - // through 4.0 (which is how SL does it). + res.Add(new LSL_Float(Math.Round(Shape.PathRevolutions * 0.015d, 2, MidpointRounding.AwayFromZero)) + 1.0d); + // Slightly inaccurate, because an unsigned byte is being used to represent + // the entire range of floating-point values from 1.0 through 4.0 (which is how + // SL does it). + // + // Using these formulas to store and retrieve PathRevolutions, it is not + // possible to use all values between 1.00 and 4.00. For instance, you can't + // represent 1.10. You can represent 1.09 and 1.11, but not 1.10. So, if you + // use llSetPrimitiveParams to set revolutions to 1.10 and then retreive them + // with llGetPrimitiveParams, you'll retrieve 1.09. You can also see a similar + // behavior in the viewer as you cannot set 1.10. The viewer jumps to 1.11. + // In SL, llSetPrimitveParams and llGetPrimitiveParams can set and get a value + // such as 1.10. So, SL must store and retreive the actual user input rather + // than only storing the encoded value. // float radiusoffset res.Add(new LSL_Float(Shape.PathRadiusOffset / 100.0)); diff --git a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs index 8cd1e84623..0cbad418bd 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Tests/LSL_ApiTest.cs @@ -49,7 +49,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests private const double ANGLE_ACCURACY_IN_RADIANS = 1E-6; private const double VECTOR_COMPONENT_ACCURACY = 0.0000005d; - private const double FLOAT_ACCURACY = 0.00005d; + private const float FLOAT_ACCURACY = 0.00005f; private LSL_Api m_lslApi; [SetUp] @@ -194,10 +194,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests ScriptBaseClass.PRIM_TYPE_SPHERE, // Prim type ScriptBaseClass.PRIM_HOLE_DEFAULT, // Prim hole type new LSL_Types.Vector3(0.0d, 0.075d, 0.0d), // Prim cut - 0.80d, // Prim hollow + 0.80f, // Prim hollow new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist new LSL_Types.Vector3(0.32d, 0.76d, 0.0d), // Prim dimple - 0.80d); // Prim hollow check + 0.80f); // Prim hollow check // Test a prism. CheckllSetPrimitiveParams( @@ -206,11 +206,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type ScriptBaseClass.PRIM_HOLE_CIRCLE, // Prim hole type new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut - 0.90d, // Prim hollow + 0.90f, // Prim hollow new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist new LSL_Types.Vector3(2.0d, 1.0d, 0.0d), // Prim taper new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear - 0.90d); // Prim hollow check + 0.90f); // Prim hollow check // Test a box. CheckllSetPrimitiveParams( @@ -219,11 +219,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests ScriptBaseClass.PRIM_TYPE_BOX, // Prim type ScriptBaseClass.PRIM_HOLE_TRIANGLE, // Prim hole type new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut - 0.95d, // Prim hollow + 0.95f, // Prim hollow new LSL_Types.Vector3(1.0d, 0.0d, 0.0d), // Prim twist new LSL_Types.Vector3(1.0d, 1.0d, 0.0d), // Prim taper new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear - 0.95d); // Prim hollow check + 0.95f); // Prim hollow check // Test a tube. CheckllSetPrimitiveParams( @@ -232,16 +232,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests ScriptBaseClass.PRIM_TYPE_TUBE, // Prim type ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut - 0.00d, // Prim hollow + 0.00f, // Prim hollow new LSL_Types.Vector3(1.0d, -1.0d, 0.0d), // Prim twist - new LSL_Types.Vector3(1.0d, 0.5d, 0.0d), // Prim hole size - new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear + new LSL_Types.Vector3(1.0d, 0.05d, 0.0d), // Prim hole size + // Expression for y selected to test precision problems during byte + // cast in SetPrimitiveShapeParams. + new LSL_Types.Vector3(0.0d, 0.35d + 0.1d, 0.0d), // Prim shear new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim profile cut - new LSL_Types.Vector3(-1.0d, 1.0d, 0.0d), // Prim taper - 1.0d, // Prim revolutions - 1.0d, // Prim radius - 0.0d, // Prim skew - 0.00d); // Prim hollow check + // Expression for y selected to test precision problems during sbyte + // cast in SetPrimitiveShapeParams. + new LSL_Types.Vector3(-1.0d, 0.70d + 0.1d + 0.1d, 0.0d), // Prim taper + 1.11f, // Prim revolutions + 0.88f, // Prim radius + 0.95f, // Prim skew + 0.00f); // Prim hollow check // Test a prism. CheckllSetPrimitiveParams( @@ -250,11 +254,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests ScriptBaseClass.PRIM_TYPE_PRISM, // Prim type ScriptBaseClass.PRIM_HOLE_SQUARE, // Prim hole type new LSL_Types.Vector3(0.0d, 1.0d, 0.0d), // Prim cut - 0.95d, // Prim hollow - new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim twist - new LSL_Types.Vector3(2.0d, 1.0d, 0.0d), // Prim taper + 0.95f, // Prim hollow + // Expression for x selected to test precision problems during sbyte + // cast in SetPrimitiveShapeBlockParams. + new LSL_Types.Vector3(0.7d + 0.2d, 0.0d, 0.0d), // Prim twist + // Expression for y selected to test precision problems during sbyte + // cast in SetPrimitiveShapeParams. + new LSL_Types.Vector3(2.0d, (1.3d + 0.1d), 0.0d), // Prim taper new LSL_Types.Vector3(0.0d, 0.0d, 0.0d), // Prim shear - 0.70d); // Prim hollow check + 0.70f); // Prim hollow check // Test a sculpted prim. CheckllSetPrimitiveParams( @@ -268,8 +276,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests // Set prim params for a box, cylinder or prism and check results. public void CheckllSetPrimitiveParams(string primTest, LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, - double primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primTaper, LSL_Types.Vector3 primShear, - double primHollowCheck) + float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primTaper, LSL_Types.Vector3 primShear, + float primHollowCheck) { // Set the prim params. m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, @@ -297,7 +305,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests // Set prim params for a sphere and check results. public void CheckllSetPrimitiveParams(string primTest, LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, - double primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primDimple, double primHollowCheck) + float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primDimple, float primHollowCheck) { // Set the prim params. m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, @@ -324,9 +332,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests // Set prim params for a torus, tube or ring and check results. public void CheckllSetPrimitiveParams(string primTest, LSL_Types.Vector3 primSize, int primType, int primHoleType, LSL_Types.Vector3 primCut, - double primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primHoleSize, + float primHollow, LSL_Types.Vector3 primTwist, LSL_Types.Vector3 primHoleSize, LSL_Types.Vector3 primShear, LSL_Types.Vector3 primProfCut, LSL_Types.Vector3 primTaper, - double primRev, double primRadius, double primSkew, double primHollowCheck) + float primRev, float primRadius, float primSkew, float primHollowCheck) { // Set the prim params. m_lslApi.llSetPrimitiveParams(new LSL_Types.list(ScriptBaseClass.PRIM_SIZE, primSize, @@ -353,7 +361,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests CheckllSetPrimitiveParamsVector(primProfCut, m_lslApi.llList2Vector(primParams, 8), primTest + " prim profile cut"); CheckllSetPrimitiveParamsVector(primTaper, m_lslApi.llList2Vector(primParams, 9), primTest + " prim taper"); Assert.AreEqual(primRev, m_lslApi.llList2Float(primParams, 10), FLOAT_ACCURACY, - "TestllSetPrimitiveParams " + primTest + " prim revolution fail"); + "TestllSetPrimitiveParams " + primTest + " prim revolutions fail"); Assert.AreEqual(primRadius, m_lslApi.llList2Float(primParams, 11), FLOAT_ACCURACY, "TestllSetPrimitiveParams " + primTest + " prim radius fail"); Assert.AreEqual(primSkew, m_lslApi.llList2Float(primParams, 12), FLOAT_ACCURACY, From 7cafc2e46eba6e46987ce6b41a8fecd2335222d3 Mon Sep 17 00:00:00 2001 From: Kevin Houlihan Date: Sun, 4 Sep 2011 14:46:52 +0100 Subject: [PATCH 26/54] Added a check to the CreateRegion method of the RemoteAdmin module that the specified user exists. A meaningful exception message is returned if the user is not found. Previously it was returning "Object not set..." --- .../RemoteController/RemoteAdminPlugin.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index 93a6915947..25ae3f1933 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -709,6 +709,14 @@ namespace OpenSim.ApplicationPlugins.RemoteController // ok, client wants us to use an explicit UUID // regardless of what the avatar name provided userID = new UUID((string) requestData["estate_owner_uuid"]); + + // Check that the specified user exists + Scene currentOrFirst = m_application.SceneManager.CurrentOrFirstScene; + IUserAccountService accountService = currentOrFirst.UserAccountService; + UserAccount user = accountService.GetUserAccount(currentOrFirst.RegionInfo.ScopeID, userID); + + if (user == null) + throw new Exception("Specified user was not found."); } else if (requestData.ContainsKey("estate_owner_first") & requestData.ContainsKey("estate_owner_last")) { @@ -720,6 +728,11 @@ namespace OpenSim.ApplicationPlugins.RemoteController IUserAccountService accountService = currentOrFirst.UserAccountService; UserAccount user = accountService.GetUserAccount(currentOrFirst.RegionInfo.ScopeID, ownerFirst, ownerLast); + + // Check that the specified user exists + if (user == null) + throw new Exception("Specified user was not found."); + userID = user.PrincipalID; } else From 1dd904b78e723af8cb4340415a8f41dcd1054541 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Mon, 5 Sep 2011 12:45:02 +0300 Subject: [PATCH 27/54] Delay loading scripts until the scene has finished loading --- OpenSim/Region/Application/OpenSimBase.cs | 2 ++ .../Framework/Interfaces/IScriptModule.cs | 5 ++++ .../Framework/Scenes/Scene.Inventory.cs | 24 +++++++++++++++++-- .../Region/ScriptEngine/XEngine/XEngine.cs | 3 +++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index 00b080c91e..92e8ed1d49 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -411,6 +411,8 @@ namespace OpenSim scene.StartTimer(); + scene.StartScripts(); + return clientServer; } diff --git a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs index d9752e64a5..b27b7da10e 100644 --- a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs @@ -52,5 +52,10 @@ namespace OpenSim.Region.Framework.Interfaces ArrayList GetScriptErrors(UUID itemID); void SaveAllState(); + + /// + /// Starts the processing threads. + /// + void StartProcessing(); } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 4700c3bb1a..9dcd10a3e5 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -57,11 +57,11 @@ namespace OpenSim.Region.Framework.Scenes protected AsyncInventorySender m_asyncInventorySender; /// - /// Start all the scripts in the scene which should be started. + /// Creates all the scripts in the scene which should be started. /// public void CreateScriptInstances() { - m_log.Info("[PRIM INVENTORY]: Starting scripts in scene"); + m_log.Info("[PRIM INVENTORY]: Creating scripts in scene"); EntityBase[] entities = Entities.GetEntities(); foreach (EntityBase group in entities) @@ -74,6 +74,26 @@ namespace OpenSim.Region.Framework.Scenes } } + /// + /// Lets the script engines start processing scripts. + /// + public void StartScripts() + { + m_log.Info("[PRIM INVENTORY]: Starting scripts in scene"); + + IScriptModule[] engines = RequestModuleInterfaces(); + if (engines != null) + { + foreach (IScriptModule engine in engines) + { + if (engine != null) + { + engine.StartProcessing(); + } + } + } + } + public void AddUploadedInventoryItem(UUID agentID, InventoryItemBase item) { IMoneyModule money = RequestModuleInterface(); diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index c44366970e..55f373e0b1 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -339,7 +339,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup), new Object[] { m_SaveTime }); } + } + public void StartProcessing() + { m_ThreadPool.Start(); } From de28c9cd24372203c7375ea8e60bc4a2f295e8c0 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 10 Sep 2011 00:23:52 +0100 Subject: [PATCH 28/54] Stop the UserManagementModule logging every user it adds for now --- .../Framework/UserManagement/UserManagementModule.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index f7003dbb12..bef0d69697 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -363,9 +363,9 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement lock (m_UserCache) m_UserCache[user.Id] = user; - m_log.DebugFormat( - "[USER MANAGEMENT MODULE]: Added user {0} {1} {2} {3}", - user.Id, user.FirstName, user.LastName, user.HomeURL); +// m_log.DebugFormat( +// "[USER MANAGEMENT MODULE]: Added user {0} {1} {2} {3}", +// user.Id, user.FirstName, user.LastName, user.HomeURL); } //public void AddUser(UUID uuid, string userData) From 7531851bec552c07e997a4c8a934a23ddd3c7342 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 10 Sep 2011 00:45:50 +0100 Subject: [PATCH 29/54] reinstate the validation logging on teleport. A 'fail' of validation still doesn't prevent the actual teleport. --- .../Framework/EntityTransfer/EntityTransferModule.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index ac13d5ea5f..a4ef2b6986 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -329,6 +329,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (sp.ParentID != (uint)0) sp.StandUp(); + sp.ValidateAttachments(); + // if (!sp.ValidateAttachments()) // { // sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state"); From 9c32b131fd0b156ada1c7e2d2107d6e1061da5e0 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 10 Sep 2011 00:57:52 +0100 Subject: [PATCH 30/54] Add extra log information when attachments fail validation --- .../EntityTransfer/EntityTransferModule.cs | 16 +++++++++++----- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 10 +++++++++- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index a4ef2b6986..8924c0a510 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -59,7 +59,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer get { return m_MaxTransferDistance; } set { m_MaxTransferDistance = value; } } - protected bool m_Enabled = false; protected Scene m_aScene; @@ -68,7 +67,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer private ExpiringCache> m_bannedRegions = new ExpiringCache>(); - #region ISharedRegionModule public Type ReplaceableInterface @@ -329,7 +327,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (sp.ParentID != (uint)0) sp.StandUp(); - sp.ValidateAttachments(); + 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()) // { @@ -941,7 +942,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// This Closes child agents on neighbouring regions /// Calls an asynchronous method to do so.. so it doesn't lag the sim. /// - protected ScenePresence CrossAgentToNewRegionAsync(ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, GridRegion neighbourRegion, bool isFlying, string version) + protected ScenePresence CrossAgentToNewRegionAsync( + ScenePresence agent, Vector3 pos, uint neighbourx, uint neighboury, GridRegion neighbourRegion, + bool isFlying, string version) { ulong neighbourHandle = Utils.UIntsToLong((uint)(neighbourx * Constants.RegionSize), (uint)(neighboury * Constants.RegionSize)); @@ -951,7 +954,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (neighbourRegion != null) { - agent.ValidateAttachments(); + 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); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index f231a390c8..18ad715a9a 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3501,8 +3501,10 @@ namespace OpenSim.Region.Framework.Scenes /// /// This is currently just being done for information. /// - public void ValidateAttachments() + public bool ValidateAttachments() { + bool validated = true; + lock (m_attachments) { // Validate @@ -3512,15 +3514,21 @@ namespace OpenSim.Region.Framework.Scenes { m_log.WarnFormat( "[SCENE PRESENCE]: Failed to validate an attachment for {0} since it was null. Continuing", Name); + + validated = false; } else if (gobj.IsDeleted) { m_log.WarnFormat( "[SCENE PRESENCE]: Failed to validate attachment {0} {1} for {2} since it had been deleted. Continuing", gobj.Name, gobj.UUID, Name); + + validated = false; } } } + + return validated; } /// From 728fd0b1b8e1c80f6961ec06efb34727645fdc3e Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Sat, 10 Sep 2011 01:09:17 +0100 Subject: [PATCH 31/54] lock attachments when enumerating through them in ScenePresence.CopyTo(). May have some effect on http://opensimulator.org/mantis/view.php?id=5644 --- OpenSim/Framework/ChildAgentDataUpdate.cs | 1 - .../Region/Framework/Scenes/ScenePresence.cs | 40 ++++++++++--------- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs index 53ec166b4e..5a4811e408 100644 --- a/OpenSim/Framework/ChildAgentDataUpdate.cs +++ b/OpenSim/Framework/ChildAgentDataUpdate.cs @@ -441,7 +441,6 @@ namespace OpenSim.Framework args["controllers"] = controls; } - if ((CallbackURI != null) && (!CallbackURI.Equals(""))) args["callback_uri"] = OSD.FromString(CallbackURI); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 18ad715a9a..d65d78dc15 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3141,26 +3141,30 @@ namespace OpenSim.Region.Framework.Scenes catch { } // Attachment objects - if (m_attachments != null && m_attachments.Count > 0) + lock (m_attachments) { - cAgent.AttachmentObjects = new List(); - cAgent.AttachmentObjectStates = new List(); -// IScriptModule se = m_scene.RequestModuleInterface(); - m_InTransitScriptStates.Clear(); - foreach (SceneObjectGroup sog in m_attachments) + if (m_attachments.Count > 0) { - // 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); - m_InTransitScriptStates.Add(state); - // Let's remove the scripts of the original object here - sog.RemoveScriptInstances(true); + cAgent.AttachmentObjects = new List(); + cAgent.AttachmentObjectStates = new List(); + // IScriptModule se = m_scene.RequestModuleInterface(); + m_InTransitScriptStates.Clear(); + + foreach (SceneObjectGroup sog in m_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); + m_InTransitScriptStates.Add(state); + // Let's remove the scripts of the original object here + sog.RemoveScriptInstances(true); + } } } } From 517932722bd73de85366b4752ce0fa65776672d3 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 12 Sep 2011 20:06:09 +0100 Subject: [PATCH 32/54] minor: put tags around some method doc --- OpenSim/Region/Framework/Scenes/UuidGatherer.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index 77b1535563..3acdaf8781 100644 --- a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs +++ b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs @@ -43,11 +43,12 @@ namespace OpenSim.Region.Framework.Scenes /// /// Gather uuids for a given entity. /// - /// + /// /// This does a deep inspection of the entity to retrieve all the assets it uses (whether as textures, as scripts /// contained in inventory, as scripts contained in objects contained in another object's inventory, etc. Assets /// are only retrieved when they are necessary to carry out the inspection (i.e. a serialized object needs to be /// retrieved to work out which assets it references). + /// public class UuidGatherer { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -76,11 +77,11 @@ namespace OpenSim.Region.Framework.Scenes /// /// Gather all the asset uuids associated with the asset referenced by a given uuid /// - /// + /// /// This includes both those directly associated with /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained /// within this object). - /// + /// /// The uuid of the asset for which to gather referenced assets /// The type of the asset for the uuid given /// The assets gathered @@ -123,11 +124,11 @@ namespace OpenSim.Region.Framework.Scenes /// /// Gather all the asset uuids associated with a given object. /// - /// + /// /// This includes both those directly associated with /// it (e.g. face textures) and recursively, those of items within it's inventory (e.g. objects contained /// within this object). - /// + /// /// The scene object for which to gather assets /// The assets gathered public void GatherAssetUuids(SceneObjectGroup sceneObject, IDictionary assetUuids) From 7f318277f141a73207ec64f8521ba410a5743215 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Sun, 11 Sep 2011 20:52:35 +0300 Subject: [PATCH 33/54] When creating an OAR, optionally exclude objects according to their permissions --- CONTRIBUTORS.txt | 1 + OpenSim/Region/Application/OpenSim.cs | 10 +- .../ArchiveWriteRequestPreparation.cs | 106 +++++++++++++++++- .../World/Archiver/ArchiverModule.cs | 1 + .../World/Permissions/PermissionsModule.cs | 89 +++++++++------ .../Interfaces/IPermissionsModule.cs | 54 +++++++++ 6 files changed, 217 insertions(+), 44 deletions(-) create mode 100644 OpenSim/Region/Framework/Interfaces/IPermissionsModule.cs diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index 2fe8b465d8..239b884363 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -117,6 +117,7 @@ what it is today. * nornalbion * Omar Vera Ustariz (IBM) * openlifegrid.com +* Oren Hurvitz (Kitely) * otakup0pe * ralphos * RemedyTomm diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index fe1525b28f..e5b9dcb4b3 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -269,13 +269,15 @@ namespace OpenSim m_console.Commands.AddCommand("region", false, "save oar", //"save oar [-v|--version=] [-p|--profile=] []", - "save oar [-p|--profile=] [--noassets] []", + "save oar [-p|--profile=] [--noassets] [--perm=] []", "Save a region's data to an OAR archive.", // "-v|--version= generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine "-p|--profile= adds the url of the profile service to the saved user information." + Environment.NewLine - + " The OAR path must be a filesystem path." - + " If this is not given then the oar is saved to region.oar in the current directory." + Environment.NewLine - + "--noassets stops assets being saved to the OAR.", + + "--noassets stops assets being saved to the OAR." + Environment.NewLine + + "--perm stops objects with insufficient permissions from being saved to the OAR." + Environment.NewLine + + " can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer" + Environment.NewLine + + "The OAR path must be a filesystem path." + + " If this is not given then the oar is saved to region.oar in the current directory.", SaveOar); m_console.Commands.AddCommand("region", false, "edit scale", diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs index 10a83ee826..b895afe85d 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs @@ -127,6 +127,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver EntityBase[] entities = m_scene.GetEntities(); List sceneObjects = new List(); + + string checkPermissions = null; + int numObjectsSkippedPermissions = 0; + Object temp; + if (options.TryGetValue("checkPermissions", out temp)) + checkPermissions = (string)temp; // Filter entities so that we only have scene objects. // FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods @@ -136,9 +142,19 @@ namespace OpenSim.Region.CoreModules.World.Archiver if (entity is SceneObjectGroup) { SceneObjectGroup sceneObject = (SceneObjectGroup)entity; - + if (!sceneObject.IsDeleted && !sceneObject.IsAttachment) - sceneObjects.Add((SceneObjectGroup)entity); + { + if (!CanUserArchiveObject(m_scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, checkPermissions)) + { + // The user isn't allowed to copy/transfer this object, so it will not be included in the OAR. + ++numObjectsSkippedPermissions; + } + else + { + sceneObjects.Add(sceneObject); + } + } } } @@ -159,7 +175,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver { m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified"); } - + + if (numObjectsSkippedPermissions > 0) + { + m_log.DebugFormat( + "[ARCHIVER]: {0} scene objects skipped due to lack of permissions", + numObjectsSkippedPermissions); + } + // Make sure that we also request terrain texture assets RegionSettings regionSettings = m_scene.RegionInfo.RegionSettings; @@ -210,6 +233,83 @@ namespace OpenSim.Region.CoreModules.World.Archiver } } + /// + /// Checks whether the user has permission to export an object group to an OAR. + /// + /// The user + /// The object group + /// Which permissions to check: "C" = Copy, "T" = Transfer + /// Whether the user is allowed to export the object to an OAR + private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string checkPermissions) + { + if (checkPermissions == null) + return true; + + IPermissionsModule module = m_scene.RequestModuleInterface(); + if (module == null) + return true; // this shouldn't happen + + // Check whether the user is permitted to export all of the parts in the SOG. If any + // part can't be exported then the entire SOG can't be exported. + + bool permitted = true; + //int primNumber = 1; + + foreach (SceneObjectPart obj in objGroup.Parts) + { + uint perm; + PermissionClass permissionClass = module.GetPermissionClass(user, obj); + switch (permissionClass) + { + case PermissionClass.Owner: + perm = obj.BaseMask; + break; + case PermissionClass.Group: + perm = obj.GroupMask | obj.EveryoneMask; + break; + case PermissionClass.Everyone: + default: + perm = obj.EveryoneMask; + break; + } + + bool canCopy = (perm & (uint)PermissionMask.Copy) != 0; + bool canTransfer = (perm & (uint)PermissionMask.Transfer) != 0; + + // Special case: if Everyone can copy the object then this implies it can also be + // Transferred. + // However, if the user is the Owner then we don't check EveryoneMask, because it seems that the mask + // always (incorrectly) includes the Copy bit set in this case. But that's a mistake: the viewer + // does NOT show that the object has Everyone-Copy permissions, and doesn't allow it to be copied. + if (permissionClass != PermissionClass.Owner) + { + canTransfer |= (obj.EveryoneMask & (uint)PermissionMask.Copy) != 0; + } + + + bool partPermitted = true; + if (checkPermissions.Contains("C") && !canCopy) + partPermitted = false; + if (checkPermissions.Contains("T") && !canTransfer) + partPermitted = false; + + //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}", + // name, obj.BaseMask, obj.OwnerMask, obj.EveryoneMask, + // permissionClass, checkPermissions, canCopy, canTransfer, permitted); + + if (!partPermitted) + { + permitted = false; + break; + } + + //++primNumber; + } + + return permitted; + } + /// /// Create the control file for the most up to date archive /// diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs index 08eb80cc2e..f44a3bac05 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs @@ -128,6 +128,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver // ops.Add("v|version=", delegate(string v) { options["version"] = v; }); ops.Add("p|profile=", delegate(string v) { options["profile"] = v; }); ops.Add("noassets", delegate(string v) { options["noassets"] = v != null; }); + ops.Add("perm=", delegate(string v) { options["checkPermissions"] = v; }); List mainParams = ops.Parse(cmdparams); diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index b9bd9a4ca9..3b661ed71c 100644 --- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs @@ -39,7 +39,7 @@ using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.World.Permissions { - public class PermissionsModule : IRegionModule + public class PermissionsModule : IRegionModule, IPermissionsModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -150,6 +150,8 @@ namespace OpenSim.Region.CoreModules.World.Permissions else m_log.Debug("[PERMISSIONS]: Enabling all region service permission checks"); + scene.RegisterModuleInterface(this); + //Register functions with Scene External Checks! m_scene.Permissions.OnBypassPermissions += BypassPermissions; m_scene.Permissions.OnSetBypassPermissions += SetBypassPermissions; @@ -574,46 +576,18 @@ namespace OpenSim.Region.CoreModules.World.Permissions if (objectOwner != UUID.Zero) objectEveryoneMask |= (uint)PrimFlags.ObjectAnyOwner; - if (m_bypassPermissions) - return objectOwnerMask; + PermissionClass permissionClass = GetPermissionClass(user, task); - // Object owners should be able to edit their own content - if (user == objectOwner) - return objectOwnerMask; - - if (IsFriendWithPerms(user, objectOwner)) + switch (permissionClass) { - return objectOwnerMask; - } - // Estate users should be able to edit anything in the sim if RegionOwnerIsGod is set - if (m_RegionOwnerIsGod && IsEstateManager(user) && !IsAdministrator(objectOwner)) - { - return objectOwnerMask; - } - - // Admin should be able to edit anything in the sim (including admin objects) - if (IsAdministrator(user)) - { - return objectOwnerMask; - } - - // Users should be able to edit what is over their land. - Vector3 taskPos = task.AbsolutePosition; - ILandObject parcel = m_scene.LandChannel.GetLandObject(taskPos.X, taskPos.Y); - if (parcel != null && parcel.LandData.OwnerID == user && m_ParcelOwnerIsGod) - { - // Admin objects should not be editable by the above - if (!IsAdministrator(objectOwner)) - { + case PermissionClass.Owner: return objectOwnerMask; - } + case PermissionClass.Group: + return objectGroupMask | objectEveryoneMask; + case PermissionClass.Everyone: + default: + return objectEveryoneMask; } - - // Group permissions - if ((task.GroupID != UUID.Zero) && IsGroupMember(task.GroupID, user, 0)) - return objectGroupMask | objectEveryoneMask; - - return objectEveryoneMask; } private uint ApplyObjectModifyMasks(uint setPermissionMask, uint objectFlagsMask) @@ -644,6 +618,47 @@ namespace OpenSim.Region.CoreModules.World.Permissions return objectFlagsMask; } + public PermissionClass GetPermissionClass(UUID user, SceneObjectPart obj) + { + if (obj == null) + return PermissionClass.Everyone; + + if (m_bypassPermissions) + return PermissionClass.Owner; + + // Object owners should be able to edit their own content + UUID objectOwner = obj.OwnerID; + if (user == objectOwner) + return PermissionClass.Owner; + + if (IsFriendWithPerms(user, objectOwner)) + return PermissionClass.Owner; + + // Estate users should be able to edit anything in the sim if RegionOwnerIsGod is set + if (m_RegionOwnerIsGod && IsEstateManager(user) && !IsAdministrator(objectOwner)) + return PermissionClass.Owner; + + // Admin should be able to edit anything in the sim (including admin objects) + if (IsAdministrator(user)) + return PermissionClass.Owner; + + // Users should be able to edit what is over their land. + Vector3 taskPos = obj.AbsolutePosition; + ILandObject parcel = m_scene.LandChannel.GetLandObject(taskPos.X, taskPos.Y); + if (parcel != null && parcel.LandData.OwnerID == user && m_ParcelOwnerIsGod) + { + // Admin objects should not be editable by the above + if (!IsAdministrator(objectOwner)) + return PermissionClass.Owner; + } + + // Group permissions + if ((obj.GroupID != UUID.Zero) && IsGroupMember(obj.GroupID, user, 0)) + return PermissionClass.Group; + + return PermissionClass.Everyone; + } + /// /// General permissions checks for any operation involving an object. These supplement more specific checks /// implemented by callers. diff --git a/OpenSim/Region/Framework/Interfaces/IPermissionsModule.cs b/OpenSim/Region/Framework/Interfaces/IPermissionsModule.cs new file mode 100644 index 0000000000..1ed978bb44 --- /dev/null +++ b/OpenSim/Region/Framework/Interfaces/IPermissionsModule.cs @@ -0,0 +1,54 @@ +/* + * 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; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.Framework.Interfaces +{ + /// + /// Which set of permissions a user has. + /// + public enum PermissionClass + { + Owner, + Group, + Everyone + }; + + public interface IPermissionsModule + { + + /// + /// Returns the type of permissions that the user has over an object. + /// + /// The user + /// The object + /// The type of permissions the user has over the object + PermissionClass GetPermissionClass(UUID user, SceneObjectPart obj); + } +} From 44a491f36bbe2094634e356591381c90f87e2125 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 12 Sep 2011 20:31:14 +0100 Subject: [PATCH 34/54] uncomment Standalone config in OpenSim.ini.example. This is to make my life easier when creating releases. I think that it also gives a better story for anybody newly compiling from source. --- bin/OpenSim.ini.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index c36d2a4ea6..342bce6b59 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -740,7 +740,7 @@ ;; "config-include/StandaloneCommon.ini.example" to "config-include/StandaloneCommon.ini" before ;; editing it to set the database and backend services that OpenSim will use. ;; - ; Include-Architecture = "config-include/Standalone.ini" + Include-Architecture = "config-include/Standalone.ini" ; Include-Architecture = "config-include/StandaloneHypergrid.ini" ; Include-Architecture = "config-include/Grid.ini" ; Include-Architecture = "config-include/GridHypergrid.ini" From dab6387bba7a7388e3cdb4ad1eeea646bc03a287 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 12 Sep 2011 21:05:26 +0100 Subject: [PATCH 35/54] lock AvatarAppearance.m_attachments when we use it This is partly to address http://opensimulator.org/mantis/view.php?id=5644, though something more thorough is needed. --- OpenSim/Framework/AvatarAppearance.cs | 91 +++++++++++++++++---------- 1 file changed, 58 insertions(+), 33 deletions(-) diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index cce44b02b8..c69dde35c7 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs @@ -391,10 +391,14 @@ namespace OpenSim.Framework public List GetAttachments() { List alist = new List(); - foreach (KeyValuePair> kvp in m_attachments) + + lock (m_attachments) { - foreach (AvatarAttachment attach in kvp.Value) - alist.Add(new AvatarAttachment(attach)); + foreach (KeyValuePair> kvp in m_attachments) + { + foreach (AvatarAttachment attach in kvp.Value) + alist.Add(new AvatarAttachment(attach)); + } } return alist; @@ -406,10 +410,13 @@ namespace OpenSim.Framework // "[AVATAR APPEARNCE]: Appending itemID={0}, assetID={1} at {2}", // attach.ItemID, attach.AssetID, attach.AttachPoint); - if (!m_attachments.ContainsKey(attach.AttachPoint)) - m_attachments[attach.AttachPoint] = new List(); - - m_attachments[attach.AttachPoint].Add(attach); + lock (m_attachments) + { + if (!m_attachments.ContainsKey(attach.AttachPoint)) + m_attachments[attach.AttachPoint] = new List(); + + m_attachments[attach.AttachPoint].Add(attach); + } } internal void ReplaceAttachment(AvatarAttachment attach) @@ -418,8 +425,11 @@ namespace OpenSim.Framework // "[AVATAR APPEARANCE]: Replacing itemID={0}, assetID={1} at {2}", // attach.ItemID, attach.AssetID, attach.AttachPoint); - m_attachments[attach.AttachPoint] = new List(); - m_attachments[attach.AttachPoint].Add(attach); + lock (m_attachments) + { + m_attachments[attach.AttachPoint] = new List(); + m_attachments[attach.AttachPoint].Add(attach); + } } /// @@ -448,10 +458,13 @@ namespace OpenSim.Framework if (item == UUID.Zero) { - if (m_attachments.ContainsKey(attachpoint)) + lock (m_attachments) { - m_attachments.Remove(attachpoint); - return true; + if (m_attachments.ContainsKey(attachpoint)) + { + m_attachments.Remove(attachpoint); + return true; + } } return false; @@ -494,11 +507,14 @@ namespace OpenSim.Framework /// Returns null if this item is not attached. public AvatarAttachment GetAttachmentForItem(UUID itemID) { - foreach (KeyValuePair> kvp in m_attachments) + lock (m_attachments) { - int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; }); - if (index >= 0) - return kvp.Value[index]; + foreach (KeyValuePair> kvp in m_attachments) + { + int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; }); + if (index >= 0) + return kvp.Value[index]; + } } return null; @@ -506,11 +522,14 @@ namespace OpenSim.Framework public int GetAttachpoint(UUID itemID) { - foreach (KeyValuePair> kvp in m_attachments) + lock (m_attachments) { - int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; }); - if (index >= 0) - return kvp.Key; + foreach (KeyValuePair> kvp in m_attachments) + { + int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; }); + if (index >= 0) + return kvp.Key; + } } return 0; @@ -518,27 +537,32 @@ namespace OpenSim.Framework public bool DetachAttachment(UUID itemID) { - foreach (KeyValuePair> kvp in m_attachments) + lock (m_attachments) { - int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; }); - if (index >= 0) + foreach (KeyValuePair> kvp in m_attachments) { - // Remove it from the list of attachments at that attach point - m_attachments[kvp.Key].RemoveAt(index); - - // And remove the list if there are no more attachments here - if (m_attachments[kvp.Key].Count == 0) - m_attachments.Remove(kvp.Key); - - return true; + int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; }); + if (index >= 0) + { + // Remove it from the list of attachments at that attach point + m_attachments[kvp.Key].RemoveAt(index); + + // And remove the list if there are no more attachments here + if (m_attachments[kvp.Key].Count == 0) + m_attachments.Remove(kvp.Key); + + return true; + } } } + return false; } public void ClearAttachments() { - m_attachments.Clear(); + lock (m_attachments) + m_attachments.Clear(); } #region Packing Functions @@ -576,7 +600,8 @@ namespace OpenSim.Framework data["visualparams"] = visualparams; // Attachments - OSDArray attachs = new OSDArray(m_attachments.Count); + List attachments = GetAttachments(); + OSDArray attachs = new OSDArray(attachments.Count); foreach (AvatarAttachment attach in GetAttachments()) attachs.Add(attach.Pack()); data["attachments"] = attachs; From ea0f78c97152d3aa54822487e5343ca2db0b47b9 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 12 Sep 2011 21:57:22 +0100 Subject: [PATCH 36/54] Start locking entire add/remove operations on an IScenePresence.AttachmentsSyncLock object Attach and detach packets are processed asynchronously when received from a viewer. Bugs like http://opensimulator.org/mantis/view.php?id=5644 indicate that in some situations (such as attaching/detaching entire folders of objects at once), there are race conditions between these threads. Since multiple data structures need to be updated on attach/detach, it's not enough to lock the individual collections. Therefore, this commit introduces a new IScenePresence.AttachmentsSyncLock which add/remove operations lock on. --- .../Avatar/Attachments/AttachmentsModule.cs | 376 ++++++++++-------- .../Interfaces/IAttachmentsModule.cs | 9 + .../Framework/Interfaces/IScenePresence.cs | 8 + .../Region/Framework/Scenes/ScenePresence.cs | 4 + 4 files changed, 225 insertions(+), 172 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 996e2ab159..2fa233b74a 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -240,80 +240,83 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments private bool AttachObject(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent) { -// 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 (sp.GetAttachments(attachmentPt).Contains(group)) + lock (sp.AttachmentsSyncLock) { -// m_log.WarnFormat( -// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", -// group.Name, group.LocalId, sp.Name, AttachmentPt); - - return false; - } - - Vector3 attachPos = group.AbsolutePosition; - - // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should - // be removed when that functionality is implemented in opensim - attachmentPt &= 0x7f; - - // If the attachment point isn't the same as the one previously used - // set it's offset position = 0 so that it appears on the attachment point - // and not in a weird location somewhere unknown. - if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint) - { - attachPos = Vector3.Zero; - } - - // AttachmentPt 0 means the client chose to 'wear' the attachment. - if (attachmentPt == 0) - { - // Check object for stored attachment point - attachmentPt = group.AttachmentPoint; - } - - // if we still didn't find a suitable attachment point....... - if (attachmentPt == 0) - { - // Stick it on left hand with Zero Offset from the attachment point. - attachmentPt = (uint)AttachmentPoint.LeftHand; - attachPos = Vector3.Zero; - } - - 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) + // 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 (sp.GetAttachments(attachmentPt).Contains(group)) { - UUID oldAttachmentItemID = attachments[0].GetFromItemID(); + // m_log.WarnFormat( + // "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since it's already attached", + // group.Name, group.LocalId, sp.Name, AttachmentPt); - if (oldAttachmentItemID != UUID.Zero) - DetachSingleAttachmentToInv(oldAttachmentItemID, sp); - 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); + return false; } - - // Add the new attachment to inventory if we don't already have it. - UUID newAttachmentItemID = group.GetFromItemID(); - if (newAttachmentItemID == UUID.Zero) - newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp.ControllingClient, group).ID; - ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group); + Vector3 attachPos = group.AbsolutePosition; + + // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should + // be removed when that functionality is implemented in opensim + attachmentPt &= 0x7f; + + // If the attachment point isn't the same as the one previously used + // set it's offset position = 0 so that it appears on the attachment point + // and not in a weird location somewhere unknown. + if (attachmentPt != 0 && attachmentPt != group.AttachmentPoint) + { + attachPos = Vector3.Zero; + } + + // AttachmentPt 0 means the client chose to 'wear' the attachment. + if (attachmentPt == 0) + { + // Check object for stored attachment point + attachmentPt = group.AttachmentPoint; + } + + // if we still didn't find a suitable attachment point....... + if (attachmentPt == 0) + { + // Stick it on left hand with Zero Offset from the attachment point. + attachmentPt = (uint)AttachmentPoint.LeftHand; + attachPos = Vector3.Zero; + } + + 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].GetFromItemID(); + + if (oldAttachmentItemID != UUID.Zero) + DetachSingleAttachmentToInv(oldAttachmentItemID, sp); + 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.GetFromItemID(); + if (newAttachmentItemID == UUID.Zero) + newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp.ControllingClient, group).ID; + + ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group); + } + + AttachToAgent(sp, group, attachmentPt, attachPos, silent); } - AttachToAgent(sp, group, attachmentPt, attachPos, silent); - return true; } @@ -322,14 +325,26 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments RezMultipleAttachmentsFromInvPacket.HeaderDataBlock header, RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[] objects) { - foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in objects) + ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); + + if (sp == null) { - RezSingleAttachmentFromInventory(remoteClient, obj.ItemID, obj.AttachmentPt); + m_log.ErrorFormat( + "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezMultipleAttachmentsFromInventory()", + remoteClient.Name, remoteClient.AgentId); + return; + } + + lock (sp.AttachmentsSyncLock) + { + foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in objects) + { + RezSingleAttachmentFromInventory(sp, obj.ItemID, obj.AttachmentPt); + } } } - public ISceneEntity RezSingleAttachmentFromInventory( - IClientAPI remoteClient, UUID itemID, uint AttachmentPt) + public ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) { // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", @@ -344,7 +359,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments remoteClient.Name, remoteClient.AgentId); return null; } - + + return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt); + } + + public ISceneEntity RezSingleAttachmentFromInventory(ScenePresence sp, UUID itemID, uint AttachmentPt) + { // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should // be removed when that functionality is implemented in opensim AttachmentPt &= 0x7f; @@ -363,65 +383,68 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments IInventoryAccessModule invAccess = m_scene.RequestModuleInterface(); if (invAccess != 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); - - if (objatt != null) + lock (sp.AttachmentsSyncLock) { - // 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); - } - 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; - } + 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); - if (tainted) - objatt.HasGroupChanged = true; + 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); + } + 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; + + // 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); - // 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); + } } - else - { - m_log.WarnFormat( - "[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}", - itemID, sp.Name, attachmentPt); - } - - return objatt; } return null; @@ -474,14 +497,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments ScenePresence presence; if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) { - // Save avatar attachment information - m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + remoteClient.AgentId + ", ItemID: " + itemID); + lock (presence.AttachmentsSyncLock) + { + // Save avatar attachment information + m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + remoteClient.AgentId + ", ItemID: " + itemID); - bool changed = presence.Appearance.DetachAttachment(itemID); - if (changed && m_scene.AvatarFactory != null) - m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); - - DetachSingleAttachmentToInv(itemID, presence); + bool changed = presence.Appearance.DetachAttachment(itemID); + if (changed && m_scene.AvatarFactory != null) + m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); + + DetachSingleAttachmentToInv(itemID, presence); + } } } @@ -508,24 +534,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments ScenePresence presence; if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) { - if (!m_scene.Permissions.CanRezObject( - so.PrimCount, remoteClient.AgentId, presence.AbsolutePosition)) - return; + lock (presence.AttachmentsSyncLock) + { + if (!m_scene.Permissions.CanRezObject( + so.PrimCount, remoteClient.AgentId, presence.AbsolutePosition)) + return; - bool changed = presence.Appearance.DetachAttachment(inventoryID); - if (changed && m_scene.AvatarFactory != null) - m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); + bool changed = presence.Appearance.DetachAttachment(inventoryID); + if (changed && m_scene.AvatarFactory != null) + m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); - presence.RemoveAttachment(so); - DetachSceneObjectToGround(so, presence); + presence.RemoveAttachment(so); + DetachSceneObjectToGround(so, presence); - List uuids = new List(); - uuids.Add(inventoryID); - m_scene.InventoryService.DeleteItems(remoteClient.AgentId, uuids); - remoteClient.SendRemoveInventoryItem(inventoryID); + List uuids = new List(); + uuids.Add(inventoryID); + m_scene.InventoryService.DeleteItems(remoteClient.AgentId, uuids); + remoteClient.SendRemoveInventoryItem(inventoryID); + } + + m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); } - - m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero); } /// @@ -567,37 +596,40 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments EntityBase[] detachEntities = m_scene.GetEntities(); SceneObjectGroup group; - foreach (EntityBase entity in detachEntities) + lock (sp.AttachmentsSyncLock) { - if (entity is SceneObjectGroup) + foreach (EntityBase entity in detachEntities) { - group = (SceneObjectGroup)entity; - if (group.GetFromItemID() == itemID) + if (entity is SceneObjectGroup) { - m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); - sp.RemoveAttachment(group); + group = (SceneObjectGroup)entity; + if (group.GetFromItemID() == itemID) + { + m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); + sp.RemoveAttachment(group); - // Prepare sog for storage - group.AttachedAvatar = UUID.Zero; + // Prepare sog for storage + group.AttachedAvatar = UUID.Zero; - group.ForEachPart( - delegate(SceneObjectPart part) - { - // If there are any scripts, - // then always trigger a new object and state persistence in UpdateKnownItem() - if (part.Inventory.ContainsScripts()) - group.HasGroupChanged = true; - } - ); + group.ForEachPart( + delegate(SceneObjectPart part) + { + // If there are any scripts, + // then always trigger a new object and state persistence in UpdateKnownItem() + if (part.Inventory.ContainsScripts()) + group.HasGroupChanged = true; + } + ); - group.RootPart.SetParentLocalId(0); - group.IsAttachment = false; - group.AbsolutePosition = group.RootPart.AttachedPos; + group.RootPart.SetParentLocalId(0); + group.IsAttachment = false; + group.AbsolutePosition = group.RootPart.AttachedPos; - UpdateKnownItem(sp.ControllingClient, group, group.GetFromItemID(), group.OwnerID); - m_scene.DeleteSceneObject(group, false); + UpdateKnownItem(sp.ControllingClient, group, group.GetFromItemID(), group.OwnerID); + m_scene.DeleteSceneObject(group, false); - return; + return; + } } } } @@ -829,4 +861,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return item; } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index 73d15a5f50..e6ac6b5e9a 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -87,6 +87,15 @@ namespace OpenSim.Region.Framework.Interfaces /// The scene object that was attached. Null if the scene object could not be found ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt); + /// + /// Rez an attachment from user inventory and change inventory status to match. + /// + /// + /// + /// + /// The scene object that was attached. Null if the scene object could not be found + ISceneEntity RezSingleAttachmentFromInventory(ScenePresence sp, UUID itemID, uint AttachmentPt); + /// /// Rez multiple attachments from a user's inventory /// diff --git a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs index 8913133404..95688ab0ca 100644 --- a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs +++ b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs @@ -60,6 +60,14 @@ namespace OpenSim.Region.Framework.Interfaces /// AvatarAppearance Appearance { get; set; } + /// + /// The AttachmentsModule synchronizes on this to avoid race conditions between commands to add and remove attachments. + /// + /// + /// All add and remove attachment operations must synchronize on this for the lifetime of their operations. + /// + Object AttachmentsSyncLock { get; } + /// /// The scene objects attached to this avatar. /// diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index d65d78dc15..86e1e119f3 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -120,6 +120,8 @@ namespace OpenSim.Region.Framework.Scenes /// protected List m_attachments = new List(); + public Object AttachmentsSyncLock { get; private set; } + private Dictionary scriptedcontrols = new Dictionary(); private ScriptControlled IgnoredControls = ScriptControlled.CONTROL_ZERO; private ScriptControlled LastCommands = ScriptControlled.CONTROL_ZERO; @@ -709,6 +711,8 @@ namespace OpenSim.Region.Framework.Scenes public ScenePresence( IClientAPI client, Scene world, RegionInfo reginfo, AvatarAppearance appearance, PresenceType type) { + AttachmentsSyncLock = new Object(); + m_sendCourseLocationsMethod = SendCoarseLocationsDefault; m_sceneViewer = new SceneViewer(this); m_animator = new ScenePresenceAnimator(this); From 294120c9d36f5c6452d5b839ef2543ed4be7af95 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 12 Sep 2011 22:26:04 +0100 Subject: [PATCH 37/54] comment out some recent terrain texture logging --- .../CoreModules/World/Estate/EstateManagementModule.cs | 8 ++++---- OpenSim/Region/Framework/Interfaces/IScenePresence.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index 94c141793d..c199a77264 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -968,10 +968,10 @@ namespace OpenSim.Region.CoreModules.World.Estate args.terrainDetail2 = Scene.RegionInfo.RegionSettings.TerrainTexture3; args.terrainDetail3 = Scene.RegionInfo.RegionSettings.TerrainTexture4; - m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 1 {0} for region {1}", args.terrainDetail0, Scene.RegionInfo.RegionName); - m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 2 {0} for region {1}", args.terrainDetail1, Scene.RegionInfo.RegionName); - m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 3 {0} for region {1}", args.terrainDetail2, Scene.RegionInfo.RegionName); - m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 4 {0} for region {1}", args.terrainDetail3, Scene.RegionInfo.RegionName); +// m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 1 {0} for region {1}", args.terrainDetail0, Scene.RegionInfo.RegionName); +// m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 2 {0} for region {1}", args.terrainDetail1, Scene.RegionInfo.RegionName); +// m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 3 {0} for region {1}", args.terrainDetail2, Scene.RegionInfo.RegionName); +// m_log.DebugFormat("[ESTATE MANAGEMENT MODULE]: Sending terrain texture 4 {0} for region {1}", args.terrainDetail3, Scene.RegionInfo.RegionName); remoteClient.SendRegionHandshake(Scene.RegionInfo,args); } diff --git a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs index 95688ab0ca..ff39283b25 100644 --- a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs +++ b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs @@ -67,7 +67,7 @@ namespace OpenSim.Region.Framework.Interfaces /// All add and remove attachment operations must synchronize on this for the lifetime of their operations. /// Object AttachmentsSyncLock { get; } - + /// /// The scene objects attached to this avatar. /// From 00f8946bd420a796128e58f025f7f380887306ab Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 12 Sep 2011 22:44:14 +0100 Subject: [PATCH 38/54] minor: if the script engine fails to find a prim for a script, also print out that prim's local id in the error message. --- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 4 ++++ OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 6f963ac6bc..89e6ddb521 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -418,6 +418,10 @@ namespace OpenSim.Region.Framework.Scenes lock (SceneObjectGroupsByLocalPartID) { +// m_log.DebugFormat( +// "[SCENE GRAPH]: Adding scene object {0} {1} {2} to SceneObjectGroupsByLocalPartID in {3}", +// sceneObject.Name, sceneObject.UUID, sceneObject.LocalId, m_parentScene.RegionInfo.RegionName); + SceneObjectGroupsByLocalPartID[sceneObject.LocalId] = sceneObject; foreach (SceneObjectPart part in children) SceneObjectGroupsByLocalPartID[part.LocalId] = sceneObject; diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 55f373e0b1..156fd579dc 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -594,7 +594,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine SceneObjectPart part = m_Scene.GetSceneObjectPart(localID); if (part == null) { - m_log.Error("[Script] SceneObjectPart unavailable. Script NOT started."); + m_log.ErrorFormat("[Script]: SceneObjectPart with localID {0} unavailable. Script NOT started.", localID); m_ScriptErrorMessage += "SceneObjectPart unavailable. Script NOT started.\n"; m_ScriptFailCount++; return false; From 56cd7d96851203efa3e84b4c8be70177e2d2d453 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 12 Sep 2011 22:51:56 +0100 Subject: [PATCH 39/54] stop the redundant passing in of RegionInfo to SceneGraph, since the Scene is always passed in at the same time. --- OpenSim/Region/Framework/Scenes/Scene.cs | 2 +- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 7 ++----- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 8 ++++---- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index f86b3b6a04..e0bc891df8 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -656,7 +656,7 @@ namespace OpenSim.Region.Framework.Scenes EventManager.OnLandObjectRemoved += new EventManager.LandObjectRemoved(simDataService.RemoveLandObject); - m_sceneGraph = new SceneGraph(this, m_regInfo); + m_sceneGraph = new SceneGraph(this); // If the scene graph has an Unrecoverable error, restart this sim. // Currently the only thing that causes it to happen is two kinds of specific diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 89e6ddb521..40dc2f80ca 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -74,7 +74,6 @@ namespace OpenSim.Region.Framework.Scenes protected internal EntityManager Entities = new EntityManager(); - protected RegionInfo m_regInfo; protected Scene m_parentScene; protected Dictionary m_updateList = new Dictionary(); protected int m_numRootAgents = 0; @@ -108,10 +107,9 @@ namespace OpenSim.Region.Framework.Scenes #endregion - protected internal SceneGraph(Scene parent, RegionInfo regInfo) + protected internal SceneGraph(Scene parent) { m_parentScene = parent; - m_regInfo = regInfo; } public PhysicsScene PhysicsScene @@ -122,7 +120,6 @@ namespace OpenSim.Region.Framework.Scenes // If we're not doing the initial set // Then we've got to remove the previous // event handler - if (_PhyScene != null) _PhyScene.OnPhysicsCrash -= physicsBasedCrash; @@ -593,7 +590,7 @@ namespace OpenSim.Region.Framework.Scenes ScenePresence newAvatar = null; // ScenePresence always defaults to child agent - newAvatar = new ScenePresence(client, m_parentScene, m_regInfo, appearance, type); + newAvatar = new ScenePresence(client, m_parentScene, appearance, type); AddScenePresence(newAvatar); diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 86e1e119f3..9b8afe3ec4 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -707,9 +707,9 @@ namespace OpenSim.Region.Framework.Scenes #endregion #region Constructor(s) - + public ScenePresence( - IClientAPI client, Scene world, RegionInfo reginfo, AvatarAppearance appearance, PresenceType type) + IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type) { AttachmentsSyncLock = new Object(); @@ -718,14 +718,14 @@ namespace OpenSim.Region.Framework.Scenes m_animator = new ScenePresenceAnimator(this); PresenceType = type; m_DrawDistance = world.DefaultDrawDistance; - m_rootRegionHandle = reginfo.RegionHandle; + m_rootRegionHandle = world.RegionInfo.RegionHandle; m_controllingClient = client; m_firstname = m_controllingClient.FirstName; m_lastname = m_controllingClient.LastName; m_name = String.Format("{0} {1}", m_firstname, m_lastname); m_scene = world; m_uuid = client.AgentId; - m_regionInfo = reginfo; + m_regionInfo = world.RegionInfo; m_localId = m_scene.AllocateLocalId(); UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, m_uuid); From 62b24505295a49b3b3ba61a1a840d0fa5825340f Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 12 Sep 2011 22:54:54 +0100 Subject: [PATCH 40/54] remove the unused SP.initializeScenePresence() --- .../Region/Framework/Scenes/ScenePresence.cs | 25 ++----------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 9b8afe3ec4..1050507f8d 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3568,29 +3568,6 @@ namespace OpenSim.Region.Framework.Scenes } } - - public void initializeScenePresence(IClientAPI client, RegionInfo region, Scene scene) - { - m_controllingClient = client; - m_regionInfo = region; - m_scene = scene; - - RegisterToEvents(); - - /* - AbsolutePosition = client.StartPos; - - Animations = new AvatarAnimations(); - Animations.LoadAnims(); - - m_animations = new List(); - m_animations.Add(Animations.AnimsUUID["STAND"]); - m_animationSeqs.Add(m_controllingClient.NextAnimationSequenceNumber); - - SetDirectionVectors(); - */ - } - internal void PushForce(Vector3 impulse) { if (PhysicsActor != null) @@ -3618,6 +3595,7 @@ namespace OpenSim.Region.Framework.Scenes obj.ignoreControls = (ScriptControlled)controls; obj.eventControls = (ScriptControlled)controls; } + if (pass_on == 1 && accept == 1) { IgnoredControls = ScriptControlled.CONTROL_ZERO; @@ -3638,6 +3616,7 @@ namespace OpenSim.Region.Framework.Scenes scriptedcontrols[Script_item_UUID] = obj; } } + ControllingClient.SendTakeControls(controls, pass_on == 1 ? true : false, true); } From dea0935361d536da7fada83069e06a7c476b5351 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Mon, 12 Sep 2011 23:00:15 +0100 Subject: [PATCH 41/54] eliminate redundant SP.m_regionInfo since it always has the scene. We were already referencing through the scene in some places. --- OpenSim/Region/Framework/Scenes/ScenePresence.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 1050507f8d..879352dd1f 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -188,7 +188,6 @@ namespace OpenSim.Region.Framework.Scenes private float m_health = 100f; - protected RegionInfo m_regionInfo; protected ulong crossingFromRegion; private readonly Vector3[] Dir_Vectors = new Vector3[9]; @@ -725,7 +724,6 @@ namespace OpenSim.Region.Framework.Scenes m_name = String.Format("{0} {1}", m_firstname, m_lastname); m_scene = world; m_uuid = client.AgentId; - m_regionInfo = world.RegionInfo; m_localId = m_scene.AllocateLocalId(); UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, m_uuid); @@ -1156,7 +1154,7 @@ namespace OpenSim.Region.Framework.Scenes //m_log.DebugFormat("Completed movement"); - m_controllingClient.MoveAgentIntoRegion(m_regionInfo, AbsolutePosition, look); + m_controllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); SendInitialData(); // Create child agents in neighbouring regions @@ -2877,8 +2875,8 @@ namespace OpenSim.Region.Framework.Scenes /// protected int HaveNeighbor(Cardinals car, ref int[] fix) { - uint neighbourx = m_regionInfo.RegionLocX; - uint neighboury = m_regionInfo.RegionLocY; + uint neighbourx = m_scene.RegionInfo.RegionLocX; + uint neighboury = m_scene.RegionInfo.RegionLocY; int dir = (int)car; @@ -2898,8 +2896,8 @@ namespace OpenSim.Region.Framework.Scenes if (neighbourRegion == null) { - fix[0] = (int)(m_regionInfo.RegionLocX - neighbourx); - fix[1] = (int)(m_regionInfo.RegionLocY - neighboury); + fix[0] = (int)(m_scene.RegionInfo.RegionLocX - neighbourx); + fix[1] = (int)(m_scene.RegionInfo.RegionLocY - neighboury); return dir * (-1); } else @@ -3616,7 +3614,7 @@ namespace OpenSim.Region.Framework.Scenes scriptedcontrols[Script_item_UUID] = obj; } } - + ControllingClient.SendTakeControls(controls, pass_on == 1 ? true : false, true); } From 306af9934aac2aaf7fe9baa156b3cc57ff3f3f56 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 13 Sep 2011 17:13:42 +0100 Subject: [PATCH 42/54] In an object return message, send a null-terminated empty string in binary bucket to prevent a viewer 3 crash. This is the message sent to the client when the object is returned. We were sending byte[0] in the binary bucket. This didn't kill viewer 1 but did terminate viewer 3 (don't know about viewer 2). So sending "\0" instead. This is to address http://opensimulator.org/mantis/view.php?id=5683 --- OpenSim/Framework/Util.cs | 42 ++++++++++++++++++++++-- OpenSim/Region/Framework/Scenes/Scene.cs | 4 ++- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 745da17665..c4fc6437aa 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1372,11 +1372,30 @@ namespace OpenSim.Framework return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri; } + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// + /// Arguments to substitute into the string via the {} mechanism. + /// + /// public static byte[] StringToBytes256(string str, params object[] args) { return StringToBytes256(string.Format(str, args)); } - + + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// public static byte[] StringToBytes256(string str) { if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } @@ -1395,11 +1414,30 @@ namespace OpenSim.Framework return data; } + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// + /// Arguments to substitute into the string via the {} mechanism. + /// + /// public static byte[] StringToBytes1024(string str, params object[] args) { return StringToBytes1024(string.Format(str, args)); } - + + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// public static byte[] StringToBytes1024(string str) { if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index e0bc891df8..a0a26240d4 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -1579,7 +1579,9 @@ namespace OpenSim.Region.Framework.Scenes msg.ParentEstateID = RegionInfo.EstateSettings.ParentEstateID; msg.Position = Vector3.Zero; msg.RegionID = RegionInfo.RegionID.Guid; - msg.binaryBucket = new byte[0]; + + // We must fill in a null-terminated 'empty' string here since bytes[0] will crash viewer 3. + msg.binaryBucket = Util.StringToBytes256("\0"); if (ret.Value.count > 1) msg.message = string.Format("Your {0} objects were returned from {1} in region {2} due to {3}", ret.Value.count, ret.Value.location.ToString(), RegionInfo.RegionName, ret.Value.reason); else From 88bd71b9786f5af9ce185fa1c885622f41712371 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 13 Sep 2011 17:40:39 +0100 Subject: [PATCH 43/54] improve TestAddSceneObject() to test a multi-part object rather than a single-part --- .../Scenes/Tests/SceneObjectBasicTests.cs | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs index 1ea2329b36..8f2e21f071 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs @@ -52,22 +52,25 @@ namespace OpenSim.Region.Framework.Scenes.Tests TestHelpers.InMethod(); Scene scene = SceneHelpers.SetupScene(); + int partsToTestCount = 3; - string objName = "obj1"; - UUID objUuid = new UUID("00000000-0000-0000-0000-000000000001"); + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(partsToTestCount, TestHelpers.ParseTail(0x1), "obj1", 0x10); + SceneObjectPart[] parts = so.Parts; - SceneObjectPart part - = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) - { Name = objName, UUID = objUuid }; - - Assert.That(scene.AddNewSceneObject(new SceneObjectGroup(part), false), Is.True); - - SceneObjectPart retrievedPart = scene.GetSceneObjectPart(objUuid); + Assert.That(scene.AddNewSceneObject(so, false), Is.True); + SceneObjectGroup retrievedSo = scene.GetSceneObjectGroup(so.UUID); + SceneObjectPart[] retrievedParts = retrievedSo.Parts; //m_log.Debug("retrievedPart : {0}", retrievedPart); // If the parts have the same UUID then we will consider them as one and the same - Assert.That(retrievedPart.Name, Is.EqualTo(objName)); - Assert.That(retrievedPart.UUID, Is.EqualTo(objUuid)); + Assert.That(retrievedSo.PrimCount, Is.EqualTo(partsToTestCount)); + + for (int i = 0; i < partsToTestCount; i++) + { + Assert.That(retrievedParts[i].Name, Is.EqualTo(parts[i].Name)); + Assert.That(retrievedParts[i].UUID, Is.EqualTo(parts[i].UUID)); + } } [Test] From c14f0a22d44c582fb277ba34dec7cee629ba7f4a Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 13 Sep 2011 17:52:10 +0100 Subject: [PATCH 44/54] Add new TestGetSceneObjectByPartLocalId() for retrieving a scene object via the local id of one of its parts --- .../Scenes/Tests/SceneObjectBasicTests.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs index 8f2e21f071..281b85ca2d 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs @@ -106,6 +106,33 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(retrievedPart.Name, Is.EqualTo(obj1Name)); Assert.That(retrievedPart.UUID, Is.EqualTo(objUuid)); } + + /// + /// Test retrieving a scene object via the local id of one of its parts. + /// + [Test] + public void TestGetSceneObjectByPartLocalId() + { + TestHelpers.InMethod(); + + Scene scene = SceneHelpers.SetupScene(); + int partsToTestCount = 3; + + SceneObjectGroup so + = SceneHelpers.CreateSceneObject(partsToTestCount, TestHelpers.ParseTail(0x1), "obj1", 0x10); + SceneObjectPart[] parts = so.Parts; + + scene.AddNewSceneObject(so, false); + + // Test getting via the root part's local id + Assert.That(scene.GetGroupByPrim(so.LocalId), Is.Not.Null); + + // Test getting via a non root part's local id + Assert.That(scene.GetGroupByPrim(parts[partsToTestCount - 1].LocalId), Is.Not.Null); + + // Test that we don't get back an object for a local id that doesn't exist + Assert.That(scene.GetGroupByPrim(999), Is.Null); + } /// /// Test deleting an object from a scene. From 07ba28f1dece06309cfbf7f487b7a779e49033bb Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 13 Sep 2011 17:56:02 +0100 Subject: [PATCH 45/54] In SG.AddSceneObject(), stop unnecessarily adding the root part to object indexes sepearately from the other parts. The SOG.Parts property contains the root part as well as the non-root parts --- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 40dc2f80ca..4d7bc0c0e3 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -369,12 +369,12 @@ namespace OpenSim.Region.Framework.Scenes // "[SCENEGRAPH]: Adding scene object {0} {1}, with {2} parts on {3}", // sceneObject.Name, sceneObject.UUID, sceneObject.Parts.Length, m_parentScene.RegionInfo.RegionName); - SceneObjectPart[] children = sceneObject.Parts; + SceneObjectPart[] parts = sceneObject.Parts; // Clamp child prim sizes and add child prims to the m_numPrim count if (m_parentScene.m_clampPrimSize) { - foreach (SceneObjectPart part in children) + foreach (SceneObjectPart part in parts) { Vector3 scale = part.Shape.Scale; @@ -388,7 +388,7 @@ namespace OpenSim.Region.Framework.Scenes part.Shape.Scale = scale; } } - m_numPrim += children.Length; + m_numPrim += parts.Length; sceneObject.AttachToScene(m_parentScene); @@ -408,8 +408,7 @@ namespace OpenSim.Region.Framework.Scenes lock (SceneObjectGroupsByFullPartID) { - SceneObjectGroupsByFullPartID[sceneObject.UUID] = sceneObject; - foreach (SceneObjectPart part in children) + foreach (SceneObjectPart part in parts) SceneObjectGroupsByFullPartID[part.UUID] = sceneObject; } @@ -419,8 +418,7 @@ namespace OpenSim.Region.Framework.Scenes // "[SCENE GRAPH]: Adding scene object {0} {1} {2} to SceneObjectGroupsByLocalPartID in {3}", // sceneObject.Name, sceneObject.UUID, sceneObject.LocalId, m_parentScene.RegionInfo.RegionName); - SceneObjectGroupsByLocalPartID[sceneObject.LocalId] = sceneObject; - foreach (SceneObjectPart part in children) + foreach (SceneObjectPart part in parts) SceneObjectGroupsByLocalPartID[part.LocalId] = sceneObject; } From f09a90d8a7cf1e4b32845c3ffddbf1ca780e664c Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 13 Sep 2011 18:08:05 +0100 Subject: [PATCH 46/54] extend TestGetSceneObjectByPartLocalId() to test state after scene object deletion --- .../Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs index 281b85ca2d..9586877c26 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs @@ -132,6 +132,12 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Test that we don't get back an object for a local id that doesn't exist Assert.That(scene.GetGroupByPrim(999), Is.Null); + + // Now delete the scene object and check again + scene.DeleteSceneObject(so, false); + + Assert.That(scene.GetGroupByPrim(so.LocalId), Is.Null); + Assert.That(scene.GetGroupByPrim(parts[partsToTestCount - 1].LocalId), Is.Null); } /// From df73833a2c79a1a60536e386b5884581d9f2f4b3 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 13 Sep 2011 18:11:13 +0100 Subject: [PATCH 47/54] stop the duplicate remove of the root part ids from the full part and local part indexes in SG.DeleteSceneObject() this is unnecessary because the parts array iterated through contains the root part as well as the non-root parts --- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 2 -- OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 4d7bc0c0e3..46c22ca6e8 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -459,7 +459,6 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart[] parts = grp.Parts; for (int i = 0; i < parts.Length; i++) SceneObjectGroupsByFullPartID.Remove(parts[i].UUID); - SceneObjectGroupsByFullPartID.Remove(grp.RootPart.UUID); } lock (SceneObjectGroupsByLocalPartID) @@ -467,7 +466,6 @@ namespace OpenSim.Region.Framework.Scenes SceneObjectPart[] parts = grp.Parts; for (int i = 0; i < parts.Length; i++) SceneObjectGroupsByLocalPartID.Remove(parts[i].LocalId); - SceneObjectGroupsByLocalPartID.Remove(grp.RootPart.LocalId); } return Entities.Remove(uuid); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs index 9586877c26..80f198d2d6 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs @@ -135,7 +135,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Now delete the scene object and check again scene.DeleteSceneObject(so, false); - + Assert.That(scene.GetGroupByPrim(so.LocalId), Is.Null); Assert.That(scene.GetGroupByPrim(parts[partsToTestCount - 1].LocalId), Is.Null); } From 618277e797c7d501f98e884e50abd313498cf00b Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 13 Sep 2011 20:25:32 +0100 Subject: [PATCH 48/54] Comment out attachments code in Scene.IncomingCreateObject(UUID userID, UUID itemID) for now As far as I can see, this is only invoked by a PUT request to ObjectHandlers, which is not being used anyway. Invoking attachments code at this point is probably inappropriate since it would still be invoked when the client entered the scene. Being commented to simplify analysis of attachments issues. Can be uncommented when in use. Also, small tweak to lock and log removal of a SOG from the SceneObjectGroupsByLocalPartID collection in SceneGraph.GetGroupByPrim() if an inconsistency is found. --- .../Avatar/Attachments/AttachmentsModule.cs | 17 ++++++++++--- OpenSim/Region/Framework/Scenes/Scene.cs | 18 +++++++------ OpenSim/Region/Framework/Scenes/SceneGraph.cs | 25 +++++++++++++++++-- 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 2fa233b74a..c817559239 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -143,6 +143,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public void SaveChangedAttachments(IScenePresence sp) { +// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name); + foreach (SceneObjectGroup grp in sp.GetAttachments()) { if (grp.HasGroupChanged) // Resizer scripts? @@ -242,9 +244,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { lock (sp.AttachmentsSyncLock) { - // 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); +// 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 (sp.GetAttachments(attachmentPt).Contains(group)) { @@ -365,6 +367,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public ISceneEntity RezSingleAttachmentFromInventory(ScenePresence sp, UUID itemID, uint AttachmentPt) { +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2}", +// (AttachmentPoint)AttachmentPt, itemID, sp.Name); + // TODO: this short circuits multiple attachments functionality in LL viewer 2.1+ and should // be removed when that functionality is implemented in opensim AttachmentPt &= 0x7f; @@ -485,6 +491,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public void DetachObject(uint objectLocalID, IClientAPI remoteClient) { +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: DetachObject() for object {0} on {1}", objectLocalID, remoteClient.Name); + SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID); if (group != null) { @@ -588,6 +597,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // To LocalId or UUID, *THAT* is the question. How now Brown UUID?? private void DetachSingleAttachmentToInv(UUID itemID, IScenePresence sp) { +// 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; diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index a0a26240d4..c5c926023b 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -2461,14 +2461,16 @@ namespace OpenSim.Region.Framework.Scenes /// False public virtual bool IncomingCreateObject(UUID userID, UUID itemID) { - //m_log.DebugFormat(" >>> IncomingCreateObject(userID, itemID) <<< {0} {1}", userID, itemID); - - ScenePresence sp = GetScenePresence(userID); - if (sp != null && AttachmentsModule != null) - { - uint attPt = (uint)sp.Appearance.GetAttachpoint(itemID); - AttachmentsModule.RezSingleAttachmentFromInventory(sp.ControllingClient, itemID, attPt); - } + 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; } diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 46c22ca6e8..f03cf7b2af 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -431,6 +431,10 @@ namespace OpenSim.Region.Framework.Scenes /// true if the object was deleted, false if there was no object to delete public bool DeleteSceneObject(UUID uuid, bool resultOfObjectLinked) { +// m_log.DebugFormat( +// "[SCENE GRAPH]: Deleting scene object with uuid {0}, resultOfObjectLinked = {1}", +// uuid, resultOfObjectLinked); + EntityBase entity; if (!Entities.TryGetValue(uuid, out entity) || (!(entity is SceneObjectGroup))) return false; @@ -878,7 +882,8 @@ namespace OpenSim.Region.Framework.Scenes if (Entities.TryGetValue(localID, out entity)) return entity as SceneObjectGroup; - //m_log.DebugFormat("Entered GetGroupByPrim with localID {0}", localID); +// m_log.DebugFormat("[SCENE GRAPH]: Entered GetGroupByPrim with localID {0}", localID); + SceneObjectGroup sog; lock (SceneObjectGroupsByLocalPartID) SceneObjectGroupsByLocalPartID.TryGetValue(localID, out sog); @@ -886,8 +891,24 @@ namespace OpenSim.Region.Framework.Scenes if (sog != null) { if (sog.HasChildPrim(localID)) + { +// m_log.DebugFormat( +// "[SCENE GRAPH]: Found scene object {0} {1} {2} containing part with local id {3} in {4}. Returning.", +// sog.Name, sog.UUID, sog.LocalId, localID, m_parentScene.RegionInfo.RegionName); + return sog; - SceneObjectGroupsByLocalPartID.Remove(localID); + } + else + { + lock (SceneObjectGroupsByLocalPartID) + { + m_log.WarnFormat( + "[SCENE GRAPH]: Found scene object {0} {1} {2} via SceneObjectGroupsByLocalPartID index but it doesn't contain part with local id {3}. Removing from entry from index in {4}.", + sog.Name, sog.UUID, sog.LocalId, localID, m_parentScene.RegionInfo.RegionName); + + SceneObjectGroupsByLocalPartID.Remove(localID); + } + } } EntityBase[] entityList = GetEntities(); From 8880aea728af2ccb95ea2400c7d180aa4dc98112 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 13 Sep 2011 22:13:58 +0100 Subject: [PATCH 49/54] Stop attempts to rewear already worn items from removing and reattaching. Viewer 2/3 will sometimes attempt to rewear attachments, even though they have already been attached during the main login process. This change ignores those attempts. This stops script failures during login, as the rewearing was racing with the script startup code. It might also help with attachments being abnormally put into deleted state. Hopefully resolves some more of http://opensimulator.org/mantis/view.php?id=5644 --- .../Avatar/Attachments/AttachmentsModule.cs | 125 +++++++++++------- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 4 +- .../Scenes/SceneObjectGroup.Inventory.cs | 13 ++ .../Scenes/SceneObjectPartInventory.cs | 5 + 4 files changed, 100 insertions(+), 47 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index c817559239..1e9a001479 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -147,18 +147,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments foreach (SceneObjectGroup grp in sp.GetAttachments()) { - if (grp.HasGroupChanged) // Resizer scripts? - { +// if (grp.HasGroupChanged) // Resizer scripts? +// { grp.IsAttachment = false; grp.AbsolutePosition = grp.RootPart.AttachedPos; UpdateKnownItem(sp.ControllingClient, grp, grp.GetFromItemID(), grp.OwnerID); grp.IsAttachment = true; - } +// } } } 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); + foreach (SceneObjectGroup sop in sp.GetAttachments()) { sop.Scene.DeleteSceneObject(sop, silent); @@ -214,7 +218,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId); // Save avatar attachment information - m_log.Info( + m_log.Debug( "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId + ", AttachmentPoint: " + AttachmentPt); @@ -339,6 +343,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments lock (sp.AttachmentsSyncLock) { +// m_log.DebugFormat("[ATTACHMENTS MODULE]: Rezzing multiple attachments from inventory for {0}", sp.Name); + foreach (RezMultipleAttachmentsFromInvPacket.ObjectDataBlock obj in objects) { RezSingleAttachmentFromInventory(sp, obj.ItemID, obj.AttachmentPt); @@ -349,7 +355,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments public ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) { // m_log.DebugFormat( -// "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", +// "[ATTACHMENTS MODULE]: Rezzing attachment to point {0} from item {1} for {2}", // (AttachmentPoint)AttachmentPt, itemID, remoteClient.Name); ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); @@ -375,6 +381,32 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // be removed when that functionality is implemented in opensim AttachmentPt &= 0x7f; + // Viewer 2/3 sometimes asks to re-wear items that are already worn (and show up in it's inventory as such). + // This often happens during login - not sure the exact reason. + // For now, we will ignore the request. Unfortunately, this means that we need to dig through all the + // ScenePresence attachments. We can't use the data in AvatarAppearance because that's present at login + // before anything has actually been attached. + bool alreadyOn = false; + List existingAttachments = sp.GetAttachments(); + foreach (SceneObjectGroup so in existingAttachments) + { + if (so.GetFromItemID() == itemID) + { + alreadyOn = true; + break; + } + } + +// if (sp.Appearance.GetAttachmentForItem(itemID) != null) + if (alreadyOn) + { +// m_log.WarnFormat( +// "[ATTACHMENTS MODULE]: Ignoring request by {0} to wear item {1} at {2} since it is already worn", +// sp.Name, itemID, AttachmentPt); + + return null; + } + SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt); if (att == null) @@ -467,8 +499,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments 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, remoteClient.Name, AttachmentPt, itemID); +// "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", +// att.Name, sp.Name, AttachmentPt, itemID); if (UUID.Zero == itemID) { @@ -524,7 +556,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: DetachSingleAttachmentToGround() for {0}, object {1}", -// remoteClient.Name, sceneObjectID); +// remoteClient.Name, soLocalId); SceneObjectGroup so = m_scene.GetGroupByPrim(soLocalId); @@ -677,45 +709,45 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { if (grp != null) { - if (!grp.HasGroupChanged) + if (grp.HasGroupChanged || grp.ContainsScripts()) + { + m_log.DebugFormat( + "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}", + grp.UUID, grp.AttachmentPoint); + + string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); + + InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); + item = m_scene.InventoryService.GetItem(item); + + if (item != null) + { + AssetBase asset = m_scene.CreateAsset( + grp.GetPartName(grp.LocalId), + grp.GetPartDescription(grp.LocalId), + (sbyte)AssetType.Object, + Utils.StringToBytes(sceneObjectXml), + remoteClient.AgentId); + m_scene.AssetService.Store(asset); + + item.AssetID = asset.FullID; + item.Description = asset.Description; + item.Name = asset.Name; + item.AssetType = asset.Type; + item.InvType = (int)InventoryType.Object; + + m_scene.InventoryService.UpdateItem(item); + + // this gets called when the agent logs off! + if (remoteClient != null) + remoteClient.SendInventoryItemCreateUpdate(item, 0); + } + } + else { m_log.DebugFormat( "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", grp.UUID, grp.AttachmentPoint); - - return; - } - - m_log.DebugFormat( - "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}", - grp.UUID, grp.AttachmentPoint); - - string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); - - InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); - item = m_scene.InventoryService.GetItem(item); - - if (item != null) - { - AssetBase asset = m_scene.CreateAsset( - grp.GetPartName(grp.LocalId), - grp.GetPartDescription(grp.LocalId), - (sbyte)AssetType.Object, - Utils.StringToBytes(sceneObjectXml), - remoteClient.AgentId); - m_scene.AssetService.Store(asset); - - item.AssetID = asset.FullID; - item.Description = asset.Description; - item.Name = asset.Name; - item.AssetType = asset.Type; - item.InvType = (int)InventoryType.Object; - - m_scene.InventoryService.UpdateItem(item); - - // this gets called when the agent logs off! - if (remoteClient != null) - remoteClient.SendInventoryItemCreateUpdate(item, 0); } } } @@ -735,7 +767,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments private void AttachToAgent( IScenePresence avatar, 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}", +// 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); so.DetachFromBackup(); @@ -788,7 +821,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// The user inventory item created that holds the attachment. private InventoryItemBase AddSceneObjectAsNewAttachmentInInv(IClientAPI remoteClient, SceneObjectGroup grp) { -// m_log.DebugFormat("[SCENE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2} {3} {4}", grp.Name, grp.LocalId, remoteClient.Name, remoteClient.AgentId, AgentId); +// 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) diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index f03cf7b2af..36c5c52483 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -652,7 +652,7 @@ namespace OpenSim.Region.Framework.Scenes if (!Entities.Remove(agentID)) { m_log.WarnFormat( - "[SCENEGRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene Entities list", + "[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene Entities list", agentID); } @@ -675,7 +675,7 @@ namespace OpenSim.Region.Framework.Scenes } else { - m_log.WarnFormat("[SCENEGRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID); + m_log.WarnFormat("[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list", agentID); } } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs index 4bca3d0099..905ecc9ff5 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs @@ -389,5 +389,18 @@ namespace OpenSim.Region.Framework.Scenes for (int i = 0; i < parts.Length; i++) parts[i].Inventory.ResumeScripts(); } + + /// + /// Returns true if any part in the scene object contains scripts, false otherwise. + /// + /// + public bool ContainsScripts() + { + foreach (SceneObjectPart part in Parts) + if (part.Inventory.ContainsScripts()) + return true; + + return false; + } } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index e40e57d5b9..57adda7be4 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -1035,10 +1035,15 @@ namespace OpenSim.Region.Framework.Scenes item.BasePermissions = perms; } } + m_inventorySerial++; HasInventoryChanged = true; } + /// + /// Returns true if this part inventory contains any scripts. False otherwise. + /// + /// public bool ContainsScripts() { lock (m_items) From 62b3e74bc5c3f08f33e15b30d04a799db4228c06 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 13 Sep 2011 22:24:33 +0100 Subject: [PATCH 50/54] minor: remove redundant grp != null check from AM.UpdateKnownItem() --- .../Avatar/Attachments/AttachmentsModule.cs | 69 +++++++++---------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 1e9a001479..ae1922451b 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -707,49 +707,46 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// public void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID) { - if (grp != null) + if (grp.HasGroupChanged || grp.ContainsScripts()) { - if (grp.HasGroupChanged || grp.ContainsScripts()) + m_log.DebugFormat( + "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}", + grp.UUID, grp.AttachmentPoint); + + string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); + + InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); + item = m_scene.InventoryService.GetItem(item); + + if (item != null) { - m_log.DebugFormat( - "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}", - grp.UUID, grp.AttachmentPoint); + AssetBase asset = m_scene.CreateAsset( + grp.GetPartName(grp.LocalId), + grp.GetPartDescription(grp.LocalId), + (sbyte)AssetType.Object, + Utils.StringToBytes(sceneObjectXml), + remoteClient.AgentId); + m_scene.AssetService.Store(asset); - string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); + item.AssetID = asset.FullID; + item.Description = asset.Description; + item.Name = asset.Name; + item.AssetType = asset.Type; + item.InvType = (int)InventoryType.Object; - InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); - item = m_scene.InventoryService.GetItem(item); + m_scene.InventoryService.UpdateItem(item); - if (item != null) - { - AssetBase asset = m_scene.CreateAsset( - grp.GetPartName(grp.LocalId), - grp.GetPartDescription(grp.LocalId), - (sbyte)AssetType.Object, - Utils.StringToBytes(sceneObjectXml), - remoteClient.AgentId); - m_scene.AssetService.Store(asset); - - item.AssetID = asset.FullID; - item.Description = asset.Description; - item.Name = asset.Name; - item.AssetType = asset.Type; - item.InvType = (int)InventoryType.Object; - - m_scene.InventoryService.UpdateItem(item); - - // this gets called when the agent logs off! - if (remoteClient != null) - remoteClient.SendInventoryItemCreateUpdate(item, 0); - } - } - else - { - m_log.DebugFormat( - "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", - grp.UUID, grp.AttachmentPoint); + // this gets called when the agent logs off! + if (remoteClient != null) + remoteClient.SendInventoryItemCreateUpdate(item, 0); } } + else + { + m_log.DebugFormat( + "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}", + grp.UUID, grp.AttachmentPoint); + } } /// From 2d62484f11710cbeb066ab6bf02f78ad379ecca3 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 13 Sep 2011 22:27:33 +0100 Subject: [PATCH 51/54] Remove UpdateKnownItem() from IAttachmentsModule. It's not appropriate for code outside the attachments module to call this. --- .../CoreModules/Avatar/Attachments/AttachmentsModule.cs | 2 +- .../Region/Framework/Interfaces/IAttachmentsModule.cs | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index ae1922451b..03837b52cf 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -705,7 +705,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// /// /// - public void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID) + private void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID) { if (grp.HasGroupChanged || grp.ContainsScripts()) { diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index e6ac6b5e9a..5ffbec873b 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -138,14 +138,5 @@ namespace OpenSim.Region.Framework.Interfaces /// /// void UpdateAttachmentPosition(SceneObjectGroup sog, Vector3 pos); - - /// - /// Update the user inventory with a changed attachment - /// - /// - /// - /// - /// - void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID); } } From 61affee814b6c2a09cb33b1823f009d386f54818 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 13 Sep 2011 22:33:15 +0100 Subject: [PATCH 52/54] remove redunant itemID and agentID arguments from UpdateKnownItem(). itemID is always taken taken from the group's stored item id, and agentID is never used. --- .../Avatar/Attachments/AttachmentsModule.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 03837b52cf..b9cd880c64 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -151,7 +151,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // { grp.IsAttachment = false; grp.AbsolutePosition = grp.RootPart.AttachedPos; - UpdateKnownItem(sp.ControllingClient, grp, grp.GetFromItemID(), grp.OwnerID); + UpdateKnownItem(sp.ControllingClient, grp); grp.IsAttachment = true; // } } @@ -668,7 +668,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments group.IsAttachment = false; group.AbsolutePosition = group.RootPart.AttachedPos; - UpdateKnownItem(sp.ControllingClient, group, group.GetFromItemID(), group.OwnerID); + UpdateKnownItem(sp.ControllingClient, group); m_scene.DeleteSceneObject(group, false); return; @@ -703,9 +703,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// /// /// - /// - /// - private void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID) + private void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp) { if (grp.HasGroupChanged || grp.ContainsScripts()) { @@ -715,7 +713,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); - InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); + InventoryItemBase item = new InventoryItemBase(grp.GetFromItemID(), remoteClient.AgentId); item = m_scene.InventoryService.GetItem(item); if (item != null) From 1084d8f6a2bcf63c594e1a8bd180c42f51b05e2f Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 13 Sep 2011 22:39:06 +0100 Subject: [PATCH 53/54] Remove code from DetachSingleAttachmentToInv() that sets group changed on all parts, now that we're performing this check in UpdateKnownItem() for other purposes --- .../Avatar/Attachments/AttachmentsModule.cs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index b9cd880c64..b965d75443 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -653,17 +653,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // Prepare sog for storage group.AttachedAvatar = UUID.Zero; - - group.ForEachPart( - delegate(SceneObjectPart part) - { - // If there are any scripts, - // then always trigger a new object and state persistence in UpdateKnownItem() - if (part.Inventory.ContainsScripts()) - group.HasGroupChanged = true; - } - ); - group.RootPart.SetParentLocalId(0); group.IsAttachment = false; group.AbsolutePosition = group.RootPart.AttachedPos; From bd991fc95f8ec648f7dbb0086ae716e4204d1687 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 13 Sep 2011 22:54:50 +0100 Subject: [PATCH 54/54] Don't try and delete attachments for child agent close --- .../Tests/AttachmentsModuleTests.cs | 32 +++++++++++++++++++ .../Region/Framework/Scenes/ScenePresence.cs | 3 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 35183b395a..ff3358f4fe 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -220,6 +220,38 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests Assert.That(m_presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo(0)); } + /// + /// Test that attachments don't hang about in the scene when the agent is closed + /// + [Test] + public void TestRemoveAttachmentsOnAvatarExit() + { + TestHelpers.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + UUID userId = TestHelpers.ParseTail(0x1); + UUID attItemId = TestHelpers.ParseTail(0x2); + UUID attAssetId = TestHelpers.ParseTail(0x3); + string attName = "att"; + + UserAccountHelpers.CreateUserWithInventory(scene, userId); + InventoryItemBase attItem + = UserInventoryHelpers.CreateInventoryItem( + scene, attName, attItemId, attAssetId, userId, InventoryType.Object); + + AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId); + acd.Appearance = new AvatarAppearance(); + acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID); + ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd); + + SceneObjectGroup rezzedAtt = presence.GetAttachments()[0]; + + scene.IncomingCloseAgent(presence.UUID); + + // Check that we can't retrieve this attachment from the scene. + Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null); + } + [Test] public void TestRezAttachmentsOnAvatarEntrance() { diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 879352dd1f..a8eff702f4 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3404,7 +3404,8 @@ namespace OpenSim.Region.Framework.Scenes public void Close() { - m_scene.AttachmentsModule.DeleteAttachmentsFromScene(this, false); + if (!IsChildAgent) + m_scene.AttachmentsModule.DeleteAttachmentsFromScene(this, false); lock (m_knownChildRegions) {