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
parent
c2ac5dc358
commit
4f15b8d4e6
|
@ -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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -276,6 +276,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;
|
||||||
|
@ -486,9 +490,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
{
|
{
|
||||||
m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero);
|
m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero);
|
||||||
// CM / XMREngine!!!! Needed to conclude attach event
|
// CM / XMREngine!!!! Needed to conclude attach event
|
||||||
SceneObjectSerializer.ToOriginalXmlFormat(group);
|
//SceneObjectSerializer.ToOriginalXmlFormat(group);
|
||||||
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;
|
||||||
|
@ -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>
|
/// <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>
|
||||||
|
@ -531,12 +523,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
{
|
{
|
||||||
if (grp != null)
|
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)
|
if (!grp.HasGroupChanged)
|
||||||
{
|
{
|
||||||
m_log.WarnFormat("[ATTACHMENTS MODULE]: Save request for {0} which is unchanged", grp.UUID);
|
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());
|
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);
|
||||||
|
|
||||||
|
@ -642,7 +627,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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -719,15 +719,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
|
// If we're rezzing an attachment then don't ask
|
||||||
// AddNewSceneObject() to update the client since
|
// AddNewSceneObject() to update the client since
|
||||||
// we'll be doing that later on. Scheduling more than
|
// we'll be doing that later on. Scheduling more
|
||||||
// one full update during the attachment
|
// than one full update during the attachment
|
||||||
// process causes some clients to fail to display the
|
// process causes some clients to fail to display
|
||||||
// attachment properly.
|
// the attachment properly.
|
||||||
|
// Also, don't persist attachments.
|
||||||
|
m_Scene.AddNewSceneObject(group, false, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
m_Scene.AddNewSceneObject(group, true, false);
|
m_Scene.AddNewSceneObject(group, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
// if attachment we set it's asset id so object updates
|
// if attachment we set it's asset id so object updates
|
||||||
// can reflect that, if not, we set it's position in world.
|
// can reflect that, if not, we set it's position in world.
|
||||||
|
|
|
@ -127,13 +127,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);
|
void UpdateKnownItem(IClientAPI remoteClient, SceneObjectGroup grp, UUID itemID, UUID agentID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,6 +185,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
|
||||||
|
|
|
@ -3255,7 +3255,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_log.Debug("[Scene] Beginning ClientClosed");
|
m_log.Debug("[Scene] Beginning ClientClosed");
|
||||||
m_eventManager.TriggerClientClosed(agentID, this);
|
m_eventManager.TriggerClientClosed(agentID, this);
|
||||||
|
@ -3271,6 +3270,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
m_eventManager.TriggerOnRemovePresence(agentID);
|
m_eventManager.TriggerOnRemovePresence(agentID);
|
||||||
m_log.Debug("[Scene] Finished OnRemovePresence");
|
m_log.Debug("[Scene] Finished OnRemovePresence");
|
||||||
|
|
||||||
|
if (avatar != null && (!avatar.IsChildAgent))
|
||||||
|
avatar.SaveChangedAttachments();
|
||||||
|
|
||||||
ForEachClient(
|
ForEachClient(
|
||||||
delegate(IClientAPI client)
|
delegate(IClientAPI client)
|
||||||
{
|
{
|
||||||
|
|
|
@ -281,7 +281,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!alreadyPersisted)
|
if (attachToBackup && (!alreadyPersisted))
|
||||||
{
|
{
|
||||||
sceneObject.ForceInventoryPersistence();
|
sceneObject.ForceInventoryPersistence();
|
||||||
sceneObject.HasGroupChanged = true;
|
sceneObject.HasGroupChanged = true;
|
||||||
|
@ -304,7 +304,9 @@ 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
|
||||||
|
// attachment
|
||||||
|
if (attachToBackup)
|
||||||
sceneObject.HasGroupChanged = true;
|
sceneObject.HasGroupChanged = true;
|
||||||
|
|
||||||
return AddSceneObject(sceneObject, attachToBackup, sendClientUpdates);
|
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 (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
|
||||||
{
|
{
|
||||||
|
|
|
@ -586,13 +586,15 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
XmlNodeList nodes = doc.GetElementsByTagName("SavedScriptState");
|
XmlNodeList nodes = doc.GetElementsByTagName("SavedScriptState");
|
||||||
if (nodes.Count > 0)
|
if (nodes.Count > 0)
|
||||||
{
|
{
|
||||||
|
if (m_savedScriptState == null)
|
||||||
m_savedScriptState = new Dictionary<UUID, string>();
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4822,7 +4822,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
{
|
{
|
||||||
TaskInventoryItem item = Inventory.GetInventoryItem(itemID);
|
TaskInventoryItem item = Inventory.GetInventoryItem(itemID);
|
||||||
item.OwnerChanged = false;
|
item.OwnerChanged = false;
|
||||||
Inventory.UpdateInventoryItem(item);
|
Inventory.UpdateInventoryItem(item, false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,12 +131,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
return;
|
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();
|
||||||
|
|
||||||
|
@ -158,12 +152,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
return;
|
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();
|
||||||
|
|
||||||
|
@ -216,8 +204,15 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
HasInventoryChanged = true;
|
||||||
m_part.ParentGroup.HasGroupChanged = true;
|
m_part.ParentGroup.HasGroupChanged = true;
|
||||||
|
}
|
||||||
|
|
||||||
IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
|
IList<TaskInventoryItem> items = new List<TaskInventoryItem>(Items.Values);
|
||||||
foreach (TaskInventoryItem item in items)
|
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>
|
/// <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)
|
||||||
{
|
{
|
||||||
m_items.LockItemsForWrite(true);
|
m_items.LockItemsForWrite(true);
|
||||||
|
|
||||||
|
@ -849,8 +849,11 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
m_inventorySerial++;
|
m_inventorySerial++;
|
||||||
if (fireScriptEvents)
|
if (fireScriptEvents)
|
||||||
m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
|
m_part.TriggerScriptChangedEvent(Changed.INVENTORY);
|
||||||
|
if (considerChanged)
|
||||||
|
{
|
||||||
HasInventoryChanged = true;
|
HasInventoryChanged = true;
|
||||||
m_part.ParentGroup.HasGroupChanged = true;
|
m_part.ParentGroup.HasGroupChanged = true;
|
||||||
|
}
|
||||||
m_items.LockItemsForWrite(false);
|
m_items.LockItemsForWrite(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4340,6 +4340,24 @@ if (m_animator.m_jumping) force.Z = m_animator.m_jumpVelocity; // add for ju
|
||||||
return(new Vector3(x,y,z));
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -565,6 +565,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);
|
||||||
|
|
Loading…
Reference in New Issue