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