diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
index f073c4abce..31e8a2e4cd 100644
--- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
@@ -28,6 +28,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
+using System.IO;
using System.Xml;
using log4net;
using Mono.Addins;
@@ -248,7 +249,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
}
}
- public void DeRezAttachments(IScenePresence sp, bool saveChanged, bool saveAllScripted)
+ public void DeRezAttachments(IScenePresence sp)
{
if (!Enabled)
return;
@@ -259,18 +260,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
{
foreach (SceneObjectGroup so in sp.GetAttachments())
{
- // We can only remove the script instances from the script engine after we've retrieved their xml state
- // when we update the attachment item.
- m_scene.DeleteSceneObject(so, false, false);
-
- if (saveChanged || saveAllScripted)
- {
- so.IsAttachment = false;
- so.AbsolutePosition = so.RootPart.AttachedPos;
- UpdateKnownItem(sp, so, saveAllScripted);
- }
-
- so.RemoveScriptInstances(true);
+ UpdateDetachedObject(sp, so);
}
sp.ClearAttachments();
@@ -597,7 +587,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
///
///
///
- private void UpdateKnownItem(IScenePresence sp, SceneObjectGroup grp, bool saveAllScripted)
+ private void UpdateKnownItem(IScenePresence sp, SceneObjectGroup grp, string scriptedState)
{
// Saving attachments for NPCs messes them up for the real owner!
INPCModule module = m_scene.RequestModuleInterface();
@@ -607,13 +597,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return;
}
- if (grp.HasGroupChanged || (saveAllScripted && grp.ContainsScripts()))
+ if (grp.HasGroupChanged)
{
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}",
// grp.UUID, grp.AttachmentPoint);
- string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp);
+ string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp, scriptedState);
InventoryItemBase item = new InventoryItemBase(grp.FromItemID, sp.UUID);
item = m_scene.InventoryService.GetItem(item);
@@ -750,6 +740,60 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return newItem;
}
+ private string GetObjectScriptStates(SceneObjectGroup grp)
+ {
+ using (StringWriter sw = new StringWriter())
+ {
+ using (XmlTextWriter writer = new XmlTextWriter(sw))
+ {
+ grp.SaveScriptedState(writer);
+ }
+
+ return sw.ToString();
+ }
+ }
+
+ private void UpdateDetachedObject(IScenePresence sp, SceneObjectGroup so)
+ {
+ // Don't save attachments for HG visitors, it
+ // messes up their inventory. When a HG visitor logs
+ // out on a foreign grid, their attachments will be
+ // reloaded in the state they were in when they left
+ // the home grid. This is best anyway as the visited
+ // grid may use an incompatible script engine.
+ bool saveChanged
+ = sp.PresenceType != PresenceType.Npc
+ && (m_scene.UserManagementModule == null
+ || m_scene.UserManagementModule.IsLocalGridUser(sp.UUID));
+
+ // Scripts MUST be snapshotted before the object is
+ // removed from the scene because doing otherwise will
+ // clobber the run flag
+ string scriptedState = GetObjectScriptStates(so);
+
+ // Remove the object from the scene so no more updates
+ // are sent. Doing this before the below changes will ensure
+ // updates can't cause "HUD artefacts"
+ m_scene.DeleteSceneObject(so, false, false);
+
+ // Prepare sog for storage
+ so.AttachedAvatar = UUID.Zero;
+ so.RootPart.SetParentLocalId(0);
+ so.IsAttachment = false;
+
+ if (saveChanged)
+ {
+ // We cannot use AbsolutePosition here because that would
+ // attempt to cross the prim as it is detached
+ so.ForEachPart(x => { x.GroupPosition = so.RootPart.AttachedPos; });
+
+ UpdateKnownItem(sp, so, scriptedState);
+ }
+
+ // Now, remove the scripts
+ so.RemoveScriptInstances(true);
+ }
+
private void DetachSingleAttachmentToInvInternal(IScenePresence sp, SceneObjectGroup so)
{
// m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name);
@@ -757,22 +801,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
m_scene.EventManager.TriggerOnAttach(so.LocalId, so.FromItemID, UUID.Zero);
sp.RemoveAttachment(so);
- // Prepare sog for storage
- so.AttachedAvatar = UUID.Zero;
- so.RootPart.SetParentLocalId(0);
- so.IsAttachment = false;
-
- // We cannot use AbsolutePosition here because that would
- // attempt to cross the prim as it is detached
- so.ForEachPart(x => { x.GroupPosition = so.RootPart.AttachedPos; });
-
- UpdateKnownItem(sp, so, true);
-
- // This MUST happen AFTER serialization because it will
- // either stop or remove the scripts. Both will cause scripts
- // to be serialized in a stopped state with the true run
- // state already lost.
- m_scene.DeleteSceneObject(so, false, true);
+ UpdateDetachedObject(sp, so);
}
protected SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
index 410eda05fa..11a13e1097 100644
--- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs
@@ -66,7 +66,7 @@ namespace OpenSim.Region.Framework.Interfaces
/// The presence closing
/// Save changed attachments.
/// Save attachments with scripts even if they haven't changed.
- void DeRezAttachments(IScenePresence sp, bool saveChanged, bool saveAllScripted);
+ void DeRezAttachments(IScenePresence sp);
///
/// Delete all the presence's attachments from the scene
diff --git a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs
index e6b926ce8c..3f68ee02ec 100644
--- a/OpenSim/Region/Framework/Interfaces/IScenePresence.cs
+++ b/OpenSim/Region/Framework/Interfaces/IScenePresence.cs
@@ -40,6 +40,8 @@ namespace OpenSim.Region.Framework.Interfaces
///
public interface IScenePresence : ISceneAgent
{
+ PresenceType PresenceType { get; }
+
///
/// Copy of the script states while the agent is in transit. This state may
/// need to be placed back in case of transfer fail.
@@ -83,4 +85,4 @@ namespace OpenSim.Region.Framework.Interfaces
void RemoveAttachment(SceneObjectGroup gobj);
void ClearAttachments();
}
-}
\ No newline at end of file
+}
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index f5018283c7..ad9e91d7b9 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -3461,17 +3461,7 @@ namespace OpenSim.Region.Framework.Scenes
{
if (AttachmentsModule != null)
{
- // Don't save attachments for HG visitors, it
- // messes up their inventory. When a HG visitor logs
- // out on a foreign grid, their attachments will be
- // reloaded in the state they were in when they left
- // the home grid. This is best anyway as the visited
- // grid may use an incompatible script engine.
- bool saveChanged
- = avatar.PresenceType != PresenceType.Npc
- && (UserManagementModule == null || UserManagementModule.IsLocalGridUser(avatar.UUID));
-
- AttachmentsModule.DeRezAttachments(avatar, saveChanged, false);
+ AttachmentsModule.DeRezAttachments(avatar);
}
ForEachClient(
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
index 2372d6ba93..0d292e7d95 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
@@ -151,6 +151,24 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
ToOriginalXmlFormat(sceneObject, writer, doScriptStates, false);
}
+ public static string ToOriginalXmlFormat(SceneObjectGroup sceneObject, string scriptedState)
+ {
+ using (StringWriter sw = new StringWriter())
+ {
+ using (XmlTextWriter writer = new XmlTextWriter(sw))
+ {
+ writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty);
+
+ ToOriginalXmlFormat(sceneObject, writer, false, true);
+
+ writer.WriteRaw(scriptedState);
+
+ writer.WriteEndElement();
+ }
+ return sw.ToString();
+ }
+ }
+
///
/// Serialize a scene object to the original xml format
///