OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
ScriptModuleCommsModule.cs
Go to the documentation of this file.
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 
28 using System;
29 using System.Reflection;
30 using System.Collections.Generic;
31 using Nini.Config;
32 using log4net;
33 using OpenSim.Framework;
34 using OpenSim.Region.Framework.Interfaces;
35 using OpenSim.Region.Framework.Scenes;
36 using Mono.Addins;
37 using OpenMetaverse;
38 using System.Linq;
39 using System.Linq.Expressions;
40 
41 namespace OpenSim.Region.CoreModules.Scripting.ScriptModuleComms
42 {
43  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ScriptModuleCommsModule")]
45  {
46  private static readonly ILog m_log =
47  LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48  private static string LogHeader = "[MODULE COMMS]";
49 
50  private Dictionary<string,object> m_constants = new Dictionary<string,object>();
51 
52 #region ScriptInvocation
53  protected class ScriptInvocationData
54  {
55  public Delegate ScriptInvocationDelegate { get; private set; }
56  public string FunctionName { get; private set; }
57  public Type[] TypeSignature { get; private set; }
58  public Type ReturnType { get; private set; }
59 
60  public ScriptInvocationData(string fname, Delegate fn, Type[] callsig, Type returnsig)
61  {
62  FunctionName = fname;
63  ScriptInvocationDelegate = fn;
64  TypeSignature = callsig;
65  ReturnType = returnsig;
66  }
67  }
68 
69  private Dictionary<string,ScriptInvocationData> m_scriptInvocation = new Dictionary<string,ScriptInvocationData>();
70 #endregion
71 
72  private IScriptModule m_scriptModule = null;
74 
75 #region RegionModuleInterface
76  public void Initialise(IConfigSource config)
77  {
78  }
79 
80  public void AddRegion(Scene scene)
81  {
82  scene.RegisterModuleInterface<IScriptModuleComms>(this);
83  }
84 
85  public void RemoveRegion(Scene scene)
86  {
87  }
88 
89  public void RegionLoaded(Scene scene)
90  {
91  m_scriptModule = scene.RequestModuleInterface<IScriptModule>();
92 
93  if (m_scriptModule != null)
94  m_log.Info("[MODULE COMMANDS]: Script engine found, module active");
95  }
96 
97  public string Name
98  {
99  get { return "ScriptModuleCommsModule"; }
100  }
101 
102  public Type ReplaceableInterface
103  {
104  get { return null; }
105  }
106 
107  public void Close()
108  {
109  }
110 #endregion
111 
112 #region ScriptModuleComms
113 
114  public void RaiseEvent(UUID script, string id, string module, string command, string k)
115  {
116  ScriptCommand c = OnScriptCommand;
117 
118  if (c == null)
119  return;
120 
121  c(script, id, module, command, k);
122  }
123 
124  public void DispatchReply(UUID script, int code, string text, string k)
125  {
126  if (m_scriptModule == null)
127  return;
128 
129  Object[] args = new Object[] {-1, code, text, k};
130 
131  m_scriptModule.PostScriptEvent(script, "link_message", args);
132  }
133 
134  private static MethodInfo GetMethodInfoFromType(Type target, string meth, bool searchInstanceMethods)
135  {
136  BindingFlags getMethodFlags =
137  BindingFlags.NonPublic | BindingFlags.Public;
138 
139  if (searchInstanceMethods)
140  getMethodFlags |= BindingFlags.Instance;
141  else
142  getMethodFlags |= BindingFlags.Static;
143 
144  return target.GetMethod(meth, getMethodFlags);
145  }
146 
147  public void RegisterScriptInvocation(object target, string meth)
148  {
149  MethodInfo mi = GetMethodInfoFromType(target.GetType(), meth, true);
150  if (mi == null)
151  {
152  m_log.WarnFormat("{0} Failed to register method {1}", LogHeader, meth);
153  return;
154  }
155 
156  RegisterScriptInvocation(target, mi);
157  }
158 
159  public void RegisterScriptInvocation(object target, string[] meth)
160  {
161  foreach (string m in meth)
162  RegisterScriptInvocation(target, m);
163  }
164 
165  public void RegisterScriptInvocation(object target, MethodInfo mi)
166  {
167 // m_log.DebugFormat("[MODULE COMMANDS] Register method {0} from type {1}", mi.Name, (target is Type) ? ((Type)target).Name : target.GetType().Name);
168 
169  Type delegateType = typeof(void);
170  List<Type> typeArgs = mi.GetParameters()
171  .Select(p => p.ParameterType)
172  .ToList();
173 
174  if (mi.ReturnType == typeof(void))
175  {
176  delegateType = Expression.GetActionType(typeArgs.ToArray());
177  }
178  else
179  {
180  try
181  {
182  typeArgs.Add(mi.ReturnType);
183  delegateType = Expression.GetFuncType(typeArgs.ToArray());
184  }
185  catch (Exception e)
186  {
187  m_log.ErrorFormat("{0} Failed to create function signature. Most likely more than 5 parameters. Method={1}. Error={2}",
188  LogHeader, mi.Name, e);
189  }
190  }
191 
192  Delegate fcall;
193  if (!(target is Type))
194  fcall = Delegate.CreateDelegate(delegateType, target, mi);
195  else
196  fcall = Delegate.CreateDelegate(delegateType, (Type)target, mi.Name);
197 
198  lock (m_scriptInvocation)
199  {
200  ParameterInfo[] parameters = fcall.Method.GetParameters();
201  if (parameters.Length < 2) // Must have two UUID params
202  return;
203 
204  // Hide the first two parameters
205  Type[] parmTypes = new Type[parameters.Length - 2];
206  for (int i = 2; i < parameters.Length; i++)
207  parmTypes[i - 2] = parameters[i].ParameterType;
208  m_scriptInvocation[fcall.Method.Name] = new ScriptInvocationData(fcall.Method.Name, fcall, parmTypes, fcall.Method.ReturnType);
209  }
210  }
211 
212  public void RegisterScriptInvocation(Type target, string[] methods)
213  {
214  foreach (string method in methods)
215  {
216  MethodInfo mi = GetMethodInfoFromType(target, method, false);
217  if (mi == null)
218  m_log.WarnFormat("[MODULE COMMANDS] Failed to register method {0}", method);
219  else
220  RegisterScriptInvocation(target, mi);
221  }
222  }
223 
225  {
226  foreach(MethodInfo method in target.GetType().GetMethods(
227  BindingFlags.Public | BindingFlags.Instance |
228  BindingFlags.Static))
229  {
230  if(method.GetCustomAttributes(
231  typeof(ScriptInvocationAttribute), true).Any())
232  {
233  if(method.IsStatic)
234  RegisterScriptInvocation(target.GetType(), method);
235  else
236  RegisterScriptInvocation(target, method);
237  }
238  }
239  }
240 
241  public Delegate[] GetScriptInvocationList()
242  {
243  List<Delegate> ret = new List<Delegate>();
244 
245  lock (m_scriptInvocation)
246  {
247  foreach (ScriptInvocationData d in m_scriptInvocation.Values)
248  ret.Add(d.ScriptInvocationDelegate);
249  }
250  return ret.ToArray();
251  }
252 
253  public string LookupModInvocation(string fname)
254  {
255  lock (m_scriptInvocation)
256  {
258  if (m_scriptInvocation.TryGetValue(fname,out sid))
259  {
260  if (sid.ReturnType == typeof(string))
261  return "modInvokeS";
262  else if (sid.ReturnType == typeof(int))
263  return "modInvokeI";
264  else if (sid.ReturnType == typeof(float))
265  return "modInvokeF";
266  else if (sid.ReturnType == typeof(UUID))
267  return "modInvokeK";
268  else if (sid.ReturnType == typeof(OpenMetaverse.Vector3))
269  return "modInvokeV";
270  else if (sid.ReturnType == typeof(OpenMetaverse.Quaternion))
271  return "modInvokeR";
272  else if (sid.ReturnType == typeof(object[]))
273  return "modInvokeL";
274  else if (sid.ReturnType == typeof(void))
275  return "modInvokeN";
276 
277  m_log.WarnFormat("[MODULE COMMANDS] failed to find match for {0} with return type {1}",fname,sid.ReturnType.Name);
278  }
279  }
280 
281  return null;
282  }
283 
284  public Delegate LookupScriptInvocation(string fname)
285  {
286  lock (m_scriptInvocation)
287  {
289  if (m_scriptInvocation.TryGetValue(fname,out sid))
290  return sid.ScriptInvocationDelegate;
291  }
292 
293  return null;
294  }
295 
296  public Type[] LookupTypeSignature(string fname)
297  {
298  lock (m_scriptInvocation)
299  {
301  if (m_scriptInvocation.TryGetValue(fname,out sid))
302  return sid.TypeSignature;
303  }
304 
305  return null;
306  }
307 
308  public Type LookupReturnType(string fname)
309  {
310  lock (m_scriptInvocation)
311  {
313  if (m_scriptInvocation.TryGetValue(fname,out sid))
314  return sid.ReturnType;
315  }
316 
317  return null;
318  }
319 
320  public object InvokeOperation(UUID hostid, UUID scriptid, string fname, params object[] parms)
321  {
322  List<object> olist = new List<object>();
323  olist.Add(hostid);
324  olist.Add(scriptid);
325  foreach (object o in parms)
326  olist.Add(o);
327  Delegate fn = LookupScriptInvocation(fname);
328  return fn.DynamicInvoke(olist.ToArray());
329  }
330 
335  public void RegisterConstant(string cname, object value)
336  {
337 // m_log.DebugFormat("[MODULE COMMANDS] register constant <{0}> with value {1}",cname,value.ToString());
338  lock (m_constants)
339  {
340  m_constants.Add(cname,value);
341  }
342  }
343 
345  {
346  foreach (FieldInfo field in target.GetType().GetFields(
347  BindingFlags.Public | BindingFlags.Static |
348  BindingFlags.Instance))
349  {
350  if (field.GetCustomAttributes(
351  typeof(ScriptConstantAttribute), true).Any())
352  {
353  RegisterConstant(field.Name, field.GetValue(target));
354  }
355  }
356  }
357 
361  public object LookupModConstant(string cname)
362  {
363  // m_log.DebugFormat("[MODULE COMMANDS] lookup constant <{0}>",cname);
364 
365  lock (m_constants)
366  {
367  object value = null;
368  if (m_constants.TryGetValue(cname,out value))
369  return value;
370  }
371 
372  return null;
373  }
374 
378  public Dictionary<string, object> GetConstants()
379  {
380  Dictionary<string, object> ret = new Dictionary<string, object>();
381 
382  lock (m_constants)
383  {
384  foreach (KeyValuePair<string, object> kvp in m_constants)
385  ret[kvp.Key] = kvp.Value;
386  }
387 
388  return ret;
389  }
390 
391 #endregion
392 
393  }
394 }
delegate void ScriptCommand(UUID script, string id, string module, string command, string k)
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
Delegate[] GetScriptInvocationList()
Returns an array of all registered script calls
void RegisterConstants(IRegionModuleBase target)
Automatically register all constants on a region module by checking for fields with ScriptConstantAtt...
object InvokeOperation(UUID hostid, UUID scriptid, string fname, params object[] parms)
object LookupModConstant(string cname)
Operation to check for a registered constant
void RegisterConstant(string cname, object value)
Operation to for a region module to register a constant to be used by the script engine ...
void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
void RaiseEvent(UUID script, string id, string module, string command, string k)
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
void RegisterScriptInvocation(Type target, string[] methods)
Register one or more static methods as script calls by method name
void RegisterScriptInvocation(object target, string[] meth)
Register one or more instance methods as script calls by method name
Interface for communication between OpenSim modules and in-world scripts
Interactive OpenSim region server
Definition: OpenSim.cs:55
void DispatchReply(UUID script, int code, string text, string k)
Send a link_message event to an in-world script
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
void RegisterScriptInvocations(IRegionModuleBase target)
Automatically register script invocations by checking for methods with ScriptInvocationAttribute. Should only check public methods.
void RegisterScriptInvocation(object target, MethodInfo mi)
Register a static or instance method as a script call by method info
void RegisterScriptInvocation(object target, string meth)
Register an instance method as a script call by method name
Dictionary< string, object > GetConstants()
Get all registered constants