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/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs index ee3d7c58bc..86c0ac8f94 100644 --- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs +++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs @@ -812,6 +812,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")) { @@ -823,6 +831,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 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 b9228d1480..3437250e5f 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/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/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index a68de574d6..21e2233ad2 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs @@ -405,31 +405,40 @@ namespace OpenSim.Framework /// public List GetAttachments() { + + lock (m_attachments) { - List alist = new List(); + List alist = new List(); foreach (KeyValuePair> kvp in m_attachments) { foreach (AvatarAttachment attach in kvp.Value) alist.Add(new AvatarAttachment(attach)); } - - return alist; - } - } + return alist; + } } internal void AppendAttachment(AvatarAttachment attach) { +// m_log.DebugFormat( +// "[AVATAR APPEARNCE]: Appending itemID={0}, assetID={1} at {2}", +// attach.ItemID, attach.AssetID, attach.AttachPoint); + 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) { +// m_log.DebugFormat( +// "[AVATAR APPEARANCE]: Replacing itemID={0}, assetID={1} at {2}", +// attach.ItemID, attach.AssetID, attach.AttachPoint); + lock (m_attachments) { m_attachments[attach.AttachPoint] = new List(); @@ -438,7 +447,7 @@ namespace OpenSim.Framework } /// - /// Add an attachment + /// Set an attachment /// /// /// If the attachpoint has the @@ -454,13 +463,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) { lock (m_attachments) @@ -470,12 +479,21 @@ namespace OpenSim.Framework m_attachments.Remove(attachpoint); return true; } - return false; } + + 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; @@ -492,9 +510,30 @@ namespace OpenSim.Framework { ReplaceAttachment(new AvatarAttachment(attachpoint,item, asset)); } + return true; } + /// + /// If the item is already attached, return it. + /// + /// + /// Returns null if this item is not attached. + public AvatarAttachment GetAttachmentForItem(UUID itemID) + { + lock (m_attachments) + { + 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) { lock (m_attachments) @@ -505,9 +544,8 @@ namespace OpenSim.Framework if (index >= 0) return kvp.Key; } - - return 0; } + return 0; } public bool DetachAttachment(UUID itemID) @@ -521,23 +559,23 @@ namespace OpenSim.Framework { // 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() { lock (m_attachments) - { m_attachments.Clear(); - } } #region Packing Functions diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs index 613db1c55a..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); @@ -628,6 +627,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/Framework/Util.cs b/OpenSim/Framework/Util.cs index 2d58807b68..1cbb53f01b 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1384,11 +1384,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; } @@ -1407,11 +1426,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/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index fae8be759c..92ccb06925 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/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index dbfd0f2290..dd0ea67731 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -489,6 +489,8 @@ namespace OpenSim scene.StartTimer(); scene.StartTimerWatchdog(); + scene.StartScripts(); + return clientServer; } diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 218b7b8096..2bf418d341 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -144,20 +144,26 @@ 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? - { +// if (grp.HasGroupChanged) // Resizer scripts? +// { grp.IsAttachment = false; grp.AbsolutePosition = grp.RootPart.AttachedPos; - UpdateKnownItem(sp.ControllingClient, grp, grp.GetFromItemID(), grp.OwnerID); + UpdateKnownItem(sp.ControllingClient, grp); 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); @@ -220,7 +226,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); @@ -248,75 +254,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; - - // 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) - { - if (attachments.Count != 0) - itemID = attachments[0].GetFromItemID(); +// 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 (itemID != UUID.Zero) - DetachSingleAttachmentToInv(itemID, sp); + if (sp.GetAttachments(attachmentPt).Contains(group)) + { + // 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); - itemID = group.GetFromItemID(); - if (itemID == UUID.Zero) - itemID = AddSceneObjectAsAttachment(sp.ControllingClient, group).ID; + return false; + } - ShowAttachInUserInventory(sp, attachmentPt, itemID, 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; } @@ -325,20 +339,28 @@ 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) + { +// 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); + } } } - 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) + public ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt) { return RezSingleAttachmentFromInventory(remoteClient, itemID, AttachmentPt, true, null); } @@ -347,21 +369,59 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments IClientAPI remoteClient, UUID itemID, uint AttachmentPt, bool updateInventoryStatus, XmlDocument doc) { ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId); - if (sp == null) { m_log.ErrorFormat( "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezSingleAttachmentFromInventory()", remoteClient.Name, remoteClient.AgentId); return null; } + + if (sp == null) + { + m_log.ErrorFormat( + "[ATTACHMENTS MODULE]: Could not find presence for client {0} {1} in RezSingleAttachmentFromInventory()", + remoteClient.Name, remoteClient.AgentId); + return null; + } + + return RezSingleAttachmentFromInventory(sp, itemID, AttachmentPt); + } + + 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; - SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt, doc); - - if (updateInventoryStatus) + // 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 (att == null) - DetachSingleAttachmentToInv(itemID, sp.ControllingClient); - else - ShowAttachInUserInventory(att, sp, itemID, AttachmentPt); + 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, null); + + if (att == null) + DetachSingleAttachmentToInv(itemID, sp.ControllingClient); + return att; } @@ -371,50 +431,67 @@ 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) { - // 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. - 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); + + 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); + } if (doc != null) { @@ -430,47 +507,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // 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); } - 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; } - - /// - /// 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); - if (m_scene.InventoryService != null) - 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 @@ -483,8 +523,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) { @@ -518,6 +558,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) { @@ -530,14 +573,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); + } } } @@ -545,7 +591,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); @@ -564,24 +610,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); } /// @@ -615,6 +664,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; @@ -623,40 +674,29 @@ 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); + group = (SceneObjectGroup)entity; if (group.GetFromItemID() == itemID) { m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); // CM / XMREngine!!!! Needed to conclude attach event //SceneObjectSerializer.ToOriginalXmlFormat(group); group.DetachToInventoryPrep(); m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString()); - // Prepare sog for storage - group.AttachedAvatar = UUID.Zero; + // Prepare sog for storage + group.AttachedAvatar = UUID.Zero; + group.RootPart.SetParentLocalId(0); + group.IsAttachment = false; + group.AbsolutePosition = group.RootPart.AttachedPos; - 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; - } - ); + UpdateKnownItem(sp.ControllingClient, group); + m_scene.DeleteSceneObject(group, false); - 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); - - return; + return; + } } } } @@ -687,28 +727,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments /// /// /// - /// - /// - public void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID) + private void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp) { - if (grp != null) + if (grp.HasGroupChanged || grp.ContainsScripts()) { - if (!grp.HasGroupChanged) - { - 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); + InventoryItemBase item = new InventoryItemBase(grp.GetFromItemID(), remoteClient.AgentId); item = m_scene.InventoryService.GetItem(item); if (item != null) @@ -734,6 +763,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments 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); + } } /// @@ -751,7 +786,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,14 +824,16 @@ 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); +// 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) @@ -879,4 +917,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments return item; } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 363e2584aa..ff3358f4fe 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 @@ -150,6 +154,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)); } @@ -215,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() { @@ -246,6 +283,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/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index faccab24a7..25d5e0e066 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 @@ -210,7 +208,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 { @@ -328,10 +329,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.StandUp(); if (!sp.ValidateAttachments()) - { - sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state"); - return; - } + 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()) +// { +// sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state"); +// return; +// } string reason; string version; @@ -955,7 +961,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)); @@ -963,8 +971,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer Scene m_scene = agent.Scene; - if (neighbourRegion != null && agent.ValidateAttachments()) + if (neighbourRegion != null) { + if (!agent.ValidateAttachments()) + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for region crossing of {0} from {1} to {2}. Continuing.", + agent.Name, agent.Scene.RegionInfo.RegionName, neighbourRegion.RegionName); + pos = pos + (agent.Velocity); SetInTransit(agent.UUID); @@ -1789,16 +1802,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/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index a4bb40ef93..f05b090b1e 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -726,8 +726,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; @@ -799,6 +798,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 @@ -839,7 +845,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (!attachment) { - if (group.RootPart.Shape.PCode == (byte)PCode.Prim) + if (rootPart.Shape.PCode == (byte)PCode.Prim) group.ClearPartAttachmentData(); // Fire on_rez @@ -1017,11 +1023,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/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index b0b35e4d0d..bef0d69697 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 @@ -365,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) 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/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/HGInventoryBroker.cs index 72ae336352..0d121edb97 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; } } @@ -140,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) @@ -323,7 +352,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 +367,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Inventory } - public bool AddFolder(InventoryFolderBase folder) + public bool AddFolder(InventoryFolderBase folder) { if (folder == null) return false; @@ -355,7 +384,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 +401,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 +420,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 +437,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 +471,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 +488,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 +507,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 +526,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 +542,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 +559,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); @@ -572,14 +601,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.Scene = m_Scenes[0]; + connector = rxisc; + } + m_connectors.Add(url, connector); } } + 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..1c83f8eb49 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) @@ -185,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 8f1f25774a..c9c716cec7 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Inventory/RemoteXInventoryServiceConnector.cs @@ -45,19 +45,30 @@ 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; private IUserManagement m_UserManager; - private IUserManagement UserManager + public IUserManagement UserManager { get { 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}", + Scene.RegionInfo.RegionName); } + return m_UserManager; } } @@ -86,12 +97,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) @@ -128,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) @@ -181,14 +190,17 @@ 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 { 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/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index f85a91701c..238863ef23 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/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/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"); diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index fb3228825e..321f6b6c31 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -992,6 +992,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/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs index afb641fc6d..2e877f0437 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/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index 59c26e7a69..d1b7dc1b24 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -89,18 +89,13 @@ namespace OpenSim.Region.Framework.Interfaces ISceneEntity RezSingleAttachmentFromInventory(IClientAPI remoteClient, UUID itemID, uint AttachmentPt); /// - /// Rez an attachment from user inventory + /// Rez an attachment from user inventory and change inventory status to match. /// - /// + /// /// /// - /// - /// 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); + /// The scene object that was attached. Null if the scene object could not be found + ISceneEntity RezSingleAttachmentFromInventory(ScenePresence sp, UUID itemID, uint AttachmentPt); // Same as above, but also load script states from a separate doc ISceneEntity RezSingleAttachmentFromInventory( @@ -146,13 +141,10 @@ namespace OpenSim.Region.Framework.Interfaces /// void DetachSingleAttachmentToInv(UUID itemID, IClientAPI remoteClient); - /// - /// Update the user inventory with a changed attachment + /// Update the position of an attachment. /// - /// - /// - /// - /// - void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID); + /// + /// + void UpdateAttachmentPosition(SceneObjectGroup sog, Vector3 pos); } } 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); + } +} diff --git a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs index 8913133404..ff39283b25 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/Interfaces/ISceneViewer.cs b/OpenSim/Region/Framework/Interfaces/ISceneViewer.cs index 2397f223b3..e715e706f2 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 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/Interfaces/IScriptModule.cs b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs index 641e226212..7dde586b8c 100644 --- a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs @@ -54,5 +54,10 @@ namespace OpenSim.Region.Framework.Interfaces bool HasScript(UUID itemID, out bool running); 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 63dd5502c0..c2ec5d01f6 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/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index a661ab8b55..c5bb2b285f 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -610,9 +610,42 @@ namespace OpenSim.Region.Framework.Scenes #region Region Settings // Load region settings - m_regInfo.WindlightSettings = SimulationDataService.LoadRegionWindlightSettings(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; - m_regInfo.RegionSettings = simDataService.LoadRegionSettings(m_regInfo.RegionID); if (estateDataService != null) m_regInfo.EstateSettings = estateDataService.LoadEstateSettings(m_regInfo.RegionID, false); @@ -645,7 +678,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 @@ -1575,7 +1608,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 @@ -2492,14 +2527,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; } @@ -3272,8 +3309,8 @@ namespace OpenSim.Region.Framework.Scenes if (AttachmentsModule != null && !avatar.IsChildAgent && avatar.PresenceType != PresenceType.Npc) AttachmentsModule.SaveChangedAttachments(avatar); - if (avatar != null && (!avatar.IsChildAgent)) - avatar.SaveChangedAttachments(); + if (AttachmentsModule != null && !avatar.IsChildAgent && avatar.PresenceType != PresenceType.Npc) + AttachmentsModule.SaveChangedAttachments(avatar); ForEachClient( delegate(IClientAPI client) diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 42e2502e8f..d1ee990fbd 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -83,7 +83,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; @@ -117,10 +116,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 @@ -131,7 +129,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; @@ -413,12 +410,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; @@ -432,7 +429,7 @@ namespace OpenSim.Region.Framework.Scenes part.Shape.Scale = scale; } } - m_numPrim += children.Length; + m_numPrim += parts.Length; sceneObject.AttachToScene(m_parentScene); @@ -452,15 +449,17 @@ 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; } lock (SceneObjectGroupsByLocalPartID) { - SceneObjectGroupsByLocalPartID[sceneObject.LocalId] = sceneObject; - foreach (SceneObjectPart part in children) +// 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); + + foreach (SceneObjectPart part in parts) SceneObjectGroupsByLocalPartID[part.LocalId] = sceneObject; } @@ -473,6 +472,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; @@ -501,7 +504,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) @@ -509,7 +511,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); @@ -654,7 +655,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); @@ -721,7 +722,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); } @@ -745,7 +746,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); } } finally @@ -956,7 +957,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); @@ -964,8 +966,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(); diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs index 9f0ac4fa34..6bd9183cb3 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.Inventory.cs @@ -388,5 +388,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 1f0840d88c..f6b690c4a3 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -1239,10 +1239,15 @@ namespace OpenSim.Region.Framework.Scenes item.CurrentPermissions = perms; item.BasePermissions = perms; } + m_inventorySerial++; HasInventoryChanged = true; } + /// + /// Returns true if this part inventory contains any scripts. False otherwise. + /// + /// public bool ContainsScripts() { foreach (TaskInventoryItem item in m_items.Values) diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 35a8df7d01..7a86f9867b 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -124,6 +124,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; @@ -199,7 +201,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[11]; @@ -770,23 +771,24 @@ 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(); + m_sendCourseLocationsMethod = SendCoarseLocationsDefault; m_sceneViewer = new SceneViewer(this); 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_localId = m_scene.AllocateLocalId(); UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, m_uuid); @@ -1302,7 +1304,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 @@ -3226,8 +3228,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; @@ -3247,8 +3249,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 @@ -3494,26 +3496,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); + } } } } @@ -3931,7 +3937,8 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju public void Close() { - m_scene.AttachmentsModule.DeleteAttachmentsFromScene(this, false); + if (!IsChildAgent) + m_scene.AttachmentsModule.DeleteAttachmentsFromScene(this, false); lock (m_knownChildRegions) { @@ -4035,8 +4042,13 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju m_attachments.Clear(); } + /// + /// This is currently just being done for information. + /// public bool ValidateAttachments() { + bool validated = true; + lock (m_attachments) { // Validate @@ -4045,21 +4057,22 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju 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) + validated = false; + } + 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; + + validated = false; } } } - return true; + return validated; } /// @@ -4091,29 +4104,6 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju } } - - 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) @@ -4141,6 +4131,7 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju obj.ignoreControls = (ScriptControlled)controls; obj.eventControls = (ScriptControlled)controls; } + if (pass_on == 1 && accept == 1) { IgnoredControls = ScriptControlled.CONTROL_ZERO; @@ -4161,6 +4152,7 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju scriptedcontrols[Script_item_UUID] = obj; } } + ControllingClient.SendTakeControls(controls, pass_on == 1 ? true : false, true); } @@ -4351,29 +4343,6 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju return(new Vector3(x,y,z)); } - public void SaveChangedAttachments() - { - // Need to copy this list because DetachToInventoryPrep mods it - List attachments = new List(GetAttachments().ToArray()); - - IAttachmentsModule attachmentsModule = m_scene.AttachmentsModule; - if (attachmentsModule != null) - { - foreach (SceneObjectGroup grp in attachments) - { - if (grp.HasGroupChanged) // Resizer scripts? - { - grp.IsAttachment = false; - grp.AbsolutePosition = grp.RootPart.AttachedPos; -// grp.DetachToInventoryPrep(); - attachmentsModule.UpdateKnownItem(ControllingClient, - grp, grp.GetFromItemID(), grp.OwnerID); - grp.IsAttachment = true; - } - } - } - } - private void CheckLandingPoint(ref Vector3 pos) { // Never constrain lures diff --git a/OpenSim/Region/Framework/Scenes/SceneViewer.cs b/OpenSim/Region/Framework/Scenes/SceneViewer.cs index 501487aac9..8a0d288aaf 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) { @@ -176,38 +193,46 @@ 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_updateTimes) + lock (m_pendingObjects) { - m_updateTimes.Clear(); + // 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(); + } } - lock (m_partsUpdateQueue) - { - m_partsUpdateQueue.Clear(); - } - Reset(); } public int GetPendingObjectsCount() { if (m_pendingObjects != null) - return m_pendingObjects.Count; + lock (m_pendingObjects) + return m_pendingObjects.Count; return 0; } diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs index 1ea2329b36..80f198d2d6 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] @@ -103,6 +106,39 @@ 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); + + // 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); + } /// /// Test deleting an object from a scene. diff --git a/OpenSim/Region/Framework/Scenes/UuidGatherer.cs b/OpenSim/Region/Framework/Scenes/UuidGatherer.cs index fdfbc7853f..8d41f000a8 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 @@ -119,11 +120,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) diff --git a/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs b/OpenSim/Region/OptionalModules/World/NPC/Tests/NPCModuleTests.cs index 78296a4e1f..246bc34219 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,21 +50,49 @@ 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() + { + // 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; + } + + [SetUp] + 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(); + + 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); @@ -87,19 +118,54 @@ 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(); + + UUID userId = TestHelpers.ParseTail(0x1); + UserAccountHelpers.CreateUserWithInventory(scene, userId); + ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId); + + 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() { 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); diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 6f341681e0..18c0dd29dc 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -7040,6 +7040,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 (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) return shapeBlock; @@ -7123,8 +7124,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; @@ -7138,6 +7151,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) return; + 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); @@ -7158,8 +7172,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; @@ -7176,8 +7192,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); @@ -7233,6 +7251,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api if (part == null || part.ParentGroup == null || part.ParentGroup.IsDeleted) return; + 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); @@ -7257,8 +7276,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; @@ -7275,8 +7296,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; @@ -7320,8 +7343,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; @@ -7330,7 +7355,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) { @@ -7340,7 +7366,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; @@ -7349,7 +7376,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); @@ -8268,10 +8296,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/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 0c1da47f24..8f450f8988 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -712,9 +712,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); } @@ -750,9 +753,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); } } 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, diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 9cb074aa72..975e9cca76 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -409,7 +409,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_ThreadPool.QueueWorkItem(new WorkItemCallback(this.DoBackup), new Object[] { m_SaveTime }); } + } + public void StartProcessing() + { m_ThreadPool.Start(); } @@ -659,7 +662,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; diff --git a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs index 9c1f1585a1..2c36bf555d 100644 --- a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs @@ -439,14 +439,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; } @@ -510,14 +510,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; } @@ -575,14 +575,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; } @@ -639,14 +639,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; } @@ -698,14 +698,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; } @@ -746,14 +746,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; } 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) 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)); 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; } 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"