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.
avinationmerge
Melanie 2010-11-16 20:44:39 +01:00
parent c2ac5dc358
commit 4f15b8d4e6
13 changed files with 105 additions and 69 deletions

View File

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

View File

@ -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);
}
/// <summary>
/// Update the attachment asset for the new sog details if they have changed.
/// </summary>
@ -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;
}
}
}

View File

@ -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.

View File

@ -127,13 +127,20 @@ namespace OpenSim.Region.Framework.Interfaces
void ShowDetachInUserInventory(UUID itemID, IClientAPI remoteClient);
/// <summary>
/// Update the position of an attachment
/// Update the user inventory with a changed attachment
/// </summary>
/// <param name="client"></param>
/// <param name="sog"></param>
/// <param name="pos"></param>
void UpdateAttachmentPosition(IClientAPI client, SceneObjectGroup sog, Vector3 pos);
/// <param name="remoteClient">
/// A <see cref="IClientAPI"/>
/// </param>
/// <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

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

View File

@ -3255,7 +3255,6 @@ namespace OpenSim.Region.Framework.Scenes
List<ulong> regions = new List<ulong>(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)
{

View File

@ -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
/// </returns>
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
{

View File

@ -586,13 +586,15 @@ namespace OpenSim.Region.Framework.Scenes
XmlNodeList nodes = doc.GetElementsByTagName("SavedScriptState");
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)
{
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;
}
}
}

View File

@ -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);
}
}
}

View File

@ -131,12 +131,6 @@ namespace OpenSim.Region.Framework.Scenes
return;
}
HasInventoryChanged = true;
if (m_part.ParentGroup != null)
{
m_part.ParentGroup.HasGroupChanged = true;
}
IList<TaskInventoryItem> items = new List<TaskInventoryItem>(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<TaskInventoryItem> items = new List<TaskInventoryItem>(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<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
foreach (TaskInventoryItem item in items)
{
@ -824,10 +819,15 @@ namespace OpenSim.Region.Framework.Scenes
/// <returns>false if the item did not exist, true if the update occurred successfully</returns>
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;
}

View File

@ -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<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;
}
if (args.ContainsKey("modified"))
sog.HasGroupChanged = args["modified"].AsBoolean();
else
sog.HasGroupChanged = false;
if ((args["state"] != null) && s.AllowScriptCrossings)
{
stateXmlStr = args["state"].AsString();

View File

@ -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);