aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/WorldCommModule.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Environment/Modules/WorldCommModule.cs481
1 files changed, 481 insertions, 0 deletions
diff --git a/OpenSim/Region/Environment/Modules/WorldCommModule.cs b/OpenSim/Region/Environment/Modules/WorldCommModule.cs
new file mode 100644
index 0000000..c2ec699
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/WorldCommModule.cs
@@ -0,0 +1,481 @@
1using System;
2using System.IO;
3using System.Net.Sockets;
4using System.Text;
5using System.Threading;
6using libsecondlife;
7using OpenSim.Framework.Interfaces;
8using OpenSim.Framework.Utilities;
9using OpenSim.Region.Environment.Interfaces;
10using OpenSim.Region.Environment.Scenes;
11using OpenSim.Framework.Servers;
12using Nwc.XmlRpc;
13using System.Collections;
14using System.Collections.Generic;
15
16/*****************************************************
17 *
18 * WorldCommModule
19 *
20 *
21 * Holding place for world comms - basically llListen
22 * function implementation.
23 *
24 * lLListen(integer channel, string name, key id, string msg)
25 * The name, id, and msg arguments specify the filtering
26 * criteria. You can pass the empty string
27 * (or NULL_KEY for id) for these to set a completely
28 * open filter; this causes the listen() event handler to be
29 * invoked for all chat on the channel. To listen only
30 * for chat spoken by a specific object or avatar,
31 * specify the name and/or id arguments. To listen
32 * only for a specific command, specify the
33 * (case-sensitive) msg argument. If msg is not empty,
34 * listener will only hear strings which are exactly equal
35 * to msg. You can also use all the arguments to establish
36 * the most restrictive filtering criteria.
37 *
38 * It might be useful for each listener to maintain a message
39 * digest, with a list of recent messages by UUID. This can
40 * be used to prevent in-world repeater loops. However, the
41 * linden functions do not have this capability, so for now
42 * thats the way it works.
43 *
44 * **************************************************/
45namespace OpenSim.Region.Environment.Modules
46{
47 public class WorldCommModule : IRegionModule, IWorldComm
48 {
49 private Scene m_scene;
50 private object CommListLock = new object();
51 private string m_name = "WorldCommModule";
52 private ListenerManager m_listenerManager;
53 private Queue<ListenerInfo> m_pending;
54
55 public WorldCommModule()
56 {
57 }
58
59 public void Initialise(Scene scene)
60 {
61
62 m_scene = scene;
63 m_scene.RegisterModuleInterface<IWorldComm>(this);
64 m_listenerManager = new ListenerManager();
65 m_pending = new Queue<ListenerInfo>();
66 m_scene.EventManager.OnNewClient += NewClient;
67
68 }
69
70 public void PostInitialise()
71 {
72 }
73
74 public void CloseDown()
75 {
76 }
77
78 public string GetName()
79 {
80 return m_name;
81 }
82
83 public bool IsSharedModule()
84 {
85 return false;
86 }
87
88 public void NewClient(IClientAPI client)
89 {
90 client.OnChatFromViewer += DeliverClientMessage;
91 }
92
93 private void DeliverClientMessage(byte[] message, byte type, int channel, LLVector3 fromPos, string fromName,
94 LLUUID fromAgentID)
95 {
96 ASCIIEncoding ae = new ASCIIEncoding();
97
98 DeliverMessage(fromAgentID.ToString(), type, channel, fromName, ae.GetString(message));
99
100 }
101
102 public int Listen(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg)
103 {
104 return m_listenerManager.AddListener(localID, itemID, hostID, channel, name, id, msg);
105 }
106
107 public void ListenControl(int handle, int active)
108 {
109 if ( active == 1 )
110 m_listenerManager.Activate(handle);
111 else if ( active == 0 )
112 m_listenerManager.Dectivate(handle);
113
114 }
115
116 public void ListenRemove(int handle)
117 {
118 m_listenerManager.Remove(handle);
119 }
120
121 // This method scans nearby objects and determines if they are listeners,
122 // and if so if this message fits the filter. If it does, then
123 // enqueue the message for delivery to the objects listen event handler.
124 // Objects that do an llSay have their messages delivered here, and for
125 // nearby avatards, the SimChat function is used.
126 public void DeliverMessage(string sourceItemID, int type, int channel, string name, string msg)
127 {
128
129 SceneObjectPart source = null;
130 ScenePresence avatar = null;
131
132 source = m_scene.GetSceneObjectPart(new LLUUID(sourceItemID));
133 if (source == null)
134 {
135 avatar = m_scene.GetScenePresence(new LLUUID(sourceItemID));
136 }
137 if( (avatar != null) || (source != null) )
138 {
139 // Loop through the objects in the scene
140 // If they are in proximity, then if they are
141 // listeners, if so add them to the pending queue
142
143 foreach (LLUUID eb in m_scene.Entities.Keys)
144 {
145 EntityBase sPart;
146
147 m_scene.Entities.TryGetValue(eb, out sPart);
148
149 // Dont process if this message is from itself!
150 if (eb.ToString().Equals(sourceItemID) ||
151 sPart.UUID.ToString().Equals(sourceItemID) )
152 continue;
153
154 double dis = 0;
155
156 if (source != null)
157 dis = sPart.AbsolutePosition.GetDistanceTo(source.AbsolutePosition);
158 else
159 dis = sPart.AbsolutePosition.GetDistanceTo(avatar.AbsolutePosition);
160
161 switch (type)
162 {
163 case 0: // Whisper
164
165 if ((dis < 10) && (dis > -10))
166 {
167 ListenerInfo isListener = m_listenerManager.IsListenerMatch(
168 sourceItemID, sPart.UUID, channel, name, msg
169 );
170 if (isListener != null)
171 {
172 m_pending.Enqueue(isListener);
173 }
174
175 }
176 break;
177
178 case 1: // Say
179
180 if ((dis < 30) && (dis > -30))
181 {
182 ListenerInfo isListener = m_listenerManager.IsListenerMatch(
183 sourceItemID, sPart.UUID, channel, name, msg
184 );
185 if (isListener != null)
186 {
187 m_pending.Enqueue(isListener);
188 }
189
190 }
191 break;
192
193 case 2: // Shout
194 if ((dis < 100) && (dis > -100))
195 {
196 ListenerInfo isListener = m_listenerManager.IsListenerMatch(
197 sourceItemID, sPart.UUID, channel, name, msg
198 );
199 if (isListener != null)
200 {
201 m_pending.Enqueue(isListener);
202 }
203
204 }
205 break;
206
207 case 0xff: // Broadcast
208 ListenerInfo isListen = m_listenerManager.IsListenerMatch(sourceItemID, eb, channel, name, msg);
209 if (isListen != null)
210 {
211 ListenerInfo isListener = m_listenerManager.IsListenerMatch(
212 sourceItemID, sPart.UUID, channel, name, msg
213 );
214 if (isListener != null)
215 {
216 m_pending.Enqueue(isListener);
217 }
218 }
219 break;
220 }
221 };
222
223 }
224
225 }
226
227 public bool HasMessages()
228 {
229 return (m_pending.Count > 0);
230 }
231
232 public ListenerInfo GetNextMessage()
233 {
234
235 ListenerInfo li = null;
236
237 lock (CommListLock)
238 {
239 li = m_pending.Dequeue();
240 }
241
242 return li;
243
244 }
245
246 }
247
248 // hostID: the ID of the ScenePart
249 // itemID: the ID of the script host engine
250 // localID: local ID of host engine
251 public class ListenerManager
252 {
253 private Dictionary<int, ListenerInfo> m_listeners;
254 private object ListenersLock = new object();
255 private int m_MaxListeners = 100;
256
257 public ListenerManager()
258 {
259 m_listeners = new Dictionary<int, ListenerInfo>();
260 }
261
262 public int AddListener(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg)
263 {
264
265 if ( m_listeners.Count < m_MaxListeners )
266 {
267 ListenerInfo isListener = IsListenerMatch(LLUUID.Zero.ToString(), itemID, channel, name, msg);
268
269 if(isListener == null)
270 {
271 int newHandle = GetNewHandle();
272
273 if (newHandle > -1)
274 {
275
276 ListenerInfo li = new ListenerInfo(localID, newHandle, itemID, hostID, channel, name, id, msg);
277
278 lock (ListenersLock)
279 {
280 m_listeners.Add(newHandle, li);
281 }
282
283 return newHandle;
284 }
285
286 }
287
288 }
289
290 return -1;
291
292 }
293
294 public void Remove(int handle)
295 {
296 m_listeners.Remove(handle);
297 }
298
299 private int GetNewHandle()
300 {
301
302 for (int i = 0; i < int.MaxValue - 1; i++)
303 {
304 if (!m_listeners.ContainsKey(i))
305 return i;
306 }
307
308 return -1;
309
310 }
311
312 public bool IsListener(LLUUID hostID)
313 {
314
315 foreach (ListenerInfo li in m_listeners.Values)
316 {
317 if (li.GetHostID().Equals(hostID))
318 return true;
319 }
320
321 return false;
322
323 }
324
325 public void Activate(int handle)
326 {
327
328 ListenerInfo li;
329
330 if( m_listeners.TryGetValue(handle, out li) )
331 {
332 li.Activate();
333 }
334 }
335
336 public void Dectivate(int handle)
337 {
338
339 ListenerInfo li;
340
341 if( m_listeners.TryGetValue(handle, out li) )
342 {
343 li.Deactivate();
344 }
345 }
346
347 // Theres probably a more clever and efficient way to
348 // do this, maybe with regex.
349 public ListenerInfo IsListenerMatch(string sourceItemID, LLUUID listenerKey, int channel, string name, string msg)
350 {
351
352 bool isMatch = true;
353
354 foreach (ListenerInfo li in m_listeners.Values)
355 {
356 if (li.GetHostID().Equals(listenerKey))
357 {
358 if ( li.IsActive() )
359 {
360 if ( channel == li.GetChannel() )
361 {
362 if ( (li.GetID().ToString().Length > 0) &&
363 (!li.GetID().Equals(LLUUID.Zero)) )
364 {
365 if (!li.GetID().ToString().Equals(sourceItemID))
366 {
367 isMatch = false;
368 }
369 }
370 if ( isMatch && (li.GetName().Length > 0) )
371 {
372 if ( li.GetName().Equals(name) )
373 {
374 isMatch = false;
375 }
376 }
377 if ( isMatch )
378 {
379 return new ListenerInfo(
380 li.GetLocalID(), li.GetHandle(), li.GetItemID(), li.GetHostID(),
381 li.GetChannel(), name, li.GetID(), msg, new LLUUID(sourceItemID)
382 );
383 }
384 }
385 }
386 }
387 }
388 return null;
389 }
390
391 }
392
393 public class ListenerInfo
394 {
395
396 private LLUUID m_itemID; // ID of the host script engine
397 private LLUUID m_hostID; // ID of the host/scene part
398 private LLUUID m_sourceItemID; // ID of the scenePart or avatar source of the message
399 private int m_channel; // Channel
400 private int m_handle; // Assigned handle of this listener
401 private uint m_localID; // Local ID from script engine
402 private string m_name; // Object name to filter messages from
403 private LLUUID m_id; // ID to filter messages from
404 private string m_message; // The message
405 private bool m_active; // Listener is active or not
406
407 public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, string message)
408 {
409 Initialise(localID, handle, ItemID, hostID, channel, name, id, message);
410 }
411
412 public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, string message, LLUUID sourceItemID)
413 {
414 Initialise(localID, handle, ItemID, hostID, channel, name, id, message);
415 m_sourceItemID = sourceItemID;
416 }
417
418 private void Initialise(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, string message)
419 {
420 m_handle = handle;
421 m_channel = channel;
422 m_itemID = ItemID;
423 m_hostID = hostID;
424 m_name = name;
425 m_id = id;
426 m_message = message;
427 m_active = true;
428 m_localID = localID;
429 }
430 public LLUUID GetItemID()
431 {
432 return m_itemID;
433 }
434 public LLUUID GetHostID()
435 {
436 return m_hostID;
437 }
438 public LLUUID GetSourceItemID()
439 {
440 return m_sourceItemID;
441 }
442 public int GetChannel()
443 {
444 return m_channel;
445 }
446 public uint GetLocalID()
447 {
448 return m_localID;
449 }
450 public int GetHandle()
451 {
452 return m_handle;
453 }
454 public string GetMessage()
455 {
456 return m_message;
457 }
458 public string GetName()
459 {
460 return m_name;
461 }
462 public bool IsActive()
463 {
464 return m_active;
465 }
466 public void Deactivate()
467 {
468 m_active = false;
469 }
470 public void Activate()
471 {
472 m_active = true;
473 }
474 public LLUUID GetID()
475 {
476 return m_id;
477 }
478
479 }
480
481}