XMRInstCapture.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.IO;
  29. using System.Xml;
  30. using OpenSim.Framework;
  31. using OpenSim.Region.ScriptEngine.Shared;
  32. using OpenSim.Region.ScriptEngine.Shared.Api;
  33. using log4net;
  34. using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
  35. using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
  36. using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  37. using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
  38. using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
  39. using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  40. using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
  41. namespace OpenSim.Region.ScriptEngine.Yengine
  42. {
  43. public partial class XMRInstance
  44. {
  45. /********************************************************************************\
  46. * The only method of interest to outside this module is GetExecutionState() *
  47. * which captures the current state of the script into an XML document. *
  48. * *
  49. * The rest of this module contains support routines for GetExecutionState(). *
  50. \********************************************************************************/
  51. /**
  52. * @brief Create an XML element that gives the current state of the script.
  53. * <ScriptState Engine="YEngine" SourceHash=m_ObjCode.sourceHash Asset=m_Item.AssetID>
  54. * <Snapshot>globalsandstackdump</Snapshot>
  55. * <Running>m_Running</Running>
  56. * <DetectArray ...
  57. * <EventQueue ...
  58. * <Permissions ...
  59. * <Plugins />
  60. * </ScriptState>
  61. * Updates the .state file while we're at it.
  62. */
  63. public XmlElement GetExecutionState(XmlDocument doc)
  64. {
  65. // When we're detaching an attachment, we need to wait here.
  66. // Change this to a 5 second timeout. If things do mess up,
  67. // we don't want to be stuck forever.
  68. //
  69. m_DetachReady.WaitOne(5000, false);
  70. XmlElement scriptStateN = doc.CreateElement("", "ScriptState", "");
  71. scriptStateN.SetAttribute("Engine", m_Engine.ScriptEngineName);
  72. scriptStateN.SetAttribute("Asset", m_Item.AssetID.ToString());
  73. scriptStateN.SetAttribute("SourceHash", m_ObjCode.sourceHash);
  74. // Make sure we aren't executing part of the script so it stays
  75. // stable. Setting suspendOnCheckRun tells CheckRun() to suspend
  76. // and return out so RunOne() will release the lock asap.
  77. suspendOnCheckRunHold = true;
  78. lock(m_RunLock)
  79. {
  80. m_RunOnePhase = "GetExecutionState enter";
  81. CheckRunLockInvariants(true);
  82. // Get copy of script globals and stack in relocateable form.
  83. Byte[] snapshotBytes;
  84. using (MemoryStream snapshotStream = new MemoryStream())
  85. {
  86. MigrateOutEventHandler(snapshotStream);
  87. snapshotBytes = snapshotStream.ToArray();
  88. }
  89. string snapshotString = Convert.ToBase64String(snapshotBytes);
  90. XmlElement snapshotN = doc.CreateElement("", "Snapshot", "");
  91. snapshotN.AppendChild(doc.CreateTextNode(snapshotString));
  92. scriptStateN.AppendChild(snapshotN);
  93. m_RunOnePhase = "GetExecutionState B";
  94. CheckRunLockInvariants(true);
  95. // "Running" says whether or not we are accepting new events.
  96. XmlElement runningN = doc.CreateElement("", "Running", "");
  97. runningN.AppendChild(doc.CreateTextNode(m_Running.ToString()));
  98. scriptStateN.AppendChild(runningN);
  99. m_RunOnePhase = "GetExecutionState C";
  100. CheckRunLockInvariants(true);
  101. // "DoGblInit" says whether or not default:state_entry() will init global vars.
  102. XmlElement doGblInitN = doc.CreateElement("", "DoGblInit", "");
  103. doGblInitN.AppendChild(doc.CreateTextNode(doGblInit.ToString()));
  104. scriptStateN.AppendChild(doGblInitN);
  105. m_RunOnePhase = "GetExecutionState D";
  106. CheckRunLockInvariants(true);
  107. if(m_XMRLSLApi != null)
  108. {
  109. double scriptTime = Util.GetTimeStampMS() - m_XMRLSLApi.getLSLTimer();
  110. XmlElement scriptTimeN = doc.CreateElement("", "scrpTime", "");
  111. scriptTimeN.AppendChild(doc.CreateTextNode(scriptTime.ToString()));
  112. scriptStateN.AppendChild(scriptTimeN);
  113. }
  114. if (m_minEventDelay != 0.0)
  115. {
  116. XmlElement minEventDelayN = doc.CreateElement("", "mEvtDly", "");
  117. minEventDelayN.AppendChild(doc.CreateTextNode(m_minEventDelay.ToString()));
  118. scriptStateN.AppendChild(minEventDelayN);
  119. m_RunOnePhase = "GetExecutionState D";
  120. CheckRunLockInvariants(true);
  121. }
  122. // More misc data.
  123. XmlNode permissionsN = doc.CreateElement("", "Permissions", "");
  124. scriptStateN.AppendChild(permissionsN);
  125. XmlAttribute granterA = doc.CreateAttribute("", "granter", "");
  126. granterA.Value = m_Item.PermsGranter.ToString();
  127. permissionsN.Attributes.Append(granterA);
  128. XmlAttribute maskA = doc.CreateAttribute("", "mask", "");
  129. maskA.Value = m_Item.PermsMask.ToString();
  130. permissionsN.Attributes.Append(maskA);
  131. m_RunOnePhase = "GetExecutionState E";
  132. CheckRunLockInvariants(true);
  133. // "DetectParams" are returned by llDetected...() script functions
  134. // for the currently active event, if any.
  135. if(m_DetectParams != null)
  136. {
  137. XmlElement detParArrayN = doc.CreateElement("", "DetectArray", "");
  138. AppendXMLDetectArray(doc, detParArrayN, m_DetectParams);
  139. scriptStateN.AppendChild(detParArrayN);
  140. }
  141. m_RunOnePhase = "GetExecutionState F";
  142. CheckRunLockInvariants(true);
  143. // Save any events we have in the queue.
  144. // <EventQueue>
  145. // <Event Name="...">
  146. // <param>...</param> ...
  147. // <DetectParams>...</DetectParams> ...
  148. // </Event>
  149. // ...
  150. // </EventQueue>
  151. XmlElement queuedEventsN = doc.CreateElement("", "EventQueue", "");
  152. lock(m_QueueLock)
  153. {
  154. foreach(EventParams evt in m_EventQueue)
  155. {
  156. XmlElement singleEventN = doc.CreateElement("", "Event", "");
  157. singleEventN.SetAttribute("Name", evt.EventName);
  158. AppendXMLObjectArray(doc, singleEventN, evt.Params, "param");
  159. AppendXMLDetectArray(doc, singleEventN, evt.DetectParams);
  160. queuedEventsN.AppendChild(singleEventN);
  161. }
  162. }
  163. scriptStateN.AppendChild(queuedEventsN);
  164. m_RunOnePhase = "GetExecutionState G";
  165. CheckRunLockInvariants(true);
  166. // "Plugins" indicate enabled timers and listens, etc.
  167. Object[] pluginData =
  168. AsyncCommandManager.GetSerializationData(m_Engine, m_ItemID);
  169. XmlNode plugins = doc.CreateElement("", "Plugins", "");
  170. AppendXMLObjectArray(doc, plugins, pluginData, "plugin");
  171. scriptStateN.AppendChild(plugins);
  172. m_RunOnePhase = "GetExecutionState H";
  173. CheckRunLockInvariants(true);
  174. // Let script run again.
  175. suspendOnCheckRunHold = false;
  176. m_RunOnePhase = "GetExecutionState leave";
  177. CheckRunLockInvariants(true);
  178. }
  179. // scriptStateN represents the contents of the .state file so
  180. // write the .state file while we are here.
  181. using(FileStream fs = File.Create(m_StateFileName))
  182. {
  183. using(StreamWriter sw = new StreamWriter(fs))
  184. sw.Write(scriptStateN.OuterXml);
  185. }
  186. return scriptStateN;
  187. }
  188. /**
  189. * @brief Write script state to output stream.
  190. * Input:
  191. * stream = stream to write event handler state information to
  192. */
  193. private void MigrateOutEventHandler(Stream stream)
  194. {
  195. // Write script state out, frames and all, to the stream.
  196. // Does not change script state.
  197. stream.WriteByte(migrationVersion);
  198. stream.WriteByte((byte)16);
  199. this.MigrateOut(new BinaryWriter(stream));
  200. }
  201. /**
  202. * @brief Convert an DetectParams[] to corresponding XML.
  203. * DetectParams[] holds the values retrievable by llDetected...() for
  204. * a given event.
  205. */
  206. private static void AppendXMLDetectArray(XmlDocument doc, XmlElement parent, DetectParams[] detect)
  207. {
  208. foreach(DetectParams d in detect)
  209. {
  210. XmlElement detectParamsN = GetXMLDetect(doc, d);
  211. parent.AppendChild(detectParamsN);
  212. }
  213. }
  214. private static XmlElement GetXMLDetect(XmlDocument doc, DetectParams d)
  215. {
  216. XmlElement detectParamsN = doc.CreateElement("", "DetectParams", "");
  217. XmlAttribute d_key = doc.CreateAttribute("", "key", "");
  218. d_key.Value = d.Key.ToString();
  219. detectParamsN.Attributes.Append(d_key);
  220. XmlAttribute pos = doc.CreateAttribute("", "pos", "");
  221. pos.Value = d.OffsetPos.ToString();
  222. detectParamsN.Attributes.Append(pos);
  223. XmlAttribute d_linkNum = doc.CreateAttribute("", "linkNum", "");
  224. d_linkNum.Value = d.LinkNum.ToString();
  225. detectParamsN.Attributes.Append(d_linkNum);
  226. XmlAttribute d_group = doc.CreateAttribute("", "group", "");
  227. d_group.Value = d.Group.ToString();
  228. detectParamsN.Attributes.Append(d_group);
  229. XmlAttribute d_name = doc.CreateAttribute("", "name", "");
  230. d_name.Value = d.Name.ToString();
  231. detectParamsN.Attributes.Append(d_name);
  232. XmlAttribute d_owner = doc.CreateAttribute("", "owner", "");
  233. d_owner.Value = d.Owner.ToString();
  234. detectParamsN.Attributes.Append(d_owner);
  235. XmlAttribute d_position = doc.CreateAttribute("", "position", "");
  236. d_position.Value = d.Position.ToString();
  237. detectParamsN.Attributes.Append(d_position);
  238. XmlAttribute d_rotation = doc.CreateAttribute("", "rotation", "");
  239. d_rotation.Value = d.Rotation.ToString();
  240. detectParamsN.Attributes.Append(d_rotation);
  241. XmlAttribute d_type = doc.CreateAttribute("", "type", "");
  242. d_type.Value = d.Type.ToString();
  243. detectParamsN.Attributes.Append(d_type);
  244. XmlAttribute d_velocity = doc.CreateAttribute("", "velocity", "");
  245. d_velocity.Value = d.Velocity.ToString();
  246. detectParamsN.Attributes.Append(d_velocity);
  247. return detectParamsN;
  248. }
  249. /**
  250. * @brief Append elements of an array of objects to an XML parent.
  251. * @param doc = document the parent is part of
  252. * @param parent = parent to append the items to
  253. * @param array = array of objects
  254. * @param tag = <tag ..>...</tag> for each element
  255. */
  256. private static void AppendXMLObjectArray(XmlDocument doc, XmlNode parent, object[] array, string tag)
  257. {
  258. foreach(object o in array)
  259. {
  260. XmlElement element = GetXMLObject(doc, o, tag);
  261. parent.AppendChild(element);
  262. }
  263. }
  264. /**
  265. * @brief Get and XML representation of an object.
  266. * @param doc = document the tag will be put in
  267. * @param o = object to be represented
  268. * @param tag = <tag ...>...</tag>
  269. */
  270. private static XmlElement GetXMLObject(XmlDocument doc, object o, string tag)
  271. {
  272. XmlAttribute typ = doc.CreateAttribute("", "type", "");
  273. XmlElement n = doc.CreateElement("", tag, "");
  274. if(o is LSL_List)
  275. {
  276. typ.Value = "list";
  277. n.Attributes.Append(typ);
  278. AppendXMLObjectArray(doc, n, ((LSL_List)o).Data, "item");
  279. }
  280. else
  281. {
  282. typ.Value = o.GetType().ToString();
  283. n.Attributes.Append(typ);
  284. n.AppendChild(doc.CreateTextNode(o.ToString()));
  285. }
  286. return n;
  287. }
  288. }
  289. }