Change the way attachments are persisted. Editing a worn attachment will now

save properly, as will the results of a resizer script working. Attachment
positions are no longer saved on each move, but instead are saved once on
logout. Attachment script states are saved as part of the attachment now
when detaching.
viewer-2-initial-appearance
Melanie 2010-11-16 21:01:56 +00:00
parent 56bd42b438
commit 7bb005b0d1
12 changed files with 109 additions and 61 deletions

View File

@ -39,5 +39,6 @@ namespace OpenSim.Framework
void ExtraFromXmlString(string xmlstr); void ExtraFromXmlString(string xmlstr);
string GetStateSnapshot(); string GetStateSnapshot();
void SetState(string xmlstr, IScene s); void SetState(string xmlstr, IScene s);
bool HasGroupChanged { get; set; }
} }
} }

View File

@ -273,6 +273,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (objatt != null) 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; bool tainted = false;
if (AttachmentPt != 0 && AttachmentPt != objatt.GetAttachmentPoint()) if (AttachmentPt != 0 && AttachmentPt != objatt.GetAttachmentPoint())
tainted = true; tainted = true;
@ -470,6 +474,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero);
group.DetachToInventoryPrep(); group.DetachToInventoryPrep();
m_log.Debug("[ATTACHMENTS MODULE]: Saving attachpoint: " + ((uint)group.GetAttachmentPoint()).ToString()); 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); UpdateKnownItem(remoteClient, group, group.GetFromItemID(), group.OwnerID);
m_scene.DeleteSceneObject(group, false); m_scene.DeleteSceneObject(group, false);
return; return;
@ -478,25 +489,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);
}
/// <summary> /// <summary>
/// Update the attachment asset for the new sog details if they have changed. /// Update the attachment asset for the new sog details if they have changed.
/// </summary> /// </summary>
@ -508,7 +500,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
/// <param name="grp"></param> /// <param name="grp"></param>
/// <param name="itemID"></param> /// <param name="itemID"></param>
/// <param name="agentID"></param> /// <param name="agentID"></param>
protected void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID) public void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID)
{ {
if (grp != null) if (grp != null)
{ {
@ -523,7 +515,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
grp.UUID, grp.GetAttachmentPoint()); grp.UUID, grp.GetAttachmentPoint());
string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp);
InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId);
item = m_scene.InventoryService.GetItem(item); item = m_scene.InventoryService.GetItem(item);
@ -617,7 +608,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
// In case it is later dropped again, don't let // In case it is later dropped again, don't let
// it get cleaned up // it get cleaned up
so.RootPart.RemFlag(PrimFlags.TemporaryOnRez); so.RootPart.RemFlag(PrimFlags.TemporaryOnRez);
so.HasGroupChanged = false;
} }
} }
} }

View File

@ -569,12 +569,20 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
{ {
group.RootPart.Flags |= PrimFlags.Phantom; group.RootPart.Flags |= PrimFlags.Phantom;
group.RootPart.IsAttachment = true; group.RootPart.IsAttachment = true;
}
// If we're rezzing an attachment then don't ask AddNewSceneObject() to update the client since // If we're rezzing an attachment then don't ask
// we'll be doing that later on. Scheduling more than one full update during the attachment // AddNewSceneObject() to update the client since
// process causes some clients to fail to display the attachment properly. // we'll be doing that later on. Scheduling more
m_Scene.AddNewSceneObject(group, true, false); // 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);
}
// m_log.InfoFormat("ray end point for inventory rezz is {0} {1} {2} ", RayEnd.X, RayEnd.Y, RayEnd.Z); // m_log.InfoFormat("ray end point for inventory rezz is {0} {1} {2} ", RayEnd.X, RayEnd.Y, RayEnd.Z);
// if attachment we set it's asset id so object updates can reflect that // if attachment we set it's asset id so object updates can reflect that

View File

@ -122,11 +122,20 @@ namespace OpenSim.Region.Framework.Interfaces
void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient); void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient);
/// <summary> /// <summary>
/// Update the position of an attachment /// Update the user inventory with a changed attachment
/// </summary> /// </summary>
/// <param name="client"></param> /// <param name="remoteClient">
/// <param name="sog"></param> /// A <see cref="IClientAPI"/>
/// <param name="pos"></param> /// </param>
void UpdateAttachmentPosition(IClientAPI client, SceneObjectGroup sog, Vector3 pos); /// <param name="grp">
/// A <see cref="SceneObjectGroup"/>
/// </param>
/// <param name="itemID">
/// A <see cref="UUID"/>
/// </param>
/// <param name="agentID">
/// A <see cref="UUID"/>
/// </param>
void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID);
} }
} }

View File

@ -183,6 +183,7 @@ namespace OpenSim.Region.Framework.Interfaces
/// <returns>false if the item did not exist, true if the update occurred successfully</returns> /// <returns>false if the item did not exist, true if the update occurred successfully</returns>
bool UpdateInventoryItem(TaskInventoryItem item); bool UpdateInventoryItem(TaskInventoryItem item);
bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents); bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents);
bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged);
/// <summary> /// <summary>
/// Remove an item from this entity's inventory /// Remove an item from this entity's inventory

View File

@ -3152,7 +3152,6 @@ namespace OpenSim.Region.Framework.Scenes
List<ulong> regions = new List<ulong>(avatar.KnownChildRegionHandles); List<ulong> regions = new List<ulong>(avatar.KnownChildRegionHandles);
regions.Remove(RegionInfo.RegionHandle); regions.Remove(RegionInfo.RegionHandle);
m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); m_sceneGridService.SendCloseChildAgentConnections(agentID, regions);
} }
m_eventManager.TriggerClientClosed(agentID, this); m_eventManager.TriggerClientClosed(agentID, this);
} }
@ -3164,6 +3163,9 @@ namespace OpenSim.Region.Framework.Scenes
m_eventManager.TriggerOnRemovePresence(agentID); m_eventManager.TriggerOnRemovePresence(agentID);
if (avatar != null && (!avatar.IsChildAgent))
avatar.SaveChangedAttachments();
ForEachClient( ForEachClient(
delegate(IClientAPI client) delegate(IClientAPI client)
{ {

View File

@ -259,7 +259,7 @@ namespace OpenSim.Region.Framework.Scenes
protected internal bool AddRestoredSceneObject( protected internal bool AddRestoredSceneObject(
SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates) SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
{ {
if (!alreadyPersisted) if (attachToBackup && (!alreadyPersisted))
{ {
sceneObject.ForceInventoryPersistence(); sceneObject.ForceInventoryPersistence();
sceneObject.HasGroupChanged = true; sceneObject.HasGroupChanged = true;
@ -282,8 +282,10 @@ namespace OpenSim.Region.Framework.Scenes
/// </returns> /// </returns>
protected internal bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates) protected internal bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
{ {
// Ensure that we persist this new scene object // Ensure that we persist this new scene object if it's not an
sceneObject.HasGroupChanged = true; // attachment
if (attachToBackup)
sceneObject.HasGroupChanged = true;
return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates); return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates);
} }
@ -1279,8 +1281,13 @@ namespace OpenSim.Region.Framework.Scenes
{ {
if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0)) if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0))
{ {
if (m_parentScene.AttachmentsModule != null) // Set the new attachment point data in the object
m_parentScene.AttachmentsModule.UpdateAttachmentPosition(remoteClient, group, pos); byte attachmentPoint = group.GetAttachmentPoint();
group.UpdateGroupPosition(pos);
group.RootPart.IsAttachment = false;
group.AbsolutePosition = group.RootPart.AttachedPos;
group.SetAttachmentPoint(attachmentPoint);
group.HasGroupChanged = true;
} }
else else
{ {

View File

@ -491,13 +491,15 @@ namespace OpenSim.Region.Framework.Scenes
XmlNodeList nodes = doc.GetElementsByTagName("SavedScriptState"); XmlNodeList nodes = doc.GetElementsByTagName("SavedScriptState");
if (nodes.Count > 0) if (nodes.Count > 0)
{ {
m_savedScriptState = new Dictionary<UUID, string>(); if (m_savedScriptState == null)
m_savedScriptState = new Dictionary<UUID, string>();
foreach (XmlNode node in nodes) foreach (XmlNode node in nodes)
{ {
if (node.Attributes["UUID"] != null) if (node.Attributes["UUID"] != null)
{ {
UUID itemid = new UUID(node.Attributes["UUID"].Value); UUID itemid = new UUID(node.Attributes["UUID"].Value);
m_savedScriptState.Add(itemid, node.InnerXml); if (itemid != UUID.Zero)
m_savedScriptState[itemid] = node.InnerXml;
} }
} }
} }

View File

@ -127,8 +127,6 @@ namespace OpenSim.Region.Framework.Scenes
if (0 == m_items.Count) if (0 == m_items.Count)
return; return;
HasInventoryChanged = true;
m_part.ParentGroup.HasGroupChanged = true;
IList<TaskInventoryItem> items = GetInventoryItems(); IList<TaskInventoryItem> items = GetInventoryItems();
m_items.Clear(); m_items.Clear();
@ -144,17 +142,6 @@ namespace OpenSim.Region.Framework.Scenes
{ {
lock (Items) lock (Items)
{ {
if (Items.Count == 0)
{
return;
}
HasInventoryChanged = true;
if (m_part.ParentGroup != null)
{
m_part.ParentGroup.HasGroupChanged = true;
}
IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values); IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
Items.Clear(); Items.Clear();
@ -208,8 +195,15 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
HasInventoryChanged = true; // Don't let this set the HasGroupChanged flag for attachments
m_part.ParentGroup.HasGroupChanged = true; // 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;
}
List<TaskInventoryItem> items = GetInventoryItems(); List<TaskInventoryItem> items = GetInventoryItems();
foreach (TaskInventoryItem item in items) foreach (TaskInventoryItem item in items)
{ {
@ -674,13 +668,19 @@ namespace OpenSim.Region.Framework.Scenes
/// <returns>false if the item did not exist, true if the update occurred successfully</returns> /// <returns>false if the item did not exist, true if the update occurred successfully</returns>
public bool UpdateInventoryItem(TaskInventoryItem item) public bool UpdateInventoryItem(TaskInventoryItem item)
{ {
return UpdateInventoryItem(item, true); return UpdateInventoryItem(item, true, true);
} }
public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents) public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents)
{
return UpdateInventoryItem(item, fireScriptEvents, true);
}
public bool UpdateInventoryItem(TaskInventoryItem item, bool fireScriptEvents, bool considerChanged)
{ {
TaskInventoryItem it = GetInventoryItem(item.ItemID); TaskInventoryItem it = GetInventoryItem(item.ItemID);
if (it != null) if (it != null)
{ {
item.ParentID = m_part.UUID; item.ParentID = m_part.UUID;
item.ParentPartID = m_part.UUID; item.ParentPartID = m_part.UUID;
@ -702,9 +702,11 @@ namespace OpenSim.Region.Framework.Scenes
if (fireScriptEvents) if (fireScriptEvents)
m_part.TriggerScriptChangedEvent(Changed.INVENTORY); m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
if (considerChanged)
HasInventoryChanged = true; {
m_part.ParentGroup.HasGroupChanged = true; HasInventoryChanged = true;
m_part.ParentGroup.HasGroupChanged = true;
}
return true; return true;
} }
else else

View File

@ -3746,5 +3746,25 @@ namespace OpenSim.Region.Framework.Scenes
m_reprioritization_called = false; m_reprioritization_called = false;
} }
} }
public void SaveChangedAttachments()
{
// Need to copy this list because DetachToInventoryPrep mods it
List<SceneObjectGroup> attachments = new List<SceneObjectGroup>(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);
}
}
}
}
} }
} }

View File

@ -162,6 +162,11 @@ namespace OpenSim.Server.Handlers.Simulation
return; return;
} }
if (args.ContainsKey("modified"))
sog.HasGroupChanged = args["modified"].AsBoolean();
else
sog.HasGroupChanged = false;
if ((args["state"] != null) && s.AllowScriptCrossings) if ((args["state"] != null) && s.AllowScriptCrossings)
{ {
stateXmlStr = args["state"].AsString(); stateXmlStr = args["state"].AsString();

View File

@ -549,6 +549,7 @@ namespace OpenSim.Services.Connectors.Simulation
OSDMap args = new OSDMap(2); OSDMap args = new OSDMap(2);
args["sog"] = OSD.FromString(sog.ToXml2()); args["sog"] = OSD.FromString(sog.ToXml2());
args["extra"] = OSD.FromString(sog.ExtraToXmlString()); args["extra"] = OSD.FromString(sog.ExtraToXmlString());
args["modified"] = OSD.FromBoolean(sog.HasGroupChanged);
string state = sog.GetStateSnapshot(); string state = sog.GetStateSnapshot();
if (state.Length > 0) if (state.Length > 0)
args["state"] = OSD.FromString(state); args["state"] = OSD.FromString(state);