diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
index 1097efb856..35e5f185bd 100644
--- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs
@@ -97,6 +97,12 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
///
string State { get; set; }
+ ///
+ /// If true then the engine is responsible for persisted state. If false then some other component may
+ /// persist state (e.g. attachments persisting in assets).
+ ///
+ bool StatePersistedHere { get; }
+
///
/// Time the script was last started
///
diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
index 79e4774aba..9498aa880a 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs
@@ -58,6 +58,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ public bool StatePersistedHere { get { return m_AttachedAvatar == UUID.Zero; } }
+
///
/// The current work item if an event for this script is running or waiting to run,
///
@@ -76,7 +78,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
private string m_CurrentEvent = String.Empty;
private bool m_InSelfDelete;
private int m_MaxScriptQueue;
- private bool m_SaveState = true;
+ private bool m_SaveState;
private int m_ControlEventsInQueue;
private int m_LastControlLevel;
private bool m_CollisionInQueue;
@@ -238,6 +240,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
m_postOnRez = postOnRez;
m_AttachedAvatar = Part.ParentGroup.AttachedAvatar;
m_RegionID = Part.ParentGroup.Scene.RegionInfo.RegionID;
+
+ m_SaveState = StatePersistedHere;
+
+// m_log.DebugFormat(
+// "[SCRIPT INSTANCE]: Instantiated script instance {0} (id {1}) in part {2} (id {3}) in object {4} attached avatar {5} in {6}",
+// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, m_AttachedAvatar, Engine.World.Name);
}
///
@@ -339,8 +347,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
return false;
}
- m_SaveState = true;
-
+ // For attachments, XEngine saves the state into a .state file when XEngine.SetXMLState() is called.
string savedState = Path.Combine(m_dataPath, ItemID.ToString() + ".state");
if (File.Exists(savedState))
@@ -389,6 +396,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
m_SaveState = false;
m_startedFromSavedState = true;
}
+
+ // If this script is in an attachment then we no longer need the state file.
+ if (!StatePersistedHere)
+ RemoveState();
}
// else
// {
@@ -984,7 +995,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
(int)m_Script.GetStateEventFlags(State));
if (running)
Start();
- m_SaveState = true;
+
+ m_SaveState = StatePersistedHere;
+
PostEvent(new EventParams("state_entry",
new Object[0], new DetectParams[0]));
}
@@ -1010,7 +1023,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
if (m_CurrentEvent != "state_entry")
{
- m_SaveState = true;
+ m_SaveState = StatePersistedHere;
PostEvent(new EventParams("state_entry",
new Object[0], new DetectParams[0]));
throw new EventAbortException();
@@ -1060,6 +1073,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
return;
}
+// m_log.DebugFormat(
+// "[SCRIPT INSTANCE]: Saving state for script {0} (id {1}) in part {2} (id {3}) in object {4} in {5}",
+// ScriptTask.Name, ScriptTask.ItemID, Part.Name, Part.UUID, Part.ParentGroup.Name, Engine.World.Name);
+
PluginData = AsyncCommandManager.GetSerializationData(Engine, ItemID);
string xml = ScriptSerializer.Serialize(this);
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Tests/XEnginePersistenceTests.cs b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEnginePersistenceTests.cs
new file mode 100644
index 0000000000..5b7e5f7722
--- /dev/null
+++ b/OpenSim/Region/ScriptEngine/XEngine/Tests/XEnginePersistenceTests.cs
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using Nini.Config;
+using NUnit.Framework;
+using OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Region.CoreModules.Avatar.Attachments;
+using OpenSim.Region.CoreModules.Framework.InventoryAccess;
+using OpenSim.Region.Framework.Scenes;
+using OpenSim.Region.ScriptEngine.XEngine;
+using OpenSim.Services.Interfaces;
+using OpenSim.Tests.Common;
+
+namespace OpenSim.Region.ScriptEngine.Tests
+{
+ [TestFixture]
+ public class XEnginePersistenceTests : OpenSimTestCase
+ {
+ private AutoResetEvent m_chatEvent = new AutoResetEvent(false);
+
+ private void OnChatFromWorld(object sender, OSChatMessage oscm)
+ {
+ // Console.WriteLine("Got chat [{0}]", oscm.Message);
+
+ // m_osChatMessageReceived = oscm;
+ m_chatEvent.Set();
+ }
+
+ private void AddCommonConfig(IConfigSource config, List