diff --git a/OpenSim/Framework/ISceneObject.cs b/OpenSim/Framework/ISceneObject.cs index 51479014cd..18631f17b1 100644 --- a/OpenSim/Framework/ISceneObject.cs +++ b/OpenSim/Framework/ISceneObject.cs @@ -39,5 +39,6 @@ namespace OpenSim.Framework void ExtraFromXmlString(string xmlstr); string GetStateSnapshot(); void SetState(string xmlstr, IScene s); + bool HasGroupChanged { get; set; } } } diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 929db21f71..fc92fc3df3 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -276,6 +276,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (objatt != null) { + // Loading the inventory from XML will have set this, but + // there is no way the object could have changed yet, + // since scripts aren't running yet. So, clear it here. + objatt.HasGroupChanged = false; bool tainted = false; if (AttachmentPt != 0 && AttachmentPt != objatt.GetAttachmentPoint()) tainted = true; @@ -486,9 +490,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); // CM / XMREngine!!!! Needed to conclude attach event - SceneObjectSerializer.ToOriginalXmlFormat(group); + //SceneObjectSerializer.ToOriginalXmlFormat(group); group.DetachToInventoryPrep(); m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString()); + + // If an item contains scripts, it's always changed. + // This ensures script state is saved on detach + foreach (SceneObjectPart p in group.Parts) + if (p.Inventory.ContainsScripts()) + group.HasGroupChanged = true; + UpdateKnownItem(remoteClient, group, group.GetFromItemID(), group.OwnerID); m_scene.DeleteSceneObject(group, false); return; @@ -497,25 +508,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } } - public void UpdateAttachmentPosition(IClientAPI client, SceneObjectGroup sog, Vector3 pos) - { - // If this is an attachment, then we need to save the modified - // object back into the avatar's inventory. First we save the - // attachment point information, then we update the relative - // positioning (which caused this method to get driven in the - // first place. Then we have to mark the object as NOT an - // attachment. This is necessary in order to correctly save - // and retrieve GroupPosition information for the attachment. - // Then we save the asset back into the appropriate inventory - // entry. Finally, we restore the object's attachment status. - byte attachmentPoint = sog.GetAttachmentPoint(); - sog.UpdateGroupPosition(pos); - sog.RootPart.IsAttachment = false; - sog.AbsolutePosition = sog.RootPart.AttachedPos; - UpdateKnownItem(client, sog, sog.GetFromItemID(), sog.OwnerID); - sog.SetAttachmentPoint(attachmentPoint); - } - /// /// Update the attachment asset for the new sog details if they have changed. /// @@ -531,12 +523,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { if (grp != null) { - // If an item contains scripts, it's always changed. - // This ensures script state is saved on detach - foreach (SceneObjectPart p in grp.Parts) - if (p.Inventory.ContainsScripts()) - grp.HasGroupChanged = true; - if (!grp.HasGroupChanged) { m_log.WarnFormat("[ATTACHMENTS MODULE]: Save request for {0} which is unchanged", grp.UUID); @@ -548,7 +534,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments grp.UUID, grp.GetAttachmentPoint()); string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); - InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); item = m_scene.InventoryService.GetItem(item); @@ -642,7 +627,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // In case it is later dropped again, don't let // it get cleaned up so.RootPart.RemFlag(PrimFlags.TemporaryOnRez); - so.HasGroupChanged = false; } } } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 0700aa55f5..2e3db48558 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -719,15 +719,20 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { group.RootPart.Flags |= PrimFlags.Phantom; group.RootPart.IsAttachment = true; - } - // If we're rezzing an attachment then don't ask - // AddNewSceneObject() to update the client since - // we'll be doing that later on. Scheduling more than - // one full update during the attachment - // process causes some clients to fail to display the - // attachment properly. - m_Scene.AddNewSceneObject(group, true, false); + // If we're rezzing an attachment then don't ask + // AddNewSceneObject() to update the client since + // we'll be doing that later on. Scheduling more + // than one full update during the attachment + // process causes some clients to fail to display + // the attachment properly. + // Also, don't persist attachments. + m_Scene.AddNewSceneObject(group, false, false); + } + else + { + m_Scene.AddNewSceneObject(group, true, false); + } // if attachment we set it's asset id so object updates // can reflect that, if not, we set it's position in world. diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index 1d9aeb96f1..788f42b494 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -127,13 +127,20 @@ namespace OpenSim.Region.Framework.Interfaces void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient); /// - /// Update the position of an attachment + /// Update the user inventory with a changed attachment /// - /// - /// - /// - void UpdateAttachmentPosition(IClientAPI client, SceneObjectGroup sog, Vector3 pos); - + /// + /// A + /// + /// + /// A + /// + /// + /// A + /// + /// + /// A + /// void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID); } } diff --git a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs index 59ce090a31..ed40da9609 100644 --- a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs +++ b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs @@ -185,6 +185,7 @@ namespace OpenSim.Region.Framework.Interfaces /// false if the item did not exist, true if the update occurred successfully bool UpdateInventoryItem(TaskInventoryItem item); bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents); + bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged); /// /// Remove an item from this entity's inventory diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index dd06be2df2..c4639c3716 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -3255,7 +3255,6 @@ namespace OpenSim.Region.Framework.Scenes List regions = new List(avatar.KnownChildRegionHandles); regions.Remove(RegionInfo.RegionHandle); m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); - } m_log.Debug("[Scene] Beginning ClientClosed"); m_eventManager.TriggerClientClosed(agentID, this); @@ -3271,6 +3270,9 @@ namespace OpenSim.Region.Framework.Scenes m_eventManager.TriggerOnRemovePresence(agentID); m_log.Debug("[Scene] Finished OnRemovePresence"); + if (avatar != null && (!avatar.IsChildAgent)) + avatar.SaveChangedAttachments(); + ForEachClient( delegate(IClientAPI client) { diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index a4621331d8..b2d9358c8e 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -281,7 +281,7 @@ namespace OpenSim.Region.Framework.Scenes } } - if (!alreadyPersisted) + if (attachToBackup && (!alreadyPersisted)) { sceneObject.ForceInventoryPersistence(); sceneObject.HasGroupChanged = true; @@ -304,8 +304,10 @@ namespace OpenSim.Region.Framework.Scenes /// protected internal bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) { - // Ensure that we persist this new scene object - sceneObject.HasGroupChanged = true; + // Ensure that we persist this new scene object if it's not an + // attachment + if (attachToBackup) + sceneObject.HasGroupChanged = true; return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates); } @@ -1342,8 +1344,13 @@ namespace OpenSim.Region.Framework.Scenes { if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0)) { - if (m_parentScene.AttachmentsModule != null) - m_parentScene.AttachmentsModule.UpdateAttachmentPosition(remoteClient, group, pos); + // Set the new attachment point data in the object + byte attachmentPoint = group.GetAttachmentPoint(); + group.UpdateGroupPosition(pos); + group.RootPart.IsAttachment = false; + group.AbsolutePosition = group.RootPart.AttachedPos; + group.SetAttachmentPoint(attachmentPoint); + group.HasGroupChanged = true; } else { diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 79f71624aa..ee08072c29 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -586,13 +586,15 @@ namespace OpenSim.Region.Framework.Scenes XmlNodeList nodes = doc.GetElementsByTagName("SavedScriptState"); if (nodes.Count > 0) { - m_savedScriptState = new Dictionary(); + if (m_savedScriptState == null) + m_savedScriptState = new Dictionary(); foreach (XmlNode node in nodes) { if (node.Attributes["UUID"] != null) { UUID itemid = new UUID(node.Attributes["UUID"].Value); - m_savedScriptState.Add(itemid, node.InnerXml); + if (itemid != UUID.Zero) + m_savedScriptState[itemid] = node.InnerXml; } } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index be3e87f552..b615d42cc3 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -4822,7 +4822,7 @@ namespace OpenSim.Region.Framework.Scenes { TaskInventoryItem item = Inventory.GetInventoryItem(itemID); item.OwnerChanged = false; - Inventory.UpdateInventoryItem(item); + Inventory.UpdateInventoryItem(item, false, false); } } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 522f75e0c8..8fcfcc5e75 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -131,12 +131,6 @@ namespace OpenSim.Region.Framework.Scenes return; } - HasInventoryChanged = true; - if (m_part.ParentGroup != null) - { - m_part.ParentGroup.HasGroupChanged = true; - } - IList items = new List(Items.Values); Items.Clear(); @@ -158,12 +152,6 @@ namespace OpenSim.Region.Framework.Scenes return; } - HasInventoryChanged = true; - if (m_part.ParentGroup != null) - { - m_part.ParentGroup.HasGroupChanged = true; - } - IList items = new List(Items.Values); Items.Clear(); @@ -216,8 +204,15 @@ namespace OpenSim.Region.Framework.Scenes return; } - HasInventoryChanged = true; - m_part.ParentGroup.HasGroupChanged = true; + // Don't let this set the HasGroupChanged flag for attachments + // as this happens during rez and we don't want a new asset + // for each attachment each time + if (!m_part.ParentGroup.RootPart.IsAttachment) + { + HasInventoryChanged = true; + m_part.ParentGroup.HasGroupChanged = true; + } + IList items = new List(Items.Values); foreach (TaskInventoryItem item in items) { @@ -824,10 +819,15 @@ namespace OpenSim.Region.Framework.Scenes /// false if the item did not exist, true if the update occurred successfully public bool UpdateInventoryItem(TaskInventoryItem item) { - return UpdateInventoryItem(item, true); + return UpdateInventoryItem(item, true, true); } public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents) + { + return UpdateInventoryItem(item, fireScriptEvents, true); + } + + public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged) { m_items.LockItemsForWrite(true); @@ -849,8 +849,11 @@ namespace OpenSim.Region.Framework.Scenes m_inventorySerial++; if (fireScriptEvents) m_part.TriggerScriptChangedEvent(Changed.INVENTORY); - HasInventoryChanged = true; - m_part.ParentGroup.HasGroupChanged = true; + if (considerChanged) + { + HasInventoryChanged = true; + m_part.ParentGroup.HasGroupChanged = true; + } m_items.LockItemsForWrite(false); return true; } diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index cc9c445c52..dfaf06d6df 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -4340,6 +4340,24 @@ 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(Attachments.ToArray()); + IAttachmentsModule attachmentsModule = m_scene.AttachmentsModule; + if (attachmentsModule != null) + { + foreach (SceneObjectGroup grp in attachments) + { + if (grp.HasGroupChanged) // Resizer scripts? + { + grp.DetachToInventoryPrep(); + attachmentsModule.UpdateKnownItem(ControllingClient, + grp, grp.GetFromItemID(), grp.OwnerID); + } + } + } + } } } diff --git a/OpenSim/Server/Handlers/Simulation/ObjectHandlers.cs b/OpenSim/Server/Handlers/Simulation/ObjectHandlers.cs index 33e5aa6b05..04ff83f9f3 100644 --- a/OpenSim/Server/Handlers/Simulation/ObjectHandlers.cs +++ b/OpenSim/Server/Handlers/Simulation/ObjectHandlers.cs @@ -162,6 +162,11 @@ namespace OpenSim.Server.Handlers.Simulation return; } + if (args.ContainsKey("modified")) + sog.HasGroupChanged = args["modified"].AsBoolean(); + else + sog.HasGroupChanged = false; + if ((args["state"] != null) && s.AllowScriptCrossings) { stateXmlStr = args["state"].AsString(); @@ -243,4 +248,4 @@ namespace OpenSim.Server.Handlers.Simulation } } -} \ No newline at end of file +} diff --git a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs index 0626ebea05..1730b95225 100644 --- a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs @@ -565,6 +565,7 @@ namespace OpenSim.Services.Connectors.Simulation OSDMap args = new OSDMap(2); args["sog"] = OSD.FromString(sog.ToXml2()); args["extra"] = OSD.FromString(sog.ExtraToXmlString()); + args["modified"] = OSD.FromBoolean(sog.HasGroupChanged); string state = sog.GetStateSnapshot(); if (state.Length > 0) args["state"] = OSD.FromString(state);