OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
ConciergeModule.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.Collections;
30 using System.Collections.Generic;
31 using System.IO;
32 using System.Net;
33 using System.Net.Sockets;
34 using System.Reflection;
35 using System.Text;
36 using System.Text.RegularExpressions;
37 using System.Threading;
38 using log4net;
39 using Mono.Addins;
40 using Nini.Config;
41 using Nwc.XmlRpc;
42 using OpenMetaverse;
43 using OpenSim.Framework;
44 using OpenSim.Framework.Servers;
45 using OpenSim.Region.Framework.Interfaces;
46 using OpenSim.Region.Framework.Scenes;
47 using OpenSim.Region.CoreModules.Avatar.Chat;
48 
49 namespace OpenSim.Region.OptionalModules.Avatar.Concierge
50 {
51  [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "ConciergeModule")]
53  {
54  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 
56  private const int DEBUG_CHANNEL = 2147483647;
57 
58  private List<IScene> m_scenes = new List<IScene>();
59  private List<IScene> m_conciergedScenes = new List<IScene>();
60 
61  private bool m_replacingChatModule = false;
62 
63  private IConfig m_config;
64 
65  private string m_whoami = "conferencier";
66  private Regex m_regions = null;
67  private string m_welcomes = null;
68  private int m_conciergeChannel = 42;
69  private string m_announceEntering = "{0} enters {1} (now {2} visitors in this region)";
70  private string m_announceLeaving = "{0} leaves {1} (back to {2} visitors in this region)";
71  private string m_xmlRpcPassword = String.Empty;
72  private string m_brokerURI = String.Empty;
73  private int m_brokerUpdateTimeout = 300;
74 
75  internal object m_syncy = new object();
76 
77  internal bool m_enabled = false;
78 
79  #region ISharedRegionModule Members
80  public override void Initialise(IConfigSource config)
81  {
82  m_config = config.Configs["Concierge"];
83 
84  if (null == m_config)
85  return;
86 
87  if (!m_config.GetBoolean("enabled", false))
88  return;
89 
90  m_enabled = true;
91 
92 
93  // check whether ChatModule has been disabled: if yes,
94  // then we'll "stand in"
95  try
96  {
97  if (config.Configs["Chat"] == null)
98  {
99  // if Chat module has not been configured it's
100  // enabled by default, so we are not going to
101  // replace it.
102  m_replacingChatModule = false;
103  }
104  else
105  {
106  m_replacingChatModule = !config.Configs["Chat"].GetBoolean("enabled", true);
107  }
108  }
109  catch (Exception)
110  {
111  m_replacingChatModule = false;
112  }
113 
114  m_log.InfoFormat("[Concierge] {0} ChatModule", m_replacingChatModule ? "replacing" : "not replacing");
115 
116  // take note of concierge channel and of identity
117  m_conciergeChannel = config.Configs["Concierge"].GetInt("concierge_channel", m_conciergeChannel);
118  m_whoami = m_config.GetString("whoami", "conferencier");
119  m_welcomes = m_config.GetString("welcomes", m_welcomes);
120  m_announceEntering = m_config.GetString("announce_entering", m_announceEntering);
121  m_announceLeaving = m_config.GetString("announce_leaving", m_announceLeaving);
122  m_xmlRpcPassword = m_config.GetString("password", m_xmlRpcPassword);
123  m_brokerURI = m_config.GetString("broker", m_brokerURI);
124  m_brokerUpdateTimeout = m_config.GetInt("broker_timeout", m_brokerUpdateTimeout);
125 
126  m_log.InfoFormat("[Concierge] reporting as \"{0}\" to our users", m_whoami);
127 
128  // calculate regions Regex
129  if (m_regions == null)
130  {
131  string regions = m_config.GetString("regions", String.Empty);
132  if (!String.IsNullOrEmpty(regions))
133  {
134  m_regions = new Regex(@regions, RegexOptions.Compiled | RegexOptions.IgnoreCase);
135  }
136  }
137  }
138 
139 
140  public override void AddRegion(Scene scene)
141  {
142  if (!m_enabled) return;
143 
144  MainServer.Instance.AddXmlRPCHandler("concierge_update_welcome", XmlRpcUpdateWelcomeMethod, false);
145 
146  lock (m_syncy)
147  {
148  if (!m_scenes.Contains(scene))
149  {
150  m_scenes.Add(scene);
151 
152  if (m_regions == null || m_regions.IsMatch(scene.RegionInfo.RegionName))
153  m_conciergedScenes.Add(scene);
154 
155  // subscribe to NewClient events
156  scene.EventManager.OnNewClient += OnNewClient;
157 
158  // subscribe to *Chat events
159  scene.EventManager.OnChatFromWorld += OnChatFromWorld;
160  if (!m_replacingChatModule)
161  scene.EventManager.OnChatFromClient += OnChatFromClient;
162  scene.EventManager.OnChatBroadcast += OnChatBroadcast;
163 
164  // subscribe to agent change events
165  scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
166  scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;
167  }
168  }
169  m_log.InfoFormat("[Concierge]: initialized for {0}", scene.RegionInfo.RegionName);
170  }
171 
172  public override void RemoveRegion(Scene scene)
173  {
174  if (!m_enabled) return;
175 
176  MainServer.Instance.RemoveXmlRPCHandler("concierge_update_welcome");
177 
178  lock (m_syncy)
179  {
180  // unsubscribe from NewClient events
181  scene.EventManager.OnNewClient -= OnNewClient;
182 
183  // unsubscribe from *Chat events
184  scene.EventManager.OnChatFromWorld -= OnChatFromWorld;
185  if (!m_replacingChatModule)
186  scene.EventManager.OnChatFromClient -= OnChatFromClient;
187  scene.EventManager.OnChatBroadcast -= OnChatBroadcast;
188 
189  // unsubscribe from agent change events
190  scene.EventManager.OnMakeRootAgent -= OnMakeRootAgent;
191  scene.EventManager.OnMakeChildAgent -= OnMakeChildAgent;
192 
193  if (m_scenes.Contains(scene))
194  {
195  m_scenes.Remove(scene);
196  }
197 
198  if (m_conciergedScenes.Contains(scene))
199  {
200  m_conciergedScenes.Remove(scene);
201  }
202  }
203  m_log.InfoFormat("[Concierge]: removed {0}", scene.RegionInfo.RegionName);
204  }
205 
206  public override void PostInitialise()
207  {
208  }
209 
210  public override void Close()
211  {
212  }
213 
214  new public Type ReplaceableInterface
215  {
216  get { return null; }
217  }
218 
219  public override string Name
220  {
221  get { return "ConciergeModule"; }
222  }
223  #endregion
224 
225  #region ISimChat Members
226  public override void OnChatBroadcast(Object sender, OSChatMessage c)
227  {
228  if (m_replacingChatModule)
229  {
230  // distribute chat message to each and every avatar in
231  // the region
232  base.OnChatBroadcast(sender, c);
233  }
234 
235  // TODO: capture logic
236  return;
237  }
238 
239  public override void OnChatFromClient(Object sender, OSChatMessage c)
240  {
241  if (m_replacingChatModule)
242  {
243  // replacing ChatModule: need to redistribute
244  // ChatFromClient to interested subscribers
245  c = FixPositionOfChatMessage(c);
246 
247  Scene scene = (Scene)c.Scene;
248  scene.EventManager.TriggerOnChatFromClient(sender, c);
249 
250  if (m_conciergedScenes.Contains(c.Scene))
251  {
252  // when we are replacing ChatModule, we treat
253  // OnChatFromClient like OnChatBroadcast for
254  // concierged regions, effectively extending the
255  // range of chat to cover the whole
256  // region. however, we don't do this for whisper
257  // (got to have some privacy)
258  if (c.Type != ChatTypeEnum.Whisper)
259  {
260  base.OnChatBroadcast(sender, c);
261  return;
262  }
263  }
264 
265  // redistribution will be done by base class
266  base.OnChatFromClient(sender, c);
267  }
268 
269  // TODO: capture chat
270  return;
271  }
272 
273  public override void OnChatFromWorld(Object sender, OSChatMessage c)
274  {
275  if (m_replacingChatModule)
276  {
277  if (m_conciergedScenes.Contains(c.Scene))
278  {
279  // when we are replacing ChatModule, we treat
280  // OnChatFromClient like OnChatBroadcast for
281  // concierged regions, effectively extending the
282  // range of chat to cover the whole
283  // region. however, we don't do this for whisper
284  // (got to have some privacy)
285  if (c.Type != ChatTypeEnum.Whisper)
286  {
287  base.OnChatBroadcast(sender, c);
288  return;
289  }
290  }
291 
292  base.OnChatFromWorld(sender, c);
293  }
294  return;
295  }
296  #endregion
297 
298 
299  public override void OnNewClient(IClientAPI client)
300  {
301  client.OnLogout += OnClientLoggedOut;
302 
303  if (m_replacingChatModule)
304  client.OnChatFromClient += OnChatFromClient;
305  }
306 
307 
308 
309  public void OnClientLoggedOut(IClientAPI client)
310  {
311  client.OnLogout -= OnClientLoggedOut;
312  client.OnConnectionClosed -= OnClientLoggedOut;
313 
314  if (m_conciergedScenes.Contains(client.Scene))
315  {
316  Scene scene = client.Scene as Scene;
317  m_log.DebugFormat("[Concierge]: {0} logs off from {1}", client.Name, scene.RegionInfo.RegionName);
318  AnnounceToAgentsRegion(scene, String.Format(m_announceLeaving, client.Name, scene.RegionInfo.RegionName, scene.GetRootAgentCount()));
319  UpdateBroker(scene);
320  }
321  }
322 
323 
324  public void OnMakeRootAgent(ScenePresence agent)
325  {
326  if (m_conciergedScenes.Contains(agent.Scene))
327  {
328  Scene scene = agent.Scene;
329  m_log.DebugFormat("[Concierge]: {0} enters {1}", agent.Name, scene.RegionInfo.RegionName);
330  WelcomeAvatar(agent, scene);
331  AnnounceToAgentsRegion(scene, String.Format(m_announceEntering, agent.Name,
332  scene.RegionInfo.RegionName, scene.GetRootAgentCount()));
333  UpdateBroker(scene);
334  }
335  }
336 
337 
338  public void OnMakeChildAgent(ScenePresence agent)
339  {
340  if (m_conciergedScenes.Contains(agent.Scene))
341  {
342  Scene scene = agent.Scene;
343  m_log.DebugFormat("[Concierge]: {0} leaves {1}", agent.Name, scene.RegionInfo.RegionName);
344  AnnounceToAgentsRegion(scene, String.Format(m_announceLeaving, agent.Name,
345  scene.RegionInfo.RegionName, scene.GetRootAgentCount()));
346  UpdateBroker(scene);
347  }
348  }
349 
350  internal class BrokerState
351  {
352  public string Uri;
353  public string Payload;
354  public HttpWebRequest Poster;
355  public Timer Timer;
356 
357  public BrokerState(string uri, string payload, HttpWebRequest poster)
358  {
359  Uri = uri;
360  Payload = payload;
361  Poster = poster;
362  }
363  }
364 
365  protected void UpdateBroker(Scene scene)
366  {
367  if (String.IsNullOrEmpty(m_brokerURI))
368  return;
369 
370  string uri = String.Format(m_brokerURI, scene.RegionInfo.RegionName, scene.RegionInfo.RegionID);
371 
372  // create XML sniplet
373  StringBuilder list = new StringBuilder();
374  list.Append(String.Format("<avatars count=\"{0}\" region_name=\"{1}\" region_uuid=\"{2}\" timestamp=\"{3}\">\n",
375  scene.GetRootAgentCount(), scene.RegionInfo.RegionName,
376  scene.RegionInfo.RegionID,
377  DateTime.UtcNow.ToString("s")));
378 
379  scene.ForEachRootScenePresence(delegate(ScenePresence sp)
380  {
381  list.Append(String.Format(" <avatar name=\"{0}\" uuid=\"{1}\" />\n", sp.Name, sp.UUID));
382  });
383 
384  list.Append("</avatars>");
385  string payload = list.ToString();
386 
387  // post via REST to broker
388  HttpWebRequest updatePost = WebRequest.Create(uri) as HttpWebRequest;
389  updatePost.Method = "POST";
390  updatePost.ContentType = "text/xml";
391  updatePost.ContentLength = payload.Length;
392  updatePost.UserAgent = "OpenSim.Concierge";
393 
394 
395  BrokerState bs = new BrokerState(uri, payload, updatePost);
396  bs.Timer = new Timer(delegate(object state)
397  {
398  BrokerState b = state as BrokerState;
399  b.Poster.Abort();
400  b.Timer.Dispose();
401  m_log.Debug("[Concierge]: async broker POST abort due to timeout");
402  }, bs, m_brokerUpdateTimeout * 1000, Timeout.Infinite);
403 
404  try
405  {
406  updatePost.BeginGetRequestStream(UpdateBrokerSend, bs);
407  m_log.DebugFormat("[Concierge] async broker POST to {0} started", uri);
408  }
409  catch (WebException we)
410  {
411  m_log.ErrorFormat("[Concierge] async broker POST to {0} failed: {1}", uri, we.Status);
412  }
413  }
414 
415  private void UpdateBrokerSend(IAsyncResult result)
416  {
417  BrokerState bs = null;
418  try
419  {
420  bs = result.AsyncState as BrokerState;
421  string payload = bs.Payload;
422  HttpWebRequest updatePost = bs.Poster;
423 
424  using (StreamWriter payloadStream = new StreamWriter(updatePost.EndGetRequestStream(result)))
425  {
426  payloadStream.Write(payload);
427  payloadStream.Close();
428  }
429  updatePost.BeginGetResponse(UpdateBrokerDone, bs);
430  }
431  catch (WebException we)
432  {
433  m_log.DebugFormat("[Concierge]: async broker POST to {0} failed: {1}", bs.Uri, we.Status);
434  }
435  catch (Exception)
436  {
437  m_log.DebugFormat("[Concierge]: async broker POST to {0} failed", bs.Uri);
438  }
439  }
440 
441  private void UpdateBrokerDone(IAsyncResult result)
442  {
443  BrokerState bs = null;
444  try
445  {
446  bs = result.AsyncState as BrokerState;
447  HttpWebRequest updatePost = bs.Poster;
448  using (HttpWebResponse response = updatePost.EndGetResponse(result) as HttpWebResponse)
449  {
450  m_log.DebugFormat("[Concierge] broker update: status {0}", response.StatusCode);
451  }
452  bs.Timer.Dispose();
453  }
454  catch (WebException we)
455  {
456  m_log.ErrorFormat("[Concierge] broker update to {0} failed with status {1}", bs.Uri, we.Status);
457  if (null != we.Response)
458  {
459  using (HttpWebResponse resp = we.Response as HttpWebResponse)
460  {
461  m_log.ErrorFormat("[Concierge] response from {0} status code: {1}", bs.Uri, resp.StatusCode);
462  m_log.ErrorFormat("[Concierge] response from {0} status desc: {1}", bs.Uri, resp.StatusDescription);
463  m_log.ErrorFormat("[Concierge] response from {0} server: {1}", bs.Uri, resp.Server);
464 
465  if (resp.ContentLength > 0)
466  {
467  StreamReader content = new StreamReader(resp.GetResponseStream());
468  m_log.ErrorFormat("[Concierge] response from {0} content: {1}", bs.Uri, content.ReadToEnd());
469  content.Close();
470  }
471  }
472  }
473  }
474  }
475 
476  protected void WelcomeAvatar(ScenePresence agent, Scene scene)
477  {
478  // welcome mechanics: check whether we have a welcomes
479  // directory set and wether there is a region specific
480  // welcome file there: if yes, send it to the agent
481  if (!String.IsNullOrEmpty(m_welcomes))
482  {
483  string[] welcomes = new string[] {
484  Path.Combine(m_welcomes, agent.Scene.RegionInfo.RegionName),
485  Path.Combine(m_welcomes, "DEFAULT")};
486  foreach (string welcome in welcomes)
487  {
488  if (File.Exists(welcome))
489  {
490  try
491  {
492  string[] welcomeLines = File.ReadAllLines(welcome);
493  foreach (string l in welcomeLines)
494  {
495  AnnounceToAgent(agent, String.Format(l, agent.Name, scene.RegionInfo.RegionName, m_whoami));
496  }
497  }
498  catch (IOException ioe)
499  {
500  m_log.ErrorFormat("[Concierge]: run into trouble reading welcome file {0} for region {1} for avatar {2}: {3}",
501  welcome, scene.RegionInfo.RegionName, agent.Name, ioe);
502  }
503  catch (FormatException fe)
504  {
505  m_log.ErrorFormat("[Concierge]: welcome file {0} is malformed: {1}", welcome, fe);
506  }
507  }
508  return;
509  }
510  m_log.DebugFormat("[Concierge]: no welcome message for region {0}", scene.RegionInfo.RegionName);
511  }
512  }
513 
514  static private Vector3 PosOfGod = new Vector3(128, 128, 9999);
515 
516  // protected void AnnounceToAgentsRegion(Scene scene, string msg)
517  // {
518  // ScenePresence agent = null;
519  // if ((client.Scene is Scene) && (client.Scene as Scene).TryGetScenePresence(client.AgentId, out agent))
520  // AnnounceToAgentsRegion(agent, msg);
521  // else
522  // m_log.DebugFormat("[Concierge]: could not find an agent for client {0}", client.Name);
523  // }
524 
525  protected void AnnounceToAgentsRegion(IScene scene, string msg)
526  {
527  OSChatMessage c = new OSChatMessage();
528  c.Message = msg;
529  c.Type = ChatTypeEnum.Say;
530  c.Channel = 0;
531  c.Position = PosOfGod;
532  c.From = m_whoami;
533  c.Sender = null;
534  c.SenderUUID = UUID.Zero;
535  c.Scene = scene;
536 
537  if (scene is Scene)
538  (scene as Scene).EventManager.TriggerOnChatBroadcast(this, c);
539  }
540 
541  protected void AnnounceToAgent(ScenePresence agent, string msg)
542  {
543  OSChatMessage c = new OSChatMessage();
544  c.Message = msg;
545  c.Type = ChatTypeEnum.Say;
546  c.Channel = 0;
547  c.Position = PosOfGod;
548  c.From = m_whoami;
549  c.Sender = null;
550  c.SenderUUID = UUID.Zero;
551  c.Scene = agent.Scene;
552 
553  agent.ControllingClient.SendChatMessage(
554  msg, (byte) ChatTypeEnum.Say, PosOfGod, m_whoami, UUID.Zero, UUID.Zero,
555  (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully);
556  }
557 
558  private static void checkStringParameters(XmlRpcRequest request, string[] param)
559  {
560  Hashtable requestData = (Hashtable) request.Params[0];
561  foreach (string p in param)
562  {
563  if (!requestData.Contains(p))
564  throw new Exception(String.Format("missing string parameter {0}", p));
565  if (String.IsNullOrEmpty((string)requestData[p]))
566  throw new Exception(String.Format("parameter {0} is empty", p));
567  }
568  }
569 
570  public XmlRpcResponse XmlRpcUpdateWelcomeMethod(XmlRpcRequest request, IPEndPoint remoteClient)
571  {
572  m_log.Info("[Concierge]: processing UpdateWelcome request");
573  XmlRpcResponse response = new XmlRpcResponse();
574  Hashtable responseData = new Hashtable();
575 
576  try
577  {
578  Hashtable requestData = (Hashtable)request.Params[0];
579  checkStringParameters(request, new string[] { "password", "region", "welcome" });
580 
581  // check password
582  if (!String.IsNullOrEmpty(m_xmlRpcPassword) &&
583  (string)requestData["password"] != m_xmlRpcPassword) throw new Exception("wrong password");
584 
585  if (String.IsNullOrEmpty(m_welcomes))
586  throw new Exception("welcome templates are not enabled, ask your OpenSim operator to set the \"welcomes\" option in the [Concierge] section of OpenSim.ini");
587 
588  string msg = (string)requestData["welcome"];
589  if (String.IsNullOrEmpty(msg))
590  throw new Exception("empty parameter \"welcome\"");
591 
592  string regionName = (string)requestData["region"];
593  IScene scene = m_scenes.Find(delegate(IScene s) { return s.RegionInfo.RegionName == regionName; });
594  if (scene == null)
595  throw new Exception(String.Format("unknown region \"{0}\"", regionName));
596 
597  if (!m_conciergedScenes.Contains(scene))
598  throw new Exception(String.Format("region \"{0}\" is not a concierged region.", regionName));
599 
600  string welcome = Path.Combine(m_welcomes, regionName);
601  if (File.Exists(welcome))
602  {
603  m_log.InfoFormat("[Concierge]: UpdateWelcome: updating existing template \"{0}\"", welcome);
604  string welcomeBackup = String.Format("{0}~", welcome);
605  if (File.Exists(welcomeBackup))
606  File.Delete(welcomeBackup);
607  File.Move(welcome, welcomeBackup);
608  }
609  File.WriteAllText(welcome, msg);
610 
611  responseData["success"] = "true";
612  response.Value = responseData;
613  }
614  catch (Exception e)
615  {
616  m_log.InfoFormat("[Concierge]: UpdateWelcome failed: {0}", e.Message);
617 
618  responseData["success"] = "false";
619  responseData["error"] = e.Message;
620 
621  response.Value = responseData;
622  }
623  m_log.Debug("[Concierge]: done processing UpdateWelcome request");
624  return response;
625  }
626  }
627 }
override void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
Scene Scene
The scene to which this entity belongs
Definition: EntityBase.cs:46
string Name
Returns the full name of the agent/avatar represented by this client
Definition: IClientAPI.cs:754
override void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
override void Initialise(IConfigSource config)
This is called to initialize the region module. For shared modules, this is called exactly once...
System.Timers.Timer Timer
override void OnChatFromClient(Object sender, OSChatMessage c)
override void OnChatBroadcast(Object sender, OSChatMessage c)
override void OnChatFromWorld(Object sender, OSChatMessage c)
override void PostInitialise()
This is called exactly once after all the shared region-modules have been instanciated and IRegionMod...
ChatFromViewer Arguments
void TriggerOnChatBroadcast(Object sender, OSChatMessage chat)
ChatTypeEnum Type
The type of message, eg say, shout, broadcast.
XmlRpcResponse XmlRpcUpdateWelcomeMethod(XmlRpcRequest request, IPEndPoint remoteClient)
override void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
Interactive OpenSim region server
Definition: OpenSim.cs:55
A class for triggering remote scene events.
Definition: EventManager.cs:44
virtual string Name
The name of this entity
Definition: EntityBase.cs:65
void TriggerOnChatFromClient(Object sender, OSChatMessage chat)