diff options
Diffstat (limited to 'OpenSim/Region/Environment/Modules/WorldCommModule.cs')
-rw-r--r-- | OpenSim/Region/Environment/Modules/WorldCommModule.cs | 584 |
1 files changed, 0 insertions, 584 deletions
diff --git a/OpenSim/Region/Environment/Modules/WorldCommModule.cs b/OpenSim/Region/Environment/Modules/WorldCommModule.cs deleted file mode 100644 index 638deed..0000000 --- a/OpenSim/Region/Environment/Modules/WorldCommModule.cs +++ /dev/null | |||
@@ -1,584 +0,0 @@ | |||
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 OpenSim 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 libsecondlife; | ||
31 | using Nini.Config; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Environment.Interfaces; | ||
34 | using OpenSim.Region.Environment.Scenes; | ||
35 | |||
36 | /***************************************************** | ||
37 | * | ||
38 | * WorldCommModule | ||
39 | * | ||
40 | * | ||
41 | * Holding place for world comms - basically llListen | ||
42 | * function implementation. | ||
43 | * | ||
44 | * lLListen(integer channel, string name, key id, string msg) | ||
45 | * The name, id, and msg arguments specify the filtering | ||
46 | * criteria. You can pass the empty string | ||
47 | * (or NULL_KEY for id) for these to set a completely | ||
48 | * open filter; this causes the listen() event handler to be | ||
49 | * invoked for all chat on the channel. To listen only | ||
50 | * for chat spoken by a specific object or avatar, | ||
51 | * specify the name and/or id arguments. To listen | ||
52 | * only for a specific command, specify the | ||
53 | * (case-sensitive) msg argument. If msg is not empty, | ||
54 | * listener will only hear strings which are exactly equal | ||
55 | * to msg. You can also use all the arguments to establish | ||
56 | * the most restrictive filtering criteria. | ||
57 | * | ||
58 | * It might be useful for each listener to maintain a message | ||
59 | * digest, with a list of recent messages by UUID. This can | ||
60 | * be used to prevent in-world repeater loops. However, the | ||
61 | * linden functions do not have this capability, so for now | ||
62 | * thats the way it works. | ||
63 | * | ||
64 | * **************************************************/ | ||
65 | |||
66 | namespace OpenSim.Region.Environment.Modules | ||
67 | { | ||
68 | public class WorldCommModule : IRegionModule, IWorldComm | ||
69 | { | ||
70 | private Scene m_scene; | ||
71 | private object CommListLock = new object(); | ||
72 | private object ListLock = new object(); | ||
73 | private string m_name = "WorldCommModule"; | ||
74 | private ListenerManager m_listenerManager; | ||
75 | private Queue m_pendingQ; | ||
76 | private Queue m_pending; | ||
77 | |||
78 | public WorldCommModule() | ||
79 | { | ||
80 | } | ||
81 | |||
82 | public void Initialise(Scene scene, IConfigSource config) | ||
83 | { | ||
84 | m_scene = scene; | ||
85 | m_scene.RegisterModuleInterface<IWorldComm>(this); | ||
86 | m_listenerManager = new ListenerManager(); | ||
87 | m_scene.EventManager.OnNewClient += NewClient; | ||
88 | m_pendingQ = new Queue(); | ||
89 | m_pending = Queue.Synchronized(m_pendingQ); | ||
90 | } | ||
91 | |||
92 | public void PostInitialise() | ||
93 | { | ||
94 | } | ||
95 | |||
96 | public void Close() | ||
97 | { | ||
98 | } | ||
99 | |||
100 | public string Name | ||
101 | { | ||
102 | get { return m_name; } | ||
103 | } | ||
104 | |||
105 | public bool IsSharedModule | ||
106 | { | ||
107 | get { return false; } | ||
108 | } | ||
109 | |||
110 | public void NewClient(IClientAPI client) | ||
111 | { | ||
112 | client.OnChatFromViewer += DeliverClientMessage; | ||
113 | } | ||
114 | |||
115 | /******************************************************************** | ||
116 | * | ||
117 | * Listener Stuff | ||
118 | * | ||
119 | * *****************************************************************/ | ||
120 | private void DeliverClientMessage(Object sender, ChatFromViewerArgs e) | ||
121 | { | ||
122 | DeliverMessage(e.Sender.AgentId.ToString(), | ||
123 | e.Type, e.Channel, | ||
124 | e.Sender.FirstName + " " + e.Sender.LastName, | ||
125 | e.Message); | ||
126 | } | ||
127 | |||
128 | public int Listen(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg) | ||
129 | { | ||
130 | return m_listenerManager.AddListener(localID, itemID, hostID, channel, name, id, msg); | ||
131 | } | ||
132 | |||
133 | public void ListenControl(int handle, int active) | ||
134 | { | ||
135 | if (m_listenerManager != null) | ||
136 | { | ||
137 | if (active == 1) | ||
138 | m_listenerManager.Activate(handle); | ||
139 | else if (active == 0) | ||
140 | m_listenerManager.Dectivate(handle); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | public void ListenRemove(int handle) | ||
145 | { | ||
146 | if (m_listenerManager != null) | ||
147 | { | ||
148 | m_listenerManager.Remove(handle); | ||
149 | } | ||
150 | } | ||
151 | |||
152 | public void DeleteListener(LLUUID itemID) | ||
153 | { | ||
154 | if (m_listenerManager != null) | ||
155 | { | ||
156 | m_listenerManager.DeleteListener(itemID); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | // This method scans nearby objects and determines if they are listeners, | ||
161 | // and if so if this message fits the filter. If it does, then | ||
162 | // enqueue the message for delivery to the objects listen event handler. | ||
163 | // Objects that do an llSay have their messages delivered here, and for | ||
164 | // nearby avatars, the SimChat function is used. | ||
165 | public void DeliverMessage(string sourceItemID, ChatTypeEnum type, int channel, string name, string msg) | ||
166 | { | ||
167 | SceneObjectPart source = null; | ||
168 | ScenePresence avatar = null; | ||
169 | |||
170 | source = m_scene.GetSceneObjectPart(new LLUUID(sourceItemID)); | ||
171 | if (source == null) | ||
172 | { | ||
173 | avatar = m_scene.GetScenePresence(new LLUUID(sourceItemID)); | ||
174 | } | ||
175 | if ((avatar != null) || (source != null)) | ||
176 | { | ||
177 | // Loop through the objects in the scene | ||
178 | // If they are in proximity, then if they are | ||
179 | // listeners, if so add them to the pending queue | ||
180 | |||
181 | foreach (ListenerInfo li in m_listenerManager.GetListeners()) | ||
182 | { | ||
183 | EntityBase sPart; | ||
184 | |||
185 | m_scene.Entities.TryGetValue(li.GetHostID(), out sPart); | ||
186 | |||
187 | if (sPart != null) | ||
188 | { | ||
189 | double dis = 0; | ||
190 | |||
191 | if (source != null) | ||
192 | dis = Util.GetDistanceTo(sPart.AbsolutePosition, source.AbsolutePosition); | ||
193 | else | ||
194 | dis = Util.GetDistanceTo(sPart.AbsolutePosition, avatar.AbsolutePosition); | ||
195 | |||
196 | switch (type) | ||
197 | { | ||
198 | case ChatTypeEnum.Whisper: | ||
199 | |||
200 | if ((dis < 10) && (dis > -10)) | ||
201 | { | ||
202 | if (li.GetChannel() == channel) | ||
203 | { | ||
204 | ListenerInfo isListener = m_listenerManager.IsListenerMatch( | ||
205 | sourceItemID, sPart.UUID, channel, name, msg | ||
206 | ); | ||
207 | if (isListener != null) | ||
208 | { | ||
209 | lock (m_pending.SyncRoot) | ||
210 | { | ||
211 | m_pending.Enqueue(isListener); | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | break; | ||
217 | |||
218 | case ChatTypeEnum.Say: | ||
219 | |||
220 | if ((dis < 30) && (dis > -30)) | ||
221 | { | ||
222 | if (li.GetChannel() == channel) | ||
223 | { | ||
224 | ListenerInfo isListener = m_listenerManager.IsListenerMatch( | ||
225 | sourceItemID, sPart.UUID, channel, name, msg | ||
226 | ); | ||
227 | if (isListener != null) | ||
228 | { | ||
229 | lock (m_pending.SyncRoot) | ||
230 | { | ||
231 | m_pending.Enqueue(isListener); | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | break; | ||
237 | |||
238 | case ChatTypeEnum.Shout: | ||
239 | if ((dis < 100) && (dis > -100)) | ||
240 | { | ||
241 | if (li.GetChannel() == channel) | ||
242 | { | ||
243 | ListenerInfo isListener = m_listenerManager.IsListenerMatch( | ||
244 | sourceItemID, sPart.UUID, channel, name, msg | ||
245 | ); | ||
246 | if (isListener != null) | ||
247 | { | ||
248 | lock (m_pending.SyncRoot) | ||
249 | { | ||
250 | m_pending.Enqueue(isListener); | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | } | ||
255 | break; | ||
256 | |||
257 | case ChatTypeEnum.Broadcast: | ||
258 | // Dont process if this message is from itself! | ||
259 | if (li.GetHostID().ToString().Equals(sourceItemID) || | ||
260 | sPart.UUID.ToString().Equals(sourceItemID)) | ||
261 | continue; | ||
262 | |||
263 | if (li.GetChannel() == channel) | ||
264 | { | ||
265 | ListenerInfo isListener = m_listenerManager.IsListenerMatch( | ||
266 | sourceItemID, sPart.UUID, channel, name, msg | ||
267 | ); | ||
268 | if (isListener != null) | ||
269 | { | ||
270 | lock (m_pending.SyncRoot) | ||
271 | { | ||
272 | m_pending.Enqueue(isListener); | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | |||
277 | break; | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | |||
284 | public bool HasMessages() | ||
285 | { | ||
286 | if (m_pending != null) | ||
287 | return (m_pending.Count > 0); | ||
288 | else | ||
289 | return false; | ||
290 | } | ||
291 | |||
292 | public ListenerInfo GetNextMessage() | ||
293 | { | ||
294 | ListenerInfo li = null; | ||
295 | |||
296 | lock (m_pending.SyncRoot) | ||
297 | { | ||
298 | li = (ListenerInfo)m_pending.Dequeue(); | ||
299 | } | ||
300 | |||
301 | return li; | ||
302 | } | ||
303 | |||
304 | public uint PeekNextMessageLocalID() | ||
305 | { | ||
306 | return ((ListenerInfo)m_pending.Peek()).GetLocalID(); | ||
307 | } | ||
308 | |||
309 | public LLUUID PeekNextMessageItemID() | ||
310 | { | ||
311 | return ((ListenerInfo)m_pending.Peek()).GetItemID(); | ||
312 | } | ||
313 | } | ||
314 | |||
315 | /********************************************************** | ||
316 | * | ||
317 | * Even more listener stuff | ||
318 | * | ||
319 | * ********************************************************/ | ||
320 | public class ListenerManager | ||
321 | { | ||
322 | //private Dictionary<int, ListenerInfo> m_listeners; | ||
323 | private Hashtable m_listeners = Hashtable.Synchronized(new Hashtable()); | ||
324 | private object ListenersLock = new object(); | ||
325 | private int m_MaxListeners = 100; | ||
326 | |||
327 | public int AddListener(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg) | ||
328 | { | ||
329 | if (m_listeners.Count < m_MaxListeners) | ||
330 | { | ||
331 | ListenerInfo isListener = IsListenerMatch(LLUUID.Zero.ToString(), itemID, channel, name, msg); | ||
332 | |||
333 | if (isListener == null) | ||
334 | { | ||
335 | int newHandle = GetNewHandle(); | ||
336 | |||
337 | if (newHandle > -1) | ||
338 | { | ||
339 | ListenerInfo li = new ListenerInfo(localID, newHandle, itemID, hostID, channel, name, id, msg); | ||
340 | |||
341 | lock (m_listeners.SyncRoot) | ||
342 | { | ||
343 | m_listeners.Add(newHandle, li); | ||
344 | } | ||
345 | |||
346 | return newHandle; | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | |||
351 | return -1; | ||
352 | } | ||
353 | |||
354 | public void Remove(int handle) | ||
355 | { | ||
356 | lock (m_listeners.SyncRoot) | ||
357 | { | ||
358 | m_listeners.Remove(handle); | ||
359 | } | ||
360 | } | ||
361 | |||
362 | public void DeleteListener(LLUUID itemID) | ||
363 | { | ||
364 | ArrayList removedListeners = new ArrayList(); | ||
365 | |||
366 | lock (m_listeners.SyncRoot) | ||
367 | { | ||
368 | IDictionaryEnumerator en = m_listeners.GetEnumerator(); | ||
369 | while (en.MoveNext()) | ||
370 | { | ||
371 | ListenerInfo li = (ListenerInfo)en.Value; | ||
372 | if (li.GetItemID().Equals(itemID)) | ||
373 | { | ||
374 | removedListeners.Add(li.GetHandle()); | ||
375 | } | ||
376 | } | ||
377 | foreach (int handle in removedListeners) | ||
378 | { | ||
379 | m_listeners.Remove(handle); | ||
380 | } | ||
381 | } | ||
382 | } | ||
383 | |||
384 | private int GetNewHandle() | ||
385 | { | ||
386 | for (int i = 0; i < int.MaxValue - 1; i++) | ||
387 | { | ||
388 | if (!m_listeners.ContainsKey(i)) | ||
389 | return i; | ||
390 | } | ||
391 | |||
392 | return -1; | ||
393 | } | ||
394 | |||
395 | public bool IsListener(LLUUID hostID) | ||
396 | { | ||
397 | foreach (ListenerInfo li in m_listeners.Values) | ||
398 | { | ||
399 | if (li.GetHostID().Equals(hostID)) | ||
400 | return true; | ||
401 | } | ||
402 | |||
403 | return false; | ||
404 | } | ||
405 | |||
406 | public void Activate(int handle) | ||
407 | { | ||
408 | |||
409 | if (m_listeners.ContainsKey(handle)) | ||
410 | { | ||
411 | lock (m_listeners.SyncRoot) | ||
412 | { | ||
413 | ListenerInfo li = (ListenerInfo)m_listeners[handle]; | ||
414 | li.Activate(); | ||
415 | } | ||
416 | } | ||
417 | } | ||
418 | |||
419 | public void Dectivate(int handle) | ||
420 | { | ||
421 | |||
422 | if (m_listeners.ContainsKey(handle)) | ||
423 | { | ||
424 | ListenerInfo li = (ListenerInfo)m_listeners[handle]; | ||
425 | li.Deactivate(); | ||
426 | } | ||
427 | } | ||
428 | |||
429 | // Theres probably a more clever and efficient way to | ||
430 | // do this, maybe with regex. | ||
431 | public ListenerInfo IsListenerMatch(string sourceItemID, LLUUID listenerKey, int channel, string name, | ||
432 | string msg) | ||
433 | { | ||
434 | bool isMatch = true; | ||
435 | lock (m_listeners.SyncRoot) | ||
436 | { | ||
437 | IDictionaryEnumerator en = m_listeners.GetEnumerator(); | ||
438 | while (en.MoveNext()) | ||
439 | { | ||
440 | ListenerInfo li = (ListenerInfo)en.Value; | ||
441 | |||
442 | if (li.IsActive()) | ||
443 | { | ||
444 | if (li.GetHostID().Equals(listenerKey)) | ||
445 | { | ||
446 | if (channel == li.GetChannel()) | ||
447 | { | ||
448 | if ((li.GetID().ToString().Length > 0) && | ||
449 | (!li.GetID().Equals(LLUUID.Zero))) | ||
450 | { | ||
451 | if (!li.GetID().ToString().Equals(sourceItemID)) | ||
452 | { | ||
453 | isMatch = false; | ||
454 | } | ||
455 | } | ||
456 | if (isMatch && (li.GetName().Length > 0)) | ||
457 | { | ||
458 | if (li.GetName().Equals(name)) | ||
459 | { | ||
460 | isMatch = false; | ||
461 | } | ||
462 | } | ||
463 | if (isMatch) | ||
464 | { | ||
465 | return new ListenerInfo( | ||
466 | li.GetLocalID(), li.GetHandle(), li.GetItemID(), li.GetHostID(), | ||
467 | li.GetChannel(), name, li.GetID(), msg, new LLUUID(sourceItemID) | ||
468 | ); | ||
469 | } | ||
470 | } | ||
471 | } | ||
472 | } | ||
473 | } | ||
474 | } | ||
475 | return null; | ||
476 | } | ||
477 | |||
478 | public ICollection GetListeners() | ||
479 | { | ||
480 | return m_listeners.Values; | ||
481 | } | ||
482 | } | ||
483 | |||
484 | public class ListenerInfo | ||
485 | { | ||
486 | private LLUUID m_itemID; // ID of the host script engine | ||
487 | private LLUUID m_hostID; // ID of the host/scene part | ||
488 | private LLUUID m_sourceItemID; // ID of the scenePart or avatar source of the message | ||
489 | private int m_channel; // Channel | ||
490 | private int m_handle; // Assigned handle of this listener | ||
491 | private uint m_localID; // Local ID from script engine | ||
492 | private string m_name; // Object name to filter messages from | ||
493 | private LLUUID m_id; // ID to filter messages from | ||
494 | private string m_message; // The message | ||
495 | private bool m_active; // Listener is active or not | ||
496 | |||
497 | public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, string message) | ||
498 | { | ||
499 | Initialise(localID, handle, ItemID, hostID, channel, name, id, message); | ||
500 | } | ||
501 | |||
502 | public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, | ||
503 | string message, LLUUID sourceItemID) | ||
504 | { | ||
505 | Initialise(localID, handle, ItemID, hostID, channel, name, id, message); | ||
506 | m_sourceItemID = sourceItemID; | ||
507 | } | ||
508 | |||
509 | private void Initialise(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, | ||
510 | LLUUID id, string message) | ||
511 | { | ||
512 | m_handle = handle; | ||
513 | m_channel = channel; | ||
514 | m_itemID = ItemID; | ||
515 | m_hostID = hostID; | ||
516 | m_name = name; | ||
517 | m_id = id; | ||
518 | m_message = message; | ||
519 | m_active = true; | ||
520 | m_localID = localID; | ||
521 | } | ||
522 | |||
523 | public LLUUID GetItemID() | ||
524 | { | ||
525 | return m_itemID; | ||
526 | } | ||
527 | |||
528 | public LLUUID GetHostID() | ||
529 | { | ||
530 | return m_hostID; | ||
531 | } | ||
532 | |||
533 | public LLUUID GetSourceItemID() | ||
534 | { | ||
535 | return m_sourceItemID; | ||
536 | } | ||
537 | |||
538 | public int GetChannel() | ||
539 | { | ||
540 | return m_channel; | ||
541 | } | ||
542 | |||
543 | public uint GetLocalID() | ||
544 | { | ||
545 | return m_localID; | ||
546 | } | ||
547 | |||
548 | public int GetHandle() | ||
549 | { | ||
550 | return m_handle; | ||
551 | } | ||
552 | |||
553 | public string GetMessage() | ||
554 | { | ||
555 | return m_message; | ||
556 | } | ||
557 | |||
558 | public string GetName() | ||
559 | { | ||
560 | return m_name; | ||
561 | } | ||
562 | |||
563 | public bool IsActive() | ||
564 | { | ||
565 | return m_active; | ||
566 | } | ||
567 | |||
568 | public void Deactivate() | ||
569 | { | ||
570 | m_active = false; | ||
571 | } | ||
572 | |||
573 | public void Activate() | ||
574 | { | ||
575 | m_active = true; | ||
576 | } | ||
577 | |||
578 | public LLUUID GetID() | ||
579 | { | ||
580 | return m_id; | ||
581 | } | ||
582 | } | ||
583 | |||
584 | } | ||