From 6e3367d68ca6e0e632078dc02f52b03bd034afce Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Wed, 27 Aug 2008 22:38:36 +0000 Subject: Refactor XScriptInstance to IScriptInstance and move into Shared/. Now engines that want to use the XEngine's instance handling and state persistence can do so. IScriptInstance is optional, but it does require the SmartThreadPool if it is used. --- .../ScriptEngine/Interfaces/IScriptEngine.cs | 3 + .../ScriptEngine/Interfaces/IScriptInstance.cs | 81 ++ .../ScriptEngine/Shared/Instance/ScriptInstance.cs | 660 ++++++++++++ .../Shared/Instance/ScriptSerializer.cs | 461 +++++++++ OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 1076 +------------------- 5 files changed, 1233 insertions(+), 1048 deletions(-) create mode 100644 OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs create mode 100644 OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs create mode 100644 OpenSim/Region/ScriptEngine/Shared/Instance/ScriptSerializer.cs (limited to 'OpenSim/Region/ScriptEngine') diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs index 0dab318..292858c 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptEngine.cs @@ -32,6 +32,7 @@ using OpenSim.Region.Environment.Scenes; using libsecondlife; using Nini.Config; using OpenSim.Region.ScriptEngine.Interfaces; +using Amib.Threading; namespace OpenSim.Region.ScriptEngine.Interfaces { @@ -47,6 +48,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces Object AsyncCommands { get; } ILog Log { get; } string ScriptEngineName { get; } + int MaxScriptQueue { get; } bool PostScriptEvent(LLUUID itemID, EventParams parms); bool PostObjectEvent(uint localID, EventParams parms); @@ -56,6 +58,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces bool GetScriptState(LLUUID itemID); void SetState(LLUUID itemID, string newState); int GetStartParameter(LLUUID itemID); + IWorkItemResult QueueEventHandler(object parms); DetectParams GetDetectParams(LLUUID item, int number); } diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs new file mode 100644 index 0000000..03a3802 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs @@ -0,0 +1,81 @@ +/* + * 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 OpenSim 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; +using System.Collections.Generic; +using libsecondlife; +using log4net; +using OpenSim.Framework; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Interfaces; + +namespace OpenSim.Region.ScriptEngine.Interfaces +{ + public enum StateSource + { + NewRez = 0, + PrimCrossing = 1, + AttachmentCrossing = 2 + } + + public interface IScriptInstance + { + bool Running { get; set; } + string State { get; set; } + IScriptEngine Engine { get; } + LLUUID AppDomain { get; set; } + string PrimName { get; } + string ScriptName { get; } + LLUUID ItemID { get; } + LLUUID ObjectID { get; } + uint LocalID { get; } + LLUUID AssetID { get; } + Queue EventQueue { get; } + + void ClearQueue(); + int StartParam { get; set; } + + void RemoveState(); + + void Start(); + bool Stop(int timeout); + void SetState(string state); + + void PostEvent(EventParams data); + object EventProcessor(); + + int EventTime(); + void ResetScript(); + void ApiResetScript(); + Dictionary GetVars(); + void SetVars(Dictionary vars); + DetectParams GetDetectParams(int idx); + LLUUID GetDetectID(int idx); + void SaveState(string assembly); + } +} diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs new file mode 100644 index 0000000..30c0274 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -0,0 +1,660 @@ +/* + * 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 OpenSim 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.IO; +using System.Threading; +using System.Collections; +using System.Collections.Generic; +using System.Security.Policy; +using System.Reflection; +using System.Globalization; +using System.Xml; +using libsecondlife; +using log4net; +using Nini.Config; +using Amib.Threading; +using OpenSim.Framework; +using OpenSim.Region.Environment; +using OpenSim.Region.Environment.Scenes; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Region.ScriptEngine.Shared.CodeTools; +using OpenSim.Region.ScriptEngine.Interfaces; + +namespace OpenSim.Region.ScriptEngine.Shared.Instance +{ + public class ScriptInstance : IScriptInstance + { + private IScriptEngine m_Engine; + private IWorkItemResult m_CurrentResult=null; + private Queue m_EventQueue = new Queue(32); + private bool m_RunEvents = false; + private LLUUID m_ItemID; + private uint m_LocalID; + private LLUUID m_ObjectID; + private LLUUID m_AssetID; + private IScript m_Script; + private LLUUID m_AppDomain; + private DetectParams[] m_DetectParams; + private bool m_TimerQueued; + private DateTime m_EventStart; + private bool m_InEvent; + private string m_PrimName; + private string m_ScriptName; + private string m_Assembly; + private int m_StartParam = 0; + private string m_CurrentEvent = String.Empty; + private bool m_InSelfDelete = false; + + private Dictionary m_Apis = new Dictionary(); + + // Script state + private string m_State="default"; + + public Object[] PluginData = new Object[0]; + + public bool Running + { + get { return m_RunEvents; } + set { m_RunEvents = value; } + } + + public string State + { + get { return m_State; } + set { m_State = value; } + } + + public IScriptEngine Engine + { + get { return m_Engine; } + } + + public LLUUID AppDomain + { + get { return m_AppDomain; } + set { m_AppDomain = value; } + } + + public string PrimName + { + get { return m_PrimName; } + } + + public string ScriptName + { + get { return m_ScriptName; } + } + + public LLUUID ItemID + { + get { return m_ItemID; } + } + + public LLUUID ObjectID + { + get { return m_ObjectID; } + } + + public uint LocalID + { + get { return m_LocalID; } + } + + public LLUUID AssetID + { + get { return m_AssetID; } + } + + public Queue EventQueue + { + get { return m_EventQueue; } + } + + public void ClearQueue() + { + m_TimerQueued = false; + m_EventQueue.Clear(); + } + + public int StartParam + { + get { return m_StartParam; } + set { m_StartParam = value; } + } + + public ScriptInstance(IScriptEngine engine, uint localID, + LLUUID objectID, LLUUID itemID, LLUUID assetID, string assembly, + AppDomain dom, string primName, string scriptName, + int startParam, bool postOnRez, StateSource stateSource) + { + m_Engine = engine; + + m_LocalID = localID; + m_ObjectID = objectID; + m_ItemID = itemID; + m_AssetID = assetID; + m_PrimName = primName; + m_ScriptName = scriptName; + m_Assembly = assembly; + m_StartParam = startParam; + + ApiManager am = new ApiManager(); + + SceneObjectPart part=engine.World.GetSceneObjectPart(localID); + if (part == null) + { + engine.Log.Error("[Script] SceneObjectPart unavailable. Script NOT started."); + return; + } + + foreach (string api in am.GetApis()) + { + m_Apis[api] = am.CreateApi(api); + m_Apis[api].Initialize(engine, part, localID, itemID); + } + + try + { + m_Script = (IScript)dom.CreateInstanceAndUnwrap( + Path.GetFileNameWithoutExtension(assembly), + "SecondLife.Script"); + } + catch (Exception e) + { + m_Engine.Log.ErrorFormat("[Script] Error loading assembly {0}\n"+e.ToString(), assembly); + } + + try + { + foreach (KeyValuePair kv in m_Apis) + { + m_Script.InitApi(kv.Key, kv.Value); + } + +// m_Engine.Log.Debug("[Script] Script instance created"); + + part.SetScriptEvents(m_ItemID, + (int)m_Script.GetStateEventFlags(State)); + } + catch (Exception e) + { + m_Engine.Log.Error("[Script] Error loading script instance\n"+e.ToString()); + return; + } + + string savedState = Path.Combine(Path.GetDirectoryName(assembly), + m_ItemID.ToString() + ".state"); + if (File.Exists(savedState)) + { + string xml = String.Empty; + + try + { + FileInfo fi = new FileInfo(savedState); + int size=(int)fi.Length; + if (size < 512000) + { + using (FileStream fs = File.Open(savedState, + FileMode.Open, FileAccess.Read, FileShare.None)) + { + System.Text.ASCIIEncoding enc = + new System.Text.ASCIIEncoding(); + + Byte[] data = new Byte[size]; + fs.Read(data, 0, size); + + xml = enc.GetString(data); + + ScriptSerializer.Deserialize(xml, this); + + AsyncCommandManager async = (AsyncCommandManager)m_Engine.AsyncCommands; + async.CreateFromData( + m_LocalID, m_ItemID, m_ObjectID, + PluginData); + + m_Engine.Log.DebugFormat("[Script] Successfully retrieved state for script {0}.{1}", m_PrimName, m_ScriptName); + + if (m_RunEvents) + { + m_RunEvents = false; + Start(); + if (postOnRez) + PostEvent(new EventParams("on_rez", + new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0])); + } + + // we get new rez events on sim restart, too + // but if there is state, then we fire the change + // event + if (stateSource == StateSource.NewRez) + { +// m_Engine.Log.Debug("[Script] Posted changed(CHANGED_REGION_RESTART) to script"); + PostEvent(new EventParams("changed", + new Object[] {new LSL_Types.LSLInteger(256)}, new DetectParams[0])); + } + } + } + else + { + m_Engine.Log.Error("[Script] Unable to load script state: Memory limit exceeded"); + Start(); + PostEvent(new EventParams("state_entry", + new Object[0], new DetectParams[0])); + if (postOnRez) + PostEvent(new EventParams("on_rez", + new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0])); + + } + } + catch (Exception e) + { + m_Engine.Log.ErrorFormat("[Script] Unable to load script state from xml: {0}\n"+e.ToString(), xml); + Start(); + PostEvent(new EventParams("state_entry", + new Object[0], new DetectParams[0])); + if (postOnRez) + PostEvent(new EventParams("on_rez", + new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0])); + } + } + else + { +// m_Engine.Log.ErrorFormat("[Script] Unable to load script state, file not found"); + Start(); + PostEvent(new EventParams("state_entry", + new Object[0], new DetectParams[0])); + + if (postOnRez) + PostEvent(new EventParams("on_rez", + new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0])); + } + } + + public void RemoveState() + { + string savedState = Path.Combine(Path.GetDirectoryName(m_Assembly), + m_ItemID.ToString() + ".state"); + + try + { + File.Delete(savedState); + } + catch(Exception) + { + } + } + + public void VarDump(Dictionary vars) + { + Console.WriteLine("Variable dump for script {0}", m_ItemID.ToString()); + foreach (KeyValuePair v in vars) + { + Console.WriteLine("Variable: {0} = '{1}'", v. Key, + v.Value.ToString()); + } + } + + public void Start() + { + lock (m_EventQueue) + { + if (Running) + return; + + m_RunEvents = true; + + if (m_EventQueue.Count > 0) + { + if (m_CurrentResult == null) + m_CurrentResult = m_Engine.QueueEventHandler(this); + else + m_Engine.Log.Error("[Script] Tried to start a script that was already queued"); + } + } + } + + public bool Stop(int timeout) + { + IWorkItemResult result; + + lock (m_EventQueue) + { + if (!Running) + return true; + + if (m_CurrentResult == null) + { + m_RunEvents = false; + return true; + } + + if (m_CurrentResult.Cancel()) + { + m_CurrentResult = null; + m_RunEvents = false; + return true; + } + + result = m_CurrentResult; + m_RunEvents = false; + } + + if (SmartThreadPool.WaitAll(new IWorkItemResult[] {result}, new TimeSpan((long)timeout * 100000), false)) + { + return true; + } + + lock (m_EventQueue) + { + result = m_CurrentResult; + } + + if (result == null) + return true; + + if (!m_InSelfDelete) + result.Abort(); + + lock (m_EventQueue) + { + m_CurrentResult = null; + } + + return true; + } + + public void SetState(string state) + { + PostEvent(new EventParams("state_exit", new Object[0], + new DetectParams[0])); + PostEvent(new EventParams("state", new Object[] { state }, + new DetectParams[0])); + PostEvent(new EventParams("state_entry", new Object[0], + new DetectParams[0])); + } + + public void PostEvent(EventParams data) + { +// m_Engine.Log.DebugFormat("[Script] Posted event {2} in state {3} to {0}.{1}", +// m_PrimName, m_ScriptName, data.EventName, m_State); + + if (!Running) + return; + + lock (m_EventQueue) + { + if (m_EventQueue.Count >= m_Engine.MaxScriptQueue) + return; + + m_EventQueue.Enqueue(data); + if (data.EventName == "timer") + { + if (m_TimerQueued) + return; + m_TimerQueued = true; + } + + if (!m_RunEvents) + return; + + if (m_CurrentResult == null) + { + m_CurrentResult = m_Engine.QueueEventHandler(this); + } + } + } + + public object EventProcessor() + { + EventParams data = null; + + lock (m_EventQueue) + { + data = (EventParams) m_EventQueue.Dequeue(); + if (data == null) // Shouldn't happen + { + m_CurrentResult = null; + return 0; + } + if (data.EventName == "timer") + m_TimerQueued = false; + } + + m_DetectParams = data.DetectParams; + + if (data.EventName == "state") // Hardcoded state change + { +// m_Engine.Log.DebugFormat("[Script] Script {0}.{1} state set to {2}", +// m_PrimName, m_ScriptName, data.Params[0].ToString()); + m_State=data.Params[0].ToString(); + AsyncCommandManager async = (AsyncCommandManager)m_Engine.AsyncCommands; + async.RemoveScript( + m_LocalID, m_ItemID); + + SceneObjectPart part = m_Engine.World.GetSceneObjectPart( + m_LocalID); + if (part != null) + { + part.SetScriptEvents(m_ItemID, + (int)m_Script.GetStateEventFlags(State)); + } + } + else + { + SceneObjectPart part = m_Engine.World.GetSceneObjectPart( + m_LocalID); +// m_Engine.Log.DebugFormat("[Script] Delivered event {2} in state {3} to {0}.{1}", +// m_PrimName, m_ScriptName, data.EventName, m_State); + + try + { + m_CurrentEvent = data.EventName; + m_EventStart = DateTime.Now; + m_InEvent = true; + + m_Script.ExecuteEvent(State, data.EventName, data.Params); + + m_InEvent = false; + m_CurrentEvent = String.Empty; + } + catch (Exception e) + { + m_InEvent = false; + m_CurrentEvent = String.Empty; + + if (!(e is TargetInvocationException) || (!(e.InnerException is EventAbortException) && (!(e.InnerException is SelfDeleteException)))) + { + if (e is System.Threading.ThreadAbortException) + { + lock (m_EventQueue) + { + if ((m_EventQueue.Count > 0) && m_RunEvents) + { + m_CurrentResult=m_Engine.QueueEventHandler(this); + } + else + { + m_CurrentResult = null; + } + } + + m_DetectParams = null; + + return 0; + } + + try + { + // DISPLAY ERROR INWORLD + string text = "Runtime error:\n" + e.ToString(); + if (text.Length > 1400) + text = text.Substring(0, 1400); + m_Engine.World.SimChat(Helpers.StringToField(text), + ChatTypeEnum.DebugChannel, 2147483647, + part.AbsolutePosition, + part.Name, part.UUID, false); + } + catch (Exception e2) // LEGIT: User Scripting + { + m_Engine.Log.Error("[Script]: "+ + "Error displaying error in-world: " + + e2.ToString()); + m_Engine.Log.Error("[Script]: " + + "Errormessage: Error compiling script:\r\n" + + e.ToString()); + } + } + else if ((e is TargetInvocationException) && (e.InnerException is SelfDeleteException)) + { + m_InSelfDelete = true; + if (part != null && part.ParentGroup != null) + m_Engine.World.DeleteSceneObject(part.ParentGroup); + } + } + } + + lock (m_EventQueue) + { + if ((m_EventQueue.Count > 0) && m_RunEvents) + { + m_CurrentResult = m_Engine.QueueEventHandler(this); + } + else + { + m_CurrentResult = null; + } + } + + m_DetectParams = null; + + return 0; + } + + public int EventTime() + { + if (!m_InEvent) + return 0; + + return (DateTime.Now - m_EventStart).Seconds; + } + + public void ResetScript() + { + bool running = Running; + + RemoveState(); + + Stop(0); + SceneObjectPart part=m_Engine.World.GetSceneObjectPart(m_LocalID); + part.GetInventoryItem(m_ItemID).PermsMask = 0; + part.GetInventoryItem(m_ItemID).PermsGranter = LLUUID.Zero; + AsyncCommandManager async = (AsyncCommandManager)m_Engine.AsyncCommands; + async.RemoveScript(m_LocalID, m_ItemID); + m_EventQueue.Clear(); + m_Script.ResetVars(); + m_State = "default"; + if (running) + Start(); + PostEvent(new EventParams("state_entry", + new Object[0], new DetectParams[0])); + } + + public void ApiResetScript() + { + // bool running = Running; + + RemoveState(); + + m_Script.ResetVars(); + SceneObjectPart part=m_Engine.World.GetSceneObjectPart(m_LocalID); + part.GetInventoryItem(m_ItemID).PermsMask = 0; + part.GetInventoryItem(m_ItemID).PermsGranter = LLUUID.Zero; + AsyncCommandManager async = (AsyncCommandManager)m_Engine.AsyncCommands; + async.RemoveScript(m_LocalID, m_ItemID); + if (m_CurrentEvent != "state_entry") + { + PostEvent(new EventParams("state_entry", + new Object[0], new DetectParams[0])); + } + } + + public Dictionary GetVars() + { + return m_Script.GetVars(); + } + + public void SetVars(Dictionary vars) + { + m_Script.SetVars(vars); + } + + public DetectParams GetDetectParams(int idx) + { + if (idx < 0 || idx >= m_DetectParams.Length) + return null; + + return m_DetectParams[idx]; + } + + public LLUUID GetDetectID(int idx) + { + if (idx < 0 || idx >= m_DetectParams.Length) + return LLUUID.Zero; + + return m_DetectParams[idx].Key; + } + + public void SaveState(string assembly) + { + AsyncCommandManager async = (AsyncCommandManager)m_Engine.AsyncCommands; + PluginData = async.GetSerializationData(m_ItemID); + + string xml = ScriptSerializer.Serialize(this); + + try + { + FileStream fs = File.Create(Path.Combine(Path.GetDirectoryName(assembly), m_ItemID.ToString() + ".state")); + System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); + Byte[] buf = enc.GetBytes(xml); + fs.Write(buf, 0, buf.Length); + fs.Close(); + } + catch(Exception e) + { + Console.WriteLine("Unable to save xml\n"+e.ToString()); + } + if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), m_ItemID.ToString() + ".state"))) + { + throw new Exception("Completed persistence save, but no file was created"); + } + } + } +} diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptSerializer.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptSerializer.cs new file mode 100644 index 0000000..ba003c5 --- /dev/null +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptSerializer.cs @@ -0,0 +1,461 @@ +/* + * 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 OpenSim 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.IO; +using System.Threading; +using System.Collections; +using System.Collections.Generic; +using System.Security.Policy; +using System.Reflection; +using System.Globalization; +using System.Xml; +using libsecondlife; +using log4net; +using Nini.Config; +using Amib.Threading; +using OpenSim.Framework; +using OpenSim.Region.Environment; +using OpenSim.Region.Environment.Scenes; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.ScriptEngine.Shared; +using OpenSim.Region.ScriptEngine.Shared.Api; +using OpenSim.Region.ScriptEngine.Shared.ScriptBase; +using OpenSim.Region.ScriptEngine.Shared.CodeTools; +using OpenSim.Region.ScriptEngine.Interfaces; + +namespace OpenSim.Region.ScriptEngine.Shared.Instance +{ + public class ScriptSerializer + { + public static string Serialize(ScriptInstance instance) + { + bool running = instance.Running; + + if (running) + instance.Stop(50); + + XmlDocument xmldoc = new XmlDocument(); + + XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, + "", ""); + xmldoc.AppendChild(xmlnode); + + XmlElement rootElement = xmldoc.CreateElement("", "ScriptState", + ""); + xmldoc.AppendChild(rootElement); + + XmlElement state = xmldoc.CreateElement("", "State", ""); + state.AppendChild(xmldoc.CreateTextNode(instance.State)); + + rootElement.AppendChild(state); + + XmlElement run = xmldoc.CreateElement("", "Running", ""); + run.AppendChild(xmldoc.CreateTextNode( + running.ToString())); + + rootElement.AppendChild(run); + + Dictionary vars = instance.GetVars(); + + XmlElement variables = xmldoc.CreateElement("", "Variables", ""); + + foreach (KeyValuePair var in vars) + WriteTypedValue(xmldoc, variables, "Variable", var.Key, + var.Value); + + rootElement.AppendChild(variables); + + XmlElement queue = xmldoc.CreateElement("", "Queue", ""); + + int count = instance.EventQueue.Count; + + while (count > 0) + { + EventParams ep = (EventParams)instance.EventQueue.Dequeue(); + instance.EventQueue.Enqueue(ep); + count--; + + XmlElement item = xmldoc.CreateElement("", "Item", ""); + XmlAttribute itemEvent = xmldoc.CreateAttribute("", "event", + ""); + itemEvent.Value = ep.EventName; + item.Attributes.Append(itemEvent); + + XmlElement parms = xmldoc.CreateElement("", "Params", ""); + + foreach (Object o in ep.Params) + WriteTypedValue(xmldoc, parms, "Param", String.Empty, o); + + item.AppendChild(parms); + + XmlElement detect = xmldoc.CreateElement("", "Detected", ""); + + foreach (DetectParams det in ep.DetectParams) + { + XmlElement objectElem = xmldoc.CreateElement("", "Object", + ""); + XmlAttribute pos = xmldoc.CreateAttribute("", "pos", ""); + pos.Value = det.OffsetPos.ToString(); + objectElem.Attributes.Append(pos); + + XmlAttribute d_linkNum = xmldoc.CreateAttribute("", + "linkNum", ""); + d_linkNum.Value = det.LinkNum.ToString(); + objectElem.Attributes.Append(d_linkNum); + + XmlAttribute d_group = xmldoc.CreateAttribute("", + "group", ""); + d_group.Value = det.Group.ToString(); + objectElem.Attributes.Append(d_group); + + XmlAttribute d_name = xmldoc.CreateAttribute("", + "name", ""); + d_name.Value = det.Name.ToString(); + objectElem.Attributes.Append(d_name); + + XmlAttribute d_owner = xmldoc.CreateAttribute("", + "owner", ""); + d_owner.Value = det.Owner.ToString(); + objectElem.Attributes.Append(d_owner); + + XmlAttribute d_position = xmldoc.CreateAttribute("", + "position", ""); + d_position.Value = det.Position.ToString(); + objectElem.Attributes.Append(d_position); + + XmlAttribute d_rotation = xmldoc.CreateAttribute("", + "rotation", ""); + d_rotation.Value = det.Rotation.ToString(); + objectElem.Attributes.Append(d_rotation); + + XmlAttribute d_type = xmldoc.CreateAttribute("", + "type", ""); + d_type.Value = det.Type.ToString(); + objectElem.Attributes.Append(d_type); + + XmlAttribute d_velocity = xmldoc.CreateAttribute("", + "velocity", ""); + d_velocity.Value = det.Velocity.ToString(); + objectElem.Attributes.Append(d_velocity); + + objectElem.AppendChild( + xmldoc.CreateTextNode(det.Key.ToString())); + + detect.AppendChild(objectElem); + } + + item.AppendChild(detect); + + queue.AppendChild(item); + } + + rootElement.AppendChild(queue); + + XmlNode plugins = xmldoc.CreateElement("", "Plugins", ""); + DumpList(xmldoc, plugins, + new LSL_Types.list(instance.PluginData)); + + rootElement.AppendChild(plugins); + + if (running) + instance.Start(); + + return xmldoc.InnerXml; + } + + public static void Deserialize(string xml, ScriptInstance instance) + { + XmlDocument doc = new XmlDocument(); + + Dictionary vars = instance.GetVars(); + + instance.PluginData = new Object[0]; + + doc.LoadXml(xml); + + XmlNodeList rootL = doc.GetElementsByTagName("ScriptState"); + if (rootL.Count != 1) + { + return; + } + XmlNode rootNode = rootL[0]; + + if (rootNode != null) + { + object varValue; + XmlNodeList partL = rootNode.ChildNodes; + + foreach (XmlNode part in partL) + { + switch (part.Name) + { + case "State": + instance.State=part.InnerText; + break; + case "Running": + instance.Running=bool.Parse(part.InnerText); + break; + case "Variables": + XmlNodeList varL = part.ChildNodes; + foreach (XmlNode var in varL) + { + string varName; + varValue=ReadTypedValue(var, out varName); + + if (vars.ContainsKey(varName)) + vars[varName] = varValue; + } + instance.SetVars(vars); + break; + case "Queue": + XmlNodeList itemL = part.ChildNodes; + foreach (XmlNode item in itemL) + { + List parms = new List(); + List detected = + new List(); + + string eventName = + item.Attributes.GetNamedItem("event").Value; + XmlNodeList eventL = item.ChildNodes; + foreach (XmlNode evt in eventL) + { + switch (evt.Name) + { + case "Params": + XmlNodeList prms = evt.ChildNodes; + foreach (XmlNode pm in prms) + parms.Add(ReadTypedValue(pm)); + + break; + case "Detected": + XmlNodeList detL = evt.ChildNodes; + foreach (XmlNode det in detL) + { + string vect = + det.Attributes.GetNamedItem( + "pos").Value; + LSL_Types.Vector3 v = + new LSL_Types.Vector3(vect); + + int d_linkNum=0; + LLUUID d_group = LLUUID.Zero; + string d_name = String.Empty; + LLUUID d_owner = LLUUID.Zero; + LSL_Types.Vector3 d_position = + new LSL_Types.Vector3(); + LSL_Types.Quaternion d_rotation = + new LSL_Types.Quaternion(); + int d_type = 0; + LSL_Types.Vector3 d_velocity = + new LSL_Types.Vector3(); + + try + { + string tmp; + + tmp = det.Attributes.GetNamedItem( + "linkNum").Value; + int.TryParse(tmp, out d_linkNum); + + tmp = det.Attributes.GetNamedItem( + "group").Value; + LLUUID.TryParse(tmp, out d_group); + + d_name = det.Attributes.GetNamedItem( + "name").Value; + + tmp = det.Attributes.GetNamedItem( + "owner").Value; + LLUUID.TryParse(tmp, out d_owner); + + tmp = det.Attributes.GetNamedItem( + "position").Value; + d_position = + new LSL_Types.Vector3(tmp); + + tmp = det.Attributes.GetNamedItem( + "rotation").Value; + d_rotation = + new LSL_Types.Quaternion(tmp); + + tmp = det.Attributes.GetNamedItem( + "type").Value; + int.TryParse(tmp, out d_type); + + tmp = det.Attributes.GetNamedItem( + "velocity").Value; + d_velocity = + new LSL_Types.Vector3(tmp); + + } + catch (Exception) // Old version XML + { + } + + LLUUID uuid = new LLUUID(); + LLUUID.TryParse(det.InnerText, + out uuid); + + DetectParams d = new DetectParams(); + d.Key = uuid; + d.OffsetPos = v; + d.LinkNum = d_linkNum; + d.Group = d_group; + d.Name = d_name; + d.Owner = d_owner; + d.Position = d_position; + d.Rotation = d_rotation; + d.Type = d_type; + d.Velocity = d_velocity; + + detected.Add(d); + } + break; + } + } + EventParams ep = new EventParams( + eventName, parms.ToArray(), + detected.ToArray()); + instance.EventQueue.Enqueue(ep); + } + break; + case "Plugins": + instance.PluginData = ReadList(part).Data; + break; + } + } + } + } + + private static void DumpList(XmlDocument doc, XmlNode parent, + LSL_Types.list l) + { + foreach (Object o in l.Data) + WriteTypedValue(doc, parent, "ListItem", "", o); + } + + private static LSL_Types.list ReadList(XmlNode parent) + { + List olist = new List(); + + XmlNodeList itemL = parent.ChildNodes; + foreach (XmlNode item in itemL) + olist.Add(ReadTypedValue(item)); + + return new LSL_Types.list(olist.ToArray()); + } + + private static void WriteTypedValue(XmlDocument doc, XmlNode parent, + string tag, string name, object value) + { + Type t=value.GetType(); + XmlAttribute typ = doc.CreateAttribute("", "type", ""); + XmlNode n = doc.CreateElement("", tag, ""); + + if (value is LSL_Types.list) + { + typ.Value = "list"; + n.Attributes.Append(typ); + + DumpList(doc, n, (LSL_Types.list) value); + + if (name != String.Empty) + { + XmlAttribute nam = doc.CreateAttribute("", "name", ""); + nam.Value = name; + n.Attributes.Append(nam); + } + + parent.AppendChild(n); + return; + } + + n.AppendChild(doc.CreateTextNode(value.ToString())); + + typ.Value = t.ToString(); + n.Attributes.Append(typ); + if (name != String.Empty) + { + XmlAttribute nam = doc.CreateAttribute("", "name", ""); + nam.Value = name; + n.Attributes.Append(nam); + } + + parent.AppendChild(n); + } + + private static object ReadTypedValue(XmlNode tag, out string name) + { + name = tag.Attributes.GetNamedItem("name").Value; + + return ReadTypedValue(tag); + } + + private static object ReadTypedValue(XmlNode tag) + { + Object varValue; + string assembly; + + string itemType = tag.Attributes.GetNamedItem("type").Value; + + if (itemType == "list") + return ReadList(tag); + + if (itemType == "libsecondlife.LLUUID") + { + LLUUID val = new LLUUID(); + LLUUID.TryParse(tag.InnerText, out val); + + return val; + } + + Type itemT = Type.GetType(itemType); + if (itemT == null) + { + Object[] args = + new Object[] { tag.InnerText }; + + assembly = itemType+", OpenSim.Region.ScriptEngine.Shared"; + itemT = Type.GetType(assembly); + if (itemT == null) + return null; + + varValue = Activator.CreateInstance(itemT, args); + + if (varValue == null) + return null; + } + else + { + varValue = Convert.ChangeType(tag.InnerText, itemT); + } + return varValue; + } + } +} diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index cfe0599..c5bcfd5 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -46,6 +46,7 @@ using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared.Api; using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenSim.Region.ScriptEngine.Shared.CodeTools; +using OpenSim.Region.ScriptEngine.Shared.Instance; using OpenSim.Region.ScriptEngine.Interfaces; namespace OpenSim.Region.ScriptEngine.XEngine @@ -67,7 +68,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine #pragma warning restore 414 private int m_EventLimit; private bool m_KillTimedOutScripts; - public AsyncCommandManager m_AsyncCommands; + private AsyncCommandManager m_AsyncCommands; bool m_firstStart = true; private static List m_ScriptEngines = @@ -80,8 +81,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine // Maps the LLUUID above to the script instance - private Dictionary m_Scripts = - new Dictionary(); + private Dictionary m_Scripts = + new Dictionary(); // Maps the asset ID to the assembly @@ -254,15 +255,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine // m_log.Debug("[XEngine] Backing up script states"); - List instances = new List(); + List instances = new List(); lock (m_Scripts) { - foreach (XScriptInstance instance in m_Scripts.Values) + foreach (IScriptInstance instance in m_Scripts.Values) instances.Add(instance); } - foreach (XScriptInstance i in instances) + foreach (IScriptInstance i in instances) { string assembly = String.Empty; @@ -289,7 +290,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine object[] parms = (object[])p; int sleepTime = (int)parms[0]; - foreach (XScriptInstance inst in m_Scripts.Values) + foreach (IScriptInstance inst in m_Scripts.Values) { if (inst.EventTime() > m_EventLimit) { @@ -502,12 +503,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine } m_DomainScripts[appDomain].Add(itemID); - XScriptInstance instance = new XScriptInstance(this,localID, + ScriptInstance instance = new ScriptInstance(this,localID, part.UUID, itemID, assetID, assembly, m_AppDomains[appDomain], part.ParentGroup.RootPart.Name, item.Name, startParam, postOnRez, - XScriptInstance.StateSource.NewRez); + StateSource.NewRez); m_log.DebugFormat("[XEngine] Loaded script {0}.{1}", part.ParentGroup.RootPart.Name, item.Name); @@ -539,7 +540,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_AsyncCommands.RemoveScript(localID, itemID); - XScriptInstance instance=m_Scripts[itemID]; + IScriptInstance instance=m_Scripts[itemID]; m_Scripts.Remove(itemID); instance.ClearQueue(); @@ -599,7 +600,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine { List assetIDList = new List(m_Assemblies.Keys); - foreach (XScriptInstance i in m_Scripts.Values) + foreach (IScriptInstance i in m_Scripts.Values) { if (assetIDList.Contains(i.AssetID)) assetIDList.Remove(i.AssetID); @@ -676,7 +677,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine CultureInfo USCulture = new CultureInfo("en-US"); Thread.CurrentThread.CurrentCulture = USCulture; - XScriptInstance instance = (XScriptInstance) parms; + IScriptInstance instance = (ScriptInstance) parms; return instance.EventProcessor(); } @@ -695,7 +696,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine { if (m_Scripts.ContainsKey(itemID)) { - XScriptInstance instance = m_Scripts[itemID]; + IScriptInstance instance = m_Scripts[itemID]; if (instance != null) { instance.PostEvent(p); @@ -713,7 +714,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine { if (m_Scripts.ContainsKey(itemID)) { - XScriptInstance instance = m_Scripts[itemID]; + IScriptInstance instance = m_Scripts[itemID]; if (instance != null) instance.PostEvent(p); return true; @@ -747,9 +748,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine return null; } - private XScriptInstance GetInstance(LLUUID itemID) + private IScriptInstance GetInstance(LLUUID itemID) { - XScriptInstance instance; + IScriptInstance instance; lock (m_Scripts) { if (!m_Scripts.ContainsKey(itemID)) @@ -761,7 +762,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine public void SetScriptState(LLUUID itemID, bool running) { - XScriptInstance instance = GetInstance(itemID); + IScriptInstance instance = GetInstance(itemID); if (instance != null) { if (running) @@ -773,7 +774,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine public bool GetScriptState(LLUUID itemID) { - XScriptInstance instance = GetInstance(itemID); + IScriptInstance instance = GetInstance(itemID); if (instance != null) return instance.Running; return false; @@ -781,35 +782,35 @@ namespace OpenSim.Region.ScriptEngine.XEngine public void ApiResetScript(LLUUID itemID) { - XScriptInstance instance = GetInstance(itemID); + IScriptInstance instance = GetInstance(itemID); if (instance != null) instance.ApiResetScript(); } public void ResetScript(LLUUID itemID) { - XScriptInstance instance = GetInstance(itemID); + IScriptInstance instance = GetInstance(itemID); if (instance != null) instance.ResetScript(); } public void StartScript(LLUUID itemID) { - XScriptInstance instance = GetInstance(itemID); + IScriptInstance instance = GetInstance(itemID); if (instance != null) instance.Start(); } public void StopScript(LLUUID itemID) { - XScriptInstance instance = GetInstance(itemID); + IScriptInstance instance = GetInstance(itemID); if (instance != null) instance.Stop(0); } public DetectParams GetDetectParams(LLUUID itemID, int idx) { - XScriptInstance instance = GetInstance(itemID); + IScriptInstance instance = GetInstance(itemID); if (instance != null) return instance.GetDetectParams(idx); return null; @@ -817,7 +818,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine public LLUUID GetDetectID(LLUUID itemID, int idx) { - XScriptInstance instance = GetInstance(itemID); + IScriptInstance instance = GetInstance(itemID); if (instance != null) return instance.GetDetectID(idx); return LLUUID.Zero; @@ -825,14 +826,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine public void SetState(LLUUID itemID, string newState) { - XScriptInstance instance = GetInstance(itemID); + IScriptInstance instance = GetInstance(itemID); if (instance == null) return; instance.SetState(newState); } public string GetState(LLUUID itemID) { - XScriptInstance instance = GetInstance(itemID); + IScriptInstance instance = GetInstance(itemID); if (instance == null) return "default"; return instance.State; @@ -840,7 +841,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine public int GetStartParameter(LLUUID itemID) { - XScriptInstance instance = GetInstance(itemID); + IScriptInstance instance = GetInstance(itemID); if (instance == null) return 0; return instance.StartParam; @@ -851,1025 +852,4 @@ namespace OpenSim.Region.ScriptEngine.XEngine return GetScriptState(itemID); } } - - public class XScriptInstance - { - private XEngine m_Engine; - private IWorkItemResult m_CurrentResult=null; - private Queue m_EventQueue = new Queue(32); - private bool m_RunEvents = false; - private LLUUID m_ItemID; - private uint m_LocalID; - private LLUUID m_ObjectID; - private LLUUID m_AssetID; - private IScript m_Script; - private LLUUID m_AppDomain; - private DetectParams[] m_DetectParams; - private bool m_TimerQueued; - private DateTime m_EventStart; - private bool m_InEvent; - private string m_PrimName; - private string m_ScriptName; - private string m_Assembly; - private int m_StartParam = 0; - private string m_CurrentEvent = String.Empty; - private bool m_InSelfDelete = false; - - private Dictionary m_Apis = new Dictionary(); - - public enum StateSource - { - NewRez = 0, - PrimCrossing = 1, - AttachmentCrossing = 2 - } - - // Script state - private string m_State="default"; - - public Object[] PluginData = new Object[0]; - - public bool Running - { - get { return m_RunEvents; } - set { m_RunEvents = value; } - } - - public string State - { - get { return m_State; } - set { m_State = value; } - } - - public XEngine Engine - { - get { return m_Engine; } - } - - public LLUUID AppDomain - { - get { return m_AppDomain; } - set { m_AppDomain = value; } - } - - public string PrimName - { - get { return m_PrimName; } - } - - public string ScriptName - { - get { return m_ScriptName; } - } - - public LLUUID ItemID - { - get { return m_ItemID; } - } - - public LLUUID ObjectID - { - get { return m_ObjectID; } - } - - public uint LocalID - { - get { return m_LocalID; } - } - - public LLUUID AssetID - { - get { return m_AssetID; } - } - - public Queue EventQueue - { - get { return m_EventQueue; } - } - - public void ClearQueue() - { - m_TimerQueued = false; - m_EventQueue.Clear(); - } - - public int StartParam - { - get { return m_StartParam; } - set { m_StartParam = value; } - } - - public XScriptInstance(XEngine engine, uint localID, LLUUID objectID, - LLUUID itemID, LLUUID assetID, string assembly, AppDomain dom, - string primName, string scriptName, int startParam, - bool postOnRez, StateSource stateSource) - { - m_Engine = engine; - - m_LocalID = localID; - m_ObjectID = objectID; - m_ItemID = itemID; - m_AssetID = assetID; - m_PrimName = primName; - m_ScriptName = scriptName; - m_Assembly = assembly; - m_StartParam = startParam; - - ApiManager am = new ApiManager(); - - SceneObjectPart part=engine.World.GetSceneObjectPart(localID); - if (part == null) - { - engine.Log.Error("[XEngine] SceneObjectPart unavailable. Script NOT started."); - return; - } - - foreach (string api in am.GetApis()) - { - m_Apis[api] = am.CreateApi(api); - m_Apis[api].Initialize(engine, part, localID, itemID); - } - - try - { - m_Script = (IScript)dom.CreateInstanceAndUnwrap( - Path.GetFileNameWithoutExtension(assembly), - "SecondLife.Script"); - } - catch (Exception e) - { - m_Engine.Log.ErrorFormat("[XEngine] Error loading assembly {0}\n"+e.ToString(), assembly); - } - - try - { - foreach (KeyValuePair kv in m_Apis) - { - m_Script.InitApi(kv.Key, kv.Value); - } - -// m_Engine.Log.Debug("[XEngine] Script instance created"); - - part.SetScriptEvents(m_ItemID, - (int)m_Script.GetStateEventFlags(State)); - } - catch (Exception e) - { - m_Engine.Log.Error("[XEngine] Error loading script instance\n"+e.ToString()); - return; - } - - string savedState = Path.Combine(Path.GetDirectoryName(assembly), - m_ItemID.ToString() + ".state"); - if (File.Exists(savedState)) - { - string xml = String.Empty; - - try - { - FileInfo fi = new FileInfo(savedState); - int size=(int)fi.Length; - if (size < 512000) - { - using (FileStream fs = File.Open(savedState, - FileMode.Open, FileAccess.Read, FileShare.None)) - { - System.Text.ASCIIEncoding enc = - new System.Text.ASCIIEncoding(); - - Byte[] data = new Byte[size]; - fs.Read(data, 0, size); - - xml = enc.GetString(data); - - ScriptSerializer.Deserialize(xml, this); - - m_Engine.m_AsyncCommands.CreateFromData( - m_LocalID, m_ItemID, m_ObjectID, - PluginData); - - m_Engine.Log.DebugFormat("[XEngine] Successfully retrieved state for script {0}.{1}", m_PrimName, m_ScriptName); - - if (m_RunEvents) - { - m_RunEvents = false; - Start(); - if (postOnRez) - PostEvent(new EventParams("on_rez", - new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0])); - } - - // we get new rez events on sim restart, too - // but if there is state, then we fire the change - // event - if (stateSource == StateSource.NewRez) - { -// m_Engine.Log.Debug("[XEngine] Posted changed(CHANGED_REGION_RESTART) to script"); - PostEvent(new EventParams("changed", - new Object[] {new LSL_Types.LSLInteger(256)}, new DetectParams[0])); - } - } - } - else - { - m_Engine.Log.Error("[XEngine] Unable to load script state: Memory limit exceeded"); - Start(); - PostEvent(new EventParams("state_entry", - new Object[0], new DetectParams[0])); - if (postOnRez) - PostEvent(new EventParams("on_rez", - new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0])); - - } - } - catch (Exception e) - { - m_Engine.Log.ErrorFormat("[XEngine] Unable to load script state from xml: {0}\n"+e.ToString(), xml); - Start(); - PostEvent(new EventParams("state_entry", - new Object[0], new DetectParams[0])); - if (postOnRez) - PostEvent(new EventParams("on_rez", - new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0])); - } - } - else - { -// m_Engine.Log.ErrorFormat("[XEngine] Unable to load script state, file not found"); - Start(); - PostEvent(new EventParams("state_entry", - new Object[0], new DetectParams[0])); - - if (postOnRez) - PostEvent(new EventParams("on_rez", - new Object[] {new LSL_Types.LSLInteger(startParam)}, new DetectParams[0])); - } - } - - public void RemoveState() - { - string savedState = Path.Combine(Path.GetDirectoryName(m_Assembly), - m_ItemID.ToString() + ".state"); - - try - { - File.Delete(savedState); - } - catch(Exception) - { - } - } - - public void VarDump(Dictionary vars) - { - Console.WriteLine("Variable dump for script {0}", m_ItemID.ToString()); - foreach (KeyValuePair v in vars) - { - Console.WriteLine("Variable: {0} = '{1}'", v. Key, - v.Value.ToString()); - } - } - - public void Start() - { - lock (m_EventQueue) - { - if (Running) - return; - - m_RunEvents = true; - - if (m_EventQueue.Count > 0) - { - if (m_CurrentResult == null) - m_CurrentResult = m_Engine.QueueEventHandler(this); - else - m_Engine.Log.Error("[XEngine] Tried to start a script that was already queued"); - } - } - } - - public bool Stop(int timeout) - { - IWorkItemResult result; - - lock (m_EventQueue) - { - if (!Running) - return true; - - if (m_CurrentResult == null) - { - m_RunEvents = false; - return true; - } - - if (m_CurrentResult.Cancel()) - { - m_CurrentResult = null; - m_RunEvents = false; - return true; - } - - result = m_CurrentResult; - m_RunEvents = false; - } - - if (SmartThreadPool.WaitAll(new IWorkItemResult[] {result}, new TimeSpan((long)timeout * 100000), false)) - { - return true; - } - - lock (m_EventQueue) - { - result = m_CurrentResult; - } - - if (result == null) - return true; - - if (!m_InSelfDelete) - result.Abort(); - - lock (m_EventQueue) - { - m_CurrentResult = null; - } - - return true; - } - - public void SetState(string state) - { - PostEvent(new EventParams("state_exit", new Object[0], - new DetectParams[0])); - PostEvent(new EventParams("state", new Object[] { state }, - new DetectParams[0])); - PostEvent(new EventParams("state_entry", new Object[0], - new DetectParams[0])); - } - - public void PostEvent(EventParams data) - { -// m_Engine.Log.DebugFormat("[XEngine] Posted event {2} in state {3} to {0}.{1}", -// m_PrimName, m_ScriptName, data.EventName, m_State); - - if (!Running) - return; - - lock (m_EventQueue) - { - if (m_EventQueue.Count >= m_Engine.MaxScriptQueue) - return; - - m_EventQueue.Enqueue(data); - if (data.EventName == "timer") - { - if (m_TimerQueued) - return; - m_TimerQueued = true; - } - - if (!m_RunEvents) - return; - - if (m_CurrentResult == null) - { - m_CurrentResult = m_Engine.QueueEventHandler(this); - } - } - } - - public object EventProcessor() - { - EventParams data = null; - - lock (m_EventQueue) - { - data = (EventParams) m_EventQueue.Dequeue(); - if (data == null) // Shouldn't happen - { - m_CurrentResult = null; - return 0; - } - if (data.EventName == "timer") - m_TimerQueued = false; - } - - m_DetectParams = data.DetectParams; - - if (data.EventName == "state") // Hardcoded state change - { -// m_Engine.Log.DebugFormat("[XEngine] Script {0}.{1} state set to {2}", -// m_PrimName, m_ScriptName, data.Params[0].ToString()); - m_State=data.Params[0].ToString(); - m_Engine.m_AsyncCommands.RemoveScript( - m_LocalID, m_ItemID); - - SceneObjectPart part = m_Engine.World.GetSceneObjectPart( - m_LocalID); - if (part != null) - { - part.SetScriptEvents(m_ItemID, - (int)m_Script.GetStateEventFlags(State)); - } - } - else - { - SceneObjectPart part = m_Engine.World.GetSceneObjectPart( - m_LocalID); -// m_Engine.Log.DebugFormat("[XEngine] Delivered event {2} in state {3} to {0}.{1}", -// m_PrimName, m_ScriptName, data.EventName, m_State); - - try - { - m_CurrentEvent = data.EventName; - m_EventStart = DateTime.Now; - m_InEvent = true; - - m_Script.ExecuteEvent(State, data.EventName, data.Params); - - m_InEvent = false; - m_CurrentEvent = String.Empty; - } - catch (Exception e) - { - m_InEvent = false; - m_CurrentEvent = String.Empty; - - if (!(e is TargetInvocationException) || (!(e.InnerException is EventAbortException) && (!(e.InnerException is SelfDeleteException)))) - { - if (e is System.Threading.ThreadAbortException) - { - lock (m_EventQueue) - { - if ((m_EventQueue.Count > 0) && m_RunEvents) - { - m_CurrentResult=m_Engine.QueueEventHandler(this); - } - else - { - m_CurrentResult = null; - } - } - - m_DetectParams = null; - - return 0; - } - - try - { - // DISPLAY ERROR INWORLD - string text = "Runtime error:\n" + e.ToString(); - if (text.Length > 1400) - text = text.Substring(0, 1400); - m_Engine.World.SimChat(Helpers.StringToField(text), - ChatTypeEnum.DebugChannel, 2147483647, - part.AbsolutePosition, - part.Name, part.UUID, false); - } - catch (Exception e2) // LEGIT: User Scripting - { - m_Engine.Log.Error("[XEngine]: "+ - "Error displaying error in-world: " + - e2.ToString()); - m_Engine.Log.Error("[XEngine]: " + - "Errormessage: Error compiling script:\r\n" + - e.ToString()); - } - } - else if ((e is TargetInvocationException) && (e.InnerException is SelfDeleteException)) - { - m_InSelfDelete = true; - if (part != null && part.ParentGroup != null) - m_Engine.World.DeleteSceneObject(part.ParentGroup); - } - } - } - - lock (m_EventQueue) - { - if ((m_EventQueue.Count > 0) && m_RunEvents) - { - m_CurrentResult = m_Engine.QueueEventHandler(this); - } - else - { - m_CurrentResult = null; - } - } - - m_DetectParams = null; - - return 0; - } - - public int EventTime() - { - if (!m_InEvent) - return 0; - - return (DateTime.Now - m_EventStart).Seconds; - } - - public void ResetScript() - { - bool running = Running; - - RemoveState(); - - Stop(0); - SceneObjectPart part=m_Engine.World.GetSceneObjectPart(m_LocalID); - part.GetInventoryItem(m_ItemID).PermsMask = 0; - part.GetInventoryItem(m_ItemID).PermsGranter = LLUUID.Zero; - m_Engine.m_AsyncCommands.RemoveScript(m_LocalID, m_ItemID); - m_EventQueue.Clear(); - m_Script.ResetVars(); - m_State = "default"; - if (running) - Start(); - PostEvent(new EventParams("state_entry", - new Object[0], new DetectParams[0])); - } - - public void ApiResetScript() - { - // bool running = Running; - - RemoveState(); - - m_Script.ResetVars(); - SceneObjectPart part=m_Engine.World.GetSceneObjectPart(m_LocalID); - part.GetInventoryItem(m_ItemID).PermsMask = 0; - part.GetInventoryItem(m_ItemID).PermsGranter = LLUUID.Zero; - m_Engine.m_AsyncCommands.RemoveScript(m_LocalID, m_ItemID); - if (m_CurrentEvent != "state_entry") - { - PostEvent(new EventParams("state_entry", - new Object[0], new DetectParams[0])); - } - } - - public Dictionary GetVars() - { - return m_Script.GetVars(); - } - - public void SetVars(Dictionary vars) - { - m_Script.SetVars(vars); - } - - public DetectParams GetDetectParams(int idx) - { - if (idx < 0 || idx >= m_DetectParams.Length) - return null; - - return m_DetectParams[idx]; - } - - public LLUUID GetDetectID(int idx) - { - if (idx < 0 || idx >= m_DetectParams.Length) - return LLUUID.Zero; - - return m_DetectParams[idx].Key; - } - - public void SaveState(string assembly) - { - PluginData = - m_Engine.m_AsyncCommands.GetSerializationData( - m_ItemID); - - string xml = ScriptSerializer.Serialize(this); - - try - { - FileStream fs = File.Create(Path.Combine(Path.GetDirectoryName(assembly), m_ItemID.ToString() + ".state")); - System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding(); - Byte[] buf = enc.GetBytes(xml); - fs.Write(buf, 0, buf.Length); - fs.Close(); - } - catch(Exception e) - { - Console.WriteLine("Unable to save xml\n"+e.ToString()); - } - if (!File.Exists(Path.Combine(Path.GetDirectoryName(assembly), m_ItemID.ToString() + ".state"))) - { - throw new Exception("Completed persistence save, but no file was created"); - } - } - } - - public class ScriptSerializer - { - public static string Serialize(XScriptInstance instance) - { - bool running = instance.Running; - - if (running) - instance.Stop(50); - - XmlDocument xmldoc = new XmlDocument(); - - XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, - "", ""); - xmldoc.AppendChild(xmlnode); - - XmlElement rootElement = xmldoc.CreateElement("", "ScriptState", - ""); - xmldoc.AppendChild(rootElement); - - XmlElement state = xmldoc.CreateElement("", "State", ""); - state.AppendChild(xmldoc.CreateTextNode(instance.State)); - - rootElement.AppendChild(state); - - XmlElement run = xmldoc.CreateElement("", "Running", ""); - run.AppendChild(xmldoc.CreateTextNode( - running.ToString())); - - rootElement.AppendChild(run); - - Dictionary vars = instance.GetVars(); - - XmlElement variables = xmldoc.CreateElement("", "Variables", ""); - - foreach (KeyValuePair var in vars) - WriteTypedValue(xmldoc, variables, "Variable", var.Key, - var.Value); - - rootElement.AppendChild(variables); - - XmlElement queue = xmldoc.CreateElement("", "Queue", ""); - - int count = instance.EventQueue.Count; - - while (count > 0) - { - EventParams ep = (EventParams)instance.EventQueue.Dequeue(); - instance.EventQueue.Enqueue(ep); - count--; - - XmlElement item = xmldoc.CreateElement("", "Item", ""); - XmlAttribute itemEvent = xmldoc.CreateAttribute("", "event", - ""); - itemEvent.Value = ep.EventName; - item.Attributes.Append(itemEvent); - - XmlElement parms = xmldoc.CreateElement("", "Params", ""); - - foreach (Object o in ep.Params) - WriteTypedValue(xmldoc, parms, "Param", String.Empty, o); - - item.AppendChild(parms); - - XmlElement detect = xmldoc.CreateElement("", "Detected", ""); - - foreach (DetectParams det in ep.DetectParams) - { - XmlElement objectElem = xmldoc.CreateElement("", "Object", - ""); - XmlAttribute pos = xmldoc.CreateAttribute("", "pos", ""); - pos.Value = det.OffsetPos.ToString(); - objectElem.Attributes.Append(pos); - - XmlAttribute d_linkNum = xmldoc.CreateAttribute("", - "linkNum", ""); - d_linkNum.Value = det.LinkNum.ToString(); - objectElem.Attributes.Append(d_linkNum); - - XmlAttribute d_group = xmldoc.CreateAttribute("", - "group", ""); - d_group.Value = det.Group.ToString(); - objectElem.Attributes.Append(d_group); - - XmlAttribute d_name = xmldoc.CreateAttribute("", - "name", ""); - d_name.Value = det.Name.ToString(); - objectElem.Attributes.Append(d_name); - - XmlAttribute d_owner = xmldoc.CreateAttribute("", - "owner", ""); - d_owner.Value = det.Owner.ToString(); - objectElem.Attributes.Append(d_owner); - - XmlAttribute d_position = xmldoc.CreateAttribute("", - "position", ""); - d_position.Value = det.Position.ToString(); - objectElem.Attributes.Append(d_position); - - XmlAttribute d_rotation = xmldoc.CreateAttribute("", - "rotation", ""); - d_rotation.Value = det.Rotation.ToString(); - objectElem.Attributes.Append(d_rotation); - - XmlAttribute d_type = xmldoc.CreateAttribute("", - "type", ""); - d_type.Value = det.Type.ToString(); - objectElem.Attributes.Append(d_type); - - XmlAttribute d_velocity = xmldoc.CreateAttribute("", - "velocity", ""); - d_velocity.Value = det.Velocity.ToString(); - objectElem.Attributes.Append(d_velocity); - - objectElem.AppendChild( - xmldoc.CreateTextNode(det.Key.ToString())); - - detect.AppendChild(objectElem); - } - - item.AppendChild(detect); - - queue.AppendChild(item); - } - - rootElement.AppendChild(queue); - - XmlNode plugins = xmldoc.CreateElement("", "Plugins", ""); - DumpList(xmldoc, plugins, - new LSL_Types.list(instance.PluginData)); - - rootElement.AppendChild(plugins); - - if (running) - instance.Start(); - - return xmldoc.InnerXml; - } - - public static void Deserialize(string xml, XScriptInstance instance) - { - XmlDocument doc = new XmlDocument(); - - Dictionary vars = instance.GetVars(); - - instance.PluginData = new Object[0]; - - doc.LoadXml(xml); - - XmlNodeList rootL = doc.GetElementsByTagName("ScriptState"); - if (rootL.Count != 1) - { - return; - } - XmlNode rootNode = rootL[0]; - - if (rootNode != null) - { - object varValue; - XmlNodeList partL = rootNode.ChildNodes; - - foreach (XmlNode part in partL) - { - switch (part.Name) - { - case "State": - instance.State=part.InnerText; - break; - case "Running": - instance.Running=bool.Parse(part.InnerText); - break; - case "Variables": - XmlNodeList varL = part.ChildNodes; - foreach (XmlNode var in varL) - { - string varName; - varValue=ReadTypedValue(var, out varName); - - if (vars.ContainsKey(varName)) - vars[varName] = varValue; - } - instance.SetVars(vars); - break; - case "Queue": - XmlNodeList itemL = part.ChildNodes; - foreach (XmlNode item in itemL) - { - List parms = new List(); - List detected = - new List(); - - string eventName = - item.Attributes.GetNamedItem("event").Value; - XmlNodeList eventL = item.ChildNodes; - foreach (XmlNode evt in eventL) - { - switch (evt.Name) - { - case "Params": - XmlNodeList prms = evt.ChildNodes; - foreach (XmlNode pm in prms) - parms.Add(ReadTypedValue(pm)); - - break; - case "Detected": - XmlNodeList detL = evt.ChildNodes; - foreach (XmlNode det in detL) - { - string vect = - det.Attributes.GetNamedItem( - "pos").Value; - LSL_Types.Vector3 v = - new LSL_Types.Vector3(vect); - - int d_linkNum=0; - LLUUID d_group = LLUUID.Zero; - string d_name = String.Empty; - LLUUID d_owner = LLUUID.Zero; - LSL_Types.Vector3 d_position = - new LSL_Types.Vector3(); - LSL_Types.Quaternion d_rotation = - new LSL_Types.Quaternion(); - int d_type = 0; - LSL_Types.Vector3 d_velocity = - new LSL_Types.Vector3(); - - try - { - string tmp; - - tmp = det.Attributes.GetNamedItem( - "linkNum").Value; - int.TryParse(tmp, out d_linkNum); - - tmp = det.Attributes.GetNamedItem( - "group").Value; - LLUUID.TryParse(tmp, out d_group); - - d_name = det.Attributes.GetNamedItem( - "name").Value; - - tmp = det.Attributes.GetNamedItem( - "owner").Value; - LLUUID.TryParse(tmp, out d_owner); - - tmp = det.Attributes.GetNamedItem( - "position").Value; - d_position = - new LSL_Types.Vector3(tmp); - - tmp = det.Attributes.GetNamedItem( - "rotation").Value; - d_rotation = - new LSL_Types.Quaternion(tmp); - - tmp = det.Attributes.GetNamedItem( - "type").Value; - int.TryParse(tmp, out d_type); - - tmp = det.Attributes.GetNamedItem( - "velocity").Value; - d_velocity = - new LSL_Types.Vector3(tmp); - - } - catch (Exception) // Old version XML - { - } - - LLUUID uuid = new LLUUID(); - LLUUID.TryParse(det.InnerText, - out uuid); - - DetectParams d = new DetectParams(); - d.Key = uuid; - d.OffsetPos = v; - d.LinkNum = d_linkNum; - d.Group = d_group; - d.Name = d_name; - d.Owner = d_owner; - d.Position = d_position; - d.Rotation = d_rotation; - d.Type = d_type; - d.Velocity = d_velocity; - - detected.Add(d); - } - break; - } - } - EventParams ep = new EventParams( - eventName, parms.ToArray(), - detected.ToArray()); - instance.EventQueue.Enqueue(ep); - } - break; - case "Plugins": - instance.PluginData = ReadList(part).Data; - break; - } - } - } - } - - private static void DumpList(XmlDocument doc, XmlNode parent, - LSL_Types.list l) - { - foreach (Object o in l.Data) - WriteTypedValue(doc, parent, "ListItem", "", o); - } - - private static LSL_Types.list ReadList(XmlNode parent) - { - List olist = new List(); - - XmlNodeList itemL = parent.ChildNodes; - foreach (XmlNode item in itemL) - olist.Add(ReadTypedValue(item)); - - return new LSL_Types.list(olist.ToArray()); - } - - private static void WriteTypedValue(XmlDocument doc, XmlNode parent, - string tag, string name, object value) - { - Type t=value.GetType(); - XmlAttribute typ = doc.CreateAttribute("", "type", ""); - XmlNode n = doc.CreateElement("", tag, ""); - - if (value is LSL_Types.list) - { - typ.Value = "list"; - n.Attributes.Append(typ); - - DumpList(doc, n, (LSL_Types.list) value); - - if (name != String.Empty) - { - XmlAttribute nam = doc.CreateAttribute("", "name", ""); - nam.Value = name; - n.Attributes.Append(nam); - } - - parent.AppendChild(n); - return; - } - - n.AppendChild(doc.CreateTextNode(value.ToString())); - - typ.Value = t.ToString(); - n.Attributes.Append(typ); - if (name != String.Empty) - { - XmlAttribute nam = doc.CreateAttribute("", "name", ""); - nam.Value = name; - n.Attributes.Append(nam); - } - - parent.AppendChild(n); - } - - private static object ReadTypedValue(XmlNode tag, out string name) - { - name = tag.Attributes.GetNamedItem("name").Value; - - return ReadTypedValue(tag); - } - - private static object ReadTypedValue(XmlNode tag) - { - Object varValue; - string assembly; - - string itemType = tag.Attributes.GetNamedItem("type").Value; - - if (itemType == "list") - return ReadList(tag); - - if (itemType == "libsecondlife.LLUUID") - { - LLUUID val = new LLUUID(); - LLUUID.TryParse(tag.InnerText, out val); - - return val; - } - - Type itemT = Type.GetType(itemType); - if (itemT == null) - { - Object[] args = - new Object[] { tag.InnerText }; - - assembly = itemType+", OpenSim.Region.ScriptEngine.Shared"; - itemT = Type.GetType(assembly); - if (itemT == null) - return null; - - varValue = Activator.CreateInstance(itemT, args); - - if (varValue == null) - return null; - } - else - { - varValue = Convert.ChangeType(tag.InnerText, itemT); - } - return varValue; - } - } } -- cgit v1.1