MOD_Api.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  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.Reflection;
  29. using System.Collections;
  30. using System.Collections.Generic;
  31. using System.Runtime.Remoting.Lifetime;
  32. using System.Threading;
  33. using log4net;
  34. using OpenMetaverse;
  35. using Nini.Config;
  36. using OpenSim;
  37. using OpenSim.Framework;
  38. using OpenSim.Region.Framework.Interfaces;
  39. using OpenSim.Region.Framework.Scenes;
  40. using OpenSim.Region.ScriptEngine.Shared;
  41. using OpenSim.Region.ScriptEngine.Shared.Api.Plugins;
  42. using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
  43. using OpenSim.Region.ScriptEngine.Interfaces;
  44. using OpenSim.Region.ScriptEngine.Shared.Api.Interfaces;
  45. using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
  46. using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
  47. using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  48. using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
  49. using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
  50. using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  51. using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
  52. namespace OpenSim.Region.ScriptEngine.Shared.Api
  53. {
  54. [Serializable]
  55. public class MOD_Api : MarshalByRefObject, IMOD_Api, IScriptApi
  56. {
  57. // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  58. internal IScriptEngine m_ScriptEngine;
  59. internal SceneObjectPart m_host;
  60. internal TaskInventoryItem m_item;
  61. internal bool m_MODFunctionsEnabled = false;
  62. internal IScriptModuleComms m_comms = null;
  63. public void Initialize(
  64. IScriptEngine scriptEngine, SceneObjectPart host, TaskInventoryItem item)
  65. {
  66. m_ScriptEngine = scriptEngine;
  67. m_host = host;
  68. m_item = item;
  69. if (m_ScriptEngine.Config.GetBoolean("AllowMODFunctions", false))
  70. m_MODFunctionsEnabled = true;
  71. m_comms = m_ScriptEngine.World.RequestModuleInterface<IScriptModuleComms>();
  72. if (m_comms == null)
  73. m_MODFunctionsEnabled = false;
  74. }
  75. public override Object InitializeLifetimeService()
  76. {
  77. ILease lease = (ILease)base.InitializeLifetimeService();
  78. if (lease.CurrentState == LeaseState.Initial)
  79. {
  80. lease.InitialLeaseTime = TimeSpan.FromMinutes(0);
  81. // lease.RenewOnCallTime = TimeSpan.FromSeconds(10.0);
  82. // lease.SponsorshipTimeout = TimeSpan.FromMinutes(1.0);
  83. }
  84. return lease;
  85. }
  86. public Scene World
  87. {
  88. get { return m_ScriptEngine.World; }
  89. }
  90. internal void MODError(string msg)
  91. {
  92. throw new ScriptException("MOD Runtime Error: " + msg);
  93. }
  94. /// <summary>
  95. /// Dumps an error message on the debug console.
  96. /// </summary>
  97. /// <param name='message'></param>
  98. internal void MODShoutError(string message)
  99. {
  100. if (message.Length > 1023)
  101. message = message.Substring(0, 1023);
  102. World.SimChat(
  103. Utils.StringToBytes(message),
  104. ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL,
  105. m_host.ParentGroup.RootPart.AbsolutePosition, m_host.Name, m_host.UUID, false);
  106. IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
  107. wComm.DeliverMessage(ChatTypeEnum.Shout, ScriptBaseClass.DEBUG_CHANNEL, m_host.Name, m_host.UUID, message);
  108. }
  109. /// <summary>
  110. ///
  111. /// </summary>
  112. /// <param name="fname">The name of the function to invoke</param>
  113. /// <param name="parms">List of parameters</param>
  114. /// <returns>string result of the invocation</returns>
  115. public void modInvokeN(string fname, params object[] parms)
  116. {
  117. // m_log.DebugFormat(
  118. // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
  119. // fname,
  120. // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
  121. // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
  122. Type returntype = m_comms.LookupReturnType(fname);
  123. if (returntype != typeof(string))
  124. MODError(String.Format("return type mismatch for {0}",fname));
  125. modInvoke(fname,parms);
  126. }
  127. public LSL_String modInvokeS(string fname, params object[] parms)
  128. {
  129. // m_log.DebugFormat(
  130. // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
  131. // fname,
  132. // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
  133. // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
  134. Type returntype = m_comms.LookupReturnType(fname);
  135. if (returntype != typeof(string))
  136. MODError(String.Format("return type mismatch for {0}",fname));
  137. string result = (string)modInvoke(fname,parms);
  138. return new LSL_String(result);
  139. }
  140. public LSL_Integer modInvokeI(string fname, params object[] parms)
  141. {
  142. // m_log.DebugFormat(
  143. // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
  144. // fname,
  145. // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
  146. // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
  147. Type returntype = m_comms.LookupReturnType(fname);
  148. if (returntype != typeof(int))
  149. MODError(String.Format("return type mismatch for {0}",fname));
  150. int result = (int)modInvoke(fname,parms);
  151. return new LSL_Integer(result);
  152. }
  153. public LSL_Float modInvokeF(string fname, params object[] parms)
  154. {
  155. // m_log.DebugFormat(
  156. // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
  157. // fname,
  158. // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
  159. // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
  160. Type returntype = m_comms.LookupReturnType(fname);
  161. if (returntype != typeof(float))
  162. MODError(String.Format("return type mismatch for {0}",fname));
  163. float result = (float)modInvoke(fname,parms);
  164. return new LSL_Float(result);
  165. }
  166. public LSL_Key modInvokeK(string fname, params object[] parms)
  167. {
  168. // m_log.DebugFormat(
  169. // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
  170. // fname,
  171. // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
  172. // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
  173. Type returntype = m_comms.LookupReturnType(fname);
  174. if (returntype != typeof(UUID))
  175. MODError(String.Format("return type mismatch for {0}",fname));
  176. UUID result = (UUID)modInvoke(fname,parms);
  177. return new LSL_Key(result.ToString());
  178. }
  179. public LSL_Vector modInvokeV(string fname, params object[] parms)
  180. {
  181. // m_log.DebugFormat(
  182. // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
  183. // fname,
  184. // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
  185. // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
  186. Type returntype = m_comms.LookupReturnType(fname);
  187. if (returntype != typeof(OpenMetaverse.Vector3))
  188. MODError(String.Format("return type mismatch for {0}",fname));
  189. OpenMetaverse.Vector3 result = (OpenMetaverse.Vector3)modInvoke(fname,parms);
  190. return new LSL_Vector(result.X,result.Y,result.Z);
  191. }
  192. public LSL_Rotation modInvokeR(string fname, params object[] parms)
  193. {
  194. // m_log.DebugFormat(
  195. // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
  196. // fname,
  197. // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
  198. // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
  199. Type returntype = m_comms.LookupReturnType(fname);
  200. if (returntype != typeof(OpenMetaverse.Quaternion))
  201. MODError(String.Format("return type mismatch for {0}",fname));
  202. OpenMetaverse.Quaternion result = (OpenMetaverse.Quaternion)modInvoke(fname,parms);
  203. return new LSL_Rotation(result.X,result.Y,result.Z,result.W);
  204. }
  205. public LSL_List modInvokeL(string fname, params object[] parms)
  206. {
  207. // m_log.DebugFormat(
  208. // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
  209. // fname,
  210. // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
  211. // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
  212. Type returntype = m_comms.LookupReturnType(fname);
  213. if (returntype != typeof(object[]))
  214. MODError(String.Format("return type mismatch for {0}",fname));
  215. object[] result = (object[])modInvoke(fname,parms);
  216. object[] llist = new object[result.Length];
  217. for (int i = 0; i < result.Length; i++)
  218. {
  219. if (result[i] is string)
  220. {
  221. llist[i] = new LSL_String((string)result[i]);
  222. }
  223. else if (result[i] is int)
  224. {
  225. llist[i] = new LSL_Integer((int)result[i]);
  226. }
  227. else if (result[i] is float)
  228. {
  229. llist[i] = new LSL_Float((float)result[i]);
  230. }
  231. else if (result[i] is double)
  232. {
  233. llist[i] = new LSL_Float((double)result[i]);
  234. }
  235. else if (result[i] is UUID)
  236. {
  237. llist[i] = new LSL_Key(result[i].ToString());
  238. }
  239. else if (result[i] is OpenMetaverse.Vector3)
  240. {
  241. OpenMetaverse.Vector3 vresult = (OpenMetaverse.Vector3)result[i];
  242. llist[i] = new LSL_Vector(vresult.X, vresult.Y, vresult.Z);
  243. }
  244. else if (result[i] is OpenMetaverse.Quaternion)
  245. {
  246. OpenMetaverse.Quaternion qresult = (OpenMetaverse.Quaternion)result[i];
  247. llist[i] = new LSL_Rotation(qresult.X, qresult.Y, qresult.Z, qresult.W);
  248. }
  249. else
  250. {
  251. MODError(String.Format("unknown list element {1} returned by {0}", fname, result[i].GetType().Name));
  252. }
  253. }
  254. return new LSL_List(llist);
  255. }
  256. /// <summary>
  257. /// Invokes a preregistered function through the ScriptModuleComms class
  258. /// </summary>
  259. /// <param name="fname">The name of the function to invoke</param>
  260. /// <param name="fname">List of parameters</param>
  261. /// <returns>string result of the invocation</returns>
  262. protected object modInvoke(string fname, params object[] parms)
  263. {
  264. if (!m_MODFunctionsEnabled)
  265. {
  266. MODShoutError("Module command functions not enabled");
  267. return "";
  268. }
  269. // m_log.DebugFormat(
  270. // "[MOD API]: Invoking dynamic function {0}, args '{1}' with {2} return type",
  271. // fname,
  272. // string.Join(",", Array.ConvertAll<object, string>(parms, o => o.ToString())),
  273. // ((MethodInfo)MethodBase.GetCurrentMethod()).ReturnType);
  274. Type[] signature = m_comms.LookupTypeSignature(fname);
  275. if (signature.Length != parms.Length)
  276. MODError(String.Format("wrong number of parameters to function {0}",fname));
  277. object[] convertedParms = new object[parms.Length];
  278. for (int i = 0; i < parms.Length; i++)
  279. convertedParms[i] = ConvertFromLSL(parms[i], signature[i], fname);
  280. // now call the function, the contract with the function is that it will always return
  281. // non-null but don't trust it completely
  282. try
  283. {
  284. object result = m_comms.InvokeOperation(m_host.UUID, m_item.ItemID, fname, convertedParms);
  285. if (result != null)
  286. return result;
  287. MODError(String.Format("Invocation of {0} failed; null return value",fname));
  288. }
  289. catch (Exception e)
  290. {
  291. MODError(String.Format("Invocation of {0} failed; {1}",fname,e.Message));
  292. }
  293. return null;
  294. }
  295. /// <summary>
  296. /// Send a command to functions registered on an event
  297. /// </summary>
  298. public string modSendCommand(string module, string command, string k)
  299. {
  300. if (!m_MODFunctionsEnabled)
  301. {
  302. MODShoutError("Module command functions not enabled");
  303. return UUID.Zero.ToString();;
  304. }
  305. UUID req = UUID.Random();
  306. m_comms.RaiseEvent(m_item.ItemID, req.ToString(), module, command, k);
  307. return req.ToString();
  308. }
  309. /// <summary>
  310. /// </summary>
  311. protected object ConvertFromLSL(object lslparm, Type type, string fname)
  312. {
  313. // ---------- String ----------
  314. if (lslparm is LSL_String)
  315. {
  316. if (type == typeof(string))
  317. return (string)(LSL_String)lslparm;
  318. // Need to check for UUID since keys are often treated as strings
  319. if (type == typeof(UUID))
  320. return new UUID((string)(LSL_String)lslparm);
  321. }
  322. // ---------- Integer ----------
  323. else if (lslparm is LSL_Integer)
  324. {
  325. if (type == typeof(int) || type == typeof(float))
  326. return (int)(LSL_Integer)lslparm;
  327. }
  328. // ---------- Float ----------
  329. else if (lslparm is LSL_Float)
  330. {
  331. if (type == typeof(float))
  332. return (float)(LSL_Float)lslparm;
  333. }
  334. // ---------- Key ----------
  335. else if (lslparm is LSL_Key)
  336. {
  337. if (type == typeof(UUID))
  338. return new UUID((LSL_Key)lslparm);
  339. }
  340. // ---------- Rotation ----------
  341. else if (lslparm is LSL_Rotation)
  342. {
  343. if (type == typeof(OpenMetaverse.Quaternion))
  344. {
  345. return (OpenMetaverse.Quaternion)((LSL_Rotation)lslparm);
  346. }
  347. }
  348. // ---------- Vector ----------
  349. else if (lslparm is LSL_Vector)
  350. {
  351. if (type == typeof(OpenMetaverse.Vector3))
  352. {
  353. return (OpenMetaverse.Vector3)((LSL_Vector)lslparm);
  354. }
  355. }
  356. // ---------- List ----------
  357. else if (lslparm is LSL_List)
  358. {
  359. if (type == typeof(object[]))
  360. {
  361. object[] plist = ((LSL_List)lslparm).Data;
  362. object[] result = new object[plist.Length];
  363. for (int i = 0; i < plist.Length; i++)
  364. {
  365. if (plist[i] is LSL_String)
  366. result[i] = (string)(LSL_String)plist[i];
  367. else if (plist[i] is LSL_Integer)
  368. result[i] = (int)(LSL_Integer)plist[i];
  369. // The int check exists because of the many plain old int script constants in ScriptBase which
  370. // are not LSL_Integers.
  371. else if (plist[i] is int)
  372. result[i] = plist[i];
  373. else if (plist[i] is LSL_Float)
  374. result[i] = (float)(LSL_Float)plist[i];
  375. else if (plist[i] is LSL_Key)
  376. result[i] = new UUID((LSL_Key)plist[i]);
  377. else if (plist[i] is LSL_Rotation)
  378. result[i] = (Quaternion)((LSL_Rotation)plist[i]);
  379. else if (plist[i] is LSL_Vector)
  380. result[i] = (Vector3)((LSL_Vector)plist[i]);
  381. else
  382. MODError(String.Format("{0}: unknown LSL list element type", fname));
  383. }
  384. return result;
  385. }
  386. }
  387. MODError(String.Format("{0}: parameter type mismatch; expecting {1}, type(parm)={2}", fname, type.Name, lslparm.GetType()));
  388. return null;
  389. }
  390. }
  391. }