From: Alan Webb <alan_webb@us.ibm.com>

Changes to enable script state persistence across non-restart
serialization situations (inventory/OAR/attachments)

Also fixing test cases for OAR and IAR so they don't barf with the new code.
0.6.5-rc1
Dr Scofield 2009-04-22 18:09:55 +00:00
parent d455d579d0
commit 7dbcf0570f
5 changed files with 188 additions and 74 deletions

View File

@ -120,6 +120,7 @@ namespace OpenSim.Framework
private UUID _permsGranter; private UUID _permsGranter;
private int _permsMask; private int _permsMask;
private int _type = 0; private int _type = 0;
private UUID _oldID;
public UUID AssetID { public UUID AssetID {
get { get {
@ -220,6 +221,15 @@ namespace OpenSim.Framework
} }
} }
public UUID OldItemID {
get {
return _oldID;
}
set {
_oldID = value;
}
}
public UUID LastOwnerID { public UUID LastOwnerID {
get { get {
return _lastOwnerID; return _lastOwnerID;
@ -327,6 +337,7 @@ namespace OpenSim.Framework
/// <param name="partID">The new part ID to which this item belongs</param> /// <param name="partID">The new part ID to which this item belongs</param>
public void ResetIDs(UUID partID) public void ResetIDs(UUID partID)
{ {
_oldID = _itemID;
_itemID = UUID.Random(); _itemID = UUID.Random();
_parentPartID = partID; _parentPartID = partID;
_parentID = partID; _parentID = partID;

View File

@ -96,6 +96,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
part1.Name = partName; part1.Name = partName;
object1 = new SceneObjectGroup(part1); object1 = new SceneObjectGroup(part1);
scene.AddNewSceneObject(object1, false);
} }
UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060");

View File

@ -201,11 +201,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
Quaternion rotationOffset = new Quaternion(60, 70, 80, 90); Quaternion rotationOffset = new Quaternion(60, 70, 80, 90);
Vector3 offsetPosition = new Vector3(20, 25, 30); Vector3 offsetPosition = new Vector3(20, 25, 30);
SerialiserModule serialiserModule = new SerialiserModule();
ArchiverModule archiverModule = new ArchiverModule();
Scene scene = SceneSetupHelpers.SetupScene();
SceneSetupHelpers.SetupSceneModules(scene, serialiserModule, archiverModule);
SceneObjectPart part1 SceneObjectPart part1
= new SceneObjectPart( = new SceneObjectPart(
UUID.Zero, shape, groupPosition, rotationOffset, offsetPosition); UUID.Zero, shape, groupPosition, rotationOffset, offsetPosition);
part1.Name = part1Name; part1.Name = part1Name;
SceneObjectGroup object1 = new SceneObjectGroup(part1); SceneObjectGroup object1 = new SceneObjectGroup(part1);
scene.AddNewSceneObject(object1, false);
string object1FileName = string.Format( string object1FileName = string.Format(
"{0}_{1:000}-{2:000}-{3:000}__{4}.xml", "{0}_{1:000}-{2:000}-{3:000}__{4}.xml",
@ -218,11 +225,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
SerialiserModule serialiserModule = new SerialiserModule(); // SerialiserModule serialiserModule = new SerialiserModule();
ArchiverModule archiverModule = new ArchiverModule(); // ArchiverModule archiverModule = new ArchiverModule();
Scene scene = SceneSetupHelpers.SetupScene(); // Scene scene = SceneSetupHelpers.SetupScene();
SceneSetupHelpers.SetupSceneModules(scene, serialiserModule, archiverModule); // SceneSetupHelpers.SetupSceneModules(scene, serialiserModule, archiverModule);
archiverModule.DearchiveRegion(archiveReadStream); archiverModule.DearchiveRegion(archiveReadStream);

View File

@ -169,6 +169,8 @@ namespace OpenSim.Region.Framework.Scenes
private bool m_scriptListens_atTarget = false; private bool m_scriptListens_atTarget = false;
private bool m_scriptListens_notAtTarget = false; private bool m_scriptListens_notAtTarget = false;
internal Dictionary<UUID, string> m_savedScriptState = null;
#region Properties #region Properties
/// <summary> /// <summary>
@ -423,6 +425,7 @@ namespace OpenSim.Region.Framework.Scenes
/// </param> /// </param>
public SceneObjectGroup(UUID fromUserInventoryItemID, string xmlData, bool isOriginalXmlFormat) public SceneObjectGroup(UUID fromUserInventoryItemID, string xmlData, bool isOriginalXmlFormat)
{ {
if (!isOriginalXmlFormat) if (!isOriginalXmlFormat)
throw new Exception("This constructor must specify the xml is in OpenSim's original format"); throw new Exception("This constructor must specify the xml is in OpenSim's original format");
@ -436,50 +439,60 @@ namespace OpenSim.Region.Framework.Scenes
// Handle Nested <UUID><UUID> property // Handle Nested <UUID><UUID> property
xmlData = xmlData.Replace("<Guid><Guid>", "<UUID><Guid>"); xmlData = xmlData.Replace("<Guid><Guid>", "<UUID><Guid>");
xmlData = xmlData.Replace("</Guid></Guid>", "</Guid></UUID>"); xmlData = xmlData.Replace("</Guid></Guid>", "</Guid></UUID>");
StringReader sr = new StringReader(xmlData);
XmlTextReader reader = new XmlTextReader(sr);
try try
{ {
reader.Read();
reader.ReadStartElement("SceneObjectGroup"); StringReader sr;
reader.ReadStartElement("RootPart"); XmlTextReader reader;
XmlNodeList parts;
XmlDocument doc;
int linkNum;
doc = new XmlDocument();
doc.LoadXml(xmlData);
parts = doc.GetElementsByTagName("RootPart");
if(parts.Count == 0)
{
throw new Exception("[SCENE] Invalid Xml format - no root part");
}
else
{
sr = new StringReader(parts[0].InnerXml);
reader = new XmlTextReader(sr);
SetRootPart(SceneObjectPart.FromXml(fromUserInventoryItemID, reader)); SetRootPart(SceneObjectPart.FromXml(fromUserInventoryItemID, reader));
reader.Close();
sr.Close();
}
reader.ReadEndElement(); parts = doc.GetElementsByTagName("Part");
while (reader.Read()) for (int i=0; i<parts.Count ; i++)
{ {
switch (reader.NodeType) sr = new StringReader(parts[i].InnerXml);
{ reader = new XmlTextReader(sr);
case XmlNodeType.Element:
if (reader.Name == "Part")
{
reader.Read();
SceneObjectPart part = SceneObjectPart.FromXml(reader); SceneObjectPart part = SceneObjectPart.FromXml(reader);
linkNum = part.LinkNum;
// We reset the link number in order to make sure that the persisted linkset order is
int linkNum = part.LinkNum;
AddPart(part); AddPart(part);
part.LinkNum = linkNum; part.LinkNum = linkNum;
part.TrimPermissions(); part.TrimPermissions();
part.StoreUndoState(); part.StoreUndoState();
reader.Close();
sr.Close();
} }
break;
case XmlNodeType.EndElement: // Script state may, or may not, exist. Not having any, is NOT
break; // ever a problem.
LoadScriptState(doc);
} }
} catch (Exception e)
}
catch (XmlException e)
{ {
m_log.ErrorFormat("[SCENE]: Deserialization of xml failed with {0}. xml was {1}", e, xmlData); m_log.ErrorFormat("[SCENE]: Deserialization of xml failed with {0}. xml was {1}", e, xmlData);
} }
reader.Close();
sr.Close();
//m_log.DebugFormat("[SOG]: Finished deserialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time); //m_log.DebugFormat("[SOG]: Finished deserialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time);
} }
@ -493,6 +506,7 @@ namespace OpenSim.Region.Framework.Scenes
protected void SetFromXml(string xmlData) protected void SetFromXml(string xmlData)
{ {
//m_log.DebugFormat("[SOG]: Starting deserialization of SOG"); //m_log.DebugFormat("[SOG]: Starting deserialization of SOG");
//int time = System.Environment.TickCount; //int time = System.Environment.TickCount;
@ -504,42 +518,46 @@ namespace OpenSim.Region.Framework.Scenes
xmlData = xmlData.Replace("<Guid><Guid>", "<UUID><Guid>"); xmlData = xmlData.Replace("<Guid><Guid>", "<UUID><Guid>");
xmlData = xmlData.Replace("</Guid></Guid>", "</Guid></UUID>"); xmlData = xmlData.Replace("</Guid></Guid>", "</Guid></UUID>");
StringReader sr = new StringReader(xmlData); try
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlData);
XmlNodeList parts = doc.GetElementsByTagName("SceneObjectPart");
// Process the root part first
if(parts.Count > 0)
{
StringReader sr = new StringReader(parts[0].OuterXml);
XmlTextReader reader = new XmlTextReader(sr); XmlTextReader reader = new XmlTextReader(sr);
reader.Read();
reader.ReadStartElement("SceneObjectGroup");
SetRootPart(CreatePartFromXml(reader)); SetRootPart(CreatePartFromXml(reader));
reader.Close();
sr.Close();
}
reader.Read(); // Then deal with the rest
bool more = true; for(int i=1; i<parts.Count; i++)
while (more)
{
switch (reader.NodeType)
{
case XmlNodeType.Element:
if (reader.Name == "SceneObjectPart")
{ {
StringReader sr = new StringReader(parts[i].OuterXml);
XmlTextReader reader = new XmlTextReader(sr);
SceneObjectPart part = CreatePartFromXml(reader); SceneObjectPart part = CreatePartFromXml(reader);
AddPart(part); AddPart(part);
part.StoreUndoState(); part.StoreUndoState();
}
else
{
m_log.Warn("found unexpected element: " + reader.Name);
reader.Read();
}
break;
case XmlNodeType.EndElement:
reader.Read();
break;
}
more = !reader.EOF;
}
reader.Close(); reader.Close();
sr.Close(); sr.Close();
}
// Script state may, or may not, exist. Not having any, is NOT
// ever a problem.
LoadScriptState(doc);
}
catch (Exception e)
{
m_log.ErrorFormat("[SCENE]: Deserialization of xml failed with {0}. xml was {1}", e, xmlData);
}
//m_log.DebugFormat("[SOG]: Finished deserialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time); //m_log.DebugFormat("[SOG]: Finished deserialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time);
} }
@ -567,6 +585,23 @@ namespace OpenSim.Region.Framework.Scenes
{ {
} }
private void LoadScriptState(XmlDocument doc)
{
XmlNodeList nodes = doc.GetElementsByTagName("SavedScriptState");
if(nodes.Count > 0)
{
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);
}
}
}
}
public void SetFromAssetID(UUID AssetId) public void SetFromAssetID(UUID AssetId)
{ {
lock (m_parts) lock (m_parts)
@ -748,8 +783,9 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
writer.WriteEndElement(); writer.WriteEndElement(); // OtherParts
writer.WriteEndElement(); SaveScriptedState(writer);
writer.WriteEndElement(); // SceneObjectGroup
//m_log.DebugFormat("[SOG]: Finished serialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time); //m_log.DebugFormat("[SOG]: Finished serialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time);
} }
@ -769,6 +805,7 @@ namespace OpenSim.Region.Framework.Scenes
public void ToXml2(XmlTextWriter writer) public void ToXml2(XmlTextWriter writer)
{ {
//m_log.DebugFormat("[SOG]: Starting serialization of SOG {0} to XML2", Name); //m_log.DebugFormat("[SOG]: Starting serialization of SOG {0} to XML2", Name);
//int time = System.Environment.TickCount; //int time = System.Environment.TickCount;
@ -787,9 +824,48 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
writer.WriteEndElement(); writer.WriteEndElement(); // End of OtherParts
writer.WriteEndElement(); SaveScriptedState(writer);
writer.WriteEndElement(); // End of SceneObjectGroup
//m_log.DebugFormat("[SOG]: Finished serialization of SOG {0} to XML2, {1}ms", Name, System.Environment.TickCount - time); //m_log.DebugFormat("[SOG]: Finished serialization of SOG {0} to XML2, {1}ms", Name, System.Environment.TickCount - time);
}
private void SaveScriptedState(XmlTextWriter writer)
{
XmlDocument doc = new XmlDocument();
Dictionary<UUID,string> states = new Dictionary<UUID,string>();
// Capture script state while holding the lock
lock (m_parts)
{
foreach (SceneObjectPart part in m_parts.Values)
{
Dictionary<UUID,string> pstates = part.Inventory.GetScriptStates();
foreach (UUID itemid in pstates.Keys)
{
states.Add(itemid, pstates[itemid]);
}
}
}
if(states.Count > 0)
{
// Now generate the necessary XML wrappings
writer.WriteStartElement(String.Empty, "GroupScriptStates", String.Empty);
foreach(UUID itemid in states.Keys)
{
doc.LoadXml(states[itemid]);
writer.WriteStartElement(String.Empty, "SavedScriptState", String.Empty);
writer.WriteAttributeString(String.Empty, "UUID", String.Empty, itemid.ToString());
writer.WriteRaw(doc.DocumentElement.OuterXml); // Writes ScriptState element
writer.WriteEndElement(); // End of SavedScriptState
}
writer.WriteEndElement(); // End of GroupScriptStates
}
} }
/// <summary> /// <summary>

View File

@ -26,6 +26,7 @@
*/ */
using System; using System;
using System.IO;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using OpenMetaverse; using OpenMetaverse;
@ -264,6 +265,8 @@ namespace OpenSim.Region.Framework.Scenes
} }
else else
{ {
if(m_part.ParentGroup.m_savedScriptState != null)
RestoreSavedScriptState(item.OldItemID, item.ItemID);
m_items[item.ItemID].PermsMask = 0; m_items[item.ItemID].PermsMask = 0;
m_items[item.ItemID].PermsGranter = UUID.Zero; m_items[item.ItemID].PermsGranter = UUID.Zero;
string script = Utils.BytesToString(asset.Data); string script = Utils.BytesToString(asset.Data);
@ -276,6 +279,22 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
static System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
private void RestoreSavedScriptState(UUID oldID, UUID newID)
{
if(m_part.ParentGroup.m_savedScriptState.ContainsKey(oldID))
{
string fpath = Path.Combine("ScriptEngines/"+m_part.ParentGroup.Scene.RegionInfo.RegionID.ToString(),
newID.ToString()+".state");
FileStream fs = File.Create(fpath);
Byte[] buffer = enc.GetBytes(m_part.ParentGroup.m_savedScriptState[oldID]);
fs.Write(buffer,0,buffer.Length);
fs.Close();
m_part.ParentGroup.m_savedScriptState.Remove(oldID);
}
}
/// <summary> /// <summary>
/// Start a script which is in this prim's inventory. /// Start a script which is in this prim's inventory.
/// </summary> /// </summary>